diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:00:34 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:00:34 +0000 |
commit | 3f619478f796eddbba6e39502fe941b285dd97b1 (patch) | |
tree | e2c7b5777f728320e5b5542b6213fd3591ba51e2 /scripts | |
parent | Initial commit. (diff) | |
download | mariadb-upstream.tar.xz mariadb-upstream.zip |
Adding upstream version 1:10.11.6.upstream/1%10.11.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'scripts')
215 files changed, 42410 insertions, 0 deletions
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt new file mode 100644 index 00000000..9eec793c --- /dev/null +++ b/scripts/CMakeLists.txt @@ -0,0 +1,409 @@ +# Copyright (c) 2006, 2017, Oracle and/or its affiliates. +# Copyright (c) 2011, 2020, 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 Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA + +# Build comp_sql - used for embedding SQL in C or C++ programs + +MACRO(INSTALL_LINK old new destination component) + EXECUTE_PROCESS( + COMMAND ${CMAKE_COMMAND} -E create_symlink ${old} ${new} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + INSTALL( + PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${new} + DESTINATION ${destination} + COMPONENT ${component} + ) +ENDMACRO() + +IF(NOT CMAKE_CROSSCOMPILING OR DEFINED CMAKE_CROSSCOMPILING_EMULATOR) + INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) + ADD_EXECUTABLE(comp_sql comp_sql.c ../sql/sql_bootstrap.cc) + TARGET_LINK_LIBRARIES(comp_sql) +ENDIF() + +# Build mysql_fix_privilege_tables.sql (concatenate 3 sql scripts) +IF(NOT WIN32 OR (CMAKE_CROSSCOMPILING AND NOT DEFINED CMAKE_CROSSCOMPILING_EMULATOR)) + FIND_PROGRAM(CAT_EXECUTABLE cat DOC "path to the executable") + MARK_AS_ADVANCED(CAT_EXECUTABLE) +ENDIF() + +IF(NOT ("${CMAKE_BINARY_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")) + FOREACH(f fill_help_tables.sql mysql_system_tables_fix.sql mysql_system_tables.sql mysql_system_tables_data.sql mysql_performance_tables.sql) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${f} ${CMAKE_CURRENT_BINARY_DIR}/${f} COPYONLY) + ENDFOREACH() +ENDIF() + +IF(CAT_EXECUTABLE) + SET(CAT_COMMAND COMMAND + ${CAT_EXECUTABLE} mysql_system_tables_fix.sql mysql_system_tables.sql mysql_performance_tables.sql mysql_sys_schema.sql> + mysql_fix_privilege_tables.sql + ) +ELSEIF(WIN32) + SET(CAT_COMMAND + COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_CURRENT_BINARY_DIR} + cmd /c copy /b mysql_system_tables_fix.sql + mysql_system_tables.sql + mysql_performance_tables.sql + mysql_sys_schema.sql + mysql_fix_privilege_tables.sql ) +ELSE() + MESSAGE(FATAL_ERROR "Cannot concatenate files") +ENDIF() + +# Build mysql_fix_privilege_tables.c +ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mysql_fix_privilege_tables_sql.c + ${CAT_COMMAND} + COMMAND comp_sql + mysql_fix_privilege_tables + mysql_fix_privilege_tables.sql + mysql_fix_privilege_tables_sql.c + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS comp_sql + ${CMAKE_CURRENT_SOURCE_DIR}/mysql_system_tables.sql + ${CMAKE_CURRENT_SOURCE_DIR}/mysql_system_tables_fix.sql + ${CMAKE_CURRENT_SOURCE_DIR}/mysql_performance_tables.sql + ${CMAKE_CURRENT_BINARY_DIR}/mysql_sys_schema.sql +) + +# Add target for the above to be built +ADD_CUSTOM_TARGET(GenFixPrivs + ALL + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/mysql_fix_privilege_tables_sql.c +) + +IF(UNIX AND NOT WITHOUT_SERVER) + FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/make_binary_distribution + "cd ${CMAKE_BINARY_DIR} && '${CMAKE_CPACK_COMMAND}' -G TGZ --config CPackConfig.cmake\n" ) + EXECUTE_PROCESS( + COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/make_binary_distribution +) +ENDIF() + +# Configure two scripts from one 'in' file. +# The maria_add_gis_sp.sql - to be sent to 'mysql' tool +# and the maria_add_gis_sp_bootstrap.sql, that can be sent to +# the server as a bootstrap command. + +SET(ADD_GIS_SP_SET_DELIMITER "delimiter |") +SET(ADD_GIS_SP_RESET_DELIMITER "delimiter ;") +SET(ADD_GIS_SP_EOL "|") +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/maria_add_gis_sp.sql.in + ${CMAKE_CURRENT_BINARY_DIR}/maria_add_gis_sp.sql ESCAPE_QUOTES @ONLY) + +SET(ADD_GIS_SP_SET_DELIMITER "") +SET(ADD_GIS_SP_RESET_DELIMITER "") +SET(ADD_GIS_SP_EOL ";") +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/maria_add_gis_sp.sql.in + ${CMAKE_CURRENT_BINARY_DIR}/maria_add_gis_sp_bootstrap.sql ESCAPE_QUOTES @ONLY) + +IF (NOT WITHOUT_SERVER) +INSTALL(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/mysql_system_tables.sql + ${CMAKE_CURRENT_SOURCE_DIR}/mysql_system_tables_data.sql + ${CMAKE_CURRENT_SOURCE_DIR}/mysql_performance_tables.sql + ${CMAKE_CURRENT_SOURCE_DIR}/mysql_test_db.sql + ${CMAKE_CURRENT_SOURCE_DIR}/fill_help_tables.sql + ${CMAKE_CURRENT_SOURCE_DIR}/mysql_test_data_timezone.sql + ${CMAKE_CURRENT_BINARY_DIR}/maria_add_gis_sp.sql + ${CMAKE_CURRENT_BINARY_DIR}/maria_add_gis_sp_bootstrap.sql + ${CMAKE_CURRENT_BINARY_DIR}/mysql_sys_schema.sql + ${FIX_PRIVILEGES_SQL} + DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT Server +) +ENDIF() + +# TCMalloc hacks +IF(MALLOC_LIB) + MESSAGE("Using tcmalloc '${MALLOC_LIB}'") + INSTALL(FILES ${MALLOC_LIB} DESTINATION ${INSTALL_LIBDIR} OPTIONAL) +ENDIF() + +IF(CMAKE_GENERATOR MATCHES "Makefiles|Ninja") + FOREACH(ARCH ${CMAKE_OSX_ARCHITECTURES}) + SET(CFLAGS "${CFLAGS} -arch ${ARCH}") + SET(CXXFLAGS "${CXXFLAGS} -arch ${ARCH}") + ENDFOREACH() +ENDIF() + +IF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + SET (PERL_PATH "/usr/local/bin/perl") +ELSE() + SET (PERL_PATH "/usr/bin/perl") +ENDIF() + +IF(UNIX) + # FIND_PROC and CHECK_PID are used by mysqld_safe +IF(CMAKE_SYSTEM_NAME MATCHES "Linux") + SET (FIND_PROC + "ps wwwp $PID | grep -v mariadbd-safe | grep -v mysqld_safe | grep -- $MYSQLD > /dev/null") +ENDIF() +IF(NOT FIND_PROC AND CMAKE_SYSTEM_NAME MATCHES "SunOS") + SET (FIND_PROC + "ps -p $PID | grep -v mariadbd-safe | grep -- $MYSQLD > /dev/null") +ENDIF() + +IF(NOT FIND_PROC) + # BSD style + EXECUTE_PROCESS(COMMAND ps -uaxww OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE result) + IF(result MATCHES 0) + SET( FIND_PROC + "ps -uaxww | grep -v mariadbd-safe | grep -- $MYSQLD | grep $PID > /dev/null") + ENDIF() +ENDIF() + +IF(NOT FIND_PROC) + # SysV style + EXECUTE_PROCESS(COMMAND ps -ef OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE result) + IF(result MATCHES 0) + SET( FIND_PROC "ps -ef | grep -v mariadbd-safe | grep -- $MYSQLD | grep $PID > /dev/null") + ENDIF() +ENDIF() + +EXECUTE_PROCESS(COMMAND sh -c "kill -0 $$" OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE result) +IF(result MATCHES 0) + SET(CHECK_PID "kill -0 $PID > /dev/null 2> /dev/null") +ELSE() + SET(CHECK_PID "kill -s SIGCONT $PID > /dev/null 2> /dev/null") +ENDIF() + +SET(HOSTNAME "uname -n") +SET(MYSQLD_USER "mysql") +SET(MYSQLD_GROUP "mysql") +ENDIF(UNIX) + +# Really ugly, one script, "mysql_install_db", needs prefix set to ".", +# i.e. makes access relative the current directory. This matches +# the documentation, so better not change this. + +IF(INSTALL_LAYOUT MATCHES "STANDALONE") + SET(prefix ".") + SET(bindir ${prefix}/${INSTALL_BINDIR}) + SET(sbindir ${prefix}/${INSTALL_SBINDIR}) + SET(scriptdir ${prefix}/${INSTALL_BINDIR}) + SET(libexecdir ${prefix}/${INSTALL_SBINDIR}) + SET(pkgdatadir ${prefix}/${INSTALL_MYSQLSHAREDIR}) + SET(pkgplugindir ${prefix}/${INSTALL_PLUGINDIR}) + SET(localstatedir ${prefix}/data) +ELSE() + SET(prefix "${CMAKE_INSTALL_PREFIX}") + SET(bindir ${INSTALL_BINDIRABS}) + SET(sbindir ${INSTALL_SBINDIRABS}) + SET(scriptdir ${INSTALL_BINDIRABS}) + SET(libexecdir ${INSTALL_SBINDIRABS}) + SET(pkgdatadir ${INSTALL_MYSQLSHAREDIRABS}) + SET(pkgplugindir ${INSTALL_PLUGINDIRABS}) + SET(localstatedir ${MYSQL_DATADIR}) +ENDIF() + +SET(resolveip_locations "$basedir/${INSTALL_BINDIR} $basedir/bin") +SET(mysqld_locations "$basedir/${INSTALL_SBINDIR} $basedir/libexec $basedir/sbin $basedir/bin") +SET(errmsg_locations "$basedir/${INSTALL_MYSQLSHAREDIR}/english $basedir/share/english $basedir/share/mysql/english") +SET(pkgdata_locations "$basedir/${INSTALL_MYSQLSHAREDIR} $basedir/share $basedir/share/mysql") + +# install mysql_install_db.sh at this point since it needs +# different values for the above variables that will change +# afterwards +IF(UNIX AND NOT WITHOUT_SERVER) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/mysql_install_db.sh + ${CMAKE_CURRENT_BINARY_DIR}/mariadb-install-db ESCAPE_QUOTES @ONLY) + EXECUTE_PROCESS(COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/mariadb-install-db) + INSTALL_SCRIPT( + "${CMAKE_CURRENT_BINARY_DIR}/mariadb-install-db" + DESTINATION ${INSTALL_SCRIPTDIR} + COMPONENT Server) + + INSTALL_LINK(mariadb-install-db mysql_install_db ${INSTALL_SCRIPTDIR} Server) +ENDIF() + +SET(prefix "${CMAKE_INSTALL_PREFIX}") +IF(INSTALL_SYSCONFDIR) + SET(sysconfdir ${DEFAULT_SYSCONFDIR}) +ELSE() + SET(sysconfdir "/etc") +ENDIF() +SET(bindir ${INSTALL_BINDIRABS}) +SET(libexecdir ${INSTALL_SBINDIRABS}) +SET(scriptdir ${INSTALL_BINDIRABS}) +SET(datadir ${INSTALL_MYSQLSHAREDIRABS}) +SET(pkgdatadir ${INSTALL_MYSQLSHAREDIRABS}) +SET(libsubdir ${INSTALL_LIBDIR}) +SET(pkgincludedir ${INSTALL_INCLUDEDIRABS}) +SET(pkglibdir ${INSTALL_LIBDIRABS}) +SET(pkgplugindir ${INSTALL_PLUGINDIRABS}) +SET(localstatedir ${MYSQL_DATADIR}) + +SET(RPATH_OPTION "") +IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS") + SET(RPATH_OPTION "-R$pkglibdir") +ENDIF() + +# some scripts use @TARGET_LINUX@ +IF(CMAKE_SYSTEM_NAME MATCHES "Linux") + SET(TARGET_LINUX "true") +ELSE() + SET(TARGET_LINUX "false") +ENDIF() + +SET(mysql_config_COMPONENT Development) +SET(msql2mysql_COMPONENT Client) +SET(mariadb-access_COMPONENT Client) +SET(mariadb-find-rows_COMPONENT Client) +SET(mytop_COMPONENT Client) +SET(mariadb-hotcopy_COMPONENT COMPONENT Client) +SET(mariadb-convert-table-format_COMPONENT COMPONENT Client) +SET(mariadb-setpermission_COMPONENT COMPONENT Client) +SET(mariadb-secure-installation_COMPONENT COMPONENT Client) +SET(mariadb-dumpslow_COMPONENT COMPONENT Client) + +IF(WIN32) + # On Windows, some .sh and some .pl.in files are configured + # The resulting files will have .pl extension (those are perl scripts) + + # Input files with pl.in extension + SET(PLIN_FILES mysql_config) + # Input files with .sh extension + + SET(SH_FILES mysql_convert_table_format mysqld_multi mysqldumpslow + mysqlhotcopy) + + FOREACH(file ${PLIN_FILES}) + IF(NOT ${file}_COMPONENT) + SET(${file}_COMPONENT Server_Scripts) + ENDIF() + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${file}.pl.in + ${CMAKE_CURRENT_BINARY_DIR}/${file}.pl ESCAPE_QUOTES @ONLY) + INSTALL_SCRIPT(${CMAKE_CURRENT_BINARY_DIR}/${file}.pl COMPONENT ${${file}_COMPONENT}) + ENDFOREACH() + + FOREACH(file ${SH_FILES}) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${file}.sh + ${CMAKE_CURRENT_BINARY_DIR}/${file}.pl ESCAPE_QUOTES @ONLY) + INSTALL_SCRIPT(${CMAKE_CURRENT_BINARY_DIR}/${file}.pl COMPONENT Server_Scripts) + ENDFOREACH() +ELSE() + IF(WITH_WSREP) + SET(WSREP_SCRIPTS + wsrep_sst_mysqldump + wsrep_sst_rsync + wsrep_sst_mariabackup + wsrep_sst_backup + ) + # The following script is sourced from other SST scripts, so it should + # not be made executable. + SET(WSREP_SOURCE + wsrep_sst_common + ) + + INSTALL_LINK(wsrep_sst_rsync wsrep_sst_rsync_wan ${INSTALL_BINDIR} Server) + FOREACH(file ${WSREP_SOURCE}) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${file}.sh + ${CMAKE_CURRENT_BINARY_DIR}/${file} ESCAPE_QUOTES @ONLY) + IF(NOT ${file}_COMPONENT) + SET(${file}_COMPONENT Server) + ENDIF() + INSTALL(FILES + ${CMAKE_CURRENT_BINARY_DIR}/${file} + DESTINATION ${INSTALL_BINDIR} + COMPONENT ${${file}_COMPONENT} + ) + ENDFOREACH() + ENDIF() + IF (NOT WITHOUT_SERVER) + SET(SERVER_SCRIPTS + mariadb-fix-extensions + mariadbd-multi + mariadbd-safe + ${SYSTEMD_SCRIPTS} + ) + ENDIF() + # Configure this one, for testing, but do not install it. + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/mysql_config.pl.in + ${CMAKE_CURRENT_BINARY_DIR}/mysql_config.pl ESCAPE_QUOTES @ONLY) + # On Unix, most of the files end up in the bin directory + SET(BIN_SCRIPTS + msql2mysql + mariadb-setpermission + mariadb-secure-installation + mariadb-access + mariadb-convert-table-format + mariadb-find-rows + mariadb-dumpslow + mysql_config + mytop + mariadb-hotcopy + ${SERVER_SCRIPTS} + ${WSREP_SCRIPTS} + ) + + FOREACH(file ${BIN_SCRIPTS}) + # set name of executable + GET_SYMLINK(${file} binname) + + if("${binname}" STREQUAL "") + set(binname ${file}) + endif() + + IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${binname}.sh) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${binname}.sh + ${CMAKE_CURRENT_BINARY_DIR}/${file} ESCAPE_QUOTES @ONLY) + ELSEIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${binname}) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${binname} + ${CMAKE_CURRENT_BINARY_DIR}/${file} COPYONLY) + ELSE() + MESSAGE(FATAL_ERROR "Cannot find ${binname}.sh or ${binname} in " + "${CMAKE_CURRENT_SOURCE_DIR}" ) + ENDIF() + + IF(NOT ${file}_COMPONENT) + SET(${file}_COMPONENT Server) + ENDIF() + + # install script + INSTALL_SCRIPT( + ${CMAKE_CURRENT_BINARY_DIR}/${file} + DESTINATION ${INSTALL_BINDIR} + COMPONENT ${${file}_COMPONENT} + ) + + # make scripts executable in build dir + IF(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${binname}) + EXECUTE_PROCESS(COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/${binname}) + ELSEIF(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${file}) + EXECUTE_PROCESS(COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/${file}) + ENDIF() + + # Create symlink + IF (NOT ${binname} STREQUAL ${file}) + INSTALL_LINK(${file} ${binname} ${INSTALL_BINDIR} ${${file}_COMPONENT}) + ENDIF() + ENDFOREACH() +ENDIF() + +# Install libgcc as mylibgcc.a +IF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_FLAGS MATCHES "-static") + EXECUTE_PROCESS ( + COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} + ${CMAKE_CXX_FLAGS} --print-libgcc + OUTPUT_VARIABLE LIBGCC_LOCATION + RESULT_VARIABLE RESULT + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + IF(${RESULT} EQUAL 0 AND EXISTS ${LIBGCC_LOCATION}) + INSTALL(FILES "${LIBGCC_LOCATION}" DESTINATION ${INSTALL_LIBDIR} + COMPONENT Development) + ENDIF() +ENDIF() + +ADD_SUBDIRECTORY(sys_schema) diff --git a/scripts/comp_sql.c b/scripts/comp_sql.c new file mode 100644 index 00000000..f72fdcb0 --- /dev/null +++ b/scripts/comp_sql.c @@ -0,0 +1,194 @@ +/* Copyright (c) 2004, 2010, Oracle and/or its affiliates. + Copyright (c) 2012, 2022, 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 Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +/* + Originally written by Magnus Svensson +*/ + +/* + Converts a SQL file into a C file that can be compiled and linked + into other programs +*/ + +#include <my_config.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> + +/* + This is an internal tool used during the build process only, + - do not make a library just for this, + which would make the Makefiles and the server link + more complex than necessary, + - do not duplicate the code either. + so just add the sql_bootstrap.cc code as is. +*/ +#include "../sql/sql_bootstrap.h" + +FILE *in, *out; + +static void die(const char *fmt, ...) +{ + va_list args; + + /* Print the error message */ + fprintf(stderr, "FATAL ERROR: "); + if (fmt) + { + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + } + else + fprintf(stderr, "unknown error"); + fprintf(stderr, "\n"); + fflush(stderr); + + /* Close any open files */ + if (in) + fclose(in); + if (out) + fclose(out); + + exit(1); +} + +char *fgets_fn(char *buffer, size_t size, fgets_input_t input, int *error) +{ + char *line= fgets(buffer, (int)size, (FILE*) input); + if (error) + *error= (line == NULL) ? ferror((FILE*)input) : 0; + return line; +} + +#define MAX_COLUMN 16000 + +static void print_query(FILE *out, const char *query) +{ + const char *ptr= query; + int column= 0; + + fprintf(out, "\""); + while (*ptr) + { + if (column >= MAX_COLUMN) + { + /* Wrap to the next line, tabulated. */ + fprintf(out, "\"\n \""); + column= 2; + } + switch(*ptr) + { + case '\n': + /* + Preserve the \n character in the query text, + and wrap to the next line, tabulated. + */ + fprintf(out, "\\n\"\n \""); + column= 2; + break; + case '\r': + /* Skipped */ + break; + case '\"': + fprintf(out, "\\\""); + column+=2; + break; + case '\\': + fprintf(out, "\\\\"); + column+=2; + break; + default: + putc(*ptr, out); + column++; + break; + } + ptr++; + } + fprintf(out, "\\n\",\n"); +} + +static char query[MAX_BOOTSTRAP_QUERY_SIZE]; + +int main(int argc, char *argv[]) +{ + char* struct_name= argv[1]; + char* infile_name= argv[2]; + char* outfile_name= argv[3]; + int rc; + int query_length; + int error= 0; + char *err_ptr; + + if (argc != 4) + die("Usage: comp_sql <struct_name> <sql_filename> <c_filename>"); + + /* Open input and output file */ + if (!(in= fopen(infile_name, "r"))) + die("Failed to open SQL file '%s'", infile_name); + if (!(out= fopen(outfile_name, "w"))) + die("Failed to open output file '%s'", outfile_name); + + fprintf(out, "/*\n"); + fprintf(out, " Do not edit this file, it is automatically generated from:\n"); + fprintf(out, " <%s>\n", infile_name); + fprintf(out, "*/\n"); + fprintf(out, "#include <stdlib.h>\n"); /* NULL */ + fprintf(out, "const char* %s[]={\n", struct_name); + + for ( ; ; ) + { + rc= read_bootstrap_query(query, &query_length, + (fgets_input_t) in, fgets_fn, 1, &error); + + if (rc == READ_BOOTSTRAP_EOF) + break; + + if (rc != READ_BOOTSTRAP_SUCCESS) + { + /* Get the most recent query text for reference. */ + err_ptr= query + (query_length <= MAX_BOOTSTRAP_ERROR_LEN ? + 0 : (query_length - MAX_BOOTSTRAP_ERROR_LEN)); + switch (rc) + { + case READ_BOOTSTRAP_ERROR: + die("Failed to read the bootstrap input file. Return code (%d).\n" + "Last query: '%s'\n", error, err_ptr); + break; + + case READ_BOOTSTRAP_QUERY_SIZE: + die("Failed to read the boostrap input file. Query size exceeded %d bytes.\n" + "Last query: '%s'.\n", MAX_BOOTSTRAP_LINE_SIZE, err_ptr); + break; + + default: + die("Failed to read the boostrap input file. Unknown error.\n"); + break; + } + } + + print_query(out, query); + } + + fprintf(out, "NULL\n};\n"); + + fclose(in); + fclose(out); + + exit(0); + +} + diff --git a/scripts/convert-debug-for-diff.sh b/scripts/convert-debug-for-diff.sh new file mode 100755 index 00000000..5b3ce05b --- /dev/null +++ b/scripts/convert-debug-for-diff.sh @@ -0,0 +1,25 @@ +#!/usr/bin/perl -i +# +# This script converts all numbers that look like addresses or memory sizes, +# in a debug files generated by --debug (like mysqld --debug-dbug), to #. +# The script also deletes all thread id's from the start of the line. + +# This allows you to easily compare the files (for example with diff) +# to find out what changes between different executions. +# This is extremely useful for comparing two mysqld versions to see +# why things now work differently. + +# The script converts the files in place. +# +# Typical usage: +# +# convert-debug-for-diff /tmp/mysqld.trace /tmp/mysqld-old.trace +# diff /tmp/mysqld.trace /tmp/mysqld-old.trace + +while (<>) +{ + s/^T@[0-9]+\s*://g; + s/0x[0-9a-f]+(\s|\n|\))/#$1/g; + s/size: [0-9]+/size: #/g; + print $_; +} diff --git a/scripts/dheadgen.pl b/scripts/dheadgen.pl new file mode 100644 index 00000000..69ece2e7 --- /dev/null +++ b/scripts/dheadgen.pl @@ -0,0 +1,332 @@ +# Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of the above-listed copyright holders nor the names +# of its contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# ident "@(#)dheadgen.pl 1.4 07/06/24 SMI" + +# +# DTrace Header Generator +# ----------------------- +# +# This script is meant to mimic the output of dtrace(1M) with the -h +# (headergen) flag on system that lack native support for DTrace. This script +# is intended to be integrated into projects that use DTrace's static tracing +# facilities (USDT), and invoked as part of the build process to have a +# common build process on all target systems. To facilitate this, this script +# is licensed under a BSD license. On system with native DTrace support, the +# dtrace(1M) command will be invoked to create the full header file; on other +# systems, this script will generated a stub header file. +# +# Normally, generated macros take the form PROVIDER_PROBENAME(). It may be +# desirable to customize the output of this script and of dtrace(1M) to +# tailor the precise macro name. To do this, edit the emit_dtrace() subroutine +# to pattern match for the lines you want to customize. +# + +use strict; + +my @lines; +my @tokens = (); +my $lineno = 0; +my $newline = 1; +my $eof = 0; +my $infile; +my $outfile; +my $force = 0; + +sub emit_dtrace { + my ($line) = @_; + + # + # Insert customization here. For example, if you want to change the + # name of the macros you may do something like this: + # + # $line =~ s/(\s)[A-Z]+_/\1TRACE_MOZILLA_/; + # + + print $line; +} + +# +# The remaining code deals with parsing D provider definitions and emitting +# the stub header file. There should be no need to edit this absent a bug. +# + +# +# Emit the two relevant macros for each probe in the given provider: +# PROVIDER_PROBENAME(<args>) +# PROVIDER_PROBENAME_ENABLED() (0) +# +sub emit_provider { + my ($provname, @probes) = @_; + + $provname = uc($provname); + + foreach my $probe (@probes) { + my $probename = uc($$probe{'name'}); + my $argc = $$probe{'argc'}; + my $line; + + $probename =~ s/__/_/g; + + $line = "#define\t${provname}_${probename}("; + for (my $i = 0; $i < $argc; $i++) { + $line .= ($i == 0 ? '' : ', '); + $line .= "arg$i"; + } + $line .= ")\n"; + emit_dtrace($line); + + $line = "#define\t${provname}_${probename}_ENABLED() (0)\n"; + emit_dtrace($line); + } + + emit_dtrace("\n"); +} + +sub emit_prologue { + my ($filename) = @_; + + $filename =~ s/.*\///g; + $filename = uc($filename); + $filename =~ s/\./_/g; + + emit_dtrace <<"EOF"; +/* + * Generated by dheadgen(1). + */ + +#ifndef\t_${filename} +#define\t_${filename} + +#ifdef\t__cplusplus +extern "C" { +#endif + +EOF +} + +sub emit_epilogue { + my ($filename) = @_; + + $filename =~ s/.*\///g; + $filename = uc($filename); + $filename =~ s/\./_/g; + + emit_dtrace <<"EOF"; +#ifdef __cplusplus +} +#endif + +#endif /* _$filename */ +EOF +} + +# +# Get the next token from the file keeping track of the line number. +# +sub get_token { + my ($eof_ok) = @_; + my $tok; + + while (1) { + while (scalar(@tokens) == 0) { + if (scalar(@lines) == 0) { + $eof = 1; + return if ($eof_ok); + die "expected more data at line $lineno"; + } + + $lineno++; + push(@tokens, split(/(\s+|\n|[(){},#;]|\/\*|\*\/)/, + shift(@lines))); + } + + $tok = shift(@tokens); + next if ($tok eq ''); + next if ($tok =~ /^[ \t]+$/); + + return ($tok); + } +} + +# +# Ignore newlines, comments and typedefs +# +sub next_token { + my ($eof_ok) = @_; + my $tok; + + while (1) { + $tok = get_token($eof_ok); + return if ($eof_ok && $eof); + if ($tok eq "typedef" or $tok =~ /^#/) { + while (1) { + $tok = get_token(0); + last if ($tok eq "\n"); + } + next; + } elsif ($tok eq '/*') { + while (get_token(0) ne '*/') { + next; + } + next; + } elsif ($tok eq "\n") { + next; + } + + last; + } + + return ($tok); +} + +sub expect_token { + my ($t) = @_; + my $tok; + + while (($tok = next_token(0)) eq "\n") { + next; + } + + die "expected '$t' at line $lineno rather than '$tok'" if ($t ne $tok); +} + +sub get_args { + expect_token('('); + + my $tok = next_token(0); + my @args = (); + + return (@args) if ($tok eq ')'); + + if ($tok eq 'void') { + expect_token(')'); + return (@args); + } + + my $arg = $tok; + + while (1) { + $tok = next_token(0); + if ($tok eq ',' || $tok eq ')') { + push(@args, $arg); + $arg = ''; + last if ($tok eq ')'); + } else { + $arg = "$arg $tok"; + } + } + + return (@args); +} + +sub usage { + die "usage: $0 [-f] <filename.d>\n"; +} + +usage() if (scalar(@ARGV) < 1); +if ($ARGV[0] eq '-f') { + usage() if (scalar(@ARGV < 2)); + $force = 1; + shift; +} +$infile = $ARGV[0]; +usage() if ($infile !~ /(.+)\.d$/); + +# +# If the system has native support for DTrace, we'll use that binary instead. +# +if (-x '/usr/sbin/dtrace' && !$force) { + open(DTRACE, "-| /usr/sbin/dtrace -C -h -s $infile -o /dev/stdout") + or die "can't invoke dtrace(1M)"; + + while (<DTRACE>) { + emit_dtrace($_); + } + + close(DTRACE); + + exit(0); +} + +emit_prologue($infile); + +open(D, "< $infile") or die "couldn't open $infile"; +@lines = <D>; +close(D); + +while (1) { + my $nl = 0; + my $tok = next_token(1); + last if $eof; + + if ($newline && $tok eq '#') { + while (1) { + $tok = get_token(0); + + last if ($tok eq "\n"); + } + $nl = 1; + } elsif ($tok eq "\n") { + $nl = 1; + } elsif ($tok eq 'provider') { + my $provname = next_token(0); + my @probes = (); + expect_token('{'); + + while (1) { + $tok = next_token(0); + if ($tok eq 'probe') { + my $probename = next_token(0); + my @args = get_args(); + + next while (next_token(0) ne ';'); + + push(@probes, { + 'name' => $probename, + 'argc' => scalar(@args) + }); + + } elsif ($tok eq '}') { + expect_token(';'); + + emit_provider($provname, @probes); + + last; + } + } + + } else { + die "syntax error at line $lineno near '$tok'\n"; + } + + $newline = $nl; +} + +emit_epilogue($infile); + +exit(0); diff --git a/scripts/fill_help_tables.sql b/scripts/fill_help_tables.sql new file mode 100644 index 00000000..7deccd17 --- /dev/null +++ b/scripts/fill_help_tables.sql @@ -0,0 +1,1254 @@ + +-- Copyright (c) 2003, 2008-2012, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +-- DO NOT EDIT THIS FILE. It is generated automatically. + +-- To use this file, load its contents into the mysql database. For example, +-- with the mysql client program, process the file like this, where +-- file_name is the name of this file: + +-- mysql -u root -p mysql < file_name + +set names 'utf8'; + +set sql_log_bin = 0; + +use mysql; +delete from help_topic; +delete from help_category; +delete from help_keyword; +delete from help_relation; + +lock tables help_topic write, help_category write, help_keyword write, help_relation write; +insert into help_category (help_category_id,name,parent_category_id,url) values (1,'Contents',0,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (2,'Polygon Properties',34,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (3,'WKT',34,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (4,'Numeric Functions',37,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (5,'Plugins',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (6,'MBR',34,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (7,'Control Flow Functions',37,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (8,'Transactions',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (9,'Help Metadata',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (10,'Account Management',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (11,'Point Properties',34,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (12,'Encryption Functions',37,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (13,'LineString Properties',34,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (14,'Miscellaneous Functions',37,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (15,'Logical Operators',47,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (16,'Functions and Modifiers for Use with GROUP BY',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (17,'Information Functions',37,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (18,'Assignment Operators',47,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (19,'Comparison Operators',47,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (20,'Bit Functions',37,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (21,'Table Maintenance',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (22,'User-Defined Functions',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (23,'Data Types',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (24,'Compound Statements',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (25,'Geometry Constructors',34,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (26,'Administration',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (27,'Data Manipulation',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (28,'Utility',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (29,'Language Structure',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (30,'Geometry Relations',34,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (31,'Date and Time Functions',37,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (32,'WKB',34,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (33,'Procedures',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (34,'Geographic Features',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (35,'Geometry Properties',34,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (36,'String Functions',37,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (37,'Functions',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (38,'Data Definition',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (39,'Sequences',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (40,'JSON Functions',37,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (41,'Window Functions',37,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (42,'Spider Functions',37,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (43,'Dynamic Column Functions',37,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (44,'Galera Functions',37,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (45,'Temporal Tables',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (46,'GeoJSON',34,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (47,'Operators',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (48,'Arithmetic Operators',47,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (49,'Replication',1,''); +insert into help_category (help_category_id,name,parent_category_id,url) values (50,'Prepared Statements',1,''); + +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (1,9,'HELP_DATE','Help Contents generated from the MariaDB Knowledge Base on 25 July 2023.','',''); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (2,9,'HELP_VERSION','Help Contents generated for MariaDB 10.11 from the MariaDB Knowledge Base on 25 July 2023.','',''); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (3,2,'AREA','A synonym for ST_AREA.\n\nURL: https://mariadb.com/kb/en/polygon-properties-area/','','https://mariadb.com/kb/en/polygon-properties-area/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (4,2,'CENTROID','A synonym for ST_CENTROID.\n\nURL: https://mariadb.com/kb/en/centroid/','','https://mariadb.com/kb/en/centroid/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (5,2,'ExteriorRing','A synonym for ST_ExteriorRing.\n\nURL: https://mariadb.com/kb/en/polygon-properties-exteriorring/','','https://mariadb.com/kb/en/polygon-properties-exteriorring/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (6,2,'InteriorRingN','A synonym for ST_InteriorRingN.\n\nURL: https://mariadb.com/kb/en/polygon-properties-interiorringn/','','https://mariadb.com/kb/en/polygon-properties-interiorringn/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (7,2,'NumInteriorRings','A synonym for ST_NumInteriorRings.\n\nURL: https://mariadb.com/kb/en/polygon-properties-numinteriorrings/','','https://mariadb.com/kb/en/polygon-properties-numinteriorrings/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (8,2,'ST_AREA','Syntax\n------\n\nST_Area(poly)\nArea(poly)\n\nDescription\n-----------\n\nReturns as a double-precision number the area of the Polygon value poly, as\nmeasured in its spatial reference system.\n\nST_Area() and Area() are synonyms.\n\nExamples\n--------\n\nSET @poly = \'Polygon((0 0,0 3,3 0,0 0),(1 1,1 2,2 1,1 1))\';\n\nSELECT Area(GeomFromText(@poly));\n+---------------------------+\n| Area(GeomFromText(@poly)) |\n+---------------------------+\n| 4 |\n+---------------------------+\n\nURL: https://mariadb.com/kb/en/st_area/','','https://mariadb.com/kb/en/st_area/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (9,2,'ST_CENTROID','Syntax\n------\n\nST_Centroid(mpoly)\nCentroid(mpoly)\n\nDescription\n-----------\n\nReturns a point reflecting the mathematical centroid (geometric center) for\nthe MultiPolygon mpoly. The resulting point will not necessarily be on the\nMultiPolygon.\n\nST_Centroid() and Centroid() are synonyms.\n\nExamples\n--------\n\nSET @poly = ST_GeomFromText(\'POLYGON((0 0,20 0,20 20,0 20,0 0))\');\nSELECT ST_AsText(ST_Centroid(@poly)) AS center;\n+--------------+\n| center |\n+--------------+\n| POINT(10 10) |\n+--------------+\n\nURL: https://mariadb.com/kb/en/st_centroid/','','https://mariadb.com/kb/en/st_centroid/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (10,2,'ST_ExteriorRing','Syntax\n------\n\nST_ExteriorRing(poly)\nExteriorRing(poly)\n\nDescription\n-----------\n\nReturns the exterior ring of the Polygon value poly as a LineString.\n\nST_ExteriorRing() and ExteriorRing() are synonyms.\n\nExamples\n--------\n\nSET @poly = \'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))\';\n\nSELECT AsText(ExteriorRing(GeomFromText(@poly)));\n+-------------------------------------------+\n| AsText(ExteriorRing(GeomFromText(@poly))) |\n+-------------------------------------------+\n| LINESTRING(0 0,0 3,3 3,3 0,0 0) |\n+-------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_exteriorring/','','https://mariadb.com/kb/en/st_exteriorring/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (11,2,'ST_InteriorRingN','Syntax\n------\n\nST_InteriorRingN(poly,N)\nInteriorRingN(poly,N)\n\nDescription\n-----------\n\nReturns the N-th interior ring for the Polygon value poly as a LineString.\nRings are numbered beginning with 1.\n\nST_InteriorRingN() and InteriorRingN() are synonyms.\n\nExamples\n--------\n\nSET @poly = \'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))\';\n\nSELECT AsText(InteriorRingN(GeomFromText(@poly),1));\n+----------------------------------------------+\n| AsText(InteriorRingN(GeomFromText(@poly),1)) |\n+----------------------------------------------+\n| LINESTRING(1 1,1 2,2 2,2 1,1 1) |\n+----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_interiorringn/','','https://mariadb.com/kb/en/st_interiorringn/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (12,2,'ST_NumInteriorRings','Syntax\n------\n\nST_NumInteriorRings(poly)\nNumInteriorRings(poly)\n\nDescription\n-----------\n\nReturns an integer containing the number of interior rings in the Polygon\nvalue poly.\n\nNote that according the the OpenGIS standard, a POLYGON should have exactly\none ExteriorRing and all other rings should lie within that ExteriorRing and\nthus be the InteriorRings. Practically, however, some systems, including\nMariaDB\'s, permit polygons to have several \'ExteriorRings\'. In the case of\nthere being multiple, non-overlapping exterior rings ST_NumInteriorRings()\nwill return 1.\n\nST_NumInteriorRings() and NumInteriorRings() are synonyms.\n\nExamples\n--------\n\nSET @poly = \'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))\';\n\nSELECT NumInteriorRings(GeomFromText(@poly));\n+---------------------------------------+\n| NumInteriorRings(GeomFromText(@poly)) |\n+---------------------------------------+\n| 1 |\n+---------------------------------------+\n\nNon-overlapping \'polygon\':\n\nSELECT ST_NumInteriorRings(ST_PolyFromText(\'POLYGON((0 0,10 0,10 10,0 10,0 0),\n (-1 -1,-5 -1,-5 -5,-1 -5,-1 -1))\')) AS NumInteriorRings;\n+------------------+\n| NumInteriorRings |\n+------------------+\n| 1 |\n+------------------+\n\nURL: https://mariadb.com/kb/en/st_numinteriorrings/','','https://mariadb.com/kb/en/st_numinteriorrings/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (13,3,'WKT Definition','Description\n-----------\n\nThe Well-Known Text (WKT) representation of Geometry is designed to exchange\ngeometry data in ASCII form. Examples of the basic geometry types include:\n\n+-----------------------------------------------------------------------------+\n| Geometry Types |\n+-----------------------------------------------------------------------------+\n| POINT |\n+-----------------------------------------------------------------------------+\n| LINESTRING |\n+-----------------------------------------------------------------------------+\n| POLYGON |\n+-----------------------------------------------------------------------------+\n| MULTIPOINT |\n+-----------------------------------------------------------------------------+\n| MULTILINESTRING |\n+-----------------------------------------------------------------------------+\n| MULTIPOLYGON |\n+-----------------------------------------------------------------------------+\n| GEOMETRYCOLLECTION |\n+-----------------------------------------------------------------------------+\n| GEOMETRY |\n+-----------------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/wkt-definition/','','https://mariadb.com/kb/en/wkt-definition/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (14,3,'AsText','A synonym for ST_AsText().\n\nURL: https://mariadb.com/kb/en/wkt-astext/','','https://mariadb.com/kb/en/wkt-astext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (15,3,'AsWKT','A synonym for ST_AsText().\n\nURL: https://mariadb.com/kb/en/wkt-aswkt/','','https://mariadb.com/kb/en/wkt-aswkt/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (16,3,'GeomCollFromText','A synonym for ST_GeomCollFromText.\n\nURL: https://mariadb.com/kb/en/wkt-geomcollfromtext/','','https://mariadb.com/kb/en/wkt-geomcollfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (17,3,'GeometryCollectionFromText','A synonym for ST_GeomCollFromText.\n\nURL: https://mariadb.com/kb/en/geometrycollectionfromtext/','','https://mariadb.com/kb/en/geometrycollectionfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (18,3,'GeometryFromText','A synonym for ST_GeomFromText.\n\nURL: https://mariadb.com/kb/en/geometryfromtext/','','https://mariadb.com/kb/en/geometryfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (19,3,'GeomFromText','A synonym for ST_GeomFromText.\n\nURL: https://mariadb.com/kb/en/wkt-geomfromtext/','','https://mariadb.com/kb/en/wkt-geomfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (20,3,'LineFromText','A synonym for ST_LineFromText.\n\nURL: https://mariadb.com/kb/en/wkt-linefromtext/','','https://mariadb.com/kb/en/wkt-linefromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (21,3,'LineStringFromText','A synonym for ST_LineFromText.\n\nURL: https://mariadb.com/kb/en/linestringfromtext/','','https://mariadb.com/kb/en/linestringfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (22,3,'MLineFromText','Syntax\n------\n\nMLineFromText(wkt[,srid])\nMultiLineStringFromText(wkt[,srid])\n\nDescription\n-----------\n\nConstructs a MULTILINESTRING value using its WKT representation and SRID.\n\nMLineFromText() and MultiLineStringFromText() are synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_multi_line (g MULTILINESTRING);\nSHOW FIELDS FROM gis_multi_line;\nINSERT INTO gis_multi_line VALUES\n (MultiLineStringFromText(\'MULTILINESTRING((10 48,10 21,10 0),(16 0,16\n23,16 48))\')),\n (MLineFromText(\'MULTILINESTRING((10 48,10 21,10 0))\')),\n (MLineFromWKB(AsWKB(MultiLineString(\n LineString(Point(1, 2), Point(3, 5)),\n LineString(Point(2, 5), Point(5, 8), Point(21, 7))))));\n\nURL: https://mariadb.com/kb/en/mlinefromtext/','','https://mariadb.com/kb/en/mlinefromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (23,3,'MPointFromText','Syntax\n------\n\nMPointFromText(wkt[,srid])\nMultiPointFromText(wkt[,srid])\n\nDescription\n-----------\n\nConstructs a MULTIPOINT value using its WKT representation and SRID.\n\nMPointFromText() and MultiPointFromText() are synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_multi_point (g MULTIPOINT);\nSHOW FIELDS FROM gis_multi_point;\nINSERT INTO gis_multi_point VALUES\n (MultiPointFromText(\'MULTIPOINT(0 0,10 10,10 20,20 20)\')),\n (MPointFromText(\'MULTIPOINT(1 1,11 11,11 21,21 21)\')),\n (MPointFromWKB(AsWKB(MultiPoint(Point(3, 6), Point(4, 10)))));\n\nURL: https://mariadb.com/kb/en/mpointfromtext/','','https://mariadb.com/kb/en/mpointfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (24,3,'MPolyFromText','Syntax\n------\n\nMPolyFromText(wkt[,srid])\nMultiPolygonFromText(wkt[,srid])\n\nDescription\n-----------\n\nConstructs a MULTIPOLYGON value using its WKT representation and SRID.\n\nMPolyFromText() and MultiPolygonFromText() are synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_multi_polygon (g MULTIPOLYGON);\nSHOW FIELDS FROM gis_multi_polygon;\nINSERT INTO gis_multi_polygon VALUES\n (MultiPolygonFromText(\'MULTIPOLYGON(\n ((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),\n ((59 18,67 18,67 13,59 13,59 18)))\')),\n (MPolyFromText(\'MULTIPOLYGON(\n ((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),\n ((59 18,67 18,67 13,59 13,59 18)))\')),\n (MPolyFromWKB(AsWKB(MultiPolygon(Polygon(\n LineString(Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3)))))));\n\nURL: https://mariadb.com/kb/en/mpolyfromtext/','','https://mariadb.com/kb/en/mpolyfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (25,3,'MultiLineStringFromText','A synonym for MLineFromText.\n\nURL: https://mariadb.com/kb/en/multilinestringfromtext/','','https://mariadb.com/kb/en/multilinestringfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (26,3,'MultiPointFromText','A synonym for MPointFromText.\n\nURL: https://mariadb.com/kb/en/multipointfromtext/','','https://mariadb.com/kb/en/multipointfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (27,3,'MultiPolygonFromText','A synonym for MPolyFromText.\n\nURL: https://mariadb.com/kb/en/multipolygonfromtext/','','https://mariadb.com/kb/en/multipolygonfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (28,3,'PointFromText','A synonym for ST_PointFromText.\n\nURL: https://mariadb.com/kb/en/wkt-pointfromtext/','','https://mariadb.com/kb/en/wkt-pointfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (29,3,'PolyFromText','A synonym for ST_PolyFromText.\n\nURL: https://mariadb.com/kb/en/wkt-polyfromtext/','','https://mariadb.com/kb/en/wkt-polyfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (30,3,'PolygonFromText','A synonym for ST_PolyFromText.\n\nURL: https://mariadb.com/kb/en/polygonfromtext/','','https://mariadb.com/kb/en/polygonfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (31,3,'ST_AsText','Syntax\n------\n\nST_AsText(g)\nAsText(g)\nST_AsWKT(g)\nAsWKT(g)\n\nDescription\n-----------\n\nConverts a value in internal geometry format to its WKT representation and\nreturns the string result.\n\nST_AsText(), AsText(), ST_AsWKT() and AsWKT() are all synonyms.\n\nExamples\n--------\n\nSET @g = \'LineString(1 1,4 4,6 6)\';\n\nSELECT ST_AsText(ST_GeomFromText(@g));\n+--------------------------------+\n| ST_AsText(ST_GeomFromText(@g)) |\n+--------------------------------+\n| LINESTRING(1 1,4 4,6 6) |\n+--------------------------------+\n\nURL: https://mariadb.com/kb/en/st_astext/','','https://mariadb.com/kb/en/st_astext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (32,3,'ST_ASWKT','A synonym for ST_ASTEXT().\n\nURL: https://mariadb.com/kb/en/st_aswkt/','','https://mariadb.com/kb/en/st_aswkt/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (33,3,'ST_GeomCollFromText','Syntax\n------\n\nST_GeomCollFromText(wkt[,srid])\nST_GeometryCollectionFromText(wkt[,srid])\nGeomCollFromText(wkt[,srid])\nGeometryCollectionFromText(wkt[,srid])\n\nDescription\n-----------\n\nConstructs a GEOMETRYCOLLECTION value using its WKT representation and SRID.\n\nST_GeomCollFromText(), ST_GeometryCollectionFromText(), GeomCollFromText() and\nGeometryCollectionFromText() are all synonyms.\n\nExample\n-------\n\nCREATE TABLE gis_geometrycollection (g GEOMETRYCOLLECTION);\nSHOW FIELDS FROM gis_geometrycollection;\nINSERT INTO gis_geometrycollection VALUES\n (GeomCollFromText(\'GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10\n10))\')),\n (GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6),\nLineString(Point(3, 6), Point(7, 9)))))),\n (GeomFromText(\'GeometryCollection()\')),\n (GeomFromText(\'GeometryCollection EMPTY\'));\n\nURL: https://mariadb.com/kb/en/st_geomcollfromtext/','','https://mariadb.com/kb/en/st_geomcollfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (34,3,'ST_GeometryCollectionFromText','A synonym for ST_GeomCollFromText.\n\nURL: https://mariadb.com/kb/en/st_geometrycollectionfromtext/','','https://mariadb.com/kb/en/st_geometrycollectionfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (35,3,'ST_GeometryFromText','A synonym for ST_GeomFromText.\n\nURL: https://mariadb.com/kb/en/st_geometryfromtext/','','https://mariadb.com/kb/en/st_geometryfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (36,3,'ST_GeomFromText','Syntax\n------\n\nST_GeomFromText(wkt[,srid])\nST_GeometryFromText(wkt[,srid])\nGeomFromText(wkt[,srid])\nGeometryFromText(wkt[,srid])\n\nDescription\n-----------\n\nConstructs a geometry value of any type using its WKT representation and SRID.\n\nGeomFromText(), GeometryFromText(), ST_GeomFromText() and\nST_GeometryFromText() are all synonyms.\n\nExample\n-------\n\nSET @g = ST_GEOMFROMTEXT(\'POLYGON((1 1,1 5,4 9,6 9,9 3,7 2,1 1))\');\n\nURL: https://mariadb.com/kb/en/st_geomfromtext/','','https://mariadb.com/kb/en/st_geomfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (37,3,'ST_LineFromText','Syntax\n------\n\nST_LineFromText(wkt[,srid])\nST_LineStringFromText(wkt[,srid])\nLineFromText(wkt[,srid])\nLineStringFromText(wkt[,srid])\n\nDescription\n-----------\n\nConstructs a LINESTRING value using its WKT representation and SRID.\n\nST_LineFromText(), ST_LineStringFromText(), ST_LineFromText() and\nST_LineStringFromText() are all synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_line (g LINESTRING);\nSHOW FIELDS FROM gis_line;\nINSERT INTO gis_line VALUES\n (LineFromText(\'LINESTRING(0 0,0 10,10 0)\')),\n (LineStringFromText(\'LINESTRING(10 10,20 10,20 20,10 20,10 10)\')),\n (LineStringFromWKB(AsWKB(LineString(Point(10, 10), Point(40, 10)))));\n\nURL: https://mariadb.com/kb/en/st_linefromtext/','','https://mariadb.com/kb/en/st_linefromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (38,3,'ST_LineStringFromText','A synonym for ST_LineFromText.\n\nURL: https://mariadb.com/kb/en/st_linestringfromtext/','','https://mariadb.com/kb/en/st_linestringfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (39,3,'ST_PointFromText','Syntax\n------\n\nST_PointFromText(wkt[,srid])\nPointFromText(wkt[,srid])\n\nDescription\n-----------\n\nConstructs a POINT value using its WKT representation and SRID.\n\nST_PointFromText() and PointFromText() are synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_point (g POINT);\nSHOW FIELDS FROM gis_point;\nINSERT INTO gis_point VALUES\n (PointFromText(\'POINT(10 10)\')),\n (PointFromText(\'POINT(20 10)\')),\n (PointFromText(\'POINT(20 20)\')),\n (PointFromWKB(AsWKB(PointFromText(\'POINT(10 20)\'))));\n\nURL: https://mariadb.com/kb/en/st_pointfromtext/','','https://mariadb.com/kb/en/st_pointfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (40,3,'ST_PolyFromText','Syntax\n------\n\nST_PolyFromText(wkt[,srid])\nST_PolygonFromText(wkt[,srid])\nPolyFromText(wkt[,srid])\nPolygonFromText(wkt[,srid])\n\nDescription\n-----------\n\nConstructs a POLYGON value using its WKT representation and SRID.\n\nST_PolyFromText(), ST_PolygonFromText(), PolyFromText() and\nST_PolygonFromText() are all synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_polygon (g POLYGON);\nINSERT INTO gis_polygon VALUES\n (PolygonFromText(\'POLYGON((10 10,20 10,20 20,10 20,10 10))\')),\n (PolyFromText(\'POLYGON((0 0,50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10\n20,10 10))\'));\n\nURL: https://mariadb.com/kb/en/st_polyfromtext/','','https://mariadb.com/kb/en/st_polyfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (41,3,'ST_PolygonFromText','A synonym for ST_PolyFromText.\n\nURL: https://mariadb.com/kb/en/st_polygonfromtext/','','https://mariadb.com/kb/en/st_polygonfromtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (42,4,'DIV','Syntax\n------\n\nDIV\n\nDescription\n-----------\n\nInteger division. Similar to FLOOR(), but is safe with BIGINT values.\nIncorrect results may occur for non-integer operands that exceed BIGINT range.\n\nIf the ERROR_ON_DIVISION_BY_ZERO SQL_MODE is used, a division by zero produces\nan error. Otherwise, it returns NULL.\n\nThe remainder of a division can be obtained using the MOD operator.\n\nExamples\n--------\n\nSELECT 300 DIV 7;\n+-----------+\n| 300 DIV 7 |\n+-----------+\n| 42 |\n+-----------+\n\nSELECT 300 DIV 0;\n+-----------+\n| 300 DIV 0 |\n+-----------+\n| NULL |\n+-----------+\n\nURL: https://mariadb.com/kb/en/div/','','https://mariadb.com/kb/en/div/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (43,4,'ABS','Syntax\n------\n\nABS(X)\n\nDescription\n-----------\n\nReturns the absolute (non-negative) value of X. If X is not a number, it is\nconverted to a numeric type.\n\nExamples\n--------\n\nSELECT ABS(42);\n+---------+\n| ABS(42) |\n+---------+\n| 42 |\n+---------+\n\nSELECT ABS(-42);\n+----------+\n| ABS(-42) |\n+----------+\n| 42 |\n+----------+\n\nSELECT ABS(DATE \'1994-01-01\');\n+------------------------+\n| ABS(DATE \'1994-01-01\') |\n+------------------------+\n| 19940101 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/abs/','','https://mariadb.com/kb/en/abs/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (44,4,'ACOS','Syntax\n------\n\nACOS(X)\n\nDescription\n-----------\n\nReturns the arc cosine of X, that is, the value whose cosine is X. Returns\nNULL if X is not in the range -1 to 1.\n\nExamples\n--------\n\nSELECT ACOS(1);\n+---------+\n| ACOS(1) |\n+---------+\n| 0 |\n+---------+\n\nSELECT ACOS(1.0001);\n+--------------+\n| ACOS(1.0001) |\n+--------------+\n| NULL |\n+--------------+\n\nSELECT ACOS(0);\n+-----------------+\n| ACOS(0) |\n+-----------------+\n| 1.5707963267949 |\n+-----------------+\n\nSELECT ACOS(0.234);\n+------------------+\n| ACOS(0.234) |\n+------------------+\n| 1.33460644244679 |\n+------------------+\n\nURL: https://mariadb.com/kb/en/acos/','','https://mariadb.com/kb/en/acos/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (45,4,'ASIN','Syntax\n------\n\nASIN(X)\n\nDescription\n-----------\n\nReturns the arc sine of X, that is, the value whose sine is X. Returns NULL if\nX is not in the range -1 to 1.\n\nExamples\n--------\n\nSELECT ASIN(0.2);\n+--------------------+\n| ASIN(0.2) |\n+--------------------+\n| 0.2013579207903308 |\n+--------------------+\n\nSELECT ASIN(\'foo\');\n+-------------+\n| ASIN(\'foo\') |\n+-------------+\n| 0 |\n+-------------+\n\nSHOW WARNINGS;\n+---------+------+-----------------------------------------+\n| Level | Code | Message |\n+---------+------+-----------------------------------------+\n| Warning | 1292 | Truncated incorrect DOUBLE value: \'foo\' |\n+---------+------+-----------------------------------------+\n\nURL: https://mariadb.com/kb/en/asin/','','https://mariadb.com/kb/en/asin/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (46,4,'ATAN','Syntax\n------\n\nATAN(X)\n\nDescription\n-----------\n\nReturns the arc tangent of X, that is, the value whose tangent is X.\n\nExamples\n--------\n\nSELECT ATAN(2);\n+--------------------+\n| ATAN(2) |\n+--------------------+\n| 1.1071487177940904 |\n+--------------------+\n\nSELECT ATAN(-2);\n+---------------------+\n| ATAN(-2) |\n+---------------------+\n| -1.1071487177940904 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/atan/','','https://mariadb.com/kb/en/atan/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (47,4,'ATAN2','Syntax\n------\n\nATAN(Y,X), ATAN2(Y,X)\n\nDescription\n-----------\n\nReturns the arc tangent of the two variables X and Y. It is similar to\ncalculating the arc tangent of Y / X, except that the signs of both arguments\nare used to determine the quadrant of the result.\n\nExamples\n--------\n\nSELECT ATAN(-2,2);\n+---------------------+\n| ATAN(-2,2) |\n+---------------------+\n| -0.7853981633974483 |\n+---------------------+\n\nSELECT ATAN2(PI(),0);\n+--------------------+\n| ATAN2(PI(),0) |\n+--------------------+\n| 1.5707963267948966 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/atan2/','','https://mariadb.com/kb/en/atan2/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (48,4,'CEIL','Syntax\n------\n\nCEIL(X)\n\nDescription\n-----------\n\nCEIL() is a synonym for CEILING().\n\nURL: https://mariadb.com/kb/en/ceil/','','https://mariadb.com/kb/en/ceil/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (49,4,'CEILING','Syntax\n------\n\nCEILING(X)\n\nDescription\n-----------\n\nReturns the smallest integer value not less than X.\n\nExamples\n--------\n\nSELECT CEILING(1.23);\n+---------------+\n| CEILING(1.23) |\n+---------------+\n| 2 |\n+---------------+\n\nSELECT CEILING(-1.23);\n+----------------+\n| CEILING(-1.23) |\n+----------------+\n| -1 |\n+----------------+\n\nURL: https://mariadb.com/kb/en/ceiling/','','https://mariadb.com/kb/en/ceiling/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (50,4,'CONV','Syntax\n------\n\nCONV(N,from_base,to_base)\n\nDescription\n-----------\n\nConverts numbers between different number bases. Returns a string\nrepresentation of the number N, converted from base from_base to base to_base.\n\nReturns NULL if any argument is NULL, or if the second or third argument are\nnot in the allowed range.\n\nThe argument N is interpreted as an integer, but may be specified as an\ninteger or a string. The minimum base is 2 and the maximum base is 36. If\nto_base is a negative number, N is regarded as a signed number. Otherwise, N\nis treated as unsigned. CONV() works with 64-bit precision.\n\nSome shortcuts for this function are also available: BIN(), OCT(), HEX(),\nUNHEX(). Also, MariaDB allows binary literal values and hexadecimal literal\nvalues.\n\nExamples\n--------\n\nSELECT CONV(\'a\',16,2);\n+----------------+\n| CONV(\'a\',16,2) |\n+----------------+\n| 1010 |\n+----------------+\n\nSELECT CONV(\'6E\',18,8);\n+-----------------+\n| CONV(\'6E\',18,8) |\n+-----------------+\n| 172 |\n+-----------------+\n\nSELECT CONV(-17,10,-18);\n+------------------+\n| CONV(-17,10,-18) |\n+------------------+\n| -H |\n+------------------+\n\nSELECT CONV(12+\'10\'+\'10\'+0xa,10,10);\n+------------------------------+\n| CONV(12+\'10\'+\'10\'+0xa,10,10) |\n+------------------------------+\n| 42 |\n+------------------------------+\n\nURL: https://mariadb.com/kb/en/conv/','','https://mariadb.com/kb/en/conv/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (51,4,'COS','Syntax\n------\n\nCOS(X)\n\nDescription\n-----------\n\nReturns the cosine of X, where X is given in radians.\n\nExamples\n--------\n\nSELECT COS(PI());\n+-----------+\n| COS(PI()) |\n+-----------+\n| -1 |\n+-----------+\n\nURL: https://mariadb.com/kb/en/cos/','','https://mariadb.com/kb/en/cos/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (52,4,'COT','Syntax\n------\n\nCOT(X)\n\nDescription\n-----------\n\nReturns the cotangent of X.\n\nExamples\n--------\n\nSELECT COT(42);\n+--------------------+\n| COT(42) |\n+--------------------+\n| 0.4364167060752729 |\n+--------------------+\n\nSELECT COT(12);\n+---------------------+\n| COT(12) |\n+---------------------+\n| -1.5726734063976893 |\n+---------------------+\n\nSELECT COT(0);\nERROR 1690 (22003): DOUBLE value is out of range in \'cot(0)\'\n\nURL: https://mariadb.com/kb/en/cot/','','https://mariadb.com/kb/en/cot/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (53,4,'CRC32','Syntax\n------\n\n<= MariaDB 10.7\n\nCRC32(expr)\n\nFrom MariaDB 10.8\n\nCRC32([par,]expr)\n\nDescription\n-----------\n\nComputes a cyclic redundancy check (CRC) value and returns a 32-bit unsigned\nvalue. The result is NULL if the argument is NULL. The argument is expected to\nbe a string and (if possible) is treated as one if it is not.\n\nUses the ISO 3309 polynomial that used by zlib and many others. MariaDB 10.8\nintroduced the CRC32C() function, which uses the alternate Castagnoli\npolynomia.\n\nMariaDB starting with 10.8\n--------------------------\nOften, CRC is computed in pieces. To facilitate this, MariaDB 10.8.0\nintroduced an optional parameter: CRC32(\'MariaDB\')=CRC32(CRC32(\'Maria\'),\'DB\').\n\nExamples\n--------\n\nSELECT CRC32(\'MariaDB\');\n+------------------+\n| CRC32(\'MariaDB\') |\n+------------------+\n| 4227209140 |\n+------------------+\n\nSELECT CRC32(\'mariadb\');\n+------------------+\n| CRC32(\'mariadb\') |\n+------------------+\n| 2594253378 |\n+------------------+\n\nFrom MariaDB 10.8.0\n\nSELECT CRC32(CRC32(\'Maria\'),\'DB\');\n+----------------------------+\n| CRC32(CRC32(\'Maria\'),\'DB\') |\n+----------------------------+\n| 4227209140 |\n+----------------------------+\n\nURL: https://mariadb.com/kb/en/crc32/','','https://mariadb.com/kb/en/crc32/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (54,4,'CRC32C','MariaDB starting with 10.8\n--------------------------\nIntroduced in MariaDB 10.8.0 to compute a cyclic redundancy check (CRC) value\nusing the Castagnoli polynomial.\n\nSyntax\n------\n\nCRC32C([par,]expr)\n\nDescription\n-----------\n\nMariaDB has always included a native unary function CRC32() that computes the\nCRC-32 of a string using the ISO 3309 polynomial that used by zlib and many\nothers.\n\nInnoDB and MyRocks use a different polynomial, which was implemented in SSE4.2\ninstructions that were introduced in the Intel Nehalem microarchitecture. This\nis commonly called CRC-32C (Castagnoli).\n\nThe CRC32C function uses the Castagnoli polynomial.\n\nThis allows SELECT…INTO DUMPFILE to be used for the creation of files with\nvalid checksums, such as a logically empty InnoDB redo log file ib_logfile0\ncorresponding to a particular log sequence number.\n\nThe optional parameter allows the checksum to be computed in pieces:\nCRC32C(\'MariaDB\')=CRC32C(CRC32C(\'Maria\'),\'DB\').\n\nExamples\n--------\n\nSELECT CRC32C(\'MariaDB\');\n+-------------------+\n| CRC32C(\'MariaDB\') |\n+-------------------+\n| 809606978 |\n+-------------------+\n\nSELECT CRC32C(CRC32C(\'Maria\'),\'DB\');\n+------------------------------+\n| CRC32C(CRC32C(\'Maria\'),\'DB\') |\n+------------------------------+\n| 809606978 |\n+------------------------------+\n\nURL: https://mariadb.com/kb/en/crc32c/','','https://mariadb.com/kb/en/crc32c/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (55,4,'DEGREES','Syntax\n------\n\nDEGREES(X)\n\nDescription\n-----------\n\nReturns the argument X, converted from radians to degrees.\n\nThis is the converse of the RADIANS() function.\n\nExamples\n--------\n\nSELECT DEGREES(PI());\n+---------------+\n| DEGREES(PI()) |\n+---------------+\n| 180 |\n+---------------+\n\nSELECT DEGREES(PI() / 2);\n+-------------------+\n| DEGREES(PI() / 2) |\n+-------------------+\n| 90 |\n+-------------------+\n\nSELECT DEGREES(45);\n+-----------------+\n| DEGREES(45) |\n+-----------------+\n| 2578.3100780887 |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/degrees/','','https://mariadb.com/kb/en/degrees/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (56,4,'EXP','Syntax\n------\n\nEXP(X)\n\nDescription\n-----------\n\nReturns the value of e (the base of natural logarithms) raised to the power of\nX. The inverse of this function is LOG() (using a single argument only) or\nLN().\n\nIf X is NULL, this function returns NULL.\n\nExamples\n--------\n\nSELECT EXP(2);\n+------------------+\n| EXP(2) |\n+------------------+\n| 7.38905609893065 |\n+------------------+\n\nSELECT EXP(-2);\n+--------------------+\n| EXP(-2) |\n+--------------------+\n| 0.1353352832366127 |\n+--------------------+\n\nSELECT EXP(0);\n+--------+\n| EXP(0) |\n+--------+\n| 1 |\n+--------+\n\nSELECT EXP(NULL);\n+-----------+\n| EXP(NULL) |\n+-----------+\n| NULL |\n+-----------+\n\nURL: https://mariadb.com/kb/en/exp/','','https://mariadb.com/kb/en/exp/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (57,4,'FLOOR','Syntax\n------\n\nFLOOR(X)\n\nDescription\n-----------\n\nReturns the largest integer value not greater than X.\n\nExamples\n--------\n\nSELECT FLOOR(1.23);\n+-------------+\n| FLOOR(1.23) |\n+-------------+\n| 1 |\n+-------------+\n\nSELECT FLOOR(-1.23);\n+--------------+\n| FLOOR(-1.23) |\n+--------------+\n| -2 |\n+--------------+\n\nURL: https://mariadb.com/kb/en/floor/','','https://mariadb.com/kb/en/floor/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (58,4,'LN','Syntax\n------\n\nLN(X)\n\nDescription\n-----------\n\nReturns the natural logarithm of X; that is, the base-e logarithm of X. If X\nis less than or equal to 0, or NULL, then NULL is returned.\n\nThe inverse of this function is EXP().\n\nExamples\n--------\n\nSELECT LN(2);\n+-------------------+\n| LN(2) |\n+-------------------+\n| 0.693147180559945 |\n+-------------------+\n\nSELECT LN(-2);\n+--------+\n| LN(-2) |\n+--------+\n| NULL |\n+--------+\n\nURL: https://mariadb.com/kb/en/ln/','','https://mariadb.com/kb/en/ln/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (59,4,'LOG','Syntax\n------\n\nLOG(X), LOG(B,X)\n\nDescription\n-----------\n\nIf called with one parameter, this function returns the natural logarithm of\nX. If X is less than or equal to 0, then NULL is returned.\n\nIf called with two parameters, it returns the logarithm of X to the base B. If\nB is <= 1 or X <= 0, the function returns NULL.\n\nIf any argument is NULL, the function returns NULL.\n\nThe inverse of this function (when called with a single argument) is the EXP()\nfunction.\n\nExamples\n--------\n\nLOG(X):\n\nSELECT LOG(2);\n+-------------------+\n| LOG(2) |\n+-------------------+\n| 0.693147180559945 |\n+-------------------+\n\nSELECT LOG(-2);\n+---------+\n| LOG(-2) |\n+---------+\n| NULL |\n+---------+\n\nLOG(B,X)\n\nSELECT LOG(2,16);\n+-----------+\n| LOG(2,16) |\n+-----------+\n| 4 |\n+-----------+\n\nSELECT LOG(3,27);\n+-----------+\n| LOG(3,27) |\n+-----------+\n| 3 |\n+-----------+\n\nSELECT LOG(3,1);\n+----------+\n| LOG(3,1) |\n+----------+\n| 0 |\n+----------+\n\nSELECT LOG(3,0);\n+----------+\n| LOG(3,0) |\n+----------+\n| NULL |\n+----------+\n\nURL: https://mariadb.com/kb/en/log/','','https://mariadb.com/kb/en/log/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (60,4,'LOG10','Syntax\n------\n\nLOG10(X)\n\nDescription\n-----------\n\nReturns the base-10 logarithm of X.\n\nExamples\n--------\n\nSELECT LOG10(2);\n+-------------------+\n| LOG10(2) |\n+-------------------+\n| 0.301029995663981 |\n+-------------------+\n\nSELECT LOG10(100);\n+------------+\n| LOG10(100) |\n+------------+\n| 2 |\n+------------+\n\nSELECT LOG10(-100);\n+-------------+\n| LOG10(-100) |\n+-------------+\n| NULL |\n+-------------+\n\nURL: https://mariadb.com/kb/en/log10/','','https://mariadb.com/kb/en/log10/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (61,4,'LOG2','Syntax\n------\n\nLOG2(X)\n\nDescription\n-----------\n\nReturns the base-2 logarithm of X.\n\nExamples\n--------\n\nSELECT LOG2(4398046511104);\n+---------------------+\n| LOG2(4398046511104) |\n+---------------------+\n| 42 |\n+---------------------+\n\nSELECT LOG2(65536);\n+-------------+\n| LOG2(65536) |\n+-------------+\n| 16 |\n+-------------+\n\nSELECT LOG2(-100);\n+------------+\n| LOG2(-100) |\n+------------+\n| NULL |\n+------------+\n\nURL: https://mariadb.com/kb/en/log2/','','https://mariadb.com/kb/en/log2/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (62,4,'MOD','Syntax\n------\n\nMOD(N,M), N % M, N MOD M\n\nDescription\n-----------\n\nModulo operation. Returns the remainder of N divided by M. See also Modulo\nOperator.\n\nIf the ERROR_ON_DIVISION_BY_ZERO SQL_MODE is used, any number modulus zero\nproduces an error. Otherwise, it returns NULL.\n\nThe integer part of a division can be obtained using DIV.\n\nExamples\n--------\n\nSELECT 1042 % 50;\n+-----------+\n| 1042 % 50 |\n+-----------+\n| 42 |\n+-----------+\n\nSELECT MOD(234, 10);\n+--------------+\n| MOD(234, 10) |\n+--------------+\n| 4 |\n+--------------+\n\nSELECT 253 % 7;\n+---------+\n| 253 % 7 |\n+---------+\n| 1 |\n+---------+\n\nSELECT MOD(29,9);\n+-----------+\n| MOD(29,9) |\n+-----------+\n| 2 |\n+-----------+\n\nSELECT 29 MOD 9;\n+----------+\n| 29 MOD 9 |\n+----------+\n| 2 |\n+----------+\n\nURL: https://mariadb.com/kb/en/mod/','','https://mariadb.com/kb/en/mod/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (63,4,'OCT','Syntax\n------\n\nOCT(N)\n\nDescription\n-----------\n\nReturns a string representation of the octal value of N, where N is a longlong\n(BIGINT) number. This is equivalent to CONV(N,10,8). Returns NULL if N is NULL.\n\nExamples\n--------\n\nSELECT OCT(34);\n+---------+\n| OCT(34) |\n+---------+\n| 42 |\n+---------+\n\nSELECT OCT(12);\n+---------+\n| OCT(12) |\n+---------+\n| 14 |\n+---------+\n\nURL: https://mariadb.com/kb/en/oct/','','https://mariadb.com/kb/en/oct/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (64,4,'PI','Syntax\n------\n\nPI()\n\nDescription\n-----------\n\nReturns the value of π (pi). The default number of decimal places displayed is\nsix, but MariaDB uses the full double-precision value internally.\n\nExamples\n--------\n\nSELECT PI();\n+----------+\n| PI() |\n+----------+\n| 3.141593 |\n+----------+\n\nSELECT PI()+0.0000000000000000000000;\n+-------------------------------+\n| PI()+0.0000000000000000000000 |\n+-------------------------------+\n| 3.1415926535897931159980 |\n+-------------------------------+\n\nURL: https://mariadb.com/kb/en/pi/','','https://mariadb.com/kb/en/pi/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (65,4,'POW','Syntax\n------\n\nPOW(X,Y)\n\nDescription\n-----------\n\nReturns the value of X raised to the power of Y.\n\nPOWER() is a synonym.\n\nExamples\n--------\n\nSELECT POW(2,3);\n+----------+\n| POW(2,3) |\n+----------+\n| 8 |\n+----------+\n\nSELECT POW(2,-2);\n+-----------+\n| POW(2,-2) |\n+-----------+\n| 0.25 |\n+-----------+\n\nURL: https://mariadb.com/kb/en/pow/','','https://mariadb.com/kb/en/pow/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (66,4,'POWER','Syntax\n------\n\nPOWER(X,Y)\n\nDescription\n-----------\n\nThis is a synonym for POW(), which returns the value of X raised to the power\nof Y.\n\nURL: https://mariadb.com/kb/en/power/','','https://mariadb.com/kb/en/power/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (67,4,'RADIANS','Syntax\n------\n\nRADIANS(X)\n\nDescription\n-----------\n\nReturns the argument X, converted from degrees to radians. Note that π radians\nequals 180 degrees.\n\nThis is the converse of the DEGREES() function.\n\nExamples\n--------\n\nSELECT RADIANS(45);\n+-------------------+\n| RADIANS(45) |\n+-------------------+\n| 0.785398163397448 |\n+-------------------+\n\nSELECT RADIANS(90);\n+-----------------+\n| RADIANS(90) |\n+-----------------+\n| 1.5707963267949 |\n+-----------------+\n\nSELECT RADIANS(PI());\n+--------------------+\n| RADIANS(PI()) |\n+--------------------+\n| 0.0548311355616075 |\n+--------------------+\n\nSELECT RADIANS(180);\n+------------------+\n| RADIANS(180) |\n+------------------+\n| 3.14159265358979 |\n+------------------+\n\nURL: https://mariadb.com/kb/en/radians/','','https://mariadb.com/kb/en/radians/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (68,4,'RAND','Syntax\n------\n\nRAND(), RAND(N)\n\nDescription\n-----------\n\nReturns a random DOUBLE precision floating point value v in the range 0 <= v <\n1.0. If a constant integer argument N is specified, it is used as the seed\nvalue, which produces a repeatable sequence of column values. In the example\nbelow, note that the sequences of values produced by RAND(3) is the same both\nplaces where it occurs.\n\nIn a WHERE clause, RAND() is evaluated each time the WHERE is executed.\n\nStatements using the RAND() function are not safe for statement-based\nreplication.\n\nPractical uses\n--------------\n\nThe expression to get a random integer from a given range is the following:\n\nFLOOR(min_value + RAND() * (max_value - min_value +1))\n\nRAND() is often used to read random rows from a table, as follows:\n\nSELECT * FROM my_table ORDER BY RAND() LIMIT 10;\n\nNote, however, that this technique should never be used on a large table as it\nwill be extremely slow. MariaDB will read all rows in the table, generate a\nrandom value for each of them, order them, and finally will apply the LIMIT\nclause.\n\nExamples\n--------\n\nCREATE TABLE t (i INT);\n\nINSERT INTO t VALUES(1),(2),(3);\n\nSELECT i, RAND() FROM t;\n+------+-------------------+\n| i | RAND() |\n+------+-------------------+\n| 1 | 0.255651095188829 |\n| 2 | 0.833920199269355 |\n| 3 | 0.40264774151393 |\n+------+-------------------+\n\nSELECT i, RAND(3) FROM t;\n+------+-------------------+\n| i | RAND(3) |\n+------+-------------------+\n| 1 | 0.90576975597606 |\n| 2 | 0.373079058130345 |\n| 3 | 0.148086053457191 |\n+------+-------------------+\n\nSELECT i, RAND() FROM t;\n+------+-------------------+\n| i | RAND() |\n+------+-------------------+\n| 1 | 0.511478140495232 |\n| 2 | 0.349447508668012 |\n| 3 | 0.212803152588013 |\n+------+-------------------+\n\nUsing the same seed, the same sequence will be returned:\n\nSELECT i, RAND(3) FROM t;\n+------+-------------------+\n| i | RAND(3) |\n+------+-------------------+\n| 1 | 0.90576975597606 |\n| 2 | 0.373079058130345 |\n| 3 | 0.148086053457191 |\n+------+-------------------+\n\nGenerating a random number from 5 to 15:\n\nSELECT FLOOR(5 + (RAND() * 11));\n\nURL: https://mariadb.com/kb/en/rand/','','https://mariadb.com/kb/en/rand/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (69,4,'ROUND','Syntax\n------\n\nROUND(X), ROUND(X,D)\n\nDescription\n-----------\n\nRounds the argument X to D decimal places. D defaults to 0 if not specified. D\ncan be negative to cause D digits left of the decimal point of the value X to\nbecome zero.\n\nThe rounding algorithm depends on the data type of X:\n\n* for floating point types (FLOAT, DOUBLE) the C libraries rounding function\nis used, so the behavior *may* differ between operating systems\n* for fixed point types (DECIMAL, DEC/NUMBER/FIXED) the \"round half up\" rule\nis used, meaning that e.g. a value ending in exactly .5 is always rounded up.\n\nExamples\n--------\n\nSELECT ROUND(-1.23);\n+--------------+\n| ROUND(-1.23) |\n+--------------+\n| -1 |\n+--------------+\n\nSELECT ROUND(-1.58);\n+--------------+\n| ROUND(-1.58) |\n+--------------+\n| -2 |\n+--------------+\n\nSELECT ROUND(1.58); \n+-------------+\n| ROUND(1.58) |\n+-------------+\n| 2 |\n+-------------+\n\nSELECT ROUND(1.298, 1);\n+-----------------+\n| ROUND(1.298, 1) |\n+-----------------+\n| 1.3 |\n+-----------------+\n\nSELECT ROUND(1.298, 0);\n+-----------------+\n| ROUND(1.298, 0) |\n+-----------------+\n| 1 |\n+-----------------+\n\nSELECT ROUND(23.298, -1);\n+-------------------+\n| ROUND(23.298, -1) |\n+-------------------+\n| 20 |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/round/','','https://mariadb.com/kb/en/round/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (70,4,'SIGN','Syntax\n------\n\nSIGN(X)\n\nDescription\n-----------\n\nReturns the sign of the argument as -1, 0, or 1, depending on whether X is\nnegative, zero, or positive.\n\nExamples\n--------\n\nSELECT SIGN(-32);\n+-----------+\n| SIGN(-32) |\n+-----------+\n| -1 |\n+-----------+\n\nSELECT SIGN(0);\n+---------+\n| SIGN(0) |\n+---------+\n| 0 |\n+---------+\n\nSELECT SIGN(234);\n+-----------+\n| SIGN(234) |\n+-----------+\n| 1 |\n+-----------+\n\nURL: https://mariadb.com/kb/en/sign/','','https://mariadb.com/kb/en/sign/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (71,4,'SIN','Syntax\n------\n\nSIN(X)\n\nDescription\n-----------\n\nReturns the sine of X, where X is given in radians.\n\nExamples\n--------\n\nSELECT SIN(1.5707963267948966);\n+-------------------------+\n| SIN(1.5707963267948966) |\n+-------------------------+\n| 1 |\n+-------------------------+\n\nSELECT SIN(PI());\n+----------------------+\n| SIN(PI()) |\n+----------------------+\n| 1.22460635382238e-16 |\n+----------------------+\n\nSELECT ROUND(SIN(PI()));\n+------------------+\n| ROUND(SIN(PI())) |\n+------------------+\n| 0 |\n+------------------+\n\nURL: https://mariadb.com/kb/en/sin/','','https://mariadb.com/kb/en/sin/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (72,4,'SQRT','Syntax\n------\n\nSQRT(X)\n\nDescription\n-----------\n\nReturns the square root of X. If X is negative, NULL is returned.\n\nExamples\n--------\n\nSELECT SQRT(4);\n+---------+\n| SQRT(4) |\n+---------+\n| 2 |\n+---------+\n\nSELECT SQRT(20);\n+------------------+\n| SQRT(20) |\n+------------------+\n| 4.47213595499958 |\n+------------------+\n\nSELECT SQRT(-16);\n+-----------+\n| SQRT(-16) |\n+-----------+\n| NULL |\n+-----------+\n\nSELECT SQRT(1764);\n+------------+\n| SQRT(1764) |\n+------------+\n| 42 |\n+------------+\n\nURL: https://mariadb.com/kb/en/sqrt/','','https://mariadb.com/kb/en/sqrt/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (73,4,'TAN','Syntax\n------\n\nTAN(X)\n\nDescription\n-----------\n\nReturns the tangent of X, where X is given in radians.\n\nExamples\n--------\n\nSELECT TAN(0.7853981633974483);\n+-------------------------+\n| TAN(0.7853981633974483) |\n+-------------------------+\n| 0.9999999999999999 |\n+-------------------------+\n\nSELECT TAN(PI());\n+-----------------------+\n| TAN(PI()) |\n+-----------------------+\n| -1.22460635382238e-16 |\n+-----------------------+\n\nSELECT TAN(PI()+1);\n+-----------------+\n| TAN(PI()+1) |\n+-----------------+\n| 1.5574077246549 |\n+-----------------+\n\nSELECT TAN(RADIANS(PI()));\n+--------------------+\n| TAN(RADIANS(PI())) |\n+--------------------+\n| 0.0548861508080033 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/tan/','','https://mariadb.com/kb/en/tan/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (74,4,'TRUNCATE','This page documents the TRUNCATE function. See TRUNCATE TABLE for the DDL\nstatement.\n\nSyntax\n------\n\nTRUNCATE(X,D)\n\nDescription\n-----------\n\nReturns the number X, truncated to D decimal places. If D is 0, the result has\nno decimal point or fractional part. D can be negative to cause D digits left\nof the decimal point of the value X to become zero.\n\nExamples\n--------\n\nSELECT TRUNCATE(1.223,1);\n+-------------------+\n| TRUNCATE(1.223,1) |\n+-------------------+\n| 1.2 |\n+-------------------+\n\nSELECT TRUNCATE(1.999,1);\n+-------------------+\n| TRUNCATE(1.999,1) |\n+-------------------+\n| 1.9 |\n+-------------------+\n\nSELECT TRUNCATE(1.999,0); \n+-------------------+\n| TRUNCATE(1.999,0) |\n+-------------------+\n| 1 |\n+-------------------+\n\nSELECT TRUNCATE(-1.999,1);\n+--------------------+\n| TRUNCATE(-1.999,1) |\n+--------------------+\n| -1.9 |\n+--------------------+\n\nSELECT TRUNCATE(122,-2);\n+------------------+\n| TRUNCATE(122,-2) |\n+------------------+\n| 100 |\n+------------------+\n\nSELECT TRUNCATE(10.28*100,0);\n+-----------------------+\n| TRUNCATE(10.28*100,0) |\n+-----------------------+\n| 1028 |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/truncate/','','https://mariadb.com/kb/en/truncate/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (75,5,'INSTALL PLUGIN','Syntax\n------\n\nINSTALL PLUGIN [IF NOT EXISTS] plugin_name SONAME \'plugin_library\'\n\nDescription\n-----------\n\nThis statement installs an individual plugin from the specified library. To\ninstall the whole library (which could be required), use INSTALL SONAME. See\nalso Installing a Plugin.\n\nplugin_name is the name of the plugin as defined in the plugin declaration\nstructure contained in the library file. Plugin names are not case sensitive.\nFor maximal compatibility, plugin names should be limited to ASCII letters,\ndigits, and underscore, because they are used in C source files, shell command\nlines, M4 and Bourne shell scripts, and SQL environments.\n\nplugin_library is the name of the shared library that contains the plugin\ncode. The file name extension can be omitted (which makes the statement look\nthe same on all architectures).\n\nThe shared library must be located in the plugin directory (that is, the\ndirectory named by the plugin_dir system variable). The library must be in the\nplugin directory itself, not in a subdirectory. By default, plugin_dir is\nplugin directory under the directory named by the pkglibdir configuration\nvariable, but it can be changed by setting the value of plugin_dir at server\nstartup. For example, set its value in a my.cnf file:\n\n[mysqld]\nplugin_dir=/path/to/plugin/directory\nIf the value of plugin_dir is a relative path name, it is taken to be relative\nto the MySQL base directory (the value of the basedir system variable).\n\nINSTALL PLUGIN adds a line to the mysql.plugin table that describes the\nplugin. This table contains the plugin name and library file name.\n\nINSTALL PLUGIN causes the server to read option (my.cnf) files just as during\nserver startup. This enables the plugin to pick up any relevant options from\nthose files. It is possible to add plugin options to an option file even\nbefore loading a plugin (if the loose prefix is used). It is also possible to\nuninstall a plugin, edit my.cnf, and install the plugin again. Restarting the\nplugin this way enables it to the new option values without a server restart.\n\nINSTALL PLUGIN also loads and initializes the plugin code to make the plugin\navailable for use. A plugin is initialized by executing its initialization\nfunction, which handles any setup that the plugin must perform before it can\nbe used.\n\nTo use INSTALL PLUGIN, you must have the INSERT privilege for the mysql.plugin\ntable.\n\nAt server startup, the server loads and initializes any plugin that is listed\nin the mysql.plugin table. This means that a plugin is installed with INSTALL\nPLUGIN only once, not every time the server starts. Plugin loading at startup\ndoes not occur if the server is started with the --skip-grant-tables option.\n\nWhen the server shuts down, it executes the de-initialization function for\neach plugin that is loaded so that the plugin has a chance to perform any\nfinal cleanup.\n\nIf you need to load plugins for a single server startup when the\n--skip-grant-tables option is given (which tells the server not to read system\ntables), use the --plugin-load mysqld option.\n\nMariaDB starting with 10.4.0\n----------------------------\n\nIF NOT EXISTS\n-------------\n\nWhen the IF NOT EXISTS clause is used, MariaDB will return a note instead of\nan error if the specified plugin already exists. See SHOW WARNINGS.\n\nExamples\n--------\n\nINSTALL PLUGIN sphinx SONAME \'ha_sphinx.so\';\n\nThe extension can also be omitted:\n\nINSTALL PLUGIN innodb SONAME \'ha_xtradb\';\n\nFrom MariaDB 10.4.0:\n\nINSTALL PLUGIN IF NOT EXISTS example SONAME \'ha_example\';\nQuery OK, 0 rows affected (0.104 sec)\n\nINSTALL PLUGIN IF NOT EXISTS example SONAME \'ha_example\';\nQuery OK, 0 rows affected, 1 warning (0.000 sec)\n\nSHOW WARNINGS;\n+-------+------+------------------------------------+\n| Level | Code | Message |\n+-------+------+------------------------------------+\n| Note | 1968 | Plugin \'example\' already installed |\n+-------+------+------------------------------------+\n\nURL: https://mariadb.com/kb/en/install-plugin/','','https://mariadb.com/kb/en/install-plugin/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (76,5,'UNINSTALL PLUGIN','Syntax\n------\n\nUNINSTALL PLUGIN [IF EXISTS] plugin_name\n\nDescription\n-----------\n\nThis statement removes a single installed plugin. To uninstall the whole\nlibrary which contains the plugin, use UNINSTALL SONAME. You cannot uninstall\na plugin if any table that uses it is open.\n\nplugin_name must be the name of some plugin that is listed in the mysql.plugin\ntable. The server executes the plugin\'s deinitialization function and removes\nthe row for the plugin from the mysql.plugin table, so that subsequent server\nrestarts will not load and initialize the plugin. UNINSTALL PLUGIN does not\nremove the plugin\'s shared library file.\n\nTo use UNINSTALL PLUGIN, you must have the DELETE privilege for the\nmysql.plugin table.\n\nMariaDB starting with 10.4.0\n----------------------------\n\nIF EXISTS\n---------\n\nIf the IF EXISTS clause is used, MariaDB will return a note instead of an\nerror if the plugin does not exist. See SHOW WARNINGS.\n\nExamples\n--------\n\nUNINSTALL PLUGIN example;\n\nFrom MariaDB 10.4.0:\n\nUNINSTALL PLUGIN IF EXISTS example;\nQuery OK, 0 rows affected (0.099 sec)\n\nUNINSTALL PLUGIN IF EXISTS example;\nQuery OK, 0 rows affected, 1 warning (0.000 sec)\n\nSHOW WARNINGS;\n+-------+------+-------------------------------+\n| Level | Code | Message |\n+-------+------+-------------------------------+\n| Note | 1305 | PLUGIN example does not exist |\n+-------+------+-------------------------------+\n\nURL: https://mariadb.com/kb/en/uninstall-plugin/','','https://mariadb.com/kb/en/uninstall-plugin/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (77,5,'INSTALL SONAME','Syntax\n------\n\nINSTALL SONAME \'plugin_library\'\n\nDescription\n-----------\n\nThis statement is a variant of INSTALL PLUGIN. It installs all plugins from a\ngiven plugin_library. See INSTALL PLUGIN for details.\n\nplugin_library is the name of the shared library that contains the plugin\ncode. The file name extension (for example, libmyplugin.so or libmyplugin.dll)\ncan be omitted (which makes the statement look the same on all architectures).\n\nThe shared library must be located in the plugin directory (that is, the\ndirectory named by the plugin_dir system variable). The library must be in the\nplugin directory itself, not in a subdirectory. By default, plugin_dir is\nplugin directory under the directory named by the pkglibdir configuration\nvariable, but it can be changed by setting the value of plugin_dir at server\nstartup. For example, set its value in a my.cnf file:\n\n[mysqld]\nplugin_dir=/path/to/plugin/directory\nIf the value of plugin_dir is a relative path name, it is taken to be relative\nto the MySQL base directory (the value of the basedir system variable).\n\nINSTALL SONAME adds one or more lines to the mysql.plugin table that describes\nthe plugin. This table contains the plugin name and library file name.\n\nINSTALL SONAME causes the server to read option (my.cnf) files just as during\nserver startup. This enables the plugin to pick up any relevant options from\nthose files. It is possible to add plugin options to an option file even\nbefore loading a plugin (if the loose prefix is used). It is also possible to\nuninstall a plugin, edit my.cnf, and install the plugin again. Restarting the\nplugin this way enables it to the new option values without a server restart.\n\nINSTALL SONAME also loads and initializes the plugin code to make the plugin\navailable for use. A plugin is initialized by executing its initialization\nfunction, which handles any setup that the plugin must perform before it can\nbe used.\n\nTo use INSTALL SONAME, you must have the INSERT privilege for the mysql.plugin\ntable.\n\nAt server startup, the server loads and initializes any plugin that is listed\nin the mysql.plugin table. This means that a plugin is installed with INSTALL\nSONAME only once, not every time the server starts. Plugin loading at startup\ndoes not occur if the server is started with the --skip-grant-tables option.\n\nWhen the server shuts down, it executes the de-initialization function for\neach plugin that is loaded so that the plugin has a chance to perform any\nfinal cleanup.\n\nIf you need to load plugins for a single server startup when the\n--skip-grant-tables option is given (which tells the server not to read system\ntables), use the --plugin-load mysqld option.\n\nIf you need to install only one plugin from a library, use the INSTALL PLUGIN\nstatement.\n\nExamples\n--------\n\nTo load the XtraDB storage engine and all of its information_schema tables\nwith one statement, use\n\nINSTALL SONAME \'ha_xtradb\';\n\nThis statement can be used instead of INSTALL PLUGIN even when the library\ncontains only one plugin:\n\nINSTALL SONAME \'ha_sequence\';\n\nURL: https://mariadb.com/kb/en/install-soname/','','https://mariadb.com/kb/en/install-soname/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (78,5,'UNINSTALL SONAME','Syntax\n------\n\nUNINSTALL SONAME [IF EXISTS] \'plugin_library\'\n\nDescription\n-----------\n\nThis statement is a variant of UNINSTALL PLUGIN statement, that removes all\nplugins belonging to a specified plugin_library. See UNINSTALL PLUGIN for\ndetails.\n\nplugin_library is the name of the shared library that contains the plugin\ncode. The file name extension (for example, libmyplugin.so or libmyplugin.dll)\ncan be omitted (which makes the statement look the same on all architectures).\n\nTo use UNINSTALL SONAME, you must have the DELETE privilege for the\nmysql.plugin table.\n\nMariaDB starting with 10.4.0\n----------------------------\n\nIF EXISTS\n---------\n\nIf the IF EXISTS clause is used, MariaDB will return a note instead of an\nerror if the plugin library does not exist. See SHOW WARNINGS.\n\nExamples\n--------\n\nTo uninstall the XtraDB plugin and all of its information_schema tables with\none statement, use\n\nUNINSTALL SONAME \'ha_xtradb\';\n\nFrom MariaDB 10.4.0:\n\nUNINSTALL SONAME IF EXISTS \'ha_example\';\nQuery OK, 0 rows affected (0.099 sec)\n\nUNINSTALL SONAME IF EXISTS \'ha_example\';\nQuery OK, 0 rows affected, 1 warning (0.000 sec)\n\nSHOW WARNINGS;\n+-------+------+-------------------------------------+\n| Level | Code | Message |\n+-------+------+-------------------------------------+\n| Note | 1305 | SONAME ha_example.so does not exist |\n+-------+------+-------------------------------------+\n\nURL: https://mariadb.com/kb/en/uninstall-soname/','','https://mariadb.com/kb/en/uninstall-soname/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (79,5,'Plugin Overview','Plugins are server components that enhance MariaDB in some way. These can be\nanything from new storage engines, plugins for enhancing full-text parsing, or\neven small enhancements, such as a plugin to get a timestamp as an integer.\n\nQuerying Plugin Information\n---------------------------\n\nThere are a number of ways to see which plugins are currently active.\n\nA server almost always has a large number of active plugins, because the\nserver contains a large number of built-in plugins, which are active by\ndefault and cannot be uninstalled.\n\nQuerying Plugin Information with SHOW PLUGINS\n---------------------------------------------\n\nThe SHOW PLUGINS statement can be used to query information about all active\nplugins.\n\nFor example:\n\nSHOW PLUGINS\\G;\n********************** 1. row **********************\n Name: binlog\n Status: ACTIVE\n Type: STORAGE ENGINE\nLibrary: NULL\nLicense: GPL\n********************** 2. row **********************\n Name: mysql_native_password\n Status: ACTIVE\n Type: AUTHENTICATION\nLibrary: NULL\nLicense: GPL\n********************** 3. row **********************\n Name: mysql_old_password\n Status: ACTIVE\n Type: AUTHENTICATION\nLibrary: NULL\nLicense: GPL\n...\n\nIf a plugin\'s Library column has a NULL value, then the plugin is built-in,\nand it cannot be uninstalled.\n\nQuerying Plugin Information with information_schema.PLUGINS\n-----------------------------------------------------------\n\nThe information_schema.PLUGINS table can be queried to get more detailed\ninformation about plugins.\n\nFor example:\n\nSELECT * FROM information_schema.PLUGINS\\G\n...\n*************************** 6. row ***************************\n PLUGIN_NAME: CSV\n PLUGIN_VERSION: 1.0\n PLUGIN_STATUS: ACTIVE\n PLUGIN_TYPE: STORAGE ENGINE\n PLUGIN_TYPE_VERSION: 100003.0\n PLUGIN_LIBRARY: NULL\nPLUGIN_LIBRARY_VERSION: NULL\n PLUGIN_AUTHOR: Brian Aker, MySQL AB\n PLUGIN_DESCRIPTION: CSV storage engine\n PLUGIN_LICENSE: GPL\n LOAD_OPTION: FORCE\n PLUGIN_MATURITY: Stable\n PLUGIN_AUTH_VERSION: 1.0\n*************************** 7. row ***************************\n PLUGIN_NAME: MEMORY\n PLUGIN_VERSION: 1.0\n PLUGIN_STATUS: ACTIVE\n PLUGIN_TYPE: STORAGE ENGINE\n PLUGIN_TYPE_VERSION: 100003.0\n PLUGIN_LIBRARY: NULL\nPLUGIN_LIBRARY_VERSION: NULL\n PLUGIN_AUTHOR: MySQL AB\n PLUGIN_DESCRIPTION: Hash based, stored in memory, useful for temporary\ntables\n PLUGIN_LICENSE: GPL\n LOAD_OPTION: FORCE\n PLUGIN_MATURITY: Stable\n PLUGIN_AUTH_VERSION: 1.0\n...\n\nIf a plugin\'s PLUGIN_LIBRARY column has the NULL value, then the plugin is\nbuilt-in, and it cannot be uninstalled.\n\nQuerying Plugin Information with mysql.plugin\n---------------------------------------------\n\nThe mysql.plugin table can be queried to get information about installed\nplugins.\n\nThis table only contains information about plugins that have been installed\nvia the following methods:\n\n* The INSTALL SONAME statement.\n* The INSTALL PLUGIN statement.\n* The mariadb-plugin utility.\n\nThis table does not contain information about:\n\n* Built-in plugins.\n* Plugins loaded with the --plugin-load-add option.\n* Plugins loaded with the --plugin-load option.\n\nThis table only contains enough information to reload the plugin when the\nserver is restarted, which means it only contains the plugin name and the\nplugin library.\n\nFor example:\n\nSELECT * FROM mysql.plugin;\n\n+------+------------+\n| name | dl |\n+------+------------+\n| PBXT | libpbxt.so |\n+------+------------+\n\nInstalling a Plugin\n-------------------\n\nThere are three primary ways to install a plugin:\n\n* A plugin can be installed dynamically with an SQL statement.\n* A plugin can be installed with a mariadbd option, but it requires a server\nrestart.\n* A plugin can be installed with the mariadb-plugin utility, while the server\nis completely offline.\n\nWhen you are installing a plugin, you also have to ensure that:\n\n* The server\'s plugin directory is properly configured, and the plugin\'s\nlibrary is in the plugin directory.\n* The server\'s minimum plugin maturity is properly configured, and the plugin\nis mature enough to be installed.\n\nInstalling a Plugin Dynamically\n-------------------------------\n\nA plugin can be installed dynamically by executing either the INSTALL SONAME\nor the INSTALL PLUGIN statement.\n\nIf a plugin is installed with one of these statements, then a record will be\nadded to the mysql.plugins table for the plugin. This means that the plugin\nwill automatically be loaded every time the server restarts, unless\nspecifically uninstalled or deactivated.\n\nInstalling a Plugin with INSTALL SONAME\n---------------------------------------\n\nYou can install a plugin dynamically by executing the INSTALL SONAME\nstatement. INSTALL SONAME installs all plugins from the given plugin library.\nThis could be required for some plugin libraries.\n\nFor example, to install all plugins in the server_audit plugin library (which\nis currently only the server_audit audit plugin), you could execute the\nfollowing:\n\nINSTALL SONAME \'server_audit\';\n\nInstalling a Plugin with INSTALL PLUGIN\n---------------------------------------\n\nYou can install a plugin dynamically by executing the INSTALL PLUGIN\nstatement. INSTALL PLUGIN installs a single plugin from the given plugin\nlibrary.\n\nFor example, to install the server_audit audit plugin from the server_audit\nplugin library, you could execute the following:\n\nINSTALL PLUGIN server_audit SONAME \'server_audit\';\n\nInstalling a Plugin with Plugin Load Options\n--------------------------------------------\n\nA plugin can be installed with a mariadbd option by providing either the\n--plugin-load-add or the --plugin-load option.\n\nIf a plugin is installed with one of these options, then a record will not be\nadded to the mysql.plugins table for the plugin. This means that if the server\nis restarted without the same option set, then the plugin will not\nautomatically be loaded.\n\nInstalling a Plugin with --plugin-load-add\n------------------------------------------\n\nYou can install a plugin with the --plugin-load-add option by specifying the\noption as a command-line argument to mariadbd or by specifying the option in a\nrelevant server option group in an option file.\n\nThe --plugin-load-add option uses the following format:\n\n* Plugins can be specified in the format name=library, where name is the\nplugin name and library is the plugin library. This format installs a single\nplugin from the given plugin library.\n* Plugins can also be specified in the format library, where library is the\nplugin library. This format installs all plugins from the given plugin library.\n* Multiple plugins can be specified by separating them with semicolons.\n\nFor example, to install all plugins in the server_audit plugin library (which\nis currently only the server_audit audit plugin) and also the ed25519\nauthentication plugin from the auth_ed25519 plugin library, you could set the\noption to the following values on the command-line:\n\n$ mariadbd --user=mysql --plugin-load-add=\'server_audit\'\n--plugin-load-add=\'ed25519=auth_ed25519\'\n\nYou could also set the option to the same values in an option file:\n\n[mariadb]\n...\nplugin_load_add = server_audit\nplugin_load_add = ed25519=auth_ed25519\n\nSpecial care must be taken when specifying both the --plugin-load option and\nthe --plugin-load-add option together. The --plugin-load option resets the\nplugin load list, and this can cause unexpected problems if you are not aware.\nThe --plugin-load-add option does not reset the plugin load list, so it is\nmuch safer to use. See Specifying Multiple Plugin Load Options for more\ninformation.\n\nInstalling a Plugin with --plugin-load\n--------------------------------------\n\nYou can install a plugin with the --plugin-load option by specifying the\noption as a command-line argument to mariadbd or by specifying the option in a\nrelevant server option group in an option file.\n\nThe --plugin-load option uses the following format:\n\n* Plugins can be specified in the format name=library, where name is the\nplugin name and library is the plugin library. This format installs a single\nplugin from the given plugin library.\n* Plugins can also be specified in the format library, where library is the\nplugin library. This format installs all plugins from the given plugin library.\n* Multiple plugins can be specified by separating them with semicolons.\n\nFor example, to install all plugins in the server_audit plugin library (which\nis currently only the server_audit audit plugin) and also the ed25519\nauthentication plugin from the auth_ed25519 plugin library, you could set the\noption to the following values on the command-line:\n\n$ mariadbd --user=mysql --plugin-load=\'server_audit;ed25519=auth_ed25519\'\n\nYou could also set the option to the same values in an option file:\n\n[mariadb]\n...\nplugin_load = server_audit;ed25519=auth_ed25519\n\nSpecial care must be taken when specifying the --plugin-load option multiple\ntimes, or when specifying both the --plugin-load option and the\n--plugin-load-add option together. The --plugin-load option resets the plugin\nload list, and this can cause unexpected problems if you are not aware. The\n--plugin-load-add option does not reset the plugin load list, so it is much\nsafer to use. See Specifying Multiple Plugin Load Options for more information.\n\nSpecifying Multiple Plugin Load Options\n---------------------------------------\n\nSpecial care must be taken when specifying the --plugin-load option multiple\ntimes, or when specifying both the --plugin-load option and the\n--plugin-load-add option. The --plugin-load option resets the plugin load\nlist, and this can cause unexpected problems if you are not aware. The\n--plugin-load-add option does not reset the plugin load list, so it is much\nsafer to use.\n\nThis can have the following consequences:\n\n* If the --plugin-load option is specified multiple times, then only the last\ninstance will have any effect. For example, in the following case, the first\ninstance of the option is reset:\n\n[mariadb]\n...\nplugin_load = server_audit\nplugin_load = ed25519=auth_ed25519\n\n* If the --plugin-load option is specified after the --plugin-load-add option,\nthen it will also reset the changes made by that option. For example, in the\nfollowing case, the --plugin-load-add option does not do anything, because the\nsubsequent --plugin-load option resets the plugin load list:\n\n[mariadb]\n...\nplugin_load_add = server_audit\nplugin_load = ed25519=auth_ed25519\n\n* In contrast, if the --plugin-load option is specified before the\n--plugin-load-add option, then it will work fine, because the\n--plugin-load-add option does not reset the plugin load list. For example, in\nthe following case, both plugins are properly loaded:\n\n[mariadb]\n...\nplugin_load = server_audit\nplugin_load_add = ed25519=auth_ed25519\n\nInstalling a Plugin with mariadb-plugin\n---------------------------------------\n\nA plugin can be installed with the mariadb-plugin utility if the server is\ncompletely offline.\n\nThe syntax is:\n\nmariadb-plugin [options] <plugin> ENABLE|DISABLE\n\nFor example, to install the server_audit audit plugin, you could execute the\nfollowing:\n\nmariadb-plugin server_audit ENABLE\n\nIf a plugin is installed with this utility, then a record will be added to the\nmysql.plugins table for the plugin. This means that the plugin will\nautomatically be loaded every time the server restarts, unless specifically\nuninstalled or deactivated.\n\nConfiguring the Plugin Directory\n--------------------------------\n\nWhen a plugin is being installed, the server looks for the plugin\'s library in\nthe server\'s plugin directory. This directory is configured by the plugin_dir\nsystem variable. This can be specified as a command-line argument to mariadbd\nor it can be specified in a relevant server option group in an option file.\nFor example:\n\n[mariadb]\n...\nplugin_dir = /usr/lib64/mysql/plugin\n\nConfiguring the Minimum Plugin Maturity\n---------------------------------------\n\nWhen a plugin is being installed, the server compares the plugin\'s maturity\nlevel against the server\'s minimum allowed plugin maturity. This can help\nprevent users from using unstable plugins on production servers. This minimum\nplugin maturity is configured by the plugin_maturity system variable. This can\nbe specified as a command-line argument to mariadbd or it can be specified in\na relevant server option group in an option file. For example:\n\n[mariadb]\n...\nplugin_maturity = stable\n\nConfiguring Plugin Activation at Server Startup\n-----------------------------------------------\n\nA plugin will be loaded by default when the server starts if:\n\n* The plugin was installed with the INSTALL SONAME statement.\n* The plugin was installed with the INSTALL PLUGIN statement.\n* The plugin was installed with the mariadb-plugin utility.\n* The server is configured to load the plugin with the --plugin-load-add\noption.\n* The server is configured to load the plugin with the --plugin-load option.\n\nThis behavior can be changed with special options that take the form\n--plugin-name. For example, for the server_audit audit plugin, the special\noption is called --server-audit.\n\nThe possible values for these special options are:\n\n+---------------------------------------+------------------------------------+\n| Option Value | Description |\n+---------------------------------------+------------------------------------+\n| OFF | Disables the plugin without |\n| | removing it from the |\n| | mysql.plugins table. |\n+---------------------------------------+------------------------------------+\n| ON | Enables the plugin. If the plugin |\n| | cannot be initialized, then the |\n| | server will still continue |\n| | starting up, but the plugin will |\n| | be disabled. |\n+---------------------------------------+------------------------------------+','','https://mariadb.com/kb/en/plugin-overview/'); +update help_topic set description = CONCAT(description, '\n| FORCE | Enables the plugin. If the plugin |\n| | cannot be initialized, then the |\n| | server will fail to start with an |\n| | error. |\n+---------------------------------------+------------------------------------+\n| FORCE_PLUS_PERMANENT | Enables the plugin. If the plugin |\n| | cannot be initialized, then the |\n| | server will fail to start with an |\n| | error. In addition, the plugin |\n| | cannot be uninstalled with |\n| | UNINSTALL SONAME or UNINSTALL |\n| | PLUGIN while the server is |\n| | running. |\n+---------------------------------------+------------------------------------+\n\nA plugin\'s status can be found by looking at the PLUGIN_STATUS column of the\ninformation_schema.PLUGINS table.\n\nUninstalling Plugins\n--------------------\n\nPlugins that are found in the mysql.plugin table, that is those that were\ninstalled with INSTALL SONAME, INSTALL PLUGIN or mariadb-plugin can be\nuninstalled in one of two ways:\n\n* The UNINSTALL SONAME or the UNINSTALL PLUGIN statement while the server is\nrunning\n* With mariadb-plugin while the server is offline.\n\nPlugins that were enabled as a --plugin-load option do not need to be\nuninstalled. If --plugin-load is omitted the next time the server starts, or\nthe plugin is not listed as one of the --plugin-load entries, the plugin will\nnot be loaded.\n\nUNINSTALL PLUGIN uninstalls a single installed plugin, while UNINSTALL SONAME\nuninstalls all plugins belonging to a given library.\n\nURL: https://mariadb.com/kb/en/plugin-overview/') WHERE help_topic_id = 79; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (80,6,'MBR Definition','Description\n-----------\n\nThe MBR (Minimum Bounding Rectangle), or Envelope is the bounding geometry,\nformed by the minimum and maximum (X,Y) coordinates:\n\nExamples\n--------\n\n((MINX MINY, MAXX MINY, MAXX MAXY, MINX MAXY, MINX MINY))\n\nURL: https://mariadb.com/kb/en/mbr-definition/','','https://mariadb.com/kb/en/mbr-definition/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (81,6,'MBRContains','Syntax\n------\n\nMBRContains(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether the Minimum Bounding Rectangle of g1\ncontains the Minimum Bounding Rectangle of g2. This tests the opposite\nrelationship as MBRWithin().\n\nExamples\n--------\n\nSET @g1 = GeomFromText(\'Polygon((0 0,0 3,3 3,3 0,0 0))\');\n\nSET @g2 = GeomFromText(\'Point(1 1)\');\n\nSELECT MBRContains(@g1,@g2), MBRContains(@g2,@g1);\n+----------------------+----------------------+\n| MBRContains(@g1,@g2) | MBRContains(@g2,@g1) |\n+----------------------+----------------------+\n| 1 | 0 |\n+----------------------+----------------------+\n\nURL: https://mariadb.com/kb/en/mbrcontains/','','https://mariadb.com/kb/en/mbrcontains/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (82,6,'MBRDisjoint','Syntax\n------\n\nMBRDisjoint(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether the Minimum Bounding Rectangles of the two\ngeometries g1 and g2 are disjoint. Two geometries are disjoint if they do not\nintersect, that is touch or overlap.\n\nExamples\n--------\n\nSET @g1 = GeomFromText(\'Polygon((0 0,0 3,3 3,3 0,0 0))\');\nSET @g2 = GeomFromText(\'Polygon((4 4,4 7,7 7,7 4,4 4))\');\nSELECTmbrdisjoint(@g1,@g2);\n+----------------------+\n| mbrdisjoint(@g1,@g2) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSET @g1 = GeomFromText(\'Polygon((0 0,0 3,3 3,3 0,0 0))\');\nSET @g2 = GeomFromText(\'Polygon((3 3,3 6,6 6,6 3,3 3))\');\nSELECT mbrdisjoint(@g1,@g2);\n+----------------------+\n| mbrdisjoint(@g1,@g2) |\n+----------------------+\n| 0 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/mbrdisjoint/','','https://mariadb.com/kb/en/mbrdisjoint/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (83,6,'MBREqual','Syntax\n------\n\nMBREqual(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether the Minimum Bounding Rectangles of the two\ngeometries g1 and g2 are the same.\n\nExamples\n--------\n\nSET @g1=GEOMFROMTEXT(\'LINESTRING(0 0, 1 2)\');\nSET @g2=GEOMFROMTEXT(\'POLYGON((0 0, 0 2, 1 2, 1 0, 0 0))\');\nSELECT MbrEqual(@g1,@g2);\n+-------------------+\n| MbrEqual(@g1,@g2) |\n+-------------------+\n| 1 |\n+-------------------+\n\nSET @g1=GEOMFROMTEXT(\'LINESTRING(0 0, 1 3)\');\nSET @g2=GEOMFROMTEXT(\'POLYGON((0 0, 0 2, 1 4, 1 0, 0 0))\');\nSELECT MbrEqual(@g1,@g2);\n+-------------------+\n| MbrEqual(@g1,@g2) |\n+-------------------+\n| 0 |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/mbrequal/','','https://mariadb.com/kb/en/mbrequal/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (84,6,'MBRIntersects','Syntax\n------\n\nMBRIntersects(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether the Minimum Bounding Rectangles of the two\ngeometries g1 and g2 intersect.\n\nExamples\n--------\n\nSET @g1 = GeomFromText(\'Polygon((0 0,0 3,3 3,3 0,0 0))\');\nSET @g2 = GeomFromText(\'Polygon((3 3,3 6,6 6,6 3,3 3))\');\nSELECT mbrintersects(@g1,@g2);\n+------------------------+\n| mbrintersects(@g1,@g2) |\n+------------------------+\n| 1 |\n+------------------------+\n\nSET @g1 = GeomFromText(\'Polygon((0 0,0 3,3 3,3 0,0 0))\');\nSET @g2 = GeomFromText(\'Polygon((4 4,4 7,7 7,7 4,4 4))\');\nSELECT mbrintersects(@g1,@g2);\n+------------------------+\n| mbrintersects(@g1,@g2) |\n+------------------------+\n| 0 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/mbrintersects/','','https://mariadb.com/kb/en/mbrintersects/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (85,6,'MBROverlaps','Syntax\n------\n\nMBROverlaps(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether the Minimum Bounding Rectangles of the two\ngeometries g1 and g2 overlap. The term spatially overlaps is used if two\ngeometries intersect and their intersection results in a geometry of the same\ndimension but not equal to either of the given geometries.\n\nExamples\n--------\n\nSET @g1 = GeomFromText(\'Polygon((0 0,0 3,3 3,3 0,0 0))\');\nSET @g2 = GeomFromText(\'Polygon((4 4,4 7,7 7,7 4,4 4))\');\nSELECT mbroverlaps(@g1,@g2);\n+----------------------+\n| mbroverlaps(@g1,@g2) |\n+----------------------+\n| 0 |\n+----------------------+\n\nSET @g1 = GeomFromText(\'Polygon((0 0,0 3,3 3,3 0,0 0))\');\nSET @g2 = GeomFromText(\'Polygon((3 3,3 6,6 6,6 3,3 3))\');\nSELECT mbroverlaps(@g1,@g2);\n+----------------------+\n| mbroverlaps(@g1,@g2) |\n+----------------------+\n| 0 |\n+----------------------+\n\nSET @g1 = GeomFromText(\'Polygon((0 0,0 4,4 4,4 0,0 0))\');\nSET @g2 = GeomFromText(\'Polygon((3 3,3 6,6 6,6 3,3 3))\');\nSELECT mbroverlaps(@g1,@g2);\n+----------------------+\n| mbroverlaps(@g1,@g2) |\n+----------------------+\n| 1 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/mbroverlaps/','','https://mariadb.com/kb/en/mbroverlaps/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (86,6,'MBRTouches','Syntax\n------\n\nMBRTouches(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether the Minimum Bounding Rectangles of the two\ngeometries g1 and g2 touch. Two geometries spatially touch if the interiors of\nthe geometries do not intersect, but the boundary of one of the geometries\nintersects either the boundary or the interior of the other.\n\nExamples\n--------\n\nSET @g1 = GeomFromText(\'Polygon((0 0,0 3,3 3,3 0,0 0))\');\nSET @g2 = GeomFromText(\'Polygon((4 4,4 7,7 7,7 4,4 4))\');\nSELECT mbrtouches(@g1,@g2);\n+---------------------+\n| mbrtouches(@g1,@g2) |\n+---------------------+\n| 0 |\n+---------------------+\n\nSET @g1 = GeomFromText(\'Polygon((0 0,0 3,3 3,3 0,0 0))\');\nSET @g2 = GeomFromText(\'Polygon((3 3,3 6,6 6,6 3,3 3))\');\nSELECT mbrtouches(@g1,@g2);\n+---------------------+\n| mbrtouches(@g1,@g2) |\n+---------------------+\n| 1 |\n+---------------------+\n\nSET @g1 = GeomFromText(\'Polygon((0 0,0 4,4 4,4 0,0 0))\');\nSET @g2 = GeomFromText(\'Polygon((3 3,3 6,6 6,6 3,3 3))\');\nSELECT mbrtouches(@g1,@g2);\n+---------------------+\n| mbrtouches(@g1,@g2) |\n+---------------------+\n| 0 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/mbrtouches/','','https://mariadb.com/kb/en/mbrtouches/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (87,6,'MBRWithin','Syntax\n------\n\nMBRWithin(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether the Minimum Bounding Rectangle of g1 is\nwithin the Minimum Bounding Rectangle of g2. This tests the opposite\nrelationship as MBRContains().\n\nExamples\n--------\n\nSET @g1 = GeomFromText(\'Polygon((0 0,0 3,3 3,3 0,0 0))\');\nSET @g2 = GeomFromText(\'Polygon((0 0,0 5,5 5,5 0,0 0))\');\nSELECT MBRWithin(@g1,@g2), MBRWithin(@g2,@g1);\n+--------------------+--------------------+\n| MBRWithin(@g1,@g2) | MBRWithin(@g2,@g1) |\n+--------------------+--------------------+\n| 1 | 0 |\n+--------------------+--------------------+\n\nURL: https://mariadb.com/kb/en/mbrwithin/','','https://mariadb.com/kb/en/mbrwithin/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (88,7,'CASE OPERATOR','Syntax\n------\n\nCASE value WHEN [compare_value] THEN result [WHEN [compare_value] THEN\nresult ...] [ELSE result] END\n\nCASE WHEN [condition] THEN result [WHEN [condition] THEN result ...]\n[ELSE result] END\n\nDescription\n-----------\n\nThe first version returns the result where value=compare_value. The second\nversion returns the result for the first condition that is true. If there was\nno matching result value, the result after ELSE is returned, or NULL if there\nis no ELSE part.\n\nThere is also a CASE statement, which differs from the CASE operator described\nhere.\n\nExamples\n--------\n\nSELECT CASE 1 WHEN 1 THEN \'one\' WHEN 2 THEN \'two\' ELSE \'more\' END;\n+------------------------------------------------------------+\n| CASE 1 WHEN 1 THEN \'one\' WHEN 2 THEN \'two\' ELSE \'more\' END |\n+------------------------------------------------------------+\n| one |\n+------------------------------------------------------------+\n\nSELECT CASE WHEN 1>0 THEN \'true\' ELSE \'false\' END;\n+--------------------------------------------+\n| CASE WHEN 1>0 THEN \'true\' ELSE \'false\' END |\n+--------------------------------------------+\n| true |\n+--------------------------------------------+\n\nSELECT CASE BINARY \'B\' WHEN \'a\' THEN 1 WHEN \'b\' THEN 2 END;\n+-----------------------------------------------------+\n| CASE BINARY \'B\' WHEN \'a\' THEN 1 WHEN \'b\' THEN 2 END |\n+-----------------------------------------------------+\n| NULL |\n+-----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/case-operator/','','https://mariadb.com/kb/en/case-operator/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (89,7,'IF Function','Syntax\n------\n\nIF(expr1,expr2,expr3)\n\nDescription\n-----------\n\nIf expr1 is TRUE (expr1 <> 0 and expr1 <> NULL) then IF() returns expr2;\notherwise it returns expr3. IF() returns a numeric or string value, depending\non the context in which it is used.\n\nNote: There is also an IF statement which differs from the IF() function\ndescribed here.\n\nExamples\n--------\n\nSELECT IF(1>2,2,3);\n+-------------+\n| IF(1>2,2,3) |\n+-------------+\n| 3 |\n+-------------+\n\nSELECT IF(1<2,\'yes\',\'no\');\n+--------------------+\n| IF(1<2,\'yes\',\'no\') |\n+--------------------+\n| yes |\n+--------------------+\n\nSELECT IF(STRCMP(\'test\',\'test1\'),\'no\',\'yes\');\n+---------------------------------------+\n| IF(STRCMP(\'test\',\'test1\'),\'no\',\'yes\') |\n+---------------------------------------+\n| no |\n+---------------------------------------+\n\nURL: https://mariadb.com/kb/en/if-function/','','https://mariadb.com/kb/en/if-function/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (90,7,'IFNULL','Syntax\n------\n\nIFNULL(expr1,expr2)\nNVL(expr1,expr2)\n\nDescription\n-----------\n\nIf expr1 is not NULL, IFNULL() returns expr1; otherwise it returns expr2.\nIFNULL() returns a numeric or string value, depending on the context in which\nit is used.\n\nFrom MariaDB 10.3, NVL() is an alias for IFNULL().\n\nExamples\n--------\n\nSELECT IFNULL(1,0); \n+-------------+\n| IFNULL(1,0) |\n+-------------+\n| 1 |\n+-------------+\n\nSELECT IFNULL(NULL,10);\n+-----------------+\n| IFNULL(NULL,10) |\n+-----------------+\n| 10 |\n+-----------------+\n\nSELECT IFNULL(1/0,10);\n+----------------+\n| IFNULL(1/0,10) |\n+----------------+\n| 10.0000 |\n+----------------+\n\nSELECT IFNULL(1/0,\'yes\');\n+-------------------+\n| IFNULL(1/0,\'yes\') |\n+-------------------+\n| yes |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/ifnull/','','https://mariadb.com/kb/en/ifnull/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (91,7,'NULLIF','Syntax\n------\n\nNULLIF(expr1,expr2)\n\nDescription\n-----------\n\nReturns NULL if expr1 = expr2 is true, otherwise returns expr1. This is the\nsame as CASE WHEN expr1 = expr2 THEN NULL ELSE expr1 END.\n\nExamples\n--------\n\nSELECT NULLIF(1,1);\n+-------------+\n| NULLIF(1,1) |\n+-------------+\n| NULL |\n+-------------+\n\nSELECT NULLIF(1,2);\n+-------------+\n| NULLIF(1,2) |\n+-------------+\n| 1 |\n+-------------+\n\nURL: https://mariadb.com/kb/en/nullif/','','https://mariadb.com/kb/en/nullif/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (92,7,'NVL','MariaDB starting with 10.3\n--------------------------\nFrom MariaDB 10.3, NVL is a synonym for IFNULL.\n\nURL: https://mariadb.com/kb/en/nvl/','','https://mariadb.com/kb/en/nvl/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (93,7,'NVL2','MariaDB starting with 10.3\n--------------------------\nThe NLV2 function was introduced in MariaDB 10.3.0.\n\nSyntax\n------\n\nNVL2(expr1,expr2,expr3)\n\nDescription\n-----------\n\nThe NVL2 function returns a value based on whether a specified expression is\nNULL or not. If expr1 is not NULL, then NVL2 returns expr2. If expr1 is NULL,\nthen NVL2 returns expr3.\n\nExamples\n--------\n\nSELECT NVL2(NULL,1,2);\n+----------------+\n| NVL2(NULL,1,2) |\n+----------------+\n| 2 |\n+----------------+\n\nSELECT NVL2(\'x\',1,2);\n+---------------+\n| NVL2(\'x\',1,2) |\n+---------------+\n| 1 |\n+---------------+\n\nURL: https://mariadb.com/kb/en/nvl2/','','https://mariadb.com/kb/en/nvl2/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (94,8,'START TRANSACTION','Syntax\n------\n\nSTART TRANSACTION [transaction_property [, transaction_property] ...] | BEGIN\n[WORK]\nCOMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]\nROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE]\nSET autocommit = {0 | 1}\n\ntransaction_property:\n WITH CONSISTENT SNAPSHOT\n | READ WRITE\n | READ ONLY\n\nDescription\n-----------\n\nThe START TRANSACTION or BEGIN statement begins a new transaction. COMMIT\ncommits the current transaction, making its changes permanent. ROLLBACK rolls\nback the current transaction, canceling its changes. The SET autocommit\nstatement disables or enables the default autocommit mode for the current\nsession.\n\nSTART TRANSACTION and SET autocommit = 1 implicitly commit the current\ntransaction, if any.\n\nThe optional WORK keyword is supported for COMMIT and ROLLBACK, as are the\nCHAIN and RELEASE clauses. CHAIN and RELEASE can be used for additional\ncontrol over transaction completion. The value of the completion_type system\nvariable determines the default completion behavior.\n\nThe AND CHAIN clause causes a new transaction to begin as soon as the current\none ends, and the new transaction has the same isolation level as the\njust-terminated transaction. The RELEASE clause causes the server to\ndisconnect the current client session after terminating the current\ntransaction. Including the NO keyword suppresses CHAIN or RELEASE completion,\nwhich can be useful if the completion_type system variable is set to cause\nchaining or release completion by default.\n\nAccess Mode\n-----------\n\nThe access mode specifies whether the transaction is allowed to write data or\nnot. By default, transactions are in READ WRITE mode (see the tx_read_only\nsystem variable). READ ONLY mode allows the storage engine to apply\noptimizations that cannot be used for transactions which write data. Note that\nunlike the global read_only mode, READ_ONLY ADMIN (and SUPER before MariaDB\n10.11.0) privilege doesn\'t allow writes and DDL statements on temporary tables\nare not allowed either.\n\nIt is not permitted to specify both READ WRITE and READ ONLY in the same\nstatement.\n\nREAD WRITE and READ ONLY can also be specified in the SET TRANSACTION\nstatement, in which case the specified mode is valid for all sessions, or for\nall subsequent transaction used by the current session.\n\nautocommit\n----------\n\nBy default, MariaDB runs with autocommit mode enabled. This means that as soon\nas you execute a statement that updates (modifies) a table, MariaDB stores the\nupdate on disk to make it permanent. To disable autocommit mode, use the\nfollowing statement:\n\nSET autocommit=0;\n\nAfter disabling autocommit mode by setting the autocommit variable to zero,\nchanges to transaction-safe tables (such as those for InnoDB or NDBCLUSTER)\nare not made permanent immediately. You must use COMMIT to store your changes\nto disk or ROLLBACK to ignore the changes.\n\nTo disable autocommit mode for a single series of statements, use the START\nTRANSACTION statement.\n\nDDL Statements\n--------------\n\nDDL statements (CREATE, ALTER, DROP) and administrative statements (FLUSH,\nRESET, OPTIMIZE, ANALYZE, CHECK, REPAIR, CACHE INDEX), transaction management\nstatements (BEGIN, START TRANSACTION) and LOAD DATA INFILE, cause an implicit\nCOMMIT and start a new transaction. An exception to this rule are the DDL that\noperate on temporary tables: you can CREATE, ALTER and DROP them without\ncausing any COMMIT, but those actions cannot be rolled back. This means that\nif you call ROLLBACK, the temporary tables you created in the transaction will\nremain, while the rest of the transaction will be rolled back.\n\nTransactions cannot be used in Stored Functions or Triggers. In Stored\nProcedures and Events BEGIN is not allowed, so you should use START\nTRANSACTION instead.\n\nA transaction acquires a metadata lock on every table it accesses to prevent\nother connections from altering their structure. The lock is released at the\nend of the transaction. This happens even with non-transactional storage\nengines (like MEMORY or CONNECT), so it makes sense to use transactions with\nnon-transactional tables.\n\nin_transaction\n--------------\n\nThe in_transaction system variable is a session-only, read-only variable that\nreturns 1 inside a transaction, and 0 if not in a transaction.\n\nWITH CONSISTENT SNAPSHOT\n------------------------\n\nThe WITH CONSISTENT SNAPSHOT option starts a consistent read for storage\nengines such as InnoDB that can do so, the same as if a START TRANSACTION\nfollowed by a SELECT from any InnoDB table was issued.\n\nSee Enhancements for START TRANSACTION WITH CONSISTENT SNAPSHOT.\n\nExamples\n--------\n\nSTART TRANSACTION;\nSELECT @A:=SUM(salary) FROM table1 WHERE type=1;\nUPDATE table2 SET summary=@A WHERE type=1;\nCOMMIT;\n\nURL: https://mariadb.com/kb/en/start-transaction/','','https://mariadb.com/kb/en/start-transaction/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (95,8,'COMMIT','The COMMIT statement ends a transaction, saving any changes to the data so\nthat they become visible to subsequent transactions. Also, unlocks metadata\nchanged by current transaction. If autocommit is set to 1, an implicit commit\nis performed after each statement. Otherwise, all transactions which don\'t end\nwith an explicit COMMIT are implicitly rollbacked and the changes are lost.\nThe ROLLBACK statement can be used to do this explicitly.\n\nThe required syntax for the COMMIT statement is as follows:\n\nCOMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]\n\nCOMMIT is the more important transaction terminator, as well as the more\ninteresting one. The basic form of the COMMIT statement is simply the keyword\nCOMMIT (the keyword WORK is simply noise and can be omitted without changing\nthe effect).\n\nThe optional AND CHAIN clause is a convenience for initiating a new\ntransaction as soon as the old transaction terminates. If AND CHAIN is\nspecified, then there is effectively nothing between the old and new\ntransactions, although they remain separate. The characteristics of the new\ntransaction will be the same as the characteristics of the old one — that is,\nthe new transaction will have the same access mode, isolation level and\ndiagnostics area size (we\'ll discuss all of these shortly) as the transaction\njust terminated.\n\nRELEASE tells the server to disconnect the client immediately after the\ncurrent transaction.\n\nThere are NO RELEASE and AND NO CHAIN options. By default, commits do not\nRELEASE or CHAIN, but it\'s possible to change this default behavior with the\ncompletion_type server system variable. In this case, the AND NO CHAIN and NO\nRELEASE options override the server default.\n\nURL: https://mariadb.com/kb/en/commit/','','https://mariadb.com/kb/en/commit/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (96,8,'ROLLBACK','The ROLLBACK statement rolls back (ends) a transaction, destroying any changes\nto SQL-data so that they never become visible to subsequent transactions. The\nrequired syntax for the ROLLBACK statement is as follows.\n\nROLLBACK [ WORK ] [ AND [ NO ] CHAIN ] \n[ TO [ SAVEPOINT ] {<savepoint name> | <simple target specification>} ]\n\nThe ROLLBACK statement will either end a transaction, destroying all data\nchanges that happened during any of the transaction, or it will just destroy\nany data changes that happened since you established a savepoint. The basic\nform of the ROLLBACK statement is just the keyword ROLLBACK (the keyword WORK\nis simply noise and can be omitted without changing the effect).\n\nThe optional AND CHAIN clause is a convenience for initiating a new\ntransaction as soon as the old transaction terminates. If AND CHAIN is\nspecified, then there is effectively nothing between the old and new\ntransactions, although they remain separate. The characteristics of the new\ntransaction will be the same as the characteristics of the old one — that is,\nthe new transaction will have the same access mode, isolation level and\ndiagnostics area size (we\'ll discuss all of these shortly) as the transaction\njust terminated. The AND NO CHAIN option just tells your DBMS to end the\ntransaction — that is, these four SQL statements are equivalent:\n\nROLLBACK; \nROLLBACK WORK; \nROLLBACK AND NO CHAIN; \nROLLBACK WORK AND NO CHAIN;\n\nAll of them end a transaction without saving any transaction characteristics.\nThe only other options, the equivalent statements:\n\nROLLBACK AND CHAIN;\nROLLBACK WORK AND CHAIN;\n\nboth tell your DBMS to end a transaction, but to save that transaction\'s\ncharacteristics for the next transaction.\n\nROLLBACK is much simpler than COMMIT: it may involve no more than a few\ndeletions (of Cursors, locks, prepared SQL statements and log-file entries).\nIt\'s usually assumed that ROLLBACK can\'t fail, although such a thing is\nconceivable (for example, an encompassing transaction might reject an attempt\nto ROLLBACK because it\'s lining up for a COMMIT).\n\nROLLBACK cancels all effects of a transaction. It does not cancel effects on\nobjects outside the DBMS\'s control (for example the values in host program\nvariables or the settings made by some SQL/CLI function calls). But in\ngeneral, it is a convenient statement for those situations when you say \"oops,\nthis isn\'t working\" or when you simply don\'t care whether your temporary work\nbecomes permanent or not.\n\nHere is a moot question. If all you\'ve been doing is SELECTs, so that there\nhave been no data changes, should you end the transaction with ROLLBACK or\nCOMMIT? It shouldn\'t really matter because both ROLLBACK and COMMIT do the\nsame transaction-terminating job. However, the popular conception is that\nROLLBACK implies failure, so after a successful series of SELECT statements\nthe convention is to end the transaction with COMMIT rather than ROLLBACK.\n\nMariaDB (and most other DBMSs) supports rollback of SQL-data change\nstatements, but not of SQL-Schema statements. This means that if you use any\nof CREATE, ALTER, DROP, GRANT, REVOKE, you are implicitly committing at\nexecution time.\n\nINSERT INTO Table_2 VALUES(5); \nDROP TABLE Table_3 CASCADE; \nROLLBACK;\n\nThe result will be that both the INSERT and the DROP will go through as\nseparate transactions so the ROLLBACK will have no effect.\n\nURL: https://mariadb.com/kb/en/rollback/','','https://mariadb.com/kb/en/rollback/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (97,8,'SET TRANSACTION','Syntax\n------\n\nSET [GLOBAL | SESSION] TRANSACTION\n transaction_property [, transaction_property] ...\n\ntransaction_property:\n ISOLATION LEVEL level\n | READ WRITE\n | READ ONLY\n\nlevel:\n REPEATABLE READ\n | READ COMMITTED\n | READ UNCOMMITTED\n | SERIALIZABLE\n\nDescription\n-----------\n\nThis statement sets the transaction isolation level or the transaction access\nmode globally, for the current session, or for the next transaction:\n\n* With the GLOBAL keyword, the statement sets the default\n transaction level globally for all subsequent sessions. Existing sessions are\n unaffected.\n* With the SESSION keyword, the statement sets the default\n transaction level for all subsequent transactions performed within the\n current session.\n* Without any SESSION or GLOBAL keyword,\n the statement sets the isolation level for the next (not started) transaction\n performed within the current session.\n\nA change to the global default isolation level requires the SUPER privilege.\nAny session is free to change its session isolation level (even in the middle\nof a transaction), or the isolation level for its next transaction.\n\nIsolation Level\n---------------\n\nTo set the global default isolation level at server startup, use the\n--transaction-isolation=level option on the command line or in an option file.\nValues of level for this option use dashes rather than spaces, so the\nallowable values are READ_UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, or\nSERIALIZABLE. For example, to set the default isolation level to REPEATABLE\nREAD, use these lines in the [mysqld] section of an option file:\n\n[mysqld]\ntransaction-isolation = REPEATABLE-READ\nTo determine the global and session transaction isolation levels at runtime,\ncheck the value of the tx_isolation system variable (note that the variable\nhas been renamed transaction_isolation from MariaDB 11.1.1, to match the\noption, and the old name deprecated).\n\nSELECT @@GLOBAL.tx_isolation, @@tx_isolation;\n\nFrom MariaDB 11.1.1:\n\nSELECT @@GLOBAL.transaction_isolation, @@transaction_isolation;\n\nInnoDB supports each of the translation isolation levels described here using\ndifferent locking strategies. The default level is REPEATABLE READ. For\nadditional information about InnoDB record-level locks and how it uses them to\nexecute various types of statements, see InnoDB Lock Modes, and\nhttp://dev.mysql.com/doc/refman/en/innodb-locks-set.html.\n\nIsolation Levels\n----------------\n\nThe following sections describe how MariaDB supports the different transaction\nlevels.\n\nREAD UNCOMMITTED\n----------------\n\nSELECT statements are performed in a non-locking fashion, but a possible\nearlier version of a row might be used. Thus, using this isolation level, such\nreads are not consistent. This is also called a \"dirty read.\" Otherwise, this\nisolation level works like READ COMMITTED.\n\nREAD COMMITTED\n--------------\n\nA somewhat Oracle-like isolation level with respect to consistent\n(non-locking) reads: Each consistent read, even within the same transaction,\nsets and reads its own fresh snapshot. See\nhttp://dev.mysql.com/doc/refman/en/innodb-consistent-read.html.\n\nFor locking reads (SELECT with FOR UPDATE or LOCK IN SHARE MODE), InnoDB locks\nonly index records, not the gaps before them, and thus allows the free\ninsertion of new records next to locked records. For UPDATE and DELETE\nstatements, locking depends on whether the statement uses a unique index with\na unique search condition (such as WHERE id = 100), or a range-type search\ncondition (such as WHERE id > 100). For a unique index with a unique search\ncondition, InnoDB locks only the index record found, not the gap before it.\nFor range-type searches, InnoDB locks the index range scanned, using gap locks\nor next-key (gap plus index-record) locks to block insertions by other\nsessions into the gaps covered by the range. This is necessary because\n\"phantom rows\" must be blocked for MySQL replication and recovery to work.\n\nNote: If the READ COMMITTED isolation level is used or the\ninnodb_locks_unsafe_for_binlog system variable is enabled, there is no InnoDB\ngap locking except for foreign-key constraint checking and duplicate-key\nchecking. Also, record locks for non-matching rows are released after MariaDB\nhas evaluated the WHERE condition.If you use READ COMMITTED or enable\ninnodb_locks_unsafe_for_binlog, you must use row-based binary logging.\n\nREPEATABLE READ\n---------------\n\nThis is the default isolation level for InnoDB. For consistent reads, there is\nan important difference from the READ COMMITTED isolation level: All\nconsistent reads within the same transaction read the snapshot established by\nthe first read. This convention means that if you issue several plain\n(non-locking) SELECT statements within the same transaction, these SELECT\nstatements are consistent also with respect to each other. See\nhttp://dev.mysql.com/doc/refman/en/innodb-consistent-read.html.\n\nFor locking reads (SELECT with FOR UPDATE or LOCK IN SHARE MODE), UPDATE, and\nDELETE statements, locking depends on whether the statement uses a unique\nindex with a unique search condition, or a range-type search condition. For a\nunique index with a unique search condition, InnoDB locks only the index\nrecord found, not the gap before it. For other search conditions, InnoDB locks\nthe index range scanned, using gap locks or next-key (gap plus index-record)\nlocks to block insertions by other sessions into the gaps covered by the range.\n\nThis is the minimum isolation level for non-distributed XA transactions.\n\nSERIALIZABLE\n------------\n\nThis level is like REPEATABLE READ, but InnoDB implicitly converts all plain\nSELECT statements to SELECT ... LOCK IN SHARE MODE if autocommit is disabled.\nIf autocommit is enabled, the SELECT is its own transaction. It therefore is\nknown to be read only and can be serialized if performed as a consistent\n(non-locking) read and need not block for other transactions. (This means that\nto force a plain SELECT to block if other transactions have modified the\nselected rows, you should disable autocommit.)\n\nDistributed XA transactions should always use this isolation level.\n\nAccess Mode\n-----------\n\nThe access mode specifies whether the transaction is allowed to write data or\nnot. By default, transactions are in READ WRITE mode (see the tx_read_only\nsystem variable). READ ONLY mode allows the storage engine to apply\noptimizations that cannot be used for transactions which write data. Note that\nunlike the global read_only mode, READ_ONLY ADMIN (and SUPER before MariaDB\n10.11.0) privilege doesn\'t allow writes and DDL statements on temporary tables\nare not allowed either.\n\nIt is not permitted to specify both READ WRITE and READ ONLY in the same\nstatement.\n\nREAD WRITE and READ ONLY can also be specified in the START TRANSACTION\nstatement, in which case the specified mode is only valid for one transaction.\n\nExamples\n--------\n\nSET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;\n\nAttempting to set the isolation level within an existing transaction without\nspecifying GLOBAL or SESSION.\n\nSTART TRANSACTION;\n\nSET TRANSACTION ISOLATION LEVEL SERIALIZABLE;\nERROR 1568 (25001): Transaction characteristics can\'t be changed while a\ntransaction is in progress\n\nURL: https://mariadb.com/kb/en/set-transaction/','','https://mariadb.com/kb/en/set-transaction/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (98,8,'LOCK TABLES','Syntax\n------\n\nLOCK TABLE[S]\n tbl_name [[AS] alias] lock_type\n [, tbl_name [[AS] alias] lock_type] ...\n [WAIT n|NOWAIT]\n\nlock_type:\n READ [LOCAL]\n | [LOW_PRIORITY] WRITE\n | WRITE CONCURRENT\n\nUNLOCK TABLES\n\nDescription\n-----------\n\nThe lock_type can be one of:\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| READ | Read lock, no writes allowed |\n+---------------------------+------------------------------------------------+\n| READ LOCAL | Read lock, but allow concurrent inserts |\n+---------------------------+------------------------------------------------+\n| WRITE | Exclusive write lock. No other connections |\n| | can read or write to this table |\n+---------------------------+------------------------------------------------+\n| LOW_PRIORITY WRITE | Exclusive write lock, but allow new read |\n| | locks on the table until we get the write |\n| | lock. |\n+---------------------------+------------------------------------------------+\n| WRITE CONCURRENT | Exclusive write lock, but allow READ LOCAL |\n| | locks to the table. |\n+---------------------------+------------------------------------------------+\n\nMariaDB enables client sessions to acquire table locks explicitly for the\npurpose of cooperating with other sessions for access to tables, or to prevent\nother sessions from modifying tables during periods when a session requires\nexclusive access to them. A session can acquire or release locks only for\nitself. One session cannot acquire locks for another session or release locks\nheld by another session.\n\nLocks may be used to emulate transactions or to get more speed when updating\ntables.\n\nLOCK TABLES explicitly acquires table locks for the current client session.\nTable locks can be acquired for base tables or views. To use LOCK TABLES, you\nmust have the LOCK TABLES privilege, and the SELECT privilege for each object\nto be locked. See GRANT\n\nFor view locking, LOCK TABLES adds all base tables used in the view to the set\nof tables to be locked and locks them automatically. If you lock a table\nexplicitly with LOCK TABLES, any tables used in triggers are also locked\nimplicitly, as described in Triggers and Implicit Locks.\n\nUNLOCK TABLES explicitly releases any table locks held by the current session.\n\nMariaDB starting with 10.3.0\n----------------------------\n\nWAIT/NOWAIT\n-----------\n\nSet the lock wait timeout. See WAIT and NOWAIT.\n\nLimitations\n-----------\n\n* LOCK TABLES doesn\'t work when using Galera cluster. You may experience\ncrashes or locks when used with Galera.\n* LOCK TABLES works on XtraDB/InnoDB tables only if the innodb_table_locks\nsystem variable is set to 1 (the default) and autocommit is set to 0 (1 is\ndefault). Please note that no error message will be returned on LOCK TABLES\nwith innodb_table_locks = 0.\n* LOCK TABLES implicitly commits the active transaction, if any. Also,\nstarting a transaction always releases all table locks acquired with LOCK\nTABLES. This means that there is no way to have table locks and an active\ntransaction at the same time. The only exceptions are the transactions in\nautocommit mode. To preserve the data integrity between transactional and\nnon-transactional tables, the GET_LOCK() function can be used.\n* When using LOCK TABLES on a TEMPORARY table, it will always be locked with a\nWRITE lock.\n* While a connection holds an explicit read lock on a table, it cannot modify\nit. If you try, the following error will be produced:\n\nERROR 1099 (HY000): Table \'tab_name\' was locked with a READ lock and can\'t be\nupdated\n\n* While a connection holds an explicit lock on a table, it cannot access a\nnon-locked table. If you try, the following error will be produced:\n\nERROR 1100 (HY000): Table \'tab_name\' was not locked with LOCK TABLES\n\n* While a connection holds an explicit lock on a table, it cannot issue the\nfollowing: INSERT DELAYED, CREATE TABLE, CREATE TABLE ... LIKE, and DDL\nstatements involving stored programs and views (except for triggers). If you\ntry, the following error will be produced:\n\nERROR 1192 (HY000): Can\'t execute the given command because you have active\nlocked tables or an active transaction\n\n* LOCK TABLES can not be used in stored routines - if you try, the following\nerror will be produced on creation:\n\nERROR 1314 (0A000): LOCK is not allowed in stored procedures\n\nURL: https://mariadb.com/kb/en/lock-tables/','','https://mariadb.com/kb/en/lock-tables/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (99,8,'SAVEPOINT','Syntax\n------\n\nSAVEPOINT identifier\nROLLBACK [WORK] TO [SAVEPOINT] identifier\nRELEASE SAVEPOINT identifier\n\nDescription\n-----------\n\nInnoDB supports the SQL statements SAVEPOINT, ROLLBACK TO SAVEPOINT, RELEASE\nSAVEPOINT and the optional WORK keyword for ROLLBACK.\n\nEach savepoint must have a legal MariaDB identifier. A savepoint is a named\nsub-transaction.\n\nNormally ROLLBACK undoes the changes performed by the whole transaction. When\nused with the TO clause, it undoes the changes performed after the specified\nsavepoint, and erases all subsequent savepoints. However, all locks that have\nbeen acquired after the save point will survive. RELEASE SAVEPOINT does not\nrollback or commit any changes, but removes the specified savepoint.\n\nWhen the execution of a trigger or a stored function begins, it is not\npossible to use statements which reference a savepoint which was defined from\nout of that stored program.\n\nWhen a COMMIT (including implicit commits) or a ROLLBACK statement (with no TO\nclause) is performed, they act on the whole transaction, and all savepoints\nare removed.\n\nErrors\n------\n\nIf COMMIT or ROLLBACK is issued and no transaction was started, no error is\nreported.\n\nIf SAVEPOINT is issued and no transaction was started, no error is reported\nbut no savepoint is created. When ROLLBACK TO SAVEPOINT or RELEASE SAVEPOINT\nis called for a savepoint that does not exist, an error like this is issued:\n\nERROR 1305 (42000): SAVEPOINT svp_name does not exist\n\nURL: https://mariadb.com/kb/en/savepoint/','','https://mariadb.com/kb/en/savepoint/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (100,8,'Metadata Locking','MariaDB supports metadata locking. This means that when a transaction\n(including XA transactions) uses a table, it locks its metadata until the end\nof transaction. Non-transactional tables are also locked, as well as views and\nobjects which are related to locked tables/views (stored functions, triggers,\netc). When a connection tries to use a DDL statement (like an ALTER TABLE)\nwhich modifies a table that is locked, that connection is queued, and has to\nwait until it\'s unlocked. Using savepoints and performing a partial rollback\ndoes not release metadata locks.\n\nLOCK TABLES ... WRITE are also queued. Some wrong statements which produce an\nerror may not need to wait for the lock to be freed.\n\nThe metadata lock\'s timeout is determined by the value of the\nlock_wait_timeout server system variable (in seconds). However, note that its\ndefault value is 31536000 (1 year, MariaDB <= 10.2.3), or 86400 (1 day,\nMariaDB >= 10.2.4). If this timeout is exceeded, the following error is\nreturned:\n\nERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction\n\nIf the metadata_lock_info plugin is installed, the Information Schema\nmetadata_lock_info table stores information about existing metadata locks.\n\nMariaDB starting with 10.5.2\n----------------------------\nFrom MariaDB 10.5, the Performance Schema metadata_locks table contains\nmetadata lock information.\n\nExample\n-------\n\nLet\'s use the following MEMORY (non-transactional) table:\n\nCREATE TABLE t (a INT) ENGINE = MEMORY;\n\nConnection 1 starts a transaction, and INSERTs a row into t:\n\nSTART TRANSACTION;\n\nINSERT INTO t SET a=1;\n\nt\'s metadata is now locked by connection 1. Connection 2 tries to alter t, but\nhas to wait:\n\nALTER TABLE t ADD COLUMN b INT;\n\nConnection 2\'s prompt is blocked now.\n\nNow connection 1 ends the transaction:\n\nCOMMIT;\n\n...and connection 2 finally gets the output of its command:\n\nQuery OK, 1 row affected (35.23 sec)\nRecords: 1 Duplicates: 0 Warnings: 0\n\nURL: https://mariadb.com/kb/en/metadata-locking/','','https://mariadb.com/kb/en/metadata-locking/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (101,8,'Transaction Timeouts','MariaDB has always had the wait_timeout and interactive_timeout settings,\nwhich close connections after a certain period of inactivity.\n\nHowever, these are by default set to a long wait period. In situations where\ntransactions may be started, but not committed or rolled back, more granular\ncontrol and a shorter timeout may be desirable so as to avoid locks being held\nfor too long.\n\nMariaDB 10.3 introduced three new variables to handle this situation.\n\n* idle_transaction_timeout (all transactions)\n* idle_write_transaction_timeout (write transactions - called\nidle_readwrite_transaction_timeout until MariaDB 10.3.2)\n* idle_readonly_transaction_timeout (read transactions)\n\nThese accept a time in seconds to time out, by closing the connection,\ntransactions that are idle for longer than this period. By default all are set\nto zero, or no timeout.\n\nidle_transaction_timeout affects all transactions,\nidle_write_transaction_timeout affects write transactions only and\nidle_readonly_transaction_timeout affects read transactions only. The latter\ntwo variables work independently. However, if either is set along with\nidle_transaction_timeout, the settings for idle_write_transaction_timeout or\nidle_readonly_transaction_timeout will take precedence.\n\nExamples\n--------\n\nSET SESSION idle_transaction_timeout=2;\nBEGIN;\nSELECT * FROM t;\nEmpty set (0.000 sec)\n## wait 3 seconds\nSELECT * FROM t;\nERROR 2006 (HY000): MySQL server has gone away\n\nSET SESSION idle_write_transaction_timeout=2;\nBEGIN;\nSELECT * FROM t;\nEmpty set (0.000 sec)\n## wait 3 seconds\nSELECT * FROM t;\nEmpty set (0.000 sec)\nINSERT INTO t VALUES(1);\n## wait 3 seconds\nSELECT * FROM t;\nERROR 2006 (HY000): MySQL server has gone away\n\nSET SESSION idle_transaction_timeout=2, SESSION\nidle_readonly_transaction_timeout=10;\nBEGIN;\nSELECT * FROM t;\nEmpty set (0.000 sec)\n ## wait 3 seconds\nSELECT * FROM t;\nEmpty set (0.000 sec)\n## wait 11 seconds\nSELECT * FROM t;\nERROR 2006 (HY000): MySQL server has gone away\n\nURL: https://mariadb.com/kb/en/transaction-timeouts/','','https://mariadb.com/kb/en/transaction-timeouts/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (102,8,'UNLOCK TABLES','Syntax\n------\n\nUNLOCK TABLES\n\nDescription\n-----------\n\nUNLOCK TABLES explicitly releases any table locks held by the current session.\nSee LOCK TABLES for more information.\n\nIn addition to releasing table locks acquired by the LOCK TABLES statement,\nthe UNLOCK TABLES statement also releases the global read lock acquired by the\nFLUSH TABLES WITH READ LOCK statement. The FLUSH TABLES WITH READ LOCK\nstatement is very useful for performing backups. See FLUSH for more\ninformation about FLUSH TABLES WITH READ LOCK.\n\nURL: https://mariadb.com/kb/en/transactions-unlock-tables/','','https://mariadb.com/kb/en/transactions-unlock-tables/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (103,8,'WAIT and NOWAIT','Extended syntax so that it is possible to set innodb_lock_wait_timeout and\nlock_wait_timeout for the following statements:\n\nSyntax\n------\n\nALTER TABLE tbl_name [WAIT n|NOWAIT] ...\nCREATE ... INDEX ON tbl_name (index_col_name, ...) [WAIT n|NOWAIT] ...\nDROP INDEX ... [WAIT n|NOWAIT]\nDROP TABLE tbl_name [WAIT n|NOWAIT] ...\nLOCK TABLE ... [WAIT n|NOWAIT]\nOPTIMIZE TABLE tbl_name [WAIT n|NOWAIT]\nRENAME TABLE tbl_name [WAIT n|NOWAIT] ...\nSELECT ... FOR UPDATE [WAIT n|NOWAIT]\nSELECT ... LOCK IN SHARE MODE [WAIT n|NOWAIT]\nTRUNCATE TABLE tbl_name [WAIT n|NOWAIT]\n\nDescription\n-----------\n\nThe lock wait timeout can be explicitly set in the statement by using either\nWAIT n (to set the wait in seconds) or NOWAIT, in which case the statement\nwill immediately fail if the lock cannot be obtained. WAIT 0 is equivalent to\nNOWAIT.\n\nURL: https://mariadb.com/kb/en/wait-and-nowait/','','https://mariadb.com/kb/en/wait-and-nowait/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (104,8,'XA Transactions','Overview\n--------\n\nThe MariaDB XA implementation is based on the X/Open CAE document Distributed\nTransaction Processing: The XA Specification. This document is published by\nThe Open Group and available at\nhttp://www.opengroup.org/public/pubs/catalog/c193.htm.\n\nXA transactions are designed to allow distributed transactions, where a\ntransaction manager (the application) controls a transaction which involves\nmultiple resources. Such resources are usually DBMSs, but could be resources\nof any type. The whole set of required transactional operations is called a\nglobal transaction. Each subset of operations which involve a single resource\nis called a local transaction. XA used a 2-phases commit (2PC). With the first\ncommit, the transaction manager tells each resource to prepare an effective\ncommit, and waits for a confirm message. The changes are not still made\neffective at this point. If any of the resources encountered an error, the\ntransaction manager will rollback the global transaction. If all resources\ncommunicate that the first commit is successful, the transaction manager can\nrequire a second commit, which makes the changes effective.\n\nIn MariaDB, XA transactions can only be used with storage engines that support\nthem. At least InnoDB, TokuDB, SPIDER and MyRocks support them. For InnoDB,\nuntil MariaDB 10.2, XA transactions can be disabled by setting the\ninnodb_support_xa server system variable to 0. From MariaDB 10.3, XA\ntransactions are always supported.\n\nLike regular transactions, XA transactions create metadata locks on accessed\ntables.\n\nXA transactions require REPEATABLE READ as a minimum isolation level. However,\ndistributed transactions should always use SERIALIZABLE.\n\nTrying to start more than one XA transaction at the same time produces a 1400\nerror (SQLSTATE \'XAE09\'). The same error is produced when attempting to start\nan XA transaction while a regular transaction is in effect. Trying to start a\nregular transaction while an XA transaction is in effect produces a 1399 error\n(SQLSTATE \'XAE07\').\n\nThe statements that cause an implicit COMMIT for regular transactions produce\na 1400 error (SQLSTATE \'XAE09\') if a XA transaction is in effect.\n\nInternal XA vs External XA\n--------------------------\n\nXA transactions are an overloaded term in MariaDB. If a storage engine is\nXA-capable, it can mean one or both of these:\n\n* It supports MariaDB\'s internal two-phase commit API. This is transparent to\nthe user. Sometimes this is called \"internal XA\", since MariaDB\'s internal\ntransaction coordinator log can handle coordinating these transactions.\n\n* It supports XA transactions, with the XA START, XA PREPARE, XA COMMIT, etc.\nstatements. Sometimes this is called \"external XA\", since it requires the use\nof an external transaction coordinator to use this feature properly.\n\nTransaction Coordinator Log\n---------------------------\n\nIf you have two or more XA-capable storage engines enabled, then a transaction\ncoordinator log must be available.\n\nThere are currently two implementations of the transaction coordinator log:\n\n* Binary log-based transaction coordinator log\n* Memory-mapped file-based transaction coordinator log\n\nIf the binary log is enabled on a server, then the server will use the binary\nlog-based transaction coordinator log. Otherwise, it will use the\nmemory-mapped file-based transaction coordinator log.\n\nSee Transaction Coordinator Log for more information.\n\nSyntax\n------\n\nXA {START|BEGIN} xid [JOIN|RESUME]\n\nXA END xid [SUSPEND [FOR MIGRATE]]\n\nXA PREPARE xid\n\nXA COMMIT xid [ONE PHASE]\n\nXA ROLLBACK xid\n\nXA RECOVER [FORMAT=[\'RAW\'|\'SQL\']]\n\nxid: gtrid [, bqual [, formatID ]]\n\nThe interface to XA transactions is a set of SQL statements starting with XA.\nEach statement changes a transaction\'s state, determining which actions it can\nperform. A transaction which does not exist is in the NON-EXISTING state.\n\nXA START (or BEGIN) starts a transaction and defines its xid (a transaction\nidentifier). The JOIN or RESUME keywords have no effect. The new transaction\nwill be in ACTIVE state.\n\nThe xid can have 3 components, though only the first one is mandatory. gtrid\nis a quoted string representing a global transaction identifier. bqual is a\nquoted string representing a local transaction identifier. formatID is an\nunsigned integer indicating the format used for the first two components; if\nnot specified, defaults to 1. MariaDB does not interpret in any way these\ncomponents, and only uses them to identify a transaction. xids of transactions\nin effect must be unique.\n\nXA END declares that the specified ACTIVE transaction is finished and it\nchanges its state to IDLE. SUSPEND [FOR MIGRATE] has no effect.\n\nXA PREPARE prepares an IDLE transaction for commit, changing its state to\nPREPARED. This is the first commit.\n\nXA COMMIT definitely commits and terminates a transaction which has already\nbeen PREPARED. If the ONE PHASE clause is specified, this statements performs\na 1-phase commit on an IDLE transaction.\n\nXA ROLLBACK rolls back and terminates an IDLE or PREPARED transaction.\n\nXA RECOVER shows information about all PREPARED transactions.\n\nWhen trying to execute an operation which is not allowed for the transaction\'s\ncurrent state, an error is produced:\n\nXA COMMIT \'test\' ONE PHASE;\nERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global\ntransaction is in the ACTIVE state\n\nXA COMMIT \'test2\';\nERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global\ntransaction is in the NON-EXISTING state\n\nXA RECOVER\n----------\n\nThe XA RECOVER statement shows information about all transactions which are in\nthe PREPARED state. It does not matter which connection created the\ntransaction: if it has been PREPARED, it appears. But this does not mean that\na connection can commit or rollback a transaction which was started by another\nconnection. Note that transactions using a 1-phase commit are never in the\nPREPARED state, so they cannot be shown by XA RECOVER.\n\nXA RECOVER produces four columns:\n\nXA RECOVER;\n+----------+--------------+--------------+------+\n| formatID | gtrid_length | bqual_length | data |\n+----------+--------------+--------------+------+\n| 1 | 4 | 0 | test |\n+----------+--------------+--------------+------+\n\nMariaDB starting with 10.3.3\n----------------------------\nYou can use XA RECOVER FORMAT=\'SQL\' to get the data in a human readable form\nthat can be directly copy-pasted into XA COMMIT or XA ROLLBACK. This is\nparticularly useful for binary xid generated by some transaction coordinators.\n\nformatID is the formatID part of xid.\n\ndata are the gtrid and bqual parts of xid, concatenated.\n\ngtrid_length and bqual_length are the lengths of gtrid and bqual, respectevely.\n\nExamples\n--------\n\n2-phases commit:\n\nXA START \'test\';\n\nINSERT INTO t VALUES (1,2);\n\nXA END \'test\';\n\nXA PREPARE \'test\';\n\nXA COMMIT \'test\';\n\n1-phase commit:\n\nXA START \'test\';\n\nINSERT INTO t VALUES (1,2);\n\nXA END \'test\';\n\nXA COMMIT \'test\' ONE PHASE;\n\nHuman-readable:\n\nxa start \'12\\r34\\t67\\v78\', \'abc\\ndef\', 3;\n\ninsert t1 values (40);\n\nxa end \'12\\r34\\t67\\v78\', \'abc\\ndef\', 3;\n\nxa prepare \'12\\r34\\t67\\v78\', \'abc\\ndef\', 3;\n\nxa recover format=\'RAW\';\n+----------+--------------+--------------+--------------------+\n| formatID | gtrid_length | bqual_length | data |\n+----------+--------------+--------------+--------------------+\n34 67v78abc 11 | 7 | 12\ndef |\n+----------+--------------+--------------+--------------------+\n\nxa recover format=\'SQL\';\n+----------+--------------+--------------+-------------------------------------\n---------+\n| formatID | gtrid_length | bqual_length | data \n |\n+----------+--------------+--------------+-------------------------------------\n---------+\n| 3 | 11 | 7 |\nX\'31320d3334093637763738\',X\'6162630a646566\',3 |\n+----------+--------------+--------------+-------------------------------------\n---------+\n\nxa rollback X\'31320d3334093637763738\',X\'6162630a646566\',3;\n\nKnown Issues\n------------\n\nMariaDB Galera Cluster\n----------------------\n\nMariaDB Galera Cluster does not support XA transactions.\n\nHowever, MariaDB Galera Cluster builds include a built-in plugin called wsrep.\nPrior to MariaDB 10.4.3, this plugin was internally considered an XA-capable\nstorage engine. Consequently, these MariaDB Galera Cluster builds have\nmultiple XA-capable storage engines by default, even if the only \"real\"\nstorage engine that supports external XA transactions enabled on these builds\nby default is InnoDB. Therefore, when using one these builds MariaDB would be\nforced to use a transaction coordinator log by default, which could have\nperformance implications.\n\nSee Transaction Coordinator Log Overview: MariaDB Galera Cluster for more\ninformation.\n\nURL: https://mariadb.com/kb/en/xa-transactions/','','https://mariadb.com/kb/en/xa-transactions/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (105,10,'CREATE USER','Syntax\n------\n\nCREATE [OR REPLACE] USER [IF NOT EXISTS] \n user_specification [,user_specification ...] \n [REQUIRE {NONE | tls_option [[AND] tls_option ...] }]\n [WITH resource_option [resource_option ...] ]\n [lock_option] [password_option]\n\nuser_specification:\n username [authentication_option]\n\nauthentication_option:\n IDENTIFIED BY \'password\'\n | IDENTIFIED BY PASSWORD \'password_hash\'\n | IDENTIFIED {VIA|WITH} authentication_rule [OR authentication_rule ...]\n\nauthentication_rule:\n authentication_plugin\n | authentication_plugin {USING|AS} \'authentication_string\'\n | authentication_plugin {USING|AS} PASSWORD(\'password\')\n\ntls_option:\n SSL\n | X509\n | CIPHER \'cipher\'\n | ISSUER \'issuer\'\n | SUBJECT \'subject\'\n\nresource_option:\n MAX_QUERIES_PER_HOUR count\n | MAX_UPDATES_PER_HOUR count\n | MAX_CONNECTIONS_PER_HOUR count\n | MAX_USER_CONNECTIONS count\n | MAX_STATEMENT_TIME time\n\npassword_option:\n PASSWORD EXPIRE\n | PASSWORD EXPIRE DEFAULT\n | PASSWORD EXPIRE NEVER\n | PASSWORD EXPIRE INTERVAL N DAY\n\nlock_option:\n ACCOUNT LOCK\n | ACCOUNT UNLOCK\n}\n\nDescription\n-----------\n\nThe CREATE USER statement creates new MariaDB accounts. To use it, you must\nhave the global CREATE USER privilege or the INSERT privilege for the mysql\ndatabase. For each account, CREATE USER creates a new row in mysql.user (until\nMariaDB 10.3 this is a table, from MariaDB 10.4 it\'s a view) or\nmysql.global_priv_table (from MariaDB 10.4) that has no privileges.\n\nIf any of the specified accounts, or any permissions for the specified\naccounts, already exist, then the server returns ERROR 1396 (HY000). If an\nerror occurs, CREATE USER will still create the accounts that do not result in\nan error. Only one error is produced for all users which have not been created:\n\nERROR 1396 (HY000): \n Operation CREATE USER failed for \'u1\'@\'%\',\'u2\'@\'%\'\n\nCREATE USER, DROP USER, CREATE ROLE, and DROP ROLE all produce the same error\ncode when they fail.\n\nSee Account Names below for details on how account names are specified.\n\nOR REPLACE\n----------\n\nIf the optional OR REPLACE clause is used, it is basically a shortcut for:\n\nDROP USER IF EXISTS name;\nCREATE USER name ...;\n\nFor example:\n\nCREATE USER foo2@test IDENTIFIED BY \'password\';\nERROR 1396 (HY000): Operation CREATE USER failed for \'foo2\'@\'test\'\n\nCREATE OR REPLACE USER foo2@test IDENTIFIED BY \'password\';\nQuery OK, 0 rows affected (0.00 sec)\n\nIF NOT EXISTS\n-------------\n\nWhen the IF NOT EXISTS clause is used, MariaDB will return a warning instead\nof an error if the specified user already exists.\n\nFor example:\n\nCREATE USER foo2@test IDENTIFIED BY \'password\';\nERROR 1396 (HY000): Operation CREATE USER failed for \'foo2\'@\'test\'\n\nCREATE USER IF NOT EXISTS foo2@test IDENTIFIED BY \'password\';\nQuery OK, 0 rows affected, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+-------+------+----------------------------------------------------+\n| Level | Code | Message |\n+-------+------+----------------------------------------------------+\n| Note | 1973 | Can\'t create user \'foo2\'@\'test\'; it already exists |\n+-------+------+----------------------------------------------------+\n\nAuthentication Options\n----------------------\n\nIDENTIFIED BY \'password\'\n------------------------\n\nThe optional IDENTIFIED BY clause can be used to provide an account with a\npassword. The password should be specified in plain text. It will be hashed by\nthe PASSWORD function prior to being stored in the\nmysql.user/mysql.global_priv_table table.\n\nFor example, if our password is mariadb, then we can create the user with:\n\nCREATE USER foo2@test IDENTIFIED BY \'mariadb\';\n\nIf you do not specify a password with the IDENTIFIED BY clause, the user will\nbe able to connect without a password. A blank password is not a wildcard to\nmatch any password. The user must connect without providing a password if no\npassword is set.\n\nThe only authentication plugins that this clause supports are\nmysql_native_password and mysql_old_password.\n\nIDENTIFIED BY PASSWORD \'password_hash\'\n--------------------------------------\n\nThe optional IDENTIFIED BY PASSWORD clause can be used to provide an account\nwith a password that has already been hashed. The password should be specified\nas a hash that was provided by the PASSWORD function. It will be stored in the\nmysql.user/mysql.global_priv_table table as-is.\n\nFor example, if our password is mariadb, then we can find the hash with:\n\nSELECT PASSWORD(\'mariadb\');\n+-------------------------------------------+\n| PASSWORD(\'mariadb\') |\n+-------------------------------------------+\n| *54958E764CE10E50764C2EECBB71D01F08549980 |\n+-------------------------------------------+\n1 row in set (0.00 sec)\n\nAnd then we can create a user with the hash:\n\nCREATE USER foo2@test IDENTIFIED BY PASSWORD\n\'*54958E764CE10E50764C2EECBB71D01F08549980\';\n\nIf you do not specify a password with the IDENTIFIED BY clause, the user will\nbe able to connect without a password. A blank password is not a wildcard to\nmatch any password. The user must connect without providing a password if no\npassword is set.\n\nThe only authentication plugins that this clause supports are\nmysql_native_password and mysql_old_password.\n\nIDENTIFIED {VIA|WITH} authentication_plugin\n-------------------------------------------\n\nThe optional IDENTIFIED VIA authentication_plugin allows you to specify that\nthe account should be authenticated by a specific authentication plugin. The\nplugin name must be an active authentication plugin as per SHOW PLUGINS. If it\ndoesn\'t show up in that output, then you will need to install it with INSTALL\nPLUGIN or INSTALL SONAME.\n\nFor example, this could be used with the PAM authentication plugin:\n\nCREATE USER foo2@test IDENTIFIED VIA pam;\n\nSome authentication plugins allow additional arguments to be specified after a\nUSING or AS keyword. For example, the PAM authentication plugin accepts a\nservice name:\n\nCREATE USER foo2@test IDENTIFIED VIA pam USING \'mariadb\';\n\nThe exact meaning of the additional argument would depend on the specific\nauthentication plugin.\n\nMariaDB starting with 10.4.0\n----------------------------\nThe USING or AS keyword can also be used to provide a plain-text password to a\nplugin if it\'s provided as an argument to the PASSWORD() function. This is\nonly valid for authentication plugins that have implemented a hook for the\nPASSWORD() function. For example, the ed25519 authentication plugin supports\nthis:\n\nCREATE USER safe@\'%\' IDENTIFIED VIA ed25519 USING PASSWORD(\'secret\');\n\nMariaDB starting with 10.4.3\n----------------------------\nOne can specify many authentication plugins, they all work as alternatives\nways of authenticating a user:\n\nCREATE USER safe@\'%\' IDENTIFIED VIA ed25519 USING PASSWORD(\'secret\') OR\nunix_socket;\n\nBy default, when you create a user without specifying an authentication\nplugin, MariaDB uses the mysql_native_password plugin.\n\nTLS Options\n-----------\n\nBy default, MariaDB transmits data between the server and clients without\nencrypting it. This is generally acceptable when the server and client run on\nthe same host or in networks where security is guaranteed through other means.\nHowever, in cases where the server and client exist on separate networks or\nthey are in a high-risk network, the lack of encryption does introduce\nsecurity concerns as a malicious actor could potentially eavesdrop on the\ntraffic as it is sent over the network between them.\n\nTo mitigate this concern, MariaDB allows you to encrypt data in transit\nbetween the server and clients using the Transport Layer Security (TLS)\nprotocol. TLS was formerly known as Secure Socket Layer (SSL), but strictly\nspeaking the SSL protocol is a predecessor to TLS and, that version of the\nprotocol is now considered insecure. The documentation still uses the term SSL\noften and for compatibility reasons TLS-related server system and status\nvariables still use the prefix ssl_, but internally, MariaDB only supports its\nsecure successors.\n\nSee Secure Connections Overview for more information about how to determine\nwhether your MariaDB server has TLS support.\n\nYou can set certain TLS-related restrictions for specific user accounts. For\ninstance, you might use this with user accounts that require access to\nsensitive data while sending it across networks that you do not control. These\nrestrictions can be enabled for a user account with the CREATE USER, ALTER\nUSER, or GRANT statements. The following options are available:\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| REQUIRE NONE | TLS is not required for this account, but can |\n| | still be used. |\n+---------------------------+------------------------------------------------+\n| REQUIRE SSL | The account must use TLS, but no valid X509 |\n| | certificate is required. This option cannot |\n| | be combined with other TLS options. |\n+---------------------------+------------------------------------------------+\n| REQUIRE X509 | The account must use TLS and must have a |\n| | valid X509 certificate. This option implies |\n| | REQUIRE SSL. This option cannot be combined |\n| | with other TLS options. |\n+---------------------------+------------------------------------------------+\n| REQUIRE ISSUER \'issuer\' | The account must use TLS and must have a |\n| | valid X509 certificate. Also, the Certificate |\n| | Authority must be the one specified via the |\n| | string issuer. This option implies REQUIRE |\n| | X509. This option can be combined with the |\n| | SUBJECT, and CIPHER options in any order. |\n+---------------------------+------------------------------------------------+\n| REQUIRE SUBJECT \'subject\' | The account must use TLS and must have a |\n| | valid X509 certificate. Also, the |\n| | certificate\'s Subject must be the one |\n| | specified via the string subject. This option |\n| | implies REQUIRE X509. This option can be |\n| | combined with the ISSUER, and CIPHER options |\n| | in any order. |\n+---------------------------+------------------------------------------------+\n| REQUIRE CIPHER \'cipher\' | The account must use TLS, but no valid X509 |\n| | certificate is required. Also, the encryption |\n| | used for the connection must use a specific |\n| | cipher method specified in the string cipher. |\n| | This option implies REQUIRE SSL. This option |\n| | can be combined with the ISSUER, and SUBJECT |\n| | options in any order. |\n+---------------------------+------------------------------------------------+\n\nThe REQUIRE keyword must be used only once for all specified options, and the\nAND keyword can be used to separate individual options, but it is not required.\n\nFor example, you can create a user account that requires these TLS options\nwith the following:\n\nCREATE USER \'alice\'@\'%\'\n REQUIRE SUBJECT \'/CN=alice/O=My Dom, Inc./C=US/ST=Oregon/L=Portland\'\n AND ISSUER \'/C=FI/ST=Somewhere/L=City/ O=Some Company/CN=Peter\nParker/emailAddress=p.parker@marvel.com\'\n AND CIPHER \'SHA-DES-CBC3-EDH-RSA\';\n\nIf any of these options are set for a specific user account, then any client\nwho tries to connect with that user account will have to be configured to\nconnect with TLS.\n\nSee Securing Connections for Client and Server for information on how to\nenable TLS on the client and server.\n\nResource Limit Options\n----------------------\n\nIt is possible to set per-account limits for certain server resources. The\nfollowing table shows the values that can be set per account:\n\n+--------------------------------------+--------------------------------------+\n| Limit Type | Decription |\n+--------------------------------------+--------------------------------------+\n| MAX_QUERIES_PER_HOUR | Number of statements that the |\n| | account can issue per hour |\n| | (including updates) |\n+--------------------------------------+--------------------------------------+\n| MAX_UPDATES_PER_HOUR | Number of updates (not queries) |\n| | that the account can issue per hour |\n+--------------------------------------+--------------------------------------+\n| MAX_CONNECTIONS_PER_HOUR | Number of connections that the |\n| | account can start per hour |\n+--------------------------------------+--------------------------------------+\n| MAX_USER_CONNECTIONS | Number of simultaneous connections |\n| | that can be accepted from the same |\n| | account; if it is 0, |\n| | max_connections will be used |\n| | instead; if max_connections is 0, |\n| | there is no limit for this |\n| | account\'s simultaneous connections. |\n+--------------------------------------+--------------------------------------+\n| MAX_STATEMENT_TIME | Timeout, in seconds, for statements |','','https://mariadb.com/kb/en/create-user/'); +update help_topic set description = CONCAT(description, '\n| | executed by the user. See also |\n| | Aborting Statements that Exceed a |\n| | Certain Time to Execute. |\n+--------------------------------------+--------------------------------------+\n\nIf any of these limits are set to 0, then there is no limit for that resource\nfor that user.\n\nHere is an example showing how to create a user with resource limits:\n\nCREATE USER \'someone\'@\'localhost\' WITH\n MAX_USER_CONNECTIONS 10\n MAX_QUERIES_PER_HOUR 200;\n\nThe resources are tracked per account, which means \'user\'@\'server\'; not per\nuser name or per connection.\n\nThe count can be reset for all users using FLUSH USER_RESOURCES, FLUSH\nPRIVILEGES or mariadb-admin reload.\n\nPer account resource limits are stored in the user table, in the mysql\ndatabase. Columns used for resources limits are named max_questions,\nmax_updates, max_connections (for MAX_CONNECTIONS_PER_HOUR), and\nmax_user_connections (for MAX_USER_CONNECTIONS).\n\nAccount Names\n-------------\n\nAccount names have both a user name component and a host name component, and\nare specified as \'user_name\'@\'host_name\'.\n\nThe user name and host name may be unquoted, quoted as strings using double\nquotes (\") or single quotes (\'), or quoted as identifiers using backticks (`).\nYou must use quotes when using special characters (such as a hyphen) or\nwildcard characters. If you quote, you must quote the user name and host name\nseparately (for example \'user_name\'@\'host_name\').\n\nHost Name Component\n-------------------\n\nIf the host name is not provided, it is assumed to be \'%\'.\n\nHost names may contain the wildcard characters % and _. They are matched as if\nby the LIKE clause. If you need to use a wildcard character literally (for\nexample, to match a domain name with an underscore), prefix the character with\na backslash. See LIKE for more information on escaping wildcard characters.\n\nHost name matches are case-insensitive. Host names can match either domain\nnames or IP addresses. Use \'localhost\' as the host name to allow only local\nclient connections. On Linux, the loopback interface (127.0.0.1) will not\nmatch \'localhost\' as it is not considered a local connection: this means that\nonly connections via UNIX-domain sockets will match \'localhost\'.\n\nYou can use a netmask to match a range of IP addresses using \'base_ip/netmask\'\nas the host name. A user with an IP address ip_addr will be allowed to connect\nif the following condition is true:\n\nip_addr & netmask = base_ip\n\nFor example, given a user:\n\nCREATE USER \'maria\'@\'247.150.130.0/255.255.255.0\';\n\nthe IP addresses satisfying this condition range from 247.150.130.0 to\n247.150.130.255.\n\nUsing 255.255.255.255 is equivalent to not using a netmask at all. Netmasks\ncannot be used for IPv6 addresses.\n\nNote that the credentials added when creating a user with the \'%\' wildcard\nhost will not grant access in all cases. For example, some systems come with\nan anonymous localhost user, and when connecting from localhost this will take\nprecedence.\n\nBefore MariaDB 10.6, the host name component could be up to 60 characters in\nlength. Starting from MariaDB 10.6, it can be up to 255 characters.\n\nUser Name Component\n-------------------\n\nUser names must match exactly, including case. A user name that is empty is\nknown as an anonymous account and is allowed to match a login attempt with any\nuser name component. These are described more in the next section.\n\nFor valid identifiers to use as user names, see Identifier Names.\n\nIt is possible for more than one account to match when a user connects.\nMariaDB selects the first matching account after sorting according to the\nfollowing criteria:\n\n* Accounts with an exact host name are sorted before accounts using a wildcard\nin the\nhost name. Host names using a netmask are considered to be exact for sorting.\n* Accounts with a wildcard in the host name are sorted according to the\nposition of\nthe first wildcard character. Those with a wildcard character later in the\nhost name\nsort before those with a wildcard character earlier in the host name.\n* Accounts with a non-empty user name sort before accounts with an empty user\nname.\n* Accounts with an empty user name are sorted last. As mentioned previously,\nthese are known as anonymous accounts. These are described more in the next\nsection.\n\nThe following table shows a list of example account as sorted by these\ncriteria:\n\n+---------+-------------+\n| User | Host |\n+---------+-------------+\n| joffrey | 192.168.0.3 |\n| | 192.168.0.% |\n| joffrey | 192.168.% |\n| | 192.168.% |\n+---------+-------------+\n\nOnce connected, you only have the privileges granted to the account that\nmatched, not all accounts that could have matched. For example, consider the\nfollowing commands:\n\nCREATE USER \'joffrey\'@\'192.168.0.3\';\nCREATE USER \'joffrey\'@\'%\';\nGRANT SELECT ON test.t1 to \'joffrey\'@\'192.168.0.3\';\nGRANT SELECT ON test.t2 to \'joffrey\'@\'%\';\n\nIf you connect as joffrey from 192.168.0.3, you will have the SELECT privilege\non the table test.t1, but not on the table test.t2. If you connect as joffrey\nfrom any other IP address, you will have the SELECT privilege on the table\ntest.t2, but not on the table test.t1.\n\nUsernames can be up to 80 characters long before 10.6 and starting from 10.6\nit can be 128 characters long.\n\nAnonymous Accounts\n------------------\n\nAnonymous accounts are accounts where the user name portion of the account\nname is empty. These accounts act as special catch-all accounts. If a user\nattempts to log into the system from a host, and an anonymous account exists\nwith a host name portion that matches the user\'s host, then the user will log\nin as the anonymous account if there is no more specific account match for the\nuser name that the user entered.\n\nFor example, here are some anonymous accounts:\n\nCREATE USER \'\'@\'localhost\';\nCREATE USER \'\'@\'192.168.0.3\';\n\nFixing a Legacy Default Anonymous Account\n-----------------------------------------\n\nOn some systems, the mysql.db table has some entries for the \'\'@\'%\' anonymous\naccount by default. Unfortunately, there is no matching entry in the\nmysql.user/mysql.global_priv_table table, which means that this anonymous\naccount doesn\'t exactly exist, but it does have privileges--usually on the\ndefault test database created by mariadb-install-db. These account-less\nprivileges are a legacy that is leftover from a time when MySQL\'s privilege\nsystem was less advanced.\n\nThis situation means that you will run into errors if you try to create a\n\'\'@\'%\' account. For example:\n\nCREATE USER \'\'@\'%\';\nERROR 1396 (HY000): Operation CREATE USER failed for \'\'@\'%\'\n\nThe fix is to DELETE the row in the mysql.db table and then execute FLUSH\nPRIVILEGES:\n\nDELETE FROM mysql.db WHERE User=\'\' AND Host=\'%\';\nFLUSH PRIVILEGES;\n\nAnd then the account can be created:\n\nCREATE USER \'\'@\'%\';\nQuery OK, 0 rows affected (0.01 sec)\n\nSee MDEV-13486 for more information.\n\nPassword Expiry\n---------------\n\nMariaDB starting with 10.4.3\n----------------------------\nBesides automatic password expiry, as determined by default_password_lifetime,\npassword expiry times can be set on an individual user basis, overriding the\nglobal setting, for example:\n\nCREATE USER \'monty\'@\'localhost\' PASSWORD EXPIRE INTERVAL 120 DAY;\n\nSee User Password Expiry for more details.\n\nAccount Locking\n---------------\n\nMariaDB starting with 10.4.2\n----------------------------\nAccount locking permits privileged administrators to lock/unlock user\naccounts. No new client connections will be permitted if an account is locked\n(existing connections are not affected). For example:\n\nCREATE USER \'marijn\'@\'localhost\' ACCOUNT LOCK;\n\nSee Account Locking for more details.\n\nFrom MariaDB 10.4.7 and MariaDB 10.5.8, the lock_option and password_option\nclauses can occur in either order.\n\nURL: https://mariadb.com/kb/en/create-user/') WHERE help_topic_id = 105; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (106,10,'ALTER USER','Syntax\n------\n\nALTER USER [IF EXISTS] \n user_specification [,user_specification] ...\n [REQUIRE {NONE | tls_option [[AND] tls_option] ...}]\n [WITH resource_option [resource_option] ...]\n [lock_option] [password_option]\n\nuser_specification:\n username [authentication_option]\n\nauthentication_option:\n IDENTIFIED BY \'password\'\n | IDENTIFIED BY PASSWORD \'password_hash\'\n | IDENTIFIED {VIA|WITH} authentication_rule [OR authentication_rule] ...\n\nauthentication_rule:\n authentication_plugin\n | authentication_plugin {USING|AS} \'authentication_string\'\n | authentication_plugin {USING|AS} PASSWORD(\'password\')\n\ntls_option\n SSL\n | X509\n | CIPHER \'cipher\'\n | ISSUER \'issuer\'\n | SUBJECT \'subject\'\n\nresource_option\n MAX_QUERIES_PER_HOUR count\n | MAX_UPDATES_PER_HOUR count\n | MAX_CONNECTIONS_PER_HOUR count\n | MAX_USER_CONNECTIONS count\n | MAX_STATEMENT_TIME time\n\npassword_option:\n PASSWORD EXPIRE\n | PASSWORD EXPIRE DEFAULT\n | PASSWORD EXPIRE NEVER\n | PASSWORD EXPIRE INTERVAL N DAY\n\nlock_option:\n ACCOUNT LOCK\n | ACCOUNT UNLOCK\n}\n\nDescription\n-----------\n\nThe ALTER USER statement modifies existing MariaDB accounts. To use it, you\nmust have the global CREATE USER privilege or the UPDATE privilege for the\nmysql database. The global SUPER privilege is also required if the read_only\nsystem variable is enabled.\n\nIf any of the specified user accounts do not yet exist, an error results. If\nan error occurs, ALTER USER will still modify the accounts that do not result\nin an error. Only one error is produced for all users which have not been\nmodified.\n\nIF EXISTS\n---------\n\nWhen the IF EXISTS clause is used, MariaDB will return a warning instead of an\nerror for each specified user that does not exist.\n\nAccount Names\n-------------\n\nFor ALTER USER statements, account names are specified as the username\nargument in the same way as they are for CREATE USER statements. See account\nnames from the CREATE USER page for details on how account names are specified.\n\nCURRENT_USER or CURRENT_USER() can also be used to alter the account logged\ninto the current session. For example, to change the current user\'s password\nto mariadb:\n\nALTER USER CURRENT_USER() IDENTIFIED BY \'mariadb\';\n\nAuthentication Options\n----------------------\n\nMariaDB starting with 10.4\n--------------------------\nFrom MariaDB 10.4, it is possible to use more than one authentication plugin\nfor each user account. For example, this can be useful to slowly migrate users\nto the more secure ed25519 authentication plugin over time, while allowing the\nold mysql_native_password authentication plugin as an alternative for the\ntransitional period. See Authentication from MariaDB 10.4 for more.\n\nWhen running ALTER USER, not specifying an authentication option in the\nIDENTIFIED VIA clause will remove that authentication method. (However this\nwas not the case before MariaDB 10.4.13, see MDEV-21928)\n\nFor example, a user is created with the ability to authenticate via both a\npassword and unix_socket:\n\nCREATE USER \'bob\'@\'localhost\' \n IDENTIFIED VIA mysql_native_password USING PASSWORD(\'pwd\')\n OR unix_socket;\n\nSHOW CREATE USER \'bob\'@\'localhost\'\\G\n*************************** 1. row ***************************\nCREATE USER for bob@localhost: CREATE USER `bob`@`localhost` \n IDENTIFIED VIA mysql_native_password\n USING \'*975B2CD4FF9AE554FE8AD33168FBFC326D2021DD\'\n OR unix_socket\n\nIf the user\'s password is updated, but unix_socket authentication is not\nspecified in the IDENTIFIED VIA clause, unix_socket authentication will no\nlonger be permitted.\n\nALTER USER \'bob\'@\'localhost\' IDENTIFIED VIA mysql_native_password \n USING PASSWORD(\'pwd2\');\n\nSHOW CREATE USER \'bob\'@\'localhost\'\\G\n*************************** 1. row ***************************\nCREATE USER for bob@localhost: CREATE USER `bob`@`localhost` \n IDENTIFIED BY PASSWORD \'*38366FDA01695B6A5A9DD4E428D9FB8F7EB75512\'\n\nIDENTIFIED BY \'password\'\n------------------------\n\nThe optional IDENTIFIED BY clause can be used to provide an account with a\npassword. The password should be specified in plain text. It will be hashed by\nthe PASSWORD function prior to being stored to the mysql.user table.\n\nFor example, if our password is mariadb, then we can set the account\'s\npassword with:\n\nALTER USER foo2@test IDENTIFIED BY \'mariadb\';\n\nIf you do not specify a password with the IDENTIFIED BY clause, the user will\nbe able to connect without a password. A blank password is not a wildcard to\nmatch any password. The user must connect without providing a password if no\npassword is set.\n\nThe only authentication plugins that this clause supports are\nmysql_native_password and mysql_old_password.\n\nIDENTIFIED BY PASSWORD \'password_hash\'\n--------------------------------------\n\nThe optional IDENTIFIED BY PASSWORD clause can be used to provide an account\nwith a password that has already been hashed. The password should be specified\nas a hash that was provided by the PASSWORD#function. It will be stored to the\nmysql.user table as-is.\n\nFor example, if our password is mariadb, then we can find the hash with:\n\nSELECT PASSWORD(\'mariadb\');\n+-------------------------------------------+\n| PASSWORD(\'mariadb\') |\n+-------------------------------------------+\n| *54958E764CE10E50764C2EECBB71D01F08549980 |\n+-------------------------------------------+\n\nAnd then we can set an account\'s password with the hash:\n\nALTER USER foo2@test \n IDENTIFIED BY PASSWORD \'*54958E764CE10E50764C2EECBB71D01F08549980\';\n\nIf you do not specify a password with the IDENTIFIED BY clause, the user will\nbe able to connect without a password. A blank password is not a wildcard to\nmatch any password. The user must connect without providing a password if no\npassword is set.\n\nThe only authentication plugins that this clause supports are\nmysql_native_password and mysql_old_password.\n\nIDENTIFIED {VIA|WITH} authentication_plugin\n-------------------------------------------\n\nThe optional IDENTIFIED VIA authentication_plugin allows you to specify that\nthe account should be authenticated by a specific authentication plugin. The\nplugin name must be an active authentication plugin as per SHOW PLUGINS. If it\ndoesn\'t show up in that output, then you will need to install it with INSTALL\nPLUGIN or INSTALL SONAME.\n\nFor example, this could be used with the PAM authentication plugin:\n\nALTER USER foo2@test IDENTIFIED VIA pam;\n\nSome authentication plugins allow additional arguments to be specified after a\nUSING or AS keyword. For example, the PAM authentication plugin accepts a\nservice name:\n\nALTER USER foo2@test IDENTIFIED VIA pam USING \'mariadb\';\n\nThe exact meaning of the additional argument would depend on the specific\nauthentication plugin.\n\nIn MariaDB 10.4 and later, the USING or AS keyword can also be used to provide\na plain-text password to a plugin if it\'s provided as an argument to the\nPASSWORD() function. This is only valid for authentication plugins that have\nimplemented a hook for the PASSWORD() function. For example, the ed25519\nauthentication plugin supports this:\n\nALTER USER safe@\'%\' IDENTIFIED VIA ed25519 USING PASSWORD(\'secret\');\n\nTLS Options\n-----------\n\nBy default, MariaDB transmits data between the server and clients without\nencrypting it. This is generally acceptable when the server and client run on\nthe same host or in networks where security is guaranteed through other means.\nHowever, in cases where the server and client exist on separate networks or\nthey are in a high-risk network, the lack of encryption does introduce\nsecurity concerns as a malicious actor could potentially eavesdrop on the\ntraffic as it is sent over the network between them.\n\nTo mitigate this concern, MariaDB allows you to encrypt data in transit\nbetween the server and clients using the Transport Layer Security (TLS)\nprotocol. TLS was formerly known as Secure Socket Layer (SSL), but strictly\nspeaking the SSL protocol is a predecessor to TLS and, that version of the\nprotocol is now considered insecure. The documentation still uses the term SSL\noften and for compatibility reasons TLS-related server system and status\nvariables still use the prefix ssl_, but internally, MariaDB only supports its\nsecure successors.\n\nSee Secure Connections Overview for more information about how to determine\nwhether your MariaDB server has TLS support.\n\nYou can set certain TLS-related restrictions for specific user accounts. For\ninstance, you might use this with user accounts that require access to\nsensitive data while sending it across networks that you do not control. These\nrestrictions can be enabled for a user account with the CREATE USER, ALTER\nUSER, or GRANT statements. The following options are available:\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| REQUIRE NONE | TLS is not required for this account, but can |\n| | still be used. |\n+---------------------------+------------------------------------------------+\n| REQUIRE SSL | The account must use TLS, but no valid X509 |\n| | certificate is required. This option cannot |\n| | be combined with other TLS options. |\n+---------------------------+------------------------------------------------+\n| REQUIRE X509 | The account must use TLS and must have a |\n| | valid X509 certificate. This option implies |\n| | REQUIRE SSL. This option cannot be combined |\n| | with other TLS options. |\n+---------------------------+------------------------------------------------+\n| REQUIRE ISSUER \'issuer\' | The account must use TLS and must have a |\n| | valid X509 certificate. Also, the Certificate |\n| | Authority must be the one specified via the |\n| | string issuer. This option implies REQUIRE |\n| | X509. This option can be combined with the |\n| | SUBJECT, and CIPHER options in any order. |\n+---------------------------+------------------------------------------------+\n| REQUIRE SUBJECT \'subject\' | The account must use TLS and must have a |\n| | valid X509 certificate. Also, the |\n| | certificate\'s Subject must be the one |\n| | specified via the string subject. This option |\n| | implies REQUIRE X509. This option can be |\n| | combined with the ISSUER, and CIPHER options |\n| | in any order. |\n+---------------------------+------------------------------------------------+\n| REQUIRE CIPHER \'cipher\' | The account must use TLS, but no valid X509 |\n| | certificate is required. Also, the encryption |\n| | used for the connection must use a specific |\n| | cipher method specified in the string cipher. |\n| | This option implies REQUIRE SSL. This option |\n| | can be combined with the ISSUER, and SUBJECT |\n| | options in any order. |\n+---------------------------+------------------------------------------------+\n\nThe REQUIRE keyword must be used only once for all specified options, and the\nAND keyword can be used to separate individual options, but it is not required.\n\nFor example, you can alter a user account to require these TLS options with\nthe following:\n\nALTER USER \'alice\'@\'%\'\n REQUIRE SUBJECT \'/CN=alice/O=My Dom, Inc./C=US/ST=Oregon/L=Portland\' AND\n ISSUER \'/C=FI/ST=Somewhere/L=City/ O=Some Company/CN=Peter\nParker/emailAddress=p.parker@marvel.com\'\n AND CIPHER \'SHA-DES-CBC3-EDH-RSA\';\n\nIf any of these options are set for a specific user account, then any client\nwho tries to connect with that user account will have to be configured to\nconnect with TLS.\n\nSee Securing Connections for Client and Server for information on how to\nenable TLS on the client and server.\n\nResource Limit Options\n----------------------\n\nIt is possible to set per-account limits for certain server resources. The\nfollowing table shows the values that can be set per account:\n\n+------------------------------------+---------------------------------------+\n| Limit Type | Description |\n+------------------------------------+---------------------------------------+\n| MAX_QUERIES_PER_HOUR | Number of statements that the |\n| | account can issue per hour |\n| | (including updates) |\n+------------------------------------+---------------------------------------+\n| MAX_UPDATES_PER_HOUR | Number of updates (not queries) that |\n| | the account can issue per hour |\n+------------------------------------+---------------------------------------+\n| MAX_CONNECTIONS_PER_HOUR | Number of connections that the |\n| | account can start per hour |\n+------------------------------------+---------------------------------------+\n| MAX_USER_CONNECTIONS | Number of simultaneous connections |\n| | that can be accepted from the same |\n| | account; if it is 0, max_connections |\n| | will be used instead; if |\n| | max_connections is 0, there is no |\n| | limit for this account\'s |\n| | simultaneous connections. |','','https://mariadb.com/kb/en/alter-user/'); +update help_topic set description = CONCAT(description, '\n+------------------------------------+---------------------------------------+\n| MAX_STATEMENT_TIME | Timeout, in seconds, for statements |\n| | executed by the user. See also |\n| | Aborting Statements that Exceed a |\n| | Certain Time to Execute. |\n+------------------------------------+---------------------------------------+\n\nIf any of these limits are set to 0, then there is no limit for that resource\nfor that user.\n\nHere is an example showing how to set an account\'s resource limits:\n\nALTER USER \'someone\'@\'localhost\' WITH\n MAX_USER_CONNECTIONS 10\n MAX_QUERIES_PER_HOUR 200;\n\nThe resources are tracked per account, which means \'user\'@\'server\'; not per\nuser name or per connection.\n\nThe count can be reset for all users using FLUSH USER_RESOURCES, FLUSH\nPRIVILEGES or mysqladmin reload.\n\nPer account resource limits are stored in the user table, in the mysql\ndatabase. Columns used for resources limits are named max_questions,\nmax_updates, max_connections (for MAX_CONNECTIONS_PER_HOUR), and\nmax_user_connections (for MAX_USER_CONNECTIONS).\n\nPassword Expiry\n---------------\n\nMariaDB starting with 10.4.3\n----------------------------\nBesides automatic password expiry, as determined by default_password_lifetime,\npassword expiry times can be set on an individual user basis, overriding the\nglobal setting, for example:\n\nALTER USER \'monty\'@\'localhost\' PASSWORD EXPIRE INTERVAL 120 DAY;\nALTER USER \'monty\'@\'localhost\' PASSWORD EXPIRE NEVER;\nALTER USER \'monty\'@\'localhost\' PASSWORD EXPIRE DEFAULT;\n\nSee User Password Expiry for more details.\n\nAccount Locking\n---------------\n\nMariaDB starting with 10.4.2\n----------------------------\nAccount locking permits privileged administrators to lock/unlock user\naccounts. No new client connections will be permitted if an account is locked\n(existing connections are not affected). For example:\n\nALTER USER \'marijn\'@\'localhost\' ACCOUNT LOCK;\n\nSee Account Locking for more details.\n\nFrom MariaDB 10.4.7 and MariaDB 10.5.8, the lock_option and password_option\nclauses can occur in either order.\n\nURL: https://mariadb.com/kb/en/alter-user/') WHERE help_topic_id = 106; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (107,10,'DROP USER','Syntax\n------\n\nDROP USER [IF EXISTS] user_name [, user_name] ...\n\nDescription\n-----------\n\nThe DROP USER statement removes one or more MariaDB accounts. It removes\nprivilege rows for the account from all grant tables. To use this statement,\nyou must have the global CREATE USER privilege or the DELETE privilege for the\nmysql database. Each account is named using the same format as for the CREATE\nUSER statement; for example, \'jeffrey\'@\'localhost\'. If you specify only the\nuser name part of the account name, a host name part of \'%\' is used. For\nadditional information about specifying account names, see CREATE USER.\n\nNote that, if you specify an account that is currently connected, it will not\nbe deleted until the connection is closed. The connection will not be\nautomatically closed.\n\nIf any of the specified user accounts do not exist, ERROR 1396 (HY000)\nresults. If an error occurs, DROP USER will still drop the accounts that do\nnot result in an error. Only one error is produced for all users which have\nnot been dropped:\n\nERROR 1396 (HY000): Operation DROP USER failed for \'u1\'@\'%\',\'u2\'@\'%\'\n\nFailed CREATE or DROP operations, for both users and roles, produce the same\nerror code.\n\nIF EXISTS\n---------\n\nIf the IF EXISTS clause is used, MariaDB will return a note instead of an\nerror if the user does not exist.\n\nExamples\n--------\n\nDROP USER bob;\n\nDROP USER foo2@localhost,foo2@\'127.%\';\n\nIF EXISTS:\n\nDROP USER bob;\nERROR 1396 (HY000): Operation DROP USER failed for \'bob\'@\'%\'\n\nDROP USER IF EXISTS bob;\nQuery OK, 0 rows affected, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+-------+------+---------------------------------------------+\n| Level | Code | Message |\n+-------+------+---------------------------------------------+\n| Note | 1974 | Can\'t drop user \'bob\'@\'%\'; it doesn\'t exist |\n+-------+------+---------------------------------------------+\n\nURL: https://mariadb.com/kb/en/drop-user/','','https://mariadb.com/kb/en/drop-user/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (108,10,'GRANT','Syntax\n------\n\nGRANT\n priv_type [(column_list)]\n [, priv_type [(column_list)]] ...\n ON [object_type] priv_level\n TO user_specification [ user_options ...]\n\nuser_specification:\n username [authentication_option]\n | PUBLIC\nauthentication_option:\n IDENTIFIED BY \'password\'\n | IDENTIFIED BY PASSWORD \'password_hash\'\n | IDENTIFIED {VIA|WITH} authentication_rule [OR authentication_rule ...]\n\nauthentication_rule:\n authentication_plugin\n | authentication_plugin {USING|AS} \'authentication_string\'\n | authentication_plugin {USING|AS} PASSWORD(\'password\')\n\nGRANT PROXY ON username\n TO user_specification [, user_specification ...]\n [WITH GRANT OPTION]\n\nGRANT rolename TO grantee [, grantee ...]\n [WITH ADMIN OPTION]\n\ngrantee:\n rolename\n username [authentication_option]\n\nuser_options:\n [REQUIRE {NONE | tls_option [[AND] tls_option] ...}]\n [WITH with_option [with_option] ...]\n\nobject_type:\n TABLE\n | FUNCTION\n | PROCEDURE\n | PACKAGE\n\npriv_level:\n *\n | *.*\n | db_name.*\n | db_name.tbl_name\n | tbl_name\n | db_name.routine_name\n\nwith_option:\n GRANT OPTION\n | resource_option\n\nresource_option:\n MAX_QUERIES_PER_HOUR count\n | MAX_UPDATES_PER_HOUR count\n | MAX_CONNECTIONS_PER_HOUR count\n | MAX_USER_CONNECTIONS count\n | MAX_STATEMENT_TIME time\n\ntls_option:\n SSL\n | X509\n | CIPHER \'cipher\'\n | ISSUER \'issuer\'\n | SUBJECT \'subject\'\n\nDescription\n-----------\n\nThe GRANT statement allows you to grant privileges or roles to accounts. To\nuse GRANT, you must have the GRANT OPTION privilege, and you must have the\nprivileges that you are granting.\n\nUse the REVOKE statement to revoke privileges granted with the GRANT statement.\n\nUse the SHOW GRANTS statement to determine what privileges an account has.\n\nAccount Names\n-------------\n\nFor GRANT statements, account names are specified as the username argument in\nthe same way as they are for CREATE USER statements. See account names from\nthe CREATE USER page for details on how account names are specified.\n\nImplicit Account Creation\n-------------------------\n\nThe GRANT statement also allows you to implicitly create accounts in some\ncases.\n\nIf the account does not yet exist, then GRANT can implicitly create it. To\nimplicitly create an account with GRANT, a user is required to have the same\nprivileges that would be required to explicitly create the account with the\nCREATE USER statement.\n\nIf the NO_AUTO_CREATE_USER SQL_MODE is set, then accounts can only be created\nif authentication information is specified, or with a CREATE USER statement.\nIf no authentication information is provided, GRANT will produce an error when\nthe specified account does not exist, for example:\n\nshow variables like \'%sql_mode%\' ;\n+---------------+--------------------------------------------+\n| Variable_name | Value |\n+---------------+--------------------------------------------+\n| sql_mode | NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |\n+---------------+--------------------------------------------+\n\nGRANT USAGE ON *.* TO \'user123\'@\'%\' IDENTIFIED BY \'\';\nERROR 1133 (28000): Can\'t find any matching row in the user table\n\nGRANT USAGE ON *.* TO \'user123\'@\'%\' \n IDENTIFIED VIA PAM using \'mariadb\' require ssl ;\nQuery OK, 0 rows affected (0.00 sec)\n\nselect host, user from mysql.user where user=\'user123\' ;\n\n+------+----------+\n| host | user |\n+------+----------+\n| % | user123 |\n+------+----------+\n\nPrivilege Levels\n----------------\n\nPrivileges can be set globally, for an entire database, for a table or\nroutine, or for individual columns in a table. Certain privileges can only be\nset at certain levels.\n\nGlobal privileges do not take effect immediately and are only applied to\nconnections created after the GRANT statement was executed.\n\n* Global privileges priv_type are granted using *.* for\npriv_level. Global privileges include privileges to administer the database\nand manage user accounts, as well as privileges for all tables, functions, and\nprocedures. Global privileges are stored in the mysql.user table prior to\nMariaDB 10.4, and in mysql.global_priv table afterwards.\n* Database privileges priv_type are granted using db_name.*\nfor priv_level, or using just * to use default database. Database\nprivileges include privileges to create tables and functions, as well as\nprivileges for all tables, functions, and procedures in the database. Database\nprivileges are stored in the mysql.db table.\n* Table privileges priv_type are granted using db_name.tbl_name\nfor priv_level, or using just tbl_name to specify a table in the default\ndatabase. The TABLE keyword is optional. Table privileges include the\nability to select and change data in the table. Certain table privileges can\nbe granted for individual columns.\n* Column privileges priv_type are granted by specifying a table for\npriv_level and providing a column list after the privilege type. They allow\nyou to control exactly which columns in a table users can select and change.\n* Function privileges priv_type are granted using FUNCTION db_name.routine_name\nfor priv_level, or using just FUNCTION routine_name to specify a function\nin the default database.\n* Procedure privileges priv_type are granted using PROCEDURE\ndb_name.routine_name\nfor priv_level, or using just PROCEDURE routine_name to specify a procedure\nin the default database.\n\nThe USAGE Privilege\n-------------------\n\nThe USAGE privilege grants no real privileges. The SHOW GRANTS statement will\nshow a global USAGE privilege for a newly-created user. You can use USAGE with\nthe GRANT statement to change options like GRANT OPTION and\nMAX_USER_CONNECTIONS without changing any account privileges.\n\nThe ALL PRIVILEGES Privilege\n----------------------------\n\nThe ALL PRIVILEGES privilege grants all available privileges. Granting all\nprivileges only affects the given privilege level. For example, granting all\nprivileges on a table does not grant any privileges on the database or\nglobally.\n\nUsing ALL PRIVILEGES does not grant the special GRANT OPTION privilege.\n\nYou can use ALL instead of ALL PRIVILEGES.\n\nThe GRANT OPTION Privilege\n--------------------------\n\nUse the WITH GRANT OPTION clause to give users the ability to grant privileges\nto other users at the given privilege level. Users with the GRANT OPTION\nprivilege can only grant privileges they have. They cannot grant privileges at\na higher privilege level than they have the GRANT OPTION privilege.\n\nThe GRANT OPTION privilege cannot be set for individual columns. If you use\nWITH GRANT OPTION when specifying column privileges, the GRANT OPTION\nprivilege will be granted for the entire table.\n\nUsing the WITH GRANT OPTION clause is equivalent to listing GRANT OPTION as a\nprivilege.\n\nGlobal Privileges\n-----------------\n\nThe following table lists the privileges that can be granted globally. You can\nalso grant all database, table, and function privileges globally. When granted\nglobally, these privileges apply to all databases, tables, or functions,\nincluding those created later.\n\nTo set a global privilege, use *.* for priv_level.\n\nBINLOG ADMIN\n------------\n\nEnables administration of the binary log, including the PURGE BINARY LOGS\nstatement and setting the system variables:\n\n* binlog_annotate_row_events\n* binlog_cache_size\n* binlog_commit_wait_count\n* binlog_commit_wait_usec\n* binlog_direct_non_transactional_updates\n* binlog_expire_logs_seconds\n* binlog_file_cache_size\n* binlog_format\n* binlog_row_image\n* binlog_row_metadata\n* binlog_stmt_cache_size\n* expire_logs_days\n* log_bin_compress\n* log_bin_compress_min_len\n* log_bin_trust_function_creators\n* max_binlog_cache_size\n* max_binlog_size\n* max_binlog_stmt_cache_size\n* sql_log_bin and\n* sync_binlog.\n\nAdded in MariaDB 10.5.2.\n\nBINLOG MONITOR\n--------------\n\nNew name for REPLICATION CLIENT from MariaDB 10.5.2, (REPLICATION CLIENT still\nsupported as an alias for compatibility purposes). Permits running SHOW\ncommands related to the binary log, in particular the SHOW BINLOG STATUS and\nSHOW BINARY LOGS statements. Unlike REPLICATION CLIENT prior to MariaDB 10.5,\nSHOW REPLICA STATUS isn\'t included in this privilege, and REPLICA MONITOR is\nrequired.\n\nBINLOG REPLAY\n-------------\n\nEnables replaying the binary log with the BINLOG statement (generated by\nmariadb-binlog), executing SET timestamp when secure_timestamp is set to\nreplication, and setting the session values of system variables usually\nincluded in BINLOG output, in particular:\n\n* gtid_domain_id\n* gtid_seq_no\n* pseudo_thread_id\n* server_id.\n\nAdded in MariaDB 10.5.2\n\nCONNECTION ADMIN\n----------------\n\nEnables administering connection resource limit options. This includes\nignoring the limits specified by:\n\n* max_connections\n* max_user_connections and\n* max_password_errors.\n\nThe statements specified in init_connect are not executed, killing connections\nand queries owned by other users is permitted. The following\nconnection-related system variables can be changed:\n\n* connect_timeout\n* disconnect_on_expired_password\n* extra_max_connections\n* init_connect\n* max_connections\n* max_connect_errors\n* max_password_errors\n* proxy_protocol_networks\n* secure_auth\n* slow_launch_time\n* thread_pool_exact_stats\n* thread_pool_dedicated_listener\n* thread_pool_idle_timeout\n* thread_pool_max_threads\n* thread_pool_min_threads\n* thread_pool_oversubscribe\n* thread_pool_prio_kickup_timer\n* thread_pool_priority\n* thread_pool_size, and\n* thread_pool_stall_limit.\n\nAdded in MariaDB 10.5.2.\n\nCREATE USER\n-----------\n\nCreate a user using the CREATE USER statement, or implicitly create a user\nwith the GRANT statement.\n\nFEDERATED ADMIN\n---------------\n\nExecute CREATE SERVER, ALTER SERVER, and DROP SERVER statements. Added in\nMariaDB 10.5.2.\n\nFILE\n----\n\nRead and write files on the server, using statements like LOAD DATA INFILE or\nfunctions like LOAD_FILE(). Also needed to create CONNECT outward tables.\nMariaDB server must have the permissions to access those files.\n\nGRANT OPTION\n------------\n\nGrant global privileges. You can only grant privileges that you have.\n\nPROCESS\n-------\n\nShow information about the active processes, for example via SHOW PROCESSLIST\nor mariadb-admin processlist. If you have the PROCESS privilege, you can see\nall threads. Otherwise, you can see only your own threads (that is, threads\nassociated with the MariaDB account that you are using).\n\nREAD_ONLY ADMIN\n---------------\n\nUser can set the read_only system variable and allows the user to perform\nwrite operations, even when the read_only option is active. Added in MariaDB\n10.5.2.\n\nFrom MariaDB 10.11.0, the READ_ONLY ADMIN privilege has been removed from\nSUPER. The benefit of this is that one can remove the READ_ONLY ADMIN\nprivilege from all users and ensure that no one can make any changes on any\nnon-temporary tables. This is useful on replicas when one wants to ensure that\nthe replica is kept identical to the primary.\n\nRELOAD\n------\n\nExecute FLUSH statements or equivalent mariadb-admin commands.\n\nREPLICATION CLIENT\n------------------\n\nExecute SHOW MASTER STATUS and SHOW BINARY LOGS informative statements.\nRenamed to BINLOG MONITOR in MariaDB 10.5.2 (but still supported as an alias\nfor compatibility reasons). SHOW SLAVE STATUS was part of REPLICATION CLIENT\nprior to MariaDB 10.5.\n\nREPLICATION MASTER ADMIN\n------------------------\n\nPermits administration of primary servers, including the SHOW REPLICA HOSTS\nstatement, and setting the gtid_binlog_state, gtid_domain_id,\nmaster_verify_checksum and server_id system variables. Added in MariaDB 10.5.2.\n\nREPLICA MONITOR\n---------------\n\nPermit SHOW REPLICA STATUS and SHOW RELAYLOG EVENTS. From MariaDB 10.5.9.\n\nWhen a user would upgrade from an older major release to a MariaDB 10.5 minor\nrelease prior to MariaDB 10.5.9, certain user accounts would lose\ncapabilities. For example, a user account that had the REPLICATION CLIENT\nprivilege in older major releases could run SHOW REPLICA STATUS, but after\nupgrading to a MariaDB 10.5 minor release prior to MariaDB 10.5.9, they could\nno longer run SHOW REPLICA STATUS, because that statement was changed to\nrequire the REPLICATION REPLICA ADMIN privilege.\n\nThis issue is fixed in MariaDB 10.5.9 with this new privilege, which now\ngrants the user the ability to execute SHOW [ALL] (SLAVE | REPLICA) STATUS.\n\nWhen a database is upgraded from an older major release to MariaDB Server\n10.5.9 or later, any user accounts with the REPLICATION CLIENT or REPLICATION\nSLAVE privileges will automatically be granted the new REPLICA MONITOR\nprivilege. The privilege fix occurs when the server is started up, not when\nmariadb-upgrade is performed.\n\nHowever, when a database is upgraded from an early 10.5 minor release to\n10.5.9 and later, the user will have to fix any user account privileges\nmanually.\n\nREPLICATION REPLICA\n-------------------\n\nSynonym for REPLICATION SLAVE. From MariaDB 10.5.1.\n\nREPLICATION SLAVE\n-----------------\n\nAccounts used by replica servers on the primary need this privilege. This is\nneeded to get the updates made on the master. From MariaDB 10.5.1, REPLICATION\nREPLICA is an alias for REPLICATION SLAVE.\n\nREPLICATION SLAVE ADMIN\n-----------------------\n\nPermits administering replica servers, including START REPLICA/SLAVE, STOP\nREPLICA/SLAVE, CHANGE MASTER, SHOW REPLICA/SLAVE STATUS, SHOW RELAYLOG EVENTS\nstatements, replaying the binary log with the BINLOG statement (generated by\nmariadb-binlog), and setting the system variables:\n\n* gtid_cleanup_batch_size\n* gtid_ignore_duplicates\n* gtid_pos_auto_engines\n* gtid_slave_pos\n* gtid_strict_mode\n* init_slave\n* read_binlog_speed_limit\n* relay_log_purge\n* relay_log_recovery\n* replicate_do_db\n* replicate_do_table\n* replicate_events_marked_for_skip\n* replicate_ignore_db\n* replicate_ignore_table\n* replicate_wild_do_table\n* replicate_wild_ignore_table\n* slave_compressed_protocol\n* slave_ddl_exec_mode\n* slave_domain_parallel_threads\n* slave_exec_mode\n* slave_max_allowed_packet\n* slave_net_timeout\n* slave_parallel_max_queued\n* slave_parallel_mode\n* slave_parallel_threads\n* slave_parallel_workers\n* slave_run_triggers_for_rbr\n* slave_sql_verify_checksum\n* slave_transaction_retry_interval\n* slave_type_conversions\n* sync_master_info\n* sync_relay_log, and','','https://mariadb.com/kb/en/grant/'); +update help_topic set description = CONCAT(description, '\n* sync_relay_log_info.\n\nAdded in MariaDB 10.5.2.\n\nSET USER\n--------\n\nEnables setting the DEFINER when creating triggers, views, stored functions\nand stored procedures. Added in MariaDB 10.5.2.\n\nSHOW DATABASES\n--------------\n\nList all databases using the SHOW DATABASES statement. Without the SHOW\nDATABASES privilege, you can still issue the SHOW DATABASES statement, but it\nwill only list databases containing tables on which you have privileges.\n\nSHUTDOWN\n--------\n\nShut down the server using SHUTDOWN or the mariadb-admin shutdown command.\n\nSUPER\n-----\n\nExecute superuser statements: CHANGE MASTER TO, KILL (users who do not have\nthis privilege can only KILL their own threads), PURGE LOGS, SET global system\nvariables, or the mariadb-admin debug command. Also, this permission allows\nthe user to write data even if the read_only startup option is set, enable or\ndisable logging, enable or disable replication on replica, specify a DEFINER\nfor statements that support that clause, connect once reaching the\nMAX_CONNECTIONS. If a statement has been specified for the init-connect mysqld\noption, that command will not be executed when a user with SUPER privileges\nconnects to the server.\n\nThe SUPER privilege has been split into multiple smaller privileges from\nMariaDB 10.5.2 to allow for more fine-grained privileges (MDEV-21743). The\nprivileges are:\n\n* SET USER\n* FEDERATED ADMIN\n* CONNECTION ADMIN\n* REPLICATION SLAVE ADMIN\n* BINLOG ADMIN\n* BINLOG REPLAY\n* REPLICA MONITOR\n* BINLOG MONITOR\n* REPLICATION MASTER ADMIN\n* READ_ONLY ADMIN\n\nHowever, the smaller privileges are still a part of the SUPER grant in MariaDB\n10.5.2. From MariaDB 11.0.1 onwards, these grants are no longer a part of\nSUPER and need to be granted separately (MDEV-29668).\n\nFrom MariaDB 10.11.0, the READ_ONLY ADMIN privilege has been removed from\nSUPER. The benefit of this is that one can remove the READ_ONLY ADMIN\nprivilege from all users and ensure that no one can make any changes on any\nnon-temporary tables. This is useful on replicas when one wants to ensure that\nthe replica is kept identical to the primary (MDEV-29596).\n\nDatabase Privileges\n-------------------\n\nThe following table lists the privileges that can be granted at the database\nlevel. You can also grant all table and function privileges at the database\nlevel. Table and function privileges on a database apply to all tables or\nfunctions in that database, including those created later.\n\nTo set a privilege for a database, specify the database using db_name.* for\npriv_level, or just use * to specify the default database.\n\n+----------------------------------+-----------------------------------------+\n| Privilege | Description |\n+----------------------------------+-----------------------------------------+\n| CREATE | Create a database using the CREATE |\n| | DATABASE statement, when the privilege |\n| | is granted for a database. You can |\n| | grant the CREATE privilege on |\n| | databases that do not yet exist. This |\n| | also grants the CREATE privilege on |\n| | all tables in the database. |\n+----------------------------------+-----------------------------------------+\n| CREATE ROUTINE | Create Stored Programs using the |\n| | CREATE PROCEDURE and CREATE FUNCTION |\n| | statements. |\n+----------------------------------+-----------------------------------------+\n| CREATE TEMPORARY TABLES | Create temporary tables with the |\n| | CREATE TEMPORARY TABLE statement. This |\n| | privilege enable writing and dropping |\n| | those temporary tables |\n+----------------------------------+-----------------------------------------+\n| DROP | Drop a database using the DROP |\n| | DATABASE statement, when the privilege |\n| | is granted for a database. This also |\n| | grants the DROP privilege on all |\n| | tables in the database. |\n+----------------------------------+-----------------------------------------+\n| EVENT | Create, drop and alter EVENTs. |\n+----------------------------------+-----------------------------------------+\n| GRANT OPTION | Grant database privileges. You can |\n| | only grant privileges that you have. |\n+----------------------------------+-----------------------------------------+\n| LOCK TABLES | Acquire explicit locks using the LOCK |\n| | TABLES statement; you also need to |\n| | have the SELECT privilege on a table, |\n| | in order to lock it. |\n+----------------------------------+-----------------------------------------+\n\nTable Privileges\n----------------\n\n+----------------------------------+-----------------------------------------+\n| Privilege | Description |\n+----------------------------------+-----------------------------------------+\n| ALTER | Change the structure of an existing |\n| | table using the ALTER TABLE statement. |\n+----------------------------------+-----------------------------------------+\n| CREATE | Create a table using the CREATE TABLE |\n| | statement. You can grant the CREATE |\n| | privilege on tables that do not yet |\n| | exist. |\n+----------------------------------+-----------------------------------------+\n| CREATE VIEW | Create a view using the CREATE_VIEW |\n| | statement. |\n+----------------------------------+-----------------------------------------+\n| DELETE | Remove rows from a table using the |\n| | DELETE statement. |\n+----------------------------------+-----------------------------------------+\n| DELETE HISTORY | Remove historical rows from a table |\n| | using the DELETE HISTORY statement. |\n| | Displays as DELETE VERSIONING ROWS |\n| | when running SHOW GRANTS until MariaDB |\n| | 10.3.15 and until MariaDB 10.4.5 |\n| | (MDEV-17655), or when running SHOW |\n| | PRIVILEGES until MariaDB 10.5.2, |\n| | MariaDB 10.4.13 and MariaDB 10.3.23 |\n| | (MDEV-20382). From MariaDB 10.3.4. |\n| | From MariaDB 10.3.5, if a user has the |\n| | SUPER privilege but not this |\n| | privilege, running mariadb-upgrade |\n| | will grant this privilege as well. |\n+----------------------------------+-----------------------------------------+\n| DROP | Drop a table using the DROP TABLE |\n| | statement or a view using the DROP |\n| | VIEW statement. Also required to |\n| | execute the TRUNCATE TABLE statement. |\n+----------------------------------+-----------------------------------------+\n| GRANT OPTION | Grant table privileges. You can only |\n| | grant privileges that you have. |\n+----------------------------------+-----------------------------------------+\n| INDEX | Create an index on a table using the |\n| | CREATE INDEX statement. Without the |\n| | INDEX privilege, you can still create |\n| | indexes when creating a table using |\n| | the CREATE TABLE statement if the you |\n| | have the CREATE privilege, and you can |\n| | create indexes using the ALTER TABLE |\n| | statement if you have the ALTER |\n| | privilege. |\n+----------------------------------+-----------------------------------------+\n| INSERT | Add rows to a table using the INSERT |\n| | statement. The INSERT privilege can |\n| | also be set on individual columns; see |\n| | Column Privileges below for details. |\n+----------------------------------+-----------------------------------------+\n| REFERENCES | Unused. |\n+----------------------------------+-----------------------------------------+\n| SELECT | Read data from a table using the |\n| | SELECT statement. The SELECT privilege |\n| | can also be set on individual columns; |\n| | see Column Privileges below for |\n| | details. |\n+----------------------------------+-----------------------------------------+\n| SHOW VIEW | Show the CREATE VIEW statement to |\n| | create a view using the SHOW CREATE |\n| | VIEW statement. |\n+----------------------------------+-----------------------------------------+\n| TRIGGER | Execute triggers associated to tables |\n| | you update, execute the CREATE |\n| | TRIGGER, DROP TRIGGER, and SHOW CREATE |\n| | TRIGGER statements. |\n+----------------------------------+-----------------------------------------+\n| UPDATE | Update existing rows in a table using |\n| | the UPDATE statement. UPDATE |\n| | statements usually include a WHERE |\n| | clause to update only certain rows. |\n| | You must have SELECT privileges on the |\n| | table or the appropriate columns for |\n| | the WHERE clause. The UPDATE privilege |\n| | can also be set on individual columns; |\n| | see Column Privileges below for |\n| | details. |\n+----------------------------------+-----------------------------------------+\n\nColumn Privileges\n-----------------\n\nSome table privileges can be set for individual columns of a table. To use\ncolumn privileges, specify the table explicitly and provide a list of column\nnames after the privilege type. For example, the following statement would\nallow the user to read the names and positions of employees, but not other\ninformation from the same table, such as salaries.\n\nGRANT SELECT (name, position) on Employee to \'jeffrey\'@\'localhost\';\n\n+----------------------------------+-----------------------------------------+\n| Privilege | Description |\n+----------------------------------+-----------------------------------------+\n| INSERT (column_list) | Add rows specifying values in columns |\n| | using the INSERT statement. If you |\n| | only have column-level INSERT |\n| | privileges, you must specify the |\n| | columns you are setting in the INSERT |\n| | statement. All other columns will be |\n| | set to their default values, or NULL. |\n+----------------------------------+-----------------------------------------+\n| REFERENCES (column_list) | Unused. |\n+----------------------------------+-----------------------------------------+\n| SELECT (column_list) | Read values in columns using the |\n| | SELECT statement. You cannot access or |\n| | query any columns for which you do not |\n| | have SELECT privileges, including in |\n| | WHERE, ON, GROUP BY, and ORDER BY |\n| | clauses. |\n+----------------------------------+-----------------------------------------+\n| UPDATE (column_list) | Update values in columns of existing |\n| | rows using the UPDATE statement. |\n| | UPDATE statements usually include a |\n| | WHERE clause to update only certain |') WHERE help_topic_id = 108; +update help_topic set description = CONCAT(description, '\n| | rows. You must have SELECT privileges |\n| | on the table or the appropriate |\n| | columns for the WHERE clause. |\n+----------------------------------+-----------------------------------------+\n\nFunction Privileges\n-------------------\n\n+----------------------------------+-----------------------------------------+\n| Privilege | Description |\n+----------------------------------+-----------------------------------------+\n| ALTER ROUTINE | Change the characteristics of a stored |\n| | function using the ALTER FUNCTION |\n| | statement. |\n+----------------------------------+-----------------------------------------+\n| EXECUTE | Use a stored function. You need SELECT |\n| | privileges for any tables or columns |\n| | accessed by the function. |\n+----------------------------------+-----------------------------------------+\n| GRANT OPTION | Grant function privileges. You can |\n| | only grant privileges that you have. |\n+----------------------------------+-----------------------------------------+\n\nProcedure Privileges\n--------------------\n\n+----------------------------------+-----------------------------------------+\n| Privilege | Description |\n+----------------------------------+-----------------------------------------+\n| ALTER ROUTINE | Change the characteristics of a stored |\n| | procedure using the ALTER PROCEDURE |\n| | statement. |\n+----------------------------------+-----------------------------------------+\n| EXECUTE | Execute a stored procedure using the |\n| | CALL statement. The privilege to call |\n| | a procedure may allow you to perform |\n| | actions you wouldn\'t otherwise be able |\n| | to do, such as insert rows into a |\n| | table. |\n+----------------------------------+-----------------------------------------+\n| GRANT OPTION | Grant procedure privileges. You can |\n| | only grant privileges that you have. |\n+----------------------------------+-----------------------------------------+\n\nGRANT EXECUTE ON PROCEDURE mysql.create_db TO maintainer;\n\nProxy Privileges\n----------------\n\n+----------------------------------+-----------------------------------------+\n| Privilege | Description |\n+----------------------------------+-----------------------------------------+\n| PROXY | Permits one user to be a proxy for |\n| | another. |\n+----------------------------------+-----------------------------------------+\n\nThe PROXY privilege allows one user to proxy as another user, which means\ntheir privileges change to that of the proxy user, and the CURRENT_USER()\nfunction returns the user name of the proxy user.\n\nThe PROXY privilege only works with authentication plugins that support it.\nThe default mysql_native_password authentication plugin does not support proxy\nusers.\n\nThe pam authentication plugin is the only plugin included with MariaDB that\ncurrently supports proxy users. The PROXY privilege is commonly used with the\npam authentication plugin to enable user and group mapping with PAM.\n\nFor example, to grant the PROXY privilege to an anonymous account that\nauthenticates with the pam authentication plugin, you could execute the\nfollowing:\n\nCREATE USER \'dba\'@\'%\' IDENTIFIED BY \'strongpassword\';\nGRANT ALL PRIVILEGES ON *.* TO \'dba\'@\'%\' ;\n\nCREATE USER \'\'@\'%\' IDENTIFIED VIA pam USING \'mariadb\';\nGRANT PROXY ON \'dba\'@\'%\' TO \'\'@\'%\';\n\nA user account can only grant the PROXY privilege for a specific user account\nif the granter also has the PROXY privilege for that specific user account,\nand if that privilege is defined WITH GRANT OPTION. For example, the following\nexample fails because the granter does not have the PROXY privilege for that\nspecific user account at all:\n\nSELECT USER(), CURRENT_USER();\n+-----------------+-----------------+\n| USER() | CURRENT_USER() |\n+-----------------+-----------------+\n| alice@localhost | alice@localhost |\n+-----------------+-----------------+\n\nSHOW GRANTS;\n+------------------------------------------------------------------------------\n----------------------------------------+\n| Grants for alice@localhost \n |\n+------------------------------------------------------------------------------\n----------------------------------------+\n| GRANT ALL PRIVILEGES ON *.* TO \'alice\'@\'localhost\' IDENTIFIED BY PASSWORD\n\'*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19\' |\n+------------------------------------------------------------------------------\n----------------------------------------+\n\nGRANT PROXY ON \'dba\'@\'localhost\' TO \'bob\'@\'localhost\';\nERROR 1698 (28000): Access denied for user \'alice\'@\'localhost\'\n\nAnd the following example fails because the granter does have the PROXY\nprivilege for that specific user account, but it is not defined WITH GRANT\nOPTION:\n\nSELECT USER(), CURRENT_USER();\n+-----------------+-----------------+\n| USER() | CURRENT_USER() |\n+-----------------+-----------------+\n| alice@localhost | alice@localhost |\n+-----------------+-----------------+\n\nSHOW GRANTS;\n+------------------------------------------------------------------------------\n----------------------------------------+\n| Grants for alice@localhost \n |\n+------------------------------------------------------------------------------\n----------------------------------------+\n| GRANT ALL PRIVILEGES ON *.* TO \'alice\'@\'localhost\' IDENTIFIED BY PASSWORD\n\'*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19\' |\n| GRANT PROXY ON \'dba\'@\'localhost\' TO \'alice\'@\'localhost\' \n |\n+------------------------------------------------------------------------------\n----------------------------------------+\n\nGRANT PROXY ON \'dba\'@\'localhost\' TO \'bob\'@\'localhost\';\nERROR 1698 (28000): Access denied for user \'alice\'@\'localhost\'\n\nBut the following example succeeds because the granter does have the PROXY\nprivilege for that specific user account, and it is defined WITH GRANT OPTION:\n\nSELECT USER(), CURRENT_USER();\n+-----------------+-----------------+\n| USER() | CURRENT_USER() |\n+-----------------+-----------------+\n| alice@localhost | alice@localhost |\n+-----------------+-----------------+\n\nSHOW GRANTS;\n+------------------------------------------------------------------------------\n----------------------------------------------------------+\n| Grants for alice@localhost \n |\n+------------------------------------------------------------------------------\n----------------------------------------------------------+\n| GRANT ALL PRIVILEGES ON *.* TO \'alice\'@\'localhost\' IDENTIFIED BY PASSWORD\n\'*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19\' WITH GRANT OPTION |\n| GRANT PROXY ON \'dba\'@\'localhost\' TO \'alice\'@\'localhost\' WITH GRANT OPTION \n |\n+------------------------------------------------------------------------------\n----------------------------------------------------------+\n\nGRANT PROXY ON \'dba\'@\'localhost\' TO \'bob\'@\'localhost\';\n\nA user account can grant the PROXY privilege for any other user account if the\ngranter has the PROXY privilege for the \'\'@\'%\' anonymous user account, like\nthis:\n\nGRANT PROXY ON \'\'@\'%\' TO \'dba\'@\'localhost\' WITH GRANT OPTION;\n\nFor example, the following example succeeds because the user can grant the\nPROXY privilege for any other user account:\n\nSELECT USER(), CURRENT_USER();\n+-----------------+-----------------+\n| USER() | CURRENT_USER() |\n+-----------------+-----------------+\n| alice@localhost | alice@localhost |\n+-----------------+-----------------+\n\nSHOW GRANTS;\n+------------------------------------------------------------------------------\n----------------------------------------------------------+\n| Grants for alice@localhost \n |\n+------------------------------------------------------------------------------\n----------------------------------------------------------+\n| GRANT ALL PRIVILEGES ON *.* TO \'alice\'@\'localhost\' IDENTIFIED BY PASSWORD\n\'*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19\' WITH GRANT OPTION |\n| GRANT PROXY ON \'\'@\'%\' TO \'alice\'@\'localhost\' WITH GRANT OPTION \n |\n+------------------------------------------------------------------------------\n----------------------------------------------------------+\n\nGRANT PROXY ON \'app1_dba\'@\'localhost\' TO \'bob\'@\'localhost\';\nQuery OK, 0 rows affected (0.004 sec)\n\nGRANT PROXY ON \'app2_dba\'@\'localhost\' TO \'carol\'@\'localhost\';\nQuery OK, 0 rows affected (0.004 sec)\n\nThe default root user accounts created by mariadb-install-db have this\nprivilege. For example:\n\nGRANT ALL PRIVILEGES ON *.* TO \'root\'@\'localhost\' WITH GRANT OPTION;\nGRANT PROXY ON \'\'@\'%\' TO \'root\'@\'localhost\' WITH GRANT OPTION;\n\nThis allows the default root user accounts to grant the PROXY privilege for\nany other user account, and it also allows the default root user accounts to\ngrant others the privilege to do the same.\n\nAuthentication Options\n----------------------\n\nThe authentication options for the GRANT statement are the same as those for\nthe CREATE USER statement.\n\nIDENTIFIED BY \'password\'\n------------------------\n\nThe optional IDENTIFIED BY clause can be used to provide an account with a\npassword. The password should be specified in plain text. It will be hashed by\nthe PASSWORD function prior to being stored.\n\nFor example, if our password is mariadb, then we can create the user with:\n\nGRANT USAGE ON *.* TO foo2@test IDENTIFIED BY \'mariadb\';\n\nIf you do not specify a password with the IDENTIFIED BY clause, the user will\nbe able to connect without a password. A blank password is not a wildcard to\nmatch any password. The user must connect without providing a password if no\npassword is set.\n\nIf the user account already exists and if you provide the IDENTIFIED BY\nclause, then the user\'s password will be changed. You must have the privileges\nneeded for the SET PASSWORD statement to change a user\'s password with GRANT.\n\nThe only authentication plugins that this clause supports are\nmysql_native_password and mysql_old_password.\n\nIDENTIFIED BY PASSWORD \'password_hash\'\n--------------------------------------\n\nThe optional IDENTIFIED BY PASSWORD clause can be used to provide an account\nwith a password that has already been hashed. The password should be specified\nas a hash that was provided by the PASSWORD function. It will be stored as-is.\n\nFor example, if our password is mariadb, then we can find the hash with:\n\nSELECT PASSWORD(\'mariadb\');\n+-------------------------------------------+\n| PASSWORD(\'mariadb\') |\n+-------------------------------------------+\n| *54958E764CE10E50764C2EECBB71D01F08549980 |\n+-------------------------------------------+\n1 row in set (0.00 sec)\n\nAnd then we can create a user with the hash:\n\nGRANT USAGE ON *.* TO foo2@test IDENTIFIED BY \n PASSWORD \'*54958E764CE10E50764C2EECBB71D01F08549980\';\n\nIf you do not specify a password with the IDENTIFIED BY clause, the user will\nbe able to connect without a password. A blank password is not a wildcard to\nmatch any password. The user must connect without providing a password if no\npassword is set.\n\nIf the user account already exists and if you provide the IDENTIFIED BY\nclause, then the user\'s password will be changed. You must have the privileges\nneeded for the SET PASSWORD statement to change a user\'s password with GRANT.\n\nThe only authentication plugins that this clause supports are\nmysql_native_password and mysql_old_password.\n\nIDENTIFIED {VIA|WITH} authentication_plugin\n-------------------------------------------\n\nThe optional IDENTIFIED VIA authentication_plugin allows you to specify that\nthe account should be authenticated by a specific authentication plugin. The\nplugin name must be an active authentication plugin as per SHOW PLUGINS. If it\ndoesn\'t show up in that output, then you will need to install it with INSTALL\nPLUGIN or INSTALL SONAME.\n\nFor example, this could be used with the PAM authentication plugin:\n\nGRANT USAGE ON *.* TO foo2@test IDENTIFIED VIA pam;\n\nSome authentication plugins allow additional arguments to be specified after a\nUSING or AS keyword. For example, the PAM authentication plugin accepts a\nservice name:\n\nGRANT USAGE ON *.* TO foo2@test IDENTIFIED VIA pam USING \'mariadb\';\n\nThe exact meaning of the additional argument would depend on the specific\nauthentication plugin.\n\nMariaDB starting with 10.4.0\n----------------------------\nThe USING or AS keyword can also be used to provide a plain-text password to a\nplugin if it\'s provided as an argument to the PASSWORD() function. This is\nonly valid for authentication plugins that have implemented a hook for the\nPASSWORD() function. For example, the ed25519 authentication plugin supports\nthis:\n\nCREATE USER safe@\'%\' IDENTIFIED VIA ed25519 \n USING PASSWORD(\'secret\');\n\nMariaDB starting with 10.4.3\n----------------------------\nOne can specify many authentication plugins, they all work as alternatives\nways of authenticating a user:\n') WHERE help_topic_id = 108; +update help_topic set description = CONCAT(description, '\nCREATE USER safe@\'%\' IDENTIFIED VIA ed25519 \n USING PASSWORD(\'secret\') OR unix_socket;\n\nBy default, when you create a user without specifying an authentication\nplugin, MariaDB uses the mysql_native_password plugin.\n\nResource Limit Options\n----------------------\n\nIt is possible to set per-account limits for certain server resources. The\nfollowing table shows the values that can be set per account:\n\n+--------------------------------------+--------------------------------------+\n| Limit Type | Decription |\n+--------------------------------------+--------------------------------------+\n| MAX_QUERIES_PER_HOUR | Number of statements that the |\n| | account can issue per hour |\n| | (including updates) |\n+--------------------------------------+--------------------------------------+\n| MAX_UPDATES_PER_HOUR | Number of updates (not queries) |\n| | that the account can issue per hour |\n+--------------------------------------+--------------------------------------+\n| MAX_CONNECTIONS_PER_HOUR | Number of connections that the |\n| | account can start per hour |\n+--------------------------------------+--------------------------------------+\n| MAX_USER_CONNECTIONS | Number of simultaneous connections |\n| | that can be accepted from the same |\n| | account; if it is 0, |\n| | max_connections will be used |\n| | instead; if max_connections is 0, |\n| | there is no limit for this |\n| | account\'s simultaneous connections. |\n+--------------------------------------+--------------------------------------+\n| MAX_STATEMENT_TIME | Timeout, in seconds, for statements |\n| | executed by the user. See also |\n| | Aborting Statements that Exceed a |\n| | Certain Time to Execute. |\n+--------------------------------------+--------------------------------------+\n\nIf any of these limits are set to 0, then there is no limit for that resource\nfor that user.\n\nTo set resource limits for an account, if you do not want to change that\naccount\'s privileges, you can issue a GRANT statement with the USAGE\nprivilege, which has no meaning. The statement can name some or all limit\ntypes, in any order.\n\nHere is an example showing how to set resource limits:\n\nGRANT USAGE ON *.* TO \'someone\'@\'localhost\' WITH\n MAX_USER_CONNECTIONS 0\n MAX_QUERIES_PER_HOUR 200;\n\nThe resources are tracked per account, which means \'user\'@\'server\'; not per\nuser name or per connection.\n\nThe count can be reset for all users using FLUSH USER_RESOURCES, FLUSH\nPRIVILEGES or mariadb-admin reload.\n\nUsers with the CONNECTION ADMIN privilege (in MariaDB 10.5.2 and later) or the\nSUPER privilege are not restricted by max_user_connections, max_connections,\nor max_password_errors.\n\nPer account resource limits are stored in the user table, in the mysql\ndatabase. Columns used for resources limits are named max_questions,\nmax_updates, max_connections (for MAX_CONNECTIONS_PER_HOUR), and\nmax_user_connections (for MAX_USER_CONNECTIONS).\n\nTLS Options\n-----------\n\nBy default, MariaDB transmits data between the server and clients without\nencrypting it. This is generally acceptable when the server and client run on\nthe same host or in networks where security is guaranteed through other means.\nHowever, in cases where the server and client exist on separate networks or\nthey are in a high-risk network, the lack of encryption does introduce\nsecurity concerns as a malicious actor could potentially eavesdrop on the\ntraffic as it is sent over the network between them.\n\nTo mitigate this concern, MariaDB allows you to encrypt data in transit\nbetween the server and clients using the Transport Layer Security (TLS)\nprotocol. TLS was formerly known as Secure Socket Layer (SSL), but strictly\nspeaking the SSL protocol is a predecessor to TLS and, that version of the\nprotocol is now considered insecure. The documentation still uses the term SSL\noften and for compatibility reasons TLS-related server system and status\nvariables still use the prefix ssl_, but internally, MariaDB only supports its\nsecure successors.\n\nSee Secure Connections Overview for more information about how to determine\nwhether your MariaDB server has TLS support.\n\nYou can set certain TLS-related restrictions for specific user accounts. For\ninstance, you might use this with user accounts that require access to\nsensitive data while sending it across networks that you do not control. These\nrestrictions can be enabled for a user account with the CREATE USER, ALTER\nUSER, or GRANT statements. The following options are available:\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| REQUIRE NONE | TLS is not required for this account, but can |\n| | still be used. |\n+---------------------------+------------------------------------------------+\n| REQUIRE SSL | The account must use TLS, but no valid X509 |\n| | certificate is required. This option cannot |\n| | be combined with other TLS options. |\n+---------------------------+------------------------------------------------+\n| REQUIRE X509 | The account must use TLS and must have a |\n| | valid X509 certificate. This option implies |\n| | REQUIRE SSL. This option cannot be combined |\n| | with other TLS options. |\n+---------------------------+------------------------------------------------+\n| REQUIRE ISSUER \'issuer\' | The account must use TLS and must have a |\n| | valid X509 certificate. Also, the Certificate |\n| | Authority must be the one specified via the |\n| | string issuer. This option implies REQUIRE |\n| | X509. This option can be combined with the |\n| | SUBJECT, and CIPHER options in any order. |\n+---------------------------+------------------------------------------------+\n| REQUIRE SUBJECT \'subject\' | The account must use TLS and must have a |\n| | valid X509 certificate. Also, the |\n| | certificate\'s Subject must be the one |\n| | specified via the string subject. This option |\n| | implies REQUIRE X509. This option can be |\n| | combined with the ISSUER, and CIPHER options |\n| | in any order. |\n+---------------------------+------------------------------------------------+\n| REQUIRE CIPHER \'cipher\' | The account must use TLS, but no valid X509 |\n| | certificate is required. Also, the encryption |\n| | used for the connection must use a specific |\n| | cipher method specified in the string cipher. |\n| | This option implies REQUIRE SSL. This option |\n| | can be combined with the ISSUER, and SUBJECT |\n| | options in any order. |\n+---------------------------+------------------------------------------------+\n\nThe REQUIRE keyword must be used only once for all specified options, and the\nAND keyword can be used to separate individual options, but it is not required.\n\nFor example, you can create a user account that requires these TLS options\nwith the following:\n\nGRANT USAGE ON *.* TO \'alice\'@\'%\'\n REQUIRE SUBJECT \'/CN=alice/O=My Dom, Inc./C=US/ST=Oregon/L=Portland\'\n AND ISSUER \'/C=FI/ST=Somewhere/L=City/ O=Some Company/CN=Peter\nParker/emailAddress=p.parker@marvel.com\'\n AND CIPHER \'SHA-DES-CBC3-EDH-RSA\';\n\nIf any of these options are set for a specific user account, then any client\nwho tries to connect with that user account will have to be configured to\nconnect with TLS.\n\nSee Securing Connections for Client and Server for information on how to\nenable TLS on the client and server.\n\nRoles\n-----\n\nSyntax\n------\n\nGRANT role TO grantee [, grantee ... ]\n[ WITH ADMIN OPTION ]\n\ngrantee:\n rolename\n username [authentication_option]\n\nThe GRANT statement is also used to grant the use of a role to one or more\nusers or other roles. In order to be able to grant a role, the grantor doing\nso must have permission to do so (see WITH ADMIN in the CREATE ROLE article).\n\nSpecifying the WITH ADMIN OPTION permits the grantee to in turn grant the role\nto another.\n\nFor example, the following commands show how to grant the same role to a\ncouple different users.\n\nGRANT journalist TO hulda;\n\nGRANT journalist TO berengar WITH ADMIN OPTION;\n\nIf a user has been granted a role, they do not automatically obtain all\npermissions associated with that role. These permissions are only in use when\nthe user activates the role with the SET ROLE statement.\n\nTO PUBLIC\n---------\n\nMariaDB starting with 10.11\n---------------------------\n\nSyntax\n------\n\nGRANT <privilege> ON <database>.<object> TO PUBLIC;\nREVOKE <privilege> ON <database>.<object> FROM PUBLIC;\n\nGRANT ... TO PUBLIC grants privileges to all users with access to the server.\nThe privileges also apply to users created after the privileges are granted.\nThis can be useful when one only wants to state once that all users need to\nhave a certain set of privileges.\n\nWhen running SHOW GRANTS, a user will also see all privileges inherited from\nPUBLIC. SHOW GRANTS FOR PUBLIC will only show TO PUBLIC grants.\n\nGrant Examples\n--------------\n\nGranting Root-like Privileges\n-----------------------------\n\nYou can create a user that has privileges similar to the default root accounts\nby executing the following:\n\nCREATE USER \'alexander\'@\'localhost\';\nGRANT ALL PRIVILEGES ON *.* to \'alexander\'@\'localhost\' WITH GRANT OPTION;\n\nURL: https://mariadb.com/kb/en/grant/') WHERE help_topic_id = 108; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (109,10,'RENAME USER','Syntax\n------\n\nRENAME USER old_user TO new_user\n [, old_user TO new_user] ...\n\nDescription\n-----------\n\nThe RENAME USER statement renames existing MariaDB accounts. To use it, you\nmust have the global CREATE USER privilege or the UPDATE privilege for the\nmysql database. Each account is named using the same format as for the CREATE\nUSER statement; for example, \'jeffrey\'@\'localhost\'. If you specify only the\nuser name part of the account name, a host name part of \'%\' is used.\n\nIf any of the old user accounts do not exist or any of the new user accounts\nalready exist, ERROR 1396 (HY000) results. If an error occurs, RENAME USER\nwill still rename the accounts that do not result in an error.\n\nExamples\n--------\n\nCREATE USER \'donald\', \'mickey\';\nRENAME USER \'donald\' TO \'duck\'@\'localhost\', \'mickey\' TO \'mouse\'@\'localhost\';\n\nURL: https://mariadb.com/kb/en/rename-user/','','https://mariadb.com/kb/en/rename-user/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (110,10,'REVOKE','Privileges\n----------\n\nSyntax\n------\n\nREVOKE \n priv_type [(column_list)]\n [, priv_type [(column_list)]] ...\n ON [object_type] priv_level\n FROM user [, user] ...\n\nREVOKE ALL PRIVILEGES, GRANT OPTION\n FROM user [, user] ...\n\nDescription\n-----------\n\nThe REVOKE statement enables system administrators to revoke privileges (or\nroles - see section below) from MariaDB accounts. Each account is named using\nthe same format as for the GRANT statement; for example,\n\'jeffrey\'@\'localhost\'. If you specify only the user name part of the account\nname, a host name part of \'%\' is used. For details on the levels at which\nprivileges exist, the allowable priv_type and priv_level values, and the\nsyntax for specifying users and passwords, see GRANT.\n\nTo use the first REVOKE syntax, you must have the GRANT OPTION privilege, and\nyou must have the privileges that you are revoking.\n\nTo revoke all privileges, use the second syntax, which drops all global,\ndatabase, table, column, and routine privileges for the named user or users:\n\nREVOKE ALL PRIVILEGES, GRANT OPTION FROM user [, user] ...\n\nTo use this REVOKE syntax, you must have the global CREATE USER privilege or\nthe UPDATE privilege for the mysql database. See GRANT.\n\nExamples\n--------\n\nREVOKE SUPER ON *.* FROM \'alexander\'@\'localhost\';\n\nRoles\n-----\n\nSyntax\n------\n\nREVOKE role [, role ...]\n FROM grantee [, grantee2 ... ]\n\nREVOKE ADMIN OPTION FOR role FROM grantee [, grantee2]\n\nDescription\n-----------\n\nREVOKE is also used to remove a role from a user or another role that it\'s\npreviously been assigned to. If a role has previously been set as a default\nrole, REVOKE does not remove the record of the default role from the\nmysql.user table. If the role is subsequently granted again, it will again be\nthe user\'s default. Use SET DEFAULT ROLE NONE to explicitly remove this.\n\nBefore MariaDB 10.1.13, the REVOKE role statement was not permitted in\nprepared statements.\n\nExample\n-------\n\nREVOKE journalist FROM hulda\n\nURL: https://mariadb.com/kb/en/revoke/','','https://mariadb.com/kb/en/revoke/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (111,10,'SET PASSWORD','Syntax\n------\n\nSET PASSWORD [FOR user] =\n {\n PASSWORD(\'some password\')\n | OLD_PASSWORD(\'some password\')\n | \'encrypted password\'\n }\n\nDescription\n-----------\n\nThe SET PASSWORD statement assigns a password to an existing MariaDB user\naccount.\n\nIf the password is specified using the PASSWORD() or OLD_PASSWORD() function,\nthe literal text of the password should be given. If the password is specified\nwithout using either function, the password should be the already-encrypted\npassword value as returned by PASSWORD().\n\nOLD_PASSWORD() should only be used if your MariaDB/MySQL clients are very old\n(< 4.0.0).\n\nWith no FOR clause, this statement sets the password for the current user. Any\nclient that has connected to the server using a non-anonymous account can\nchange the password for that account.\n\nWith a FOR clause, this statement sets the password for a specific account on\nthe current server host. Only clients that have the UPDATE privilege for the\nmysql database can do this. The user value should be given in\nuser_name@host_name format, where user_name and host_name are exactly as they\nare listed in the User and Host columns of the mysql.user table (or view in\nMariaDB-10.4 onwards) entry.\n\nThe argument to PASSWORD() and the password given to MariaDB clients can be of\narbitrary length.\n\nAuthentication Plugin Support\n-----------------------------\n\nMariaDB starting with 10.4\n--------------------------\nIn MariaDB 10.4 and later, SET PASSWORD (with or without PASSWORD()) works for\naccounts authenticated via any authentication plugin that supports passwords\nstored in the mysql.global_priv table.\n\nThe ed25519, mysql_native_password, and mysql_old_password authentication\nplugins store passwords in the mysql.global_priv table.\n\nIf you run SET PASSWORD on an account that authenticates with one of these\nauthentication plugins that stores passwords in the mysql.global_priv table,\nthen the PASSWORD() function is evaluated by the specific authentication\nplugin used by the account. The authentication plugin hashes the password with\na method that is compatible with that specific authentication plugin.\n\nThe unix_socket, named_pipe, gssapi, and pam authentication plugins do not\nstore passwords in the mysql.global_priv table. These authentication plugins\nrely on other methods to authenticate the user.\n\nIf you attempt to run SET PASSWORD on an account that authenticates with one\nof these authentication plugins that doesn\'t store a password in the\nmysql.global_priv table, then MariaDB Server will raise a warning like the\nfollowing:\n\nSET PASSWORD is ignored for users authenticating via unix_socket plugin\n\nSee Authentication from MariaDB 10.4 for an overview of authentication changes\nin MariaDB 10.4.\n\nMariaDB until 10.3\n------------------\nIn MariaDB 10.3 and before, SET PASSWORD (with or without PASSWORD()) only\nworks for accounts authenticated via mysql_native_password or\nmysql_old_password authentication plugins\n\nPasswordless User Accounts\n--------------------------\n\nUser accounts do not always require passwords to login.\n\nThe unix_socket , named_pipe and gssapi authentication plugins do not require\na password to authenticate the user.\n\nThe pam authentication plugin may or may not require a password to\nauthenticate the user, depending on the specific configuration.\n\nThe mysql_native_password and mysql_old_password authentication plugins\nrequire passwords for authentication, but the password can be blank. In that\ncase, no password is required.\n\nIf you provide a password while attempting to log into the server as an\naccount that doesn\'t require a password, then MariaDB server will simply\nignore the password.\n\nMariaDB starting with 10.4\n--------------------------\nIn MariaDB 10.4 and later, a user account can be defined to use multiple\nauthentication plugins in a specific order of preference. This specific\nscenario may be more noticeable in these versions, since an account could be\nassociated with some authentication plugins that require a password, and some\nthat do not.\n\nExample\n-------\n\nFor example, if you had an entry with User and Host column values of \'bob\' and\n\'%.loc.gov\', you would write the statement like this:\n\nSET PASSWORD FOR \'bob\'@\'%.loc.gov\' = PASSWORD(\'newpass\');\n\nIf you want to delete a password for a user, you would do:\n\nSET PASSWORD FOR \'bob\'@localhost = PASSWORD(\"\");\n\nURL: https://mariadb.com/kb/en/set-password/','','https://mariadb.com/kb/en/set-password/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (112,10,'CREATE ROLE','Syntax\n------\n\nCREATE [OR REPLACE] ROLE [IF NOT EXISTS] role \n [WITH ADMIN\n {CURRENT_USER | CURRENT_ROLE | user | role}]\n\nDescription\n-----------\n\nThe CREATE ROLE statement creates one or more MariaDB roles. To use it, you\nmust have the global CREATE USER privilege or the INSERT privilege for the\nmysql database. For each account, CREATE ROLE creates a new row in the\nmysql.user table that has no privileges, and with the corresponding is_role\nfield set to Y. It also creates a record in the mysql.roles_mapping table.\n\nIf any of the specified roles already exist, ERROR 1396 (HY000) results. If an\nerror occurs, CREATE ROLE will still create the roles that do not result in an\nerror. The maximum length for a role is 128 characters. Role names can be\nquoted, as explained in the Identifier names page. Only one error is produced\nfor all roles which have not been created:\n\nERROR 1396 (HY000): Operation CREATE ROLE failed for \'a\',\'b\',\'c\'\n\nFailed CREATE or DROP operations, for both users and roles, produce the same\nerror code.\n\nPUBLIC and NONE are reserved, and cannot be used as role names. NONE is used\nto unset a role and PUBLIC has a special use in other systems, such as Oracle,\nso is reserved for compatibility purposes.\n\nFor valid identifiers to use as role names, see Identifier Names.\n\nWITH ADMIN\n----------\n\nThe optional WITH ADMIN clause determines whether the current user, the\ncurrent role or another user or role has use of the newly created role. If the\nclause is omitted, WITH ADMIN CURRENT_USER is treated as the default, which\nmeans that the current user will be able to GRANT this role to users.\n\nOR REPLACE\n----------\n\nIf the optional OR REPLACE clause is used, it acts as a shortcut for:\n\nDROP ROLE IF EXISTS name;\nCREATE ROLE name ...;\n\nIF NOT EXISTS\n-------------\n\nWhen the IF NOT EXISTS clause is used, MariaDB will return a warning instead\nof an error if the specified role already exists. Cannot be used together with\nthe OR REPLACE clause.\n\nExamples\n--------\n\nCREATE ROLE journalist;\n\nCREATE ROLE developer WITH ADMIN lorinda@localhost;\n\nGranting the role to another user. Only user lorinda@localhost has permission\nto grant the developer role:\n\nSELECT USER();\n+-------------------+\n| USER() |\n+-------------------+\n| henning@localhost |\n+-------------------+\n...\nGRANT developer TO ian@localhost;\nAccess denied for user \'henning\'@\'localhost\'\n\nSELECT USER();\n+-------------------+\n| USER() |\n+-------------------+\n| lorinda@localhost |\n+-------------------+\n\nGRANT m_role TO ian@localhost;\n\nThe OR REPLACE and IF NOT EXISTS clauses. The journalist role already exists:\n\nCREATE ROLE journalist;\nERROR 1396 (HY000): Operation CREATE ROLE failed for \'journalist\'\n\nCREATE OR REPLACE ROLE journalist;\nQuery OK, 0 rows affected (0.00 sec)\n\nCREATE ROLE IF NOT EXISTS journalist;\nQuery OK, 0 rows affected, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+-------+------+---------------------------------------------------+\n| Level | Code | Message |\n+-------+------+---------------------------------------------------+\n| Note | 1975 | Can\'t create role \'journalist\'; it already exists |\n+-------+------+---------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/create-role/','','https://mariadb.com/kb/en/create-role/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (113,10,'DROP ROLE','Syntax\n------\n\nDROP ROLE [IF EXISTS] role_name [,role_name ...]\n\nDescription\n-----------\n\nThe DROP ROLE statement removes one or more MariaDB roles. To use this\nstatement, you must have the global CREATE USER privilege or the DELETE\nprivilege for the mysql database.\n\nDROP ROLE does not disable roles for connections which selected them with SET\nROLE. If a role has previously been set as a default role, DROP ROLE does not\nremove the record of the default role from the mysql.user table. If the role\nis subsequently recreated and granted, it will again be the user\'s default.\nUse SET DEFAULT ROLE NONE to explicitly remove this.\n\nIf any of the specified user accounts do not exist, ERROR 1396 (HY000)\nresults. If an error occurs, DROP ROLE will still drop the roles that do not\nresult in an error. Only one error is produced for all roles which have not\nbeen dropped:\n\nERROR 1396 (HY000): Operation DROP ROLE failed for \'a\',\'b\',\'c\'\n\nFailed CREATE or DROP operations, for both users and roles, produce the same\nerror code.\n\nIF EXISTS\n---------\n\nIf the IF EXISTS clause is used, MariaDB will return a warning instead of an\nerror if the role does not exist.\n\nExamples\n--------\n\nDROP ROLE journalist;\n\nThe same thing using the optional IF EXISTS clause:\n\nDROP ROLE journalist;\nERROR 1396 (HY000): Operation DROP ROLE failed for \'journalist\'\n\nDROP ROLE IF EXISTS journalist;\nQuery OK, 0 rows affected, 1 warning (0.00 sec)\n\nNote (Code 1975): Can\'t drop role \'journalist\'; it doesn\'t exist\n\nURL: https://mariadb.com/kb/en/drop-role/','','https://mariadb.com/kb/en/drop-role/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (114,10,'SET ROLE','Syntax\n------\n\nSET ROLE { role | NONE }\n\nDescription\n-----------\n\nThe SET ROLE statement enables a role, along with all of its associated\npermissions, for the current session. To unset a role, use NONE .\n\nIf a role that doesn\'t exist, or to which the user has not been assigned, is\nspecified, an ERROR 1959 (OP000): Invalid role specification error occurs.\n\nAn automatic SET ROLE is implicitly performed when a user connects if that\nuser has been assigned a default role. See SET DEFAULT ROLE.\n\nExample\n-------\n\nSELECT CURRENT_ROLE;\n+--------------+\n| CURRENT_ROLE |\n+--------------+\n| NULL |\n+--------------+\n\nSET ROLE staff;\n\nSELECT CURRENT_ROLE;\n+--------------+\n| CURRENT_ROLE |\n+--------------+\n| staff |\n+--------------+\n\nSET ROLE NONE;\n\nSELECT CURRENT_ROLE();\n+----------------+\n| CURRENT_ROLE() |\n+----------------+\n| NULL |\n+----------------+\n\nURL: https://mariadb.com/kb/en/set-role/','','https://mariadb.com/kb/en/set-role/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (115,10,'SET DEFAULT ROLE','Syntax\n------\n\nSET DEFAULT ROLE { role | NONE } [ FOR user@host ]\n\nDescription\n-----------\n\nThe SET DEFAULT ROLE statement sets a default role for a specified (or\ncurrent) user. A default role is automatically enabled when a user connects\n(an implicit SET ROLE statement is executed immediately after a connection is\nestablished).\n\nTo be able to set a role as a default, the role must already have been granted\nto that user, and one needs the privileges to enable this role (if you cannot\ndo SET ROLE X, you won\'t be able to do SET DEFAULT ROLE X). To set a default\nrole for another user one needs to have write access to the mysql database.\n\nTo remove a user\'s default role, use SET DEFAULT ROLE NONE [ FOR user@host ].\nThe record of the default role is not removed if the role is dropped or\nrevoked, so if the role is subsequently re-created or granted, it will again\nbe the user\'s default role.\n\nThe default role is stored in the default_role column in the mysql.user\ntable/view, as well as in the Information Schema APPLICABLE_ROLES table, so\nthese can be viewed to see which role has been assigned to a user as the\ndefault.\n\nExamples\n--------\n\nSetting a default role for the current user:\n\nSET DEFAULT ROLE journalist;\n\nRemoving a default role from the current user:\n\nSET DEFAULT ROLE NONE;\n\nSetting a default role for another user. The role has to have been granted to\nthe user before it can be set as default:\n\nCREATE ROLE journalist;\nCREATE USER taniel;\n\nSET DEFAULT ROLE journalist FOR taniel;\nERROR 1959 (OP000): Invalid role specification `journalist`\n\nGRANT journalist TO taniel;\nSET DEFAULT ROLE journalist FOR taniel;\n\nViewing mysql.user:\n\nselect * from mysql.user where user=\'taniel\'\\G\n*************************** 1. row ***************************\n Host: %\n User: taniel\n...\n is_role: N\n default_role: journalist\n...\n\nRemoving a default role for another user\n\nSET DEFAULT ROLE NONE FOR taniel;\n\nURL: https://mariadb.com/kb/en/set-default-role/','','https://mariadb.com/kb/en/set-default-role/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (116,10,'Roles Overview','Description\n-----------\n\nA role bundles a number of privileges together. It assists larger\norganizations where, typically, a number of users would have the same\nprivileges, and, previously, the only way to change the privileges for a group\nof users was by changing each user\'s privileges individually.\n\nAlternatively, multiple external users could have been assigned the same user,\nand there would have been no way to see which actual user was responsible for\nwhich action.\n\nWith roles, managing this is easy. For example, there could be a number of\nusers assigned to a journalist role, with identical privileges. Changing the\nprivileges for all the journalists is a matter of simply changing the role\'s\nprivileges, while the individual user is still linked with any changes that\ntake place.\n\nRoles are created with the CREATE ROLE statement, and dropped with the DROP\nROLE statement. Roles are then assigned to a user with an extension to the\nGRANT statement, while privileges are assigned to a role in the regular way\nwith GRANT. Similarly, the REVOKE statement can be used to both revoke a role\nfrom a user, or revoke a privilege from a role.\n\nOnce a user has connected, he can obtain all privileges associated with a role\nby setting a role with the SET ROLE statement. The CURRENT_ROLE function\nreturns the currently set role for the session, if any.\n\nOnly roles granted directly to a user can be set, roles granted to other roles\ncannot. Instead the privileges granted to a role, which is, in turn, granted\nto another role (grantee), will be immediately available to any user who sets\nthis second grantee role.\n\nThe SET DEFAULT ROLE statement allows one to set a default role for a user. A\ndefault role is automatically enabled when a user connects (an implicit SET\nROLE statement is executed immediately after a connection is established).\n\nRoles were implemented as a GSoC 2013 project by Vicentiu Ciorbaru.\n\nSystem Tables\n-------------\n\nInformation about roles and who they\'ve been granted to can be found in the\nInformation Schema APPLICABLE_ROLES table as well as the mysql.ROLES_MAPPING\ntable.\n\nThe Information Schema ENABLED_ROLES table shows the enabled roles for the\ncurrent session.\n\nExamples\n--------\n\nCreating a role and granting a privilege:\n\nCREATE ROLE journalist;\n\nGRANT SHOW DATABASES ON *.* TO journalist;\n\nGRANT journalist to hulda;\n\nNote, that hulda has no SHOW DATABASES privilege, even though she was granted\nthe journalist role. She needs to set the role first:\n\nSHOW DATABASES;\n+--------------------+\n| Database |\n+--------------------+\n| information_schema |\n+--------------------+\n\nSELECT CURRENT_ROLE;\n+--------------+\n| CURRENT_ROLE |\n+--------------+\n| NULL |\n+--------------+\n\nSET ROLE journalist;\n\nSELECT CURRENT_ROLE;\n+--------------+\n| CURRENT_ROLE |\n+--------------+\n| journalist |\n+--------------+\n\nSHOW DATABASES;\n+--------------------+\n| Database |\n+--------------------+\n| ... |\n| information_schema |\n| mysql |\n| performance_schema |\n| test |\n| ... |\n+--------------------+\n\nSET ROLE NONE;\n\nRoles can be granted to roles:\n\nCREATE ROLE writer;\n\nGRANT SELECT ON data.* TO writer;\n\nGRANT writer TO journalist;\n\nBut one does not need to set a role granted to a role. For example, hulda will\nautomatically get all writer privileges when she sets the journalist role:\n\nSELECT CURRENT_ROLE;\n+--------------+\n| CURRENT_ROLE |\n+--------------+\n| NULL |\n+--------------+\n\nSHOW TABLES FROM data;\nEmpty set (0.01 sec)\n\nSET ROLE journalist;\n\nSELECT CURRENT_ROLE;\n+--------------+\n| CURRENT_ROLE |\n+--------------+\n| journalist |\n+--------------+\n\nSHOW TABLES FROM data;\n+------------------------------+\n| Tables_in_data |\n+------------------------------+\n| set1 |\n| ... |\n+------------------------------+\n\nRoles and Views (and Stored Routines)\n-------------------------------------\n\nWhen a user sets a role, he, in a sense, has two identities with two\nassociated sets of privileges. But a view (or a stored routine) can have only\none definer. So, when a view (or a stored routine) is created with the SQL\nSECURITY DEFINER, one can specify whether the definer should be CURRENT_USER\n(and the view will have none of the privileges of the user\'s role) or\nCURRENT_ROLE (in this case, the view will use role\'s privileges, but none of\nthe user\'s privileges). As a result, sometimes one can create a view that is\nimpossible to use.\n\nCREATE ROLE r1;\n\nGRANT ALL ON db1.* TO r1;\n\nGRANT r1 TO foo@localhost;\n\nGRANT ALL ON db.* TO foo@localhost;\n\nSELECT CURRENT_USER\n+---------------+\n| current_user |\n+---------------+\n| foo@localhost |\n+---------------+\n\nSET ROLE r1;\n\nCREATE TABLE db1.t1 (i int);\n\nCREATE VIEW db.v1 AS SELECT * FROM db1.t1;\n\nSHOW CREATE VIEW db.v1;\n+------+-----------------------------------------------------------------------\n------------------------------------------------------------------+------------\n---------+----------------------+\n| View | Create View \n |\ncharacter_set_client | collation_connection |\n+------+-----------------------------------------------------------------------\n------------------------------------------------------------------+------------\n---------+----------------------+\n| v1 | CREATE ALGORITHM=UNDEFINED DEFINER=`foo`@`localhost` SQL SECURITY\nDEFINER VIEW `db`.`v1` AS SELECT `db1`.`t1`.`i` AS `i` from `db1`.`t1` | utf8 \n | utf8_general_ci |\n+------+-----------------------------------------------------------------------\n------------------------------------------------------------------+------------\n---------+----------------------+\n\nCREATE DEFINER=CURRENT_ROLE VIEW db.v2 AS SELECT * FROM db1.t1;\n\nSHOW CREATE VIEW db.b2;\n+------+-----------------------------------------------------------------------\n-----------------------------------------------------+----------------------+--\n-------------------+\n| View | Create View \n | character_set_client |\ncollation_connection |\n+------+-----------------------------------------------------------------------\n-----------------------------------------------------+----------------------+--\n-------------------+\n| v2 | CREATE ALGORITHM=UNDEFINED DEFINER=`r1` SQL SECURITY DEFINER VIEW\n`db`.`v2` AS select `db1`.`t1`.`a` AS `a` from `db1`.`t1` | utf8 \n | utf8_general_ci |\n+------+-----------------------------------------------------------------------\n-----------------------------------------------------+----------------------+--\n-------------------+\n\nOther Resources\n---------------\n\n* Roles Review by Peter Gulutzan\n\nURL: https://mariadb.com/kb/en/roles_overview/','','https://mariadb.com/kb/en/roles_overview/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (117,10,'Account Locking','MariaDB starting with 10.4.2\n----------------------------\nAccount locking was introduced in MariaDB 10.4.2.\n\nDescription\n-----------\n\nAccount locking permits privileged administrators to lock/unlock user\naccounts. No new client connections will be permitted if an account is locked\n(existing connections are not affected).\n\nUser accounts can be locked at creation, with the CREATE USER statement, or\nmodified after creation with the ALTER USER statement. For example:\n\nCREATE USER \'lorin\'@\'localhost\' ACCOUNT LOCK;\n\nor\n\nALTER USER \'marijn\'@\'localhost\' ACCOUNT LOCK;\n\nThe server will return an ER_ACCOUNT_HAS_BEEN_LOCKED error when locked users\nattempt to connect:\n\nmysql -ulorin\n ERROR 4151 (HY000): Access denied, this account is locked\n\nThe ALTER USER statement is also used to unlock a user:\n\nALTER USER \'lorin\'@\'localhost\' ACCOUNT UNLOCK;\n\nThe SHOW CREATE USER statement will show whether the account is locked:\n\nSHOW CREATE USER \'marijn\'@\'localhost\';\n+-----------------------------------------------+\n| CREATE USER for marijn@localhost |\n+-----------------------------------------------+\n| CREATE USER \'marijn\'@\'localhost\' ACCOUNT LOCK |\n+-----------------------------------------------+\n\nas well as querying the mysql.global_priv table:\n\nSELECT CONCAT(user, \'@\', host, \' => \', JSON_DETAILED(priv)) FROM\nmysql.global_priv \n WHERE user=\'marijn\';\n+------------------------------------------------------------------------------\n-------+\n| CONCAT(user, \'@\', host, \' => \', JSON_DETAILED(priv)) \n |\n+------------------------------------------------------------------------------\n-------+\n| marijn@localhost => {\n \"access\": 0,\n \"plugin\": \"mysql_native_password\",\n \"authentication_string\": \"\",\n \"account_locked\": true,\n \"password_last_changed\": 1558017158\n} |\n+------------------------------------------------------------------------------\n-------+\n\nURL: https://mariadb.com/kb/en/account-locking/','','https://mariadb.com/kb/en/account-locking/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (118,10,'Authentication from MariaDB 10.4','MariaDB starting with 10.4\n--------------------------\nMariaDB 10.4 introduced a number of changes to the authentication process,\nintended to make things easier and more intuitive.\n\nOverview\n--------\n\nThere are four new main features in 10.4 relating to authentication:\n\n* It is possible to use more than one authentication plugin for each user\naccount. For example, this can be useful to slowly migrate users to the more\nsecure ed25519 authentication plugin over time, while allowing the old\nmysql_native_password authentication plugin as an alternative for the\ntransitional period.\n* The root@localhost user account created by mariadb-install-db is created\nwith the ability to use two authentication plugins.\nFirst, it is configured to try to use the unix_socket authentication plugin.\nThis allows the root@localhost user to login without a password via the local\nUnix socket file defined by the socket system variable, as long as the login\nis attempted from a process owned by the operating system root user account.\nSecond, if authentication fails with the unix_socket authentication plugin,\nthen it is configured to try to use the mysql_native_password authentication\nplugin. However, an invalid password is initially set, so in order to\nauthenticate this way, a password must be set with SET PASSWORD.\nHowever, just using the unix_socket authentication plugin may be fine for many\nusers, and it is very secure. You may want to try going without password\nauthentication to see how well it works for you. Remember, the best way to\nkeep your password safe is not to have one!\n\n* All user accounts, passwords, and global privileges are now stored in the\nmysql.global_priv table. The mysql.user table still exists and has exactly the\nsame set of columns as before, but it’s now a view that references the\nmysql.global_priv table. Tools that analyze the mysql.user table should\ncontinue to work as before. From MariaDB 10.4.13, the dedicated mariadb.sys\nuser is created as the definer of this view. Previously root was the definer,\nwhich resulted in privilege problems when this username was changed.\n* MariaDB 10.4 adds supports for User Password Expiry, which is not active by\ndefault.\n\nDescription\n-----------\n\nAs a result of the above changes, the open-for-everyone all-powerful root\naccount is finally gone. And installation scripts will no longer demand that\nyou \"PLEASE REMEMBER TO SET A PASSWORD FOR THE MariaDB root USER !\", because\nthe root account is securely created automatically.\n\nTwo all-powerful accounts are created by default — root and the OS user that\nowns the data directory, typically mysql. They are created as:\n\nCREATE USER root@localhost IDENTIFIED VIA unix_socket OR mysql_native_password\nUSING \'invalid\'\nCREATE USER mysql@localhost IDENTIFIED VIA unix_socket OR\nmysql_native_password USING \'invalid\'\n\nUsing unix_socket means that if you are the system root user, you can login as\nroot@locahost without a password. This technique was pioneered by Otto\nKekäläinen in Debian MariaDB packages and has been successfully used in Debian\nsince as early as MariaDB 10.0.\n\nIt is based on a simple fact that asking the system root for a password adds\nno extra security — root has full access to all the data files and all process\nmemory anyway. But not asking for a password means, there is no root password\nto forget (no need for the numerous tutorials on \"how to reset MariaDB root\npassword\"). And if you want to script some tedious database work, there is no\nneed to store the root password in plain text for the script to use (no need\nfor debian-sys-maint user).\n\nStill, some users may wish to log in as MariaDB root without using sudo. Hence\nthe old authentication method — conventional MariaDB password — is still\navailable. By default it is disabled (\"invalid\" is not a valid password hash),\nbut one can set the password with a usual SET PASSWORD statement. And still\nretain the password-less access via sudo.\n\nIf you install MariaDB locally (say from a tarball), you would not want to use\nsudo to be able to login. This is why MariaDB creates a second all-powerful\nuser with the same name as a system user that owns the data directory. In\nlocal (not system-wide) installations, this will be the user who installed\nMariaDB — they automatically get convenient password-less root-like access,\nbecause they can access all the data files anyway.\n\nEven if MariaDB is installed system-wide, you may not want to run your\ndatabase maintenance scripts as system root — now you can run them as system\nmysql user. And you will know that they will never destroy your entire system,\neven if you make a typo in a shell script.\n\nHowever, seasoned MariaDB DBAs who are used to the old ways do need to make\nsome changes. See the examples below for common tasks.\n\nCookbook\n--------\n\nAfter installing MariaDB system-wide the first thing you’ve got used to doing\nis logging in into the unprotected root account and protecting it, that is,\nsetting the root password:\n\n$ sudo dnf install MariaDB-server\n$ mysql -uroot\n...\nMariaDB> set password = password(\"XH4VmT3_jt\");\n\nThis is not only unnecessary now, it will simply not work — there is no\nunprotected root account. To login as root use\n\n$ sudo dnf install MariaDB-server\n$ sudo mysql\n\nNote that it implies you are connecting via the unix socket, not tcp. If you\nhappen to have protocol=tcp in a system-wide /etc/my.cnf file, use sudo mysql\n--protocol=socket.\n\nAfter installing MariaDB locally you’ve also used to connect to the\nunprotected root account using mysql -uroot. This will not work either, simply\nuse mysql without specifying a username.\n\nIf you\'ve forgotten your root password, no problem — you can still connect\nusing sudo and change the password. And if you\'ve also removed unix_socket\nauthentication, to restore access do as follows:\n\n* restart MariaDB with --skip-grant-tables\n* login into the unprotected server\n* run FLUSH PRIVILEGES (note, before 10.4 this would’ve been the last step,\nnot anymore). This disables --skip-grant-tables and allows you to change the\nstored authentication method\n* run SET PASSWORD FOR root@localhost to change the root password.\n\nTo view inside privilege tables, the old mysql.user table still exists. You\ncan select from it as before, although you cannot update it anymore. It\ndoesn’t show alternative authentication plugins and this was one of the\nreasons for switching to the mysql.global_priv table — complex authentication\nrules did not fit into rigid structure of a relational table. You can select\nfrom the new table, for example:\n\nselect concat(user, \'@\', host, \' => \', json_detailed(priv)) from\nmysql.global_priv;\n\nReverting to the Previous Authentication Method for root@localhost\n------------------------------------------------------------------\n\nIf you don\'t want the root@localhost user account created by\nmariadb-install-db to use unix_socket authentication by default, then there\nare a few ways to revert to the previous mysql_native_password authentication\nmethod for this user account.\n\nConfiguring mariadb-install-db to Revert to the Previous Authentication Method\n------------------------------------------------------------------------------\n\nOne way to revert to the previous mysql_native_password authentication method\nfor the root@localhost user account is to execute mariadb-install-db with a\nspecial option. If mariadb-install-db is executed while\n--auth-root-authentication-method=normal is specified, then it will create the\ndefault user accounts using the default behavior of MariaDB 10.3 and before.\n\nThis means that the root@localhost user account will use mysql_native_password\nauthentication by default. There are some other differences as well. See\nmariadb-install-db: User Accounts Created by Default for more information.\n\nFor example, the option can be set on the command-line while running\nmariadb-install-db:\n\nmariadb-install-db --user=mysql --datadir=/var/lib/mysql\n--auth-root-authentication-method=normal\n\nThe option can also be set in an option file in an option group supported by\nmariadb-install-db. For example:\n\n[mysql_install_db]\nauth_root_authentication_method=normal\n\nIf the option is set in an option file and if mariadb-install-db is executed,\nthen mariadb-install-db will read this option from the option file, and it\nwill automatically set this option.\n\nAltering the User Account to Revert to the Previous Authentication Method\n-------------------------------------------------------------------------\n\nIf you have already installed MariaDB, and if the root@localhost user account\nis already using unix_socket authentication, then you can revert to the old\nmysql_native_password authentication method for the user account by executing\nthe following:\n\nALTER USER root@localhost IDENTIFIED VIA mysql_native_password USING\nPASSWORD(\"verysecret\")\n\nURL: https://mariadb.com/kb/en/authentication-from-mariadb-104/','','https://mariadb.com/kb/en/authentication-from-mariadb-104/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (119,10,'User Password Expiry','MariaDB starting with 10.4.3\n----------------------------\nUser password expiry was introduced in MariaDB 10.4.3.\n\nPassword expiry permits administrators to expire user passwords, either\nmanually or automatically.\n\nSystem Variables\n----------------\n\nThere are two system variables which affect password expiry:\ndefault_password_lifetime, which determines the amount of time between\nrequiring the user to change their password. 0, the default, means automatic\npassword expiry is not active.\n\nThe second variable, disconnect_on_expired_password determines whether a\nclient is permitted to connect if their password has expired, or whether they\nare permitted to connect in sandbox mode, able to perform a limited subset of\nqueries related to resetting the password, in particular SET PASSWORD and SET.\n\nSetting a Password Expiry Limit for a User\n------------------------------------------\n\nBesides automatic password expiry, as determined by default_password_lifetime,\npassword expiry times can be set on an individual user basis, overriding the\nglobal using the CREATE USER or ALTER USER statements, for example:\n\nCREATE USER \'monty\'@\'localhost\' PASSWORD EXPIRE INTERVAL 120 DAY;\n\nALTER USER \'monty\'@\'localhost\' PASSWORD EXPIRE INTERVAL 120 DAY;\n\nLimits can be disabled by use of the NEVER keyword, for example:\n\nCREATE USER \'monty\'@\'localhost\' PASSWORD EXPIRE NEVER;\n\nALTER USER \'monty\'@\'localhost\' PASSWORD EXPIRE NEVER;\n\nA manually set limit can be restored the system default by use of DEFAULT, for\nexample:\n\nCREATE USER \'monty\'@\'localhost\' PASSWORD EXPIRE DEFAULT;\n\nALTER USER \'monty\'@\'localhost\' PASSWORD EXPIRE DEFAULT;\n\nSHOW CREATE USER\n----------------\n\nThe SHOW CREATE USER statement will display information about the password\nexpiry status of the user. Unlike MySQL, it will not display if the user is\nunlocked, or if the password expiry is set to default.\n\nCREATE USER \'monty\'@\'localhost\' PASSWORD EXPIRE INTERVAL 120 DAY;\nCREATE USER \'konstantin\'@\'localhost\' PASSWORD EXPIRE NEVER;\nCREATE USER \'amse\'@\'localhost\' PASSWORD EXPIRE DEFAULT;\n\nSHOW CREATE USER \'monty\'@\'localhost\';\n+------------------------------------------------------------------+\n| CREATE USER for monty@localhost |\n+------------------------------------------------------------------+\n| CREATE USER \'monty\'@\'localhost\' PASSWORD EXPIRE INTERVAL 120 DAY |\n+------------------------------------------------------------------+\n\nSHOW CREATE USER \'konstantin\'@\'localhost\';\n+------------------------------------------------------------+\n| CREATE USER for konstantin@localhost |\n+------------------------------------------------------------+\n| CREATE USER \'konstantin\'@\'localhost\' PASSWORD EXPIRE NEVER |\n+------------------------------------------------------------+\n\nSHOW CREATE USER \'amse\'@\'localhost\';\n+--------------------------------+\n| CREATE USER for amse@localhost |\n+--------------------------------+\n| CREATE USER \'amse\'@\'localhost\' |\n+--------------------------------+\n\nChecking When Passwords Expire\n------------------------------\n\nThe following query can be used to check when the current passwords expire for\nall users:\n\nWITH password_expiration_info AS (\n SELECT User, Host,\n IF(\n IFNULL(JSON_EXTRACT(Priv, \'$.password_lifetime\'), -1) = -1,\n @@global.default_password_lifetime,\n JSON_EXTRACT(Priv, \'$.password_lifetime\')\n ) AS password_lifetime,\n JSON_EXTRACT(Priv, \'$.password_last_changed\') AS password_last_changed\n FROM mysql.global_priv\n)\nSELECT pei.User, pei.Host,\n pei.password_lifetime,\n FROM_UNIXTIME(pei.password_last_changed) AS password_last_changed_datetime,\n FROM_UNIXTIME(\n pei.password_last_changed +\n (pei.password_lifetime * 60 * 60 * 24)\n ) AS password_expiration_datetime\n FROM password_expiration_info pei\n WHERE pei.password_lifetime != 0\n AND pei.password_last_changed IS NOT NULL\nUNION\nSELECT pei.User, pei.Host,\n pei.password_lifetime,\n FROM_UNIXTIME(pei.password_last_changed) AS password_last_changed_datetime,\n 0 AS password_expiration_datetime\n FROM password_expiration_info pei\n WHERE pei.password_lifetime = 0\n OR pei.password_last_changed IS NULL;\n\n--connect-expired-password Client Option\n----------------------------------------\n\nThe mariadb client --connect-expired-password option notifies the server that\nthe client is prepared to handle expired password sandbox mode (even if the\n--batch option was specified).\n\nURL: https://mariadb.com/kb/en/user-password-expiry/','','https://mariadb.com/kb/en/user-password-expiry/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (120,11,'ST_X','Syntax\n------\n\nST_X(p)\nX(p)\n\nDescription\n-----------\n\nReturns the X-coordinate value for the point p as a double-precision number.\n\nST_X() and X() are synonyms.\n\nExamples\n--------\n\nSET @pt = \'Point(56.7 53.34)\';\n\nSELECT X(GeomFromText(@pt));\n+----------------------+\n| X(GeomFromText(@pt)) |\n+----------------------+\n| 56.7 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/st_x/','','https://mariadb.com/kb/en/st_x/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (121,11,'ST_Y','Syntax\n------\n\nST_Y(p)\nY(p)\n\nDescription\n-----------\n\nReturns the Y-coordinate value for the point p as a double-precision number.\n\nST_Y() and Y() are synonyms.\n\nExamples\n--------\n\nSET @pt = \'Point(56.7 53.34)\';\n\nSELECT Y(GeomFromText(@pt));\n+----------------------+\n| Y(GeomFromText(@pt)) |\n+----------------------+\n| 53.34 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/st_y/','','https://mariadb.com/kb/en/st_y/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (122,11,'X','A synonym for ST_X.\n\nURL: https://mariadb.com/kb/en/point-properties-x/','','https://mariadb.com/kb/en/point-properties-x/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (123,11,'Y','A synonym for ST_Y.\n\nURL: https://mariadb.com/kb/en/point-properties-y/','','https://mariadb.com/kb/en/point-properties-y/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (124,12,'UNCOMPRESS','Syntax\n------\n\nUNCOMPRESS(string_to_uncompress)\n\nDescription\n-----------\n\nUncompresses a string compressed by the COMPRESS() function. If the argument\nis not a compressed value, the result is NULL. This function requires MariaDB\nto have been compiled with a compression library such as zlib. Otherwise, the\nreturn value is always NULL. The have_compress server system variable\nindicates whether a compression library is present.\n\nExamples\n--------\n\nSELECT UNCOMPRESS(COMPRESS(\'a string\'));\n+----------------------------------+\n| UNCOMPRESS(COMPRESS(\'a string\')) |\n+----------------------------------+\n| a string |\n+----------------------------------+\n\nSELECT UNCOMPRESS(\'a string\');\n+------------------------+\n| UNCOMPRESS(\'a string\') |\n+------------------------+\n| NULL |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/uncompress/','','https://mariadb.com/kb/en/uncompress/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (125,12,'DECODE','Syntax\n------\n\nDECODE(crypt_str,pass_str)\n\nIn Oracle mode from MariaDB 10.3.2:\n\nDECODE(expr, search_expr, result_expr [, search_expr2, result_expr2 ...]\n[default_expr])\n\nIn all modes from MariaDB 10.3.2:\n\nDECODE_ORACLE(expr, search_expr, result_expr [, search_expr2, result_expr2\n...] [default_expr])\n\nDescription\n-----------\n\nIn the default mode, DECODE decrypts the encrypted string crypt_str using\npass_str as the password. crypt_str should be a string returned from ENCODE().\nThe resulting string will be the original string only if pass_str is the same.\n\nIn Oracle mode from MariaDB 10.3.2, DECODE compares expr to the search\nexpressions, in order. If it finds a match, the corresponding result\nexpression is returned. If no matches are found, the default expression is\nreturned, or NULL if no default is provided.\n\nNULLs are treated as equivalent.\n\nDECODE_ORACLE is a synonym for the Oracle-mode version of the function, and is\navailable in all modes.\n\nExamples\n--------\n\nFrom MariaDB 10.3.2:\n\nSELECT DECODE_ORACLE(2+1,3*1,\'found1\',3*2,\'found2\',\'default\');\n+--------------------------------------------------------+\n| DECODE_ORACLE(2+1,3*1,\'found1\',3*2,\'found2\',\'default\') |\n+--------------------------------------------------------+\n| found1 |\n+--------------------------------------------------------+\n\nSELECT DECODE_ORACLE(2+4,3*1,\'found1\',3*2,\'found2\',\'default\');\n+--------------------------------------------------------+\n| DECODE_ORACLE(2+4,3*1,\'found1\',3*2,\'found2\',\'default\') |\n+--------------------------------------------------------+\n| found2 |\n+--------------------------------------------------------+\n\nSELECT DECODE_ORACLE(2+2,3*1,\'found1\',3*2,\'found2\',\'default\');\n+--------------------------------------------------------+\n| DECODE_ORACLE(2+2,3*1,\'found1\',3*2,\'found2\',\'default\') |\n+--------------------------------------------------------+\n| default |\n+--------------------------------------------------------+\n\nNulls are treated as equivalent:\n\nSELECT DECODE_ORACLE(NULL,NULL,\'Nulls are equivalent\',\'Nulls are not\nequivalent\');\n+----------------------------------------------------------------------------+\n| DECODE_ORACLE(NULL,NULL,\'Nulls are equivalent\',\'Nulls are not equivalent\') |\n+----------------------------------------------------------------------------+\n| Nulls are equivalent |\n+----------------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/decode/','','https://mariadb.com/kb/en/decode/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (126,12,'DECODE_ORACLE','MariaDB starting with 10.3.2\n----------------------------\nDECODE_ORACLE is a synonym for the Oracle mode version of the DECODE function,\nand is available in all modes.\n\nURL: https://mariadb.com/kb/en/decode_oracle/','','https://mariadb.com/kb/en/decode_oracle/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (127,12,'AES_DECRYPT','Syntax\n------\n\nAES_DECRYPT(crypt_str,key_str)\n\nFrom MariaDB 11.2.0\n\nAES_ENCRYPT(crypt_str, key_str, [, iv [, mode]])\n\nDescription\n-----------\n\nThis function allows decryption of data using the official AES (Advanced\nEncryption Standard) algorithm. For more information, see the description of\nAES_ENCRYPT().\n\nMariaDB starting with 11.2\n--------------------------\nFrom MariaDB 11.2, the function supports an initialization vector, and control\nof the block encryption mode. The default mode is specified by the\nblock_encryption_mode system variable, which can be changed when calling the\nfunction with a mode. mode is aes-{128,192,256}-{ecb,cbc,ctr} for example:\n\"AES-128-cbc\".\n\nFor modes that require it, the initialization_vector iv should be 16 bytes (it\ncan be longer, but the extra bytes are ignored). A shorter iv, where one is\nrequired, results in the function returning NULL. Calling RANDOM_BYTES(16)\nwill generate a random series of bytes that can be used for the iv.\n\nExamples\n--------\n\nFrom MariaDB 11.2.0:\n\nSELECT HEX(AES_ENCRYPT(\'foo\', \'bar\', \'0123456789abcdef\', \'aes-128-ctr\')) AS x; \n+--------+\n| x |\n+--------+\n| C57C4B |\n+--------+\n\nSELECT AES_DECRYPT(x\'C57C4B\', \'bar\', \'0123456789abcdef\', \'aes-128-ctr\'); \n+------------------------------------------------------------------+\n| AES_DECRYPT(x\'C57C4B\', \'bar\', \'0123456789abcdef\', \'aes-128-ctr\') |\n+------------------------------------------------------------------+\n| foo |\n+------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/aes_decrypt/','','https://mariadb.com/kb/en/aes_decrypt/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (128,12,'AES_ENCRYPT','Syntax\n------\n\nAES_ENCRYPT(str,key_str)\n\nFrom MariaDB 11.2.0\n\nAES_ENCRYPT(str, key, [, iv [, mode]])\n\nDescription\n-----------\n\nAES_ENCRYPT() and AES_DECRYPT() allow encryption and decryption of data using\nthe official AES (Advanced Encryption Standard) algorithm, previously known as\n\"Rijndael.\" Encoding with a 128-bit key length is used (from MariaDB 11.2.0,\nthis is the default, and can be changed). 128 bits is much faster and is\nsecure enough for most purposes.\n\nAES_ENCRYPT() encrypts a string str using the key key_str, and returns a\nbinary string.\n\nAES_DECRYPT() decrypts the encrypted string and returns the original string.\n\nThe input arguments may be any length. If either argument is NULL, the result\nof this function is also NULL.\n\nBecause AES is a block-level algorithm, padding is used to encode uneven\nlength strings and so the result string length may be calculated using this\nformula:\n\n16 x (trunc(string_length / 16) + 1)\n\nIf AES_DECRYPT() detects invalid data or incorrect padding, it returns NULL.\nHowever, it is possible for AES_DECRYPT() to return a non-NULL value (possibly\ngarbage) if the input data or the key is invalid.\n\nMariaDB starting with 11.2\n--------------------------\nFrom MariaDB 11.2, the function supports an initialization vector, and control\nof the block encryption mode. The default mode is specified by the\nblock_encryption_mode system variable, which can be changed when calling the\nfunction with a mode. mode is aes-{128,192,256}-{ecb,cbc,ctr} for example:\n\"AES-128-cbc\".\n\nAES_ENCRYPT(str, key) can no longer be used in persistent virtual columns (and\nthe like).\n\nExamples\n--------\n\nINSERT INTO t VALUES (AES_ENCRYPT(\'text\',SHA2(\'password\',512)));\n\nFrom MariaDB 11.2.0:\n\nSELECT HEX(AES_ENCRYPT(\'foo\', \'bar\', \'0123456789abcdef\', \'aes-256-cbc\')) AS x;\n+----------------------------------+\n| x |\n+----------------------------------+\n| 42A3EB91E6DFC40A900D278F99E0726E |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/aes_encrypt/','','https://mariadb.com/kb/en/aes_encrypt/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (129,12,'COMPRESS','Syntax\n------\n\nCOMPRESS(string_to_compress)\n\nDescription\n-----------\n\nCompresses a string and returns the result as a binary string. This function\nrequires MariaDB to have been compiled with a compression library such as\nzlib. Otherwise, the return value is always NULL. The compressed string can be\nuncompressed with UNCOMPRESS().\n\nThe have_compress server system variable indicates whether a compression\nlibrary is present.\n\nExamples\n--------\n\nSELECT LENGTH(COMPRESS(REPEAT(\'a\',1000)));\n+------------------------------------+\n| LENGTH(COMPRESS(REPEAT(\'a\',1000))) |\n+------------------------------------+\n| 21 |\n+------------------------------------+\n\nSELECT LENGTH(COMPRESS(\'\'));\n+----------------------+\n| LENGTH(COMPRESS(\'\')) |\n+----------------------+\n| 0 |\n+----------------------+\n\nSELECT LENGTH(COMPRESS(\'a\'));\n+-----------------------+\n| LENGTH(COMPRESS(\'a\')) |\n+-----------------------+\n| 13 |\n+-----------------------+\n\nSELECT LENGTH(COMPRESS(REPEAT(\'a\',16)));\n+----------------------------------+\n| LENGTH(COMPRESS(REPEAT(\'a\',16))) |\n+----------------------------------+\n| 15 |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/compress/','','https://mariadb.com/kb/en/compress/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (130,12,'DES_DECRYPT','DES_DECRYPT has been deprecated from MariaDB 10.10.0, and will be removed in a\nfuture release.\n\nSyntax\n------\n\nDES_DECRYPT(crypt_str[,key_str])\n\nDescription\n-----------\n\nDecrypts a string encrypted with DES_ENCRYPT(). If an error occurs, this\nfunction returns NULL.\n\nThis function works only if MariaDB has been configured with TLS support.\n\nIf no key_str argument is given, DES_DECRYPT() examines the first byte of the\nencrypted string to determine the DES key number that was used to encrypt the\noriginal string, and then reads the key from the DES key file to decrypt the\nmessage. For this to work, the user must have the SUPER privilege. The key\nfile can be specified with the --des-key-file server option.\n\nIf you pass this function a key_str argument, that string is used as the key\nfor decrypting the message.\n\nIf the crypt_str argument does not appear to be an encrypted string, MariaDB\nreturns the given crypt_str.\n\nURL: https://mariadb.com/kb/en/des_decrypt/','','https://mariadb.com/kb/en/des_decrypt/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (131,12,'DES_ENCRYPT','DES_ENCRYPT has been deprecated from MariaDB 10.10.0, and will be removed in a\nfuture release.\n\nSyntax\n------\n\nDES_ENCRYPT(str[,{key_num|key_str}])\n\nDescription\n-----------\n\nEncrypts the string with the given key using the Triple-DES algorithm.\n\nThis function works only if MariaDB has been configured with TLS support.\n\nThe encryption key to use is chosen based on the second argument to\nDES_ENCRYPT(), if one was given. With no argument, the first key from the DES\nkey file is used. With a key_num argument, the given key number (0-9) from the\nDES key file is used. With a key_str argument, the given key string is used to\nencrypt str.\n\nThe key file can be specified with the --des-key-file server option.\n\nThe return string is a binary string where the first character is CHAR(128 |\nkey_num). If an error occurs, DES_ENCRYPT() returns NULL.\n\nThe 128 is added to make it easier to recognize an encrypted key. If you use a\nstring key, key_num is 127.\n\nThe string length for the result is given by this formula:\n\nnew_len = orig_len + (8 - (orig_len % 8)) + 1\n\nEach line in the DES key file has the following format:\n\nkey_num des_key_str\n\nEach key_num value must be a number in the range from 0 to 9. Lines in the\nfile may be in any order. des_key_str is the string that is used to encrypt\nthe message. There should be at least one space between the number and the\nkey. The first key is the default key that is used if you do not specify any\nkey argument to DES_ENCRYPT().\n\nYou can tell MariaDB to read new key values from the key file with the FLUSH\nDES_KEY_FILE statement. This requires the RELOAD privilege.\n\nOne benefit of having a set of default keys is that it gives applications a\nway to check for the existence of encrypted column values, without giving the\nend user the right to decrypt those values.\n\nExamples\n--------\n\nSELECT customer_address FROM customer_table \n WHERE crypted_credit_card = DES_ENCRYPT(\'credit_card_number\');\n\nURL: https://mariadb.com/kb/en/des_encrypt/','','https://mariadb.com/kb/en/des_encrypt/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (132,12,'ENCODE','Syntax\n------\n\nENCODE(str,pass_str)\n\nDescription\n-----------\n\nENCODE is not considered cryptographically secure, and should not be used for\npassword encryption.\n\nEncrypt str using pass_str as the password. To decrypt the result, use\nDECODE().\n\nThe result is a binary string of the same length as str.\n\nThe strength of the encryption is based on how good the random generator is.\n\nIt is not recommended to rely on the encryption performed by the ENCODE\nfunction. Using a salt value (changed when a password is updated) will improve\nmatters somewhat, but for storing passwords, consider a more cryptographically\nsecure function, such as SHA2().\n\nExamples\n--------\n\nENCODE(\'not so secret text\', CONCAT(\'random_salt\',\'password\'))\n\nURL: https://mariadb.com/kb/en/encode/','','https://mariadb.com/kb/en/encode/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (133,12,'ENCRYPT','Syntax\n------\n\nENCRYPT(str[,salt])\n\nDescription\n-----------\n\nEncrypts a string using the Unix crypt() system call, returning an encrypted\nbinary string. The salt argument should be a string with at least two\ncharacters or the returned result will be NULL. If no salt argument is given,\na random value of sufficient length is used.\n\nIt is not recommended to use ENCRYPT() with utf16, utf32 or ucs2 multi-byte\ncharacter sets because the crypt() system call expects a string terminated\nwith a zero byte.\n\nNote that the underlying crypt() system call may have some limitations, such\nas ignoring all but the first eight characters.\n\nIf the have_crypt system variable is set to NO (because the crypt() system\ncall is not available), the ENCRYPT function will always return NULL.\n\nExamples\n--------\n\nSELECT ENCRYPT(\'encrypt me\');\n+-----------------------+\n| ENCRYPT(\'encrypt me\') |\n+-----------------------+\n| 4I5BsEx0lqTDk |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/encrypt/','','https://mariadb.com/kb/en/encrypt/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (134,12,'MD5','Syntax\n------\n\nMD5(str)\n\nDescription\n-----------\n\nCalculates an MD5 128-bit checksum for the string.\n\nThe return value is a 32-hex digit string, and as of MariaDB 5.5, is a\nnonbinary string in the connection character set and collation, determined by\nthe values of the character_set_connection and collation_connection system\nvariables. Before 5.5, the return value was a binary string.\n\nNULL is returned if the argument was NULL.\n\nExamples\n--------\n\nSELECT MD5(\'testing\');\n+----------------------------------+\n| MD5(\'testing\') |\n+----------------------------------+\n| ae2b1fca515949e5d54fb22b8ed95575 |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/md5/','','https://mariadb.com/kb/en/md5/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (135,12,'OLD_PASSWORD','Syntax\n------\n\nOLD_PASSWORD(str)\n\nDescription\n-----------\n\nOLD_PASSWORD() was added to MySQL when the implementation of PASSWORD() was\nchanged to improve security. OLD_PASSWORD() returns the value of the old\n(pre-MySQL 4.1) implementation of PASSWORD() as a string, and is intended to\npermit you to reset passwords for any pre-4.1 clients that need to connect to\na more recent MySQL server version, or any version of MariaDB, without locking\nthem out.\n\nAs of MariaDB 5.5, the return value is a nonbinary string in the connection\ncharacter set and collation, determined by the values of the\ncharacter_set_connection and collation_connection system variables. Before\n5.5, the return value was a binary string.\n\nThe return value is 16 bytes in length, or NULL if the argument was NULL.\n\nURL: https://mariadb.com/kb/en/old_password/','','https://mariadb.com/kb/en/old_password/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (136,12,'PASSWORD','Syntax\n------\n\nPASSWORD(str)\n\nDescription\n-----------\n\nThe PASSWORD() function is used for hashing passwords for use in\nauthentication by the MariaDB server. It is not intended for use in other\napplications.\n\nCalculates and returns a hashed password string from the plaintext password\nstr. Returns an empty string (>= MariaDB 10.0.4) if the argument was NULL.\n\nThe return value is a nonbinary string in the connection character set and\ncollation, determined by the values of the character_set_connection and\ncollation_connection system variables.\n\nThis is the function that is used for hashing MariaDB passwords for storage in\nthe Password column of the user table (see privileges), usually used with the\nSET PASSWORD statement. It is not intended for use in other applications.\n\nUntil MariaDB 10.3, the return value is 41-bytes in length, and the first\ncharacter is always \'*\'. From MariaDB 10.4, the function takes into account\nthe authentication plugin where applicable (A CREATE USER or SET PASSWORD\nstatement). For example, when used in conjunction with a user authenticated by\nthe ed25519 plugin, the statement will create a longer hash:\n\nCREATE USER edtest@localhost IDENTIFIED VIA ed25519 USING PASSWORD(\'secret\');\n\nCREATE USER edtest2@localhost IDENTIFIED BY \'secret\';\n\nSELECT CONCAT(user, \'@\', host, \' => \', JSON_DETAILED(priv)) FROM\nmysql.global_priv\n WHERE user LIKE \'edtest%\'\\G\n*************************** 1. row ***************************\nCONCAT(user, \'@\', host, \' => \', JSON_DETAILED(priv)): edtest@localhost => {\n...\n \"plugin\": \"ed25519\",\n \"authentication_string\": \"ZIgUREUg5PVgQ6LskhXmO+eZLS0nC8be6HPjYWR4YJY\",\n...\n}\n*************************** 2. row ***************************\nCONCAT(user, \'@\', host, \' => \', JSON_DETAILED(priv)): edtest2@localhost => {\n...\n \"plugin\": \"mysql_native_password\",\n \"authentication_string\": \"*14E65567ABDB5135D0CFD9A70B3032C179A49EE7\",\n...\n}\n\nThe behavior of this function is affected by the value of the old_passwords\nsystem variable. If this is set to 1 (0 is default), MariaDB reverts to using\nthe mysql_old_password authentication plugin by default for newly created\nusers and passwords.\n\nExamples\n--------\n\nSELECT PASSWORD(\'notagoodpwd\');\n+-------------------------------------------+\n| PASSWORD(\'notagoodpwd\') |\n+-------------------------------------------+\n| *3A70EE9FC6594F88CE9E959CD51C5A1C002DC937 |\n+-------------------------------------------+\n\nSET PASSWORD FOR \'bob\'@\'%.loc.gov\' = PASSWORD(\'newpass\');\n\nURL: https://mariadb.com/kb/en/password/','','https://mariadb.com/kb/en/password/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (137,12,'RANDOM_BYTES','MariaDB starting with 10.10.0\n-----------------------------\nThe RANDOM_BYTES function generates a binary string of random bytes. It was\nadded in MariaDB 10.10.0.\n\nSyntax\n------\n\nRANDOM_BYTES(length)\n\nDescription\n-----------\n\nGiven a length from 1 to 1024, generates a binary string of length consisting\nof random bytes generated by the SSL library\'s random number generator.\n\nSee the RAND_bytes() function documentation of your SSL library for\ninformation on the random number generator. In the case of OpenSSL, a\ncryptographically secure pseudo random generator (CSPRNG) is used.\n\nStatements containing the RANDOM_BYTES function are unsafe for statement-based\nreplication.\n\nAn error occurs if length is outside the range 1 to 1024.\n\nURL: https://mariadb.com/kb/en/random_bytes/','','https://mariadb.com/kb/en/random_bytes/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (138,12,'SHA1','Syntax\n------\n\nSHA1(str), SHA(str)\n\nDescription\n-----------\n\nCalculates an SHA-1 160-bit checksum for the string str, as described in RFC\n3174 (Secure Hash Algorithm).\n\nThe value is returned as a string of 40 hex digits, or NULL if the argument\nwas NULL. As of MariaDB 5.5, the return value is a nonbinary string in the\nconnection character set and collation, determined by the values of the\ncharacter_set_connection and collation_connection system variables. Before\n5.5, the return value was a binary string.\n\nExamples\n--------\n\nSELECT SHA1(\'some boring text\');\n+------------------------------------------+\n| SHA1(\'some boring text\') |\n+------------------------------------------+\n| af969fc2085b1bb6d31e517d5c456def5cdd7093 |\n+------------------------------------------+\n\nURL: https://mariadb.com/kb/en/sha1/','','https://mariadb.com/kb/en/sha1/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (139,12,'SHA2','Syntax\n------\n\nSHA2(str,hash_len)\n\nDescription\n-----------\n\nGiven a string str, calculates an SHA-2 checksum, which is considered more\ncryptographically secure than its SHA-1 equivalent. The SHA-2 family includes\nSHA-224, SHA-256, SHA-384, and SHA-512, and the hash_len must correspond to\none of these, i.e. 224, 256, 384 or 512. 0 is equivalent to 256.\n\nThe return value is a nonbinary string in the connection character set and\ncollation, determined by the values of the character_set_connection and\ncollation_connection system variables.\n\nNULL is returned if the hash length is not valid, or the string str is NULL.\n\nSHA2 will only work if MariaDB was has been configured with TLS support.\n\nExamples\n--------\n\nSELECT SHA2(\'Maria\',224);\n+----------------------------------------------------------+\n| SHA2(\'Maria\',224) |\n+----------------------------------------------------------+\n| 6cc67add32286412efcab9d0e1675a43a5c2ef3cec8879f81516ff83 |\n+----------------------------------------------------------+\n\nSELECT SHA2(\'Maria\',256);\n+------------------------------------------------------------------+\n| SHA2(\'Maria\',256) |\n+------------------------------------------------------------------+\n| 9ff18ebe7449349f358e3af0b57cf7a032c1c6b2272cb2656ff85eb112232f16 |\n+------------------------------------------------------------------+\n\nSELECT SHA2(\'Maria\',0);\n+------------------------------------------------------------------+\n| SHA2(\'Maria\',0) |\n+------------------------------------------------------------------+\n| 9ff18ebe7449349f358e3af0b57cf7a032c1c6b2272cb2656ff85eb112232f16 |\n+------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/sha2/','','https://mariadb.com/kb/en/sha2/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (140,13,'ENDPOINT','A synonym for ST_ENDPOINT.\n\nURL: https://mariadb.com/kb/en/linestring-properties-endpoint/','','https://mariadb.com/kb/en/linestring-properties-endpoint/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (141,13,'GLENGTH','Syntax\n------\n\nGLength(ls)\n\nDescription\n-----------\n\nReturns as a double-precision number the length of the LineString value ls in\nits associated spatial reference.\n\nExamples\n--------\n\nSET @ls = \'LineString(1 1,2 2,3 3)\';\n\nSELECT GLength(GeomFromText(@ls));\n+----------------------------+\n| GLength(GeomFromText(@ls)) |\n+----------------------------+\n| 2.82842712474619 |\n+----------------------------+\n\nURL: https://mariadb.com/kb/en/glength/','','https://mariadb.com/kb/en/glength/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (142,13,'NumPoints','A synonym for ST_NumPoints.\n\nURL: https://mariadb.com/kb/en/linestring-properties-numpoints/','','https://mariadb.com/kb/en/linestring-properties-numpoints/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (143,13,'PointN','A synonym for ST_PointN.\n\nURL: https://mariadb.com/kb/en/linestring-properties-pointn/','','https://mariadb.com/kb/en/linestring-properties-pointn/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (144,13,'STARTPOINT','A synonym for ST_STARTPOINT.\n\nURL: https://mariadb.com/kb/en/linestring-properties-startpoint/','','https://mariadb.com/kb/en/linestring-properties-startpoint/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (145,13,'ST_ENDPOINT','Syntax\n------\n\nST_EndPoint(ls)\nEndPoint(ls)\n\nDescription\n-----------\n\nReturns the Point that is the endpoint of the LineString value ls.\n\nST_EndPoint() and EndPoint() are synonyms.\n\nExamples\n--------\n\nSET @ls = \'LineString(1 1,2 2,3 3)\';\n\nSELECT AsText(EndPoint(GeomFromText(@ls)));\n+-------------------------------------+\n| AsText(EndPoint(GeomFromText(@ls))) |\n+-------------------------------------+\n| POINT(3 3) |\n+-------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_endpoint/','','https://mariadb.com/kb/en/st_endpoint/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (146,13,'ST_NUMPOINTS','Syntax\n------\n\nST_NumPoints(ls)\nNumPoints(ls)\n\nDescription\n-----------\n\nReturns the number of Point objects in the LineString value ls.\n\nST_NumPoints() and NumPoints() are synonyms.\n\nExamples\n--------\n\nSET @ls = \'LineString(1 1,2 2,3 3)\';\n\nSELECT NumPoints(GeomFromText(@ls));\n+------------------------------+\n| NumPoints(GeomFromText(@ls)) |\n+------------------------------+\n| 3 |\n+------------------------------+\n\nURL: https://mariadb.com/kb/en/st_numpoints/','','https://mariadb.com/kb/en/st_numpoints/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (147,13,'ST_POINTN','Syntax\n------\n\nST_PointN(ls,N)\nPointN(ls,N)\n\nDescription\n-----------\n\nReturns the N-th Point in the LineString value ls. Points are numbered\nbeginning with 1.\n\nST_PointN() and PointN() are synonyms.\n\nExamples\n--------\n\nSET @ls = \'LineString(1 1,2 2,3 3)\';\n\nSELECT AsText(PointN(GeomFromText(@ls),2));\n+-------------------------------------+\n| AsText(PointN(GeomFromText(@ls),2)) |\n+-------------------------------------+\n| POINT(2 2) |\n+-------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_pointn/','','https://mariadb.com/kb/en/st_pointn/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (148,13,'ST_STARTPOINT','Syntax\n------\n\nST_StartPoint(ls)\nStartPoint(ls)\n\nDescription\n-----------\n\nReturns the Point that is the start point of the LineString value ls.\n\nST_StartPoint() and StartPoint() are synonyms.\n\nExamples\n--------\n\nSET @ls = \'LineString(1 1,2 2,3 3)\';\n\nSELECT AsText(StartPoint(GeomFromText(@ls)));\n+---------------------------------------+\n| AsText(StartPoint(GeomFromText(@ls))) |\n+---------------------------------------+\n| POINT(1 1) |\n+---------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_startpoint/','','https://mariadb.com/kb/en/st_startpoint/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (149,14,'GET_LOCK','Syntax\n------\n\nGET_LOCK(str,timeout)\n\nDescription\n-----------\n\nTries to obtain a lock with a name given by the string str, using a timeout of\ntimeout seconds. Returns 1 if the lock was obtained successfully, 0 if the\nattempt timed out (for example, because another client has previously locked\nthe name), or NULL if an error occurred (such as running out of memory or the\nthread was killed with mariadb-admin kill).\n\nA lock is released with RELEASE_LOCK(), when the connection terminates (either\nnormally or abnormally). A connection can hold multiple locks at the same\ntime, so a lock that is no longer needed needs to be explicitly released.\n\nThe IS_FREE_LOCK function returns whether a specified lock a free or not, and\nthe IS_USED_LOCK whether the function is in use or not.\n\nLocks obtained with GET_LOCK() do not interact with transactions. That is,\ncommitting a transaction does not release any such locks obtained during the\ntransaction.\n\nIt is also possible to recursively set the same lock. If a lock with the same\nname is set n times, it needs to be released n times as well.\n\nstr is case insensitive for GET_LOCK() and related functions. If str is an\nempty string or NULL, GET_LOCK() returns NULL and does nothing. timeout\nsupports microseconds.\n\nIf the metadata_lock_info plugin is installed, locks acquired with this\nfunction are visible in the Information Schema METADATA_LOCK_INFO table.\n\nThis function can be used to implement application locks or to simulate record\nlocks. Names are locked on a server-wide basis. If a name has been locked by\none client, GET_LOCK() blocks any request by another client for a lock with\nthe same name. This allows clients that agree on a given lock name to use the\nname to perform cooperative advisory locking. But be aware that it also allows\na client that is not among the set of cooperating clients to lock a name,\neither inadvertently or deliberately, and thus prevent any of the cooperating\nclients from locking that name. One way to reduce the likelihood of this is to\nuse lock names that are database-specific or application-specific. For\nexample, use lock names of the form db_name.str or app_name.str.\n\nStatements using the GET_LOCK function are not safe for statement-based\nreplication.\n\nThe patch to permit multiple locks was contributed by Konstantin \"Kostja\"\nOsipov (MDEV-3917).\n\nExamples\n--------\n\nSELECT GET_LOCK(\'lock1\',10);\n+----------------------+\n| GET_LOCK(\'lock1\',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSELECT IS_FREE_LOCK(\'lock1\'), IS_USED_LOCK(\'lock1\');\n+-----------------------+-----------------------+\n| IS_FREE_LOCK(\'lock1\') | IS_USED_LOCK(\'lock1\') |\n+-----------------------+-----------------------+\n| 0 | 46 |\n+-----------------------+-----------------------+\n\nSELECT IS_FREE_LOCK(\'lock2\'), IS_USED_LOCK(\'lock2\');\n+-----------------------+-----------------------+\n| IS_FREE_LOCK(\'lock2\') | IS_USED_LOCK(\'lock2\') |\n+-----------------------+-----------------------+\n| 1 | NULL |\n+-----------------------+-----------------------+\n\nMultiple locks can be held:\n\nSELECT GET_LOCK(\'lock2\',10);\n+----------------------+\n| GET_LOCK(\'lock2\',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSELECT IS_FREE_LOCK(\'lock1\'), IS_FREE_LOCK(\'lock2\');\n+-----------------------+-----------------------+\n| IS_FREE_LOCK(\'lock1\') | IS_FREE_LOCK(\'lock2\') |\n+-----------------------+-----------------------+\n| 0 | 0 |\n+-----------------------+-----------------------+\n\nSELECT RELEASE_LOCK(\'lock1\'), RELEASE_LOCK(\'lock2\');\n+-----------------------+-----------------------+\n| RELEASE_LOCK(\'lock1\') | RELEASE_LOCK(\'lock2\') |\n+-----------------------+-----------------------+\n| 1 | 1 |\n+-----------------------+-----------------------+\n\nIt is possible to hold the same lock recursively. This example is viewed using\nthe metadata_lock_info plugin:\n\nSELECT GET_LOCK(\'lock3\',10);\n+----------------------+\n| GET_LOCK(\'lock3\',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSELECT GET_LOCK(\'lock3\',10);\n+----------------------+\n| GET_LOCK(\'lock3\',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSELECT * FROM INFORMATION_SCHEMA.METADATA_LOCK_INFO;\n+-----------+---------------------+---------------+-----------+--------------+-\n----------+\n| THREAD_ID | LOCK_MODE | LOCK_DURATION | LOCK_TYPE | TABLE_SCHEMA |\nTABLE_NAME |\n+-----------+---------------------+---------------+-----------+--------------+-\n----------+\n| 46 | MDL_SHARED_NO_WRITE | NULL | User lock | lock3 |\n |\n+-----------+---------------------+---------------+-----------+--------------+-\n----------+\n\nSELECT RELEASE_LOCK(\'lock3\');\n+-----------------------+\n| RELEASE_LOCK(\'lock3\') |\n+-----------------------+\n| 1 |\n+-----------------------+\n\nSELECT * FROM INFORMATION_SCHEMA.METADATA_LOCK_INFO;\n+-----------+---------------------+---------------+-----------+--------------+-\n----------+\n| THREAD_ID | LOCK_MODE | LOCK_DURATION | LOCK_TYPE | TABLE_SCHEMA |\nTABLE_NAME |\n+-----------+---------------------+---------------+-----------+--------------+-\n----------+\n| 46 | MDL_SHARED_NO_WRITE | NULL | User lock | lock3 |\n |\n+-----------+---------------------+---------------+-----------+--------------+-\n----------+\n\nSELECT RELEASE_LOCK(\'lock3\');\n+-----------------------+\n| RELEASE_LOCK(\'lock3\') |\n+-----------------------+\n| 1 |\n+-----------------------+\n\nSELECT * FROM INFORMATION_SCHEMA.METADATA_LOCK_INFO;\nEmpty set (0.000 sec)\n\nTimeout example: Connection 1:\n\nSELECT GET_LOCK(\'lock4\',10);\n+----------------------+\n| GET_LOCK(\'lock4\',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nConnection 2:\n\nSELECT GET_LOCK(\'lock4\',10);\n\nAfter 10 seconds...\n\n+----------------------+\n| GET_LOCK(\'lock4\',10) |\n+----------------------+\n| 0 |\n+----------------------+\n\nDeadlocks are automatically detected and resolved. Connection 1:\n\nSELECT GET_LOCK(\'lock5\',10); \n+----------------------+\n| GET_LOCK(\'lock5\',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nConnection 2:\n\nSELECT GET_LOCK(\'lock6\',10);\n+----------------------+\n| GET_LOCK(\'lock6\',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nConnection 1:\n\nSELECT GET_LOCK(\'lock6\',10); \n+----------------------+\n| GET_LOCK(\'lock6\',10) |\n+----------------------+\n| 0 |\n+----------------------+\n\nConnection 2:\n\nSELECT GET_LOCK(\'lock5\',10);\nERROR 1213 (40001): Deadlock found when trying to get lock; try restarting\ntransaction\n\nURL: https://mariadb.com/kb/en/get_lock/','','https://mariadb.com/kb/en/get_lock/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (150,14,'INET6_ATON','Syntax\n------\n\nINET6_ATON(expr)\n\nDescription\n-----------\n\nGiven an IPv6 or IPv4 network address as a string, returns a binary string\nthat represents the numeric value of the address.\n\nNo trailing zone ID\'s or traling network masks are permitted. For IPv4\naddresses, or IPv6 addresses with IPv4 address parts, no classful addresses or\ntrailing port numbers are permitted and octal numbers are not supported.\n\nThe returned binary string will be VARBINARY(16) or VARBINARY(4) for IPv6 and\nIPv4 addresses respectively.\n\nReturns NULL if the argument is not understood.\n\nMariaDB starting with 10.5.0\n----------------------------\nFrom MariaDB 10.5.0, INET6_ATON can take INET6 as an argument.\n\nExamples\n--------\n\nSELECT HEX(INET6_ATON(\'10.0.1.1\'));\n+-----------------------------+\n| HEX(INET6_ATON(\'10.0.1.1\')) |\n+-----------------------------+\n| 0A000101 |\n+-----------------------------+\n\nSELECT HEX(INET6_ATON(\'48f3::d432:1431:ba23:846f\'));\n+----------------------------------------------+\n| HEX(INET6_ATON(\'48f3::d432:1431:ba23:846f\')) |\n+----------------------------------------------+\n| 48F3000000000000D4321431BA23846F |\n+----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/inet6_aton/','','https://mariadb.com/kb/en/inet6_aton/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (151,14,'INET6_NTOA','Syntax\n------\n\nINET6_NTOA(expr)\n\nDescription\n-----------\n\nGiven an IPv6 or IPv4 network address as a numeric binary string, returns the\naddress as a nonbinary string in the connection character set.\n\nThe return string is lowercase, and is platform independent, since it does not\nuse functions specific to the operating system. It has a maximum length of 39\ncharacters.\n\nReturns NULL if the argument is not understood.\n\nExamples\n--------\n\nSELECT INET6_NTOA(UNHEX(\'0A000101\'));\n+-------------------------------+\n| INET6_NTOA(UNHEX(\'0A000101\')) |\n+-------------------------------+\n| 10.0.1.1 |\n+-------------------------------+\n\nSELECT INET6_NTOA(UNHEX(\'48F3000000000000D4321431BA23846F\'));\n+-------------------------------------------------------+\n| INET6_NTOA(UNHEX(\'48F3000000000000D4321431BA23846F\')) |\n+-------------------------------------------------------+\n| 48f3::d432:1431:ba23:846f |\n+-------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/inet6_ntoa/','','https://mariadb.com/kb/en/inet6_ntoa/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (152,14,'INET_ATON','Syntax\n------\n\nINET_ATON(expr)\n\nDescription\n-----------\n\nGiven the dotted-quad representation of an IPv4 network address as a string,\nreturns an integer that represents the numeric value of the address. Addresses\nmay be 4- or 8-byte addresses.\n\nReturns NULL if the argument is not understood.\n\nExamples\n--------\n\nSELECT INET_ATON(\'192.168.1.1\');\n+--------------------------+\n| INET_ATON(\'192.168.1.1\') |\n+--------------------------+\n| 3232235777 |\n+--------------------------+\n\nThis is calculated as follows: 192 x 2563 + 168 x 256 2 + 1 x 256 + 1\n\nURL: https://mariadb.com/kb/en/inet_aton/','','https://mariadb.com/kb/en/inet_aton/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (153,14,'INET_NTOA','Syntax\n------\n\nINET_NTOA(expr)\n\nDescription\n-----------\n\nGiven a numeric IPv4 network address in network byte order (4 or 8 byte),\nreturns the dotted-quad representation of the address as a string.\n\nExamples\n--------\n\nSELECT INET_NTOA(3232235777);\n+-----------------------+\n| INET_NTOA(3232235777) |\n+-----------------------+\n| 192.168.1.1 |\n+-----------------------+\n\n192.168.1.1 corresponds to 3232235777 since 192 x 2563 + 168 x 256 2 + 1 x 256\n+ 1 = 3232235777\n\nURL: https://mariadb.com/kb/en/inet_ntoa/','','https://mariadb.com/kb/en/inet_ntoa/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (154,14,'IS_FREE_LOCK','Syntax\n------\n\nIS_FREE_LOCK(str)\n\nDescription\n-----------\n\nChecks whether the lock named str is free to use (that is, not locked).\nReturns 1 if the lock is free (no one is using the lock), 0 if the lock is in\nuse, and NULL if an error occurs (such as an incorrect argument, like an empty\nstring or NULL). str is case insensitive.\n\nIf the metadata_lock_info plugin is installed, the Information Schema\nmetadata_lock_info table contains information about locks of this kind (as\nwell as metadata locks).\n\nStatements using the IS_FREE_LOCK function are not safe for statement-based\nreplication.\n\nURL: https://mariadb.com/kb/en/is_free_lock/','','https://mariadb.com/kb/en/is_free_lock/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (155,14,'IS_IPV4','Syntax\n------\n\nIS_IPV4(expr)\n\nDescription\n-----------\n\nIf the expression is a valid IPv4 address, returns 1, otherwise returns 0.\n\nIS_IPV4() is stricter than INET_ATON(), but as strict as INET6_ATON(), in\ndetermining the validity of an IPv4 address. This implies that if IS_IPV4\nreturns 1, the same expression will always return a non-NULL result when\npassed to INET_ATON(), but that the reverse may not apply.\n\nExamples\n--------\n\nSELECT IS_IPV4(\'1110.0.1.1\');\n+-----------------------+\n| IS_IPV4(\'1110.0.1.1\') |\n+-----------------------+\n| 0 |\n+-----------------------+\n\nSELECT IS_IPV4(\'48f3::d432:1431:ba23:846f\');\n+--------------------------------------+\n| IS_IPV4(\'48f3::d432:1431:ba23:846f\') |\n+--------------------------------------+\n| 0 |\n+--------------------------------------+\n\nURL: https://mariadb.com/kb/en/is_ipv4/','','https://mariadb.com/kb/en/is_ipv4/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (156,14,'IS_IPV4_COMPAT','Syntax\n------\n\nIS_IPV4_COMPAT(expr)\n\nDescription\n-----------\n\nReturns 1 if a given numeric binary string IPv6 address, such as returned by\nINET6_ATON(), is IPv4-compatible, otherwise returns 0.\n\nMariaDB starting with 10.5.0\n----------------------------\nFrom MariaDB 10.5.0, when the argument is not INET6, automatic implicit CAST\nto INET6 is applied. As a consequence, IS_IPV4_COMPAT now understands\narguments in both text representation and binary(16) representation. Before\nMariaDB 10.5.0, the function understood only binary(16) representation.\n\nExamples\n--------\n\nSELECT IS_IPV4_COMPAT(INET6_ATON(\'::10.0.1.1\'));\n+------------------------------------------+\n| IS_IPV4_COMPAT(INET6_ATON(\'::10.0.1.1\')) |\n+------------------------------------------+\n| 1 |\n+------------------------------------------+\n\nSELECT IS_IPV4_COMPAT(INET6_ATON(\'::48f3::d432:1431:ba23:846f\'));\n+-----------------------------------------------------------+\n| IS_IPV4_COMPAT(INET6_ATON(\'::48f3::d432:1431:ba23:846f\')) |\n+-----------------------------------------------------------+\n| 0 |\n+-----------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/is_ipv4_compat/','','https://mariadb.com/kb/en/is_ipv4_compat/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (157,14,'IS_IPV4_MAPPED','Syntax\n------\n\nIS_IPV4_MAPPED(expr)\n\nDescription\n-----------\n\nReturns 1 if a given a numeric binary string IPv6 address, such as returned by\nINET6_ATON(), is a valid IPv4-mapped address, otherwise returns 0.\n\nMariaDB starting with 10.5.0\n----------------------------\nFrom MariaDB 10.5.0, when the argument is not INET6, automatic implicit CAST\nto INET6 is applied. As a consequence, IS_IPV4_MAPPED now understands\narguments in both text representation and binary(16) representation. Before\nMariaDB 10.5.0, the function understood only binary(16) representation.\n\nExamples\n--------\n\nSELECT IS_IPV4_MAPPED(INET6_ATON(\'::10.0.1.1\'));\n+------------------------------------------+\n| IS_IPV4_MAPPED(INET6_ATON(\'::10.0.1.1\')) |\n+------------------------------------------+\n| 0 |\n+------------------------------------------+\n\nSELECT IS_IPV4_MAPPED(INET6_ATON(\'::ffff:10.0.1.1\'));\n+-----------------------------------------------+\n| IS_IPV4_MAPPED(INET6_ATON(\'::ffff:10.0.1.1\')) |\n+-----------------------------------------------+\n| 1 |\n+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/is_ipv4_mapped/','','https://mariadb.com/kb/en/is_ipv4_mapped/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (158,14,'IS_IPV6','Syntax\n------\n\nIS_IPV6(expr)\n\nDescription\n-----------\n\nReturns 1 if the expression is a valid IPv6 address specified as a string,\notherwise returns 0. Does not consider IPv4 addresses to be valid IPv6\naddresses.\n\nExamples\n--------\n\nSELECT IS_IPV6(\'48f3::d432:1431:ba23:846f\');\n+--------------------------------------+\n| IS_IPV6(\'48f3::d432:1431:ba23:846f\') |\n+--------------------------------------+\n| 1 |\n+--------------------------------------+\n1 row in set (0.02 sec)\n\nSELECT IS_IPV6(\'10.0.1.1\');\n+---------------------+\n| IS_IPV6(\'10.0.1.1\') |\n+---------------------+\n| 0 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/is_ipv6/','','https://mariadb.com/kb/en/is_ipv6/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (159,14,'IS_USED_LOCK','Syntax\n------\n\nIS_USED_LOCK(str)\n\nDescription\n-----------\n\nChecks whether the lock named str is in use (that is, locked). If so, it\nreturns the connection identifier of the client that holds the lock.\nOtherwise, it returns NULL. str is case insensitive.\n\nIf the metadata_lock_info plugin is installed, the Information Schema\nmetadata_lock_info table contains information about locks of this kind (as\nwell as metadata locks).\n\nStatements using the IS_USED_LOCK function are not safe for statement-based\nreplication.\n\nURL: https://mariadb.com/kb/en/is_used_lock/','','https://mariadb.com/kb/en/is_used_lock/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (160,14,'MASTER_GTID_WAIT','Syntax\n------\n\nMASTER_GTID_WAIT(gtid-list[, timeout)\n\nDescription\n-----------\n\nThis function takes a string containing a comma-separated list of global\ntransaction id\'s (similar to the value of, for example, gtid_binlog_pos). It\nwaits until the value of gtid_slave_pos has the same or higher seq_no within\nall replication domains specified in the gtid-list; in other words, it waits\nuntil the slave has reached the specified GTID position.\n\nAn optional second argument gives a timeout in seconds. If the timeout expires\nbefore the specified GTID position is reached, then the function returns -1.\nPassing NULL or a negative number for the timeout means no timeout, and the\nfunction will wait indefinitely.\n\nIf the wait completes without a timeout, 0 is returned. Passing NULL for the\ngtid-list makes the function return NULL immediately, without waiting.\n\nThe gtid-list may be the empty string, in which case MASTER_GTID_WAIT()\nreturns immediately. If the gtid-list contains fewer domains than\ngtid_slave_pos, then only those domains are waited upon. If gtid-list contains\na domain that is not present in @@gtid_slave_pos, then MASTER_GTID_WAIT() will\nwait until an event containing such domain_id arrives on the slave (or until\ntimed out or killed).\n\nMASTER_GTID_WAIT() can be useful to ensure that a slave has caught up to a\nmaster. Simply take the value of gtid_binlog_pos on the master, and use it in\na MASTER_GTID_WAIT() call on the slave; when the call completes, the slave\nwill have caught up with that master position.\n\nMASTER_GTID_WAIT() can also be used in client applications together with the\nlast_gtid session variable. This is useful in a read-scaleout replication\nsetup, where the application writes to a single master but divides the reads\nout to a number of slaves to distribute the load. In such a setup, there is a\nrisk that an application could first do an update on the master, and then a\nbit later do a read on a slave, and if the slave is not fast enough, the data\nread from the slave might not include the update just made, possibly confusing\nthe application and/or the end-user. One way to avoid this is to request the\nvalue of last_gtid on the master just after the update. Then before doing the\nread on the slave, do a MASTER_GTID_WAIT() on the value obtained from the\nmaster; this will ensure that the read is not performed until the slave has\nreplicated sufficiently far for the update to have become visible.\n\nNote that MASTER_GTID_WAIT() can be used even if the slave is configured not\nto use GTID for connections (CHANGE MASTER TO master_use_gtid=no). This is\nbecause from MariaDB 10, GTIDs are always logged on the master server, and\nalways recorded on the slave servers.\n\nDifferences to MASTER_POS_WAIT()\n--------------------------------\n\n* MASTER_GTID_WAIT() is global; it waits for any master connection to reach\n the specified GTID position. MASTER_POS_WAIT() works only against a\n specific connection. This also means that while MASTER_POS_WAIT() aborts if\n its master connection is terminated with STOP SLAVE or due to an error,\n MASTER_GTID_WAIT() continues to wait while slaves are stopped.\n\n* MASTER_GTID_WAIT() can take its timeout as a floating-point value, so a\n timeout in fractional seconds is supported, eg. MASTER_GTID_WAIT(\"0-1-100\",\n 0.5). (The minimum wait is one microsecond, 0.000001 seconds).\n\n* MASTER_GTID_WAIT() allows one to specify a timeout of zero in order to do a\n non-blocking check to see if the slaves have progressed to a specific GTID\nposition\n (MASTER_POS_WAIT() takes a zero timeout as meaning an infinite wait). To do\n an infinite MASTER_GTID_WAIT(), specify a negative timeout, or omit the\n timeout argument.\n\n* MASTER_GTID_WAIT() does not return the number of events executed since the\n wait started, nor does it return NULL if a slave thread is stopped. It\n always returns either 0 for successful wait completed, or -1 for timeout\n reached (or NULL if the specified gtid-pos is NULL).\n\nSince MASTER_GTID_WAIT() looks only at the seq_no part of the GTIDs, not the\nserver_id, care is needed if a slave becomes diverged from another server so\nthat two different GTIDs with the same seq_no (in the same domain) arrive at\nthe same server. This situation is in any case best avoided; setting\ngtid_strict_mode is recommended, as this will prevent any such out-of-order\nsequence numbers from ever being replicated on a slave.\n\nURL: https://mariadb.com/kb/en/master_gtid_wait/','','https://mariadb.com/kb/en/master_gtid_wait/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (161,14,'MASTER_POS_WAIT','Syntax\n------\n\nMASTER_POS_WAIT(log_name,log_pos[,timeout,[\"connection_name\"]])\n\nDescription\n-----------\n\nThis function is useful in replication for controlling primary/replica\nsynchronization. It blocks until the replica has read and applied all updates\nup to the specified position (log_name,log_pos) in the primary log. The return\nvalue is the number of log events the replica had to wait for to advance to\nthe specified position. The function returns NULL if the replica SQL thread is\nnot started, the replica\'s primary information is not initialized, the\narguments are incorrect, or an error occurs. It returns -1 if the timeout has\nbeen exceeded. If the replica SQL thread stops while MASTER_POS_WAIT() is\nwaiting, the function returns NULL. If the replica is past the specified\nposition, the function returns immediately.\n\nIf a timeout value is specified, MASTER_POS_WAIT() stops waiting when timeout\nseconds have elapsed. timeout must be greater than 0; a zero or negative\ntimeout means no timeout.\n\nThe connection_name is used when you are using multi-source-replication. If\nyou don\'t specify it, it\'s set to the value of the default_master_connection\nsystem variable.\n\nStatements using the MASTER_POS_WAIT() function are not safe for replication.\n\nURL: https://mariadb.com/kb/en/master_pos_wait/','','https://mariadb.com/kb/en/master_pos_wait/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (162,14,'NAME_CONST','Syntax\n------\n\nNAME_CONST(name,value)\n\nDescription\n-----------\n\nReturns the given value. When used to produce a result set column,\nNAME_CONST() causes the column to have the given name. The arguments should be\nconstants.\n\nThis function is used internally when replicating stored procedures. It makes\nlittle sense to use it explicitly in SQL statements, and it was not supposed\nto be used like that.\n\nSELECT NAME_CONST(\'myname\', 14);\n+--------+\n| myname |\n+--------+\n| 14 |\n+--------+\n\nURL: https://mariadb.com/kb/en/name_const/','','https://mariadb.com/kb/en/name_const/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (163,14,'RELEASE_ALL_LOCKS','MariaDB until 10.5.2\n--------------------\nRELEASE_ALL_LOCKS was added in MariaDB 10.5.2.\n\nSyntax\n------\n\nRELEASE_ALL_LOCKS()\n\nDescription\n-----------\n\nReleases all named locks held by the current session. Returns the number of\nlocks released, or 0 if none were held.\n\nStatements using the RELEASE_ALL_LOCKS function are not safe for\nstatement-based replication.\n\nExamples\n--------\n\nSELECT RELEASE_ALL_LOCKS();\n+---------------------+\n| RELEASE_ALL_LOCKS() | \n+---------------------+\n| 0 |\n+---------------------+\n\nSELECT GET_LOCK(\'lock1\',10);\n+----------------------+\n| GET_LOCK(\'lock1\',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSELECT RELEASE_ALL_LOCKS();\n+---------------------+\n| RELEASE_ALL_LOCKS() | \n+---------------------+\n| 1 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/release_all_locks/','','https://mariadb.com/kb/en/release_all_locks/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (164,14,'RELEASE_LOCK','Syntax\n------\n\nRELEASE_LOCK(str)\n\nDescription\n-----------\n\nReleases the lock named by the string str that was obtained with GET_LOCK().\nReturns 1 if the lock was released, 0 if the lock was not established by this\nthread (in which case the lock is not released), and NULL if the named lock\ndid not exist. The lock does not exist if it was never obtained by a call to\nGET_LOCK() or if it has previously been released.\n\nstr is case insensitive. If str is an empty string or NULL, RELEASE_LOCK()\nreturns NULL and does nothing.\n\nStatements using the RELEASE_LOCK() function are not safe for replication.\n\nThe DO statement is convenient to use with RELEASE_LOCK().\n\nExamples\n--------\n\nConnection1:\n\nSELECT GET_LOCK(\'lock1\',10);\n+----------------------+\n| GET_LOCK(\'lock1\',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nConnection 2:\n\nSELECT GET_LOCK(\'lock2\',10);\n+----------------------+\n| GET_LOCK(\'lock2\',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nConnection 1:\n\nSELECT RELEASE_LOCK(\'lock1\'), RELEASE_LOCK(\'lock2\'), RELEASE_LOCK(\'lock3\');\n+-----------------------+-----------------------+-----------------------+\n| RELEASE_LOCK(\'lock1\') | RELEASE_LOCK(\'lock2\') | RELEASE_LOCK(\'lock3\') |\n+-----------------------+-----------------------+-----------------------+\n| 1 | 0 | NULL |\n+-----------------------+-----------------------+-----------------------+\n\nFrom MariaDB 10.0.2, it is possible to hold the same lock recursively. This\nexample is viewed using the metadata_lock_info plugin:\n\nSELECT GET_LOCK(\'lock3\',10);\n+----------------------+\n| GET_LOCK(\'lock3\',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSELECT GET_LOCK(\'lock3\',10);\n+----------------------+\n| GET_LOCK(\'lock3\',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSELECT * FROM INFORMATION_SCHEMA.METADATA_LOCK_INFO;\n+-----------+---------------------+---------------+-----------+--------------+-\n----------+\n| THREAD_ID | LOCK_MODE | LOCK_DURATION | LOCK_TYPE | TABLE_SCHEMA |\nTABLE_NAME |\n+-----------+---------------------+---------------+-----------+--------------+-\n----------+\n| 46 | MDL_SHARED_NO_WRITE | NULL | User lock | lock3 |\n |\n+-----------+---------------------+---------------+-----------+--------------+-\n----------+\n\nSELECT RELEASE_LOCK(\'lock3\');\n+-----------------------+\n| RELEASE_LOCK(\'lock3\') |\n+-----------------------+\n| 1 |\n+-----------------------+\n\nSELECT * FROM INFORMATION_SCHEMA.METADATA_LOCK_INFO;\n+-----------+---------------------+---------------+-----------+--------------+-\n----------+\n| THREAD_ID | LOCK_MODE | LOCK_DURATION | LOCK_TYPE | TABLE_SCHEMA |\nTABLE_NAME |\n+-----------+---------------------+---------------+-----------+--------------+-\n----------+\n| 46 | MDL_SHARED_NO_WRITE | NULL | User lock | lock3 |\n |\n+-----------+---------------------+---------------+-----------+--------------+-\n----------+\n\nSELECT RELEASE_LOCK(\'lock3\');\n+-----------------------+\n| RELEASE_LOCK(\'lock3\') |\n+-----------------------+\n| 1 |\n+-----------------------+\n\nSELECT * FROM INFORMATION_SCHEMA.METADATA_LOCK_INFO;\nEmpty set (0.000 sec)\n\nURL: https://mariadb.com/kb/en/release_lock/','','https://mariadb.com/kb/en/release_lock/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (165,14,'SLEEP','Syntax\n------\n\nSLEEP(duration)\n\nDescription\n-----------\n\nSleeps (pauses) for the number of seconds given by the duration argument, then\nreturns 0. If SLEEP() is interrupted, it returns 1. The duration may have a\nfractional part given in microseconds.\n\nStatements using the SLEEP() function are not safe for replication.\n\nExample\n-------\n\nSELECT SLEEP(5.5);\n+------------+\n| SLEEP(5.5) |\n+------------+\n| 0 |\n+------------+\n1 row in set (5.50 sec)\n\nURL: https://mariadb.com/kb/en/sleep/','','https://mariadb.com/kb/en/sleep/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (166,14,'SYS_GUID','MariaDB starting with 10.6.1\n----------------------------\nThe SYS_GUID function was introduced in MariaDB 10.6.1 to enhance Oracle\ncompatibility. Similar functionality can be achieved with the UUID function.\n\nSyntax\n------\n\nSYS_GUID()\n\nDescription\n-----------\n\nReturns a 16-byte globally unique identifier (GUID), similar to the UUID\nfunction, but without the - character.\n\nExample\n-------\n\nSELECT SYS_GUID();\n+----------------------------------+\n| SYS_GUID() |\n+----------------------------------+\n| 2C574E45BA2811EBB265F859713E4BE4 |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/sys_guid/','','https://mariadb.com/kb/en/sys_guid/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (167,14,'UUID','Syntax\n------\n\nUUID()\n\nDescription\n-----------\n\nReturns a Universally Unique Identifier (UUID).\n\nA UUID is designed as a number that is globally unique in space and time. Two\ncalls to UUID() are expected to generate two different values, even if these\ncalls are performed on two separate computers that are not connected to each\nother.\n\nUUID() results are intended to be unique, but cannot always be relied upon to\nunpredictable and unguessable, so should not be relied upon for these purposes.\n\nA UUID is a 128-bit number represented by a utf8 string of five hexadecimal\nnumbers in aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee format:\n\n* The first three numbers are generated from a timestamp.\n* The fourth number preserves temporal uniqueness in case the timestamp value\n loses monotonicity (for example, due to daylight saving time).\n* The fifth number is an IEEE 802 node number that provides spatial uniqueness.\n A random number is substituted if the latter is not available (for example,\n because the host computer has no Ethernet card, or we do not know how to find\n the hardware address of an interface on your operating system). In this case,\n spatial uniqueness cannot be guaranteed. Nevertheless, a collision should\n have very low probability.\n\nCurrently, the MAC address of an interface is taken into account only on\nFreeBSD and Linux. On other operating systems, MariaDB uses a randomly\ngenerated 48-bit number.\n\nStatements using the UUID() function are not safe for replication.\n\nThe results are generated according to the \"DCE 1.1:Remote Procedure Call\"\n(Appendix A) CAE (Common Applications Environment) Specifications published by\nThe Open Group in October 1997 (Document Number C706).\n\nExamples\n--------\n\nSELECT UUID();\n+--------------------------------------+\n| UUID() |\n+--------------------------------------+\n| cd41294a-afb0-11df-bc9b-00241dd75637 |\n+--------------------------------------+\n\nURL: https://mariadb.com/kb/en/uuid/','','https://mariadb.com/kb/en/uuid/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (168,14,'UUID_SHORT','Syntax\n------\n\nUUID_SHORT()\n\nDescription\n-----------\n\nReturns a \"short\" universally unique identifier as a 64-bit unsigned integer\n(rather than a string-form 128-bit identifier as returned by the UUID()\nfunction).\n\nThe value of UUID_SHORT() is guaranteed to be unique if the following\nconditions hold:\n\n* The server_id of the current host is unique among your set of master and\n slave servers\n* server_id is between 0 and 255\n* You don\'t set back your system time for your server between mysqld restarts\n* You do not invoke UUID_SHORT() on average more than 16\n million times per second between mysqld restarts\n\nThe UUID_SHORT() return value is constructed this way:\n\n(server_id & 255) << 56\n+ (server_startup_time_in_seconds << 24)\n+ incremented_variable++;\n\nStatements using the UUID_SHORT() function are not safe for statement-based\nreplication.\n\nExamples\n--------\n\nSELECT UUID_SHORT();\n+-------------------+\n| UUID_SHORT() |\n+-------------------+\n| 21517162376069120 |\n+-------------------+\n\ncreate table t1 (a bigint unsigned default(uuid_short()) primary key);\ninsert into t1 values(),();\nselect * from t1;\n+-------------------+\n| a |\n+-------------------+\n| 98113699159474176 |\n| 98113699159474177 |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/uuid_short/','','https://mariadb.com/kb/en/uuid_short/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (169,14,'VALUES / VALUE','Syntax\n------\n\nMariaDB starting with 10.3.3\n----------------------------\n\nVALUE(col_name)\n\nMariaDB until 10.3.2\n--------------------\n\nVALUES(col_name)\n\nDescription\n-----------\n\nIn an INSERT ... ON DUPLICATE KEY UPDATE statement, you can use the\nVALUES(col_name) function in the UPDATE clause to refer to column values from\nthe INSERT portion of the statement. In other words, VALUES(col_name) in the\nUPDATE clause refers to the value of col_name that would be inserted, had no\nduplicate-key conflict occurred. This function is especially useful in\nmultiple-row inserts.\n\nThe VALUES() function is meaningful only in INSERT ... ON DUPLICATE KEY UPDATE\nstatements and returns NULL otherwise.\n\nIn MariaDB 10.3.3 this function was renamed to VALUE(), because it\'s\nincompatible with the standard Table Value Constructors syntax, implemented in\nMariaDB 10.3.3.\n\nThe VALUES() function can still be used even from MariaDB 10.3.3, but only in\nINSERT ... ON DUPLICATE KEY UPDATE statements; it\'s a syntax error otherwise.\n\nExamples\n--------\n\nMariaDB starting with 10.3.3\n----------------------------\n\nINSERT INTO t (a,b,c) VALUES (1,2,3),(4,5,6)\n ON DUPLICATE KEY UPDATE c=VALUE(a)+VALUE(b);\n\nMariaDB until 10.3.2\n--------------------\n\nINSERT INTO t (a,b,c) VALUES (1,2,3),(4,5,6)\n ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);\n\nURL: https://mariadb.com/kb/en/values-value/','','https://mariadb.com/kb/en/values-value/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (170,15,'!','Syntax\n------\n\nNOT, !\n\nDescription\n-----------\n\nLogical NOT. Evaluates to 1 if the operand is 0, to 0 if the operand is\nnon-zero, and NOT NULL returns NULL.\n\nBy default, the ! operator has a higher precedence. If the HIGH_NOT_PRECEDENCE\nSQL_MODE flag is set, NOT and ! have the same precedence.\n\nExamples\n--------\n\nSELECT NOT 10;\n+--------+\n| NOT 10 |\n+--------+\n| 0 |\n+--------+\n\nSELECT NOT 0;\n+-------+\n| NOT 0 |\n+-------+\n| 1 |\n+-------+\n\nSELECT NOT NULL;\n+----------+\n| NOT NULL |\n+----------+\n| NULL |\n+----------+\n\nSELECT ! (1+1);\n+---------+\n| ! (1+1) |\n+---------+\n| 0 |\n+---------+\n\nSELECT ! 1+1;\n+-------+\n| ! 1+1 |\n+-------+\n| 1 |\n+-------+\n\nURL: https://mariadb.com/kb/en/not/','','https://mariadb.com/kb/en/not/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (171,15,'&&','Syntax\n------\n\nAND, &&\n\nDescription\n-----------\n\nLogical AND. Evaluates to 1 if all operands are non-zero and not NULL, to 0 if\none or more operands are 0, otherwise NULL is returned.\n\nFor this operator, short-circuit evaluation can be used.\n\nExamples\n--------\n\nSELECT 1 && 1;\n+--------+\n| 1 && 1 |\n+--------+\n| 1 |\n+--------+\n\nSELECT 1 && 0;\n+--------+\n| 1 && 0 |\n+--------+\n| 0 |\n+--------+\n\nSELECT 1 && NULL;\n+-----------+\n| 1 && NULL |\n+-----------+\n| NULL |\n+-----------+\n\nSELECT 0 && NULL;\n+-----------+\n| 0 && NULL |\n+-----------+\n| 0 |\n+-----------+\n\nSELECT NULL && 0;\n+-----------+\n| NULL && 0 |\n+-----------+\n| 0 |\n+-----------+\n\nURL: https://mariadb.com/kb/en/and/','','https://mariadb.com/kb/en/and/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (172,15,'XOR','Syntax\n------\n\nXOR\n\nDescription\n-----------\n\nXOR stands for eXclusive OR. Returns NULL if either operand is NULL. For\nnon-NULL operands, evaluates to 1 if an odd number of operands is non-zero,\notherwise 0 is returned.\n\nExamples\n--------\n\nSELECT 1 XOR 1;\n+---------+\n| 1 XOR 1 |\n+---------+\n| 0 |\n+---------+\n\nSELECT 1 XOR 0;\n+---------+\n| 1 XOR 0 |\n+---------+\n| 1 |\n+---------+\n\nSELECT 1 XOR NULL;\n+------------+\n| 1 XOR NULL |\n+------------+\n| NULL |\n+------------+\n\nIn the following example, the right 1 XOR 1 is evaluated first, and returns 0.\nThen, 1 XOR 0 is evaluated, and 1 is returned.\n\nSELECT 1 XOR 1 XOR 1;\n+---------------+\n| 1 XOR 1 XOR 1 |\n+---------------+\n| 1 |\n+---------------+\n\nURL: https://mariadb.com/kb/en/xor/','','https://mariadb.com/kb/en/xor/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (173,15,'||','Syntax\n------\n\nOR, ||\n\nDescription\n-----------\n\nLogical OR. When both operands are non-NULL, the result is 1 if any operand is\nnon-zero, and 0 otherwise. With a NULL operand, the result is 1 if the other\noperand is non-zero, and NULL otherwise. If both operands are NULL, the result\nis NULL.\n\nFor this operator, short-circuit evaluation can be used.\n\nNote that, if the PIPES_AS_CONCAT SQL_MODE is set, || is used as a string\nconcatenation operator. This means that a || b is the same as CONCAT(a,b). See\nCONCAT() for details.\n\nOracle Mode\n-----------\n\nMariaDB starting with 10.3\n--------------------------\nIn Oracle mode from MariaDB 10.3, || ignores NULL.\n\nExamples\n--------\n\nSELECT 1 || 1;\n+--------+\n| 1 || 1 |\n+--------+\n| 1 |\n+--------+\n\nSELECT 1 || 0;\n+--------+\n| 1 || 0 |\n+--------+\n| 1 |\n+--------+\n\nSELECT 0 || 0;\n+--------+\n| 0 || 0 |\n+--------+\n| 0 |\n+--------+\n\nSELECT 0 || NULL;\n+-----------+\n| 0 || NULL |\n+-----------+\n| NULL |\n+-----------+\n\nSELECT 1 || NULL;\n+-----------+\n| 1 || NULL |\n+-----------+\n| 1 |\n+-----------+\n\nIn Oracle mode, from MariaDB 10.3:\n\nSELECT 0 || NULL;\n+-----------+\n| 0 || NULL |\n+-----------+\n| 0 |\n+-----------+\n\nURL: https://mariadb.com/kb/en/or/','','https://mariadb.com/kb/en/or/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (174,16,'Stored Aggregate Functions','MariaDB starting with 10.3.3\n----------------------------\nThe ability to create stored aggregate functions was added in MariaDB 10.3.3.\n\nAggregate functions are functions that are computed over a sequence of rows\nand return one result for the sequence of rows.\n\nCreating a custom aggregate function is done using the CREATE FUNCTION\nstatement with two main differences:\n\n* The addition of the AGGREGATE keyword, so CREATE AGGREGATE FUNCTION\n* The FETCH GROUP NEXT ROW instruction inside the loop\n* Oracle PL/SQL compatibility using SQL/PL is provided\n\nStandard Syntax\n---------------\n\nCREATE AGGREGATE FUNCTION function_name (parameters) RETURNS return_type\nBEGIN\n All types of declarations\n DECLARE CONTINUE HANDLER FOR NOT FOUND RETURN return_val;\n LOOP\n FETCH GROUP NEXT ROW; // fetches next row from table\n other instructions\n END LOOP;\nEND\n\nStored aggregate functions were a 2016 Google Summer of Code project by Varun\nGupta.\n\nUsing SQL/PL\n------------\n\nSET sql_mode=Oracle;\nDELIMITER //\n\nCREATE AGGREGATE FUNCTION function_name (parameters) RETURN return_type\n declarations\nBEGIN\n LOOP\n FETCH GROUP NEXT ROW; -- fetches next row from table\n -- other instructions\n\nEND LOOP;\nEXCEPTION\n WHEN NO_DATA_FOUND THEN\n RETURN return_val;\nEND //\n\nDELIMITER ;\n\nExamples\n--------\n\nFirst a simplified example:\n\nCREATE TABLE marks(stud_id INT, grade_count INT);\n\nINSERT INTO marks VALUES (1,6), (2,4), (3,7), (4,5), (5,8);\n\nSELECT * FROM marks;\n+---------+-------------+\n| stud_id | grade_count |\n+---------+-------------+\n| 1 | 6 |\n| 2 | 4 |\n| 3 | 7 |\n| 4 | 5 |\n| 5 | 8 |\n+---------+-------------+\n\nDELIMITER //\nCREATE AGGREGATE FUNCTION IF NOT EXISTS aggregate_count(x INT) RETURNS INT\nBEGIN\n DECLARE count_students INT DEFAULT 0;\n DECLARE CONTINUE HANDLER FOR NOT FOUND\n RETURN count_students;\n LOOP\n FETCH GROUP NEXT ROW;\n IF x THEN\n SET count_students = count_students+1;\n END IF;\n END LOOP;\nEND //\nDELIMITER ;\n\nA non-trivial example that cannot easily be rewritten using existing functions:\n\nDELIMITER //\nCREATE AGGREGATE FUNCTION medi_int(x INT) RETURNS DOUBLE\nBEGIN\n DECLARE CONTINUE HANDLER FOR NOT FOUND\n BEGIN\n DECLARE res DOUBLE;\n DECLARE cnt INT DEFAULT (SELECT COUNT(*) FROM tt);\n DECLARE lim INT DEFAULT (cnt-1) DIV 2;\n IF cnt % 2 = 0 THEN\n SET res = (SELECT AVG(a) FROM (SELECT a FROM tt ORDER BY a LIMIT\nlim,2) ttt);\n ELSE\n SET res = (SELECT a FROM tt ORDER BY a LIMIT lim,1);\n END IF;\n DROP TEMPORARY TABLE tt;\n RETURN res;\n END;\n CREATE TEMPORARY TABLE tt (a INT);\n LOOP\n FETCH GROUP NEXT ROW;\n INSERT INTO tt VALUES (x);\n END LOOP;\nEND //\nDELIMITER ;\n\nSQL/PL Example\n--------------\n\nThis uses the same marks table as created above.\n\nSET sql_mode=Oracle;\nDELIMITER //\n\nCREATE AGGREGATE FUNCTION aggregate_count(x INT) RETURN INT AS count_students\nINT DEFAULT 0;\nBEGIN\n LOOP\n FETCH GROUP NEXT ROW;\n IF x THEN\n SET count_students := count_students+1;\n END IF;\n END LOOP;\nEXCEPTION\n WHEN NO_DATA_FOUND THEN\n RETURN count_students;\nEND aggregate_count //\nDELIMITER ;\n\nSELECT aggregate_count(stud_id) FROM marks;\n\nURL: https://mariadb.com/kb/en/stored-aggregate-functions/','','https://mariadb.com/kb/en/stored-aggregate-functions/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (175,16,'AVG','Syntax\n------\n\nAVG([DISTINCT] expr)\n\nDescription\n-----------\n\nReturns the average value of expr. The DISTINCT option can be used to return\nthe average of the distinct values of expr. NULL values are ignored. It is an\naggregate function, and so can be used with the GROUP BY clause.\n\nAVG() returns NULL if there were no matching rows.\n\nAVG() can be used as a window function.\n\nExamples\n--------\n\nCREATE TABLE sales (sales_value INT);\n\nINSERT INTO sales VALUES(10),(20),(20),(40);\n\nSELECT AVG(sales_value) FROM sales;\n+------------------+\n| AVG(sales_value) |\n+------------------+\n| 22.5000 |\n+------------------+\n\nSELECT AVG(DISTINCT(sales_value)) FROM sales;\n+----------------------------+\n| AVG(DISTINCT(sales_value)) |\n+----------------------------+\n| 23.3333 |\n+----------------------------+\n\nCommonly, AVG() is used with a GROUP BY clause:\n\nCREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87), (\'Tatiana\', \'Tuning\', 83);\n\nSELECT name, AVG(score) FROM student GROUP BY name;\n+---------+------------+\n| name | AVG(score) |\n+---------+------------+\n| Chun | 74.0000 |\n| Esben | 37.0000 |\n| Kaolin | 72.0000 |\n| Tatiana | 85.0000 |\n+---------+------------+\n\nBe careful to avoid this common mistake, not grouping correctly and returning\nmismatched data:\n\nSELECT name,test,AVG(score) FROM student;\n+------+------+------------+\n| name | test | MIN(score) |\n+------+------+------------+\n| Chun | SQL | 31 |\n+------+------+------------+\n\nAs a window function:\n\nCREATE TABLE student_test (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student_test VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87), (\'Tatiana\', \'Tuning\', 83);\n\nSELECT name, test, score, AVG(score) OVER (PARTITION BY test) \n AS average_by_test FROM student_test;\n+---------+--------+-------+-----------------+\n| name | test | score | average_by_test |\n+---------+--------+-------+-----------------+\n| Chun | SQL | 75 | 65.2500 |\n| Chun | Tuning | 73 | 68.7500 |\n| Esben | SQL | 43 | 65.2500 |\n| Esben | Tuning | 31 | 68.7500 |\n| Kaolin | SQL | 56 | 65.2500 |\n| Kaolin | Tuning | 88 | 68.7500 |\n| Tatiana | SQL | 87 | 65.2500 |\n| Tatiana | Tuning | 83 | 68.7500 |\n+---------+--------+-------+-----------------+\n\nURL: https://mariadb.com/kb/en/avg/','','https://mariadb.com/kb/en/avg/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (176,16,'BIT_AND','Syntax\n------\n\nBIT_AND(expr) [over_clause]\n\nDescription\n-----------\n\nReturns the bitwise AND of all bits in expr. The calculation is performed with\n64-bit (BIGINT) precision. It is an aggregate function, and so can be used\nwith the GROUP BY clause.\n\nIf no rows match, BIT_AND will return a value with all bits set to 1. NULL\nvalues have no effect on the result unless all results are NULL, which is\ntreated as no match.\n\nBIT_AND can be used as a window function with the addition of the over_clause.\n\nExamples\n--------\n\nCREATE TABLE vals (x INT);\n\nINSERT INTO vals VALUES(111),(110),(100);\n\nSELECT BIT_AND(x), BIT_OR(x), BIT_XOR(x) FROM vals;\n+------------+-----------+------------+\n| BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+------------+-----------+------------+\n| 100 | 111 | 101 |\n+------------+-----------+------------+\n\nAs an aggregate function:\n\nCREATE TABLE vals2 (category VARCHAR(1), x INT);\n\nINSERT INTO vals2 VALUES\n (\'a\',111),(\'a\',110),(\'a\',100),\n (\'b\',\'000\'),(\'b\',001),(\'b\',011);\n\nSELECT category, BIT_AND(x), BIT_OR(x), BIT_XOR(x) \n FROM vals GROUP BY category;\n+----------+------------+-----------+------------+\n| category | BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+----------+------------+-----------+------------+\n| a | 100 | 111 | 101 |\n| b | 0 | 11 | 10 |\n+----------+------------+-----------+------------+\n\nNo match:\n\nSELECT BIT_AND(NULL);\n+----------------------+\n| BIT_AND(NULL) |\n+----------------------+\n| 18446744073709551615 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/bit_and/','','https://mariadb.com/kb/en/bit_and/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (177,16,'BIT_OR','Syntax\n------\n\nBIT_OR(expr) [over_clause]\n\nDescription\n-----------\n\nReturns the bitwise OR of all bits in expr. The calculation is performed with\n64-bit (BIGINT) precision. It is an aggregate function, and so can be used\nwith the GROUP BY clause.\n\nIf no rows match, BIT_OR will return a value with all bits set to 0. NULL\nvalues have no effect on the result unless all results are NULL, which is\ntreated as no match.\n\nBIT_OR can be used as a window function with the addition of the over_clause.\n\nExamples\n--------\n\nCREATE TABLE vals (x INT);\n\nINSERT INTO vals VALUES(111),(110),(100);\n\nSELECT BIT_AND(x), BIT_OR(x), BIT_XOR(x) FROM vals;\n+------------+-----------+------------+\n| BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+------------+-----------+------------+\n| 100 | 111 | 101 |\n+------------+-----------+------------+\n\nAs an aggregate function:\n\nCREATE TABLE vals2 (category VARCHAR(1), x INT);\n\nINSERT INTO vals2 VALUES\n (\'a\',111),(\'a\',110),(\'a\',100),\n (\'b\',\'000\'),(\'b\',001),(\'b\',011);\n\nSELECT category, BIT_AND(x), BIT_OR(x), BIT_XOR(x) \n FROM vals GROUP BY category;\n+----------+------------+-----------+------------+\n| category | BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+----------+------------+-----------+------------+\n| a | 100 | 111 | 101 |\n| b | 0 | 11 | 10 |\n+----------+------------+-----------+------------+\n\nNo match:\n\nSELECT BIT_OR(NULL);\n+--------------+\n| BIT_OR(NULL) |\n+--------------+\n| 0 |\n+--------------+\n\nURL: https://mariadb.com/kb/en/bit_or/','','https://mariadb.com/kb/en/bit_or/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (178,16,'BIT_XOR','Syntax\n------\n\nBIT_XOR(expr) [over_clause]\n\nDescription\n-----------\n\nReturns the bitwise XOR of all bits in expr. The calculation is performed with\n64-bit (BIGINT) precision. It is an aggregate function, and so can be used\nwith the GROUP BY clause.\n\nIf no rows match, BIT_XOR will return a value with all bits set to 0. NULL\nvalues have no effect on the result unless all results are NULL, which is\ntreated as no match.\n\nBIT_XOR can be used as a window function with the addition of the over_clause.\n\nExamples\n--------\n\nCREATE TABLE vals (x INT);\n\nINSERT INTO vals VALUES(111),(110),(100);\n\nSELECT BIT_AND(x), BIT_OR(x), BIT_XOR(x) FROM vals;\n+------------+-----------+------------+\n| BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+------------+-----------+------------+\n| 100 | 111 | 101 |\n+------------+-----------+------------+\n\nAs an aggregate function:\n\nCREATE TABLE vals2 (category VARCHAR(1), x INT);\n\nINSERT INTO vals2 VALUES\n (\'a\',111),(\'a\',110),(\'a\',100),\n (\'b\',\'000\'),(\'b\',001),(\'b\',011);\n\nSELECT category, BIT_AND(x), BIT_OR(x), BIT_XOR(x) \n FROM vals GROUP BY category;\n+----------+------------+-----------+------------+\n| category | BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+----------+------------+-----------+------------+\n| a | 100 | 111 | 101 |\n| b | 0 | 11 | 10 |\n+----------+------------+-----------+------------+\n\nNo match:\n\nSELECT BIT_XOR(NULL);\n+---------------+\n| BIT_XOR(NULL) |\n+---------------+\n| 0 |\n+---------------+\n\nURL: https://mariadb.com/kb/en/bit_xor/','','https://mariadb.com/kb/en/bit_xor/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (179,16,'COUNT','Syntax\n------\n\nCOUNT(expr)\n\nDescription\n-----------\n\nReturns a count of the number of non-NULL values of expr in the rows retrieved\nby a SELECT statement. The result is a BIGINT value. It is an aggregate\nfunction, and so can be used with the GROUP BY clause.\n\nCOUNT(*) counts the total number of rows in a table.\n\nCOUNT() returns 0 if there were no matching rows.\n\nCOUNT() can be used as a window function.\n\nExamples\n--------\n\nCREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87), (\'Tatiana\', \'Tuning\', 83);\n\nSELECT COUNT(*) FROM student;\n+----------+\n| COUNT(*) |\n+----------+\n| 8 |\n+----------+\n\nCOUNT(DISTINCT) example:\n\nSELECT COUNT(DISTINCT (name)) FROM student;\n+------------------------+\n| COUNT(DISTINCT (name)) |\n+------------------------+\n| 4 |\n+------------------------+\n\nAs a window function\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87);\n\nSELECT name, test, score, COUNT(score) OVER (PARTITION BY name) \n AS tests_written FROM student_test;\n+---------+--------+-------+---------------+\n| name | test | score | tests_written |\n+---------+--------+-------+---------------+\n| Chun | SQL | 75 | 2 |\n| Chun | Tuning | 73 | 2 |\n| Esben | SQL | 43 | 2 |\n| Esben | Tuning | 31 | 2 |\n| Kaolin | SQL | 56 | 2 |\n| Kaolin | Tuning | 88 | 2 |\n| Tatiana | SQL | 87 | 1 |\n+---------+--------+-------+---------------+\n\nURL: https://mariadb.com/kb/en/count/','','https://mariadb.com/kb/en/count/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (180,16,'COUNT DISTINCT','Syntax\n------\n\nCOUNT(DISTINCT expr,[expr...])\n\nDescription\n-----------\n\nReturns a count of the number of different non-NULL values.\n\nCOUNT(DISTINCT) returns 0 if there were no matching rows.\n\nAlthough, from MariaDB 10.2.0, COUNT can be used as a window function, COUNT\nDISTINCT cannot be.\n\nExamples\n--------\n\nCREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87), (\'Tatiana\', \'Tuning\', 83);\n\nSELECT COUNT(*) FROM student;\n+----------+\n| COUNT(*) |\n+----------+\n| 8 |\n+----------+\n\nSELECT COUNT(DISTINCT (name)) FROM student;\n+------------------------+\n| COUNT(DISTINCT (name)) |\n+------------------------+\n| 4 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/count-distinct/','','https://mariadb.com/kb/en/count-distinct/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (181,16,'GROUP_CONCAT','Syntax\n------\n\nGROUP_CONCAT(expr)\n\nDescription\n-----------\n\nThis function returns a string result with the concatenated non-NULL values\nfrom a group. It returns NULL if there are no non-NULL values.\n\nThe maximum returned length in bytes is determined by the group_concat_max_len\nserver system variable, which defaults to 1M (>= MariaDB 10.2.4) or 1K (<=\nMariaDB 10.2.3).\n\nIf group_concat_max_len <= 512, the return type is VARBINARY or VARCHAR;\notherwise, the return type is BLOB or TEXT. The choice between binary or\nnon-binary types depends from the input.\n\nThe full syntax is as follows:\n\nGROUP_CONCAT([DISTINCT] expr [,expr ...]\n [ORDER BY {unsigned_integer | col_name | expr}\n [ASC | DESC] [,col_name ...]]\n [SEPARATOR str_val]\n [LIMIT {[offset,] row_count | row_count OFFSET offset}])\n\nDISTINCT eliminates duplicate values from the output string.\n\nORDER BY determines the order of returned values.\n\nSEPARATOR specifies a separator between the values. The default separator is a\ncomma (,). It is possible to avoid using a separator by specifying an empty\nstring.\n\nLIMIT\n-----\n\nMariaDB starting with 10.3.3\n----------------------------\nUntil MariaDB 10.3.2, it was not possible to use the LIMIT clause with\nGROUP_CONCAT. This restriction was lifted in MariaDB 10.3.3.\n\nExamples\n--------\n\nSELECT student_name,\n GROUP_CONCAT(test_score)\n FROM student\n GROUP BY student_name;\n\nGet a readable list of MariaDB users from the mysql.user table:\n\nSELECT GROUP_CONCAT(DISTINCT User ORDER BY User SEPARATOR \'\\n\')\n FROM mysql.user;\n\nIn the former example, DISTINCT is used because the same user may occur more\nthan once. The new line (\\n) used as a SEPARATOR makes the results easier to\nread.\n\nGet a readable list of hosts from which each user can connect:\n\nSELECT User, GROUP_CONCAT(Host ORDER BY Host SEPARATOR \', \') \n FROM mysql.user GROUP BY User ORDER BY User;\n\nThe former example shows the difference between the GROUP_CONCAT\'s ORDER BY\n(which sorts the concatenated hosts), and the SELECT\'s ORDER BY (which sorts\nthe rows).\n\nFrom MariaDB 10.3.3, LIMIT can be used with GROUP_CONCAT, so, for example,\ngiven the following table:\n\nCREATE TABLE d (dd DATE, cc INT);\n\nINSERT INTO d VALUES (\'2017-01-01\',1);\nINSERT INTO d VALUES (\'2017-01-02\',2);\nINSERT INTO d VALUES (\'2017-01-04\',3);\n\nthe following query:\n\nSELECT SUBSTRING_INDEX(GROUP_CONCAT(CONCAT_WS(\":\",dd,cc) ORDER BY cc\nDESC),\",\",1) FROM d;\n+----------------------------------------------------------------------------+\n| SUBSTRING_INDEX(GROUP_CONCAT(CONCAT_WS(\":\",dd,cc) ORDER BY cc DESC),\",\",1) |\n+----------------------------------------------------------------------------+\n| 2017-01-04:3 |\n+----------------------------------------------------------------------------+\n\ncan be more simply rewritten as:\n\nSELECT GROUP_CONCAT(CONCAT_WS(\":\",dd,cc) ORDER BY cc DESC LIMIT 1) FROM d;\n+-------------------------------------------------------------+\n| GROUP_CONCAT(CONCAT_WS(\":\",dd,cc) ORDER BY cc DESC LIMIT 1) |\n+-------------------------------------------------------------+\n| 2017-01-04:3 |\n+-------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/group_concat/','','https://mariadb.com/kb/en/group_concat/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (182,16,'MAX','Syntax\n------\n\nMAX([DISTINCT] expr)\n\nDescription\n-----------\n\nReturns the largest, or maximum, value of expr. MAX() can also take a string\nargument in which case it returns the maximum string value. The DISTINCT\nkeyword can be used to find the maximum of the distinct values of expr,\nhowever, this produces the same result as omitting DISTINCT.\n\nNote that SET and ENUM fields are currently compared by their string value\nrather than their relative position in the set, so MAX() may produce a\ndifferent highest result than ORDER BY DESC.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nMAX() can be used as a window function.\n\nMAX() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nCREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87), (\'Tatiana\', \'Tuning\', 83);\n\nSELECT name, MAX(score) FROM student GROUP BY name;\n+---------+------------+\n| name | MAX(score) |\n+---------+------------+\n| Chun | 75 |\n| Esben | 43 |\n| Kaolin | 88 |\n| Tatiana | 87 |\n+---------+------------+\n\nMAX string:\n\nSELECT MAX(name) FROM student;\n+-----------+\n| MAX(name) |\n+-----------+\n| Tatiana |\n+-----------+\n\nBe careful to avoid this common mistake, not grouping correctly and returning\nmismatched data:\n\nSELECT name,test,MAX(SCORE) FROM student;\n+------+------+------------+\n| name | test | MAX(SCORE) |\n+------+------+------------+\n| Chun | SQL | 88 |\n+------+------+------------+\n\nDifference between ORDER BY DESC and MAX():\n\nCREATE TABLE student2(name CHAR(10),grade ENUM(\'b\',\'c\',\'a\'));\n\nINSERT INTO student2 VALUES(\'Chun\',\'b\'),(\'Esben\',\'c\'),(\'Kaolin\',\'a\');\n\nSELECT MAX(grade) FROM student2;\n+------------+\n| MAX(grade) |\n+------------+\n| c |\n+------------+\n\nSELECT grade FROM student2 ORDER BY grade DESC LIMIT 1;\n+-------+\n| grade |\n+-------+\n| a |\n+-------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\nINSERT INTO student_test VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87);\n\nSELECT name, test, score, MAX(score) \n OVER (PARTITION BY name) AS highest_score FROM student_test;\n+---------+--------+-------+---------------+\n| name | test | score | highest_score |\n+---------+--------+-------+---------------+\n| Chun | SQL | 75 | 75 |\n| Chun | Tuning | 73 | 75 |\n| Esben | SQL | 43 | 43 |\n| Esben | Tuning | 31 | 43 |\n| Kaolin | SQL | 56 | 88 |\n| Kaolin | Tuning | 88 | 88 |\n| Tatiana | SQL | 87 | 87 |\n+---------+--------+-------+---------------+\n\nURL: https://mariadb.com/kb/en/max/','','https://mariadb.com/kb/en/max/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (183,16,'MIN','Syntax\n------\n\nMIN([DISTINCT] expr)\n\nDescription\n-----------\n\nReturns the minimum value of expr. MIN() may take a string argument, in which\ncase it returns the minimum string value. The DISTINCT keyword can be used to\nfind the minimum of the distinct values of expr, however, this produces the\nsame result as omitting DISTINCT.\n\nNote that SET and ENUM fields are currently compared by their string value\nrather than their relative position in the set, so MIN() may produce a\ndifferent lowest result than ORDER BY ASC.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nMIN() can be used as a window function.\n\nMIN() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nCREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87), (\'Tatiana\', \'Tuning\', 83);\n\nSELECT name, MIN(score) FROM student GROUP BY name;\n+---------+------------+\n| name | MIN(score) |\n+---------+------------+\n| Chun | 73 |\n| Esben | 31 |\n| Kaolin | 56 |\n| Tatiana | 83 |\n+---------+------------+\n\nMIN() with a string:\n\nSELECT MIN(name) FROM student;\n+-----------+\n| MIN(name) |\n+-----------+\n| Chun |\n+-----------+\n\nBe careful to avoid this common mistake, not grouping correctly and returning\nmismatched data:\n\nSELECT name,test,MIN(score) FROM student;\n+------+------+------------+\n| name | test | MIN(score) |\n+------+------+------------+\n| Chun | SQL | 31 |\n+------+------+------------+\n\nDifference between ORDER BY ASC and MIN():\n\nCREATE TABLE student2(name CHAR(10),grade ENUM(\'b\',\'c\',\'a\'));\n\nINSERT INTO student2 VALUES(\'Chun\',\'b\'),(\'Esben\',\'c\'),(\'Kaolin\',\'a\');\n\nSELECT MIN(grade) FROM student2;\n+------------+\n| MIN(grade) |\n+------------+\n| a |\n+------------+\n\nSELECT grade FROM student2 ORDER BY grade ASC LIMIT 1;\n+-------+\n| grade |\n+-------+\n| b |\n+-------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\nINSERT INTO student_test VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87);\n\nSELECT name, test, score, MIN(score) \n OVER (PARTITION BY name) AS lowest_score FROM student_test;\n+---------+--------+-------+--------------+\n| name | test | score | lowest_score |\n+---------+--------+-------+--------------+\n| Chun | SQL | 75 | 73 |\n| Chun | Tuning | 73 | 73 |\n| Esben | SQL | 43 | 31 |\n| Esben | Tuning | 31 | 31 |\n| Kaolin | SQL | 56 | 56 |\n| Kaolin | Tuning | 88 | 56 |\n| Tatiana | SQL | 87 | 87 |\n+---------+--------+-------+--------------+\n\nURL: https://mariadb.com/kb/en/min/','','https://mariadb.com/kb/en/min/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (184,16,'STD','Syntax\n------\n\nSTD(expr)\n\nDescription\n-----------\n\nReturns the population standard deviation of expr. This is an extension to\nstandard SQL. The standard SQL function STDDEV_POP() can be used instead.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nSTD() can be used as a window function.\n\nThis function returns NULL if there were no matching rows.\n\nExamples\n--------\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n (\'a\',1),(\'a\',2),(\'a\',3),\n (\'b\',11),(\'b\',12),(\'b\',20),(\'b\',30),(\'b\',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n+----------+---------------+----------------+------------+\n| a | 0.8165 | 1.0000 | 0.6667 |\n| b | 18.0400 | 20.1693 | 325.4400 |\n+----------+---------------+----------------+------------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87);\n\nSELECT name, test, score, STDDEV_POP(score) \n OVER (PARTITION BY test) AS stddev_results FROM student_test;\n+---------+--------+-------+----------------+\n| name | test | score | stddev_results |\n+---------+--------+-------+----------------+\n| Chun | SQL | 75 | 16.9466 |\n| Chun | Tuning | 73 | 24.1247 |\n| Esben | SQL | 43 | 16.9466 |\n| Esben | Tuning | 31 | 24.1247 |\n| Kaolin | SQL | 56 | 16.9466 |\n| Kaolin | Tuning | 88 | 24.1247 |\n| Tatiana | SQL | 87 | 16.9466 |\n+---------+--------+-------+----------------+\n\nURL: https://mariadb.com/kb/en/std/','','https://mariadb.com/kb/en/std/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (185,16,'STDDEV','Syntax\n------\n\nSTDDEV(expr)\n\nDescription\n-----------\n\nReturns the population standard deviation of expr. This function is provided\nfor compatibility with Oracle. The standard SQL function STDDEV_POP() can be\nused instead.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nSTDDEV() can be used as a window function.\n\nThis function returns NULL if there were no matching rows.\n\nExamples\n--------\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n (\'a\',1),(\'a\',2),(\'a\',3),\n (\'b\',11),(\'b\',12),(\'b\',20),(\'b\',30),(\'b\',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n+----------+---------------+----------------+------------+\n| a | 0.8165 | 1.0000 | 0.6667 |\n| b | 18.0400 | 20.1693 | 325.4400 |\n+----------+---------------+----------------+------------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87);\n\nSELECT name, test, score, STDDEV_POP(score) \n OVER (PARTITION BY test) AS stddev_results FROM student_test;\n+---------+--------+-------+----------------+\n| name | test | score | stddev_results |\n+---------+--------+-------+----------------+\n| Chun | SQL | 75 | 16.9466 |\n| Chun | Tuning | 73 | 24.1247 |\n| Esben | SQL | 43 | 16.9466 |\n| Esben | Tuning | 31 | 24.1247 |\n| Kaolin | SQL | 56 | 16.9466 |\n| Kaolin | Tuning | 88 | 24.1247 |\n| Tatiana | SQL | 87 | 16.9466 |\n+---------+--------+-------+----------------+\n\nURL: https://mariadb.com/kb/en/stddev/','','https://mariadb.com/kb/en/stddev/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (186,16,'STDDEV_POP','Syntax\n------\n\nSTDDEV_POP(expr)\n\nDescription\n-----------\n\nReturns the population standard deviation of expr (the square root of\nVAR_POP()). You can also use STD() or STDDEV(), which are equivalent but not\nstandard SQL.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nSTDDEV_POP() can be used as a window function.\n\nSTDDEV_POP() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n (\'a\',1),(\'a\',2),(\'a\',3),\n (\'b\',11),(\'b\',12),(\'b\',20),(\'b\',30),(\'b\',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n+----------+---------------+----------------+------------+\n| a | 0.8165 | 1.0000 | 0.6667 |\n| b | 18.0400 | 20.1693 | 325.4400 |\n+----------+---------------+----------------+------------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87);\n\nSELECT name, test, score, STDDEV_POP(score) \n OVER (PARTITION BY test) AS stddev_results FROM student_test;\n+---------+--------+-------+----------------+\n| name | test | score | stddev_results |\n+---------+--------+-------+----------------+\n| Chun | SQL | 75 | 16.9466 |\n| Chun | Tuning | 73 | 24.1247 |\n| Esben | SQL | 43 | 16.9466 |\n| Esben | Tuning | 31 | 24.1247 |\n| Kaolin | SQL | 56 | 16.9466 |\n| Kaolin | Tuning | 88 | 24.1247 |\n| Tatiana | SQL | 87 | 16.9466 |\n+---------+--------+-------+----------------+\n\nURL: https://mariadb.com/kb/en/stddev_pop/','','https://mariadb.com/kb/en/stddev_pop/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (187,16,'STDDEV_SAMP','Syntax\n------\n\nSTDDEV_SAMP(expr)\n\nDescription\n-----------\n\nReturns the sample standard deviation of expr (the square root of VAR_SAMP()).\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nSTDDEV_SAMP() can be used as a window function.\n\nSTDDEV_SAMP() returns NULL if there were no matching rows.\n\nURL: https://mariadb.com/kb/en/stddev_samp/','','https://mariadb.com/kb/en/stddev_samp/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (188,16,'SUM','Syntax\n------\n\nSUM([DISTINCT] expr)\n\nDescription\n-----------\n\nReturns the sum of expr. If the return set has no rows, SUM() returns NULL.\nThe DISTINCT keyword can be used to sum only the distinct values of expr.\n\nSUM() can be used as a window function, although not with the DISTINCT\nspecifier.\n\nExamples\n--------\n\nCREATE TABLE sales (sales_value INT);\nINSERT INTO sales VALUES(10),(20),(20),(40);\n\nSELECT SUM(sales_value) FROM sales;\n+------------------+\n| SUM(sales_value) |\n+------------------+\n| 90 |\n+------------------+\n\nSELECT SUM(DISTINCT(sales_value)) FROM sales;\n+----------------------------+\n| SUM(DISTINCT(sales_value)) |\n+----------------------------+\n| 70 |\n+----------------------------+\n\nCommonly, SUM is used with a GROUP BY clause:\n\nCREATE TABLE sales (name CHAR(10), month CHAR(10), units INT);\n\nINSERT INTO sales VALUES \n (\'Chun\', \'Jan\', 75), (\'Chun\', \'Feb\', 73),\n (\'Esben\', \'Jan\', 43), (\'Esben\', \'Feb\', 31),\n (\'Kaolin\', \'Jan\', 56), (\'Kaolin\', \'Feb\', 88),\n (\'Tatiana\', \'Jan\', 87), (\'Tatiana\', \'Feb\', 83);\n\nSELECT name, SUM(units) FROM sales GROUP BY name;\n+---------+------------+\n| name | SUM(units) |\n+---------+------------+\n| Chun | 148 |\n| Esben | 74 |\n| Kaolin | 144 |\n| Tatiana | 170 |\n+---------+------------+\n\nThe GROUP BY clause is required when using an aggregate function along with\nregular column data, otherwise the result will be a mismatch, as in the\nfollowing common type of mistake:\n\nSELECT name,SUM(units) FROM sales\n;+------+------------+\n| name | SUM(units) |\n+------+------------+\n| Chun | 536 |\n+------+------------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\nINSERT INTO student_test VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87);\n\nSELECT name, test, score, SUM(score) OVER (PARTITION BY name) AS total_score\nFROM student_test;\n+---------+--------+-------+-------------+\n| name | test | score | total_score |\n+---------+--------+-------+-------------+\n| Chun | SQL | 75 | 148 |\n| Chun | Tuning | 73 | 148 |\n| Esben | SQL | 43 | 74 |\n| Esben | Tuning | 31 | 74 |\n| Kaolin | SQL | 56 | 144 |\n| Kaolin | Tuning | 88 | 144 |\n| Tatiana | SQL | 87 | 87 |\n+---------+--------+-------+-------------+\n\nURL: https://mariadb.com/kb/en/sum/','','https://mariadb.com/kb/en/sum/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (189,16,'VARIANCE','Syntax\n------\n\nVARIANCE(expr)\n\nDescription\n-----------\n\nReturns the population standard variance of expr. This is an extension to\nstandard SQL. The standard SQL function VAR_POP() can be used instead.\n\nVariance is calculated by\n\n* working out the mean for the set\n* for each number, subtracting the mean and squaring the result\n* calculate the average of the resulting differences\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nVARIANCE() can be used as a window function.\n\nVARIANCE() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nCREATE TABLE v(i tinyint);\n\nINSERT INTO v VALUES(101),(99);\n\nSELECT VARIANCE(i) FROM v;\n+-------------+\n| VARIANCE(i) |\n+-------------+\n| 1.0000 |\n+-------------+\n\nINSERT INTO v VALUES(120),(80);\n\nSELECT VARIANCE(i) FROM v;\n+-------------+\n| VARIANCE(i) |\n+-------------+\n| 200.5000 |\n+-------------+\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n (\'a\',1),(\'a\',2),(\'a\',3),\n (\'b\',11),(\'b\',12),(\'b\',20),(\'b\',30),(\'b\',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n+----------+---------------+----------------+------------+\n| a | 0.8165 | 1.0000 | 0.6667 |\n| b | 18.0400 | 20.1693 | 325.4400 |\n+----------+---------------+----------------+------------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87);\n\nSELECT name, test, score, VAR_POP(score) \n OVER (PARTITION BY test) AS variance_results FROM student_test;\n+---------+--------+-------+------------------+\n| name | test | score | variance_results |\n+---------+--------+-------+------------------+\n| Chun | SQL | 75 | 287.1875 |\n| Chun | Tuning | 73 | 582.0000 |\n| Esben | SQL | 43 | 287.1875 |\n| Esben | Tuning | 31 | 582.0000 |\n| Kaolin | SQL | 56 | 287.1875 |\n| Kaolin | Tuning | 88 | 582.0000 |\n| Tatiana | SQL | 87 | 287.1875 |\n+---------+--------+-------+------------------+\n\nURL: https://mariadb.com/kb/en/variance/','','https://mariadb.com/kb/en/variance/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (190,16,'VAR_POP','Syntax\n------\n\nVAR_POP(expr)\n\nDescription\n-----------\n\nReturns the population standard variance of expr. It considers rows as the\nwhole population, not as a sample, so it has the number of rows as the\ndenominator. You can also use VARIANCE(), which is equivalent but is not\nstandard SQL.\n\nVariance is calculated by\n\n* working out the mean for the set\n* for each number, subtracting the mean and squaring the result\n* calculate the average of the resulting differences\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nVAR_POP() can be used as a window function.\n\nVAR_POP() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nCREATE TABLE v(i tinyint);\n\nINSERT INTO v VALUES(101),(99);\n\nSELECT VAR_POP(i) FROM v;\n+------------+\n| VAR_POP(i) |\n+------------+\n| 1.0000 |\n+------------+\n\nINSERT INTO v VALUES(120),(80);\n\nSELECT VAR_POP(i) FROM v;\n+------------+\n| VAR_POP(i) |\n+------------+\n| 200.5000 |\n+------------+\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n (\'a\',1),(\'a\',2),(\'a\',3),\n (\'b\',11),(\'b\',12),(\'b\',20),(\'b\',30),(\'b\',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n+----------+---------------+----------------+------------+\n| a | 0.8165 | 1.0000 | 0.6667 |\n| b | 18.0400 | 20.1693 | 325.4400 |\n+----------+---------------+----------------+------------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87);\n\nSELECT name, test, score, VAR_POP(score) \n OVER (PARTITION BY test) AS variance_results FROM student_test;\n+---------+--------+-------+------------------+\n| name | test | score | variance_results |\n+---------+--------+-------+------------------+\n| Chun | SQL | 75 | 287.1875 |\n| Esben | SQL | 43 | 287.1875 |\n| Kaolin | SQL | 56 | 287.1875 |\n| Tatiana | SQL | 87 | 287.1875 |\n| Chun | Tuning | 73 | 582.0000 |\n| Esben | Tuning | 31 | 582.0000 |\n| Kaolin | Tuning | 88 | 582.0000 |\n+---------+--------+-------+------------------+\n\nURL: https://mariadb.com/kb/en/var_pop/','','https://mariadb.com/kb/en/var_pop/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (191,16,'VAR_SAMP','Syntax\n------\n\nVAR_SAMP(expr)\n\nDescription\n-----------\n\nReturns the sample variance of expr. That is, the denominator is the number of\nrows minus one.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nVAR_SAMP() can be used as a window function.\n\nVAR_SAMP() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n (\'a\',1),(\'a\',2),(\'a\',3),\n (\'b\',11),(\'b\',12),(\'b\',20),(\'b\',30),(\'b\',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n+----------+---------------+----------------+------------+\n| a | 0.8165 | 1.0000 | 0.6667 |\n| b | 18.0400 | 20.1693 | 325.4400 |\n+----------+---------------+----------------+------------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87);\n\nSELECT name, test, score, VAR_SAMP(score) \n OVER (PARTITION BY test) AS variance_results FROM student_test;\n+---------+--------+-------+------------------+\n| name | test | score | variance_results |\n+---------+--------+-------+------------------+\n| Chun | SQL | 75 | 382.9167 |\n| Chun | Tuning | 73 | 873.0000 |\n| Esben | SQL | 43 | 382.9167 |\n| Esben | Tuning | 31 | 873.0000 |\n| Kaolin | SQL | 56 | 382.9167 |\n| Kaolin | Tuning | 88 | 873.0000 |\n| Tatiana | SQL | 87 | 382.9167 |\n+---------+--------+-------+------------------+\n\nURL: https://mariadb.com/kb/en/var_samp/','','https://mariadb.com/kb/en/var_samp/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (192,17,'BENCHMARK','Syntax\n------\n\nBENCHMARK(count,expr)\n\nDescription\n-----------\n\nThe BENCHMARK() function executes the expression expr repeatedly count times.\nIt may be used to time how quickly MariaDB processes the expression. The\nresult value is always 0. The intended use is from within the mariadb client,\nwhich reports query execution times.\n\nExamples\n--------\n\nSELECT BENCHMARK(1000000,ENCODE(\'hello\',\'goodbye\'));\n+----------------------------------------------+\n| BENCHMARK(1000000,ENCODE(\'hello\',\'goodbye\')) |\n+----------------------------------------------+\n| 0 |\n+----------------------------------------------+\n1 row in set (0.21 sec)\n\nURL: https://mariadb.com/kb/en/benchmark/','','https://mariadb.com/kb/en/benchmark/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (193,17,'BINLOG_GTID_POS','Syntax\n------\n\nBINLOG_GTID_POS(binlog_filename,binlog_offset)\n\nDescription\n-----------\n\nThe BINLOG_GTID_POS() function takes as input an old-style binary log position\nin the form of a file name and a file offset. It looks up the position in the\ncurrent binlog, and returns a string representation of the corresponding GTID\nposition. If the position is not found in the current binlog, NULL is returned.\n\nExamples\n--------\n\nSELECT BINLOG_GTID_POS(\"master-bin.000001\", 600);\n\nURL: https://mariadb.com/kb/en/binlog_gtid_pos/','','https://mariadb.com/kb/en/binlog_gtid_pos/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (194,17,'CHARSET','Syntax\n------\n\nCHARSET(str)\n\nDescription\n-----------\n\nReturns the character set of the string argument. If str is not a string, it\nis considered as a binary string (so the function returns \'binary\'). This\napplies to NULL, too. The return value is a string in the utf8 character set.\n\nExamples\n--------\n\nSELECT CHARSET(\'abc\');\n+----------------+\n| CHARSET(\'abc\') |\n+----------------+\n| latin1 |\n+----------------+\n\nSELECT CHARSET(CONVERT(\'abc\' USING utf8));\n+------------------------------------+\n| CHARSET(CONVERT(\'abc\' USING utf8)) |\n+------------------------------------+\n| utf8 |\n+------------------------------------+\n\nSELECT CHARSET(USER());\n+-----------------+\n| CHARSET(USER()) |\n+-----------------+\n| utf8 |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/charset/','','https://mariadb.com/kb/en/charset/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (195,17,'COERCIBILITY','Syntax\n------\n\nCOERCIBILITY(str)\n\nDescription\n-----------\n\nReturns the collation coercibility value of the string argument. Coercibility\ndefines what will be converted to what in case of collation conflict, with an\nexpression with higher coercibility being converted to the collation of an\nexpression with lower coercibility.\n\n+-----------------------------+---------------------------+------------------+\n| Coercibility | Description | Example |\n+-----------------------------+---------------------------+------------------+\n| 0 | Explicit | Value using a |\n| | | COLLATE clause |\n+-----------------------------+---------------------------+------------------+\n| 1 | No collation | Concatenated |\n| | | strings using |\n| | | different |\n| | | collations |\n+-----------------------------+---------------------------+------------------+\n| 2 | Implicit | Column value |\n+-----------------------------+---------------------------+------------------+\n| 3 | Constant | USER() return |\n| | | value |\n+-----------------------------+---------------------------+------------------+\n| 4 | Coercible | Literal string |\n+-----------------------------+---------------------------+------------------+\n| 5 | Ignorable | NULL or derived |\n| | | from NULL |\n+-----------------------------+---------------------------+------------------+\n\nExamples\n--------\n\nSELECT COERCIBILITY(\'abc\' COLLATE latin1_swedish_ci);\n+-----------------------------------------------+\n| COERCIBILITY(\'abc\' COLLATE latin1_swedish_ci) |\n+-----------------------------------------------+\n| 0 |\n+-----------------------------------------------+\n\nSELECT COERCIBILITY(USER());\n+----------------------+\n| COERCIBILITY(USER()) |\n+----------------------+\n| 3 |\n+----------------------+\n\nSELECT COERCIBILITY(\'abc\');\n+---------------------+\n| COERCIBILITY(\'abc\') |\n+---------------------+\n| 4 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/coercibility/','','https://mariadb.com/kb/en/coercibility/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (196,17,'COLLATION','Syntax\n------\n\nCOLLATION(str)\n\nDescription\n-----------\n\nReturns the collation of the string argument. If str is not a string, it is\nconsidered as a binary string (so the function returns \'binary\'). This applies\nto NULL, too. The return value is a string in the utf8 character set.\n\nSee Character Sets and Collations.\n\nExamples\n--------\n\nSELECT COLLATION(\'abc\');\n+-------------------+\n| COLLATION(\'abc\') |\n+-------------------+\n| latin1_swedish_ci |\n+-------------------+\n\nSELECT COLLATION(_utf8\'abc\');\n+-----------------------+\n| COLLATION(_utf8\'abc\') |\n+-----------------------+\n| utf8_general_ci |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/collation/','','https://mariadb.com/kb/en/collation/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (197,17,'CONNECTION_ID','Syntax\n------\n\nCONNECTION_ID()\n\nDescription\n-----------\n\nReturns the connection ID for the connection. Every connection (including\nevents) has an ID that is unique among the set of currently connected clients.\n\nUntil MariaDB 10.3.1, returns MYSQL_TYPE_LONGLONG, or bigint(10), in all\ncases. From MariaDB 10.3.1, returns MYSQL_TYPE_LONG, or int(10), when the\nresult would fit within 32-bits.\n\nExamples\n--------\n\nSELECT CONNECTION_ID();\n+-----------------+\n| CONNECTION_ID() |\n+-----------------+\n| 3 |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/connection_id/','','https://mariadb.com/kb/en/connection_id/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (198,17,'CURRENT_ROLE','Syntax\n------\n\nCURRENT_ROLE, CURRENT_ROLE()\n\nDescription\n-----------\n\nReturns the current role name. This determines your access privileges. The\nreturn value is a string in the utf8 character set.\n\nIf there is no current role, NULL is returned.\n\nThe output of SELECT CURRENT_ROLE is equivalent to the contents of the\nENABLED_ROLES Information Schema table.\n\nUSER() returns the combination of user and host used to login. CURRENT_USER()\nreturns the account used to determine current connection\'s privileges.\n\nExamples\n--------\n\nSELECT CURRENT_ROLE;\n+--------------+\n| CURRENT_ROLE |\n+--------------+\n| NULL |\n+--------------+\n\nSET ROLE staff;\n\nSELECT CURRENT_ROLE;\n+--------------+\n| CURRENT_ROLE |\n+--------------+\n| staff |\n+--------------+\n\nURL: https://mariadb.com/kb/en/current_role/','','https://mariadb.com/kb/en/current_role/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (199,17,'CURRENT_USER','Syntax\n------\n\nCURRENT_USER, CURRENT_USER()\n\nDescription\n-----------\n\nReturns the user name and host name combination for the MariaDB account that\nthe server used to authenticate the current client. This account determines\nyour access privileges. The return value is a string in the utf8 character set.\n\nThe value of CURRENT_USER() can differ from the value of USER().\nCURRENT_ROLE() returns the current active role.\n\nExamples\n--------\n\nshell> mysql --user=\"anonymous\"\n\nselect user(),current_user();\n+---------------------+----------------+\n| user() | current_user() |\n+---------------------+----------------+\n| anonymous@localhost | @localhost |\n+---------------------+----------------+\n\nWhen calling CURRENT_USER() in a stored procedure, it returns the owner of the\nstored procedure, as defined with DEFINER.\n\nURL: https://mariadb.com/kb/en/current_user/','','https://mariadb.com/kb/en/current_user/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (200,17,'DATABASE','Syntax\n------\n\nDATABASE()\nSCHEMA()\n\nDescription\n-----------\n\nReturns the default (current) database name as a string in the utf8 character\nset. If there is no default database, DATABASE() returns NULL. Within a stored\nroutine, the default database is the database that the routine is associated\nwith, which is not necessarily the same as the database that is the default in\nthe calling context.\n\nSCHEMA() is a synonym for DATABASE().\n\nTo select a default database, the USE statement can be run. Another way to set\nthe default database is specifying its name at mariadb command line client\nstartup.\n\nExamples\n--------\n\nSELECT DATABASE();\n+------------+\n| DATABASE() |\n+------------+\n| NULL |\n+------------+\n\nUSE test;\nDatabase changed\n\nSELECT DATABASE();\n+------------+\n| DATABASE() |\n+------------+\n| test |\n+------------+\n\nURL: https://mariadb.com/kb/en/database/','','https://mariadb.com/kb/en/database/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (201,17,'DECODE_HISTOGRAM','Syntax\n------\n\nDECODE_HISTOGRAM(hist_type,histogram)\n\nDescription\n-----------\n\nReturns a string of comma separated numeric values corresponding to a\nprobability distribution represented by the histogram of type hist_type\n(SINGLE_PREC_HB or DOUBLE_PREC_HB). The hist_type and histogram would be\ncommonly used from the mysql.column_stats table.\n\nSee Histogram Based Statistics for details.\n\nExamples\n--------\n\nCREATE TABLE origin (\n i INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,\n v INT UNSIGNED NOT NULL\n);\n\nINSERT INTO origin(v) VALUES \n (1),(2),(3),(4),(5),(10),(20),\n (30),(40),(50),(60),(70),(80),\n (90),(100),(200),(400),(800);\n\nSET histogram_size=10,histogram_type=SINGLE_PREC_HB;\n\nANALYZE TABLE origin PERSISTENT FOR ALL;\n+-------------+---------+----------+-----------------------------------------+\n| Table | Op | Msg_type | Msg_text |\n+-------------+---------+----------+-----------------------------------------+\n| test.origin | analyze | status | Engine-independent statistics collected |\n| test.origin | analyze | status | OK |\n+-------------+---------+----------+-----------------------------------------+\n\nSELECT db_name,table_name,column_name,hist_type,\n hex(histogram),decode_histogram(hist_type,histogram)\n FROM mysql.column_stats WHERE db_name=\'test\' and table_name=\'origin\';\n+---------+------------+-------------+----------------+----------------------+-\n-----------------------------------------------------------------+\n| db_name | table_name | column_name | hist_type | hex(histogram) |\ndecode_histogram(hist_type,histogram) |\n+---------+------------+-------------+----------------+----------------------+-\n-----------------------------------------------------------------+\n| test | origin | i | SINGLE_PREC_HB | 0F2D3C5A7887A5C3D2F0 |\n0.059,0.118,0.059,0.118,0.118,0.059,0.118,0.118,0.059,0.118,0.059 |\n| test | origin | v | SINGLE_PREC_HB | 000001060C0F161C1F7F |\n0.000,0.000,0.004,0.020,0.024,0.012,0.027,0.024,0.012,0.376,0.502 |\n+---------+------------+-------------+----------------+----------------------+-\n-----------------------------------------------------------------+\n\nSET histogram_size=20,histogram_type=DOUBLE_PREC_HB;\n\nANALYZE TABLE origin PERSISTENT FOR ALL;\n+-------------+---------+----------+-----------------------------------------+\n| Table | Op | Msg_type | Msg_text |\n+-------------+---------+----------+-----------------------------------------+\n| test.origin | analyze | status | Engine-independent statistics collected |\n| test.origin | analyze | status | OK |\n+-------------+---------+----------+-----------------------------------------+\n\nSELECT db_name,table_name,column_name,\n hist_type,hex(histogram),decode_histogram(hist_type,histogram)\n FROM mysql.column_stats WHERE db_name=\'test\' and table_name=\'origin\';\n+---------+------------+-------------+----------------+------------------------\n-----------------+-------------------------------------------------------------\n---------------------------+\n| db_name | table_name | column_name | hist_type | hex(histogram) \n | decode_histogram(hist_type,histogram)\n |\n+---------+------------+-------------+----------------+------------------------\n-----------------+-------------------------------------------------------------\n---------------------------+\n| test | origin | i | DOUBLE_PREC_HB |\n0F0F2D2D3C3C5A5A78788787A5A5C3C3D2D2F0F0 |\n0.05882,0.11765,0.05882,0.11765,0.11765,0.05882,0.11765,0.11765,0.05882,0.11765\n0.05882 |\n| test | origin | v | DOUBLE_PREC_HB |\n5200F600480116067E0CB30F1B16831CB81FD67F |\n0.00125,0.00250,0.00125,0.01877,0.02502,0.01253,0.02502,0.02502,0.01253,0.37546\n0.50063 |\n\nURL: https://mariadb.com/kb/en/decode_histogram/','','https://mariadb.com/kb/en/decode_histogram/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (202,17,'DEFAULT','Syntax\n------\n\nDEFAULT(col_name)\n\nDescription\n-----------\n\nReturns the default value for a table column. If the column has no default\nvalue (and is not NULLABLE - NULLABLE fields have a NULL default), an error is\nreturned.\n\nFor integer columns using AUTO_INCREMENT, 0 is returned.\n\nWhen using DEFAULT as a value to set in an INSERT or UPDATE statement, you can\nuse the bare keyword DEFAULT without the parentheses and argument to refer to\nthe column in context. You can only use DEFAULT as a bare keyword if you are\nusing it alone without a surrounding expression or function.\n\nExamples\n--------\n\nSelect only non-default values for a column:\n\nSELECT i FROM t WHERE i != DEFAULT(i);\n\nUpdate values to be one greater than the default value:\n\nUPDATE t SET i = DEFAULT(i)+1 WHERE i < 100;\n\nWhen referring to the default value exactly in UPDATE or INSERT, you can omit\nthe argument:\n\nINSERT INTO t (i) VALUES (DEFAULT);\nUPDATE t SET i = DEFAULT WHERE i < 100;\n\nCREATE OR REPLACE TABLE t (\n i INT NOT NULL AUTO_INCREMENT,\n j INT NOT NULL,\n k INT DEFAULT 3,\n l INT NOT NULL DEFAULT 4,\n m INT,\n PRIMARY KEY (i)\n);\n\nDESC t;\n+-------+---------+------+-----+---------+----------------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+---------+------+-----+---------+----------------+\n| i | int(11) | NO | PRI | NULL | auto_increment |\n| j | int(11) | NO | | NULL | |\n| k | int(11) | YES | | 3 | |\n| l | int(11) | NO | | 4 | |\n| m | int(11) | YES | | NULL | |\n+-------+---------+------+-----+---------+----------------+\n\nINSERT INTO t (j) VALUES (1);\nINSERT INTO t (j,m) VALUES (2,2);\nINSERT INTO t (j,l,m) VALUES (3,3,3);\n\nSELECT * FROM t;\n+---+---+------+---+------+\n| i | j | k | l | m |\n+---+---+------+---+------+\n| 1 | 1 | 3 | 4 | NULL |\n| 2 | 2 | 3 | 4 | 2 |\n| 3 | 3 | 3 | 3 | 3 |\n+---+---+------+---+------+\n\nSELECT DEFAULT(i), DEFAULT(k), DEFAULT (l), DEFAULT(m) FROM t;\n+------------+------------+-------------+------------+\n| DEFAULT(i) | DEFAULT(k) | DEFAULT (l) | DEFAULT(m) |\n+------------+------------+-------------+------------+\n| 0 | 3 | 4 | NULL |\n| 0 | 3 | 4 | NULL |\n| 0 | 3 | 4 | NULL |\n+------------+------------+-------------+------------+\n\nSELECT DEFAULT(i), DEFAULT(k), DEFAULT (l), DEFAULT(m), DEFAULT(j) FROM t;\nERROR 1364 (HY000): Field \'j\' doesn\'t have a default value\n\nSELECT * FROM t WHERE i = DEFAULT(i);\nEmpty set (0.001 sec)\n\nSELECT * FROM t WHERE j = DEFAULT(j);\nERROR 1364 (HY000): Field \'j\' doesn\'t have a default value\n\nSELECT * FROM t WHERE k = DEFAULT(k);\n+---+---+------+---+------+\n| i | j | k | l | m |\n+---+---+------+---+------+\n| 1 | 1 | 3 | 4 | NULL |\n| 2 | 2 | 3 | 4 | 2 |\n| 3 | 3 | 3 | 3 | 3 |\n+---+---+------+---+------+\n\nSELECT * FROM t WHERE l = DEFAULT(l);\n+---+---+------+---+------+\n| i | j | k | l | m |\n+---+---+------+---+------+\n| 1 | 1 | 3 | 4 | NULL |\n| 2 | 2 | 3 | 4 | 2 |\n+---+---+------+---+------+\n\nSELECT * FROM t WHERE m = DEFAULT(m);\nEmpty set (0.001 sec)\n\nSELECT * FROM t WHERE m <=> DEFAULT(m);\n+---+---+------+---+------+\n| i | j | k | l | m |\n+---+---+------+---+------+\n| 1 | 1 | 3 | 4 | NULL |\n+---+---+------+---+------+\n\nURL: https://mariadb.com/kb/en/default/','','https://mariadb.com/kb/en/default/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (203,17,'FOUND_ROWS','Syntax\n------\n\nFOUND_ROWS()\n\nDescription\n-----------\n\nA SELECT statement may include a LIMIT clause to restrict the number of rows\nthe server returns to the client. In some cases, it is desirable to know how\nmany rows the statement would have returned without the LIMIT, but without\nrunning the statement again. To obtain this row count, include a\nSQL_CALC_FOUND_ROWS option in the SELECT statement, and then invoke\nFOUND_ROWS() afterwards.\n\nYou can also use FOUND_ROWS() to obtain the number of rows returned by a\nSELECT which does not contain a LIMIT clause. In this case you don\'t need to\nuse the SQL_CALC_FOUND_ROWS option. This can be useful for example in a stored\nprocedure.\n\nAlso, this function works with some other statements which return a resultset,\nincluding SHOW, DESC and HELP. For DELETE ... RETURNING you should use\nROW_COUNT(). It also works as a prepared statement, or after executing a\nprepared statement.\n\nStatements which don\'t return any results don\'t affect FOUND_ROWS() - the\nprevious value will still be returned.\n\nWarning: When used after a CALL statement, this function returns the number of\nrows selected by the last query in the procedure, not by the whole procedure.\n\nStatements using the FOUND_ROWS() function are not safe for replication.\n\nExamples\n--------\n\nSHOW ENGINES\\G\n*************************** 1. row ***************************\n Engine: CSV\n Support: YES\n Comment: Stores tables as CSV files\nTransactions: NO\n XA: NO\n Savepoints: NO\n*************************** 2. row ***************************\n Engine: MRG_MyISAM\n Support: YES\n Comment: Collection of identical MyISAM tables\nTransactions: NO\n XA: NO\n Savepoints: NO\n\n...\n\n*************************** 8. row ***************************\n Engine: PERFORMANCE_SCHEMA\n Support: YES\n Comment: Performance Schema\nTransactions: NO\n XA: NO\n Savepoints: NO\n8 rows in set (0.000 sec)\n\nSELECT FOUND_ROWS();\n+--------------+\n| FOUND_ROWS() |\n+--------------+\n| 8 |\n+--------------+\n\nSELECT SQL_CALC_FOUND_ROWS * FROM tbl_name WHERE id > 100 LIMIT 10;\n\nSELECT FOUND_ROWS();\n+--------------+\n| FOUND_ROWS() |\n+--------------+\n| 23 |\n+--------------+\n\nURL: https://mariadb.com/kb/en/found_rows/','','https://mariadb.com/kb/en/found_rows/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (204,17,'LAST_INSERT_ID','Syntax\n------\n\nLAST_INSERT_ID(), LAST_INSERT_ID(expr)\n\nDescription\n-----------\n\nLAST_INSERT_ID() (no arguments) returns the first automatically generated\nvalue successfully inserted for an AUTO_INCREMENT column as a result of the\nmost recently executed INSERT statement. The value of LAST_INSERT_ID() remains\nunchanged if no rows are successfully inserted.\n\nIf one gives an argument to LAST_INSERT_ID(), then it will return the value of\nthe expression and the next call to LAST_INSERT_ID() will return the same\nvalue. The value will also be sent to the client and can be accessed by the\nmysql_insert_id function.\n\nFor example, after inserting a row that generates an AUTO_INCREMENT value, you\ncan get the value like this:\n\nSELECT LAST_INSERT_ID();\n+------------------+\n| LAST_INSERT_ID() |\n+------------------+\n| 9 |\n+------------------+\n\nYou can also use LAST_INSERT_ID() to delete the last inserted row:\n\nDELETE FROM product WHERE id = LAST_INSERT_ID();\n\nIf no rows were successfully inserted, LAST_INSERT_ID() returns 0.\n\nThe value of LAST_INSERT_ID() will be consistent across all versions if all\nrows in the INSERT or UPDATE statement were successful.\n\nThe currently executing statement does not affect the value of\nLAST_INSERT_ID(). Suppose that you generate an AUTO_INCREMENT value with one\nstatement, and then refer to LAST_INSERT_ID() in a multiple-row INSERT\nstatement that inserts rows into a table with its own AUTO_INCREMENT column.\nThe value of LAST_INSERT_ID() will remain stable in the second statement; its\nvalue for the second and later rows is not affected by the earlier row\ninsertions. (However, if you mix references to LAST_INSERT_ID() and\nLAST_INSERT_ID(expr), the effect is undefined.)\n\nIf the previous statement returned an error, the value of LAST_INSERT_ID() is\nundefined. For transactional tables, if the statement is rolled back due to an\nerror, the value of LAST_INSERT_ID() is left undefined. For manual ROLLBACK,\nthe value of LAST_INSERT_ID() is not restored to that before the transaction;\nit remains as it was at the point of the ROLLBACK.\n\nWithin the body of a stored routine (procedure or function) or a trigger, the\nvalue of LAST_INSERT_ID() changes the same way as for statements executed\noutside the body of these kinds of objects. The effect of a stored routine or\ntrigger upon the value of LAST_INSERT_ID() that is seen by following\nstatements depends on the kind of routine:\n\n* If a stored procedure executes statements that change the value of\nLAST_INSERT_ID(), the new value will be seen by statements that follow the\nprocedure call.\n\n* For stored functions and triggers that change the value, the value is\nrestored when the function or trigger ends, so following statements will not\nsee a changed value.\n\nExamples\n--------\n\nCREATE TABLE t (\n id INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY,\n f VARCHAR(1))\nENGINE = InnoDB;\n\nINSERT INTO t(f) VALUES(\'a\');\n\nSELECT LAST_INSERT_ID();\n+------------------+\n| LAST_INSERT_ID() |\n+------------------+\n| 1 |\n+------------------+\n\nINSERT INTO t(f) VALUES(\'b\');\n\nINSERT INTO t(f) VALUES(\'c\');\n\nSELECT LAST_INSERT_ID();\n+------------------+\n| LAST_INSERT_ID() |\n+------------------+\n| 3 |\n+------------------+\n\nINSERT INTO t(f) VALUES(\'d\'),(\'e\');\n\nSELECT LAST_INSERT_ID();\n+------------------+\n| LAST_INSERT_ID() |\n+------------------+\n| 4 |\n+------------------+\n\nSELECT * FROM t;\n+----+------+\n| id | f |\n+----+------+\n| 1 | a |\n| 2 | b |\n| 3 | c |\n| 4 | d |\n| 5 | e |\n+----+------+\n\nSELECT LAST_INSERT_ID(12);\n+--------------------+\n| LAST_INSERT_ID(12) |\n+--------------------+\n| 12 |\n+--------------------+\n\nSELECT LAST_INSERT_ID();\n+------------------+\n| LAST_INSERT_ID() |\n+------------------+\n| 12 |\n+------------------+\n\nINSERT INTO t(f) VALUES(\'f\');\n\nSELECT LAST_INSERT_ID();\n+------------------+\n| LAST_INSERT_ID() |\n+------------------+\n| 6 |\n+------------------+\n\nSELECT * FROM t;\n+----+------+\n| id | f |\n+----+------+\n| 1 | a |\n| 2 | b |\n| 3 | c |\n| 4 | d |\n| 5 | e |\n| 6 | f |\n+----+------+\n\nSELECT LAST_INSERT_ID(12);\n+--------------------+\n| LAST_INSERT_ID(12) |\n+--------------------+\n| 12 |\n+--------------------+\n\nINSERT INTO t(f) VALUES(\'g\');\n\nSELECT * FROM t;\n+----+------+\n| id | f |\n+----+------+\n| 1 | a |\n| 2 | b |\n| 3 | c |\n| 4 | d |\n| 5 | e |\n| 6 | f |\n| 7 | g |\n+----+------+\n\nURL: https://mariadb.com/kb/en/last_insert_id/','','https://mariadb.com/kb/en/last_insert_id/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (205,17,'LAST_VALUE','Syntax\n------\n\nLAST_VALUE(expr,[expr,...])\n\nLAST_VALUE(expr) OVER (\n [ PARTITION BY partition_expression ]\n [ ORDER BY order_list ]\n)\n\nDescription\n-----------\n\nLAST_VALUE() evaluates all expressions and returns the last.\n\nThis is useful together with setting user variables to a value with\n@var:=expr, for example when you want to get data of rows updated/deleted\nwithout having to do two queries against the table.\n\nLAST_VALUE can be used as a window function.\n\nReturns NULL if no last value exists.\n\nExamples\n--------\n\nCREATE TABLE t1 (a int, b int);\nINSERT INTO t1 VALUES(1,10),(2,20);\nDELETE FROM t1 WHERE a=1 AND last_value(@a:=a,@b:=b,1);\nSELECT @a,@b;\n+------+------+\n| @a | @b |\n+------+------+\n| 1 | 10 |\n+------+------+\n\nAs a window function:\n\nCREATE TABLE t1 (\n pk int primary key,\n a int,\n b int,\n c char(10),\n d decimal(10, 3),\n e real\n);\n\nINSERT INTO t1 VALUES\n( 1, 0, 1, \'one\', 0.1, 0.001),\n( 2, 0, 2, \'two\', 0.2, 0.002),\n( 3, 0, 3, \'three\', 0.3, 0.003),\n( 4, 1, 2, \'three\', 0.4, 0.004),\n( 5, 1, 1, \'two\', 0.5, 0.005),\n( 6, 1, 1, \'one\', 0.6, 0.006),\n( 7, 2, NULL, \'n_one\', 0.5, 0.007),\n( 8, 2, 1, \'n_two\', NULL, 0.008),\n( 9, 2, 2, NULL, 0.7, 0.009),\n(10, 2, 0, \'n_four\', 0.8, 0.010),\n(11, 2, 10, NULL, 0.9, NULL);\n\nSELECT pk, FIRST_VALUE(pk) OVER (ORDER BY pk) AS first_asc,\n LAST_VALUE(pk) OVER (ORDER BY pk) AS last_asc,\n FIRST_VALUE(pk) OVER (ORDER BY pk DESC) AS first_desc,\n LAST_VALUE(pk) OVER (ORDER BY pk DESC) AS last_desc\nFROM t1\nORDER BY pk DESC;\n\n+----+-----------+----------+------------+-----------+\n| pk | first_asc | last_asc | first_desc | last_desc |\n+----+-----------+----------+------------+-----------+\n| 11 | 1 | 11 | 11 | 11 |\n| 10 | 1 | 10 | 11 | 10 |\n| 9 | 1 | 9 | 11 | 9 |\n| 8 | 1 | 8 | 11 | 8 |\n| 7 | 1 | 7 | 11 | 7 |\n| 6 | 1 | 6 | 11 | 6 |\n| 5 | 1 | 5 | 11 | 5 |\n| 4 | 1 | 4 | 11 | 4 |\n| 3 | 1 | 3 | 11 | 3 |\n| 2 | 1 | 2 | 11 | 2 |\n| 1 | 1 | 1 | 11 | 1 |\n+----+-----------+----------+------------+-----------+\n\nCREATE OR REPLACE TABLE t1 (i int);\nINSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);\n\nSELECT i,\n FIRST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW and 1 FOLLOWING) AS\nf_1f,\n LAST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW and 1 FOLLOWING) AS\nl_1f,\n FIRST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS\nf_1p1f,\n LAST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS\nl_1p1f,\n FIRST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING) AS\nf_2p1p,\n LAST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING) AS\nl_2p1p,\n FIRST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN 1 FOLLOWING AND 2 FOLLOWING) AS\nf_1f2f,\n LAST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN 1 FOLLOWING AND 2 FOLLOWING) AS\nl_1f2f\nFROM t1;\n\n+------+------+------+--------+--------+--------+--------+--------+--------+\n| i | f_1f | l_1f | f_1p1f | l_1p1f | f_2p1p | l_2p1p | f_1f2f | l_1f2f |\n+------+------+------+--------+--------+--------+--------+--------+--------+\n| 1 | 1 | 2 | 1 | 2 | NULL | NULL | 2 | 3 |\n| 2 | 2 | 3 | 1 | 3 | 1 | 1 | 3 | 4 |\n| 3 | 3 | 4 | 2 | 4 | 1 | 2 | 4 | 5 |\n| 4 | 4 | 5 | 3 | 5 | 2 | 3 | 5 | 6 |\n| 5 | 5 | 6 | 4 | 6 | 3 | 4 | 6 | 7 |\n| 6 | 6 | 7 | 5 | 7 | 4 | 5 | 7 | 8 |\n| 7 | 7 | 8 | 6 | 8 | 5 | 6 | 8 | 9 |\n| 8 | 8 | 9 | 7 | 9 | 6 | 7 | 9 | 10 |\n| 9 | 9 | 10 | 8 | 10 | 7 | 8 | 10 | 10 |\n| 10 | 10 | 10 | 9 | 10 | 8 | 9 | NULL | NULL |\n+------+------+------+--------+--------+--------+--------+--------+--------+\n\nURL: https://mariadb.com/kb/en/last_value/','','https://mariadb.com/kb/en/last_value/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (206,17,'PROCEDURE ANALYSE','Syntax\n------\n\nanalyse([max_elements[,max_memory]])\n\nDescription\n-----------\n\nThis procedure is defined in the sql/sql_analyse.cc file. It examines the\nresult from a query and returns an analysis of the results that suggests\noptimal data types for each column. To obtain this analysis, append PROCEDURE\nANALYSE to the end of a SELECT statement:\n\nSELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max_elements,[max_memory]])\n\nFor example:\n\nSELECT col1, col2 FROM table1 PROCEDURE ANALYSE(10, 2000);\n\nThe results show some statistics for the values returned by the query, and\npropose an optimal data type for the columns. This can be helpful for checking\nyour existing tables, or after importing new data. You may need to try\ndifferent settings for the arguments so that PROCEDURE ANALYSE() does not\nsuggest the ENUM data type when it is not appropriate.\n\nThe arguments are optional and are used as follows:\n\n* max_elements (default 256) is the maximum number of distinct values that\nanalyse notices per column. This is used by analyse to check whether the\noptimal data type should be of type ENUM; if there are more than max_elements\ndistinct values, then ENUM is not a suggested type.\n* max_memory (default 8192) is the maximum amount of memory that analyse\nshould allocate per column while trying to find all distinct values.\n\nURL: https://mariadb.com/kb/en/procedure-analyse/','','https://mariadb.com/kb/en/procedure-analyse/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (207,17,'ROWNUM','MariaDB starting with 10.6.1\n----------------------------\nFrom MariaDB 10.6.1, the ROWNUM() function is supported.\n\nSyntax\n------\n\nROWNUM()\n\nIn Oracle mode one can just use ROWNUM, without the parentheses.\n\nDescription\n-----------\n\nROWNUM() returns the current number of accepted rows in the current context.\nIt main purpose is to emulate the ROWNUM pseudo column in Oracle. For MariaDB\nnative applications, we recommend the usage of LIMIT, as it is easier to use\nand gives more predictable results than the usage of ROWNUM().\n\nThe main difference between using LIMIT and ROWNUM() to limit the rows in the\nresult is that LIMIT works on the result set while ROWNUM works on the number\nof accepted rows (before any ORDER or GROUP BY clauses).\n\nThe following queries will return the same results:\n\nSELECT * from t1 LIMIT 10;\nSELECT * from t1 WHERE ROWNUM() <= 10;\n\nWhile the following may return different results based on in which orders the\nrows are found:\n\nSELECT * from t1 ORDER BY a LIMIT 10;\nSELECT * from t1 ORDER BY a WHERE ROWNUM() <= 10;\n\nThe recommended way to use ROWNUM to limit the number of returned rows and get\npredictable results is to have the query in a subquery and test for ROWNUM()\nin the outer query:\n\nSELECT * FROM (select * from t1 ORDER BY a) WHERE ROWNUM() <= 10;\n\nROWNUM() can be used in the following contexts:\n\n* SELECT\n* INSERT\n* UPDATE\n* DELETE\n* LOAD DATA INFILE\n\nUsed in other contexts, ROWNUM() will return 0.\n\nExamples\n--------\n\nINSERT INTO t1 VALUES (1,ROWNUM()),(2,ROWNUM()),(3,ROWNUM());\n\nINSERT INTO t1 VALUES (1),(2) returning a, ROWNUM();\n\nUPDATE t1 SET row_num_column=ROWNUM();\n\nDELETE FROM t1 WHERE a < 10 AND ROWNUM() < 2;\n\nLOAD DATA INFILE \'filename\' into table t1 fields terminated by \',\' \n lines terminated by \"\\r\\n\" (a,b) set c=ROWNUM();\n\nOptimizations\n-------------\n\nIn many cases where ROWNUM() is used, MariaDB will use the same optimizations\nit uses with LIMIT.\n\nLIMIT optimization is possible when using ROWNUM in the following manner:\n\n* When one is in a top level WHERE clause comparing ROWNUM() with a numerical\nconstant using any of the following expressions:\nROWNUM() < number\nROWNUM() <= number\nROWNUM() = 1\nROWNUM() can be also be the right argument to the comparison function.\n\nIn the above cases, LIMIT optimization can be done in the following cases:\n\n* For the current sub query when the ROWNUM comparison is done on the top\nlevel:\n\nSELECT * from t1 WHERE ROWNUM() <= 2 AND t1.a > 0\n\n* For an inner sub query, when the upper level has only a ROWNUM() comparison\nin the WHERE clause:\n\nSELECT * from (select * from t1) as t WHERE ROWNUM() <= 2\n\nOther Changes Related to ROWNUM\n-------------------------------\n\nWhen ROWNUM() is used anywhere in a query, the optimization to ignore ORDER BY\nin subqueries are disabled.\n\nThis was done to get the following common Oracle query to work as expected:\n\nselect * from (select * from t1 order by a desc) as t where rownum() <= 2;\n\nBy default MariaDB ignores any ORDER BY in subqueries both because the SQL\nstandard defines results sets in subqueries to be un-ordered and because of\nperformance reasons (especially when using views in subqueries). See MDEV-3926\n\"Wrong result with GROUP BY ... WITH ROLLUP\" for a discussion of this topic.\n\nOther Considerations\n--------------------\n\nWhile MariaDB tries to emulate Oracle\'s usage of ROWNUM() as closely as\npossible, there are cases where the result is different:\n\n* When the optimizer finds rows in a different order (because of different\nstorage methods or optimization). This may also happen in Oracle if one adds\nor deletes an index, in which case the rows may be found in a different order.\n\nNote that usage of ROWNUM() in functions or stored procedures will use their\nown context, not the caller\'s context.\n\nURL: https://mariadb.com/kb/en/rownum/','','https://mariadb.com/kb/en/rownum/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (208,17,'ROW_COUNT','Syntax\n------\n\nROW_COUNT()\n\nDescription\n-----------\n\nROW_COUNT() returns the number of rows updated, inserted or deleted by the\npreceding statement. This is the same as the row count that the mariadb client\ndisplays and the value from the mysql_affected_rows() C API function.\n\nGenerally:\n\n* For statements which return a result set (such as SELECT, SHOW, DESC or\nHELP), returns -1, even when the result set is empty. This is also true for\nadministrative statements, such as OPTIMIZE.\n* For DML statements other than SELECT and for ALTER TABLE, returns the number\nof affected rows.\n* For DDL statements (including TRUNCATE) and for other statements which don\'t\nreturn any result set (such as USE, DO, SIGNAL or DEALLOCATE PREPARE), returns\n0.\n\nFor UPDATE, affected rows is by default the number of rows that were actually\nchanged. If the CLIENT_FOUND_ROWS flag to mysql_real_connect() is specified\nwhen connecting to mysqld, affected rows is instead the number of rows matched\nby the WHERE clause.\n\nFor REPLACE, deleted rows are also counted. So, if REPLACE deletes a row and\nadds a new row, ROW_COUNT() returns 2.\n\nFor INSERT ... ON DUPLICATE KEY, updated rows are counted twice. So, if INSERT\nadds a new rows and modifies another row, ROW_COUNT() returns 3.\n\nROW_COUNT() does not take into account rows that are not directly\ndeleted/updated by the last statement. This means that rows deleted by foreign\nkeys or triggers are not counted.\n\nWarning: You can use ROW_COUNT() with prepared statements, but you need to\ncall it after EXECUTE, not after DEALLOCATE PREPARE, because the row count for\nallocate prepare is always 0.\n\nWarning: When used after a CALL statement, this function returns the number of\nrows affected by the last statement in the procedure, not by the whole\nprocedure.\n\nWarning: After INSERT DELAYED, ROW_COUNT() returns the number of the rows you\ntried to insert, not the number of the successful writes.\n\nThis information can also be found in the diagnostics area.\n\nStatements using the ROW_COUNT() function are not safe for replication.\n\nExamples\n--------\n\nCREATE TABLE t (A INT);\n\nINSERT INTO t VALUES(1),(2),(3);\n\nSELECT ROW_COUNT();\n+-------------+\n| ROW_COUNT() |\n+-------------+\n| 3 |\n+-------------+\n\nDELETE FROM t WHERE A IN(1,2);\n\nSELECT ROW_COUNT(); \n+-------------+\n| ROW_COUNT() |\n+-------------+\n| 2 |\n+-------------+\n\nExample with prepared statements:\n\nSET @q = \'INSERT INTO t VALUES(1),(2),(3);\';\n\nPREPARE stmt FROM @q;\n\nEXECUTE stmt;\nQuery OK, 3 rows affected (0.39 sec)\nRecords: 3 Duplicates: 0 Warnings: 0\n\nSELECT ROW_COUNT();\n+-------------+\n| ROW_COUNT() |\n+-------------+\n| 3 |\n+-------------+\n\nURL: https://mariadb.com/kb/en/row_count/','','https://mariadb.com/kb/en/row_count/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (209,17,'SCHEMA','Syntax\n------\n\nSCHEMA()\n\nDescription\n-----------\n\nThis function is a synonym for DATABASE().\n\nURL: https://mariadb.com/kb/en/schema/','','https://mariadb.com/kb/en/schema/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (210,17,'SESSION_USER','Syntax\n------\n\nSESSION_USER()\n\nDescription\n-----------\n\nSESSION_USER() is a synonym for USER().\n\nURL: https://mariadb.com/kb/en/session_user/','','https://mariadb.com/kb/en/session_user/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (211,17,'SYSTEM_USER','Syntax\n------\n\nSYSTEM_USER()\n\nDescription\n-----------\n\nSYSTEM_USER() is a synonym for USER().\n\nURL: https://mariadb.com/kb/en/system_user/','','https://mariadb.com/kb/en/system_user/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (212,17,'USER','Syntax\n------\n\nUSER()\n\nDescription\n-----------\n\nReturns the current MariaDB user name and host name, given when authenticating\nto MariaDB, as a string in the utf8 character set.\n\nNote that the value of USER() may differ from the value of CURRENT_USER(),\nwhich is the user used to authenticate the current client. CURRENT_ROLE()\nreturns the current active role.\n\nSYSTEM_USER() and SESSION_USER are synonyms for USER().\n\nStatements using the USER() function or one of its synonyms are not safe for\nstatement level replication.\n\nExamples\n--------\n\nshell> mysql --user=\"anonymous\"\n\nSELECT USER(),CURRENT_USER();\n+---------------------+----------------+\n| USER() | CURRENT_USER() |\n+---------------------+----------------+\n| anonymous@localhost | @localhost |\n+---------------------+----------------+\n\nTo select only the IP address, use SUBSTRING_INDEX(),\n\nSELECT SUBSTRING_INDEX(USER(), \'@\', -1);\n+----------------------------------+\n| SUBSTRING_INDEX(USER(), \'@\', -1) |\n+----------------------------------+\n| 192.168.0.101 |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/user/','','https://mariadb.com/kb/en/user/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (213,17,'VERSION','Syntax\n------\n\nVERSION()\n\nDescription\n-----------\n\nReturns a string that indicates the MariaDB server version. The string uses\nthe utf8 character set.\n\nExamples\n--------\n\nSELECT VERSION();\n+----------------+\n| VERSION() |\n+----------------+\n| 10.4.7-MariaDB |\n+----------------+\n\nThe VERSION() string may have one or more of the following suffixes:\n\n+---------------------------+------------------------------------------------+\n| Suffix | Description |\n+---------------------------+------------------------------------------------+\n| -embedded | The server is an embedded server |\n| | (libmariadbd). |\n+---------------------------+------------------------------------------------+\n| -log | General logging, slow logging or binary |\n| | (replication) logging is enabled. |\n+---------------------------+------------------------------------------------+\n| -debug | The server is compiled for debugging. |\n+---------------------------+------------------------------------------------+\n| -valgrind | The server is compiled to be instrumented |\n| | with valgrind. |\n+---------------------------+------------------------------------------------+\n\nChanging the Version String\n---------------------------\n\nSome old legacy code may break because they are parsing the VERSION string and\nexpecting a MySQL string or a simple version string like Joomla til API17, see\nMDEV-7780.\n\nOne can fool these applications by setting the version string from the command\nline or the my.cnf files with --version=....\n\nURL: https://mariadb.com/kb/en/version/','','https://mariadb.com/kb/en/version/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (214,18,'Assignment Operator (:=)','Syntax\n------\n\nvar_name := expr\n\nDescription\n-----------\n\nAssignment operator for assigning a value. The value on the right is assigned\nto the variable on left.\n\nUnlike the = operator, := can always be used to assign a value to a variable.\n\nThis operator works with both user-defined variables and local variables.\n\nWhen assigning the same value to several variables, LAST_VALUE() can be useful.\n\nExamples\n--------\n\nSELECT @x := 10;\n+----------+\n| @x := 10 |\n+----------+\n| 10 |\n+----------+\n\nSELECT @x, @y := @x;\n+------+----------+\n| @x | @y := @x |\n+------+----------+\n| 10 | 10 |\n+------+----------+\n\nURL: https://mariadb.com/kb/en/assignment-operator/','','https://mariadb.com/kb/en/assignment-operator/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (215,18,'Assignment Operator (=)','Syntax\n------\n\nidentifier = expr\n\nDescription\n-----------\n\nThe equal sign is used as both an assignment operator in certain contexts, and\nas a comparison operator. When used as assignment operator, the value on the\nright is assigned to the variable (or column, in some contexts) on the left.\n\nSince its use can be ambiguous, unlike the := assignment operator, the =\nassignment operator cannot be used in all contexts, and is only valid as part\nof a SET statement, or the SET clause of an UPDATE statement\n\nThis operator works with both user-defined variables and local variables.\n\nExamples\n--------\n\nUPDATE table_name SET x = 2 WHERE x > 100;\n\nSET @x = 1, @y := 2;\n\nURL: https://mariadb.com/kb/en/assignment-operators-assignment-operator/','','https://mariadb.com/kb/en/assignment-operators-assignment-operator/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (216,19,'Not Equal Operator','Syntax\n------\n\n<>, !=\n\nDescription\n-----------\n\nNot equal operator. Evaluates both SQL expressions and returns 1 if they are\nnot equal and 0 if they are equal, or NULL if either expression is NULL. If\nthe expressions return different data types, (for instance, a number and a\nstring), performs type conversion.\n\nWhen used in row comparisons these two queries return the same results:\n\nSELECT (t1.a, t1.b) != (t2.x, t2.y) \nFROM t1 INNER JOIN t2;\n\nSELECT (t1.a != t2.x) OR (t1.b != t2.y)\nFROM t1 INNER JOIN t2;\n\nExamples\n--------\n\nSELECT \'.01\' <> \'0.01\';\n+-----------------+\n| \'.01\' <> \'0.01\' |\n+-----------------+\n| 1 |\n+-----------------+\n\nSELECT .01 <> \'0.01\';\n+---------------+\n| .01 <> \'0.01\' |\n+---------------+\n| 0 |\n+---------------+\n\nSELECT \'zapp\' <> \'zappp\';\n+-------------------+\n| \'zapp\' <> \'zappp\' |\n+-------------------+\n| 1 |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/not-equal/','','https://mariadb.com/kb/en/not-equal/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (217,19,'<','Syntax\n------\n\n<\n\nDescription\n-----------\n\nLess than operator. Evaluates both SQL expressions and returns 1 if the left\nvalue is less than the right value and 0 if it is not, or NULL if either\nexpression is NULL. If the expressions return different data types, (for\ninstance, a number and a string), performs type conversion.\n\nWhen used in row comparisons these two queries return the same results:\n\nSELECT (t1.a, t1.b) < (t2.x, t2.y) \nFROM t1 INNER JOIN t2;\n\nSELECT (t1.a < t2.x) OR ((t1.a = t2.x) AND (t1.b < t2.y))\nFROM t1 INNER JOIN t2;\n\nExamples\n--------\n\nSELECT 2 < 2;\n+-------+\n| 2 < 2 |\n+-------+\n| 0 |\n+-------+\n\nType conversion:\n\nSELECT 3<\'4\';\n+-------+\n| 3<\'4\' |\n+-------+\n| 1 |\n+-------+\n\nCase insensitivity - see Character Sets and Collations:\n\nSELECT \'a\'<\'A\';\n+---------+\n| \'a\'<\'A\' |\n+---------+\n| 0 |\n+---------+\n\nURL: https://mariadb.com/kb/en/less-than/','','https://mariadb.com/kb/en/less-than/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (218,19,'<=','Syntax\n------\n\n<=\n\nDescription\n-----------\n\nLess than or equal operator. Evaluates both SQL expressions and returns 1 if\nthe left value is less than or equal to the right value and 0 if it is not, or\nNULL if either expression is NULL. If the expressions return different data\ntypes, (for instance, a number and a string), performs type conversion.\n\nWhen used in row comparisons these two queries return the same results:\n\nSELECT (t1.a, t1.b) <= (t2.x, t2.y) \nFROM t1 INNER JOIN t2;\n\nSELECT (t1.a < t2.x) OR ((t1.a = t2.x) AND (t1.b <= t2.y))\nFROM t1 INNER JOIN t2;\n\nExamples\n--------\n\nSELECT 0.1 <= 2;\n+----------+\n| 0.1 <= 2 |\n+----------+\n| 1 |\n+----------+\n\nSELECT \'a\'<=\'A\';\n+----------+\n| \'a\'<=\'A\' |\n+----------+\n| 1 |\n+----------+\n\nURL: https://mariadb.com/kb/en/less-than-or-equal/','','https://mariadb.com/kb/en/less-than-or-equal/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (219,19,'<=>','Syntax\n------\n\n<=>\n\nDescription\n-----------\n\nNULL-safe equal operator. It performs an equality comparison like the =\noperator, but returns 1 rather than NULL if both operands are NULL, and 0\nrather than NULL if one operand is NULL.\n\na <=> b is equivalent to a = b OR (a IS NULL AND b IS NULL).\n\nWhen used in row comparisons these two queries return the same results:\n\nSELECT (t1.a, t1.b) <=> (t2.x, t2.y) \nFROM t1 INNER JOIN t2;\n\nSELECT (t1.a <=> t2.x) AND (t1.b <=> t2.y)\nFROM t1 INNER JOIN t2;\n\nSee also NULL Values in MariaDB.\n\nExamples\n--------\n\nSELECT 1 <=> 1, NULL <=> NULL, 1 <=> NULL;\n+---------+---------------+------------+\n| 1 <=> 1 | NULL <=> NULL | 1 <=> NULL |\n+---------+---------------+------------+\n| 1 | 1 | 0 |\n+---------+---------------+------------+\n\nSELECT 1 = 1, NULL = NULL, 1 = NULL;\n+-------+-------------+----------+\n| 1 = 1 | NULL = NULL | 1 = NULL |\n+-------+-------------+----------+\n| 1 | NULL | NULL |\n+-------+-------------+----------+\n\nURL: https://mariadb.com/kb/en/null-safe-equal/','','https://mariadb.com/kb/en/null-safe-equal/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (220,19,'=','Syntax\n------\n\nleft_expr = right_expr\n\nDescription\n-----------\n\nEqual operator. Evaluates both SQL expressions and returns 1 if they are\nequal, 0 if they are not equal, or NULL if either expression is NULL. If the\nexpressions return different data types (for example, a number and a string),\na type conversion is performed.\n\nWhen used in row comparisons these two queries are synonymous and return the\nsame results:\n\nSELECT (t1.a, t1.b) = (t2.x, t2.y) FROM t1 INNER JOIN t2;\n\nSELECT (t1.a = t2.x) AND (t1.b = t2.y) FROM t1 INNER JOIN t2;\n\nTo perform a NULL-safe comparison, use the <=> operator.\n\n= can also be used as an assignment operator.\n\nExamples\n--------\n\nSELECT 1 = 0;\n+-------+\n| 1 = 0 |\n+-------+\n| 0 |\n+-------+\n\nSELECT \'0\' = 0;\n+---------+\n| \'0\' = 0 |\n+---------+\n| 1 |\n+---------+\n\nSELECT \'0.0\' = 0;\n+-----------+\n| \'0.0\' = 0 |\n+-----------+\n| 1 |\n+-----------+\n\nSELECT \'0.01\' = 0;\n+------------+\n| \'0.01\' = 0 |\n+------------+\n| 0 |\n+------------+\n\nSELECT \'.01\' = 0.01;\n+--------------+\n| \'.01\' = 0.01 |\n+--------------+\n| 1 |\n+--------------+\n\nSELECT (5 * 2) = CONCAT(\'1\', \'0\');\n+----------------------------+\n| (5 * 2) = CONCAT(\'1\', \'0\') |\n+----------------------------+\n| 1 |\n+----------------------------+\n\nSELECT 1 = NULL;\n+----------+\n| 1 = NULL |\n+----------+\n| NULL |\n+----------+\n\nSELECT NULL = NULL;\n+-------------+\n| NULL = NULL |\n+-------------+\n| NULL |\n+-------------+\n\nURL: https://mariadb.com/kb/en/equal/','','https://mariadb.com/kb/en/equal/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (221,19,'>','Syntax\n------\n\n>\n\nDescription\n-----------\n\nGreater than operator. Evaluates both SQL expressions and returns 1 if the\nleft value is greater than the right value and 0 if it is not, or NULL if\neither expression is NULL. If the expressions return different data types,\n(for instance, a number and a string), performs type conversion.\n\nWhen used in row comparisons these two queries return the same results:\n\nSELECT (t1.a, t1.b) > (t2.x, t2.y) \nFROM t1 INNER JOIN t2;\n\nSELECT (t1.a > t2.x) OR ((t1.a = t2.x) AND (t1.b > t2.y))\nFROM t1 INNER JOIN t2;\n\nExamples\n--------\n\nSELECT 2 > 2;\n+-------+\n| 2 > 2 |\n+-------+\n| 0 |\n+-------+\n\nSELECT \'b\' > \'a\';\n+-----------+\n| \'b\' > \'a\' |\n+-----------+\n| 1 |\n+-----------+\n\nURL: https://mariadb.com/kb/en/greater-than/','','https://mariadb.com/kb/en/greater-than/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (222,19,'>=','Syntax\n------\n\n>=\n\nDescription\n-----------\n\nGreater than or equal operator. Evaluates both SQL expressions and returns 1\nif the left value is greater than or equal to the right value and 0 if it is\nnot, or NULL if either expression is NULL. If the expressions return different\ndata types, (for instance, a number and a string), performs type conversion.\n\nWhen used in row comparisons these two queries return the same results:\n\nSELECT (t1.a, t1.b) >= (t2.x, t2.y) \nFROM t1 INNER JOIN t2;\n\nSELECT (t1.a > t2.x) OR ((t1.a = t2.x) AND (t1.b >= t2.y))\nFROM t1 INNER JOIN t2;\n\nExamples\n--------\n\nSELECT 2 >= 2;\n+--------+\n| 2 >= 2 |\n+--------+\n| 1 |\n+--------+\n\nSELECT \'A\' >= \'a\';\n+------------+\n| \'A\' >= \'a\' |\n+------------+\n| 1 |\n+------------+\n\nURL: https://mariadb.com/kb/en/greater-than-or-equal/','','https://mariadb.com/kb/en/greater-than-or-equal/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (223,19,'BETWEEN AND','Syntax\n------\n\nexpr BETWEEN min AND max\n\nDescription\n-----------\n\nIf expr is greater than or equal to min and expr is less than or equal to max,\nBETWEEN returns 1, otherwise it returns 0. This is equivalent to the\nexpression (min <= expr AND expr <= max) if all the arguments are of the same\ntype. Otherwise type conversion takes place according to the rules described\nat Type Conversion, but applied to all the three arguments.\n\nExamples\n--------\n\nSELECT 1 BETWEEN 2 AND 3;\n+-------------------+\n| 1 BETWEEN 2 AND 3 |\n+-------------------+\n| 0 |\n+-------------------+\n\nSELECT \'b\' BETWEEN \'a\' AND \'c\';\n+-------------------------+\n| \'b\' BETWEEN \'a\' AND \'c\' |\n+-------------------------+\n| 1 |\n+-------------------------+\n\nSELECT 2 BETWEEN 2 AND \'3\';\n+---------------------+\n| 2 BETWEEN 2 AND \'3\' |\n+---------------------+\n| 1 |\n+---------------------+\n\nSELECT 2 BETWEEN 2 AND \'x-3\';\n+-----------------------+\n| 2 BETWEEN 2 AND \'x-3\' |\n+-----------------------+\n| 0 |\n+-----------------------+\n1 row in set, 1 warning (0.00 sec)\n\nWarning (Code 1292): Truncated incorrect DOUBLE value: \'x-3\'\n\nNULL:\n\nSELECT 1 BETWEEN 1 AND NULL;\n+----------------------+\n| 1 BETWEEN 1 AND NULL |\n+----------------------+\n| NULL |\n+----------------------+\n\nDATE, DATETIME and TIMESTAMP examples. Omitting the time component compares\nagainst 00:00, so later times on the same date are not returned:\n\nCREATE TABLE `x` (\n a date ,\n b datetime,\n c timestamp\n)\n\nINSERT INTO x VALUES \n (\'2018-11-11\', \'2018-11-11 05:15\', \'2018-11-11 05:15\'), \n (\'2018-11-12\', \'2018-11-12 05:15\', \'2018-11-12 05:15\');\n\nSELECT * FROM x WHERE a BETWEEN \'2018-11-11\' AND \'2018-11-12\';\n+------------+---------------------+---------------------+\n| a | b | c |\n+------------+---------------------+---------------------+\n| 2018-11-11 | 2018-11-11 05:15:00 | 2018-11-11 05:15:00 |\n| 2018-11-12 | 2018-11-12 05:15:00 | 2018-11-12 05:15:00 |\n+------------+---------------------+---------------------+\n\nSELECT * FROM x WHERE b BETWEEN \'2018-11-11\' AND \'2018-11-12\';\n+------------+---------------------+---------------------+\n| a | b | c |\n+------------+---------------------+---------------------+\n| 2018-11-11 | 2018-11-11 05:15:00 | 2018-11-11 05:15:00 |\n+------------+---------------------+---------------------+\n\nSELECT * FROM x WHERE c BETWEEN \'2018-11-11\' AND \'2018-11-12\';\n+------------+---------------------+---------------------+\n| a | b | c |\n+------------+---------------------+---------------------+\n| 2018-11-11 | 2018-11-11 05:15:00 | 2018-11-11 05:15:00 |\n+------------+---------------------+---------------------+\n\nURL: https://mariadb.com/kb/en/between-and/','','https://mariadb.com/kb/en/between-and/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (224,19,'COALESCE','Syntax\n------\n\nCOALESCE(value,...)\n\nDescription\n-----------\n\nReturns the first non-NULL value in the list, or NULL if there are no non-NULL\nvalues. At least one parameter must be passed.\n\nThe function is useful when substituting a default value for null values when\ndisplaying data.\n\nSee also NULL Values in MariaDB.\n\nExamples\n--------\n\nSELECT COALESCE(NULL,1);\n+------------------+\n| COALESCE(NULL,1) |\n+------------------+\n| 1 |\n+------------------+\n\nSELECT COALESCE(NULL,NULL,NULL);\n+--------------------------+\n| COALESCE(NULL,NULL,NULL) |\n+--------------------------+\n| NULL |\n+--------------------------+\n\nWhen two arguments are given, COALESCE() is the same as IFNULL():\n\nSET @a=NULL, @b=1;\n\nSELECT COALESCE(@a, @b), IFNULL(@a, @b);\n+------------------+----------------+\n| COALESCE(@a, @b) | IFNULL(@a, @b) |\n+------------------+----------------+\n| 1 | 1 |\n+------------------+----------------+\n\nHex type confusion:\n\nCREATE TABLE t1 (a INT, b VARCHAR(10));\nINSERT INTO t1 VALUES (0x31, 0x61),(COALESCE(0x31), COALESCE(0x61));\n\nSELECT * FROM t1;\n+------+------+\n| a | b |\n+------+------+\n| 49 | a |\n| 1 | a |\n+------+------+\n\nThe reason for the differing results above is that when 0x31 is inserted\ndirectly to the column, it\'s treated as a number (see Hexadecimal Literals),\nwhile when 0x31 is passed to COALESCE(), it\'s treated as a string, because:\n\n* HEX values have a string data type by default.\n* COALESCE() has the same data type as the argument.\n\nSubstituting zero for NULL (in this case when the aggregate function returns\nNULL after finding no rows):\n\nSELECT SUM(score) FROM student;\n+------------+\n| SUM(score) |\n+------------+\n| NULL |\n+------------+\n\nSELECT COALESCE(SUM(score),0) FROM student;\n+------------------------+\n| COALESCE(SUM(score),0) |\n+------------------------+\n| 0 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/coalesce/','','https://mariadb.com/kb/en/coalesce/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (225,19,'GREATEST','Syntax\n------\n\nGREATEST(value1,value2,...)\n\nDescription\n-----------\n\nWith two or more arguments, returns the largest (maximum-valued) argument. The\narguments are compared using the same rules as for LEAST().\n\nExamples\n--------\n\nSELECT GREATEST(2,0);\n+---------------+\n| GREATEST(2,0) |\n+---------------+\n| 2 |\n+---------------+\n\nSELECT GREATEST(34.0,3.0,5.0,767.0);\n+------------------------------+\n| GREATEST(34.0,3.0,5.0,767.0) |\n+------------------------------+\n| 767.0 |\n+------------------------------+\n\nSELECT GREATEST(\'B\',\'A\',\'C\');\n+-----------------------+\n| GREATEST(\'B\',\'A\',\'C\') |\n+-----------------------+\n| C |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/greatest/','','https://mariadb.com/kb/en/greatest/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (226,19,'IN','Syntax\n------\n\nexpr IN (value,...)\n\nDescription\n-----------\n\nReturns 1 if expr is equal to any of the values in the IN list, else returns\n0. If all values are constants, they are evaluated according to the type of\nexpr and sorted. The search for the item then is done using a binary search.\nThis means IN is very quick if the IN value list consists entirely of\nconstants. Otherwise, type conversion takes place according to the rules\ndescribed at Type Conversion, but applied to all the arguments.\n\nIf expr is NULL, IN always returns NULL. If at least one of the values in the\nlist is NULL, and one of the comparisons is true, the result is 1. If at least\none of the values in the list is NULL and none of the comparisons is true, the\nresult is NULL.\n\nExamples\n--------\n\nSELECT 2 IN (0,3,5,7);\n+----------------+\n| 2 IN (0,3,5,7) |\n+----------------+\n| 0 |\n+----------------+\n\nSELECT \'wefwf\' IN (\'wee\',\'wefwf\',\'weg\');\n+----------------------------------+\n| \'wefwf\' IN (\'wee\',\'wefwf\',\'weg\') |\n+----------------------------------+\n| 1 |\n+----------------------------------+\n\nType conversion:\n\nSELECT 1 IN (\'1\', \'2\', \'3\');\n+----------------------+\n| 1 IN (\'1\', \'2\', \'3\') |\n+----------------------+\n| 1 |\n+----------------------+\n\nSELECT NULL IN (1, 2, 3);\n+-------------------+\n| NULL IN (1, 2, 3) |\n+-------------------+\n| NULL |\n+-------------------+\n\nSELECT 1 IN (1, 2, NULL);\n+-------------------+\n| 1 IN (1, 2, NULL) |\n+-------------------+\n| 1 |\n+-------------------+\n\nSELECT 5 IN (1, 2, NULL);\n+-------------------+\n| 5 IN (1, 2, NULL) |\n+-------------------+\n| NULL |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/in/','','https://mariadb.com/kb/en/in/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (227,19,'INTERVAL','Syntax\n------\n\nINTERVAL(N,N1,N2,N3,...)\n\nDescription\n-----------\n\nReturns the index of the last argument that is less than the first argument or\nis NULL.\n\nReturns 0 if N < N1, 1 if N < N2, 2 if N < N3 and so on or -1 if N is NULL.\nAll arguments are treated as integers. It is required that N1 < N2 < N3 < ...\n< Nn for this function to work correctly. This is because a fast binary search\nis used.\n\nExamples\n--------\n\nSELECT INTERVAL(23, 1, 15, 17, 30, 44, 200);\n+--------------------------------------+\n| INTERVAL(23, 1, 15, 17, 30, 44, 200) |\n+--------------------------------------+\n| 3 |\n+--------------------------------------+\n\nSELECT INTERVAL(10, 1, 10, 100, 1000);\n+--------------------------------+\n| INTERVAL(10, 1, 10, 100, 1000) |\n+--------------------------------+\n| 2 |\n+--------------------------------+\n\nSELECT INTERVAL(22, 23, 30, 44, 200);\n+-------------------------------+\n| INTERVAL(22, 23, 30, 44, 200) |\n+-------------------------------+\n| 0 |\n+-------------------------------+\n\nSELECT INTERVAL(10, 2, NULL);\n+-----------------------+\n| INTERVAL(10, 2, NULL) |\n+-----------------------+\n| 2 |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/interval/','','https://mariadb.com/kb/en/interval/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (228,19,'IS','Syntax\n------\n\nIS boolean_value\n\nDescription\n-----------\n\nTests a value against a boolean value, where boolean_value can be TRUE, FALSE,\nor UNKNOWN.\n\nThere is an important difference between using IS TRUE or comparing a value\nwith TRUE using =. When using =, only 1 equals to TRUE. But when using IS\nTRUE, all values which are logically true (like a number > 1) return TRUE.\n\nExamples\n--------\n\nSELECT 1 IS TRUE, 0 IS FALSE, NULL IS UNKNOWN;\n+-----------+------------+-----------------+\n| 1 IS TRUE | 0 IS FALSE | NULL IS UNKNOWN |\n+-----------+------------+-----------------+\n| 1 | 1 | 1 |\n+-----------+------------+-----------------+\n\nDifference between = and IS TRUE:\n\nSELECT 2 = TRUE, 2 IS TRUE;\n+----------+-----------+\n| 2 = TRUE | 2 IS TRUE |\n+----------+-----------+\n| 0 | 1 |\n+----------+-----------+\n\nURL: https://mariadb.com/kb/en/is/','','https://mariadb.com/kb/en/is/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (229,19,'IS NOT','Syntax\n------\n\nIS NOT boolean_value\n\nDescription\n-----------\n\nTests a value against a boolean value, where boolean_value can be TRUE, FALSE,\nor UNKNOWN.\n\nExamples\n--------\n\nSELECT 1 IS NOT UNKNOWN, 0 IS NOT UNKNOWN, NULL IS NOT UNKNOWN;\n+------------------+------------------+---------------------+\n| 1 IS NOT UNKNOWN | 0 IS NOT UNKNOWN | NULL IS NOT UNKNOWN |\n+------------------+------------------+---------------------+\n| 1 | 1 | 0 |\n+------------------+------------------+---------------------+\n\nSELECT NULL IS NOT TRUE, NULL IS NOT FALSE;\n+------------------+-------------------+\n| NULL IS NOT TRUE | NULL IS NOT FALSE |\n+------------------+-------------------+\n| 1 | 1 |\n+------------------+-------------------+\n\nURL: https://mariadb.com/kb/en/is-not/','','https://mariadb.com/kb/en/is-not/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (230,19,'IS NOT NULL','Syntax\n------\n\nIS NOT NULL\n\nDescription\n-----------\n\nTests whether a value is not NULL. See also NULL Values in MariaDB.\n\nExamples\n--------\n\nSELECT 1 IS NOT NULL, 0 IS NOT NULL, NULL IS NOT NULL;\n+---------------+---------------+------------------+\n| 1 IS NOT NULL | 0 IS NOT NULL | NULL IS NOT NULL |\n+---------------+---------------+------------------+\n| 1 | 1 | 0 |\n+---------------+---------------+------------------+\n\nURL: https://mariadb.com/kb/en/is-not-null/','','https://mariadb.com/kb/en/is-not-null/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (231,19,'IS NULL','Syntax\n------\n\nIS NULL\n\nDescription\n-----------\n\nTests whether a value is NULL. See also NULL Values in MariaDB.\n\nExamples\n--------\n\nSELECT 1 IS NULL, 0 IS NULL, NULL IS NULL;\n+-----------+-----------+--------------+\n| 1 IS NULL | 0 IS NULL | NULL IS NULL |\n+-----------+-----------+--------------+\n| 0 | 0 | 1 |\n+-----------+-----------+--------------+\n\nCompatibility\n-------------\n\nSome ODBC applications use the syntax auto_increment_field IS NOT NULL to find\nthe latest row that was inserted with an autogenerated key value. If your\napplications need this, you can set the sql_auto_is_null variable to 1.\n\nSET @@sql_auto_is_null=1;\nCREATE TABLE t1 (auto_increment_column INT NOT NULL AUTO_INCREMENT PRIMARY\nKEY);\nINSERT INTO t1 VALUES (NULL);\nSELECT * FROM t1 WHERE auto_increment_column IS NULL;\n\n+-----------------------+\n| auto_increment_column |\n+-----------------------+\n| 1 |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/is-null/','','https://mariadb.com/kb/en/is-null/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (232,19,'ISNULL','Syntax\n------\n\nISNULL(expr)\n\nDescription\n-----------\n\nIf expr is NULL, ISNULL() returns 1, otherwise it returns 0.\n\nSee also NULL Values in MariaDB.\n\nExamples\n--------\n\nSELECT ISNULL(1+1);\n+-------------+\n| ISNULL(1+1) |\n+-------------+\n| 0 |\n+-------------+\n\nSELECT ISNULL(1/0);\n+-------------+\n| ISNULL(1/0) |\n+-------------+\n| 1 |\n+-------------+\n\nURL: https://mariadb.com/kb/en/isnull/','','https://mariadb.com/kb/en/isnull/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (233,19,'LEAST','Syntax\n------\n\nLEAST(value1,value2,...)\n\nDescription\n-----------\n\nWith two or more arguments, returns the smallest (minimum-valued) argument.\nThe arguments are compared using the following rules:\n\n* If the return value is used in an INTEGER context or all arguments are\ninteger-valued, they are compared as integers.\n* If the return value is used in a REAL context or all arguments are\nreal-valued, they are compared as reals.\n* If any argument is a case-sensitive string, the arguments are compared as\ncase-sensitive strings.\n* In all other cases, the arguments are compared as case-insensitive strings.\n\nLEAST() returns NULL if any argument is NULL.\n\nExamples\n--------\n\nSELECT LEAST(2,0);\n+------------+\n| LEAST(2,0) |\n+------------+\n| 0 |\n+------------+\n\nSELECT LEAST(34.0,3.0,5.0,767.0);\n+---------------------------+\n| LEAST(34.0,3.0,5.0,767.0) |\n+---------------------------+\n| 3.0 |\n+---------------------------+\n\nSELECT LEAST(\'B\',\'A\',\'C\');\n+--------------------+\n| LEAST(\'B\',\'A\',\'C\') |\n+--------------------+\n| A |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/least/','','https://mariadb.com/kb/en/least/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (234,19,'NOT BETWEEN','Syntax\n------\n\nexpr NOT BETWEEN min AND max\n\nDescription\n-----------\n\nThis is the same as NOT (expr BETWEEN min AND max).\n\nNote that the meaning of the alternative form NOT expr BETWEEN min AND max is\naffected by the HIGH_NOT_PRECEDENCE SQL_MODE flag.\n\nExamples\n--------\n\nSELECT 1 NOT BETWEEN 2 AND 3;\n+-----------------------+\n| 1 NOT BETWEEN 2 AND 3 |\n+-----------------------+\n| 1 |\n+-----------------------+\n\nSELECT \'b\' NOT BETWEEN \'a\' AND \'c\';\n+-----------------------------+\n| \'b\' NOT BETWEEN \'a\' AND \'c\' |\n+-----------------------------+\n| 0 |\n+-----------------------------+\n\nNULL:\n\nSELECT 1 NOT BETWEEN 1 AND NULL;\n+--------------------------+\n| 1 NOT BETWEEN 1 AND NULL |\n+--------------------------+\n| NULL |\n+--------------------------+\n\nURL: https://mariadb.com/kb/en/not-between/','','https://mariadb.com/kb/en/not-between/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (235,19,'NOT IN','Syntax\n------\n\nexpr NOT IN (value,...)\n\nDescription\n-----------\n\nThis is the same as NOT (expr IN (value,...)).\n\nExamples\n--------\n\nSELECT 2 NOT IN (0,3,5,7);\n+--------------------+\n| 2 NOT IN (0,3,5,7) |\n+--------------------+\n| 1 |\n+--------------------+\n\nSELECT \'wefwf\' NOT IN (\'wee\',\'wefwf\',\'weg\');\n+--------------------------------------+\n| \'wefwf\' NOT IN (\'wee\',\'wefwf\',\'weg\') |\n+--------------------------------------+\n| 0 |\n+--------------------------------------+\n\nSELECT 1 NOT IN (\'1\', \'2\', \'3\');\n+--------------------------+\n| 1 NOT IN (\'1\', \'2\', \'3\') |\n+--------------------------+\n| 0 |\n+--------------------------+\n\nNULL:\n\nSELECT NULL NOT IN (1, 2, 3);\n+-----------------------+\n| NULL NOT IN (1, 2, 3) |\n+-----------------------+\n| NULL |\n+-----------------------+\n\nSELECT 1 NOT IN (1, 2, NULL);\n+-----------------------+\n| 1 NOT IN (1, 2, NULL) |\n+-----------------------+\n| 0 |\n+-----------------------+\n\nSELECT 5 NOT IN (1, 2, NULL);\n+-----------------------+\n| 5 NOT IN (1, 2, NULL) |\n+-----------------------+\n| NULL |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/not-in/','','https://mariadb.com/kb/en/not-in/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (236,20,'&','Syntax\n------\n\n&\n\nDescription\n-----------\n\nBitwise AND. Converts the values to binary and compares bits. Only if both the\ncorresponding bits are 1 is the resulting bit also 1.\n\nSee also bitwise OR.\n\nExamples\n--------\n\nSELECT 2&1;\n+-----+\n| 2&1 |\n+-----+\n| 0 |\n+-----+\n\nSELECT 3&1;\n+-----+\n| 3&1 |\n+-----+\n| 1 |\n+-----+\n\nSELECT 29 & 15;\n+---------+\n| 29 & 15 |\n+---------+\n| 13 |\n+---------+\n\nURL: https://mariadb.com/kb/en/bitwise_and/','','https://mariadb.com/kb/en/bitwise_and/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (237,20,'<<','Syntax\n------\n\nvalue1 << value2\n\nDescription\n-----------\n\nConverts a longlong (BIGINT) number (value1) to binary and shifts value2 units\nto the left.\n\nExamples\n--------\n\nSELECT 1 << 2;\n+--------+\n| 1 << 2 |\n+--------+\n| 4 |\n+--------+\n\nURL: https://mariadb.com/kb/en/shift-left/','','https://mariadb.com/kb/en/shift-left/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (238,20,'>>','Syntax\n------\n\nvalue1 >> value2\n\nDescription\n-----------\n\nConverts a longlong (BIGINT) number (value1) to binary and shifts value2 units\nto the right.\n\nExamples\n--------\n\nSELECT 4 >> 2;\n+--------+\n| 4 >> 2 |\n+--------+\n| 1 |\n+--------+\n\nURL: https://mariadb.com/kb/en/shift-right/','','https://mariadb.com/kb/en/shift-right/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (239,20,'BIT_COUNT','Syntax\n------\n\nBIT_COUNT(N)\n\nDescription\n-----------\n\nReturns the number of bits that are set in the argument N.\n\nExamples\n--------\n\nSELECT BIT_COUNT(29), BIT_COUNT(b\'101010\');\n+---------------+----------------------+\n| BIT_COUNT(29) | BIT_COUNT(b\'101010\') |\n+---------------+----------------------+\n| 4 | 3 |\n+---------------+----------------------+\n\nURL: https://mariadb.com/kb/en/bit_count/','','https://mariadb.com/kb/en/bit_count/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (240,20,'^','Syntax\n------\n\n^\n\nDescription\n-----------\n\nBitwise XOR. Converts the values to binary and compares bits. If one (and only\none) of the corresponding bits is 1 is the resulting bit also 1.\n\nExamples\n--------\n\nSELECT 1 ^ 1;\n+-------+\n| 1 ^ 1 |\n+-------+\n| 0 |\n+-------+\n\nSELECT 1 ^ 0;\n+-------+\n| 1 ^ 0 |\n+-------+\n| 1 |\n+-------+\n\nSELECT 11 ^ 3;\n+--------+\n| 11 ^ 3 |\n+--------+\n| 8 |\n+--------+\n\nURL: https://mariadb.com/kb/en/bitwise-xor/','','https://mariadb.com/kb/en/bitwise-xor/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (241,20,'|','Syntax\n------\n\n|\n\nDescription\n-----------\n\nBitwise OR. Converts the values to binary and compares bits. If either of the\ncorresponding bits has a value of 1, the resulting bit is also 1.\n\nSee also bitwise AND.\n\nExamples\n--------\n\nSELECT 2|1;\n+-----+\n| 2|1 |\n+-----+\n| 3 |\n+-----+\n\nSELECT 29 | 15;\n+---------+\n| 29 | 15 |\n+---------+\n| 31 |\n+---------+\n\nURL: https://mariadb.com/kb/en/bitwise-or/','','https://mariadb.com/kb/en/bitwise-or/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (242,20,'~','Syntax\n------\n\n~\n\nDescription\n-----------\n\nBitwise NOT. Converts the value to 4 bytes binary and inverts all bits.\n\nExamples\n--------\n\nSELECT 3 & ~1;\n+--------+\n| 3 & ~1 |\n+--------+\n| 2 |\n+--------+\n\nSELECT 5 & ~1;\n+--------+\n| 5 & ~1 |\n+--------+\n| 4 |\n+--------+\n\nURL: https://mariadb.com/kb/en/bitwise-not/','','https://mariadb.com/kb/en/bitwise-not/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (243,20,'Parentheses','Parentheses are sometimes called precedence operators - this means that they\ncan be used to change the other operator\'s precedence in an expression. The\nexpressions that are written between parentheses are computed before the\nexpressions that are written outside. Parentheses must always contain an\nexpression (that is, they cannot be empty), and can be nested.\n\nFor example, the following expressions could return different results:\n\n* NOT a OR b\n* NOT (a OR b)\n\nIn the first case, NOT applies to a, so if a is FALSE or b is TRUE, the\nexpression returns TRUE. In the second case, NOT applies to the result of a OR\nb, so if at least one of a or b is TRUE, the expression is TRUE.\n\nWhen the precedence of operators is not intuitive, you can use parentheses to\nmake it immediately clear for whoever reads the statement.\n\nThe precedence of the NOT operator can also be affected by the\nHIGH_NOT_PRECEDENCE SQL_MODE flag.\n\nOther uses\n----------\n\nParentheses must always be used to enclose subqueries.\n\nParentheses can also be used in a JOIN statement between multiple tables to\ndetermine which tables must be joined first.\n\nAlso, parentheses are used to enclose the list of parameters to be passed to\nbuilt-in functions, user-defined functions and stored routines. However, when\nno parameter is passed to a stored procedure, parentheses are optional. For\nbuiltin functions and user-defined functions, spaces are not allowed between\nthe function name and the open parenthesis, unless the IGNORE_SPACE SQL_MODE\nis set. For stored routines (and for functions if IGNORE_SPACE is set) spaces\nare allowed before the open parenthesis, including tab characters and new line\ncharacters.\n\nSyntax errors\n-------------\n\nIf there are more open parentheses than closed parentheses, the error usually\nlooks like this:\n\nERROR 1064 (42000): You have an error in your SQL syntax; check the manual that\ncorresponds to your MariaDB server version for the right syntax to use near \'\'\na\nt line 1\n\nNote the empty string.\n\nIf there are more closed parentheses than open parentheses, the error usually\nlooks like this:\n\nERROR 1064 (42000): You have an error in your SQL syntax; check the manual that\ncorresponds to your MariaDB server version for the right syntax to use near \')\'\nat line 1\n\nNote the quoted closed parenthesis.\n\nURL: https://mariadb.com/kb/en/parentheses/','','https://mariadb.com/kb/en/parentheses/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (244,20,'TRUE FALSE','Description\n-----------\n\nThe constants TRUE and FALSE evaluate to 1 and 0, respectively. The constant\nnames can be written in any lettercase.\n\nExamples\n--------\n\nSELECT TRUE, true, FALSE, false;\n+------+------+-------+-------+\n| TRUE | TRUE | FALSE | FALSE |\n+------+------+-------+-------+\n| 1 | 1 | 0 | 0 |\n+------+------+-------+-------+\n\nURL: https://mariadb.com/kb/en/true-false/','','https://mariadb.com/kb/en/true-false/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (245,21,'ANALYZE TABLE','Syntax\n------\n\nANALYZE [NO_WRITE_TO_BINLOG | LOCAL] TABLE tbl_name [,tbl_name ...]\n [PERSISTENT FOR\n { ALL\n | COLUMNS ([col_name [,col_name ...]]) INDEXES ([index_name [,index_name\n...]])\n }\n ]\n\nDescription\n-----------\n\nANALYZE TABLE analyzes and stores the key distribution for a table (index\nstatistics). This statement works with MyISAM, Aria and InnoDB tables. During\nthe analysis, InnoDB will allow reads/writes, and MyISAM/Aria reads/inserts.\nFor MyISAM tables, this statement is equivalent to using myisamchk --analyze.\n\nFor more information on how the analysis works within InnoDB, see InnoDB\nLimitations.\n\nMariaDB uses the stored key distribution to decide the order in which tables\nshould be joined when you perform a join on something other than a constant.\nIn addition, key distributions can be used when deciding which indexes to use\nfor a specific table within a query.\n\nThis statement requires SELECT and INSERT privileges for the table.\n\nBy default, ANALYZE TABLE statements are written to the binary log and will be\nreplicated. The NO_WRITE_TO_BINLOG keyword (LOCAL is an alias) will ensure the\nstatement is not written to the binary log.\n\nFrom MariaDB 10.3.19, ANALYZE TABLE statements are not logged to the binary\nlog if read_only is set. See also Read-Only Replicas.\n\nANALYZE TABLE is also supported for partitioned tables. You can use ALTER\nTABLE ... ANALYZE PARTITION to analyze one or more partitions.\n\nThe Aria storage engine supports progress reporting for the ANALYZE TABLE\nstatement.\n\nEngine-Independent Statistics\n-----------------------------\n\nANALYZE TABLE supports engine-independent statistics. See Engine-Independent\nTable Statistics: Collecting Statistics with the ANALYZE TABLE Statement for\nmore information.\n\nUseful Variables\n----------------\n\nFor calculating the number of duplicates, ANALYZE TABLE uses a buffer of\nsort_buffer_size bytes per column. You can slightly increase the speed of\nANALYZE TABLE by increasing this variable.\n\nExamples\n--------\n\n-- update all engine-independent statistics for all columns and indexes\nANALYZE TABLE tbl PERSISTENT FOR ALL;\n\n-- update specific columns and indexes:\nANALYZE TABLE tbl PERSISTENT FOR COLUMNS (col1,col2,...) INDEXES\n(idx1,idx2,...);\n\n-- empty lists are allowed:\nANALYZE TABLE tbl PERSISTENT FOR COLUMNS (col1,col2,...) INDEXES ();\nANALYZE TABLE tbl PERSISTENT FOR COLUMNS () INDEXES (idx1,idx2,...);\n\n-- the following will only update mysql.table_stats fields:\nANALYZE TABLE tbl PERSISTENT FOR COLUMNS () INDEXES ();\n\n-- when use_stat_tables is set to \'COMPLEMENTARY\' or \'PREFERABLY\', \n-- a simple ANALYZE TABLE collects engine-independent statistics for all\ncolumns and indexes.\nSET SESSION use_stat_tables=\'COMPLEMENTARY\';\nANALYZE TABLE tbl;\n\nURL: https://mariadb.com/kb/en/analyze-table/','','https://mariadb.com/kb/en/analyze-table/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (246,21,'CHECK TABLE','Syntax\n------\n\nCHECK TABLE tbl_name [, tbl_name] ... [option] ...\n\noption = {FOR UPGRADE | QUICK | FAST | MEDIUM | EXTENDED | CHANGED}\n\nDescription\n-----------\n\nCHECK TABLE checks a table or tables for errors. CHECK TABLE works for\nArchive, Aria, CSV, InnoDB and MyISAM tables. For Aria and MyISAM tables, the\nkey statistics are updated as well. For CSV, see also Checking and Repairing\nCSV Tables.\n\nAs an alternative, myisamchk is a commandline tool for checking MyISAM tables\nwhen the tables are not being accessed. For Aria tables, there is a similar\ntool: aria_chk.\n\nFor checking dynamic columns integrity, COLUMN_CHECK() can be used.\n\nCHECK TABLE can also check views for problems, such as tables that are\nreferenced in the view definition that no longer exist.\n\nCHECK TABLE is also supported for partitioned tables. You can use ALTER TABLE\n... CHECK PARTITION to check one or more partitions.\n\nThe meaning of the different options are as follows - note that this can vary\na bit between storage engines:\n\n+-----+----------------------------------------------------------------------+\n| FOR | Do a very quick check if the storage format for the table has |\n| UPG | changed so that one needs to do a REPAIR. This is only needed when |\n| ADE | one upgrades between major versions of MariaDB or MySQL. This is |\n| | usually done by running mariadb-upgrade. |\n+-----+----------------------------------------------------------------------+\n| FAS | Only check tables that has not been closed properly or are marked |\n| | as corrupt. Only supported by the MyISAM and Aria engines. For |\n| | other engines the table is checked normally |\n+-----+----------------------------------------------------------------------+\n| CHA | Check only tables that has changed since last REPAIR / CHECK. Only |\n| GED | supported by the MyISAM and Aria engines. For other engines the |\n| | table is checked normally. |\n+-----+----------------------------------------------------------------------+\n| QUI | Do a fast check. For MyISAM and Aria, this means skipping the check |\n| K | of the delete link chain, which may take some time. |\n+-----+----------------------------------------------------------------------+\n| MED | Scan also the data files. Checks integrity between data and index |\n| UM | files with checksums. In most cases this should find all possible |\n| | errors. |\n+-----+----------------------------------------------------------------------+\n| EXT | Does a full check to verify every possible error. For InnoDB, Aria, |\n| NDE | and MyISAM, verify for each row that all its keys exists, and for |\n| | those index keys, they point back to the primary clustered key. |\n| | This may take a long time on large tables. This option was |\n| | previously ignored by InnoDB before MariaDB 10.6.11, MariaDB |\n| | 10.7.7, MariaDB 10.8.6 and MariaDB 10.9.4. |\n+-----+----------------------------------------------------------------------+\n\nFor most cases running CHECK TABLE without options or MEDIUM should be good\nenough.\n\nThe Aria storage engine supports progress reporting for this statement.\n\nIf you want to know if two tables are identical, take a look at CHECKSUM TABLE.\n\nInnoDB\n------\n\nIf CHECK TABLE finds an error in an InnoDB table, MariaDB might shutdown to\nprevent the error propagation. In this case, the problem will be reported in\nthe error log. Otherwise the table or an index might be marked as corrupted,\nto prevent use. This does not happen with some minor problems, like a wrong\nnumber of entries in a secondary index. Those problems are reported in the\noutput of CHECK TABLE.\n\nEach tablespace contains a header with metadata. This header is not checked by\nthis statement.\n\nDuring the execution of CHECK TABLE, other threads may be blocked.\n\nURL: https://mariadb.com/kb/en/check-table/','','https://mariadb.com/kb/en/check-table/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (247,21,'CHECK VIEW','Syntax\n------\n\nCHECK VIEW view_name\n\nDescription\n-----------\n\nThe CHECK VIEW statement was introduced in MariaDB 10.0.18 to assist with\nfixing MDEV-6916, an issue introduced in MariaDB 5.2 where the view algorithms\nwere swapped. It checks whether the view algorithm is correct. It is run as\npart of mariadb-upgrade, and should not normally be required in regular use.\n\nURL: https://mariadb.com/kb/en/check-view/','','https://mariadb.com/kb/en/check-view/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (248,21,'CHECKSUM TABLE','Syntax\n------\n\nCHECKSUM TABLE tbl_name [, tbl_name] ... [ QUICK | EXTENDED ]\n\nDescription\n-----------\n\nCHECKSUM TABLE reports a table checksum. This is very useful if you want to\nknow if two tables are the same (for example on a master and slave).\n\nWith QUICK, the live table checksum is reported if it is available, or NULL\notherwise. This is very fast. A live checksum is enabled by specifying the\nCHECKSUM=1 table option when you create the table; currently, this is\nsupported only for Aria and MyISAM tables.\n\nWith EXTENDED, the entire table is read row by row and the checksum is\ncalculated. This can be very slow for large tables.\n\nIf neither QUICK nor EXTENDED is specified, MariaDB returns a live checksum if\nthe table storage engine supports it and scans the table otherwise.\n\nCHECKSUM TABLE requires the SELECT privilege for the table.\n\nFor a nonexistent table, CHECKSUM TABLE returns NULL and generates a warning.\n\nThe table row format affects the checksum value. If the row format changes,\nthe checksum will change. This means that when a table created with a\nMariaDB/MySQL version is upgraded to another version, the checksum value will\nprobably change.\n\nTwo identical tables should always match to the same checksum value; however,\nalso for non-identical tables there is a very slight chance that they will\nreturn the same value as the hashing algorithm is not completely\ncollision-free.\n\nIdentical Tables\n----------------\n\nIdentical tables mean that the CREATE statement is identical and that the\nfollowing variable, which affects the storage formats, was the same when the\ntables were created:\n\n* mysql56-temporal-format\n\nDifferences Between MariaDB and MySQL\n-------------------------------------\n\nCHECKSUM TABLE may give a different result as MariaDB doesn\'t ignore NULLs in\nthe columns as MySQL 5.1 does (Later MySQL versions should calculate checksums\nthe same way as MariaDB). You can get the \'old style\' checksum in MariaDB by\nstarting mysqld with the --old option. Note however that that the MyISAM and\nAria storage engines in MariaDB are using the new checksum internally, so if\nyou are using --old, the CHECKSUM command will be slower as it needs to\ncalculate the checksum row by row. Starting from MariaDB Server 10.9, --old is\ndeprecated and will be removed in a future release. Set --old-mode or OLD_MODE\nto COMPAT_5_1_CHECKSUM to get \'old style\' checksum.\n\nURL: https://mariadb.com/kb/en/checksum-table/','','https://mariadb.com/kb/en/checksum-table/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (249,21,'OPTIMIZE TABLE','Syntax\n------\n\nOPTIMIZE [NO_WRITE_TO_BINLOG | LOCAL] TABLE\n tbl_name [, tbl_name] ...\n [WAIT n | NOWAIT]\n\nDescription\n-----------\n\nOPTIMIZE TABLE has two main functions. It can either be used to defragment\ntables, or to update the InnoDB fulltext index.\n\nWAIT/NOWAIT\n-----------\n\nSet the lock wait timeout. See WAIT and NOWAIT.\n\nDefragmenting\n-------------\n\nOPTIMIZE TABLE works for InnoDB (before MariaDB 10.1.1, only if the\ninnodb_file_per_table server system variable is set), Aria, MyISAM and ARCHIVE\ntables, and should be used if you have deleted a large part of a table or if\nyou have made many changes to a table with variable-length rows (tables that\nhave VARCHAR, VARBINARY, BLOB, or TEXT columns). Deleted rows are maintained\nin a linked list and subsequent INSERT operations reuse old row positions.\n\nThis statement requires SELECT and INSERT privileges for the table.\n\nBy default, OPTIMIZE TABLE statements are written to the binary log and will\nbe replicated. The NO_WRITE_TO_BINLOG keyword (LOCAL is an alias) will ensure\nthe statement is not written to the binary log.\n\nOPTIMIZE TABLE statements are not logged to the binary log if read_only is\nset. See also Read-Only Replicas.\n\nOPTIMIZE TABLE is also supported for partitioned tables. You can use ALTER\nTABLE ... OPTIMIZE PARTITION to optimize one or more partitions.\n\nYou can use OPTIMIZE TABLE to reclaim the unused space and to defragment the\ndata file. With other storage engines, OPTIMIZE TABLE does nothing by default,\nand returns this message: \" The storage engine for the table doesn\'t support\noptimize\". However, if the server has been started with the --skip-new option,\nOPTIMIZE TABLE is linked to ALTER TABLE, and recreates the table. This\noperation frees the unused space and updates index statistics.\n\nThe Aria storage engine supports progress reporting for this statement.\n\nIf a MyISAM table is fragmented, concurrent inserts will not be performed\nuntil an OPTIMIZE TABLE statement is executed on that table, unless the\nconcurrent_insert server system variable is set to ALWAYS.\n\nUpdating an InnoDB fulltext index\n---------------------------------\n\nWhen rows are added or deleted to an InnoDB fulltext index, the index is not\nimmediately re-organized, as this can be an expensive operation. Change\nstatistics are stored in a separate location . The fulltext index is only\nfully re-organized when an OPTIMIZE TABLE statement is run.\n\nBy default, an OPTIMIZE TABLE will defragment a table. In order to use it to\nupdate fulltext index statistics, the innodb_optimize_fulltext_only system\nvariable must be set to 1. This is intended to be a temporary setting, and\nshould be reset to 0 once the fulltext index has been re-organized.\n\nSince fulltext re-organization can take a long time, the\ninnodb_ft_num_word_optimize variable limits the re-organization to a number of\nwords (2000 by default). You can run multiple OPTIMIZE statements to fully\nre-organize the index.\n\nDefragmenting InnoDB tablespaces\n--------------------------------\n\nMariaDB 10.1.1 merged the Facebook/Kakao defragmentation patch, allowing one\nto use OPTIMIZE TABLE to defragment InnoDB tablespaces. For this functionality\nto be enabled, the innodb_defragment system variable must be enabled. No new\ntables are created and there is no need to copy data from old tables to new\ntables. Instead, this feature loads n pages (determined by\ninnodb-defragment-n-pages) and tries to move records so that pages would be\nfull of records and then frees pages that are fully empty after the operation.\nNote that tablespace files (including ibdata1) will not shrink as the result\nof defragmentation, but one will get better memory utilization in the InnoDB\nbuffer pool as there are fewer data pages in use.\n\nSee Defragmenting InnoDB Tablespaces for more details.\n\nURL: https://mariadb.com/kb/en/optimize-table/','','https://mariadb.com/kb/en/optimize-table/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (250,21,'REPAIR TABLE','Syntax\n------\n\nREPAIR [NO_WRITE_TO_BINLOG | LOCAL] TABLE\n tbl_name [, tbl_name] ...\n [QUICK] [EXTENDED] [USE_FRM]\n\nDescription\n-----------\n\nREPAIR TABLE repairs a possibly corrupted table. By default, it has the same\neffect as\n\nmyisamchk --recover tbl_name\n\nor\n\naria_chk --recover tbl_name\n\nSee aria_chk and myisamchk for more.\n\nREPAIR TABLE works for Archive, Aria, CSV and MyISAM tables. For InnoDB, see\nrecovery modes. For CSV, see also Checking and Repairing CSV Tables. For\nArchive, this statement also improves compression. If the storage engine does\nnot support this statement, a warning is issued.\n\nThis statement requires SELECT and INSERT privileges for the table.\n\nBy default, REPAIR TABLE statements are written to the binary log and will be\nreplicated. The NO_WRITE_TO_BINLOG keyword (LOCAL is an alias) will ensure the\nstatement is not written to the binary log.\n\nFrom MariaDB 10.3.19, REPAIR TABLE statements are not logged to the binary log\nif read_only is set. See also Read-Only Replicas.\n\nWhen an index is recreated, the storage engine may use a configurable buffer\nin the process. Incrementing the buffer speeds up the index creation. Aria and\nMyISAM allocate a buffer whose size is defined by aria_sort_buffer_size or\nmyisam_sort_buffer_size, also used for ALTER TABLE.\n\nREPAIR TABLE is also supported for partitioned tables. However, the USE_FRM\noption cannot be used with this statement on a partitioned table.\n\nALTER TABLE ... REPAIR PARTITION can be used to repair one or more partitions.\n\nThe Aria storage engine supports progress reporting for this statement.\n\nURL: https://mariadb.com/kb/en/repair-table/','','https://mariadb.com/kb/en/repair-table/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (251,21,'REPAIR VIEW','Syntax\n------\n\nREPAIR [NO_WRITE_TO_BINLOG | LOCAL] VIEW view_name[, view_name] ... [FROM\nMYSQL]\n\nDescription\n-----------\n\nThe REPAIR VIEW statement was introduced to assist with fixing MDEV-6916, an\nissue introduced in MariaDB 5.2 where the view algorithms were swapped\ncompared to their MySQL on disk representation. It checks whether the view\nalgorithm is correct. It is run as part of mariadb-upgrade, and should not\nnormally be required in regular use.\n\nBy default it corrects the checksum and if necessary adds the mariadb-version\nfield. If the optional FROM MYSQL clause is used, and no mariadb-version field\nis present, the MERGE and TEMPTABLE algorithms are toggled.\n\nBy default, REPAIR VIEW statements are written to the binary log and will be\nreplicated. The NO_WRITE_TO_BINLOG keyword (LOCAL is an alias) will ensure the\nstatement is not written to the binary log.\n\nURL: https://mariadb.com/kb/en/repair-view/','','https://mariadb.com/kb/en/repair-view/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (252,22,'mysql.func Table','The mysql.func table stores information about user-defined functions (UDFs)\ncreated with the CREATE FUNCTION UDF statement.\n\nMariaDB starting with 10.4\n--------------------------\nIn MariaDB 10.4 and later, this table uses the Aria storage engine.\n\nMariaDB until 10.3\n------------------\nIn MariaDB 10.3 and before, this table uses the MyISAM storage engine.\n\nThe mysql.func table contains the following fields:\n\n+----------+---------+---------+-------+--------------+---------------------+\n| Field | Type | Null | Key | Default | Description |\n+----------+---------+---------+-------+--------------+---------------------+\n| name | char(64 | NO | PRI | | UDF name |\n| | | | | | |\n+----------+---------+---------+-------+--------------+---------------------+\n| ret | tinyint | NO | | 0 | |\n| | 1) | | | | |\n+----------+---------+---------+-------+--------------+---------------------+\n| dl | char(12 | NO | | | Shared library name |\n| | ) | | | | |\n+----------+---------+---------+-------+--------------+---------------------+\n| type | enum(\'f | NO | | NULL | Type, either |\n| | nction\' | | | | function or |\n| | \'aggreg | | | | aggregate. |\n| | te\') | | | | Aggregate |\n| | | | | | functions are |\n| | | | | | summary functions |\n| | | | | | such as SUM() and |\n| | | | | | AVG(). |\n+----------+---------+---------+-------+--------------+---------------------+\n\nExample\n-------\n\nSELECT * FROM mysql.func;\n+------------------------------+-----+--------------+-----------+\n| name | ret | dl | type |\n+------------------------------+-----+--------------+-----------+\n| spider_direct_sql | 2 | ha_spider.so | function |\n| spider_bg_direct_sql | 2 | ha_spider.so | aggregate |\n| spider_ping_table | 2 | ha_spider.so | function |\n| spider_copy_tables | 2 | ha_spider.so | function |\n| spider_flush_table_mon_cache | 2 | ha_spider.so | function |\n+------------------------------+-----+--------------+-----------+\n\nURL: https://mariadb.com/kb/en/mysqlfunc-table/','','https://mariadb.com/kb/en/mysqlfunc-table/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (253,22,'CREATE FUNCTION UDF','Syntax\n------\n\nCREATE [OR REPLACE] [AGGREGATE] FUNCTION [IF NOT EXISTS] function_name\n RETURNS {STRING|INTEGER|REAL|DECIMAL}\n SONAME shared_library_name\n\nDescription\n-----------\n\nA user-defined function (UDF) is a way to extend MariaDB with a new function\nthat works like a native (built-in) MariaDB function such as ABS() or CONCAT().\n\nfunction_name is the name that should be used in SQL statements to invoke the\nfunction.\n\nTo create a function, you must have the INSERT privilege for the mysql\ndatabase. This is necessary becauseCREATE FUNCTION adds a row to the\nmysql.func system table that records the function\'s name, type, and shared\nlibrary name. If you do not have this table, you should run the\nmariadb-upgrade command to create it.\n\nUDFs need to be written in C, C++ or another language that uses C calling\nconventions, MariaDB needs to have been dynamically compiled, and your\noperating system must support dynamic loading.\n\nFor an example, see sql/udf_example.cc in the source tree. For a collection of\nexisting UDFs see http://www.mysqludf.org/.\n\nStatements making use of user-defined functions are not safe for replication.\n\nFor creating a stored function as opposed to a user-defined function, see\nCREATE FUNCTION.\n\nFor valid identifiers to use as function names, see Identifier Names.\n\nRETURNS\n-------\n\nThe RETURNS clause indicates the type of the function\'s return value, and can\nbe one of STRING, INTEGER, REAL or DECIMAL. DECIMAL functions currently return\nstring values and should be written like STRING functions.\n\nshared_library_name\n-------------------\n\nshared_library_name is the basename of the shared object file that contains\nthe code that implements the function. The file must be located in the plugin\ndirectory. This directory is given by the value of the plugin_dir system\nvariable. Note that before MariaDB/MySQL 5.1, the shared object could be\nlocated in any directory that was searched by your system\'s dynamic linker.\n\nAGGREGATE\n---------\n\nAggregate functions are summary functions such as SUM() and AVG().\n\nMariaDB starting with 10.4\n--------------------------\nAggregate UDF functions can be used as window functions.\n\nOR REPLACE\n----------\n\nMariaDB starting with 10.1.3\n----------------------------\nThe OR REPLACE clause was added in MariaDB 10.1.3\n\nIf the optional OR REPLACE clause is used, it acts as a shortcut for:\n\nDROP FUNCTION IF EXISTS function_name;\nCREATE FUNCTION name ...;\n\nIF NOT EXISTS\n-------------\n\nMariaDB starting with 10.1.3\n----------------------------\nThe IF NOT EXISTS clause was added in MariaDB 10.1.3\n\nWhen the IF NOT EXISTS clause is used, MariaDB will return a warning instead\nof an error if the specified function already exists. Cannot be used together\nwith OR REPLACE.\n\nUpgrading a UDF\n---------------\n\nTo upgrade the UDF\'s shared library, first run a DROP FUNCTION statement, then\nupgrade the shared library and finally run the CREATE FUNCTION statement. If\nyou upgrade without following this process, you may crash the server.\n\nExamples\n--------\n\nCREATE FUNCTION jsoncontains_path RETURNS integer SONAME \'ha_connect.so\';\nQuery OK, 0 rows affected (0.00 sec)\n\nOR REPLACE and IF NOT EXISTS:\n\nCREATE FUNCTION jsoncontains_path RETURNS integer SONAME \'ha_connect.so\';\nERROR 1125 (HY000): Function \'jsoncontains_path\' already exists\n\nCREATE OR REPLACE FUNCTION jsoncontains_path RETURNS integer SONAME\n\'ha_connect.so\';\nQuery OK, 0 rows affected (0.00 sec)\n\nCREATE FUNCTION IF NOT EXISTS jsoncontains_path RETURNS integer SONAME\n\'ha_connect.so\';\nQuery OK, 0 rows affected, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+-------+------+---------------------------------------------+\n| Level | Code | Message |\n+-------+------+---------------------------------------------+\n| Note | 1125 | Function \'jsoncontains_path\' already exists |\n+-------+------+---------------------------------------------+\n\nURL: https://mariadb.com/kb/en/create-function-udf/','','https://mariadb.com/kb/en/create-function-udf/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (254,22,'DROP FUNCTION UDF','Syntax\n------\n\nDROP FUNCTION [IF EXISTS] function_name\n\nDescription\n-----------\n\nThis statement drops the user-defined function (UDF) named function_name.\n\nTo drop a function, you must have the DELETE privilege for the mysql database.\nThis is because DROP FUNCTION removes the row from the mysql.func system table\nthat records the function\'s name, type and shared library name.\n\nFor dropping a stored function, see DROP FUNCTION.\n\nUpgrading a UDF\n---------------\n\nTo upgrade the UDF\'s shared library, first run a DROP FUNCTION statement, then\nupgrade the shared library and finally run the CREATE FUNCTION statement. If\nyou upgrade without following this process, you may crash the server.\n\nExamples\n--------\n\nDROP FUNCTION jsoncontains_path;\n\nIF EXISTS:\n\nDROP FUNCTION jsoncontains_path;\nERROR 1305 (42000): FUNCTION test.jsoncontains_path does not exist\n\nDROP FUNCTION IF EXISTS jsoncontains_path;\nQuery OK, 0 rows affected, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+-------+------+------------------------------------------------+\n| Level | Code | Message |\n+-------+------+------------------------------------------------+\n| Note | 1305 | FUNCTION test.jsoncontains_path does not exist |\n+-------+------+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/drop-function-udf/','','https://mariadb.com/kb/en/drop-function-udf/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (255,22,'Creating User-Defined Functions','User-defined functions allow MariaDB to be extended with a new function that\nworks like a native (built-in) MariaDB function such as ABS() or CONCAT().\nThere are alternative ways to add a new function: writing a native function\n(which requires modifying and compiling the server source code), or writing a\nstored function.\n\nStatements making use of user-defined functions are not safe for replication.\n\nFunctions are written in C or C++, and to make use of them, the operating\nsystem must support dynamic loading.\n\nEach new SQL function requires corresponding functions written in C/C++. In\nthe list below, at least the main function - x() - and one other, are\nrequired. x should be replaced by the name of the function you are creating.\n\nAll functions need to be thread-safe, so not global or static variables that\nchange can be allocated. Memory is allocated in x_init()/ and freed in\nx_deinit().\n\nSimple Functions\n----------------\n\nx()\n---\n\nRequired for all UDFs; this is where the results are calculated.\n\n+------------------------------------------+----------------------------------+\n| C/C++ type | SQL type |\n+------------------------------------------+----------------------------------+\n| char * | STRING |\n+------------------------------------------+----------------------------------+\n| long long | INTEGER |\n+------------------------------------------+----------------------------------+\n| double | REAL |\n+------------------------------------------+----------------------------------+\n\nDECIMAL functions return string values, and so should be written accordingly.\nIt is not possible to create ROW functions.\n\nx_init()\n--------\n\nInitialization function for x(). Can be used for the following:\n\n* Check the number of arguments to X() (the SQL equivalent).\n* Verify the argument types, or to force arguments to be of a particular type\nafter the function is called.\n* Specify whether the result can be NULL.\n* Specify the maximum result length.\n* For REAL functions, specify the maximum number of decimals for the result.\n* Allocate any required memory.\n\nx_deinit()\n----------\n\nDe-initialization function for x(). Used to de-allocate memory that was\nallocated in x_init().\n\nDescription\n-----------\n\nEach time the SQL function X() is called:\n\n* MariaDB will first call the C/C++ initialization function, x_init(),\nassuming it exists. All setup will be performed, and if it returns an error,\nthe SQL statement is aborted and no further functions are called.\n* If there is no x_init() function, or it has been called and did not return\nan error, x() is then called once per row.\n* After all rows have finished processing, x_deinit() is called, if present,\nto clean up by de-allocating any memory that was allocated in x_init().\n* See User-defined Functions Calling Sequences for more details on the\nfunctions.\n\nAggregate Functions\n-------------------\n\nThe following functions are required for aggregate functions, such as AVG()\nand SUM(). When using CREATE FUNCTION, the AGGREGATE keyword is required.\n\nx_clear()\n---------\n\nUsed to reset the current aggregate, but without inserting the argument as the\ninitial aggregate value for the new group.\n\nx_add()\n-------\n\nUsed to add the argument to the current aggregate.\n\nx_remove()\n----------\n\nStarting from MariaDB 10.4, improves the support of window functions (so it is\nnot obligatory to add it) and should remove the argument from the current\naggregate.\n\nDescription\n-----------\n\nEach time the aggregate SQL function X() is called:\n\n* MariaDB will first call the C/C++ initialization function, x_init(),\nassuming it exists. All setup will be performed, and if it returns an error,\nthe SQL statement is aborted and no further functions are called.\n* If there is no x_init() function, or it has been called and did not return\nan error, x() is then called once per row.\n* After all rows have finished processing, x_deinit() is called, if present,\nto clean up by de-allocating any memory that was allocated in x_init().\n\n* MariaDB will first call the C/C++ initialization function, x_init(),\nassuming it exists. All setup will be performed, and if it returns an error,\nthe SQL statement is aborted and no further functions are called.\n* The table is sorted according to the GROUP BY expression.\n* x_clear() is called for the first row of each new group.\n* x_add() is called once per row for each row in the same group.\n* x() is called when the group changes, or after the last row, to get the\naggregate result. \n* The latter three steps are repeated until all rows have been processed.\n* After all rows have finished processing, x_deinit() is called, if present,\nto clean up by de-allocating any memory that was allocated in x_init().\n\nExamples\n--------\n\nFor an example, see sql/udf_example.cc in the source tree. For a collection of\nexisting UDFs see https://github.com/mysqludf.\n\nURL: https://mariadb.com/kb/en/creating-user-defined-functions/','','https://mariadb.com/kb/en/creating-user-defined-functions/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (256,22,'User-Defined Functions Calling Sequences','The functions described in Creating User-defined Functions are expanded on\nthis page. They are declared as follows:\n\nSimple Functions\n----------------\n\nx()\n---\n\nIf x() returns an integer, it is declared as follows:\n\nlong long x(UDF_INIT *initid, UDF_ARGS *args,\n char *is_null, char *error);\n\nIf x() returns a string (DECIMAL functions also return string values), it is\ndeclared as follows:\n\nchar *x(UDF_INIT *initid, UDF_ARGS *args,\n char *result, unsigned long *length,\n char *is_null, char *error);\n\nIf x() returns a real, it is declared as follows:\n\ndouble x(UDF_INIT *initid, UDF_ARGS *args,\n char *is_null, char *error);\n\nx_init()\n--------\n\nmy_bool x_init(UDF_INIT *initid, UDF_ARGS *args, char *message);\n\nx_deinit()\n----------\n\nvoid x_deinit(UDF_INIT *initid);\n\nDescription\n-----------\n\ninitid is a parameter passed to all three functions that points to a UDF_INIT\nstructure, used for communicating information between the functions. Its\nstructure members are:\n\n* my_bool maybe_null\nmaybe_null should be set to 1 if x_init can return a NULL value, Defaults to 1\nif any arguments are declared maybe_null.\n\n* unsigned int decimals\nNumber of decimals after the decimal point. The default, if an explicit number\nof decimals is passed in the arguments to the main function, is the maximum\nnumber of decimals, so if 9.5, 9.55 and 9.555 are passed to the function, the\ndefault would be three (based on 9.555, the maximum). If there are no\nexplicit number of decimals, the default is set to 31, or one more than the\nmaximum for the DOUBLE, FLOAT and DECIMAL types. This default can be changed\nin the function to suit the actual calculation.\n\n* unsigned int max_length\nMaximum length of the result. For integers, the default is 21. For strings,\nthe length of the longest argument. For reals, the default is 13 plus the\nnumber of decimals indicated by initid->decimals. The length includes any\nsigns or decimal points. Can also be set to 65KB or 16MB in order to return a\nBLOB. The memory remains unallocated, but this is used to decide on the data\ntype to use if the data needs to be temporarily stored.\n\n* char *ptr\nA pointer for use as required by the function. Commonly, initid->ptr is used\nto communicate allocated memory, with x_init() allocating the memory and\nassigning it to this pointer, x() using it, and x_deinit() de-allocating it.\n\n* my_bool const_item\nShould be set to 1 in x_init() if x() always returns the same value, otherwise\n0.\n\nAggregate Functions\n-------------------\n\nx_clear()\n---------\n\nx_clear() is a required function for aggregate functions, and is declared as\nfollows:\n\nvoid x_clear(UDF_INIT *initid, char *is_null, char *error);\n\nIt is called when the summary results need to be reset, that is at the\nbeginning of each new group. but also to reset the values when there were no\nmatching rows.\n\nis_null is set to point to CHAR(0) before calling x_clear().\n\nIn the case of an error, you can store the value to which the error argument\npoints (a single-byte variable, not a string string buffer) in the variable.\n\nx_reset()\n---------\n\nx_reset() is declared as follows:\n\nvoid x_reset(UDF_INIT *initid, UDF_ARGS *args,\n char *is_null, char *error);\n\nIt is called on finding the first row in a new group. Should reset the summary\nvariables, and then use UDF_ARGS as the first value in the group\'s internal\nsummary value. The function is not required if the UDF interface uses\nx_clear().\n\nx_add()\n-------\n\nx_add() is declared as follows:\n\nvoid x_add(UDF_INIT *initid, UDF_ARGS *args,\n char *is_null, char *error);\n\nIt is called for all rows belonging to the same group, and should be used to\nadd the value in UDF_ARGS to the internal summary variable.\n\nx_remove()\n----------\n\nx_remove() was added in MariaDB 10.4 and is declared as follows (same as\nx_add()):\n\nvoid x_remove(UDF_INIT* initid, UDF_ARGS* args,\n char* is_null, char *error );\n\nIt adds more efficient support of aggregate UDFs as window functions.\nx_remove() should \"subtract\" the row (reverse x_add()). In MariaDB 10.4\naggregate UDFs will work as WINDOW functions without x_remove() but it will\nnot be so efficient.\n\nIf x_remove() supported (defined) detected automatically.\n\nURL: https://mariadb.com/kb/en/user-defined-functions-calling-sequences/','','https://mariadb.com/kb/en/user-defined-functions-calling-sequences/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (257,22,'User-Defined Functions Security','The MariaDB server imposes a number of limitations on user-defined functions\nfor security purposes.\n\n* The INSERT privilege for the mysql database is required to run CREATE\nFUNCTION, as a record will be added to the mysql.func-table.\n* The DELETE privilege for the mysql database is required to run DROP FUNCTION\nas the corresponding record will be removed from the mysql.func-table.\n* UDF object files can only be placed in the plugin directory, as specified by\nthe value of the plugin_dir system variable.\n* At least one symbol, beyond the required x() - corresponding to an SQL\nfunction X()) - is required. These can be x_init(), x_deinit(), xxx_reset(),\nx_clear() and x_add() functions (see Creating User-defined Functions). The\nallow-suspicious-udfs mysqld option (by default unset) provides a workaround,\npermitting only one symbol to be used. This is not recommended, as it opens\nthe possibility of loading shared objects that are not legitimate user-defined\nfunctions.\n\nURL: https://mariadb.com/kb/en/user-defined-functions-security/','','https://mariadb.com/kb/en/user-defined-functions-security/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (258,23,'Numeric Data Type Overview','There are a number of numeric data types:\n\n* TINYINT\n* BOOLEAN - Synonym for TINYINT(1)\n* INT1 - Synonym for TINYINT\n* SMALLINT\n* INT2 - Synonym for SMALLINT\n* MEDIUMINT\n* INT3 - Synonym for MEDIUMINT\n* INT, INTEGER\n* INT4 - Synonym for INT\n* BIGINT\n* INT8 - Synonym for BIGINT\n* DECIMAL, DEC, NUMERIC, FIXED\n* FLOAT\n* DOUBLE, DOUBLE PRECISION, REAL\n* BIT\n\nSee the specific articles for detailed information on each.\n\nSIGNED, UNSIGNED and ZEROFILL\n-----------------------------\n\nMost numeric types can be defined as SIGNED, UNSIGNED or ZEROFILL, for example:\n\nTINYINT[(M)] [SIGNED | UNSIGNED | ZEROFILL]\n\nIf SIGNED, or no attribute, is specified, a portion of the numeric type will\nbe reserved for the sign (plus or minus). For example, a TINYINT SIGNED can\nrange from -128 to 127.\n\nIf UNSIGNED is specified, no portion of the numeric type is reserved for the\nsign, so for integer types range can be larger. For example, a TINYINT\nUNSIGNED can range from 0 to 255. Floating point and fixed-point types also\ncan be UNSIGNED, but this only prevents negative values from being stored and\ndoesn\'t alter the range.\n\nIf ZEROFILL is specified, the column will be set to UNSIGNED and the spaces\nused by default to pad the field are replaced with zeros. ZEROFILL is ignored\nin expressions or as part of a UNION. ZEROFILL is a non-standard MySQL and\nMariaDB enhancement.\n\nNote that although the preferred syntax indicates that the attributes are\nexclusive, more than one attribute can be specified.\n\nUntil MariaDB 10.2.7 (MDEV-8659), any combination of the attributes could be\nused in any order, with duplicates. In this case:\n\n* the presence of ZEROFILL makes the column UNSIGNED ZEROFILL.\n* the presence of UNSIGNED makes the column UNSIGNED.\n\nFrom MariaDB 10.2.8, only the following combinations are supported:\n\n* SIGNED\n* UNSIGNED\n* ZEROFILL\n* UNSIGNED ZEROFILL\n* ZEROFILL UNSIGNED\n\nThe latter two should be replaced with simply ZEROFILL, but are still accepted\nby the parser.\n\nExamples\n--------\n\nCREATE TABLE zf (\n i1 TINYINT SIGNED,\n i2 TINYINT UNSIGNED,\n i3 TINYINT ZEROFILL\n);\n\nINSERT INTO zf VALUES (2,2,2);\n\nSELECT * FROM zf;\n+------+------+------+\n| i1 | i2 | i3 |\n+------+------+------+\n| 2 | 2 | 002 |\n+------+------+------+\n\nRange\n-----\n\nWhen attempting to add a value that is out of the valid range for the numeric\ntype, MariaDB will react depending on the strict SQL_MODE setting.\n\nIf strict_mode has been set (the default from MariaDB 10.2.4), MariaDB will\nreturn an error.\n\nIf strict_mode has not been set (the default until MariaDB 10.2.3), MariaDB\nwill adjust the number to fit in the field, returning a warning.\n\nExamples\n--------\n\nWith strict_mode set:\n\nSHOW VARIABLES LIKE \'sql_mode\';\n+---------------+--------------------------------------------------------------\n----------------------------+\n| Variable_name | Value \n |\n+---------------+--------------------------------------------------------------\n----------------------------+\n| sql_mode |\nSTRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SU\nSTITUTION |\n+---------------+--------------------------------------------------------------\n----------------------------+\n\nCREATE TABLE ranges (i1 TINYINT, i2 SMALLINT, i3 TINYINT UNSIGNED);\n\nINSERT INTO ranges VALUES (257,257,257);\nERROR 1264 (22003): Out of range value for column \'i1\' at row 1\n\nSELECT * FROM ranges;\nEmpty set (0.10 sec)\n\nWith strict_mode unset:\n\nSHOW VARIABLES LIKE \'sql_mode%\';\n+---------------+-------+\n| Variable_name | Value |\n+---------------+-------+\n| sql_mode | |\n+---------------+-------+\n\nCREATE TABLE ranges (i1 TINYINT, i2 SMALLINT, i3 TINYINT UNSIGNED);\n\nINSERT INTO ranges VALUES (257,257,257);\nQuery OK, 1 row affected, 2 warnings (0.00 sec)\n\nSHOW WARNINGS;\n+---------+------+---------------------------------------------+\n| Level | Code | Message |\n+---------+------+---------------------------------------------+\n| Warning | 1264 | Out of range value for column \'i1\' at row 1 |\n| Warning | 1264 | Out of range value for column \'i3\' at row 1 |\n+---------+------+---------------------------------------------+\n2 rows in set (0.00 sec)\n\nSELECT * FROM ranges;\n+------+------+------+\n| i1 | i2 | i3 |\n+------+------+------+\n| 127 | 257 | 255 |\n+------+------+------+\n\nAuto_increment\n--------------\n\nThe AUTO_INCREMENT attribute can be used to generate a unique identity for new\nrows. For more details, see auto_increment.\n\nURL: https://mariadb.com/kb/en/numeric-data-type-overview/','','https://mariadb.com/kb/en/numeric-data-type-overview/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (259,23,'TINYINT','Syntax\n------\n\nTINYINT[(M)] [SIGNED | UNSIGNED | ZEROFILL]\n\nDescription\n-----------\n\nA very small integer. The signed range is -128 to 127. The unsigned range is 0\nto 255. For details on the attributes, see Numeric Data Type Overview.\n\nINT1 is a synonym for TINYINT. BOOL and BOOLEAN are synonyms for TINYINT(1).\n\nExamples\n--------\n\nCREATE TABLE tinyints (a TINYINT,b TINYINT UNSIGNED,c TINYINT ZEROFILL);\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO tinyints VALUES (-10,-10,-10);\nERROR 1264 (22003): Out of range value for column \'b\' at row 1\n\nINSERT INTO tinyints VALUES (-10,10,-10);\nERROR 1264 (22003): Out of range value for column \'c\' at row 1\n\nINSERT INTO tinyints VALUES (-10,10,10);\n\nSELECT * FROM tinyints;\n+------+------+------+\n| a | b | c |\n+------+------+------+\n| -10 | 10 | 010 |\n+------+------+------+\n\nINSERT INTO tinyints VALUES (128,128,128);\nERROR 1264 (22003): Out of range value for column \'a\' at row 1\n\nINSERT INTO tinyints VALUES (127,128,128);\n\nSELECT * FROM tinyints;\n+------+------+------+\n| a | b | c |\n+------+------+------+\n| -10 | 10 | 010 |\n| 127 | 128 | 128 |\n+------+------+------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nINSERT INTO tinyints VALUES (-10,-10,-10);\nQuery OK, 1 row affected, 2 warnings (0.08 sec)\nWarning (Code 1264): Out of range value for column \'b\' at row 1\nWarning (Code 1264): Out of range value for column \'c\' at row 1\n\nINSERT INTO tinyints VALUES (-10,10,-10);\nQuery OK, 1 row affected, 1 warning (0.11 sec)\nWarning (Code 1264): Out of range value for column \'c\' at row 1\n\nINSERT INTO tinyints VALUES (-10,10,10);\n\nSELECT * FROM tinyints;\n+------+------+------+\n| a | b | c |\n+------+------+------+\n| -10 | 0 | 000 |\n| -10 | 10 | 000 |\n| -10 | 10 | 010 |\n+------+------+------+\n\nINSERT INTO tinyints VALUES (128,128,128);\nQuery OK, 1 row affected, 1 warning (0.19 sec)\nWarning (Code 1264): Out of range value for column \'a\' at row 1\n\nINSERT INTO tinyints VALUES (127,128,128);\n\nSELECT * FROM tinyints;\n+------+------+------+\n| a | b | c |\n+------+------+------+\n| -10 | 0 | 000 |\n| -10 | 10 | 000 |\n| -10 | 10 | 010 |\n| 127 | 128 | 128 |\n| 127 | 128 | 128 |\n+------+------+------+\n\nURL: https://mariadb.com/kb/en/tinyint/','','https://mariadb.com/kb/en/tinyint/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (260,23,'BOOLEAN','Syntax\n------\n\nBOOL, BOOLEAN\n\nDescription\n-----------\n\nThese types are synonyms for TINYINT(1). A value of zero is considered false.\nNon-zero values are considered true.\n\nHowever, the values TRUE and FALSE are merely aliases for 1 and 0. See Boolean\nLiterals, as well as the IS operator for testing values against a boolean.\n\nExamples\n--------\n\nCREATE TABLE boo (i BOOLEAN);\n\nDESC boo;\n+-------+------------+------+-----+---------+-------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+------------+------+-----+---------+-------+\n| i | tinyint(1) | YES | | NULL | |\n+-------+------------+------+-----+---------+-------+\n\nSELECT IF(0, \'true\', \'false\');\n+------------------------+\n| IF(0, \'true\', \'false\') |\n+------------------------+\n| false |\n+------------------------+\n\nSELECT IF(1, \'true\', \'false\');\n+------------------------+\n| IF(1, \'true\', \'false\') |\n+------------------------+\n| true |\n+------------------------+\n\nSELECT IF(2, \'true\', \'false\');\n+------------------------+\n| IF(2, \'true\', \'false\') |\n+------------------------+\n| true |\n+------------------------+\n\nTRUE and FALSE as aliases for 1 and 0:\n\nSELECT IF(0 = FALSE, \'true\', \'false\');\n\n+--------------------------------+\n| IF(0 = FALSE, \'true\', \'false\') |\n+--------------------------------+\n| true |\n+--------------------------------+\n\nSELECT IF(1 = TRUE, \'true\', \'false\');\n+-------------------------------+\n| IF(1 = TRUE, \'true\', \'false\') |\n+-------------------------------+\n| true |\n+-------------------------------+\n\nSELECT IF(2 = TRUE, \'true\', \'false\');\n+-------------------------------+\n| IF(2 = TRUE, \'true\', \'false\') |\n+-------------------------------+\n| false |\n+-------------------------------+\n\nSELECT IF(2 = FALSE, \'true\', \'false\');\n+--------------------------------+\n| IF(2 = FALSE, \'true\', \'false\') |\n+--------------------------------+\n| false |\n+--------------------------------+\n\nThe last two statements display the results shown because 2 is equal to\nneither 1 nor 0.\n\nURL: https://mariadb.com/kb/en/boolean/','','https://mariadb.com/kb/en/boolean/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (261,23,'SMALLINT','Syntax\n------\n\nSMALLINT[(M)] [SIGNED | UNSIGNED | ZEROFILL]\n\nDescription\n-----------\n\nA small integer. The signed range is -32768 to 32767. The unsigned range is 0\nto 65535.\n\nIf a column has been set to ZEROFILL, all values will be prepended by zeros so\nthat the SMALLINT value contains a number of M digits.\n\nNote: If the ZEROFILL attribute has been specified, the column will\nautomatically become UNSIGNED.\n\nINT2 is a synonym for SMALLINT.\n\nFor more details on the attributes, see Numeric Data Type Overview.\n\nExamples\n--------\n\nCREATE TABLE smallints (a SMALLINT,b SMALLINT UNSIGNED,c SMALLINT ZEROFILL);\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO smallints VALUES (-10,-10,-10);\nERROR 1264 (22003): Out of range value for column \'b\' at row 1\n\nINSERT INTO smallints VALUES (-10,10,-10);\nERROR 1264 (22003): Out of range value for column \'c\' at row 1\n\nINSERT INTO smallints VALUES (-10,10,10);\n\nINSERT INTO smallints VALUES (32768,32768,32768);\nERROR 1264 (22003): Out of range value for column \'a\' at row 1\n\nINSERT INTO smallints VALUES (32767,32768,32768);\n\nSELECT * FROM smallints;\n+-------+-------+-------+\n| a | b | c |\n+-------+-------+-------+\n| -10 | 10 | 00010 |\n| 32767 | 32768 | 32768 |\n+-------+-------+-------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nINSERT INTO smallints VALUES (-10,-10,-10);\nQuery OK, 1 row affected, 2 warnings (0.09 sec)\nWarning (Code 1264): Out of range value for column \'b\' at row 1\nWarning (Code 1264): Out of range value for column \'c\' at row 1\n\nINSERT INTO smallints VALUES (-10,10,-10);\nQuery OK, 1 row affected, 1 warning (0.08 sec)\nWarning (Code 1264): Out of range value for column \'c\' at row 1\n\nINSERT INTO smallints VALUES (-10,10,10);\n\nINSERT INTO smallints VALUES (32768,32768,32768);\nQuery OK, 1 row affected, 1 warning (0.04 sec)\nWarning (Code 1264): Out of range value for column \'a\' at row 1\n\nINSERT INTO smallints VALUES (32767,32768,32768);\n\nSELECT * FROM smallints;\n+-------+-------+-------+\n| a | b | c |\n+-------+-------+-------+\n| -10 | 0 | 00000 |\n| -10 | 10 | 00000 |\n| -10 | 10 | 00010 |\n| 32767 | 32768 | 32768 |\n| 32767 | 32768 | 32768 |\n+-------+-------+-------+\n\nURL: https://mariadb.com/kb/en/smallint/','','https://mariadb.com/kb/en/smallint/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (262,23,'MEDIUMINT','Syntax\n------\n\nMEDIUMINT[(M)] [SIGNED | UNSIGNED | ZEROFILL]\n\nDescription\n-----------\n\nA medium-sized integer. The signed range is -8388608 to 8388607. The unsigned\nrange is 0 to 16777215.\n\nZEROFILL pads the integer with zeroes and assumes UNSIGNED (even if UNSIGNED\nis not specified).\n\nINT3 is a synonym for MEDIUMINT.\n\nFor details on the attributes, see Numeric Data Type Overview.\n\nExamples\n--------\n\nCREATE TABLE mediumints (a MEDIUMINT,b MEDIUMINT UNSIGNED,c MEDIUMINT\nZEROFILL);\n\nDESCRIBE mediumints;\n+-------+--------------------------------+------+-----+---------+-------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+--------------------------------+------+-----+---------+-------+\n| a | mediumint(9) | YES | | NULL | |\n| b | mediumint(8) unsigned | YES | | NULL | |\n| c | mediumint(8) unsigned zerofill | YES | | NULL | |\n+-------+--------------------------------+------+-----+---------+-------+\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO mediumints VALUES (-10,-10,-10);\nERROR 1264 (22003): Out of range value for column \'b\' at row 1\n\nINSERT INTO mediumints VALUES (-10,10,-10);\nERROR 1264 (22003): Out of range value for column \'c\' at row 1\n\nINSERT INTO mediumints VALUES (-10,10,10);\n\nINSERT INTO mediumints VALUES (8388608,8388608,8388608);\nERROR 1264 (22003): Out of range value for column \'a\' at row 1\n\nINSERT INTO mediumints VALUES (8388607,8388608,8388608);\n\nSELECT * FROM mediumints;\n+---------+---------+----------+\n| a | b | c |\n+---------+---------+----------+\n| -10 | 10 | 00000010 |\n| 8388607 | 8388608 | 08388608 |\n+---------+---------+----------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nINSERT INTO mediumints VALUES (-10,-10,-10);\nQuery OK, 1 row affected, 2 warnings (0.05 sec)\nWarning (Code 1264): Out of range value for column \'b\' at row 1\nWarning (Code 1264): Out of range value for column \'c\' at row 1\n\nINSERT INTO mediumints VALUES (-10,10,-10);\nQuery OK, 1 row affected, 1 warning (0.08 sec)\nWarning (Code 1264): Out of range value for column \'c\' at row 1\n\nINSERT INTO mediumints VALUES (-10,10,10);\n\nINSERT INTO mediumints VALUES (8388608,8388608,8388608);\nQuery OK, 1 row affected, 1 warning (0.05 sec)\nWarning (Code 1264): Out of range value for column \'a\' at row 1\n\nINSERT INTO mediumints VALUES (8388607,8388608,8388608);\n\nSELECT * FROM mediumints;\n+---------+---------+----------+\n| a | b | c |\n+---------+---------+----------+\n| -10 | 0 | 00000000 |\n| -10 | 0 | 00000000 |\n| -10 | 10 | 00000000 |\n| -10 | 10 | 00000010 |\n| 8388607 | 8388608 | 08388608 |\n| 8388607 | 8388608 | 08388608 |\n+---------+---------+----------+\n\nURL: https://mariadb.com/kb/en/mediumint/','','https://mariadb.com/kb/en/mediumint/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (263,23,'INT','Syntax\n------\n\nINT[(M)] [SIGNED | UNSIGNED | ZEROFILL]\nINTEGER[(M)] [SIGNED | UNSIGNED | ZEROFILL]\n\nDescription\n-----------\n\nA normal-size integer. When marked UNSIGNED, it ranges from 0 to 4294967295,\notherwise its range is -2147483648 to 2147483647 (SIGNED is the default). If a\ncolumn has been set to ZEROFILL, all values will be prepended by zeros so that\nthe INT value contains a number of M digits. INTEGER is a synonym for INT.\n\nNote: If the ZEROFILL attribute has been specified, the column will\nautomatically become UNSIGNED.\n\nINT4 is a synonym for INT.\n\nFor details on the attributes, see Numeric Data Type Overview.\n\nExamples\n--------\n\nCREATE TABLE ints (a INT,b INT UNSIGNED,c INT ZEROFILL);\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO ints VALUES (-10,-10,-10);\nERROR 1264 (22003): Out of range value for column \'b\' at row 1\n\nINSERT INTO ints VALUES (-10,10,-10);\nERROR 1264 (22003): Out of range value for column \'c\' at row 1\n\nINSERT INTO ints VALUES (-10,10,10);\n\nINSERT INTO ints VALUES (2147483648,2147483648,2147483648);\nERROR 1264 (22003): Out of range value for column \'a\' at row 1\n\nINSERT INTO ints VALUES (2147483647,2147483648,2147483648);\n\nSELECT * FROM ints;\n+------------+------------+------------+\n| a | b | c |\n+------------+------------+------------+\n| -10 | 10 | 0000000010 |\n| 2147483647 | 2147483648 | 2147483648 |\n+------------+------------+------------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nINSERT INTO ints VALUES (-10,-10,-10);\nQuery OK, 1 row affected, 2 warnings (0.10 sec)\nWarning (Code 1264): Out of range value for column \'b\' at row 1\nWarning (Code 1264): Out of range value for column \'c\' at row 1\n\nINSERT INTO ints VALUES (-10,10,-10);\nQuery OK, 1 row affected, 1 warning (0.08 sec)\nWarning (Code 1264): Out of range value for column \'c\' at row 1\n\nINSERT INTO ints VALUES (-10,10,10);\n\nINSERT INTO ints VALUES (2147483648,2147483648,2147483648);\nQuery OK, 1 row affected, 1 warning (0.07 sec)\nWarning (Code 1264): Out of range value for column \'a\' at row 1\n\nINSERT INTO ints VALUES (2147483647,2147483648,2147483648);\n\nSELECT * FROM ints;\n+------------+------------+------------+\n| a | b | c |\n+------------+------------+------------+\n| -10 | 0 | 0000000000 |\n| -10 | 10 | 0000000000 |\n| -10 | 10 | 0000000010 |\n| 2147483647 | 2147483648 | 2147483648 |\n| 2147483647 | 2147483648 | 2147483648 |\n+------------+------------+------------+\n\nURL: https://mariadb.com/kb/en/int/','','https://mariadb.com/kb/en/int/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (264,23,'BIGINT','Syntax\n------\n\nBIGINT[(M)] [SIGNED | UNSIGNED | ZEROFILL]\n\nDescription\n-----------\n\nA large integer. The signed range is -9223372036854775808 to\n9223372036854775807. The unsigned range is 0 to 18446744073709551615.\n\nIf a column has been set to ZEROFILL, all values will be prepended by zeros so\nthat the BIGINT value contains a number of M digits.\n\nNote: If the ZEROFILL attribute has been specified, the column will\nautomatically become UNSIGNED.\n\nFor more details on the attributes, see Numeric Data Type Overview.\n\nSERIAL is an alias for:\n\nBIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE\n\nINT8 is a synonym for BIGINT.\n\nExamples\n--------\n\nCREATE TABLE bigints (a BIGINT,b BIGINT UNSIGNED,c BIGINT ZEROFILL);\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO bigints VALUES (-10,-10,-10);\nERROR 1264 (22003): Out of range value for column \'b\' at row 1\n\nINSERT INTO bigints VALUES (-10,10,-10);\nERROR 1264 (22003): Out of range value for column \'c\' at row 1\n\nINSERT INTO bigints VALUES (-10,10,10);\n\nINSERT INTO bigints VALUES\n(9223372036854775808,9223372036854775808,9223372036854775808);\nERROR 1264 (22003): Out of range value for column \'a\' at row 1\n\nINSERT INTO bigints VALUES\n(9223372036854775807,9223372036854775808,9223372036854775808);\n\nSELECT * FROM bigints;\n+---------------------+---------------------+----------------------+\n| a | b | c |\n+---------------------+---------------------+----------------------+\n| -10 | 10 | 00000000000000000010 |\n| 9223372036854775807 | 9223372036854775808 | 09223372036854775808 |\n+---------------------+---------------------+----------------------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nINSERT INTO bigints VALUES (-10,-10,-10);\nQuery OK, 1 row affected, 2 warnings (0.08 sec)\nWarning (Code 1264): Out of range value for column \'b\' at row 1\nWarning (Code 1264): Out of range value for column \'c\' at row 1\n\nINSERT INTO bigints VALUES (-10,10,-10);\nQuery OK, 1 row affected, 1 warning (0.08 sec)\nWarning (Code 1264): Out of range value for column \'c\' at row 1\n\nINSERT INTO bigints VALUES (-10,10,10);\n\nINSERT INTO bigints VALUES\n(9223372036854775808,9223372036854775808,9223372036854775808);\nQuery OK, 1 row affected, 1 warning (0.07 sec)\nWarning (Code 1264): Out of range value for column \'a\' at row 1\n\nINSERT INTO bigints VALUES\n(9223372036854775807,9223372036854775808,9223372036854775808);\n\nSELECT * FROM bigints;\n+---------------------+---------------------+----------------------+\n| a | b | c |\n+---------------------+---------------------+----------------------+\n| -10 | 0 | 00000000000000000000 |\n| -10 | 10 | 00000000000000000000 |\n| -10 | 10 | 00000000000000000010 |\n| 9223372036854775807 | 9223372036854775808 | 09223372036854775808 |\n| 9223372036854775807 | 9223372036854775808 | 09223372036854775808 |\n+---------------------+---------------------+----------------------+\n\nURL: https://mariadb.com/kb/en/bigint/','','https://mariadb.com/kb/en/bigint/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (265,23,'DECIMAL','Syntax\n------\n\nDECIMAL[(M[,D])] [SIGNED | UNSIGNED | ZEROFILL]\n\nDescription\n-----------\n\nA packed \"exact\" fixed-point number. M is the total number of digits (the\nprecision) and D is the number of digits after the decimal point (the scale).\n\n* The decimal point and (for negative numbers) the \"-\" sign are not\ncounted in M. \n* If D is 0, values have no decimal point or fractional\npart and on INSERT the value will be rounded to the nearest DECIMAL. \n* The maximum number of digits (M) for DECIMAL is 65. \n* The maximum number of supported decimals (D) is 30 before MariadB 10.2.1 and\n38 afterwards. \n* If D is omitted, the default is 0. If M is omitted, the default is 10.\n\nUNSIGNED, if specified, disallows negative values.\n\nZEROFILL, if specified, pads the number with zeros, up to the total number of\ndigits specified by M.\n\nAll basic calculations (+, -, *, /) with DECIMAL columns are done with a\nprecision of 65 digits.\n\nFor more details on the attributes, see Numeric Data Type Overview.\n\nDEC, NUMERIC and FIXED are synonyms, as well as NUMBER in Oracle mode from\nMariaDB 10.3.\n\nExamples\n--------\n\nCREATE TABLE t1 (d DECIMAL UNSIGNED ZEROFILL);\n\nINSERT INTO t1 VALUES (1),(2),(3),(4.0),(5.2),(5.7);\nQuery OK, 6 rows affected, 2 warnings (0.16 sec)\nRecords: 6 Duplicates: 0 Warnings: 2\n\nNote (Code 1265): Data truncated for column \'d\' at row 5\nNote (Code 1265): Data truncated for column \'d\' at row 6\n\nSELECT * FROM t1;\n+------------+\n| d |\n+------------+\n| 0000000001 |\n| 0000000002 |\n| 0000000003 |\n| 0000000004 |\n| 0000000005 |\n| 0000000006 |\n+------------+\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO t1 VALUES (-7);\nERROR 1264 (22003): Out of range value for column \'d\' at row 1\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nINSERT INTO t1 VALUES (-7);\nQuery OK, 1 row affected, 1 warning (0.02 sec)\nWarning (Code 1264): Out of range value for column \'d\' at row 1\n\nSELECT * FROM t1;\n+------------+\n| d |\n+------------+\n| 0000000001 |\n| 0000000002 |\n| 0000000003 |\n| 0000000004 |\n| 0000000005 |\n| 0000000006 |\n| 0000000000 |\n+------------+\n\nURL: https://mariadb.com/kb/en/decimal/','','https://mariadb.com/kb/en/decimal/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (266,23,'FLOAT','Syntax\n------\n\nFLOAT[(M,D)] [SIGNED | UNSIGNED | ZEROFILL]\n\nDescription\n-----------\n\nA small (single-precision) floating-point number (see DOUBLE for a\nregular-size floating point number). Allowable values are:\n\n* -3.402823466E+38 to -1.175494351E-38\n* 0\n* 1.175494351E-38 to 3.402823466E+38.\n\nThese are the theoretical limits, based on the IEEE standard. The actual range\nmight be slightly smaller depending on your hardware or operating system.\n\nM is the total number of digits and D is the number of digits following the\ndecimal point. If M and D are omitted, values are stored to the limits allowed\nby the hardware. A single-precision floating-point number is accurate to\napproximately 7 decimal places.\n\nUNSIGNED, if specified, disallows negative values.\n\nUsing FLOAT might give you some unexpected problems because all calculations\nin MariaDB are done with double precision. See Floating Point Accuracy.\n\nFor more details on the attributes, see Numeric Data Type Overview.\n\nURL: https://mariadb.com/kb/en/float/','','https://mariadb.com/kb/en/float/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (267,23,'DOUBLE','Syntax\n------\n\nDOUBLE[(M,D)] [SIGNED | UNSIGNED | ZEROFILL]\nDOUBLE PRECISION[(M,D)] [SIGNED | UNSIGNED | ZEROFILL]\nREAL[(M,D)] [SIGNED | UNSIGNED | ZEROFILL]\n\nDescription\n-----------\n\nA normal-size (double-precision) floating-point number (see FLOAT for a\nsingle-precision floating-point number).\n\nAllowable values are:\n\n* -1.7976931348623157E+308 to -2.2250738585072014E-308\n* 0\n* 2.2250738585072014E-308 to 1.7976931348623157E+308\n\nThese are the theoretical limits, based on the IEEE standard. The actual range\nmight be slightly smaller depending on your hardware or operating system.\n\nM is the total number of digits and D is the number of digits following the\ndecimal point. If M and D are omitted, values are stored to the limits allowed\nby the hardware. A double-precision floating-point number is accurate to\napproximately 15 decimal places.\n\nUNSIGNED, if specified, disallows negative values.\n\nZEROFILL, if specified, pads the number with zeros, up to the total number of\ndigits specified by M.\n\nREAL and DOUBLE PRECISION are synonyms, unless the REAL_AS_FLOAT SQL mode is\nenabled, in which case REAL is a synonym for FLOAT rather than DOUBLE.\n\nSee Floating Point Accuracy for issues when using floating-point numbers.\n\nFor more details on the attributes, see Numeric Data Type Overview.\n\nExamples\n--------\n\nCREATE TABLE t1 (d DOUBLE(5,0) zerofill);\n\nINSERT INTO t1 VALUES (1),(2),(3),(4);\n\nSELECT * FROM t1;\n+-------+\n| d |\n+-------+\n| 00001 |\n| 00002 |\n| 00003 |\n| 00004 |\n+-------+\n\nURL: https://mariadb.com/kb/en/double/','','https://mariadb.com/kb/en/double/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (268,23,'BIT','Syntax\n------\n\nBIT[(M)]\n\nDescription\n-----------\n\nA bit-field type. M indicates the number of bits per value, from 1 to 64. The\ndefault is 1 if M is omitted.\n\nBit values can be inserted with b\'value\' notation, where value is the bit\nvalue in 0\'s and 1\'s.\n\nBit fields are automatically zero-padded from the left to the full length of\nthe bit, so for example in a BIT(4) field, \'10\' is equivalent to \'0010\'.\n\nBits are returned as binary, so to display them, either add 0, or use a\nfunction such as HEX, OCT or BIN to convert them.\n\nExamples\n--------\n\nCREATE TABLE b ( b1 BIT(8) );\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO b VALUES (b\'11111111\');\n\nINSERT INTO b VALUES (b\'01010101\');\n\nINSERT INTO b VALUES (b\'1111111111111\');\nERROR 1406 (22001): Data too long for column \'b1\' at row 1\n\nSELECT b1+0, HEX(b1), OCT(b1), BIN(b1) FROM b;\n+------+---------+---------+----------+\n| b1+0 | HEX(b1) | OCT(b1) | BIN(b1) |\n+------+---------+---------+----------+\n| 255 | FF | 377 | 11111111 |\n| 85 | 55 | 125 | 1010101 |\n+------+---------+---------+----------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nINSERT INTO b VALUES (b\'11111111\'),(b\'01010101\'),(b\'1111111111111\');\nQuery OK, 3 rows affected, 1 warning (0.10 sec)\nRecords: 3 Duplicates: 0 Warnings: 1\n\nSHOW WARNINGS;\n+---------+------+---------------------------------------------+\n| Level | Code | Message |\n+---------+------+---------------------------------------------+\n| Warning | 1264 | Out of range value for column \'b1\' at row 3 |\n+---------+------+---------------------------------------------+\n\nSELECT b1+0, HEX(b1), OCT(b1), BIN(b1) FROM b;\n+------+---------+---------+----------+\n| b1+0 | HEX(b1) | OCT(b1) | BIN(b1) |\n+------+---------+---------+----------+\n| 255 | FF | 377 | 11111111 |\n| 85 | 55 | 125 | 1010101 |\n| 255 | FF | 377 | 11111111 |\n+------+---------+---------+----------+\n\nURL: https://mariadb.com/kb/en/bit/','','https://mariadb.com/kb/en/bit/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (269,23,'Floating-point Accuracy','Due to their nature, not all floating-point numbers can be stored with exact\nprecision. Hardware architecture, the CPU or even the compiler version and\noptimization level may affect the precision.\n\nIf you are comparing DOUBLEs or FLOATs with numeric decimals, it is not safe\nto use the equality operator.\n\nSometimes, changing a floating-point number from single-precision (FLOAT) to\ndouble-precision (DOUBLE) will fix the problem.\n\nExample\n-------\n\nf1, f2 and f3 have seemingly identical values across each row, but due to\nfloating point accuracy, the results may be unexpected.\n\nCREATE TABLE fpn (id INT, f1 FLOAT, f2 DOUBLE, f3 DECIMAL (10,3));\nINSERT INTO fpn VALUES (1,2,2,2),(2,0.1,0.1,0.1);\n\nSELECT * FROM fpn WHERE f1*f1 = f2*f2;\n+------+------+------+-------+\n| id | f1 | f2 | f3 |\n+------+------+------+-------+\n| 1 | 2 | 2 | 2.000 |\n+------+------+------+-------+\n\nThe reason why only one instead of two rows was returned becomes clear when we\nsee how the floating point squares were evaluated.\n\nSELECT f1*f1, f2*f2, f3*f3 FROM fpn;\n+----------------------+----------------------+----------+\n| f1*f1 | f2*f2 | f3*f3 |\n+----------------------+----------------------+----------+\n| 4 | 4 | 4.000000 |\n| 0.010000000298023226 | 0.010000000000000002 | 0.010000 |\n+----------------------+----------------------+----------+\n\nURL: https://mariadb.com/kb/en/floating-point-accuracy/','','https://mariadb.com/kb/en/floating-point-accuracy/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (270,23,'BINARY','This page describes the BINARY data type. For details about the operator, see\nBinary Operator.\n\nSyntax\n------\n\nBINARY(M)\n\nDescription\n-----------\n\nThe BINARY type is similar to the CHAR type, but stores binary byte strings\nrather than non-binary character strings. M represents the column length in\nbytes.\n\nIt contains no character set, and comparison and sorting are based on the\nnumeric value of the bytes.\n\nIf the maximum length is exceeded, and SQL strict mode is not enabled , the\nextra characters will be dropped with a warning. If strict mode is enabled, an\nerror will occur.\n\nBINARY values are right-padded with 0x00 (the zero byte) to the specified\nlength when inserted. The padding is not removed on select, so this needs to\nbe taken into account when sorting and comparing, where all bytes are\nsignificant. The zero byte, 0x00 is less than a space for comparison purposes.\n\nExamples\n--------\n\nInserting too many characters, first with strict mode off, then with it on:\n\nCREATE TABLE bins (a BINARY(10));\n\nINSERT INTO bins VALUES(\'12345678901\');\nQuery OK, 1 row affected, 1 warning (0.04 sec)\n\nSELECT * FROM bins;\n+------------+\n| a |\n+------------+\n| 1234567890 |\n+------------+\n\nSET sql_mode=\'STRICT_ALL_TABLES\';\n\nINSERT INTO bins VALUES(\'12345678901\');\nERROR 1406 (22001): Data too long for column \'a\' at row 1\n\nSorting is performed with the byte value:\n\nTRUNCATE bins;\n\nINSERT INTO bins VALUES(\'A\'),(\'B\'),(\'a\'),(\'b\');\n\nSELECT * FROM bins ORDER BY a;\n+------+\n| a |\n+------+\n| A |\n| B |\n| a |\n| b |\n+------+\n\nUsing CAST to sort as a CHAR instead:\n\nSELECT * FROM bins ORDER BY CAST(a AS CHAR);\n+------+\n| a |\n+------+\n| a |\n| A |\n| b |\n| B |\n+------+\n\nThe field is a BINARY(10), so padding of two \'\\0\'s are inserted, causing\ncomparisons that don\'t take this into account to fail:\n\nTRUNCATE bins;\n\nINSERT INTO bins VALUES(\'12345678\');\n\nSELECT a = \'12345678\', a = \'12345678\\0\\0\' from bins;\n+----------------+--------------------+\n| a = \'12345678\' | a = \'12345678\\0\\0\' |\n+----------------+--------------------+\n| 0 | 1 |\n+----------------+--------------------+\n\nURL: https://mariadb.com/kb/en/binary/','','https://mariadb.com/kb/en/binary/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (271,23,'BLOB','Syntax\n------\n\nBLOB[(M)]\n\nDescription\n-----------\n\nA BLOB column with a maximum length of 65,535 (216 - 1) bytes. Each BLOB value\nis stored using a two-byte length prefix that indicates the number of bytes in\nthe value.\n\nAn optional length M can be given for this type. If this is done, MariaDB\ncreates the column as the smallest BLOB type large enough to hold values M\nbytes long.\n\nBLOBS can also be used to store dynamic columns.\n\nBLOB and TEXT columns can both be assigned a DEFAULT value.\n\nIndexing\n--------\n\nMariaDB starting with 10.4\n--------------------------\nFrom MariaDB 10.4, it is possible to set a unique index on a column that uses\nthe BLOB data type. In previous releases this was not possible, as the index\nwould only guarantee the uniqueness of a fixed number of characters.\n\nOracle Mode\n-----------\n\nIn Oracle mode from MariaDB 10.3, BLOB is a synonym for LONGBLOB.\n\nURL: https://mariadb.com/kb/en/blob/','','https://mariadb.com/kb/en/blob/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (272,23,'BLOB and TEXT Data Types','Description\n-----------\n\nA BLOB is a binary large object that can hold a variable amount of data. The\nfour BLOB types are\n\n* TINYBLOB,\n* BLOB, \n* MEDIUMBLOB, and\n* LONGBLOB.\n\nThese differ only in the maximum length of the values they can hold.\n\nThe TEXT types are\n\n* TINYTEXT,\n* TEXT,\n* MEDIUMTEXT, and\n* LONGTEXT.\n* JSON (alias for LONGTEXT)\n\nThese correspond to the four BLOB types and have the same maximum lengths and\nstorage requirements.\n\nBLOB and TEXT columns can have a DEFAULT value.\n\nMariaDB starting with 10.4.3\n----------------------------\nFrom MariaDB 10.4, it is possible to set a unique index on columns that use\nthe BLOB or TEXT data types.\n\nURL: https://mariadb.com/kb/en/blob-and-text-data-types/','','https://mariadb.com/kb/en/blob-and-text-data-types/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (273,23,'CHAR','This article covers the CHAR data type. See CHAR Function for the function.\n\nSyntax\n------\n\n[NATIONAL] CHAR[(M)] [CHARACTER SET charset_name] [COLLATE collation_name]\n\nDescription\n-----------\n\nA fixed-length string that is always right-padded with spaces to the specified\nlength when stored. M represents the column length in characters. The range of\nM is 0 to 255. If M is omitted, the length is 1.\n\nCHAR(0) columns can contain 2 values: an empty string or NULL. Such columns\ncannot be part of an index. The CONNECT storage engine does not support\nCHAR(0).\n\nNote: Trailing spaces are removed when CHAR values are retrieved unless the\nPAD_CHAR_TO_FULL_LENGTH SQL mode is enabled.\n\nBefore MariaDB 10.2, all collations were of type PADSPACE, meaning that CHAR\n(as well as VARCHAR and TEXT) values are compared without regard for trailing\nspaces. This does not apply to the LIKE pattern-matching operator, which takes\ninto account trailing spaces.\n\nIf a unique index consists of a column where trailing pad characters are\nstripped or ignored, inserts into that column where values differ only by the\nnumber of trailing pad characters will result in a duplicate-key error.\n\nExamples\n--------\n\nTrailing spaces:\n\nCREATE TABLE strtest (c CHAR(10));\nINSERT INTO strtest VALUES(\'Maria \');\n\nSELECT c=\'Maria\',c=\'Maria \' FROM strtest;\n+-----------+--------------+\n| c=\'Maria\' | c=\'Maria \' |\n+-----------+--------------+\n| 1 | 1 |\n+-----------+--------------+\n\nSELECT c LIKE \'Maria\',c LIKE \'Maria \' FROM strtest;\n+----------------+-------------------+\n| c LIKE \'Maria\' | c LIKE \'Maria \' |\n+----------------+-------------------+\n| 1 | 0 |\n+----------------+-------------------+\n\nNO PAD Collations\n-----------------\n\nNO PAD collations regard trailing spaces as normal characters. You can get a\nlist of all NO PAD collations by querying the Information Schema Collations\ntable, for example:\n\nSELECT collation_name FROM information_schema.collations \n WHERE collation_name LIKE \"%nopad%\";\n+------------------------------+\n| collation_name |\n+------------------------------+\n| big5_chinese_nopad_ci |\n| big5_nopad_bin |\n...\n\nURL: https://mariadb.com/kb/en/char/','','https://mariadb.com/kb/en/char/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (274,23,'CHAR BYTE','Description\n-----------\n\nThe CHAR BYTE data type is an alias for the BINARY data type. This is a\ncompatibility feature.\n\nURL: https://mariadb.com/kb/en/char-byte/','','https://mariadb.com/kb/en/char-byte/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (275,23,'ENUM','Syntax\n------\n\nENUM(\'value1\',\'value2\',...) [CHARACTER SET charset_name] [COLLATE\ncollation_name]\n\nDescription\n-----------\n\nAn enumeration. A string object that can have only one value, chosen from the\nlist of values \'value1\', \'value2\', ..., NULL or the special \'\' error value. In\ntheory, an ENUM column can have a maximum of 65,535 distinct values; in\npractice, the real maximum depends on many factors. ENUM values are\nrepresented internally as integers.\n\nTrailing spaces are automatically stripped from ENUM values on table creation.\n\nENUMs require relatively little storage space compared to strings, either one\nor two bytes depending on the number of enumeration values.\n\nNULL and empty values\n---------------------\n\nAn ENUM can also contain NULL and empty values. If the ENUM column is declared\nto permit NULL values, NULL becomes a valid value, as well as the default\nvalue (see below). If strict SQL Mode is not enabled, and an invalid value is\ninserted into an ENUM, a special empty string, with an index value of zero\n(see Numeric index, below), is inserted, with a warning. This may be\nconfusing, because the empty string is also a possible value, and the only\ndifference if that is this case its index is not 0. Inserting will fail with\nan error if strict mode is active.\n\nIf a DEFAULT clause is missing, the default value will be:\n\n* NULL if the column is nullable;\n* otherwise, the first value in the enumeration.\n\nNumeric index\n-------------\n\nENUM values are indexed numerically in the order they are defined, and sorting\nwill be performed in this numeric order. We suggest not using ENUM to store\nnumerals, as there is little to no storage space benefit, and it is easy to\nconfuse the enum integer with the enum numeral value by leaving out the quotes.\n\nAn ENUM defined as ENUM(\'apple\',\'orange\',\'pear\') would have the following\nindex values:\n\n+--------------------------------------+--------------------------------------+\n| Index | Value |\n+--------------------------------------+--------------------------------------+\n| NULL | NULL |\n+--------------------------------------+--------------------------------------+\n| 0 | \'\' |\n+--------------------------------------+--------------------------------------+\n| 1 | \'apple\' |\n+--------------------------------------+--------------------------------------+\n| 2 | \'orange\' |\n+--------------------------------------+--------------------------------------+\n| 3 | \'pear\' |\n+--------------------------------------+--------------------------------------+\n\nExamples\n--------\n\nCREATE TABLE fruits (\n id INT NOT NULL auto_increment PRIMARY KEY,\n fruit ENUM(\'apple\',\'orange\',\'pear\'),\n bushels INT);\n\nDESCRIBE fruits;\n+---------+-------------------------------+------+-----+---------+-------------\n--+\n| Field | Type | Null | Key | Default | Extra \n |\n+---------+-------------------------------+------+-----+---------+-------------\n--+\n| id | int(11) | NO | PRI | NULL |\nauto_increment |\n| fruit | enum(\'apple\',\'orange\',\'pear\') | YES | | NULL | \n |\n| bushels | int(11) | YES | | NULL | \n |\n+---------+-------------------------------+------+-----+---------+-------------\n--+\n\nINSERT INTO fruits\n (fruit,bushels) VALUES\n (\'pear\',20),\n (\'apple\',100),\n (\'orange\',25);\n\nINSERT INTO fruits\n (fruit,bushels) VALUES\n (\'avocado\',10);\nERROR 1265 (01000): Data truncated for column \'fruit\' at row 1\n\nSELECT * FROM fruits;\n+----+--------+---------+\n| id | fruit | bushels |\n+----+--------+---------+\n| 1 | pear | 20 |\n| 2 | apple | 100 |\n| 3 | orange | 25 |\n+----+--------+---------+\n\nSelecting by numeric index:\n\nSELECT * FROM fruits WHERE fruit=2;\n+----+--------+---------+\n| id | fruit | bushels |\n+----+--------+---------+\n| 3 | orange | 25 |\n+----+--------+---------+\n\nSorting is according to the index value:\n\nCREATE TABLE enums (a ENUM(\'2\',\'1\'));\n\nINSERT INTO enums VALUES (\'1\'),(\'2\');\n\nSELECT * FROM enums ORDER BY a ASC;\n+------+\n| a |\n+------+\n| 2 |\n| 1 |\n+------+\n\nIt\'s easy to get confused between returning the enum integer with the stored\nvalue, so we don\'t suggest using ENUM to store numerals. The first example\nreturns the 1st indexed field (\'2\' has an index value of 1, as it\'s defined\nfirst), while the second example returns the string value \'1\'.\n\nSELECT * FROM enums WHERE a=1;\n+------+\n| a |\n+------+\n| 2 |\n+------+\n\nSELECT * FROM enums WHERE a=\'1\';\n+------+\n| a |\n+------+\n| 1 |\n+------+\n\nURL: https://mariadb.com/kb/en/enum/','','https://mariadb.com/kb/en/enum/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (276,23,'INET4','MariaDB starting with 10.10.0\n-----------------------------\nThe INET4 data type was added in MariaDB 10.10.0\n\nSyntax\n------\n\nINET4\n\nDescription\n-----------\n\nINET4 is a data type to store IPv4 addresses, as 4-byte binary strings.\n\nExamples\n--------\n\nCREATE OR REPLACE TABLE t1 (a INET4);\n\nINSERT INTO t1 VALUES(\'0.0.0.0\'), (\'255.10.0.0\'), (\'255.255.255.255\');\n\nINSERT INTO t1 VALUES (0xa0000001);\nINSERT INTO t1 VALUES (0xf0000000);\nINSERT INTO t1 VALUES (0xff000001);\n\nSELECT HEX(a), a FROM t1 ORDER BY a;\n+----------+-----------------+\n| HEX(a) | a |\n+----------+-----------------+\n| 00000000 | 0.0.0.0 |\n| A0000001 | 160.0.0.1 |\n| F0000000 | 240.0.0.0 |\n| FF000001 | 255.0.0.1 |\n| FF0A0000 | 255.10.0.0 |\n| FFFFFFFF | 255.255.255.255 |\n+----------+-----------------+\n\nURL: https://mariadb.com/kb/en/inet4/','','https://mariadb.com/kb/en/inet4/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (277,23,'INET6','MariaDB starting with 10.5.0\n----------------------------\nThe INET6 data type was added in MariaDB 10.5.0\n\nSyntax\n------\n\nINET6\n\nDescription\n-----------\n\nThe INET6 data type is intended for storage of IPv6 addresses, as well as IPv4\naddresses assuming conventional mapping of IPv4 addresses into IPv6 addresses.\n\nBoth short and long IPv6 notation are permitted, according to RFC-5952.\n\n* Values are stored as a 16-byte fixed length binary string, with most\nsignificant byte first.\n* Storage engines see INET6 as BINARY(16).\n* Clients see INET6 as CHAR(39) and get text representation on retrieval.\n\nThe IPv4-compatible notation is considered as deprecated. It is supported for\ncompatibility with the INET6_ATON function, which also understands this\nformat. It\'s recommended to use the mapped format to store IPv4 addresses in\nINET6.\n\nWhen an IPv4 mapped (or compatible) value is stored in INET6, it still\noccupies 16 bytes:\n\nRetrieval\n---------\n\nOn retrieval, in the client-server text protocol, INET6 values are converted\nto the short text representation, according to RFC-5952, that is with all\nleading zeroes in each group removed and with consequent zero groups\ncompressed.\n\nBesides creating one\'s own stored function, there is no a way to retrieve an\nINET6 value using long text representation.\n\nCasting\n-------\n\n* CAST from a character string to INET6 understands addresses in short or long\ntext notation (including IPv4 mapped and compatible addresses). NULL is\nreturned if the format is not understood.\n* CAST from a binary string to INET6 requires a 16-byte string as an argument.\nNULL is returned if the argument length is not equal to 16.\n* CAST from other data types to INET6 first converts data to a character\nstring, then CAST from character string to INET6 is applied.\n* CAST from INET6 to CHAR returns short text address notation.\n* CAST from INET6 to BINARY returns its 16-byte binary string representation.\n* CAST from INET6 to data types other than CHAR (e.g. SIGNED, UNSIGNED, TIME,\netc) returns an error.\n\nComparisons\n-----------\n\nAn INET6 expression can be compared to:\n\n* another INET6 expression\n* a character string expression with a text (short or long) address\nrepresentation:\n* a 16-byte binary string expression:\n\nAttempting to compare INET6 to an expression of any other data type returns an\nerror.\n\nMixing INET6 Values for Result\n------------------------------\n\nAn INET6 expression can be mixed for result (i.e. UNION, CASE..THEN, COALESCE\netc) with:\n\n* another INET6 expression. The resulting data type is INET6.\n* a character string in text (short or long) address representation. The\nresult data type is INET6. The character string counterpart is automatically\nconverted to INET6. If the string format is not understood, it\'s converted\nwith a warning to either NULL or to \'::\', depending on the NULL-ability of the\nresult.\n* a 16-byte binary string. The resulting data type is INET6. The binary string\ncounterpart is automatically converted to INET6. If the length of the binary\nstring is not equal to 16, it\'s converted with a warning to NULL or to \'::\'\ndepending on the NULL-ability of the result.\n\nAttempts to mix INET6 for result with other data types will return an error.\n\nMixing INET6 with other data types for LEAST and GREATEST, when mixing for\ncomparison and mixing for result are involved at the same time, uses the same\nrules with mixing for result, described in the previous paragraphs.\n\nFunctions and Operators\n-----------------------\n\n* HEX() with an INET6 argument returns a hexadecimal representation of the\nunderlying 16-byte binary string\n* Arithmetic operators (+,-,*,/,MOD,DIV) are not supported for INET6. This may\nchange in the future.\n* The INET6_ATON function now understands INET6 values as an argument\n* The prototypes of the IS_IPV4_COMPAT and IS_IPV4_MAPPED functions have\nchanged from a BINARY(16) to a INET6,\n* When the argument for these two functions is not INET6, automatic implicit\nCAST to INET6 is applied. As a consequence, both functions now understand\narguments in both text representation and binary(16) representation. Before\nMariaDB 10.5.0, these functions understood only binary(16) representation.\n\nPrepared Statement Parameters\n-----------------------------\n\nINET6 understands both text and binary(16) address representation in prepared\nstatement parameters (PREPARE..EXECUTE and EXECUTE IMMEDIATE statements).\n\nMigration between BINARY(16) and INET6\n---------------------------------------\n\nBefore MariaDB 10.5.0, you may have used BINARY(16) as a storage for IPv6\ninternet addresses, in combination with INET6_ATON and INET6_NTOA to\nrespectively insert and retrieve data.\n\nFrom 10.5, you can ALTER BINARY(16) columns storing IPv6 addresses to INET6.\nAfter such an alter, there is no a need to use INET6_ATON() and INET6_NTOA().\nAddresses can be inserted and retrieved directly.\n\nIt is also possible to convert INET6 columns to BINARY(16) and continue using\nthe data in combination with INET6_NTOA() and INET6_ATON().\n\nExamples\n--------\n\nCREATE TABLE t1 (a INET6);\n\nInserting using short text address notation:\n\nINSERT INTO t1 VALUES (\'2001:db8::ff00:42:8329\');\n\nLong text address notation:\n\nINSERT INTO t1 VALUES (\'2001:0db8:0000:0000:0000:ff00:0042:8329\');\n\n16-byte binary string notation:\n\nINSERT INTO t1 VALUES (0x20010DB8000000000000FF0000428329);\nINSERT INTO t1 VALUES (UNHEX(\'20010DB8000000000000FF0000428329\'));\n\nIPv4 addresses, using IPv4-mapped and IPv4-compatible notations:\n\nINSERT INTO t1 VALUES (\'::ffff:192.0.2.128\'); -- mapped\nINSERT INTO t1 VALUES (\'::192.0.2.128\'); -- compatible\n\nSELECT * FROM t1;\n+------------------------+\n| a |\n+------------------------+\n| 2001:db8::ff00:42:8329 |\n| 2001:db8::ff00:42:8329 |\n| 2001:db8::ff00:42:8329 |\n| 2001:db8::ff00:42:8329 |\n| ::ffff:192.0.2.128 |\n| ::192.0.2.128 |\n+------------------------+\n\nIPv4 mapped (or compatible) values still occupy 16 bytes:\n\nCREATE OR REPLACE TABLE t1 (a INET6);\n\nINSERT INTO t1 VALUES (\'::ffff:192.0.2.128\');\n\nSELECT * FROM t1;\n+--------------------+\n| a |\n+--------------------+\n| ::ffff:192.0.2.128 |\n+--------------------+\n\nSELECT HEX(a) FROM t1;\n+----------------------------------+\n| HEX(a) |\n+----------------------------------+\n| 00000000000000000000FFFFC0000280 |\n+----------------------------------+\n\nCasting from INET6 to anything other than CHAR returns an error:\n\nSELECT CAST(a AS DECIMAL) FROM t1;\n\nERROR 4079 (HY000): Illegal parameter data type inet6 for operation\n\'decimal_typecast\'\n\nComparison Examples\n-------------------\n\nComparison with another INET6 expression:\n\nCREATE OR REPLACE TABLE t1 (a INET6);\n CREATE OR REPLACE TABLE t2 (a INET6);\n\nINSERT INTO t1 VALUES\n(\'2001:db8::ff00:42:8328\'),(\'2001:db8::ff00:42:8329\');\n INSERT INTO t2 VALUES\n(\'2001:db8::ff00:42:832a\'),(\'2001:db8::ff00:42:8329\');\n\nSELECT t1.* FROM t1,t2 WHERE t1.a=t2.a;\n +------------------------+\n | a |\n +------------------------+\n | 2001:db8::ff00:42:8329 |\n +------------------------+\n\nWith a character string expression with a text (short or long) address\nrepresentation:\n\nCREATE OR REPLACE TABLE t1 (a INET6);\n\nINSERT INTO t1 VALUES (\'2001:db8::ff00:42:8329\');\n\nSELECT * FROM t1 WHERE a=\'2001:db8::ff00:42:8329\';\n +------------------------+\n | a |\n +------------------------+\n | 2001:db8::ff00:42:8329 |\n +------------------------+\n\nWith a 16-byte binary string expression:\n\nCREATE OR REPLACE TABLE t1 (a INET6);\n\nINSERT INTO t1 VALUES (\'2001:db8::ff00:42:8329\');\n\nSELECT * FROM t1 WHERE a=X\'20010DB8000000000000FF0000428329\';\n +------------------------+\n | a |\n +------------------------+\n | 2001:db8::ff00:42:8329 |\n +------------------------+\n\nWith an expression of another data type:\n\nSELECT * FROM t1 WHERE a=1;\nERROR 4078 (HY000): Illegal parameter data types inet6 and int for operation\n\'=\'\n\nMixing for Result Examples\n--------------------------\n\nMixed with another INET6 expression, returning an INET6 data type:\n\nCREATE OR REPLACE TABLE t1 (a INET6, b INET6);\n\nINSERT INTO t1 VALUES (NULL,\'2001:db8::ff00:42:8329\');\n\nSELECT a FROM t1 UNION SELECT b FROM t1;\n +------------------------+\n | a |\n +------------------------+\n | NULL |\n | 2001:db8::ff00:42:8329 |\n +------------------------+\n\nSELECT COALESCE(a, b) FROM t1;\n +------------------------+\n | COALESCE(a, b) |\n +------------------------+\n | 2001:db8::ff00:42:8329 |\n +------------------------+\n\nMixed with a character string in text (short or long) address representation:\n\nCREATE OR REPLACE TABLE t1 (a INET6, b VARCHAR(64));\n\nINSERT INTO t1 VALUES (NULL,\'2001:db8::ff00:42:8328\');\n\nINSERT INTO t1 VALUES (NULL,\'2001:db8::ff00:42:832a garbage\');\n\nSELECT COALESCE(a,b) FROM t1;\n +------------------------+\n | COALESCE(a,b) |\n +------------------------+\n | 2001:db8::ff00:42:8328 |\n | NULL |\n +------------------------+\n 2 rows in set, 1 warning (0.001 sec)\n\nSHOW WARNINGS;\n\n+---------+------+---------------------------------------------------------+\n | Level | Code | Message\n|\n\n+---------+------+---------------------------------------------------------+\n | Warning | 1292 | Incorrect inet6 value: \'2001:db8::ff00:42:832a garbage\'\n|\n\n+---------+------+---------------------------------------------------------+\n\nMixed with a 16-byte binary string:\n\nCREATE OR REPLACE TABLE t1 (a INET6, b VARBINARY(16));\n\nINSERT INTO t1 VALUES (NULL,CONCAT(0xFFFF,REPEAT(0x0000,6),0xFFFF));\n\nINSERT INTO t1 VALUES (NULL,0x00/*garbage*/);\n\nSELECT COALESCE(a,b) FROM t1;\n +---------------+\n | COALESCE(a,b) |\n +---------------+\n | ffff::ffff |\n | NULL |\n +---------------+\n 2 rows in set, 1 warning (0.001 sec)\n\nSHOW WARNINGS;\n +---------+------+-------------------------------+\n | Level | Code | Message |\n +---------+------+-------------------------------+\n | Warning | 1292 | Incorrect inet6 value: \'\\x00\' |\n +---------+------+-------------------------------+\n\nMixing with other data types:\n\nSELECT CAST(\'ffff::ffff\' AS INET6) UNION SELECT 1;\nERROR 4078 (HY000): Illegal parameter data types inet6 and int for operation\n\'UNION\'\n\nFunctions and Operators Examples\n--------------------------------\n\nHEX with an INET6 argument returning a hexadecimal representation:\n\nSELECT HEX(CAST(\'2001:db8::ff00:42:8329\' AS INET6));\n +----------------------------------------------+\n | HEX(CAST(\'2001:db8::ff00:42:8329\' AS INET6)) |\n +----------------------------------------------+\n | 20010DB8000000000000FF0000428329 |\n +----------------------------------------------+\n\nINET6_ATON now understands INET6 values as an argument:\n\nCREATE OR REPLACE TABLE t1 (a INET6);\n\nINSERT INTO t1 VALUES (\'2001:db8::ff00:42:8329\');\n\nSELECT a, HEX(INET6_ATON(a)) FROM t1;\n +------------------------+----------------------------------+\n | a | HEX(INET6_ATON(a)) |\n +------------------------+----------------------------------+\n | 2001:db8::ff00:42:8329 | 20010DB8000000000000FF0000428329 |\n +------------------------+----------------------------------+\n\nIS_IPV4_COMPAT and IS_IPV4_MAPPED prototype now a BINARY(16)):\n\nCREATE OR REPLACE TABLE t1 (a INET6);\n\nINSERT INTO t1 VALUES (\'2001:db8::ff00:42:8329\');\n INSERT INTO t1 VALUES (\'::ffff:192.168.0.1\');\n INSERT INTO t1 VALUES (\'::192.168.0.1\');\n\nSELECT a, IS_IPV4_MAPPED(a), IS_IPV4_COMPAT(a) FROM t1;\n +------------------------+-------------------+-------------------+\n | a | IS_IPV4_MAPPED(a) | IS_IPV4_COMPAT(a) |\n +------------------------+-------------------+-------------------+\n | 2001:db8::ff00:42:8329 | 0 | 0 |\n | ::ffff:192.168.0.1 | 1 | 0 |\n | ::192.168.0.1 | 0 | 1 |\n +------------------------+-------------------+-------------------+\n\nAutomatic implicit CAST to INET6:\n\nCREATE OR REPLACE TABLE t1 (\n a INET6,\n b VARCHAR(39) DEFAULT a\n );\n\nINSERT INTO t1 (a) VALUES (\'ffff::ffff\'),(\'::ffff:192.168.0.1\');\n\nSELECT a, IS_IPV4_MAPPED(a), b, IS_IPV4_MAPPED(b) FROM t1;\n\n+--------------------+-------------------+--------------------+----------------\n--+\n | a | IS_IPV4_MAPPED(a) | b |\nIS_IPV4_MAPPED(b) |\n\n+--------------------+-------------------+--------------------+----------------\n--+\n | ffff::ffff | 0 | ffff::ffff |\n 0 |\n | ::ffff:192.168.0.1 | 1 | ::ffff:192.168.0.1 |\n 1 |\n\n+--------------------+-------------------+--------------------+----------------\n--+\n\nCREATE OR REPLACE TABLE t1 (\n a INET6,\n b BINARY(16) DEFAULT UNHEX(HEX(a))\n );\n\nINSERT INTO t1 (a) VALUES (\'ffff::ffff\'),(\'::ffff:192.168.0.1\');\n\nSELECT a, IS_IPV4_MAPPED(a), HEX(b), IS_IPV4_MAPPED(b) FROM t1;\n\n+--------------------+-------------------+----------------------------------+--\n----------------+\n | a | IS_IPV4_MAPPED(a) | HEX(b)\n | IS_IPV4_MAPPED(b) |\n\n+--------------------+-------------------+----------------------------------+--\n----------------+\n | ffff::ffff | 0 |\nFFFF000000000000000000000000FFFF | 0 |\n | ::ffff:192.168.0.1 | 1 |\n00000000000000000000FFFFC0A80001 | 1 |\n\n+--------------------+-------------------+----------------------------------+--\n----------------+\n\nPrepared Statement Parameters Examples\n--------------------------------------\n\nCREATE OR REPLACE TABLE t1 (a INET6);\n\nEXECUTE IMMEDIATE \'INSERT INTO t1 VALUES (?)\' USING \'ffff::fffe\';\nEXECUTE IMMEDIATE \'INSERT INTO t1 VALUES (?)\' USING\nX\'FFFF000000000000000000000000FFFF\';\n\nSELECT * FROM t1;\n+------------+\n| a |\n+------------+\n| ffff::fffe |\n| ffff::ffff |\n+------------+\n\nEXECUTE IMMEDIATE \'SELECT * FROM t1 WHERE a=?\' USING \'ffff::fffe\';\n+------------+\n| a |\n+------------+\n| ffff::fffe |\n+------------+\n\nEXECUTE IMMEDIATE \'SELECT * FROM t1 WHERE a=?\' USING','','https://mariadb.com/kb/en/inet6/'); +update help_topic set description = CONCAT(description, '\nX\'FFFF000000000000000000000000FFFF\';\n+------------+\n| a |\n+------------+\n| ffff::ffff |\n+------------+\n\nMigration between BINARY(16) and INET6 Examples\n-----------------------------------------------\n\nBefore MariaDB 10.5:\n\nCREATE OR REPLACE TABLE t1 (a BINARY(16));\n\nINSERT INTO t1 VALUES (INET6_ATON(\'ffff::ffff\'));\n\nSELECT INET6_NTOA(a) FROM t1;\n+---------------+\n| INET6_NTOA(a) |\n+---------------+\n| ffff::ffff |\n+---------------+\n\nMigrating to INET6, from MariaDB 10.5:\n\nALTER TABLE t1 MODIFY a INET6;\n\nINSERT INTO t1 VALUES (\'ffff::fffe\');\n\nSELECT * FROM t1;\n+------------+\n| a |\n+------------+\n| ffff::ffff |\n| ffff::fffe |\n+------------+\n\nMigration from INET6 to BINARY(16):\n\nCREATE OR REPLACE TABLE t1 (a INET6);\n\nINSERT INTO t1 VALUES (\'2001:db8::ff00:42:8329\');\nINSERT INTO t1 VALUES (\'::ffff:192.168.0.1\');\nINSERT INTO t1 VALUES (\'::192.168.0.1\');\n\nALTER TABLE t1 MODIFY a BINARY(16);\n\nSELECT INET6_NTOA(a) FROM t1;\n+------------------------+\n| INET6_NTOA(a) |\n+------------------------+\n| 2001:db8::ff00:42:8329 |\n| ::ffff:192.168.0.1 |\n| ::192.168.0.1 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/inet6/') WHERE help_topic_id = 277; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (278,23,'JSON Data Type','The JSON alias was added to make it possible to use JSON columns in statement\nbased replication from MySQL to MariaDB and to make it possible for MariaDB to\nread mysqldumps from MySQL.\n\nJSON is an alias for LONGTEXT introduced for compatibility reasons with\nMySQL\'s JSON data type. MariaDB implements this as a LONGTEXT rather, as the\nJSON data type contradicts the SQL standard, and MariaDB\'s benchmarks indicate\nthat performance is at least equivalent.\n\nIn order to ensure that a a valid json document is inserted, the JSON_VALID\nfunction can be used as a CHECK constraint. This constraint is automatically\nincluded for types using the JSON alias from MariaDB 10.4.3.\n\nExamples\n--------\n\nCREATE TABLE t (j JSON);\n\nDESC t;\n+-------+----------+------+-----+---------+-------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+----------+------+-----+---------+-------+\n| j | longtext | YES | | NULL | |\n+-------+----------+------+-----+---------+-------+\n\nWith validation:\n\nCREATE TABLE t2 (\n j JSON\n CHECK (JSON_VALID(j))\n);\n\nINSERT INTO t2 VALUES (\'invalid\');\nERROR 4025 (23000): CONSTRAINT `j` failed for `test`.`t2`\n\nINSERT INTO t2 VALUES (\'{\"id\": 1, \"name\": \"Monty\"}\');\nQuery OK, 1 row affected (0.13 sec)\n\nReplicating JSON Data Between MySQL and MariaDB\n-----------------------------------------------\n\nThe JSON type in MySQL stores the JSON object in a compact form, not as\nLONGTEXT as in MariaDB. This means that row based replication will not work\nfor JSON types from MySQL to MariaDB.\n\nThere are a a few different ways to solve this:\n\n* Use statement based replication.\n* Change the JSON column to type TEXT in MySQL\n* If you must use row-based replication and cannot change the MySQL master\nfrom JSON to TEXT, you can try to introduce an intermediate MySQL slave and\nchange the column type from JSON to TEXT on it. Then you replicate from this\nintermediate slave to MariaDB.\n\nConverting a MySQL TABLE with JSON Fields to MariaDB\n----------------------------------------------------\n\nMariaDB can\'t directly access MySQL\'s JSON format.\n\nThere are a a few different ways to move the table to MariaDB:\n\n* From MariaDB 10.5.7, see the you can use the mysql_json plugin. See Making\nMariaDB understand MySQL JSON.\n* Change the JSON column to type TEXT in MySQL. After this, MariaDB can\ndirectly use the table without any need for a dump and restore.\n* Use mysqldump to copy the table.\n\nDifferences Between MySQL JSON Strings and MariaDB JSON Strings\n---------------------------------------------------------------\n\n* In MySQL, JSON is an object and is compared according to json values. In\nMariaDB JSON strings are normal strings and compared as strings. One exception\nis when using JSON_EXTRACT() in which case strings are unescaped before\ncomparison.\n\nURL: https://mariadb.com/kb/en/json-data-type/','','https://mariadb.com/kb/en/json-data-type/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (279,23,'MEDIUMBLOB','Syntax\n------\n\nMEDIUMBLOB\n\nDescription\n-----------\n\nA BLOB column with a maximum length of 16,777,215 (224 - 1) bytes. Each\nMEDIUMBLOB value is stored using a three-byte length prefix that indicates the\nnumber of bytes in the value.\n\nURL: https://mariadb.com/kb/en/mediumblob/','','https://mariadb.com/kb/en/mediumblob/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (280,23,'MEDIUMTEXT','Syntax\n------\n\nMEDIUMTEXT [CHARACTER SET charset_name] [COLLATE collation_name]\n\nDescription\n-----------\n\nA TEXT column with a maximum length of 16,777,215 (224 - 1) characters. The\neffective maximum length is less if the value contains multi-byte characters.\nEach MEDIUMTEXT value is stored using a three-byte length prefix that\nindicates the number of bytes in the value.\n\nURL: https://mariadb.com/kb/en/mediumtext/','','https://mariadb.com/kb/en/mediumtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (281,23,'LONGBLOB','Syntax\n------\n\nLONGBLOB\n\nDescription\n-----------\n\nA BLOB column with a maximum length of 4,294,967,295 bytes or 4GB (232 - 1).\nThe effective maximum length of LONGBLOB columns depends on the configured\nmaximum packet size in the client/server protocol and available memory. Each\nLONGBLOB value is stored using a four-byte length prefix that indicates the\nnumber of bytes in the value.\n\nOracle Mode\n-----------\n\nMariaDB starting with 10.3\n--------------------------\nIn Oracle mode from MariaDB 10.3, BLOB is a synonym for LONGBLOB.\n\nURL: https://mariadb.com/kb/en/longblob/','','https://mariadb.com/kb/en/longblob/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (282,23,'LONGTEXT','Syntax\n------\n\nLONGTEXT [CHARACTER SET charset_name] [COLLATE collation_name]\n\nDescription\n-----------\n\nA TEXT column with a maximum length of 4,294,967,295 or 4GB (232 - 1)\ncharacters. The effective maximum length is less if the value contains\nmulti-byte characters. The effective maximum length of LONGTEXT columns also\ndepends on the configured maximum packet size in the client/server protocol\nand available memory. Each LONGTEXT value is stored using a four-byte length\nprefix that indicates the number of bytes in the value.\n\nFrom MariaDB 10.2.7, JSON is an alias for LONGTEXT. See JSON Data Type for\ndetails.\n\nOracle Mode\n-----------\n\nMariaDB starting with 10.3\n--------------------------\nIn Oracle mode from MariaDB 10.3, CLOB is a synonym for LONGTEXT.\n\nURL: https://mariadb.com/kb/en/longtext/','','https://mariadb.com/kb/en/longtext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (283,23,'ROW','MariaDB starting with 10.3.0\n----------------------------\nThe ROW data type was introduced in MariaDB 10.3.0.\n\nSyntax\n------\n\nROW (<field name> <data type> [{, <field name> <data type>}... ])\n\nDescription\n-----------\n\nROW is a data type for stored procedure variables.\n\nFeatures\n--------\n\nROW fields as normal variables\n------------------------------\n\nROW fields (members) act as normal variables, and are able to appear in all\nquery parts where a stored procedure variable is allowed:\n\n* Assignment is using the := operator and the SET command:\n\na.x:= 10;\na.x:= b.x;\nSET a.x= 10, a.y=20, a.z= b.z;\n\n* Passing to functions and operators:\n\nSELECT f1(rec.a), rec.a<10;\n\n* Clauses (select list, WHERE, HAVING, LIMIT, etc...,):\n\nSELECT var.a, t1.b FROM t1 WHERE t1.b=var.b LIMIT var.c;\n\n* INSERT values:\n\nINSERT INTO t1 VALUES (rec.a, rec.b, rec.c);\n\n* SELECT .. INTO targets\n\nSELECT a,b INTO rec.a, rec.b FROM t1 WHERE t1.id=10;\n\n* Dynamic SQL out parameters (EXECUTE and EXECUTE IMMEDIATE)\n\nEXECUTE IMMEDIATE \'CALL proc_with_out_param(?)\' USING rec.a;\n\nROW type variables as FETCH targets\n-----------------------------------\n\nROW type variables are allowed as FETCH targets:\n\nFETCH cur INTO rec;\n\nwhere cur is a CURSOR and rec is a ROW type stored procedure variable.\n\nNote, currently an attempt to use FETCH for a ROW type variable returns this\nerror:\n\nERROR 1328 (HY000): Incorrect number of FETCH variables\n\nFETCH from a cursor cur into a ROW variable rec works as follows:\n\n* The number of fields in cur must match the number of fields in rec.\n Otherwise, an error is reported.\n\n* Assignment is done from left to right. The first cursor field is assigned to\n the first variable field, the second cursor field is assigned to the second\n variable field, etc.\n\n* Field names in rec are not important and can differ from field names\n in cur.\n\nSee FETCH Examples (below) for examples of using this with sql_mode=ORACLE and\nsql_mode=DEFAULT.\n\nROW type variables as SELECT...INTO targets\n-------------------------------------------\n\nROW type variables are allowed as SELECT..INTO targets with some differences\ndepending on which sql_mode is in use.\n\n* When using sql_mode=ORACLE, table%ROWTYPE and cursor%ROWTYPE\n variables can be used as SELECT...INTO targets.\n\n* Using multiple ROW variables in the SELECT..INTO list will report an\n error.\n\n* Using ROW variables with a different column count than in\n the SELECT..INTO list will report an error.\n\nSee SELECT...INTO Examples (below) for examples of using this with\nsql_mode=ORACLE and sql_mode=DEFAULT.\n\nFeatures not implemented\n------------------------\n\nThe following features are planned, but not implemented yet:\n\n* Returning a ROW type expression from a stored function (see MDEV-12252).\nThis will need some grammar change to support field names after parentheses:\n\nSELECT f1().x FROM DUAL;\n\n* Returning a ROW type expression from a built-in hybrid type function, such\nas CASE, IF, etc. \n* ROW of ROWs\n\nExamples\n--------\n\nDeclaring a ROW in a stored procedure\n-------------------------------------\n\nDELIMITER $$\nCREATE PROCEDURE p1()\nBEGIN\n DECLARE r ROW (c1 INT, c2 VARCHAR(10));\n SET r.c1= 10;\n SET r.c2= \'test\';\n INSERT INTO t1 VALUES (r.c1, r.c2);\nEND;\n$$\nDELIMITER ;\nCALL p1();\n\nFETCH Examples\n--------------\n\nA complete FETCH example for sql_mode=ORACLE:\n\nDROP TABLE IF EXISTS t1;\nCREATE TABLE t1 (a INT, b VARCHAR(32));\nINSERT INTO t1 VALUES (10,\'b10\');\nINSERT INTO t1 VALUES (20,\'b20\');\nINSERT INTO t1 VALUES (30,\'b30\');\n\nSET sql_mode=oracle;\nDROP PROCEDURE IF EXISTS p1;\nDELIMITER $$\nCREATE PROCEDURE p1 AS\n rec ROW(a INT, b VARCHAR(32));\n CURSOR c IS SELECT a,b FROM t1;\nBEGIN\n OPEN c;\n LOOP\n FETCH c INTO rec;\n EXIT WHEN c%NOTFOUND;\n SELECT (\'rec=(\' || rec.a ||\',\'|| rec.b||\')\');\n END LOOP;\n CLOSE c;\nEND;\n$$\nDELIMITER ;\nCALL p1();\n\nA complete FETCH example for sql_mode=DEFAULT:\n\nDROP TABLE IF EXISTS t1;\nCREATE TABLE t1 (a INT, b VARCHAR(32));\nINSERT INTO t1 VALUES (10,\'b10\');\nINSERT INTO t1 VALUES (20,\'b20\');\nINSERT INTO t1 VALUES (30,\'b30\');\n\nSET sql_mode=DEFAULT;\nDROP PROCEDURE IF EXISTS p1;\nDELIMITER $$\nCREATE PROCEDURE p1()\nBEGIN\n DECLARE done INT DEFAULT FALSE;\n DECLARE rec ROW(a INT, b VARCHAR(32));\n DECLARE c CURSOR FOR SELECT a,b FROM t1;\n DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;\n OPEN c;\nread_loop:\n LOOP\n FETCH c INTO rec;\n IF done THEN\n LEAVE read_loop;\n END IF;\n SELECT CONCAT(\'rec=(\',rec.a,\',\',rec.b,\')\');\n END LOOP;\n CLOSE c;\nEND;\n$$\nDELIMITER ;\nCALL p1();\n\nSELECT...INTO Examples\n----------------------\n\nA SELECT...INTO example for sql_mode=DEFAULT:\n\nSET sql_mode=DEFAULT;\nDROP TABLE IF EXISTS t1;\nDROP PROCEDURE IF EXISTS p1;\nCREATE TABLE t1 (a INT, b VARCHAR(32));\nINSERT INTO t1 VALUES (10,\'b10\');\nDELIMITER $$\nCREATE PROCEDURE p1()\nBEGIN\n DECLARE rec1 ROW(a INT, b VARCHAR(32));\n SELECT * FROM t1 INTO rec1;\n SELECT rec1.a, rec1.b;\nEND;\n$$\nDELIMITER ;\nCALL p1();\n\nThe above example returns:\n\n+--------+--------+\n| rec1.a | rec1.b |\n+--------+--------+\n| 10 | b10 |\n+--------+--------+\n\nA SELECT...INTO example for sql_mode=ORACLE:\n\nSET sql_mode=ORACLE;\nDROP TABLE IF EXISTS t1;\nDROP PROCEDURE IF EXISTS p1;\nCREATE TABLE t1 (a INT, b VARCHAR(32));\nINSERT INTO t1 VALUES (10,\'b10\');\nDELIMITER $$\nCREATE PROCEDURE p1 AS\n rec1 ROW(a INT, b VARCHAR(32));\nBEGIN\n SELECT * FROM t1 INTO rec1;\n SELECT rec1.a, rec1.b;\nEND;\n$$\nDELIMITER ;\nCALL p1();\n\nThe above example returns:\n\n+--------+--------+\n| rec1.a | rec1.b |\n+--------+--------+\n| 10 | b10 |\n+--------+--------+\n\nAn example for sql_mode=ORACLE using table%ROWTYPE variables as SELECT..INTO\ntargets:\n\nSET sql_mode=ORACLE;\nDROP TABLE IF EXISTS t1;\nDROP PROCEDURE IF EXISTS p1;\nCREATE TABLE t1 (a INT, b VARCHAR(32));\nINSERT INTO t1 VALUES (10,\'b10\');\nDELIMITER $$\nCREATE PROCEDURE p1 AS\n rec1 t1%ROWTYPE;\nBEGIN\n SELECT * FROM t1 INTO rec1;\n SELECT rec1.a, rec1.b;\nEND;\n$$\nDELIMITER ;\nCALL p1();\n\nThe above example returns:\n\n+--------+--------+\n| rec1.a | rec1.b |\n+--------+--------+\n| 10 | b10 |\n+--------+--------+\n\nAn example for sql_mode=ORACLE using cursor%ROWTYPE variables as SELECT..INTO\ntargets:\n\nSET sql_mode=ORACLE;\nDROP TABLE IF EXISTS t1;\nDROP PROCEDURE IF EXISTS p1;\nCREATE TABLE t1 (a INT, b VARCHAR(32));\nINSERT INTO t1 VALUES (10,\'b10\');\nDELIMITER $$\nCREATE PROCEDURE p1 AS\n CURSOR cur1 IS SELECT * FROM t1;\n rec1 cur1%ROWTYPE;\nBEGIN\n SELECT * FROM t1 INTO rec1;\n SELECT rec1.a, rec1.b;\nEND;\n$$\nDELIMITER ;\nCALL p1();\n\nThe above example returns:\n\n+--------+--------+\n| rec1.a | rec1.b |\n+--------+--------+\n| 10 | b10 |\n+--------+--------+\n\nURL: https://mariadb.com/kb/en/row/','','https://mariadb.com/kb/en/row/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (284,23,'TEXT','Syntax\n------\n\nTEXT[(M)] [CHARACTER SET charset_name] [COLLATE collation_name]\n\nDescription\n-----------\n\nA TEXT column with a maximum length of 65,535 (216 - 1) characters. The\neffective maximum length is less if the value contains multi-byte characters.\nEach TEXT value is stored using a two-byte length prefix that indicates the\nnumber of bytes in the value. If you need a bigger storage, consider using\nMEDIUMTEXT instead.\n\nAn optional length M can be given for this type. If this is done, MariaDB\ncreates the column as the smallest TEXT type large enough to hold values M\ncharacters long.\n\nBefore MariaDB 10.2, all MariaDB collations were of type PADSPACE, meaning\nthat TEXT (as well as VARCHAR and CHAR values) are compared without regard for\ntrailing spaces. This does not apply to the LIKE pattern-matching operator,\nwhich takes into account trailing spaces.\n\nBefore MariaDB 10.2.1, BLOB and TEXT columns could not be assigned a DEFAULT\nvalue. This restriction was lifted in MariaDB 10.2.1.\n\nExamples\n--------\n\nTrailing spaces:\n\nCREATE TABLE strtest (d TEXT(10));\nINSERT INTO strtest VALUES(\'Maria \');\n\nSELECT d=\'Maria\',d=\'Maria \' FROM strtest;\n+-----------+--------------+\n| d=\'Maria\' | d=\'Maria \' |\n+-----------+--------------+\n| 1 | 1 |\n+-----------+--------------+\n\nSELECT d LIKE \'Maria\',d LIKE \'Maria \' FROM strtest;\n+----------------+-------------------+\n| d LIKE \'Maria\' | d LIKE \'Maria \' |\n+----------------+-------------------+\n| 0 | 1 |\n+----------------+-------------------+\n\nIndexing\n--------\n\nTEXT columns can only be indexed over a specified length. This means that they\ncannot be used as the primary key of a table norm until MariaDB 10.4, can a\nunique index be created on them.\n\nMariaDB starting with 10.4\n--------------------------\nStarting with MariaDB 10.4, a unique index can be created on a TEXT column.\n\nInternally, this uses hash indexing to quickly check the values and if a hash\ncollision is found, the actual stored values are compared in order to retain\nthe uniqueness.\n\nDifference between VARCHAR and TEXT\n-----------------------------------\n\n* VARCHAR columns can be fully indexed. TEXT columns can only be indexed over\na specified length.\n* Using TEXT or BLOB in a SELECT query that uses temporary tables for storing\nintermediate results will force the temporary table to be disk based (using\nthe Aria storage engine instead of the memory storage engine, which is a bit\nslower. This is not that bad as the Aria storage engine caches the rows in\nmemory. To get the benefit of this, one should ensure that the\naria_pagecache_buffer_size variable is big enough to hold most of the row and\nindex data for temporary tables.\n\nFor Storage Engine Developers\n-----------------------------\n\n* Internally the full length of the VARCHAR column is allocated inside each\nTABLE objects record[] structure. As there are three such buffers, each open\ntable will allocate 3 times max-length-to-store-varchar bytes of memory.\n* TEXT and BLOB columns are stored with a pointer (4 or 8 bytes) + a 1-4 bytes\nlength. The TEXT data is only stored once. This means that internally TEXT\nuses less memory for each open table but instead has the additional overhead\nthat each TEXT object needs to be allocated and freed for each row access\n(with some caching in between).\n\nURL: https://mariadb.com/kb/en/text/','','https://mariadb.com/kb/en/text/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (285,23,'TINYBLOB','Syntax\n------\n\nTINYBLOB\n\nDescription\n-----------\n\nA BLOB column with a maximum length of 255 (28 - 1) bytes. Each TINYBLOB value\nis stored using a one-byte length prefix that indicates the number of bytes in\nthe value.\n\nURL: https://mariadb.com/kb/en/tinyblob/','','https://mariadb.com/kb/en/tinyblob/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (286,23,'TINYTEXT','Syntax\n------\n\nTINYTEXT [CHARACTER SET charset_name] [COLLATE collation_name]\n\nDescription\n-----------\n\nA TEXT column with a maximum length of 255 (28 - 1) characters. The effective\nmaximum length is less if the value contains multi-byte characters. Each\nTINYTEXT value is stored using a one-byte length prefix that indicates the\nnumber of bytes in the value.\n\nURL: https://mariadb.com/kb/en/tinytext/','','https://mariadb.com/kb/en/tinytext/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (287,23,'VARBINARY','Syntax\n------\n\nVARBINARY(M)\n\nDescription\n-----------\n\nThe VARBINARY type is similar to the VARCHAR type, but stores binary byte\nstrings rather than non-binary character strings. M represents the maximum\ncolumn length in bytes.\n\nIt contains no character set, and comparison and sorting are based on the\nnumeric value of the bytes.\n\nIf the maximum length is exceeded, and SQL strict mode is not enabled , the\nextra characters will be dropped with a warning. If strict mode is enabled, an\nerror will occur.\n\nUnlike BINARY values, VARBINARYs are not right-padded when inserting.\n\nOracle Mode\n-----------\n\nMariaDB starting with 10.3\n--------------------------\nIn Oracle mode from MariaDB 10.3, RAW is a synonym for VARBINARY.\n\nExamples\n--------\n\nInserting too many characters, first with strict mode off, then with it on:\n\nCREATE TABLE varbins (a VARBINARY(10));\n\nINSERT INTO varbins VALUES(\'12345678901\');\nQuery OK, 1 row affected, 1 warning (0.04 sec)\n\nSELECT * FROM varbins;\n+------------+\n| a |\n+------------+\n| 1234567890 |\n+------------+\n\nSET sql_mode=\'STRICT_ALL_TABLES\';\n\nINSERT INTO varbins VALUES(\'12345678901\');\nERROR 1406 (22001): Data too long for column \'a\' at row 1\n\nSorting is performed with the byte value:\n\nTRUNCATE varbins;\n\nINSERT INTO varbins VALUES(\'A\'),(\'B\'),(\'a\'),(\'b\');\n\nSELECT * FROM varbins ORDER BY a;\n+------+\n| a |\n+------+\n| A |\n| B |\n| a |\n| b |\n+------+\n\nUsing CAST to sort as a CHAR instead:\n\nSELECT * FROM varbins ORDER BY CAST(a AS CHAR);\n+------+\n| a |\n+------+\n| a |\n| A |\n| b |\n| B |\n+------+\n\nURL: https://mariadb.com/kb/en/varbinary/','','https://mariadb.com/kb/en/varbinary/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (288,23,'VARCHAR','Syntax\n------\n\n[NATIONAL] VARCHAR(M) [CHARACTER SET charset_name] [COLLATE collation_name]\n\nDescription\n-----------\n\nA variable-length string. M represents the maximum column length in\ncharacters. The range of M is 0 to 65,532. The effective maximum length of a\nVARCHAR is subject to the maximum row size and the character set used. For\nexample, utf8 characters can require up to three bytes per character, so a\nVARCHAR column that uses the utf8 character set can be declared to be a\nmaximum of 21,844 characters.\n\nNote: For the ColumnStore engine, M represents the maximum column length in\nbytes.\n\nMariaDB stores VARCHAR values as a one-byte or two-byte length prefix plus\ndata. The length prefix indicates the number of bytes in the value. A VARCHAR\ncolumn uses one length byte if values require no more than 255 bytes, two\nlength bytes if values may require more than 255 bytes.\n\nMariaDB follows the standard SQL specification, and does not remove trailing\nspaces from VARCHAR values.\n\nVARCHAR(0) columns can contain 2 values: an empty string or NULL. Such columns\ncannot be part of an index. The CONNECT storage engine does not support\nVARCHAR(0).\n\nVARCHAR is shorthand for CHARACTER VARYING. NATIONAL VARCHAR is the standard\nSQL way to define that a VARCHAR column should use some predefined character\nset. MariaDB uses utf8 as this predefined character set, as does MySQL 4.1 and\nup. NVARCHAR is shorthand for NATIONAL VARCHAR.\n\nBefore MariaDB 10.2, all MariaDB collations were of type PADSPACE, meaning\nthat VARCHAR (as well as CHAR and TEXT values) are compared without regard for\ntrailing spaces. This does not apply to the LIKE pattern-matching operator,\nwhich takes into account trailing spaces. From MariaDB 10.2, a number of NO\nPAD collations are available.\n\nIf a unique index consists of a column where trailing pad characters are\nstripped or ignored, inserts into that column where values differ only by the\nnumber of trailing pad characters will result in a duplicate-key error.\n\nExamples\n--------\n\nThe following are equivalent:\n\nVARCHAR(30) CHARACTER SET utf8\nNATIONAL VARCHAR(30)\nNVARCHAR(30)\nNCHAR VARCHAR(30)\nNATIONAL CHARACTER VARYING(30)\nNATIONAL CHAR VARYING(30)\n\nTrailing spaces:\n\nCREATE TABLE strtest (v VARCHAR(10));\nINSERT INTO strtest VALUES(\'Maria \');\n\nSELECT v=\'Maria\',v=\'Maria \' FROM strtest;\n+-----------+--------------+\n| v=\'Maria\' | v=\'Maria \' |\n+-----------+--------------+\n| 1 | 1 |\n+-----------+--------------+\n\nSELECT v LIKE \'Maria\',v LIKE \'Maria \' FROM strtest;\n+----------------+-------------------+\n| v LIKE \'Maria\' | v LIKE \'Maria \' |\n+----------------+-------------------+\n| 0 | 1 |\n+----------------+-------------------+\n\nTruncation\n----------\n\n* Depending on whether or not strict sql mode is set, you will either get a\nwarning or an error if you try to insert a string that is too long into a\nVARCHAR column. If the extra characters are spaces, the spaces that can\'t fit\nwill be removed and you will always get a warning, regardless of the sql mode\nsetting.\n\nDifference Between VARCHAR and TEXT\n-----------------------------------\n\n* VARCHAR columns can be fully indexed. TEXT columns can only be indexed over\na specified length.\n* Using TEXT or BLOB in a SELECT query that uses temporary tables for storing\nintermediate results will force the temporary table to be disk based (using\nthe Aria storage engine instead of the memory storage engine, which is a bit\nslower. This is not that bad as the Aria storage engine caches the rows in\nmemory. To get the benefit of this, one should ensure that the\naria_pagecache_buffer_size variable is big enough to hold most of the row and\nindex data for temporary tables.\n\nOracle Mode\n-----------\n\nMariaDB starting with 10.3\n--------------------------\nIn Oracle mode from MariaDB 10.3, VARCHAR2 is a synonym.\n\nFor Storage Engine Developers\n-----------------------------\n\n* Internally the full length of the VARCHAR column is allocated inside each\nTABLE objects record[] structure. As there are three such buffers, each open\ntable will allocate 3 times max-length-to-store-varchar bytes of memory.\n* TEXT and BLOB columns are stored with a pointer (4 or 8 bytes) + a 1-4 bytes\nlength. The TEXT data is only stored once. This means that internally TEXT\nuses less memory for each open table but instead has the additional overhead\nthat each TEXT object needs to be allocated and freed for each row access\n(with some caching in between).\n\nURL: https://mariadb.com/kb/en/varchar/','','https://mariadb.com/kb/en/varchar/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (289,23,'SET Data Type','Syntax\n------\n\nSET(\'value1\',\'value2\',...) [CHARACTER SET charset_name] [COLLATE\ncollation_name]\n\nDescription\n-----------\n\nA set. A string object that can have zero or more values, each of which must\nbe chosen from the list of values \'value1\', \'value2\', ... A SET column can\nhave a maximum of 64 members. SET values are represented internally as\nintegers.\n\nSET values cannot contain commas.\n\nIf a SET contains duplicate values, an error will be returned if strict mode\nis enabled, or a warning if strict mode is not enabled.\n\nURL: https://mariadb.com/kb/en/set-data-type/','','https://mariadb.com/kb/en/set-data-type/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (290,23,'UUID Data Type','MariaDB starting with 10.7.0\n----------------------------\nThe UUID data type was added in a MariaDB 10.7.0 preview.\n\nSyntax\n------\n\nUUID\n\nDescription\n-----------\n\nThe UUID data type is intended for the storage of 128-bit UUID (Universally\nUnique Identifier) data. See the UUID function page for more details on UUIDs\nthemselves.\n\nRetrieval\n---------\n\nData retrieved by this data type is in the string representation defined in\nRFC4122.\n\nCasting\n-------\n\nString literals of hexadecimal characters and CHAR/VARCHAR/TEXT can be cast to\nthe UUID data type. Likewise hexadecimal literals, binary-literals, and\nBINARY/VARBINARY/BLOB types can also be cast to UUID.\n\nThe data type will not accept a short UUID generated with the UUID_SHORT\nfunction, but will accept a value without the - character generated by the\nSYS_GUID function (or inserted directly). Hyphens can be partially omitted as\nwell, or included after any group of two digits.\n\nThe type does not accept UUIDs in braces, permitted by some implementations.\n\nStorage\n-------\n\nUUID are stored in an index friendly manner, the order of a UUID of\nllllllll-mmmm-Vhhh-vsss-nnnnnnnnnnnn is stored as:\n\nnnnnnnnnnnnn-vsss-Vhhh-mmmm-llllllll\n\nThis provides a sorting order, if a UUIDv1 (node and timestamp) is used, of\nthe node, followed by the timestamp.\n\nExamples\n--------\n\nCREATE TABLE t1 (id UUID);\n\nDirectly Inserting via string literals:\n\nINSERT INTO t1 VALUES(\'123e4567-e89b-12d3-a456-426655440000\');\n\nDirectly Inserting via hexadecimal literals:\n\nINSERT INTO t1 VALUES (x\'fffffffffffffffffffffffffffffffe\');\n\nGenerating and inserting via the UUID function.\n\nINSERT INTO t1 VALUES (UUID());\n\nRetrieval:\n\nSELECT * FROM t1;\n+--------------------------------------+\n| id |\n+--------------------------------------+\n| 123e4567-e89b-12d3-a456-426655440000 |\n| ffffffff-ffff-ffff-ffff-fffffffffffe |\n| 93aac041-1a14-11ec-ab4e-f859713e4be4 |\n+--------------------------------------+\n\nThe UUID_SHORT function does not generate valid full-length UUID:\n\nINSERT INTO t1 VALUES (UUID_SHORT());\nERROR 1292 (22007): Incorrect uuid value: \'99440417627439104\' \n for column `test`.`t1`.`id` at row 1\n\nAccepting a value without the - character, either directly or generated by the\nSYS_GUID function:\n\nINSERT INTO t1 VALUES (SYS_GUID());\n\nSELECT * FROM t1;\n+--------------------------------------+\n| id |\n+--------------------------------------+\n| 123e4567-e89b-12d3-a456-426655440000 |\n| ffffffff-ffff-ffff-ffff-fffffffffffe |\n| 93aac041-1a14-11ec-ab4e-f859713e4be4 |\n| ea0368d3-1a14-11ec-ab4e-f859713e4be4 |\n+--------------------------------------+\n\nSELECT SYS_GUID();\n+----------------------------------+\n| SYS_GUID() |\n+----------------------------------+\n| ff5b6bcc1a1411ecab4ef859713e4be4 |\n+----------------------------------+\n\nINSERT INTO t1 VALUES (\'ff5b6bcc1a1411ecab4ef859713e4be4\');\n\nSELECT * FROM t1;\n+--------------------------------------+\n| id |\n+--------------------------------------+\n| 123e4567-e89b-12d3-a456-426655440000 |\n| ffffffff-ffff-ffff-ffff-fffffffffffe |\n| 93aac041-1a14-11ec-ab4e-f859713e4be4 |\n| ea0368d3-1a14-11ec-ab4e-f859713e4be4 |\n| ff5b6bcc-1a14-11ec-ab4e-f859713e4be4 |\n+--------------------------------------+\n\nValid and invalid hyphen and brace usage:\n\nTRUNCATE t1;\n\nINSERT INTO t1 VALUES (\'f8aa-ed66-1a1b-11ec-ab4e-f859-713e-4be4\');\n\nINSERT INTO t1 VALUES (\'1b80667f1a1c-11ecab4ef859713e4be4\');\n\nINSERT INTO t1 VALUES (\'2fd6c945-1a-1c-11ec-ab4e-f859713e4be4\');\n\nINSERT INTO t1 VALUES (\'49-c9-f9-59-1a-1c-11ec-ab4e-f859713e4be4\');\n\nINSERT INTO t1 VALUES (\'57-96-da-c1-1a-1c-11-ec-ab-4e-f8-59-71-3e-4b-e4\');\n\nINSERT INTO t1 VALUES (\'6-eb74f8f-1a1c-11ec-ab4e-f859713e4be4\');\n\nINSERT INTO t1 VALUES (\'{29bad136-1a1d-11ec-ab4e-f859713e4be4}\');\nERROR 1292 (22007): Incorrect uuid value:\n\'{29bad136-1a1d-11ec-ab4e-f859713e4be4}\' \n for column `test`.`t1`.`id` at row 1\n\nSELECT * FROM t1;\n+--------------------------------------+\n| id |\n+--------------------------------------+\n| f8aaed66-1a1b-11ec-ab4e-f859713e4be4 |\n| 1b80667f-1a1c-11ec-ab4e-f859713e4be4 |\n| 2fd6c945-1a1c-11ec-ab4e-f859713e4be4 |\n| 49c9f959-1a1c-11ec-ab4e-f859713e4be4 |\n| 5796dac1-1a1c-11ec-ab4e-f859713e4be4 |\n| 6eb74f8f-1a1c-11ec-ab4e-f859713e4be4 |\n+--------------------------------------+\n\nURL: https://mariadb.com/kb/en/uuid-data-type/','','https://mariadb.com/kb/en/uuid-data-type/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (291,23,'DATE','Syntax\n------\n\nDATE\n\nDescription\n-----------\n\nA date. The supported range is \'1000-01-01\' to \'9999-12-31\'. MariaDB displays\nDATE values in \'YYYY-MM-DD\' format, but can be assigned dates in looser\nformats, including strings or numbers, as long as they make sense. These\ninclude a short year, YY-MM-DD, no delimiters, YYMMDD, or any other acceptable\ndelimiter, for example YYYY/MM/DD. For details, see date and time literals.\n\n\'0000-00-00\' is a permitted special value (zero-date), unless the NO_ZERO_DATE\nSQL_MODE is used. Also, individual components of a date can be set to 0 (for\nexample: \'2015-00-12\'), unless the NO_ZERO_IN_DATE SQL_MODE is used. In many\ncases, the result of en expression involving a zero-date, or a date with\nzero-parts, is NULL. If the ALLOW_INVALID_DATES SQL_MODE is enabled, if the\nday part is in the range between 1 and 31, the date does not produce any\nerror, even for months that have less than 31 days.\n\nOracle Mode\n-----------\n\nMariaDB starting with 10.3\n--------------------------\nIn Oracle mode from MariaDB 10.3, DATE with a time portion is a synonym for\nDATETIME. See also mariadb_schema.\n\nExamples\n--------\n\nCREATE TABLE t1 (d DATE);\n\nINSERT INTO t1 VALUES (\"2010-01-12\"), (\"2011-2-28\"), (\'120314\'),(\'13*04*21\');\n\nSELECT * FROM t1;\n+------------+\n| d |\n+------------+\n| 2010-01-12 |\n| 2011-02-28 |\n| 2012-03-14 |\n| 2013-04-21 |\n+------------+\n\nURL: https://mariadb.com/kb/en/date/','','https://mariadb.com/kb/en/date/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (292,23,'TIME','Syntax\n------\n\nTIME [(<microsecond precision>)]\n\nDescription\n-----------\n\nA time. The range is \'-838:59:59.999999\' to \'838:59:59.999999\'. Microsecond\nprecision can be from 0-6; if not specified 0 is used. Microseconds have been\navailable since MariaDB 5.3.\n\nMariaDB displays TIME values in \'HH:MM:SS.ssssss\' format, but allows\nassignment of times in looser formats, including \'D HH:MM:SS\', \'HH:MM:SS\',\n\'HH:MM\', \'D HH:MM\', \'D HH\', \'SS\', or \'HHMMSS\', as well as permitting dropping\nof any leading zeros when a delimiter is provided, for example \'3:9:10\'. For\ndetails, see date and time literals.\n\nMariaDB 10.1.2 introduced the --mysql56-temporal-format option, on by default,\nwhich allows MariaDB to store TIMEs using the same low-level format MySQL 5.6\nuses.\n\nInternal Format\n---------------\n\nIn MariaDB 10.1.2 a new temporal format was introduced from MySQL 5.6 that\nalters how the TIME, DATETIME and TIMESTAMP columns operate at lower levels.\nThese changes allow these temporal data types to have fractional parts and\nnegative values. You can disable this feature using the\nmysql56_temporal_format system variable.\n\nTables that include TIMESTAMP values that were created on an older version of\nMariaDB or that were created while the mysql56_temporal_format system variable\nwas disabled continue to store data using the older data type format.\n\nIn order to update table columns from the older format to the newer format,\nexecute an ALTER TABLE... MODIFY COLUMN statement that changes the column to\nthe *same* data type. This change may be needed if you want to export the\ntable\'s tablespace and import it onto a server that has\nmysql56_temporal_format=ON set (see MDEV-15225).\n\nFor instance, if you have a TIME column in your table:\n\nSHOW VARIABLES LIKE \'mysql56_temporal_format\';\n\n+-------------------------+-------+\n| Variable_name | Value |\n+-------------------------+-------+\n| mysql56_temporal_format | ON |\n+-------------------------+-------+\n\nALTER TABLE example_table MODIFY ts_col TIME;\n\nWhen MariaDB executes the ALTER TABLE statement, it converts the data from the\nolder temporal format to the newer one.\n\nIn the event that you have several tables and columns using temporal data\ntypes that you want to switch over to the new format, make sure the system\nvariable is enabled, then perform a dump and restore using mariadb-dump. The\ncolumns using relevant temporal data types are restored using the new temporal\nformat.\n\nStarting from MariaDB 10.5.1 columns with old temporal formats are marked with\na /* mariadb-5.3 */ comment in the output of SHOW CREATE TABLE, SHOW COLUMNS,\nDESCRIBE statements, as well as in the COLUMN_TYPE column of the\nINFORMATION_SCHEMA.COLUMNS Table.\n\nSHOW CREATE TABLE mariadb5312_time\\G\n*************************** 1. row ***************************\n Table: mariadb5312_time\nCreate Table: CREATE TABLE `mariadb5312_time` (\n `t0` time /* mariadb-5.3 */ DEFAULT NULL,\n `t6` time(6) /* mariadb-5.3 */ DEFAULT NULL\n) ENGINE=MyISAM DEFAULT CHARSET=latin1\n\nNote, columns with the current format are not marked with a comment.\n\nExamples\n--------\n\nINSERT INTO time VALUES (\'90:00:00\'), (\'800:00:00\'), (800), (22), (151413),\n(\'9:6:3\'), (\'12 09\');\n\nSELECT * FROM time;\n+-----------+\n| t |\n+-----------+\n| 90:00:00 |\n| 800:00:00 |\n| 00:08:00 |\n| 00:00:22 |\n| 15:14:13 |\n| 09:06:03 |\n| 297:00:00 |\n+-----------+\n\nURL: https://mariadb.com/kb/en/time/','','https://mariadb.com/kb/en/time/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (293,23,'DATETIME','Syntax\n------\n\nDATETIME [(microsecond precision)]\n\nDescription\n-----------\n\nA date and time combination.\n\nMariaDB displays DATETIME values in \'YYYY-MM-DD HH:MM:SS.ffffff\' format, but\nallows assignment of values to DATETIME columns using either strings or\nnumbers. For details, see date and time literals.\n\nDATETIME columns also accept CURRENT_TIMESTAMP as the default value.\n\nMariaDB 10.1.2 introduced the --mysql56-temporal-format option, on by default,\nwhich allows MariaDB to store DATETMEs using the same low-level format MySQL\n5.6 uses. For more information, see Internal Format, below.\n\nFor storage requirements, see Data Type Storage Requirements.\n\nSupported Values\n----------------\n\nMariaDB stores values that use the DATETIME data type in a format that\nsupports values between 1000-01-01 00:00:00.000000 and 9999-12-31\n23:59:59.999999.\n\nMariaDB can also store microseconds with a precision between 0 and 6. If no\nmicrosecond precision is specified, then 0 is used by default.\n\nMariaDB also supports \'0000-00-00\' as a special zero-date value, unless\nNO_ZERO_DATE is specified in the SQL_MODE. Similarly, individual components of\na date can be set to 0 (for example: \'2015-00-12\'), unless NO_ZERO_IN_DATE is\nspecified in the SQL_MODE. In many cases, the result of en expression\ninvolving a zero-date, or a date with zero-parts, is NULL. If the\nALLOW_INVALID_DATES SQL_MODE is enabled, if the day part is in the range\nbetween 1 and 31, the date does not produce any error, even for months that\nhave less than 31 days.\n\nOracle Mode\n-----------\n\nMariaDB starting with 10.3\n--------------------------\nIn Oracle mode from MariaDB 10.3, DATE with a time portion is a synonym for\nDATETIME. See also mariadb_schema.\n\nInternal Format\n---------------\n\nIn MariaDB 10.1.2 a new temporal format was introduced from MySQL 5.6 that\nalters how the TIME, DATETIME and TIMESTAMP columns operate at lower levels.\nThese changes allow these temporal data types to have fractional parts and\nnegative values. You can disable this feature using the\nmysql56_temporal_format system variable.\n\nTables that include TIMESTAMP values that were created on an older version of\nMariaDB or that were created while the mysql56_temporal_format system variable\nwas disabled continue to store data using the older data type format.\n\nIn order to update table columns from the older format to the newer format,\nexecute an ALTER TABLE... MODIFY COLUMN statement that changes the column to\nthe *same* data type. This change may be needed if you want to export the\ntable\'s tablespace and import it onto a server that has\nmysql56_temporal_format=ON set (see MDEV-15225).\n\nFor instance, if you have a DATETIME column in your table:\n\nSHOW VARIABLES LIKE \'mysql56_temporal_format\';\n\n+-------------------------+-------+\n| Variable_name | Value |\n+-------------------------+-------+\n| mysql56_temporal_format | ON |\n+-------------------------+-------+\n\nALTER TABLE example_table MODIFY ts_col DATETIME;\n\nWhen MariaDB executes the ALTER TABLE statement, it converts the data from the\nolder temporal format to the newer one.\n\nIn the event that you have several tables and columns using temporal data\ntypes that you want to switch over to the new format, make sure the system\nvariable is enabled, then perform a dump and restore using mysqldump. The\ncolumns using relevant temporal data types are restored using the new temporal\nformat.\n\nStarting from MariaDB 10.5.1 columns with old temporal formats are marked with\na /* mariadb-5.3 */ comment in the output of SHOW CREATE TABLE, SHOW COLUMNS,\nDESCRIBE statements, as well as in the COLUMN_TYPE column of the\nINFORMATION_SCHEMA.COLUMNS Table.\n\nSHOW CREATE TABLE mariadb5312_datetime\\G\n*************************** 1. row ***************************\n Table: mariadb5312_datetime\nCreate Table: CREATE TABLE `mariadb5312_datetime` (\n `dt0` datetime /* mariadb-5.3 */ DEFAULT NULL,\n `dt6` datetime(6) /* mariadb-5.3 */ DEFAULT NULL\n) ENGINE=MyISAM DEFAULT CHARSET=latin1\n\nExamples\n--------\n\nCREATE TABLE t1 (d DATETIME);\n\nINSERT INTO t1 VALUES (\"2011-03-11\"), (\"2012-04-19 13:08:22\"),\n (\"2013-07-18 13:44:22.123456\");\n\nSELECT * FROM t1;\n+---------------------+\n| d |\n+---------------------+\n| 2011-03-11 00:00:00 |\n| 2012-04-19 13:08:22 |\n| 2013-07-18 13:44:22 |\n+---------------------+\n\nCREATE TABLE t2 (d DATETIME(6));\n\nINSERT INTO t2 VALUES (\"2011-03-11\"), (\"2012-04-19 13:08:22\"),\n (\"2013-07-18 13:44:22.123456\");\n\nSELECT * FROM t2;\n+----------------------------+\n| d |\n+----------------------------+\n| 2011-03-11 00:00:00.000000 |\n| 2012-04-19 13:08:22.000000 |\n| 2013-07-18 13:44:22.123456 |\n+----------------------------++\n\nStrings used in datetime context are automatically converted to datetime(6).\nIf you want to have a datetime without seconds, you should use\nCONVERT(..,datetime).\n\nSELECT CONVERT(\'2007-11-30 10:30:19\',datetime);\n+-----------------------------------------+\n| CONVERT(\'2007-11-30 10:30:19\',datetime) |\n+-----------------------------------------+\n| 2007-11-30 10:30:19 |\n+-----------------------------------------+\n\nSELECT CONVERT(\'2007-11-30 10:30:19\',datetime(6));\n+--------------------------------------------+\n| CONVERT(\'2007-11-30 10:30:19\',datetime(6)) |\n+--------------------------------------------+\n| 2007-11-30 10:30:19.000000 |\n+--------------------------------------------+\n\nURL: https://mariadb.com/kb/en/datetime/','','https://mariadb.com/kb/en/datetime/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (294,23,'TIMESTAMP','Syntax\n------\n\nTIMESTAMP [(<microsecond precision)]\n\nDescription\n-----------\n\nA timestamp in the format YYYY-MM-DD HH:MM:SS.ffffff.\n\nThe timestamp field is generally used to define at which moment in time a row\nwas added or updated and by default will automatically be assigned the current\ndatetime when a record is inserted or updated. The automatic properties only\napply to the first TIMESTAMP in the record; subsequent TIMESTAMP columns will\nnot be changed.\n\nMariaDB includes the --mysql56-temporal-format option, on by default, which\nallows MariaDB to store TIMESTAMPs using the same low-level format MySQL 5.6\nuses.\n\nFor more information, see Internal Format.\n\nSupported Values\n----------------\n\nMariaDB stores values that use the TIMESTAMP data type as the number of\nseconds since \'1970-01-01 00:00:00\' (UTC). This means that the TIMESTAMP data\ntype can hold values between \'1970-01-01 00:00:01\' (UTC) and \'2038-01-19\n03:14:07\' (UTC).\n\nMariaDB can also store microseconds with a precision between 0 and 6. If no\nmicrosecond precision is specified, then 0 is used by default.\n\nAutomatic Values\n----------------\n\nMariaDB has special behavior for the first column that uses the TIMESTAMP data\ntype in a specific table when the system variable\nexplicit_defaults_for_timestamp is not set (which is the default until MariaDB\n10.10). For the first column that uses the TIMESTAMP data type in a specific\ntable, MariaDB automatically assigns the following properties to the column:\n\n* DEFAULT CURRENT_TIMESTAMP\n* ON UPDATE CURRENT_TIMESTAMP\n\nThis means that if the column is not explicitly assigned a value in an INSERT\nor UPDATE query, then MariaDB will automatically initialize the column\'s value\nwith the current date and time.\n\nThis automatic initialization for INSERT and UPDATE queries can also be\nexplicitly enabled for a column that uses the TIMESTAMP data type by\nspecifying the DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP\nclauses for the column. In these clauses, any synonym of CURRENT_TIMESTAMP is\naccepted, including CURRENT_TIMESTAMP(), NOW(), LOCALTIME, LOCALTIME(),\nLOCALTIMESTAMP, and LOCALTIMESTAMP().\n\nThis automatic initialization for INSERT queries can also be explicitly\ndisabled for a column that uses the TIMESTAMP data type by specifying a\nconstant DEFAULT value. For example, DEFAULT 0.\n\nThis automatic initialization for UPDATE queries can also be explicitly\ndisabled for a column that uses the TIMESTAMP data type by specifying a\nDEFAULT clause for the column, but no ON UPDATE clause. If a DEFAULT clause is\nexplicitly specified for a column that uses the TIMESTAMP data type, but an ON\nUPDATE clause is not specified for the column, then the timestamp value will\nnot automatically change when an UPDATE statement is executed.\n\nMariaDB also has special behavior if NULL is assigned to column that uses the\nTIMESTAMP data type. If the column is assigned the NULL value in an INSERT or\nUPDATE query, then MariaDB will automatically initialize the column\'s value\nwith the current date and time. For details, see NULL values in MariaDB.\n\nThis automatic initialization for NULL values can also be explicitly disabled\nfor a column that uses the TIMESTAMP data type by specifying the NULL\nattribute for the column. In this case, if the column\'s value is set to NULL,\nthen the column\'s value will actually be set to NULL.\n\nTime Zones\n----------\n\nIf a column uses the TIMESTAMP data type, then any inserted values are\nconverted from the session\'s time zone to Coordinated Universal Time (UTC)\nwhen stored, and converted back to the session\'s time zone when retrieved.\n\nMariaDB validates TIMESTAMP literals against the session\'s time zone. For\nexample, if a specific time range never occurred in a specific time zone due\nto daylight savings time, then TIMESTAMP values within that range would be\ninvalid for that time zone.\n\nMariaDB does not currently store any time zone identifier with the value of\nthe TIMESTAMP data type. See MDEV-10018 for more information.\n\nMariaDB does not currently support time zone literals that contain time zone\nidentifiers. See MDEV-11829 for more information.\n\nLimitations\n-----------\n\n* Because the TIMESTAMP value is stored as Epoch Seconds, the timestamp value\n\'1970-01-01 00:00:00\' (UTC) is reserved since the second #0 is used to\nrepresent \'0000-00-00 00:00:00\'.\n* In MariaDB 5.5 and before there could only be one TIMESTAMP column per table\nthat had CURRENT_TIMESTAMP defined as its default value. This limit has no\nlonger applied since MariaDB 10.0.\n\nSQL_MODE=MAXDB\n--------------\n\nIf the SQL_MODE is set to MAXDB, TIMESTAMP fields will be silently converted\nto DATETIME.\n\nInternal Format\n---------------\n\nIn MariaDB 10.1.2 a new temporal format was introduced from MySQL 5.6 that\nalters how the TIME, DATETIME and TIMESTAMP columns operate at lower levels.\nThese changes allow these temporal data types to have fractional parts and\nnegative values. You can disable this feature using the\nmysql56_temporal_format system variable.\n\nTables that include TIMESTAMP values that were created on an older version of\nMariaDB or that were created while the mysql56_temporal_format system variable\nwas disabled continue to store data using the older data type format.\n\nIn order to update table columns from the older format to the newer format,\nexecute an ALTER TABLE... MODIFY COLUMN statement that changes the column to\nthe *same* data type. This change may be needed if you want to export the\ntable\'s tablespace and import it onto a server that has\nmysql56_temporal_format=ON set (see MDEV-15225).\n\nFor instance, if you have a TIMESTAMP column in your table:\n\nSHOW VARIABLES LIKE \'mysql56_temporal_format\';\n\n+-------------------------+-------+\n| Variable_name | Value |\n+-------------------------+-------+\n| mysql56_temporal_format | ON |\n+-------------------------+-------+\n\nALTER TABLE example_table MODIFY ts_col TIMESTAMP;\n\nWhen MariaDB executes the ALTER TABLE statement, it converts the data from the\nolder temporal format to the newer one.\n\nIn the event that you have several tables and columns using temporal data\ntypes that you want to switch over to the new format, make sure the system\nvariable is enabled, then perform a dump and restore using mysqldump. The\ncolumns using relevant temporal data types are restored using the new temporal\nformat.\n\nStarting from MariaDB 10.5.1 columns with old temporal formats are marked with\na /* mariadb-5.3 */ comment in the output of SHOW CREATE TABLE, SHOW COLUMNS,\nDESCRIBE statements, as well as in the COLUMN_TYPE column of the\nINFORMATION_SCHEMA.COLUMNS Table.\n\nSHOW CREATE TABLE mariadb5312_timestamp\\G\n*************************** 1. row ***************************\n Table: mariadb5312_timestamp\nCreate Table: CREATE TABLE `mariadb5312_timestamp` (\n `ts0` timestamp /* mariadb-5.3 */ NOT NULL DEFAULT current_timestamp() ON\nUPDATE current_timestamp(),\n `ts6` timestamp(6) /* mariadb-5.3 */ NOT NULL DEFAULT \'0000-00-00\n00:00:00.000000\'\n) ENGINE=MyISAM DEFAULT CHARSET=latin1\n\nNote: Prior to MySQL 4.1 a different format for the TIMESTAMP datatype was\nused. This format is unsupported in MariaDB 5.1 and upwards.\n\nExamples\n--------\n\nCREATE TABLE t (id INT, ts TIMESTAMP);\n\nDESC t;\n+-------+-----------+------+-----+-------------------+-------------------------\n---+\n| Field | Type | Null | Key | Default | Extra \n |\n+-------+-----------+------+-----+-------------------+-------------------------\n---+\n| id | int(11) | YES | | NULL | \n |\n| ts | timestamp | NO | | CURRENT_TIMESTAMP | on update\nCURRENT_TIMESTAMP |\n+-------+-----------+------+-----+-------------------+-------------------------\n---+\n\nINSERT INTO t(id) VALUES (1),(2);\n\nSELECT * FROM t;\n+------+---------------------+\n| id | ts |\n+------+---------------------+\n| 1 | 2013-07-22 12:50:05 |\n| 2 | 2013-07-22 12:50:05 |\n+------+---------------------+\n\nINSERT INTO t VALUES (3,NULL),(4,\'2001-07-22 12:12:12\');\n\nSELECT * FROM t;\n+------+---------------------+\n| id | ts |\n+------+---------------------+\n| 1 | 2013-07-22 12:50:05 |\n| 2 | 2013-07-22 12:50:05 |\n| 3 | 2013-07-22 12:51:56 |\n| 4 | 2001-07-22 12:12:12 |\n+------+---------------------+\n\nConverting to Unix epoch:\n\nSELECT ts, UNIX_TIMESTAMP(ts) FROM t;\n+---------------------+--------------------+\n| ts | UNIX_TIMESTAMP(ts) |\n+---------------------+--------------------+\n| 2013-07-22 12:50:05 | 1374490205 |\n| 2013-07-22 12:50:05 | 1374490205 |\n| 2013-07-22 12:51:56 | 1374490316 |\n| 2001-07-22 12:12:12 | 995796732 |\n+---------------------+--------------------+\n\nUpdate also changes the timestamp:\n\nUPDATE t set id=5 WHERE id=1;\n\nSELECT * FROM t;\n+------+---------------------+\n| id | ts |\n+------+---------------------+\n| 5 | 2013-07-22 14:52:33 |\n| 2 | 2013-07-22 12:50:05 |\n| 3 | 2013-07-22 12:51:56 |\n| 4 | 2001-07-22 12:12:12 |\n+------+---------------------+\n\nDefault NULL:\n\nCREATE TABLE t2 (id INT, ts TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP);\n\nINSERT INTO t(id) VALUES (1),(2);\n\nSELECT * FROM t2;\n\nINSERT INTO t2(id) VALUES (1),(2);\n\nSELECT * FROM t2;\n+------+------+\n| id | ts |\n+------+------+\n| 1 | NULL |\n| 2 | NULL |\n+------+------+\n\nUPDATE t2 SET id=3 WHERE id=1;\n\nSELECT * FROM t2;\n+------+---------------------+\n| id | ts |\n+------+---------------------+\n| 3 | 2013-07-22 15:32:22 |\n| 2 | NULL |\n+------+---------------------+\n\nOnly the first timestamp is automatically inserted and updated:\n\nCREATE TABLE t3 (id INT, ts1 TIMESTAMP, ts2 TIMESTAMP);\n\nINSERT INTO t3(id) VALUES (1),(2);\n\nSELECT * FROM t3;\n+------+---------------------+---------------------+\n| id | ts1 | ts2 |\n+------+---------------------+---------------------+\n| 1 | 2013-07-22 15:35:07 | 0000-00-00 00:00:00 |\n| 2 | 2013-07-22 15:35:07 | 0000-00-00 00:00:00 |\n+------+---------------------+---------------------+\n\nDESC t3;\n+-------+-----------+------+-----+---------------------+-----------------------\n-----+\n| Field | Type | Null | Key | Default | Extra \n |\n+-------+-----------+------+-----+---------------------+-----------------------\n-----+\n| id | int(11) | YES | | NULL | \n |\n| ts1 | timestamp | NO | | CURRENT_TIMESTAMP | on update\nCURRENT_TIMESTAMP |\n| ts2 | timestamp | NO | | 0000-00-00 00:00:00 | \n |\n+-------+-----------+------+-----+---------------------+-----------------------\n-----+\n\nExplicitly setting a timestamp with the CURRENT_TIMESTAMP function:\n\nINSERT INTO t3(id,ts2) VALUES (3,CURRENT_TIMESTAMP());\n\nSELECT * FROM t3;\n+------+---------------------+---------------------+\n| id | ts1 | ts2 |\n+------+---------------------+---------------------+\n| 1 | 2013-07-22 15:35:07 | 0000-00-00 00:00:00 |\n| 2 | 2013-07-22 15:35:07 | 0000-00-00 00:00:00 |\n| 3 | 2013-07-22 15:38:52 | 2013-07-22 15:38:52 |\n+------+---------------------+---------------------+\n\nSpecifying the timestamp as NOT NULL:\n\nCREATE TABLE t4 (id INT, ts TIMESTAMP NOT NULL);\n\nINSERT INTO t4(id) VALUES (1);\nSELECT SLEEP(1);\nINSERT INTO t4(id,ts) VALUES (2,NULL);\n\nSELECT * FROM t4;\n\nURL: https://mariadb.com/kb/en/timestamp/','','https://mariadb.com/kb/en/timestamp/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (295,23,'YEAR Data Type','Syntax\n------\n\nYEAR[(4)]\n\nDescription\n-----------\n\nA year in two-digit or four-digit format. The default is four-digit format.\nNote that the two-digit format has been deprecated since MariaDB 5.5.27.\n\nIn four-digit format, the allowable values are 1901 to 2155, and 0000. In\ntwo-digit format, the allowable values are 70 to 69, representing years from\n1970 to 2069. MariaDB displays YEAR values in YYYY format, but allows you to\nassign values to YEAR columns using either strings or numbers.\n\nInserting numeric zero has a different result for YEAR(4) and YEAR(2). For\nYEAR(2), the value 00 reflects the year 2000. For YEAR(4), the value 0000\nreflects the year zero. This only applies to numeric zero. String zero always\nreflects the year 2000.\n\nExamples\n--------\n\nAccepting a string or a number:\n\nCREATE TABLE y(y YEAR);\n\nINSERT INTO y VALUES (1990),(\'2012\');\n\nSELECT * FROM y;\n+------+\n| y |\n+------+\n| 1990 |\n| 2012 |\n+------+\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nOut of range:\n\nINSERT INTO y VALUES (1005),(\'3080\');\nERROR 1264 (22003): Out of range value for column \'y\' at row 1\n\nINSERT INTO y VALUES (\'2013-12-12\');\nERROR 1265 (01000): Data truncated for column \'y\' at row 1\n\nSELECT * FROM y;\n+------+\n| y |\n+------+\n| 1990 |\n| 2012 |\n+------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nOut of range:\n\nINSERT INTO y VALUES (1005),(\'3080\');\nQuery OK, 2 rows affected, 2 warnings (0.05 sec)\nRecords: 2 Duplicates: 0 Warnings: 2\n\nSHOW WARNINGS;\n+---------+------+--------------------------------------------+\n| Level | Code | Message |\n+---------+------+--------------------------------------------+\n| Warning | 1264 | Out of range value for column \'y\' at row 1 |\n| Warning | 1264 | Out of range value for column \'y\' at row 2 |\n+---------+------+--------------------------------------------+\n\nSELECT * FROM y;\n+------+\n| y |\n+------+\n| 1990 |\n| 2012 |\n| 0000 |\n| 0000 |\n+------+\n\nTruncating:\n\nINSERT INTO y VALUES (\'2013-12-12\');\nQuery OK, 1 row affected, 1 warning (0.05 sec)\n\nSHOW WARNINGS;\n+---------+------+----------------------------------------+\n| Level | Code | Message |\n+---------+------+----------------------------------------+\n| Warning | 1265 | Data truncated for column \'y\' at row 1 |\n+---------+------+----------------------------------------+\n\nSELECT * FROM y;\n+------+\n| y |\n+------+\n| 1990 |\n| 2012 |\n| 0000 |\n| 0000 |\n| 2013 |\n+------+\n\nDifference between YEAR(2) and YEAR(4), and string and numeric zero:\n\nCREATE TABLE y2(y YEAR(4), y2 YEAR(2));\nQuery OK, 0 rows affected, 1 warning (0.40 sec)\n\nNote (Code 1287): \'YEAR(2)\' is deprecated and will be removed in a future\nrelease. \n Please use YEAR(4) instead\n\nINSERT INTO y2 VALUES(0,0),(\'0\',\'0\');\n\nSELECT YEAR(y),YEAR(y2) FROM y2;\n+---------+----------+\n| YEAR(y) | YEAR(y2) |\n+---------+----------+\n| 0 | 2000 |\n| 2000 | 2000 |\n+---------+----------+\n\nURL: https://mariadb.com/kb/en/year-data-type/','','https://mariadb.com/kb/en/year-data-type/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (296,23,'AUTO_INCREMENT','Description\n-----------\n\nThe AUTO_INCREMENT attribute can be used to generate a unique identity for new\nrows. When you insert a new record to the table (or upon adding an\nAUTO_INCREMENT attribute with the ALTER TABLE statement), and the\nauto_increment field is NULL or DEFAULT (in the case of an INSERT), the value\nwill automatically be incremented. This also applies to 0, unless the\nNO_AUTO_VALUE_ON_ZERO SQL_MODE is enabled.\n\nAUTO_INCREMENT columns start from 1 by default. The automatically generated\nvalue can never be lower than 0.\n\nEach table can have only one AUTO_INCREMENT column. It must defined as a key\n(not necessarily the PRIMARY KEY or UNIQUE key). In some storage engines\n(including the default InnoDB), if the key consists of multiple columns, the\nAUTO_INCREMENT column must be the first column. Storage engines that permit\nthe column to be placed elsewhere are Aria, MyISAM, MERGE, Spider, TokuDB,\nBLACKHOLE, FederatedX and Federated.\n\nCREATE TABLE animals (\n id MEDIUMINT NOT NULL AUTO_INCREMENT,\n name CHAR(30) NOT NULL,\n PRIMARY KEY (id)\n );\n\nINSERT INTO animals (name) VALUES\n (\'dog\'),(\'cat\'),(\'penguin\'),\n (\'fox\'),(\'whale\'),(\'ostrich\');\n\nSELECT * FROM animals;\n+----+---------+\n| id | name |\n+----+---------+\n| 1 | dog |\n| 2 | cat |\n| 3 | penguin |\n| 4 | fox |\n| 5 | whale |\n| 6 | ostrich |\n+----+---------+\n\nSERIAL is an alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE.\n\nCREATE TABLE t (id SERIAL, c CHAR(1)) ENGINE=InnoDB;\n\nSHOW CREATE TABLE t \\G\n*************************** 1. row ***************************\n Table: t\nCreate Table: CREATE TABLE `t` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,\n `c` char(1) DEFAULT NULL,\n UNIQUE KEY `id` (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1\n\nSetting or Changing the Auto_Increment Value\n--------------------------------------------\n\nYou can use an ALTER TABLE statement to assign a new value to the\nauto_increment table option, or set the insert_id server system variable to\nchange the next AUTO_INCREMENT value inserted by the current session.\n\nLAST_INSERT_ID() can be used to see the last AUTO_INCREMENT value inserted by\nthe current session.\n\nALTER TABLE animals AUTO_INCREMENT=8;\n\nINSERT INTO animals (name) VALUES (\'aardvark\');\n\nSELECT * FROM animals;\n+----+-----------+\n| id | name |\n+----+-----------+\n| 1 | dog |\n| 2 | cat |\n| 3 | penguin |\n| 4 | fox |\n| 5 | whale |\n| 6 | ostrich |\n| 8 | aardvark |\n+----+-----------+\n\nSET insert_id=12;\n\nINSERT INTO animals (name) VALUES (\'gorilla\');\n\nSELECT * FROM animals;\n+----+-----------+\n| id | name |\n+----+-----------+\n| 1 | dog |\n| 2 | cat |\n| 3 | penguin |\n| 4 | fox |\n| 5 | whale |\n| 6 | ostrich |\n| 8 | aardvark |\n| 12 | gorilla |\n+----+-----------+\n\nInnoDB\n------\n\nUntil MariaDB 10.2.3, InnoDB used an auto-increment counter that is stored in\nmemory. When the server restarts, the counter is re-initialized to the highest\nvalue used in the table, which cancels the effects of any AUTO_INCREMENT = N\noption in the table statements.\n\nFrom MariaDB 10.2.4, this restriction has been lifted and AUTO_INCREMENT is\npersistent.\n\nSee also AUTO_INCREMENT Handling in InnoDB.\n\nSetting Explicit Values\n-----------------------\n\nIt is possible to specify a value for an AUTO_INCREMENT column. If the key is\nprimary or unique, the value must not already exist in the key.\n\nIf the new value is higher than the current maximum value, the AUTO_INCREMENT\nvalue is updated, so the next value will be higher. If the new value is lower\nthan the current maximum value, the AUTO_INCREMENT value remains unchanged.\n\nThe following example demonstrates these behaviors:\n\nCREATE TABLE t (id INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY) ENGINE =\nInnoDB;\n\nINSERT INTO t VALUES (NULL);\nSELECT id FROM t;\n+----+\n| id |\n+----+\n| 1 |\n+----+\n\nINSERT INTO t VALUES (10); -- higher value\nSELECT id FROM t;\n+----+\n| id |\n+----+\n| 1 |\n| 10 |\n+----+\n\nINSERT INTO t VALUES (2); -- lower value\nINSERT INTO t VALUES (NULL); -- auto value\nSELECT id FROM t;\n+----+\n| id |\n+----+\n| 1 |\n| 2 |\n| 10 |\n| 11 |\n+----+\n\nThe ARCHIVE storage engine does not allow to insert a value that is lower than\nthe current maximum.\n\nMissing Values\n--------------\n\nAn AUTO_INCREMENT column normally has missing values. This happens because if\na row is deleted, or an AUTO_INCREMENT value is explicitly updated, old values\nare never re-used. The REPLACE statement also deletes a row, and its value is\nwasted. With InnoDB, values can be reserved by a transaction; but if the\ntransaction fails (for example, because of a ROLLBACK) the reserved value will\nbe lost.\n\nThus AUTO_INCREMENT values can be used to sort results in a chronological\norder, but not to create a numeric sequence.\n\nReplication\n-----------\n\nTo make master-master or Galera safe to use AUTO_INCREMENT one should use the\nsystem variables auto_increment_increment and auto_increment_offset to\ngenerate unique values for each server.\n\nCHECK Constraints, DEFAULT Values and Virtual Columns\n-----------------------------------------------------\n\nMariaDB starting with 10.2.6\n----------------------------\nFrom MariaDB 10.2.6 auto_increment columns are no longer permitted in CHECK\nconstraints, DEFAULT value expressions and virtual columns. They were\npermitted in earlier versions, but did not work correctly. See MDEV-11117.\n\nGenerating Auto_Increment Values When Adding the Attribute\n----------------------------------------------------------\n\nCREATE OR REPLACE TABLE t1 (a INT);\nINSERT t1 VALUES (0),(0),(0);\nALTER TABLE t1 MODIFY a INT NOT NULL AUTO_INCREMENT PRIMARY KEY;\nSELECT * FROM t1;\n+---+\n| a |\n+---+\n| 1 |\n| 2 |\n| 3 |\n+---+\n\nCREATE OR REPLACE TABLE t1 (a INT);\nINSERT t1 VALUES (5),(0),(8),(0);\nALTER TABLE t1 MODIFY a INT NOT NULL AUTO_INCREMENT PRIMARY KEY;\nSELECT * FROM t1;\n+---+\n| a |\n+---+\n| 5 |\n| 6 |\n| 8 |\n| 9 |\n+---+\n\nIf the NO_AUTO_VALUE_ON_ZERO SQL_MODE is set, zero values will not be\nautomatically incremented:\n\nSET SQL_MODE=\'no_auto_value_on_zero\';\nCREATE OR REPLACE TABLE t1 (a INT);\nINSERT t1 VALUES (3), (0);\nALTER TABLE t1 MODIFY a INT NOT NULL AUTO_INCREMENT PRIMARY KEY;\nSELECT * FROM t1;\n+---+\n| a |\n+---+\n| 0 |\n| 3 |\n+---+\n\nURL: https://mariadb.com/kb/en/auto_increment/','','https://mariadb.com/kb/en/auto_increment/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (297,24,'Using Compound Statements Outside of Stored Programs','Compound statements can also be used outside of stored programs.\n\ndelimiter |\nIF @have_innodb THEN\n CREATE TABLE IF NOT EXISTS innodb_index_stats (\n database_name VARCHAR(64) NOT NULL,\n table_name VARCHAR(64) NOT NULL,\n index_name VARCHAR(64) NOT NULL,\n last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE\nCURRENT_TIMESTAMP,\n stat_name VARCHAR(64) NOT NULL,\n stat_value BIGINT UNSIGNED NOT NULL,\n sample_size BIGINT UNSIGNED,\n stat_description VARCHAR(1024) NOT NULL,\n PRIMARY KEY (database_name, table_name, index_name, stat_name)\n ) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0;\nEND IF|\nQuery OK, 0 rows affected, 2 warnings (0.00 sec)\n\nNote, that using compound statements this way is subject to following\nlimitations:\n\n* Only BEGIN, IF, CASE, LOOP, WHILE, REPEAT statements may start a compound\nstatement outside of stored programs.\n* BEGIN must use the BEGIN NOT ATOMIC syntax (otherwise it\'ll be confused with\nBEGIN that starts a transaction).\n* A compound statement might not start with a label.\n* A compound statement is parsed completely—note \"2 warnings\" in the above\nexample, even if the condition was false (InnoDB was, indeed, disabled), and\nthe CREATE TABLE statement was not executed, it was still parsed and the\nparser produced \"Unknown storage engine\" warning.\n\nInside a compound block first three limitations do not apply, one can use\nanything that can be used inside a stored program — including labels,\ncondition handlers, variables, and so on:\n\nBEGIN NOT ATOMIC\n DECLARE foo CONDITION FOR 1146;\n DECLARE x INT DEFAULT 0;\n DECLARE CONTINUE HANDLER FOR SET x=1;\n INSERT INTO test.t1 VALUES (\"hndlr1\", val, 2);\n END|\n\nExample how to use IF:\n\nIF (1>0) THEN BEGIN NOT ATOMIC SELECT 1; END ; END IF;;\n\nExample of how to use WHILE loop:\n\nDELIMITER |\nBEGIN NOT ATOMIC\n DECLARE x INT DEFAULT 0;\n WHILE x <= 10 DO\n SET x = x + 1;\n SELECT x;\n END WHILE;\nEND|\nDELIMITER ;\n\nURL:\nhttps://mariadb.com/kb/en/using-compound-statements-outside-of-stored-programs/','','https://mariadb.com/kb/en/using-compound-statements-outside-of-stored-programs/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (298,24,'BEGIN END','Syntax\n------\n\n[begin_label:] BEGIN [NOT ATOMIC]\n [statement_list]\nEND [end_label]\n\nNOT ATOMIC is required when used outside of a stored procedure. Inside stored\nprocedures or within an anonymous block, BEGIN alone starts a new anonymous\nblock.\n\nDescription\n-----------\n\nBEGIN ... END syntax is used for writing compound statements. A compound\nstatement can contain multiple statements, enclosed by the BEGIN and END\nkeywords. statement_list represents a list of one or more statements, each\nterminated by a semicolon (i.e., ;) statement delimiter. statement_list is\noptional, which means that the empty compound statement (BEGIN END) is legal.\n\nNote that END will perform a commit. If you are running in autocommit mode,\nevery statement will be committed separately. If you are not running in\nautocommit mode, you must execute a COMMIT or ROLLBACK after END to get the\ndatabase up to date.\n\nUse of multiple statements requires that a client is able to send statement\nstrings containing the ; statement delimiter. This is handled in the mysql\ncommand-line client with the DELIMITER command. Changing the ;\nend-of-statement delimiter (for example, to //) allows ; to be used in a\nprogram body.\n\nA compound statement within a stored program can be labeled. end_label cannot\nbe given unless begin_label also is present. If both are present, they must be\nthe same.\n\nBEGIN ... END constructs can be nested. Each block can define its own\nvariables, a CONDITION, a HANDLER and a CURSOR, which don\'t exist in the outer\nblocks. The most local declarations override the outer objects which use the\nsame name (see example below).\n\nThe declarations order is the following:\n\n* DECLARE local variables;\n* DECLARE CONDITIONs;\n* DECLARE CURSORs;\n* DECLARE HANDLERs;\n\nNote that DECLARE HANDLER contains another BEGIN ... END construct.\n\nHere is an example of a very simple, anonymous block:\n\nBEGIN NOT ATOMIC\nSET @a=1;\nCREATE TABLE test.t1(a INT);\nEND|\n\nBelow is an example of nested blocks in a stored procedure:\n\nCREATE PROCEDURE t( )\nBEGIN\n DECLARE x TINYINT UNSIGNED DEFAULT 1;\n BEGIN\n DECLARE x CHAR(2) DEFAULT \'02\';\n DECLARE y TINYINT UNSIGNED DEFAULT 10;\n SELECT x, y;\n END;\n SELECT x;\nEND;\n\nIn this example, a TINYINT variable, x is declared in the outter block. But in\nthe inner block x is re-declared as a CHAR and an y variable is declared. The\ninner SELECT shows the \"new\" value of x, and the value of y. But when x is\nselected in the outer block, the \"old\" value is returned. The final SELECT\ndoesn\'t try to read y, because it doesn\'t exist in that context.\n\nURL: https://mariadb.com/kb/en/begin-end/','','https://mariadb.com/kb/en/begin-end/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (299,24,'CASE Statement','Syntax\n------\n\nCASE case_value\n WHEN when_value THEN statement_list\n [WHEN when_value THEN statement_list] ...\n [ELSE statement_list]\nEND CASE\n\nOr:\n\nCASE\n WHEN search_condition THEN statement_list\n [WHEN search_condition THEN statement_list] ...\n [ELSE statement_list]\nEND CASE\n\nDescription\n-----------\n\nThe text on this page describes the CASE statement for stored programs. See\nthe CASE OPERATOR for details on the CASE operator outside of stored programs.\n\nThe CASE statement for stored programs implements a complex conditional\nconstruct. If a search_condition evaluates to true, the corresponding SQL\nstatement list is executed. If no search condition matches, the statement list\nin the ELSE clause is executed. Each statement_list consists of one or more\nstatements.\n\nThe CASE statement cannot have an ELSE NULL clause, and it is terminated with\nEND CASE instead of END. implements a complex conditional construct. If a\nsearch_condition evaluates to true, the corresponding SQL statement list is\nexecuted. If no search condition matches, the statement list in the ELSE\nclause is executed. Each statement_list consists of one or more statements.\n\nIf no when_value or search_condition matches the value tested and the CASE\nstatement contains no ELSE clause, a Case not found for CASE statement error\nresults.\n\nEach statement_list consists of one or more statements; an empty\nstatement_list is not allowed. To handle situations where no value is matched\nby any WHEN clause, use an ELSE containing an empty BEGIN ... END block, as\nshown in this example:\n\nDELIMITER |\nCREATE PROCEDURE p()\nBEGIN\n DECLARE v INT DEFAULT 1;\n CASE v\n WHEN 2 THEN SELECT v;\n WHEN 3 THEN SELECT 0;\n ELSE BEGIN END;\n END CASE;\nEND;\n|\n\nThe indentation used here in the ELSE clause is for purposes of clarity only,\nand is not otherwise significant. See Delimiters in the mariadb client for\nmore on the use of the delimiter command.\n\nNote: The syntax of the CASE statement used inside stored programs differs\nslightly from that of the SQL CASE expression described in CASE OPERATOR. The\nCASE statement cannot have an ELSE NULL clause, and it is terminated with END\nCASE instead of END.\n\nURL: https://mariadb.com/kb/en/case-statement/','','https://mariadb.com/kb/en/case-statement/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (300,24,'DECLARE CONDITION','Syntax\n------\n\nDECLARE condition_name CONDITION FOR condition_value\n\ncondition_value:\n SQLSTATE [VALUE] sqlstate_value\n | mysql_error_code\n\nDescription\n-----------\n\nThe DECLARE ... CONDITION statement defines a named error condition. It\nspecifies a condition that needs specific handling and associates a name with\nthat condition. Later, the name can be used in a DECLARE ... HANDLER, SIGNAL\nor RESIGNAL statement (as long as the statement is located in the same BEGIN\n... END block).\n\nConditions must be declared after local variables, but before CURSORs and\nHANDLERs.\n\nA condition_value for DECLARE ... CONDITION can be an SQLSTATE value (a\n5-character string literal) or a MySQL error code (a number). You should not\nuse SQLSTATE value \'00000\' or MySQL error code 0, because those indicate\nsucess rather than an error condition. If you try, or if you specify an\ninvalid SQLSTATE value, an error like this is produced:\n\nERROR 1407 (42000): Bad SQLSTATE: \'00000\'\n\nFor a list of SQLSTATE values and MariaDB error codes, see MariaDB Error Codes.\n\nURL: https://mariadb.com/kb/en/declare-condition/','','https://mariadb.com/kb/en/declare-condition/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (301,24,'DECLARE HANDLER','Syntax\n------\n\nDECLARE handler_type HANDLER\n FOR condition_value [, condition_value] ...\n statement\n\nhandler_type:\n CONTINUE\n | EXIT\n | UNDO\n\ncondition_value:\n SQLSTATE [VALUE] sqlstate_value\n | condition_name\n | SQLWARNING\n | NOT FOUND\n | SQLEXCEPTION\n | mariadb_error_code\n\nDescription\n-----------\n\nThe DECLARE ... HANDLER statement specifies handlers that each may deal with\none or more conditions. If one of these conditions occurs, the specified\nstatement is executed. statement can be a simple statement (for example, SET\nvar_name = value), or it can be a compound statement written using BEGIN and\nEND.\n\nHandlers must be declared after local variables, a CONDITION and a CURSOR.\n\nFor a CONTINUE handler, execution of the current program continues after\nexecution of the handler statement. For an EXIT handler, execution terminates\nfor the BEGIN ... END compound statement in which the handler is declared.\n(This is true even if the condition occurs in an inner block.) The UNDO\nhandler type statement is not supported.\n\nIf a condition occurs for which no handler has been declared, the default\naction is EXIT.\n\nA condition_value for DECLARE ... HANDLER can be any of the following values:\n\n* An SQLSTATE value (a 5-character string literal) or a MariaDB error\ncode (a number). You should not use SQLSTATE value \'00000\' or MariaDB\nerror code 0, because those indicate sucess rather than an error\ncondition. For a list of SQLSTATE values and MariaDB error codes, see\nMariaDB Error Codes.\n* A condition name previously specified with DECLARE ... CONDITION. It must be\nin the same stored program. See DECLARE CONDITION.\n* SQLWARNING is shorthand for the class of SQLSTATE values that begin\nwith \'01\'.\n* NOT FOUND is shorthand for the class of SQLSTATE values that begin\nwith \'02\'. This is relevant only the context of cursors and is used to\ncontrol what happens when a cursor reaches the end of a data set. If\nno more rows are available, a No Data condition occurs with SQLSTATE\nvalue 02000. To detect this condition, you can set up a handler for it\n(or for a NOT FOUND condition). An example is shown in Cursor Overview. This\ncondition also occurs for SELECT ... INTO var_list statements that retrieve no\nrows.\n* SQLEXCEPTION is shorthand for the class of SQLSTATE values that do\nnot begin with \'00\', \'01\', or \'02\'.\n\nWhen an error raises, in some cases it could be handled by multiple HANDLERs.\nFor example, there may be an handler for 1050 error, a separate handler for\nthe 42S01 SQLSTATE, and another separate handler for the SQLEXCEPTION class:\nin theory all occurrences of HANDLER may catch the 1050 error, but MariaDB\nchooses the HANDLER with the highest precedence. Here are the precedence rules:\n\n* Handlers which refer to an error code have the highest precedence.\n* Handlers which refer to a SQLSTATE come next.\n* Handlers which refer to an error class have the lowest precedence.\n\nIn some cases, a statement could produce multiple errors. If this happens, in\nsome cases multiple handlers could have the highest precedence. In such cases,\nthe choice of the handler is indeterminate.\n\nNote that if an error occurs within a CONTINUE HANDLER block, it can be\nhandled by another HANDLER. However, a HANDLER which is already in the stack\n(that is, it has been called to handle an error and its execution didn\'t\nfinish yet) cannot handle new errors—this prevents endless loops. For example,\nsuppose that a stored procedure contains a CONTINUE HANDLER for SQLWARNING and\nanother CONTINUE HANDLER for NOT FOUND. At some point, a NOT FOUND error\noccurs, and the execution enters the NOT FOUND HANDLER. But within that\nhandler, a warning occurs, and the execution enters the SQLWARNING HANDLER. If\nanother NOT FOUND error occurs, it cannot be handled again by the NOT FOUND\nHANDLER, because its execution is not finished.\n\nWhen a DECLARE HANDLER block can handle more than one error condition, it may\nbe useful to know which errors occurred. To do so, you can use the GET\nDIAGNOSTICS statement.\n\nAn error that is handled by a DECLARE HANDLER construct can be issued again\nusing the RESIGNAL statement.\n\nBelow is an example using DECLARE HANDLER:\n\nCREATE TABLE test.t (s1 INT, PRIMARY KEY (s1));\n\nDELIMITER //\n\nCREATE PROCEDURE handlerdemo ( )\n BEGIN\n DECLARE CONTINUE HANDLER FOR SQLSTATE \'23000\' SET @x2 = 1;\n SET @x = 1;\n INSERT INTO test.t VALUES (1);\n SET @x = 2;\n INSERT INTO test.t VALUES (1);\n SET @x = 3;\n END;\n //\n\nDELIMITER ;\n\nCALL handlerdemo( );\n\nSELECT @x;\n+------+\n| @x |\n+------+\n| 3 |\n+------+\n\nURL: https://mariadb.com/kb/en/declare-handler/','','https://mariadb.com/kb/en/declare-handler/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (302,24,'DECLARE Variable','Syntax\n------\n\nDECLARE var_name [, var_name] ... [[ROW] TYPE OF]] type [DEFAULT value]\n\nDescription\n-----------\n\nThis statement is used to declare local variables within stored programs. To\nprovide a default value for the variable, include a DEFAULT clause. The value\ncan be specified as an expression (even subqueries are permitted); it need not\nbe a constant. If the DEFAULT clause is missing, the initial value is NULL.\n\nLocal variables are treated like stored routine parameters with respect to\ndata type and overflow checking. See CREATE PROCEDURE.\n\nLocal variables must be declared before CONDITIONs, CURSORs and HANDLERs.\n\nLocal variable names are not case sensitive.\n\nThe scope of a local variable is within the BEGIN ... END block where it is\ndeclared. The variable can be referred to in blocks nested within the\ndeclaring block, except those blocks that declare a variable with the same\nname.\n\nTYPE OF / ROW TYPE OF\n---------------------\n\nMariaDB starting with 10.3\n--------------------------\nTYPE OF and ROW TYPE OF anchored data types for stored routines were\nintroduced in MariaDB 10.3.\n\nAnchored data types allow a data type to be defined based on another object,\nsuch as a table row, rather than specifically set in the declaration. If the\nanchor object changes, so will the anchored data type. This can lead to\nroutines being easier to maintain, so that if the data type in the table is\nchanged, it will automatically be changed in the routine as well.\n\nVariables declared with ROW TYPE OF will have the same features as implicit\nROW variables. It is not possible to use ROW TYPE OF variables in a LIMIT\nclause.\n\nThe real data type of TYPE OF and ROW TYPE OF table_name will become known at\nthe very beginning of the stored routine call. ALTER TABLE or DROP TABLE\nstatements performed inside the current routine on the tables that appear in\nanchors won\'t affect the data type of the anchored variables, even if the\nvariable is declared after an ALTER TABLE or DROP TABLE statement.\n\nThe real data type of a ROW TYPE OF cursor_name variable will become known\nwhen execution enters into the block where the variable is declared. Data type\ninstantiation will happen only once. In a cursor ROW TYPE OF variable that is\ndeclared inside a loop, its data type will become known on the very first\niteration and won\'t change on further loop iterations.\n\nThe tables referenced in TYPE OF and ROW TYPE OF declarations will be checked\nfor existence at the beginning of the stored routine call. CREATE PROCEDURE or\nCREATE FUNCTION will not check the referenced tables for existence.\n\nExamples\n--------\n\nTYPE OF and ROW TYPE OF from MariaDB 10.3:\n\nDECLARE tmp TYPE OF t1.a; -- Get the data type from the column {{a}} in the\ntable {{t1}}\n\nDECLARE rec1 ROW TYPE OF t1; -- Get the row data type from the table {{t1}}\n\nDECLARE rec2 ROW TYPE OF cur1; -- Get the row data type from the cursor\n{{cur1}}\n\nURL: https://mariadb.com/kb/en/declare-variable/','','https://mariadb.com/kb/en/declare-variable/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (303,24,'FOR','MariaDB starting with 10.3\n--------------------------\nFOR loops were introduced in MariaDB 10.3.\n\nSyntax\n------\n\nInteger range FOR loop:\n\n[begin_label:]\nFOR var_name IN [ REVERSE ] lower_bound .. upper_bound\nDO statement_list\nEND FOR [ end_label ]\n\nExplicit cursor FOR loop\n\n[begin_label:]\nFOR record_name IN cursor_name [ ( cursor_actual_parameter_list)]\nDO statement_list\nEND FOR [ end_label ]\n\nExplicit cursor FOR loop (Oracle mode)\n\n[begin_label:]\nFOR record_name IN cursor_name [ ( cursor_actual_parameter_list)]\nLOOP\n statement_list\nEND LOOP [ end_label ]\n\nImplicit cursor FOR loop\n\n[begin_label:]\nFOR record_name IN ( select_statement )\nDO statement_list\nEND FOR [ end_label ]\n\nDescription\n-----------\n\nFOR loops allow code to be executed a fixed number of times.\n\nIn an integer range FOR loop, MariaDB will compare the lower bound and upper\nbound values, and assign the lower bound value to a counter. If REVERSE is not\nspecified, and the upper bound value is greater than or equal to the counter,\nthe counter will be incremented and the statement will continue, after which\nthe loop is entered again. If the upper bound value is greater than the\ncounter, the loop will be exited.\n\nIf REVERSE is specified, the counter is decremented, and the upper bound value\nneeds to be less than or equal for the loop to continue.\n\nExamples\n--------\n\nIntger range FOR loop:\n\nCREATE TABLE t1 (a INT);\n\nDELIMITER //\n\nFOR i IN 1..3\nDO\n INSERT INTO t1 VALUES (i);\nEND FOR;\n//\n\nDELIMITER ;\n\nSELECT * FROM t1;\n+------+\n| a |\n+------+\n| 1 |\n| 2 |\n| 3 |\n+------+\n\nREVERSE integer range FOR loop:\n\nCREATE OR REPLACE TABLE t1 (a INT);\n\nDELIMITER //\nFOR i IN REVERSE 4..12\n DO\n INSERT INTO t1 VALUES (i);\nEND FOR;\n//\nQuery OK, 9 rows affected (0.422 sec)\n\nDELIMITER ;\n\nSELECT * FROM t1;\n+------+\n| a |\n+------+\n| 12 |\n| 11 |\n| 10 |\n| 9 |\n| 8 |\n| 7 |\n| 6 |\n| 5 |\n| 4 |\n+------+\n\nExplicit cursor in Oracle mode:\n\nSET sql_mode=ORACLE;\n\nCREATE OR REPLACE TABLE t1 (a INT, b VARCHAR(32));\n\nINSERT INTO t1 VALUES (10,\'b0\');\nINSERT INTO t1 VALUES (11,\'b1\');\nINSERT INTO t1 VALUES (12,\'b2\');\n\nDELIMITER //\n\nCREATE OR REPLACE PROCEDURE p1(pa INT) AS \n CURSOR cur(va INT) IS\n SELECT a, b FROM t1 WHERE a=va;\nBEGIN\n FOR rec IN cur(pa)\n LOOP\n SELECT rec.a, rec.b;\n END LOOP;\nEND;\n//\n\nDELIMITER ;\n\nCALL p1(10);\n+-------+-------+\n| rec.a | rec.b |\n+-------+-------+\n| 10 | b0 |\n+-------+-------+\n\nCALL p1(11);\n+-------+-------+\n| rec.a | rec.b |\n+-------+-------+\n| 11 | b1 |\n+-------+-------+\n\nCALL p1(12);\n+-------+-------+\n| rec.a | rec.b |\n+-------+-------+\n| 12 | b2 |\n+-------+-------+\n\nCALL p1(13);\nQuery OK, 0 rows affected (0.000 sec)\n\nURL: https://mariadb.com/kb/en/for/','','https://mariadb.com/kb/en/for/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (304,24,'GOTO','MariaDB starting with 10.3\n--------------------------\nThe GOTO statement was introduced in MariaDB 10.3 for Oracle compatibility.\n\nSyntax\n------\n\nGOTO label\n\nDescription\n-----------\n\nThe GOTO statement causes the code to jump to the specified label, and\ncontinue operating from there. It is only accepted when in Oracle mode.\n\nExample\n-------\n\nSET sql_mode=ORACLE;\n\nDELIMITER //\n\nCREATE OR REPLACE PROCEDURE p1 AS\n\nBEGIN\n\nSELECT 1;\n GOTO label;\n SELECT 2;\n <<label>>\n SELECT 3;\n\nEND;\n\n//\n\nDELIMITER\n\ncall p1();\n+---+\n| 1 |\n+---+\n| 1 |\n+---+\n1 row in set (0.000 sec)\n\n+---+\n| 3 |\n+---+\n| 3 |\n+---+\n1 row in set (0.000 sec)\n\nURL: https://mariadb.com/kb/en/goto/','','https://mariadb.com/kb/en/goto/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (305,24,'IF','Syntax\n------\n\nIF search_condition THEN statement_list\n [ELSEIF search_condition THEN statement_list] ...\n [ELSE statement_list]\nEND IF;\n\nDescription\n-----------\n\nIF implements a basic conditional construct. If the search_condition evaluates\nto true, the corresponding SQL statement list is executed. If no\nsearch_condition matches, the statement list in the ELSE clause is executed.\nEach statement_list consists of one or more statements.\n\nURL: https://mariadb.com/kb/en/if/','','https://mariadb.com/kb/en/if/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (306,24,'ITERATE','Syntax\n------\n\nITERATE label\n\nITERATE can appear only within LOOP, REPEAT, and WHILE statements. ITERATE\nmeans \"do the loop again\", and uses the statement\'s label to determine which\nstatements to repeat. The label must be in the same stored program, not in a\ncaller procedure.\n\nIf you try to use ITERATE with a non-existing label, or if the label is\nassociated to a construct which is not a loop, the following error will be\nproduced:\n\nERROR 1308 (42000): ITERATE with no matching label: <label_name>\n\nBelow is an example of how ITERATE might be used:\n\nCREATE PROCEDURE doiterate(p1 INT)\nBEGIN\n label1: LOOP\n SET p1 = p1 + 1;\n IF p1 < 10 THEN ITERATE label1; END IF;\n LEAVE label1;\n END LOOP label1;\n SET @x = p1;\nEND\n\nURL: https://mariadb.com/kb/en/iterate/','','https://mariadb.com/kb/en/iterate/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (307,24,'Labels','Syntax\n------\n\nlabel: <construct>\n[label]\n\nLabels are MariaDB identifiers which can be used to identify a BEGIN ... END\nconstruct or a loop. They have a maximum length of 16 characters and can be\nquoted with backticks (i.e.., `).\n\nLabels have a start part and an end part. The start part must precede the\nportion of code it refers to, must be followed by a colon (:) and can be on\nthe same or different line. The end part is optional and adds nothing, but can\nmake the code more readable. If used, the end part must precede the\nconstruct\'s delimiter (;). Constructs identified by a label can be nested.\nEach construct can be identified by only one label.\n\nLabels need not be unique in the stored program they belong to. However, a\nlabel for an inner loop cannot be identical to a label for an outer loop. In\nthis case, the following error would be produced:\n\nERROR 1309 (42000): Redefining label <label_name>\n\nLEAVE and ITERATE statements can be used to exit or repeat a portion of code\nidentified by a label. They must be in the same Stored Routine, Trigger or\nEvent which contains the target label.\n\nBelow is an example using a simple label that is used to exit a LOOP:\n\nCREATE PROCEDURE `test_sp`()\nBEGIN\n `my_label`:\n LOOP\n SELECT \'looping\';\n LEAVE `my_label`;\n END LOOP;\n SELECT \'out of loop\';\nEND;\n\nThe following label is used to exit a procedure, and has an end part:\n\nCREATE PROCEDURE `test_sp`()\n`my_label`:\nBEGIN\n IF @var = 1 THEN\n LEAVE `my_label`;\n END IF;\n DO something();\nEND `my_label`;\n\nURL: https://mariadb.com/kb/en/labels/','','https://mariadb.com/kb/en/labels/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (308,24,'LEAVE','Syntax\n------\n\nLEAVE label\n\nThis statement is used to exit the flow control construct that has the given\nlabel. The label must be in the same stored program, not in a caller\nprocedure. LEAVE can be used within BEGIN ... END or loop constructs (LOOP,\nREPEAT, WHILE). In Stored Procedures, Triggers and Events, LEAVE can refer to\nthe outmost BEGIN ... END construct; in that case, the program exits the\nprocedure. In Stored Functions, RETURN can be used instead.\n\nNote that LEAVE cannot be used to exit a DECLARE HANDLER block.\n\nIf you try to LEAVE a non-existing label, or if you try to LEAVE a HANDLER\nblock, the following error will be produced:\n\nERROR 1308 (42000): LEAVE with no matching label: <label_name>\n\nThe following example uses LEAVE to exit the procedure if a condition is true:\n\nCREATE PROCEDURE proc(IN p TINYINT)\nCONTAINS SQL\n`whole_proc`:\nBEGIN\n SELECT 1;\n IF p < 1 THEN\n LEAVE `whole_proc`;\n END IF;\n SELECT 2;\nEND;\n\nCALL proc(0);\n+---+\n| 1 |\n+---+\n| 1 |\n+---+\n\nURL: https://mariadb.com/kb/en/leave/','','https://mariadb.com/kb/en/leave/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (309,24,'LOOP','Syntax\n------\n\n[begin_label:] LOOP\n statement_list\nEND LOOP [end_label]\n\nDescription\n-----------\n\nLOOP implements a simple loop construct, enabling repeated execution of the\nstatement list, which consists of one or more statements, each terminated by a\nsemicolon (i.e., ;) statement delimiter. The statements within the loop are\nrepeated until the loop is exited; usually this is accomplished with a LEAVE\nstatement.\n\nA LOOP statement can be labeled. end_label cannot be given unless begin_label\nalso is present. If both are present, they must be the same.\n\nSee Delimiters in the mariadb client for more on delimiter usage in the client.\n\nURL: https://mariadb.com/kb/en/loop/','','https://mariadb.com/kb/en/loop/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (310,24,'REPEAT LOOP','Syntax\n------\n\n[begin_label:] REPEAT\n statement_list\nUNTIL search_condition\nEND REPEAT [end_label]\n\nThe statement list within a REPEAT statement is repeated until the\nsearch_condition is true. Thus, a REPEAT always enters the loop at least once.\nstatement_list consists of one or more statements, each terminated by a\nsemicolon (i.e., ;) statement delimiter.\n\nA REPEAT statement can be labeled. end_label cannot be given unless\nbegin_label also is present. If both are present, they must be the same.\n\nSee Delimiters in the mariadb client for more on client delimiter usage.\n\nDELIMITER //\n\nCREATE PROCEDURE dorepeat(p1 INT)\n BEGIN\n SET @x = 0;\n REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;\n END\n//\n\nCALL dorepeat(1000)//\n\nSELECT @x//\n+------+\n| @x |\n+------+\n| 1001 |\n+------+\n\nURL: https://mariadb.com/kb/en/repeat-loop/','','https://mariadb.com/kb/en/repeat-loop/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (311,24,'RESIGNAL','Syntax\n------\n\nRESIGNAL [error_condition]\n [SET error_property\n [, error_property] ...]\n\nerror_condition:\n SQLSTATE [VALUE] \'sqlstate_value\'\n | condition_name\n\nerror_property:\n error_property_name = <error_property_value>\n\nerror_property_name:\n CLASS_ORIGIN\n | SUBCLASS_ORIGIN\n | MESSAGE_TEXT\n | MYSQL_ERRNO\n | CONSTRAINT_CATALOG\n | CONSTRAINT_SCHEMA\n | CONSTRAINT_NAME\n | CATALOG_NAME\n | SCHEMA_NAME\n | TABLE_NAME\n | COLUMN_NAME\n | CURSOR_NAME\n\nDescription\n-----------\n\nThe syntax of RESIGNAL and its semantics are very similar to SIGNAL. This\nstatement can only be used within an error HANDLER. It produces an error, like\nSIGNAL. RESIGNAL clauses are the same as SIGNAL, except that they all are\noptional, even SQLSTATE. All the properties which are not specified in\nRESIGNAL, will be identical to the properties of the error that was received\nby the error HANDLER. For a description of the clauses, see diagnostics area.\n\nNote that RESIGNAL does not empty the diagnostics area: it just appends\nanother error condition.\n\nRESIGNAL, without any clauses, produces an error which is identical to the\nerror that was received by HANDLER.\n\nIf used out of a HANDLER construct, RESIGNAL produces the following error:\n\nERROR 1645 (0K000): RESIGNAL when handler not active\n\nIn MariaDB 5.5, if a HANDLER contained a CALL to another procedure, that\nprocedure could use RESIGNAL. Since MariaDB 10.0, trying to do this raises the\nabove error.\n\nFor a list of SQLSTATE values and MariaDB error codes, see MariaDB Error Codes.\n\nThe following procedure tries to query two tables which don\'t exist, producing\na 1146 error in both cases. Those errors will trigger the HANDLER. The first\ntime the error will be ignored and the client will not receive it, but the\nsecond time, the error is re-signaled, so the client will receive it.\n\nCREATE PROCEDURE test_error( )\nBEGIN\n DECLARE CONTINUE HANDLER\n FOR 1146\n BEGIN\n IF @hide_errors IS FALSE THEN\n RESIGNAL;\n END IF;\n END;\n SET @hide_errors = TRUE;\n SELECT \'Next error will be ignored\' AS msg;\n SELECT `c` FROM `temptab_one`;\n SELECT \'Next error won\'\'t be ignored\' AS msg;\n SET @hide_errors = FALSE;\n SELECT `c` FROM `temptab_two`;\nEND;\n\nCALL test_error( );\n\n+----------------------------+\n| msg |\n+----------------------------+\n| Next error will be ignored |\n+----------------------------+\n\n+-----------------------------+\n| msg |\n+-----------------------------+\n| Next error won\'t be ignored |\n+-----------------------------+\n\nERROR 1146 (42S02): Table \'test.temptab_two\' doesn\'t exist\n\nThe following procedure re-signals an error, modifying only the error message\nto clarify the cause of the problem.\n\nCREATE PROCEDURE test_error()\nBEGIN\n DECLARE CONTINUE HANDLER\n FOR 1146\n BEGIN\n RESIGNAL SET\n MESSAGE_TEXT = \'`temptab` does not exist\';\n END;\n SELECT `c` FROM `temptab`;\nEND;\n\nCALL test_error( );\nERROR 1146 (42S02): `temptab` does not exist\n\nAs explained above, this works on MariaDB 5.5, but produces a 1645 error since\n10.0.\n\nCREATE PROCEDURE handle_error()\nBEGIN\n RESIGNAL;\nEND;\nCREATE PROCEDURE p()\nBEGIN\n DECLARE EXIT HANDLER FOR SQLEXCEPTION CALL p();\n SIGNAL SQLSTATE \'45000\';\nEND;\n\nURL: https://mariadb.com/kb/en/resignal/','','https://mariadb.com/kb/en/resignal/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (312,24,'RETURN','Syntax\n------\n\nRETURN expr\n\nThe RETURN statement terminates execution of a stored function and returns the\nvalue expr to the function caller. There must be at least one RETURN statement\nin a stored function. If the function has multiple exit points, all exit\npoints must have a RETURN.\n\nThis statement is not used in stored procedures, triggers, or events. LEAVE\ncan be used instead.\n\nThe following example shows that RETURN can return the result of a scalar\nsubquery:\n\nCREATE FUNCTION users_count() RETURNS BOOL\n READS SQL DATA\nBEGIN\n RETURN (SELECT COUNT(DISTINCT User) FROM mysql.user);\nEND;\n\nURL: https://mariadb.com/kb/en/return/','','https://mariadb.com/kb/en/return/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (313,24,'SELECT INTO','Syntax\n------\n\nSELECT col_name [, col_name] ...\n INTO var_name [, var_name] ...\n table_expr\n\nDescription\n-----------\n\nSELECT ... INTO enables selected columns to be stored directly into variables.\nNo resultset is produced. The query should return a single row. If the query\nreturns no rows, a warning with error code 1329 occurs (No data), and the\nvariable values remain unchanged. If the query returns multiple rows, error\n1172 occurs (Result consisted of more than one row). If it is possible that\nthe statement may retrieve multiple rows, you can use LIMIT 1 to limit the\nresult set to a single row.\n\nThe INTO clause can also be specified at the end of the statement.\n\nIn the context of such statements that occur as part of events executed by the\nEvent Scheduler, diagnostics messages (not only errors, but also warnings) are\nwritten to the error log, and, on Windows, to the application event log.\n\nThis statement can be used with both local variables and user-defined\nvariables.\n\nFor the complete syntax, see SELECT.\n\nAnother way to set a variable\'s value is the SET statement.\n\nSELECT ... INTO results are not stored in the query cache even if SQL_CACHE is\nspecified.\n\nExamples\n--------\n\nSELECT id, data INTO @x,@y \nFROM test.t1 LIMIT 1;\nSELECT * from t1 where t1.a=@x and t1.b=@y\n\nIf you want to use this construct with UNION you have to use the syntax:\n\nSELECT * INTO @x FROM (SELECT t1.a FROM t1 UNION SELECT t2.a FROM t2);\n\nURL: https://mariadb.com/kb/en/selectinto/','','https://mariadb.com/kb/en/selectinto/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (314,24,'SIGNAL','Syntax\n------\n\nSIGNAL error_condition\n [SET error_property\n [, error_property] ...]\n\nerror_condition:\n SQLSTATE [VALUE] \'sqlstate_value\'\n | condition_name\n\nerror_property:\n error_property_name = <error_property_value>\n\nerror_property_name:\n CLASS_ORIGIN\n | SUBCLASS_ORIGIN\n | MESSAGE_TEXT\n | MYSQL_ERRNO\n | CONSTRAINT_CATALOG\n | CONSTRAINT_SCHEMA\n | CONSTRAINT_NAME\n | CATALOG_NAME\n | SCHEMA_NAME\n | TABLE_NAME\n | COLUMN_NAME\n | CURSOR_NAME\n\nSIGNAL empties the diagnostics area and produces a custom error. This\nstatement can be used anywhere, but is generally useful when used inside a\nstored program. When the error is produced, it can be caught by a HANDLER. If\nnot, the current stored program, or the current statement, will terminate with\nthe specified error.\n\nSometimes an error HANDLER just needs to SIGNAL the same error it received,\noptionally with some changes. Usually the RESIGNAL statement is the most\nconvenient way to do this.\n\nerror_condition can be an SQLSTATE value or a named error condition defined\nvia DECLARE CONDITION. SQLSTATE must be a constant string consisting of five\ncharacters. These codes are standard to ODBC and ANSI SQL. For customized\nerrors, the recommended SQLSTATE is \'45000\'. For a list of SQLSTATE values\nused by MariaDB, see the MariaDB Error Codes page. The SQLSTATE can be read\nvia the API method mysql_sqlstate( ).\n\nTo specify error properties user-defined variables and local variables can be\nused, as well as character set conversions (but you can\'t set a collation).\n\nThe error properties, their type and their default values are explained in the\ndiagnostics area page.\n\nErrors\n------\n\nIf the SQLSTATE is not valid, the following error like this will be produced:\n\nERROR 1407 (42000): Bad SQLSTATE: \'123456\'\n\nIf a property is specified more than once, an error like this will be produced:\n\nERROR 1641 (42000): Duplicate condition information item \'MESSAGE_TEXT\'\n\nIf you specify a condition name which is not declared, an error like this will\nbe produced:\n\nERROR 1319 (42000): Undefined CONDITION: cond_name\n\nIf MYSQL_ERRNO is out of range, you will get an error like this:\n\nERROR 1231 (42000): Variable \'MYSQL_ERRNO\' can\'t be set to the value of \'0\'\n\nExamples\n--------\n\nHere\'s what happens if SIGNAL is used in the client to generate errors:\n\nSIGNAL SQLSTATE \'01000\';\nQuery OK, 0 rows affected, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n\n+---------+------+------------------------------------------+\n| Level | Code | Message |\n+---------+------+------------------------------------------+\n| Warning | 1642 | Unhandled user-defined warning condition |\n+---------+------+------------------------------------------+\n1 row in set (0.06 sec)\n\nSIGNAL SQLSTATE \'02000\';\nERROR 1643 (02000): Unhandled user-defined not found condition\n\nHow to specify MYSQL_ERRNO and MESSAGE_TEXT properties:\n\nSIGNAL SQLSTATE \'45000\' SET MYSQL_ERRNO=30001, MESSAGE_TEXT=\'H\nello, world!\';\n\nERROR 30001 (45000): Hello, world!\n\nThe following code shows how to use user variables, local variables and\ncharacter set conversion with SIGNAL:\n\nCREATE PROCEDURE test_error(x INT)\nBEGIN\n DECLARE errno SMALLINT UNSIGNED DEFAULT 31001;\n SET @errmsg = \'Hello, world!\';\n IF x = 1 THEN\n SIGNAL SQLSTATE \'45000\' SET\n MYSQL_ERRNO = errno,\n MESSAGE_TEXT = @errmsg;\n ELSE\n SIGNAL SQLSTATE \'45000\' SET\n MYSQL_ERRNO = errno,\n MESSAGE_TEXT = _utf8\'Hello, world!\';\n END IF;\nEND;\n\nHow to use named error conditions:\n\nCREATE PROCEDURE test_error(n INT)\nBEGIN\n DECLARE `too_big` CONDITION FOR SQLSTATE \'45000\';\n IF n > 10 THEN\n SIGNAL `too_big`;\n END IF;\nEND;\n\nIn this example, we\'ll define a HANDLER for an error code. When the error\noccurs, we SIGNAL a more informative error which makes sense for our procedure:\n\nCREATE PROCEDURE test_error()\nBEGIN\n DECLARE EXIT HANDLER\n FOR 1146\n BEGIN\n SIGNAL SQLSTATE \'45000\' SET\n MESSAGE_TEXT = \'Temporary tables not found; did you call init()\nprocedure?\';\n END;\n -- this will produce a 1146 error\n SELECT `c` FROM `temptab`;\nEND;\n\nURL: https://mariadb.com/kb/en/signal/','','https://mariadb.com/kb/en/signal/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (315,24,'WHILE','Syntax\n------\n\n[begin_label:] WHILE search_condition DO\n statement_list\nEND WHILE [end_label]\n\nDescription\n-----------\n\nThe statement list within a WHILE statement is repeated as long as the\nsearch_condition is true. statement_list consists of one or more statements.\nIf the loop must be executed at least once, REPEAT ... LOOP can be used\ninstead.\n\nA WHILE statement can be labeled. end_label cannot be given unless begin_label\nalso is present. If both are present, they must be the same.\n\nExamples\n--------\n\nCREATE PROCEDURE dowhile()\nBEGIN\n DECLARE v1 INT DEFAULT 5;\n\nWHILE v1 > 0 DO\n ...\n SET v1 = v1 - 1;\n END WHILE;\nEND\n\nURL: https://mariadb.com/kb/en/while/','','https://mariadb.com/kb/en/while/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (316,24,'Cursor Overview','Description\n-----------\n\nA cursor is a structure that allows you to go over records sequentially, and\nperform processing based on the result.\n\nMariaDB permits cursors inside stored programs, and MariaDB cursors are\nnon-scrollable, read-only and asensitive.\n\n* Non-scrollable means that the rows can only be fetched in the order\nspecified by the SELECT statement. Rows cannot be skipped, you cannot jump to\na specific row, and you cannot fetch rows in reverse order.\n* Read-only means that data cannot be updated through the cursor.\n* Asensitive means that the cursor points to the actual underlying data. This\nkind of cursor is quicker than the alternative, an insensitive cursor, as no\ndata is copied to a temporary table. However, changes to the data being used\nby the cursor will affect the cursor data.\n\nCursors are created with a DECLARE CURSOR statement and opened with an OPEN\nstatement. Rows are read with a FETCH statement before the cursor is finally\nclosed with a CLOSE statement.\n\nWhen FETCH is issued and there are no more rows to extract, the following\nerror is produced:\n\nERROR 1329 (02000): No data - zero rows fetched, selected, or processed\n\nTo avoid problems, a DECLARE HANDLER statement is generally used. The HANDLER\nshould handler the 1329 error, or the \'02000\' SQLSTATE, or the NOT FOUND error\nclass.\n\nOnly SELECT statements are allowed for cursors, and they cannot be contained\nin a variable - so, they cannot be composed dynamically. However, it is\npossible to SELECT from a view. Since the CREATE VIEW statement can be\nexecuted as a prepared statement, it is possible to dynamically create the\nview that is queried by the cursor.\n\nFrom MariaDB 10.3.0, cursors can have parameters. Cursor parameters can appear\nin any part of the DECLARE CURSOR select_statement where a stored procedure\nvariable is allowed (select list, WHERE, HAVING, LIMIT etc). See DECLARE\nCURSOR and OPEN for syntax, and below for an example:\n\nExamples\n--------\n\nCREATE TABLE c1(i INT);\n\nCREATE TABLE c2(i INT);\n\nCREATE TABLE c3(i INT);\n\nDELIMITER //\n\nCREATE PROCEDURE p1()\nBEGIN\n DECLARE done INT DEFAULT FALSE;\n DECLARE x, y INT;\n DECLARE cur1 CURSOR FOR SELECT i FROM test.c1;\n DECLARE cur2 CURSOR FOR SELECT i FROM test.c2;\n DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;\n\nOPEN cur1;\n OPEN cur2;\n\nread_loop: LOOP\n FETCH cur1 INTO x;\n FETCH cur2 INTO y;\n IF done THEN\n LEAVE read_loop;\n END IF;\n IF x < y THEN\n INSERT INTO test.c3 VALUES (x);\n ELSE\n INSERT INTO test.c3 VALUES (y);\n END IF;\n END LOOP;\n\nCLOSE cur1;\n CLOSE cur2;\nEND; //\n\nDELIMITER ;\n\nINSERT INTO c1 VALUES(5),(50),(500);\n\nINSERT INTO c2 VALUES(10),(20),(30);\n\nCALL p1;\n\nSELECT * FROM c3;\n+------+\n| i |\n+------+\n| 5 |\n| 20 |\n| 30 |\n+------+\n\nFrom MariaDB 10.3.0\n\nDROP PROCEDURE IF EXISTS p1;\nDROP TABLE IF EXISTS t1;\nCREATE TABLE t1 (a INT, b VARCHAR(10));\n\nINSERT INTO t1 VALUES (1,\'old\'),(2,\'old\'),(3,\'old\'),(4,\'old\'),(5,\'old\');\n\nDELIMITER //\n\nCREATE PROCEDURE p1(min INT,max INT)\nBEGIN\n DECLARE done INT DEFAULT FALSE;\n DECLARE va INT;\n DECLARE cur CURSOR(pmin INT, pmax INT) FOR SELECT a FROM t1 WHERE a BETWEEN\npmin AND pmax;\n DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=TRUE;\n OPEN cur(min,max);\n read_loop: LOOP\n FETCH cur INTO va;\n IF done THEN\n LEAVE read_loop;\n END IF;\n INSERT INTO t1 VALUES (va,\'new\');\n END LOOP;\n CLOSE cur;\nEND;\n//\n\nDELIMITER ;\n\nCALL p1(2,4);\n\nSELECT * FROM t1;\n+------+------+\n| a | b |\n+------+------+\n| 1 | old |\n| 2 | old |\n| 3 | old |\n| 4 | old |\n| 5 | old |\n| 2 | new |\n| 3 | new |\n| 4 | new |\n+------+------+\n\nURL: https://mariadb.com/kb/en/cursor-overview/','','https://mariadb.com/kb/en/cursor-overview/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (317,24,'DECLARE CURSOR','Syntax\n------\n\n<= MariaDB 10.2\n\nDECLARE cursor_name CURSOR FOR select_statement\n\nFrom MariaDB 10.3\n\nDECLARE cursor_name CURSOR [(cursor_formal_parameter[,...])] FOR\nselect_statement\n\ncursor_formal_parameter:\n name type [collate clause]\n\nFrom MariaDB 10.8\n\nDECLARE cursor_name CURSOR [(cursor_formal_parameter[,...])] FOR\nselect_statement\n\ncursor_formal_parameter:\n [IN] name type [collate clause]\n\nDescription\n-----------\n\nThis statement declares a cursor. Multiple cursors may be declared in a stored\nprogram, but each cursor in a given block must have a unique name.\n\nselect_statement is not executed until the OPEN statement is executed. It is\nimportant to remember this if the query produces an error, or calls functions\nwhich have side effects.\n\nA SELECT associated to a cursor can use variables, but the query itself cannot\nbe a variable, and cannot be dynamically composed. The SELECT statement cannot\nhave an INTO clause.\n\nCursors must be declared before HANDLERs, but after local variables and\nCONDITIONs.\n\nParameters\n----------\n\nMariaDB starting with 10.3.0\n----------------------------\nFrom MariaDB 10.3.0, cursors can have parameters. This is a non-standard SQL\nextension. Cursor parameters can appear in any part of the DECLARE CURSOR\nselect_statement where a stored procedure variable is allowed (select list,\nWHERE, HAVING, LIMIT etc).\n\nIN\n--\n\nMariaDB starting with 10.8.0\n----------------------------\nFrom MariaDB 10.8.0 preview release, the IN qualifier is supported in the\ncursor_format_parameter part of the syntax.\n\nSee Cursor Overview for an example.\n\nURL: https://mariadb.com/kb/en/declare-cursor/','','https://mariadb.com/kb/en/declare-cursor/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (318,24,'OPEN','Syntax\n------\n\n<= MariaDB 10.2\n\nOPEN cursor_name\n\nFrom MariaDB 10.3\n\nOPEN cursor_name [expression[,...]];\n\nDescription\n-----------\n\nThis statement opens a cursor which was previously declared with DECLARE\nCURSOR.\n\nThe query associated to the DECLARE CURSOR is executed when OPEN is executed.\nIt is important to remember this if the query produces an error, or calls\nfunctions which have side effects.\n\nThis is necessary in order to FETCH rows from a cursor.\n\nSee Cursor Overview for an example.\n\nURL: https://mariadb.com/kb/en/open/','','https://mariadb.com/kb/en/open/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (319,24,'FETCH','Syntax\n------\n\nFETCH cursor_name INTO var_name [, var_name] ...\n\nDescription\n-----------\n\nThis statement fetches the next row (if a row exists) using the specified open\ncursor, and advances the cursor pointer.\n\nvar_name can be a local variable, but not a user-defined variable.\n\nIf no more rows are available, a No Data condition occurs with SQLSTATE value\n02000. To detect this condition, you can set up a handler for it (or for a NOT\nFOUND condition).\n\nSee Cursor Overview for an example.\n\nURL: https://mariadb.com/kb/en/fetch/','','https://mariadb.com/kb/en/fetch/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (320,24,'CLOSE','Syntax\n------\n\nCLOSE cursor_name\n\nDescription\n-----------\n\nThis statement closes a previously opened cursor. The cursor must have been\npreviously opened or else an error occurs.\n\nIf not closed explicitly, a cursor is closed at the end of the compound\nstatement in which it was declared.\n\nSee Cursor Overview for an example.\n\nURL: https://mariadb.com/kb/en/close/','','https://mariadb.com/kb/en/close/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (321,25,'BUFFER','A synonym for ST_BUFFER.\n\nURL: https://mariadb.com/kb/en/buffer/','','https://mariadb.com/kb/en/buffer/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (322,25,'CONVEXHULL','A synonym for ST_CONVEXHULL.\n\nURL: https://mariadb.com/kb/en/convexhull/','','https://mariadb.com/kb/en/convexhull/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (323,25,'GEOMETRYCOLLECTION','Syntax\n------\n\nGeometryCollection(g1,g2,...)\n\nDescription\n-----------\n\nConstructs a WKB GeometryCollection. If any argument is not a well-formed WKB\nrepresentation of a geometry, the return value is NULL.\n\nExamples\n--------\n\nCREATE TABLE gis_geometrycollection (g GEOMETRYCOLLECTION);\nSHOW FIELDS FROM gis_geometrycollection;\nINSERT INTO gis_geometrycollection VALUES\n (GeomCollFromText(\'GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10\n10))\')),\n (GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6),\nLineString(Point(3, 6), Point(7, 9)))))),\n (GeomFromText(\'GeometryCollection()\')),\n (GeomFromText(\'GeometryCollection EMPTY\'));\n\nURL: https://mariadb.com/kb/en/geometrycollection/','','https://mariadb.com/kb/en/geometrycollection/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (324,25,'LINESTRING','Syntax\n------\n\nLineString(pt1,pt2,...)\n\nDescription\n-----------\n\nConstructs a WKB LineString value from a number of WKB Point arguments. If any\nargument is not a WKB Point, the return value is NULL. If the number of Point\narguments is less than two, the return value is NULL.\n\nExamples\n--------\n\nSET @ls = \'LineString(1 1,2 2,3 3)\';\n\nSELECT AsText(EndPoint(GeomFromText(@ls)));\n+-------------------------------------+\n| AsText(EndPoint(GeomFromText(@ls))) |\n+-------------------------------------+\n| POINT(3 3) |\n+-------------------------------------+\n\nCREATE TABLE gis_line (g LINESTRING);\nINSERT INTO gis_line VALUES\n (LineFromText(\'LINESTRING(0 0,0 10,10 0)\')),\n (LineStringFromText(\'LINESTRING(10 10,20 10,20 20,10 20,10 10)\')),\n (LineStringFromWKB(AsWKB(LineString(Point(10, 10), Point(40, 10)))));\n\nURL: https://mariadb.com/kb/en/linestring/','','https://mariadb.com/kb/en/linestring/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (325,25,'MULTILINESTRING','Syntax\n------\n\nMultiLineString(ls1,ls2,...)\n\nDescription\n-----------\n\nConstructs a WKB MultiLineString value using WKB LineString arguments. If any\nargument is not a WKB LineString, the return value is NULL.\n\nExample\n-------\n\nCREATE TABLE gis_multi_line (g MULTILINESTRING);\nINSERT INTO gis_multi_line VALUES\n (MultiLineStringFromText(\'MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16\n48))\')),\n (MLineFromText(\'MULTILINESTRING((10 48,10 21,10 0))\')),\n (MLineFromWKB(AsWKB(MultiLineString(LineString(Point(1, 2), \n Point(3, 5)), LineString(Point(2, 5),Point(5, 8),Point(21, 7))))));\n\nURL: https://mariadb.com/kb/en/multilinestring/','','https://mariadb.com/kb/en/multilinestring/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (326,25,'MULTIPOINT','Syntax\n------\n\nMultiPoint(pt1,pt2,...)\n\nDescription\n-----------\n\nConstructs a WKB MultiPoint value using WKB Point arguments. If any argument\nis not a WKB Point, the return value is NULL.\n\nExamples\n--------\n\nSET @g = ST_GEOMFROMTEXT(\'MultiPoint( 1 1, 2 2, 5 3, 7 2, 9 3, 8 4, 6 6, 6 9,\n4 9, 1 5 )\');\n\nCREATE TABLE gis_multi_point (g MULTIPOINT);\nINSERT INTO gis_multi_point VALUES\n (MultiPointFromText(\'MULTIPOINT(0 0,10 10,10 20,20 20)\')),\n (MPointFromText(\'MULTIPOINT(1 1,11 11,11 21,21 21)\')),\n (MPointFromWKB(AsWKB(MultiPoint(Point(3, 6), Point(4, 10)))));\n\nURL: https://mariadb.com/kb/en/multipoint/','','https://mariadb.com/kb/en/multipoint/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (327,25,'MULTIPOLYGON','Syntax\n------\n\nMultiPolygon(poly1,poly2,...)\n\nDescription\n-----------\n\nConstructs a WKB MultiPolygon value from a set of WKB Polygon arguments. If\nany argument is not a WKB Polygon, the return value is NULL.\n\nExample\n-------\n\nCREATE TABLE gis_multi_polygon (g MULTIPOLYGON);\nINSERT INTO gis_multi_polygon VALUES\n (MultiPolygonFromText(\'MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52\n18,66 23,73 9,48 6,52 18)),\n ((59 18,67 18,67 13,59 13,59 18)))\')),\n (MPolyFromText(\'MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66\n23,73 9,48 6,52 18)),\n ((59 18,67 18,67 13,59 13,59 18)))\')),\n (MPolyFromWKB(AsWKB(MultiPolygon(Polygon(LineString(\n Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3)))))));\n\nURL: https://mariadb.com/kb/en/multipolygon/','','https://mariadb.com/kb/en/multipolygon/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (328,25,'POINT','Syntax\n------\n\nPoint(x,y)\n\nDescription\n-----------\n\nConstructs a WKB Point using the given coordinates.\n\nExamples\n--------\n\nSET @g = ST_GEOMFROMTEXT(\'Point(1 1)\');\n\nCREATE TABLE gis_point (g POINT);\nINSERT INTO gis_point VALUES\n (PointFromText(\'POINT(10 10)\')),\n (PointFromText(\'POINT(20 10)\')),\n (PointFromText(\'POINT(20 20)\')),\n (PointFromWKB(AsWKB(PointFromText(\'POINT(10 20)\'))));\n\nURL: https://mariadb.com/kb/en/point/','','https://mariadb.com/kb/en/point/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (329,25,'PointOnSurface','A synonym for ST_PointOnSurface.\n\nURL: https://mariadb.com/kb/en/pointonsurface/','','https://mariadb.com/kb/en/pointonsurface/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (330,25,'POLYGON','Syntax\n------\n\nPolygon(ls1,ls2,...)\n\nDescription\n-----------\n\nConstructs a WKB Polygon value from a number of WKB LineString arguments. If\nany argument does not represent the WKB of a LinearRing (that is, not a closed\nand simple LineString) the return value is NULL.\n\nNote that according to the OpenGIS standard, a POLYGON should have exactly one\nExteriorRing and all other rings should lie within that ExteriorRing and thus\nbe the InteriorRings. Practically, however, some systems, including MariaDB\'s,\npermit polygons to have several \'ExteriorRings\'. In the case of there being\nmultiple, non-overlapping exterior rings ST_NUMINTERIORRINGS() will return 1.\n\nExamples\n--------\n\nSET @g = ST_GEOMFROMTEXT(\'POLYGON((1 1,1 5,4 9,6 9,9 3,7 2,1 1))\');\n\nCREATE TABLE gis_polygon (g POLYGON);\nINSERT INTO gis_polygon VALUES\n (PolygonFromText(\'POLYGON((10 10,20 10,20 20,10 20,10 10))\')),\n (PolyFromText(\'POLYGON((0 0,50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10\n20,10 10))\')),\n (PolyFromWKB(AsWKB(Polygon(LineString(Point(0, 0), Point(30, 0), Point(30,\n30), Point(0, 0))))));\n\nNon-overlapping \'polygon\':\n\nSELECT ST_NumInteriorRings(ST_PolyFromText(\'POLYGON((0 0,10 0,10 10,0 10,0 0),\n (-1 -1,-5 -1,-5 -5,-1 -5,-1 -1))\')) AS NumInteriorRings;\n+------------------+\n| NumInteriorRings |\n+------------------+\n| 1 |\n+------------------+\n\nURL: https://mariadb.com/kb/en/polygon/','','https://mariadb.com/kb/en/polygon/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (331,25,'ST_BUFFER','Syntax\n------\n\nST_BUFFER(g1,r)\nBUFFER(g1,r)\n\nDescription\n-----------\n\nReturns a geometry that represents all points whose distance from geometry g1\nis less than or equal to distance, or radius, r.\n\nUses for this function could include creating for example a new geometry\nrepresenting a buffer zone around an island.\n\nBUFFER() is a synonym.\n\nExamples\n--------\n\nDetermining whether a point is within a buffer zone:\n\nSET @g1 = ST_GEOMFROMTEXT(\'POLYGON((10 10, 10 20, 20 20, 20 10, 10 10))\');\n\nSET @g2 = ST_GEOMFROMTEXT(\'POINT(8 8)\');\n\nSELECT ST_WITHIN(@g2,ST_BUFFER(@g1,5));\n+---------------------------------+\n| ST_WITHIN(@g2,ST_BUFFER(@g1,5)) |\n+---------------------------------+\n| 1 |\n+---------------------------------+\n\nSELECT ST_WITHIN(@g2,ST_BUFFER(@g1,1));\n+---------------------------------+\n| ST_WITHIN(@g2,ST_BUFFER(@g1,1)) |\n+---------------------------------+\n| 0 |\n+---------------------------------+\n\nURL: https://mariadb.com/kb/en/st_buffer/','','https://mariadb.com/kb/en/st_buffer/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (332,25,'ST_CONVEXHULL','MariaDB starting with 10.1.2\n----------------------------\nST_ConvexHull() was introduced in MariaDB 10.1.2\n\nSyntax\n------\n\nST_ConvexHull(g)\nConvexHull(g)\n\nDescription\n-----------\n\nGiven a geometry, returns a geometry that is the minimum convex geometry\nenclosing all geometries within the set. Returns NULL if the geometry value is\nNULL or an empty value.\n\nST_ConvexHull() and ConvexHull() are synonyms.\n\nExamples\n--------\n\nThe ConvexHull of a single point is simply the single point:\n\nSET @g = ST_GEOMFROMTEXT(\'Point(0 0)\');\n\nSELECT ST_ASTEXT(ST_CONVEXHULL(@g));\n+------------------------------+\n| ST_ASTEXT(ST_CONVEXHULL(@g)) |\n+------------------------------+\n| POINT(0 0) |\n+------------------------------+\n\nSET @g = ST_GEOMFROMTEXT(\'MultiPoint(0 0, 1 2, 2 3)\');\n\nSELECT ST_ASTEXT(ST_CONVEXHULL(@g));\n+------------------------------+\n| ST_ASTEXT(ST_CONVEXHULL(@g)) |\n+------------------------------+\n| POLYGON((0 0,1 2,2 3,0 0)) |\n+------------------------------+\n\nSET @g = ST_GEOMFROMTEXT(\'MultiPoint( 1 1, 2 2, 5 3, 7 2, 9 3, 8 4, 6 6, 6 9,\n4 9, 1 5 )\');\n\nSELECT ST_ASTEXT(ST_CONVEXHULL(@g));\n+----------------------------------------+\n| ST_ASTEXT(ST_CONVEXHULL(@g)) |\n+----------------------------------------+\n| POLYGON((1 1,1 5,4 9,6 9,9 3,7 2,1 1)) |\n+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_convexhull/','','https://mariadb.com/kb/en/st_convexhull/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (333,25,'ST_INTERSECTION','Syntax\n------\n\nST_INTERSECTION(g1,g2)\n\nDescription\n-----------\n\nReturns a geometry that is the intersection, or shared portion, of geometry g1\nand geometry g2.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT(\'POINT(2 1)\');\n\nSET @g2 = ST_GEOMFROMTEXT(\'LINESTRING(2 1, 0 2)\');\n\nSELECT ASTEXT(ST_INTERSECTION(@g1,@g2));\n+----------------------------------+\n| ASTEXT(ST_INTERSECTION(@g1,@g2)) |\n+----------------------------------+\n| POINT(2 1) |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/st_intersection/','','https://mariadb.com/kb/en/st_intersection/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (334,25,'ST_POINTONSURFACE','MariaDB starting with 10.1.2\n----------------------------\nST_POINTONSURFACE() was introduced in MariaDB 10.1.2\n\nSyntax\n------\n\nST_PointOnSurface(g)\nPointOnSurface(g)\n\nDescription\n-----------\n\nGiven a geometry, returns a POINT guaranteed to intersect a surface. However,\nsee MDEV-7514.\n\nST_PointOnSurface() and PointOnSurface() are synonyms.\n\nURL: https://mariadb.com/kb/en/st_pointonsurface/','','https://mariadb.com/kb/en/st_pointonsurface/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (335,25,'ST_SYMDIFFERENCE','Syntax\n------\n\nST_SYMDIFFERENCE(g1,g2)\n\nDescription\n-----------\n\nReturns a geometry that represents the portions of geometry g1 and geometry g2\nthat don\'t intersect.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT(\'LINESTRING(10 20, 10 40)\');\n\nSET @g2 = ST_GEOMFROMTEXT(\'LINESTRING(10 15, 10 25)\');\n\nSELECT ASTEXT(ST_SYMDIFFERENCE(@g1,@g2));\n+----------------------------------------------+\n| ASTEXT(ST_SYMDIFFERENCE(@g1,@g2)) |\n+----------------------------------------------+\n| MULTILINESTRING((10 15,10 20),(10 25,10 40)) |\n+----------------------------------------------+\n\nSET @g2 = ST_GeomFromText(\'LINESTRING(10 20, 10 41)\');\n\nSELECT ASTEXT(ST_SYMDIFFERENCE(@g1,@g2));\n+-----------------------------------+\n| ASTEXT(ST_SYMDIFFERENCE(@g1,@g2)) |\n+-----------------------------------+\n| LINESTRING(10 40,10 41) |\n+-----------------------------------+\n\nURL: https://mariadb.com/kb/en/st_symdifference/','','https://mariadb.com/kb/en/st_symdifference/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (336,25,'ST_UNION','Syntax\n------\n\nST_UNION(g1,g2)\n\nDescription\n-----------\n\nReturns a geometry that is the union of the geometry g1 and geometry g2.\n\nExamples\n--------\n\nSET @g1 = GEOMFROMTEXT(\'POINT (0 2)\');\n\nSET @g2 = GEOMFROMTEXT(\'POINT (2 0)\');\n\nSELECT ASTEXT(ST_UNION(@g1,@g2));\n+---------------------------+\n| ASTEXT(ST_UNION(@g1,@g2)) |\n+---------------------------+\n| MULTIPOINT(2 0,0 2) |\n+---------------------------+\n\nSET @g1 = GEOMFROMTEXT(\'POLYGON((0 0,0 3,3 3,3 0,0 0))\');\n\nSET @g2 = GEOMFROMTEXT(\'POLYGON((2 2,4 2,4 4,2 4,2 2))\');\n\nSELECT ASTEXT(ST_UNION(@g1,@g2));\n+------------------------------------------------+\n| ASTEXT(ST_UNION(@g1,@g2)) |\n+------------------------------------------------+\n| POLYGON((0 0,0 3,2 3,2 4,4 4,4 2,3 2,3 0,0 0)) |\n+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_union/','','https://mariadb.com/kb/en/st_union/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (337,26,'SHOW GRANTS','Syntax\n------\n\nSHOW GRANTS [FOR user|role]\n\nDescription\n-----------\n\nThe SHOW GRANTS statement lists privileges granted to a particular user or\nrole.\n\nUsers\n-----\n\nThe statement lists the GRANT statement or statements that must be issued to\nduplicate the privileges that are granted to a MariaDB user account. The\naccount is named using the same format as for the GRANT statement; for\nexample, \'jeffrey\'@\'localhost\'. If you specify only the user name part of the\naccount name, a host name part of \'%\' is used. For additional information\nabout specifying account names, see GRANT.\n\nSHOW GRANTS FOR \'root\'@\'localhost\';\n+---------------------------------------------------------------------+\n| Grants for root@localhost |\n+---------------------------------------------------------------------+\n| GRANT ALL PRIVILEGES ON *.* TO \'root\'@\'localhost\' WITH GRANT OPTION |\n+---------------------------------------------------------------------+\n\nTo list the privileges granted to the account that you are using to connect to\nthe server, you can use any of the following statements:\n\nSHOW GRANTS;\nSHOW GRANTS FOR CURRENT_USER;\nSHOW GRANTS FOR CURRENT_USER();\n\nIf SHOW GRANTS FOR CURRENT_USER (or any of the equivalent syntaxes) is used in\nDEFINER context (such as within a stored procedure that is defined with SQL\nSECURITY DEFINER), the grants displayed are those of the definer and not the\ninvoker.\n\nNote that the DELETE HISTORY privilege, introduced in MariaDB 10.3.4, was\ndisplayed as DELETE VERSIONING ROWS when running SHOW GRANTS until MariaDB\n10.3.15 (MDEV-17655).\n\nRoles\n-----\n\nSHOW GRANTS can also be used to view the privileges granted to a role.\n\nExample\n-------\n\nSHOW GRANTS FOR journalist;\n+------------------------------------------+\n| Grants for journalist |\n+------------------------------------------+\n| GRANT USAGE ON *.* TO \'journalist\' |\n| GRANT DELETE ON `test`.* TO \'journalist\' |\n+------------------------------------------+\n\nFOR PUBLIC\n----------\n\nMariaDB starting with 10.11\n---------------------------\nGRANT ... TO PUBLIC was introduced in MariaDB 10.11 to grant privileges to all\nusers. SHOW GRANTS FOR PUBLIC shows all these grants.\n\nSHOW GRANTS FOR public;\n+------------------------------------------------+\n| Grants for PUBLIC |\n+------------------------------------------------+\n| GRANT ALL PRIVILEGES ON `dev_db`.* TO `PUBLIC` |\n+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/show-grants/','','https://mariadb.com/kb/en/show-grants/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (338,26,'SHOW CREATE USER','Syntax\n------\n\nSHOW CREATE USER user_name\n\nDescription\n-----------\n\nShows the CREATE USER statement that created the given user. The statement\nrequires the SELECT privilege for the mysql database, except for the current\nuser.\n\nExamples\n--------\n\nCREATE USER foo4@test require cipher \'text\' \n issuer \'foo_issuer\' subject \'foo_subject\';\n\nSHOW CREATE USER foo4@test\\G\n*************************** 1. row ***************************\nCREATE USER \'foo4\'@\'test\' \n REQUIRE ISSUER \'foo_issuer\'\n SUBJECT \'foo_subject\'\n CIPHER \'text\'\n\nUser Password Expiry:\n\nCREATE USER \'monty\'@\'localhost\' PASSWORD EXPIRE INTERVAL 120 DAY;\n\nSHOW CREATE USER \'monty\'@\'localhost\';\n+------------------------------------------------------------------+\n| CREATE USER for monty@localhost |\n+------------------------------------------------------------------+\n| CREATE USER \'monty\'@\'localhost\' PASSWORD EXPIRE INTERVAL 120 DAY |\n+------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/show-create-user/','','https://mariadb.com/kb/en/show-create-user/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (339,26,'SHOW COLUMNS','Syntax\n------\n\nSHOW [FULL] {COLUMNS | FIELDS} FROM tbl_name [FROM db_name]\n [LIKE \'pattern\' | WHERE expr]\n\nDescription\n-----------\n\nSHOW COLUMNS displays information about the columns in a given table. It also\nworks for views. The LIKE clause, if present on its own, indicates which\ncolumn names to match. The WHERE and LIKE clauses can be given to select rows\nusing more general conditions, as discussed in Extended SHOW.\n\nIf the data types differ from what you expect them to be based on a CREATE\nTABLE statement, note that MariaDB sometimes changes data types when you\ncreate or alter a table. The conditions under which this occurs are described\nin the Silent Column Changes article.\n\nThe FULL keyword causes the output to include the column collation and\ncomments, as well as the privileges you have for each column.\n\nYou can use db_name.tbl_name as an alternative to the tbl_name FROM db_name\nsyntax. In other words, these two statements are equivalent:\n\nSHOW COLUMNS FROM mytable FROM mydb;\nSHOW COLUMNS FROM mydb.mytable;\n\nSHOW COLUMNS displays the following values for each table column:\n\nField indicates the column name.\n\nType indicates the column data type.\n\nCollation indicates the collation for non-binary string columns, or NULL for\nother columns. This value is displayed only if you use the FULL keyword.\n\nThe Null field contains YES if NULL values can be stored in the column, NO if\nnot.\n\nThe Key field indicates whether the column is indexed:\n\n* If Key is empty, the column either is not indexed or is indexed only as a\n secondary column in a multiple-column, non-unique index.\n* If Key is PRI, the column is a PRIMARY KEY or\n is one of the columns in a multiple-column PRIMARY KEY.\n* If Key is UNI, the column is the first column of a unique-valued\n index that cannot contain NULL values.\n* If Key is MUL, multiple occurrences of a given value are allowed\n within the column. The column is the first column of a non-unique index or a\n unique-valued index that can contain NULL values.\n\nIf more than one of the Key values applies to a given column of a table, Key\ndisplays the one with the highest priority, in the order PRI, UNI, MUL.\n\nA UNIQUE index may be displayed as PRI if it cannot contain NULL values and\nthere is no PRIMARY KEY in the table. A UNIQUE index may display as MUL if\nseveral columns form a composite UNIQUE index; although the combination of the\ncolumns is unique, each column can still hold multiple occurrences of a given\nvalue.\n\nThe Default field indicates the default value that is assigned to the column.\n\nThe Extra field contains any additional information that is available about a\ngiven column.\n\n+------------------------+---------------------------------------------------+\n| Value | Description |\n+------------------------+---------------------------------------------------+\n| AUTO_INCREMENT | The column was created with the AUTO_INCREMENT |\n| | keyword. |\n+------------------------+---------------------------------------------------+\n| PERSISTENT | The column was created with the PERSISTENT |\n| | keyword. (New in 5.3) |\n+------------------------+---------------------------------------------------+\n| VIRTUAL | The column was created with the VIRTUAL keyword. |\n| | (New in 5.3) |\n+------------------------+---------------------------------------------------+\n| on update | The column is a TIMESTAMP column that is |\n| CURRENT_TIMESTAMP | automatically updated on INSERT and UPDATE. |\n+------------------------+---------------------------------------------------+\n\nPrivileges indicates the privileges you have for the column. This value is\ndisplayed only if you use the FULL keyword.\n\nComment indicates any comment the column has. This value is displayed only if\nyou use the FULL keyword.\n\nSHOW FIELDS is a synonym for SHOW COLUMNS. Also DESCRIBE and EXPLAIN can be\nused as shortcuts.\n\nYou can also list a table\'s columns with:\n\nmariadb-show db_name tbl_name\n\nSee the mariadb-show command for more details.\n\nThe DESCRIBE statement provides information similar to SHOW COLUMNS. The\ninformation_schema.COLUMNS table provides similar, but more complete,\ninformation.\n\nThe SHOW CREATE TABLE, SHOW TABLE STATUS, and SHOW INDEX statements also\nprovide information about tables.\n\nExamples\n--------\n\nSHOW COLUMNS FROM city;\n+------------+----------+------+-----+---------+----------------+\n| Field | Type | Null | Key | Default | Extra |\n+------------+----------+------+-----+---------+----------------+\n| Id | int(11) | NO | PRI | NULL | auto_increment |\n| Name | char(35) | NO | | | |\n| Country | char(3) | NO | UNI | | |\n| District | char(20) | YES | MUL | | |\n| Population | int(11) | NO | | 0 | |\n+------------+----------+------+-----+---------+----------------+\n\nSHOW COLUMNS FROM employees WHERE Type LIKE \'Varchar%\';\n+---------------+-------------+------+-----+---------+-------+\n| Field | Type | Null | Key | Default | Extra |\n+---------------+-------------+------+-----+---------+-------+\n| first_name | varchar(30) | NO | MUL | NULL | |\n| last_name | varchar(40) | NO | | NULL | |\n| position | varchar(25) | NO | | NULL | |\n| home_address | varchar(50) | NO | | NULL | |\n| home_phone | varchar(12) | NO | | NULL | |\n| employee_code | varchar(25) | NO | UNI | NULL | |\n+---------------+-------------+------+-----+---------+-------+\n\nURL: https://mariadb.com/kb/en/show-columns/','','https://mariadb.com/kb/en/show-columns/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (340,26,'SHOW CREATE TABLE','Syntax\n------\n\nSHOW CREATE TABLE tbl_name\n\nDescription\n-----------\n\nShows the CREATE TABLE statement that created the given table. The statement\nrequires the SELECT privilege for the table. This statement also works with\nviews and SEQUENCE.\n\nSHOW CREATE TABLE quotes table and column names according to the value of the\nsql_quote_show_create server system variable.\n\nCertain SQL_MODE values can result in parts of the original CREATE statement\nnot being included in the output. MariaDB-specific table options, column\noptions, and index options are not included in the output of this statement if\nthe NO_TABLE_OPTIONS, NO_FIELD_OPTIONS and NO_KEY_OPTIONS SQL_MODE flags are\nused. All MariaDB-specific table attributes are also not shown when a\nnon-MariaDB/MySQL emulation mode is used, which includes ANSI, DB2,\nPOSTGRESQL, MSSQL, MAXDB or ORACLE.\n\nInvalid table options, column options and index options are normally commented\nout (note, that it is possible to create a table with invalid options, by\naltering a table of a different engine, where these options were valid). To\nhave them uncommented, enable the IGNORE_BAD_TABLE_OPTIONS SQL_MODE. Remember\nthat replaying a CREATE TABLE statement with uncommented invalid options will\nfail with an error, unless the IGNORE_BAD_TABLE_OPTIONS SQL_MODE is in effect.\n\nNote that SHOW CREATE TABLE is not meant to provide metadata about a table. It\nprovides information about how the table was declared, but the real table\nstructure could differ a bit. For example, if an index has been declared as\nHASH, the CREATE TABLE statement returned by SHOW CREATE TABLE will declare\nthat index as HASH; however, it is possible that the index is in fact a BTREE,\nbecause the storage engine does not support HASH.\n\nMariaDB starting with 10.2.1\n----------------------------\nMariaDB 10.2.1 permits TEXT and BLOB data types to be assigned a DEFAULT\nvalue. As a result, from MariaDB 10.2.1, SHOW CREATE TABLE will append a\nDEFAULT NULL to nullable TEXT or BLOB fields if no specific default is\nprovided.\n\nMariaDB starting with 10.2.2\n----------------------------\nFrom MariaDB 10.2.2, numbers are no longer quoted in the DEFAULT clause in\nSHOW CREATE statement. Previously, MariaDB quoted numbers.\n\nIndex Order\n-----------\n\nIndexes are sorted and displayed in the following order, which may differ from\nthe order of the CREATE TABLE statement.\n\n* PRIMARY KEY\n* UNIQUE keys where all column are NOT NULL\n* UNIQUE keys that don\'t contain partial segments\n* Other UNIQUE keys\n* LONG UNIQUE keys\n* Normal keys\n* Fulltext keys\n\nSee sql/sql_table.cc for details.\n\nExamples\n--------\n\nSHOW CREATE TABLE t\\G\n*************************** 1. row ***************************\n Table: t\nCreate Table: CREATE TABLE `t` (\n `id` int(11) NOT NULL AUTO_INCREMENT,\n `s` char(60) DEFAULT NULL,\n PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1\n\nWith sql_quote_show_create off:\n\nSHOW CREATE TABLE t\\G\n*************************** 1. row ***************************\n Table: t\nCreate Table: CREATE TABLE t (\n id int(11) NOT NULL AUTO_INCREMENT,\n s char(60) DEFAULT NULL,\n PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1\n\nUnquoted numeric DEFAULTs, from MariaDB 10.2.2:\n\nCREATE TABLE td (link TINYINT DEFAULT 1);\n\nSHOW CREATE TABLE td\\G\n*************************** 1. row ***************************\n Table: td\nCreate Table: CREATE TABLE `td` (\n `link` tinyint(4) DEFAULT 1\n) ENGINE=InnoDB DEFAULT CHARSET=latin1\n\nQuoted numeric DEFAULTs, until MariaDB 10.2.1:\n\nCREATE TABLE td (link TINYINT DEFAULT 1);\n\nSHOW CREATE TABLE td\\G\n*************************** 1. row ***************************\n Table: td\nCreate Table: CREATE TABLE `td` (\n `link` tinyint(4) DEFAULT \'1\'\n) ENGINE=InnoDB DEFAULT CHARSET=latin1\n\nSQL_MODE impacting the output:\n\nSELECT @@sql_mode;\n+------------------------------------------------------------------------------\n------------+\n| @@sql_mode \n |\n+------------------------------------------------------------------------------\n------------+\n|\nSTRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SU\nSTITUTION |\n+------------------------------------------------------------------------------\n------------+\n\nCREATE TABLE `t1` (\n `id` int(11) NOT NULL AUTO_INCREMENT,\n `msg` varchar(100) DEFAULT NULL,\n PRIMARY KEY (`id`)\n ) ENGINE=InnoDB DEFAULT CHARSET=latin1\n;\n\nSHOW CREATE TABLE t1\\G\n*************************** 1. row ***************************\n Table: t1\nCreate Table: CREATE TABLE `t1` (\n `id` int(11) NOT NULL AUTO_INCREMENT,\n `msg` varchar(100) DEFAULT NULL,\n PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1\n\nSET SQL_MODE=ORACLE;\n\nSHOW CREATE TABLE t1\\G\n*************************** 1. row ***************************\n Table: t1\nCreate Table: CREATE TABLE \"t1\" (\n \"id\" int(11) NOT NULL,\n \"msg\" varchar(100) DEFAULT NULL,\n PRIMARY KEY (\"id\")\n\nURL: https://mariadb.com/kb/en/show-create-table/','','https://mariadb.com/kb/en/show-create-table/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (341,26,'SHOW INDEX','Syntax\n------\n\nSHOW {INDEX | INDEXES | KEYS} \n FROM tbl_name [FROM db_name]\n [WHERE expr]\n\nDescription\n-----------\n\nSHOW INDEX returns table index information. The format resembles that of the\nSQLStatistics call in ODBC.\n\nYou can use db_name.tbl_name as an alternative to the tbl_name FROM db_name\nsyntax. These two statements are equivalent:\n\nSHOW INDEX FROM mytable FROM mydb;\nSHOW INDEX FROM mydb.mytable;\n\nSHOW KEYS and SHOW INDEXES are synonyms for SHOW INDEX.\n\nYou can also list a table\'s indexes with the mariadb-show command:\n\nmariadb-show -k db_name tbl_name\n\nThe information_schema.STATISTICS table stores similar information.\n\nThe following fields are returned by SHOW INDEX.\n\n+------------------------+---------------------------------------------------+\n| Field | Description |\n+------------------------+---------------------------------------------------+\n| Table | Table name |\n+------------------------+---------------------------------------------------+\n| Non_unique | 1 if the index permits duplicate values, 0 if |\n| | values must be unique. |\n+------------------------+---------------------------------------------------+\n| Key_name | Index name. The primary key is always named |\n| | PRIMARY. |\n+------------------------+---------------------------------------------------+\n| Seq_in_index | The column\'s sequence in the index, beginning |\n| | with 1. |\n+------------------------+---------------------------------------------------+\n| Column_name | Column name. |\n+------------------------+---------------------------------------------------+\n| Collation | Either A, if the column is sorted in ascending |\n| | order in the index, or NULL if it\'s not sorted. |\n+------------------------+---------------------------------------------------+\n| Cardinality | Estimated number of unique values in the index. |\n| | The cardinality statistics are calculated at |\n| | various times, and can help the optimizer make |\n| | improved decisions. |\n+------------------------+---------------------------------------------------+\n| Sub_part | NULL if the entire column is included in the |\n| | index, or the number of included characters if |\n| | not. |\n+------------------------+---------------------------------------------------+\n| Packed | NULL if the index is not packed, otherwise how |\n| | the index is packed. |\n+------------------------+---------------------------------------------------+\n| Null | NULL if NULL values are permitted in the column, |\n| | an empty string if NULLs are not permitted. |\n+------------------------+---------------------------------------------------+\n| Index_type | The index type, which can be BTREE, FULLTEXT, |\n| | HASH or RTREE. See Storage Engine Index Types. |\n+------------------------+---------------------------------------------------+\n| Comment | Other information, such as whether the index is |\n| | disabled. |\n+------------------------+---------------------------------------------------+\n| Index_comment | Contents of the COMMENT attribute when the index |\n| | was created. |\n+------------------------+---------------------------------------------------+\n| Ignored | Whether or not an index will be ignored by the |\n| | optimizer. See Ignored Indexes. From MariaDB |\n| | 10.6.0. |\n+------------------------+---------------------------------------------------+\n\nThe WHERE and LIKE clauses can be given to select rows using more general\nconditions, as discussed in Extended SHOW.\n\nExamples\n--------\n\nCREATE TABLE IF NOT EXISTS `employees_example` (\n `id` int(11) NOT NULL AUTO_INCREMENT,\n `first_name` varchar(30) NOT NULL,\n `last_name` varchar(40) NOT NULL,\n `position` varchar(25) NOT NULL,\n `home_address` varchar(50) NOT NULL,\n `home_phone` varchar(12) NOT NULL,\n `employee_code` varchar(25) NOT NULL,\n PRIMARY KEY (`id`),\n UNIQUE KEY `employee_code` (`employee_code`),\n KEY `first_name` (`first_name`,`last_name`)\n) ENGINE=Aria;\n\nINSERT INTO `employees_example` (`first_name`, `last_name`, `position`,\n`home_address`, `home_phone`, `employee_code`)\n VALUES\n (\'Mustapha\', \'Mond\', \'Chief Executive Officer\', \'692 Promiscuous Plaza\',\n\'326-555-3492\', \'MM1\'),\n (\'Henry\', \'Foster\', \'Store Manager\', \'314 Savage Circle\', \'326-555-3847\',\n\'HF1\'),\n (\'Bernard\', \'Marx\', \'Cashier\', \'1240 Ambient Avenue\', \'326-555-8456\', \'BM1\'),\n (\'Lenina\', \'Crowne\', \'Cashier\', \'281 Bumblepuppy Boulevard\', \'328-555-2349\',\n\'LC1\'),\n (\'Fanny\', \'Crowne\', \'Restocker\', \'1023 Bokanovsky Lane\', \'326-555-6329\',\n\'FC1\'),\n (\'Helmholtz\', \'Watson\', \'Janitor\', \'944 Soma Court\', \'329-555-2478\', \'HW1\');\n\nSHOW INDEXES FROM employees_example\\G\n*************************** 1. row ***************************\n Table: employees_example\n Non_unique: 0\n Key_name: PRIMARY\n Seq_in_index: 1\n Column_name: id\n Collation: A\n Cardinality: 6\n Sub_part: NULL\n Packed: NULL\n Null:\n Index_type: BTREE\n Comment:\nIndex_comment: \n Ignored: NO\n*************************** 2. row ***************************\n Table: employees_example\n Non_unique: 0\n Key_name: employee_code\n Seq_in_index: 1\n Column_name: employee_code\n Collation: A\n Cardinality: 6\n Sub_part: NULL\n Packed: NULL\n Null:\n Index_type: BTREE\n Comment:\nIndex_comment: \n Ignored: NO\n*************************** 3. row ***************************\n Table: employees_example\n Non_unique: 1\n Key_name: first_name\n Seq_in_index: 1\n Column_name: first_name\n Collation: A\n Cardinality: NULL\n Sub_part: NULL\n Packed: NULL\n Null:\n Index_type: BTREE\n Comment:\nIndex_comment: \n Ignored: NO\n*************************** 4. row ***************************\n Table: employees_example\n Non_unique: 1\n Key_name: first_name\n Seq_in_index: 2\n Column_name: last_name\n Collation: A\n Cardinality: NULL\n Sub_part: NULL\n Packed: NULL\n Null:\n Index_type: BTREE\n Comment:\nIndex_comment: \n Ignored: NO\n\nURL: https://mariadb.com/kb/en/show-index/','','https://mariadb.com/kb/en/show-index/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (342,26,'SHOW EXPLAIN','Syntax\n------\n\nSHOW EXPLAIN [FORMAT=JSON] FOR <connection_id>;\nEXPLAIN [FORMAT=JSON] FOR CONNECTION <connection_id>;\n\nDescription\n-----------\n\nThe SHOW EXPLAIN command allows one to get an EXPLAIN (that is, a description\nof a query plan) of a query running in a certain connection.\n\nSHOW EXPLAIN FOR <connection_id>;\n\nwill produce an EXPLAIN output for the query that connection number\nconnection_id is running. The connection id can be obtained with SHOW\nPROCESSLIST.\n\nSHOW EXPLAIN FOR 1;\n+------+-------------+-------+-------+---------------+------+---------+------+-\n-------+-------------+\n| id | select_type | table | type | possible_keys | key | key_len | ref |\nrows | Extra |\n+------+-------------+-------+-------+---------------+------+---------+------+-\n-------+-------------+\n| 1 | SIMPLE | tbl | index | NULL | a | 5 | NULL |\n1000107 | Using index |\n+------+-------------+-------+-------+---------------+------+---------+------+-\n-------+-------------+\n1 row in set, 1 warning (0.00 sec)\n\nThe output is always accompanied with a warning which shows the query the\ntarget connection is running (this shows what the EXPLAIN is for):\n\nSHOW WARNINGS;\n+-------+------+------------------------+\n| Level | Code | Message |\n+-------+------+------------------------+\n| Note | 1003 | select sum(a) from tbl |\n+-------+------+------------------------+\n1 row in set (0.00 sec)\n\nEXPLAIN FOR CONNECTION\n----------------------\n\nMariaDB starting with 10.9\n--------------------------\nThe EXPLAIN FOR CONNECTION syntax was added for MySQL compatibility.\n\nFORMAT=JSON\n-----------\n\nMariaDB starting with 10.9\n--------------------------\nSHOW EXPLAIN [FORMAT=JSON] FOR <connection_id> extends SHOW EXPLAIN to return\nmore detailed JSON output.\n\nPossible Errors\n---------------\n\nThe output can be only produced if the target connection is currently running\na query, which has a ready query plan. If this is not the case, the output\nwill be:\n\nSHOW EXPLAIN FOR 2;\nERROR 1932 (HY000): Target is not running an EXPLAINable command\n\nYou will get this error when:\n\n* the target connection is not running a command for which one can run EXPLAIN\n* the target connection is running a command for which one can run EXPLAIN, but\nthere is no query plan yet (for example, tables are open and locks are\n acquired before the query plan is produced)\n\nDifferences Between SHOW EXPLAIN and EXPLAIN Outputs\n----------------------------------------------------\n\nBackground\n----------\n\nIn MySQL, EXPLAIN execution takes a slightly different route from the way the\nreal query (typically the SELECT) is optimized. This is unfortunate, and has\ncaused a number of bugs in EXPLAIN. (For example, see MDEV-326, MDEV-410, and\nlp:1013343. lp:992942 is not directly about EXPLAIN, but it also would not\nhave existed if MySQL didn\'t try to delete parts of a query plan in the middle\nof the query)\n\nSHOW EXPLAIN examines a running SELECT, and hence its output may be slightly\ndifferent from what EXPLAIN SELECT would produce. We did our best to make sure\nthat either the difference is negligible, or SHOW EXPLAIN\'s output is closer\nto reality than EXPLAIN\'s output.\n\nList of Recorded Differences\n----------------------------\n\n* SHOW EXPLAIN may have Extra=\'no matching row in const table\', where EXPLAIN\nwould produce Extra=\'Impossible WHERE ...\'\n* For queries with subqueries, SHOW EXPLAIN may print select_type==PRIMARY\nwhere regular EXPLAIN used to print select_type==SIMPLE, or vice versa.\n\nRequired Permissions\n--------------------\n\nRunning SHOW EXPLAIN requires the same permissions as running SHOW PROCESSLIST\nwould.\n\nURL: https://mariadb.com/kb/en/show-explain/','','https://mariadb.com/kb/en/show-explain/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (343,26,'BACKUP STAGE','MariaDB starting with 10.4.1\n----------------------------\nThe BACKUP STAGE commands were introduced in MariaDB 10.4.1.\n\nThe BACKUP STAGE commands are a set of commands to make it possible to make an\nefficient external backup tool.\n\nSyntax\n------\n\nBACKUP STAGE [START | FLUSH | BLOCK_DDL | BLOCK_COMMIT | END ]\n\nIn the following text, a transactional table means InnoDB or \"InnoDB-like\nengine with redo log that can lock redo purges and can be copied without locks\nby an outside process\".\n\nGoals with BACKUP STAGE Commands\n--------------------------------\n\n* To be able to do a majority of the backup with the minimum possible server\nlocks. Especially for transactional tables (InnoDB, MyRocks etc) there is only\nneed for a very short block of new commits while copying statistics and log\ntables.\n* DDL are only needed to be blocked for a very short duration of the backup\nwhile mariabackup is copying the tables affected by DDL during the initial\npart of the backup.\n* Most non transactional tables (those that are not in use) will be copied\nduring BACKUP STAGE START. The exceptions are system statistic and log tables\nthat are not blocked during the backup until BLOCK_COMMIT.\n* Should work efficiently with backup tools that use disk snapshots.\n* Should work as efficiently as possible for all table types that store data\non the local disks.\n* As little copying as possible under higher level stages/locks. For example,\n.frm (dictionary) and .trn (trigger) files should be copying while copying the\ntable data.\n\nBACKUP STAGE Commands\n---------------------\n\nBACKUP STAGE START\n------------------\n\nThe START stage is designed for the following tasks:\n\n* Blocks purge of redo files for storage engines that needs this (Aria)\n* Start logging of DDL commands into \'datadir\'/ddl.log. This may take a short\ntime as the command has to wait until there are no active DDL commands.\n\nBACKUP STAGE FLUSH\n------------------\n\nThe FLUSH stage is designed for the following tasks:\n\n* FLUSH all changes for inactive non-transactional tables, except for\nstatistics and log tables.\n* Close all tables that are not in use, to ensure they are marked as closed\nfor the backup.\n* BLOCK all new write locks for all non transactional tables (except\nstatistics and log tables). The command will not wait for tables that are in\nuse by read-only transactions.\n\nDDLs don\'t have to be blocked at this stage as they can\'t cause the table to\nbe in an inconsistent state. This is true also for non-transactional tables.\n\nBACKUP STAGE BLOCK_DDL\n----------------------\n\nThe BLOCK_DDL stage is designed for the following tasks:\n\n* Wait for all statements using write locked non-transactional tables to end.\n* Blocks CREATE TABLE, DROP TABLE, TRUNCATE TABLE, and RENAME TABLE.\n* Blocks also start off a new ALTER TABLE and the final rename phase of ALTER\nTABLE. Running ALTER TABLES are not blocked.\n\nBACKUP STAGE BLOCK_COMMIT\n-------------------------\n\nThe BLOCK_COMMIT stage is designed for the following tasks:\n\n* Lock the binary log and commit/rollback to ensure that no changes are\ncommitted to any tables. If there are active commits or data to be copied to\nthe binary log this will be allowed to finish. Active transactions will not\naffect BLOCK_COMMIT.\n* This doesn\'t lock temporary tables that are not used by replication. However\nthese will be blocked when it\'s time to write to the binary log.\n* Lock system log tables and statistics tables, flush them and mark them\nclosed.\n\nWhen the BLOCK_COMMIT\'s stages return, this is the \'backup time\'. Everything\ncommitted will be in the backup and everything not committed will roll back.\n\nTransactional engines will continue to do changes to the redo log during the\nBLOCK COMMIT stage, but this is not important as all of these will roll back\nlater as the changes will not be committed.\n\nBACKUP STAGE END\n----------------\n\nThe END stage is designed for the following tasks:\n\n* End DDL logging\n* Free resources\n\nUsing BACKUP STAGE Commands with Backup Tools\n---------------------------------------------\n\nUsing BACKUP STAGE Commands with Mariabackup\n--------------------------------------------\n\nThe BACKUP STAGE commands are a set of commands to make it possible to make an\nefficient external backup tool. How Mariabackup uses these commands depends on\nwhether you are using the version that is bundled with MariaDB Community\nServer or the version that is bundled with MariaDB Enterprise Server. See\nMariabackup and BACKUP STAGE Commands for some examples on how Mariabackup\nuses these commands.\n\nIf you would like to use a version of Mariabackup that uses the BACKUP STAGE\ncommands in an efficient way, then one option is to use MariaDB Enterprise\nBackup that is bundled with MariaDB Enterprise Server.\n\nUsing BACKUP STAGE Commands with Storage Snapshots\n--------------------------------------------------\n\nThe BACKUP STAGE commands are a set of commands to make it possible to make an\nefficient external backup tool. These commands could even be used by tools\nthat perform backups by taking a snapshot of a file system, SAN, or some other\nkind of storage device. See Storage Snapshots and BACKUP STAGE Commands for\nsome examples on how to use each BACKUP STAGE command in an efficient way.\n\nPrivileges\n----------\n\nBACKUP STAGE requires the RELOAD privilege.\n\nNotes\n-----\n\n* Only one connection can run BACKUP STAGE START. If a second connection\ntries, it will wait until the first one has executed BACKUP STAGE END.\n* If the user skips a BACKUP STAGE, then all intermediate backup stages will\nautomatically be run. This will allow us to add new stages within the BACKUP\nSTAGE hierarchy in the future with even more precise locks without causing\nproblems for tools using an earlier version of the BACKUP STAGE implementation.\n* One can use the max_statement_time or lock_wait_timeout system variables to\nensure that a BACKUP STAGE command doesn\'t block the server too long.\n* DDL logging will only be available in MariaDB Enterprise Server 10.2 and\nlater.\n* A disconnect will automatically release backup stages.\n* There is no easy way to see which is the current stage.\n\nURL: https://mariadb.com/kb/en/backup-stage/','','https://mariadb.com/kb/en/backup-stage/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (344,26,'BACKUP LOCK','MariaDB starting with 10.4.2\n----------------------------\nThe BACKUP LOCK command was introduced in MariaDB 10.4.2.\n\nBACKUP LOCK blocks a table from DDL statements. This is mainly intended to be\nused by tools like mariabackup that need to ensure there are no DDLs on a\ntable while the table files are opened. For example, for an Aria table that\nstores data in 3 files with extensions .frm, .MAI and .MAD. Normal read/write\noperations can continue as normal.\n\nSyntax\n------\n\nTo lock a table:\n\nBACKUP LOCK table_name\n\nTo unlock a table:\n\nBACKUP UNLOCK\n\nUsage in a Backup Tool\n----------------------\n\nBACKUP LOCK [database.]table_name;\n - Open all files related to a table (for example, t.frm, t.MAI and t.MYD)\nBACKUP UNLOCK;\n- Copy data\n- Close files\n\nThis ensures that all files are from the same generation, that is created at\nthe same time by the MariaDB server. This works, because the open files will\npoint to the original table files which will not be affected if there is any\nALTER TABLE while copying the files.\n\nPrivileges\n----------\n\nBACKUP LOCK requires the RELOAD privilege.\n\nNotes\n-----\n\n* The idea is that the BACKUP LOCK should be held for as short a time as\npossible by the backup tool. The time to take an uncontested lock is very\nshort! One can easily do 50,000 locks/unlocks per second on low end hardware.\n* One should use different connections for BACKUP STAGE commands and BACKUP\nLOCK.\n\nImplementation\n--------------\n\n* Internally, BACKUP LOCK is implemented by taking an MDLSHARED_HIGH_PRIO MDL\nlock on the table object, which protects the table from any DDL operations.\n\nURL: https://mariadb.com/kb/en/backup-lock/','','https://mariadb.com/kb/en/backup-lock/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (345,26,'FLUSH','Syntax\n------\n\nFLUSH [NO_WRITE_TO_BINLOG | LOCAL]\n flush_option [, flush_option] ...\n\nor when flushing tables:\n\nFLUSH [NO_WRITE_TO_BINLOG | LOCAL] TABLES [table_list] [table_flush_option]\n\nwhere table_list is a list of tables separated by , (comma).\n\nDescription\n-----------\n\nThe FLUSH statement clears or reloads various internal caches used by MariaDB.\nTo execute FLUSH, you must have the RELOAD privilege. See GRANT.\n\nThe RESET statement is similar to FLUSH. See RESET.\n\nYou cannot issue a FLUSH statement from within a stored function or a trigger.\nDoing so within a stored procedure is permitted, as long as it is not called\nby a stored function or trigger. See Stored Routine Limitations, Stored\nFunction Limitations and Trigger Limitations.\n\nIf a listed table is a view, an error like the following will be produced:\n\nERROR 1347 (HY000): \'test.v\' is not BASE TABLE\n\nBy default, FLUSH statements are written to the binary log and will be\nreplicated. The NO_WRITE_TO_BINLOG keyword (LOCAL is an alias) will ensure the\nstatement is not written to the binary log.\n\nThe different flush options are:\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| CHANGED_PAGE_BITMAPS | XtraDB only. Internal command used for backup |\n| | purposes. See the Information Schema |\n| | CHANGED_PAGE_BITMAPS Table. |\n+---------------------------+------------------------------------------------+\n| CLIENT_STATISTICS | Reset client statistics (see SHOW |\n| | CLIENT_STATISTICS). |\n+---------------------------+------------------------------------------------+\n| DES_KEY_FILE | Reloads the DES key file (Specified with the |\n| | --des-key-file startup option). |\n+---------------------------+------------------------------------------------+\n| HOSTS | Flush the hostname cache (used for converting |\n| | ip to host names and for unblocking blocked |\n| | hosts. See max_connect_errors and |\n| | performance_schema.host_cache |\n+---------------------------+------------------------------------------------+\n| INDEX_STATISTICS | Reset index statistics (see SHOW |\n| | INDEX_STATISTICS). |\n+---------------------------+------------------------------------------------+\n| [ERROR | ENGINE | | Close and reopen the specified log type, or |\n| GENERAL | SLOW | BINARY | all log types if none are specified. FLUSH |\n| | RELAY] LOGS | RELAY LOGS [connection-name] can be used to |\n| | flush the relay logs for a specific |\n| | connection. Only one connection can be |\n| | specified per FLUSH command. See Multi-source |\n| | replication. FLUSH ENGINE LOGS will delete |\n| | all unneeded Aria redo logs. FLUSH BINARY |\n| | LOGS DELETE_DOMAIN_ID=(list-of-domains) can |\n| | be used to discard obsolete GTID domains from |\n| | the server\'s binary log state. In order for |\n| | this to be successful, no event group from |\n| | the listed GTID domains can be present in |\n| | existing binary log files. If some still |\n| | exist, then they must be purged prior to |\n| | executing this command. If the command |\n| | completes successfully, then it also rotates |\n| | the binary log. |\n+---------------------------+------------------------------------------------+\n| MASTER | Deprecated option, use RESET MASTER instead. |\n+---------------------------+------------------------------------------------+\n| PRIVILEGES | Reload all privileges from the privilege |\n| | tables in the mysql database. If the server |\n| | is started with --skip-grant-table option, |\n| | this will activate the privilege tables again. |\n+---------------------------+------------------------------------------------+\n| QUERY CACHE | Defragment the query cache to better utilize |\n| | its memory. If you want to reset the query |\n| | cache, you can do it with RESET QUERY CACHE. |\n+---------------------------+------------------------------------------------+\n| QUERY_RESPONSE_TIME | See the QUERY_RESPONSE_TIME plugin. |\n+---------------------------+------------------------------------------------+\n| SLAVE | Deprecated option, use RESET REPLICA or RESET |\n| | SLAVE instead. |\n+---------------------------+------------------------------------------------+\n| SSL | Used to dynamically reinitialize the server\'s |\n| | TLS context by reloading the files defined by |\n| | several TLS system variables. See FLUSH SSL |\n| | for more information. |\n+---------------------------+------------------------------------------------+\n| STATUS | Resets all server status variables that can |\n| | be reset to 0. Not all global status |\n| | variables support this, so not all global |\n| | values are reset. See FLUSH STATUS for more |\n| | information. |\n+---------------------------+------------------------------------------------+\n| TABLE | Close tables given as options or all open |\n| | tables if no table list was used. From |\n| | MariaDB 10.4.1, using without any table list |\n| | will only close tables not in use, and tables |\n| | not locked by the FLUSH TABLES connection. If |\n| | there are no locked tables, FLUSH TABLES will |\n| | be instant and will not cause any waits, as |\n| | it no longer waits for tables in use. When a |\n| | table list is provided, from MariaDB 10.4.1, |\n| | the server will wait for the end of any |\n| | transactions that are using the tables. |\n| | Previously, FLUSH TABLES only waited for the |\n| | statements to complete. |\n+---------------------------+------------------------------------------------+\n| TABLES | Same as FLUSH TABLE. |\n+---------------------------+------------------------------------------------+\n| TABLES ... FOR EXPORT | For InnoDB tables, flushes table changes to |\n| | disk to permit binary table copies while the |\n| | server is running. See FLUSH TABLES ... FOR |\n| | EXPORT for more. |\n+---------------------------+------------------------------------------------+\n| TABLES WITH READ LOCK | Closes all open tables. New tables are only |\n| | allowed to be opened with read locks until an |\n| | UNLOCK TABLES is given. |\n+---------------------------+------------------------------------------------+\n| TABLES WITH READ LOCK | As TABLES WITH READ LOCK but also disable all |\n| AND DISABLE CHECKPOINT | checkpoint writes by transactional table |\n| | engines. This is useful when doing a disk |\n| | snapshot of all tables. |\n+---------------------------+------------------------------------------------+\n| TABLE_STATISTICS | Reset table statistics (see SHOW |\n| | TABLE_STATISTICS). |\n+---------------------------+------------------------------------------------+\n| USER_RESOURCES | Resets all per hour user resources. This |\n| | enables clients that have exhausted their |\n| | resources to connect again. |\n+---------------------------+------------------------------------------------+\n| USER_STATISTICS | Reset user statistics (see SHOW |\n| | USER_STATISTICS). |\n+---------------------------+------------------------------------------------+\n| USER_VARIABLES | Reset user variables (see User-defined |\n| | variables). |\n+---------------------------+------------------------------------------------+\n\nYou can also use the mariadb-admin client to flush things. Use mariadb-admin\n--help to examine what flush commands it supports.\n\nFLUSH RELAY LOGS\n----------------\n\nFLUSH RELAY LOGS \'connection_name\';\n\nCompatibility with MySQL\n------------------------\n\nMariaDB starting with 10.7.0\n----------------------------\nThe FOR CHANNEL keyword was added for MySQL compatibility. This is identical\nas using the channel_name directly after the FLUSH command.\n\nFor example, one can now use:\n\nFLUSH RELAY LOGS FOR CHANNEL \'connection_name\';\n\nFLUSH STATUS\n------------\n\nServer status variables can be reset by executing the following:\n\nFLUSH STATUS;\n\nGlobal Status Variables that Support FLUSH STATUS\n-------------------------------------------------\n\nNot all global status variables support being reset by FLUSH STATUS.\nCurrently, the following status variables are reset by FLUSH STATUS:\n\n* Aborted_clients\n* Aborted_connects\n* Binlog_cache_disk_use\n* Binlog_cache_use\n* Binlog_stmt_cache_disk_use\n* Binlog_stmt_cache_use\n* Connection_errors_accept\n* Connection_errors_internal\n* Connection_errors_max_connections\n* Connection_errors_peer_address\n* Connection_errors_select\n* Connection_errors_tcpwrap\n* Created_tmp_files\n* Delayed_errors\n* Delayed_writes\n* Feature_check_constraint\n* Feature_delay_key_write\n* Max_used_connections\n* Opened_plugin_libraries\n* Performance_schema_accounts_lost\n* Performance_schema_cond_instances_lost\n* Performance_schema_digest_lost\n* Performance_schema_file_handles_lost\n* Performance_schema_file_instances_lost\n* Performance_schema_hosts_lost\n* Performance_schema_locker_lost\n* Performance_schema_mutex_instances_lost\n* Performance_schema_rwlock_instances_lost\n* Performance_schema_session_connect_attrs_lost\n* Performance_schema_socket_instances_lost\n* Performance_schema_stage_classes_lost\n* Performance_schema_statement_classes_lost\n* Performance_schema_table_handles_lost\n* Performance_schema_table_instances_lost\n* Performance_schema_thread_instances_lost\n* Performance_schema_users_lost\n* Qcache_hits\n* Qcache_inserts\n* Qcache_lowmem_prunes\n* Qcache_not_cached\n* Rpl_semi_sync_master_no_times\n* Rpl_semi_sync_master_no_tx\n* Rpl_semi_sync_master_timefunc_failures\n* Rpl_semi_sync_master_wait_pos_backtraverse\n* Rpl_semi_sync_master_yes_tx\n* Rpl_transactions_multi_engine\n* Server_audit_writes_failed\n* Slave_retried_transactions\n* Slow_launch_threads\n* Ssl_accept_renegotiates\n* Ssl_accepts\n* Ssl_callback_cache_hits\n* Ssl_client_connects\n* Ssl_connect_renegotiates\n* Ssl_ctx_verify_depth\n* Ssl_ctx_verify_mode\n* Ssl_finished_accepts\n* Ssl_finished_connects\n* Ssl_session_cache_hits\n* Ssl_session_cache_misses\n* Ssl_session_cache_overflows\n* Ssl_session_cache_size\n* Ssl_session_cache_timeouts\n* Ssl_sessions_reused\n* Ssl_used_session_cache_entries\n* Subquery_cache_hit\n* Subquery_cache_miss\n* Table_locks_immediate\n* Table_locks_waited\n* Tc_log_max_pages_used\n* Tc_log_page_waits\n* Transactions_gtid_foreign_engine\n* Transactions_multi_engine\n\nThe different usage of FLUSH TABLES\n-----------------------------------\n\nThe purpose of FLUSH TABLES\n---------------------------\n\nThe purpose of FLUSH TABLES is to clean up the open table cache and table\ndefinition cache from not in use tables. This frees up memory and file\ndescriptors. Normally this is not needed as the caches works on a FIFO bases,\nbut can be useful if the server seams to use up to much memory for some reason.\n\nThe purpose of FLUSH TABLES WITH READ LOCK \n-------------------------------------------\n\nFLUSH TABLES WITH READ LOCK is useful if you want to take a backup of some\ntables. When FLUSH TABLES WITH READ LOCK returns, all write access to tables\nare blocked and all tables are marked as \'properly closed\' on disk. The tables\ncan still be used for read operations.\n\nThe purpose of FLUSH TABLES table_list\n--------------------------------------\n\nFLUSH TABLES table_list is useful if you want to copy a table object/files to\nor from the server. This command puts a lock that stops new users of the table\nand will wait until everyone has stopped using the table. The table is then\nremoved from the table definition and table cache.\n\nNote that it\'s up to the user to ensure that no one is accessing the table\nbetween FLUSH TABLES and the table is copied to or from the server. This can\nbe secured by using LOCK TABLES.\n\nIf there are any tables locked by the connection that is using FLUSH TABLES\nall the locked tables will be closed as part of the flush and reopened and','','https://mariadb.com/kb/en/flush/'); +update help_topic set description = CONCAT(description, '\nrelocked before FLUSH TABLES returns. This allows one to copy the table after\nFLUSH TABLES returns without having any writes on the table. For now this\nworks works with most tables, except InnoDB as InnoDB may do background purges\non the table even while it\'s write locked.\n\nThe purpose of FLUSH TABLES table_list WITH READ LOCK\n-----------------------------------------------------\n\nFLUSH TABLES table_list WITH READ LOCK should work as FLUSH TABLES WITH READ\nLOCK, but only those tables that are listed will be properly closed. However\nin practice this works exactly like FLUSH TABLES WITH READ LOCK as the FLUSH\ncommand has anyway to wait for all WRITE operations to end because we are\ndepending on a global read lock for this code. In the future we should\nconsider fixing this to instead use meta data locks.\n\nImplementation of FLUSH TABLES commands in MariaDB 10.4.8 and above\n-------------------------------------------------------------------\n\nImplementation of FLUSH TABLES\n------------------------------\n\n* Free memory and file descriptors not in use\n\nImplementation of FLUSH TABLES WITH READ LOCK\n---------------------------------------------\n\n* Lock all tables read only for simple old style backup.\n* All background writes are suspended and tables are marked as closed.\n* No statement requiring table changes are allowed for any user until UNLOCK\nTABLES.\n\nInstead of using FLUSH TABLE WITH READ LOCK one should in most cases instead\nuse BACKUP STAGE BLOCK_COMMIT.\n\nImplementation of FLUSH TABLES table_list\n-----------------------------------------\n\n* Free memory and file descriptors for tables not in use from table list.\n* Lock given tables as read only.\n* Wait until all translations has ended that uses any of the given tables.\n* Wait until all background writes are suspended and tables are marked as\nclosed.\n\nImplementation of FLUSH TABLES table_list FOR EXPORT\n----------------------------------------------------\n\n* Free memory and file descriptors for tables not in use from table list\n* Lock given tables as read.\n* Wait until all background writes are suspended and tables are marked as\nclosed.\n* Check that all tables supports FOR EXPORT\n* No changes to these tables allowed until UNLOCK TABLES\n\nThis is basically the same behavior as in old MariaDB version if one first\nlock the tables, then do FLUSH TABLES. The tables will be copyable until\nUNLOCK TABLES.\n\nFLUSH SSL\n---------\n\nMariaDB starting with 10.4\n--------------------------\nThe FLUSH SSL command was first added in MariaDB 10.4.\n\nIn MariaDB 10.4 and later, the FLUSH SSL command can be used to dynamically\nreinitialize the server\'s TLS context. This is most useful if you need to\nreplace a certificate that is about to expire without restarting the server.\n\nThis operation is performed by reloading the files defined by the following\nTLS system variables:\n\n* ssl_cert\n* ssl_key\n* ssl_ca\n* ssl_capath\n* ssl_crl\n* ssl_crlpath\n\nThese TLS system variables are not dynamic, so their values can not be changed\nwithout restarting the server.\n\nIf you want to dynamically reinitialize the server\'s TLS context, then you\nneed to change the certificate and key files at the relevant paths defined by\nthese TLS system variables, without actually changing the values of the\nvariables. See MDEV-19341 for more information.\n\nReducing Memory Usage\n---------------------\n\nTo flush some of the global caches that take up memory, you could execute the\nfollowing command:\n\nFLUSH LOCAL HOSTS,\n QUERY CACHE,\n TABLE_STATISTICS,\n INDEX_STATISTICS,\n USER_STATISTICS;\n\nURL: https://mariadb.com/kb/en/flush/') WHERE help_topic_id = 345; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (346,26,'FLUSH QUERY CACHE','Description\n-----------\n\nYou can defragment the query cache to better utilize its memory with the FLUSH\nQUERY CACHE statement. The statement does not remove any queries from the\ncache.\n\nThe RESET QUERY CACHE statement removes all query results from the query\ncache. The FLUSH TABLES statement also does this.\n\nURL: https://mariadb.com/kb/en/flush-query-cache/','','https://mariadb.com/kb/en/flush-query-cache/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (347,26,'FLUSH TABLES FOR EXPORT','Syntax\n------\n\nFLUSH TABLES table_name [, table_name] FOR EXPORT\n\nDescription\n-----------\n\nFLUSH TABLES ... FOR EXPORT flushes changes to the specified tables to disk so\nthat binary copies can be made while the server is still running. This works\nfor Archive, Aria, CSV, InnoDB, MyISAM, MERGE, and XtraDB tables.\n\nThe table is read locked until one has issued UNLOCK TABLES.\n\nIf a storage engine does not support FLUSH TABLES FOR EXPORT, a 1031 error\n(SQLSTATE \'HY000\') is produced.\n\nIf FLUSH TABLES ... FOR EXPORT is in effect in the session, the following\nstatements will produce an error if attempted:\n\n* FLUSH TABLES WITH READ LOCK\n* FLUSH TABLES ... WITH READ LOCK\n* FLUSH TABLES ... FOR EXPORT\n* Any statement trying to update any table\n\nIf any of the following statements is in effect in the session, attempting\nFLUSH TABLES ... FOR EXPORT will produce an error.\n\n* FLUSH TABLES ... WITH READ LOCK\n* FLUSH TABLES ... FOR EXPORT\n* LOCK TABLES ... READ\n* LOCK TABLES ... WRITE\n\nFLUSH FOR EXPORT is not written to the binary log.\n\nThis statement requires the RELOAD and the LOCK TABLES privileges.\n\nIf one of the specified tables cannot be locked, none of the tables will be\nlocked.\n\nIf a table does not exist, an error like the following will be produced:\n\nERROR 1146 (42S02): Table \'test.xxx\' doesn\'t exist\n\nIf a table is a view, an error like the following will be produced:\n\nERROR 1347 (HY000): \'test.v\' is not BASE TABLE\n\nExample\n-------\n\nFLUSH TABLES test.t1 FOR EXPORT;\n# Copy files related to the table (see below)\nUNLOCK TABLES;\n\nFor a full description, please see copying MariaDB tables.\n\nURL: https://mariadb.com/kb/en/flush-tables-for-export/','','https://mariadb.com/kb/en/flush-tables-for-export/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (348,26,'SHOW RELAYLOG EVENTS','The terms master and slave have historically been used in replication, but the\nterms terms primary and replica are now preferred. The old terms are used\nstill used in parts of the documentation, and in MariaDB commands, although\nMariaDB 10.5 has begun the process of renaming. The documentation process is\nongoing. See MDEV-18777 to follow progress on this effort.\n\nSyntax\n------\n\nSHOW RELAYLOG [\'connection_name\'] EVENTS\n [IN \'log_name\'] [FROM pos] [LIMIT [offset,] row_count]\n [ FOR CHANNEL \'channel_name\']\n\nDescription\n-----------\n\nOn replicas, this command shows the events in the relay log. If \'log_name\' is\nnot specified, the first relay log is shown.\n\nSyntax for the LIMIT clause is the same as for SELECT ... LIMIT.\n\nUsing the LIMIT clause is highly recommended because the SHOW RELAYLOG EVENTS\ncommand returns the complete contents of the relay log, which can be quite\nlarge.\n\nThis command does not return events related to setting user and system\nvariables. If you need those, use mariadb-binlog.\n\nOn the primary, this command does nothing.\n\nRequires the REPLICA MONITOR privilege (>= MariaDB 10.5.9), the REPLICATION\nSLAVE ADMIN privilege (>= MariaDB 10.5.2) or the REPLICATION SLAVE privilege\n(<= MariaDB 10.5.1).\n\nconnection_name\n---------------\n\nIf there is only one nameless primary, or the default primary (as specified by\nthe default_master_connection system variable) is intended, connection_name\ncan be omitted. If provided, the SHOW RELAYLOG statement will apply to the\nspecified primary. connection_name is case-insensitive.\n\nMariaDB starting with 10.7.0\n----------------------------\nThe FOR CHANNEL keyword was added for MySQL compatibility. This is identical\nas using the channel_name directly after SHOW RELAYLOG.\n\nURL: https://mariadb.com/kb/en/show-relaylog-events/','','https://mariadb.com/kb/en/show-relaylog-events/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (349,26,'SHOW SLAVE STATUS','Syntax\n------\n\nSHOW SLAVE [\"connection_name\"] STATUS [FOR CHANNEL \"connection_name\"]\nSHOW REPLICA [\"connection_name\"] STATUS -- From MariaDB 10.5.1\n\nor\n\nSHOW ALL SLAVES STATUS\nSHOW ALL REPLICAS STATUS -- From MariaDB 10.5.1\n\nDescription\n-----------\n\nThis statement is to be run on a replica and provides status information on\nessential parameters of the replica threads.\n\nThis statement requires the SUPER privilege, the REPLICATION_CLIENT privilege,\nor, from MariaDB 10.5.2, the REPLICATION SLAVE ADMIN privilege, or, from\nMariaDB 10.5.9, the REPLICA MONITOR privilege.\n\nMulti-Source\n------------\n\nThe ALL and \"connection_name\" options allow you to connect to many primaries\nat the same time.\n\nALL SLAVES (or ALL REPLICAS from MariaDB 10.5.1) gives you a list of all\nconnections to the primary nodes.\n\nThe rows will be sorted according to Connection_name.\n\nIf you specify a connection_name, you only get the information about that\nconnection. If connection_name is not used, then the name set by\ndefault_master_connection is used. If the connection name doesn\'t exist you\nwill get an error: There is no master connection for \'xxx\'.\n\nMariaDB starting with 10.7.0\n----------------------------\nThe FOR CHANNEL keyword was added for MySQL compatibility. This is identical\nto using the channel_name directly after SHOW SLAVE.\n\nColumn Descriptions\n-------------------\n\n+---------------------+------------------------------------------------------+\n| Name | Description |\n+---------------------+------------------------------------------------------+\n| Connection_name | Name of the primary connection. Returned with SHOW |\n| | ALL SLAVES STATUS (or SHOW ALL REPLICAS STATUS from |\n| | MariaDB 10.5.1) only. |\n+---------------------+------------------------------------------------------+\n| Slave_SQL_State | State of SQL thread. Returned with SHOW ALL SLAVES |\n| | STATUS (or SHOW ALL REPLICAS STATUS from MariaDB |\n| | 10.5.1) only. See Slave SQL Thread States. |\n+---------------------+------------------------------------------------------+\n| Slave_IO_State | State of I/O thread. See Slave I/O Thread States. |\n+---------------------+------------------------------------------------------+\n| Master_host | Master host that the replica is connected to. |\n+---------------------+------------------------------------------------------+\n| Master_user | Account user name being used to connect to the |\n| | primary. |\n+---------------------+------------------------------------------------------+\n| Master_port | The port being used to connect to the primary. |\n+---------------------+------------------------------------------------------+\n| Connect_Retry | Time in seconds between retries to connect. The |\n| | default is 60. The CHANGE MASTER TO statement can |\n| | set this. The master-retry-count option determines |\n| | the maximum number of reconnection attempts. |\n+---------------------+------------------------------------------------------+\n| Master_Log_File | Name of the primary binary log file that the I/O |\n| | thread is currently reading from. |\n+---------------------+------------------------------------------------------+\n| Read_Master_Log_Pos | Position up to which the I/O thread has read in the |\n| | current primary binary log file. |\n+---------------------+------------------------------------------------------+\n| Relay_Log_File | Name of the relay log file that the SQL thread is |\n| | currently processing. |\n+---------------------+------------------------------------------------------+\n| Relay_Log_Pos | Position up to which the SQL thread has finished |\n| | processing in the current relay log file. |\n+---------------------+------------------------------------------------------+\n| Relay_Master_Log_Fi | Name of the primary binary log file that contains |\n| e | the most recent event executed by the SQL thread. |\n+---------------------+------------------------------------------------------+\n| Slave_IO_Running | Whether the replica I/O thread is running and |\n| | connected (Yes), running but not connected to a |\n| | primary (Connecting) or not running (No). |\n+---------------------+------------------------------------------------------+\n| Slave_SQL_Running | Whether or not the SQL thread is running. |\n+---------------------+------------------------------------------------------+\n| Replicate_Rewrite_D | Databases specified for replicating and rewriting |\n| | with the replicate_rewrite_db option. Added in |\n| | MariaDB 10.11 |\n+---------------------+------------------------------------------------------+\n| Replicate_Do_DB | Databases specified for replicating with the |\n| | replicate_do_db option. |\n+---------------------+------------------------------------------------------+\n| Replicate_Ignore_DB | Databases specified for ignoring with the |\n| | replicate_ignore_db option. |\n+---------------------+------------------------------------------------------+\n| Replicate_Do_Table | Tables specified for replicating with the |\n| | replicate_do_table option. |\n+---------------------+------------------------------------------------------+\n| Replicate_Ignore_Ta | Tables specified for ignoring with the |\n| le | replicate_ignore_table option. |\n+---------------------+------------------------------------------------------+\n| Replicate_Wild_Do_T | Tables specified for replicating with the |\n| ble | replicate_wild_do_table option. |\n+---------------------+------------------------------------------------------+\n| Replicate_Wild_Igno | Tables specified for ignoring with the |\n| e_Table | replicate_wild_ignore_table option. |\n+---------------------+------------------------------------------------------+\n| Last_Errno | Alias for Last_SQL_Errno (see below) |\n+---------------------+------------------------------------------------------+\n| Last Error | Alias for Last_SQL_Error (see below) |\n+---------------------+------------------------------------------------------+\n| Skip_Counter | Number of events that a replica skips from the |\n| | master, as recorded in the sql_slave_skip_counter |\n| | system variable. |\n+---------------------+------------------------------------------------------+\n| Exec_Master_Log_Pos | Position up to which the SQL thread has processed |\n| | in the current master binary log file. Can be used |\n| | to start a new replica from a current replica with |\n| | the CHANGE MASTER TO ... MASTER_LOG_POS option. |\n+---------------------+------------------------------------------------------+\n| Relay_Log_Space | Total size of all relay log files combined. |\n+---------------------+------------------------------------------------------+\n| Until_Condition | |\n+---------------------+------------------------------------------------------+\n| Until_Log_File | The MASTER_LOG_FILE value of the START SLAVE UNTIL |\n| | condition. |\n+---------------------+------------------------------------------------------+\n| Until_Log_Pos | The MASTER_LOG_POS value of the START SLAVE UNTIL |\n| | condition. |\n+---------------------+------------------------------------------------------+\n| Master_SSL_Allowed | Whether an SSL connection is permitted (Yes), not |\n| | permitted (No) or permitted but without the replica |\n| | having SSL support enabled (Ignored) |\n+---------------------+------------------------------------------------------+\n| Master_SSL_CA_File | The MASTER_SSL_CA option of the CHANGE MASTER TO |\n| | statement. |\n+---------------------+------------------------------------------------------+\n| Master_SSL_CA_Path | The MASTER_SSL_CAPATH option of the CHANGE MASTER |\n| | TO statement. |\n+---------------------+------------------------------------------------------+\n| Master_SSL_Cert | The MASTER_SSL_CERT option of the CHANGE MASTER TO |\n| | statement. |\n+---------------------+------------------------------------------------------+\n| Master_SSL_Cipher | The MASTER_SSL_CIPHER option of the CHANGE MASTER |\n| | TO statement. |\n+---------------------+------------------------------------------------------+\n| Master_SSL_Key | The MASTER_SSL_KEY option of the CHANGE MASTER TO |\n| | statement. |\n+---------------------+------------------------------------------------------+\n| Seconds_Behind_Mast | Difference between the timestamp logged on the |\n| r | master for the event that the replica is currently |\n| | processing, and the current timestamp on the |\n| | replica. Zero if the replica is not currently |\n| | processing an event. With serial replication, |\n| | seconds_behind_master is updated when the SQL |\n| | thread begins executing a transaction. With |\n| | parallel replication, seconds_behind_master is |\n| | updated only after transactions commit. Starting in |\n| | MariaDB 10.3.38, 10.4.28, 10.5.19, 10.6.12, 10.8.7, |\n| | 10.9.5, 10.10.3, and 10.11.2, an exception is drawn |\n| | on the parallel replica to additionally update |\n| | seconds_behind_master when the first transaction |\n| | received after idling is queued to a worker for |\n| | execution, to provide a reliable initial value for |\n| | the duration until a transaction commits. |\n| | Additional behaviors to be aware of are as follows: |\n| | 1) Seconds_Behind_Master will update for ignored |\n| | events, e.g. those skipped due to |\n| | sql_slave_skip_counter. 2) On the serial replica, |\n| | transactions with prior timestamps can update |\n| | Seconds_Behind_Master such that it can go |\n| | backwards, though this is not true for the parallel |\n| | replica. 3) When configured with MASTER_DELAY, as a |\n| | replicated transaction begins executing (i.e. on a |\n| | serial or post-idle parallel replica), |\n| | Seconds_Behind_Master will update before delaying, |\n| | and while delaying occurs will grow to encompass |\n| | the configured value. 4) There is a known issue, |\n| | tracked by MDEV-17516, such that |\n| | Seconds_Behind_Master will initially present as 0 |\n| | on replica restart until a replicated transaction |\n| | begins executing, even if the last replica session |\n| | was lagging behind when stopped. |\n+---------------------+------------------------------------------------------+\n| Master_SSL_Verify_S | The MASTER_SSL_VERIFY_SERVER_CERT option of the |\n| rver_Cert | CHANGE MASTER TO statement. |\n+---------------------+------------------------------------------------------+\n| Last_IO_Errno | Error code of the most recent error that caused the |\n| | I/O thread to stop (also recorded in the replica\'s |\n| | error log). 0 means no error. RESET SLAVE or RESET |\n| | MASTER will reset this value. |\n+---------------------+------------------------------------------------------+\n| Last_IO_Error | Error message of the most recent error that caused |\n| | the I/O thread to stop (also recorded in the |\n| | replica\'s error log). An empty string means no |\n| | error. RESET SLAVE or RESET MASTER will reset this |\n| | value. |\n+---------------------+------------------------------------------------------+\n| Last_SQL_Errno | Error code of the most recent error that caused the |\n| | SQL thread to stop (also recorded in the replica\'s |\n| | error log). 0 means no error. RESET SLAVE or RESET |\n| | MASTER will reset this value. |\n+---------------------+------------------------------------------------------+','','https://mariadb.com/kb/en/show-replica-status/'); +update help_topic set description = CONCAT(description, '\n| Last_SQL_Error | Error message of the most recent error that caused |\n| | the SQL thread to stop (also recorded in the |\n| | replica\'s error log). An empty string means no |\n| | error. RESET SLAVE or RESET MASTER will reset this |\n| | value. |\n+---------------------+------------------------------------------------------+\n| Replicate_Ignore_Se | List of server_ids that are currently being ignored |\n| ver_Ids | for replication purposes, or an empty string for |\n| | none, as specified in the IGNORE_SERVER_IDS option |\n| | of the CHANGE MASTER TO statement. |\n+---------------------+------------------------------------------------------+\n| Master_Server_Id | The master\'s server_id value. |\n+---------------------+------------------------------------------------------+\n| Master_SSL_Crl | The MASTER_SSL_CRL option of the CHANGE MASTER TO |\n| | statement. |\n+---------------------+------------------------------------------------------+\n| Master_SSL_Crlpath | The MASTER_SSL_CRLPATH option of the CHANGE MASTER |\n| | TO statement. |\n+---------------------+------------------------------------------------------+\n| Using_Gtid | Whether or not global transaction ID\'s are being |\n| | used for replication (can be No, Slave_Pos, or |\n| | Current_Pos). |\n+---------------------+------------------------------------------------------+\n| Gtid_IO_Pos | Current global transaction ID value. |\n+---------------------+------------------------------------------------------+\n| Retried_transaction | Number of retried transactions for this connection. |\n| | Returned with SHOW ALL SLAVES STATUS only. |\n+---------------------+------------------------------------------------------+\n| Max_relay_log_size | Max relay log size for this connection. Returned |\n| | with SHOW ALL SLAVES STATUS only. |\n+---------------------+------------------------------------------------------+\n| Executed_log_entrie | How many log entries the replica has executed. |\n| | Returned with SHOW ALL SLAVES STATUS only. |\n+---------------------+------------------------------------------------------+\n| Slave_received_hear | How many heartbeats we have got from the master. |\n| beats | Returned with SHOW ALL SLAVES STATUS only. |\n+---------------------+------------------------------------------------------+\n| Slave_heartbeat_per | How often to request a heartbeat packet from the |\n| od | master (in seconds). Returned with SHOW ALL SLAVES |\n| | STATUS only. |\n+---------------------+------------------------------------------------------+\n| Gtid_Slave_Pos | GTID of the last event group replicated on a |\n| | replica server, for each replication domain, as |\n| | stored in the gtid_slave_pos system variable. |\n| | Returned with SHOW ALL SLAVES STATUS only. |\n+---------------------+------------------------------------------------------+\n| SQL_Delay | Value specified by MASTER_DELAY in CHANGE MASTER |\n| | (or 0 if none). |\n+---------------------+------------------------------------------------------+\n| SQL_Remaining_Delay | When the replica is delaying the execution of an |\n| | event due to MASTER_DELAY, this is the number of |\n| | seconds of delay remaining before the event will be |\n| | applied. Otherwise, the value is NULL. |\n+---------------------+------------------------------------------------------+\n| Slave_SQL_Running_S | The state of the SQL driver threads, same as in |\n| ate | SHOW PROCESSLIST. When the replica is delaying the |\n| | execution of an event due to MASTER_DELAY, this |\n| | field displays: \"Waiting until MASTER_DELAY seconds |\n| | after master executed event\". |\n+---------------------+------------------------------------------------------+\n| Slave_DDL_Groups | This status variable counts the occurrence of DDL |\n| | statements. This is a replica-side counter for |\n| | optimistic parallel replication. |\n+---------------------+------------------------------------------------------+\n| Slave_Non_Transacti | This status variable counts the occurrence of |\n| nal_Groups | non-transactional event groups. This is a |\n| | replica-side counter for optimistic parallel |\n| | replication. |\n+---------------------+------------------------------------------------------+\n| Slave_Transactional | This status variable counts the occurrence of |\n| Groups | transactional event groups. This is a replica-side |\n| | counter for optimistic parallel replication. |\n+---------------------+------------------------------------------------------+\n\nSHOW REPLICA STATUS\n-------------------\n\nMariaDB starting with 10.5.1\n----------------------------\nSHOW REPLICA STATUS is an alias for SHOW SLAVE STATUS from MariaDB 10.5.1.\n\nExamples\n--------\n\nIf you issue this statement using the mariadb client, you can use a \\G\nstatement terminator rather than a semicolon to obtain a more readable\nvertical layout.\n\nSHOW SLAVE STATUS\\G\n*************************** 1. row ***************************\n Slave_IO_State: Waiting for master to send event\n Master_Host: db01.example.com\n Master_User: replicant\n Master_Port: 3306\n Connect_Retry: 60\n Master_Log_File: mariadb-bin.000010\n Read_Master_Log_Pos: 548\n Relay_Log_File: relay-bin.000004\n Relay_Log_Pos: 837\n Relay_Master_Log_File: mariadb-bin.000010\n Slave_IO_Running: Yes\n Slave_SQL_Running: Yes\n Replicate_Do_DB:\n Replicate_Ignore_DB:\n Replicate_Do_Table:\n Replicate_Ignore_Table:\n Replicate_Wild_Do_Table:\n Replicate_Wild_Ignore_Table:\n Last_Errno: 0\n Last_Error:\n Skip_Counter: 0\n Exec_Master_Log_Pos: 548\n Relay_Log_Space: 1497\n Until_Condition: None\n Until_Log_File:\n Until_Log_Pos: 0\n Master_SSL_Allowed: No\n Master_SSL_CA_File:\n Master_SSL_CA_Path:\n Master_SSL_Cert:\n Master_SSL_Cipher:\n Master_SSL_Key:\n Seconds_Behind_Master: 0\nMaster_SSL_Verify_Server_Cert: No\n Last_IO_Errno: 0\n Last_IO_Error:\n Last_SQL_Errno: 0\n Last_SQL_Error:\n Replicate_Ignore_Server_Ids:\n Master_Server_Id: 101\n Master_SSL_Crl:\n Master_SSL_Crlpath:\n Using_Gtid: No\n Gtid_IO_Pos:\n\nSHOW ALL SLAVES STATUS\\G\n*************************** 1. row ***************************\n Connection_name:\n Slave_SQL_State: Slave has read all relay log; waiting for the\nslave I/O thread to update it\n Slave_IO_State: Waiting for master to send event\n Master_Host: db01.example.com\n Master_User: replicant\n Master_Port: 3306\n Connect_Retry: 60\n Master_Log_File: mariadb-bin.000010\n Read_Master_Log_Pos: 3608\n Relay_Log_File: relay-bin.000004\n Relay_Log_Pos: 3897\n Relay_Master_Log_File: mariadb-bin.000010\n Slave_IO_Running: Yes\n Slave_SQL_Running: Yes\n Replicate_Do_DB:\n Replicate_Ignore_DB:\n Replicate_Do_Table:\n Replicate_Ignore_Table:\n Replicate_Wild_Do_Table:\n Replicate_Wild_Ignore_Table:\n Last_Errno: 0\n Last_Error:\n Skip_Counter: 0\n Exec_Master_Log_Pos: 3608\n Relay_Log_Space: 4557\n Until_Condition: None\n Until_Log_File:\n Until_Log_Pos: 0\n Master_SSL_Allowed: No\n Master_SSL_CA_File:\n Master_SSL_CA_Path:\n Master_SSL_Cert:\n Master_SSL_Cipher:\n Master_SSL_Key:\n Seconds_Behind_Master: 0\nMaster_SSL_Verify_Server_Cert: No\n Last_IO_Errno: 0\n Last_IO_Error:\n Last_SQL_Errno: 0\n Last_SQL_Error:\n Replicate_Ignore_Server_Ids:\n Master_Server_Id: 101\n Master_SSL_Crl:\n Master_SSL_Crlpath:\n Using_Gtid: No\n Gtid_IO_Pos:\n Retried_transactions: 0\n Max_relay_log_size: 104857600\n Executed_log_entries: 40\n Slave_received_heartbeats: 11\n Slave_heartbeat_period: 1800.000\n Gtid_Slave_Pos: 0-101-2320\n\nYou can also access some of the variables directly from status variables:\n\nSET @@default_master_connection=\"test\" ;\nshow status like \"%slave%\"\n\nVariable_name Value\nCom_show_slave_hosts 0\nCom_show_slave_status 0\nCom_start_all_slaves 0\nCom_start_slave 0\nCom_stop_all_slaves 0\nCom_stop_slave 0\nRpl_semi_sync_slave_status OFF\nSlave_connections 0\nSlave_heartbeat_period 1800.000\nSlave_open_temp_tables 0\nSlave_received_heartbeats 0\nSlave_retried_transactions 0\nSlave_running OFF\nSlaves_connected 0\nSlaves_running 1\n\nURL: https://mariadb.com/kb/en/show-replica-status/') WHERE help_topic_id = 349; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (350,26,'SHOW MASTER STATUS','Syntax\n------\n\nSHOW MASTER STATUS\nSHOW BINLOG STATUS -- From MariaDB 10.5.2\n\nDescription\n-----------\n\nProvides status information about the binary log files of the primary.\n\nThis statement requires the SUPER privilege, the REPLICATION_CLIENT privilege,\nor, from MariaDB 10.5.2, the BINLOG MONITOR privilege.\n\nTo see information about the current GTIDs in the binary log, use the\ngtid_binlog_pos variable.\n\nSHOW MASTER STATUS was renamed to SHOW BINLOG STATUS in MariaDB 10.5.2, but\nthe old name remains an alias for compatibility purposes.\n\nExample\n-------\n\nSHOW MASTER STATUS;\n+--------------------+----------+--------------+------------------+\n| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |\n+--------------------+----------+--------------+------------------+\n| mariadb-bin.000016 | 475 | | |\n+--------------------+----------+--------------+------------------+\nSELECT @@global.gtid_binlog_pos;\n+--------------------------+\n| @@global.gtid_binlog_pos |\n+--------------------------+\n| 0-1-2 |\n+--------------------------+\n\nURL: https://mariadb.com/kb/en/show-binlog-status/','','https://mariadb.com/kb/en/show-binlog-status/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (351,26,'SHOW SLAVE HOSTS','Syntax\n------\n\nSHOW SLAVE HOSTS\nSHOW REPLICA HOSTS -- from MariaDB 10.5.1\n\nDescription\n-----------\n\nThis command is run on the primary and displays a list of replicas that are\ncurrently registered with it. Only replicas started with the\n--report-host=host_name option are visible in this list.\n\nThe output looks like this:\n\nSHOW SLAVE HOSTS;\n+------------+-----------+------+-----------+\n| Server_id | Host | Port | Master_id |\n+------------+-----------+------+-----------+\n| 192168010 | iconnect2 | 3306 | 192168011 |\n| 1921680101 | athena | 3306 | 192168011 |\n+------------+-----------+------+-----------+\n\n* Server_id: The unique server ID of the replica server, as configured in the\nserver\'s option file, or on the command line with --server-id=value.\n* Host: The host name of the replica server, as configured in the server\'s\noption file, or on the command line with --report-host=host_name. Note that\nthis can differ from the machine name as configured in the operating system.\n* Port: The port the replica server is listening on.\n* Master_id: The unique server ID of the primary server that the replica\nserver is replicating from.\n\nSome MariaDB and MySQL versions report another variable, rpl_recovery_rank.\nThis variable was never used, and was eventually removed in MariaDB 10.1.2 .\n\nRequires the REPLICATION MASTER ADMIN privilege (>= MariaDB 10.5.2) or the\nREPLICATION SLAVE privilege (<= MariaDB 10.5.1).\n\nSHOW REPLICA HOSTS\n------------------\n\nMariaDB starting with 10.5.1\n----------------------------\nSHOW REPLICA HOSTS is an alias for SHOW SLAVE HOSTS from MariaDB 10.5.1.\n\nURL: https://mariadb.com/kb/en/show-replica-hosts/','','https://mariadb.com/kb/en/show-replica-hosts/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (352,26,'SHOW PLUGINS','Syntax\n------\n\nSHOW PLUGINS;\n\nDescription\n-----------\n\nSHOW PLUGINS displays information about installed plugins. The Library column\nindicates the plugin library - if it is NULL, the plugin is built-in and\ncannot be uninstalled.\n\nThe PLUGINS table in the information_schema database contains more detailed\ninformation.\n\nFor specific information about storage engines (a particular type of plugin),\nsee the information_schema.ENGINES table and the SHOW ENGINES statement.\n\nExamples\n--------\n\nSHOW PLUGINS;\n+----------------------------+----------+--------------------+-------------+---\n-----+\n| Name | Status | Type | Library |\nLicense |\n+----------------------------+----------+--------------------+-------------+---\n-----+\n| binlog | ACTIVE | STORAGE ENGINE | NULL |\nGPL |\n| mysql_native_password | ACTIVE | AUTHENTICATION | NULL |\nGPL |\n| mysql_old_password | ACTIVE | AUTHENTICATION | NULL |\nGPL |\n| MRG_MyISAM | ACTIVE | STORAGE ENGINE | NULL |\nGPL |\n| MyISAM | ACTIVE | STORAGE ENGINE | NULL |\nGPL |\n| CSV | ACTIVE | STORAGE ENGINE | NULL |\nGPL |\n| MEMORY | ACTIVE | STORAGE ENGINE | NULL |\nGPL |\n| FEDERATED | ACTIVE | STORAGE ENGINE | NULL |\nGPL |\n| PERFORMANCE_SCHEMA | ACTIVE | STORAGE ENGINE | NULL |\nGPL |\n| Aria | ACTIVE | STORAGE ENGINE | NULL |\nGPL |\n| InnoDB | ACTIVE | STORAGE ENGINE | NULL |\nGPL |\n| INNODB_TRX | ACTIVE | INFORMATION SCHEMA | NULL |\nGPL |\n...\n| INNODB_SYS_FOREIGN | ACTIVE | INFORMATION SCHEMA | NULL |\nGPL |\n| INNODB_SYS_FOREIGN_COLS | ACTIVE | INFORMATION SCHEMA | NULL |\nGPL |\n| SPHINX | ACTIVE | STORAGE ENGINE | NULL |\nGPL |\n| ARCHIVE | ACTIVE | STORAGE ENGINE | NULL |\nGPL |\n| BLACKHOLE | ACTIVE | STORAGE ENGINE | NULL |\nGPL |\n| FEEDBACK | DISABLED | INFORMATION SCHEMA | NULL |\nGPL |\n| partition | ACTIVE | STORAGE ENGINE | NULL |\nGPL |\n| pam | ACTIVE | AUTHENTICATION | auth_pam.so |\nGPL |\n+----------------------------+----------+--------------------+-------------+---\n-----+\n\nURL: https://mariadb.com/kb/en/show-plugins/','','https://mariadb.com/kb/en/show-plugins/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (353,26,'SHOW PLUGINS SONAME','Syntax\n------\n\nSHOW PLUGINS SONAME { library | LIKE \'pattern\' | WHERE expr };\n\nDescription\n-----------\n\nSHOW PLUGINS SONAME displays information about compiled-in and all server\nplugins in the plugin_dir directory, including plugins that haven\'t been\ninstalled.\n\nExamples\n--------\n\nSHOW PLUGINS SONAME \'ha_example.so\';\n+----------+---------------+----------------+---------------+---------+\n| Name | Status | Type | Library | License |\n+----------+---------------+----------------+---------------+---------+\n| EXAMPLE | NOT INSTALLED | STORAGE ENGINE | ha_example.so | GPL |\n| UNUSABLE | NOT INSTALLED | DAEMON | ha_example.so | GPL |\n+----------+---------------+----------------+---------------+---------+\n\nThere is also a corresponding information_schema table, called ALL_PLUGINS,\nwhich contains more complete information.\n\nURL: https://mariadb.com/kb/en/show-plugins-soname/','','https://mariadb.com/kb/en/show-plugins-soname/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (354,26,'SET','Syntax\n------\n\nSET variable_assignment [, variable_assignment] ...\n\nvariable_assignment:\n user_var_name = expr\n | [GLOBAL | SESSION] system_var_name = expr\n | [@@global. | @@session. | @@]system_var_name = expr\n\nOne can also set a user variable in any expression with this syntax:\n\nuser_var_name:= expr\n\nDescription\n-----------\n\nThe SET statement assigns values to different types of variables that affect\nthe operation of the server or your client. Older versions of MySQL employed\nSET OPTION, but this syntax was deprecated in favor of SET without OPTION, and\nwas removed in MariaDB 10.0.\n\nChanging a system variable by using the SET statement does not make the change\npermanently. To do so, the change must be made in a configuration file.\n\nFor setting variables on a per-query basis, see SET STATEMENT.\n\nSee SHOW VARIABLES for documentation on viewing server system variables.\n\nSee Server System Variables for a list of all the system variables.\n\nGLOBAL / SESSION\n----------------\n\nWhen setting a system variable, the scope can be specified as either GLOBAL or\nSESSION.\n\nA global variable change affects all new sessions. It does not affect any\ncurrently open sessions, including the one that made the change.\n\nA session variable change affects the current session only.\n\nIf the variable has a session value, not specifying either GLOBAL or SESSION\nwill be the same as specifying SESSION. If the variable only has a global\nvalue, not specifying GLOBAL or SESSION will apply to the change to the global\nvalue.\n\nDEFAULT\n-------\n\nSetting a global variable to DEFAULT will restore it to the server default,\nand setting a session variable to DEFAULT will restore it to the current\nglobal value.\n\nExamples\n--------\n\n* innodb_sync_spin_loops is a global variable.\n* skip_parallel_replication is a session variable.\n* max_error_count is both global and session.\n\nSELECT VARIABLE_NAME, SESSION_VALUE, GLOBAL_VALUE FROM\n INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE \n VARIABLE_NAME IN (\'max_error_count\', \'skip_parallel_replication\',\n\'innodb_sync_spin_loops\');\n+---------------------------+---------------+--------------+\n| VARIABLE_NAME | SESSION_VALUE | GLOBAL_VALUE |\n+---------------------------+---------------+--------------+\n| MAX_ERROR_COUNT | 64 | 64 |\n| SKIP_PARALLEL_REPLICATION | OFF | NULL |\n| INNODB_SYNC_SPIN_LOOPS | NULL | 30 |\n+---------------------------+---------------+--------------+\n\nSetting the session values:\n\nSET max_error_count=128;Query OK, 0 rows affected (0.000 sec)\n\nSET skip_parallel_replication=ON;Query OK, 0 rows affected (0.000 sec)\n\nSET innodb_sync_spin_loops=60;\nERROR 1229 (HY000): Variable \'innodb_sync_spin_loops\' is a GLOBAL variable \n and should be set with SET GLOBAL\n\nSELECT VARIABLE_NAME, SESSION_VALUE, GLOBAL_VALUE FROM\n INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE \n VARIABLE_NAME IN (\'max_error_count\', \'skip_parallel_replication\',\n\'innodb_sync_spin_loops\');\n+---------------------------+---------------+--------------+\n| VARIABLE_NAME | SESSION_VALUE | GLOBAL_VALUE |\n+---------------------------+---------------+--------------+\n| MAX_ERROR_COUNT | 128 | 64 |\n| SKIP_PARALLEL_REPLICATION | ON | NULL |\n| INNODB_SYNC_SPIN_LOOPS | NULL | 30 |\n+---------------------------+---------------+--------------+\n\nSetting the global values:\n\nSET GLOBAL max_error_count=256;\n\nSET GLOBAL skip_parallel_replication=ON;\nERROR 1228 (HY000): Variable \'skip_parallel_replication\' is a SESSION variable \n and can\'t be used with SET GLOBAL\n\nSET GLOBAL innodb_sync_spin_loops=120;\n\nSELECT VARIABLE_NAME, SESSION_VALUE, GLOBAL_VALUE FROM\n INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE \n VARIABLE_NAME IN (\'max_error_count\', \'skip_parallel_replication\',\n\'innodb_sync_spin_loops\');\n+---------------------------+---------------+--------------+\n| VARIABLE_NAME | SESSION_VALUE | GLOBAL_VALUE |\n+---------------------------+---------------+--------------+\n| MAX_ERROR_COUNT | 128 | 256 |\n| SKIP_PARALLEL_REPLICATION | ON | NULL |\n| INNODB_SYNC_SPIN_LOOPS | NULL | 120 |\n+---------------------------+---------------+--------------+\n\nSHOW VARIABLES will by default return the session value unless the variable is\nglobal only.\n\nSHOW VARIABLES LIKE \'max_error_count\';\n+-----------------+-------+\n| Variable_name | Value |\n+-----------------+-------+\n| max_error_count | 128 |\n+-----------------+-------+\n\nSHOW VARIABLES LIKE \'skip_parallel_replication\';\n+---------------------------+-------+\n| Variable_name | Value |\n+---------------------------+-------+\n| skip_parallel_replication | ON |\n+---------------------------+-------+\n\nSHOW VARIABLES LIKE \'innodb_sync_spin_loops\';\n+------------------------+-------+\n| Variable_name | Value |\n+------------------------+-------+\n| innodb_sync_spin_loops | 120 |\n+------------------------+-------+\n\nUsing the inplace syntax:\n\nSELECT (@a:=1);\n+---------+\n| (@a:=1) |\n+---------+\n| 1 |\n+---------+\n\nSELECT @a;\n+------+\n| @a |\n+------+\n| 1 |\n+------+\n\nURL: https://mariadb.com/kb/en/set/','','https://mariadb.com/kb/en/set/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (355,26,'SET CHARACTER SET','Syntax\n------\n\nSET {CHARACTER SET | CHARSET}\n {charset_name | DEFAULT}\n\nDescription\n-----------\n\nSets the character_set_client and character_set_results session system\nvariables to the specified character set and collation_connection to the value\nof collation_database, which implicitly sets character_set_connection to the\nvalue of character_set_database.\n\nThis maps all strings sent between the current client and the server with the\ngiven mapping.\n\nExample\n-------\n\nSHOW VARIABLES LIKE \'character_set\\_%\';\n+--------------------------+--------+\n| Variable_name | Value |\n+--------------------------+--------+\n| character_set_client | utf8 |\n| character_set_connection | utf8 |\n| character_set_database | latin1 |\n| character_set_filesystem | binary |\n| character_set_results | utf8 |\n| character_set_server | latin1 |\n| character_set_system | utf8 |\n+--------------------------+--------+\n\nSHOW VARIABLES LIKE \'collation%\';\n+----------------------+-------------------+\n| Variable_name | Value |\n+----------------------+-------------------+\n| collation_connection | utf8_general_ci |\n| collation_database | latin1_swedish_ci |\n| collation_server | latin1_swedish_ci |\n+----------------------+-------------------+\n\nSET CHARACTER SET utf8mb4;\n\nSHOW VARIABLES LIKE \'character_set\\_%\';\n+--------------------------+---------+\n| Variable_name | Value |\n+--------------------------+---------+\n| character_set_client | utf8mb4 |\n| character_set_connection | latin1 |\n| character_set_database | latin1 |\n| character_set_filesystem | binary |\n| character_set_results | utf8mb4 |\n| character_set_server | latin1 |\n| character_set_system | utf8 |\n+--------------------------+---------+\n\nSHOW VARIABLES LIKE \'collation%\';\n+----------------------+-------------------+\n| Variable_name | Value |\n+----------------------+-------------------+\n| collation_connection | latin1_swedish_ci |\n| collation_database | latin1_swedish_ci |\n| collation_server | latin1_swedish_ci |\n+----------------------+-------------------+\n\nURL: https://mariadb.com/kb/en/set-character-set/','','https://mariadb.com/kb/en/set-character-set/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (356,26,'SET NAMES','Syntax\n------\n\nSET NAMES {\'charset_name\'\n [COLLATE \'collation_name\'] | DEFAULT}\n\nDescription\n-----------\n\nSets the character_set_client, character_set_connection, character_set_results\nand, implicitly, the collation_connection session system variables to the\nspecified character set and collation.\n\nThis determines which character set the client will use to send statements to\nthe server, and the server will use for sending results back to the client.\n\nucs2, utf16, utf16le and utf32 are not valid character sets for SET NAMES, as\nthey cannot be used as client character sets.\n\nThe collation clause is optional. If not defined (or if DEFAULT is specified),\nthe default collation for the character set will be used.\n\nQuotes are optional for the character set or collation clauses.\n\nExamples\n--------\n\nSELECT VARIABLE_NAME, SESSION_VALUE \n FROM INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE\n VARIABLE_NAME LIKE \'character_set_c%\' OR\n VARIABLE_NAME LIKE \'character_set_re%\' OR\n VARIABLE_NAME LIKE \'collation_c%\';\n+--------------------------+-----------------+\n| VARIABLE_NAME | SESSION_VALUE |\n+--------------------------+-----------------+\n| CHARACTER_SET_RESULTS | utf8 |\n| CHARACTER_SET_CONNECTION | utf8 |\n| CHARACTER_SET_CLIENT | utf8 |\n| COLLATION_CONNECTION | utf8_general_ci |\n+--------------------------+-----------------+\n\nSET NAMES big5;\n\nSELECT VARIABLE_NAME, SESSION_VALUE \n FROM INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE\n VARIABLE_NAME LIKE \'character_set_c%\' OR\n VARIABLE_NAME LIKE \'character_set_re%\' OR\n VARIABLE_NAME LIKE \'collation_c%\';\n+--------------------------+-----------------+\n| VARIABLE_NAME | SESSION_VALUE |\n+--------------------------+-----------------+\n| CHARACTER_SET_RESULTS | big5 |\n| CHARACTER_SET_CONNECTION | big5 |\n| CHARACTER_SET_CLIENT | big5 |\n| COLLATION_CONNECTION | big5_chinese_ci |\n+--------------------------+-----------------+\n\nSET NAMES \'latin1\' COLLATE \'latin1_bin\';\n\nSELECT VARIABLE_NAME, SESSION_VALUE \n FROM INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE\n VARIABLE_NAME LIKE \'character_set_c%\' OR\n VARIABLE_NAME LIKE \'character_set_re%\' OR\n VARIABLE_NAME LIKE \'collation_c%\';\n+--------------------------+---------------+\n| VARIABLE_NAME | SESSION_VALUE |\n+--------------------------+---------------+\n| CHARACTER_SET_RESULTS | latin1 |\n| CHARACTER_SET_CONNECTION | latin1 |\n| CHARACTER_SET_CLIENT | latin1 |\n| COLLATION_CONNECTION | latin1_bin |\n+--------------------------+---------------+\n\nSET NAMES DEFAULT;\n\nSELECT VARIABLE_NAME, SESSION_VALUE \n FROM INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE\n VARIABLE_NAME LIKE \'character_set_c%\' OR\n VARIABLE_NAME LIKE \'character_set_re%\' OR\n VARIABLE_NAME LIKE \'collation_c%\';\n+--------------------------+-------------------+\n| VARIABLE_NAME | SESSION_VALUE |\n+--------------------------+-------------------+\n| CHARACTER_SET_RESULTS | latin1 |\n| CHARACTER_SET_CONNECTION | latin1 |\n| CHARACTER_SET_CLIENT | latin1 |\n| COLLATION_CONNECTION | latin1_swedish_ci |\n+--------------------------+-------------------+\n\nURL: https://mariadb.com/kb/en/set-names/','','https://mariadb.com/kb/en/set-names/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (357,26,'SET SQL_LOG_BIN','Syntax\n------\n\nSET [SESSION] sql_log_bin = {0|1}\n\nDescription\n-----------\n\nSets the sql_log_bin system variable, which disables or enables binary logging\nfor the current connection, if the client has the SUPER privilege. The\nstatement is refused with an error if the client does not have that privilege.\n\nBefore MariaDB 5.5 and before MySQL 5.6 one could also set sql_log_bin as a\nglobal variable. This was disabled as this was too dangerous as it could\ndamage replication.\n\nURL: https://mariadb.com/kb/en/set-sql_log_bin/','','https://mariadb.com/kb/en/set-sql_log_bin/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (358,26,'SET STATEMENT','MariaDB starting with 10.1.2\n----------------------------\nPer-query variables were introduced in MariaDB 10.1.2\n\nSET STATEMENT can be used to set the value of a system variable for the\nduration of the statement. It is also possible to set multiple variables.\n\nSyntax\n------\n\nSET STATEMENT var1=value1 [, var2=value2, ...] \n FOR <statement>\n\nwhere varN is a system variable (list of allowed variables is provided below),\nand valueN is a constant literal.\n\nDescription\n-----------\n\nSET STATEMENT var1=value1 FOR stmt\n\nis roughly equivalent to\n\nSET @save_value=@@var1;\nSET SESSION var1=value1;\nstmt;\nSET SESSION var1=@save_value;\n\nThe server parses the whole statement before executing it, so any variables\nset in this fashion that affect the parser may not have the expected effect.\nExamples include the charset variables, sql_mode=ansi_quotes, etc.\n\nExamples\n--------\n\nOne can limit statement execution time max_statement_time:\n\nSET STATEMENT max_statement_time=1000 FOR SELECT ... ;\n\nOne can switch on/off individual optimizations:\n\nSET STATEMENT optimizer_switch=\'materialization=off\' FOR SELECT ....;\n\nIt is possible to enable MRR/BKA for a query:\n\nSET STATEMENT join_cache_level=6, optimizer_switch=\'mrr=on\' FOR SELECT ...\n\nNote that it makes no sense to try to set a session variable inside a SET\nSTATEMENT:\n\n#USELESS STATEMENT\nSET STATEMENT sort_buffer_size = 100000 for SET SESSION sort_buffer_size =\n200000;\n\nFor the above, after setting sort_buffer_size to 200000 it will be reset to\nits original state (the state before the SET STATEMENT started) after the\nstatement execution.\n\nLimitations\n-----------\n\nThere are a number of variables that cannot be set on per-query basis. These\ninclude:\n\n* autocommit\n* character_set_client\n* character_set_connection\n* character_set_filesystem\n* collation_connection\n* default_master_connection\n* debug_sync\n* interactive_timeout\n* gtid_domain_id\n* last_insert_id\n* log_slow_filter\n* log_slow_rate_limit\n* log_slow_verbosity\n* long_query_time\n* min_examined_row_limit\n* profiling\n* profiling_history_size\n* query_cache_type\n* rand_seed1\n* rand_seed2\n* skip_replication\n* slow_query_log\n* sql_log_off\n* tx_isolation\n* wait_timeout\n\nSource\n------\n\n* The feature was originally implemented as a Google Summer of Code 2009\nproject by Joseph Lukas. \n* Percona Server 5.6 included it as Per-query variable statement\n* MariaDB ported the patch and fixed many bugs. The task in MariaDB Jira is\nMDEV-5231.\n\nURL: https://mariadb.com/kb/en/set-statement/','','https://mariadb.com/kb/en/set-statement/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (359,26,'SET Variable','Syntax\n------\n\nSET var_name = expr [, var_name = expr] ...\n\nDescription\n-----------\n\nThe SET statement in stored programs is an extended version of the general SET\nstatement. Referenced variables may be ones declared inside a stored program,\nglobal system variables, or user-defined variables.\n\nThe SET statement in stored programs is implemented as part of the\npre-existing SET syntax. This allows an extended syntax of SET a=x, b=y, ...\nwhere different variable types (locally declared variables, global and session\nserver variables, user-defined variables) can be mixed. This also allows\ncombinations of local variables and some options that make sense only for\nsystem variables; in that case, the options are recognized but ignored.\n\nSET can be used with both local variables and user-defined variables.\n\nWhen setting several variables using the columns returned by a query, SELECT\nINTO should be preferred.\n\nTo set many variables to the same value, the LAST_VALUE( ) function can be\nused.\n\nBelow is an example of how a user-defined variable may be set:\n\nSET @x = 1;\n\nURL: https://mariadb.com/kb/en/set-variable/','','https://mariadb.com/kb/en/set-variable/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (360,26,'About SHOW','SHOW has many forms that provide information about databases, tables, columns,\nor status information about the server. These include:\n\n* SHOW AUTHORS\n* SHOW CHARACTER SET [like_or_where]\n* SHOW COLLATION [like_or_where]\n* SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [like_or_where]\n* SHOW CONTRIBUTORS\n* SHOW CREATE DATABASE db_name\n* SHOW CREATE EVENT event_name\n* SHOW CREATE PACKAGE package_name\n* SHOW CREATE PACKAGE BODY package_name\n* SHOW CREATE PROCEDURE proc_name\n* SHOW CREATE TABLE tbl_name\n* SHOW CREATE TRIGGER trigger_name\n* SHOW CREATE VIEW view_name\n* SHOW DATABASES [like_or_where]\n* SHOW ENGINE engine_name {STATUS | MUTEX}\n* SHOW [STORAGE] ENGINES\n* SHOW ERRORS [LIMIT [offset,] row_count]\n* SHOW [FULL] EVENTS\n* SHOW FUNCTION CODE func_name\n* SHOW FUNCTION STATUS [like_or_where]\n* SHOW GRANTS FOR user\n* SHOW INDEX FROM tbl_name [FROM db_name]\n* SHOW INNODB STATUS\n* SHOW OPEN TABLES [FROM db_name] [like_or_where]\n* SHOW PLUGINS\n* SHOW PROCEDURE CODE proc_name\n* SHOW PROCEDURE STATUS [like_or_where]\n* SHOW PRIVILEGES\n* SHOW [FULL] PROCESSLIST\n* SHOW PROFILE [types] [FOR QUERY n] [OFFSET n] [LIMIT n]\n* SHOW PROFILES\n* SHOW [GLOBAL | SESSION] STATUS [like_or_where]\n* SHOW TABLE STATUS [FROM db_name] [like_or_where]\n* SHOW TABLES [FROM db_name] [like_or_where]\n* SHOW TRIGGERS [FROM db_name] [like_or_where]\n* SHOW [GLOBAL | SESSION] VARIABLES [like_or_where]\n* SHOW WARNINGS [LIMIT [offset,] row_count]\n\nlike_or_where:\n LIKE \'pattern\'\n | WHERE expr\n\nIf the syntax for a given SHOW statement includes a LIKE \'pattern\' part,\n\'pattern\' is a string that can contain the SQL \"%\" and \"_\" wildcard\ncharacters. The pattern is useful for restricting statement output to matching\nvalues.\n\nSeveral SHOW statements also accept a WHERE clause that provides more\nflexibility in specifying which rows to display. See Extended Show.\n\nURL: https://mariadb.com/kb/en/about-show/','','https://mariadb.com/kb/en/about-show/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (361,26,'Extended Show','The following SHOW statements can be extended by using a WHERE clause and a\nLIKE clause to refine the results:\n\n* SHOW CHARACTER SET\n* SHOW COLLATION\n* SHOW COLUMNS\n* SHOW DATABASES\n* SHOW FUNCTION STATUS\n* SHOW INDEX\n* SHOW OPEN TABLES\n* SHOW PACKAGE STATUS\n* SHOW PACKAGE BODY STATUS\n* SHOW INDEX\n* SHOW PROCEDURE STATUS\n* SHOW STATUS\n* SHOW TABLE STATUS\n* SHOW TABLES\n* SHOW TRIGGERS\n* SHOW VARIABLES\n\nAs with a regular SELECT, the WHERE clause can be used for the specific\ncolumns returned, and the LIKE clause with the regular wildcards.\n\nExamples\n--------\n\nSHOW TABLES;\n+----------------------+\n| Tables_in_test |\n+----------------------+\n| animal_count |\n| animals |\n| are_the_mooses_loose |\n| aria_test2 |\n| t1 |\n| view1 |\n+----------------------+\n\nShowing the tables beginning with a only.\n\nSHOW TABLES WHERE Tables_in_test LIKE \'a%\';\n+----------------------+\n| Tables_in_test |\n+----------------------+\n| animal_count |\n| animals |\n| are_the_mooses_loose |\n| aria_test2 |\n+----------------------+\n\nVariables whose name starts with aria and with a valued of greater than 8192:\n\nSHOW VARIABLES WHERE Variable_name LIKE \'aria%\' AND Value >8192;\n+------------------------------+---------------------+\n| Variable_name | Value |\n+------------------------------+---------------------+\n| aria_checkpoint_log_activity | 1048576 |\n| aria_log_file_size | 1073741824 |\n| aria_max_sort_file_size | 9223372036853727232 |\n| aria_pagecache_buffer_size | 134217728 |\n| aria_sort_buffer_size | 134217728 |\n+------------------------------+---------------------+\n\nShortcut, just returning variables whose name begins with aria.\n\nSHOW VARIABLES LIKE \'aria%\';\n+------------------------------------------+---------------------+\n| Variable_name | Value |\n+------------------------------------------+---------------------+\n| aria_block_size | 8192 |\n| aria_checkpoint_interval | 30 |\n| aria_checkpoint_log_activity | 1048576 |\n| aria_force_start_after_recovery_failures | 0 |\n| aria_group_commit | none |\n| aria_group_commit_interval | 0 |\n| aria_log_file_size | 1073741824 |\n| aria_log_purge_type | immediate |\n| aria_max_sort_file_size | 9223372036853727232 |\n| aria_page_checksum | ON |\n| aria_pagecache_age_threshold | 300 |\n| aria_pagecache_buffer_size | 134217728 |\n| aria_pagecache_division_limit | 100 |\n| aria_recover | NORMAL |\n| aria_repair_threads | 1 |\n| aria_sort_buffer_size | 134217728 |\n| aria_stats_method | nulls_unequal |\n| aria_sync_log_dir | NEWFILE |\n| aria_used_for_temp_tables | ON |\n+------------------------------------------+---------------------+\n\nURL: https://mariadb.com/kb/en/extended-show/','','https://mariadb.com/kb/en/extended-show/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (362,26,'SHOW AUTHORS','Syntax\n------\n\nSHOW AUTHORS\n\nDescription\n-----------\n\nThe SHOW AUTHORS statement displays information about the people who work on\nMariaDB. For each author, it displays Name, Location, and Comment values. All\ncolumns are encoded as latin1.\n\nThese include:\n\n* First the active people in MariaDB are listed.\n* Then the active people in MySQL.\n* Last the people that have contributed to MariaDB/MySQL in the past.\n\nThe order is somewhat related to importance of the contribution given to the\nMariaDB project, but this is not 100% accurate. There is still room for\nimprovement and debate...\n\nExample\n-------\n\nSHOW AUTHORS\\G\n*************************** 1. row ***************************\n Name: Michael (Monty) Widenius\nLocation: Tusby, Finland\n Comment: Lead developer and main author\n*************************** 2. row ***************************\n Name: Sergei Golubchik\nLocation: Kerpen, Germany\n Comment: Architect, Full-text search, precision math, plugin framework,\nmerges etc\n*************************** 3. row ***************************\n Name: Igor Babaev\nLocation: Bellevue, USA\n Comment: Optimizer, keycache, core work\n*************************** 4. row ***************************\n Name: Sergey Petrunia\nLocation: St. Petersburg, Russia\n Comment: Optimizer\n*************************** 5. row ***************************\n Name: Oleksandr Byelkin\nLocation: Lugansk, Ukraine\n Comment: Query Cache (4.0), Subqueries (4.1), Views (5.0)\n*************************** 6. row ***************************\n Name: Timour Katchaounov\nLocation: Sofia , Bulgaria\n Comment: Optimizer\n*************************** 7. row ***************************\n Name: Kristian Nielsen\nLocation: Copenhagen, Denmark\n Comment: Replication, Async client prototocol, General buildbot stuff\n*************************** 8. row ***************************\n Name: Alexander (Bar) Barkov\nLocation: Izhevsk, Russia\n Comment: Unicode and character sets\n*************************** 9. row ***************************\n Name: Alexey Botchkov (Holyfoot)\nLocation: Izhevsk, Russia\n Comment: GIS extensions, embedded server, precision math\n*************************** 10. row ***************************\n Name: Daniel Bartholomew\nLocation: Raleigh, USA\n Comment: MariaDB documentation, Buildbot, releases\n*************************** 11. row ***************************\n Name: Colin Charles\nLocation: Selangor, Malesia\n Comment: MariaDB documentation, talks at a LOT of conferences\n*************************** 12. row ***************************\n Name: Sergey Vojtovich\nLocation: Izhevsk, Russia\n Comment: initial implementation of plugin architecture, maintained native\nstorage engines (MyISAM, MEMORY, ARCHIVE, etc), rewrite of table cache\n*************************** 13. row ***************************\n Name: Vladislav Vaintroub\nLocation: Mannheim, Germany\n Comment: MariaDB Java connector, new thread pool, Windows optimizations\n*************************** 14. row ***************************\n Name: Elena Stepanova\nLocation: Sankt Petersburg, Russia\n Comment: QA, test cases\n*************************** 15. row ***************************\n Name: Georg Richter\nLocation: Heidelberg, Germany\n Comment: New LGPL C connector, PHP connector\n*************************** 16. row ***************************\n Name: Jan Lindström\nLocation: Ylämylly, Finland\n Comment: Working on InnoDB\n*************************** 17. row ***************************\n Name: Lixun Peng\nLocation: Hangzhou, China\n Comment: Multi Source replication\n*************************** 18. row ***************************\n Name: Olivier Bertrand\nLocation: Paris, France\n Comment: CONNECT storage engine\n*************************** 19. row ***************************\n Name: Kentoku Shiba\nLocation: Tokyo, Japan\n Comment: Spider storage engine, metadata_lock_info Information schema\n*************************** 20. row ***************************\n Name: Percona\nLocation: CA, USA\n Comment: XtraDB, microslow patches, extensions to slow log\n*************************** 21. row ***************************\n Name: Vicentiu Ciorbaru\nLocation: Bucharest, Romania\n Comment: Roles\n*************************** 22. row ***************************\n Name: Sudheera Palihakkara\nLocation: \n Comment: PCRE Regular Expressions\n*************************** 23. row ***************************\n Name: Pavel Ivanov\nLocation: USA\n Comment: Some patches and bug fixes\n*************************** 24. row ***************************\n Name: Konstantin Osipov\nLocation: Moscow, Russia\n Comment: Prepared statements (4.1), Cursors (5.0), GET_LOCK (10.0)\n*************************** 25. row ***************************\n Name: Ian Gilfillan\nLocation: South Africa\n Comment: MariaDB documentation\n*************************** 26. row ***************************\n Name: Federico Razolli\nLocation: Italy\n Comment: MariaDB documentation Italian translation\n*************************** 27. row ***************************\n Name: Guilhem Bichot\nLocation: Bordeaux, France\n Comment: Replication (since 4.0)\n*************************** 28. row ***************************\n Name: Andrei Elkin\nLocation: Espoo, Finland\n Comment: Replication\n*************************** 29. row ***************************\n Name: Dmitri Lenev\nLocation: Moscow, Russia\n Comment: Time zones support (4.1), Triggers (5.0)\n*************************** 30. row ***************************\n Name: Marc Alff\nLocation: Denver, CO, USA\n Comment: Signal, Resignal, Performance schema\n*************************** 31. row ***************************\n Name: Mikael Ronström\nLocation: Stockholm, Sweden\n Comment: NDB Cluster, Partitioning, online alter table\n*************************** 32. row ***************************\n Name: Ingo Strüwing\nLocation: Berlin, Germany\n Comment: Bug fixing in MyISAM, Merge tables etc\n*************************** 33. row ***************************\n Name: Marko Mäkelä\nLocation: Helsinki, Finland\n Comment: InnoDB core developer\n...\n\nURL: https://mariadb.com/kb/en/show-authors/','','https://mariadb.com/kb/en/show-authors/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (363,26,'SHOW BINARY LOGS','Syntax\n------\n\nSHOW BINARY LOGS\nSHOW MASTER LOGS\n\nDescription\n-----------\n\nLists the binary log files on the server. This statement is used as part of\nthe procedure described in PURGE BINARY LOGS, that shows how to determine\nwhich logs can be purged.\n\nThis statement requires the SUPER privilege, the REPLICATION_CLIENT privilege,\nor, from MariaDB 10.5.2, the BINLOG MONITOR privilege.\n\nExamples\n--------\n\nSHOW BINARY LOGS;\n+--------------------+-----------+\n| Log_name | File_size |\n+--------------------+-----------+\n| mariadb-bin.000001 | 19039 |\n| mariadb-bin.000002 | 717389 |\n| mariadb-bin.000003 | 300 |\n| mariadb-bin.000004 | 333 |\n| mariadb-bin.000005 | 899 |\n| mariadb-bin.000006 | 125 |\n| mariadb-bin.000007 | 18907 |\n| mariadb-bin.000008 | 19530 |\n| mariadb-bin.000009 | 151 |\n| mariadb-bin.000010 | 151 |\n| mariadb-bin.000011 | 125 |\n| mariadb-bin.000012 | 151 |\n| mariadb-bin.000013 | 151 |\n| mariadb-bin.000014 | 125 |\n| mariadb-bin.000015 | 151 |\n| mariadb-bin.000016 | 314 |\n+--------------------+-----------+\n\nURL: https://mariadb.com/kb/en/show-binary-logs/','','https://mariadb.com/kb/en/show-binary-logs/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (364,26,'SHOW BINLOG EVENTS','Syntax\n------\n\nSHOW BINLOG EVENTS\n [IN \'log_name\'] [FROM pos] [LIMIT [offset,] row_count]\n\nDescription\n-----------\n\nShows the events in the binary log. If you do not specify \'log_name\', the\nfirst binary log is displayed.\n\nRequires the BINLOG MONITOR privilege (>= MariaDB 10.5.2) or the REPLICATION\nSLAVE privilege (<= MariaDB 10.5.1).\n\nExample\n-------\n\nSHOW BINLOG EVENTS IN \'mysql_sandbox10019-bin.000002\';\n+-------------------------------+-----+-------------------+-----------+--------\n----+------------------------------------------------+\n| Log_name | Pos | Event_type | Server_id |\nEnd_log_pos | Info |\n+-------------------------------+-----+-------------------+-----------+--------\n----+------------------------------------------------+\n| mysql_sandbox10019-bin.000002 | 4 | Format_desc | 1 | \n 248 | Server ver: 10.0.19-MariaDB-log, Binlog ver: 4 |\n| mysql_sandbox10019-bin.000002 | 248 | Gtid_list | 1 | \n 273 | [] |\n| mysql_sandbox10019-bin.000002 | 273 | Binlog_checkpoint | 1 | \n 325 | mysql_sandbox10019-bin.000002 |\n| mysql_sandbox10019-bin.000002 | 325 | Gtid | 1 | \n 363 | GTID 0-1-1 |\n| mysql_sandbox10019-bin.000002 | 363 | Query | 1 | \n 446 | CREATE DATABASE blog |\n| mysql_sandbox10019-bin.000002 | 446 | Gtid | 1 | \n 484 | GTID 0-1-2 |\n| mysql_sandbox10019-bin.000002 | 484 | Query | 1 | \n 571 | use `blog`; CREATE TABLE bb (id INT) |\n+-------------------------------+-----+-------------------+-----------+--------\n----+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/show-binlog-events/','','https://mariadb.com/kb/en/show-binlog-events/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (365,26,'SHOW CHARACTER SET','Syntax\n------\n\nSHOW CHARACTER SET\n [LIKE \'pattern\' | WHERE expr]\n\nDescription\n-----------\n\nThe SHOW CHARACTER SET statement shows all available character sets. The LIKE\nclause, if present on its own, indicates which character set names to match.\nThe WHERE and LIKE clauses can be given to select rows using more general\nconditions, as discussed in Extended SHOW.\n\nThe same information can be queried from the Information Schema CHARACTER_SETS\ntable.\n\nSee Setting Character Sets and Collations for details on specifying the\ncharacter set at the server, database, table and column levels.\n\nExamples\n--------\n\nSHOW CHARACTER SET LIKE \'latin%\';\n+---------+-----------------------------+-------------------+--------+\n| Charset | Description | Default collation | Maxlen |\n+---------+-----------------------------+-------------------+--------+\n| latin1 | cp1252 West European | latin1_swedish_ci | 1 |\n| latin2 | ISO 8859-2 Central European | latin2_general_ci | 1 |\n| latin5 | ISO 8859-9 Turkish | latin5_turkish_ci | 1 |\n| latin7 | ISO 8859-13 Baltic | latin7_general_ci | 1 |\n+---------+-----------------------------+-------------------+--------+\n\nSHOW CHARACTER SET WHERE Maxlen LIKE \'2\';\n+---------+---------------------------+-------------------+--------+\n| Charset | Description | Default collation | Maxlen |\n+---------+---------------------------+-------------------+--------+\n| big5 | Big5 Traditional Chinese | big5_chinese_ci | 2 |\n| sjis | Shift-JIS Japanese | sjis_japanese_ci | 2 |\n| euckr | EUC-KR Korean | euckr_korean_ci | 2 |\n| gb2312 | GB2312 Simplified Chinese | gb2312_chinese_ci | 2 |\n| gbk | GBK Simplified Chinese | gbk_chinese_ci | 2 |\n| ucs2 | UCS-2 Unicode | ucs2_general_ci | 2 |\n| cp932 | SJIS for Windows Japanese | cp932_japanese_ci | 2 |\n+---------+---------------------------+-------------------+--------+\n\nURL: https://mariadb.com/kb/en/show-character-set/','','https://mariadb.com/kb/en/show-character-set/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (366,26,'SHOW CLIENT_STATISTICS','Syntax\n------\n\nSHOW CLIENT_STATISTICS\n\nDescription\n-----------\n\nThe SHOW CLIENT_STATISTICS statement is part of the User Statistics feature.\nIt was removed as a separate statement in MariaDB 10.1.1, but effectively\nreplaced by the generic SHOW information_schema_table statement. The\ninformation_schema.CLIENT_STATISTICS table holds statistics about client\nconnections.\n\nThe userstat system variable must be set to 1 to activate this feature. See\nthe User Statistics and information_schema.CLIENT_STATISTICS articles for more\ninformation.\n\nExample\n-------\n\nSHOW CLIENT_STATISTICS\\G\n*************************** 1. row ***************************\n Client: localhost\n Total_connections: 35\nConcurrent_connections: 0\n Connected_time: 708\n Busy_time: 2.5557979999999985\n Cpu_time: 0.04123740000000002\n Bytes_received: 3883\n Bytes_sent: 21595\n Binlog_bytes_written: 0\n Rows_read: 18\n Rows_sent: 115\n Rows_deleted: 0\n Rows_inserted: 0\n Rows_updated: 0\n Select_commands: 70\n Update_commands: 0\n Other_commands: 0\n Commit_transactions: 1\n Rollback_transactions: 0\n Denied_connections: 0\n Lost_connections: 0\n Access_denied: 0\n Empty_queries: 35\n\nURL: https://mariadb.com/kb/en/show-client-statistics/','','https://mariadb.com/kb/en/show-client-statistics/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (367,26,'SHOW CONTRIBUTORS','Syntax\n------\n\nSHOW CONTRIBUTORS\n\nDescription\n-----------\n\nThe SHOW CONTRIBUTORS statement displays information about the companies and\npeople who financially contribute to MariaDB. For each contributor, it\ndisplays Name, Location, and Comment values. All columns are encoded as latin1.\n\nIt displays all members and sponsors of the MariaDB Foundation as well as\nother financial contributors.\n\nExample\n-------\n\nSHOW CONTRIBUTORS;\n+---------------------+-------------------------------+------------------------\n------------------------------------+\n| Name | Location | Comment \n |\n+---------------------+-------------------------------+------------------------\n------------------------------------+\n| Alibaba Cloud | https://www.alibabacloud.com/ | Platinum Sponsor of\nthe MariaDB Foundation |\n| Tencent Cloud | https://cloud.tencent.com | Platinum Sponsor of\nthe MariaDB Foundation |\n| Microsoft | https://microsoft.com/ | Platinum Sponsor of\nthe MariaDB Foundation |\n| MariaDB Corporation | https://mariadb.com | Founding member,\nPlatinum Sponsor of the MariaDB Foundation |\n| ServiceNow | https://servicenow.com | Platinum Sponsor of\nthe MariaDB Foundation |\n| Intel | https://www.intel.com | Platinum Sponsor of\nthe MariaDB Foundation |\n| SIT | https://sit.org | Platinum Sponsor of\nthe MariaDB Foundation |\n| Visma | https://visma.com | Gold Sponsor of the\nMariaDB Foundation |\n| DBS | https://dbs.com | Gold Sponsor of the\nMariaDB Foundation |\n| IBM | https://www.ibm.com | Gold Sponsor of the\nMariaDB Foundation |\n| Automattic | https://automattic.com | Silver Sponsor of the\nMariaDB Foundation |\n| Percona | https://www.percona.com/ | Sponsor of the MariaDB\nFoundation |\n| Galera Cluster | https://galeracluster.com | Sponsor of the MariaDB\nFoundation |\n| Google | USA | Sponsoring encryption,\nparallel replication and GTID |\n| Facebook | USA | Sponsoring\nnon-blocking API, LIMIT ROWS EXAMINED etc |\n| Ronald Bradford | Brisbane, Australia | EFF contribution for\nUC2006 Auction |\n| Sheeri Kritzer | Boston, Mass. USA | EFF contribution for\nUC2006 Auction |\n| Mark Shuttleworth | London, UK. | EFF contribution for\nUC2006 Auction |\n+---------------------+-------------------------------+------------------------\n------------------------------------+\n\nURL: https://mariadb.com/kb/en/show-contributors/','','https://mariadb.com/kb/en/show-contributors/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (368,26,'SHOW CREATE DATABASE','Syntax\n------\n\nSHOW CREATE {DATABASE | SCHEMA} db_name\n\nDescription\n-----------\n\nShows the CREATE DATABASE statement that creates the given database. SHOW\nCREATE SCHEMA is a synonym for SHOW CREATE DATABASE. SHOW CREATE DATABASE\nquotes database names according to the value of the sql_quote_show_create\nserver system variable.\n\nExamples\n--------\n\nSHOW CREATE DATABASE test;\n+----------+-----------------------------------------------------------------+\n| Database | Create Database |\n+----------+-----------------------------------------------------------------+\n| test | CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET latin1 */ |\n+----------+-----------------------------------------------------------------+\n\nSHOW CREATE SCHEMA test;\n+----------+-----------------------------------------------------------------+\n| Database | Create Database |\n+----------+-----------------------------------------------------------------+\n| test | CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET latin1 */ |\n+----------+-----------------------------------------------------------------+\n\nWith sql_quote_show_create off:\n\nSHOW CREATE DATABASE test;\n+----------+---------------------------------------------------------------+\n| Database | Create Database |\n+----------+---------------------------------------------------------------+\n| test | CREATE DATABASE test /*!40100 DEFAULT CHARACTER SET latin1 */ |\n+----------+---------------------------------------------------------------+\n\nWith a comment, from MariaDB 10.5:\n\nSHOW CREATE DATABASE p;\n+----------+-------------------------------------------------------------------\n------------------+\n| Database | Create Database \n |\n+----------+-------------------------------------------------------------------\n------------------+\n| p | CREATE DATABASE `p` /*!40100 DEFAULT CHARACTER SET latin1 */\nCOMMENT \'presentations\' |\n+----------+-------------------------------------------------------------------\n------------------+\n\nURL: https://mariadb.com/kb/en/show-create-database/','','https://mariadb.com/kb/en/show-create-database/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (369,26,'SHOW CREATE EVENT','Syntax\n------\n\nSHOW CREATE EVENT event_name\n\nDescription\n-----------\n\nThis statement displays the CREATE EVENT statement needed to re-create a given\nevent, as well as the SQL_MODE that was used when the trigger has been created\nand the character set used by the connection. To find out which events are\npresent, use SHOW EVENTS.\n\nThe output of this statement is unreliably affected by the\nsql_quote_show_create server system variable - see\nhttp://bugs.mysql.com/bug.php?id=12719\n\nThe information_schema.EVENTS table provides similar, but more complete,\ninformation.\n\nExamples\n--------\n\nSHOW CREATE EVENT test.e_daily\\G\n*************************** 1. row ***************************\n Event: e_daily\n sql_mode:\n time_zone: SYSTEM\n Create Event: CREATE EVENT `e_daily`\n ON SCHEDULE EVERY 1 DAY\n STARTS CURRENT_TIMESTAMP + INTERVAL 6 HOUR\n ON COMPLETION NOT PRESERVE\n ENABLE\n COMMENT \'Saves total number of sessions then\n clears the table each day\'\n DO BEGIN\n INSERT INTO site_activity.totals (time, total)\n SELECT CURRENT_TIMESTAMP, COUNT(*)\n FROM site_activity.sessions;\n DELETE FROM site_activity.sessions;\n END\ncharacter_set_client: latin1\ncollation_connection: latin1_swedish_ci\n Database Collation: latin1_swedish_ci\n\nURL: https://mariadb.com/kb/en/show-create-event/','','https://mariadb.com/kb/en/show-create-event/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (370,26,'SHOW CREATE FUNCTION','Syntax\n------\n\nSHOW CREATE FUNCTION func_name\n\nDescription\n-----------\n\nThis statement is similar to SHOW CREATE PROCEDURE but for stored functions.\n\nThe output of this statement is unreliably affected by the\nsql_quote_show_create server system variable - see\nhttp://bugs.mysql.com/bug.php?id=12719\n\nExample\n-------\n\nSHOW CREATE FUNCTION VatCents\\G\n*************************** 1. row ***************************\n Function: VatCents\n sql_mode:\n Create Function: CREATE DEFINER=`root`@`localhost` FUNCTION\n`VatCents`(price DECIMAL(10,2)) RETURNS int(11)\n DETERMINISTIC\nBEGIN\n DECLARE x INT;\n SET x = price * 114;\n RETURN x;\nEND\ncharacter_set_client: utf8\ncollation_connection: utf8_general_ci\n Database Collation: latin1_swedish_ci\n\nURL: https://mariadb.com/kb/en/show-create-function/','','https://mariadb.com/kb/en/show-create-function/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (371,26,'SHOW CREATE PACKAGE','MariaDB starting with 10.3.5\n----------------------------\nOracle-style packages were introduced in MariaDB 10.3.5.\n\nSyntax\n------\n\nSHOW CREATE PACKAGE [ db_name . ] package_name\n\nDescription\n-----------\n\nThe SHOW CREATE PACKAGE statement can be used when Oracle SQL_MODE is set.\n\nShows the CREATE statement that creates the given package specification.\n\nExamples\n--------\n\nSHOW CREATE PACKAGE employee_tools\\G\n*************************** 1. row ***************************\n Package: employee_tools\n sql_mode:\nPIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS\nNO_FIELD_OPTIONS,NO_AUTO_CREATE_USER\n Create Package: CREATE DEFINER=\"root\"@\"localhost\" PACKAGE\n\"employee_tools\" AS\n FUNCTION getSalary(eid INT) RETURN DECIMAL(10,2);\n PROCEDURE raiseSalary(eid INT, amount DECIMAL(10,2));\n PROCEDURE raiseSalaryStd(eid INT);\n PROCEDURE hire(ename TEXT, esalary DECIMAL(10,2));\nEND\ncharacter_set_client: utf8\ncollation_connection: utf8_general_ci\n Database Collation: latin1_swedish_ci\n\nURL: https://mariadb.com/kb/en/show-create-package/','','https://mariadb.com/kb/en/show-create-package/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (372,26,'SHOW CREATE PACKAGE BODY','MariaDB starting with 10.3.5\n----------------------------\nOracle-style packages were introduced in MariaDB 10.3.5.\n\nSyntax\n------\n\nSHOW CREATE PACKAGE BODY [ db_name . ] package_name\n\nDescription\n-----------\n\nThe SHOW CREATE PACKAGE BODY statement can be used when Oracle SQL_MODE is set.\n\nShows the CREATE statement that creates the given package body (i.e. the\nimplementation).\n\nExamples\n--------\n\nSHOW CREATE PACKAGE BODY employee_tools\\G\n*************************** 1. row ***************************\n Package body: employee_tools\n sql_mode:\nPIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS\nNO_FIELD_OPTIONS,NO_AUTO_CREATE_USER\n Create Package Body: CREATE DEFINER=\"root\"@\"localhost\" PACKAGE BODY\n\"employee_tools\" AS\n\nstdRaiseAmount DECIMAL(10,2):=500;\n\nPROCEDURE log (eid INT, ecmnt TEXT) AS\n BEGIN\n INSERT INTO employee_log (id, cmnt) VALUES (eid, ecmnt);\n END;\n\nPROCEDURE hire(ename TEXT, esalary DECIMAL(10,2)) AS\n eid INT;\n BEGIN\n INSERT INTO employee (name, salary) VALUES (ename, esalary);\n eid:= last_insert_id();\n log(eid, \'hire \' || ename);\n END;\n\nFUNCTION getSalary(eid INT) RETURN DECIMAL(10,2) AS\n nSalary DECIMAL(10,2);\n BEGIN\n SELECT salary INTO nSalary FROM employee WHERE id=eid;\n log(eid, \'getSalary id=\' || eid || \' salary=\' || nSalary);\n RETURN nSalary;\n END;\n\nPROCEDURE raiseSalary(eid INT, amount DECIMAL(10,2)) AS\n BEGIN\n UPDATE employee SET salary=salary+amount WHERE id=eid;\n log(eid, \'raiseSalary id=\' || eid || \' amount=\' || amount);\n END;\n\nPROCEDURE raiseSalaryStd(eid INT) AS\n BEGIN\n raiseSalary(eid, stdRaiseAmount);\n log(eid, \'raiseSalaryStd id=\' || eid);\n END;\n\nBEGIN \n log(0, \'Session \' || connection_id() || \' \' || current_user || \' started\');\nEND\ncharacter_set_client: utf8\ncollation_connection: utf8_general_ci\n Database Collation: latin1_swedish_ci\n\nURL: https://mariadb.com/kb/en/show-create-package-body/','','https://mariadb.com/kb/en/show-create-package-body/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (373,26,'SHOW CREATE PROCEDURE','Syntax\n------\n\nSHOW CREATE PROCEDURE proc_name\n\nDescription\n-----------\n\nThis statement is a MariaDB extension. It returns the exact string that can be\nused to re-create the named stored procedure, as well as the SQL_MODE that was\nused when the trigger has been created and the character set used by the\nconnection.. A similar statement, SHOW CREATE FUNCTION, displays information\nabout stored functions.\n\nBoth statements require that you are the owner of the routine or have the\nSELECT privilege on the mysql.proc table. When neither is true, the statements\ndisplay NULL for the Create Procedure or Create Function field.\n\nWarning Users with SELECT privileges on mysql.proc or USAGE privileges on *.*\ncan view the text of routines, even when they do not have privileges for the\nfunction or procedure itself.\n\nThe output of these statements is unreliably affected by the\nsql_quote_show_create server system variable - see\nhttp://bugs.mysql.com/bug.php?id=12719\n\nExamples\n--------\n\nHere\'s a comparison of the SHOW CREATE PROCEDURE and SHOW CREATE FUNCTION\nstatements.\n\nSHOW CREATE PROCEDURE test.simpleproc\\G\n*************************** 1. row ***************************\n Procedure: simpleproc\n sql_mode:\n Create Procedure: CREATE PROCEDURE `simpleproc`(OUT param1 INT)\n BEGIN\n SELECT COUNT(*) INTO param1 FROM t;\n END\ncharacter_set_client: latin1\ncollation_connection: latin1_swedish_ci\n Database Collation: latin1_swedish_ci\n\nSHOW CREATE FUNCTION test.hello\\G\n*************************** 1. row ***************************\n Function: hello\n sql_mode:\n Create Function: CREATE FUNCTION `hello`(s CHAR(20))\n RETURNS CHAR(50)\n RETURN CONCAT(\'Hello, \',s,\'!\')\ncharacter_set_client: latin1\ncollation_connection: latin1_swedish_ci\n Database Collation: latin1_swedish_ci\n\nWhen the user issuing the statement does not have privileges on the routine,\nattempting to CALL the procedure raises Error 1370.\n\nCALL test.prc1();\nError 1370 (42000): execute command denieed to user \'test_user\'@\'localhost\'\nfor routine \'test\'.\'prc1\'\n\nIf the user neither has privilege to the routine nor the SELECT privilege on\nmysql.proc table, it raises Error 1305, informing them that the procedure does\nnot exist.\n\nSHOW CREATE TABLES test.prc1\\G\nError 1305 (42000): PROCEDURE prc1 does not exist\n\nURL: https://mariadb.com/kb/en/show-create-procedure/','','https://mariadb.com/kb/en/show-create-procedure/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (374,26,'SHOW CREATE SEQUENCE','Syntax\n------\n\nSHOW CREATE SEQUENCE sequence_name;\n\nDescription\n-----------\n\nShows the CREATE SEQUENCE statement that created the given sequence. The\nstatement requires the SELECT privilege for the table.\n\nExample\n-------\n\nCREATE SEQUENCE s1 START WITH 50;\nSHOW CREATE SEQUENCE s1\\G;\n*************************** 1. row ***************************\n Table: s1\nCreate Table: CREATE SEQUENCE `s1` start with 50 minvalue 1 maxvalue\n9223372036854775806 \n increment by 1 cache 1000 nocycle ENGINE=InnoDB\n\nNotes\n-----\n\nIf you want to see the underlying table structure used for the SEQUENCE you\ncan use SHOW CREATE TABLE on the SEQUENCE. You can also use SELECT to read the\ncurrent recorded state of the SEQUENCE:\n\nSHOW CREATE TABLE s1\\G\n*************************** 1. row ***************************\n Table: s1\nCreate Table: CREATE TABLE `s1` (\n `next_not_cached_value` bigint(21) NOT NULL,\n `minimum_value` bigint(21) NOT NULL,\n `maximum_value` bigint(21) NOT NULL,\n `start_value` bigint(21) NOT NULL COMMENT \'start value when sequences is\ncreated \n or value if RESTART is used\',\n `increment` bigint(21) NOT NULL COMMENT \'increment value\',\n `cache_size` bigint(21) unsigned NOT NULL,\n `cycle_option` tinyint(1) unsigned NOT NULL COMMENT \'0 if no cycles are\nallowed, \n 1 if the sequence should begin a new cycle when maximum_value is passed\',\n `cycle_count` bigint(21) NOT NULL COMMENT \'How many cycles have been done\'\n) ENGINE=InnoDB SEQUENCE=1\n\nSELECT * FROM s1\\G\n*************************** 1. row ***************************\nnext_not_cached_value: 50\n minimum_value: 1\n maximum_value: 9223372036854775806\n start_value: 50\n increment: 1\n cache_size: 1000\n cycle_option: 0\n cycle_count: 0\n\nURL: https://mariadb.com/kb/en/show-create-sequence/','','https://mariadb.com/kb/en/show-create-sequence/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (375,26,'SHOW CREATE TRIGGER','Syntax\n------\n\nSHOW CREATE TRIGGER trigger_name\n\nDescription\n-----------\n\nThis statement shows a CREATE TRIGGER statement that creates the given\ntrigger, as well as the SQL_MODE that was used when the trigger has been\ncreated and the character set used by the connection.\n\nThe TRIGGER privilege is required on the table the trigger is defined for to\nexecute this statement.\n\nThe output of this statement is unreliably affected by the\nsql_quote_show_create server system variable - see\nhttp://bugs.mysql.com/bug.php?id=12719\n\nExamples\n--------\n\nSHOW CREATE TRIGGER example\\G\n*************************** 1. row ***************************\n Trigger: example\n sql_mode:\nONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,STRICT_ALL_TABLES\n,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO\n\nENGINE_SUBSTITUTION\nSQL Original Statement: CREATE DEFINER=`root`@`localhost` TRIGGER example\nBEFORE\n INSERT ON t FOR EACH ROW\nBEGIN\n SET NEW.c = NEW.c * 2;\nEND\n character_set_client: cp850\n collation_connection: cp850_general_ci\n Database Collation: utf8_general_ci\n Created: 2016-09-29 13:53:34.35\n\nMariaDB starting with 10.2.3\n----------------------------\nThe Created column was added in MySQL 5.7 and MariaDB 10.2.3 as part of\nintroducing multiple trigger events per action.\n\nURL: https://mariadb.com/kb/en/show-create-trigger/','','https://mariadb.com/kb/en/show-create-trigger/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (376,26,'SHOW CREATE VIEW','Syntax\n------\n\nSHOW CREATE VIEW view_name\n\nDescription\n-----------\n\nThis statement shows a CREATE VIEW statement that creates the given view, as\nwell as the character set used by the connection when the view was created.\nThis statement also works with views.\n\nSHOW CREATE VIEW quotes table, column and stored function names according to\nthe value of the sql_quote_show_create server system variable.\n\nExamples\n--------\n\nSHOW CREATE VIEW example\\G\n*************************** 1. row ***************************\n View: example\n Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL\nSECURITY DEFINER VIEW `example` AS (select `t`.`id` AS `id`,`t`.`s` AS `s` from\n`t`)\ncharacter_set_client: cp850\ncollation_connection: cp850_general_ci\n\nWith sql_quote_show_create off:\n\nSHOW CREATE VIEW example\\G\n*************************** 1. row ***************************\n View: example\n Create View: CREATE ALGORITHM=UNDEFINED DEFINER=root@localhost SQL\nSECU\nRITY DEFINER VIEW example AS (select t.id AS id,t.s AS s from t)\ncharacter_set_client: cp850\ncollation_connection: cp850_general_ci\n\nGrants\n------\n\nTo be able to see a view, you need to have the SHOW VIEW and the SELECT\nprivilege on the view:\n\nGRANT SHOW VIEW,SELECT ON test_database.test_view TO \'test\'@\'localhost\';\n\nURL: https://mariadb.com/kb/en/show-create-view/','','https://mariadb.com/kb/en/show-create-view/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (377,26,'SHOW DATABASES','Syntax\n------\n\nSHOW {DATABASES | SCHEMAS}\n [LIKE \'pattern\' | WHERE expr]\n\nDescription\n-----------\n\nSHOW DATABASES lists the databases on the MariaDB server host. SHOW SCHEMAS is\na synonym for SHOW DATABASES. The LIKE clause, if present on its own,\nindicates which database names to match. The WHERE and LIKE clauses can be\ngiven to select rows using more general conditions, as discussed in Extended\nSHOW.\n\nYou see only those databases for which you have some kind of privilege, unless\nyou have the global SHOW DATABASES privilege. You can also get this list using\nthe mariadb-show command.\n\nIf the server was started with the --skip-show-database option, you cannot use\nthis statement at all unless you have the SHOW DATABASES privilege.\n\nThe list of results returned by SHOW DATABASES is based on directories in the\ndata directory, which is how MariaDB implements databases. It\'s possible that\noutput includes directories that do not correspond to actual databases.\n\nThe Information Schema SCHEMATA table also contains database information.\n\nExamples\n--------\n\nSHOW DATABASES;\n+--------------------+\n| Database |\n+--------------------+\n| information_schema |\n| mysql |\n| performance_schema |\n| test |\n+--------------------+\n\nSHOW DATABASES LIKE \'m%\';\n+---------------+\n| Database (m%) |\n+---------------+\n| mysql |\n+---------------+\n\nURL: https://mariadb.com/kb/en/show-databases/','','https://mariadb.com/kb/en/show-databases/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (378,26,'SHOW ENGINE','Syntax\n------\n\nSHOW ENGINE engine_name {STATUS | MUTEX}\n\nDescription\n-----------\n\nSHOW ENGINE displays operational information about a storage engine. The\nfollowing statements currently are supported:\n\nSHOW ENGINE INNODB STATUS\nSHOW ENGINE INNODB MUTEX\nSHOW ENGINE PERFORMANCE_SCHEMA STATUS\nSHOW ENGINE ROCKSDB STATUS\n\nIf the Sphinx Storage Engine is installed, the following is also supported:\n\nSHOW ENGINE SPHINX STATUS\n\nSee SHOW ENGINE SPHINX STATUS.\n\nOlder (and now removed) synonyms were SHOW INNODB STATUS for SHOW ENGINE\nINNODB STATUS and SHOW MUTEX STATUS for SHOW ENGINE INNODB MUTEX.\n\nSHOW ENGINE INNODB STATUS\n-------------------------\n\nSHOW ENGINE INNODB STATUS displays extensive information from the standard\nInnoDB Monitor about the state of the InnoDB storage engine. See SHOW ENGINE\nINNODB STATUS for more.\n\nSHOW ENGINE INNODB MUTEX\n------------------------\n\nSHOW ENGINE INNODB MUTEX displays InnoDB mutex statistics.\n\nThe statement displays the following output fields:\n\n* Type: Always InnoDB.\n* Name: The source file where the mutex is implemented, and the line number\n in the file where the mutex is created. The line number is dependent on the\nMariaDB version.\n* Status: This field displays the following values if UNIV_DEBUG was defined\nat compilation time (for example, in include/univ.h in the InnoDB part of the\nsource tree). Only the os_waits value is displayed if UNIV_DEBUG was not\ndefined. Without UNIV_DEBUG, the information on which the output is based is\ninsufficient to distinguish regular mutexes and mutexes that protect\n rw-locks (which allow multiple readers or a single writer). Consequently, the\n output may appear to contain multiple rows for the same mutex.\ncount indicates how many times the mutex was requested.\nspin_waits indicates how many times the spinlock had to run.\nspin_rounds indicates the number of spinlock rounds. (spin_rounds divided by\n spin_waits provides the average round count.)\nos_waits indicates the number of operating system waits. This occurs when\n the spinlock did not work (the mutex was not locked during the spinlock and\n it was necessary to yield to the operating system and wait).\nos_yields indicates the number of times a the thread trying to lock a mutex\n gave up its timeslice and yielded to the operating system (on the\n presumption that allowing other threads to run will free the mutex so that\n it can be locked).\nos_wait_times indicates the amount of time (in ms) spent in operating system\n waits, if the timed_mutexes system variable is 1 (ON). If timed_mutexes is 0\n (OFF), timing is disabled, so os_wait_times is 0. timed_mutexes is off by\n default.\n\nInformation from this statement can be used to diagnose system problems. For\nexample, large values of spin_waits and spin_rounds may indicate scalability\nproblems.\n\nThe information_schema.INNODB_MUTEXES table provides similar information.\n\nSHOW ENGINE PERFORMANCE_SCHEMA STATUS\n-------------------------------------\n\nThis statement shows how much memory is used for performance_schema tables and\ninternal buffers.\n\nThe output contains the following fields:\n\n* Type: Always performance_schema.\n* Name: The name of a table, the name of an internal buffer, or the\nperformance_schema word, followed by a dot and an attribute. Internal buffers\nnames are enclosed by parenthesis. performance_schema means that the attribute\nrefers to the whole database (it is a total). \n* Status: The value for the attribute.\n\nThe following attributes are shown, in this order, for all tables:\n\n* row_size: The memory used for an individual record. This value will never\nchange.\n* row_count: The number of rows in the table or buffer. For some tables, this\nvalue depends on a server system variable.\n* memory: For tables and performance_schema, this is the result of row_size *\nrow_count.\n\nFor internal buffers, the attributes are:\n\n* count\n* size\n\nSHOW ENGINE ROCKSDB STATUS\n--------------------------\n\nSee also MyRocks Performance Troubleshooting\n\nURL: https://mariadb.com/kb/en/show-engine/','','https://mariadb.com/kb/en/show-engine/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (379,26,'SHOW ENGINE INNODB STATUS','SHOW ENGINE INNODB STATUS is a specific form of the SHOW ENGINE statement that\ndisplays the InnoDB Monitor output, which is extensive InnoDB information\nwhich can be useful in diagnosing problems.\n\nThe following sections are displayed\n\n* Status: Shows the timestamp, monitor name and the number of seconds, or the\nelapsed time between the current time and the time the InnoDB Monitor output\nwas last displayed. The per-second averages are based upon this time.\n* BACKGROUND THREAD: srv_master_thread lines show work performed by the main\nbackground thread.\n* SEMAPHORES: Threads waiting for a semaphore and stats on how the number of\ntimes threads have needed a spin or a wait on a mutex or rw-lock semaphore. If\nthis number of threads is large, there may be I/O or contention issues.\nReducing the size of the innodb_thread_concurrency system variable may help if\ncontention is related to thread scheduling. Spin rounds per wait shows the\nnumber of spinlock rounds per OS wait for a mutex. \n* LATEST FOREIGN KEY ERROR: Only shown if there has been a foreign key\nconstraint error, it displays the failed statement and information about the\nconstraint and the related tables.\n* LATEST DETECTED DEADLOCK: Only shown if there has been a deadlock, it\ndisplays the transactions involved in the deadlock and the statements being\nexecuted, held and required locked and the transaction rolled back to.\n* TRANSACTIONS: The output of this section can help identify lock contention,\nas well as reasons for the deadlocks.\n* FILE I/O: InnoDB thread information as well as pending I/O operations and\nI/O performance statistics.\n* INSERT BUFFER AND ADAPTIVE HASH INDEX: InnoDB insert buffer (old name for\nthe change buffer) and adaptive hash index status information, including the\nnumber of each type of operation performed, and adaptive hash index\nperformance.\n* LOG: InnoDB log information, including current log sequence number, how far\nthe log has been flushed to disk, the position at which InnoDB last took a\ncheckpoint, pending writes and write performance statistics.\n* BUFFER POOL AND MEMORY: Information on buffer pool pages read and written,\nwhich allows you to see the number of data file I/O operations performed by\nyour queries. See InnoDB Buffer Pool for more. Similar information is also\navailable from the INFORMATION_SCHEMA.INNODB_BUFFER_POOL_STATS table.\n* ROW OPERATIONS:Information about the main thread, including the number and\nperformance rate for each type of row operation.\n\nIf the innodb_status_output_locks system variable is set to 1, extended lock\ninformation will be displayed.\n\nExample output:\n\n=====================================\n2019-09-06 12:44:13 0x7f93cc236700 INNODB MONITOR OUTPUT\n=====================================\nPer second averages calculated from the last 4 seconds\n-----------------\nBACKGROUND THREAD\n-----------------\nsrv_master_thread loops: 2 srv_active, 0 srv_shutdown, 83698 srv_idle\nsrv_master_thread log flush and writes: 83682\n----------\nSEMAPHORES\n----------\nOS WAIT ARRAY INFO: reservation count 15\nOS WAIT ARRAY INFO: signal count 8\nRW-shared spins 0, rounds 20, OS waits 7\nRW-excl spins 0, rounds 0, OS waits 0\nRW-sx spins 0, rounds 0, OS waits 0\nSpin rounds per wait: 20.00 RW-shared, 0.00 RW-excl, 0.00 RW-sx\n------------\nTRANSACTIONS\n------------\nTrx id counter 236\nPurge done for trx\'s n:o < 236 undo n:o < 0 state: running\nHistory list length 22\nLIST OF TRANSACTIONS FOR EACH SESSION:\n---TRANSACTION 421747401994584, not started\n0 lock struct(s), heap size 1136, 0 row lock(s)\n---TRANSACTION 421747401990328, not started\n0 lock struct(s), heap size 1136, 0 row lock(s)\n--------\nFILE I/O\n--------\nI/O thread 0 state: waiting for completed aio requests (insert buffer thread)\nI/O thread 1 state: waiting for completed aio requests (log thread)\nI/O thread 2 state: waiting for completed aio requests (read thread)\nI/O thread 3 state: waiting for completed aio requests (read thread)\nI/O thread 4 state: waiting for completed aio requests (read thread)\nI/O thread 5 state: waiting for completed aio requests (read thread)\nI/O thread 6 state: waiting for completed aio requests (write thread)\nI/O thread 7 state: waiting for completed aio requests (write thread)\nI/O thread 8 state: waiting for completed aio requests (write thread)\nI/O thread 9 state: waiting for completed aio requests (write thread)\nPending normal aio reads: [0, 0, 0, 0] , aio writes: [0, 0, 0, 0] ,\n ibuf aio reads:, log i/o\'s:, sync i/o\'s:\nPending flushes (fsync) log: 0; buffer pool: 0\n286 OS file reads, 171 OS file writes, 22 OS fsyncs\n0.00 reads/s, 0 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s\n-------------------------------------\nINSERT BUFFER AND ADAPTIVE HASH INDEX\n-------------------------------------\nIbuf: size 1, free list len 0, seg size 2, 0 merges\nmerged operations:\n insert 0, delete mark 0, delete 0\ndiscarded operations:\n insert 0, delete mark 0, delete 0\nHash table size 34679, node heap has 0 buffer(s)\nHash table size 34679, node heap has 0 buffer(s)\nHash table size 34679, node heap has 0 buffer(s)\nHash table size 34679, node heap has 0 buffer(s)\nHash table size 34679, node heap has 0 buffer(s)\nHash table size 34679, node heap has 0 buffer(s)\nHash table size 34679, node heap has 0 buffer(s)\nHash table size 34679, node heap has 0 buffer(s)\n0.00 hash searches/s, 0.00 non-hash searches/s\n---\nLOG\n---\nLog sequence number 445926\nLog flushed up to 445926\nPages flushed up to 445926\nLast checkpoint at 445917\n0 pending log flushes, 0 pending chkp writes\n18 log i/o\'s done, 0.00 log i/o\'s/second\n----------------------\nBUFFER POOL AND MEMORY\n----------------------\nTotal large memory allocated 167772160\nDictionary memory allocated 50768\nBuffer pool size 8012\nFree buffers 7611\nDatabase pages 401\nOld database pages 0\nModified db pages 0\nPercent of dirty pages(LRU & free pages): 0.000\nMax dirty pages percent: 75.000\nPending reads 0\nPending writes: LRU 0, flush list 0, single page 0\nPages made young 0, not young 0\n0.00 youngs/s, 0.00 non-youngs/s\nPages read 264, created 137, written 156\n0.00 reads/s, 0.00 creates/s, 0.00 writes/s\nNo buffer pool page gets since the last printout\nPages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead\n0.00/s\nLRU len: 401, unzip_LRU len: 0\nI/O sum[0]:cur[0], unzip sum[0]:cur[0]\n--------------\nROW OPERATIONS\n--------------\n0 queries inside InnoDB, 0 queries in queue\n0 read views open inside InnoDB\nProcess ID=4267, Main thread ID=140272021272320, state: sleeping\nNumber of rows inserted 1, updated 0, deleted 0, read 1\n0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s\nNumber of system rows inserted 0, updated 0, deleted 0, read 0\n0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s\n----------------------------\nEND OF INNODB MONITOR OUTPUT\n============================\n\nURL: https://mariadb.com/kb/en/show-engine-innodb-status/','','https://mariadb.com/kb/en/show-engine-innodb-status/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (380,26,'SHOW ENGINES','Syntax\n------\n\nSHOW [STORAGE] ENGINES\n\nDescription\n-----------\n\nSHOW ENGINES displays status information about the server\'s storage engines.\nThis is particularly useful for checking whether a storage engine is\nsupported, or to see what the default engine is. SHOW TABLE TYPES is a\ndeprecated synonym.\n\nThe information_schema.ENGINES table provides the same information.\n\nSince storage engines are plugins, different information about them is also\nshown in the information_schema.PLUGINS table and by the SHOW PLUGINS\nstatement.\n\nNote that both MySQL\'s InnoDB and Percona\'s XtraDB replacement are labeled as\nInnoDB. However, if XtraDB is in use, it will be specified in the COMMENT\nfield. See XtraDB and InnoDB. The same applies to FederatedX.\n\nThe output consists of the following columns:\n\n* Engine indicates the engine\'s name.\n* Support indicates whether the engine is installed, and whether it is the\ndefault engine for the current session.\n* Comment is a brief description.\n* Transactions, XA and Savepoints indicate whether transactions, XA\ntransactions and transaction savepoints are supported by the engine.\n\nExamples\n--------\n\nSHOW ENGINES\\G\n*************************** 1. row ***************************\n Engine: InnoDB\n Support: DEFAULT\n Comment: Supports transactions, row-level locking, and foreign keys\nTransactions: YES\n XA: YES\n Savepoints: YES\n*************************** 2. row ***************************\n Engine: CSV\n Support: YES\n Comment: CSV storage engine\nTransactions: NO\n XA: NO\n Savepoints: NO\n*************************** 3. row ***************************\n Engine: MyISAM\n Support: YES\n Comment: MyISAM storage engine\nTransactions: NO\n XA: NO\n Savepoints: NO\n*************************** 4. row ***************************\n Engine: BLACKHOLE\n Support: YES\n Comment: /dev/null storage engine (anything you write to it disappears)\nTransactions: NO\n XA: NO\n Savepoints: NO\n*************************** 5. row ***************************\n Engine: FEDERATED\n Support: YES\n Comment: FederatedX pluggable storage engine\nTransactions: YES\n XA: NO\n Savepoints: YES\n*************************** 6. row ***************************\n Engine: MRG_MyISAM\n Support: YES\n Comment: Collection of identical MyISAM tables\nTransactions: NO\n XA: NO\n Savepoints: NO\n*************************** 7. row ***************************\n Engine: ARCHIVE\n Support: YES\n Comment: Archive storage engine\nTransactions: NO\n XA: NO\n Savepoints: NO\n*************************** 8. row ***************************\n Engine: MEMORY\n Support: YES\n Comment: Hash based, stored in memory, useful for temporary tables\nTransactions: NO\n XA: NO\n Savepoints: NO\n*************************** 9. row ***************************\n Engine: PERFORMANCE_SCHEMA\n Support: YES\n Comment: Performance Schema\nTransactions: NO\n XA: NO\n Savepoints: NO\n*************************** 10. row ***************************\n Engine: Aria\n Support: YES\n Comment: Crash-safe tables with MyISAM heritage\nTransactions: NO\n XA: NO\n Savepoints: NO\n10 rows in set (0.00 sec)\n\nURL: https://mariadb.com/kb/en/show-engines/','','https://mariadb.com/kb/en/show-engines/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (381,26,'SHOW ERRORS','Syntax\n------\n\nSHOW ERRORS [LIMIT [offset,] row_count]\nSHOW ERRORS [LIMIT row_count OFFSET offset]\nSHOW COUNT(*) ERRORS\n\nDescription\n-----------\n\nThis statement is similar to SHOW WARNINGS, except that instead of displaying\nerrors, warnings, and notes, it displays only errors.\n\nThe LIMIT clause has the same syntax as for the SELECT statement.\n\nThe SHOW COUNT(*) ERRORS statement displays the number of errors. You can also\nretrieve this number from the error_count variable.\n\nSHOW COUNT(*) ERRORS;\nSELECT @@error_count;\n\nThe value of error_count might be greater than the number of messages\ndisplayed by SHOW WARNINGS if the max_error_count system variable is set so\nlow that not all messages are stored.\n\nFor a list of MariaDB error codes, see MariaDB Error Codes.\n\nExamples\n--------\n\nSELECT f();\nERROR 1305 (42000): FUNCTION f does not exist\n\nSHOW COUNT(*) ERRORS;\n+-----------------------+\n| @@session.error_count |\n+-----------------------+\n| 1 |\n+-----------------------+\n\nSHOW ERRORS;\n+-------+------+---------------------------+\n| Level | Code | Message |\n+-------+------+---------------------------+\n| Error | 1305 | FUNCTION f does not exist |\n+-------+------+---------------------------+\n\nURL: https://mariadb.com/kb/en/show-errors/','','https://mariadb.com/kb/en/show-errors/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (382,26,'SHOW EVENTS','Syntax\n------\n\nSHOW EVENTS [{FROM | IN} schema_name]\n [LIKE \'pattern\' | WHERE expr]\n\nDescription\n-----------\n\nShows information about Event Manager events (created with CREATE EVENT).\nRequires the EVENT privilege. Without any arguments, SHOW EVENTS lists all of\nthe events in the current schema:\n\nSELECT CURRENT_USER(), SCHEMA();\n+----------------+----------+\n| CURRENT_USER() | SCHEMA() |\n+----------------+----------+\n| jon@ghidora | myschema |\n+----------------+----------+\n\nSHOW EVENTS\\G\n*************************** 1. row ***************************\n Db: myschema\n Name: e_daily\n Definer: jon@ghidora\n Time zone: SYSTEM\n Type: RECURRING\n Execute at: NULL\n Interval value: 10\n Interval field: SECOND\n Starts: 2006-02-09 10:41:23\n Ends: NULL\n Status: ENABLED\n Originator: 0\ncharacter_set_client: latin1\ncollation_connection: latin1_swedish_ci\n Database Collation: latin1_swedish_ci\n\nTo see the event action, use SHOW CREATE EVENT instead, or look at the\ninformation_schema.EVENTS table.\n\nTo see events for a specific schema, use the FROM clause. For example, to see\nevents for the test schema, use the following statement:\n\nSHOW EVENTS FROM test;\n\nThe LIKE clause, if present, indicates which event names to match. The WHERE\nclause can be given to select rows using more general conditions, as discussed\nin Extended Show.\n\nURL: https://mariadb.com/kb/en/show-events/','','https://mariadb.com/kb/en/show-events/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (383,26,'SHOW FUNCTION STATUS','Syntax\n------\n\nSHOW FUNCTION STATUS\n [LIKE \'pattern\' | WHERE expr]\n\nDescription\n-----------\n\nThis statement is similar to SHOW PROCEDURE STATUS but for stored functions.\n\nThe LIKE clause, if present on its own, indicates which function names to\nmatch.\n\nThe WHERE and LIKE clauses can be given to select rows using more general\nconditions, as discussed in Extended SHOW.\n\nThe information_schema.ROUTINES table contains more detailed information.\n\nExamples\n--------\n\nShowing all stored functions:\n\nSHOW FUNCTION STATUS\\G\n*************************** 1. row ***************************\n Db: test\n Name: VatCents\n Type: FUNCTION\n Definer: root@localhost\n Modified: 2013-06-01 12:40:31\n Created: 2013-06-01 12:40:31\n Security_type: DEFINER\n Comment:\ncharacter_set_client: utf8\ncollation_connection: utf8_general_ci\n Database Collation: latin1_swedish_ci\n\nStored functions whose name starts with \'V\':\n\nSHOW FUNCTION STATUS LIKE \'V%\' \\G\n*************************** 1. row ***************************\n Db: test\n Name: VatCents\n Type: FUNCTION\n Definer: root@localhost\n Modified: 2013-06-01 12:40:31\n Created: 2013-06-01 12:40:31\n Security_type: DEFINER\n Comment:\ncharacter_set_client: utf8\ncollation_connection: utf8_general_ci\n Database Collation: latin1_swedish_ci\n\nStored functions with a security type of \'DEFINER\':\n\nSHOW FUNCTION STATUS WHERE Security_type LIKE \'DEFINER\' \\G\n*************************** 1. row ***************************\n Db: test\n Name: VatCents\n Type: FUNCTION\n Definer: root@localhost\n Modified: 2013-06-01 12:40:31\n Created: 2013-06-01 12:40:31\n Security_type: DEFINER\n Comment:\ncharacter_set_client: utf8\ncollation_connection: utf8_general_ci\n Database Collation: latin1_swedish_ci\n\nURL: https://mariadb.com/kb/en/show-function-status/','','https://mariadb.com/kb/en/show-function-status/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (384,26,'SHOW LOCALES','SHOW LOCALES was introduced as part of the Information Schema plugin extension.\n\nSHOW LOCALES is used to return locales information as part of the Locales\nplugin. While the information_schema.LOCALES table has 8 columns, the SHOW\nLOCALES statement will only display 4 of them:\n\nExample\n-------\n\nSHOW LOCALES;\n+-----+-------+-------------------------------------+------------------------+\n| Id | Name | Description | Error_Message_Language |\n+-----+-------+-------------------------------------+------------------------+\n| 0 | en_US | English - United States | english |\n| 1 | en_GB | English - United Kingdom | english |\n| 2 | ja_JP | Japanese - Japan | japanese |\n| 3 | sv_SE | Swedish - Sweden | swedish |\n...\n\nURL: https://mariadb.com/kb/en/show-locales/','','https://mariadb.com/kb/en/show-locales/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (385,26,'SHOW OPEN TABLES','Syntax\n------\n\nSHOW OPEN TABLES [FROM db_name]\n [LIKE \'pattern\' | WHERE expr]\n\nDescription\n-----------\n\nSHOW OPEN TABLES lists the non-TEMPORARY tables that are currently open in the\ntable cache. See http://dev.mysql.com/doc/refman/5.1/en/table-cache.html.\n\nThe FROM and LIKE clauses may be used.\n\nThe FROM clause, if present, restricts the tables shown to those present in\nthe db_name database.\n\nThe LIKE clause, if present on its own, indicates which table names to match.\nThe WHERE and LIKE clauses can be given to select rows using more general\nconditions, as discussed in Extended SHOW.\n\nThe following information is returned:\n\n+---------------------------+------------------------------------------------+\n| Column | Description |\n+---------------------------+------------------------------------------------+\n| Database | Database name. |\n+---------------------------+------------------------------------------------+\n| Name | Table name. |\n+---------------------------+------------------------------------------------+\n| In_use | Number of table instances being used. |\n+---------------------------+------------------------------------------------+\n| Name_locked | 1 if the table is name-locked, e.g. if it is |\n| | being dropped or renamed, otherwise 0. |\n+---------------------------+------------------------------------------------+\n\nBefore MariaDB 5.5, each use of, for example, LOCK TABLE ... WRITE would\nincrement In_use for that table. With the implementation of the metadata\nlocking improvements in MariaDB 5.5, LOCK TABLE... WRITE acquires a strong MDL\nlock, and concurrent connections will wait on this MDL lock, so any subsequent\nLOCK TABLE... WRITE will not increment In_use.\n\nExample\n-------\n\nSHOW OPEN TABLES;\n+----------+---------------------------+--------+-------------+\n| Database | Table | In_use | Name_locked |\n+----------+---------------------------+--------+-------------+\n...\n| test | xjson | 0 | 0 |\n| test | jauthor | 0 | 0 |\n| test | locks | 1 | 0 |\n...\n+----------+---------------------------+--------+-------------+\n\nURL: https://mariadb.com/kb/en/show-open-tables/','','https://mariadb.com/kb/en/show-open-tables/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (386,26,'SHOW PACKAGE BODY STATUS','MariaDB starting with 10.3.5\n----------------------------\nOracle-style packages were introduced in MariaDB 10.3.5.\n\nSyntax\n------\n\nSHOW PACKAGE BODY STATUS\n [LIKE \'pattern\' | WHERE expr]\n\nDescription\n-----------\n\nThe SHOW PACKAGE BODY STATUS statement returns characteristics of stored\npackage bodies (implementations), such as the database, name, type, creator,\ncreation and modification dates, and character set information. A similar\nstatement, SHOW PACKAGE STATUS, displays information about stored package\nspecifications.\n\nThe LIKE clause, if present, indicates which package names to match. The WHERE\nand LIKE clauses can be given to select rows using more general conditions, as\ndiscussed in Extended SHOW.\n\nThe ROUTINES table in the INFORMATION_SCHEMA database contains more detailed\ninformation.\n\nExamples\n--------\n\nSHOW PACKAGE BODY STATUS LIKE \'pkg1\'\\G\n*************************** 1. row ***************************\n Db: test\n Name: pkg1\n Type: PACKAGE BODY\n Definer: root@localhost\n Modified: 2018-02-27 14:44:14\n Created: 2018-02-27 14:44:14\n Security_type: DEFINER\n Comment: This is my first package body\ncharacter_set_client: utf8\ncollation_connection: utf8_general_ci\n Database Collation: latin1_swedish_ci\n\nURL: https://mariadb.com/kb/en/show-package-body-status/','','https://mariadb.com/kb/en/show-package-body-status/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (387,26,'SHOW PACKAGE STATUS','MariaDB starting with 10.3.5\n----------------------------\nOracle-style packages were introduced in MariaDB 10.3.5.\n\nSyntax\n------\n\nSHOW PACKAGE STATUS\n [LIKE \'pattern\' | WHERE expr]\n\nDescription\n-----------\n\nThe SHOW PACKAGE STATUS statement returns characteristics of stored package\nspecifications, such as the database, name, type, creator, creation and\nmodification dates, and character set information. A similar statement, SHOW\nPACKAGE BODY STATUS, displays information about stored package bodies (i.e.\nimplementations).\n\nThe LIKE clause, if present, indicates which package names to match. The WHERE\nand LIKE clauses can be given to select rows using more general conditions, as\ndiscussed in Extended SHOW.\n\nThe ROUTINES table in the INFORMATION_SCHEMA database contains more detailed\ninformation.\n\nExamples\n--------\n\nSHOW PACKAGE STATUS LIKE \'pkg1\'\\G\n*************************** 1. row ***************************\n Db: test\n Name: pkg1\n Type: PACKAGE\n Definer: root@localhost\n Modified: 2018-02-27 14:38:15\n Created: 2018-02-27 14:38:15\n Security_type: DEFINER\n Comment: This is my first package\ncharacter_set_client: utf8\ncollation_connection: utf8_general_ci\n Database Collation: latin1_swedish_ci\n\nURL: https://mariadb.com/kb/en/show-package-status/','','https://mariadb.com/kb/en/show-package-status/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (388,26,'SHOW PRIVILEGES','Syntax\n------\n\nSHOW PRIVILEGES\n\nDescription\n-----------\n\nSHOW PRIVILEGES shows the list of system privileges that the MariaDB server\nsupports. The exact list of privileges depends on the version of your server.\n\nNote that before MariaDB 10.3.23, MariaDB 10.4.13 and MariaDB 10.5.2 , the\nDelete history privilege displays as Delete versioning rows (MDEV-20382).\n\nExample\n-------\n\nFrom MariaDB 10.5.9\n\nSHOW PRIVILEGES;\n+--------------------------+---------------------------------------+-----------\n--------------------------------------------------------+\n| Privilege | Context | Comment \n |\n+--------------------------+---------------------------------------+-----------\n--------------------------------------------------------+\n| Alter | Tables | To alter\nthe table |\n| Alter routine | Functions,Procedures | To alter\nor drop stored functions/procedures |\n| Create | Databases,Tables,Indexes | To create\nnew databases and tables |\n| Create routine | Databases | To use\nCREATE FUNCTION/PROCEDURE |\n| Create temporary tables | Databases | To use\nCREATE TEMPORARY TABLE |\n| Create view | Tables | To create\nnew views |\n| Create user | Server Admin | To create\nnew users |\n| Delete | Tables | To delete\nexisting rows |\n| Delete history | Tables | To delete\nversioning table historical rows |\n| Drop | Databases,Tables | To drop\ndatabases, tables, and views |\n| Event | Server Admin | To\ncreate, alter, drop and execute events |\n| Execute | Functions,Procedures | To\nexecute stored routines |\n| File | File access on server | To read\nand write files on the server |\n| Grant option | Databases,Tables,Functions,Procedures | To give\nto other users those privileges you possess |\n| Index | Tables | To create\nor drop indexes |\n| Insert | Tables | To insert\ndata into tables |\n| Lock tables | Databases | To use\nLOCK TABLES (together with SELECT privilege) |\n| Process | Server Admin | To view\nthe plain text of currently executing queries |\n| Proxy | Server Admin | To make\nproxy user possible |\n| References | Databases,Tables | To have\nreferences on tables |\n| Reload | Server Admin | To reload\nor refresh tables, logs and privileges |\n| Binlog admin | Server | To purge\nbinary logs |\n| Binlog monitor | Server | To use\nSHOW BINLOG STATUS and SHOW BINARY LOG |\n| Binlog replay | Server | To use\nBINLOG (generated by mariadb-binlog) |\n| Replication master admin | Server | To\nmonitor connected slaves |\n| Replication slave admin | Server | To\nstart/stop slave and apply binlog events |\n| Slave monitor | Server | To use\nSHOW SLAVE STATUS and SHOW RELAYLOG EVENTS |\n| Replication slave | Server Admin | To read\nbinary log events from the master |\n| Select | Tables | To\nretrieve rows from table |\n| Show databases | Server Admin | To see\nall databases with SHOW DATABASES |\n| Show view | Tables | To see\nviews with SHOW CREATE VIEW |\n| Shutdown | Server Admin | To shut\ndown the server |\n| Super | Server Admin | To use\nKILL thread, SET GLOBAL, CHANGE MASTER, etc. |\n| Trigger | Tables | To use\ntriggers |\n| Create tablespace | Server Admin | To\ncreate/alter/drop tablespaces |\n| Update | Tables | To update\nexisting rows |\n| Set user | Server | To create\nviews and stored routines with a different definer |\n| Federated admin | Server | To\nexecute the CREATE SERVER, ALTER SERVER, DROP SERVER statements |\n| Connection admin | Server | To bypass\nconnection limits and kill other users\' connections |\n| Read_only admin | Server | To\nperform write operations even if @@read_only=ON |\n| Usage | Server Admin | No\nprivileges - allow connect only |\n+--------------------------+---------------------------------------+-----------\n--------------------------------------------------------+\n41 rows in set (0.000 sec)\n\nURL: https://mariadb.com/kb/en/show-privileges/','','https://mariadb.com/kb/en/show-privileges/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (389,26,'SHOW PROCEDURE CODE','Syntax\n------\n\nSHOW PROCEDURE CODE proc_name\n\nDescription\n-----------\n\nThis statement is a MariaDB extension that is available only for servers that\nhave been built with debugging support. It displays a representation of the\ninternal implementation of the named stored procedure. A similar statement,\nSHOW FUNCTION CODE, displays information about stored functions.\n\nBoth statements require that you be the owner of the routine or have SELECT\naccess to the mysql.proc table.\n\nIf the named routine is available, each statement produces a result set. Each\nrow in the result set corresponds to one \"instruction\" in the routine. The\nfirst column is Pos, which is an ordinal number beginning with 0. The second\ncolumn is Instruction, which contains an SQL statement (usually changed from\nthe original source), or a directive which has meaning only to the\nstored-routine handler.\n\nExamples\n--------\n\nDELIMITER //\n\nCREATE PROCEDURE p1 ()\n BEGIN\n DECLARE fanta INT DEFAULT 55;\n DROP TABLE t2;\n LOOP\n INSERT INTO t3 VALUES (fanta);\n END LOOP;\n END//\nQuery OK, 0 rows affected (0.00 sec)\n\nSHOW PROCEDURE CODE p1//\n+-----+----------------------------------------+\n| Pos | Instruction |\n+-----+----------------------------------------+\n| 0 | set fanta@0 55 |\n| 1 | stmt 9 \"DROP TABLE t2\" |\n| 2 | stmt 5 \"INSERT INTO t3 VALUES (fanta)\" |\n| 3 | jump 2 |\n+-----+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/show-procedure-code/','','https://mariadb.com/kb/en/show-procedure-code/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (390,26,'SHOW PROCEDURE STATUS','Syntax\n------\n\nSHOW PROCEDURE STATUS\n [LIKE \'pattern\' | WHERE expr]\n\nDescription\n-----------\n\nThis statement is a MariaDB extension. It returns characteristics of a stored\nprocedure, such as the database, name, type, creator, creation and\nmodification dates, and character set information. A similar statement, SHOW\nFUNCTION STATUS, displays information about stored functions.\n\nThe LIKE clause, if present, indicates which procedure or function names to\nmatch. The WHERE and LIKE clauses can be given to select rows using more\ngeneral conditions, as discussed in Extended SHOW.\n\nThe ROUTINES table in the INFORMATION_SCHEMA database contains more detailed\ninformation.\n\nExamples\n--------\n\nSHOW PROCEDURE STATUS LIKE \'p1\'\\G\n*************************** 1. row ***************************\n Db: test\n Name: p1\n Type: PROCEDURE\n Definer: root@localhost\n Modified: 2010-08-23 13:23:03\n Created: 2010-08-23 13:23:03\n Security_type: DEFINER\n Comment:\ncharacter_set_client: latin1\ncollation_connection: latin1_swedish_ci\n Database Collation: latin1_swedish_ci\n\nURL: https://mariadb.com/kb/en/show-procedure-status/','','https://mariadb.com/kb/en/show-procedure-status/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (391,26,'SHOW PROCESSLIST','Syntax\n------\n\nSHOW [FULL] PROCESSLIST\n\nDescription\n-----------\n\nSHOW PROCESSLIST shows you which threads are running. You can also get this\ninformation from the information_schema.PROCESSLIST table or the mariadb-admin\nprocesslist command. If you have the PROCESS privilege, you can see all\nthreads. Otherwise, you can see only your own threads (that is, threads\nassociated with the MariaDB account that you are using). If you do not use the\nFULL keyword, only the first 100 characters of each statement are shown in the\nInfo field.\n\nThe columns shown in SHOW PROCESSLIST are:\n\n+---------------------+------------------------------------------------------+\n| Name | Description |\n+---------------------+------------------------------------------------------+\n| ID | The client\'s process ID. |\n+---------------------+------------------------------------------------------+\n| USER | The username associated with the process. |\n+---------------------+------------------------------------------------------+\n| HOST | The host the client is connected to. |\n+---------------------+------------------------------------------------------+\n| DB | The default database of the process (NULL if no |\n| | default). |\n+---------------------+------------------------------------------------------+\n| COMMAND | The command type. See Thread Command Values. |\n+---------------------+------------------------------------------------------+\n| TIME | The amount of time, in seconds, the process has |\n| | been in its current state. For a replica SQL thread |\n| | before MariaDB 10.1, this is the time in seconds |\n| | between the last replicated event\'s timestamp and |\n| | the replica machine\'s real time. |\n+---------------------+------------------------------------------------------+\n| STATE | See Thread States. |\n+---------------------+------------------------------------------------------+\n| INFO | The statement being executed. |\n+---------------------+------------------------------------------------------+\n| PROGRESS | The total progress of the process (0-100%) (see |\n| | Progress Reporting). |\n+---------------------+------------------------------------------------------+\n\nSee TIME_MS column in information_schema.PROCESSLIST for differences in the\nTIME column between MariaDB and MySQL.\n\nThe information_schema.PROCESSLIST table contains the following additional\ncolumns:\n\n+---------------------+------------------------------------------------------+\n| Name | Description |\n+---------------------+------------------------------------------------------+\n| TIME_MS | The amount of time, in milliseconds, the process |\n| | has been in its current state. |\n+---------------------+------------------------------------------------------+\n| STAGE | The stage the process is currently in. |\n+---------------------+------------------------------------------------------+\n| MAX_STAGE | The maximum number of stages. |\n+---------------------+------------------------------------------------------+\n| PROGRESS | The progress of the process within the current |\n| | stage (0-100%). |\n+---------------------+------------------------------------------------------+\n| MEMORY_USED | The amount of memory used by the process. |\n+---------------------+------------------------------------------------------+\n| EXAMINED_ROWS | The number of rows the process has examined. |\n+---------------------+------------------------------------------------------+\n| QUERY_ID | Query ID. |\n+---------------------+------------------------------------------------------+\n\nNote that the PROGRESS field from the information schema, and the PROGRESS\nfield from SHOW PROCESSLIST display different results. SHOW PROCESSLIST shows\nthe total progress, while the information schema shows the progress for the\ncurrent stage only.\n\nThreads can be killed using their thread_id or their query_id, with the KILL\nstatement.\n\nSince queries on this table are locking, if the performance_schema is enabled,\nyou may want to query the THREADS table instead.\n\nExamples\n--------\n\nSHOW PROCESSLIST;\n+----+-----------------+-----------+------+---------+------+-------------------\n----+------------------+----------+\n| Id | User | Host | db | Command | Time | State \n | Info | Progress |\n+----+-----------------+-----------+------+---------+------+-------------------\n----+------------------+----------+\n| 2 | event_scheduler | localhost | NULL | Daemon | 2693 | Waiting on empty\nqueue | NULL | 0.000 |\n| 4 | root | localhost | NULL | Query | 0 | Table lock \n | SHOW PROCESSLIST | 0.000 |\n+----+-----------------+-----------+------+---------+------+-------------------\n----+------------------+----------+\n\nURL: https://mariadb.com/kb/en/show-processlist/','','https://mariadb.com/kb/en/show-processlist/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (392,26,'SHOW PROFILE','Syntax\n------\n\nSHOW PROFILE [type [, type] ... ]\n [FOR QUERY n]\n [LIMIT row_count [OFFSET offset]]\n\ntype:\n ALL\n | BLOCK IO\n | CONTEXT SWITCHES\n | CPU\n | IPC\n | MEMORY\n | PAGE FAULTS\n | SOURCE\n | SWAPS\n\nDescription\n-----------\n\nThe SHOW PROFILE and SHOW PROFILES statements display profiling information\nthat indicates resource usage for statements executed during the course of the\ncurrent session.\n\nProfiling is controlled by the profiling session variable, which has a default\nvalue of 0 (OFF). Profiling is enabled by setting profiling to 1 or ON:\n\nSET profiling = 1;\n\nSHOW PROFILES displays a list of the most recent statements sent to the\nmaster. The size of the list is controlled by the profiling_history_size\nsession variable, which has a default value of 15. The maximum value is 100.\nSetting the value to 0 has the practical effect of disabling profiling.\n\nAll statements are profiled except SHOW PROFILES and SHOW PROFILE, so you will\nfind neither of those statements in the profile list. Malformed statements are\nprofiled. For example, SHOW PROFILING is an illegal statement, and a syntax\nerror occurs if you try to execute it, but it will show up in the profiling\nlist.\n\nSHOW PROFILE displays detailed information about a single statement. Without\nthe FOR QUERY n clause, the output pertains to the most recently executed\nstatement. If FOR QUERY n is included, SHOW PROFILE displays information for\nstatement n. The values of n correspond to the Query_ID values displayed by\nSHOW PROFILES.\n\nThe LIMIT row_count clause may be given to limit the output to row_count rows.\nIf LIMIT is given, OFFSET offset may be added to begin the output offset rows\ninto the full set of rows.\n\nBy default, SHOW PROFILE displays Status and Duration columns. The Status\nvalues are like the State values displayed by SHOW PROCESSLIST, although there\nmight be some minor differences in interpretation for the two statements for\nsome status values (see\nhttp://dev.mysql.com/doc/refman/5.6/en/thread-information.html).\n\nOptional type values may be specified to display specific additional types of\ninformation:\n\n* ALL displays all information\n* BLOCK IO displays counts for block input and output operations\n* CONTEXT SWITCHES displays counts for voluntary and involuntary context\nswitches\n* CPU displays user and system CPU usage times\n* IPC displays counts for messages sent and received\n* MEMORY is not currently implemented\n* PAGE FAULTS displays counts for major and minor page faults\n* SOURCE displays the names of functions from the source code, together with\nthe name and line number of the file in which the function occurs\n* SWAPS displays swap counts\n\nProfiling is enabled per session. When a session ends, its profiling\ninformation is lost.\n\nThe information_schema.PROFILING table contains similar information.\n\nExamples\n--------\n\nSELECT @@profiling;\n+-------------+\n| @@profiling |\n+-------------+\n| 0 |\n+-------------+\n\nSET profiling = 1;\n\nUSE test;\n\nDROP TABLE IF EXISTS t1;\n\nCREATE TABLE T1 (id INT);\n\nSHOW PROFILES;\n+----------+------------+--------------------------+\n| Query_ID | Duration | Query |\n+----------+------------+--------------------------+\n| 1 | 0.00009200 | SELECT DATABASE() |\n| 2 | 0.00023800 | show databases |\n| 3 | 0.00018900 | show tables |\n| 4 | 0.00014700 | DROP TABLE IF EXISTS t1 |\n| 5 | 0.24476900 | CREATE TABLE T1 (id INT) |\n+----------+------------+--------------------------+\n\nSHOW PROFILE;\n+----------------------+----------+\n| Status | Duration |\n+----------------------+----------+\n| starting | 0.000042 |\n| checking permissions | 0.000044 |\n| creating table | 0.244645 |\n| After create | 0.000013 |\n| query end | 0.000003 |\n| freeing items | 0.000016 |\n| logging slow query | 0.000003 |\n| cleaning up | 0.000003 |\n+----------------------+----------+\n\nSHOW PROFILE FOR QUERY 4;\n+--------------------+----------+\n| Status | Duration |\n+--------------------+----------+\n| starting | 0.000126 |\n| query end | 0.000004 |\n| freeing items | 0.000012 |\n| logging slow query | 0.000003 |\n| cleaning up | 0.000002 |\n+--------------------+----------+\n\nSHOW PROFILE CPU FOR QUERY 5;\n+----------------------+----------+----------+------------+\n| Status | Duration | CPU_user | CPU_system |\n+----------------------+----------+----------+------------+\n| starting | 0.000042 | 0.000000 | 0.000000 |\n| checking permissions | 0.000044 | 0.000000 | 0.000000 |\n| creating table | 0.244645 | 0.000000 | 0.000000 |\n| After create | 0.000013 | 0.000000 | 0.000000 |\n| query end | 0.000003 | 0.000000 | 0.000000 |\n| freeing items | 0.000016 | 0.000000 | 0.000000 |\n| logging slow query | 0.000003 | 0.000000 | 0.000000 |\n| cleaning up | 0.000003 | 0.000000 | 0.000000 |\n+----------------------+----------+----------+------------+\n\nURL: https://mariadb.com/kb/en/show-profile/','','https://mariadb.com/kb/en/show-profile/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (393,26,'SHOW PROFILES','Syntax\n------\n\nSHOW PROFILES\n\nDescription\n-----------\n\nThe SHOW PROFILES statement displays profiling information that indicates\nresource usage for statements executed during the course of the current\nsession. It is used together with SHOW PROFILE.\n\nURL: https://mariadb.com/kb/en/show-profiles/','','https://mariadb.com/kb/en/show-profiles/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (394,26,'SHOW QUERY_RESPONSE_TIME','It is possible to use SHOW QUERY_RESPONSE_TIME as an alternative for\nretrieving information from the QUERY_RESPONSE_TIME plugin.\n\nThis was introduced as part of the Information Schema plugin extension.\n\nURL: https://mariadb.com/kb/en/show-query_response_time/','','https://mariadb.com/kb/en/show-query_response_time/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (395,26,'SHOW STATUS','Syntax\n------\n\nSHOW [GLOBAL | SESSION] STATUS\n [LIKE \'pattern\' | WHERE expr]\n\nDescription\n-----------\n\nSHOW STATUS provides server status information. This information also can be\nobtained using the mariadb-admin extended-status command, or by querying the\nInformation Schema GLOBAL_STATUS and SESSION_STATUS tables. The LIKE clause,\nif present, indicates which variable names to match. The WHERE clause can be\ngiven to select rows using more general conditions.\n\nWith the GLOBAL modifier, SHOW STATUS displays the status values for all\nconnections to MariaDB. With SESSION, it displays the status values for the\ncurrent connection. If no modifier is present, the default is SESSION. LOCAL\nis a synonym for SESSION. If you see a lot of 0 values, the reason is probably\nthat you have used SHOW STATUS with a new connection instead of SHOW GLOBAL\nSTATUS.\n\nSome status variables have only a global value. For these, you get the same\nvalue for both GLOBAL and SESSION.\n\nSee Server Status Variables for a full list, scope and description of the\nvariables that can be viewed with SHOW STATUS.\n\nThe LIKE clause, if present on its own, indicates which variable name to match.\n\nThe WHERE and LIKE clauses can be given to select rows using more general\nconditions, as discussed in Extended SHOW.\n\nExamples\n--------\n\nSHOW GLOBAL STATUS;\n+--------------------------------------------------------------+---------------\n------------------------+\n| Variable_name | Value \n |\n+--------------------------------------------------------------+---------------\n------------------------+\n| Aborted_clients | 0 \n |\n| Aborted_connects | 0 \n |\n| Access_denied_errors | 0 \n |\n| Acl_column_grants | 0 \n |\n| Acl_database_grants | 2 \n |\n| Acl_function_grants | 0 \n |\n| Acl_procedure_grants | 0 \n |\n| Acl_proxy_users | 2 \n |\n| Acl_role_grants | 0 \n |\n| Acl_roles | 0 \n |\n| Acl_table_grants | 0 \n |\n| Acl_users | 6 \n |\n| Aria_pagecache_blocks_not_flushed | 0 \n |\n| Aria_pagecache_blocks_unused | 15706 \n |\n...\n| wsrep_local_index |\n18446744073709551615 |\n| wsrep_provider_name | \n |\n| wsrep_provider_vendor | \n |\n| wsrep_provider_version | \n |\n| wsrep_ready | OFF \n |\n| wsrep_thread_count | 0 \n |\n+--------------------------------------------------------------+---------------\n------------------------+\n516 rows in set (0.00 sec)\n\nExample of filtered output:\n\nSHOW STATUS LIKE \'Key%\';\n+------------------------+--------+\n| Variable_name | Value |\n+------------------------+--------+\n| Key_blocks_not_flushed | 0 |\n| Key_blocks_unused | 107163 |\n| Key_blocks_used | 0 |\n| Key_blocks_warm | 0 |\n| Key_read_requests | 0 |\n| Key_reads | 0 |\n| Key_write_requests | 0 |\n| Key_writes | 0 |\n+------------------------+--------+\n8 rows in set (0.00 sec)\n\nURL: https://mariadb.com/kb/en/show-status/','','https://mariadb.com/kb/en/show-status/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (396,26,'SHOW TABLE STATUS','Syntax\n------\n\nSHOW TABLE STATUS [{FROM | IN} db_name]\n [LIKE \'pattern\' | WHERE expr]\n\nDescription\n-----------\n\nSHOW TABLE STATUS works like SHOW TABLES, but provides more extensive\ninformation about each table (until MariaDB 11.2.0, only non-TEMPORARY tables\nare shown).\n\nThe LIKE clause, if present on its own, indicates which table names to match.\nThe WHERE and LIKE clauses can be given to select rows using more general\nconditions, as discussed in Extended SHOW.\n\nThe following information is returned:\n\n+---------------------------+------------------------------------------------+\n| Column | Description |\n+---------------------------+------------------------------------------------+\n| Name | Table name. |\n+---------------------------+------------------------------------------------+\n| Engine | Table storage engine. |\n+---------------------------+------------------------------------------------+\n| Version | Version number from the table\'s .frm file. |\n+---------------------------+------------------------------------------------+\n| Row_format | Row format (see InnoDB, Aria and MyISAM row |\n| | formats). |\n+---------------------------+------------------------------------------------+\n| Rows | Number of rows in the table. Some engines, |\n| | such as InnoDB may store an estimate. |\n+---------------------------+------------------------------------------------+\n| Avg_row_length | Average row length in the table. |\n+---------------------------+------------------------------------------------+\n| Data_length | For InnoDB, the index size, in pages, |\n| | multiplied by the page size. For Aria and |\n| | MyISAM, length of the data file, in bytes. |\n| | For MEMORY, the approximate allocated memory. |\n+---------------------------+------------------------------------------------+\n| Max_data_length | Maximum length of the data file, ie the total |\n| | number of bytes that could be stored in the |\n| | table. Not used in InnoDB. |\n+---------------------------+------------------------------------------------+\n| Index_length | Length of the index file. |\n+---------------------------+------------------------------------------------+\n| Data_free | Bytes allocated but unused. For InnoDB tables |\n| | in a shared tablespace, the free space of the |\n| | shared tablespace with small safety margin. |\n| | An estimate in the case of partitioned tables |\n| | - see the PARTITIONS table. |\n+---------------------------+------------------------------------------------+\n| Auto_increment | Next AUTO_INCREMENT value. |\n+---------------------------+------------------------------------------------+\n| Create_time | Time the table was created. Some engines just |\n| | return the ctime information from the file |\n| | system layer here, in that case the value is |\n| | not necessarily the table creation time but |\n| | rather the time the file system metadata for |\n| | it had last changed. |\n+---------------------------+------------------------------------------------+\n| Update_time | Time the table was last updated. On Windows, |\n| | the timestamp is not updated on update, so |\n| | MyISAM values will be inaccurate. In InnoDB, |\n| | if shared tablespaces are used, will be NULL, |\n| | while buffering can also delay the update, so |\n| | the value will differ from the actual time of |\n| | the last UPDATE, INSERT or DELETE. |\n+---------------------------+------------------------------------------------+\n| Check_time | Time the table was last checked. Not kept by |\n| | all storage engines, in which case will be |\n| | NULL. |\n+---------------------------+------------------------------------------------+\n| Collation | Character set and collation. |\n+---------------------------+------------------------------------------------+\n| Checksum | Live checksum value, if any. |\n+---------------------------+------------------------------------------------+\n| Create_options | Extra CREATE TABLE options. |\n+---------------------------+------------------------------------------------+\n| Comment | Table comment provided when MariaDB created |\n| | the table. |\n+---------------------------+------------------------------------------------+\n| Max_index_length | Maximum index length (supported by MyISAM and |\n| | Aria tables). |\n+---------------------------+------------------------------------------------+\n| Temporary | Until MariaDB 11.2.0, placeholder to signal |\n| | that a table is a temporary table and always |\n| | \"N\", except \"Y\" for generated |\n| | information_schema tables and NULL for views. |\n| | From MariaDB 11.2.0, will also be set to \"Y\" |\n| | for local temporary tables. |\n+---------------------------+------------------------------------------------+\n\nSimilar information can be found in the information_schema.TABLES table as\nwell as by using mariadb-show:\n\nmariadb-show --status db_name\n\nViews\n-----\n\nFor views, all columns in SHOW TABLE STATUS are NULL except \'Name\' and\n\'Comment\'\n\nExample\n-------\n\nshow table status\\G\n*************************** 1. row ***************************\n Name: bus_routes\n Engine: InnoDB\n Version: 10\n Row_format: Dynamic\n Rows: 5\n Avg_row_length: 3276\n Data_length: 16384\nMax_data_length: 0\n Index_length: 0\n Data_free: 0\n Auto_increment: NULL\n Create_time: 2017-05-24 11:17:46\n Update_time: NULL\n Check_time: NULL\n Collation: latin1_swedish_ci\n Checksum: NULL\n Create_options: \n Comment:\n\nURL: https://mariadb.com/kb/en/show-table-status/','','https://mariadb.com/kb/en/show-table-status/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (397,26,'SHOW TABLES','Syntax\n------\n\nSHOW [FULL] TABLES [FROM db_name]\n [LIKE \'pattern\' | WHERE expr]\n\nDescription\n-----------\n\nSHOW TABLES lists the tables (until MariaDB 11.2.0, only non-TEMPORARY tables\nare shown), sequences and views in a given database.\n\nThe LIKE clause, if present on its own, indicates which table names to match.\nThe WHERE and LIKE clauses can be given to select rows using more general\nconditions, as discussed in Extended SHOW. For example, when searching for\ntables in the test database, the column name for use in the WHERE and LIKE\nclauses will be Tables_in_test\n\nThe FULL modifier is supported such that SHOW FULL TABLES displays a second\noutput column. Values for the second column, Table_type, are BASE TABLE for a\ntable, VIEW for a view and SEQUENCE for a sequence.\n\nYou can also get this information using:\n\nmariadb-show db_name\n\nSee mariadb-show for more details.\n\nIf you have no privileges for a base table or view, it does not show up in the\noutput from SHOW TABLES or mariadb-show db_name.\n\nThe information_schema.TABLES table, as well as the SHOW TABLE STATUS\nstatement, provide extended information about tables.\n\nExamples\n--------\n\nSHOW TABLES;\n+----------------------+\n| Tables_in_test |\n+----------------------+\n| animal_count |\n| animals |\n| are_the_mooses_loose |\n| aria_test2 |\n| t1 |\n| view1 |\n+----------------------+\n\nShowing the tables beginning with a only.\n\nSHOW TABLES WHERE Tables_in_test LIKE \'a%\';\n+----------------------+\n| Tables_in_test |\n+----------------------+\n| animal_count |\n| animals |\n| are_the_mooses_loose |\n| aria_test2 |\n+----------------------+\n\nShowing tables and table types:\n\nSHOW FULL TABLES;\n+----------------+------------+\n| Tables_in_test | Table_type |\n+----------------+------------+\n| s1 | SEQUENCE |\n| student | BASE TABLE |\n| v1 | VIEW |\n+----------------+------------+\n\nShowing temporary tables: <= MariaDB 11.1\n\nCREATE TABLE t (t int(11));\nCREATE TEMPORARY TABLE t (t int(11));\nCREATE TEMPORARY TABLE te (t int(11));\n\nSHOW TABLES;\n+----------------+\n| Tables_in_test |\n+----------------+\n| t |\n+----------------+\n\nFrom MariaDB 11.2.0:\n\nCREATE TABLE t (t int(11));\nCREATE TEMPORARY TABLE t (t int(11));\nCREATE TEMPORARY TABLE te (t int(11));\n\nSHOW TABLES;\n+----------------+\n| Tables_in_test |\n+----------------+\n| te |\n| t |\n| t |\n+----------------+\n\nURL: https://mariadb.com/kb/en/show-tables/','','https://mariadb.com/kb/en/show-tables/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (398,26,'SHOW TABLE_STATISTICS','Syntax\n------\n\nSHOW TABLE_STATISTICS\n\nDescription\n-----------\n\nThe SHOW TABLE_STATISTICS statementis part of the User Statistics feature. It\nwas removed as a separate statement in MariaDB 10.1.1, but effectively\nreplaced by the generic SHOW information_schema_table statement. The\ninformation_schema.TABLE_STATISTICS table shows statistics on table usage\n\nThe userstat system variable must be set to 1 to activate this feature. See\nthe User Statistics and information_schema.TABLE_STATISTICS articles for more\ninformation.\n\nExample\n-------\n\nSHOW TABLE_STATISTICS\\G\n*************************** 1. row ***************************\n Table_schema: mysql\n Table_name: proxies_priv\n Rows_read: 2\n Rows_changed: 0\nRows_changed_x_#indexes: 0\n*************************** 2. row ***************************\n Table_schema: test\n Table_name: employees_example\n Rows_read: 7\n Rows_changed: 0\nRows_changed_x_#indexes: 0\n*************************** 3. row ***************************\n Table_schema: mysql\n Table_name: user\n Rows_read: 16\n Rows_changed: 0\nRows_changed_x_#indexes: 0\n*************************** 4. row ***************************\n Table_schema: mysql\n Table_name: db\n Rows_read: 2\n Rows_changed: 0\nRows_changed_x_#indexes: 0\n\nURL: https://mariadb.com/kb/en/show-table-statistics/','','https://mariadb.com/kb/en/show-table-statistics/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (399,26,'SHOW TRIGGERS','Syntax\n------\n\nSHOW TRIGGERS [FROM db_name]\n [LIKE \'pattern\' | WHERE expr]\n\nDescription\n-----------\n\nSHOW TRIGGERS lists the triggers currently defined for tables in a database\n(the default database unless a FROM clause is given). This statement requires\nthe TRIGGER privilege (prior to MySQL 5.1.22, it required the SUPER privilege).\n\nThe LIKE clause, if present on its own, indicates which table names to match\nand causes the statement to display triggers for those tables. The WHERE and\nLIKE clauses can be given to select rows using more general conditions, as\ndiscussed in Extended SHOW.\n\nSimilar information is stored in the information_schema.TRIGGERS table.\n\nMariaDB starting with 10.2.3\n----------------------------\nIf there are multiple triggers for the same action, then the triggers are\nshown in action order.\n\nExamples\n--------\n\nFor the trigger defined at Trigger Overview:\n\nSHOW triggers Like \'animals\' \\G\n*************************** 1. row ***************************\n Trigger: the_mooses_are_loose\n Event: INSERT\n Table: animals\n Statement: BEGIN\n IF NEW.name = \'Moose\' THEN\n UPDATE animal_count SET animal_count.animals = animal_count.animals+100;\n ELSE \n UPDATE animal_count SET animal_count.animals = animal_count.animals+1;\n END IF;\nEND\n Timing: AFTER\n Created: 2016-09-29 13:53:34.35\n sql_mode:\n Definer: root@localhost\ncharacter_set_client: utf8\ncollation_connection: utf8_general_ci\n Database Collation: latin1_swedish_ci\n\nListing all triggers associated with a certain table:\n\nSHOW TRIGGERS FROM test WHERE `Table` = \'user\' \\G\n*************************** 1. row ***************************\n Trigger: user_ai\n Event: INSERT\n Table: user\n Statement: BEGIN END\n Timing: AFTER\n Created: 2016-09-29 13:53:34.35\n sql_mode:\n Definer: root@%\ncharacter_set_client: utf8\ncollation_connection: utf8_general_ci\n Database Collation: latin1_swedish_ci\n\nSHOW triggers WHERE Event Like \'Insert\' \\G\n*************************** 1. row ***************************\n Trigger: the_mooses_are_loose\n Event: INSERT\n Table: animals\n Statement: BEGIN\n IF NEW.name = \'Moose\' THEN\n UPDATE animal_count SET animal_count.animals = animal_count.animals+100;\n ELSE \n UPDATE animal_count SET animal_count.animals = animal_count.animals+1;\n END IF;\nEND\n Timing: AFTER\n Created: 2016-09-29 13:53:34.35\n sql_mode:\n Definer: root@localhost\ncharacter_set_client: utf8\ncollation_connection: utf8_general_ci\n Database Collation: latin1_swedish_ci\n\n* character_set_client is the session value of the character_set_client system\nvariable when the trigger was created. \n* collation_connection is the session value of the collation_connection system\nvariable when the trigger was\n created. \n* Database Collation is the collation of the database \n with which the trigger is associated.\n\nThese columns were added in MariaDB/MySQL 5.1.21.\n\nOld triggers created before MySQL 5.7 and MariaDB 10.2.3 has NULL in the\nCreated column.\n\nURL: https://mariadb.com/kb/en/show-triggers/','','https://mariadb.com/kb/en/show-triggers/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (400,26,'SHOW USER_STATISTICS','Syntax\n------\n\nSHOW USER_STATISTICS\n\nDescription\n-----------\n\nThe SHOW USER_STATISTICS statement is part of the User Statistics feature. It\nwas removed as a separate statement in MariaDB 10.1.1, but effectively\nreplaced by the generic SHOW information_schema_table statement. The\ninformation_schema.USER_STATISTICS table holds statistics about user activity.\nYou can use this table to find out such things as which user is causing the\nmost load and which users are being abusive. You can also use this table to\nmeasure how close to capacity the server may be.\n\nThe userstat system variable must be set to 1 to activate this feature. See\nthe User Statistics and information_schema.USER_STATISTICS table for more\ninformation.\n\nExample\n-------\n\nSHOW USER_STATISTICS\\G\n*************************** 1. row ***************************\n User: root\n Total_connections: 1\nConcurrent_connections: 0\n Connected_time: 3297\n Busy_time: 0.14113400000000006\n Cpu_time: 0.017637000000000003\n Bytes_received: 969\n Bytes_sent: 22355\n Binlog_bytes_written: 0\n Rows_read: 10\n Rows_sent: 67\n Rows_deleted: 0\n Rows_inserted: 0\n Rows_updated: 0\n Select_commands: 7\n Update_commands: 0\n Other_commands: 0\n Commit_transactions: 1\n Rollback_transactions: 0\n Denied_connections: 0\n Lost_connections: 0\n Access_denied: 0\n Empty_queries: 7\n\nURL: https://mariadb.com/kb/en/show-user-statistics/','','https://mariadb.com/kb/en/show-user-statistics/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (401,26,'SHOW VARIABLES','Syntax\n------\n\nSHOW [GLOBAL | SESSION] VARIABLES\n [LIKE \'pattern\' | WHERE expr]\n\nDescription\n-----------\n\nSHOW VARIABLES shows the values of MariaDB system variables. This information\nalso can be obtained using the mariadb-admin variables command. The LIKE\nclause, if present, indicates which variable names to match. The WHERE clause\ncan be given to select rows using more general conditions.\n\nWith the GLOBAL modifier, SHOW VARIABLES displays the values that are used for\nnew connections to MariaDB. With SESSION, it displays the values that are in\neffect for the current connection. If no modifier is present, the default is\nSESSION. LOCAL is a synonym for SESSION. With a LIKE clause, the statement\ndisplays only rows for those variables with names that match the pattern. To\nobtain the row for a specific variable, use a LIKE clause as shown:\n\nSHOW VARIABLES LIKE \'maria_group_commit\';\nSHOW SESSION VARIABLES LIKE \'maria_group_commit\';\n\nTo get a list of variables whose name match a pattern, use the \"%\" wildcard\ncharacter in a LIKE clause:\n\nSHOW VARIABLES LIKE \'%maria%\';\nSHOW GLOBAL VARIABLES LIKE \'%maria%\';\n\nWildcard characters can be used in any position within the pattern to be\nmatched. Strictly speaking, because \"_\" is a wildcard that matches any single\ncharacter, you should escape it as \"\\_\" to match it literally. In practice,\nthis is rarely necessary.\n\nThe WHERE and LIKE clauses can be given to select rows using more general\nconditions, as discussed in Extended SHOW.\n\nSee SET for information on setting server system variables.\n\nSee Server System Variables for a list of all the variables that can be set.\n\nYou can also see the server variables by querying the Information Schema\nGLOBAL_VARIABLES and SESSION_VARIABLES tables.\n\nExamples\n--------\n\nSHOW VARIABLES LIKE \'aria%\';\n+------------------------------------------+---------------------+\n| Variable_name | Value |\n+------------------------------------------+---------------------+\n| aria_block_size | 8192 |\n| aria_checkpoint_interval | 30 |\n| aria_checkpoint_log_activity | 1048576 |\n| aria_force_start_after_recovery_failures | 0 |\n| aria_group_commit | none |\n| aria_group_commit_interval | 0 |\n| aria_log_file_size | 1073741824 |\n| aria_log_purge_type | immediate |\n| aria_max_sort_file_size | 9223372036853727232 |\n| aria_page_checksum | ON |\n| aria_pagecache_age_threshold | 300 |\n| aria_pagecache_buffer_size | 134217728 |\n| aria_pagecache_division_limit | 100 |\n| aria_recover | NORMAL |\n| aria_repair_threads | 1 |\n| aria_sort_buffer_size | 134217728 |\n| aria_stats_method | nulls_unequal |\n| aria_sync_log_dir | NEWFILE |\n| aria_used_for_temp_tables | ON |\n+------------------------------------------+---------------------+\n\nSELECT VARIABLE_NAME, SESSION_VALUE, GLOBAL_VALUE FROM\n INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE\n VARIABLE_NAME LIKE \'max_error_count\' OR\n VARIABLE_NAME LIKE \'innodb_sync_spin_loops\';\n+---------------------------+---------------+--------------+\n| VARIABLE_NAME | SESSION_VALUE | GLOBAL_VALUE |\n+---------------------------+---------------+--------------+\n| MAX_ERROR_COUNT | 64 | 64 |\n| INNODB_SYNC_SPIN_LOOPS | NULL | 30 |\n+---------------------------+---------------+--------------+\n\nSET GLOBAL max_error_count=128;\n\nSELECT VARIABLE_NAME, SESSION_VALUE, GLOBAL_VALUE FROM\n INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE\n VARIABLE_NAME LIKE \'max_error_count\' OR\n VARIABLE_NAME LIKE \'innodb_sync_spin_loops\';\n+---------------------------+---------------+--------------+\n| VARIABLE_NAME | SESSION_VALUE | GLOBAL_VALUE |\n+---------------------------+---------------+--------------+\n| MAX_ERROR_COUNT | 64 | 128 |\n| INNODB_SYNC_SPIN_LOOPS | NULL | 30 |\n+---------------------------+---------------+--------------+\n\nSET GLOBAL max_error_count=128;\n\nSHOW VARIABLES LIKE \'max_error_count\';\n+-----------------+-------+\n| Variable_name | Value |\n+-----------------+-------+\n| max_error_count | 64 |\n+-----------------+-------+\n\nSHOW GLOBAL VARIABLES LIKE \'max_error_count\';\n+-----------------+-------+\n| Variable_name | Value |\n+-----------------+-------+\n| max_error_count | 128 |\n+-----------------+-------+\n\nBecause the following variable only has a global scope, the global value is\nreturned even when specifying SESSION (in this case by default):\n\nSHOW VARIABLES LIKE \'innodb_sync_spin_loops\';\n+------------------------+-------+\n| Variable_name | Value |\n+------------------------+-------+\n| innodb_sync_spin_loops | 30 |\n+------------------------+-------+\n\nURL: https://mariadb.com/kb/en/show-variables/','','https://mariadb.com/kb/en/show-variables/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (402,26,'SHOW WARNINGS','Syntax\n------\n\nSHOW WARNINGS [LIMIT [offset,] row_count]\nSHOW ERRORS [LIMIT row_count OFFSET offset]\nSHOW COUNT(*) WARNINGS\n\nDescription\n-----------\n\nSHOW WARNINGS shows the error, warning, and note messages that resulted from\nthe last statement that generated messages in the current session. It shows\nnothing if the last statement used a table and generated no messages. (That\nis, a statement that uses a table but generates no messages clears the message\nlist.) Statements that do not use tables and do not generate messages have no\neffect on the message list.\n\nA note is different to a warning in that it only appears if the sql_notes\nvariable is set to 1 (the default), and is not converted to an error if strict\nmode is enabled.\n\nA related statement, SHOW ERRORS, shows only the errors.\n\nThe SHOW COUNT(*) WARNINGS statement displays the total number of errors,\nwarnings, and notes. You can also retrieve this number from the warning_count\nvariable:\n\nSHOW COUNT(*) WARNINGS;\nSELECT @@warning_count;\n\nThe value of warning_count might be greater than the number of messages\ndisplayed by SHOW WARNINGS if the max_error_count system variable is set so\nlow that not all messages are stored.\n\nThe LIMIT clause has the same syntax as for the SELECT statement.\n\nSHOW WARNINGS can be used after EXPLAIN EXTENDED to see how a query is\ninternally rewritten by MariaDB.\n\nIf the sql_notes server variable is set to 1, Notes are included in the output\nof SHOW WARNINGS; if it is set to 0, this statement will not show (or count)\nNotes.\n\nThe results of SHOW WARNINGS and SHOW COUNT(*) WARNINGS are directly sent to\nthe client. If you need to access those information in a stored program, you\ncan use the GET DIAGNOSTICS statement instead.\n\nFor a list of MariaDB error codes, see MariaDB Error Codes.\n\nThe mariadb client also has a number of options related to warnings. The \\W\ncommand will show warnings after every statement, while \\w will disable this.\nStarting the client with the --show-warnings option will show warnings after\nevery statement.\n\nMariaDB implements a stored routine error stack trace. SHOW WARNINGS can also\nbe used to show more information. See the example below.\n\nExamples\n--------\n\nSELECT 1/0;\n+------+\n| 1/0 |\n+------+\n| NULL |\n+------+\n\nSHOW COUNT(*) WARNINGS;\n+-------------------------+\n| @@session.warning_count |\n+-------------------------+\n| 1 |\n+-------------------------+\n\nSHOW WARNINGS;\n+---------+------+---------------+\n| Level | Code | Message |\n+---------+------+---------------+\n| Warning | 1365 | Division by 0 |\n+---------+------+---------------+\n\nStack Trace\n-----------\n\nDisplaying a stack trace:\n\nDELIMITER $$\nCREATE OR REPLACE PROCEDURE p1()\n BEGIN\n DECLARE c CURSOR FOR SELECT * FROM not_existing;\n OPEN c;\n CLOSE c;\n END;\n$$\nCREATE OR REPLACE PROCEDURE p2()\n BEGIN\n CALL p1;\n END;\n$$\nDELIMITER ;\nCALL p2;\nERROR 1146 (42S02): Table \'test.not_existing\' doesn\'t exist\n\nSHOW WARNINGS;\n+-------+------+-----------------------------------------+\n| Level | Code | Message |\n+-------+------+-----------------------------------------+\n| Error | 1146 | Table \'test.not_existing\' doesn\'t exist |\n| Note | 4091 | At line 6 in test.p1 |\n| Note | 4091 | At line 4 in test.p2 |\n+-------+------+-----------------------------------------+\n\nSHOW WARNINGS displays a stack trace, showing where the error actually\nhappened:\n\n* Line 4 in test.p1 is the OPEN command which actually raised the error\n* Line 3 in test.p2 is the CALL statement, calling p1 from p2.\n\nURL: https://mariadb.com/kb/en/show-warnings/','','https://mariadb.com/kb/en/show-warnings/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (403,26,'SHOW WSREP_MEMBERSHIP','SHOW WSREP_MEMBERSHIP is part of the WSREP_INFO plugin.\n\nSyntax\n------\n\nSHOW WSREP_MEMBERSHIP\n\nDescription\n-----------\n\nThe SHOW WSREP_MEMBERSHIP statement returns Galera node cluster membership\ninformation. It returns the same information as found in the\ninformation_schema.WSREP_MEMBERSHIP table. Only users with the SUPER privilege\ncan access this information.\n\nExamples\n--------\n\nSHOW WSREP_MEMBERSHIP;\n+-------+--------------------------------------+----------+-----------------+\n| Index | Uuid | Name | Address |\n+-------+--------------------------------------+----------+-----------------+\n| 0 | 19058073-8940-11e4-8570-16af7bf8fced | my_node1 | 10.0.2.15:16001 |\n| 1 | 19f2b0e0-8942-11e4-9cb8-b39e8ee0b5dd | my_node3 | 10.0.2.15:16003 |\n| 2 | d85e62db-8941-11e4-b1ef-4bc9980e476d | my_node2 | 10.0.2.15:16002 |\n+-------+--------------------------------------+----------+-----------------+\n\nURL: https://mariadb.com/kb/en/show-wsrep_membership/','','https://mariadb.com/kb/en/show-wsrep_membership/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (404,26,'SHOW WSREP_STATUS','SHOW WSREP_STATUS is part of the WSREP_INFO plugin.\n\nSyntax\n------\n\nSHOW WSREP_STATUS\n\nDescription\n-----------\n\nThe SHOW WSREP_STATUS statement returns Galera node and cluster status\ninformation. It returns the same information as found in the\ninformation_schema.WSREP_STATUS table. Only users with the SUPER privilege can\naccess this information.\n\nExamples\n--------\n\nSHOW WSREP_STATUS;\n+------------+-------------+----------------+--------------+\n| Node_Index | Node_Status | Cluster_Status | Cluster_Size |\n+------------+-------------+----------------+--------------+\n| 0 | Synced | Primary | 3 |\n+------------+-------------+----------------+--------------+\n\nURL: https://mariadb.com/kb/en/show-wsrep_status/','','https://mariadb.com/kb/en/show-wsrep_status/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (405,26,'BINLOG','Syntax\n------\n\nBINLOG \'str\'\n\nDescription\n-----------\n\nBINLOG is an internal-use statement. It is generated by the mariadb-binlog\nprogram as the printable representation of certain events in binary log files.\nThe \'str\' value is a base 64-encoded string that the server decodes to\ndetermine the data change indicated by the corresponding event. This statement\nrequires the SUPER privilege (<= MariaDB 10.5.1) or the BINLOG REPLAY\nprivilege (>= MariaDB 10.5.2).\n\nURL: https://mariadb.com/kb/en/binlog/','','https://mariadb.com/kb/en/binlog/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (406,26,'PURGE BINARY LOGS','Syntax\n------\n\nPURGE { BINARY | MASTER } LOGS\n { TO \'log_name\' | BEFORE datetime_expr }\n\nDescription\n-----------\n\nThe PURGE BINARY LOGS statement deletes all the binary log files listed in the\nlog index file prior to the specified log file name or date. BINARY and MASTER\nare synonyms. Deleted log files also are removed from the list recorded in the\nindex file, so that the given log file becomes the first in the list.\n\nThe datetime expression is in the format \'YYYY-MM-DD hh:mm:ss\'.\n\nIf a replica is active but has yet to read from a binary log file you attempt\nto delete, the statement will fail with an error. However, if the replica is\nnot connected and has yet to read from a log file you delete, the file will be\ndeleted, but the replica will be unable to continue replicating once it\nconnects again.\n\nThis statement has no effect if the server was not started with the --log-bin\noption to enable binary logging.\n\nTo list the binary log files on the server, use SHOW BINARY LOGS. To see which\nfiles they are reading, use SHOW SLAVE STATUS (or SHOW REPLICA STATUS from\nMariaDB 10.5.1). You can only delete the files that are older than the oldest\nfile that is used by the slaves.\n\nTo delete all binary log files, use RESET MASTER. To move to a new log file\n(for example if you want to remove the current log file), use FLUSH LOGS\nbefore you execute PURGE LOGS.\n\nIf the expire_logs_days server system variable is not set to 0, the server\nautomatically deletes binary log files after the given number of days. From\nMariaDB 10.6, the binlog_expire_logs_seconds variable allows more precise\ncontrol over binlog deletion, and takes precedence if both are non-zero.\n\nRequires the SUPER privilege or, from MariaDB 10.5.2, the BINLOG ADMIN\nprivilege, to run.\n\nExamples\n--------\n\nPURGE BINARY LOGS TO \'mariadb-bin.000063\';\n\nPURGE BINARY LOGS BEFORE \'2013-04-21\';\n\nPURGE BINARY LOGS BEFORE \'2013-04-22 09:55:22\';\n\nURL: https://mariadb.com/kb/en/purge-binary-logs/','','https://mariadb.com/kb/en/purge-binary-logs/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (407,26,'CACHE INDEX','Syntax\n------\n\nCACHE INDEX \n tbl_index_list [, tbl_index_list] ...\n IN key_cache_name\n\ntbl_index_list:\n tbl_name [[INDEX|KEY] (index_name[, index_name] ...)]\n\nDescription\n-----------\n\nThe CACHE INDEX statement assigns table indexes to a specific key cache. It is\nused only for MyISAM tables.\n\nA default key cache exists and cannot be destroyed. To create more key caches,\nthe key_buffer_size server system variable.\n\nThe associations between tables indexes and key caches are lost on server\nrestart. To recreate them automatically, it is necessary to configure caches\nin a configuration file and include some CACHE INDEX (and optionally LOAD\nINDEX) statements in the init file.\n\nExamples\n--------\n\nThe following statement assigns indexes from the tables t1, t2, and t3 to the\nkey cache named hot_cache:\n\nCACHE INDEX t1, t2, t3 IN hot_cache;\n+---------+--------------------+----------+----------+\n| Table | Op | Msg_type | Msg_text |\n+---------+--------------------+----------+----------+\n| test.t1 | assign_to_keycache | status | OK |\n| test.t2 | assign_to_keycache | status | OK |\n| test.t3 | assign_to_keycache | status | OK |\n+---------+--------------------+----------+----------+\n\nImplementation (for MyISAM)\n---------------------------\n\nNormally CACHE INDEX should not take a long time to execute. Internally it\'s\nimplemented the following way:\n\n* Find the right key cache (under LOCK_global_system_variables)\n* Open the table with a TL_READ_NO_INSERT lock.\n* Flush the original key cache for the given file (under key cache lock)\n* Flush the new key cache for the given file (safety)\n* Move the file to the new key cache (under file share lock)\n\nThe only possible long operations are getting the locks for the table and\nflushing the original key cache, if there were many key blocks for the file in\nit.\n\nWe plan to also add CACHE INDEX for Aria tables if there is a need for this.\n\nURL: https://mariadb.com/kb/en/cache-index/','','https://mariadb.com/kb/en/cache-index/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (408,26,'HELP Command','Syntax\n------\n\nHELP search_string\n\nDescription\n-----------\n\nThe HELP command can be used in any MariaDB client, such as the mariadb\ncommand-line client, to get basic syntax help and a short description for most\ncommands and functions.\n\nIf you provide an argument to the HELP command, the mariadb client uses it as\na search string to access server-side help. The proper operation of this\ncommand requires that the help tables in the mysql database be initialized\nwith help topic information.\n\nIf there is no match for the search string, the search fails. Use HELP\ncontents to see a list of the help categories:\n\nHELP contents\nYou asked for help about help category: \"Contents\"\nFor more information, type \'help <item>\', where <item> is one of the following\ncategories:\n Account Management\n Administration\n Compound Statements\n Data Definition\n Data Manipulation\n Data Types\n Functions\n Functions and Modifiers for Use with GROUP BY\n Geographic Features\n Help Metadata\n Language Structure\n Plugins\n Procedures\n Sequences\n Table Maintenance\n Transactions\n User-Defined Functions\n Utility\n\nIf a search string matches multiple items, MariaDB shows a list of matching\ntopics:\n\nHELP drop\nMany help items for your request exist.\nTo make a more specific request, please type \'help <item>\',\nwhere <item> is one of the following\ntopics:\n ALTER TABLE\n DROP DATABASE\n DROP EVENT\n DROP FUNCTION\n DROP FUNCTION UDF\n DROP INDEX\n DROP PACKAGE\n DROP PACKAGE BODY\n DROP PROCEDURE\n DROP ROLE\n DROP SEQUENCE\n DROP SERVER\n DROP TABLE\n DROP TRIGGER\n DROP USER\n DROP VIEW\n\nThen you can enter a topic as the search string to see the help entry for that\ntopic.\n\nThe help is provided with the MariaDB server and makes use of four help tables\nfound in the mysql database: help_relation, help_topic, help_category and\nhelp_keyword. These tables are populated by the mariadb-install-db or\nfill_help_table.sql scripts.\n\nURL: https://mariadb.com/kb/en/help-command/','','https://mariadb.com/kb/en/help-command/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (409,26,'KILL [CONNECTION | QUERY]','Syntax\n------\n\nKILL [HARD | SOFT] { {CONNECTION|QUERY} thread_id | QUERY ID query_id | USER\nuser_name }\n\nDescription\n-----------\n\nEach connection to mysqld runs in a separate thread. You can see which threads\nare running with the SHOW PROCESSLIST statement and kill a thread with the\nKILL thread_id statement. KILL allows the optional CONNECTION or QUERY\nmodifier:\n\n* KILL CONNECTION is the same as KILL with no\n modifier: It terminates the connection associated with the given thread or\nquery id.\n* KILL QUERY terminates the statement that the connection thread_id is\n currently executing, but leaves the connection itself intact.\n* KILL QUERY ID terminates the query by query_id, leaving the connection\nintact.\n\nIf a connection is terminated that has an active transaction, the transaction\nwill be rolled back. If only a query is killed, the current transaction will\nstay active. See also idle_transaction_timeout.\n\nIf you have the PROCESS privilege, you can see all threads. If you have the\nSUPER privilege, or, from MariaDB 10.5.2, the CONNECTION ADMIN privilege, you\ncan kill all threads and statements. Otherwise, you can see and kill only your\nown threads and statements.\n\nKilling queries that repair or create indexes on MyISAM and Aria tables may\nresult in corrupted tables. Use the SOFT option to avoid this!\n\nThe HARD option (default) kills a command as soon as possible. If you use\nSOFT, then critical operations that may leave a table in an inconsistent state\nwill not be interrupted. Such operations include REPAIR and INDEX creation for\nMyISAM and Aria tables (REPAIR TABLE, OPTIMIZE TABLE).\n\nKILL ... USER username will kill all connections/queries for a given user.\nUSER can be specified one of the following ways:\n\n* username (Kill without regard to hostname)\n* username@hostname\n* CURRENT_USER or CURRENT_USER()\n\nIf you specify a thread id and that thread does not exist, you get the\nfollowing error:\n\nERROR 1094 (HY000): Unknown thread id: <thread_id>\n\nIf you specify a query id that doesn\'t exist, you get the following error:\n\nERROR 1957 (HY000): Unknown query id: <query_id>\n\nHowever, if you specify a user name, no error is issued for non-connected (or\neven non-existing) users. To check if the connection/query has been killed,\nyou can use the ROW_COUNT() function.\n\nA client whose connection is killed receives the following error:\n\nERROR 1317 (70100): Query execution was interrupted\n\nTo obtain a list of existing sessions, use the SHOW PROCESSLIST statement or\nquery the Information Schema PROCESSLIST table.\n\nNote: You cannot use KILL with the Embedded MariaDB Server library because the\nembedded server merely runs inside the threads of the host application. It\ndoes not create any connection threads of its own.\n\nNote: You can also use mariadb-admin kill thread_id [,thread_id...] to kill\nconnections. To get a list of running queries, use mariadb-admin processlist.\nSee mariadb-admin.\n\nPercona Toolkit contains a program, pt-kill that can be used to automatically\nkill connections that match certain criteria. For example, it can be used to\nterminate idle connections, or connections that have been busy for more than\n60 seconds.\n\nURL: https://mariadb.com/kb/en/kill/','','https://mariadb.com/kb/en/kill/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (410,26,'LOAD INDEX','Syntax\n------\n\nLOAD INDEX INTO CACHE\n tbl_index_list [, tbl_index_list] ...\n\ntbl_index_list:\n tbl_name\n [[INDEX|KEY] (index_name[, index_name] ...)]\n [IGNORE LEAVES]\n\nDescription\n-----------\n\nThe LOAD INDEX INTO CACHE statement preloads a table index into the key cache\nto which it has been assigned by an explicit CACHE INDEX statement, or into\nthe default key cache otherwise. LOAD INDEX INTO CACHE is used only for MyISAM\nor Aria tables.\n\nThe IGNORE LEAVES modifier causes only blocks for the nonleaf nodes of the\nindex to be preloaded.\n\nURL: https://mariadb.com/kb/en/load-index/','','https://mariadb.com/kb/en/load-index/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (411,26,'RESET','Syntax\n------\n\nRESET reset_option [, reset_option] ...\n\nDescription\n-----------\n\nThe RESET statement is used to clear the state of various server operations.\nYou must have the RELOAD privilege to execute RESET.\n\nRESET acts as a stronger version of the FLUSH statement.\n\nThe different RESET options are:\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| SLAVE | Deletes all relay logs from the slave and |\n| [\"connection_name\"] [ALL] | reset the replication position in the master |\n| | binary log. |\n+---------------------------+------------------------------------------------+\n| MASTER | Deletes all old binary logs, makes the binary |\n| | index file (--log-bin-index) empty and |\n| | creates a new binary log file. This is |\n| | useful when you want to reset the master to |\n| | an initial state. If you want to just delete |\n| | old, not used binary logs, you should use the |\n| | PURGE BINARY LOGS command. |\n+---------------------------+------------------------------------------------+\n| QUERY CACHE | Removes all queries from the query cache. See |\n| | also FLUSH QUERY CACHE. |\n+---------------------------+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/reset/','','https://mariadb.com/kb/en/reset/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (412,26,'SHUTDOWN','Syntax\n------\n\nSHUTDOWN [WAIT FOR ALL { SLAVES | REPLICAS } ]\n\nDescription\n-----------\n\nThe SHUTDOWN command shuts the server down.\n\nWAIT FOR ALL REPLICAS / SLAVES\n------------------------------\n\nMariaDB starting with 10.4.4\n----------------------------\nThe WAIT FOR ALL SLAVES option was first added in MariaDB 10.4.4. WAIT FOR ALL\nREPLICAS has been a synonym since MariaDB 10.5.1.\n\nWhen a primary server is shutdown and it goes through the normal shutdown\nprocess, the primary kills client threads in random order. By default, the\nprimary also considers its binary log dump threads to be regular client\nthreads. As a consequence, the binary log dump threads can be killed while\nclient threads still exist, and this means that data can be written on the\nprimary during a normal shutdown that won\'t be replicated. This is true even\nif semi-synchronous replication is being used.\n\nIn MariaDB 10.4 and later, this problem can be solved by shutting down the\nserver with the SHUTDOWN command and by providing the WAIT FOR ALL\nREPLICAS/WAIT FOR ALL SLAVES option to the command. For example:\n\nSHUTDOWN WAIT FOR ALL REPLICAS;\n\nWhen the WAIT FOR ALL REPLICAS option is provided, the server only kills its\nbinary log dump threads after all client threads have been killed, and it only\ncompletes the shutdown after the last binary log has been sent to all\nconnected replicas.\n\nSee Replication Threads: Binary Log Dump Threads and the Shutdown Process for\nmore information.\n\nRequired Permissions\n--------------------\n\nOne must have a SHUTDOWN privilege (see GRANT) to use this command. It is the\nsame privilege one needs to use the mariadb-admin shutdown command.\n\nShutdown for Upgrades\n---------------------\n\nIf you are doing a shutdown to migrate to another major version of MariaDB,\nplease ensure that the innodb_fast_shutdown variable is not 2 (fast crash\nshutdown). The default of this variable is 1.\n\nExample\n-------\n\nThe following example shows how to create an event which turns off the server\nat a certain time:\n\nCREATE EVENT `test`.`shutd`\n ON SCHEDULE\n EVERY 1 DAY\n STARTS \'2014-01-01 20:00:00\'\n COMMENT \'Shutdown Maria when the office is closed\'\nDO BEGIN\n SHUTDOWN;\nEND;\n\nOther Ways to Stop mysqld\n-------------------------\n\nYou can use the mariadb-admin shutdown command to take down mysqld cleanly.\n\nYou can also use the system kill command on Unix with signal SIGTERM (15)\n\nkill -SIGTERM pid-of-mysqld-process\n\nYou can find the process number of the server process in the file that ends\nwith .pid in your data directory.\n\nThe above is identical to mariadb-admin shutdown.\n\nOn windows you should use:\n\nNET STOP MySQL\n\nURL: https://mariadb.com/kb/en/shutdown/','','https://mariadb.com/kb/en/shutdown/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (413,26,'USE [DATABASE]','Syntax\n------\n\nUSE db_name\n\nIn MariaDB 11.3 one can also use\n\nUSE DATABASE db_name;\n\nDescription\n-----------\n\nThe \'USE db_name\' statement tells MariaDB to use the db_name database as the\ndefault (current) database for subsequent statements. The database remains the\ndefault until the end of the session or another USE statement is issued:\n\nUSE db1;\nSELECT COUNT(*) FROM mytable; # selects from db1.mytable\nUSE db2;\nSELECT COUNT(*) FROM mytable; # selects from db2.mytable\n\nThe DATABASE() function (SCHEMA() is a synonym) returns the default database.\n\nAnother way to set the default database is specifying its name at mariadb\ncommand line client startup.\n\nOne cannot use USE DATABASE to a database one has no privileges to. The reason\nis that a user with no privileges to a database should not be able to know if\na database exists or not.\n\nURL: https://mariadb.com/kb/en/use-database/','','https://mariadb.com/kb/en/use-database/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (414,26,'SHOW FUNCTION CODE','Syntax\n------\n\nSHOW FUNCTION CODE func_name\n\nDescription\n-----------\n\nSHOW FUNCTION CODE shows a representation of the internal implementation of\nthe stored function.\n\nIt is similar to SHOW PROCEDURE CODE but for stored functions.\n\nURL: https://mariadb.com/kb/en/show-function-code/','','https://mariadb.com/kb/en/show-function-code/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (415,26,'SHOW COLLATION','Syntax\n------\n\nSHOW COLLATION\n [LIKE \'pattern\' | WHERE expr]\n\nDescription\n-----------\n\nThe output from SHOW COLLATION includes all available collations. The LIKE\nclause, if present on its own, indicates which collation names to match. The\nWHERE and LIKE clauses can be given to select rows using more general\nconditions, as discussed in Extended SHOW.\n\nThe same information can be queried from the Information Schema COLLATIONS\ntable.\n\nSee Setting Character Sets and Collations for details on specifying the\ncollation at the server, database, table and column levels.\n\nExamples\n--------\n\nSHOW COLLATION LIKE \'latin1%\';\n+-------------------------+---------+------+---------+----------+---------+\n| Collation | Charset | Id | Default | Compiled | Sortlen |\n+-------------------------+---------+------+---------+----------+---------+\n| latin1_german1_ci | latin1 | 5 | | Yes | 1 |\n| latin1_swedish_ci | latin1 | 8 | Yes | Yes | 1 |\n| latin1_danish_ci | latin1 | 15 | | Yes | 1 |\n| latin1_german2_ci | latin1 | 31 | | Yes | 2 |\n| latin1_bin | latin1 | 47 | | Yes | 1 |\n| latin1_general_ci | latin1 | 48 | | Yes | 1 |\n| latin1_general_cs | latin1 | 49 | | Yes | 1 |\n| latin1_spanish_ci | latin1 | 94 | | Yes | 1 |\n| latin1_swedish_nopad_ci | latin1 | 1032 | | Yes | 1 |\n| latin1_nopad_bin | latin1 | 1071 | | Yes | 1 |\n+-------------------------+---------+------+---------+----------+---------+\n\nSHOW COLLATION WHERE Sortlen LIKE \'8\' AND Charset LIKE \'utf8mb4\';\n+------------------------------+---------+------+---------+----------+---------\n\n| Collation | Charset | Id | Default | Compiled | Sortlen\n|\n+------------------------------+---------+------+---------+----------+---------\n\n| utf8mb4_unicode_ci | utf8mb4 | 224 | | Yes | 8\n|\n| utf8mb4_icelandic_ci | utf8mb4 | 225 | | Yes | 8\n|\n| utf8mb4_latvian_ci | utf8mb4 | 226 | | Yes | 8\n|\n| utf8mb4_romanian_ci | utf8mb4 | 227 | | Yes | 8\n|\n| utf8mb4_slovenian_ci | utf8mb4 | 228 | | Yes | 8\n|\n| utf8mb4_polish_ci | utf8mb4 | 229 | | Yes | 8\n|\n| utf8mb4_estonian_ci | utf8mb4 | 230 | | Yes | 8\n|\n| utf8mb4_spanish_ci | utf8mb4 | 231 | | Yes | 8\n|\n| utf8mb4_swedish_ci | utf8mb4 | 232 | | Yes | 8\n|\n| utf8mb4_turkish_ci | utf8mb4 | 233 | | Yes | 8\n|\n| utf8mb4_czech_ci | utf8mb4 | 234 | | Yes | 8\n|\n| utf8mb4_danish_ci | utf8mb4 | 235 | | Yes | 8\n|\n| utf8mb4_lithuanian_ci | utf8mb4 | 236 | | Yes | 8\n|\n| utf8mb4_slovak_ci | utf8mb4 | 237 | | Yes | 8\n|\n| utf8mb4_spanish2_ci | utf8mb4 | 238 | | Yes | 8\n|\n| utf8mb4_roman_ci | utf8mb4 | 239 | | Yes | 8\n|\n| utf8mb4_persian_ci | utf8mb4 | 240 | | Yes | 8\n|\n| utf8mb4_esperanto_ci | utf8mb4 | 241 | | Yes | 8\n|\n| utf8mb4_hungarian_ci | utf8mb4 | 242 | | Yes | 8\n|\n| utf8mb4_sinhala_ci | utf8mb4 | 243 | | Yes | 8\n|\n| utf8mb4_german2_ci | utf8mb4 | 244 | | Yes | 8\n|\n| utf8mb4_croatian_mysql561_ci | utf8mb4 | 245 | | Yes | 8\n|\n| utf8mb4_unicode_520_ci | utf8mb4 | 246 | | Yes | 8\n|\n| utf8mb4_vietnamese_ci | utf8mb4 | 247 | | Yes | 8\n|\n| utf8mb4_croatian_ci | utf8mb4 | 608 | | Yes | 8\n|\n| utf8mb4_myanmar_ci | utf8mb4 | 609 | | Yes | 8\n|\n| utf8mb4_unicode_nopad_ci | utf8mb4 | 1248 | | Yes | 8\n|\n| utf8mb4_unicode_520_nopad_ci | utf8mb4 | 1270 | | Yes | 8\n|\n+------------------------------+---------+------+---------+----------+---------\n\nURL: https://mariadb.com/kb/en/show-collation/','','https://mariadb.com/kb/en/show-collation/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (416,27,'DELETE','Syntax\n------\n\nSingle-table syntax:\n\nDELETE [LOW_PRIORITY] [QUICK] [IGNORE] \n FROM tbl_name [PARTITION (partition_list)]\n [FOR PORTION OF period FROM expr1 TO expr2]\n [WHERE where_condition]\n [ORDER BY ...]\n [LIMIT row_count]\n [RETURNING select_expr\n [, select_expr ...]]\n\nMultiple-table syntax:\n\nDELETE [LOW_PRIORITY] [QUICK] [IGNORE]\n tbl_name[.*] [, tbl_name[.*]] ...\n FROM table_references\n [WHERE where_condition]\n\nOr:\n\nDELETE [LOW_PRIORITY] [QUICK] [IGNORE]\n FROM tbl_name[.*] [, tbl_name[.*]] ...\n USING table_references\n [WHERE where_condition]\n\nTrimming history:\n\nDELETE HISTORY\n FROM tbl_name [PARTITION (partition_list)]\n [BEFORE SYSTEM_TIME [TIMESTAMP|TRANSACTION] expression]\n\nDescription\n-----------\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| LOW_PRIORITY | Wait until all SELECT\'s are done before |\n| | starting the statement. Used with storage |\n| | engines that uses table locking (MyISAM, Aria |\n| | etc). See HIGH_PRIORITY and LOW_PRIORITY |\n| | clauses for details. |\n+---------------------------+------------------------------------------------+\n| QUICK | Signal the storage engine that it should |\n| | expect that a lot of rows are deleted. The |\n| | storage engine engine can do things to speed |\n| | up the DELETE like ignoring merging of data |\n| | blocks until all rows are deleted from the |\n| | block (instead of when a block is half full). |\n| | This speeds up things at the expanse of lost |\n| | space in data blocks. At least MyISAM and |\n| | Aria support this feature. |\n+---------------------------+------------------------------------------------+\n| IGNORE | Don\'t stop the query even if a not-critical |\n| | error occurs (like data overflow). See How |\n| | IGNORE works for a full description. |\n+---------------------------+------------------------------------------------+\n\nFor the single-table syntax, the DELETE statement deletes rows from tbl_name\nand returns a count of the number of deleted rows. This count can be obtained\nby calling the ROW_COUNT() function. The WHERE clause, if given, specifies the\nconditions that identify which rows to delete. With no WHERE clause, all rows\nare deleted. If the ORDER BY clause is specified, the rows are deleted in the\norder that is specified. The LIMIT clause places a limit on the number of rows\nthat can be deleted.\n\nFor the multiple-table syntax, DELETE deletes from each tbl_name the rows that\nsatisfy the conditions. In this case, ORDER BY and LIMIT> cannot be used. A\nDELETE can also reference tables which are located in different databases; see\nIdentifier Qualifiers for the syntax.\n\nwhere_condition is an expression that evaluates to true for each row to be\ndeleted. It is specified as described in SELECT.\n\nCurrently, you cannot delete from a table and select from the same table in a\nsubquery.\n\nYou need the DELETE privilege on a table to delete rows from it. You need only\nthe SELECT privilege for any columns that are only read, such as those named\nin the WHERE clause. See GRANT.\n\nAs stated, a DELETE statement with no WHERE clause deletes all rows. A faster\nway to do this, when you do not need to know the number of deleted rows, is to\nuse TRUNCATE TABLE. However, within a transaction or if you have a lock on the\ntable, TRUNCATE TABLE cannot be used whereas DELETE can. See TRUNCATE TABLE,\nand LOCK.\n\nPARTITION\n---------\n\nSee Partition Pruning and Selection for details.\n\nFOR PORTION OF\n--------------\n\nMariaDB starting with 10.4.3\n----------------------------\nSee Application Time Periods - Deletion by Portion.\n\nRETURNING\n---------\n\nIt is possible to return a resultset of the deleted rows for a single table to\nthe client by using the syntax DELETE ... RETURNING select_expr [,\nselect_expr2 ...]]\n\nAny of SQL expression that can be calculated from a single row fields is\nallowed. Subqueries are allowed. The AS keyword is allowed, so it is possible\nto use aliases.\n\nThe use of aggregate functions is not allowed. RETURNING cannot be used in\nmulti-table DELETEs.\n\nMariaDB starting with 10.3.1\n----------------------------\n\nSame Source and Target Table\n----------------------------\n\nUntil MariaDB 10.3.1, deleting from a table with the same source and target\nwas not possible. From MariaDB 10.3.1, this is now possible. For example:\n\nDELETE FROM t1 WHERE c1 IN (SELECT b.c1 FROM t1 b WHERE b.c2=0);\n\nMariaDB starting with 10.3.4\n----------------------------\n\nDELETE HISTORY\n--------------\n\nOne can use DELETE HISTORY to delete historical information from\nSystem-versioned tables.\n\nExamples\n--------\n\nHow to use the ORDER BY and LIMIT clauses:\n\nDELETE FROM page_hit ORDER BY timestamp LIMIT 1000000;\n\nHow to use the RETURNING clause:\n\nDELETE FROM t RETURNING f1;\n+------+\n| f1 |\n+------+\n| 5 |\n| 50 |\n| 500 |\n+------+\n\nThe following statement joins two tables: one is only used to satisfy a WHERE\ncondition, but no row is deleted from it; rows from the other table are\ndeleted, instead.\n\nDELETE post FROM blog INNER JOIN post WHERE blog.id = post.blog_id;\n\nDeleting from the Same Source and Target\n----------------------------------------\n\nCREATE TABLE t1 (c1 INT, c2 INT);\nDELETE FROM t1 WHERE c1 IN (SELECT b.c1 FROM t1 b WHERE b.c2=0);\n\nUntil MariaDB 10.3.1, this returned:\n\nERROR 1093 (HY000): Table \'t1\' is specified twice, both as a target for\n\'DELETE\' \n and as a separate source for\n\nFrom MariaDB 10.3.1:\n\nQuery OK, 0 rows affected (0.00 sec)\n\nURL: https://mariadb.com/kb/en/delete/','','https://mariadb.com/kb/en/delete/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (417,27,'REPLACE','Syntax\n------\n\nREPLACE [LOW_PRIORITY | DELAYED]\n [INTO] tbl_name [PARTITION (partition_list)] [(col,...)]\n {VALUES | VALUE} ({expr | DEFAULT},...),(...),...\n[RETURNING select_expr \n [, select_expr ...]]\n\nOr:\n\nREPLACE [LOW_PRIORITY | DELAYED]\n [INTO] tbl_name [PARTITION (partition_list)]\n SET col={expr | DEFAULT}, ...\n[RETURNING select_expr \n [, select_expr ...]]\n\nOr:\n\nREPLACE [LOW_PRIORITY | DELAYED]\n [INTO] tbl_name [PARTITION (partition_list)] [(col,...)]\n SELECT ...\n[RETURNING select_expr \n [, select_expr ...]]\n\nDescription\n-----------\n\nREPLACE works exactly like INSERT, except that if an old row in the table has\nthe same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row\nis deleted before the new row is inserted. If the table has more than one\nUNIQUE keys, it is possible that the new row conflicts with more than one row.\nIn this case, all conflicting rows will be deleted.\n\nThe table name can be specified in the form db_name.tbl_name or, if a default\ndatabase is selected, in the form tbl_name (see Identifier Qualifiers). This\nallows to use REPLACE ... SELECT to copy rows between different databases.\n\nMariaDB starting with 10.5.0\n----------------------------\nThe RETURNING clause was introduced in MariaDB 10.5.0\n\nBasically it works like this:\n\nBEGIN;\nSELECT 1 FROM t1 WHERE key=# FOR UPDATE;\nIF found-row\n DELETE FROM t1 WHERE key=# ;\nENDIF\nINSERT INTO t1 VALUES (...);\nEND;\n\nThe above can be replaced with:\n\nREPLACE INTO t1 VALUES (...)\n\nREPLACE is a MariaDB/MySQL extension to the SQL standard. It either inserts,\nor deletes and inserts. For other MariaDB/MySQL extensions to standard SQL ---\nthat also handle duplicate values --- see IGNORE and INSERT ON DUPLICATE KEY\nUPDATE.\n\nNote that unless the table has a PRIMARY KEY or UNIQUE index, using a REPLACE\nstatement makes no sense. It becomes equivalent to INSERT, because there is no\nindex to be used to determine whether a new row duplicates another.\n\nValues for all columns are taken from the values sSee Partition Pruning and\nSelection for details.pecified in the REPLACE statement. Any missing columns\nare set to their default values, just as happens for INSERT. You cannot refer\nto values from the current row and use them in the new row. If you use an\nassignment such as \'SET col = col + 1\', the reference to the column name on\nthe right hand side is treated as DEFAULT(col), so the assignment is\nequivalent to \'SET col = DEFAULT(col) + 1\'.\n\nTo use REPLACE, you must have both the INSERT and DELETE privileges for the\ntable.\n\nThere are some gotchas you should be aware of, before using REPLACE:\n\n* If there is an AUTO_INCREMENT field, a new value will be generated.\n* If there are foreign keys, ON DELETE action will be activated by REPLACE.\n* Triggers on DELETE and INSERT will be activated by REPLACE.\n\nTo avoid some of these behaviors, you can use INSERT ... ON DUPLICATE KEY\nUPDATE.\n\nThis statement activates INSERT and DELETE triggers. See Trigger Overview for\ndetails.\n\nPARTITION\n---------\n\nSee Partition Pruning and Selection for details.\n\nREPLACE RETURNING\n-----------------\n\nREPLACE ... RETURNING returns a resultset of the replaced rows.\n\nThis returns the listed columns for all the rows that are replaced, or\nalternatively, the specified SELECT expression. Any SQL expressions which can\nbe calculated can be used in the select expression for the RETURNING clause,\nincluding virtual columns and aliases, expressions which use various operators\nsuch as bitwise, logical and arithmetic operators, string functions, date-time\nfunctions, numeric functions, control flow functions, secondary functions and\nstored functions. Along with this, statements which have subqueries and\nprepared statements can also be used.\n\nExamples\n--------\n\nSimple REPLACE statement\n\nREPLACE INTO t2 VALUES (1,\'Leopard\'),(2,\'Dog\') RETURNING id2, id2+id2 \nas Total ,id2|id2, id2&&id2;\n+-----+-------+---------+----------+\n| id2 | Total | id2|id2 | id2&&id2 |\n+-----+-------+---------+----------+\n| 1 | 2 | 1 | 1 |\n| 2 | 4 | 2 | 1 |\n+-----+-------+---------+----------+\n\nUsing stored functions in RETURNING\n\nDELIMITER |\nCREATE FUNCTION f(arg INT) RETURNS INT\n BEGIN\n RETURN (SELECT arg+arg);\n END|\n\nDELIMITER ;\nPREPARE stmt FROM \"REPLACE INTO t2 SET id2=3, animal2=\'Fox\' RETURNING f2(id2),\nUPPER(animal2)\";\n\nEXECUTE stmt;\n+---------+----------------+\n| f2(id2) | UPPER(animal2) |\n+---------+----------------+\n| 6 | FOX |\n+---------+----------------+\n\nSubqueries in the statement\n\nREPLACE INTO t1 SELECT * FROM t2 RETURNING (SELECT id2 FROM t2 WHERE \nid2 IN (SELECT id2 FROM t2 WHERE id2=1)) AS new_id;\n+--------+\n| new_id |\n+--------+\n| 1 |\n| 1 |\n| 1 |\n| 1 |\n+--------+\n\nSubqueries in the RETURNING clause that return more than one row or column\ncannot be used..\n\nAggregate functions cannot be used in the RETURNING clause. Since aggregate\nfunctions work on a set of values and if the purpose is to get the row count,\nROW_COUNT() with SELECT can be used, or it can be used in REPLACE...SEL==\nDescription\n\nREPLACE ... RETURNING returns a resultset of the replaced rows.\n\nThis returns the listed columns for all the rows that are replaced, or\nalternatively, the specified SELECT expression. Any SQL expressions which can\nbe calculated can be used in the select expression for the RETURNING clause,\nincluding virtual columns and aliases, expressions which use various operators\nsuch as bitwise, logical and arithmetic operators, string functions, date-time\nfunctions, numeric functions, control flow functions, secondary functions and\nstored functions. Along with this, statements which have subqueries and\nprepared statements can also be used.\n\nExamples\n--------\n\nSimple REPLACE statement\n\nREPLACE INTO t2 VALUES (1,\'Leopard\'),(2,\'Dog\') RETURNING id2, id2+id2 \nas Total ,id2|id2, id2&&id2;\n+-----+-------+---------+----------+\n| id2 | Total | id2|id2 | id2&&id2 |\n+-----+-------+---------+----------+\n| 1 | 2 | 1 | 1 |\n| 2 | 4 | 2 | 1 |\n+-----+-------+---------+----------+\n\nUsing stored functions in RETURNING\n\nDELIMITER |\nCREATE FUNCTION f(arg INT) RETURNS INT\n BEGIN\n RETURN (SELECT arg+arg);\n END|\n\nDELIMITER ;\nPREPARE stmt FROM \"REPLACE INTO t2 SET id2=3, animal2=\'Fox\' RETURNING f2(id2),\nUPPER(animal2)\";\n\nEXECUTE stmt;\n+---------+----------------+\n| f2(id2) | UPPER(animal2) |\n+---------+----------------+\n| 6 | FOX |\n+---------+----------------+\n\nSubqueries in the statement\n\nREPLACE INTO t1 SELECT * FROM t2 RETURNING (SELECT id2 FROM t2 WHERE \nid2 IN (SELECT id2 FROM t2 WHERE id2=1)) AS new_id;\n+--------+\n| new_id |\n+--------+\n| 1 |\n| 1 |\n| 1 |\n| 1 |\n+--------+\n\nSubqueries in the RETURNING clause that return more than one row or column\ncannot be used..\n\nAggregate functions cannot be used in the RETURNING clause. Since aggregate\nfunctions work on a set of values and if the purpose is to get the row count,\nROW_COUNT() with SELECT can be used, or it can be used in\nREPLACE...SELECT...RETURNING if the table in the RETURNING clause is not the\nsame as the REPLACE table. ECT...RETURNING if the table in the RETURNING\nclause is not the same as the REPLACE table.\n\nURL: https://mariadb.com/kb/en/replace/','','https://mariadb.com/kb/en/replace/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (418,27,'UPDATE','Syntax\n------\n\nSingle-table syntax:\n\nUPDATE [LOW_PRIORITY] [IGNORE] table_reference \n [PARTITION (partition_list)]\n [FOR PORTION OF period FROM expr1 TO expr2]\n SET col1={expr1|DEFAULT} [,col2={expr2|DEFAULT}] ...\n [WHERE where_condition]\n [ORDER BY ...]\n [LIMIT row_count]\n\nMultiple-table syntax:\n\nUPDATE [LOW_PRIORITY] [IGNORE] table_references\n SET col1={expr1|DEFAULT} [, col2={expr2|DEFAULT}] ...\n [WHERE where_condition]\n\nDescription\n-----------\n\nFor the single-table syntax, the UPDATE statement updates columns of existing\nrows in the named table with new values. The SET clause indicates which\ncolumns to modify and the values they should be given. Each value can be given\nas an expression, or the keyword DEFAULT to set a column explicitly to its\ndefault value. The WHERE clause, if given, specifies the conditions that\nidentify which rows to update. With no WHERE clause, all rows are updated. If\nthe ORDER BY clause is specified, the rows are updated in the order that is\nspecified. The LIMIT clause places a limit on the number of rows that can be\nupdated.\n\nUntil MariaDB 10.3.2, for the multiple-table syntax, UPDATE updates rows in\neach table named in table_references that satisfy the conditions. In this\ncase, ORDER BY and LIMIT cannot be used. This restriction was lifted in\nMariaDB 10.3.2 and both clauses can be used with multiple-table updates. An\nUPDATE can also reference tables which are located in different databases; see\nIdentifier Qualifiers for the syntax.\n\nwhere_condition is an expression that evaluates to true for each row to be\nupdated.\n\ntable_references and where_condition are as specified as described in SELECT.\n\nFor single-table updates, assignments are evaluated in left-to-right order,\nwhile for multi-table updates, there is no guarantee of a particular order. If\nthe SIMULTANEOUS_ASSIGNMENT sql_mode (available from MariaDB 10.3.5) is set,\nUPDATE statements evaluate all assignments simultaneously.\n\nYou need the UPDATE privilege only for columns referenced in an UPDATE that\nare actually updated. You need only the SELECT privilege for any columns that\nare read but not modified. See GRANT.\n\nThe UPDATE statement supports the following modifiers:\n\n* If you use the LOW_PRIORITY keyword, execution of\n the UPDATE is delayed until no other clients are reading from\n the table. This affects only storage engines that use only table-level\n locking (MyISAM, MEMORY, MERGE). See HIGH_PRIORITY and LOW_PRIORITY clauses\nfor details.\n* If you use the IGNORE keyword, the update statement does \n not abort even if errors occur during the update. Rows for which\n duplicate-key conflicts occur are not updated. Rows for which columns are\n updated to values that would cause data conversion errors are updated to the\n closest valid values instead.\n\nPARTITION\n---------\n\nSee Partition Pruning and Selection for details.\n\nFOR PORTION OF\n--------------\n\nMariaDB starting with 10.4.3\n----------------------------\nSee Application Time Periods - Updating by Portion.\n\nUPDATE Statements With the Same Source and Target\n-------------------------------------------------\n\nMariaDB starting with 10.3.2\n----------------------------\nFrom MariaDB 10.3.2, UPDATE statements may have the same source and target.\n\nFor example, given the following table:\n\nDROP TABLE t1;\nCREATE TABLE t1 (c1 INT, c2 INT);\nINSERT INTO t1 VALUES (10,10), (20,20);\n\nUntil MariaDB 10.3.1, the following UPDATE statement would not work:\n\nUPDATE t1 SET c1=c1+1 WHERE c2=(SELECT MAX(c2) FROM t1);\nERROR 1093 (HY000): Table \'t1\' is specified twice, \n both as a target for \'UPDATE\' and as a separate source for data\n\nFrom MariaDB 10.3.2, the statement executes successfully:\n\nUPDATE t1 SET c1=c1+1 WHERE c2=(SELECT MAX(c2) FROM t1);\n\nSELECT * FROM t1;\n+------+------+\n| c1 | c2 |\n+------+------+\n| 10 | 10 |\n| 21 | 20 |\n+------+------+\n\nExample\n-------\n\nSingle-table syntax:\n\nUPDATE table_name SET column1 = value1, column2 = value2 WHERE id=100;\n\nMultiple-table syntax:\n\nUPDATE tab1, tab2 SET tab1.column1 = value1, tab1.column2 = value2 WHERE\ntab1.id = tab2.id;\n\nURL: https://mariadb.com/kb/en/update/','','https://mariadb.com/kb/en/update/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (419,27,'IGNORE','The IGNORE option tells the server to ignore some common errors.\n\nIGNORE can be used with the following statements:\n\n* DELETE\n* INSERT (see also INSERT IGNORE)\n* LOAD DATA INFILE\n* UPDATE\n* ALTER TABLE\n* CREATE TABLE ... SELECT\n* INSERT ... SELECT\n\nThe logic used:\n\n* Variables out of ranges are replaced with the maximum/minimum value.\n\n* SQL_MODEs STRICT_TRANS_TABLES, STRICT_ALL_TABLES, NO_ZERO_IN_DATE,\nNO_ZERO_DATE are ignored.\n\n* Inserting NULL in a NOT NULL field will insert 0 ( in a numerical\n field), 0000-00-00 ( in a date field) or an empty string ( in a character\n field).\n\n* Rows that cause a duplicate key error or break a foreign key constraint are\n not inserted, updated, or deleted.\n\nThe following errors are ignored:\n\n+---------------------+---------------------------------+--------------------+\n| Error number | Symbolic error name | Description |\n+---------------------+---------------------------------+--------------------+\n| 1022 | ER_DUP_KEY | Can\'t write; |\n| | | duplicate key in |\n| | | table \'%s\' |\n+---------------------+---------------------------------+--------------------+\n| 1048 | ER_BAD_NULL_ERROR | Column \'%s\' |\n| | | cannot be null |\n+---------------------+---------------------------------+--------------------+\n| 1062 | ER_DUP_ENTRY | Duplicate entry |\n| | | \'%s\' for key %d |\n+---------------------+---------------------------------+--------------------+\n| 1242 | ER_SUBQUERY_NO_1_ROW | Subquery returns |\n| | | more than 1 row |\n+---------------------+---------------------------------+--------------------+\n| 1264 | ER_WARN_DATA_OUT_OF_RANGE | Out of range |\n| | | value for column |\n| | | \'%s\' at row %ld |\n+---------------------+---------------------------------+--------------------+\n| 1265 | WARN_DATA_TRUNCATED | Data truncated |\n| | | for column \'%s\' |\n| | | at row %ld |\n+---------------------+---------------------------------+--------------------+\n| 1292 | ER_TRUNCATED_WRONG_VALUE | Truncated |\n| | | incorrect %s |\n| | | value: \'%s\' |\n+---------------------+---------------------------------+--------------------+\n| 1366 | ER_TRUNCATED_WRONG_VALUE_FOR_FI | Incorrect integer |\n| | LD | value |\n+---------------------+---------------------------------+--------------------+\n| 1369 | ER_VIEW_CHECK_FAILED | CHECK OPTION |\n| | | failed \'%s.%s\' |\n+---------------------+---------------------------------+--------------------+\n| 1451 | ER_ROW_IS_REFERENCED_2 | Cannot delete or |\n| | | update a parent |\n| | | row |\n+---------------------+---------------------------------+--------------------+\n| 1452 | ER_NO_REFERENCED_ROW_2 | Cannot add or |\n| | | update a child |\n| | | row: a foreign |\n| | | key constraint |\n| | | fails (%s) |\n+---------------------+---------------------------------+--------------------+\n| 1526 | ER_NO_PARTITION_FOR_GIVEN_VALUE | Table has no |\n| | | partition for |\n| | | value %s |\n+---------------------+---------------------------------+--------------------+\n| 1586 | ER_DUP_ENTRY_WITH_KEY_NAME | Duplicate entry |\n| | | \'%s\' for key \'%s\' |\n+---------------------+---------------------------------+--------------------+\n| 1591 | ER_NO_PARTITION_FOR_GIVEN_VALUE | Table has no |\n| | SILENT | partition for |\n| | | some existing |\n| | | values |\n+---------------------+---------------------------------+--------------------+\n| 1748 | ER_ROW_DOES_NOT_MATCH_GIVEN_PAR | Found a row not |\n| | ITION_SET | matching the |\n| | | given partition |\n| | | set |\n+---------------------+---------------------------------+--------------------+\n\nIgnored errors normally generate a warning.\n\nA property of the IGNORE clause consists in causing transactional engines and\nnon-transactional engines (like InnoDB and Aria) to behave the same way. For\nexample, normally a multi-row insert which tries to violate a UNIQUE contraint\nis completely rolled back on InnoDB, but might be partially executed on Aria.\nWith the IGNORE clause, the statement will be partially executed in both\nengines.\n\nDuplicate key errors also generate warnings. The OLD_MODE server variable can\nbe used to prevent this.\n\nURL: https://mariadb.com/kb/en/ignore/','','https://mariadb.com/kb/en/ignore/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (420,27,'SELECT','Syntax\n------\n\nSELECT\n [ALL | DISTINCT | DISTINCTROW]\n [HIGH_PRIORITY]\n [STRAIGHT_JOIN]\n [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]\n [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]\n select_expr [, select_expr ...]\n [ FROM table_references\n [WHERE where_condition]\n [GROUP BY {col_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]]\n [HAVING where_condition]\n [ORDER BY {col_name | expr | position} [ASC | DESC], ...]\n [LIMIT {[offset,] row_count | row_count OFFSET offset [ROWS EXAMINED\nrows_limit] } |\n [OFFSET start { ROW | ROWS }]\n [FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES }]\n]\n procedure|[PROCEDURE procedure_name(argument_list)]\n [INTO OUTFILE \'file_name\' [CHARACTER SET charset_name] [export_options] |\n INTO DUMPFILE \'file_name\' | INTO var_name [, var_name] ]\n [FOR UPDATE lock_option | LOCK IN SHARE MODE lock_option]\nexport_options:\n [{FIELDS | COLUMNS}\n [TERMINATED BY \'string\']\n [[OPTIONALLY] ENCLOSED BY \'char\']\n [ESCAPED BY \'char\']\n ]\n [LINES\n [STARTING BY \'string\']\n [TERMINATED BY \'string\']\n ]\nlock_option:\n [WAIT n | NOWAIT | SKIP LOCKED]\n\nDescription\n-----------\n\nSELECT is used to retrieve rows selected from one or more tables, and can\ninclude UNION statements and subqueries.\n\n* Each select_expr expression indicates a column or data that you want to\nretrieve. You\nmust have at least one select expression. See Select Expressions below.\n\n* The FROM clause indicates the table or tables from which to retrieve rows.\nUse either a single table name or a JOIN expression. See JOIN\nfor details. If no table is involved, FROM DUAL can be specified.\n\n* Each table can also be specified as db_name.tabl_name. Each column can also\nbe specified as tbl_name.col_name or even db_name.tbl_name.col_name. This\nallows one to write queries which involve multiple databases. See Identifier\nQualifiers for syntax details.\n\n* The WHERE clause, if given, indicates the condition or\n conditions that rows must satisfy to be selected.\n where_condition is an expression that evaluates to true for\n each row to be selected. The statement selects all rows if there is no WHERE\n clause.\nIn the WHERE clause, you can use any of the functions and\n operators that MariaDB supports, except for aggregate (summary) functions.\nSee Functions and Operators and Functions and Modifiers for use with GROUP BY\n(aggregate).\n\n* Use the ORDER BY clause to order the results.\n\n* Use the LIMIT clause allows you to restrict the results to only\na certain number of rows, optionally with an offset.\n\n* Use the GROUP BY and HAVING clauses to group\nrows together when they have columns or computed values in common.\n\nSELECT can also be used to retrieve rows computed without reference to any\ntable.\n\nSelect Expressions\n------------------\n\nA SELECT statement must contain one or more select expressions, separated by\ncommas. Each select expression can be one of the following:\n\n* The name of a column.\n* Any expression using functions and operators.\n* * to select all columns from all tables in the FROM clause.\n* tbl_name.* to select all columns from just the table tbl_name.\n\nWhen specifying a column, you can either use just the column name or qualify\nthe column name with the name of the table using tbl_name.col_name. The\nqualified form is useful if you are joining multiple tables in the FROM\nclause. If you do not qualify the column names when selecting from multiple\ntables, MariaDB will try to find the column in each table. It is an error if\nthat column name exists in multiple tables.\n\nYou can quote column names using backticks. If you are qualifying column names\nwith table names, quote each part separately as `tbl_name`.`col_name`.\n\nIf you use any grouping functions in any of the select expressions, all rows\nin your results will be implicitly grouped, as if you had used GROUP BY NULL.\n\nDISTINCT\n--------\n\nA query may produce some identical rows. By default, all rows are retrieved,\neven when their values are the same. To explicitly specify that you want to\nretrieve identical rows, use the ALL option. If you want duplicates to be\nremoved from the resultset, use the DISTINCT option. DISTINCTROW is a synonym\nfor DISTINCT. See also COUNT DISTINCT and SELECT UNIQUE in Oracle mode.\n\nINTO\n----\n\nThe INTO clause is used to specify that the query results should be written to\na file or variable.\n\n* SELECT INTO OUTFILE - formatting and writing the result to an external file.\n* SELECT INTO DUMPFILE - binary-safe writing of the unformatted results to an\nexternal file.\n* SELECT INTO Variable - selecting and setting variables.\n\nThe reverse of SELECT INTO OUTFILE is LOAD DATA.\n\nLIMIT\n-----\n\nRestricts the number of returned rows. See LIMIT and LIMIT ROWS EXAMINED for\ndetails.\n\nLOCK IN SHARE MODE/FOR UPDATE\n-----------------------------\n\nSee LOCK IN SHARE MODE and FOR UPDATE for details on the respective locking\nclauses.\n\nOFFSET ... FETCH\n----------------\n\nMariaDB starting with 10.6\n--------------------------\nSee SELECT ... OFFSET ... FETCH.\n\nORDER BY\n--------\n\nOrder a resultset. See ORDER BY for details.\n\nPARTITION\n---------\n\nSpecifies to the optimizer which partitions are relevant for the query. Other\npartitions will not be read. See Partition Pruning and Selection for details.\n\nPROCEDURE\n---------\n\nPasses the whole result set to a C Procedure. See PROCEDURE and PROCEDURE\nANALYSE (the only built-in procedure not requiring the server to be\nrecompiled).\n\nSKIP LOCKED\n-----------\n\nMariaDB starting with 10.6\n--------------------------\nThe SKIP LOCKED clause was introduced in MariaDB 10.6.0.\n\nThis causes those rows that couldn\'t be locked (LOCK IN SHARE MODE or FOR\nUPDATE) to be excluded from the result set. An explicit NOWAIT is implied\nhere. This is only implemented on InnoDB tables and ignored otherwise.\n\nSQL_CALC_FOUND_ROWS\n-------------------\n\nWhen SQL_CALC_FOUND_ROWS is used, then MariaDB will calculate how many rows\nwould have been in the result, if there would be no LIMIT clause. The result\ncan be found by calling the function FOUND_ROWS() in your next sql statement.\n\nmax_statement_time clause\n-------------------------\n\nBy using max_statement_time in conjunction with SET STATEMENT, it is possible\nto limit the execution time of individual queries. For example:\n\nSET STATEMENT max_statement_time=100 FOR \n SELECT field1 FROM table_name ORDER BY field1;\n\nWAIT/NOWAIT\n-----------\n\nSet the lock wait timeout. See WAIT and NOWAIT.\n\nExamples\n--------\n\nSELECT f1,f2 FROM t1 WHERE (f3<=10) AND (f4=\'y\');\n\nSee Getting Data from MariaDB (Beginner tutorial), or the various\nsub-articles, for more examples.\n\nURL: https://mariadb.com/kb/en/select/','','https://mariadb.com/kb/en/select/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (421,27,'JOIN Syntax','Description\n-----------\n\nMariaDB supports the following JOIN syntaxes for the table_references part of\nSELECT statements and multiple-table DELETE and UPDATE statements:\n\ntable_references:\n table_reference [, table_reference] ...\n\ntable_reference:\n table_factor\n | join_table\n\ntable_factor:\n tbl_name [PARTITION (partition_list)]\n [query_system_time_period_specification] [[AS] alias] [index_hint_list]\n | table_subquery [query_system_time_period_specification] [AS] alias\n | ( table_references )\n | { ON table_reference LEFT OUTER JOIN table_reference\n ON conditional_expr }\n\njoin_table:\n table_reference [INNER | CROSS] JOIN table_factor [join_condition]\n | table_reference STRAIGHT_JOIN table_factor\n | table_reference STRAIGHT_JOIN table_factor ON conditional_expr\n | table_reference {LEFT|RIGHT} [OUTER] JOIN table_reference join_condition\n | table_reference NATURAL [{LEFT|RIGHT} [OUTER]] JOIN table_factor\n\njoin_condition:\n ON conditional_expr\n | USING (column_list)\n\nquery_system_time_period_specification:\n FOR SYSTEM_TIME AS OF point_in_time\n | FOR SYSTEM_TIME BETWEEN point_in_time AND point_in_time\n | FOR SYSTEM_TIME FROM point_in_time TO point_in_time\n | FOR SYSTEM_TIME ALL\n\npoint_in_time:\n [TIMESTAMP] expression\n | TRANSACTION expression\n\nindex_hint_list:\n index_hint [, index_hint] ...\n\nindex_hint:\n USE {INDEX|KEY}\n [{FOR {JOIN|ORDER BY|GROUP BY}] ([index_list])\n | IGNORE {INDEX|KEY}\n [{FOR {JOIN|ORDER BY|GROUP BY}] (index_list)\n | FORCE {INDEX|KEY}\n [{FOR {JOIN|ORDER BY|GROUP BY}] (index_list)\n\nindex_list:\n index_name [, index_name] ...\n\nA table reference is also known as a join expression.\n\nEach table can also be specified as db_name.tabl_name. This allows to write\nqueries which involve multiple databases. See Identifier Qualifiers for syntax\ndetails.\n\nThe syntax of table_factor is extended in comparison with the SQL Standard.\nThe latter accepts only table_reference, not a list of them inside a pair of\nparentheses.\n\nThis is a conservative extension if we consider each comma in a list of\ntable_reference items as equivalent to an inner join. For example:\n\nSELECT * FROM t1 LEFT JOIN (t2, t3, t4)\n ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)\n\nis equivalent to:\n\nSELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)\n ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)\n\nIn MariaDB, CROSS JOIN is a syntactic equivalent to INNER JOIN (they can\nreplace each other). In standard SQL, they are not equivalent. INNER JOIN is\nused with an ON clause, CROSS JOIN is used otherwise.\n\nIn general, parentheses can be ignored in join expressions containing only\ninner join operations. MariaDB also supports nested joins (see\nhttp://dev.mysql.com/doc/refman/5.1/en/nested-join-optimization.html).\n\nSee System-versioned tables for more information about FOR SYSTEM_TIME syntax.\n\nIndex hints can be specified to affect how the MariaDB optimizer makes use of\nindexes. For more information, see How to force query plans.\n\nExamples\n--------\n\nSELECT left_tbl.*\n FROM left_tbl LEFT JOIN right_tbl ON left_tbl.id = right_tbl.id\n WHERE right_tbl.id IS NULL;\n\nURL: https://mariadb.com/kb/en/join-syntax/','','https://mariadb.com/kb/en/join-syntax/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (422,27,'Scalar Subqueries','A scalar subquery is a subquery that returns a single value. This is the\nsimplest form of a subquery, and can be used in most places a literal or\nsingle column value is valid.\n\nThe data type, length and character set and collation are all taken from the\nresult returned by the subquery. The result of a subquery can always be NULL,\nthat is, no result returned. Even if the original value is defined as NOT\nNULL, this is disregarded.\n\nA subquery cannot be used where only a literal is expected, for example LOAD\nDATA INFILE expects a literal string containing the file name, and LIMIT\nrequires a literal integer.\n\nExamples\n--------\n\nCREATE TABLE sq1 (num TINYINT);\n\nCREATE TABLE sq2 (num TINYINT);\n\nINSERT INTO sq1 VALUES (1);\n\nINSERT INTO sq2 VALUES (10* (SELECT num FROM sq1));\n\nSELECT * FROM sq2;\n+------+\n| num |\n+------+\n| 10 |\n+------+\n\nInserting a second row means the subquery is no longer a scalar, and this\nparticular query is not valid:\n\nINSERT INTO sq1 VALUES (2);\n\nINSERT INTO sq2 VALUES (10* (SELECT num FROM sq1));\nERROR 1242 (21000): Subquery returns more than 1 row\n\nNo rows in the subquery, so the scalar is NULL:\n\nINSERT INTO sq2 VALUES (10* (SELECT num FROM sq3 WHERE num=\'3\'));\n\nSELECT * FROM sq2;\n+------+\n| num |\n+------+\n| 10 |\n| NULL |\n+------+\n\nA more traditional scalar subquery, as part of a WHERE clause:\n\nSELECT * FROM sq1 WHERE num = (SELECT MAX(num)/10 FROM sq2); \n+------+\n| num |\n+------+\n| 1 |\n+------+\n\nURL: https://mariadb.com/kb/en/subqueries-scalar-subqueries/','','https://mariadb.com/kb/en/subqueries-scalar-subqueries/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (423,27,'Row Subqueries','A row subquery is a subquery returning a single row, as opposed to a scalar\nsubquery, which returns a single column from a row, or a literal.\n\nExamples\n--------\n\nCREATE TABLE staff (name VARCHAR(10), age TINYINT);\n\nCREATE TABLE customer (name VARCHAR(10), age TINYINT);\n\nINSERT INTO staff VALUES (\'Bilhah\',37), (\'Valerius\',61), (\'Maia\',25);\n\nINSERT INTO customer VALUES (\'Thanasis\',48), (\'Valerius\',61), (\'Brion\',51);\n\nSELECT * FROM staff WHERE (name,age) = (SELECT name,age FROM customer WHERE\nname=\'Valerius\');\n+----------+------+\n| name | age |\n+----------+------+\n| Valerius | 61 |\n+----------+------+\n\nFinding all rows in one table also in another:\n\nSELECT name,age FROM staff WHERE (name,age) IN (SELECT name,age FROM customer);\n+----------+------+\n| name | age |\n+----------+------+\n| Valerius | 61 |\n+----------+------+\n\nURL: https://mariadb.com/kb/en/subqueries-row-subqueries/','','https://mariadb.com/kb/en/subqueries-row-subqueries/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (424,27,'Subqueries and ALL','Subqueries using the ALL keyword will return true if the comparison returns\ntrue for each row returned by the subquery, or the subquery returns no rows.\n\nSyntax\n------\n\nscalar_expression comparison_operator ALL <Table subquery>\n\n* scalar_expression may be any expression that evaluates to a single\nvalue\n* comparison_operator may be any one of: =, >, <, >=, <=, <> or !=\n\nALL returns:\n\n* NULL if the comparison operator returns NULL for at least one row returned\nby the Table subquery or scalar_expression returns NULL.\n* FALSE if the comparison operator returns FALSE for at least one row returned\nby the Table subquery.\n* TRUE if the comparison operator returns TRUE for all rows returned by the\nTable subquery, or if Table subquery returns no rows.\n\nNOT IN is an alias for <> ALL.\n\nExamples\n--------\n\nCREATE TABLE sq1 (num TINYINT);\n\nCREATE TABLE sq2 (num2 TINYINT);\n\nINSERT INTO sq1 VALUES(100);\n\nINSERT INTO sq2 VALUES(40),(50),(60);\n\nSELECT * FROM sq1 WHERE num > ALL (SELECT * FROM sq2);\n+------+\n| num |\n+------+\n| 100 |\n+------+\n\nSince 100 > all of 40,50 and 60, the evaluation is true and the row is returned\n\nAdding a second row to sq1, where the evaluation for that record is false:\n\nINSERT INTO sq1 VALUES(30);\n\nSELECT * FROM sq1 WHERE num > ALL (SELECT * FROM sq2);\n+------+\n| num |\n+------+\n| 100 |\n+------+\n\nAdding a new row to sq2, causing all evaluations to be false:\n\nINSERT INTO sq2 VALUES(120);\n\nSELECT * FROM sq1 WHERE num > ALL (SELECT * FROM sq2);\nEmpty set (0.00 sec)\n\nWhen the subquery returns no results, the evaluation is still true:\n\nSELECT * FROM sq1 WHERE num > ALL (SELECT * FROM sq2 WHERE num2 > 300);\n+------+\n| num |\n+------+\n| 100 |\n| 30 |\n+------+\n\nEvaluating against a NULL will cause the result to be unknown, or not true,\nand therefore return no rows:\n\nINSERT INTO sq2 VALUES (NULL);\n\nSELECT * FROM sq1 WHERE num > ALL (SELECT * FROM sq2);\n\nURL: https://mariadb.com/kb/en/subqueries-and-all/','','https://mariadb.com/kb/en/subqueries-and-all/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (425,27,'Subqueries and ANY','Subqueries using the ANY keyword will return true if the comparison returns\ntrue for at least one row returned by the subquery.\n\nSyntax\n------\n\nThe required syntax for an ANY or SOME quantified comparison is:\n\nscalar_expression comparison_operator ANY <Table subquery>\n\nOr:\n\nscalar_expression comparison_operator SOME <Table subquery>\n\n* scalar_expression may be any expression that evaluates to a\nsingle value.\n* comparison_operator may be any one of =, >, <, >=, <=, <> or !=.\n\nANY returns:\n\n* TRUE if the comparison operator returns TRUE for at least one row returned\nby the Table subquery.\n* FALSE if the comparison operator returns FALSE for all rows returned by the\nTable subquery, or Table subquery has zero rows.\n* NULL if the comparison operator returns NULL for at least one row returned\nby the Table subquery and doesn\'t returns TRUE for any of them, or if\nscalar_expression returns NULL.\n\nSOME is a synmonym for ANY, and IN is a synonym for = ANY\n\nExamples\n--------\n\nCREATE TABLE sq1 (num TINYINT);\n\nCREATE TABLE sq2 (num2 TINYINT);\n\nINSERT INTO sq1 VALUES(100);\n\nINSERT INTO sq2 VALUES(40),(50),(120);\n\nSELECT * FROM sq1 WHERE num > ANY (SELECT * FROM sq2);\n+------+\n| num |\n+------+\n| 100 |\n+------+\n\n100 is greater than two of the three values, and so the expression evaluates\nas true.\n\nSOME is a synonym for ANY:\n\nSELECT * FROM sq1 WHERE num < SOME (SELECT * FROM sq2);\n+------+\n| num |\n+------+\n| 100 |\n+------+\n\nIN is a synonym for = ANY, and here there are no matches, so no results are\nreturned:\n\nSELECT * FROM sq1 WHERE num IN (SELECT * FROM sq2);\nEmpty set (0.00 sec)\n\nINSERT INTO sq2 VALUES(100);\nQuery OK, 1 row affected (0.05 sec)\n\nSELECT * FROM sq1 WHERE num <> ANY (SELECT * FROM sq2);\n+------+\n| num |\n+------+\n| 100 |\n+------+\n\nReading this query, the results may be counter-intuitive. It may seem to read\nas \"SELECT * FROM sq1 WHERE num does not match any results in sq2. Since it\ndoes match 100, it could seem that the results are incorrect. However, the\nquery returns a result if the match does not match any of sq2. Since 100\nalready does not match 40, the expression evaluates to true immediately,\nregardless of the 100\'s matching. It may be more easily readable to use SOME\nin a case such as this:\n\nSELECT * FROM sq1 WHERE num <> SOME (SELECT * FROM sq2);\n+------+\n| num |\n+------+\n| 100 |\n+------+\n\nURL: https://mariadb.com/kb/en/subqueries-and-any/','','https://mariadb.com/kb/en/subqueries-and-any/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (426,27,'Subqueries and EXISTS','Syntax\n------\n\nSELECT ... WHERE EXISTS <Table subquery>\n\nDescription\n-----------\n\nSubqueries using the EXISTS keyword will return true if the subquery returns\nany rows. Conversely, subqueries using NOT EXISTS will return true only if the\nsubquery returns no rows from the table.\n\nEXISTS subqueries ignore the columns specified by the SELECT of the subquery,\nsince they\'re not relevant. For example,\n\nSELECT col1 FROM t1 WHERE EXISTS (SELECT * FROM t2);\n\nand\n\nSELECT col1 FROM t1 WHERE EXISTS (SELECT col2 FROM t2);\n\nproduce identical results.\n\nExamples\n--------\n\nCREATE TABLE sq1 (num TINYINT);\n\nCREATE TABLE sq2 (num2 TINYINT);\n\nINSERT INTO sq1 VALUES(100);\n\nINSERT INTO sq2 VALUES(40),(50),(60);\n\nSELECT * FROM sq1 WHERE EXISTS (SELECT * FROM sq2 WHERE num2>50);\n+------+\n| num |\n+------+\n| 100 |\n+------+\n\nSELECT * FROM sq1 WHERE NOT EXISTS (SELECT * FROM sq2 GROUP BY num2 HAVING\nMIN(num2)=40);\nEmpty set (0.00 sec)\n\nURL: https://mariadb.com/kb/en/subqueries-and-exists/','','https://mariadb.com/kb/en/subqueries-and-exists/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (427,27,'Subqueries in a FROM Clause','Although subqueries are more commonly placed in a WHERE clause, they can also\nform part of the FROM clause. Such subqueries are commonly called derived\ntables.\n\nIf a subquery is used in this way, you must also use an AS clause to name the\nresult of the subquery.\n\nORACLE mode\n-----------\n\nMariaDB starting with 10.6.0\n----------------------------\nFrom MariaDB 10.6.0, anonymous subqueries in a FROM clause (no AS clause) are\npermitted in ORACLE mode.\n\nExamples\n--------\n\nCREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87), (\'Tatiana\', \'Tuning\', 83);\n\nAssume that, given the data above, you want to return the average total for\nall students. In other words, the average of Chun\'s 148 (75+73), Esben\'s 74\n(43+31), etc.\n\nYou cannot do the following:\n\nSELECT AVG(SUM(score)) FROM student GROUP BY name;\nERROR 1111 (HY000): Invalid use of group function\n\nA subquery in the FROM clause is however permitted:\n\nSELECT AVG(sq_sum) FROM (SELECT SUM(score) AS sq_sum FROM student GROUP BY\nname) AS t;\n+-------------+\n| AVG(sq_sum) |\n+-------------+\n| 134.0000 |\n+-------------+\n\nFrom MariaDB 10.6 in ORACLE mode, the following is permitted:\n\nSELECT * FROM (SELECT 1 FROM DUAL), (SELECT 2 FROM DUAL);\n\nURL: https://mariadb.com/kb/en/subqueries-in-a-from-clause/','','https://mariadb.com/kb/en/subqueries-in-a-from-clause/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (428,27,'Subqueries and JOINs','A subquery can quite often, but not in all cases, be rewritten as a JOIN.\n\nRewriting Subqueries as JOINS\n-----------------------------\n\nA subquery using IN can be rewritten with the DISTINCT keyword, for example:\n\nSELECT * FROM table1 WHERE col1 IN (SELECT col1 FROM table2);\n\ncan be rewritten as:\n\nSELECT DISTINCT table1.* FROM table1, table2 WHERE table1.col1=table2.col1;\n\nNOT IN or NOT EXISTS queries can also be rewritten. For example, these two\nqueries returns the same result:\n\nSELECT * FROM table1 WHERE col1 NOT IN (SELECT col1 FROM table2);\nSELECT * FROM table1 WHERE NOT EXISTS (SELECT col1 FROM table2 WHERE\ntable1.col1=table2.col1);\n\nand both can be rewritten as:\n\nSELECT table1.* FROM table1 LEFT JOIN table2 ON table1.id=table2.id WHERE\ntable2.id IS NULL;\n\nSubqueries that can be rewritten as a LEFT JOIN are sometimes more efficient.\n\nUsing Subqueries instead of JOINS\n---------------------------------\n\nThere are some scenarios, though, which call for subqueries rather than joins:\n\n* When you want duplicates, but not false duplicates. Suppose Table_1\n has three rows — {1,1,2}\n — and Table_2 has two rows\n — {1,2,2}. If you need to list the rows\n in Table_1 which are also in Table_2, only this\n subquery-based SELECT statement will give the right answer\n (1,1,2):\n\nSELECT Table_1.column_1 \nFROM Table_1 \nWHERE Table_1.column_1 IN \n (SELECT Table_2.column_1\n FROM Table_2);\n\n* This SQL statement won\'t work:\n\nSELECT Table_1.column_1 \nFROM Table_1,Table_2 \nWHERE Table_1.column_1 = Table_2.column_1;\n\n* because the result will be {1,1,2,2}\n — and the duplication of 2 is an error. This SQL\n statement won\'t work either:\n\nSELECT DISTINCT Table_1.column_1 \nFROM Table_1,Table_2 \nWHERE Table_1.column_1 = Table_2.column_1;\n\n* because the result will be {1,2} — and\n the removal of the duplicated 1 is an error too.\n\n* When the outermost statement is not a query. The SQL statement:\n\nUPDATE Table_1 SET column_1 = (SELECT column_1 FROM Table_2);\n\n* can\'t be expressed using a join unless some rare SQL3 features are used.\n\n* When the join is over an expression. The SQL statement:\n\nSELECT * FROM Table_1 \nWHERE column_1 + 5 =\n (SELECT MAX(column_1) FROM Table_2);\n\n* is hard to express with a join. In fact, the only way we can think of is\n this SQL statement:\n\nSELECT Table_1.*\nFROM Table_1, \n (SELECT MAX(column_1) AS max_column_1 FROM Table_2) AS Table_2\nWHERE Table_1.column_1 + 5 = Table_2.max_column_1;\n\n* which still involves a parenthesized query, so nothing is gained from the\n transformation.\n\n* When you want to see the exception. For example, suppose the question is:\n what books are longer than Das Kapital? These two queries are effectively\n almost the same:\n\nSELECT DISTINCT Bookcolumn_1.* \nFROM Books AS Bookcolumn_1 JOIN Books AS Bookcolumn_2 USING(page_count) \nWHERE title = \'Das Kapital\';\n\nSELECT DISTINCT Bookcolumn_1.* \nFROM Books AS Bookcolumn_1 \nWHERE Bookcolumn_1.page_count > \n (SELECT DISTINCT page_count\n FROM Books AS Bookcolumn_2\n WHERE title = \'Das Kapital\');\n\n* The difference is between these two SQL statements is, if there are two\n editions of Das Kapital (with different page counts), then the self-join\n example will return the books which are longer than the shortest edition\n of Das Kapital. That might be the wrong answer, since the original\n question didn\'t ask for \"... longer than ANY book named Das Kapital\"\n (it seems to contain a false assumption that there\'s only one edition).\n\nURL: https://mariadb.com/kb/en/subqueries-and-joins/','','https://mariadb.com/kb/en/subqueries-and-joins/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (429,27,'Subquery Limitations','There are a number of limitations regarding subqueries, which are discussed\nbelow. The following tables and data will be used in the examples that follow:\n\nCREATE TABLE staff(name VARCHAR(10),age TINYINT);\n\nCREATE TABLE customer(name VARCHAR(10),age TINYINT);\n\nINSERT INTO staff VALUES \n(\'Bilhah\',37), (\'Valerius\',61), (\'Maia\',25);\n\nINSERT INTO customer VALUES \n(\'Thanasis\',48), (\'Valerius\',61), (\'Brion\',51);\n\nORDER BY and LIMIT\n------------------\n\nTo use ORDER BY or limit LIMIT in subqueries both must be used.. For example:\n\nSELECT * FROM staff WHERE name IN (SELECT name FROM customer ORDER BY name);\n+----------+------+\n| name | age |\n+----------+------+\n| Valerius | 61 |\n+----------+------+\n\nis valid, but\n\nSELECT * FROM staff WHERE name IN (SELECT NAME FROM customer ORDER BY name\nLIMIT 1);\nERROR 1235 (42000): This version of MariaDB doesn\'t \n yet support \'LIMIT & IN/ALL/ANY/SOME subquery\'\n\nis not.\n\nModifying and Selecting from the Same Table\n-------------------------------------------\n\nIt\'s not possible to both modify and select from the same table in a subquery.\nFor example:\n\nDELETE FROM staff WHERE name = (SELECT name FROM staff WHERE age=61);\nERROR 1093 (HY000): Table \'staff\' is specified twice, both \n as a target for \'DELETE\' and as a separate source for data\n\nRow Comparison Operations\n-------------------------\n\nThere is only partial support for row comparison operations. The expression in\n\nexpr op {ALL|ANY|SOME} subquery,\n\nmust be scalar and the subquery can only return a single column.\n\nHowever, because of the way IN is implemented (it is rewritten as a sequence\nof = comparisons and AND), the expression in\n\nexpression [NOT] IN subquery\n\nis permitted to be an n-tuple and the subquery can return rows of n-tuples.\n\nFor example:\n\nSELECT * FROM staff WHERE (name,age) NOT IN (\n SELECT name,age FROM customer WHERE age >=51]\n);\n+--------+------+\n| name | age |\n+--------+------+\n| Bilhah | 37 |\n| Maia | 25 |\n+--------+------+\n\nis permitted, but\n\nSELECT * FROM staff WHERE (name,age) = ALL (\n SELECT name,age FROM customer WHERE age >=51\n);\nERROR 1241 (21000): Operand should contain 1 column(s)\n\nis not.\n\nCorrelated Subqueries\n---------------------\n\nSubqueries in the FROM clause cannot be correlated subqueries. They cannot be\nevaluated for each row of the outer query since they are evaluated to produce\na result set during when the query is executed.\n\nStored Functions\n----------------\n\nA subquery can refer to a stored function which modifies data. This is an\nextension to the SQL standard, but can result in indeterminate outcomes. For\nexample, take:\n\nSELECT ... WHERE x IN (SELECT f() ...);\n\nwhere f() inserts rows. The function f() could be executed a different number\nof times depending on how the optimizer chooses to handle the query.\n\nThis sort of construct is therefore not safe to use in replication that is not\nrow-based, as there could be different results on the master and the slave.\n\nURL: https://mariadb.com/kb/en/subquery-limitations/','','https://mariadb.com/kb/en/subquery-limitations/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (430,27,'UNION','UNION is used to combine the results from multiple SELECT statements into a\nsingle result set.\n\nSyntax\n------\n\nSELECT ...\nUNION [ALL | DISTINCT] SELECT ...\n[UNION [ALL | DISTINCT] SELECT ...]\n[ORDER BY [column [, column ...]]]\n[LIMIT {[offset,] row_count | row_count OFFSET offset}]\n\nDescription\n-----------\n\nUNION is used to combine the results from multiple SELECT statements into a\nsingle result set.\n\nThe column names from the first SELECT statement are used as the column names\nfor the results returned. Selected columns listed in corresponding positions\nof each SELECT statement should have the same data type. (For example, the\nfirst column selected by the first statement should have the same type as the\nfirst column selected by the other statements.)\n\nIf they don\'t, the type and length of the columns in the result take into\naccount the values returned by all of the SELECTs, so there is no need for\nexplicit casting. Note that currently this is not the case for recursive CTEs\n- see MDEV-12325.\n\nTable names can be specified as db_name.tbl_name. This permits writing UNIONs\nwhich involve multiple databases. See Identifier Qualifiers for syntax details.\n\nUNION queries cannot be used with aggregate functions.\n\nEXCEPT and UNION have the same operation precedence and INTERSECT has a higher\nprecedence, unless running in Oracle mode, in which case all three have the\nsame precedence.\n\nALL/DISTINCT\n------------\n\nThe ALL keyword causes duplicate rows to be preserved. The DISTINCT keyword\n(the default if the keyword is omitted) causes duplicate rows to be removed by\nthe results.\n\nUNION ALL and UNION DISTINCT can both be present in a query. In this case,\nUNION DISTINCT will override any UNION ALLs to its left.\n\nMariaDB starting with 10.1.1\n----------------------------\nUntil MariaDB 10.1.1, all UNION ALL statements required the server to create a\ntemporary table. Since MariaDB 10.1.1, the server can in most cases execute\nUNION ALL without creating a temporary table, improving performance (see\nMDEV-334).\n\nORDER BY and LIMIT\n------------------\n\nIndividual SELECTs can contain their own ORDER BY and LIMIT clauses. In this\ncase, the individual queries need to be wrapped between parentheses. However,\nthis does not affect the order of the UNION, so they only are useful to limit\nthe record read by one SELECT.\n\nThe UNION can have global ORDER BY and LIMIT clauses, which affect the whole\nresultset. If the columns retrieved by individual SELECT statements have an\nalias (AS), the ORDER BY must use that alias, not the real column names.\n\nHIGH_PRIORITY\n-------------\n\nSpecifying a query as HIGH_PRIORITY will not work inside a UNION. If applied\nto the first SELECT, it will be ignored. Applying to a later SELECT results in\na syntax error:\n\nERROR 1234 (42000): Incorrect usage/placement of \'HIGH_PRIORITY\'\n\nSELECT ... INTO ...\n-------------------\n\nIndividual SELECTs cannot be written INTO DUMPFILE or INTO OUTFILE. If the\nlast SELECT statement specifies INTO DUMPFILE or INTO OUTFILE, the entire\nresult of the UNION will be written. Placing the clause after any other SELECT\nwill result in a syntax error.\n\nIf the result is a single row, SELECT ... INTO @var_name can also be used.\n\nMariaDB starting with 10.4.0\n----------------------------\n\nParentheses\n-----------\n\nFrom MariaDB 10.4.0, parentheses can be used to specify precedence. Before\nthis, a syntax error would be returned.\n\nExamples\n--------\n\nUNION between tables having different column names:\n\n(SELECT e_name AS name, email FROM employees)\nUNION\n(SELECT c_name AS name, email FROM customers);\n\nSpecifying the UNION\'s global order and limiting total rows:\n\n(SELECT name, email FROM employees)\nUNION\n(SELECT name, email FROM customers)\nORDER BY name LIMIT 10;\n\nAdding a constant row:\n\n(SELECT \'John Doe\' AS name, \'john.doe@example.net\' AS email)\nUNION\n(SELECT name, email FROM customers);\n\nDiffering types:\n\nSELECT CAST(\'x\' AS CHAR(1)) UNION SELECT REPEAT(\'y\',4);\n+----------------------+\n| CAST(\'x\' AS CHAR(1)) |\n+----------------------+\n| x |\n| yyyy |\n+----------------------+\n\nReturning the results in order of each individual SELECT by use of a sort\ncolumn:\n\n(SELECT 1 AS sort_column, e_name AS name, email FROM employees)\nUNION\n(SELECT 2, c_name AS name, email FROM customers) ORDER BY sort_column;\n\nDifference between UNION, EXCEPT and INTERSECT. INTERSECT ALL and EXCEPT ALL\nare available from MariaDB 10.5.0.\n\nCREATE TABLE seqs (i INT);\nINSERT INTO seqs VALUES (1),(2),(2),(3),(3),(4),(5),(6);\n\nSELECT i FROM seqs WHERE i <= 3 UNION SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 3 |\n| 4 |\n| 5 |\n| 6 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 UNION ALL SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 2 |\n| 3 |\n| 3 |\n| 3 |\n| 3 |\n| 4 |\n| 5 |\n| 6 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 EXCEPT SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 EXCEPT ALL SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 2 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 INTERSECT SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 3 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 INTERSECT ALL SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 3 |\n| 3 |\n+------+\n\nParentheses for specifying precedence, from MariaDB 10.4.0\n\nCREATE OR REPLACE TABLE t1 (a INT);\nCREATE OR REPLACE TABLE t2 (b INT);\nCREATE OR REPLACE TABLE t3 (c INT);\n\nINSERT INTO t1 VALUES (1),(2),(3),(4);\nINSERT INTO t2 VALUES (5),(6);\nINSERT INTO t3 VALUES (1),(6);\n\n((SELECT a FROM t1) UNION (SELECT b FROM t2)) INTERSECT (SELECT c FROM t3);\n+------+\n| a |\n+------+\n| 1 |\n| 6 |\n+------+\n\n(SELECT a FROM t1) UNION ((SELECT b FROM t2) INTERSECT (SELECT c FROM t3));\n+------+\n| a |\n+------+\n| 1 |\n| 2 |\n| 3 |\n| 4 |\n| 6 |\n+------+\n\nURL: https://mariadb.com/kb/en/union/','','https://mariadb.com/kb/en/union/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (431,27,'EXCEPT','The result of EXCEPT is all records of the left SELECT result set except\nrecords which are in right SELECT result set, i.e. it is subtraction of two\nresult sets. From MariaDB 10.6.1, MINUS is a synonym when SQL_MODE=ORACLE is\nset.\n\nSyntax\n------\n\nSELECT ...\n(INTERSECT [ALL | DISTINCT] | EXCEPT [ALL | DISTINCT] | UNION [ALL |\nDISTINCT]) \n SELECT ...\n[(INTERSECT [ALL | DISTINCT] | EXCEPT [ALL | DISTINCT] | UNION [ALL |\nDISTINCT]) \n SELECT ...]\n[ORDER BY [{col_name | expr | position} [ASC | DESC] \n [, {col_name | expr | position} [ASC | DESC] ...]]]\n[LIMIT {[offset,] row_count | row_count OFFSET offset}\n| OFFSET start { ROW | ROWS }\n| FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES } ]\n\nPlease note:\n\n* Brackets for explicit operation precedence are not supported; use a subquery\nin the FROM clause as a workaround).\n\nDescription\n-----------\n\nMariaDB has supported EXCEPT and INTERSECT in addition to UNION since MariaDB\n10.3.\n\nThe queries before and after EXCEPT must be SELECT or VALUES statements.\n\nAll behavior for naming columns, ORDER BY and LIMIT is the same as for UNION.\nNote that the alternative SELECT ... OFFSET ... FETCH syntax is only\nsupported. This allows us to use the WITH TIES clause.\n\nEXCEPT implicitly supposes a DISTINCT operation.\n\nThe result of EXCEPT is all records of the left SELECT result except records\nwhich are in right SELECT result set, i.e. it is subtraction of two result\nsets.\n\nEXCEPT and UNION have the same operation precedence and INTERSECT has a higher\nprecedence, unless running in Oracle mode, in which case all three have the\nsame precedence.\n\nMariaDB starting with 10.4.0\n----------------------------\n\nParentheses\n-----------\n\nFrom MariaDB 10.4.0, parentheses can be used to specify precedence. Before\nthis, a syntax error would be returned.\n\nMariaDB starting with 10.5.0\n----------------------------\n\nALL/DISTINCT\n------------\n\nEXCEPT ALL and EXCEPT DISTINCT were introduced in MariaDB 10.5.0. The ALL\noperator leaves duplicates intact, while the DISTINCT operator removes\nduplicates. DISTINCT is the default behavior if neither operator is supplied,\nand the only behavior prior to MariaDB 10.5.\n\nExamples\n--------\n\nShow customers which are not employees:\n\n(SELECT e_name AS name, email FROM customers)\nEXCEPT\n(SELECT c_name AS name, email FROM employees);\n\nDifference between UNION, EXCEPT and INTERSECT. INTERSECT ALL and EXCEPT ALL\nare available from MariaDB 10.5.0.\n\nCREATE TABLE seqs (i INT);\nINSERT INTO seqs VALUES (1),(2),(2),(3),(3),(4),(5),(6);\n\nSELECT i FROM seqs WHERE i <= 3 UNION SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 3 |\n| 4 |\n| 5 |\n| 6 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 UNION ALL SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 2 |\n| 3 |\n| 3 |\n| 3 |\n| 3 |\n| 4 |\n| 5 |\n| 6 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 EXCEPT SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 EXCEPT ALL SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 2 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 INTERSECT SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 3 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 INTERSECT ALL SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 3 |\n| 3 |\n+------+\n\nParentheses for specifying precedence, from MariaDB 10.4.0\n\nCREATE OR REPLACE TABLE t1 (a INT);\nCREATE OR REPLACE TABLE t2 (b INT);\nCREATE OR REPLACE TABLE t3 (c INT);\n\nINSERT INTO t1 VALUES (1),(2),(3),(4);\nINSERT INTO t2 VALUES (5),(6);\nINSERT INTO t3 VALUES (1),(6);\n\n((SELECT a FROM t1) UNION (SELECT b FROM t2)) EXCEPT (SELECT c FROM t3);\n+------+\n| a |\n+------+\n| 2 |\n| 3 |\n| 4 |\n| 5 |\n+------+\n\n(SELECT a FROM t1) UNION ((SELECT b FROM t2) EXCEPT (SELECT c FROM t3));\n+------+\n| a |\n+------+\n| 1 |\n| 2 |\n| 3 |\n| 4 |\n| 5 |\n+------+\n\nHere is an example that makes use of the SEQUENCE storage engine and the\nVALUES statement, to generate a numeric sequence and remove some arbitrary\nnumbers from it:\n\n(SELECT seq FROM seq_1_to_10) EXCEPT VALUES (2), (3), (4);\n+-----+\n| seq |\n+-----+\n| 1 |\n| 5 |\n| 6 |\n| 7 |\n| 8 |\n| 9 |\n| 10 |\n+-----+\n\nURL: https://mariadb.com/kb/en/except/','','https://mariadb.com/kb/en/except/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (432,27,'INTERSECT','MariaDB starting with 10.3.0\n----------------------------\nINTERSECT was introduced in MariaDB 10.3.0.\n\nThe result of an intersect is the intersection of right and left SELECT\nresults, i.e. only records that are present in both result sets will be\nincluded in the result of the operation.\n\nSyntax\n------\n\nSELECT ...\n(INTERSECT [ALL | DISTINCT] | EXCEPT [ALL | DISTINCT] | UNION [ALL |\nDISTINCT]) SELECT ...\n[(INTERSECT [ALL | DISTINCT] | EXCEPT [ALL | DISTINCT] | UNION [ALL |\nDISTINCT]) SELECT ...]\n[ORDER BY [column [, column ...]]]\n[LIMIT {[offset,] row_count | row_count OFFSET offset}]\n\nDescription\n-----------\n\nMariaDB has supported INTERSECT (as well as EXCEPT) in addition to UNION since\nMariaDB 10.3.\n\nAll behavior for naming columns, ORDER BY and LIMIT is the same as for UNION.\n\nINTERSECT implicitly supposes a DISTINCT operation.\n\nThe result of an intersect is the intersection of right and left SELECT\nresults, i.e. only records that are present in both result sets will be\nincluded in the result of the operation.\n\nINTERSECT has higher precedence than UNION and EXCEPT (unless running running\nin Oracle mode, in which case all three have the same precedence). If possible\nit will be executed linearly but if not it will be translated to a subquery in\nthe FROM clause:\n\n(select a,b from t1)\nunion\n(select c,d from t2)\nintersect\n(select e,f from t3)\nunion\n(select 4,4);\n\nwill be translated to:\n\n(select a,b from t1)\nunion\nselect c,d from\n ((select c,d from t2)\n intersect\n (select e,f from t3)) dummy_subselect\nunion\n(select 4,4)\n\nMariaDB starting with 10.4.0\n----------------------------\n\nParentheses\n-----------\n\nFrom MariaDB 10.4.0, parentheses can be used to specify precedence. Before\nthis, a syntax error would be returned.\n\nMariaDB starting with 10.5.0\n----------------------------\n\nALL/DISTINCT\n------------\n\nINTERSECT ALL and INTERSECT DISTINCT were introduced in MariaDB 10.5.0. The\nALL operator leaves duplicates intact, while the DISTINCT operator removes\nduplicates. DISTINCT is the default behavior if neither operator is supplied,\nand the only behavior prior to MariaDB 10.5.\n\nExamples\n--------\n\nShow customers which are employees:\n\n(SELECT e_name AS name, email FROM employees)\nINTERSECT\n(SELECT c_name AS name, email FROM customers);\n\nDifference between UNION, EXCEPT and INTERSECT. INTERSECT ALL and EXCEPT ALL\nare available from MariaDB 10.5.0.\n\nCREATE TABLE seqs (i INT);\nINSERT INTO seqs VALUES (1),(2),(2),(3),(3),(4),(5),(6);\n\nSELECT i FROM seqs WHERE i <= 3 UNION SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 3 |\n| 4 |\n| 5 |\n| 6 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 UNION ALL SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 2 |\n| 3 |\n| 3 |\n| 3 |\n| 3 |\n| 4 |\n| 5 |\n| 6 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 EXCEPT SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 EXCEPT ALL SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 2 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 INTERSECT SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 3 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 INTERSECT ALL SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 3 |\n| 3 |\n+------+\n\nParentheses for specifying precedence, from MariaDB 10.4.0\n\nCREATE OR REPLACE TABLE t1 (a INT);\nCREATE OR REPLACE TABLE t2 (b INT);\nCREATE OR REPLACE TABLE t3 (c INT);\n\nINSERT INTO t1 VALUES (1),(2),(3),(4);\nINSERT INTO t2 VALUES (5),(6);\nINSERT INTO t3 VALUES (1),(6);\n\n((SELECT a FROM t1) UNION (SELECT b FROM t2)) INTERSECT (SELECT c FROM t3);\n+------+\n| a |\n+------+\n| 1 |\n| 6 |\n+------+\n\n(SELECT a FROM t1) UNION ((SELECT b FROM t2) INTERSECT (SELECT c FROM t3));\n+------+\n| a |\n+------+\n| 1 |\n| 2 |\n| 3 |\n| 4 |\n| 6 |\n+------+\n\nURL: https://mariadb.com/kb/en/intersect/','','https://mariadb.com/kb/en/intersect/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (433,27,'Precedence Control in Table Operations','MariaDB starting with 10.4.0\n----------------------------\nBeginning in MariaDB 10.4, you can control the ordering of execution on table\noperations using parentheses.\n\nSyntax\n------\n\n( expression )\n[ORDER BY [column[, column...]]]\n[LIMIT {[offset,] row_count | row_count OFFSET offset}]\n\nDescription\n-----------\n\nUsing parentheses in your SQL allows you to control the order of execution for\nSELECT statements and Table Value Constructor, including UNION, EXCEPT, and\nINTERSECT operations. MariaDB executes the parenthetical expression before the\nrest of the statement. You can then use ORDER BY and LIMIT clauses the further\norganize the result-set.\n\nNote: In practice, the Optimizer may rearrange the exact order in which\nMariaDB executes different parts of the statement. When it calculates the\nresult-set, however, it returns values as though the parenthetical expression\nwere executed first.\n\nExample\n-------\n\nCREATE TABLE test.t1 (num INT);\n\nINSERT INTO test.t1 VALUES (1),(2),(3);\n\n(SELECT * FROM test.t1 \n UNION \n VALUES (10)) \nINTERSECT \nVALUES (1),(3),(10),(11);\n+------+\n| num |\n+------+\n| 1 |\n| 3 |\n| 10 |\n+------+\n\n((SELECT * FROM test.t1 \n UNION\n VALUES (10))\n INTERSECT \n VALUES (1),(3),(10),(11)) \nORDER BY 1 DESC;\n+------+\n| num |\n+------+\n| 10 |\n| 3 |\n| 1 |\n+------+\n\nURL: https://mariadb.com/kb/en/precedence-control-in-table-operations/','','https://mariadb.com/kb/en/precedence-control-in-table-operations/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (434,27,'LIMIT','Description\n-----------\n\nUse the LIMIT clause to restrict the number of returned rows. When you use a\nsingle integer n with LIMIT, the first n rows will be returned. Use the ORDER\nBY clause to control which rows come first. You can also select a number of\nrows after an offset using either of the following:\n\nLIMIT offset, row_count\nLIMIT row_count OFFSET offset\n\nWhen you provide an offset m with a limit n, the first m rows will be ignored,\nand the following n rows will be returned.\n\nExecuting an UPDATE with the LIMIT clause is not safe for replication. LIMIT 0\nis an exception to this rule (see MDEV-6170).\n\nThere is a LIMIT ROWS EXAMINED optimization which provides the means to\nterminate the execution of SELECT statements which examine too many rows, and\nthus use too many resources. See LIMIT ROWS EXAMINED.\n\nMulti-Table Updates\n-------------------\n\nMariaDB starting with 10.3.2\n----------------------------\nUntil MariaDB 10.3.1, it was not possible to use LIMIT (or ORDER BY) in a\nmulti-table UPDATE statement. This restriction was lifted in MariaDB 10.3.2.\n\nGROUP_CONCAT\n------------\n\nMariaDB starting with 10.3.2\n----------------------------\nStarting from MariaDB 10.3.3, it is possible to use LIMIT with GROUP_CONCAT().\n\nExamples\n--------\n\nCREATE TABLE members (name VARCHAR(20));\nINSERT INTO members VALUES(\'Jagdish\'),(\'Kenny\'),(\'Rokurou\'),(\'Immaculada\');\n\nSELECT * FROM members;\n+------------+\n| name |\n+------------+\n| Jagdish |\n| Kenny |\n| Rokurou |\n| Immaculada |\n+------------+\n\nSelect the first two names (no ordering specified):\n\nSELECT * FROM members LIMIT 2;\n+---------+\n| name |\n+---------+\n| Jagdish |\n| Kenny |\n+---------+\n\nAll the names in alphabetical order:\n\nSELECT * FROM members ORDER BY name;\n+------------+\n| name |\n+------------+\n| Immaculada |\n| Jagdish |\n| Kenny |\n| Rokurou |\n+------------+\n\nThe first two names, ordered alphabetically:\n\nSELECT * FROM members ORDER BY name LIMIT 2;\n+------------+\n| name |\n+------------+\n| Immaculada |\n| Jagdish |\n+------------+\n\nThe third name, ordered alphabetically (the first name would be offset zero,\nso the third is offset two):\n\nSELECT * FROM members ORDER BY name LIMIT 2,1;\n+-------+\n| name |\n+-------+\n| Kenny |\n+-------+\n\nFrom MariaDB 10.3.2, LIMIT can be used in a multi-table update:\n\nCREATE TABLE warehouse (product_id INT, qty INT);\nINSERT INTO warehouse VALUES (1,100),(2,100),(3,100),(4,100);\n\nCREATE TABLE store (product_id INT, qty INT);\nINSERT INTO store VALUES (1,5),(2,5),(3,5),(4,5);\n\nUPDATE warehouse,store SET warehouse.qty = warehouse.qty-2, store.qty =\nstore.qty+2 \n WHERE (warehouse.product_id = store.product_id AND store.product_id >= 1)\n ORDER BY store.product_id DESC LIMIT 2;\n\nSELECT * FROM warehouse;\n+------------+------+\n| product_id | qty |\n+------------+------+\n| 1 | 100 |\n| 2 | 100 |\n| 3 | 98 |\n| 4 | 98 |\n+------------+------+\n\nSELECT * FROM store;\n+------------+------+\n| product_id | qty |\n+------------+------+\n| 1 | 5 |\n| 2 | 5 |\n| 3 | 7 |\n| 4 | 7 |\n+------------+------+\n\nFrom MariaDB 10.3.3, LIMIT can be used with GROUP_CONCAT, so, for example,\ngiven the following table:\n\nCREATE TABLE d (dd DATE, cc INT);\n\nINSERT INTO d VALUES (\'2017-01-01\',1);\nINSERT INTO d VALUES (\'2017-01-02\',2);\nINSERT INTO d VALUES (\'2017-01-04\',3);\n\nthe following query:\n\nSELECT SUBSTRING_INDEX(GROUP_CONCAT(CONCAT_WS(\":\",dd,cc) ORDER BY cc\nDESC),\",\",1) FROM d;\n+----------------------------------------------------------------------------+\n| SUBSTRING_INDEX(GROUP_CONCAT(CONCAT_WS(\":\",dd,cc) ORDER BY cc DESC),\",\",1) |\n+----------------------------------------------------------------------------+\n| 2017-01-04:3 |\n+----------------------------------------------------------------------------+\n\ncan be more simply rewritten as:\n\nSELECT GROUP_CONCAT(CONCAT_WS(\":\",dd,cc) ORDER BY cc DESC LIMIT 1) FROM d;\n+-------------------------------------------------------------+\n| GROUP_CONCAT(CONCAT_WS(\":\",dd,cc) ORDER BY cc DESC LIMIT 1) |\n+-------------------------------------------------------------+\n| 2017-01-04:3 |\n+-------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/limit/','','https://mariadb.com/kb/en/limit/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (435,27,'ORDER BY','Description\n-----------\n\nUse the ORDER BY clause to order a resultset, such as that are returned from a\nSELECT statement. You can specify just a column or use any expression with\nfunctions. If you are using the GROUP BY clause, you can use grouping\nfunctions in ORDER BY. Ordering is done after grouping.\n\nYou can use multiple ordering expressions, separated by commas. Rows will be\nsorted by the first expression, then by the second expression if they have the\nsame value for the first, and so on.\n\nYou can use the keywords ASC and DESC after each ordering expression to force\nthat ordering to be ascending or descending, respectively. Ordering is\nascending by default.\n\nYou can also use a single integer as the ordering expression. If you use an\ninteger n, the results will be ordered by the nth column in the select\nexpression.\n\nWhen string values are compared, they are compared as if by the STRCMP\nfunction. STRCMP ignores trailing whitespace and may normalize characters and\nignore case, depending on the collation in use.\n\nDuplicated entries in the ORDER BY clause are removed.\n\nORDER BY can also be used to order the activities of a DELETE or UPDATE\nstatement (usually with the LIMIT clause).\n\nMariaDB starting with 10.3.2\n----------------------------\nUntil MariaDB 10.3.1, it was not possible to use ORDER BY (or LIMIT) in a\nmulti-table UPDATE statement. This restriction was lifted in MariaDB 10.3.2.\n\nMariaDB starting with 10.5\n--------------------------\nFrom MariaDB 10.5, MariaDB allows packed sort keys and values of non-sorted\nfields in the sort buffer. This can make filesort temporary files much smaller\nwhen VARCHAR, CHAR or BLOBs are used, notably speeding up some ORDER BY sorts.\n\nExamples\n--------\n\nCREATE TABLE seq (i INT, x VARCHAR(1));\nINSERT INTO seq VALUES (1,\'a\'), (2,\'b\'), (3,\'b\'), (4,\'f\'), (5,\'e\');\n\nSELECT * FROM seq ORDER BY i;\n+------+------+\n| i | x |\n+------+------+\n| 1 | a |\n| 2 | b |\n| 3 | b |\n| 4 | f |\n| 5 | e |\n+------+------+\n\nSELECT * FROM seq ORDER BY i DESC;\n+------+------+\n| i | x |\n+------+------+\n| 5 | e |\n| 4 | f |\n| 3 | b |\n| 2 | b |\n| 1 | a |\n+------+------+\n\nSELECT * FROM seq ORDER BY x,i;\n+------+------+\n| i | x |\n+------+------+\n| 1 | a |\n| 2 | b |\n| 3 | b |\n| 5 | e |\n| 4 | f |\n+------+------+\n\nORDER BY in an UPDATE statement, in conjunction with LIMIT:\n\nUPDATE seq SET x=\'z\' WHERE x=\'b\' ORDER BY i DESC LIMIT 1;\n\nSELECT * FROM seq;\n+------+------+\n| i | x |\n+------+------+\n| 1 | a |\n| 2 | b |\n| 3 | z |\n| 4 | f |\n| 5 | e |\n+------+------+\n\nFrom MariaDB 10.3.2, ORDER BY can be used in a multi-table update:\n\nCREATE TABLE warehouse (product_id INT, qty INT);\nINSERT INTO warehouse VALUES (1,100),(2,100),(3,100),(4,100);\n\nCREATE TABLE store (product_id INT, qty INT);\nINSERT INTO store VALUES (1,5),(2,5),(3,5),(4,5);\n\nUPDATE warehouse,store SET warehouse.qty = warehouse.qty-2, store.qty =\nstore.qty+2 \n WHERE (warehouse.product_id = store.product_id AND store.product_id >= 1)\n ORDER BY store.product_id DESC LIMIT 2;\n\nSELECT * FROM warehouse;\n+------------+------+\n| product_id | qty |\n+------------+------+\n| 1 | 100 |\n| 2 | 100 |\n| 3 | 98 |\n| 4 | 98 |\n+------------+------+\n\nSELECT * FROM store;\n+------------+------+\n| product_id | qty |\n+------------+------+\n| 1 | 5 |\n| 2 | 5 |\n| 3 | 7 |\n| 4 | 7 |\n+------------+------+\n\nURL: https://mariadb.com/kb/en/order-by/','','https://mariadb.com/kb/en/order-by/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (436,27,'GROUP BY','Use the GROUP BY clause in a SELECT statement to group rows together that have\nthe same value in one or more column, or the same computed value using\nexpressions with any functions and operators except grouping functions. When\nyou use a GROUP BY clause, you will get a single result row for each group of\nrows that have the same value for the expression given in GROUP BY.\n\nWhen grouping rows, grouping values are compared as if by the = operator. For\nstring values, the = operator ignores trailing whitespace and may normalize\ncharacters and ignore case, depending on the collation in use.\n\nYou can use any of the grouping functions in your select expression. Their\nvalues will be calculated based on all the rows that have been grouped\ntogether for each result row. If you select a non-grouped column or a value\ncomputed from a non-grouped column, it is undefined which row the returned\nvalue is taken from. This is not permitted if the ONLY_FULL_GROUP_BY SQL_MODE\nis used.\n\nYou can use multiple expressions in the GROUP BY clause, separated by commas.\nRows are grouped together if they match on each of the expressions.\n\nYou can also use a single integer as the grouping expression. If you use an\ninteger n, the results will be grouped by the nth column in the select\nexpression.\n\nThe WHERE clause is applied before the GROUP BY clause. It filters\nnon-aggregated rows before the rows are grouped together. To filter grouped\nrows based on aggregate values, use the HAVING clause. The HAVING clause takes\nany expression and evaluates it as a boolean, just like the WHERE clause. You\ncan use grouping functions in the HAVING clause. As with the select\nexpression, if you reference non-grouped columns in the HAVING clause, the\nbehavior is undefined.\n\nBy default, if a GROUP BY clause is present, the rows in the output will be\nsorted by the expressions used in the GROUP BY. You can also specify ASC or\nDESC (ascending, descending) after those expressions, like in ORDER BY. The\ndefault is ASC.\n\nIf you want the rows to be sorted by another field, you can add an explicit\nORDER BY. If you don\'t want the result to be ordered, you can add ORDER BY\nNULL.\n\nWITH ROLLUP\n-----------\n\nThe WITH ROLLUP modifer adds extra rows to the resultset that represent\nsuper-aggregate summaries. For a full description with examples, see SELECT\nWITH ROLLUP.\n\nGROUP BY Examples\n-----------------\n\nConsider the following table that records how many times each user has played\nand won a game:\n\nCREATE TABLE plays (name VARCHAR(16), plays INT, wins INT);\nINSERT INTO plays VALUES \n (\"John\", 20, 5),\n (\"Robert\", 22, 8),\n (\"Wanda\", 32, 8),\n (\"Susan\", 17, 3);\n\nGet a list of win counts along with a count:\n\nSELECT wins, COUNT(*) FROM plays GROUP BY wins;\n+------+----------+\n| wins | COUNT(*) |\n+------+----------+\n| 3 | 1 |\n| 5 | 1 |\n| 8 | 2 |\n+------+----------+\n3 rows in set (0.00 sec)\n\nThe GROUP BY expression can be a computed value, and can refer back to an\nidentifer specified with AS. Get a list of win averages along with a count:\n\nSELECT (wins / plays) AS winavg, COUNT(*) FROM plays GROUP BY winavg;\n+--------+----------+\n| winavg | COUNT(*) |\n+--------+----------+\n| 0.1765 | 1 |\n| 0.2500 | 2 |\n| 0.3636 | 1 |\n+--------+----------+\n3 rows in set (0.00 sec)\n\nYou can use any grouping function in the select expression. For each win\naverage as above, get a list of the average play count taken to get that\naverage:\n\nSELECT (wins / plays) AS winavg, AVG(plays) FROM plays \n GROUP BY winavg;\n+--------+------------+\n| winavg | AVG(plays) |\n+--------+------------+\n| 0.1765 | 17.0000 |\n| 0.2500 | 26.0000 |\n| 0.3636 | 22.0000 |\n+--------+------------+\n3 rows in set (0.00 sec)\n\nYou can filter on aggregate information using the HAVING clause. The HAVING\nclause is applied after GROUP BY and allows you to filter on aggregate data\nthat is not available to the WHERE clause. Restrict the above example to\nresults that involve an average number of plays over 20:\n\nSELECT (wins / plays) AS winavg, AVG(plays) FROM plays \n GROUP BY winavg HAVING AVG(plays) > 20;\n+--------+------------+\n| winavg | AVG(plays) |\n+--------+------------+\n| 0.2500 | 26.0000 |\n| 0.3636 | 22.0000 |\n+--------+------------+\n2 rows in set (0.00 sec)\n\nURL: https://mariadb.com/kb/en/group-by/','','https://mariadb.com/kb/en/group-by/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (437,27,'WITH','MariaDB starting with 10.2.1\n----------------------------\nCommon Table Expressions were introduced in MariaDB 10.2.1.\n\nSyntax\n------\n\nWITH [RECURSIVE] table_reference [(columns_list)] AS (\n SELECT ...\n)\n[CYCLE cycle_column_list RESTRICT]\nSELECT ...\n\nDescription\n-----------\n\nThe WITH keyword signifies a Common Table Expression (CTE). It allows you to\nrefer to a subquery expression many times in a query, as if having a temporary\ntable that only exists for the duration of a query.\n\nThere are two kinds of CTEs:\n\n* Non-Recursive\n* Recursive (signified by the RECURSIVE keyword, supported since MariaDB\n10.2.2)\n\nYou can use table_reference as any normal table in the external SELECT part.\nYou can also use WITH in subqueries, as well as with EXPLAIN and SELECT.\n\nPoorly-formed recursive CTEs can in theory cause infinite loops. The\nmax_recursive_iterations system variable limits the number of recursions.\n\nCYCLE ... RESTRICT\n------------------\n\nMariaDB starting with 10.5.2\n----------------------------\nThe CYCLE clause enables CTE cycle detection, avoiding excessive or infinite\nloops, MariaDB supports a relaxed, non-standard grammar.\n\nThe SQL Standard permits a CYCLE clause, as follows:\n\nWITH RECURSIVE ... (\n ...\n)\nCYCLE <cycle column list>\nSET <cycle mark column> TO <cycle mark value> DEFAULT <non-cycle mark value>\nUSING <path column>\n\nwhere all clauses are mandatory.\n\nMariaDB does not support this, but from 10.5.2 permits a non-standard relaxed\ngrammar, as follows:\n\nWITH RECURSIVE ... (\n ...\n)\nCYCLE <cycle column list> RESTRICT\n\nWith the use of CYCLE ... RESTRICT it makes no difference whether the CTE uses\nUNION ALL or UNION DISTINCT anymore. UNION ALL means \"all rows, but without\ncycles\", which is exactly what the CYCLE clause enables. And UNION DISTINCT\nmeans all rows should be different, which, again, is what will happen — as\nuniqueness is enforced over a subset of columns, complete rows will\nautomatically all be different.\n\nExamples\n--------\n\nBelow is an example with the WITH at the top level:\n\nWITH t AS (SELECT a FROM t1 WHERE b >= \'c\') \n SELECT * FROM t2, t WHERE t2.c = t.a;\n\nThe example below uses WITH in a subquery:\n\nSELECT t1.a, t1.b FROM t1, t2\n WHERE t1.a > t2.c\n AND t2.c IN(WITH t AS (SELECT * FROM t1 WHERE t1.a < 5)\n SELECT t2.c FROM t2, t WHERE t2.c = t.a);\n\nBelow is an example of a Recursive CTE:\n\nWITH RECURSIVE ancestors AS \n ( SELECT * FROM folks\n WHERE name=\"Alex\"\n UNION\n SELECT f.*\n FROM folks AS f, ancestors AS a\n WHERE f.id = a.father OR f.id = a.mother )\nSELECT * FROM ancestors;\n\nTake the following structure, and data,\n\nCREATE TABLE t1 (from_ int, to_ int);\nINSERT INTO t1 VALUES (1,2), (1,100), (2,3), (3,4), (4,1);\nSELECT * FROM t1;\n+-------+------+\n| from_ | to_ |\n+-------+------+\n| 1 | 2 |\n| 1 | 100 |\n| 2 | 3 |\n| 3 | 4 |\n| 4 | 1 |\n+-------+------+\n\nGiven the above, the following query would theoretically result in an infinite\nloop due to the last record in t1 (note that max_recursive_iterations is set\nto 10 for the purposes of this example, to avoid the excessive number of\ncycles):\n\nSET max_recursive_iterations=10;\n\nWITH RECURSIVE cte (depth, from_, to_) AS ( \n SELECT 0,1,1 UNION DISTINCT SELECT depth+1, t1.from_, t1.to_\n FROM t1, cte WHERE t1.from_ = cte.to_\n) \nSELECT * FROM cte;\n+-------+-------+------+\n| depth | from_ | to_ |\n+-------+-------+------+\n| 0 | 1 | 1 |\n| 1 | 1 | 2 |\n| 1 | 1 | 100 |\n| 2 | 2 | 3 |\n| 3 | 3 | 4 |\n| 4 | 4 | 1 |\n| 5 | 1 | 2 |\n| 5 | 1 | 100 |\n| 6 | 2 | 3 |\n| 7 | 3 | 4 |\n| 8 | 4 | 1 |\n| 9 | 1 | 2 |\n| 9 | 1 | 100 |\n| 10 | 2 | 3 |\n+-------+-------+------+\n\nHowever, the CYCLE ... RESTRICT clause (from MariaDB 10.5.2) can overcome this:\n\nWITH RECURSIVE cte (depth, from_, to_) AS ( \n SELECT 0,1,1 UNION SELECT depth+1, t1.from_, t1.to_\n FROM t1, cte WHERE t1.from_ = cte.to_\n) \nCYCLE from_, to_ RESTRICT \nSELECT * FROM cte;\n+-------+-------+------+\n| depth | from_ | to_ |\n+-------+-------+------+\n| 0 | 1 | 1 |\n| 1 | 1 | 2 |\n| 1 | 1 | 100 |\n| 2 | 2 | 3 |\n| 3 | 3 | 4 |\n| 4 | 4 | 1 |\n+-------+-------+------+\n\nURL: https://mariadb.com/kb/en/with/','','https://mariadb.com/kb/en/with/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (438,27,'Non-Recursive Common Table Expressions Overview','Common Table Expressions (CTEs) are a standard SQL feature, and are\nessentially temporary named result sets. There are two kinds of CTEs:\nNon-Recursive, which this article covers; and Recursive.\n\nNon-Recursive CTEs\n------------------\n\nThe WITH keyword signifies a CTE. It is given a name, followed by a body (the\nmain query) as follows:\n\nCTEs are similar to derived tables. For example\n\nWITH engineers AS \n ( SELECT * FROM employees\n WHERE dept = \'Engineering\' )\n\nSELECT * FROM engineers\nWHERE ...\n\nSELECT * FROM\n ( SELECT * FROM employees\n WHERE dept = \'Engineering\' ) AS engineers\nWHERE\n...\n\nA non-recursive CTE is basically a query-local VIEW. There are several\nadvantages and caveats to them. The syntax is more readable than nested FROM\n(SELECT ...). A CTE can refer to another and it can be referenced from\nmultiple places.\n\nA CTE referencing Another CTE\n-----------------------------\n\nUsing this format makes for a more readable SQL than a nested FROM(SELECT ...)\nclause. Below is an example of this:\n\nWITH engineers AS (\nSELECT * FROM employees\nWHERE dept IN(\'Development\',\'Support\') ),\neu_engineers AS ( SELECT * FROM engineers WHERE country IN(\'NL\',...) )\nSELECT\n...\nFROM eu_engineers;\n\nMultiple Uses of a CTE\n----------------------\n\nThis can be an \'anti-self join\', for example:\n\nWITH engineers AS (\nSELECT * FROM employees\nWHERE dept IN(\'Development\',\'Support\') )\n\nSELECT * FROM engineers E1\nWHERE NOT EXISTS\n (SELECT 1 FROM engineers E2\n WHERE E2.country=E1.country\n AND E2.name <> E1.name );\n\nOr, for year-over-year comparisons, for example:\n\nWITH sales_product_year AS (\nSELECT product, YEAR(ship_date) AS year,\nSUM(price) AS total_amt\nFROM item_sales\nGROUP BY product, year )\n\nSELECT *\nFROM sales_product_year CUR,\nsales_product_year PREV,\nWHERE CUR.product=PREV.product \nAND CUR.year=PREV.year + 1 \nAND CUR.total_amt > PREV.total_amt\n\nAnother use is to compare individuals against their group. Below is an example\nof how this might be executed:\n\nWITH sales_product_year AS (\nSELECT product,\nYEAR(ship_date) AS year,\nSUM(price) AS total_amt\nFROM item_sales\nGROUP BY product, year\n)\n\nSELECT * \nFROM sales_product_year S1\nWHERE\ntotal_amt > \n (SELECT 0.1 * SUM(total_amt)\n FROM sales_product_year S2\n WHERE S2.year = S1.year)\n\nURL: https://mariadb.com/kb/en/non-recursive-common-table-expressions-overview/','','https://mariadb.com/kb/en/non-recursive-common-table-expressions-overview/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (439,27,'Recursive Common Table Expressions Overview','Common Table Expressions (CTEs) are a standard SQL feature, and are\nessentially temporary named result sets. CTEs first appeared in the SQL\nstandard in 1999, and the first implementations began appearing in 2007.\n\nThere are two kinds of CTEs:\n\n* Non-recursive\n* Recursive, which this article covers.\n\nSQL is generally poor at recursive structures.\n\nCTEs permit a query to reference itself. A recursive CTE will repeatedly\nexecute subsets of the data until it obtains the complete result set. This\nmakes it particularly useful for handing hierarchical or tree-structured data.\nmax_recursive_iterations avoids infinite loops.\n\nSyntax example\n--------------\n\nWITH RECURSIVE signifies a recursive CTE. It is given a name, followed by a\nbody (the main query) as follows:\n\nComputation\n-----------\n\nGiven the following structure:\n\nFirst execute the anchor part of the query:\n\nNext, execute the recursive part of the query:\n\nSummary so far\n--------------\n\nwith recursive R as (\n select anchor_data\n union [all]\n select recursive_part\n from R, ...\n)\nselect ...\n\n* Compute anchor_data\n* Compute recursive_part to get the new data\n* if (new data is non-empty) goto 2;\n\nCAST to avoid truncating data\n-----------------------------\n\nAs currently implemented by MariaDB and by the SQL Standard, data may be\ntruncated if not correctly cast. It is necessary to CAST the column to the\ncorrect width if the CTE\'s recursive part produces wider values for a column\nthan the CTE\'s nonrecursive part. Some other DBMS give an error in this\nsituation, and MariaDB\'s behavior may change in future - see MDEV-12325. See\nthe examples below.\n\nExamples\n--------\n\nTransitive closure - determining bus destinations\n-------------------------------------------------\n\nSample data:\n\nCREATE TABLE bus_routes (origin varchar(50), dst varchar(50));\nINSERT INTO bus_routes VALUES \n (\'New York\', \'Boston\'),\n (\'Boston\', \'New York\'),\n (\'New York\', \'Washington\'),\n (\'Washington\', \'Boston\'),\n (\'Washington\', \'Raleigh\');\n\nNow, we want to return the bus destinations with New York as the origin:\n\nWITH RECURSIVE bus_dst as ( \n SELECT origin as dst FROM bus_routes WHERE origin=\'New York\'\n UNION\n SELECT bus_routes.dst FROM bus_routes JOIN bus_dst ON bus_dst.dst=\nbus_routes.origin \n) \nSELECT * FROM bus_dst;\n+------------+\n| dst |\n+------------+\n| New York |\n| Boston |\n| Washington |\n| Raleigh |\n+------------+\n\nThe above example is computed as follows:\n\nFirst, the anchor data is calculated:\n\n* Starting from New York\n* Boston and Washington are added\n\nNext, the recursive part:\n\n* Starting from Boston and then Washington\n* Raleigh is added\n* UNION excludes nodes that are already present.\n\nComputing paths - determining bus routes\n----------------------------------------\n\nThis time, we are trying to get bus routes such as \"New York -> Washington ->\nRaleigh\".\n\nUsing the same sample data as the previous example:\n\nWITH RECURSIVE paths (cur_path, cur_dest) AS (\n SELECT origin, origin FROM bus_routes WHERE origin=\'New York\'\n UNION\n SELECT CONCAT(paths.cur_path, \',\', bus_routes.dst), bus_routes.dst\n FROM paths\n JOIN bus_routes\n ON paths.cur_dest = bus_routes.origin AND\n NOT FIND_IN_SET(bus_routes.dst, paths.cur_path)\n) \nSELECT * FROM paths;\n+-----------------------------+------------+\n| cur_path | cur_dest |\n+-----------------------------+------------+\n| New York | New York |\n| New York,Boston | Boston |\n| New York,Washington | Washington |\n| New York,Washington,Boston | Boston |\n| New York,Washington,Raleigh | Raleigh |\n+-----------------------------+------------+\n\nCAST to avoid data truncation\n-----------------------------\n\nIn the following example, data is truncated because the results are not\nspecifically cast to a wide enough type:\n\nWITH RECURSIVE tbl AS (\n SELECT NULL AS col\n UNION\n SELECT \"THIS NEVER SHOWS UP\" AS col FROM tbl\n)\nSELECT col FROM tbl\n+------+\n| col |\n+------+\n| NULL |\n| |\n+------+\n\nExplicitly use CAST to overcome this:\n\nWITH RECURSIVE tbl AS (\n SELECT CAST(NULL AS CHAR(50)) AS col\n UNION SELECT \"THIS NEVER SHOWS UP\" AS col FROM tbl\n) \nSELECT * FROM tbl;\n+---------------------+\n| col |\n+---------------------+\n| NULL |\n| THIS NEVER SHOWS UP |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/recursive-common-table-expressions-overview/','','https://mariadb.com/kb/en/recursive-common-table-expressions-overview/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (440,27,'SELECT WITH ROLLUP','Syntax\n------\n\nSee SELECT for the full syntax.\n\nDescription\n-----------\n\nThe WITH ROLLUP modifier adds extra rows to the resultset that represent\nsuper-aggregate summaries. The super-aggregated column is represented by a\nNULL value. Multiple aggregates over different columns will be added if there\nare multiple GROUP BY columns.\n\nThe LIMIT clause can be used at the same time, and is applied after the WITH\nROLLUP rows have been added.\n\nWITH ROLLUP cannot be used with ORDER BY. Some sorting is still possible by\nusing ASC or DESC clauses with the GROUP BY column, although the\nsuper-aggregate rows will always be added last.\n\nExamples\n--------\n\nThese examples use the following sample table\n\nCREATE TABLE booksales ( \n country VARCHAR(35), genre ENUM(\'fiction\',\'non-fiction\'), year YEAR, sales\nINT);\n\nINSERT INTO booksales VALUES\n (\'Senegal\',\'fiction\',2014,12234), (\'Senegal\',\'fiction\',2015,15647),\n (\'Senegal\',\'non-fiction\',2014,64980), (\'Senegal\',\'non-fiction\',2015,78901),\n (\'Paraguay\',\'fiction\',2014,87970), (\'Paraguay\',\'fiction\',2015,76940),\n (\'Paraguay\',\'non-fiction\',2014,8760), (\'Paraguay\',\'non-fiction\',2015,9030);\n\nThe addition of the WITH ROLLUP modifier in this example adds an extra row\nthat aggregates both years:\n\nSELECT year, SUM(sales) FROM booksales GROUP BY year;\n+------+------------+\n| year | SUM(sales) |\n+------+------------+\n| 2014 | 173944 |\n| 2015 | 180518 |\n+------+------------+\n2 rows in set (0.08 sec)\n\nSELECT year, SUM(sales) FROM booksales GROUP BY year WITH ROLLUP;\n+------+------------+\n| year | SUM(sales) |\n+------+------------+\n| 2014 | 173944 |\n| 2015 | 180518 |\n| NULL | 354462 |\n+------+------------+\n\nIn the following example, each time the genre, the year or the country change,\nanother super-aggregate row is added:\n\nSELECT country, year, genre, SUM(sales) \n FROM booksales GROUP BY country, year, genre;\n+----------+------+-------------+------------+\n| country | year | genre | SUM(sales) |\n+----------+------+-------------+------------+\n| Paraguay | 2014 | fiction | 87970 |\n| Paraguay | 2014 | non-fiction | 8760 |\n| Paraguay | 2015 | fiction | 76940 |\n| Paraguay | 2015 | non-fiction | 9030 |\n| Senegal | 2014 | fiction | 12234 |\n| Senegal | 2014 | non-fiction | 64980 |\n| Senegal | 2015 | fiction | 15647 |\n| Senegal | 2015 | non-fiction | 78901 |\n+----------+------+-------------+------------+\n\nSELECT country, year, genre, SUM(sales) \n FROM booksales GROUP BY country, year, genre WITH ROLLUP;\n+----------+------+-------------+------------+\n| country | year | genre | SUM(sales) |\n+----------+------+-------------+------------+\n| Paraguay | 2014 | fiction | 87970 |\n| Paraguay | 2014 | non-fiction | 8760 |\n| Paraguay | 2014 | NULL | 96730 |\n| Paraguay | 2015 | fiction | 76940 |\n| Paraguay | 2015 | non-fiction | 9030 |\n| Paraguay | 2015 | NULL | 85970 |\n| Paraguay | NULL | NULL | 182700 |\n| Senegal | 2014 | fiction | 12234 |\n| Senegal | 2014 | non-fiction | 64980 |\n| Senegal | 2014 | NULL | 77214 |\n| Senegal | 2015 | fiction | 15647 |\n| Senegal | 2015 | non-fiction | 78901 |\n| Senegal | 2015 | NULL | 94548 |\n| Senegal | NULL | NULL | 171762 |\n| NULL | NULL | NULL | 354462 |\n+----------+------+-------------+------------+\n\nThe LIMIT clause, applied after WITH ROLLUP:\n\nSELECT country, year, genre, SUM(sales) \n FROM booksales GROUP BY country, year, genre WITH ROLLUP LIMIT 4;\n+----------+------+-------------+------------+\n| country | year | genre | SUM(sales) |\n+----------+------+-------------+------------+\n| Paraguay | 2014 | fiction | 87970 |\n| Paraguay | 2014 | non-fiction | 8760 |\n| Paraguay | 2014 | NULL | 96730 |\n| Paraguay | 2015 | fiction | 76940 |\n+----------+------+-------------+------------+\n\nSorting by year descending:\n\nSELECT country, year, genre, SUM(sales) \n FROM booksales GROUP BY country, year DESC, genre WITH ROLLUP;\n+----------+------+-------------+------------+\n| country | year | genre | SUM(sales) |\n+----------+------+-------------+------------+\n| Paraguay | 2015 | fiction | 76940 |\n| Paraguay | 2015 | non-fiction | 9030 |\n| Paraguay | 2015 | NULL | 85970 |\n| Paraguay | 2014 | fiction | 87970 |\n| Paraguay | 2014 | non-fiction | 8760 |\n| Paraguay | 2014 | NULL | 96730 |\n| Paraguay | NULL | NULL | 182700 |\n| Senegal | 2015 | fiction | 15647 |\n| Senegal | 2015 | non-fiction | 78901 |\n| Senegal | 2015 | NULL | 94548 |\n| Senegal | 2014 | fiction | 12234 |\n| Senegal | 2014 | non-fiction | 64980 |\n| Senegal | 2014 | NULL | 77214 |\n| Senegal | NULL | NULL | 171762 |\n| NULL | NULL | NULL | 354462 |\n+----------+------+-------------+------------+\n\nURL: https://mariadb.com/kb/en/select-with-rollup/','','https://mariadb.com/kb/en/select-with-rollup/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (441,27,'SELECT INTO OUTFILE','Syntax\n------\n\nSELECT ... INTO OUTFILE \'file_name\'\n [CHARACTER SET charset_name]\n [export_options]\n\nexport_options:\n [{FIELDS | COLUMNS}\n [TERMINATED BY \'string\']\n [[OPTIONALLY] ENCLOSED BY \'char\']\n [ESCAPED BY \'char\']\n ]\n [LINES\n [STARTING BY \'string\']\n [TERMINATED BY \'string\']\n ]\n\nDescription\n-----------\n\nSELECT INTO OUTFILE writes the resulting rows to a file, and allows the use of\ncolumn and row terminators to specify a particular output format. The default\nis to terminate fields with tabs (\\t) and lines with newlines (\\n).\n\nThe file must not exist. It cannot be overwritten. A user needs the FILE\nprivilege to run this statement. Also, MariaDB needs permission to write files\nin the specified location. If the secure_file_priv system variable is set to a\nnon-empty directory name, the file can only be written to that directory.\n\nThe LOAD DATA INFILE statement complements SELECT INTO OUTFILE.\n\nCharacter-sets\n--------------\n\nThe CHARACTER SET clause specifies the character set in which the results are\nto be written. Without the clause, no conversion takes place (the binary\ncharacter set). In this case, if there are multiple character sets, the output\nwill contain these too, and may not easily be able to be reloaded.\n\nIn cases where you have two servers using different character-sets, using\nSELECT INTO OUTFILE to transfer data from one to the other can have unexpected\nresults. To ensure that MariaDB correctly interprets the escape sequences, use\nthe CHARACTER SET clause on both the SELECT INTO OUTFILE statement and the\nsubsequent LOAD DATA INFILE statement.\n\nExample\n-------\n\nThe following example produces a file in the CSV format:\n\nSELECT customer_id, firstname, surname from customer\n INTO OUTFILE \'/exportdata/customers.txt\'\n FIELDS TERMINATED BY \',\' OPTIONALLY ENCLOSED BY \'\"\'\n LINES TERMINATED BY \'\\n\';\n\nThe following ANSI syntax is also supported for simple SELECT without UNION\n\nSELECT customer_id, firstname, surname INTO OUTFILE \'/exportdata/customers.txt\'\n FIELDS TERMINATED BY \',\' OPTIONALLY ENCLOSED BY \'\"\'\n LINES TERMINATED BY \'\\n\'\n FROM customers;\n\nIf you want to use the ANSI syntax with UNION or similar construct you have to\nuse the syntax:\n\nSELECT * INTO OUTFILE \"/tmp/skr3\" FROM (SELECT * FROM t1 UNION SELECT * FROM\nt1);\n\nURL: https://mariadb.com/kb/en/select-into-outfile/','','https://mariadb.com/kb/en/select-into-outfile/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (442,27,'SELECT INTO DUMPFILE','Syntax\n------\n\nSELECT ... INTO DUMPFILE \'file_path\'\n\nDescription\n-----------\n\nSELECT ... INTO DUMPFILE is a SELECT clause which writes the resultset into a\nsingle unformatted row, without any separators, in a file. The results will\nnot be returned to the client.\n\nfile_path can be an absolute path, or a relative path starting from the data\ndirectory. It can only be specified as a string literal, not as a variable.\nHowever, the statement can be dynamically composed and executed as a prepared\nstatement to work around this limitation.\n\nThis statement is binary-safe and so is particularly useful for writing BLOB\nvalues to file. It can be used, for example, to copy an image or an audio\ndocument from the database to a file. SELECT ... INTO FILE can be used to save\na text file.\n\nThe file must not exist. It cannot be overwritten. A user needs the FILE\nprivilege to run this statement. Also, MariaDB needs permission to write files\nin the specified location. If the secure_file_priv system variable is set to a\nnon-empty directory name, the file can only be written to that directory.\n\nSince MariaDB 5.1, the character_set_filesystem system variable has controlled\ninterpretation of file names that are given as literal strings.\n\nExample\n-------\n\nSELECT _utf8\'Hello world!\' INTO DUMPFILE \'/tmp/world\';\n\nSELECT LOAD_FILE(\'/tmp/world\') AS world;\n+--------------+\n| world |\n+--------------+\n| Hello world! |\n+--------------+\n\nURL: https://mariadb.com/kb/en/select-into-dumpfile/','','https://mariadb.com/kb/en/select-into-dumpfile/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (443,27,'FOR UPDATE','InnoDB supports row-level locking. Selected rows can be locked using LOCK IN\nSHARE MODE or FOR UPDATE. In both cases, a lock is acquired on the rows read\nby the query, and it will be released when the current transaction is\ncommitted.\n\nThe FOR UPDATE clause of SELECT applies only when autocommit is set to 0 or\nthe SELECT is enclosed in a transaction. A lock is acquired on the rows, and\nother transactions are prevented from writing the rows, acquire locks, and\nfrom reading them (unless their isolation level is READ UNCOMMITTED).\n\nIf autocommit is set to 1, the LOCK IN SHARE MODE and FOR UPDATE clauses have\nno effect.\n\nIf the isolation level is set to SERIALIZABLE, all plain SELECT statements are\nconverted to SELECT ... LOCK IN SHARE MODE.\n\nExample\n-------\n\nSELECT * FROM trans WHERE period=2001 FOR UPDATE;\n\nURL: https://mariadb.com/kb/en/for-update/','','https://mariadb.com/kb/en/for-update/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (444,27,'LOCK IN SHARE MODE','InnoDB supports row-level locking. Selected rows can be locked using LOCK IN\nSHARE MODE or FOR UPDATE. In both cases, a lock is acquired on the rows read\nby the query, and it will be released when the current transaction is\ncommitted.\n\nWhen LOCK IN SHARE MODE is specified in a SELECT statement, MariaDB will wait\nuntil all transactions that have modified the rows are committed. Then, a\nwrite lock is acquired. All transactions can read the rows, but if they want\nto modify them, they have to wait until your transaction is committed.\n\nIf autocommit is set to 1 (the default), the LOCK IN SHARE MODE and FOR UPDATE\nclauses have no effect.\n\nURL: https://mariadb.com/kb/en/lock-in-share-mode/','','https://mariadb.com/kb/en/lock-in-share-mode/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (445,27,'Optimizer Hints','Optimizer hints\n---------------\n\nThere are some options available in SELECT to affect the execution plan. These\nare known as optimizer hints.\n\nHIGH PRIORITY\n-------------\n\nHIGH_PRIORITY gives the statement a higher priority. If the table is locked,\nhigh priority SELECTs will be executed as soon as the lock is released, even\nif other statements are queued. HIGH_PRIORITY applies only if the storage\nengine only supports table-level locking (MyISAM, MEMORY, MERGE). See\nHIGH_PRIORITY and LOW_PRIORITY clauses for details.\n\nSQL_CACHE / SQL_NO_CACHE\n------------------------\n\nIf the query_cache_type system variable is set to 2 or DEMAND, and the current\nstatement is cacheable, SQL_CACHE causes the query to be cached and\nSQL_NO_CACHE causes the query not to be cached. For UNIONs, SQL_CACHE or\nSQL_NO_CACHE should be specified for the first query. See also The Query Cache\nfor more detail and a list of the types of statements that aren\'t cacheable.\n\nSQL_BUFFER_RESULT\n-----------------\n\nSQL_BUFFER_RESULT forces the optimizer to use a temporary table to process the\nresult. This is useful to free locks as soon as possible.\n\nSQL_SMALL_RESULT / SQL_BIG_RESULT\n---------------------------------\n\nSQL_SMALL_RESULT and SQL_BIG_RESULT tell the optimizer whether the result is\nvery big or not. Usually, GROUP BY and DISTINCT operations are performed using\na temporary table. Only if the result is very big, using a temporary table is\nnot convenient. The optimizer automatically knows if the result is too big,\nbut you can force the optimizer to use a temporary table with\nSQL_SMALL_RESULT, or avoid the temporary table using SQL_BIG_RESULT.\n\nSTRAIGHT_JOIN\n-------------\n\nSTRAIGHT_JOIN applies to the JOIN queries, and tells the optimizer that the\ntables must be read in the order they appear in the SELECT. For const and\nsystem table this options is sometimes ignored.\n\nSQL_CALC_FOUND_ROWS\n-------------------\n\nSQL_CALC_FOUND_ROWS is only applied when using the LIMIT clause. If this\noption is used, MariaDB will count how many rows would match the query,\nwithout the LIMIT clause. That number can be retrieved in the next query,\nusing FOUND_ROWS().\n\nUSE/FORCE/IGNORE INDEX\n----------------------\n\nUSE INDEX, FORCE INDEX and IGNORE INDEX constrain the query planning to a\nspecific index.\n\nFor further information about some of these options, see How to force query\nplans.\n\nURL: https://mariadb.com/kb/en/optimizer-hints/','','https://mariadb.com/kb/en/optimizer-hints/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (446,27,'PROCEDURE','The PROCEDURE clause of SELECT passes the whole result set to a Procedure\nwhich will process it. These Procedures are not Stored Procedures, and can\nonly be written in the C language, so it is necessary to recompile the server.\n\nCurrently, the only available procedure is ANALYSE, which examines the\nresultset and suggests the optimal datatypes for each column. It is defined in\nthe sql/sql_analyse.cc file, and can be used as an example to create more\nProcedures.\n\nThis clause cannot be used in a view\'s definition.\n\nURL: https://mariadb.com/kb/en/procedure/','','https://mariadb.com/kb/en/procedure/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (447,27,'DUAL','Description\n-----------\n\nYou are allowed to specify DUAL as a dummy table name in situations where no\ntables are referenced, such as the following SELECT statement:\n\nSELECT 1 + 1 FROM DUAL;\n+-------+\n| 1 + 1 |\n+-------+\n| 2 |\n+-------+\n\nDUAL is purely for the convenience of people who require that all SELECT\nstatements should have FROM and possibly other clauses. MariaDB ignores the\nclauses. MariaDB does not require FROM DUAL if no tables are referenced.\n\nFROM DUAL could be used when you only SELECT computed values, but require a\nWHERE clause, perhaps to test that a script correctly handles empty resultsets:\n\nSELECT 1 FROM DUAL WHERE FALSE;\nEmpty set (0.00 sec)\n\nURL: https://mariadb.com/kb/en/dual/','','https://mariadb.com/kb/en/dual/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (448,27,'SELECT ... OFFSET ... FETCH','MariaDB starting with 10.6.0\n----------------------------\nSELECT ... OFFSET ... FETCH was introduced in MariaDB 10.6.\n\nSyntax\n------\n\nOFFSET start { ROW | ROWS }\nFETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES }\n\nDescription\n-----------\n\nThe OFFSET clause allows one to return only those elements of a resultset that\ncome after a specified offset. The FETCH clause specifies the number of rows\nto return, while ONLY or WITH TIES specifies whether or not to also return any\nfurther results that tie for last place according to the ordered resultset.\n\nEither the singular ROW or the plural ROWS can be used after the OFFSET and\nFETCH clauses; the choice has no impact on the results.\n\nIn the case of WITH TIES, an ORDER BY clause is required, otherwise an ERROR\nwill be returned.\n\nSELECT i FROM t1 FETCH FIRST 2 ROWS WITH TIES;\nERROR 4180 (HY000): FETCH ... WITH TIES requires ORDER BY clause to be present\n\nExamples\n--------\n\nGiven a table with 6 rows:\n\nCREATE OR REPLACE TABLE t1 (i INT);\nINSERT INTO t1 VALUES (1),(2),(3),(4), (4), (5);\nSELECT i FROM t1 ORDER BY i ASC;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 3 |\n| 4 |\n| 4 |\n| 5 |\n+------+\n\nOFFSET 2 allows one to skip the first two results.\n\nSELECT i FROM t1 ORDER BY i ASC OFFSET 2 ROWS;\n+------+\n| i |\n+------+\n| 3 |\n| 4 |\n| 4 |\n| 5 |\n+------+\n\nFETCH FIRST 3 ROWS ONLY limits the results to three rows only\n\nSELECT i FROM t1 ORDER BY i ASC OFFSET 1 ROWS FETCH FIRST 3 ROWS ONLY;\n+------+\n| i |\n+------+\n| 2 |\n| 3 |\n| 4 |\n+------+\n\nThe same outcome can also be achieved with the LIMIT clause:\n\nSELECT i FROM t1 ORDER BY i ASC LIMIT 3 OFFSET 1;\n+------+\n| i |\n+------+\n| 2 |\n| 3 |\n| 4 |\n+------+\n\nWITH TIES ensures the tied result 4 is also returned.\n\nSELECT i FROM t1 ORDER BY i ASC OFFSET 1 ROWS FETCH FIRST 3 ROWS WITH TIES;\n+------+\n| i |\n+------+\n| 2 |\n| 3 |\n| 4 |\n| 4 |\n+------+\n\nURL: https://mariadb.com/kb/en/select-offset-fetch/','','https://mariadb.com/kb/en/select-offset-fetch/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (449,27,'INSERT','Syntax\n------\n\nINSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]\n [INTO] tbl_name [PARTITION (partition_list)] [(col,...)]\n {VALUES | VALUE} ({expr | DEFAULT},...),(...),...\n [ ON DUPLICATE KEY UPDATE\n col=expr\n [, col=expr] ... ] [RETURNING select_expr\n [, select_expr ...]]\n\nOr:\n\nINSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]\n [INTO] tbl_name [PARTITION (partition_list)]\n SET col={expr | DEFAULT}, ...\n [ ON DUPLICATE KEY UPDATE\n col=expr\n [, col=expr] ... ] [RETURNING select_expr\n [, select_expr ...]]\n\nOr:\n\nINSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]\n [INTO] tbl_name [PARTITION (partition_list)] [(col,...)]\n SELECT ...\n [ ON DUPLICATE KEY UPDATE\n col=expr\n [, col=expr] ... ] [RETURNING select_expr\n [, select_expr ...]]\n\nThe INSERT statement is used to insert new rows into an existing table. The\nINSERT ... VALUES and INSERT ... SET forms of the statement insert rows based\non explicitly specified values. The INSERT ... SELECT form inserts rows\nselected from another table or tables. INSERT ... SELECT is discussed further\nin the INSERT ... SELECT article.\n\nThe table name can be specified in the form db_name.tbl_name or, if a default\ndatabase is selected, in the form tbl_name (see Identifier Qualifiers). This\nallows to use INSERT ... SELECT to copy rows between different databases.\n\nThe PARTITION clause can be used in both the INSERT and the SELECT part. See\nPartition Pruning and Selection for details.\n\nMariaDB starting with 10.5\n--------------------------\nThe RETURNING clause was introduced in MariaDB 10.5.\n\nThe columns list is optional. It specifies which values are explicitly\ninserted, and in which order. If this clause is not specified, all values must\nbe explicitly specified, in the same order they are listed in the table\ndefinition.\n\nThe list of value follow the VALUES or VALUE keyword (which are\ninterchangeable, regardless how much values you want to insert), and is\nwrapped by parenthesis. The values must be listed in the same order as the\ncolumns list. It is possible to specify more than one list to insert more than\none rows with a single statement. If many rows are inserted, this is a speed\noptimization.\n\nFor one-row statements, the SET clause may be more simple, because you don\'t\nneed to remember the columns order. All values are specified in the form col =\nexpr.\n\nValues can also be specified in the form of a SQL expression or subquery.\nHowever, the subquery cannot access the same table that is named in the INTO\nclause.\n\nIf you use the LOW_PRIORITY keyword, execution of the INSERT is delayed until\nno other clients are reading from the table. If you use the HIGH_PRIORITY\nkeyword, the statement has the same priority as SELECTs. This affects only\nstorage engines that use only table-level locking (MyISAM, MEMORY, MERGE).\nHowever, if one of these keywords is specified, concurrent inserts cannot be\nused. See HIGH_PRIORITY and LOW_PRIORITY clauses for details.\n\nINSERT DELAYED\n--------------\n\nFor more details on the DELAYED option, see INSERT DELAYED.\n\nHIGH PRIORITY and LOW PRIORITY\n------------------------------\n\nSee HIGH_PRIORITY and LOW_PRIORITY.\n\nDefaults and Duplicate Values\n-----------------------------\n\nSee INSERT - Default & Duplicate Values for details..\n\nINSERT IGNORE\n-------------\n\nSee INSERT IGNORE.\n\nINSERT ON DUPLICATE KEY UPDATE\n------------------------------\n\nSee INSERT ON DUPLICATE KEY UPDATE.\n\nExamples\n--------\n\nSpecifying the column names:\n\nINSERT INTO person (first_name, last_name) VALUES (\'John\', \'Doe\');\n\nInserting more than 1 row at a time:\n\nINSERT INTO tbl_name VALUES (1, \"row 1\"), (2, \"row 2\");\n\nUsing the SET clause:\n\nINSERT INTO person SET first_name = \'John\', last_name = \'Doe\';\n\nSELECTing from another table:\n\nINSERT INTO contractor SELECT * FROM person WHERE status = \'c\';\n\nSee INSERT ON DUPLICATE KEY UPDATE and INSERT IGNORE for further examples.\n\nINSERT ... RETURNING\n--------------------\n\nINSERT ... RETURNING returns a resultset of the inserted rows.\n\nThis returns the listed columns for all the rows that are inserted, or\nalternatively, the specified SELECT expression. Any SQL expressions which can\nbe calculated can be used in the select expression for the RETURNING clause,\nincluding virtual columns and aliases, expressions which use various operators\nsuch as bitwise, logical and arithmetic operators, string functions, date-time\nfunctions, numeric functions, control flow functions, secondary functions and\nstored functions. Along with this, statements which have subqueries and\nprepared statements can also be used.\n\nExamples\n--------\n\nSimple INSERT statement\n\nINSERT INTO t2 VALUES (1,\'Dog\'),(2,\'Lion\'),(3,\'Tiger\'),(4,\'Leopard\') \nRETURNING id2,id2+id2,id2&id2,id2||id2;\n+-----+---------+---------+----------+\n| id2 | id2+id2 | id2&id2 | id2||id2 |\n+-----+---------+---------+----------+\n| 1 | 2 | 1 | 1 |\n| 2 | 4 | 2 | 1 |\n| 3 | 6 | 3 | 1 |\n| 4 | 8 | 4 | 1 |\n+-----+---------+---------+----------+\n\nUsing stored functions in RETURNING\n\nDELIMITER |\nCREATE FUNCTION f(arg INT) RETURNS INT\n BEGIN\n RETURN (SELECT arg+arg);\n END|\n\nDELIMITER ;\n\nPREPARE stmt FROM \"INSERT INTO t1 SET id1=1, animal1=\'Bear\' RETURNING f(id1),\nUPPER(animal1)\";\n\nEXECUTE stmt;\n+---------+----------------+\n| f(id1) | UPPER(animal1) |\n+---------+----------------+\n| 2 | BEAR |\n+---------+----------------+\n\nSubqueries in the RETURNING clause that return more than one row or column\ncannot be used.\n\nAggregate functions cannot be used in the RETURNING clause. Since aggregate\nfunctions work on a set of values, and if the purpose is to get the row count,\nROW_COUNT() with SELECT can be used or it can be used in\nINSERT...SELECT...RETURNING if the table in the RETURNING clause is not the\nsame as the INSERT table.\n\nURL: https://mariadb.com/kb/en/insert/','','https://mariadb.com/kb/en/insert/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (450,27,'INSERT DELAYED','Syntax\n------\n\nINSERT DELAYED ...\n\nDescription\n-----------\n\nThe DELAYED option for the INSERT statement is a MariaDB/MySQL extension to\nstandard SQL that is very useful if you have clients that cannot or need not\nwait for the INSERT to complete. This is a common situation when you use\nMariaDB for logging and you also periodically run SELECT and UPDATE statements\nthat take a long time to complete.\n\nWhen a client uses INSERT DELAYED, it gets an okay from the server at once,\nand the row is queued to be inserted when the table is not in use by any other\nthread.\n\nAnother major benefit of using INSERT DELAYED is that inserts from many\nclients are bundled together and written in one block. This is much faster\nthan performing many separate inserts.\n\nNote that INSERT DELAYED is slower than a normal INSERT if the table is not\notherwise in use. There is also the additional overhead for the server to\nhandle a separate thread for each table for which there are delayed rows. This\nmeans that you should use INSERT DELAYED only when you are really sure that\nyou need it.\n\nThe queued rows are held only in memory until they are inserted into the\ntable. This means that if you terminate mysqld forcibly (for example, with\nkill -9) or if mysqld dies unexpectedly, any queued rows that have not been\nwritten to disk are lost.\n\nThe number of concurrent INSERT DELAYED threads is limited by the\nmax_delayed_threads server system variables. If it is set to 0, INSERT DELAYED\nis disabled. The session value can be equal to the global value, or 0 to\ndisable this statement for the current session. If this limit has been\nreached, the DELAYED clause will be silently ignore for subsequent statements\n(no error will be produced).\n\nLimitations\n-----------\n\nThere are some limitations on the use of DELAYED:\n\n* INSERT DELAYED works only with MyISAM, MEMORY, ARCHIVE,\n and BLACKHOLE tables. If you execute INSERT DELAYED with another storage\nengine, you will get an error like this: ERROR 1616 (HY000): DELAYED option\nnot supported for table \'tab_name\'\n* For MyISAM tables, if there are no free blocks in the middle of the data\n file, concurrent SELECT and INSERT statements are supported. Under these\n circumstances, you very seldom need to use INSERT DELAYED\n with MyISAM.\n* INSERT DELAYED should be used only for\n INSERT statements that specify value lists. The server\n ignores DELAYED for INSERT ... SELECT\n or INSERT ... ON DUPLICATE KEY UPDATE statements.\n* Because the INSERT DELAYED statement returns immediately,\n before the rows are inserted, you cannot use\n LAST_INSERT_ID() to get the\n AUTO_INCREMENT value that the statement might generate.\n* DELAYED rows are not visible to SELECT\n statements until they actually have been inserted.\n* After INSERT DELAYED, ROW_COUNT() returns the number of the rows you tried\nto insert, not the number of the successful writes.\n* DELAYED is ignored on slave replication servers, so that \n INSERT DELAYED is treated as a normal\n INSERT on slaves. This is because\n DELAYED could cause the slave to have different data than\n the master. INSERT DELAYED statements are not safe for replication.\n* Pending INSERT DELAYED statements are lost if a table is\n write locked and ALTER TABLE is used to modify the table structure.\n* INSERT DELAYED is not supported for views. If you try, you will get an error\nlike this: ERROR 1347 (HY000): \'view_name\' is not BASE TABLE\n* INSERT DELAYED is not supported for partitioned tables.\n* INSERT DELAYED is not supported within stored programs.\n* INSERT DELAYED does not work with triggers.\n* INSERT DELAYED does not work if there is a check constraint in place.\n* INSERT DELAYED does not work if skip-new mode is active.\n\nURL: https://mariadb.com/kb/en/insert-delayed/','','https://mariadb.com/kb/en/insert-delayed/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (451,27,'INSERT SELECT','Syntax\n------\n\nINSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]\n [INTO] tbl_name [(col_name,...)]\n SELECT ...\n [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]\n\nDescription\n-----------\n\nWith INSERT ... SELECT, you can quickly insert many rows into a table from one\nor more other tables. For example:\n\nINSERT INTO tbl_temp2 (fld_id)\n SELECT tbl_temp1.fld_order_id\n FROM tbl_temp1 WHERE tbl_temp1.fld_order_id > 100;\n\ntbl_name can also be specified in the form db_name.tbl_name (see Identifier\nQualifiers). This allows to copy rows between different databases.\n\nIf the new table has a primary key or UNIQUE indexes, you can use IGNORE to\nhandle duplicate key errors during the query. The newer values will not be\ninserted if an identical value already exists.\n\nREPLACE can be used instead of INSERT to prevent duplicates on UNIQUE indexes\nby deleting old values. In that case, ON DUPLICATE KEY UPDATE cannot be used.\n\nINSERT ... SELECT works for tables which already exist. To create a table for\na given resultset, you can use CREATE TABLE ... SELECT.\n\nURL: https://mariadb.com/kb/en/insert-select/','','https://mariadb.com/kb/en/insert-select/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (452,27,'LOAD DATA INFILE','Syntax\n------\n\nLOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE \'file_name\'\n [REPLACE | IGNORE]\n INTO TABLE tbl_name\n [CHARACTER SET charset_name]\n [{FIELDS | COLUMNS}\n [TERMINATED BY \'string\']\n [[OPTIONALLY] ENCLOSED BY \'char\']\n [ESCAPED BY \'char\']\n ]\n [LINES\n [STARTING BY \'string\']\n [TERMINATED BY \'string\']\n ]\n [IGNORE number {LINES|ROWS}]\n [(col_name_or_user_var,...)]\n [SET col_name = expr,...]\n\nDescription\n-----------\n\nLOAD DATA INFILE is unsafe for statement-based replication.\n\nReads rows from a text file into the designated table on the database at a\nvery high speed. The file name must be given as a literal string.\n\nFiles are written to disk using the SELECT INTO OUTFILE statement. You can\nthen read the files back into a table using the LOAD DATA INFILE statement.\nThe FIELDS and LINES clauses are the same in both statements. These clauses\nare optional, but if both are specified then the FIELDS clause must precede\nLINES.\n\nExecuting this statement activates INSERT triggers.\n\nOne must have the FILE privilege to be able to execute LOAD DATA INFILE. This\nis to ensure normal users cannot read system files. LOAD DATA LOCAL INFILE\ndoes not have this requirement.\n\nIf the secure_file_priv system variable is set (by default it is not), the\nloaded file must be present in the specified directory.\n\nNote that MariaDB\'s systemd unit file restricts access to /home, /root, and\n/run/user by default. See Configuring access to home directories.\n\nLOAD DATA LOCAL INFILE\n----------------------\n\nWhen you execute the LOAD DATA INFILE statement, MariaDB Server attempts to\nread the input file from its own file system. By contrast, when you execute\nthe LOAD DATA LOCAL INFILE statement, the client attempts to read the input\nfile from its file system, and it sends the contents of the input file to the\nMariaDB Server. This allows you to load files from the client\'s local file\nsystem into the database.\n\nIf you don\'t want to permit this operation (perhaps for security reasons), you\ncan disable the LOAD DATA LOCAL INFILE statement on either the server or the\nclient.\n\n* The LOAD DATA LOCAL INFILE statement can be disabled on the server by\nsetting the local_infile system variable to 0.\n* The LOAD DATA LOCAL INFILE statement can be disabled on the client. If you\nare using MariaDB Connector/C, this can be done by unsetting the\nCLIENT_LOCAL_FILES capability flag with the mysql_real_connect function or by\nunsetting the MYSQL_OPT_LOCAL_INFILE option with mysql_optionsv function. If\nyou are using a different client or client library, then see the documentation\nfor your specific client or client library to determine how it handles the\nLOAD DATA LOCAL INFILE statement.\n\nIf the LOAD DATA LOCAL INFILE statement is disabled by either the server or\nthe client and if the user attempts to execute it, then the server will cause\nthe statement to fail with the following error message:\n\nThe used command is not allowed with this MariaDB version\n\nNote that it is not entirely accurate to say that the MariaDB version does not\nsupport the command. It would be more accurate to say that the MariaDB\nconfiguration does not support the command. See MDEV-20500 for more\ninformation.\n\nFrom MariaDB 10.5.2, the error message is more accurate:\n\nThe used command is not allowed because the MariaDB server or client \n has disabled the local infile capability\n\nREPLACE and IGNORE\n------------------\n\nIf you load data from a file into a table that already contains data and has a\nprimary key, you may encounter issues where the statement attempts to insert a\nrow with a primary key that already exists. When this happens, the statement\nfails with Error 1064, protecting the data already on the table. If you want\nMariaDB to overwrite duplicates, use the REPLACE keyword.\n\nThe REPLACE keyword works like the REPLACE statement. Here, the statement\nattempts to load the data from the file. If the row does not exist, it adds it\nto the table. If the row contains an existing primary key, it replaces the\ntable data. That is, in the event of a conflict, it assumes the file contains\nthe desired row.\n\nThis operation can cause a degradation in load speed by a factor of 20 or more\nif the part that has already been loaded is larger than the capacity of the\nInnoDB Buffer Pool. This happens because it causes a lot of turnaround in the\nbuffer pool.\n\nUse the IGNORE keyword when you want to skip any rows that contain a\nconflicting primary key. Here, the statement attempts to load the data from\nthe file. If the row does not exist, it adds it to the table. If the row\ncontains an existing primary key, it ignores the addition request and moves on\nto the next. That is, in the event of a conflict, it assumes the table\ncontains the desired row.\n\nCharacter-sets\n--------------\n\nWhen the statement opens the file, it attempts to read the contents using the\ndefault character-set, as defined by the character_set_database system\nvariable.\n\nIn the cases where the file was written using a character-set other than the\ndefault, you can specify the character-set to use with the CHARACTER SET\nclause in the statement. It ignores character-sets specified by the SET NAMES\nstatement and by the character_set_client system variable. Setting the\nCHARACTER SET clause to a value of binary indicates \"no conversion.\"\n\nThe statement interprets all fields in the file as having the same\ncharacter-set, regardless of the column data type. To properly interpret file\ncontents, you must ensure that it was written with the correct character-set.\nIf you write a data file with mariadb-dump -T or with the SELECT INTO OUTFILE\nstatement with the mariadb client, be sure to use the --default-character-set\noption, so that the output is written with the desired character-set.\n\nWhen using mixed character sets, use the CHARACTER SET clause in both SELECT\nINTO OUTFILE and LOAD DATA INFILE to ensure that MariaDB correctly interprets\nthe escape sequences.\n\nThe character_set_filesystem system variable controls the interpretation of\nthe filename.\n\nIt is currently not possible to load data files that use the ucs2 character\nset.\n\nPreprocessing Inputs\n--------------------\n\ncol_name_or_user_var can be a column name, or a user variable. In the case of\na variable, the SET statement can be used to preprocess the value before\nloading into the table.\n\nPriority and Concurrency\n------------------------\n\nIn storage engines that perform table-level locking (MyISAM, MEMORY and\nMERGE), using the LOW_PRIORITY keyword, MariaDB delays insertions until no\nother clients are reading from the table. Alternatively, when using the MyISAM\nstorage engine, you can use the CONCURRENT keyword to perform concurrent\ninsertion.\n\nThe LOW_PRIORITY and CONCURRENT keywords are mutually exclusive. They cannot\nbe used in the same statement.\n\nProgress Reporting\n------------------\n\nThe LOAD DATA INFILE statement supports progress reporting. You may find this\nuseful when dealing with long-running operations. Using another client you can\nissue a SHOW PROCESSLIST query to check the progress of the data load.\n\nUsing mariadb-import\n--------------------\n\nMariaDB ships with a separate utility for loading data from files:\nmariadb-import (or mysqlimport before MariaDB 10.5). It operates by sending\nLOAD DATA INFILE statements to the server.\n\nUsing mariadb-import you can compress the file using the --compress option, to\nget better performance over slow networks, providing both the client and\nserver support the compressed protocol. Use the --local option to load from\nthe local file system.\n\nIndexing\n--------\n\nIn cases where the storage engine supports ALTER TABLE... DISABLE KEYS\nstatements (MyISAM and Aria), the LOAD DATA INFILE statement automatically\ndisables indexes during the execution.\n\nExamples\n--------\n\nYou have a file with this content (note the the separator is \',\', not tab,\nwhich is the default):\n\n2,2\n3,3\n4,4\n5,5\n6,8\n\nCREATE TABLE t1 (a int, b int, c int, d int, PRIMARY KEY (a));\nLOAD DATA LOCAL INFILE \n \'/tmp/loaddata7.dat\' INTO TABLE t1 FIELDS TERMINATED BY \',\' (a,b) SET c=a+b;\nSELECT * FROM t1;\n+------+------+------+\n| a | b | c |\n+------+------+------+\n| 2 | 2 | 4 |\n| 3 | 3 | 6 |\n| 4 | 4 | 8 |\n| 5 | 5 | 10 |\n| 6 | 8 | 14 |\n+------+------+------+\n\nAnother example, given the following data (the separator is a tab):\n\n1 a\n2 b\n\nThe value of the first column is doubled before loading:\n\nLOAD DATA INFILE \'ld.txt\' INTO TABLE ld (@i,v) SET i=@i*2;\n\nSELECT * FROM ld;\n+------+------+\n| i | v |\n+------+------+\n| 2 | a |\n| 4 | b |\n+------+------+\n\nURL: https://mariadb.com/kb/en/load-data-infile/','','https://mariadb.com/kb/en/load-data-infile/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (453,27,'LOAD XML','Syntax\n------\n\nLOAD XML [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE \'file_name\'\n [REPLACE | IGNORE]\n INTO TABLE [db_name.]tbl_name\n [CHARACTER SET charset_name]\n [ROWS IDENTIFIED BY \'<tagname>\']\n [IGNORE number {LINES | ROWS}]\n [(column_or_user_var,...)]\n [SET col_name = expr,...]\n\nDescription\n-----------\n\nThe LOAD XML statement reads data from an XML file into a table. The file_name\nmust be given as a literal string. The tagname in the optional ROWS IDENTIFIED\nBY clause must also be given as a literal string, and must be surrounded by\nangle brackets (< and >).\n\nLOAD XML acts as the complement of running the mariadb client in XML output\nmode (that is, starting the client with the --xml option). To write data from\na table to an XML file, use a command such as the following one from the\nsystem shell:\n\nshell> mariadb --xml -e \'SELECT * FROM mytable\' > file.xml\n\nTo read the file back into a table, use LOAD XML INFILE. By default, the <row>\nelement is considered to be the equivalent of a database table row; this can\nbe changed using the ROWS IDENTIFIED BY clause.\n\nThis statement supports three different XML formats:\n\n* Column names as attributes and column values as attribute values:\n\n<row column1=\"value1\" column2=\"value2\" .../>\n\n* Column names as tags and column values as the content of these tags:\n\n<row>\n <column1>value1</column1>\n <column2>value2</column2>\n</row>\n\n* Column names are the name attributes of <field> tags, and values are\n the contents of these tags:\n\n<row>\n <field name=\'column1\'>value1</field>\n <field name=\'column2\'>value2</field>\n</row>\n\nThis is the format used by other tools, such as mariadb-dump.\n\nAll 3 formats can be used in the same XML file; the import routine\nautomatically detects the format for each row and interprets it correctly.\nTags are matched based on the tag or attribute name and the column name.\n\nThe following clauses work essentially the same way for LOAD XML as they do\nfor LOAD DATA:\n\n* LOW_PRIORITY or CONCURRENT\n* LOCAL\n* REPLACE or IGNORE\n* CHARACTER SET\n* (column_or_user_var,...)\n* SET\n\nSee LOAD DATA for more information about these clauses.\n\nThe IGNORE number LINES or IGNORE number ROWS clause causes the first number\nrows in the XML file to be skipped. It is analogous to the LOAD DATA\nstatement\'s IGNORE ... LINES clause.\n\nIf the LOW_PRIORITY keyword is used, insertions are delayed until no other\nclients are reading from the table. The CONCURRENT keyword allows the use of\nconcurrent inserts. These clauses cannot be specified together.\n\nThis statement activates INSERT triggers.\n\nURL: https://mariadb.com/kb/en/load-xml/','','https://mariadb.com/kb/en/load-xml/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (454,27,'Concurrent Inserts','The MyISAM storage engine supports concurrent inserts. This feature allows\nSELECT statements to be executed during INSERT operations, reducing contention.\n\nWhether concurrent inserts can be used or not depends on the value of the\nconcurrent_insert server system variable:\n\n* NEVER (0) disables concurrent inserts.\n* AUTO (1) allows concurrent inserts only when the target table has no free\nblocks (no data in the middle of the table has been deleted after the last\nOPTIMIZE TABLE). This is the default.\n* ALWAYS (2) always enables concurrent inserts, in which case new rows are\nadded at the end of a table if the table is being used by another thread.\n\nIf the binary log is used, CREATE TABLE ... SELECT and INSERT ... SELECT\nstatements cannot use concurrent inserts. These statements acquire a read lock\non the table, so concurrent inserts will need to wait. This way the log can be\nsafely used to restore data.\n\nConcurrent inserts are not used by replicas with the row based replication\n(see binary log formats).\n\nIf an INSERT statement contain the HIGH_PRIORITY clause, concurrent inserts\ncannot be used. INSERT ... DELAYED is usually unneeded if concurrent inserts\nare enabled.\n\nLOAD DATA INFILE uses concurrent inserts if the CONCURRENT keyword is\nspecified and concurrent_insert is not NEVER. This makes the statement slower\n(even if no other sessions access the table) but reduces contention.\n\nLOCK TABLES allows non-conflicting concurrent inserts if a READ LOCAL lock is\nused. Concurrent inserts are not allowed if the LOCAL keyword is omitted.\n\nNotes\n-----\n\nThe decision to enable concurrent insert for a table is done when the table is\nopened. If you change the value of concurrent_insert it will only affect new\nopened tables. If you want it to work for also for tables in use or cached,\nyou should do FLUSH TABLES after setting the variable.\n\nURL: https://mariadb.com/kb/en/concurrent-inserts/','','https://mariadb.com/kb/en/concurrent-inserts/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (455,27,'HIGH_PRIORITY and LOW_PRIORITY','The InnoDB storage engine uses row-level locking to ensure data integrity.\nHowever some storage engines (such as MEMORY, MyISAM, Aria and MERGE) lock the\nwhole table to prevent conflicts. These storage engines use two separate\nqueues to remember pending statements; one is for SELECTs and the other one is\nfor write statements (INSERT, DELETE, UPDATE). By default, the latter has a\nhigher priority.\n\nTo give write operations a lower priority, the low_priority_updates server\nsystem variable can be set to ON. The option is available on both the global\nand session levels, and it can be set at startup or via the SET statement.\n\nWhen too many table locks have been set by write statements, some pending\nSELECTs are executed. The maximum number of write locks that can be acquired\nbefore this happens is determined by the max_write_lock_count server system\nvariable, which is dynamic.\n\nIf write statements have a higher priority (default), the priority of\nindividual write statements (INSERT, REPLACE, UPDATE, DELETE) can be changed\nvia the LOW_PRIORITY attribute, and the priority of a SELECT statement can be\nraised via the HIGH_PRIORITY attribute. Also, LOCK TABLES supports a\nLOW_PRIORITY attribute for WRITE locks.\n\nIf read statements have a higher priority, the priority of an INSERT can be\nchanged via the HIGH_PRIORITY attribute. However, the priority of other write\nstatements cannot be raised individually.\n\nThe use of LOW_PRIORITY or HIGH_PRIORITY for an INSERT prevents Concurrent\nInserts from being used.\n\nURL: https://mariadb.com/kb/en/high_priority-and-low_priority/','','https://mariadb.com/kb/en/high_priority-and-low_priority/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (456,27,'INSERT - Default & Duplicate Values','Default Values\n--------------\n\nIf the SQL_MODE contains STRICT_TRANS_TABLES and you are inserting into a\ntransactional table (like InnoDB), or if the SQL_MODE contains\nSTRICT_ALL_TABLES, all NOT NULL columns which do not have a DEFAULT value (and\nare not AUTO_INCREMENT) must be explicitly referenced in INSERT statements. If\nnot, an error like this is produced:\n\nERROR 1364 (HY000): Field \'col\' doesn\'t have a default value\n\nIn all other cases, if a NOT NULL column without a DEFAULT value is not\nreferenced, an empty value will be inserted (for example, 0 for INTEGER\ncolumns and \'\' for CHAR columns). See NULL Values in MariaDB:Inserting for\nexamples.\n\nIf a NOT NULL column having a DEFAULT value is not referenced, NULL will be\ninserted.\n\nIf a NULL column having a DEFAULT value is not referenced, its default value\nwill be inserted. It is also possible to explicitly assign the default value\nusing the DEFAULT keyword or the DEFAULT() function.\n\nIf the DEFAULT keyword is used but the column does not have a DEFAULT value,\nan error like this is produced:\n\nERROR 1364 (HY000): Field \'col\' doesn\'t have a default value\n\nDuplicate Values\n----------------\n\nBy default, if you try to insert a duplicate row and there is a UNIQUE index,\nINSERT stops and an error like this is produced:\n\nERROR 1062 (23000): Duplicate entry \'dup_value\' for key \'col\'\n\nTo handle duplicates you can use the IGNORE clause, INSERT ON DUPLICATE KEY\nUPDATE or the REPLACE statement. Note that the IGNORE and DELAYED options are\nignored when you use ON DUPLICATE KEY UPDATE.\n\nURL: https://mariadb.com/kb/en/insert-default-duplicate-values/','','https://mariadb.com/kb/en/insert-default-duplicate-values/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (457,27,'INSERT IGNORE','Ignoring Errors\n---------------\n\nNormally INSERT stops and rolls back when it encounters an error.\n\nBy using the IGNORE keyword all errors are converted to warnings, which will\nnot stop inserts of additional rows.\n\nInvalid values are changed to the closest valid value and inserted, with a\nwarning produced.\n\nThe IGNORE and DELAYED options are ignored when you use ON DUPLICATE KEY\nUPDATE.\n\nPrior to MySQL and MariaDB 5.5.28, no warnings were issued for duplicate key\nerrors when using IGNORE. You can get the old behavior if you set OLD_MODE to\nNO_DUP_KEY_WARNINGS_WITH_IGNORE.\n\nSee IGNORE for a full description of effects.\n\nExamples\n--------\n\nCREATE TABLE t1 (x INT UNIQUE);\n\nINSERT INTO t1 VALUES(1),(2);\n\nINSERT INTO t1 VALUES(2),(3);\nERROR 1062 (23000): Duplicate entry \'2\' for key \'x\'\nSELECT * FROM t1;\n+------+\n| x |\n+------+\n| 1 |\n| 2 |\n+------+\n\nINSERT IGNORE INTO t1 VALUES(2),(3);\nQuery OK, 1 row affected, 1 warning (0.04 sec)\n\nSHOW WARNINGS;\n+---------+------+---------------------------------+\n| Level | Code | Message |\n+---------+------+---------------------------------+\n| Warning | 1062 | Duplicate entry \'2\' for key \'x\' |\n+---------+------+---------------------------------+\n\nSELECT * FROM t1;\n+------+\n| x |\n+------+\n| 1 |\n| 2 |\n| 3 |\n+------+\n\nConverting values:\n\nCREATE OR REPLACE TABLE t2(id INT, t VARCHAR(2) NOT NULL, n INT NOT NULL);\n\nINSERT INTO t2(id) VALUES (1),(2);\nERROR 1364 (HY000): Field \'t\' doesn\'t have a default value\n\nINSERT IGNORE INTO t2(id) VALUES (1),(2);\nQuery OK, 2 rows affected, 2 warnings (0.026 sec)\nRecords: 2 Duplicates: 0 Warnings: 2\n\nSHOW WARNINGS;\n+---------+------+----------------------------------------+\n| Level | Code | Message |\n+---------+------+----------------------------------------+\n| Warning | 1364 | Field \'t\' doesn\'t have a default value |\n| Warning | 1364 | Field \'n\' doesn\'t have a default value |\n+---------+------+----------------------------------------+\n\nSELECT * FROM t2;\n+------+---+---+\n| id | t | n |\n+------+---+---+\n| 1 | | 0 |\n| 2 | | 0 |\n+------+---+---+\n\nSee INSERT ON DUPLICATE KEY UPDATE for further examples using that syntax.\n\nURL: https://mariadb.com/kb/en/insert-ignore/','','https://mariadb.com/kb/en/insert-ignore/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (458,27,'INSERT ON DUPLICATE KEY UPDATE','Syntax\n------\n\nINSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]\n [INTO] tbl_name [PARTITION (partition_list)] [(col,...)]\n {VALUES | VALUE} ({expr | DEFAULT},...),(...),...\n [ ON DUPLICATE KEY UPDATE\n col=expr\n [, col=expr] ... ]\n\nOr:\n\nINSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]\n [INTO] tbl_name [PARTITION (partition_list)]\n SET col={expr | DEFAULT}, ...\n [ ON DUPLICATE KEY UPDATE\n col=expr\n [, col=expr] ... ]\n\nOr:\n\nINSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]\n [INTO] tbl_name [PARTITION (partition_list)] [(col,...)]\n SELECT ...\n [ ON DUPLICATE KEY UPDATE\n col=expr\n [, col=expr] ... ]\n\nDescription\n-----------\n\nINSERT ... ON DUPLICATE KEY UPDATE is a MariaDB/MySQL extension to the INSERT\nstatement that, if it finds a duplicate unique or primary key, will instead\nperform an UPDATE.\n\nThe row/s affected value is reported as 1 if a row is inserted, and 2 if a row\nis updated, unless the API\'s CLIENT_FOUND_ROWS flag is set.\n\nIf more than one unique index is matched, only the first is updated. It is not\nrecommended to use this statement on tables with more than one unique index.\n\nIf the table has an AUTO_INCREMENT primary key and the statement inserts or\nupdates a row, the LAST_INSERT_ID() function returns its AUTO_INCREMENT value.\n\nThe VALUES() function can only be used in a ON DUPLICATE KEY UPDATE clause and\nhas no meaning in any other context. It returns the column values from the\nINSERT portion of the statement. This function is particularly useful for\nmulti-rows inserts.\n\nThe IGNORE and DELAYED options are ignored when you use ON DUPLICATE KEY\nUPDATE.\n\nSee Partition Pruning and Selection for details on the PARTITION clause.\n\nThis statement activates INSERT and UPDATE triggers. See Trigger Overview for\ndetails.\n\nSee also a similar statement, REPLACE.\n\nExamples\n--------\n\nCREATE TABLE ins_duplicate (id INT PRIMARY KEY, animal VARCHAR(30));\nINSERT INTO ins_duplicate VALUES (1,\'Aardvark\'), (2,\'Cheetah\'), (3,\'Zebra\');\n\nIf there is no existing key, the statement runs as a regular INSERT:\n\nINSERT INTO ins_duplicate VALUES (4,\'Gorilla\') \n ON DUPLICATE KEY UPDATE animal=\'Gorilla\';\nQuery OK, 1 row affected (0.07 sec)\n\nSELECT * FROM ins_duplicate;\n+----+----------+\n| id | animal |\n+----+----------+\n| 1 | Aardvark |\n| 2 | Cheetah |\n| 3 | Zebra |\n| 4 | Gorilla |\n+----+----------+\n\nA regular INSERT with a primary key value of 1 will fail, due to the existing\nkey:\n\nINSERT INTO ins_duplicate VALUES (1,\'Antelope\');\nERROR 1062 (23000): Duplicate entry \'1\' for key \'PRIMARY\'\n\nHowever, we can use an INSERT ON DUPLICATE KEY UPDATE instead:\n\nINSERT INTO ins_duplicate VALUES (1,\'Antelope\') \n ON DUPLICATE KEY UPDATE animal=\'Antelope\';\nQuery OK, 2 rows affected (0.09 sec)\n\nNote that there are two rows reported as affected, but this refers only to the\nUPDATE.\n\nSELECT * FROM ins_duplicate;\n+----+----------+\n| id | animal |\n+----+----------+\n| 1 | Antelope |\n| 2 | Cheetah |\n| 3 | Zebra |\n| 4 | Gorilla |\n+----+----------+\n\nAdding a second unique column:\n\nALTER TABLE ins_duplicate ADD id2 INT;\nUPDATE ins_duplicate SET id2=id+10;\nALTER TABLE ins_duplicate ADD UNIQUE KEY(id2);\n\nWhere two rows match the unique keys match, only the first is updated. This\ncan be unsafe and is not recommended unless you are certain what you are doing.\n\nINSERT INTO ins_duplicate VALUES (2,\'Lion\',13) \n ON DUPLICATE KEY UPDATE animal=\'Lion\';\nQuery OK, 2 rows affected (0.004 sec)\n\nSELECT * FROM ins_duplicate;\n+----+----------+------+\n| id | animal | id2 |\n+----+----------+------+\n| 1 | Antelope | 11 |\n| 2 | Lion | 12 |\n| 3 | Zebra | 13 |\n| 4 | Gorilla | 14 |\n+----+----------+------+\n\nAlthough the third row with an id of 3 has an id2 of 13, which also matched,\nit was not updated.\n\nChanging id to an auto_increment field. If a new row is added, the\nauto_increment is moved forward. If the row is updated, it remains the same.\n\nALTER TABLE `ins_duplicate` CHANGE `id` `id` INT( 11 ) NOT NULL AUTO_INCREMENT;\nALTER TABLE ins_duplicate DROP id2;\nSELECT Auto_increment FROM INFORMATION_SCHEMA.TABLES \n WHERE TABLE_NAME=\'ins_duplicate\';\n+----------------+\n| Auto_increment |\n+----------------+\n| 5 |\n+----------------+\n\nINSERT INTO ins_duplicate VALUES (2,\'Leopard\') \n ON DUPLICATE KEY UPDATE animal=\'Leopard\';\nQuery OK, 2 rows affected (0.00 sec)\n\nSELECT Auto_increment FROM INFORMATION_SCHEMA.TABLES \n WHERE TABLE_NAME=\'ins_duplicate\';\n+----------------+\n| Auto_increment |\n+----------------+\n| 5 |\n+----------------+\n\nINSERT INTO ins_duplicate VALUES (5,\'Wild Dog\') \n ON DUPLICATE KEY UPDATE animal=\'Wild Dog\';\nQuery OK, 1 row affected (0.09 sec)\n\nSELECT * FROM ins_duplicate;\n+----+----------+\n| id | animal |\n+----+----------+\n| 1 | Antelope |\n| 2 | Leopard |\n| 3 | Zebra |\n| 4 | Gorilla |\n| 5 | Wild Dog |\n+----+----------+\n\nSELECT Auto_increment FROM INFORMATION_SCHEMA.TABLES \n WHERE TABLE_NAME=\'ins_duplicate\';\n+----------------+\n| Auto_increment |\n+----------------+\n| 6 |\n+----------------+\n\nRefering to column values from the INSERT portion of the statement:\n\nINSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)\n ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);\n\nSee the VALUES() function for more.\n\nURL: https://mariadb.com/kb/en/insert-on-duplicate-key-update/','','https://mariadb.com/kb/en/insert-on-duplicate-key-update/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (459,27,'INSERT...RETURNING','MariaDB starting with 10.5.0\n----------------------------\nINSERT ... RETURNING was added in MariaDB 10.5.0, and returns a resultset of\nthe inserted rows.\n\nSyntax\n------\n\nINSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]\n [INTO] tbl_name [PARTITION (partition_list)] [(col,...)]\n {VALUES | VALUE} ({expr | DEFAULT},...),(...),...\n [ ON DUPLICATE KEY UPDATE\n col=expr\n [, col=expr] ... ] [RETURNING select_expr\n [, select_expr ...]]\n\nOr:\n\nINSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]\n [INTO] tbl_name [PARTITION (partition_list)]\n SET col={expr | DEFAULT}, ...\n [ ON DUPLICATE KEY UPDATE\n col=expr\n [, col=expr] ... ] [RETURNING select_expr\n [, select_expr ...]]\n\nOr:\n\nINSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]\n [INTO] tbl_name [PARTITION (partition_list)] [(col,...)]\n SELECT ...\n [ ON DUPLICATE KEY UPDATE\n col=expr\n [, col=expr] ... ] [RETURNING select_expr\n [, select_expr ...]]\n\nDescription\n-----------\n\nINSERT ... RETURNING returns a resultset of the inserted rows.\n\nThis returns the listed columns for all the rows that are inserted, or\nalternatively, the specified SELECT expression. Any SQL expressions which can\nbe calculated can be used in the select expression for the RETURNING clause,\nincluding virtual columns and aliases, expressions which use various operators\nsuch as bitwise, logical and arithmetic operators, string functions, date-time\nfunctions, numeric functions, control flow functions, secondary functions and\nstored functions. Along with this, statements which have subqueries and\nprepared statements can also be used.\n\nExamples\n--------\n\nSimple INSERT statements:\n\nCREATE OR REPLACE TABLE t2 (id INT, animal VARCHAR(20), t TIMESTAMP);\n\nINSERT INTO t2 (id) VALUES (2),(3) RETURNING id,t;\n+------+---------------------+\n| id | t |\n+------+---------------------+\n| 2 | 2021-04-28 00:59:32 |\n| 3 | 2021-04-28 00:59:32 |\n+------+---------------------+\n\nINSERT INTO t2(id,animal) VALUES\n(1,\'Dog\'),(2,\'Lion\'),(3,\'Tiger\'),(4,\'Leopard\') \n RETURNING id,id+id,id&id,id||id;\n+------+-------+-------+--------+\n| id | id+id | id&id | id||id |\n+------+-------+-------+--------+\n| 1 | 2 | 1 | 1 |\n| 2 | 4 | 2 | 1 |\n| 3 | 6 | 3 | 1 |\n| 4 | 8 | 4 | 1 |\n+------+-------+-------+--------+\n\nUsing stored functions in RETURNING\n\nDELIMITER |\nCREATE FUNCTION f(arg INT) RETURNS INT\n BEGIN\n RETURN (SELECT arg+arg);\n END|\n\nDELIMITER ;\n\nPREPARE stmt FROM \"INSERT INTO t1 SET id1=1, animal1=\'Bear\' RETURNING f(id1),\nUPPER(animal1)\";\n\nEXECUTE stmt;\n+---------+----------------+\n| f(id1) | UPPER(animal1) |\n+---------+----------------+\n| 2 | BEAR |\n+---------+----------------+\n\nSubqueries in the RETURNING clause that return more than one row or column\ncannot be used.\n\nAggregate functions cannot be used in the RETURNING clause. Since aggregate\nfunctions work on a set of values, and if the purpose is to get the row count,\nROW_COUNT() with SELECT can be used or it can be used in\nINSERT...SELECT...RETURNING if the table in the RETURNING clause is not the\nsame as the INSERT table.\n\nURL: https://mariadb.com/kb/en/insertreturning/','','https://mariadb.com/kb/en/insertreturning/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (460,27,'REPLACE...RETURNING','MariaDB starting with 10.5.0\n----------------------------\nREPLACE ... RETURNING was added in MariaDB 10.5.0, and returns a resultset of\nthe replaced rows.\n\nSyntax\n------\n\nREPLACE [LOW_PRIORITY | DELAYED]\n [INTO] tbl_name [PARTITION (partition_list)] [(col,...)]\n {VALUES | VALUE} ({expr | DEFAULT},...),(...),...\n[RETURNING select_expr \n [, select_expr ...]]\n\nOr:\n\nREPLACE [LOW_PRIORITY | DELAYED]\n [INTO] tbl_name [PARTITION (partition_list)]\n SET col={expr | DEFAULT}, ...\n[RETURNING select_expr \n [, select_expr ...]]\n\nOr:\n\nREPLACE [LOW_PRIORITY | DELAYED]\n [INTO] tbl_name [PARTITION (partition_list)] [(col,...)]\n SELECT ...\n[RETURNING select_expr \n [, select_expr ...]]\n\nDescription\n-----------\n\nREPLACE ... RETURNING returns a resultset of the replaced rows.\n\nThis returns the listed columns for all the rows that are replaced, or\nalternatively, the specified SELECT expression. Any SQL expressions which can\nbe calculated can be used in the select expression for the RETURNING clause,\nincluding virtual columns and aliases, expressions which use various operators\nsuch as bitwise, logical and arithmetic operators, string functions, date-time\nfunctions, numeric functions, control flow functions, secondary functions and\nstored functions. Along with this, statements which have subqueries and\nprepared statements can also be used.\n\nExamples\n--------\n\nSimple REPLACE statement\n\nREPLACE INTO t2 VALUES (1,\'Leopard\'),(2,\'Dog\') RETURNING id2, id2+id2 \nas Total ,id2|id2, id2&&id2;\n+-----+-------+---------+----------+\n| id2 | Total | id2|id2 | id2&&id2 |\n+-----+-------+---------+----------+\n| 1 | 2 | 1 | 1 |\n| 2 | 4 | 2 | 1 |\n+-----+-------+---------+----------+\n\nUsing stored functions in RETURNING\n\nDELIMITER |\nCREATE FUNCTION f(arg INT) RETURNS INT\n BEGIN\n RETURN (SELECT arg+arg);\n END|\n\nDELIMITER ;\nPREPARE stmt FROM \"REPLACE INTO t2 SET id2=3, animal2=\'Fox\' RETURNING f2(id2),\nUPPER(animal2)\";\n\nEXECUTE stmt;\n+---------+----------------+\n| f2(id2) | UPPER(animal2) |\n+---------+----------------+\n| 6 | FOX |\n+---------+----------------+\n\nSubqueries in the statement\n\nREPLACE INTO t1 SELECT * FROM t2 RETURNING (SELECT id2 FROM t2 WHERE \nid2 IN (SELECT id2 FROM t2 WHERE id2=1)) AS new_id;\n+--------+\n| new_id |\n+--------+\n| 1 |\n| 1 |\n| 1 |\n| 1 |\n+--------+\n\nSubqueries in the RETURNING clause that return more than one row or column\ncannot be used..\n\nAggregate functions cannot be used in the RETURNING clause. Since aggregate\nfunctions work on a set of values and if the purpose is to get the row count,\nROW_COUNT() with SELECT can be used, or it can be used in\nREPLACE...SELECT...RETURNING if the table in the RETURNING clause is not the\nsame as the REPLACE table.\n\nURL: https://mariadb.com/kb/en/replacereturning/','','https://mariadb.com/kb/en/replacereturning/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (461,27,'CALL','Syntax\n------\n\nCALL sp_name([parameter[,...]])\nCALL sp_name[()]\n\nDescription\n-----------\n\nThe CALL statement invokes a stored procedure that was defined previously with\nCREATE PROCEDURE.\n\nStored procedure names can be specified as database_name.procedure_name.\nProcedure names and database names can be quoted with backticks (). This is\nnecessary if they are reserved words, or contain special characters. See\nidentifier qualifiers for details.\n\nCALL p() and CALL p are equivalent.\n\nIf parentheses are used, any number of spaces, tab characters and newline\ncharacters are allowed between the procedure\'s name and the open parenthesis.\n\nCALL can pass back values to its caller using parameters that are declared as\nOUT or INOUT parameters. If no value is assigned to an OUT parameter, NULL is\nassigned (and its former value is lost). To pass such values from another\nstored program you can use user-defined variables, local variables or\nroutine\'s parameters; in other contexts, you can only use user-defined\nvariables.\n\nCALL can also be executed as a prepared statement. Placeholders can be used\nfor IN parameters in all versions of MariaDB; for OUT and INOUT parameters,\nplaceholders can be used since MariaDB 5.5.\n\nWhen the procedure returns, a client program can also obtain the number of\nrows affected for the final statement executed within the routine: At the SQL\nlevel, call the ROW_COUNT() function; from the C API, call the\nmysql_affected_rows() function.\n\nIf the CLIENT_MULTI_RESULTS API flag is set, CALL can return any number of\nresultsets and the called stored procedure can execute prepared statements. If\nit is not set, at most one resultset can be returned and prepared statements\ncannot be used within procedures.\n\nURL: https://mariadb.com/kb/en/call/','','https://mariadb.com/kb/en/call/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (462,27,'DO','Syntax\n------\n\nDO expr [, expr] ...\n\nDescription\n-----------\n\nDO executes the expressions but does not return any results. In most respects,\nDO is shorthand for SELECT expr, ..., but has the advantage that it is\nslightly faster when you do not care about the result.\n\nDO is useful primarily with functions that have side effects, such as\nRELEASE_LOCK().\n\nURL: https://mariadb.com/kb/en/do/','','https://mariadb.com/kb/en/do/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (463,27,'Comment Syntax','There are three supported comment styles in MariaDB:\n\n* From a \'#\' to the end of a line:SELECT * FROM users; # This is a comment\n\n* From a \'-- \' to the end of a line. The space after the two dashes is\nrequired (as in MySQL).SELECT * FROM users; -- This is a comment\n\n* C style comments from an opening \'/*\' to a closing \'*/\'. Comments of this\nform can span multiple lines:SELECT * FROM users; /* This is a\nmulti-line\ncomment */\n\nNested comments are possible in some situations, but they are not supported or\nrecommended.\n\nExecutable Comments\n-------------------\n\nAs an aid to portability between different databases, MariaDB supports\nexecutable comments. These special comments allow you to embed SQL code which\nwill not execute when run on other databases, but will execute when run on\nMariaDB.\n\nMariaDB supports both MySQL\'s executable comment format, and a slightly\nmodified version specific to MariaDB. This way, if you have SQL code that\nworks on MySQL and MariaDB, but not other databases, you can wrap it in a\nMySQL executable comment, and if you have code that specifically takes\nadvantage of features only available in MariaDB you can use the MariaDB\nspecific format to hide the code from MySQL.\n\nExecutable Comment Syntax\n-------------------------\n\nMySQL and MariaDB executable comment syntax:\n\n/*! MySQL or MariaDB-specific code */\n\nCode that should be executed only starting from a specific MySQL or MariaDB\nversion:\n\n/*!##### MySQL or MariaDB-specific code */\n\nThe numbers, represented by \'######\' in the syntax examples above specify the\nspecific the minimum versions of MySQL and MariaDB that should execute the\ncomment. The first number is the major version, the second 2 numbers are the\nminor version and the last 2 is the patch level.\n\nFor example, if you want to embed some code that should only execute on MySQL\nor MariaDB starting from 5.1.0, you would do the following:\n\n/*!50100 MySQL and MariaDB 5.1.0 (and above) code goes here. */\n\nMariaDB-only executable comment syntax (starting from MariaDB 5.3.1):\n\n/*M! MariaDB-specific code */\n/*M!###### MariaDB-specific code */\n\nMariaDB ignores MySQL-style executable comments that have a version number in\nthe range 50700..99999. This is needed to skip features introduced in\nMySQL-5.7 that are not ported to MariaDB 10.x yet.\n\n/*!50701 MariaDB-10.x ignores MySQL-5.7 specific code */\n\nNote: comments which have a version number in the range 50700..99999 that use\nMariaDB-style executable comment syntax are still executed.\n\n/*M!50701 MariaDB-10.x does not ignore this */\n\nStatement delimiters cannot be used within executable comments.\n\nExamples\n--------\n\nIn MySQL all the following will return 2: In MariaDB, the last 2 queries would\nreturn 3.\n\nSELECT 2 /* +1 */;\nSELECT 1 /*! +1 */;\nSELECT 1 /*!50101 +1 */;\nSELECT 2 /*M! +1 */;\nSELECT 2 /*M!50301 +1 */;\n\nThe following executable statement will not work due to the delimiter inside\nthe executable portion:\n\n/*M!100100 select 1 ; */\nERROR 1064 (42000): You have an error in your SQL syntax; check the manual\nthat corresponds to your MariaDB server version for the right syntax to use\nnear \'\' at line 1\n\nInstead, the delimiter should be placed outside the executable portion:\n\n/*M!100100 select 1 */;\n+---+\n| 1 |\n+---+\n| 1 |\n+---+\n\nURL: https://mariadb.com/kb/en/comment-syntax/','','https://mariadb.com/kb/en/comment-syntax/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (464,27,'HANDLER Commands','Syntax\n------\n\nHANDLER tbl_name OPEN [ [AS] alias]\nHANDLER tbl_name READ index_name { = | >= | <= | < } (value1,value2,...)\n [ WHERE where_condition ] [LIMIT ... ]\nHANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }\n [ WHERE where_condition ] [LIMIT ... ]\nHANDLER tbl_name READ { FIRST | NEXT }\n [ WHERE where_condition ] [LIMIT ... ]\nHANDLER tbl_name CLOSE\n\nDescription\n-----------\n\nThe HANDLER statement provides direct access to table storage engine\ninterfaces for key lookups and key or table scans. It is available for at\nleast Aria, Memory, MyISAM and InnoDB tables (and should work with most\n\'normal\' storage engines, but not with system tables, MERGE or views).\n\nHANDLER ... OPEN opens a table, allowing it to be accessible to subsequent\nHANDLER ... READ statements. The table can either be opened using an alias\n(which must then be used by HANDLER ... READ, or a table name.\n\nThe table object is only closed when HANDLER ... CLOSE is called by the\nsession, and is not shared by other sessions.\n\nPrepared statements work with HANDLER READ, which gives a much higher\nperformance (50% speedup) as there is no parsing and all data is transformed\nin binary (without conversions to text, as with the normal protocol).\n\nThe HANDLER command does not work with partitioned tables.\n\nKey Lookup\n----------\n\nA key lookup is started with:\n\nHANDLER tbl_name READ index_name { = | >= | <= | < } (value,value) [LIMIT...]\n\nThe values stands for the value of each of the key columns. For most key types\n(except for HASH keys in MEMORY storage engine) you can use a prefix subset of\nit\'s columns.\n\nIf you are using LIMIT, then in case of >= or > then there is an implicit NEXT\nimplied, while if you are using <= or < then there is an implicit PREV implied.\n\nAfter the initial read, you can use\n\nHANDLER tbl_name READ index_name NEXT [ LIMIT ... ]\nor\nHANDLER tbl_name READ index_name PREV [ LIMIT ... ]\n\nto scan the rows in key order.\n\nNote that the row order is not defined for keys with duplicated values and\nwill vary from engine to engine.\n\nKey Scans\n---------\n\nYou can scan a table in key order by doing:\n\nHANDLER tbl_name READ index_name FIRST [ LIMIT ... ]\nHANDLER tbl_name READ index_name NEXT [ LIMIT ... ]\n\nor, if the handler supports backwards key scans (most do):\n\nHANDLER tbl_name READ index_name LAST [ LIMIT ... ]\nHANDLER tbl_name READ index_name PREV [ LIMIT ... ]\n\nTable Scans\n-----------\n\nYou can scan a table in row order by doing:\n\nHANDLER tbl_name READ FIRST [ LIMIT ... ]\nHANDLER tbl_name READ NEXT [ LIMIT ... ]\n\nLimitations\n-----------\n\nAs this is a direct interface to the storage engine, some limitations may\napply for what you can do and what happens if the table changes. Here follows\nsome of the common limitations:\n\nFinding \'Old Rows\'\n------------------\n\nHANDLER READ is not transaction safe, consistent or atomic. It\'s ok for the\nstorage engine to returns rows that existed when you started the scan but that\nwere later deleted. This can happen as the storage engine may cache rows as\npart of the scan from a previous read.\n\nYou may also find rows committed since the scan originally started.\n\nInvisible Columns\n-----------------\n\nHANDLER ... READ also reads the data of invisible-columns.\n\nSystem-Versioned Tables\n-----------------------\n\nHANDLER ... READ reads everything from system-versioned tables, and so\nincludes row_start and row_end fields, as well as all rows that have since\nbeen deleted or changed, including when history partitions are used.\n\nOther Limitations\n-----------------\n\n* If you do an ALTER TABLE, all your HANDLERs for that table are automatically\nclosed.\n* If you do an ALTER TABLE for a table that is used by some other connection\nwith HANDLER, the ALTER TABLE will wait for the HANDLER to be closed.\n* For HASH keys, you must use all key parts when searching for a row.\n* For HASH keys, you can\'t do a key scan of all values. You can only find all\nrows with the same key value.\n* While each HANDLER READ command is atomic, if you do a scan in many steps,\nthen some engines may give you error 1020 if the table changed between the\ncommands. Please refer to the specific engine handler page if this happens.\n\nError Codes\n-----------\n\n* Error 1031 (ER_ILLEGAL_HA) Table storage engine for \'t1\' doesn\'t have this\noption\nIf you get this for HANDLER OPEN it means the storage engine doesn\'t support\nHANDLER calls.\nIf you get this for HANDLER READ it means you are trying to use an incomplete\nHASH key.\n\n* Error 1020 (ER_CHECKREAD) Record has changed since last read in table \'...\'\nThis means that the table changed between two reads and the handler can\'t\nhandle this case for the given scan.\n\nURL: https://mariadb.com/kb/en/handler-commands/','','https://mariadb.com/kb/en/handler-commands/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (465,27,'HANDLER for MEMORY Tables','This article explains how to use HANDLER commands efficiently with MEMORY/HEAP\ntables.\n\nIf you want to scan a table for over different key values, not just search for\nexact key values, you should create your keys with \'USING BTREE\':\n\nCREATE TABLE t1 (a INT, b INT, KEY(a), KEY b USING BTREE (b)) engine=memory;\n\nIn the above table, a is a HASH key that only supports exact matches (=) while\nb is a BTREE key that you can use to scan the table in key order, starting\nfrom start or from a given key value.\n\nThe limitations for HANDLER READ with Memory|HEAP tables are:\n\nLimitations for HASH keys\n-------------------------\n\n* You must use all key parts when searching for a row.\n* You can\'t do a key scan of all values. You can only find all rows with the\nsame key value.\n* READ NEXT gives error 1031 if the tables changed since last read.\n\nLimitations for BTREE keys\n--------------------------\n\n* READ NEXT gives error 1031 if the tables changed since last read. This\nlimitation can be lifted in the future.\n\nLimitations for table scans\n---------------------------\n\n* READ NEXT gives error 1031 if the table was truncated since last READ call.\n\nURL: https://mariadb.com/kb/en/handler-for-memory-tables/','','https://mariadb.com/kb/en/handler-for-memory-tables/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (466,27,'Useful MariaDB Queries','This page is intended to be a quick reference of commonly-used and/or useful\nqueries in MariaDB.\n\nCreating a Table\n----------------\n\nCREATE TABLE t1 ( a INT );\nCREATE TABLE t2 ( b INT );\nCREATE TABLE student_tests (\n name CHAR(10), test CHAR(10), \n score TINYINT, test_date DATE\n);\n\nSee CREATE TABLE for more.\n\nInserting Records\n-----------------\n\nINSERT INTO t1 VALUES (1), (2), (3);\nINSERT INTO t2 VALUES (2), (4);\n\nINSERT INTO student_tests \n (name, test, score, test_date) VALUES\n (\'Chun\', \'SQL\', 75, \'2012-11-05\'), \n (\'Chun\', \'Tuning\', 73, \'2013-06-14\'),\n (\'Esben\', \'SQL\', 43, \'2014-02-11\'), \n (\'Esben\', \'Tuning\', 31, \'2014-02-09\'), \n (\'Kaolin\', \'SQL\', 56, \'2014-01-01\'),\n (\'Kaolin\', \'Tuning\', 88, \'2013-12-29\'), \n (\'Tatiana\', \'SQL\', 87, \'2012-04-28\'), \n (\'Tatiana\', \'Tuning\', 83, \'2013-09-30\');\n\nSee INSERT for more.\n\nUsing AUTO_INCREMENT\n--------------------\n\nThe AUTO_INCREMENT attribute is used to automatically generate a unique\nidentity for new rows.\n\nCREATE TABLE student_details (\n id INT NOT NULL AUTO_INCREMENT, name CHAR(10), \n date_of_birth DATE, PRIMARY KEY (id)\n);\n\nWhen inserting, the id field can be omitted, and is automatically created.\n\nINSERT INTO student_details (name,date_of_birth) VALUES \n (\'Chun\', \'1993-12-31\'), \n (\'Esben\',\'1946-01-01\'),\n (\'Kaolin\',\'1996-07-16\'),\n (\'Tatiana\', \'1988-04-13\');\n\nSELECT * FROM student_details;\n+----+---------+---------------+\n| id | name | date_of_birth |\n+----+---------+---------------+\n| 1 | Chun | 1993-12-31 |\n| 2 | Esben | 1946-01-01 |\n| 3 | Kaolin | 1996-07-16 |\n| 4 | Tatiana | 1988-04-13 |\n+----+---------+---------------+\n\nSee AUTO_INCREMENT for more.\n\nQuerying from two tables on a common value\n------------------------------------------\n\nSELECT * FROM t1 INNER JOIN t2 ON t1.a = t2.b;\n\nThis kind of query is called a join - see JOINS for more.\n\nFinding the Maximum Value\n-------------------------\n\nSELECT MAX(a) FROM t1;\n+--------+\n| MAX(a) |\n+--------+\n| 3 |\n+--------+\n\nSee the MAX() function for more, as well as Finding the maximum value and\ngrouping the results below for a more practical example.\n\nFinding the Minimum Value\n-------------------------\n\nSELECT MIN(a) FROM t1;\n+--------+\n| MIN(a) |\n+--------+\n| 1 |\n+--------+\n\nSee the MIN() function for more.\n\nFinding the Average Value\n-------------------------\n\nSELECT AVG(a) FROM t1;\n+--------+\n| AVG(a) |\n+--------+\n| 2.0000 |\n+--------+\n\nSee the AVG() function for more.\n\nFinding the Maximum Value and Grouping the Results\n--------------------------------------------------\n\nSELECT name, MAX(score) FROM student_tests GROUP BY name;\n+---------+------------+\n| name | MAX(score) |\n+---------+------------+\n| Chun | 75 |\n| Esben | 43 |\n| Kaolin | 88 |\n| Tatiana | 87 |\n+---------+------------+\n\nSee the MAX() function for more.\n\nOrdering Results\n----------------\n\nSELECT name, test, score FROM student_tests ORDER BY score DESC;\n+---------+--------+-------+\n| name | test | score |\n+---------+--------+-------+\n| Kaolin | Tuning | 88 |\n| Tatiana | SQL | 87 |\n| Tatiana | Tuning | 83 |\n| Chun | SQL | 75 |\n| Chun | Tuning | 73 |\n| Kaolin | SQL | 56 |\n| Esben | SQL | 43 |\n| Esben | Tuning | 31 |\n+---------+--------+-------+\n\nSee ORDER BY for more.\n\nFinding the Row with the Minimum of a Particular Column\n-------------------------------------------------------\n\nIn this example, we want to find the lowest test score for any student.\n\nSELECT name,test, score FROM student_tests WHERE score=(SELECT MIN(score) FROM\nstudent);\n+-------+--------+-------+\n| name | test | score |\n+-------+--------+-------+\n| Esben | Tuning | 31 |\n+-------+--------+-------+\n\nFinding Rows with the Maximum Value of a Column by Group\n--------------------------------------------------------\n\nThis example returns the best test results of each student:\n\nSELECT name, test, score FROM student_tests st1 WHERE score = (\n SELECT MAX(score) FROM student st2 WHERE st1.name = st2.name\n); \n+---------+--------+-------+\n| name | test | score |\n+---------+--------+-------+\n| Chun | SQL | 75 |\n| Esben | SQL | 43 |\n| Kaolin | Tuning | 88 |\n| Tatiana | SQL | 87 |\n+---------+--------+-------+\n\nCalculating Age\n---------------\n\nThe TIMESTAMPDIFF function can be used to calculate someone\'s age:\n\nSELECT CURDATE() AS today;\n+------------+\n| today |\n+------------+\n| 2014-02-17 |\n+------------+\n\nSELECT name, date_of_birth, TIMESTAMPDIFF(YEAR,date_of_birth,\'2014-08-02\') AS\nage \n FROM student_details;\n+---------+---------------+------+\n| name | date_of_birth | age |\n+---------+---------------+------+\n| Chun | 1993-12-31 | 20 |\n| Esben | 1946-01-01 | 68 |\n| Kaolin | 1996-07-16 | 18 |\n| Tatiana | 1988-04-13 | 26 |\n+---------+---------------+------+\n\nSee TIMESTAMPDIFF() for more.\n\nUsing User-defined Variables\n----------------------------\n\nThis example sets a user-defined variable with the average test score, and\nthen uses it in a later query to return all results above the average.\n\nSELECT @avg_score:= AVG(score) FROM student_tests;\n+-------------------------+\n| @avg_score:= AVG(score) |\n+-------------------------+\n| 67.000000000 |\n+-------------------------+\n\nSELECT * FROM student_tests WHERE score > @avg_score;\n+---------+--------+-------+------------+\n| name | test | score | test_date |\n+---------+--------+-------+------------+\n| Chun | SQL | 75 | 2012-11-05 |\n| Chun | Tuning | 73 | 2013-06-14 |\n| Kaolin | Tuning | 88 | 2013-12-29 |\n| Tatiana | SQL | 87 | 2012-04-28 |\n| Tatiana | Tuning | 83 | 2013-09-30 |\n+---------+--------+-------+------------+\n\nUser-defined variables can also be used to add an incremental counter to a\nresultset:\n\nSET @count = 0;\n\nSELECT @count := @count + 1 AS counter, name, date_of_birth FROM\nstudent_details;\n+---------+---------+---------------+\n| counter | name | date_of_birth |\n+---------+---------+---------------+\n| 1 | Chun | 1993-12-31 |\n| 2 | Esben | 1946-01-01 |\n| 3 | Kaolin | 1996-07-16 |\n| 4 | Tatiana | 1988-04-13 |\n+---------+---------+---------------+\n\nSee User-defined Variables for more.\n\nView Tables in Order of Size\n----------------------------\n\nReturns a list of all tables in the database, ordered by size:\n\nSELECT table_schema as `DB`, table_name AS `Table`, \n ROUND(((data_length + index_length) / 1024 / 1024), 2) `Size (MB)`\n FROM information_schema.TABLES\n ORDER BY (data_length + index_length) DESC;\n\n+--------------------+---------------------------------------+-----------+\n| DB | Table | Size (MB) |\n+--------------------+---------------------------------------+-----------+\n| wordpress | wp_simple_history_contexts | 7.05 |\n| wordpress | wp_posts | 6.59 |\n| wordpress | wp_simple_history | 3.05 |\n| wordpress | wp_comments | 2.73 |\n| wordpress | wp_commentmeta | 2.47 |\n| wordpress | wp_simple_login_log | 2.03 |\n...\n\nRemoving Duplicates\n-------------------\n\nMariaDB starting with 10.3\n--------------------------\nThe following syntax is only valid MariaDB 10.3 and beyond:\n\nThis example assumes there\'s a unique ID, but that all other fields are\nidentical. In the example below, there are 4 records, 3 of which are\nduplicates, so two of the three duplicates need to be removed. The\nintermediate SELECT is not necessary, but demonstrates what is being returned.\n\nCREATE TABLE t (id INT, f1 VARCHAR(2));\n\nINSERT INTO t VALUES (1,\'a\'), (2,\'a\'), (3,\'b\'), (4,\'a\');\n\nSELECT * FROM t t1, t t2 WHERE t1.f1=t2.f1 AND t1.id<>t2.id AND t1.id=(\n SELECT MAX(id) FROM t tab WHERE tab.f1=t1.f1\n);\n+------+------+------+------+\n| id | f1 | id | f1 |\n+------+------+------+------+\n| 4 | a | 1 | a |\n| 4 | a | 2 | a |\n+------+------+------+------+\n\nDELETE FROM t WHERE id IN (\n SELECT t2.id FROM t t1, t t2 WHERE t1.f1=t2.f1 AND t1.id<>t2.id AND t1.id=(\n SELECT MAX(id) FROM t tab WHERE tab.f1=t1.f1\n )\n);\nQuery OK, 2 rows affected (0.120 sec)\n\nSELECT * FROM t;\n+------+------+\n| id | f1 |\n+------+------+\n| 3 | b |\n| 4 | a |\n+------+------\n\nURL: https://mariadb.com/kb/en/useful-mariadb-queries/','','https://mariadb.com/kb/en/useful-mariadb-queries/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (467,28,'ANALYZE FORMAT=JSON','ANALYZE FORMAT=JSON is a mix of the EXPLAIN FORMAT=JSON and ANALYZE statement\nfeatures. The ANALYZE FORMAT=JSON $statement will execute $statement, and then\nprint the output of EXPLAIN FORMAT=JSON, amended with data from the query\nexecution.\n\nBasic Execution Data\n--------------------\n\nYou can get the following also from tabular ANALYZE statement form:\n\n* r_rows is provided for any node that reads rows. It shows how many rows\nwere read, on average \n* r_filtered is provided whenever there is a condition that is checked. It\nshows the percentage of rows left after checking the condition.\n\nAdvanced Execution Data\n-----------------------\n\nThe most important data not available in the regular tabula ANALYZE statement\nare:\n\n* r_loops field. This shows how many times the node was executed. Most query\nplan elements have this field.\n* r_total_time_ms field. It shows how much time in total, in milliseconds, was\nspent executing this node. If the node has subnodes, their execution time is\nincluded.\n* r_buffer_size field. Query plan nodes that make use of buffers report the\nsize of buffer that was was used.\n\nSHOW ANALYZE FORMAT=JSON\n------------------------\n\nMariaDB starting with 10.9\n--------------------------\nSHOW ANALYZE FORMAT=JSON for <connection_id> extends ANALYZE [FORMAT=JSON]\n<select> to allow one to analyze a query currently running in another\nconnection.\n\nData About Individual Query Plan Nodes\n--------------------------------------\n\n* filesort node reports whether sorting was done with LIMIT n parameter, and\nhow many rows were in the sort result. \n* block-nl-join node has r_loops field, which allows to tell whether Using\njoin buffer was efficient \n* range-checked-for-each-record reports counters that show the result of the\ncheck. \n* expression-cache is used for subqueries, and it reports how many times the\ncache was used, and what cache hit ratio was.\n* union_result node has r_rows so one can see how many rows were produced\nafter UNION operation\n* and so forth\n\nUse Cases\n---------\n\nSee Examples of ANALYZE FORMAT=JSON.\n\nURL: https://mariadb.com/kb/en/analyze-format-json/','','https://mariadb.com/kb/en/analyze-format-json/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (468,28,'ANALYZE FORMAT=JSON Examples','Example #1\n----------\n\nCustomers who have ordered more than 1M goods.\n\nANALYZE FORMAT=JSON\nSELECT COUNT(*)\nFROM customer\nWHERE\n (SELECT SUM(o_totalprice) FROM orders WHERE o_custkey=c_custkey) > 1000*1000;\n\nThe query takes 40 seconds over cold cache\n\nEXPLAIN: {\n \"query_block\": {\n \"select_id\": 1,\n \"r_loops\": 1,\n \"r_total_time_ms\": 39872,\n \"table\": {\n \"table_name\": \"customer\",\n \"access_type\": \"index\",\n \"key\": \"i_c_nationkey\",\n \"key_length\": \"5\",\n \"used_key_parts\": [\"c_nationkey\"],\n \"r_loops\": 1,\n \"rows\": 150303,\n \"r_rows\": 150000,\n \"r_total_time_ms\": 270.3,\n \"filtered\": 100,\n \"r_filtered\": 60.691,\n \"attached_condition\": \"((subquery#2) > <cache>((1000 * 1000)))\",\n \"using_index\": true\n },\n \"subqueries\": [\n {\n \"query_block\": {\n \"select_id\": 2,\n \"r_loops\": 150000,\n \"r_total_time_ms\": 39531,\n \"table\": {\n \"table_name\": \"orders\",\n \"access_type\": \"ref\",\n \"possible_keys\": [\"i_o_custkey\"],\n \"key\": \"i_o_custkey\",\n \"key_length\": \"5\",\n \"used_key_parts\": [\"o_custkey\"],\n \"ref\": [\"dbt3sf1.customer.c_custkey\"],\n \"r_loops\": 150000,\n \"rows\": 7,\n \"r_rows\": 10,\n \"r_total_time_ms\": 39208,\n \"filtered\": 100,\n \"r_filtered\": 100\n }\n }\n }\n ]\n }\n}\nANALYZE shows that 39.2 seconds were spent in the subquery, which was executed\n150K times (for every row of outer table).\n\nURL: https://mariadb.com/kb/en/analyze-formatjson-examples/','','https://mariadb.com/kb/en/analyze-formatjson-examples/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (469,28,'ANALYZE Statement','Description\n-----------\n\nThe ANALYZE statement is similar to the EXPLAIN statement. ANALYZE statement\nwill invoke the optimizer, execute the statement, and then produce EXPLAIN\noutput instead of the result set. The EXPLAIN output will be annotated with\nstatistics from statement execution.\n\nThis lets one check how close the optimizer\'s estimates about the query plan\nare to the reality. ANALYZE produces an overview, while the ANALYZE\nFORMAT=JSON command provides a more detailed view of the query plan and the\nquery execution.\n\nThe syntax is\n\nANALYZE explainable_statement;\n\nwhere the statement is any statement for which one can run EXPLAIN.\n\nCommand Output\n--------------\n\nConsider an example:\n\nANALYZE SELECT * FROM tbl1 \nWHERE key1 \n BETWEEN 10 AND 200 AND\n col1 LIKE \'foo%\'\\G\n\n*************************** 1. row ***************************\n id: 1\n select_type: SIMPLE\n table: tbl1\n type: range\npossible_keys: key1\n key: key1\n key_len: 5\n ref: NULL\n rows: 181\n r_rows: 181\n filtered: 100.00\n r_filtered: 10.50\n Extra: Using index condition; Using where\n\nCompared to EXPLAIN, ANALYZE produces two extra columns:\n\n* r_rows is an observation-based counterpart of the rows column. It shows how\nmany rows were actually read from the table. \n* r_filtered is an observation-based counterpart of the filtered column. It\nshows which fraction of rows was left after applying the WHERE condition.\n\nInterpreting the Output\n-----------------------\n\nJoins\n-----\n\nLet\'s consider a more complicated example.\n\nANALYZE SELECT *\nFROM orders, customer \nWHERE\n customer.c_custkey=orders.o_custkey AND\n customer.c_acctbal < 0 AND\n orders.o_totalprice > 200*1000\n\n+----+-------------+----------+------+---------------+-------------+---------+-\n------------------+--------+--------+----------+------------+-------------+\n| id | select_type | table | type | possible_keys | key | key_len |\nref | rows | r_rows | filtered | r_filtered | Extra |\n+----+-------------+----------+------+---------------+-------------+---------+-\n------------------+--------+--------+----------+------------+-------------+\n| 1 | SIMPLE | customer | ALL | PRIMARY,... | NULL | NULL |\nNULL | 149095 | 150000 | 18.08 | 9.13 | Using where |\n| 1 | SIMPLE | orders | ref | i_o_custkey | i_o_custkey | 5 |\ncustomer.c_custkey | 7 | 10 | 100.00 | 30.03 | Using where |\n+----+-------------+----------+------+---------------+-------------+---------+-\n------------------+--------+--------+----------+------------+-------------+\n\nHere, one can see that\n\n* For table customer, customer.rows=149095, customer.r_rows=150000. The\nestimate for number of rows we will read was fairly precise\n* customer.filtered=18.08, customer.r_filtered=9.13. The optimizer somewhat\noverestimated the number of records that will match selectivity of condition\nattached to `customer` table (in general, when you have a full scan and\nr_filtered is less than 15%, it\'s time to consider adding an appropriate\nindex).\n* For table orders, orders.rows=7, orders.r_rows=10. This means that on\naverage, there are 7 orders for a given c_custkey, but in our case there were\n10, which is close to the expectation (when this number is consistently far\nfrom the expectation, it may be time to run ANALYZE TABLE, or even edit the\ntable statistics manually to get better query plans).\n* orders.filtered=100, orders.r_filtered=30.03. The optimizer didn\'t have any\nway to estimate which fraction of records will be left after it checks the\ncondition that is attached to table orders (it\'s orders.o_totalprice >\n200*1000). So, it used 100%. In reality, it is 30%. 30% is typically not\nselective enough to warrant adding new indexes. For joins with many tables, it\nmight be worth to collect and use column statistics for columns in question,\nthis may help the optimizer to pick a better query plan.\n\nMeaning of NULL in r_rows and r_filtered\n----------------------------------------\n\nLet\'s modify the previous example slightly\n\nANALYZE SELECT * \nFROM orders, customer \nWHERE\n customer.c_custkey=orders.o_custkey AND\n customer.c_acctbal < -0 AND\n customer.c_comment LIKE \'%foo%\' AND\n orders.o_totalprice > 200*1000;\n\n+----+-------------+----------+------+---------------+-------------+---------+-\n------------------+--------+--------+----------+------------+-------------+\n| id | select_type | table | type | possible_keys | key | key_len |\nref | rows | r_rows | filtered | r_filtered | Extra |\n+----+-------------+----------+------+---------------+-------------+---------+-\n------------------+--------+--------+----------+------------+-------------+\n| 1 | SIMPLE | customer | ALL | PRIMARY,... | NULL | NULL |\nNULL | 149095 | 150000 | 18.08 | 0.00 | Using where |\n| 1 | SIMPLE | orders | ref | i_o_custkey | i_o_custkey | 5 |\ncustomer.c_custkey | 7 | NULL | 100.00 | NULL | Using where |\n+----+-------------+----------+------+---------------+-------------+---------+-\n------------------+--------+--------+----------+------------+-------------+\n\nHere, one can see that orders.r_rows=NULL and orders.r_filtered=NULL. This\nmeans that table orders was not scanned even once. Indeed, we can also see\ncustomer.r_filtered=0.00. This shows that a part of WHERE attached to table\n`customer` was never satisfied (or, satisfied in less than 0.01% of cases).\n\nANALYZE FORMAT=JSON\n-------------------\n\nANALYZE FORMAT=JSON produces JSON output. It produces much more information\nthan tabular ANALYZE.\n\nNotes\n-----\n\n* ANALYZE UPDATE or ANALYZE DELETE will actually make updates/deletes (ANALYZE\nSELECT will perform the select operation and then discard the resultset).\n* PostgreSQL has a similar command, EXPLAIN ANALYZE.\n* The EXPLAIN in the slow query log feature allows MariaDB to have ANALYZE\noutput of slow queries printed into the slow query log (see MDEV-6388).\n\nURL: https://mariadb.com/kb/en/analyze-statement/','','https://mariadb.com/kb/en/analyze-statement/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (470,28,'EXPLAIN','Syntax\n------\n\nEXPLAIN tbl_name [col_name | wild]\n\nOr\n\nEXPLAIN [EXTENDED | PARTITIONS | FORMAT=JSON] \n {SELECT select_options | UPDATE update_options | DELETE delete_options}\n\nDescription\n-----------\n\nThe EXPLAIN statement can be used either as a synonym for DESCRIBE or as a way\nto obtain information about how MariaDB executes a SELECT, UPDATE or DELETE\nstatement:\n\n* \'EXPLAIN tbl_name\' is synonymous with \n \'DESCRIBE tbl_name\' or\n \'SHOW COLUMNS FROM tbl_name\'.\n* When you precede a SELECT, UPDATE or a DELETE statement with the keyword \n EXPLAIN, MariaDB displays information from the optimizer\n about the query execution plan. That is, MariaDB explains how it would\n process the SELECT, UPDATE or DELETE, including information about how tables\n are joined and in which order. EXPLAIN EXTENDED can be\n used to provide additional information.\n* EXPLAIN PARTITIONS is useful only when examining queries involving\npartitioned tables. For details, see Partition pruning and selection.\n* ANALYZE statement performs the query as well as producing EXPLAIN output,\nand provides actual as well as estimated statistics.\n* EXPLAIN output can be printed in the slow query log. See EXPLAIN in the Slow\nQuery Log for details.\n\nSHOW EXPLAIN shows the output of a running statement. In some cases, its\noutput can be closer to reality than EXPLAIN.\n\nThe ANALYZE statement runs a statement and returns information about its\nexecution plan. It also shows additional columns, to check how much the\noptimizer\'s estimation about filtering and found rows are close to reality.\n\nThere is an online EXPLAIN Analyzer that you can use to share EXPLAIN and\nEXPLAIN EXTENDED output with others.\n\nEXPLAIN can acquire metadata locks in the same way that SELECT does, as it\nneeds to know table metadata and, sometimes, data as well.\n\nColumns in EXPLAIN ... SELECT\n-----------------------------\n\n+--------------------------------------+--------------------------------------+\n| Column name | Description |\n+--------------------------------------+--------------------------------------+\n| id | Sequence number that shows in which |\n| | order tables are joined. |\n+--------------------------------------+--------------------------------------+\n| select_type | What kind of SELECT the table comes |\n| | from. |\n+--------------------------------------+--------------------------------------+\n| table | Alias name of table. Materialized |\n| | temporary tables for sub queries |\n| | are named <subquery#> |\n+--------------------------------------+--------------------------------------+\n| type | How rows are found from the table |\n| | (join type). |\n+--------------------------------------+--------------------------------------+\n| possible_keys | keys in table that could be used to |\n| | find rows in the table |\n+--------------------------------------+--------------------------------------+\n| key | The name of the key that is used to |\n| | retrieve rows. NULL is no key was |\n| | used. |\n+--------------------------------------+--------------------------------------+\n| key_len | How many bytes of the key that was |\n| | used (shows if we are using only |\n| | parts of the multi-column key). |\n+--------------------------------------+--------------------------------------+\n| ref | The reference that is used as the |\n| | key value. |\n+--------------------------------------+--------------------------------------+\n| rows | An estimate of how many rows we |\n| | will find in the table for each key |\n| | lookup. |\n+--------------------------------------+--------------------------------------+\n| Extra | Extra information about this join. |\n+--------------------------------------+--------------------------------------+\n\nHere are descriptions of the values for some of the more complex columns in\nEXPLAIN ... SELECT:\n\n\"Select_type\" Column\n--------------------\n\nThe select_type column can have the following values:\n\n+-----------------+-----------------------------------+-----------------------+\n| Value | Description | Comment |\n+-----------------+-----------------------------------+-----------------------+\n| DEPENDENT | The SUBQUERY is DEPENDENT. | |\n| SUBQUERY | | |\n+-----------------+-----------------------------------+-----------------------+\n| DEPENDENT UNION | The UNION is DEPENDENT. | |\n+-----------------+-----------------------------------+-----------------------+\n| DERIVED | The SELECT is DERIVED from the | |\n| | PRIMARY. | |\n+-----------------+-----------------------------------+-----------------------+\n| MATERIALIZED | The SUBQUERY is MATERIALIZED. | Materialized tables |\n| | | will be populated at |\n| | | first access and |\n| | | will be accessed by |\n| | | the primary key (= |\n| | | one key lookup). |\n| | | Number of rows in |\n| | | EXPLAIN shows the |\n| | | cost of populating |\n| | | the table |\n+-----------------+-----------------------------------+-----------------------+\n| PRIMARY | The SELECT is in the outermost | |\n| | query, but there is also a | |\n| | SUBQUERY within it. | |\n+-----------------+-----------------------------------+-----------------------+\n| SIMPLE | It is a simple SELECT query | |\n| | without any SUBQUERY or UNION. | |\n+-----------------+-----------------------------------+-----------------------+\n| SUBQUERY | The SELECT is a SUBQUERY of the | |\n| | PRIMARY. | |\n+-----------------+-----------------------------------+-----------------------+\n| UNCACHEABLE | The SUBQUERY is UNCACHEABLE. | |\n| SUBQUERY | | |\n+-----------------+-----------------------------------+-----------------------+\n| UNCACHEABLE | The UNION is UNCACHEABLE. | |\n| UNION | | |\n+-----------------+-----------------------------------+-----------------------+\n| UNION | The SELECT is a UNION of the | |\n| | PRIMARY. | |\n+-----------------+-----------------------------------+-----------------------+\n| UNION RESULT | The result of the UNION. | |\n+-----------------+-----------------------------------+-----------------------+\n| LATERAL DERIVED | The SELECT uses a Lateral | |\n| | Derived optimization | |\n+-----------------+-----------------------------------+-----------------------+\n\n\"Type\" Column\n-------------\n\nThis column contains information on how the table is accessed.\n\n+------------------------+---------------------------------------------------+\n| Value | Description |\n+------------------------+---------------------------------------------------+\n| ALL | A full table scan is done for the table (all |\n| | rows are read). This is bad if the table is |\n| | large and the table is joined against a previous |\n| | table! This happens when the optimizer could |\n| | not find any usable index to access rows. |\n+------------------------+---------------------------------------------------+\n| const | There is only one possibly matching row in the |\n| | table. The row is read before the optimization |\n| | phase and all columns in the table are treated |\n| | as constants. |\n+------------------------+---------------------------------------------------+\n| eq_ref | A unique index is used to find the rows. This is |\n| | the best possible plan to find the row. |\n+------------------------+---------------------------------------------------+\n| fulltext | A fulltext index is used to access the rows. |\n+------------------------+---------------------------------------------------+\n| index_merge | A \'range\' access is done for for several index |\n| | and the found rows are merged. The key column |\n| | shows which keys are used. |\n+------------------------+---------------------------------------------------+\n| index_subquery | This is similar as ref, but used for sub queries |\n| | that are transformed to key lookups. |\n+------------------------+---------------------------------------------------+\n| index | A full scan over the used index. Better than |\n| | ALL but still bad if index is large and the |\n| | table is joined against a previous table. |\n+------------------------+---------------------------------------------------+\n| range | The table will be accessed with a key over one |\n| | or more value ranges. |\n+------------------------+---------------------------------------------------+\n| ref_or_null | Like \'ref\' but in addition another search for |\n| | the \'null\' value is done if the first value was |\n| | not found. This happens usually with sub queries. |\n+------------------------+---------------------------------------------------+\n| ref | A non unique index or prefix of an unique index |\n| | is used to find the rows. Good if the prefix |\n| | doesn\'t match many rows. |\n+------------------------+---------------------------------------------------+\n| system | The table has 0 or 1 rows. |\n+------------------------+---------------------------------------------------+\n| unique_subquery | This is similar as eq_ref, but used for sub |\n| | queries that are transformed to key lookups |\n+------------------------+---------------------------------------------------+\n\n\"Extra\" Column\n--------------\n\nThis column consists of one or more of the following values, separated by \';\'\n\nNote that some of these values are detected after the optimization phase.\n\nThe optimization phase can do the following changes to the WHERE clause:\n\n* Add the expressions from the ON and USING clauses to the WHERE\n clause.\n* Constant propagation: If there is column=constant, replace all column\n instances with this constant.\n* Replace all columns from \'const\' tables with their values.\n* Remove the used key columns from the WHERE (as this will be tested as\n part of the key lookup).\n* Remove impossible constant sub expressions.\n For example WHERE \'(a=1 and a=2) OR b=1\' becomes \'b=1\'.\n* Replace columns with other columns that has identical values:\n Example: WHERE a=b and a=c may be treated\n as \'WHERE a=b and a=c and b=c\'.\n* Add extra conditions to detect impossible row conditions earlier. This\n happens mainly with OUTER JOIN where we in some cases add detection\n of NULL values in the WHERE (Part of \'Not exists\' optimization).\n This can cause an unexpected \'Using where\' in the Extra column.\n* For each table level we remove expressions that have already been tested when\n we read the previous row. Example: When joining tables t1 with t2\n using the following WHERE \'t1.a=1 and t1.a=t2.b\', we don\'t have to\n test \'t1.a=1\' when checking rows in t2 as we already know that this\n expression is true.\n\n+------------------------+---------------------------------------------------+\n| Value | Description |\n+------------------------+---------------------------------------------------+\n| const row not found | The table was a system table (a table with |\n| | should exactly one row), but no row was found. |\n+------------------------+---------------------------------------------------+\n| Distinct | If distinct optimization (remove duplicates) was |','','https://mariadb.com/kb/en/explain/'); +update help_topic set description = CONCAT(description, '\n| | used. This is marked only for the last table in |\n| | the SELECT. |\n+------------------------+---------------------------------------------------+\n| Full scan on NULL key | The table is a part of the sub query and if the |\n| | value that is used to match the sub query will |\n| | be NULL, we will do a full table scan. |\n+------------------------+---------------------------------------------------+\n| Impossible HAVING | The used HAVING clause is always false so the |\n| | SELECT will return no rows. |\n+------------------------+---------------------------------------------------+\n| Impossible WHERE | The used WHERE clause is always false so the |\n| noticed after reading | SELECT will return no rows. This case was |\n| const tables. | detected after we had read all \'const\' tables |\n| | and used the column values as constant in the |\n| | WHERE clause. For example: WHERE const_column=5 |\n| | and const_column had a value of 4. |\n+------------------------+---------------------------------------------------+\n| Impossible WHERE | The used WHERE clause is always false so the |\n| | SELECT will return no rows. For example: WHERE |\n| | 1=2 |\n+------------------------+---------------------------------------------------+\n| No matching min/max | During early optimization of MIN()/MAX() values |\n| row | it was detected that no row could match the |\n| | WHERE clause. The MIN()/MAX() function will |\n| | return NULL. |\n+------------------------+---------------------------------------------------+\n| no matching row in | The table was a const table (a table with only |\n| const table | one possible matching row), but no row was found. |\n+------------------------+---------------------------------------------------+\n| No tables used | The SELECT was a sub query that did not use any |\n| | tables. For example a there was no FROM clause |\n| | or a FROM DUAL clause. |\n+------------------------+---------------------------------------------------+\n| Not exists | Stop searching after more row if we find one |\n| | single matching row. This optimization is used |\n| | with LEFT JOIN where one is explicitly searching |\n| | for rows that doesn\'t exists in the LEFT JOIN |\n| | TABLE. Example: SELECT * FROM t1 LEFT JOIN t2 on |\n| | (...) WHERE t2.not_null_column IS NULL. As |\n| | t2.not_null_column can only be NULL if there was |\n| | no matching row for on condition, we can stop |\n| | searching if we find a single matching row. |\n+------------------------+---------------------------------------------------+\n| Open_frm_only | For information_schema tables. Only the frm |\n| | (table definition file was opened) was opened |\n| | for each matching row. |\n+------------------------+---------------------------------------------------+\n| Open_full_table | For information_schema tables. A full table open |\n| | for each matching row is done to retrieve the |\n| | requested information. (Slow) |\n+------------------------+---------------------------------------------------+\n| Open_trigger_only | For information_schema tables. Only the trigger |\n| | file definition was opened for each matching row. |\n+------------------------+---------------------------------------------------+\n| Range checked for | This only happens when there was no good default |\n| each record (index | index to use but there may some index that could |\n| map: ...) | be used when we can treat all columns from |\n| | previous table as constants. For each row |\n| | combination the optimizer will decide which |\n| | index to use (if any) to fetch a row from this |\n| | table. This is not fast, but faster than a full |\n| | table scan that is the only other choice. The |\n| | index map is a bitmask that shows which index |\n| | are considered for each row condition. |\n+------------------------+---------------------------------------------------+\n| Scanned 0/1/all | For information_schema tables. Shows how many |\n| databases | times we had to do a directory scan. |\n+------------------------+---------------------------------------------------+\n| Select tables | All tables in the join was optimized away. This |\n| optimized away | happens when we are only using COUNT(*), MIN() |\n| | and MAX() functions in the SELECT and we where |\n| | able to replace all of these with constants. |\n+------------------------+---------------------------------------------------+\n| Skip_open_table | For information_schema tables. The queried table |\n| | didn\'t need to be opened. |\n+------------------------+---------------------------------------------------+\n| unique row not found | The table was detected to be a const table (a |\n| | table with only one possible matching row) |\n| | during the early optimization phase, but no row |\n| | was found. |\n+------------------------+---------------------------------------------------+\n| Using filesort | Filesort is needed to resolve the query. This |\n| | means an extra phase where we first collect all |\n| | columns to sort, sort them with a disk based |\n| | merge sort and then use the sorted set to |\n| | retrieve the rows in sorted order. If the column |\n| | set is small, we store all the columns in the |\n| | sort file to not have to go to the database to |\n| | retrieve them again. |\n+------------------------+---------------------------------------------------+\n| Using index | Only the index is used to retrieve the needed |\n| | information from the table. There is no need to |\n| | perform an extra seek to retrieve the actual |\n| | record. |\n+------------------------+---------------------------------------------------+\n| Using index condition | Like \'Using where\' but the where condition is |\n| | pushed down to the table engine for internal |\n| | optimization at the index level. |\n+------------------------+---------------------------------------------------+\n| Using index | Like \'Using index condition\' but in addition we |\n| condition(BKA) | use batch key access to retrieve rows. |\n+------------------------+---------------------------------------------------+\n| Using index for | The index is being used to resolve a GROUP BY or |\n| group-by | DISTINCT query. The rows are not read. This is |\n| | very efficient if the table has a lot of |\n| | identical index entries as duplicates are |\n| | quickly jumped over. |\n+------------------------+---------------------------------------------------+\n| Using intersect(...) | For index_merge joins. Shows which index are |\n| | part of the intersect. |\n+------------------------+---------------------------------------------------+\n| Using join buffer | We store previous row combinations in a row |\n| | buffer to be able to match each row against all |\n| | of the rows combinations in the join buffer at |\n| | one go. |\n+------------------------+---------------------------------------------------+\n| Using sort_union(...) | For index_merge joins. Shows which index are |\n| | part of the union. |\n+------------------------+---------------------------------------------------+\n| Using temporary | A temporary table is created to hold the result. |\n| | This typically happens if you are using GROUP |\n| | BY, DISTINCT or ORDER BY. |\n+------------------------+---------------------------------------------------+\n| Using where | A WHERE expression (in additional to the |\n| | possible key lookup) is used to check if the row |\n| | should be accepted. If you don\'t have \'Using |\n| | where\' together with a join type of ALL, you are |\n| | probably doing something wrong! |\n+------------------------+---------------------------------------------------+\n| Using where with | Like \'Using where\' but the where condition is |\n| pushed condition | pushed down to the table engine for internal |\n| | optimization at the row level. |\n+------------------------+---------------------------------------------------+\n| Using buffer | The UPDATE statement will first buffer the rows, |\n| | and then run the updates, rather than do updates |\n| | on the fly. See Using Buffer UPDATE Algorithm |\n| | for a detailed explanation. |\n+------------------------+---------------------------------------------------+\n\nEXPLAIN EXTENDED\n----------------\n\nThe EXTENDED keyword adds another column, filtered, to the output. This is a\npercentage estimate of the table rows that will be filtered by the condition.\n\nAn EXPLAIN EXTENDED will always throw a warning, as it adds extra Message\ninformation to a subsequent SHOW WARNINGS statement. This includes what the\nSELECT query would look like after optimizing and rewriting rules are applied\nand how the optimizer qualifies columns and tables.\n\nExamples\n--------\n\nAs synonym for DESCRIBE or SHOW COLUMNS FROM:\n\nDESCRIBE city;\n+------------+----------+------+-----+---------+----------------+\n| Field | Type | Null | Key | Default | Extra |\n+------------+----------+------+-----+---------+----------------+\n| Id | int(11) | NO | PRI | NULL | auto_increment |\n| Name | char(35) | YES | | NULL | |\n| Country | char(3) | NO | UNI | | |\n| District | char(20) | YES | MUL | | |\n| Population | int(11) | YES | | NULL | |\n+------------+----------+------+-----+---------+----------------+\n\nA simple set of examples to see how EXPLAIN can identify poor index usage:\n\nCREATE TABLE IF NOT EXISTS `employees_example` (\n `id` int(11) NOT NULL AUTO_INCREMENT,\n `first_name` varchar(30) NOT NULL,\n `last_name` varchar(40) NOT NULL,\n `position` varchar(25) NOT NULL,\n `home_address` varchar(50) NOT NULL,\n `home_phone` varchar(12) NOT NULL,\n `employee_code` varchar(25) NOT NULL,\n PRIMARY KEY (`id`),\n UNIQUE KEY `employee_code` (`employee_code`),\n KEY `first_name` (`first_name`,`last_name`)\n) ENGINE=Aria;\n\nINSERT INTO `employees_example` (`first_name`, `last_name`, `position`,\n`home_address`, `home_phone`, `employee_code`)\n VALUES\n (\'Mustapha\', \'Mond\', \'Chief Executive Officer\', \'692 Promiscuous Plaza\',\n\'326-555-3492\', \'MM1\'),\n (\'Henry\', \'Foster\', \'Store Manager\', \'314 Savage Circle\', \'326-555-3847\',\n\'HF1\'),\n (\'Bernard\', \'Marx\', \'Cashier\', \'1240 Ambient Avenue\', \'326-555-8456\', \'BM1\'),\n (\'Lenina\', \'Crowne\', \'Cashier\', \'281 Bumblepuppy Boulevard\', \'328-555-2349\',\n\'LC1\'),\n (\'Fanny\', \'Crowne\', \'Restocker\', \'1023 Bokanovsky Lane\', \'326-555-6329\',\n\'FC1\'),\n (\'Helmholtz\', \'Watson\', \'Janitor\', \'944 Soma Court\', \'329-555-2478\', \'HW1\');\n\nSHOW INDEXES FROM employees_example;\n+-------------------+------------+---------------+--------------+--------------\n+-----------+-------------+----------+--------+------+------------+---------+--\n------------+\n| Table | Non_unique | Key_name | Seq_in_index | Column_name \n | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |\nIndex_comment |\n+-------------------+------------+---------------+--------------+--------------\n+-----------+-------------+----------+--------+------+------------+---------+--\n------------+\n| employees_example | 0 | PRIMARY | 1 | id \n | A | 7 | NULL | NULL | | BTREE | |\n |\n| employees_example | 0 | employee_code | 1 |\nemployee_code | A | 7 | NULL | NULL | | BTREE \n | | |\n| employees_example | 1 | first_name | 1 | first_name \n | A | NULL | NULL | NULL | | BTREE | |\n |') WHERE help_topic_id = 470; +update help_topic set description = CONCAT(description, '\n| employees_example | 1 | first_name | 2 | last_name \n | A | NULL | NULL | NULL | | BTREE | |\n |\n+-------------------+------------+---------------+--------------+--------------\n+-----------+-------------+----------+--------+------+------------+---------+--\n------------+\n\nSELECT on a primary key:\n\nEXPLAIN SELECT * FROM employees_example WHERE id=1;\n+------+-------------+-------------------+-------+---------------+---------+---\n-----+-------+------+-------+\n| id | select_type | table | type | possible_keys | key |\nkey_len | ref | rows | Extra |\n+------+-------------+-------------------+-------+---------------+---------+---\n-----+-------+------+-------+\n| 1 | SIMPLE | employees_example | const | PRIMARY | PRIMARY | 4\n | const | 1 | |\n+------+-------------+-------------------+-------+---------------+---------+---\n-----+-------+------+-------+\n\nThe type is const, which means that only one possible result could be\nreturned. Now, returning the same record but searching by their phone number:\n\nEXPLAIN SELECT * FROM employees_example WHERE home_phone=\'326-555-3492\';\n+------+-------------+-------------------+------+---------------+------+-------\n-+------+------+-------------+\n| id | select_type | table | type | possible_keys | key |\nkey_len | ref | rows | Extra |\n+------+-------------+-------------------+------+---------------+------+-------\n-+------+------+-------------+\n| 1 | SIMPLE | employees_example | ALL | NULL | NULL | NULL \n | NULL | 6 | Using where |\n+------+-------------+-------------------+------+---------------+------+-------\n-+------+------+-------------+\n\nHere, the type is All, which means no index could be used. Looking at the rows\ncount, a full table scan (all six rows) had to be performed in order to\nretrieve the record. If it\'s a requirement to search by phone number, an index\nwill have to be created.\n\nSHOW EXPLAIN example:\n\nSHOW EXPLAIN FOR 1;\n+------+-------------+-------+-------+---------------+------+---------+------+-\n-------+-------------+\n| id | select_type | table | type | possible_keys | key | key_len | ref |\nrows | Extra |\n+------+-------------+-------+-------+---------------+------+---------+------+-\n-------+-------------+\n| 1 | SIMPLE | tbl | index | NULL | a | 5 | NULL |\n1000107 | Using index |\n+------+-------------+-------+-------+---------------+------+---------+------+-\n-------+-------------+\n1 row in set, 1 warning (0.00 sec)\n\nExample of ref_or_null Optimization\n-----------------------------------\n\nSELECT * FROM table_name\n WHERE key_column=expr OR key_column IS NULL;\n\nref_or_null is something that often happens when you use subqueries with NOT\nIN as then one has to do an extra check for NULL values if the first value\ndidn\'t have a matching row.\n\nURL: https://mariadb.com/kb/en/explain/') WHERE help_topic_id = 470; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (471,28,'EXPLAIN ANALYZE','The syntax for the EXPLAIN ANALYZE feature was changed to ANALYZE statement,\navailable since MariaDB 10.1.0. See ANALYZE statement.\n\nURL: https://mariadb.com/kb/en/explain-analyze/','','https://mariadb.com/kb/en/explain-analyze/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (472,28,'EXPLAIN FORMAT=JSON','Synopsis\n--------\n\nEXPLAIN FORMAT=JSON is a variant of EXPLAIN command that produces output in\nJSON form. The output always has one row which has only one column titled\n\"JSON\". The contents are a JSON representation of the query plan, formatted\nfor readability:\n\nEXPLAIN FORMAT=JSON SELECT * FROM t1 WHERE col1=1\\G\n\n*************************** 1. row ***************************\nEXPLAIN: {\n \"query_block\": {\n \"select_id\": 1,\n \"table\": {\n \"table_name\": \"t1\",\n \"access_type\": \"ALL\",\n \"rows\": 1000,\n \"filtered\": 100,\n \"attached_condition\": \"(t1.col1 = 1)\"\n }\n }\n}\n\nOutput is different from MySQL\n------------------------------\n\nThe output of MariaDB\'s EXPLAIN FORMAT=JSON is different from EXPLAIN\nFORMAT=JSON in MySQL.The reasons for that are:\n\n* MySQL\'s output has deficiencies. Some are listed here: EXPLAIN FORMAT=JSON\nin MySQL\n* The output of MySQL\'s EXPLAIN FORMAT=JSON is not defined. Even MySQL\nWorkbench has trouble parsing it (see this blog post).\n* MariaDB has query optimizations that MySQL does not have. Ergo, MariaDB\ngenerates query plans that MySQL does not generate.\n\nA (as yet incomplete) list of how MariaDB\'s output is different from MySQL can\nbe found here: EXPLAIN FORMAT=JSON differences from MySQL.\n\nOutput Format\n-------------\n\nTODO: MariaDB\'s output format description.\n\nURL: https://mariadb.com/kb/en/explain-format-json/','','https://mariadb.com/kb/en/explain-format-json/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (473,28,'DESCRIBE','Syntax\n------\n\n{DESCRIBE | DESC} tbl_name [col_name | wild]\n\nDescription\n-----------\n\nDESCRIBE provides information about the columns in a table. It is a shortcut\nfor SHOW COLUMNS FROM. These statements also display information for views.\n\ncol_name can be a column name, or a string containing the SQL \"%\" and \"_\"\nwildcard characters to obtain output only for the columns with names matching\nthe string. There is no need to enclose the string within quotes unless it\ncontains spaces or other special characters.\n\nDESCRIBE city;\n+------------+----------+------+-----+---------+----------------+\n| Field | Type | Null | Key | Default | Extra |\n+------------+----------+------+-----+---------+----------------+\n| Id | int(11) | NO | PRI | NULL | auto_increment |\n| Name | char(35) | YES | | NULL | |\n| Country | char(3) | NO | UNI | | |\n| District | char(20) | YES | MUL | | |\n| Population | int(11) | YES | | NULL | |\n+------------+----------+------+-----+---------+----------------+\n\nThe description for SHOW COLUMNS provides more information about the output\ncolumns.\n\nURL: https://mariadb.com/kb/en/describe/','','https://mariadb.com/kb/en/describe/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (474,29,'Identifier Names','Databases, tables, indexes, columns, aliases, views, stored routines,\ntriggers, events, variables, partitions, tablespaces, savepoints, labels,\nusers, roles, are collectively known as identifiers, and have certain rules\nfor naming.\n\nIdentifiers may be quoted using the backtick character - `. Quoting is\noptional for identifiers that don\'t contain special characters, or for\nidentifiers that are not reserved words. If the ANSI_QUOTES SQL_MODE flag is\nset, double quotes (\") can also be used to quote identifiers. If the MSSQL\nflag is set, square brackets ([ and ]) can be used for quoting.\n\nEven when using reserved words as names, fully qualified names do not need to\nbe quoted. For example, test.select has only one possible meaning, so it is\ncorrectly parsed even without quotes.\n\nUnquoted\n--------\n\nThe following characters are valid, and allow identifiers to be unquoted:\n\n* ASCII: [0-9,a-z,A-Z$_] (numerals 0-9, basic Latin letters, both lowercase\nand uppercase, dollar sign, underscore)\n* Extended: U+0080 .. U+FFFF\n\nQuoted\n------\n\nThe following characters are valid, but identifiers using them must be quoted:\n\n* ASCII: U+0001 .. U+007F (full Unicode Basic Multilingual Plane (BMP) except\nfor U+0000)\n* Extended: U+0080 .. U+FFFF \n* Identifier quotes can themselves be used as part of an identifier, as long\nas they are quoted.\n\nFurther Rules\n-------------\n\nThere are a number of other rules for identifiers:\n\n* Identifiers are stored as Unicode (UTF-8)\n* Identifiers may or may not be case-sensitive. See Indentifier\nCase-sensitivity.\n* Database, table and column names can\'t end with space characters\n* Identifier names may begin with a numeral, but can\'t only contain numerals\nunless quoted.\n* An identifier starting with a numeral, followed by an \'e\', may be parsed as\na floating point number, and needs to be quoted.\n* Identifiers are not permitted to contain the ASCII NUL character (U+0000)\nand supplementary characters (U+10000 and higher).\n* Names such as 5e6, 9e are not prohibited, but it\'s strongly recommended not\nto use them, as they could lead to ambiguity in certain contexts, being\ntreated as a number or expression.\n* User variables cannot be used as part of an identifier, or as an identifier\nin an SQL statement.\n\nQuote Character\n---------------\n\nThe regular quote character is the backtick character - `, but if the\nANSI_QUOTES SQL_MODE option is specified, a regular double quote - \" may be\nused as well.\n\nThe backtick character can be used as part of an identifier. In that case the\nidentifier needs to be quoted. The quote character can be the backtick, but in\nthat case, the backtick in the name must be escaped with another backtick.\n\nMaximum Length\n--------------\n\n* Databases, tables, columns, indexes, constraints, stored routines, triggers,\nevents, views, tablespaces, servers and log file groups have a maximum length\nof 64 characters.\n* Compound statement labels have a maximum length of 16 characters\n* Aliases have a maximum length of 256 characters, except for column aliases\nin CREATE VIEW statements, which are checked against the maximum column length\nof 64 characters (not the maximum alias length of 256 characters).\n* Users have a maximum length of 80 characters.\n* Roles have a maximum length of 128 characters.\n* Multi-byte characters do not count extra towards towards the character limit.\n\nMultiple Identifiers\n--------------------\n\nMariaDB allows the column name to be used on its own if the reference will be\nunambiguous, or the table name to be used with the column name, or all three\nof the database, table and column names. A period is used to separate the\nidentifiers, and the period can be surrounded by spaces.\n\nExamples\n--------\n\nUsing the period to separate identifiers:\n\nCREATE TABLE t1 (i int);\n\nINSERT INTO t1(i) VALUES (10);\n\nSELECT i FROM t1;\n+------+\n| i |\n+------+\n| 10 |\n+------+\n\nSELECT t1.i FROM t1;\n+------+\n| i |\n+------+\n| 10 |\n+------+\n\nSELECT test.t1.i FROM t1;\n+------+\n| i |\n+------+\n| 10 |\n+------+\n\nThe period can be separated by spaces:\n\nSELECT test . t1 . i FROM t1;\n+------+\n| i |\n+------+\n| 10 |\n+------+\n\nResolving ambiguity:\n\nCREATE TABLE t2 (i int);\n\nSELECT i FROM t1 LEFT JOIN t2 ON t1.i=t2.i;\nERROR 1052 (23000): Column \'i\' in field list is ambiguous\n\nSELECT t1.i FROM t1 LEFT JOIN t2 ON t1.i=t2.i;\n+------+\n| i |\n+------+\n| 10 |\n+------+\n\nCreating a table with characters that require quoting:\n\nCREATE TABLE 123% (i int);\nERROR 1064 (42000): You have an error in your SQL syntax; \n check the manual that corresponds to your MariaDB server version for the\nright syntax \n to use near \'123% (i int)\' at line 1\n\nCREATE TABLE `123%` (i int);\nQuery OK, 0 rows affected (0.85 sec)\n\nCREATE TABLE `TABLE` (i int);\nQuery OK, 0 rows affected (0.36 sec)\n\nUsing double quotes as a quoting character:\n\nCREATE TABLE \"SELECT\" (i int);\nERROR 1064 (42000): You have an error in your SQL syntax; \n check the manual that corresponds to your MariaDB server version for the\nright syntax \n to use near \'\"SELECT\" (i int)\' at line 1\n\nSET sql_mode=\'ANSI_QUOTES\';\nQuery OK, 0 rows affected (0.03 sec)\n\nCREATE TABLE \"SELECT\" (i int);\nQuery OK, 0 rows affected (0.46 sec)\n\nUsing an identifier quote as part of an identifier name:\n\nSHOW VARIABLES LIKE \'sql_mode\';\n+---------------+-------------+\n| Variable_name | Value |\n+---------------+-------------+\n| sql_mode | ANSI_QUOTES |\n+---------------+-------------+\n\nCREATE TABLE \"fg`d\" (i int);\nQuery OK, 0 rows affected (0.34 sec)\n\nCreating the table named * (Unicode number: U+002A) requires quoting.\n\nCREATE TABLE `*` (a INT);\n\nFloating point ambiguity:\n\nCREATE TABLE 8984444cce5d (x INT);\nQuery OK, 0 rows affected (0.38 sec)\n\nCREATE TABLE 8981e56cce5d (x INT);\nERROR 1064 (42000): You have an error in your SQL syntax; \n check the manual that corresponds to your MariaDB server version for the\nright syntax \n to use near \'8981e56cce5d (x INT)\' at line 1\n\nCREATE TABLE `8981e56cce5d` (x INT);\nQuery OK, 0 rows affected (0.39 sec)\n\nURL: https://mariadb.com/kb/en/identifier-names/','','https://mariadb.com/kb/en/identifier-names/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (475,29,'Identifier Case-sensitivity','Whether objects are case-sensitive or not is partly determined by the\nunderlying operating system. Unix-based systems are case-sensitive, Windows is\nnot, while Mac OS X is usually case-insensitive by default, but devices can be\nconfigured as case-sensitive using Disk Utility.\n\nDatabase, table, table aliases and trigger names are affected by the systems\ncase-sensitivity, while index, column, column aliases, stored routine and\nevent names are never case sensitive.\n\nLog file group name are case sensitive.\n\nThe lower_case_table_names server system variable plays a key role. It\ndetermines whether table names, aliases and database names are compared in a\ncase-sensitive manner. If set to 0 (the default on Unix-based systems), table\nnames and aliases and database names are compared in a case-sensitive manner.\nIf set to 1 (the default on Windows), names are stored in lowercase and not\ncompared in a case-sensitive manner. If set to 2 (the default on Mac OS X),\nnames are stored as declared, but compared in lowercase.\n\nIt is thus possible to make Unix-based systems behave like Windows and ignore\ncase-sensitivity, but the reverse is not true, as the underlying Windows\nfilesystem can not support this.\n\nEven on case-insensitive systems, you are required to use the same case\nconsistently within the same statement. The following statement fails, as it\nrefers to the table name in a different case.\n\nSELECT * FROM a_table WHERE A_table.id>10;\n\nFor a full list of identifier naming rules, see Identifier Names.\n\nPlease note that lower_case_table_names is a database initialization\nparameter. This means that, along with innodb_page_size, this variable must be\nset before running mariadb-install-db, and will not change the behavior of\nservers unless applied before the creation of core system databases.\n\nURL: https://mariadb.com/kb/en/identifier-case-sensitivity/','','https://mariadb.com/kb/en/identifier-case-sensitivity/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (476,29,'Binary Literals','Binary literals can be written in one of the following formats: b\'value\',\nB\'value\' or 0bvalue, where value is a string composed by 0 and 1 digits.\n\nBinary literals are interpreted as binary strings, and are convenient to\nrepresent VARBINARY, BINARY or BIT values.\n\nTo convert a binary literal into an integer, just add 0.\n\nExamples\n--------\n\nPrinting the value as a binary string:\n\nSELECT 0b1000001;\n+-----------+\n| 0b1000001 |\n+-----------+\n| A |\n+-----------+\n\nConverting the same value into a number:\n\nSELECT 0b1000001+0;\n+-------------+\n| 0b1000001+0 |\n+-------------+\n| 65 |\n+-------------+\n\nURL: https://mariadb.com/kb/en/binary-literals/','','https://mariadb.com/kb/en/binary-literals/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (477,29,'Boolean Literals','In MariaDB, FALSE is a synonym of 0 and TRUE is a synonym of 1. These\nconstants are case insensitive, so TRUE, True, and true are equivalent.\n\nThese terms are not synonyms of 0 and 1 when used with the IS operator. So,\nfor example, 10 IS TRUE returns 1, while 10 = TRUE returns 0 (because 1 != 10).\n\nThe IS operator accepts a third constant exists: UNKNOWN. It is always a\nsynonym of NULL.\n\nTRUE and FALSE are reserved words, while UNKNOWN is not.\n\nURL: https://mariadb.com/kb/en/sql-language-structure-boolean-literals/','','https://mariadb.com/kb/en/sql-language-structure-boolean-literals/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (478,29,'Date and Time Literals','Standard syntaxes\n-----------------\n\nMariaDB supports the SQL standard and ODBC syntaxes for DATE, TIME and\nTIMESTAMP literals.\n\nSQL standard syntax:\n\n* DATE \'string\'\n* TIME \'string\'\n* TIMESTAMP \'string\'\n\nODBC syntax:\n\n* {d \'string\'}\n* {t \'string\'}\n* {ts \'string\'}\n\nThe timestamp literals are treated as DATETIME literals, because in MariaDB\nthe range of DATETIME is closer to the TIMESTAMP range in the SQL standard.\n\nstring is a string in a proper format, as explained below.\n\nDATE literals\n-------------\n\nA DATE string is a string in one of the following formats: \'YYYY-MM-DD\' or\n\'YY-MM-DD\'. Note that any punctuation character can be used as delimiter. All\ndelimiters must consist of 1 character. Different delimiters can be used in\nthe same string. Delimiters are optional (but if one delimiter is used, all\ndelimiters must be used).\n\nA DATE literal can also be an integer, in one of the following formats:\nYYYYMMDD or YYMMDD.\n\nAll the following DATE literals are valid, and they all represent the same\nvalue:\n\n\'19940101\'\n\'940101\'\n\'1994-01-01\'\n\'94/01/01\'\n\'1994-01/01\'\n\'94:01!01\'\n19940101\n940101\n\nDATETIME literals\n-----------------\n\nA DATETIME string is a string in one of the following formats: \'YYYY-MM-DD\nHH:MM:SS\' or \'YY-MM-DD HH:MM:SS\'. Note that any punctuation character can be\nused as delimiter for the date part and for the time part. All delimiters must\nconsist of 1 character. Different delimiters can be used in the same string.\nThe hours, minutes and seconds parts can consist of one character. For this\nreason, delimiters are mandatory for DATETIME literals.\n\nThe delimiter between the date part and the time part can be a T or any\nsequence of space characters (including tabs, new lines and carriage returns).\n\nA DATETIME literal can also be a number, in one of the following formats:\nYYYYMMDDHHMMSS, YYMMDDHHMMSS, YYYYMMDD or YYMMDD. In this case, all the time\nsubparts must consist of 2 digits.\n\nAll the following DATE literals are valid, and they all represent the same\nvalue:\n\n\'1994-01-01T12:30:03\'\n\'1994/01/01\\n\\t 12+30+03\'\n\'1994/01\\\\01\\n\\t 12+30-03\'\n\'1994-01-01 12:30:3\'\n\nTIME literals\n-------------\n\nA TIME string is a string in one of the following formats: \'D HH:MM:SS\',\n\'HH:MM:SS, \'D HH:MM\', \'HH:MM\', \'D HH\', or \'SS\'. D is a value from 0 to 34\nwhich represents days. : is the only allowed delimiter for TIME literals.\nDelimiters are mandatory, with an exception: the \'HHMMSS\' format is allowed.\nWhen delimiters are used, each part of the literal can consist of one\ncharacter.\n\nA TIME literal can also be a number in one of the following formats: HHMMSS,\nMMSS, or SS.\n\nThe following literals are equivalent:\n\n\'09:05:00\'\n\'9:05:0\'\n\'9:5:0\'\n\'090500\'\n\n2-digit years\n-------------\n\nThe year part in DATE and DATETIME literals is determined as follows:\n\n* 70 - 99 = 1970 - 1999\n* 00 - 69 = 2000 - 2069\n\nMicroseconds\n------------\n\nDATETIME and TIME literals can have an optional microseconds part. For both\nstring and numeric forms, it is expressed as a decimal part. Up to 6 decimal\ndigits are allowed. Examples:\n\n\'12:30:00.123456\'\n123000.123456\n\nSee Microseconds in MariaDB for details.\n\nDate and time literals and the SQL_MODE\n---------------------------------------\n\nUnless the SQL_MODE NO_ZERO_DATE flag is set, some special values are allowed:\nthe \'0000-00-00\' DATE, the \'00:00:00\' TIME, and the 0000-00-00 00:00:00\nDATETIME.\n\nIf the ALLOW_INVALID_DATES flag is set, the invalid dates (for example, 30th\nFebruary) are allowed. If not, if the NO_ZERO_DATE is set, an error is\nproduced; otherwise, a zero-date is returned.\n\nUnless the NO_ZERO_IN_DATE flag is set, each subpart of a date or time value\n(years, hours...) can be set to 0.\n\nURL: https://mariadb.com/kb/en/date-and-time-literals/','','https://mariadb.com/kb/en/date-and-time-literals/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (479,29,'Hexadecimal Literals','Hexadecimal literals can be written using any of the following syntaxes:\n\n* x\'value\'\n* X\'value\' (SQL standard)\n* 0xvalue (ODBC)\n\nvalue is a sequence of hexadecimal digits (from 0 to 9 and from A to F). The\ncase of the digits does not matter. With the first two syntaxes, value must\nconsist of an even number of digits. With the last syntax, digits can be even,\nand they are treated as if they had an extra 0 at the beginning.\n\nNormally, hexadecimal literals are interpreted as binary string, where each\npair of digits represents a character. When used in a numeric context, they\nare interpreted as integers. (See the example below). In no case can a\nhexadecimal literal be a decimal number.\n\nThe first two syntaxes; X\'value\' and x\'value, follow the SQL standard, and\nbehave as a string in all contexts in MariaDB since MariaDB 10.0.3 and MariaDB\n5.5.31 (fixing MDEV-4489). The latter syntax, 0xvalue, is a MySQL/MariaDB\nextension for hex hybrids and behaves as a string or as a number depending on\ncontext. MySQL treats all syntaxes the same, so there may be different results\nin MariaDB and MySQL (see below).\n\nExamples\n--------\n\nRepresenting the a character with the three syntaxes explained above:\n\nSELECT x\'61\', X\'61\', 0x61;\n+-------+-------+------+\n| x\'61\' | X\'61\' | 0x61 |\n+-------+-------+------+\n| a | a | a |\n+-------+-------+------+\n\nHexadecimal literals in a numeric context:\n\nSELECT 0 + 0xF, -0xF;\n+---------+------+\n| 0 + 0xF | -0xF |\n+---------+------+\n| 15 | -15 |\n+---------+------+\n\nFun with Types\n--------------\n\nCREATE TABLE t1 (a INT, b VARCHAR(10));\nINSERT INTO t1 VALUES (0x31, 0x61),(COALESCE(0x31), COALESCE(0x61));\n\nSELECT * FROM t1;\n+------+------+\n| a | b |\n+------+------+\n| 49 | a |\n| 1 | a |\n+------+------+\n\nThe reason for the differing results above is that when 0x31 is inserted\ndirectly to the column, it\'s treated as a number, while when 0x31 is passed to\nCOALESCE(), it\'s treated as a string, because:\n\n* HEX values have a string data type by default.\n* COALESCE() has the same data type as the argument.\n\nDifferences Between MariaDB and MySQL\n-------------------------------------\n\nSELECT x\'0a\'+0;\n+---------+\n| x\'0a\'+0 |\n+---------+\n| 0 |\n+---------+\n1 row in set, 1 warning (0.00 sec)\n\nWarning (Code 1292): Truncated incorrect DOUBLE value: \'\\x0A\'\n\nSELECT X\'0a\'+0;\n+---------+\n| X\'0a\'+0 |\n+---------+\n| 0 |\n+---------+\n1 row in set, 1 warning (0.00 sec)\n\nWarning (Code 1292): Truncated incorrect DOUBLE value: \'\\x0A\'\n\nSELECT 0x0a+0;\n+--------+\n| 0x0a+0 |\n+--------+\n| 10 |\n+--------+\n\nIn MySQL (up until at least MySQL 8.0.26):\n\nSELECT x\'0a\'+0;\n+---------+\n| x\'0a\'+0 |\n+---------+\n| 10 |\n+---------+\n\nSELECT X\'0a\'+0;\n+---------+\n| X\'0a\'+0 |\n+---------+\n| 10 |\n+---------+\n\nSELECT 0x0a+0;\n+--------+\n| 0x0a+0 |\n+--------+\n| 10 |\n+--------+\n\nURL: https://mariadb.com/kb/en/hexadecimal-literals/','','https://mariadb.com/kb/en/hexadecimal-literals/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (480,29,'Identifier Qualifiers','Qualifiers are used within SQL statements to reference data structures, such\nas databases, tables, or columns. For example, typically a SELECT query\ncontains references to some columns and at least one table.\n\nQualifiers can be composed by one or more identifiers, where the initial parts\naffect the context within which the final identifier is interpreted:\n\n* For a database, only the database identifier needs to be specified.\n* For objects which are contained in a database (like tables, views,\nfunctions, etc) the database identifier can be specified. If no database is\nspecified, the current database is assumed (see USE and DATABASE() for more\ndetails). If there is no default database and no database is specified, an\nerror is issued.\n* For column names, the table and the database are generally obvious from the\ncontext of the statement. It is however possible to specify the table\nidentifier, or the database identifier plus the table identifier.\n* An identifier is fully-qualified if it contains all possible qualifiers, for\nexample, the following column is fully qualified: db_name.tbl_name.col_name.\n\nIf a qualifier is composed by more than one identifier, a dot (.) must be used\nas a separator. All identifiers can be quoted individually. Extra spacing\n(including new lines and tabs) is allowed.\n\nAll the following examples are valid:\n\n* db_name.tbl_name.col_name\n* tbl_name\n* `db_name`.`tbl_name`.`col_name`\n* `db_name` . `tbl_name`\n* db_name. tbl_name\n\nIf a table identifier is prefixed with a dot (.), the default database is\nassumed. This syntax is supported for ODBC compliance, but has no practical\neffect on MariaDB. These qualifiers are equivalent:\n\n* tbl_name\n* . tbl_name\n* .`tbl_name`\n* . `tbl_name`\n\nFor DML statements, it is possible to specify a list of the partitions using\nthe PARTITION clause. See Partition Pruning and Selection for details.\n\nURL: https://mariadb.com/kb/en/identifier-qualifiers/','','https://mariadb.com/kb/en/identifier-qualifiers/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (481,29,'Identifier to File Name Mapping','Some identifiers map to a file name on the filesystem. Databases each have\ntheir own directory, while, depending on the storage engine, table names and\nindex names may map to a file name.\n\nNot all characters that are allowed in table names can be used in file names.\nEvery filesystem has its own rules of what characters can be used in file\nnames. To let the user create tables using all characters allowed in the SQL\nStandard and to not depend on whatever particular filesystem a particular\ndatabase resides, MariaDB encodes \"potentially unsafe\" characters in the table\nname to derive the corresponding file name.\n\nThis is implemented using a special character set. MariaDB converts a table\nname to the \"filename\" character set to get the file name for this table. And\nit converts the file name from the \"filename\" character set to, for example,\nutf8 to get the table name for this file name.\n\nThe conversion rules are as follows: if the identifier is made up only of\nbasic Latin numbers, letters and/or the underscore character, the encoding\nmatches the name (see however Identifier Case Sensitivity). Otherwise they are\nencoded according to the following table:\n\n+-----------------+------------+-----------+--------+-----------+-----------+\n| Code Range | Pattern | Number | Used | Unused | Blocks |\n+-----------------+------------+-----------+--------+-----------+-----------+\n| 00C0..017F | [@][0..4][ | 5*20= 100 | 97 | 3 | Latin-1 |\n| | ..z] | | | | Supplemen |\n| | | | | | + Latin |\n| | | | | | Extended- |\n| | | | | | |\n+-----------------+------------+-----------+--------+-----------+-----------+\n| 0370..03FF | [@][5..9][ | 5*20= 100 | 88 | 12 | Greek |\n| | ..z] | | | | and |\n| | | | | | Coptic |\n+-----------------+------------+-----------+--------+-----------+-----------+\n| 0400..052F | [@][g..z][ | 20*7= 140 | 137 | 3 | Cyrillic |\n| | ..6] | | | | + |\n| | | | | | Cyrillic |\n| | | | | | Supplemen |\n| | | | | | |\n+-----------------+------------+-----------+--------+-----------+-----------+\n| 0530..058F | [@][g..z][ | 20*2= 40 | 38 | 2 | Armenian |\n| | ..8] | | | | |\n+-----------------+------------+-----------+--------+-----------+-----------+\n| 2160..217F | [@][g..z][ | 20*1= 20 | 16 | 4 | Number |\n| | ] | | | | Forms |\n+-----------------+------------+-----------+--------+-----------+-----------+\n| 0180..02AF | [@][g..z][ | 20*11=220 | 203 | 17 | Latin |\n| | ..k] | | | | Extended- |\n| | | | | | + IPA |\n| | | | | | Extension |\n| | | | | | |\n+-----------------+------------+-----------+--------+-----------+-----------+\n| 1E00..1EFF | [@][g..z][ | 20*7= 140 | 136 | 4 | Latin |\n| | ..r] | | | | Extended |\n| | | | | | Additiona |\n| | | | | | |\n+-----------------+------------+-----------+--------+-----------+-----------+\n| 1F00..1FFF | [@][g..z][ | 20*8= 160 | 144 | 16 | Greek |\n| | ..z] | | | | Extended |\n+-----------------+------------+-----------+--------+-----------+-----------+\n| .... .... | [@][a..f][ | 6*20= 120 | 0 | 120 | RESERVED |\n| | ..z] | | | | |\n+-----------------+------------+-----------+--------+-----------+-----------+\n| 24B6..24E9 | [@][@][a.. | 26 | 26 | 0 | Enclosed |\n| | ] | | | | Alphanume |\n| | | | | | ics |\n+-----------------+------------+-----------+--------+-----------+-----------+\n| FF21..FF5A | [@][a..z][ | 26 | 26 | 0 | Halfwidth |\n| | ] | | | | and |\n| | | | | | Fullwidth |\n| | | | | | forms |\n+-----------------+------------+-----------+--------+-----------+-----------+\n\nCode Range values are UCS-2.\n\nAll of this encoding happens transparently at the filesystem level with one\nexception. Until MySQL 5.1.6, an old encoding was used. Identifiers created in\na version before MySQL 5.1.6, and which haven\'t been updated to the new\nencoding, the server prefixes mysql50 to their name.\n\nExamples\n--------\n\nFind the file name for a table with a non-Latin1 name:\n\nselect cast(convert(\"this_is_таблица\" USING filename) as binary);\n+------------------------------------------------------------------+\n| cast(convert(\"this_is_таблица\" USING filename) as binary) |\n+------------------------------------------------------------------+\n| this_is_@y0@g0@h0@r0@o0@i1@g0 |\n+------------------------------------------------------------------+\n\nFind the table name for a file name:\n\nselect convert(_filename \"this_is_@y0@g0@h0@r0@o0@i1@g0\" USING utf8);\n+---------------------------------------------------------------+\n| convert(_filename \"this_is_@y0@g0@h0@r0@o0@i1@g0\" USING utf8) |\n+---------------------------------------------------------------+\n| this_is_таблица |\n+---------------------------------------------------------------+\n\nAn old table created before MySQL 5.1.6, with the old encoding:\n\nSHOW TABLES;\n+--------------------+\n| Tables_in_test |\n+--------------------+\n| #mysql50#table@1 |\n+--------------------+\n\nThe prefix needs to be supplied to reference this table:\n\nSHOW COLUMNS FROM `table@1`;\nERROR 1146 (42S02): Table \'test.table@1\' doesn\'t exist\n\nSHOW COLUMNS FROM `#mysql50#table@1`;\n+-------+---------+------+-----+---------+-------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+---------+------+-----+---------+-------+\n| i | int(11) | YES | | NULL | |\n+-------+---------+------+-----+---------+-------+\n\nURL: https://mariadb.com/kb/en/identifier-to-file-name-mapping/','','https://mariadb.com/kb/en/identifier-to-file-name-mapping/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (482,29,'Numeric Literals','Numeric literals are written as a sequence of digits from 0 to 9. Initial\nzeros are ignored. A sign can always precede the digits, but it is optional\nfor positive numbers. In decimal numbers, the integer part and the decimal\npart are divided with a dot (.).\n\nIf the integer part is zero, it can be omitted, but the literal must begin\nwith a dot.\n\nThe notation with exponent can be used. The exponent is preceded by an E or e\ncharacter. The exponent can be preceded by a sign and must be an integer. A\nnumber N with an exponent part X, is calculated as N * POW(10, X).\n\nIn some cases, adding zeroes at the end of a decimal number can increment the\nprecision of the expression where the number is used. For example, PI() by\ndefault returns a number with 6 decimal digits. But the PI()+0.0000000000\nexpression (with 10 zeroes) returns a number with 10 decimal digits.\n\nHexadecimal literals are interpreted as numbers when used in numeric contexts.\n\nExamples\n--------\n\n10\n+10\n-10\n\nAll these literals are equivalent:\n\n0.1\n.1\n+0.1\n+.1\n\nWith exponents:\n\n0.2E3 -- 0.2 * POW(10, 3) = 200\n.2e3\n.2e+2\n1.1e-10 -- 0.00000000011\n-1.1e10 -- -11000000000\n\nURL: https://mariadb.com/kb/en/numeric-iterals/','','https://mariadb.com/kb/en/numeric-iterals/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (483,29,'Reserved Words','The following is a list of all reserved words in MariaDB.\n\nReserved words cannot be used as Identifiers, unless they are quoted.\n\nThe definitive list of reserved words for each version can be found by\nexamining the sql/lex.h and sql/sql_yacc.yy files.\n\nReserved Words\n--------------\n\n+--------------------------------------------+--------------------------------+\n| Keyword | Notes |\n+--------------------------------------------+--------------------------------+\n| ACCESSIBLE | |\n+--------------------------------------------+--------------------------------+\n| ADD | |\n+--------------------------------------------+--------------------------------+\n| ALL | |\n+--------------------------------------------+--------------------------------+\n| ALTER | |\n+--------------------------------------------+--------------------------------+\n| ANALYZE | |\n+--------------------------------------------+--------------------------------+\n| AND | |\n+--------------------------------------------+--------------------------------+\n| AS | |\n+--------------------------------------------+--------------------------------+\n| ASC | |\n+--------------------------------------------+--------------------------------+\n| ASENSITIVE | |\n+--------------------------------------------+--------------------------------+\n| BEFORE | |\n+--------------------------------------------+--------------------------------+\n| BETWEEN | |\n+--------------------------------------------+--------------------------------+\n| BIGINT | |\n+--------------------------------------------+--------------------------------+\n| BINARY | |\n+--------------------------------------------+--------------------------------+\n| BLOB | |\n+--------------------------------------------+--------------------------------+\n| BOTH | |\n+--------------------------------------------+--------------------------------+\n| BY | |\n+--------------------------------------------+--------------------------------+\n| CALL | |\n+--------------------------------------------+--------------------------------+\n| CASCADE | |\n+--------------------------------------------+--------------------------------+\n| CASE | |\n+--------------------------------------------+--------------------------------+\n| CHANGE | |\n+--------------------------------------------+--------------------------------+\n| CHAR | |\n+--------------------------------------------+--------------------------------+\n| CHARACTER | |\n+--------------------------------------------+--------------------------------+\n| CHECK | |\n+--------------------------------------------+--------------------------------+\n| COLLATE | |\n+--------------------------------------------+--------------------------------+\n| COLUMN | |\n+--------------------------------------------+--------------------------------+\n| CONDITION | |\n+--------------------------------------------+--------------------------------+\n| CONSTRAINT | |\n+--------------------------------------------+--------------------------------+\n| CONTINUE | |\n+--------------------------------------------+--------------------------------+\n| CONVERT | |\n+--------------------------------------------+--------------------------------+\n| CREATE | |\n+--------------------------------------------+--------------------------------+\n| CROSS | |\n+--------------------------------------------+--------------------------------+\n| CURRENT_DATE | |\n+--------------------------------------------+--------------------------------+\n| CURRENT_ROLE | |\n+--------------------------------------------+--------------------------------+\n| CURRENT_TIME | |\n+--------------------------------------------+--------------------------------+\n| CURRENT_TIMESTAMP | |\n+--------------------------------------------+--------------------------------+\n| CURRENT_USER | |\n+--------------------------------------------+--------------------------------+\n| CURSOR | |\n+--------------------------------------------+--------------------------------+\n| DATABASE | |\n+--------------------------------------------+--------------------------------+\n| DATABASES | |\n+--------------------------------------------+--------------------------------+\n| DAY_HOUR | |\n+--------------------------------------------+--------------------------------+\n| DAY_MICROSECOND | |\n+--------------------------------------------+--------------------------------+\n| DAY_MINUTE | |\n+--------------------------------------------+--------------------------------+\n| DAY_SECOND | |\n+--------------------------------------------+--------------------------------+\n| DEC | |\n+--------------------------------------------+--------------------------------+\n| DECIMAL | |\n+--------------------------------------------+--------------------------------+\n| DECLARE | |\n+--------------------------------------------+--------------------------------+\n| DEFAULT | |\n+--------------------------------------------+--------------------------------+\n| DELAYED | |\n+--------------------------------------------+--------------------------------+\n| DELETE | |\n+--------------------------------------------+--------------------------------+\n| DELETE_DOMAIN_ID | |\n+--------------------------------------------+--------------------------------+\n| DESC | |\n+--------------------------------------------+--------------------------------+\n| DESCRIBE | |\n+--------------------------------------------+--------------------------------+\n| DETERMINISTIC | |\n+--------------------------------------------+--------------------------------+\n| DISTINCT | |\n+--------------------------------------------+--------------------------------+\n| DISTINCTROW | |\n+--------------------------------------------+--------------------------------+\n| DIV | |\n+--------------------------------------------+--------------------------------+\n| DO_DOMAIN_IDS | |\n+--------------------------------------------+--------------------------------+\n| DOUBLE | |\n+--------------------------------------------+--------------------------------+\n| DROP | |\n+--------------------------------------------+--------------------------------+\n| DUAL | |\n+--------------------------------------------+--------------------------------+\n| EACH | |\n+--------------------------------------------+--------------------------------+\n| ELSE | |\n+--------------------------------------------+--------------------------------+\n| ELSEIF | |\n+--------------------------------------------+--------------------------------+\n| ENCLOSED | |\n+--------------------------------------------+--------------------------------+\n| ESCAPED | |\n+--------------------------------------------+--------------------------------+\n| EXCEPT | Added in MariaDB 10.3.0 |\n+--------------------------------------------+--------------------------------+\n| EXISTS | |\n+--------------------------------------------+--------------------------------+\n| EXIT | |\n+--------------------------------------------+--------------------------------+\n| EXPLAIN | |\n+--------------------------------------------+--------------------------------+\n| FALSE | |\n+--------------------------------------------+--------------------------------+\n| FETCH | |\n+--------------------------------------------+--------------------------------+\n| FLOAT | |\n+--------------------------------------------+--------------------------------+\n| FLOAT4 | |\n+--------------------------------------------+--------------------------------+\n| FLOAT8 | |\n+--------------------------------------------+--------------------------------+\n| FOR | |\n+--------------------------------------------+--------------------------------+\n| FORCE | |\n+--------------------------------------------+--------------------------------+\n| FOREIGN | |\n+--------------------------------------------+--------------------------------+\n| FROM | |\n+--------------------------------------------+--------------------------------+\n| FULLTEXT | |\n+--------------------------------------------+--------------------------------+\n| GENERAL | |\n+--------------------------------------------+--------------------------------+\n| GRANT | |\n+--------------------------------------------+--------------------------------+\n| GROUP | |\n+--------------------------------------------+--------------------------------+\n| HAVING | |\n+--------------------------------------------+--------------------------------+\n| HIGH_PRIORITY | |\n+--------------------------------------------+--------------------------------+\n| HOUR_MICROSECOND | |\n+--------------------------------------------+--------------------------------+\n| HOUR_MINUTE | |\n+--------------------------------------------+--------------------------------+\n| HOUR_SECOND | |','','https://mariadb.com/kb/en/reserved-words/'); +update help_topic set description = CONCAT(description, '\n+--------------------------------------------+--------------------------------+\n| IF | |\n+--------------------------------------------+--------------------------------+\n| IGNORE | |\n+--------------------------------------------+--------------------------------+\n| IGNORE_DOMAIN_IDS | |\n+--------------------------------------------+--------------------------------+\n| IGNORE_SERVER_IDS | |\n+--------------------------------------------+--------------------------------+\n| IN | |\n+--------------------------------------------+--------------------------------+\n| INDEX | |\n+--------------------------------------------+--------------------------------+\n| INFILE | |\n+--------------------------------------------+--------------------------------+\n| INNER | |\n+--------------------------------------------+--------------------------------+\n| INOUT | |\n+--------------------------------------------+--------------------------------+\n| INSENSITIVE | |\n+--------------------------------------------+--------------------------------+\n| INSERT | |\n+--------------------------------------------+--------------------------------+\n| INT | |\n+--------------------------------------------+--------------------------------+\n| INT1 | |\n+--------------------------------------------+--------------------------------+\n| INT2 | |\n+--------------------------------------------+--------------------------------+\n| INT3 | |\n+--------------------------------------------+--------------------------------+\n| INT4 | |\n+--------------------------------------------+--------------------------------+\n| INT8 | |\n+--------------------------------------------+--------------------------------+\n| INTEGER | |\n+--------------------------------------------+--------------------------------+\n| INTERSECT | Added in MariaDB 10.3.0 |\n+--------------------------------------------+--------------------------------+\n| INTERVAL | |\n+--------------------------------------------+--------------------------------+\n| INTO | |\n+--------------------------------------------+--------------------------------+\n| IS | |\n+--------------------------------------------+--------------------------------+\n| ITERATE | |\n+--------------------------------------------+--------------------------------+\n| JOIN | |\n+--------------------------------------------+--------------------------------+\n| KEY | |\n+--------------------------------------------+--------------------------------+\n| KEYS | |\n+--------------------------------------------+--------------------------------+\n| KILL | |\n+--------------------------------------------+--------------------------------+\n| LEADING | |\n+--------------------------------------------+--------------------------------+\n| LEAVE | |\n+--------------------------------------------+--------------------------------+\n| LEFT | |\n+--------------------------------------------+--------------------------------+\n| LIKE | |\n+--------------------------------------------+--------------------------------+\n| LIMIT | |\n+--------------------------------------------+--------------------------------+\n| LINEAR | |\n+--------------------------------------------+--------------------------------+\n| LINES | |\n+--------------------------------------------+--------------------------------+\n| LOAD | |\n+--------------------------------------------+--------------------------------+\n| LOCALTIME | |\n+--------------------------------------------+--------------------------------+\n| LOCALTIMESTAMP | |\n+--------------------------------------------+--------------------------------+\n| LOCK | |\n+--------------------------------------------+--------------------------------+\n| LONG | |\n+--------------------------------------------+--------------------------------+\n| LONGBLOB | |\n+--------------------------------------------+--------------------------------+\n| LONGTEXT | |\n+--------------------------------------------+--------------------------------+\n| LOOP | |\n+--------------------------------------------+--------------------------------+\n| LOW_PRIORITY | |\n+--------------------------------------------+--------------------------------+\n| MASTER_HEARTBEAT_PERIOD | |\n+--------------------------------------------+--------------------------------+\n| MASTER_SSL_VERIFY_SERVER_CERT | |\n+--------------------------------------------+--------------------------------+\n| MATCH | |\n+--------------------------------------------+--------------------------------+\n| MAXVALUE | |\n+--------------------------------------------+--------------------------------+\n| MEDIUMBLOB | |\n+--------------------------------------------+--------------------------------+\n| MEDIUMINT | |\n+--------------------------------------------+--------------------------------+\n| MEDIUMTEXT | |\n+--------------------------------------------+--------------------------------+\n| MIDDLEINT | |\n+--------------------------------------------+--------------------------------+\n| MINUTE_MICROSECOND | |\n+--------------------------------------------+--------------------------------+\n| MINUTE_SECOND | |\n+--------------------------------------------+--------------------------------+\n| MOD | |\n+--------------------------------------------+--------------------------------+\n| MODIFIES | |\n+--------------------------------------------+--------------------------------+\n| NATURAL | |\n+--------------------------------------------+--------------------------------+\n| NOT | |\n+--------------------------------------------+--------------------------------+\n| NO_WRITE_TO_BINLOG | |\n+--------------------------------------------+--------------------------------+\n| NULL | |\n+--------------------------------------------+--------------------------------+\n| NUMERIC | |\n+--------------------------------------------+--------------------------------+\n| OFFSET | Added in MariaDB 10.6.0 |\n+--------------------------------------------+--------------------------------+\n| ON | |\n+--------------------------------------------+--------------------------------+\n| OPTIMIZE | |\n+--------------------------------------------+--------------------------------+\n| OPTION | |\n+--------------------------------------------+--------------------------------+\n| OPTIONALLY | |\n+--------------------------------------------+--------------------------------+\n| OR | |\n+--------------------------------------------+--------------------------------+\n| ORDER | |\n+--------------------------------------------+--------------------------------+\n| OUT | |\n+--------------------------------------------+--------------------------------+\n| OUTER | |\n+--------------------------------------------+--------------------------------+\n| OUTFILE | |\n+--------------------------------------------+--------------------------------+\n| OVER | |\n+--------------------------------------------+--------------------------------+\n| PAGE_CHECKSUM | |\n+--------------------------------------------+--------------------------------+\n| PARSE_VCOL_EXPR | |\n+--------------------------------------------+--------------------------------+\n| PARTITION | |\n+--------------------------------------------+--------------------------------+\n| POSITION | |\n+--------------------------------------------+--------------------------------+\n| PRECISION | |\n+--------------------------------------------+--------------------------------+\n| PRIMARY | |\n+--------------------------------------------+--------------------------------+\n| PROCEDURE | |\n+--------------------------------------------+--------------------------------+\n| PURGE | |\n+--------------------------------------------+--------------------------------+\n| RANGE | |\n+--------------------------------------------+--------------------------------+\n| READ | |\n+--------------------------------------------+--------------------------------+\n| READS | |\n+--------------------------------------------+--------------------------------+\n| READ_WRITE | |\n+--------------------------------------------+--------------------------------+\n| REAL | |\n+--------------------------------------------+--------------------------------+\n| RECURSIVE | |\n+--------------------------------------------+--------------------------------+\n| REF_SYSTEM_ID | |\n+--------------------------------------------+--------------------------------+\n| REFERENCES | |\n+--------------------------------------------+--------------------------------+\n| REGEXP | |\n+--------------------------------------------+--------------------------------+\n| RELEASE | |\n+--------------------------------------------+--------------------------------+\n| RENAME | |') WHERE help_topic_id = 483; +update help_topic set description = CONCAT(description, '\n+--------------------------------------------+--------------------------------+\n| REPEAT | |\n+--------------------------------------------+--------------------------------+\n| REPLACE | |\n+--------------------------------------------+--------------------------------+\n| REQUIRE | |\n+--------------------------------------------+--------------------------------+\n| RESIGNAL | |\n+--------------------------------------------+--------------------------------+\n| RESTRICT | |\n+--------------------------------------------+--------------------------------+\n| RETURN | |\n+--------------------------------------------+--------------------------------+\n| RETURNING | |\n+--------------------------------------------+--------------------------------+\n| REVOKE | |\n+--------------------------------------------+--------------------------------+\n| RIGHT | |\n+--------------------------------------------+--------------------------------+\n| RLIKE | |\n+--------------------------------------------+--------------------------------+\n| ROW_NUMBER | From MariaDB 10.7 |\n+--------------------------------------------+--------------------------------+\n| ROWS | |\n+--------------------------------------------+--------------------------------+\n| SCHEMA | |\n+--------------------------------------------+--------------------------------+\n| SCHEMAS | |\n+--------------------------------------------+--------------------------------+\n| SECOND_MICROSECOND | |\n+--------------------------------------------+--------------------------------+\n| SELECT | |\n+--------------------------------------------+--------------------------------+\n| SENSITIVE | |\n+--------------------------------------------+--------------------------------+\n| SEPARATOR | |\n+--------------------------------------------+--------------------------------+\n| SET | |\n+--------------------------------------------+--------------------------------+\n| SHOW | |\n+--------------------------------------------+--------------------------------+\n| SIGNAL | |\n+--------------------------------------------+--------------------------------+\n| SLOW | |\n+--------------------------------------------+--------------------------------+\n| SMALLINT | |\n+--------------------------------------------+--------------------------------+\n| SPATIAL | |\n+--------------------------------------------+--------------------------------+\n| SPECIFIC | |\n+--------------------------------------------+--------------------------------+\n| SQL | |\n+--------------------------------------------+--------------------------------+\n| SQLEXCEPTION | |\n+--------------------------------------------+--------------------------------+\n| SQLSTATE | |\n+--------------------------------------------+--------------------------------+\n| SQLWARNING | |\n+--------------------------------------------+--------------------------------+\n| SQL_BIG_RESULT | |\n+--------------------------------------------+--------------------------------+\n| SQL_CALC_FOUND_ROWS | |\n+--------------------------------------------+--------------------------------+\n| SQL_SMALL_RESULT | |\n+--------------------------------------------+--------------------------------+\n| SSL | |\n+--------------------------------------------+--------------------------------+\n| STARTING | |\n+--------------------------------------------+--------------------------------+\n| STATS_AUTO_RECALC | |\n+--------------------------------------------+--------------------------------+\n| STATS_PERSISTENT | |\n+--------------------------------------------+--------------------------------+\n| STATS_SAMPLE_PAGES | |\n+--------------------------------------------+--------------------------------+\n| STRAIGHT_JOIN | |\n+--------------------------------------------+--------------------------------+\n| TABLE | |\n+--------------------------------------------+--------------------------------+\n| TERMINATED | |\n+--------------------------------------------+--------------------------------+\n| THEN | |\n+--------------------------------------------+--------------------------------+\n| TINYBLOB | |\n+--------------------------------------------+--------------------------------+\n| TINYINT | |\n+--------------------------------------------+--------------------------------+\n| TINYTEXT | |\n+--------------------------------------------+--------------------------------+\n| TO | |\n+--------------------------------------------+--------------------------------+\n| TRAILING | |\n+--------------------------------------------+--------------------------------+\n| TRIGGER | |\n+--------------------------------------------+--------------------------------+\n| TRUE | |\n+--------------------------------------------+--------------------------------+\n| UNDO | |\n+--------------------------------------------+--------------------------------+\n| UNION | |\n+--------------------------------------------+--------------------------------+\n| UNIQUE | |\n+--------------------------------------------+--------------------------------+\n| UNLOCK | |\n+--------------------------------------------+--------------------------------+\n| UNSIGNED | |\n+--------------------------------------------+--------------------------------+\n| UPDATE | |\n+--------------------------------------------+--------------------------------+\n| USAGE | |\n+--------------------------------------------+--------------------------------+\n| USE | |\n+--------------------------------------------+--------------------------------+\n| USING | |\n+--------------------------------------------+--------------------------------+\n| UTC_DATE | |\n+--------------------------------------------+--------------------------------+\n| UTC_TIME | |\n+--------------------------------------------+--------------------------------+\n| UTC_TIMESTAMP | |\n+--------------------------------------------+--------------------------------+\n| VALUES | |\n+--------------------------------------------+--------------------------------+\n| VARBINARY | |\n+--------------------------------------------+--------------------------------+\n| VARCHAR | |\n+--------------------------------------------+--------------------------------+\n| VARCHARACTER | |\n+--------------------------------------------+--------------------------------+\n| VARYING | |\n+--------------------------------------------+--------------------------------+\n| WHEN | |\n+--------------------------------------------+--------------------------------+\n| WHERE | |\n+--------------------------------------------+--------------------------------+\n| WHILE | |\n+--------------------------------------------+--------------------------------+\n| WINDOW | Only disallowed for table |\n| | aliases. |\n+--------------------------------------------+--------------------------------+\n| WITH | |\n+--------------------------------------------+--------------------------------+\n| WRITE | |\n+--------------------------------------------+--------------------------------+\n| XOR | |\n+--------------------------------------------+--------------------------------+\n| YEAR_MONTH | |\n+--------------------------------------------+--------------------------------+\n| ZEROFILL | |\n+--------------------------------------------+--------------------------------+\n\nExceptions\n----------\n\nSome keywords are exceptions for historical reasons, and are permitted as\nunquoted identifiers. These include:\n\n+-----------------------------------------------------------------------------+\n| Keyword |\n+-----------------------------------------------------------------------------+\n| ACTION |\n+-----------------------------------------------------------------------------+\n| BIT |\n+-----------------------------------------------------------------------------+\n| DATE |\n+-----------------------------------------------------------------------------+\n| ENUM |\n+-----------------------------------------------------------------------------+\n| NO |\n+-----------------------------------------------------------------------------+\n| TEXT |\n+-----------------------------------------------------------------------------+\n| TIME |\n+-----------------------------------------------------------------------------+\n| TIMESTAMP |\n+-----------------------------------------------------------------------------+\n\nOracle Mode\n-----------\n\nIn Oracle mode, from MariaDB 10.3, there are a number of extra reserved words:\n\n+--------------------------------------------+--------------------------------+\n| Keyword | Notes |\n+--------------------------------------------+--------------------------------+\n| BODY | |\n+--------------------------------------------+--------------------------------+\n| ELSIF | |\n+--------------------------------------------+--------------------------------+\n| GOTO | |') WHERE help_topic_id = 483; +update help_topic set description = CONCAT(description, '\n+--------------------------------------------+--------------------------------+\n| HISTORY | <= MariaDB 10.3.6 only |\n+--------------------------------------------+--------------------------------+\n| MINUS | From MariaDB 10.6.1 |\n+--------------------------------------------+--------------------------------+\n| OTHERS | |\n+--------------------------------------------+--------------------------------+\n| PACKAGE | |\n+--------------------------------------------+--------------------------------+\n| PERIOD | <= MariaDB 10.3.6 only |\n+--------------------------------------------+--------------------------------+\n| RAISE | |\n+--------------------------------------------+--------------------------------+\n| ROWNUM | From MariaDB 10.6.1 |\n+--------------------------------------------+--------------------------------+\n| ROWTYPE | |\n+--------------------------------------------+--------------------------------+\n| SYSDATE | From MariaDB 10.6.1 |\n+--------------------------------------------+--------------------------------+\n| SYSTEM | <= MariaDB 10.3.6 only. Note |\n| | however that SYSTEM sometimes |\n| | needs to be quoted to avoid |\n| | confusion with |\n| | System-versioned tables. |\n+--------------------------------------------+--------------------------------+\n| SYSTEM_TIME | <= MariaDB 10.3.6 only |\n+--------------------------------------------+--------------------------------+\n| VERSIONING | <= MariaDB 10.3.6 only |\n+--------------------------------------------+--------------------------------+\n| WITHOUT | <= MariaDB 10.3.6 only |\n+--------------------------------------------+--------------------------------+\n\nFunction Names\n--------------\n\nIf the IGNORE_SPACE SQL_MODE flag is set, function names become reserved words.\n\nURL: https://mariadb.com/kb/en/reserved-words/') WHERE help_topic_id = 483; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (484,29,'String Literals','Strings are sequences of characters and are enclosed with quotes.\n\nThe syntax is:\n\n[_charset_name]\'string\' [COLLATE collation_name]\n\nFor example:\n\n\'The MariaDB Foundation\'\n_utf8 \'Foundation\' COLLATE utf8_unicode_ci;\n\nStrings can either be enclosed in single quotes or in double quotes (the same\ncharacter must be used to both open and close the string).\n\nThe ANSI SQL-standard does not permit double quotes for enclosing strings, and\nalthough MariaDB does by default, if the MariaDB server has enabled the\nANSI_QUOTES_SQL SQL_MODE, double quotes will be treated as being used for\nidentifiers instead of strings.\n\nStrings that are next to each other are automatically concatenated. For\nexample:\n\n\'The \' \'MariaDB \' \'Foundation\'\n\nand\n\n\'The MariaDB Foundation\'\n\nare equivalent.\n\nThe \\ (backslash character) is used to escape characters (unless the SQL_MODE\nhasn\'t been set to NO_BACKSLASH_ESCAPES). For example:\n\n\'MariaDB\'s new features\'\n\nis not a valid string because of the single quote in the middle of the string,\nwhich is treated as if it closes the string, but is actually meant as part of\nthe string, an apostrophe. The backslash character helps in situations like\nthis:\n\n\'MariaDB\\\'s new features\'\n\nis now a valid string, and if displayed, will appear without the backslash.\n\nSELECT \'MariaDB\\\'s new features\';\n+------------------------+\n| MariaDB\'s new features |\n+------------------------+\n| MariaDB\'s new features |\n+------------------------+\n\nAnother way to escape the quoting character is repeating it twice:\n\nSELECT \'I\'\'m here\', \"\"\"Double\"\"\";\n+----------+----------+\n| I\'m here | \"Double\" |\n+----------+----------+\n| I\'m here | \"Double\" |\n+----------+----------+\n\nEscape Sequences\n----------------\n\nThere are other escape sequences also. Here is a full list:\n\n+-----------------------------------------------+-----------------------------+\n| Escape sequence | Character |\n+-----------------------------------------------+-----------------------------+\n| \\0 | ASCII NUL (0x00). |\n+-----------------------------------------------+-----------------------------+\n| \\\' | Single quote (\"\'\"). |\n+-----------------------------------------------+-----------------------------+\n| \\\" | Double quote (\"\"\"). |\n+-----------------------------------------------+-----------------------------+\n| \\b | Backspace. |\n+-----------------------------------------------+-----------------------------+\n| \\n | Newline, or linefeed,. |\n+-----------------------------------------------+-----------------------------+\n| \\r | Carriage return. |\n+-----------------------------------------------+-----------------------------+\n| \\t | Tab. |\n+-----------------------------------------------+-----------------------------+\n| \\Z | ASCII 26 (Control+Z). See |\n| | note following the table. |\n+-----------------------------------------------+-----------------------------+\n| \\\\ | Backslash (\"\\\"). |\n+-----------------------------------------------+-----------------------------+\n| \\% | \"%\" character. See note |\n| | following the table. |\n+-----------------------------------------------+-----------------------------+\n| \\_ | A \"_\" character. See note |\n| | following the table. |\n+-----------------------------------------------+-----------------------------+\n\nEscaping the % and _ characters can be necessary when using the LIKE operator,\nwhich treats them as special characters.\n\nThe ASCII 26 character (\\Z) needs to be escaped when included in a batch file\nwhich needs to be executed in Windows. The reason is that ASCII 26, in\nWindows, is the end of file (EOF).\n\nBackslash (\\), if not used as an escape character, must always be escaped.\nWhen followed by a character that is not in the above table, backslashes will\nsimply be ignored.\n\nURL: https://mariadb.com/kb/en/string-literals/','','https://mariadb.com/kb/en/string-literals/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (485,29,'Table Value Constructors','MariaDB starting with 10.3.3\n----------------------------\nTable Value Constructors were introduced in MariaDB 10.3.3\n\nSyntax\n------\n\nVALUES ( row_value[, row_value...]), (...)...\n\nDescription\n-----------\n\nIn Unions, Views, and sub-queries, a Table Value Constructor (TVC) allows you\nto inject arbitrary values into the result-set. The given values must have the\nsame number of columns as the result-set, otherwise it returns Error 1222.\n\nExamples\n--------\n\nUsing TVC\'s with UNION operations:\n\nCREATE TABLE test.t1 (val1 INT, val2 INT);\nINSERT INTO test.t1 VALUES(5, 8), (3, 4), (1, 2);\n\nSELECT * FROM test.t1\nUNION\nVALUES (70, 90), (100, 110);\n\n+------+------+\n| val1 | val2 |\n+------+------+\n| 5 | 8 | \n| 3 | 4 |\n| 1 | 2 |\n| 70 | 90 |\n| 100 | 110 |\n+------+------+\n\nUsing TVC\'s with a CREATE VIEW statement:\n\nCREATE VIEW v1 AS VALUES (7, 9), (9, 10);\n\nSELECT * FROM v1;\n+---+----+\n| 7 | 9 |\n+---+----+\n| 7 | 9 |\n| 9 | 10 |\n+---+----+\n\nUsing TVC with an ORDER BY clause:\n\nSELECT * FROM test.t1\nUNION\nVALUES (10, 20), (30, 40), (50, 60), (70, 80)\nORDER BY val1 DESC;\n\nUsing TVC with LIMIT clause:\n\nSELECT * FROM test.t1\nUNION\nVALUES (10, 20), (30, 40), (50, 60), (70, 80)\nLIMIT 2 OFFSET 4;\n\n+------+------+\n| val1 | val2 |\n+------+------+\n| 30 | 40 | \n| 50 | 60 |\n+------+------+\n\nURL: https://mariadb.com/kb/en/table-value-constructors/','','https://mariadb.com/kb/en/table-value-constructors/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (486,29,'User-Defined Variables','User-defined variables are variables which can be created by the user and\nexist in the session. This means that no one can access user-defined variables\nthat have been set by another user, and when the session is closed these\nvariables expire. However, these variables can be shared between several\nqueries and stored programs.\n\nUser-defined variables names must be preceded by a single at character (@).\nWhile it is safe to use a reserved word as a user-variable name, the only\nallowed characters are ASCII letters, digits, dollar sign ($), underscore (_)\nand dot (.). If other characters are used, the name can be quoted in one of\nthe following ways:\n\n* @`var_name`\n* @\'var_name\'\n* @\"var_name\"\n\nThese characters can be escaped as usual.\n\nUser-variables names are case insensitive, though they were case sensitive in\nMySQL 4.1 and older versions.\n\nUser-defined variables cannot be declared. They can be read even if no value\nhas been set yet; in that case, they are NULL. To set a value for a\nuser-defined variable you can use:\n\n* SET statement;\n* := operator within a SQL statement;\n* SELECT ... INTO.\n\nSince user-defined variables type cannot be declared, the only way to force\ntheir type is using CAST() or CONVERT():\n\nSET @str = CAST(123 AS CHAR(5));\n\nIf a variable has not been used yet, its value is NULL:\n\nSELECT @x IS NULL;\n+------------+\n| @x IS NULL |\n+------------+\n| 1 |\n+------------+\n\nIt is unsafe to read a user-defined variable and set its value in the same\nstatement (unless the command is SET), because the order of these actions is\nundefined.\n\nUser-defined variables can be used in most MariaDB\'s statements and clauses\nwhich accept an SQL expression. However there are some exceptions, like the\nLIMIT clause.\n\nThey must be used to PREPARE a prepared statement:\n\n@sql = \'DELETE FROM my_table WHERE c>1;\';\nPREPARE stmt FROM @sql;\nEXECUTE stmt;\nDEALLOCATE PREPARE stmt;\n\nAnother common use is to include a counter in a query:\n\nSET @var = 0;\nSELECT a, b, c, (@var:=@var+1) AS counter FROM my_table;\n\nInformation Schema\n------------------\n\nUser-defined variables can be viewed in the Information Schema USER_VARIABLES\nTable (as part of the User Variables plugin) from MariaDB 10.2.\n\nFlushing User-Defined Variables\n-------------------------------\n\nUser-defined variables are reset and the Information Schema table emptied with\nthe FLUSH USER_VARIABLES statement.\n\nSET @str = CAST(123 AS CHAR(5));\n\nSELECT * FROM information_schema.USER_VARIABLES ORDER BY VARIABLE_NAME;\n+---------------+----------------+---------------+--------------------+\n| VARIABLE_NAME | VARIABLE_VALUE | VARIABLE_TYPE | CHARACTER_SET_NAME |\n+---------------+----------------+---------------+--------------------+\n| str | 123 | VARCHAR | utf8mb3 |\n+---------------+----------------+---------------+--------------------+\n\nFLUSH USER_VARIABLES;\n\nSELECT * FROM information_schema.USER_VARIABLES ORDER BY VARIABLE_NAME;\nEmpty set (0.000 sec)\n\nURL: https://mariadb.com/kb/en/user-defined-variables/','','https://mariadb.com/kb/en/user-defined-variables/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (487,29,'Delimiters','The default delimiter in the mariadb client is the semicolon.\n\nWhen creating stored programs from the command-line, it is likely you will\nneed to differentiate between the regular delimiter and a delimiter inside a\nBEGIN END block. To understand better, consider the following example:\n\nCREATE FUNCTION FortyTwo() RETURNS TINYINT DETERMINISTIC\nBEGIN\n DECLARE x TINYINT;\n SET x = 42;\n RETURN x;\nEND;\n\nIf you enter the above line by line, the mariadb client will treat the first\nsemicolon, at the end of the DECLARE x TINYINT line, as the end of the\nstatement. Since that\'s only a partial definition, it will throw a syntax\nerror, as follows:\n\nCREATE FUNCTION FortyTwo() RETURNS TINYINT DETERMINISTIC\nBEGIN\nDECLARE x TINYINT;\nERROR 1064 (42000): You have an error in your SQL syntax; \ncheck the manual that corresponds to your MariaDB server version\n for the right syntax to use near \'\' at line 3\n\nThe solution is to specify a distinct delimiter for the duration of the\nprocess, using the DELIMITER command. The delimiter can be any set of\ncharacters you choose, but it needs to be a distinctive set of characters that\nwon\'t cause further confusion. // is a common choice, and used throughout the\nKnowledge Base.\n\nHere\'s how the function could be successfully entered from the mariadb client\nwith the new delimiter.\n\nDELIMITER //\n\nCREATE FUNCTION FortyTwo() RETURNS TINYINT DETERMINISTIC\nBEGIN\n DECLARE x TINYINT;\n SET x = 42;\n RETURN x;\nEND\n\n//\n\nDELIMITER ;\n\nAt the end, the delimiter is restored to the default semicolon. The \\g and \\G\ndelimiters can always be used, even when a custom delimiter is specified.\n\nURL: https://mariadb.com/kb/en/delimiters/','','https://mariadb.com/kb/en/delimiters/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (488,29,'SQL_MODE=ORACLE','From MariaDB 10.3, setting the sql_mode system variable to Oracle allows the\nserver to understand a subset of Oracle\'s PL/SQL language. For example:\n\nSET SQL_MODE=\'ORACLE\';\n\nAll traditional MariaDB SQL/PSM syntax should work as before, as long as it\ndoes not conflict with Oracle\'s PL/SQL syntax. All MariaDB functions should be\nsupported in both normal and Oracle modes.\n\nPrior to MariaDB 10.3, MariaDB does not support Oracle\'s PL/SQL language, and\nSET SQL_MODE=ORACLE is only an alias for the following sql_mode in those\nversions:\n\nSET SQL_MODE=\'PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, NO_KEY_OPTIONS,\nNO_TABLE_OPTIONS, NO_FIELD_OPTIONS, NO_AUTO_CREATE_USER\';\n\nFrom MariaDB 10.3, SET SQL_MODE=ORACLE is same as:\n\nSET SQL_MODE=\'PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,\nNO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT\';\n\nSupported Syntax in Oracle Mode\n-------------------------------\n\nStored Procedures and Stored Functions\n--------------------------------------\n\nOracle mode makes the following changes to Stored Procedures and Stored\nFunctions:\n\n+-----------------------------------------+-----------------------------------+\n| Oracle syntax | Description |\n+-----------------------------------------+-----------------------------------+\n| CREATE PROCEDURE p1 (param OUT INT) | ANSI uses (OUT param INT) |\n+-----------------------------------------+-----------------------------------+\n| CREATE PROCEDURE p1 (a IN OUT INT) | ANSI uses (INOUT param INT) |\n+-----------------------------------------+-----------------------------------+\n| AS before function body | CREATE FUNCTION f1 RETURN NUMBER |\n| | AS BEGIN... |\n+-----------------------------------------+-----------------------------------+\n| IS before function body | CREATE FUNCTION f1 RETURN NUMBER |\n| | IS BEGIN... |\n+-----------------------------------------+-----------------------------------+\n| If function has no parameters then | Example: CREATE PROCEDURE p1 AS |\n| parentheses must be omitted | BEGIN NULL; END; |\n+-----------------------------------------+-----------------------------------+\n| CREATE PROCEDURE p1 AS BEGIN END p1; | Optional routine name after END |\n| | keyword. MDEV-12089 |\n+-----------------------------------------+-----------------------------------+\n| CREATE FUNCTION f1(a VARCHAR) | VARCHAR can be used without |\n| | length for routine parameters |\n| | and RETURN clause. The length is |\n| | inherited from the argument at |\n| | call time. MDEV-10596 |\n+-----------------------------------------+-----------------------------------+\n| CREATE AGGREGATE FUNCTION f1( ) | Creates an aggregate function, |\n| | which performs the function |\n| | against a set of rows and |\n| | returns one aggregate result. |\n+-----------------------------------------+-----------------------------------+\n| No CALL needed in Stored Procedures | In Oracle mode one can call |\n| | other stored procedures with |\n| | name only. MDEV-12107 |\n+-----------------------------------------+-----------------------------------+\n| RETURN. Can also be used in stored | ANSI uses RETURNS. MariaDB mode |\n| procedures | only supports RETURNS in stored |\n| | functions |\n+-----------------------------------------+-----------------------------------+\n\nCursors\n-------\n\nOracle mode makes the following changes to Cursors:\n\n+-----------------------------------------+-----------------------------------+\n| Oracle syntax | Description |\n+-----------------------------------------+-----------------------------------+\n| CREATE PROCEDURE p1 AS CURSOR cur IS | Explicit cursor with FOR loop. |\n| (SELECT a, b FROM t1); BEGIN FOR rec | MDEV-10581 |\n| IN cur ... | |\n+-----------------------------------------+-----------------------------------+\n| CREATE PROCEDURE p1 AS rec IN (SELECT | Implicit cursor with FOR loop. |\n| a, b FROM t1) | MDEV-12098 |\n+-----------------------------------------+-----------------------------------+\n| CURSOR c(prm_a VARCHAR2, prm_b | Cursor with parameters. |\n| VARCHAR2) ... OPEN c(1,2) | MDEV-10597 |\n+-----------------------------------------+-----------------------------------+\n| CURSOR c(prm_a VARCHAR2, prm_b | Cursor with parameters and FOR |\n| VARCHAR2) ... FOR rec in c(1,2) | loop. MDEV-12314 |\n+-----------------------------------------+-----------------------------------+\n| s %ISOPEN, %ROWCOUNT, %FOUND, %NOTFOUND | Explicit cursor attributes. |\n| | MDEV-10582 |\n+-----------------------------------------+-----------------------------------+\n\nLOOP\n----\n\nOracle mode makes the following changes to LOOP:\n\n+-----------------------------------------+-----------------------------------+\n| Oracle syntax | Description |\n+-----------------------------------------+-----------------------------------+\n| FOR i IN 1..10 LOOP ... END LOOP | Numeric FOR loop. MDEV-10580 |\n+-----------------------------------------+-----------------------------------+\n| GOTO | GOTO statement. MDEV-10697 |\n+-----------------------------------------+-----------------------------------+\n| <<label>> used with GOTO | ANSI uses label:. MDEV-10697 |\n+-----------------------------------------+-----------------------------------+\n| To leave loop block: EXIT [ label ] [ | ANSI syntax is IF bool_expr THEN |\n| WHEN bool_expr ] | LEAVE label |\n+-----------------------------------------+-----------------------------------+\n| [<<label>>] WHILE boolean_expression | Oracle style WHILE loop |\n| LOOP statement... END LOOP [ label ] ; | |\n+-----------------------------------------+-----------------------------------+\n| CONTINUE [ label ] [ WHEN | CONTINUE is only valid inside a |\n| boolean_expression] | loop |\n+-----------------------------------------+-----------------------------------+\n\nVariables\n---------\n\n+------------------------------+-----------------+--------------------------+\n| Oracle syntax | Version | Description |\n+------------------------------+-----------------+--------------------------+\n| var:= 10; Can also be used | 10.3 | MariaDB uses SET var= |\n| with MariaDB systemvariables | | 10; |\n+------------------------------+-----------------+--------------------------+\n| var INT := 10 | 10.3 | Default variable value |\n+------------------------------+-----------------+--------------------------+\n| var1 | 10.3 | Take data type from a |\n| table_name.column_name%TYPE | | table column. MDEV-10577 |\n+------------------------------+-----------------+--------------------------+\n| var2 var1%TYPE | 10.3 | Take data type from |\n| | | another variable |\n+------------------------------+-----------------+--------------------------+\n| rec1 table_name%ROWTYPE | 10.3 | Take ROW structure from |\n| | | a table. MDEV-12133 |\n+------------------------------+-----------------+--------------------------+\n| rec2 rec1%ROWTYPE | 10.3 | Take ROW structure from |\n| | | ROW variable |\n+------------------------------+-----------------+--------------------------+\n| CURSOR c1 IS SELECT a,b | 10.3 | Take ROW structure from |\n| FROM t1; rec1 c1%ROWTYPE; | | a cursor. MDEV-12011 |\n+------------------------------+-----------------+--------------------------+\n| Variables can be declared | 10.3 | In MariaDB mode, |\n| after cursor declarations | | variables must be |\n| | | declared before |\n| | | cursors. MDEV-10598 |\n+------------------------------+-----------------+--------------------------+\n| Triggers uses :NEW and :OLD | 10.3 | ANSI uses NEW and OLD. |\n| | | MDEV-10579 |\n+------------------------------+-----------------+--------------------------+\n| SQLCODE | 10.3 | Returns the number code |\n| | | of the most recent |\n| | | exception. Can only be |\n| | | used in Stored |\n| | | Procedures. MDEV-10578 |\n+------------------------------+-----------------+--------------------------+\n| SQLERRM | 10.3 | Returns the error |\n| | | message associdated to |\n| | | it\'s error number |\n| | | argument or SQLCODE if |\n| | | no argument is given. |\n| | | Can only be used in |\n| | | Stored Procedures. |\n| | | MDEV-10578 |\n+------------------------------+-----------------+--------------------------+\n| SQL%ROWCOUNT | 10.3 | Almost same as |\n| | | ROW_COUNT(). MDEV-10583 |\n+------------------------------+-----------------+--------------------------+\n| ROWNUM | 10.6.1 | Returns number of |\n| | | accepted rows |\n+------------------------------+-----------------+--------------------------+\n\nExceptions\n----------\n\n+-----------------------------------------+-----------------------------------+\n| Oracle syntax | Description |\n+-----------------------------------------+-----------------------------------+\n| BEGIN ... EXCEPTION WHEN OTHERS THEN | Exception handlers are declared |\n| BEGIN .. END; END; | at the end of a block |\n+-----------------------------------------+-----------------------------------+\n| TOO_MANY_ROWS, NO_DATA_FOUND, | Predefined exceptions. MDEV-10839 |\n| DUP_VAL_ON_INDEX | |\n+-----------------------------------------+-----------------------------------+\n| RAISE TOO_MANY_ROWS ; .... EXCEPTION | Exception can be used with RAISE |\n| WHEN TOO_MANY_ROWS THEN ... | and EXCEPTION...WHEN. MDEV-10840 |\n+-----------------------------------------+-----------------------------------+\n| CREATE OR REPLACE FUNCTION f1 (a INT) | User defined exceptions. |\n| RETURN INT AS e1 EXCEPTION... | MDEV-10587 |\n+-----------------------------------------+-----------------------------------+\n\nBEGIN Blocks\n------------\n\n+-----------------------------------------+-----------------------------------+\n| Oracle syntax | Description |\n+-----------------------------------------+-----------------------------------+\n| BEGIN to start a block | MariaDB uses BEGIN NOT ATOMIC |\n| | for anyonymous blocks. MDEV-10655 |\n+-----------------------------------------+-----------------------------------+\n| DECLARE is used before BEGIN | DECLARE a INT; b VARCHAR(10); |\n| | BEGIN v:= 10; END; |\n+-----------------------------------------+-----------------------------------+\n| WHEN DUP_VAL_ON_INDEX THEN NULL ; | Do not require BEGIN..END in |\n| NULL; WHEN OTHERS THEN NULL | multi-statement exception |\n| | handlers in THEN clause. |\n| | MDEV-12088 |\n+-----------------------------------------+-----------------------------------+\n\nSimple Syntax Compatibility\n---------------------------\n\n+------------------------------+-----------------+--------------------------+\n| Oracle syntax | Version | Description |\n+------------------------------+-----------------+--------------------------+\n| ELSIF | 10.3 | ANSI uses ELSEIF |\n+------------------------------+-----------------+--------------------------+\n| SELECT UNIQUE | 10.3 | Same as SELECT |\n| | | DISTINCT. MDEV-12086 |','','https://mariadb.com/kb/en/sql_modeoracle/'); +update help_topic set description = CONCAT(description, '\n+------------------------------+-----------------+--------------------------+\n| TRUNCATE TABLE t1 [DROP | 10.3 | DROP STORAGE and REUSE |\n| STORAGE] or [REUSE STORAGE] | | STORAGE are allowed as |\n| | | optional keywords for |\n| | | TRUNCATE TABLE. |\n| | | MDEV-10588 |\n+------------------------------+-----------------+--------------------------+\n| Subqueries in a FROM clause | 10.6 | SELECT * FROM (SELECT 1 |\n| without an alias | | FROM DUAL), (SELECT 2 |\n| | | FROM DUAL) |\n+------------------------------+-----------------+--------------------------+\n| UNION, EXCEPT and INTERSECT | 10.3 | INTERSECT has higher |\n| all have the same | | precedence than UNION |\n| precedence. | | and EXCEPT in |\n| | | non-Oracle modes. |\n+------------------------------+-----------------+--------------------------+\n| MINUS | 10.6 | MINUS is a synonym for |\n| | | EXCEPT. |\n+------------------------------+-----------------+--------------------------+\n\nFunctions\n---------\n\n+------------------------------+-----------------+--------------------------+\n| Oracle syntax | Version | Description |\n+------------------------------+-----------------+--------------------------+\n| ADD_MONTHS() | 10.6.1 | Added as a wrapper for |\n| | | DATE_ADD() to enhance |\n| | | Oracle compatibility. |\n| | | All modes. |\n+------------------------------+-----------------+--------------------------+\n| CAST(expr as VARCHAR(N)) | 10.3 | Cast expression to a |\n| | | VARCHAR(N). MDEV-11275 |\n+------------------------------+-----------------+--------------------------+\n| DECODE | 10.3 | In Oracle mode, |\n| | | compares and matches |\n| | | search expressions |\n+------------------------------+-----------------+--------------------------+\n| LENGTH() is same as | 10.3 | MariaDB translates |\n| CHAR_LENGTH() | | LENGTH() to |\n| | | OCTET_LENGTH(). In all |\n| | | modes one can use |\n| | | LENGTHB() as a synonym |\n| | | to OCTET_LENGTH() |\n+------------------------------+-----------------+--------------------------+\n| CHR(num) | 10.3 | Returns a VARCHAR(1) |\n| | | with character set and |\n| | | collation according to |\n| | | @@character_set_database |\n| | | and @@collation_database |\n+------------------------------+-----------------+--------------------------+\n| substr(\'abc\',0 ,3) same as | 10.3 | Position 0 for substr() |\n| substr(\'abc\', 1 ,3) | | is same as position 1 |\n+------------------------------+-----------------+--------------------------+\n| SYS_GUID | 10.6.1 | Generates a globally |\n| | | unique identifier. |\n| | | Similar to UUID but |\n| | | without the -. All |\n| | | modes. |\n+------------------------------+-----------------+--------------------------+\n| TO_CHAR | 10.6.1 | Added to enhance Oracle |\n| | | compatibility. All |\n| | | modes. |\n+------------------------------+-----------------+--------------------------+\n| TRIM, LTRIM, RTRIM, LPAD | 10.3 | Returns NULL instead of |\n| and RPAD | | an empty string if |\n| | | returning an empty |\n| | | result. These functions |\n| | | can also be accessed |\n| | | outside of ORACLE mode |\n| | | by suffixing _ORACLE |\n| | | onto the end of the |\n| | | function name, such as |\n| | | TRIM_ORACLE. |\n+------------------------------+-----------------+--------------------------+\n\nPrepared Statements\n-------------------\n\nOracle mode makes the following changes to Prepared Statements:\n\n+-----------------------------------------+-----------------------------------+\n| Oracle syntax | Description |\n+-----------------------------------------+-----------------------------------+\n| PREPARE stmt FROM \'SELECT :1, :2\' | ANSI uses ?. MDEV-10801 |\n+-----------------------------------------+-----------------------------------+\n| EXECUTE IMMEDIATE \'INSERT INTO t1 | Dynamic placeholders. MDEV-10801 |\n| SELECT (:x,:y) FROM DUAL\' USING 10,20 | |\n+-----------------------------------------+-----------------------------------+\n\nSynonyms for Basic SQL Types\n----------------------------\n\n+--------------------------------+-------------------------------------------+\n| Oracle type | MariaDB synonym |\n+--------------------------------+-------------------------------------------+\n| VARCHAR2 | VARCHAR |\n+--------------------------------+-------------------------------------------+\n| NUMBER | DECIMAL |\n+--------------------------------+-------------------------------------------+\n| DATE (with time portion) | MariaDB DATETIME |\n+--------------------------------+-------------------------------------------+\n| RAW | VARBINARY |\n+--------------------------------+-------------------------------------------+\n| CLOB | LONGTEXT |\n+--------------------------------+-------------------------------------------+\n| BLOB | LONGBLOB |\n+--------------------------------+-------------------------------------------+\n\nThis was implemented as part of MDEV-10343.\n\nIf one does a SHOW CREATE TABLE in ORACLE mode on a table that has a native\nMariaDB DATE column, it will be displayed as mariadb_schema.date to not\nconflict with the Oracle DATE type.\n\nPackages\n--------\n\nThe following syntax has been supported since MariaDB 10.3.5:\n\n* CREATE PACKAGE\n* CREATE PACKAGE BODY\n* DROP PACKAGE\n* DROP PACKAGE BODY\n* SHOW CREATE PACKAGE\n* SHOW CREATE PACKAGE BODY\n\nNULL Handling\n-------------\n\nOracle mode makes the following changes to NULL handling:\n\nNULL As a Statement\n-------------------\n\nNULL can be used as a statement:\n\nIF a=10 THEN NULL; ELSE NULL; END IF\n\nTranslating Empty String Literals to NULL\n-----------------------------------------\n\nIn Oracle, empty string (\'\') and NULL are the same thing,\n\nBy using sql_mode=EMPTY_STRING_IS_NULL you can get a similar experience in\nMariaDB:\n\nSET sql_mode=EMPTY_STRING_IS_NULL;\nSELECT \'\' IS NULL; -- returns TRUE\nINSERT INTO t1 VALUES (\'\'); -- inserts NULL\n\nConcat Operator Ignores NULL\n----------------------------\n\nCONCAT() and || ignore NULL in Oracle mode. Can also be accessed outside of\nORACLE mode by using CONCAT_OPERATOR_ORACLE. MDEV-11880 and MDEV-12143.\n\nReserved Words\n--------------\n\nThere are a number of extra reserved words in Oracle mode.\n\nSHOW CREATE TABLE\n-----------------\n\nThe SHOW CREATE TABLE statement will not display MariaDB-specific table\noptions, such as AUTO_INCREMENT or CHARSET, when Oracle mode is set.\n\nURL: https://mariadb.com/kb/en/sql_modeoracle/') WHERE help_topic_id = 488; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (489,30,'CONTAINS','Syntax\n------\n\nContains(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether a geometry g1 completely contains geometry\ng2. CONTAINS() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_CONTAINS() uses object shapes.\n\nThis tests the opposite relationship to Within().\n\nURL: https://mariadb.com/kb/en/contains/','','https://mariadb.com/kb/en/contains/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (490,30,'CROSSES','Syntax\n------\n\nCrosses(g1,g2)\n\nDescription\n-----------\n\nReturns 1 if g1 spatially crosses g2. Returns NULL if g1 is a Polygon or a\nMultiPolygon, or if g2 is a Point or a MultiPoint. Otherwise, returns 0.\n\nThe term spatially crosses denotes a spatial relation between two given\ngeometries that has the following properties:\n\n* The two geometries intersect\n* Their intersection results in a geometry that has a dimension that is one\n less than the maximum dimension of the two given geometries\n* Their intersection is not equal to either of the two given geometries\n\nCROSSES() is based on the original MySQL implementation, and uses object\nbounding rectangles, while ST_CROSSES() uses object shapes.\n\nURL: https://mariadb.com/kb/en/crosses/','','https://mariadb.com/kb/en/crosses/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (491,30,'DISJOINT','Syntax\n------\n\nDisjoint(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether g1 is spatially disjoint from (does not\nintersect) g2.\n\nDISJOINT() tests the opposite relationship to INTERSECTS().\n\nDISJOINT() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_DISJOINT() uses object shapes.\n\nURL: https://mariadb.com/kb/en/disjoint/','','https://mariadb.com/kb/en/disjoint/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (492,30,'EQUALS','Syntax\n------\n\nEquals(g1,g2)\n\nFrom MariaDB 10.2.3:\n\nMBREQUALS(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether g1 is spatially equal to g2.\n\nEQUALS() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_EQUALS() uses object shapes.\n\nFrom MariaDB 10.2.3, MBREQUALS is a synonym for Equals.\n\nURL: https://mariadb.com/kb/en/equals/','','https://mariadb.com/kb/en/equals/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (493,30,'INTERSECTS','Syntax\n------\n\nINTERSECTS(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether geometry g1 spatially intersects geometry\ng2.\n\nINTERSECTS() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_INTERSECTS() uses object shapes.\n\nINTERSECTS() tests the opposite relationship to DISJOINT().\n\nURL: https://mariadb.com/kb/en/intersects/','','https://mariadb.com/kb/en/intersects/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (494,30,'OVERLAPS','Syntax\n------\n\nOVERLAPS(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether g1 spatially overlaps g2. The term\nspatially overlaps is used if two geometries intersect and their intersection\nresults in a geometry of the same dimension but not equal to either of the\ngiven geometries.\n\nOVERLAPS() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_OVERLAPS() uses object shapes.\n\nURL: https://mariadb.com/kb/en/overlaps/','','https://mariadb.com/kb/en/overlaps/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (495,30,'ST_CONTAINS','Syntax\n------\n\nST_CONTAINS(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether a geometry g1 completely contains geometry\ng2.\n\nST_CONTAINS() uses object shapes, while CONTAINS(), based on the original\nMySQL implementation, uses object bounding rectangles.\n\nST_CONTAINS tests the opposite relationship to ST_WITHIN().\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT(\'POLYGON((175 150, 20 40, 50 60, 125 100, 175\n150))\');\n\nSET @g2 = ST_GEOMFROMTEXT(\'POINT(174 149)\');\n\nSELECT ST_CONTAINS(@g1,@g2);\n+----------------------+\n| ST_CONTAINS(@g1,@g2) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSET @g2 = ST_GEOMFROMTEXT(\'POINT(175 151)\');\n\nSELECT ST_CONTAINS(@g1,@g2);\n+----------------------+\n| ST_CONTAINS(@g1,@g2) |\n+----------------------+\n| 0 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/st-contains/','','https://mariadb.com/kb/en/st-contains/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (496,30,'ST_CROSSES','Syntax\n------\n\nST_CROSSES(g1,g2)\n\nDescription\n-----------\n\nReturns 1 if geometry g1 spatially crosses geometry g2. Returns NULL if g1 is\na Polygon or a MultiPolygon, or if g2 is a Point or a MultiPoint. Otherwise,\nreturns 0.\n\nThe term spatially crosses denotes a spatial relation between two given\ngeometries that has the following properties:\n\n* The two geometries intersect\n* Their intersection results in a geometry that has a dimension that is one\n less than the maximum dimension of the two given geometries\n* Their intersection is not equal to either of the two given geometries\n\nST_CROSSES() uses object shapes, while CROSSES(), based on the original MySQL\nimplementation, uses object bounding rectangles.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT(\'LINESTRING(174 149, 176 151)\');\n\nSET @g2 = ST_GEOMFROMTEXT(\'POLYGON((175 150, 20 40, 50 60, 125 100, 175\n150))\');\n\nSELECT ST_CROSSES(@g1,@g2);\n+---------------------+\n| ST_CROSSES(@g1,@g2) |\n+---------------------+\n| 1 |\n+---------------------+\n\nSET @g1 = ST_GEOMFROMTEXT(\'LINESTRING(176 149, 176 151)\');\n\nSELECT ST_CROSSES(@g1,@g2);\n+---------------------+\n| ST_CROSSES(@g1,@g2) |\n+---------------------+\n| 0 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/st-crosses/','','https://mariadb.com/kb/en/st-crosses/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (497,30,'ST_DIFFERENCE','Syntax\n------\n\nST_DIFFERENCE(g1,g2)\n\nDescription\n-----------\n\nReturns a geometry representing the point set difference of the given geometry\nvalues.\n\nExample\n-------\n\nSET @g1 = POINT(10,10), @g2 = POINT(20,20);\n\nSELECT ST_AsText(ST_Difference(@g1, @g2));\n+------------------------------------+\n| ST_AsText(ST_Difference(@g1, @g2)) |\n+------------------------------------+\n| POINT(10 10) |\n+------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_difference/','','https://mariadb.com/kb/en/st_difference/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (498,30,'ST_DISJOINT','Syntax\n------\n\nST_DISJOINT(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether geometry g1 is spatially disjoint from\n(does not intersect with) geometry g2.\n\nST_DISJOINT() uses object shapes, while DISJOINT(), based on the original\nMySQL implementation, uses object bounding rectangles.\n\nST_DISJOINT() tests the opposite relationship to ST_INTERSECTS().\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT(\'POINT(0 0)\');\n\nSET @g2 = ST_GEOMFROMTEXT(\'LINESTRING(2 0, 0 2)\');\n\nSELECT ST_DISJOINT(@g1,@g2);\n+----------------------+\n| ST_DISJOINT(@g1,@g2) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSET @g2 = ST_GEOMFROMTEXT(\'LINESTRING(0 0, 0 2)\');\n\nSELECT ST_DISJOINT(@g1,@g2);\n+----------------------+\n| ST_DISJOINT(@g1,@g2) |\n+----------------------+\n| 0 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/st_disjoint/','','https://mariadb.com/kb/en/st_disjoint/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (499,30,'ST_DISTANCE','Syntax\n------\n\nST_DISTANCE(g1,g2)\n\nDescription\n-----------\n\nReturns the distance between two geometries, or null if not given valid inputs.\n\nExample\n-------\n\nSELECT ST_Distance(POINT(1,2),POINT(2,2));\n+------------------------------------+\n| ST_Distance(POINT(1,2),POINT(2,2)) |\n+------------------------------------+\n| 1 |\n+------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_distance/','','https://mariadb.com/kb/en/st_distance/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (500,30,'ST_DISTANCE_SPHERE','MariaDB starting with 10.2.38\n-----------------------------\nST_DISTANCE_SPHERE was introduced in MariaDB 10.2.38, MariaDB 10.3.29, MariaDB\n10.4.19 and MariaDB 10.5.10.\n\nSyntax\n------\n\nST_DISTANCE_SPHERE(g1,g2,[r])\n\nDescription\n-----------\n\nReturns the spherical distance between two geometries (point or multipoint) on\na sphere with the optional radius r (default is the Earth radius if r is not\nspecified), or NULL if not given valid inputs.\n\nExample\n-------\n\nset @zenica = ST_GeomFromText(\'POINT(17.907743 44.203438)\');\nset @sarajevo = ST_GeomFromText(\'POINT(18.413076 43.856258)\');\nSELECT ST_Distance_Sphere(@zenica, @sarajevo);\n55878.59337591705\n\nURL: https://mariadb.com/kb/en/st_distance_sphere/','','https://mariadb.com/kb/en/st_distance_sphere/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (501,30,'ST_EQUALS','Syntax\n------\n\nST_EQUALS(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether geometry g1 is spatially equal to geometry\ng2.\n\nST_EQUALS() uses object shapes, while EQUALS(), based on the original MySQL\nimplementation, uses object bounding rectangles.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT(\'LINESTRING(174 149, 176 151)\');\n\nSET @g2 = ST_GEOMFROMTEXT(\'LINESTRING(176 151, 174 149)\');\n\nSELECT ST_EQUALS(@g1,@g2);\n+--------------------+\n| ST_EQUALS(@g1,@g2) |\n+--------------------+\n| 1 |\n+--------------------+\n\nSET @g1 = ST_GEOMFROMTEXT(\'POINT(0 2)\');\n\nSET @g1 = ST_GEOMFROMTEXT(\'POINT(2 0)\');\n\nSELECT ST_EQUALS(@g1,@g2);\n+--------------------+\n| ST_EQUALS(@g1,@g2) |\n+--------------------+\n| 0 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/st-equals/','','https://mariadb.com/kb/en/st-equals/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (502,30,'ST_INTERSECTS','Syntax\n------\n\nST_INTERSECTS(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether geometry g1 spatially intersects geometry\ng2.\n\nST_INTERSECTS() uses object shapes, while INTERSECTS(), based on the original\nMySQL implementation, uses object bounding rectangles.\n\nST_INTERSECTS() tests the opposite relationship to ST_DISJOINT().\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT(\'POINT(0 0)\');\n\nSET @g2 = ST_GEOMFROMTEXT(\'LINESTRING(0 0, 0 2)\');\n\nSELECT ST_INTERSECTS(@g1,@g2);\n+------------------------+\n| ST_INTERSECTS(@g1,@g2) |\n+------------------------+\n| 1 |\n+------------------------+\n\nSET @g2 = ST_GEOMFROMTEXT(\'LINESTRING(2 0, 0 2)\');\n\nSELECT ST_INTERSECTS(@g1,@g2);\n+------------------------+\n| ST_INTERSECTS(@g1,@g2) |\n+------------------------+\n| 0 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/st-intersects/','','https://mariadb.com/kb/en/st-intersects/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (503,30,'ST_LENGTH','Syntax\n------\n\nST_LENGTH(ls)\n\nDescription\n-----------\n\nReturns as a double-precision number the length of the LineString value ls in\nits associated spatial reference.\n\nExamples\n--------\n\nSET @ls = \'LineString(1 1,2 2,3 3)\';\n\nSELECT ST_LENGTH(ST_GeomFromText(@ls));\n+---------------------------------+\n| ST_LENGTH(ST_GeomFromText(@ls)) |\n+---------------------------------+\n| 2.82842712474619 |\n+---------------------------------+\n\nURL: https://mariadb.com/kb/en/st_length/','','https://mariadb.com/kb/en/st_length/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (504,30,'ST_OVERLAPS','Syntax\n------\n\nST_OVERLAPS(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether geometry g1 spatially overlaps geometry g2.\n\nThe term spatially overlaps is used if two geometries intersect and their\nintersection results in a geometry of the same dimension but not equal to\neither of the given geometries.\n\nST_OVERLAPS() uses object shapes, while OVERLAPS(), based on the original\nMySQL implementation, uses object bounding rectangles.\n\nURL: https://mariadb.com/kb/en/st-overlaps/','','https://mariadb.com/kb/en/st-overlaps/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (505,30,'ST_TOUCHES','Syntax\n------\n\nST_TOUCHES(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether geometry g1 spatially touches geometry g2.\nTwo geometries spatially touch if the interiors of the geometries do not\nintersect, but the boundary of one of the geometries intersects either the\nboundary or the interior of the other.\n\nST_TOUCHES() uses object shapes, while TOUCHES(), based on the original MySQL\nimplementation, uses object bounding rectangles.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT(\'POINT(2 0)\');\n\nSET @g2 = ST_GEOMFROMTEXT(\'LINESTRING(2 0, 0 2)\');\n\nSELECT ST_TOUCHES(@g1,@g2);\n+---------------------+\n| ST_TOUCHES(@g1,@g2) |\n+---------------------+\n| 1 |\n+---------------------+\n\nSET @g1 = ST_GEOMFROMTEXT(\'POINT(2 1)\');\n\nSELECT ST_TOUCHES(@g1,@g2);\n+---------------------+\n| ST_TOUCHES(@g1,@g2) |\n+---------------------+\n| 0 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/st-touches/','','https://mariadb.com/kb/en/st-touches/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (506,30,'ST_WITHIN','Syntax\n------\n\nST_WITHIN(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether geometry g1 is spatially within geometry g2.\n\nThis tests the opposite relationship as ST_CONTAINS().\n\nST_WITHIN() uses object shapes, while WITHIN(), based on the original MySQL\nimplementation, uses object bounding rectangles.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT(\'POINT(174 149)\');\n\nSET @g2 = ST_GEOMFROMTEXT(\'POLYGON((175 150, 20 40, 50 60, 125 100, 175\n150))\');\n\nSELECT ST_WITHIN(@g1,@g2);\n+--------------------+\n| ST_WITHIN(@g1,@g2) |\n+--------------------+\n| 1 |\n+--------------------+\n\nSET @g1 = ST_GEOMFROMTEXT(\'POINT(176 151)\');\n\nSELECT ST_WITHIN(@g1,@g2);\n+--------------------+\n| ST_WITHIN(@g1,@g2) |\n+--------------------+\n| 0 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/st-within/','','https://mariadb.com/kb/en/st-within/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (507,30,'TOUCHES','Syntax\n------\n\nTouches(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether g1 spatially touches g2. Two geometries\nspatially touch if the interiors of the geometries do not intersect, but the\nboundary of one of the geometries intersects either the boundary or the\ninterior of the other.\n\nTOUCHES() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_TOUCHES() uses object shapes.\n\nURL: https://mariadb.com/kb/en/touches/','','https://mariadb.com/kb/en/touches/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (508,30,'WITHIN','Syntax\n------\n\nWithin(g1,g2)\n\nDescription\n-----------\n\nReturns 1 or 0 to indicate whether g1 is spatially within g2. This tests the\nopposite relationship as Contains().\n\nWITHIN() is based on the original MySQL implementation, and uses object\nbounding rectangles, while ST_WITHIN() uses object shapes.\n\nExamples\n--------\n\nSET @g1 = GEOMFROMTEXT(\'POINT(174 149)\');\nSET @g2 = GEOMFROMTEXT(\'POINT(176 151)\');\nSET @g3 = GEOMFROMTEXT(\'POLYGON((175 150, 20 40, 50 60, 125 100, 175 150))\');\n\nSELECT within(@g1,@g3);\n+-----------------+\n| within(@g1,@g3) |\n+-----------------+\n| 1 |\n+-----------------+\n\nSELECT within(@g2,@g3);\n+-----------------+\n| within(@g2,@g3) |\n+-----------------+\n| 0 |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/within/','','https://mariadb.com/kb/en/within/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (509,31,'Microseconds in MariaDB','The TIME, DATETIME, and TIMESTAMP types, along with the temporal functions,\nCAST and dynamic columns, support microseconds. The datetime precision of a\ncolumn can be specified when creating the table with CREATE TABLE, for example:\n\nCREATE TABLE example(\n col_microsec DATETIME(6),\n col_millisec TIME(3)\n);\n\nGenerally, the precision can be specified for any TIME, DATETIME, or TIMESTAMP\ncolumn, in parentheses, after the type name. The datetime precision specifies\nnumber of digits after the decimal dot and can be any integer number from 0 to\n6. If no precision is specified it is assumed to be 0, for backward\ncompatibility reasons.\n\nA datetime precision can be specified wherever a type name is used. For\nexample:\n\n* when declaring arguments of stored routines.\n* when specifying a return type of a stored function.\n* when declaring variables.\n* in a CAST function:create function example(x datetime(5)) returns time(4)\nbegin\n declare y timestamp(6);\n return cast(x as time(2));\nend;\n\n%f is used as the formatting option for microseconds in the STR_TO_DATE,\nDATE_FORMAT and FROM_UNIXTIME functions, for example:\n\nSELECT STR_TO_DATE(\'20200809 020917076\',\'%Y%m%d %H%i%s%f\');\n+-----------------------------------------------------+\n| STR_TO_DATE(\'20200809 020917076\',\'%Y%m%d %H%i%s%f\') |\n+-----------------------------------------------------+\n| 2020-08-09 02:09:17.076000 |\n+-----------------------------------------------------+\n\nAdditional Information\n----------------------\n\n* when comparing anything to a temporal value (DATETIME, TIME, DATE, or\nTIMESTAMP), both values are compared as temporal values, not as strings.\n* The INFORMATION_SCHEMA.COLUMNS table has a new column DATETIME_PRECISION\n* NOW(), CURTIME(), UTC_TIMESTAMP(), UTC_TIME(), CURRENT_TIME(),\nCURRENT_TIMESTAMP(), LOCALTIME() and LOCALTIMESTAMP() now accept datetime\nprecision as an optional argument. For example:SELECT CURTIME(4);\n--> 10:11:12.3456\n\n* TIME_TO_SEC() and UNIX_TIMESTAMP() preserve microseconds of the argument.\nThese functions will return a decimal number if the result non-zero datetime\nprecision and an integer otherwise (for backward compatibility).SELECT\nTIME_TO_SEC(\'10:10:10.12345\');\n--> 36610.12345\n\n* Current versions of this patch fix a bug in the following optimization: in\n certain queries with DISTINCT MariaDB can ignore this clause if it can\n prove that all result rows are unique anyway, for example, when a primary key\n is compared with a constant. Sometimes this optimization was applied\n incorrectly, though — for example, when comparing a\n string with a date constant. This is now fixed.\n* DATE_ADD() and DATE_SUB() functions can now take a TIME\n expression as an argument (not just DATETIME as before).SELECT\nTIME(\'10:10:10\') + INTERVAL 100 MICROSECOND;\n--> 10:10:10.000100\n\n* The event_time field in the mysql.general_log table and the start_time,\nquery_time, and lock_time fields in the mysql.slow_log table now store values\nwith microsecond precision.\n* This patch fixed a bug when comparing a temporal value using the BETWEEN\noperator and one of the operands is NULL.\n* The old syntax TIMESTAMP(N), where N is the display width, is no longer\nsupported. It was deprecated in MySQL 4.1.0 (released on\n 2003-04-03).\n* when a DATETIME value is compared to a TIME value, the latter is treated as\na full datetime with a zero date part, similar to comparing DATE to a\nDATETIME, or to comparing DECIMAL numbers.\n Earlier versions of MariaDB used to compare only the time part of both\noperands in such a case.\n* In MariaDB, an extra column TIME_MS has been added to the\nINFORMATION_SCHEMA.PROCESSLIST table, as well as to the output of SHOW FULL\nPROCESSLIST.\n\nNote: When you convert a temporal value to a value with a smaller precision,\nit will be truncated, not rounded. This is done to guarantee that the date\npart is not changed. For example:\n\nSELECT CAST(\'2009-12-31 23:59:59.998877\' as DATETIME(3));\n-> 2009-12-31 23:59:59.998\n\nMySQL 5.6 Microseconds\n----------------------\n\nMySQL 5.6 introduced microseconds using a slightly different implementation to\nMariaDB 5.3. Since MariaDB 10.1, MariaDB has defaulted to the MySQL format, by\nmeans of the --mysql56-temporal-format variable. The MySQL version requires\nslightly more storage but has some advantages in permitting the eventual\nsupport of negative dates, and in replication.\n\nURL: https://mariadb.com/kb/en/microseconds-in-mariadb/','','https://mariadb.com/kb/en/microseconds-in-mariadb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (510,31,'Date and Time Units','The INTERVAL keyword can be used to add or subtract a time interval of time to\na DATETIME, DATE or TIME value.\n\nThe syntax is:\n\nINTERVAL time_quantity time_unit\n\nFor example, the SECOND unit is used below by the DATE_ADD() function:\n\nSELECT \'2008-12-31 23:59:59\' + INTERVAL 1 SECOND;\n+-------------------------------------------+\n| \'2008-12-31 23:59:59\' + INTERVAL 1 SECOND |\n+-------------------------------------------+\n| 2009-01-01 00:00:00 |\n+-------------------------------------------+\n\nThe following units are valid:\n\n+---------------------+------------------------------------------------------+\n| Unit | Description |\n+---------------------+------------------------------------------------------+\n| MICROSECOND | Microseconds |\n+---------------------+------------------------------------------------------+\n| SECOND | Seconds |\n+---------------------+------------------------------------------------------+\n| MINUTE | Minutes |\n+---------------------+------------------------------------------------------+\n| HOUR | Hours |\n+---------------------+------------------------------------------------------+\n| DAY | Days |\n+---------------------+------------------------------------------------------+\n| WEEK | Weeks |\n+---------------------+------------------------------------------------------+\n| MONTH | Months |\n+---------------------+------------------------------------------------------+\n| QUARTER | Quarters |\n+---------------------+------------------------------------------------------+\n| YEAR | Years |\n+---------------------+------------------------------------------------------+\n| SECOND_MICROSECOND | Seconds.Microseconds |\n+---------------------+------------------------------------------------------+\n| MINUTE_MICROSECOND | Minutes.Seconds.Microseconds |\n+---------------------+------------------------------------------------------+\n| MINUTE_SECOND | Minutes.Seconds |\n+---------------------+------------------------------------------------------+\n| HOUR_MICROSECOND | Hours.Minutes.Seconds.Microseconds |\n+---------------------+------------------------------------------------------+\n| HOUR_SECOND | Hours.Minutes.Seconds |\n+---------------------+------------------------------------------------------+\n| HOUR_MINUTE | Hours.Minutes |\n+---------------------+------------------------------------------------------+\n| DAY_MICROSECOND | Days Hours.Minutes.Seconds.Microseconds |\n+---------------------+------------------------------------------------------+\n| DAY_SECOND | Days Hours.Minutes.Seconds |\n+---------------------+------------------------------------------------------+\n| DAY_MINUTE | Days Hours.Minutes |\n+---------------------+------------------------------------------------------+\n| DAY_HOUR | Days Hours |\n+---------------------+------------------------------------------------------+\n| YEAR_MONTH | Years-Months |\n+---------------------+------------------------------------------------------+\n\nThe time units containing an underscore are composite; that is, they consist\nof multiple base time units. For base time units, time_quantity is an integer\nnumber. For composite units, the quantity must be expressed as a string with\nmultiple integer numbers separated by any punctuation character.\n\nExample of composite units:\n\nINTERVAL \'2:2\' YEAR_MONTH\nINTERVAL \'1:30:30\' HOUR_SECOND\nINTERVAL \'1!30!30\' HOUR_SECOND -- same as above\n\nTime units can be used in the following contexts:\n\n* after a + or a - operator;\n* with the following DATE or TIME functions: ADDDATE(), SUBDATE(), DATE_ADD(),\nDATE_SUB(), TIMESTAMPADD(), TIMESTAMPDIFF(), EXTRACT();\n* in the ON SCHEDULE clause of CREATE EVENT and ALTER EVENT.\n* when defining a partitioning BY SYSTEM_TIME\n\nURL: https://mariadb.com/kb/en/date-and-time-units/','','https://mariadb.com/kb/en/date-and-time-units/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (511,31,'ADD_MONTHS','MariaDB starting with 10.6.1\n----------------------------\nThe ADD_MONTHS function was introduced in MariaDB 10.6.1 to enhance Oracle\ncompatibility. Similar functionality can be achieved with the DATE_ADD\nfunction.\n\nSyntax\n------\n\nADD_MONTHS(date, months)\n\nDescription\n-----------\n\nADD_MONTHS adds an integer months to a given date (DATE, DATETIME or\nTIMESTAMP), returning the resulting date.\n\nmonths can be positive or negative.\n\nThe resulting day component will remain the same as that specified in date,\nunless the resulting month has fewer days than the day component of the given\ndate, in which case the day will be the last day of the resulting month.\n\nReturns NULL if given an invalid date, or a NULL argument.\n\nExamples\n--------\n\nSELECT ADD_MONTHS(\'2012-01-31\', 2);\n+-----------------------------+\n| ADD_MONTHS(\'2012-01-31\', 2) |\n+-----------------------------+\n| 2012-03-31 |\n+-----------------------------+\n\nSELECT ADD_MONTHS(\'2012-01-31\', -5);\n+------------------------------+\n| ADD_MONTHS(\'2012-01-31\', -5) |\n+------------------------------+\n| 2011-08-31 |\n+------------------------------+\n\nSELECT ADD_MONTHS(\'2011-01-31\', 1);\n+-----------------------------+\n| ADD_MONTHS(\'2011-01-31\', 1) |\n+-----------------------------+\n| 2011-02-28 |\n+-----------------------------+\n\nSELECT ADD_MONTHS(\'2012-01-31\', 1);\n+-----------------------------+\n| ADD_MONTHS(\'2012-01-31\', 1) |\n+-----------------------------+\n| 2012-02-29 |\n+-----------------------------+\n\nSELECT ADD_MONTHS(\'2012-01-31\', 2);\n+-----------------------------+\n| ADD_MONTHS(\'2012-01-31\', 2) |\n+-----------------------------+\n| 2012-03-31 |\n+-----------------------------+\n\nSELECT ADD_MONTHS(\'2012-01-31\', 3);\n+-----------------------------+\n| ADD_MONTHS(\'2012-01-31\', 3) |\n+-----------------------------+\n| 2012-04-30 |\n+-----------------------------+\n\nURL: https://mariadb.com/kb/en/add_months/','','https://mariadb.com/kb/en/add_months/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (512,31,'ADDDATE','Syntax\n------\n\nADDDATE(date,INTERVAL expr unit), ADDDATE(expr,days)\n\nDescription\n-----------\n\nWhen invoked with the INTERVAL form of the second argument, ADDDATE() is a\nsynonym for DATE_ADD(). The related function SUBDATE() is a synonym for\nDATE_SUB(). For information on the INTERVAL unit argument, see the discussion\nfor DATE_ADD().\n\nWhen invoked with the days form of the second argument, MariaDB treats it as\nan integer number of days to be added to expr.\n\nExamples\n--------\n\nSELECT DATE_ADD(\'2008-01-02\', INTERVAL 31 DAY);\n+-----------------------------------------+\n| DATE_ADD(\'2008-01-02\', INTERVAL 31 DAY) |\n+-----------------------------------------+\n| 2008-02-02 |\n+-----------------------------------------+\n\nSELECT ADDDATE(\'2008-01-02\', INTERVAL 31 DAY);\n+----------------------------------------+\n| ADDDATE(\'2008-01-02\', INTERVAL 31 DAY) |\n+----------------------------------------+\n| 2008-02-02 |\n+----------------------------------------+\n\nSELECT ADDDATE(\'2008-01-02\', 31);\n+---------------------------+\n| ADDDATE(\'2008-01-02\', 31) |\n+---------------------------+\n| 2008-02-02 |\n+---------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n (\"2007-01-30 21:31:07\"),\n (\"1983-10-15 06:42:51\"),\n (\"2011-04-21 12:34:56\"),\n (\"2011-10-30 06:31:41\"),\n (\"2011-01-30 14:03:25\"),\n (\"2004-10-07 11:19:34\");\n\nSELECT d, ADDDATE(d, 10) from t1;\n+---------------------+---------------------+\n| d | ADDDATE(d, 10) |\n+---------------------+---------------------+\n| 2007-01-30 21:31:07 | 2007-02-09 21:31:07 |\n| 1983-10-15 06:42:51 | 1983-10-25 06:42:51 |\n| 2011-04-21 12:34:56 | 2011-05-01 12:34:56 |\n| 2011-10-30 06:31:41 | 2011-11-09 06:31:41 |\n| 2011-01-30 14:03:25 | 2011-02-09 14:03:25 |\n| 2004-10-07 11:19:34 | 2004-10-17 11:19:34 |\n+---------------------+---------------------+\n\nSELECT d, ADDDATE(d, INTERVAL 10 HOUR) from t1;\n+---------------------+------------------------------+\n| d | ADDDATE(d, INTERVAL 10 HOUR) |\n+---------------------+------------------------------+\n| 2007-01-30 21:31:07 | 2007-01-31 07:31:07 |\n| 1983-10-15 06:42:51 | 1983-10-15 16:42:51 |\n| 2011-04-21 12:34:56 | 2011-04-21 22:34:56 |\n| 2011-10-30 06:31:41 | 2011-10-30 16:31:41 |\n| 2011-01-30 14:03:25 | 2011-01-31 00:03:25 |\n| 2004-10-07 11:19:34 | 2004-10-07 21:19:34 |\n+---------------------+------------------------------+\n\nURL: https://mariadb.com/kb/en/adddate/','','https://mariadb.com/kb/en/adddate/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (513,31,'ADDTIME','Syntax\n------\n\nADDTIME(expr1,expr2)\n\nDescription\n-----------\n\nADDTIME() adds expr2 to expr1 and returns the result. expr1 is a time or\ndatetime expression, and expr2 is a time expression.\n\nExamples\n--------\n\nSELECT ADDTIME(\'2007-12-31 23:59:59.999999\', \'1 1:1:1.000002\');\n+---------------------------------------------------------+\n| ADDTIME(\'2007-12-31 23:59:59.999999\', \'1 1:1:1.000002\') |\n+---------------------------------------------------------+\n| 2008-01-02 01:01:01.000001 |\n+---------------------------------------------------------+\n\nSELECT ADDTIME(\'01:00:00.999999\', \'02:00:00.999998\');\n+-----------------------------------------------+\n| ADDTIME(\'01:00:00.999999\', \'02:00:00.999998\') |\n+-----------------------------------------------+\n| 03:00:01.999997 |\n+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/addtime/','','https://mariadb.com/kb/en/addtime/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (514,31,'CONVERT_TZ','Syntax\n------\n\nCONVERT_TZ(dt,from_tz,to_tz)\n\nDescription\n-----------\n\nCONVERT_TZ() converts a datetime value dt from the time zone given by from_tz\nto the time zone given by to_tz and returns the resulting value.\n\nIn order to use named time zones, such as GMT, MET or Africa/Johannesburg, the\ntime_zone tables must be loaded (see mysql_tzinfo_to_sql).\n\nNo conversion will take place if the value falls outside of the supported\nTIMESTAMP range (\'1970-01-01 00:00:01\' to \'2038-01-19 05:14:07\' UTC) when\nconverted from from_tz to UTC.\n\nThis function returns NULL if the arguments are invalid (or named time zones\nhave not been loaded).\n\nSee time zones for more information.\n\nExamples\n--------\n\nSELECT CONVERT_TZ(\'2016-01-01 12:00:00\',\'+00:00\',\'+10:00\');\n+-----------------------------------------------------+\n| CONVERT_TZ(\'2016-01-01 12:00:00\',\'+00:00\',\'+10:00\') |\n+-----------------------------------------------------+\n| 2016-01-01 22:00:00 |\n+-----------------------------------------------------+\n\nUsing named time zones (with the time zone tables loaded):\n\nSELECT CONVERT_TZ(\'2016-01-01 12:00:00\',\'GMT\',\'Africa/Johannesburg\');\n+---------------------------------------------------------------+\n| CONVERT_TZ(\'2016-01-01 12:00:00\',\'GMT\',\'Africa/Johannesburg\') |\n+---------------------------------------------------------------+\n| 2016-01-01 14:00:00 |\n+---------------------------------------------------------------+\n\nThe value is out of the TIMESTAMP range, so no conversion takes place:\n\nSELECT CONVERT_TZ(\'1969-12-31 22:00:00\',\'+00:00\',\'+10:00\');\n+-----------------------------------------------------+\n| CONVERT_TZ(\'1969-12-31 22:00:00\',\'+00:00\',\'+10:00\') |\n+-----------------------------------------------------+\n| 1969-12-31 22:00:00 |\n+-----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/convert_tz/','','https://mariadb.com/kb/en/convert_tz/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (515,31,'CURDATE','Syntax\n------\n\nCURDATE()\nCURRENT_DATE\nCURRENT_DATE()\n\nDescription\n-----------\n\nCURDATE returns the current date as a value in \'YYYY-MM-DD\' or YYYYMMDD\nformat, depending on whether the function is used in a string or numeric\ncontext.\n\nCURRENT_DATE and CURRENT_DATE() are synonyms.\n\nExamples\n--------\n\nSELECT CURDATE();\n+------------+\n| CURDATE() |\n+------------+\n| 2019-03-05 |\n+------------+\n\nIn a numeric context (note this is not performing date calculations):\n\nSELECT CURDATE() +0;\n+--------------+\n| CURDATE() +0 |\n+--------------+\n| 20190305 |\n+--------------+\n\nData calculation:\n\nSELECT CURDATE() - INTERVAL 5 DAY;\n+----------------------------+\n| CURDATE() - INTERVAL 5 DAY |\n+----------------------------+\n| 2019-02-28 |\n+----------------------------+\n\nURL: https://mariadb.com/kb/en/curdate/','','https://mariadb.com/kb/en/curdate/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (516,31,'CURRENT_DATE','Syntax\n------\n\nCURRENT_DATE, CURRENT_DATE()\n\nDescription\n-----------\n\nCURRENT_DATE and CURRENT_DATE() are synonyms for CURDATE().\n\nURL: https://mariadb.com/kb/en/current_date/','','https://mariadb.com/kb/en/current_date/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (517,31,'CURRENT_TIME','Syntax\n------\n\nCURRENT_TIME\nCURRENT_TIME([precision])\n\nDescription\n-----------\n\nCURRENT_TIME and CURRENT_TIME() are synonyms for CURTIME().\n\nURL: https://mariadb.com/kb/en/current_time/','','https://mariadb.com/kb/en/current_time/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (518,31,'CURRENT_TIMESTAMP','Syntax\n------\n\nCURRENT_TIMESTAMP\nCURRENT_TIMESTAMP([precision])\n\nDescription\n-----------\n\nCURRENT_TIMESTAMP and CURRENT_TIMESTAMP() are synonyms for NOW().\n\nURL: https://mariadb.com/kb/en/current_timestamp/','','https://mariadb.com/kb/en/current_timestamp/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (519,31,'CURTIME','Syntax\n------\n\nCURTIME([precision])\n\nDescription\n-----------\n\nReturns the current time as a value in \'HH:MM:SS\' or HHMMSS.uuuuuu format,\ndepending on whether the function is used in a string or numeric context. The\nvalue is expressed in the current time zone.\n\nThe optional precision determines the microsecond precision. See Microseconds\nin MariaDB.\n\nExamples\n--------\n\nSELECT CURTIME();\n+-----------+\n| CURTIME() |\n+-----------+\n| 12:45:39 |\n+-----------+\n\nSELECT CURTIME() + 0;\n+---------------+\n| CURTIME() + 0 |\n+---------------+\n| 124545.000000 |\n+---------------+\n\nWith precision:\n\nSELECT CURTIME(2);\n+-------------+\n| CURTIME(2) |\n+-------------+\n| 09:49:08.09 |\n+-------------+\n\nURL: https://mariadb.com/kb/en/curtime/','','https://mariadb.com/kb/en/curtime/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (520,31,'DATE FUNCTION','Syntax\n------\n\nDATE(expr)\n\nDescription\n-----------\n\nExtracts the date part of the date or datetime expression expr. Returns NULL\nand throws a warning when passed an invalid date.\n\nExamples\n--------\n\nSELECT DATE(\'2013-07-18 12:21:32\');\n+-----------------------------+\n| DATE(\'2013-07-18 12:21:32\') |\n+-----------------------------+\n| 2013-07-18 |\n+-----------------------------+\n\nURL: https://mariadb.com/kb/en/date-function/','','https://mariadb.com/kb/en/date-function/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (521,31,'DATEDIFF','Syntax\n------\n\nDATEDIFF(expr1,expr2)\n\nDescription\n-----------\n\nDATEDIFF() returns (expr1 – expr2) expressed as a value in days from one date\nto the other. expr1 and expr2 are date or date-and-time expressions. Only the\ndate parts of the values are used in the calculation.\n\nExamples\n--------\n\nSELECT DATEDIFF(\'2007-12-31 23:59:59\',\'2007-12-30\');\n+----------------------------------------------+\n| DATEDIFF(\'2007-12-31 23:59:59\',\'2007-12-30\') |\n+----------------------------------------------+\n| 1 |\n+----------------------------------------------+\n\nSELECT DATEDIFF(\'2010-11-30 23:59:59\',\'2010-12-31\');\n+----------------------------------------------+\n| DATEDIFF(\'2010-11-30 23:59:59\',\'2010-12-31\') |\n+----------------------------------------------+\n| -31 |\n+----------------------------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n (\"2007-01-30 21:31:07\"),\n (\"1983-10-15 06:42:51\"),\n (\"2011-04-21 12:34:56\"),\n (\"2011-10-30 06:31:41\"),\n (\"2011-01-30 14:03:25\"),\n (\"2004-10-07 11:19:34\");\n\nSELECT NOW();\n+---------------------+\n| NOW() |\n+---------------------+\n| 2011-05-23 10:56:05 |\n+---------------------+\n\nSELECT d, DATEDIFF(NOW(),d) FROM t1;\n+---------------------+-------------------+\n| d | DATEDIFF(NOW(),d) |\n+---------------------+-------------------+\n| 2007-01-30 21:31:07 | 1574 |\n| 1983-10-15 06:42:51 | 10082 |\n| 2011-04-21 12:34:56 | 32 |\n| 2011-10-30 06:31:41 | -160 |\n| 2011-01-30 14:03:25 | 113 |\n| 2004-10-07 11:19:34 | 2419 |\n+---------------------+-------------------+\n\nURL: https://mariadb.com/kb/en/datediff/','','https://mariadb.com/kb/en/datediff/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (522,31,'DATE_ADD','Syntax\n------\n\nDATE_ADD(date,INTERVAL expr unit)\n\nDescription\n-----------\n\nPerforms date arithmetic. The date argument specifies the starting date or\ndatetime value. expr is an expression specifying the interval value to be\nadded or subtracted from the starting date. expr is a string; it may start\nwith a \"-\" for negative intervals. unit is a keyword indicating the units in\nwhich the expression should be interpreted. See Date and Time Units for a\ncomplete list of permitted units.\n\nExamples\n--------\n\nSELECT \'2008-12-31 23:59:59\' + INTERVAL 1 SECOND;\n+-------------------------------------------+\n| \'2008-12-31 23:59:59\' + INTERVAL 1 SECOND |\n+-------------------------------------------+\n| 2009-01-01 00:00:00 |\n+-------------------------------------------+\n\nSELECT INTERVAL 1 DAY + \'2008-12-31\';\n+-------------------------------+\n| INTERVAL 1 DAY + \'2008-12-31\' |\n+-------------------------------+\n| 2009-01-01 |\n+-------------------------------+\n\nSELECT \'2005-01-01\' - INTERVAL 1 SECOND;\n+----------------------------------+\n| \'2005-01-01\' - INTERVAL 1 SECOND |\n+----------------------------------+\n| 2004-12-31 23:59:59 |\n+----------------------------------+\n\nSELECT DATE_ADD(\'2000-12-31 23:59:59\', INTERVAL 1 SECOND);\n+----------------------------------------------------+\n| DATE_ADD(\'2000-12-31 23:59:59\', INTERVAL 1 SECOND) |\n+----------------------------------------------------+\n| 2001-01-01 00:00:00 |\n+----------------------------------------------------+\n\nSELECT DATE_ADD(\'2010-12-31 23:59:59\', INTERVAL 1 DAY);\n+-------------------------------------------------+\n| DATE_ADD(\'2010-12-31 23:59:59\', INTERVAL 1 DAY) |\n+-------------------------------------------------+\n| 2011-01-01 23:59:59 |\n+-------------------------------------------------+\n\nSELECT DATE_ADD(\'2100-12-31 23:59:59\', INTERVAL \'1:1\' MINUTE_SECOND);\n+---------------------------------------------------------------+\n| DATE_ADD(\'2100-12-31 23:59:59\', INTERVAL \'1:1\' MINUTE_SECOND) |\n+---------------------------------------------------------------+\n| 2101-01-01 00:01:00 |\n+---------------------------------------------------------------+\n\nSELECT DATE_ADD(\'1900-01-01 00:00:00\', INTERVAL \'-1 10\' DAY_HOUR);\n+------------------------------------------------------------+\n| DATE_ADD(\'1900-01-01 00:00:00\', INTERVAL \'-1 10\' DAY_HOUR) |\n+------------------------------------------------------------+\n| 1899-12-30 14:00:00 |\n+------------------------------------------------------------+\n\nSELECT DATE_ADD(\'1992-12-31 23:59:59.000002\', INTERVAL \'1.999999\'\nSECOND_MICROSECOND);\n+------------------------------------------------------------------------------\n-+\n| DATE_ADD(\'1992-12-31 23:59:59.000002\', INTERVAL \'1.999999\'\nSECOND_MICROSECOND) |\n+------------------------------------------------------------------------------\n-+\n| 1993-01-01 00:00:01.000001 \n |\n+------------------------------------------------------------------------------\n-+\n\nURL: https://mariadb.com/kb/en/date_add/','','https://mariadb.com/kb/en/date_add/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (523,31,'DATE_FORMAT','Syntax\n------\n\nDATE_FORMAT(date, format[, locale])\n\nDescription\n-----------\n\nFormats the date value according to the format string.\n\nThe language used for the names is controlled by the value of the\nlc_time_names system variable. See server locale for more on the supported\nlocales.\n\nThe options that can be used by DATE_FORMAT(), as well as its inverse\nSTR_TO_DATE() and the FROM_UNIXTIME() function, are:\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| %a | Short weekday name in current locale |\n| | (Variable lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %b | Short form month name in current locale. For |\n| | locale en_US this is one of: |\n| | Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov |\n| | or Dec. |\n+---------------------------+------------------------------------------------+\n| %c | Month with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %D | Day with English suffix \'th\', \'nd\', \'st\' or |\n| | \'rd\'\'. (1st, 2nd, 3rd...). |\n+---------------------------+------------------------------------------------+\n| %d | Day with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %e | Day with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %f | Microseconds 6 digits. |\n+---------------------------+------------------------------------------------+\n| %H | Hour with 2 digits between 00-23. |\n+---------------------------+------------------------------------------------+\n| %h | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %I | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %i | Minute with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %j | Day of the year (001-366) |\n+---------------------------+------------------------------------------------+\n| %k | Hour with 1 digits between 0-23. |\n+---------------------------+------------------------------------------------+\n| %l | Hour with 1 digits between 1-12. |\n+---------------------------+------------------------------------------------+\n| %M | Full month name in current locale (Variable |\n| | lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %m | Month with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %p | AM/PM according to current locale (Variable |\n| | lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %r | Time in 12 hour format, followed by AM/PM. |\n| | Short for \'%I:%i:%S %p\'. |\n+---------------------------+------------------------------------------------+\n| %S | Seconds with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %s | Seconds with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %T | Time in 24 hour format. Short for \'%H:%i:%S\'. |\n+---------------------------+------------------------------------------------+\n| %U | Week number (00-53), when first day of the |\n| | week is Sunday. |\n+---------------------------+------------------------------------------------+\n| %u | Week number (00-53), when first day of the |\n| | week is Monday. |\n+---------------------------+------------------------------------------------+\n| %V | Week number (01-53), when first day of the |\n| | week is Sunday. Used with %X. |\n+---------------------------+------------------------------------------------+\n| %v | Week number (01-53), when first day of the |\n| | week is Monday. Used with %x. |\n+---------------------------+------------------------------------------------+\n| %W | Full weekday name in current locale (Variable |\n| | lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %w | Day of the week. 0 = Sunday, 6 = Saturday. |\n+---------------------------+------------------------------------------------+\n| %X | Year with 4 digits when first day of the week |\n| | is Sunday. Used with %V. |\n+---------------------------+------------------------------------------------+\n| %x | Year with 4 digits when first day of the week |\n| | is Monday. Used with %v. |\n+---------------------------+------------------------------------------------+\n| %Y | Year with 4 digits. |\n+---------------------------+------------------------------------------------+\n| %y | Year with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %# | For str_to_date(), skip all numbers. |\n+---------------------------+------------------------------------------------+\n| %. | For str_to_date(), skip all punctation |\n| | characters. |\n+---------------------------+------------------------------------------------+\n| %@ | For str_to_date(), skip all alpha characters. |\n+---------------------------+------------------------------------------------+\n| %% | A literal % character. |\n+---------------------------+------------------------------------------------+\n\nTo get a date in one of the standard formats, GET_FORMAT() can be used.\n\nExamples\n--------\n\nSELECT DATE_FORMAT(\'2009-10-04 22:23:00\', \'%W %M %Y\');\n+------------------------------------------------+\n| DATE_FORMAT(\'2009-10-04 22:23:00\', \'%W %M %Y\') |\n+------------------------------------------------+\n| Sunday October 2009 |\n+------------------------------------------------+\n\nSELECT DATE_FORMAT(\'2007-10-04 22:23:00\', \'%H:%i:%s\');\n+------------------------------------------------+\n| DATE_FORMAT(\'2007-10-04 22:23:00\', \'%H:%i:%s\') |\n+------------------------------------------------+\n| 22:23:00 |\n+------------------------------------------------+\n\nSELECT DATE_FORMAT(\'1900-10-04 22:23:00\', \'%D %y %a %d %m %b %j\');\n+------------------------------------------------------------+\n| DATE_FORMAT(\'1900-10-04 22:23:00\', \'%D %y %a %d %m %b %j\') |\n+------------------------------------------------------------+\n| 4th 00 Thu 04 10 Oct 277 |\n+------------------------------------------------------------+\n\nSELECT DATE_FORMAT(\'1997-10-04 22:23:00\', \'%H %k %I %r %T %S %w\');\n+------------------------------------------------------------+\n| DATE_FORMAT(\'1997-10-04 22:23:00\', \'%H %k %I %r %T %S %w\') |\n+------------------------------------------------------------+\n| 22 22 10 10:23:00 PM 22:23:00 00 6 |\n+------------------------------------------------------------+\n\nSELECT DATE_FORMAT(\'1999-01-01\', \'%X %V\');\n+------------------------------------+\n| DATE_FORMAT(\'1999-01-01\', \'%X %V\') |\n+------------------------------------+\n| 1998 52 |\n+------------------------------------+\n\nSELECT DATE_FORMAT(\'2006-06-00\', \'%d\');\n+---------------------------------+\n| DATE_FORMAT(\'2006-06-00\', \'%d\') |\n+---------------------------------+\n| 00 |\n+---------------------------------+\n\nOptionally, the locale can be explicitly specified as the third DATE_FORMAT()\nargument. Doing so makes the function independent from the session settings,\nand the three argument version of DATE_FORMAT() can be used in virtual indexed\nand persistent generated-columns:\n\nSELECT DATE_FORMAT(\'2006-01-01\', \'%W\', \'el_GR\');\n+------------------------------------------+\n| DATE_FORMAT(\'2006-01-01\', \'%W\', \'el_GR\') |\n+------------------------------------------+\n| Κυριακή |\n+------------------------------------------+\n\nURL: https://mariadb.com/kb/en/date_format/','','https://mariadb.com/kb/en/date_format/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (524,31,'DATE_SUB','Syntax\n------\n\nDATE_SUB(date,INTERVAL expr unit)\n\nDescription\n-----------\n\nPerforms date arithmetic. The date argument specifies the starting date or\ndatetime value. expr is an expression specifying the interval value to be\nadded or subtracted from the starting date. expr is a string; it may start\nwith a \"-\" for negative intervals. unit is a keyword indicating the units in\nwhich the expression should be interpreted. See Date and Time Units for a\ncomplete list of permitted units.\n\nSee also DATE_ADD().\n\nExamples\n--------\n\nSELECT DATE_SUB(\'1998-01-02\', INTERVAL 31 DAY);\n+-----------------------------------------+\n| DATE_SUB(\'1998-01-02\', INTERVAL 31 DAY) |\n+-----------------------------------------+\n| 1997-12-02 |\n+-----------------------------------------+\n\nSELECT DATE_SUB(\'2005-01-01 00:00:00\', INTERVAL \'1 1:1:1\' DAY_SECOND);\n+----------------------------------------------------------------+\n| DATE_SUB(\'2005-01-01 00:00:00\', INTERVAL \'1 1:1:1\' DAY_SECOND) |\n+----------------------------------------------------------------+\n| 2004-12-30 22:58:59 |\n+----------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/date_sub/','','https://mariadb.com/kb/en/date_sub/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (525,31,'DAY','Syntax\n------\n\nDAY(date)\n\nDescription\n-----------\n\nDAY() is a synonym for DAYOFMONTH().\n\nURL: https://mariadb.com/kb/en/day/','','https://mariadb.com/kb/en/day/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (526,31,'DAYNAME','Syntax\n------\n\nDAYNAME(date)\n\nDescription\n-----------\n\nReturns the name of the weekday for date. The language used for the name is\ncontrolled by the value of the lc_time_names system variable. See server\nlocale for more on the supported locales.\n\nExamples\n--------\n\nSELECT DAYNAME(\'2007-02-03\');\n+-----------------------+\n| DAYNAME(\'2007-02-03\') |\n+-----------------------+\n| Saturday |\n+-----------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n (\"2007-01-30 21:31:07\"),\n (\"1983-10-15 06:42:51\"),\n (\"2011-04-21 12:34:56\"),\n (\"2011-10-30 06:31:41\"),\n (\"2011-01-30 14:03:25\"),\n (\"2004-10-07 11:19:34\");\n\nSELECT d, DAYNAME(d) FROM t1;\n+---------------------+------------+\n| d | DAYNAME(d) |\n+---------------------+------------+\n| 2007-01-30 21:31:07 | Tuesday |\n| 1983-10-15 06:42:51 | Saturday |\n| 2011-04-21 12:34:56 | Thursday |\n| 2011-10-30 06:31:41 | Sunday |\n| 2011-01-30 14:03:25 | Sunday |\n| 2004-10-07 11:19:34 | Thursday |\n+---------------------+------------+\n\nChanging the locale:\n\nSET lc_time_names = \'fr_CA\';\n\nSELECT DAYNAME(\'2013-04-01\');\n+-----------------------+\n| DAYNAME(\'2013-04-01\') |\n+-----------------------+\n| lundi |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/dayname/','','https://mariadb.com/kb/en/dayname/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (527,31,'DAYOFMONTH','Syntax\n------\n\nDAYOFMONTH(date)\n\nDescription\n-----------\n\nReturns the day of the month for date, in the range 1 to 31, or 0 for dates\nsuch as \'0000-00-00\' or \'2008-00-00\' which have a zero day part.\n\nDAY() is a synonym.\n\nExamples\n--------\n\nSELECT DAYOFMONTH(\'2007-02-03\');\n+--------------------------+\n| DAYOFMONTH(\'2007-02-03\') |\n+--------------------------+\n| 3 |\n+--------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n (\"2007-01-30 21:31:07\"),\n (\"1983-10-15 06:42:51\"),\n (\"2011-04-21 12:34:56\"),\n (\"2011-10-30 06:31:41\"),\n (\"2011-01-30 14:03:25\"),\n (\"2004-10-07 11:19:34\");\n\nSELECT d FROM t1 where DAYOFMONTH(d) = 30;\n+---------------------+\n| d |\n+---------------------+\n| 2007-01-30 21:31:07 |\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/dayofmonth/','','https://mariadb.com/kb/en/dayofmonth/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (528,31,'DAYOFWEEK','Syntax\n------\n\nDAYOFWEEK(date)\n\nDescription\n-----------\n\nReturns the day of the week index for the date (1 = Sunday, 2 = Monday, ..., 7\n= Saturday). These index values correspond to the ODBC standard.\n\nThis contrasts with WEEKDAY() which follows a different index numbering (0 =\nMonday, 1 = Tuesday, ... 6 = Sunday).\n\nExamples\n--------\n\nSELECT DAYOFWEEK(\'2007-02-03\');\n+-------------------------+\n| DAYOFWEEK(\'2007-02-03\') |\n+-------------------------+\n| 7 |\n+-------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n (\"2007-01-30 21:31:07\"),\n (\"1983-10-15 06:42:51\"),\n (\"2011-04-21 12:34:56\"),\n (\"2011-10-30 06:31:41\"),\n (\"2011-01-30 14:03:25\"),\n (\"2004-10-07 11:19:34\");\n\nSELECT d, DAYNAME(d), DAYOFWEEK(d), WEEKDAY(d) from t1;\n+---------------------+------------+--------------+------------+\n| d | DAYNAME(d) | DAYOFWEEK(d) | WEEKDAY(d) |\n+---------------------+------------+--------------+------------+\n| 2007-01-30 21:31:07 | Tuesday | 3 | 1 |\n| 1983-10-15 06:42:51 | Saturday | 7 | 5 |\n| 2011-04-21 12:34:56 | Thursday | 5 | 3 |\n| 2011-10-30 06:31:41 | Sunday | 1 | 6 |\n| 2011-01-30 14:03:25 | Sunday | 1 | 6 |\n| 2004-10-07 11:19:34 | Thursday | 5 | 3 |\n+---------------------+------------+--------------+------------+\n\nURL: https://mariadb.com/kb/en/dayofweek/','','https://mariadb.com/kb/en/dayofweek/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (529,31,'DAYOFYEAR','Syntax\n------\n\nDAYOFYEAR(date)\n\nDescription\n-----------\n\nReturns the day of the year for date, in the range 1 to 366.\n\nExamples\n--------\n\nSELECT DAYOFYEAR(\'2018-02-16\');\n+-------------------------+\n| DAYOFYEAR(\'2018-02-16\') |\n+-------------------------+\n| 47 |\n+-------------------------+\n\nURL: https://mariadb.com/kb/en/dayofyear/','','https://mariadb.com/kb/en/dayofyear/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (530,31,'EXTRACT','Syntax\n------\n\nEXTRACT(unit FROM date)\n\nDescription\n-----------\n\nThe EXTRACT() function extracts the required unit from the date. See Date and\nTime Units for a complete list of permitted units.\n\nIn MariaDB 10.0.7 and MariaDB 5.5.35, EXTRACT (HOUR FROM ...) was changed to\nreturn a value from 0 to 23, adhering to the SQL standard. Until MariaDB\n10.0.6 and MariaDB 5.5.34, and in all versions of MySQL at least as of MySQL\n5.7, it could return a value > 23. HOUR() is not a standard function, so\ncontinues to adhere to the old behaviour inherited from MySQL.\n\nExamples\n--------\n\nSELECT EXTRACT(YEAR FROM \'2009-07-02\');\n+---------------------------------+\n| EXTRACT(YEAR FROM \'2009-07-02\') |\n+---------------------------------+\n| 2009 |\n+---------------------------------+\n\nSELECT EXTRACT(YEAR_MONTH FROM \'2009-07-02 01:02:03\');\n+------------------------------------------------+\n| EXTRACT(YEAR_MONTH FROM \'2009-07-02 01:02:03\') |\n+------------------------------------------------+\n| 200907 |\n+------------------------------------------------+\n\nSELECT EXTRACT(DAY_MINUTE FROM \'2009-07-02 01:02:03\');\n+------------------------------------------------+\n| EXTRACT(DAY_MINUTE FROM \'2009-07-02 01:02:03\') |\n+------------------------------------------------+\n| 20102 |\n+------------------------------------------------+\n\nSELECT EXTRACT(MICROSECOND FROM \'2003-01-02 10:30:00.000123\');\n+--------------------------------------------------------+\n| EXTRACT(MICROSECOND FROM \'2003-01-02 10:30:00.000123\') |\n+--------------------------------------------------------+\n| 123 |\n+--------------------------------------------------------+\n\nFrom MariaDB 10.0.7 and MariaDB 5.5.35, EXTRACT (HOUR FROM...) returns a value\nfrom 0 to 23, as per the SQL standard. HOUR is not a standard function, so\ncontinues to adhere to the old behaviour inherited from MySQL.\n\nSELECT EXTRACT(HOUR FROM \'26:30:00\'), HOUR(\'26:30:00\');\n+-------------------------------+------------------+\n| EXTRACT(HOUR FROM \'26:30:00\') | HOUR(\'26:30:00\') |\n+-------------------------------+------------------+\n| 2 | 26 |\n+-------------------------------+------------------+\n\nURL: https://mariadb.com/kb/en/extract/','','https://mariadb.com/kb/en/extract/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (531,31,'FROM_DAYS','Syntax\n------\n\nFROM_DAYS(N)\n\nDescription\n-----------\n\nGiven a day number N, returns a DATE value. The day count is based on the\nnumber of days from the start of the standard calendar (0000-00-00).\n\nThe function is not designed for use with dates before the advent of the\nGregorian calendar in October 1582. Results will not be reliable since it\ndoesn\'t account for the lost days when the calendar changed from the Julian\ncalendar.\n\nThis is the converse of the TO_DAYS() function.\n\nExamples\n--------\n\nSELECT FROM_DAYS(730669);\n+-------------------+\n| FROM_DAYS(730669) |\n+-------------------+\n| 2000-07-03 |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/from_days/','','https://mariadb.com/kb/en/from_days/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (532,31,'FROM_UNIXTIME','Syntax\n------\n\nFROM_UNIXTIME(unix_timestamp), FROM_UNIXTIME(unix_timestamp,format)\n\nDescription\n-----------\n\nReturns a representation of the unix_timestamp argument as a value in\n\'YYYY-MM-DD HH:MM:SS\' or YYYYMMDDHHMMSS.uuuuuu format, depending on whether\nthe function is used in a string or numeric context. The value is expressed in\nthe current time zone. unix_timestamp is an internal timestamp value such as\nis produced by the UNIX_TIMESTAMP() function.\n\nIf format is given, the result is formatted according to the format string,\nwhich is used the same way as listed in the entry for the DATE_FORMAT()\nfunction.\n\nTimestamps in MariaDB have a maximum value of 2147483647, equivalent to\n2038-01-19 05:14:07. This is due to the underlying 32-bit limitation. Using\nthe function on a timestamp beyond this will result in NULL being returned.\nUse DATETIME as a storage type if you require dates beyond this.\n\nThe options that can be used by FROM_UNIXTIME(), as well as DATE_FORMAT() and\nSTR_TO_DATE(), are:\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| %a | Short weekday name in current locale |\n| | (Variable lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %b | Short form month name in current locale. For |\n| | locale en_US this is one of: |\n| | Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov |\n| | or Dec. |\n+---------------------------+------------------------------------------------+\n| %c | Month with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %D | Day with English suffix \'th\', \'nd\', \'st\' or |\n| | \'rd\'\'. (1st, 2nd, 3rd...). |\n+---------------------------+------------------------------------------------+\n| %d | Day with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %e | Day with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %f | Microseconds 6 digits. |\n+---------------------------+------------------------------------------------+\n| %H | Hour with 2 digits between 00-23. |\n+---------------------------+------------------------------------------------+\n| %h | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %I | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %i | Minute with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %j | Day of the year (001-366) |\n+---------------------------+------------------------------------------------+\n| %k | Hour with 1 digits between 0-23. |\n+---------------------------+------------------------------------------------+\n| %l | Hour with 1 digits between 1-12. |\n+---------------------------+------------------------------------------------+\n| %M | Full month name in current locale (Variable |\n| | lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %m | Month with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %p | AM/PM according to current locale (Variable |\n| | lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %r | Time in 12 hour format, followed by AM/PM. |\n| | Short for \'%I:%i:%S %p\'. |\n+---------------------------+------------------------------------------------+\n| %S | Seconds with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %s | Seconds with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %T | Time in 24 hour format. Short for \'%H:%i:%S\'. |\n+---------------------------+------------------------------------------------+\n| %U | Week number (00-53), when first day of the |\n| | week is Sunday. |\n+---------------------------+------------------------------------------------+\n| %u | Week number (00-53), when first day of the |\n| | week is Monday. |\n+---------------------------+------------------------------------------------+\n| %V | Week number (01-53), when first day of the |\n| | week is Sunday. Used with %X. |\n+---------------------------+------------------------------------------------+\n| %v | Week number (01-53), when first day of the |\n| | week is Monday. Used with %x. |\n+---------------------------+------------------------------------------------+\n| %W | Full weekday name in current locale (Variable |\n| | lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %w | Day of the week. 0 = Sunday, 6 = Saturday. |\n+---------------------------+------------------------------------------------+\n| %X | Year with 4 digits when first day of the week |\n| | is Sunday. Used with %V. |\n+---------------------------+------------------------------------------------+\n| %x | Year with 4 digits when first day of the week |\n| | is Sunday. Used with %v. |\n+---------------------------+------------------------------------------------+\n| %Y | Year with 4 digits. |\n+---------------------------+------------------------------------------------+\n| %y | Year with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %# | For str_to_date(), skip all numbers. |\n+---------------------------+------------------------------------------------+\n| %. | For str_to_date(), skip all punctation |\n| | characters. |\n+---------------------------+------------------------------------------------+\n| %@ | For str_to_date(), skip all alpha characters. |\n+---------------------------+------------------------------------------------+\n| %% | A literal % character. |\n+---------------------------+------------------------------------------------+\n\nPerformance Considerations\n--------------------------\n\nIf your session time zone is set to SYSTEM (the default), FROM_UNIXTIME() will\ncall the OS function to convert the data using the system time zone. At least\non Linux, the corresponding function (localtime_r) uses a global mutex inside\nglibc that can cause contention under high concurrent load.\n\nSet your time zone to a named time zone to avoid this issue. See mysql time\nzone tables for details on how to do this.\n\nExamples\n--------\n\nSELECT FROM_UNIXTIME(1196440219);\n+---------------------------+\n| FROM_UNIXTIME(1196440219) |\n+---------------------------+\n| 2007-11-30 11:30:19 |\n+---------------------------+\n\nSELECT FROM_UNIXTIME(1196440219) + 0;\n+-------------------------------+\n| FROM_UNIXTIME(1196440219) + 0 |\n+-------------------------------+\n| 20071130113019.000000 |\n+-------------------------------+\n\nSELECT FROM_UNIXTIME(UNIX_TIMESTAMP(), \'%Y %D %M %h:%i:%s %x\');\n+---------------------------------------------------------+\n| FROM_UNIXTIME(UNIX_TIMESTAMP(), \'%Y %D %M %h:%i:%s %x\') |\n+---------------------------------------------------------+\n| 2010 27th March 01:03:47 2010 |\n+---------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/from_unixtime/','','https://mariadb.com/kb/en/from_unixtime/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (533,31,'GET_FORMAT','Syntax\n------\n\nGET_FORMAT({DATE|DATETIME|TIME}, {\'EUR\'|\'USA\'|\'JIS\'|\'ISO\'|\'INTERNAL\'})\n\nDescription\n-----------\n\nReturns a format string. This function is useful in combination with the\nDATE_FORMAT() and the STR_TO_DATE() functions.\n\nPossible result formats are:\n\n+--------------------------------------+--------------------------------------+\n| Function Call | Result Format |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATE,\'EUR\') | \'%d.%m.%Y\' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATE,\'USA\') | \'%m.%d.%Y\' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATE,\'JIS\') | \'%Y-%m-%d\' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATE,\'ISO\') | \'%Y-%m-%d\' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATE,\'INTERNAL\') | \'%Y%m%d\' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATETIME,\'EUR\') | \'%Y-%m-%d %H.%i.%s\' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATETIME,\'USA\') | \'%Y-%m-%d %H.%i.%s\' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATETIME,\'JIS\') | \'%Y-%m-%d %H:%i:%s\' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATETIME,\'ISO\') | \'%Y-%m-%d %H:%i:%s\' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATETIME,\'INTERNAL\') | \'%Y%m%d%H%i%s\' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(TIME,\'EUR\') | \'%H.%i.%s\' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(TIME,\'USA\') | \'%h:%i:%s %p\' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(TIME,\'JIS\') | \'%H:%i:%s\' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(TIME,\'ISO\') | \'%H:%i:%s\' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(TIME,\'INTERNAL\') | \'%H%i%s\' |\n+--------------------------------------+--------------------------------------+\n\nExamples\n--------\n\nObtaining the string matching to the standard European date format:\n\nSELECT GET_FORMAT(DATE, \'EUR\');\n+-------------------------+\n| GET_FORMAT(DATE, \'EUR\') |\n+-------------------------+\n| %d.%m.%Y |\n+-------------------------+\n\nUsing the same string to format a date:\n\nSELECT DATE_FORMAT(\'2003-10-03\',GET_FORMAT(DATE,\'EUR\'));\n+--------------------------------------------------+\n| DATE_FORMAT(\'2003-10-03\',GET_FORMAT(DATE,\'EUR\')) |\n+--------------------------------------------------+\n| 03.10.2003 |\n+--------------------------------------------------+\n\nSELECT STR_TO_DATE(\'10.31.2003\',GET_FORMAT(DATE,\'USA\'));\n+--------------------------------------------------+\n| STR_TO_DATE(\'10.31.2003\',GET_FORMAT(DATE,\'USA\')) |\n+--------------------------------------------------+\n| 2003-10-31 |\n+--------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/get_format/','','https://mariadb.com/kb/en/get_format/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (534,31,'HOUR','Syntax\n------\n\nHOUR(time)\n\nDescription\n-----------\n\nReturns the hour for time. The range of the return value is 0 to 23 for\ntime-of-day values. However, the range of TIME values actually is much larger,\nso HOUR can return values greater than 23.\n\nThe return value is always positive, even if a negative TIME value is provided.\n\nExamples\n--------\n\nSELECT HOUR(\'10:05:03\');\n+------------------+\n| HOUR(\'10:05:03\') |\n+------------------+\n| 10 |\n+------------------+\n\nSELECT HOUR(\'272:59:59\');\n+-------------------+\n| HOUR(\'272:59:59\') |\n+-------------------+\n| 272 |\n+-------------------+\n\nDifference between EXTRACT (HOUR FROM ...) (>= MariaDB 10.0.7 and MariaDB\n5.5.35) and HOUR:\n\nSELECT EXTRACT(HOUR FROM \'26:30:00\'), HOUR(\'26:30:00\');\n+-------------------------------+------------------+\n| EXTRACT(HOUR FROM \'26:30:00\') | HOUR(\'26:30:00\') |\n+-------------------------------+------------------+\n| 2 | 26 |\n+-------------------------------+------------------+\n\nURL: https://mariadb.com/kb/en/hour/','','https://mariadb.com/kb/en/hour/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (535,31,'LAST_DAY','Syntax\n------\n\nLAST_DAY(date)\n\nDescription\n-----------\n\nTakes a date or datetime value and returns the corresponding value for the\nlast day of the month. Returns NULL if the argument is invalid.\n\nExamples\n--------\n\nSELECT LAST_DAY(\'2003-02-05\');\n+------------------------+\n| LAST_DAY(\'2003-02-05\') |\n+------------------------+\n| 2003-02-28 |\n+------------------------+\n\nSELECT LAST_DAY(\'2004-02-05\');\n+------------------------+\n| LAST_DAY(\'2004-02-05\') |\n+------------------------+\n| 2004-02-29 |\n+------------------------+\n\nSELECT LAST_DAY(\'2004-01-01 01:01:01\');\n+---------------------------------+\n| LAST_DAY(\'2004-01-01 01:01:01\') |\n+---------------------------------+\n| 2004-01-31 |\n+---------------------------------+\n\nSELECT LAST_DAY(\'2003-03-32\');\n+------------------------+\n| LAST_DAY(\'2003-03-32\') |\n+------------------------+\n| NULL |\n+------------------------+\n1 row in set, 1 warning (0.00 sec)\n\nWarning (Code 1292): Incorrect datetime value: \'2003-03-32\'\n\nURL: https://mariadb.com/kb/en/last_day/','','https://mariadb.com/kb/en/last_day/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (536,31,'LOCALTIME','Syntax\n------\n\nLOCALTIME\nLOCALTIME([precision])\n\nDescription\n-----------\n\nLOCALTIME and LOCALTIME() are synonyms for NOW().\n\nURL: https://mariadb.com/kb/en/localtime/','','https://mariadb.com/kb/en/localtime/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (537,31,'LOCALTIMESTAMP','Syntax\n------\n\nLOCALTIMESTAMP\nLOCALTIMESTAMP([precision])\n\nDescription\n-----------\n\nLOCALTIMESTAMP and LOCALTIMESTAMP() are synonyms for NOW().\n\nURL: https://mariadb.com/kb/en/localtimestamp/','','https://mariadb.com/kb/en/localtimestamp/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (538,31,'MAKEDATE','Syntax\n------\n\nMAKEDATE(year,dayofyear)\n\nDescription\n-----------\n\nReturns a date, given year and day-of-year values. dayofyear must be greater\nthan 0 or the result is NULL.\n\nExamples\n--------\n\nSELECT MAKEDATE(2011,31), MAKEDATE(2011,32);\n+-------------------+-------------------+\n| MAKEDATE(2011,31) | MAKEDATE(2011,32) |\n+-------------------+-------------------+\n| 2011-01-31 | 2011-02-01 |\n+-------------------+-------------------+\n\nSELECT MAKEDATE(2011,365), MAKEDATE(2014,365);\n+--------------------+--------------------+\n| MAKEDATE(2011,365) | MAKEDATE(2014,365) |\n+--------------------+--------------------+\n| 2011-12-31 | 2014-12-31 |\n+--------------------+--------------------+\n\nSELECT MAKEDATE(2011,0);\n+------------------+\n| MAKEDATE(2011,0) |\n+------------------+\n| NULL |\n+------------------+\n\nURL: https://mariadb.com/kb/en/makedate/','','https://mariadb.com/kb/en/makedate/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (539,31,'MAKETIME','Syntax\n------\n\nMAKETIME(hour,minute,second)\n\nDescription\n-----------\n\nReturns a time value calculated from the hour, minute, and second arguments.\n\nIf minute or second are out of the range 0 to 60, NULL is returned. The hour\ncan be in the range -838 to 838, outside of which the value is truncated with\na warning.\n\nExamples\n--------\n\nSELECT MAKETIME(13,57,33);\n+--------------------+\n| MAKETIME(13,57,33) |\n+--------------------+\n| 13:57:33 |\n+--------------------+\n\nSELECT MAKETIME(-13,57,33);\n+---------------------+\n| MAKETIME(-13,57,33) |\n+---------------------+\n| -13:57:33 |\n+---------------------+\n\nSELECT MAKETIME(13,67,33);\n+--------------------+\n| MAKETIME(13,67,33) |\n+--------------------+\n| NULL |\n+--------------------+\n\nSELECT MAKETIME(-1000,57,33);\n+-----------------------+\n| MAKETIME(-1000,57,33) |\n+-----------------------+\n| -838:59:59 |\n+-----------------------+\n1 row in set, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+---------+------+-----------------------------------------------+\n| Level | Code | Message |\n+---------+------+-----------------------------------------------+\n| Warning | 1292 | Truncated incorrect time value: \'-1000:57:33\' |\n+---------+------+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/maketime/','','https://mariadb.com/kb/en/maketime/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (540,31,'MICROSECOND','Syntax\n------\n\nMICROSECOND(expr)\n\nDescription\n-----------\n\nReturns the microseconds from the time or datetime expression expr as a number\nin the range from 0 to 999999.\n\nIf expr is a time with no microseconds, zero is returned, while if expr is a\ndate with no time, zero with a warning is returned.\n\nExamples\n--------\n\nSELECT MICROSECOND(\'12:00:00.123456\');\n+--------------------------------+\n| MICROSECOND(\'12:00:00.123456\') |\n+--------------------------------+\n| 123456 |\n+--------------------------------+\n\nSELECT MICROSECOND(\'2009-12-31 23:59:59.000010\');\n+-------------------------------------------+\n| MICROSECOND(\'2009-12-31 23:59:59.000010\') |\n+-------------------------------------------+\n| 10 |\n+-------------------------------------------+\n\nSELECT MICROSECOND(\'2013-08-07 12:13:14\');\n+------------------------------------+\n| MICROSECOND(\'2013-08-07 12:13:14\') |\n+------------------------------------+\n| 0 |\n+------------------------------------+\n\nSELECT MICROSECOND(\'2013-08-07\');\n+---------------------------+\n| MICROSECOND(\'2013-08-07\') |\n+---------------------------+\n| 0 |\n+---------------------------+\n1 row in set, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+---------+------+----------------------------------------------+\n| Level | Code | Message |\n+---------+------+----------------------------------------------+\n| Warning | 1292 | Truncated incorrect time value: \'2013-08-07\' |\n+---------+------+----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/microsecond/','','https://mariadb.com/kb/en/microsecond/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (541,31,'MINUTE','Syntax\n------\n\nMINUTE(time)\n\nDescription\n-----------\n\nReturns the minute for time, in the range 0 to 59.\n\nExamples\n--------\n\nSELECT MINUTE(\'2013-08-03 11:04:03\');\n+-------------------------------+\n| MINUTE(\'2013-08-03 11:04:03\') |\n+-------------------------------+\n| 4 |\n+-------------------------------+\n\nSELECT MINUTE (\'23:12:50\');\n+---------------------+\n| MINUTE (\'23:12:50\') |\n+---------------------+\n| 12 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/minute/','','https://mariadb.com/kb/en/minute/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (542,31,'MONTH','Syntax\n------\n\nMONTH(date)\n\nDescription\n-----------\n\nReturns the month for date in the range 1 to 12 for January to December, or 0\nfor dates such as \'0000-00-00\' or \'2008-00-00\' that have a zero month part.\n\nExamples\n--------\n\nSELECT MONTH(\'2019-01-03\');\n+---------------------+\n| MONTH(\'2019-01-03\') |\n+---------------------+\n| 1 |\n+---------------------+\n\nSELECT MONTH(\'2019-00-03\');\n+---------------------+\n| MONTH(\'2019-00-03\') |\n+---------------------+\n| 0 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/month/','','https://mariadb.com/kb/en/month/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (543,31,'MONTHNAME','Syntax\n------\n\nMONTHNAME(date)\n\nDescription\n-----------\n\nReturns the full name of the month for date. The language used for the name is\ncontrolled by the value of the lc_time_names system variable. See server\nlocale for more on the supported locales.\n\nExamples\n--------\n\nSELECT MONTHNAME(\'2019-02-03\');\n+-------------------------+\n| MONTHNAME(\'2019-02-03\') |\n+-------------------------+\n| February |\n+-------------------------+\n\nChanging the locale:\n\nSET lc_time_names = \'fr_CA\';\n\nSELECT MONTHNAME(\'2019-05-21\');\n+-------------------------+\n| MONTHNAME(\'2019-05-21\') |\n+-------------------------+\n| mai |\n+-------------------------+\n\nURL: https://mariadb.com/kb/en/monthname/','','https://mariadb.com/kb/en/monthname/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (544,31,'NOW','Syntax\n------\n\nNOW([precision])\nCURRENT_TIMESTAMP\nCURRENT_TIMESTAMP([precision])\nLOCALTIME, LOCALTIME([precision])\nLOCALTIMESTAMP\nLOCALTIMESTAMP([precision])\n\nDescription\n-----------\n\nReturns the current date and time as a value in \'YYYY-MM-DD HH:MM:SS\' or\nYYYYMMDDHHMMSS.uuuuuu format, depending on whether the function is used in a\nstring or numeric context. The value is expressed in the current time zone.\n\nThe optional precision determines the microsecond precision. See Microseconds\nin MariaDB.\n\nNOW() (or its synonyms) can be used as the default value for TIMESTAMP columns\nas well as, since MariaDB 10.0.1, DATETIME columns. Before MariaDB 10.0.1, it\nwas only possible for a single TIMESTAMP column per table to contain the\nCURRENT_TIMESTAMP as its default.\n\nWhen displayed in the INFORMATION_SCHEMA.COLUMNS table, a default CURRENT\nTIMESTAMP is displayed as CURRENT_TIMESTAMP up until MariaDB 10.2.2, and as\ncurrent_timestamp() from MariaDB 10.2.3, due to to MariaDB 10.2 accepting\nexpressions in the DEFAULT clause.\n\nChanging the timestamp system variable with a SET timestamp statement affects\nthe value returned by NOW(), but not by SYSDATE().\n\nExamples\n--------\n\nSELECT NOW();\n+---------------------+\n| NOW() |\n+---------------------+\n| 2010-03-27 13:13:25 |\n+---------------------+\n\nSELECT NOW() + 0;\n+-----------------------+\n| NOW() + 0 |\n+-----------------------+\n| 20100327131329.000000 |\n+-----------------------+\n\nWith precision:\n\nSELECT CURRENT_TIMESTAMP(2);\n+------------------------+\n| CURRENT_TIMESTAMP(2) |\n+------------------------+\n| 2018-07-10 09:47:26.24 |\n+------------------------+\n\nUsed as a default TIMESTAMP:\n\nCREATE TABLE t (createdTS TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);\n\nFrom MariaDB 10.2.2:\n\nSELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=\'test\'\n AND COLUMN_NAME LIKE \'%ts%\'\\G\n*************************** 1. row ***************************\n TABLE_CATALOG: def\n TABLE_SCHEMA: test\n TABLE_NAME: t\n COLUMN_NAME: ts\n ORDINAL_POSITION: 1\n COLUMN_DEFAULT: current_timestamp()\n...\n\n<= MariaDB 10.2.1\n\nSELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=\'test\'\n AND COLUMN_NAME LIKE \'%ts%\'\\G\n*************************** 1. row ***************************\n TABLE_CATALOG: def\n TABLE_SCHEMA: test\n TABLE_NAME: t\n COLUMN_NAME: createdTS\n ORDINAL_POSITION: 1\n COLUMN_DEFAULT: CURRENT_TIMESTAMP\n...\n\nURL: https://mariadb.com/kb/en/now/','','https://mariadb.com/kb/en/now/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (545,31,'PERIOD_ADD','Syntax\n------\n\nPERIOD_ADD(P,N)\n\nDescription\n-----------\n\nAdds N months to period P. P is in the format YYMM or YYYYMM, and is not a\ndate value. If P contains a two-digit year, values from 00 to 69 are converted\nto from 2000 to 2069, while values from 70 are converted to 1970 upwards.\n\nReturns a value in the format YYYYMM.\n\nExamples\n--------\n\nSELECT PERIOD_ADD(200801,2);\n+----------------------+\n| PERIOD_ADD(200801,2) |\n+----------------------+\n| 200803 |\n+----------------------+\n\nSELECT PERIOD_ADD(6910,2);\n+--------------------+\n| PERIOD_ADD(6910,2) |\n+--------------------+\n| 206912 |\n+--------------------+\n\nSELECT PERIOD_ADD(7010,2);\n+--------------------+\n| PERIOD_ADD(7010,2) |\n+--------------------+\n| 197012 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/period_add/','','https://mariadb.com/kb/en/period_add/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (546,31,'PERIOD_DIFF','Syntax\n------\n\nPERIOD_DIFF(P1,P2)\n\nDescription\n-----------\n\nReturns the number of months between periods P1 and P2. P1 and P2 can be in\nthe format YYMM or YYYYMM, and are not date values.\n\nIf P1 or P2 contains a two-digit year, values from 00 to 69 are converted to\nfrom 2000 to 2069, while values from 70 are converted to 1970 upwards.\n\nExamples\n--------\n\nSELECT PERIOD_DIFF(200802,200703);\n+----------------------------+\n| PERIOD_DIFF(200802,200703) |\n+----------------------------+\n| 11 |\n+----------------------------+\n\nSELECT PERIOD_DIFF(6902,6803);\n+------------------------+\n| PERIOD_DIFF(6902,6803) |\n+------------------------+\n| 11 |\n+------------------------+\n\nSELECT PERIOD_DIFF(7002,6803);\n+------------------------+\n| PERIOD_DIFF(7002,6803) |\n+------------------------+\n| -1177 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/period_diff/','','https://mariadb.com/kb/en/period_diff/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (547,31,'QUARTER','Syntax\n------\n\nQUARTER(date)\n\nDescription\n-----------\n\nReturns the quarter of the year for date, in the range 1 to 4. Returns 0 if\nmonth contains a zero value, or NULL if the given value is not otherwise a\nvalid date (zero values are accepted).\n\nExamples\n--------\n\nSELECT QUARTER(\'2008-04-01\');\n+-----------------------+\n| QUARTER(\'2008-04-01\') |\n+-----------------------+\n| 2 |\n+-----------------------+\n\nSELECT QUARTER(\'2019-00-01\');\n+-----------------------+\n| QUARTER(\'2019-00-01\') |\n+-----------------------+\n| 0 |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/quarter/','','https://mariadb.com/kb/en/quarter/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (548,31,'SECOND','Syntax\n------\n\nSECOND(time)\n\nDescription\n-----------\n\nReturns the second for a given time (which can include microseconds), in the\nrange 0 to 59, or NULL if not given a valid time value.\n\nExamples\n--------\n\nSELECT SECOND(\'10:05:03\');\n+--------------------+\n| SECOND(\'10:05:03\') |\n+--------------------+\n| 3 |\n+--------------------+\n\nSELECT SECOND(\'10:05:01.999999\');\n+---------------------------+\n| SECOND(\'10:05:01.999999\') |\n+---------------------------+\n| 1 |\n+---------------------------+\n\nURL: https://mariadb.com/kb/en/second/','','https://mariadb.com/kb/en/second/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (549,31,'SEC_TO_TIME','Syntax\n------\n\nSEC_TO_TIME(seconds)\n\nDescription\n-----------\n\nReturns the seconds argument, converted to hours, minutes, and seconds, as a\nTIME value. The range of the result is constrained to that of the TIME data\ntype. A warning occurs if the argument corresponds to a value outside that\nrange.\n\nThe time will be returned in the format hh:mm:ss, or hhmmss if used in a\nnumeric calculation.\n\nExamples\n--------\n\nSELECT SEC_TO_TIME(12414);\n+--------------------+\n| SEC_TO_TIME(12414) |\n+--------------------+\n| 03:26:54 |\n+--------------------+\n\nSELECT SEC_TO_TIME(12414)+0;\n+----------------------+\n| SEC_TO_TIME(12414)+0 |\n+----------------------+\n| 32654 |\n+----------------------+\n\nSELECT SEC_TO_TIME(9999999);\n+----------------------+\n| SEC_TO_TIME(9999999) |\n+----------------------+\n| 838:59:59 |\n+----------------------+\n1 row in set, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+---------+------+-------------------------------------------+\n| Level | Code | Message |\n+---------+------+-------------------------------------------+\n| Warning | 1292 | Truncated incorrect time value: \'9999999\' |\n+---------+------+-------------------------------------------+\n\nURL: https://mariadb.com/kb/en/sec_to_time/','','https://mariadb.com/kb/en/sec_to_time/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (550,31,'STR_TO_DATE','Syntax\n------\n\nSTR_TO_DATE(str,format)\n\nDescription\n-----------\n\nThis is the inverse of the DATE_FORMAT() function. It takes a string str and a\nformat string format. STR_TO_DATE() returns a DATETIME value if the format\nstring contains both date and time parts, or a DATE or TIME value if the\nstring contains only date or time parts.\n\nThe date, time, or datetime values contained in str should be given in the\nformat indicated by format. If str contains an illegal date, time, or datetime\nvalue, STR_TO_DATE() returns NULL. An illegal value also produces a warning.\n\nUnder specific SQL_MODE settings an error may also be generated if the str\nisn\'t a valid date:\n\n* ALLOW_INVALID_DATES\n* NO_ZERO_DATE\n* NO_ZERO_IN_DATE\n\nThe options that can be used by STR_TO_DATE(), as well as its inverse\nDATE_FORMAT() and the FROM_UNIXTIME() function, are:\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| %a | Short weekday name in current locale |\n| | (Variable lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %b | Short form month name in current locale. For |\n| | locale en_US this is one of: |\n| | Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov |\n| | or Dec. |\n+---------------------------+------------------------------------------------+\n| %c | Month with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %D | Day with English suffix \'th\', \'nd\', \'st\' or |\n| | \'rd\'\'. (1st, 2nd, 3rd...). |\n+---------------------------+------------------------------------------------+\n| %d | Day with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %e | Day with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %f | Microseconds 6 digits. |\n+---------------------------+------------------------------------------------+\n| %H | Hour with 2 digits between 00-23. |\n+---------------------------+------------------------------------------------+\n| %h | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %I | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %i | Minute with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %j | Day of the year (001-366) |\n+---------------------------+------------------------------------------------+\n| %k | Hour with 1 digits between 0-23. |\n+---------------------------+------------------------------------------------+\n| %l | Hour with 1 digits between 1-12. |\n+---------------------------+------------------------------------------------+\n| %M | Full month name in current locale (Variable |\n| | lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %m | Month with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %p | AM/PM according to current locale (Variable |\n| | lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %r | Time in 12 hour format, followed by AM/PM. |\n| | Short for \'%I:%i:%S %p\'. |\n+---------------------------+------------------------------------------------+\n| %S | Seconds with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %s | Seconds with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %T | Time in 24 hour format. Short for \'%H:%i:%S\'. |\n+---------------------------+------------------------------------------------+\n| %U | Week number (00-53), when first day of the |\n| | week is Sunday. |\n+---------------------------+------------------------------------------------+\n| %u | Week number (00-53), when first day of the |\n| | week is Monday. |\n+---------------------------+------------------------------------------------+\n| %V | Week number (01-53), when first day of the |\n| | week is Sunday. Used with %X. |\n+---------------------------+------------------------------------------------+\n| %v | Week number (01-53), when first day of the |\n| | week is Monday. Used with %x. |\n+---------------------------+------------------------------------------------+\n| %W | Full weekday name in current locale (Variable |\n| | lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %w | Day of the week. 0 = Sunday, 6 = Saturday. |\n+---------------------------+------------------------------------------------+\n| %X | Year with 4 digits when first day of the week |\n| | is Sunday. Used with %V. |\n+---------------------------+------------------------------------------------+\n| %x | Year with 4 digits when first day of the week |\n| | is Monday. Used with %v. |\n+---------------------------+------------------------------------------------+\n| %Y | Year with 4 digits. |\n+---------------------------+------------------------------------------------+\n| %y | Year with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %# | For str_to_date(), skip all numbers. |\n+---------------------------+------------------------------------------------+\n| %. | For str_to_date(), skip all punctation |\n| | characters. |\n+---------------------------+------------------------------------------------+\n| %@ | For str_to_date(), skip all alpha characters. |\n+---------------------------+------------------------------------------------+\n| %% | A literal % character. |\n+---------------------------+------------------------------------------------+\n\nExamples\n--------\n\nSELECT STR_TO_DATE(\'Wednesday, June 2, 2014\', \'%W, %M %e, %Y\');\n+---------------------------------------------------------+\n| STR_TO_DATE(\'Wednesday, June 2, 2014\', \'%W, %M %e, %Y\') |\n+---------------------------------------------------------+\n| 2014-06-02 |\n+---------------------------------------------------------+\n\nSELECT STR_TO_DATE(\'Wednesday23423, June 2, 2014\', \'%W, %M %e, %Y\');\n+--------------------------------------------------------------+\n| STR_TO_DATE(\'Wednesday23423, June 2, 2014\', \'%W, %M %e, %Y\') |\n+--------------------------------------------------------------+\n| NULL |\n+--------------------------------------------------------------+\n1 row in set, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+---------+------+-------------------------------------------------------------\n---------------------+\n| Level | Code | Message \n |\n+---------+------+-------------------------------------------------------------\n---------------------+\n| Warning | 1411 | Incorrect datetime value: \'Wednesday23423, June 2, 2014\'\nfor function str_to_date |\n+---------+------+-------------------------------------------------------------\n---------------------+\n\nSELECT STR_TO_DATE(\'Wednesday23423, June 2, 2014\', \'%W%#, %M %e, %Y\');\n+----------------------------------------------------------------+\n| STR_TO_DATE(\'Wednesday23423, June 2, 2014\', \'%W%#, %M %e, %Y\') |\n+----------------------------------------------------------------+\n| 2014-06-02 |\n+----------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/str_to_date/','','https://mariadb.com/kb/en/str_to_date/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (551,31,'SUBDATE','Syntax\n------\n\nSUBDATE(date,INTERVAL expr unit), SUBDATE(expr,days)\n\nDescription\n-----------\n\nWhen invoked with the INTERVAL form of the second argument, SUBDATE() is a\nsynonym for DATE_SUB(). See Date and Time Units for a complete list of\npermitted units.\n\nThe second form allows the use of an integer value for days. In such cases, it\nis interpreted as the number of days to be subtracted from the date or\ndatetime expression expr.\n\nExamples\n--------\n\nSELECT DATE_SUB(\'2008-01-02\', INTERVAL 31 DAY);\n+-----------------------------------------+\n| DATE_SUB(\'2008-01-02\', INTERVAL 31 DAY) |\n+-----------------------------------------+\n| 2007-12-02 |\n+-----------------------------------------+\n\nSELECT SUBDATE(\'2008-01-02\', INTERVAL 31 DAY);\n+----------------------------------------+\n| SUBDATE(\'2008-01-02\', INTERVAL 31 DAY) |\n+----------------------------------------+\n| 2007-12-02 |\n+----------------------------------------+\n\nSELECT SUBDATE(\'2008-01-02 12:00:00\', 31);\n+------------------------------------+\n| SUBDATE(\'2008-01-02 12:00:00\', 31) |\n+------------------------------------+\n| 2007-12-02 12:00:00 |\n+------------------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n (\"2007-01-30 21:31:07\"),\n (\"1983-10-15 06:42:51\"),\n (\"2011-04-21 12:34:56\"),\n (\"2011-10-30 06:31:41\"),\n (\"2011-01-30 14:03:25\"),\n (\"2004-10-07 11:19:34\");\n\nSELECT d, SUBDATE(d, 10) from t1;\n+---------------------+---------------------+\n| d | SUBDATE(d, 10) |\n+---------------------+---------------------+\n| 2007-01-30 21:31:07 | 2007-01-20 21:31:07 |\n| 1983-10-15 06:42:51 | 1983-10-05 06:42:51 |\n| 2011-04-21 12:34:56 | 2011-04-11 12:34:56 |\n| 2011-10-30 06:31:41 | 2011-10-20 06:31:41 |\n| 2011-01-30 14:03:25 | 2011-01-20 14:03:25 |\n| 2004-10-07 11:19:34 | 2004-09-27 11:19:34 |\n+---------------------+---------------------+\n\nSELECT d, SUBDATE(d, INTERVAL 10 MINUTE) from t1;\n+---------------------+--------------------------------+\n| d | SUBDATE(d, INTERVAL 10 MINUTE) |\n+---------------------+--------------------------------+\n| 2007-01-30 21:31:07 | 2007-01-30 21:21:07 |\n| 1983-10-15 06:42:51 | 1983-10-15 06:32:51 |\n| 2011-04-21 12:34:56 | 2011-04-21 12:24:56 |\n| 2011-10-30 06:31:41 | 2011-10-30 06:21:41 |\n| 2011-01-30 14:03:25 | 2011-01-30 13:53:25 |\n| 2004-10-07 11:19:34 | 2004-10-07 11:09:34 |\n+---------------------+--------------------------------+\n\nURL: https://mariadb.com/kb/en/subdate/','','https://mariadb.com/kb/en/subdate/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (552,31,'SUBTIME','Syntax\n------\n\nSUBTIME(expr1,expr2)\n\nDescription\n-----------\n\nSUBTIME() returns expr1 - expr2 expressed as a value in the same format as\nexpr1. expr1 is a time or datetime expression, and expr2 is a time expression.\n\nExamples\n--------\n\nSELECT SUBTIME(\'2007-12-31 23:59:59.999999\',\'1 1:1:1.000002\');\n+--------------------------------------------------------+\n| SUBTIME(\'2007-12-31 23:59:59.999999\',\'1 1:1:1.000002\') |\n+--------------------------------------------------------+\n| 2007-12-30 22:58:58.999997 |\n+--------------------------------------------------------+\n\nSELECT SUBTIME(\'01:00:00.999999\', \'02:00:00.999998\');\n+-----------------------------------------------+\n| SUBTIME(\'01:00:00.999999\', \'02:00:00.999998\') |\n+-----------------------------------------------+\n| -00:59:59.999999 |\n+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/subtime/','','https://mariadb.com/kb/en/subtime/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (553,31,'SYSDATE','Syntax\n------\n\nSYSDATE([precision])\n\nDescription\n-----------\n\nReturns the current date and time as a value in \'YYYY-MM-DD HH:MM:SS\' or\nYYYYMMDDHHMMSS.uuuuuu format, depending on whether the function is used in a\nstring or numeric context.\n\nThe optional precision determines the microsecond precision. See Microseconds\nin MariaDB.\n\nSYSDATE() returns the time at which it executes. This differs from the\nbehavior for NOW(), which returns a constant time that indicates the time at\nwhich the statement began to execute. (Within a stored routine or trigger,\nNOW() returns the time at which the routine or triggering statement began to\nexecute.)\n\nIn addition, changing the timestamp system variable with a SET timestamp\nstatement affects the value returned by NOW() but not by SYSDATE(). This means\nthat timestamp settings in the binary log have no effect on invocations of\nSYSDATE().\n\nBecause SYSDATE() can return different values even within the same statement,\nand is not affected by SET TIMESTAMP, it is non-deterministic and therefore\nunsafe for replication if statement-based binary logging is used. If that is a\nproblem, you can use row-based logging, or start the server with the mysqld\noption --sysdate-is-now to cause SYSDATE() to be an alias for NOW(). The\nnon-deterministic nature of SYSDATE() also means that indexes cannot be used\nfor evaluating expressions that refer to it, and that statements using the\nSYSDATE() function are unsafe for statement-based replication.\n\nExamples\n--------\n\nDifference between NOW() and SYSDATE():\n\nSELECT NOW(), SLEEP(2), NOW();\n+---------------------+----------+---------------------+\n| NOW() | SLEEP(2) | NOW() |\n+---------------------+----------+---------------------+\n| 2010-03-27 13:23:40 | 0 | 2010-03-27 13:23:40 |\n+---------------------+----------+---------------------+\n\nSELECT SYSDATE(), SLEEP(2), SYSDATE();\n+---------------------+----------+---------------------+\n| SYSDATE() | SLEEP(2) | SYSDATE() |\n+---------------------+----------+---------------------+\n| 2010-03-27 13:23:52 | 0 | 2010-03-27 13:23:54 |\n+---------------------+----------+---------------------+\n\nWith precision:\n\nSELECT SYSDATE(4);\n+--------------------------+\n| SYSDATE(4) |\n+--------------------------+\n| 2018-07-10 10:17:13.1689 |\n+--------------------------+\n\nURL: https://mariadb.com/kb/en/sysdate/','','https://mariadb.com/kb/en/sysdate/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (554,31,'TIME Function','Syntax\n------\n\nTIME(expr)\n\nDescription\n-----------\n\nExtracts the time part of the time or datetime expression expr and returns it\nas a string.\n\nExamples\n--------\n\nSELECT TIME(\'2003-12-31 01:02:03\');\n+-----------------------------+\n| TIME(\'2003-12-31 01:02:03\') |\n+-----------------------------+\n| 01:02:03 |\n+-----------------------------+\n\nSELECT TIME(\'2003-12-31 01:02:03.000123\');\n+------------------------------------+\n| TIME(\'2003-12-31 01:02:03.000123\') |\n+------------------------------------+\n| 01:02:03.000123 |\n+------------------------------------+\n\nURL: https://mariadb.com/kb/en/time-function/','','https://mariadb.com/kb/en/time-function/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (555,31,'TIMEDIFF','Syntax\n------\n\nTIMEDIFF(expr1,expr2)\n\nDescription\n-----------\n\nTIMEDIFF() returns expr1 - expr2 expressed as a time value. expr1 and expr2\nare time or date-and-time expressions, but both must be of the same type.\n\nExamples\n--------\n\nSELECT TIMEDIFF(\'2000:01:01 00:00:00\', \'2000:01:01 00:00:00.000001\');\n+---------------------------------------------------------------+\n| TIMEDIFF(\'2000:01:01 00:00:00\', \'2000:01:01 00:00:00.000001\') |\n+---------------------------------------------------------------+\n| -00:00:00.000001 |\n+---------------------------------------------------------------+\n\nSELECT TIMEDIFF(\'2008-12-31 23:59:59.000001\', \'2008-12-30 01:01:01.000002\');\n+----------------------------------------------------------------------+\n| TIMEDIFF(\'2008-12-31 23:59:59.000001\', \'2008-12-30 01:01:01.000002\') |\n+----------------------------------------------------------------------+\n| 46:58:57.999999 |\n+----------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/timediff/','','https://mariadb.com/kb/en/timediff/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (556,31,'TIMESTAMP FUNCTION','Syntax\n------\n\nTIMESTAMP(expr), TIMESTAMP(expr1,expr2)\n\nDescription\n-----------\n\nWith a single argument, this function returns the date or datetime expression\nexpr as a datetime value. With two arguments, it adds the time expression\nexpr2 to the date or datetime expression expr1 and returns the result as a\ndatetime value.\n\nExamples\n--------\n\nSELECT TIMESTAMP(\'2003-12-31\');\n+-------------------------+\n| TIMESTAMP(\'2003-12-31\') |\n+-------------------------+\n| 2003-12-31 00:00:00 |\n+-------------------------+\n\nSELECT TIMESTAMP(\'2003-12-31 12:00:00\',\'6:30:00\');\n+--------------------------------------------+\n| TIMESTAMP(\'2003-12-31 12:00:00\',\'6:30:00\') |\n+--------------------------------------------+\n| 2003-12-31 18:30:00 |\n+--------------------------------------------+\n\nURL: https://mariadb.com/kb/en/timestamp-function/','','https://mariadb.com/kb/en/timestamp-function/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (557,31,'TIMESTAMPADD','Syntax\n------\n\nTIMESTAMPADD(unit,interval,datetime_expr)\n\nDescription\n-----------\n\nAdds the integer expression interval to the date or datetime expression\ndatetime_expr. The unit for interval is given by the unit argument, which\nshould be one of the following values: MICROSECOND, SECOND, MINUTE, HOUR, DAY,\nWEEK, MONTH, QUARTER, or YEAR.\n\nThe unit value may be specified using one of keywords as shown, or with a\nprefix of SQL_TSI_. For example, DAY and SQL_TSI_DAY both are legal.\n\nBefore MariaDB 5.5, FRAC_SECOND was permitted as a synonym for MICROSECOND.\n\nExamples\n--------\n\nSELECT TIMESTAMPADD(MINUTE,1,\'2003-01-02\');\n+-------------------------------------+\n| TIMESTAMPADD(MINUTE,1,\'2003-01-02\') |\n+-------------------------------------+\n| 2003-01-02 00:01:00 |\n+-------------------------------------+\n\nSELECT TIMESTAMPADD(WEEK,1,\'2003-01-02\');\n+-----------------------------------+\n| TIMESTAMPADD(WEEK,1,\'2003-01-02\') |\n+-----------------------------------+\n| 2003-01-09 |\n+-----------------------------------+\n\nURL: https://mariadb.com/kb/en/timestampadd/','','https://mariadb.com/kb/en/timestampadd/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (558,31,'TIMESTAMPDIFF','Syntax\n------\n\nTIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2)\n\nDescription\n-----------\n\nReturns datetime_expr2 - datetime_expr1, where datetime_expr1 and\ndatetime_expr2 are date or datetime expressions. One expression may be a date\nand the other a datetime; a date value is treated as a datetime having the\ntime part \'00:00:00\' where necessary. The unit for the result (an integer) is\ngiven by the unit argument. The legal values for unit are the same as those\nlisted in the description of the TIMESTAMPADD() function, i.e MICROSECOND,\nSECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, or YEAR.\n\nTIMESTAMPDIFF can also be used to calculate age.\n\nExamples\n--------\n\nSELECT TIMESTAMPDIFF(MONTH,\'2003-02-01\',\'2003-05-01\');\n+------------------------------------------------+\n| TIMESTAMPDIFF(MONTH,\'2003-02-01\',\'2003-05-01\') |\n+------------------------------------------------+\n| 3 |\n+------------------------------------------------+\n\nSELECT TIMESTAMPDIFF(YEAR,\'2002-05-01\',\'2001-01-01\');\n+-----------------------------------------------+\n| TIMESTAMPDIFF(YEAR,\'2002-05-01\',\'2001-01-01\') |\n+-----------------------------------------------+\n| -1 |\n+-----------------------------------------------+\n\nSELECT TIMESTAMPDIFF(MINUTE,\'2003-02-01\',\'2003-05-01 12:05:55\');\n+----------------------------------------------------------+\n| TIMESTAMPDIFF(MINUTE,\'2003-02-01\',\'2003-05-01 12:05:55\') |\n+----------------------------------------------------------+\n| 128885 |\n+----------------------------------------------------------+\n\nCalculating age:\n\nSELECT CURDATE();\n+------------+\n| CURDATE() |\n+------------+\n| 2019-05-27 |\n+------------+\n\nSELECT TIMESTAMPDIFF(YEAR, \'1971-06-06\', CURDATE()) AS age;\n+------+\n| age |\n+------+\n| 47 |\n+------+\n\nSELECT TIMESTAMPDIFF(YEAR, \'1971-05-06\', CURDATE()) AS age;\n+------+\n| age |\n+------+\n| 48 |\n+------+\n\nAge as of 2014-08-02:\n\nSELECT name, date_of_birth, TIMESTAMPDIFF(YEAR,date_of_birth,\'2014-08-02\') AS\nage \n FROM student_details;\n+---------+---------------+------+\n| name | date_of_birth | age |\n+---------+---------------+------+\n| Chun | 1993-12-31 | 20 |\n| Esben | 1946-01-01 | 68 |\n| Kaolin | 1996-07-16 | 18 |\n| Tatiana | 1988-04-13 | 26 |\n+---------+---------------+------+\n\nURL: https://mariadb.com/kb/en/timestampdiff/','','https://mariadb.com/kb/en/timestampdiff/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (559,31,'TIME_FORMAT','Syntax\n------\n\nTIME_FORMAT(time,format)\n\nDescription\n-----------\n\nThis is used like the DATE_FORMAT() function, but the format string may\ncontain format specifiers only for hours, minutes, and seconds. Other\nspecifiers produce a NULL value or 0.\n\nExamples\n--------\n\nSELECT TIME_FORMAT(\'100:00:00\', \'%H %k %h %I %l\');\n+--------------------------------------------+\n| TIME_FORMAT(\'100:00:00\', \'%H %k %h %I %l\') |\n+--------------------------------------------+\n| 100 100 04 04 4 |\n+--------------------------------------------+\n\nURL: https://mariadb.com/kb/en/time_format/','','https://mariadb.com/kb/en/time_format/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (560,31,'TIME_TO_SEC','Syntax\n------\n\nTIME_TO_SEC(time)\n\nDescription\n-----------\n\nReturns the time argument, converted to seconds.\n\nThe value returned by TIME_TO_SEC is of type DOUBLE. Before MariaDB 5.3 (and\nMySQL 5.6), the type was INT. The returned value preserves microseconds of the\nargument. See also Microseconds in MariaDB.\n\nExamples\n--------\n\nSELECT TIME_TO_SEC(\'22:23:00\');\n+-------------------------+\n| TIME_TO_SEC(\'22:23:00\') |\n+-------------------------+\n| 80580 |\n+-------------------------+\n\nSELECT TIME_TO_SEC(\'00:39:38\');\n+-------------------------+\n| TIME_TO_SEC(\'00:39:38\') |\n+-------------------------+\n| 2378 |\n+-------------------------+\n\nSELECT TIME_TO_SEC(\'09:12:55.2355\');\n+------------------------------+\n| TIME_TO_SEC(\'09:12:55.2355\') |\n+------------------------------+\n| 33175.2355 |\n+------------------------------+\n1 row in set (0.000 sec)\n\nURL: https://mariadb.com/kb/en/time_to_sec/','','https://mariadb.com/kb/en/time_to_sec/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (561,31,'TO_DAYS','Syntax\n------\n\nTO_DAYS(date)\n\nDescription\n-----------\n\nGiven a date date, returns the number of days since the start of the current\ncalendar (0000-00-00).\n\nThe function is not designed for use with dates before the advent of the\nGregorian calendar in October 1582. Results will not be reliable since it\ndoesn\'t account for the lost days when the calendar changed from the Julian\ncalendar.\n\nThis is the converse of the FROM_DAYS() function.\n\nExamples\n--------\n\nSELECT TO_DAYS(\'2007-10-07\');\n+-----------------------+\n| TO_DAYS(\'2007-10-07\') |\n+-----------------------+\n| 733321 |\n+-----------------------+\n\nSELECT TO_DAYS(\'0000-01-01\');\n+-----------------------+\n| TO_DAYS(\'0000-01-01\') |\n+-----------------------+\n| 1 |\n+-----------------------+\n\nSELECT TO_DAYS(950501);\n+-----------------+\n| TO_DAYS(950501) |\n+-----------------+\n| 728779 |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/to_days/','','https://mariadb.com/kb/en/to_days/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (562,31,'TO_SECONDS','Syntax\n------\n\nTO_SECONDS(expr)\n\nDescription\n-----------\n\nReturns the number of seconds from year 0 till expr, or NULL if expr is not a\nvalid date or datetime.\n\nExamples\n--------\n\nSELECT TO_SECONDS(\'2013-06-13\');\n+--------------------------+\n| TO_SECONDS(\'2013-06-13\') |\n+--------------------------+\n| 63538300800 |\n+--------------------------+\n\nSELECT TO_SECONDS(\'2013-06-13 21:45:13\');\n+-----------------------------------+\n| TO_SECONDS(\'2013-06-13 21:45:13\') |\n+-----------------------------------+\n| 63538379113 |\n+-----------------------------------+\n\nSELECT TO_SECONDS(NOW());\n+-------------------+\n| TO_SECONDS(NOW()) |\n+-------------------+\n| 63543530875 |\n+-------------------+\n\nSELECT TO_SECONDS(20130513);\n+----------------------+\n| TO_SECONDS(20130513) |\n+----------------------+\n| 63535622400 |\n+----------------------+\n1 row in set (0.00 sec)\n\nSELECT TO_SECONDS(130513);\n+--------------------+\n| TO_SECONDS(130513) |\n+--------------------+\n| 63535622400 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/to_seconds/','','https://mariadb.com/kb/en/to_seconds/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (563,31,'UNIX_TIMESTAMP','Syntax\n------\n\nUNIX_TIMESTAMP()\nUNIX_TIMESTAMP(date)\n\nDescription\n-----------\n\nIf called with no argument, returns a Unix timestamp (seconds since\n\'1970-01-01 00:00:00\' UTC) as an unsigned integer. If UNIX_TIMESTAMP() is\ncalled with a date argument, it returns the value of the argument as seconds\nsince \'1970-01-01 00:00:00\' UTC. date may be a DATE string, a DATETIME string,\na TIMESTAMP, or a number in the format YYMMDD or YYYYMMDD. The server\ninterprets date as a value in the current time zone and converts it to an\ninternal value in UTC. Clients can set their time zone as described in time\nzones.\n\nThe inverse function of UNIX_TIMESTAMP() is FROM_UNIXTIME()\n\nUNIX_TIMESTAMP() supports microseconds.\n\nTimestamps in MariaDB have a maximum value of 2147483647, equivalent to\n2038-01-19 05:14:07. This is due to the underlying 32-bit limitation. Using\nthe function on a date beyond this will result in NULL being returned. Use\nDATETIME as a storage type if you require dates beyond this.\n\nError Handling\n--------------\n\nReturns NULL for wrong arguments to UNIX_TIMESTAMP(). In MySQL and MariaDB\nbefore 5.3 wrong arguments to UNIX_TIMESTAMP() returned 0.\n\nCompatibility\n-------------\n\nAs you can see in the examples above, UNIX_TIMESTAMP(constant-date-string)\nreturns a timestamp with 6 decimals while MariaDB 5.2 and before returns it\nwithout decimals. This can cause a problem if you are using UNIX_TIMESTAMP()\nas a partitioning function. You can fix this by using\nFLOOR(UNIX_TIMESTAMP(..)) or changing the date string to a date number, like\n20080101000000.\n\nExamples\n--------\n\nSELECT UNIX_TIMESTAMP();\n+------------------+\n| UNIX_TIMESTAMP() |\n+------------------+\n| 1269711082 |\n+------------------+\n\nSELECT UNIX_TIMESTAMP(\'2007-11-30 10:30:19\');\n+---------------------------------------+\n| UNIX_TIMESTAMP(\'2007-11-30 10:30:19\') |\n+---------------------------------------+\n| 1196436619.000000 |\n+---------------------------------------+\n\nSELECT UNIX_TIMESTAMP(\"2007-11-30 10:30:19.123456\");\n+----------------------------------------------+\n| unix_timestamp(\"2007-11-30 10:30:19.123456\") |\n+----------------------------------------------+\n| 1196411419.123456 |\n+----------------------------------------------+\n\nSELECT FROM_UNIXTIME(UNIX_TIMESTAMP(\'2007-11-30 10:30:19\'));\n+------------------------------------------------------+\n| FROM_UNIXTIME(UNIX_TIMESTAMP(\'2007-11-30 10:30:19\')) |\n+------------------------------------------------------+\n| 2007-11-30 10:30:19.000000 |\n+------------------------------------------------------+\n\nSELECT FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(\'2007-11-30 10:30:19\')));\n+-------------------------------------------------------------+\n| FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(\'2007-11-30 10:30:19\'))) |\n+-------------------------------------------------------------+\n| 2007-11-30 10:30:19 |\n+-------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/unix_timestamp/','','https://mariadb.com/kb/en/unix_timestamp/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (564,31,'UTC_DATE','Syntax\n------\n\nUTC_DATE, UTC_DATE()\n\nDescription\n-----------\n\nReturns the current UTC date as a value in \'YYYY-MM-DD\' or YYYYMMDD format,\ndepending on whether the function is used in a string or numeric context.\n\nExamples\n--------\n\nSELECT UTC_DATE(), UTC_DATE() + 0;\n+------------+----------------+\n| UTC_DATE() | UTC_DATE() + 0 |\n+------------+----------------+\n| 2010-03-27 | 20100327 |\n+------------+----------------+\n\nURL: https://mariadb.com/kb/en/utc_date/','','https://mariadb.com/kb/en/utc_date/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (565,31,'UTC_TIME','Syntax\n------\n\nUTC_TIME\nUTC_TIME([precision])\n\nDescription\n-----------\n\nReturns the current UTC time as a value in \'HH:MM:SS\' or HHMMSS.uuuuuu format,\ndepending on whether the function is used in a string or numeric context.\n\nThe optional precision determines the microsecond precision. See Microseconds\nin MariaDB.\n\nExamples\n--------\n\nSELECT UTC_TIME(), UTC_TIME() + 0;\n+------------+----------------+\n| UTC_TIME() | UTC_TIME() + 0 |\n+------------+----------------+\n| 17:32:34 | 173234.000000 |\n+------------+----------------+\n\nWith precision:\n\nSELECT UTC_TIME(5);\n+----------------+\n| UTC_TIME(5) |\n+----------------+\n| 07:52:50.78369 |\n+----------------+\n\nURL: https://mariadb.com/kb/en/utc_time/','','https://mariadb.com/kb/en/utc_time/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (566,31,'UTC_TIMESTAMP','Syntax\n------\n\nUTC_TIMESTAMP\nUTC_TIMESTAMP([precision])\n\nDescription\n-----------\n\nReturns the current UTC date and time as a value in \'YYYY-MM-DD HH:MM:SS\' or\nYYYYMMDDHHMMSS.uuuuuu format, depending on whether the function is used in a\nstring or numeric context.\n\nThe optional precision determines the microsecond precision. See Microseconds\nin MariaDB.\n\nExamples\n--------\n\nSELECT UTC_TIMESTAMP(), UTC_TIMESTAMP() + 0;\n+---------------------+-----------------------+\n| UTC_TIMESTAMP() | UTC_TIMESTAMP() + 0 |\n+---------------------+-----------------------+\n| 2010-03-27 17:33:16 | 20100327173316.000000 |\n+---------------------+-----------------------+\n\nWith precision:\n\nSELECT UTC_TIMESTAMP(4);\n+--------------------------+\n| UTC_TIMESTAMP(4) |\n+--------------------------+\n| 2018-07-10 07:51:09.1019 |\n+--------------------------+\n\nURL: https://mariadb.com/kb/en/utc_timestamp/','','https://mariadb.com/kb/en/utc_timestamp/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (567,31,'WEEK','Syntax\n------\n\nWEEK(date[,mode])\n\nDescription\n-----------\n\nThis function returns the week number for date. The two-argument form of\nWEEK() allows you to specify whether the week starts on Sunday or Monday and\nwhether the return value should be in the range from 0 to 53 or from 1 to 53.\nIf the mode argument is omitted, the value of the default_week_format system\nvariable is used.\n\nModes\n-----\n\n+-------+---------------------+--------+------------------------------------+\n| Mode | 1st day of week | Range | Week 1 is the 1st week with |\n+-------+---------------------+--------+------------------------------------+\n| 0 | Sunday | 0-53 | a Sunday in this year |\n+-------+---------------------+--------+------------------------------------+\n| 1 | Monday | 0-53 | more than 3 days this year |\n+-------+---------------------+--------+------------------------------------+\n| 2 | Sunday | 1-53 | a Sunday in this year |\n+-------+---------------------+--------+------------------------------------+\n| 3 | Monday | 1-53 | more than 3 days this year |\n+-------+---------------------+--------+------------------------------------+\n| 4 | Sunday | 0-53 | more than 3 days this year |\n+-------+---------------------+--------+------------------------------------+\n| 5 | Monday | 0-53 | a Monday in this year |\n+-------+---------------------+--------+------------------------------------+\n| 6 | Sunday | 1-53 | more than 3 days this year |\n+-------+---------------------+--------+------------------------------------+\n| 7 | Monday | 1-53 | a Monday in this year |\n+-------+---------------------+--------+------------------------------------+\n\nWith the mode value of 3, which means \'more than 3 days this year\', weeks are\nnumbered according to ISO 8601:1988.\n\nExamples\n--------\n\nSELECT WEEK(\'2008-02-20\');\n+--------------------+\n| WEEK(\'2008-02-20\') |\n+--------------------+\n| 7 |\n+--------------------+\n\nSELECT WEEK(\'2008-02-20\',0);\n+----------------------+\n| WEEK(\'2008-02-20\',0) |\n+----------------------+\n| 7 |\n+----------------------+\n\nSELECT WEEK(\'2008-02-20\',1);\n+----------------------+\n| WEEK(\'2008-02-20\',1) |\n+----------------------+\n| 8 |\n+----------------------+\n\nSELECT WEEK(\'2008-12-31\',0);\n+----------------------+\n| WEEK(\'2008-12-31\',0) |\n+----------------------+\n| 52 |\n+----------------------+\n\nSELECT WEEK(\'2008-12-31\',1);\n+----------------------+\n| WEEK(\'2008-12-31\',1) |\n+----------------------+\n| 53 |\n+----------------------+\n\nSELECT WEEK(\'2019-12-30\',3);\n+----------------------+\n| WEEK(\'2019-12-30\',3) |\n+----------------------+\n| 1 |\n+----------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n (\"2007-01-30 21:31:07\"),\n (\"1983-10-15 06:42:51\"),\n (\"2011-04-21 12:34:56\"),\n (\"2011-10-30 06:31:41\"),\n (\"2011-01-30 14:03:25\"),\n (\"2004-10-07 11:19:34\");\n\nSELECT d, WEEK(d,0), WEEK(d,1) from t1;\n+---------------------+-----------+-----------+\n| d | WEEK(d,0) | WEEK(d,1) |\n+---------------------+-----------+-----------+\n| 2007-01-30 21:31:07 | 4 | 5 |\n| 1983-10-15 06:42:51 | 41 | 41 |\n| 2011-04-21 12:34:56 | 16 | 16 |\n| 2011-10-30 06:31:41 | 44 | 43 |\n| 2011-01-30 14:03:25 | 5 | 4 |\n| 2004-10-07 11:19:34 | 40 | 41 |\n+---------------------+-----------+-----------+\n\nURL: https://mariadb.com/kb/en/week/','','https://mariadb.com/kb/en/week/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (568,31,'WEEKDAY','Syntax\n------\n\nWEEKDAY(date)\n\nDescription\n-----------\n\nReturns the weekday index for date (0 = Monday, 1 = Tuesday, ... 6 = Sunday).\n\nThis contrasts with DAYOFWEEK() which follows the ODBC standard (1 = Sunday, 2\n= Monday, ..., 7 = Saturday).\n\nExamples\n--------\n\nSELECT WEEKDAY(\'2008-02-03 22:23:00\');\n+--------------------------------+\n| WEEKDAY(\'2008-02-03 22:23:00\') |\n+--------------------------------+\n| 6 |\n+--------------------------------+\n\nSELECT WEEKDAY(\'2007-11-06\');\n+-----------------------+\n| WEEKDAY(\'2007-11-06\') |\n+-----------------------+\n| 1 |\n+-----------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n (\"2007-01-30 21:31:07\"),\n (\"1983-10-15 06:42:51\"),\n (\"2011-04-21 12:34:56\"),\n (\"2011-10-30 06:31:41\"),\n (\"2011-01-30 14:03:25\"),\n (\"2004-10-07 11:19:34\");\n\nSELECT d FROM t1 where WEEKDAY(d) = 6;\n+---------------------+\n| d |\n+---------------------+\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/weekday/','','https://mariadb.com/kb/en/weekday/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (569,31,'WEEKOFYEAR','Syntax\n------\n\nWEEKOFYEAR(date)\n\nDescription\n-----------\n\nReturns the calendar week of the date as a number in the range from 1 to 53.\nWEEKOFYEAR() is a compatibility function that is equivalent to WEEK(date,3).\n\nExamples\n--------\n\nSELECT WEEKOFYEAR(\'2008-02-20\');\n+--------------------------+\n| WEEKOFYEAR(\'2008-02-20\') |\n+--------------------------+\n| 8 |\n+--------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n (\"2007-01-30 21:31:07\"),\n (\"1983-10-15 06:42:51\"),\n (\"2011-04-21 12:34:56\"),\n (\"2011-10-30 06:31:41\"),\n (\"2011-01-30 14:03:25\"),\n (\"2004-10-07 11:19:34\");\n\nselect * from t1;\n+---------------------+\n| d |\n+---------------------+\n| 2007-01-30 21:31:07 |\n| 1983-10-15 06:42:51 |\n| 2011-04-21 12:34:56 |\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n| 2004-10-07 11:19:34 |\n+---------------------+\n\nSELECT d, WEEKOFYEAR(d), WEEK(d,3) from t1;\n+---------------------+---------------+-----------+\n| d | WEEKOFYEAR(d) | WEEK(d,3) |\n+---------------------+---------------+-----------+\n| 2007-01-30 21:31:07 | 5 | 5 |\n| 1983-10-15 06:42:51 | 41 | 41 |\n| 2011-04-21 12:34:56 | 16 | 16 |\n| 2011-10-30 06:31:41 | 43 | 43 |\n| 2011-01-30 14:03:25 | 4 | 4 |\n| 2004-10-07 11:19:34 | 41 | 41 |\n+---------------------+---------------+-----------+\n\nURL: https://mariadb.com/kb/en/weekofyear/','','https://mariadb.com/kb/en/weekofyear/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (570,31,'YEAR','Syntax\n------\n\nYEAR(date)\n\nDescription\n-----------\n\nReturns the year for the given date, in the range 1000 to 9999, or 0 for the\n\"zero\" date.\n\nExamples\n--------\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n (\"2007-01-30 21:31:07\"),\n (\"1983-10-15 06:42:51\"),\n (\"2011-04-21 12:34:56\"),\n (\"2011-10-30 06:31:41\"),\n (\"2011-01-30 14:03:25\"),\n (\"2004-10-07 11:19:34\");\n\nSELECT * FROM t1;\n+---------------------+\n| d |\n+---------------------+\n| 2007-01-30 21:31:07 |\n| 1983-10-15 06:42:51 |\n| 2011-04-21 12:34:56 |\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n| 2004-10-07 11:19:34 |\n+---------------------+\n\nSELECT * FROM t1 WHERE YEAR(d) = 2011;\n+---------------------+\n| d |\n+---------------------+\n| 2011-04-21 12:34:56 |\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n+---------------------+\n\nSELECT YEAR(\'1987-01-01\');\n+--------------------+\n| YEAR(\'1987-01-01\') |\n+--------------------+\n| 1987 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/year/','','https://mariadb.com/kb/en/year/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (571,31,'YEARWEEK','Syntax\n------\n\nYEARWEEK(date), YEARWEEK(date,mode)\n\nDescription\n-----------\n\nReturns year and week for a date. The mode argument works exactly like the\nmode argument to WEEK(). The year in the result may be different from the year\nin the date argument for the first and the last week of the year.\n\nExamples\n--------\n\nSELECT YEARWEEK(\'1987-01-01\');\n+------------------------+\n| YEARWEEK(\'1987-01-01\') |\n+------------------------+\n| 198652 |\n+------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n (\"2007-01-30 21:31:07\"),\n (\"1983-10-15 06:42:51\"),\n (\"2011-04-21 12:34:56\"),\n (\"2011-10-30 06:31:41\"),\n (\"2011-01-30 14:03:25\"),\n (\"2004-10-07 11:19:34\");\n\nSELECT * FROM t1;\n+---------------------+\n| d |\n+---------------------+\n| 2007-01-30 21:31:07 |\n| 1983-10-15 06:42:51 |\n| 2011-04-21 12:34:56 |\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n| 2004-10-07 11:19:34 |\n+---------------------+\n6 rows in set (0.02 sec)\n\nSELECT YEARWEEK(d) FROM t1 WHERE YEAR(d) = 2011;\n+-------------+\n| YEARWEEK(d) |\n+-------------+\n| 201116 |\n| 201144 |\n| 201105 |\n+-------------+\n3 rows in set (0.03 sec)\n\nURL: https://mariadb.com/kb/en/yearweek/','','https://mariadb.com/kb/en/yearweek/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (572,32,'Well-Known Binary (WKB) Format','WKB stands for Well-Known Binary, a format for representing geographical and\ngeometrical data.\n\nWKB uses 1-byte unsigned integers, 4-byte unsigned integers, and 8-byte\ndouble-precision numbers.\n\n* The first byte indicates the byte order. 00 for big endian, or 01 for little\nendian.\n* The next 4 bytes indicate the geometry type. Values from 1 to 7 indicate\nwhether the type is Point, LineString, Polygon, MultiPoint, MultiLineString,\nMultiPolygon, or GeometryCollection respectively. \n* The 8-byte floats represent the co-ordinates.\n\nTake the following example, a sequence of 21 bytes each represented by two hex\ndigits:\n\n000000000140000000000000004010000000000000\n\n* It\'s big endian\n000000000140000000000000004010000000000000\n\n* It\'s a POINT\n000000000140000000000000004010000000000000\n\n* The X co-ordinate is 2.0\n000000000140000000000000004010000000000000\n\n* The Y-co-ordinate is 4.0\n000000000140000000000000004010000000000000\n\nURL: https://mariadb.com/kb/en/well-known-binary-wkb-format/','','https://mariadb.com/kb/en/well-known-binary-wkb-format/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (573,32,'AsBinary','A synonym for ST_AsBinary().\n\nURL: https://mariadb.com/kb/en/wkb-asbinary/','','https://mariadb.com/kb/en/wkb-asbinary/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (574,32,'AsWKB','A synonym for ST_AsBinary().\n\nURL: https://mariadb.com/kb/en/aswkb/','','https://mariadb.com/kb/en/aswkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (575,32,'MLineFromWKB','Syntax\n------\n\nMLineFromWKB(wkb[,srid])\nMultiLineStringFromWKB(wkb[,srid])\n\nDescription\n-----------\n\nConstructs a MULTILINESTRING value using its WKB representation and SRID.\n\nMLineFromWKB() and MultiLineStringFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(MLineFromText(\'MULTILINESTRING((10 48,10 21,10 0),(16\n0,16 23,16 48))\'));\n\nSELECT ST_AsText(MLineFromWKB(@g));\n+--------------------------------------------------------+\n| ST_AsText(MLineFromWKB(@g)) |\n+--------------------------------------------------------+\n| MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48)) |\n+--------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/mlinefromwkb/','','https://mariadb.com/kb/en/mlinefromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (576,32,'MPointFromWKB','Syntax\n------\n\nMPointFromWKB(wkb[,srid])\nMultiPointFromWKB(wkb[,srid])\n\nDescription\n-----------\n\nConstructs a MULTIPOINT value using its WKB representation and SRID.\n\nMPointFromWKB() and MultiPointFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(MPointFromText(\'MultiPoint( 1 1, 2 2, 5 3, 7 2, 9 3, 8 4,\n6 6, 6 9, 4 9, 1 5 )\'));\n\nSELECT ST_AsText(MPointFromWKB(@g));\n+-----------------------------------------------------+\n| ST_AsText(MPointFromWKB(@g)) |\n+-----------------------------------------------------+\n| MULTIPOINT(1 1,2 2,5 3,7 2,9 3,8 4,6 6,6 9,4 9,1 5) |\n+-----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/mpointfromwkb/','','https://mariadb.com/kb/en/mpointfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (577,32,'MPolyFromWKB','Syntax\n------\n\nMPolyFromWKB(wkb[,srid])\nMultiPolygonFromWKB(wkb[,srid])\n\nDescription\n-----------\n\nConstructs a MULTIPOLYGON value using its WKB representation and SRID.\n\nMPolyFromWKB() and MultiPolygonFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(MPointFromText(\'MULTIPOLYGON(((28 26,28 0,84 0,84 42,28\n26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))\'));\n\nSELECT ST_AsText(MPolyFromWKB(@g))\\G\n*************************** 1. row ***************************\nST_AsText(MPolyFromWKB(@g)): MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52\n18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))\n\nURL: https://mariadb.com/kb/en/mpolyfromwkb/','','https://mariadb.com/kb/en/mpolyfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (578,32,'GeomCollFromWKB','A synonym for ST_GeomCollFromWKB.\n\nURL: https://mariadb.com/kb/en/wkb-geomcollfromwkb/','','https://mariadb.com/kb/en/wkb-geomcollfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (579,32,'GeometryCollectionFromWKB','A synonym for ST_GeomCollFromWKB.\n\nURL: https://mariadb.com/kb/en/geometrycollectionfromwkb/','','https://mariadb.com/kb/en/geometrycollectionfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (580,32,'GeometryFromWKB','A synonym for ST_GeomFromWKB.\n\nURL: https://mariadb.com/kb/en/geometryfromwkb/','','https://mariadb.com/kb/en/geometryfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (581,32,'GeomFromWKB','A synonym for ST_GeomFromWKB.\n\nURL: https://mariadb.com/kb/en/wkb-geomfromwkb/','','https://mariadb.com/kb/en/wkb-geomfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (582,32,'LineFromWKB','A synonym for ST_LineFromWKB.\n\nURL: https://mariadb.com/kb/en/wkb-linefromwkb/','','https://mariadb.com/kb/en/wkb-linefromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (583,32,'LineStringFromWKB','A synonym for ST_LineFromWKB.\n\nURL: https://mariadb.com/kb/en/linestringfromwkb/','','https://mariadb.com/kb/en/linestringfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (584,32,'MultiLineStringFromWKB','A synonym for MLineFromWKB().\n\nURL: https://mariadb.com/kb/en/multilinestringfromwkb/','','https://mariadb.com/kb/en/multilinestringfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (585,32,'MultiPointFromWKB','A synonym for MPointFromWKB.\n\nURL: https://mariadb.com/kb/en/multipointfromwkb/','','https://mariadb.com/kb/en/multipointfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (586,32,'MultiPolygonFromWKB','Synonym for MPolyFromWKB.\n\nURL: https://mariadb.com/kb/en/multipolygonfromwkb/','','https://mariadb.com/kb/en/multipolygonfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (587,32,'PointFromWKB','A synonym for ST_PointFromWKB.\n\nURL: https://mariadb.com/kb/en/wkb-pointfromwkb/','','https://mariadb.com/kb/en/wkb-pointfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (588,32,'PolyFromWKB','A synonym for ST_PolyFromWKB.\n\nURL: https://mariadb.com/kb/en/wkb-polyfromwkb/','','https://mariadb.com/kb/en/wkb-polyfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (589,32,'PolygonFromWKB','A synonym for ST_PolyFromWKB.\n\nURL: https://mariadb.com/kb/en/polygonfromwkb/','','https://mariadb.com/kb/en/polygonfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (590,32,'ST_AsBinary','Syntax\n------\n\nST_AsBinary(g)\nAsBinary(g)\nST_AsWKB(g)\nAsWKB(g)\n\nDescription\n-----------\n\nConverts a value in internal geometry format to its WKB representation and\nreturns the binary result.\n\nST_AsBinary(), AsBinary(), ST_AsWKB() and AsWKB() are synonyms,\n\nExamples\n--------\n\nSET @poly = ST_GeomFromText(\'POLYGON((0 0,0 1,1 1,1 0,0 0))\');\nSELECT ST_AsBinary(@poly);\n\nSELECT ST_AsText(ST_GeomFromWKB(ST_AsWKB(@poly)));\n+--------------------------------------------+\n| ST_AsText(ST_GeomFromWKB(ST_AsWKB(@poly))) |\n+--------------------------------------------+\n| POLYGON((0 0,0 1,1 1,1 0,0 0)) |\n+--------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_asbinary/','','https://mariadb.com/kb/en/st_asbinary/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (591,32,'ST_AsWKB','A synonym for ST_AsBinary().\n\nURL: https://mariadb.com/kb/en/st_aswkb/','','https://mariadb.com/kb/en/st_aswkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (592,32,'ST_GeomCollFromWKB','Syntax\n------\n\nST_GeomCollFromWKB(wkb[,srid])\nST_GeometryCollectionFromWKB(wkb[,srid])\nGeomCollFromWKB(wkb[,srid])\nGeometryCollectionFromWKB(wkb[,srid])\n\nDescription\n-----------\n\nConstructs a GEOMETRYCOLLECTION value using its WKB representation and SRID.\n\nST_GeomCollFromWKB(), ST_GeometryCollectionFromWKB(), GeomCollFromWKB() and\nGeometryCollectionFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(ST_GeomFromText(\'GEOMETRYCOLLECTION(\n POLYGON((5 5,10 5,10 10,5 5)),POINT(10 10))\'));\n\nSELECT ST_AsText(ST_GeomCollFromWKB(@g));\n+----------------------------------------------------------------+\n| ST_AsText(ST_GeomCollFromWKB(@g)) |\n+----------------------------------------------------------------+\n| GEOMETRYCOLLECTION(POLYGON((5 5,10 5,10 10,5 5)),POINT(10 10)) |\n+----------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_geomcollfromwkb/','','https://mariadb.com/kb/en/st_geomcollfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (593,32,'ST_GeometryCollectionFromWKB','A synonym for ST_GeomCollFromWKB.\n\nURL: https://mariadb.com/kb/en/st_geometrycollectionfromwkb/','','https://mariadb.com/kb/en/st_geometrycollectionfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (594,32,'ST_GeometryFromWKB','A synonym for ST_GeomFromWKB.\n\nURL: https://mariadb.com/kb/en/st_geometryfromwkb/','','https://mariadb.com/kb/en/st_geometryfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (595,32,'ST_GeomFromWKB','Syntax\n------\n\nST_GeomFromWKB(wkb[,srid])\nST_GeometryFromWKB(wkb[,srid])\nGeomFromWKB(wkb[,srid])\nGeometryFromWKB(wkb[,srid])\n\nDescription\n-----------\n\nConstructs a geometry value of any type using its WKB representation and SRID.\n\nST_GeomFromWKB(), ST_GeometryFromWKB(), GeomFromWKB() and GeometryFromWKB()\nare synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(ST_LineFromText(\'LINESTRING(0 4, 4 6)\'));\n\nSELECT ST_AsText(ST_GeomFromWKB(@g));\n+-------------------------------+\n| ST_AsText(ST_GeomFromWKB(@g)) |\n+-------------------------------+\n| LINESTRING(0 4,4 6) |\n+-------------------------------+\n\nURL: https://mariadb.com/kb/en/st_geomfromwkb/','','https://mariadb.com/kb/en/st_geomfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (596,32,'ST_LineFromWKB','Syntax\n------\n\nST_LineFromWKB(wkb[,srid])\nLineFromWKB(wkb[,srid])\nST_LineStringFromWKB(wkb[,srid])\nLineStringFromWKB(wkb[,srid])\n\nDescription\n-----------\n\nConstructs a LINESTRING value using its WKB representation and SRID.\n\nST_LineFromWKB(), LineFromWKB(), ST_LineStringFromWKB(), and\nLineStringFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(ST_LineFromText(\'LineString(0 4,4 6)\'));\n\nSELECT ST_AsText(ST_LineFromWKB(@g)) AS l;\n+---------------------+\n| l |\n+---------------------+\n| LINESTRING(0 4,4 6) |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/st_linefromwkb/','','https://mariadb.com/kb/en/st_linefromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (597,32,'ST_LineStringFromWKB','A synonym for ST_LineFromWKB.\n\nURL: https://mariadb.com/kb/en/st_linestringfromwkb/','','https://mariadb.com/kb/en/st_linestringfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (598,32,'ST_PointFromWKB','Syntax\n------\n\nST_PointFromWKB(wkb[,srid])\nPointFromWKB(wkb[,srid])\n\nDescription\n-----------\n\nConstructs a POINT value using its WKB representation and SRID.\n\nST_PointFromWKB() and PointFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(ST_PointFromText(\'POINT(0 4)\'));\n\nSELECT ST_AsText(ST_PointFromWKB(@g)) AS p;\n+------------+\n| p |\n+------------+\n| POINT(0 4) |\n+------------+\n\nURL: https://mariadb.com/kb/en/st_pointfromwkb/','','https://mariadb.com/kb/en/st_pointfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (599,32,'ST_PolyFromWKB','Syntax\n------\n\nST_PolyFromWKB(wkb[,srid])\nST_PolygonFromWKB(wkb[,srid])\nPolyFromWKB(wkb[,srid])\nPolygonFromWKB(wkb[,srid])\n\nDescription\n-----------\n\nConstructs a POLYGON value using its WKB representation and SRID.\n\nST_PolyFromWKB(), ST_PolygonFromWKB(), PolyFromWKB() and PolygonFromWKB() are\nsynonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(ST_PolyFromText(\'POLYGON((1 1,1 5,4 9,6 9,9 3,7 2,1\n1))\'));\n\nSELECT ST_AsText(ST_PolyFromWKB(@g)) AS p;\n+----------------------------------------+\n| p |\n+----------------------------------------+\n| POLYGON((1 1,1 5,4 9,6 9,9 3,7 2,1 1)) |\n+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_polyfromwkb/','','https://mariadb.com/kb/en/st_polyfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (600,32,'ST_PolygonFromWKB','A synonym for ST_PolyFromWKB.\n\nURL: https://mariadb.com/kb/en/st_polygonfromwkb/','','https://mariadb.com/kb/en/st_polygonfromwkb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (601,34,'Geometry Types','Description\n-----------\n\nMariaDB provides a standard way of creating spatial columns for geometry\ntypes, for example, with CREATE TABLE or ALTER TABLE. Currently, spatial\ncolumns are supported for MyISAM, InnoDB and ARCHIVE tables. See also SPATIAL\nINDEX.\n\nThe basic geometry type is GEOMETRY. But the type can be more specific. The\nfollowing types are supported:\n\n+-----------------------------------------------------------------------------+\n| Geometry Types |\n+-----------------------------------------------------------------------------+\n| POINT |\n+-----------------------------------------------------------------------------+\n| LINESTRING |\n+-----------------------------------------------------------------------------+\n| POLYGON |\n+-----------------------------------------------------------------------------+\n| MULTIPOINT |\n+-----------------------------------------------------------------------------+\n| MULTILINESTRING |\n+-----------------------------------------------------------------------------+\n| MULTIPOLYGON |\n+-----------------------------------------------------------------------------+\n| GEOMETRYCOLLECTION |\n+-----------------------------------------------------------------------------+\n| GEOMETRY |\n+-----------------------------------------------------------------------------+\n\nExamples\n--------\n\nNote: For clarity, only one type is listed per table in the examples below,\nbut a table row can contain multiple types. For example:\n\nCREATE TABLE object (shapeA POLYGON, shapeB LINESTRING);\n\nPOINT\n-----\n\nCREATE TABLE gis_point (g POINT);\nSHOW FIELDS FROM gis_point;\nINSERT INTO gis_point VALUES\n (PointFromText(\'POINT(10 10)\')),\n (PointFromText(\'POINT(20 10)\')),\n (PointFromText(\'POINT(20 20)\')),\n (PointFromWKB(AsWKB(PointFromText(\'POINT(10 20)\'))));\n\nLINESTRING\n----------\n\nCREATE TABLE gis_line (g LINESTRING);\nSHOW FIELDS FROM gis_line;\nINSERT INTO gis_line VALUES\n (LineFromText(\'LINESTRING(0 0,0 10,10 0)\')),\n (LineStringFromText(\'LINESTRING(10 10,20 10,20 20,10 20,10 10)\')),\n (LineStringFromWKB(AsWKB(LineString(Point(10, 10), Point(40, 10)))));\n\nPOLYGON\n-------\n\nCREATE TABLE gis_polygon (g POLYGON);\nSHOW FIELDS FROM gis_polygon;\nINSERT INTO gis_polygon VALUES\n (PolygonFromText(\'POLYGON((10 10,20 10,20 20,10 20,10 10))\')),\n (PolyFromText(\'POLYGON((0 0,50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10\n20,10 10))\')),\n (PolyFromWKB(AsWKB(Polygon(LineString(Point(0, 0), Point(30, 0), Point(30,\n30), Point(0, 0))))));\n\nMULTIPOINT\n----------\n\nCREATE TABLE gis_multi_point (g MULTIPOINT);\nSHOW FIELDS FROM gis_multi_point;\nINSERT INTO gis_multi_point VALUES\n (MultiPointFromText(\'MULTIPOINT(0 0,10 10,10 20,20 20)\')),\n (MPointFromText(\'MULTIPOINT(1 1,11 11,11 21,21 21)\')),\n (MPointFromWKB(AsWKB(MultiPoint(Point(3, 6), Point(4, 10)))));\n\nMULTILINESTRING\n---------------\n\nCREATE TABLE gis_multi_line (g MULTILINESTRING);\nSHOW FIELDS FROM gis_multi_line;\nINSERT INTO gis_multi_line VALUES\n (MultiLineStringFromText(\'MULTILINESTRING((10 48,10 21,10 0),(16 0,16\n23,16 48))\')),\n (MLineFromText(\'MULTILINESTRING((10 48,10 21,10 0))\')),\n (MLineFromWKB(AsWKB(MultiLineString(LineString(Point(1, 2), Point(3, 5)),\nLineString(Point(2, 5), Point(5, 8), Point(21, 7))))));\n\nMULTIPOLYGON\n------------\n\nCREATE TABLE gis_multi_polygon (g MULTIPOLYGON);\nSHOW FIELDS FROM gis_multi_polygon;\nINSERT INTO gis_multi_polygon VALUES\n (MultiPolygonFromText(\'MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52\n18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))\')),\n (MPolyFromText(\'MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66\n23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))\')),\n (MPolyFromWKB(AsWKB(MultiPolygon(Polygon(LineString(Point(0, 3), Point(3,\n3), Point(3, 0), Point(0, 3)))))));\n\nGEOMETRYCOLLECTION\n------------------\n\nCREATE TABLE gis_geometrycollection (g GEOMETRYCOLLECTION);\nSHOW FIELDS FROM gis_geometrycollection;\nINSERT INTO gis_geometrycollection VALUES\n (GeomCollFromText(\'GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10\n10))\')),\n (GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6),\nLineString(Point(3, 6), Point(7, 9)))))),\n (GeomFromText(\'GeometryCollection()\')),\n (GeomFromText(\'GeometryCollection EMPTY\'));\n\nGEOMETRY\n--------\n\nCREATE TABLE gis_geometry (g GEOMETRY);\nSHOW FIELDS FROM gis_geometry;\nINSERT into gis_geometry SELECT * FROM gis_point;\nINSERT into gis_geometry SELECT * FROM gis_line;\nINSERT into gis_geometry SELECT * FROM gis_polygon;\nINSERT into gis_geometry SELECT * FROM gis_multi_point;\nINSERT into gis_geometry SELECT * FROM gis_multi_line;\nINSERT into gis_geometry SELECT * FROM gis_multi_polygon;\nINSERT into gis_geometry SELECT * FROM gis_geometrycollection;\n\nURL: https://mariadb.com/kb/en/geometry-types/','','https://mariadb.com/kb/en/geometry-types/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (602,34,'Geometry Hierarchy','Description\n-----------\n\nGeometry is the base class. It is an abstract class. The instantiable\nsubclasses of Geometry are restricted to zero-, one-, and two-dimensional\ngeometric objects that exist in two-dimensional coordinate space. All\ninstantiable geometry classes are defined so that valid instances of a\ngeometry class are topologically closed (that is, all defined geometries\ninclude their boundary).\n\nThe base Geometry class has subclasses for Point, Curve, Surface, and\nGeometryCollection:\n\n* Point represents zero-dimensional objects.\n* Curve represents one-dimensional objects, and has subclass LineString, with\nsub-subclasses Line and LinearRing.\n* Surface is designed for two-dimensional objects and has subclass Polygon.\n* GeometryCollection has specialized zero-, one-, and two-dimensional\ncollection classes named MultiPoint, MultiLineString, and MultiPolygon for\nmodeling geometries corresponding to collections of Points, LineStrings, and\nPolygons, respectively. MultiCurve and MultiSurface are introduced as abstract\nsuperclasses that generalize the collection interfaces to handle Curves and\nSurfaces.\n\nGeometry, Curve, Surface, MultiCurve, and MultiSurface are defined as\nnon-instantiable classes. They define a common set of methods for their\nsubclasses and are included for extensibility.\n\nPoint, LineString, Polygon, GeometryCollection, MultiPoint, MultiLineString,\nand MultiPolygon are instantiable classes.\n\nURL: https://mariadb.com/kb/en/geometry-hierarchy/','','https://mariadb.com/kb/en/geometry-hierarchy/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (603,34,'SPATIAL INDEX','Description\n-----------\n\nOn MyISAM, Aria and InnoDB tables, MariaDB can create spatial indexes (an\nR-tree index) using syntax similar to that for creating regular indexes, but\nextended with the SPATIAL keyword. Currently, columns in spatial indexes must\nbe declared NOT NULL.\n\nSpatial indexes can be created when the table is created, or added after the\nfact like so:\n\n* with CREATE TABLE: CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g));\n\n* with ALTER TABLE: ALTER TABLE geom ADD SPATIAL INDEX(g);\n\n* with CREATE INDEX: CREATE SPATIAL INDEX sp_index ON geom (g);\n\nSPATIAL INDEX creates an R-tree index. For storage engines that support\nnon-spatial indexing of spatial columns, the engine creates a B-tree index. A\nB-tree index on spatial values is useful for exact-value lookups, but not for\nrange scans.\n\nFor more information on indexing spatial columns, see CREATE INDEX.\n\nTo drop spatial indexes, use ALTER TABLE or DROP INDEX:\n\n* with ALTER TABLE: ALTER TABLE geom DROP INDEX g;\n\n* with DROP INDEX: DROP INDEX sp_index ON geom;\n\nData-at-Rest Encyption\n----------------------\n\nBefore MariaDB 10.4.3, InnoDB\'s spatial indexes could not be encrypted. If an\nInnoDB table was encrypted and if it contained spatial indexes, then those\nindexes would be unencrypted.\n\nIn MariaDB 10.4.3 and later, if innodb_checksum_algorithm is set to full_crc32\nor strict_full_crc32, and if the table does not use ROW_FORMAT=COMPRESSED,\nthen InnoDB spatial indexes will be encrypted if the table is encrypted.\n\nSee MDEV-12026 for more information.\n\nURL: https://mariadb.com/kb/en/spatial-index/','','https://mariadb.com/kb/en/spatial-index/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (604,35,'BOUNDARY','A synonym for ST_BOUNDARY.\n\nURL: https://mariadb.com/kb/en/geometry-properties-boundary/','','https://mariadb.com/kb/en/geometry-properties-boundary/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (605,35,'DIMENSION','A synonym for ST_DIMENSION.\n\nURL: https://mariadb.com/kb/en/dimension/','','https://mariadb.com/kb/en/dimension/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (606,35,'ENVELOPE','A synonym for ST_ENVELOPE.\n\nURL: https://mariadb.com/kb/en/geometry-properties-envelope/','','https://mariadb.com/kb/en/geometry-properties-envelope/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (607,35,'GeometryN','A synonym for ST_GeometryN.\n\nURL: https://mariadb.com/kb/en/geometry-properties-geometryn/','','https://mariadb.com/kb/en/geometry-properties-geometryn/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (608,35,'GeometryType','A synonym for ST_GeometryType.\n\nURL: https://mariadb.com/kb/en/geometry-properties-geometrytype/','','https://mariadb.com/kb/en/geometry-properties-geometrytype/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (609,35,'IsClosed','A synonym for ST_IsClosed.\n\nURL: https://mariadb.com/kb/en/isclosed/','','https://mariadb.com/kb/en/isclosed/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (610,35,'IsEmpty','A synonym for ST_IsEmpty.\n\nURL: https://mariadb.com/kb/en/geometry-properties-isempty/','','https://mariadb.com/kb/en/geometry-properties-isempty/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (611,35,'IsRing','A synonym for ST_IsRing.\n\nURL: https://mariadb.com/kb/en/isring/','','https://mariadb.com/kb/en/isring/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (612,35,'IsSimple','A synonym for ST_IsSImple.\n\nURL: https://mariadb.com/kb/en/geometry-properties-issimple/','','https://mariadb.com/kb/en/geometry-properties-issimple/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (613,35,'NumGeometries','A synonym for ST_NumGeometries.\n\nURL: https://mariadb.com/kb/en/geometry-properties-numgeometries/','','https://mariadb.com/kb/en/geometry-properties-numgeometries/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (614,35,'SRID','A synonym for ST_SRID.\n\nURL: https://mariadb.com/kb/en/geometry-properties-srid/','','https://mariadb.com/kb/en/geometry-properties-srid/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (615,35,'ST_BOUNDARY','MariaDB starting with 10.1.2\n----------------------------\nThe ST_BOUNDARY function was introduced in MariaDB 10.1.2\n\nSyntax\n------\n\nST_BOUNDARY(g)\nBOUNDARY(g)\n\nDescription\n-----------\n\nReturns a geometry that is the closure of the combinatorial boundary of the\ngeometry value g.\n\nBOUNDARY() is a synonym.\n\nExamples\n--------\n\nSELECT ST_AsText(ST_Boundary(ST_GeomFromText(\'LINESTRING(3 3,0 0, -3 3)\')));\n+----------------------------------------------------------------------+\n| ST_AsText(ST_Boundary(ST_GeomFromText(\'LINESTRING(3 3,0 0, -3 3)\'))) |\n+----------------------------------------------------------------------+\n| MULTIPOINT(3 3,-3 3) |\n+----------------------------------------------------------------------+\n\nSELECT ST_AsText(ST_Boundary(ST_GeomFromText(\'POLYGON((3 3,0 0, -3 3, 3\n3))\')));\n+--------------------------------------------------------------------------+\n| ST_AsText(ST_Boundary(ST_GeomFromText(\'POLYGON((3 3,0 0, -3 3, 3 3))\'))) |\n+--------------------------------------------------------------------------+\n| LINESTRING(3 3,0 0,-3 3,3 3) |\n+--------------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_boundary/','','https://mariadb.com/kb/en/st_boundary/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (616,35,'ST_DIMENSION','Syntax\n------\n\nST_Dimension(g)\nDimension(g)\n\nDescription\n-----------\n\nReturns the inherent dimension of the geometry value g. The result can be\n\n+------------------------------------+---------------------------------------+\n| Dimension | Definition |\n+------------------------------------+---------------------------------------+\n| -1 | empty geometry |\n+------------------------------------+---------------------------------------+\n| 0 | geometry with no length or area |\n+------------------------------------+---------------------------------------+\n| 1 | geometry with no area but nonzero |\n| | length |\n+------------------------------------+---------------------------------------+\n| 2 | geometry with nonzero area |\n+------------------------------------+---------------------------------------+\n\nST_Dimension() and Dimension() are synonyms.\n\nExamples\n--------\n\nSELECT Dimension(GeomFromText(\'LineString(1 1,2 2)\'));\n+------------------------------------------------+\n| Dimension(GeomFromText(\'LineString(1 1,2 2)\')) |\n+------------------------------------------------+\n| 1 |\n+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_dimension/','','https://mariadb.com/kb/en/st_dimension/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (617,35,'ST_ENVELOPE','Syntax\n------\n\nST_ENVELOPE(g)\nENVELOPE(g)\n\nDescription\n-----------\n\nReturns the Minimum Bounding Rectangle (MBR) for the geometry value g. The\nresult is returned as a Polygon value.\n\nThe polygon is defined by the corner points of the bounding box:\n\nPOLYGON((MINX MINY, MAXX MINY, MAXX MAXY, MINX MAXY, MINX MINY))\n\nST_ENVELOPE() and ENVELOPE() are synonyms.\n\nExamples\n--------\n\nSELECT AsText(ST_ENVELOPE(GeomFromText(\'LineString(1 1,4 4)\')));\n+----------------------------------------------------------+\n| AsText(ST_ENVELOPE(GeomFromText(\'LineString(1 1,4 4)\'))) |\n+----------------------------------------------------------+\n| POLYGON((1 1,4 1,4 4,1 4,1 1)) |\n+----------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_envelope/','','https://mariadb.com/kb/en/st_envelope/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (618,35,'ST_GEOMETRYN','Syntax\n------\n\nST_GeometryN(gc,N)\nGeometryN(gc,N)\n\nDescription\n-----------\n\nReturns the N-th geometry in the GeometryCollection gc. Geometries are\nnumbered beginning with 1.\n\nST_GeometryN() and GeometryN() are synonyms.\n\nExample\n-------\n\nSET @gc = \'GeometryCollection(Point(1 1),LineString(12 14, 9 11))\';\n\nSELECT AsText(GeometryN(GeomFromText(@gc),1));\n+----------------------------------------+\n| AsText(GeometryN(GeomFromText(@gc),1)) |\n+----------------------------------------+\n| POINT(1 1) |\n+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_geometryn/','','https://mariadb.com/kb/en/st_geometryn/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (619,35,'ST_GEOMETRYTYPE','Syntax\n------\n\nST_GeometryType(g)\nGeometryType(g)\n\nDescription\n-----------\n\nReturns as a string the name of the geometry type of which the geometry\ninstance g is a member. The name corresponds to one of the instantiable\nGeometry subclasses.\n\nST_GeometryType() and GeometryType() are synonyms.\n\nExamples\n--------\n\nSELECT GeometryType(GeomFromText(\'POINT(1 1)\'));\n+------------------------------------------+\n| GeometryType(GeomFromText(\'POINT(1 1)\')) |\n+------------------------------------------+\n| POINT |\n+------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_geometrytype/','','https://mariadb.com/kb/en/st_geometrytype/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (620,35,'ST_ISCLOSED','Syntax\n------\n\nST_IsClosed(g)\nIsClosed(g)\n\nDescription\n-----------\n\nReturns 1 if a given LINESTRING\'s start and end points are the same, or 0 if\nthey are not the same. Before MariaDB 10.1.5, returns NULL if not given a\nLINESTRING. After MariaDB 10.1.5, returns -1.\n\nST_IsClosed() and IsClosed() are synonyms.\n\nExamples\n--------\n\nSET @ls = \'LineString(0 0, 0 4, 4 4, 0 0)\';\nSELECT ST_ISCLOSED(GEOMFROMTEXT(@ls));\n+--------------------------------+\n| ST_ISCLOSED(GEOMFROMTEXT(@ls)) |\n+--------------------------------+\n| 1 |\n+--------------------------------+\n\nSET @ls = \'LineString(0 0, 0 4, 4 4, 0 1)\';\nSELECT ST_ISCLOSED(GEOMFROMTEXT(@ls));\n+--------------------------------+\n| ST_ISCLOSED(GEOMFROMTEXT(@ls)) |\n+--------------------------------+\n| 0 |\n+--------------------------------+\n\nURL: https://mariadb.com/kb/en/st_isclosed/','','https://mariadb.com/kb/en/st_isclosed/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (621,35,'ST_ISEMPTY','Syntax\n------\n\nST_IsEmpty(g)\nIsEmpty(g)\n\nDescription\n-----------\n\nIsEmpty is a function defined by the OpenGIS specification, but is not fully\nimplemented by MariaDB or MySQL.\n\nSince MariaDB and MySQL do not support GIS EMPTY values such as POINT EMPTY,\nas implemented it simply returns 1 if the geometry value g is invalid, 0 if it\nis valid, and NULL if the argument is NULL.\n\nST_IsEmpty() and IsEmpty() are synonyms.\n\nURL: https://mariadb.com/kb/en/st_isempty/','','https://mariadb.com/kb/en/st_isempty/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (622,35,'ST_IsRing','MariaDB starting with 10.1.2\n----------------------------\nThe ST_IsRing function was introduced in MariaDB 10.1.2\n\nSyntax\n------\n\nST_IsRing(g)\nIsRing(g)\n\nDescription\n-----------\n\nReturns true if a given LINESTRING is a ring, that is, both ST_IsClosed and\nST_IsSimple. A simple curve does not pass through the same point more than\nonce. However, see MDEV-7510.\n\nSt_IsRing() and IsRing() are synonyms.\n\nURL: https://mariadb.com/kb/en/st_isring/','','https://mariadb.com/kb/en/st_isring/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (623,35,'ST_IsSimple','Syntax\n------\n\nST_IsSimple(g)\nIsSimple(g)\n\nDescription\n-----------\n\nReturns true if the given Geometry has no anomalous geometric points, false if\nit does, or NULL if given a NULL value.\n\nST_IsSimple() and IsSimple() are synonyms.\n\nExamples\n--------\n\nA POINT is always simple.\n\nSET @g = \'Point(1 2)\';\n\nSELECT ST_ISSIMPLE(GEOMFROMTEXT(@g));\n+-------------------------------+\n| ST_ISSIMPLE(GEOMFROMTEXT(@g)) |\n+-------------------------------+\n| 1 |\n+-------------------------------+\n\nURL: https://mariadb.com/kb/en/st_issimple/','','https://mariadb.com/kb/en/st_issimple/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (624,35,'ST_NUMGEOMETRIES','Syntax\n------\n\nST_NumGeometries(gc)\nNumGeometries(gc)\n\nDescription\n-----------\n\nReturns the number of geometries in the GeometryCollection gc.\n\nST_NumGeometries() and NumGeometries() are synonyms.\n\nExample\n-------\n\nSET @gc = \'GeometryCollection(Point(1 1),LineString(2 2, 3 3))\';\n\nSELECT NUMGEOMETRIES(GeomFromText(@gc));\n+----------------------------------+\n| NUMGEOMETRIES(GeomFromText(@gc)) |\n+----------------------------------+\n| 2 |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/st_numgeometries/','','https://mariadb.com/kb/en/st_numgeometries/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (625,35,'ST_RELATE','MariaDB starting with 10.1.2\n----------------------------\nThe ST_RELATE() function was introduced in MariaDB 10.1.2\n\nSyntax\n------\n\nST_Relate(g1, g2, i)\n\nDescription\n-----------\n\nReturns true if Geometry g1 is spatially related to Geometryg2 by testing for\nintersections between the interior, boundary and exterior of the two\ngeometries as specified by the values in intersection matrix pattern i.\n\nURL: https://mariadb.com/kb/en/st_relate/','','https://mariadb.com/kb/en/st_relate/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (626,35,'ST_SRID','Syntax\n------\n\nST_SRID(g)\nSRID(g)\n\nDescription\n-----------\n\nReturns an integer indicating the Spatial Reference System ID for the geometry\nvalue g.\n\nIn MariaDB, the SRID value is just an integer associated with the geometry\nvalue. All calculations are done assuming Euclidean (planar) geometry.\n\nST_SRID() and SRID() are synonyms.\n\nExamples\n--------\n\nSELECT SRID(GeomFromText(\'LineString(1 1,2 2)\',101));\n+-----------------------------------------------+\n| SRID(GeomFromText(\'LineString(1 1,2 2)\',101)) |\n+-----------------------------------------------+\n| 101 |\n+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_srid/','','https://mariadb.com/kb/en/st_srid/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (627,36,'LOAD_FILE','Syntax\n------\n\nLOAD_FILE(file_name)\n\nDescription\n-----------\n\nReads the file and returns the file contents as a string. To use this\nfunction, the file must be located on the server host, you must specify the\nfull path name to the file, and you must have the FILE privilege. The file\nmust be readable by all and it must be less than the size, in bytes, of the\nmax_allowed_packet system variable. If the secure_file_priv system variable is\nset to a non-empty directory name, the file to be loaded must be located in\nthat directory.\n\nIf the file does not exist or cannot be read because one of the preceding\nconditions is not satisfied, the function returns NULL.\n\nSince MariaDB 5.1, the character_set_filesystem system variable has controlled\ninterpretation of file names that are given as literal strings.\n\nStatements using the LOAD_FILE() function are not safe for statement based\nreplication. This is because the slave will execute the LOAD_FILE() command\nitself. If the file doesn\'t exist on the slave, the function will return NULL.\n\nExamples\n--------\n\nUPDATE t SET blob_col=LOAD_FILE(\'/tmp/picture\') WHERE id=1;\n\nURL: https://mariadb.com/kb/en/load_file/','','https://mariadb.com/kb/en/load_file/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (628,36,'NOT REGEXP','Syntax\n------\n\nexpr NOT REGEXP pat, expr NOT RLIKE pat\n\nDescription\n-----------\n\nThis is the same as NOT (expr REGEXP pat).\n\nURL: https://mariadb.com/kb/en/not-regexp/','','https://mariadb.com/kb/en/not-regexp/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (629,36,'REGEXP','Syntax\n------\n\nexpr REGEXP pat, expr RLIKE pat\n\nDescription\n-----------\n\nPerforms a pattern match of a string expression expr against a pattern pat.\nThe pattern can be an extended regular expression. See Regular Expressions\nOverview for details on the syntax for regular expressions (see also PCRE\nRegular Expressions).\n\nReturns 1 if expr matches pat or 0 if it doesn\'t match. If either expr or pat\nare NULL, the result is NULL.\n\nThe negative form NOT REGEXP also exists, as an alias for NOT (string REGEXP\npattern). RLIKE and NOT RLIKE are synonyms for REGEXP and NOT REGEXP,\noriginally provided for mSQL compatibility.\n\nThe pattern need not be a literal string. For example, it can be specified as\na string expression or table column.\n\nNote: Because MariaDB uses the C escape syntax in strings (for example, \"\\n\"\nto represent the newline character), you must double any \"\\\" that you use in\nyour REGEXP strings.\n\nREGEXP is not case sensitive, except when used with binary strings.\n\nMariaDB 10.0.5 moved to the PCRE regex library - see PCRE Regular Expressions\nfor enhancements to REGEXP introduced in MariaDB 10.0.5.\n\nThe default_regex_flags variable addresses the remaining compatibilities\nbetween PCRE and the old regex library.\n\nExamples\n--------\n\nSELECT \'Monty!\' REGEXP \'m%y%%\';\n+-------------------------+\n| \'Monty!\' REGEXP \'m%y%%\' |\n+-------------------------+\n| 0 |\n+-------------------------+\n\nSELECT \'Monty!\' REGEXP \'.*\';\n+----------------------+\n| \'Monty!\' REGEXP \'.*\' |\n+----------------------+\n| 1 |\n+----------------------+\n\nSELECT \'new*\\n*line\' REGEXP \'new\\\\*.\\\\*line\';\n+---------------------------------------+\n| \'new*\\n*line\' REGEXP \'new\\\\*.\\\\*line\' |\n+---------------------------------------+\n| 1 |\n+---------------------------------------+\n\nSELECT \'a\' REGEXP \'A\', \'a\' REGEXP BINARY \'A\';\n+----------------+-----------------------+\n| \'a\' REGEXP \'A\' | \'a\' REGEXP BINARY \'A\' |\n+----------------+-----------------------+\n| 1 | 0 |\n+----------------+-----------------------+\n\nSELECT \'a\' REGEXP \'^[a-d]\';\n+---------------------+\n| \'a\' REGEXP \'^[a-d]\' |\n+---------------------+\n| 1 |\n+---------------------+\n\ndefault_regex_flags examples\n----------------------------\n\nMariaDB 10.0.11 introduced the default_regex_flags variable to address the\nremaining compatibilities between PCRE and the old regex library.\n\nThe default behaviour (multiline match is off)\n\nSELECT \'a\\nb\\nc\' RLIKE \'^b$\';\n+---------------------------+\n| \'(?m)a\\nb\\nc\' RLIKE \'^b$\' |\n+---------------------------+\n| 0 |\n+---------------------------+\n\nEnabling the multiline option using the PCRE option syntax:\n\nSELECT \'a\\nb\\nc\' RLIKE \'(?m)^b$\';\n+---------------------------+\n| \'a\\nb\\nc\' RLIKE \'(?m)^b$\' |\n+---------------------------+\n| 1 |\n+---------------------------+\n\nEnabling the multiline option using default_regex_flags\n\nSET default_regex_flags=\'MULTILINE\';\nSELECT \'a\\nb\\nc\' RLIKE \'^b$\';\n+-----------------------+\n| \'a\\nb\\nc\' RLIKE \'^b$\' |\n+-----------------------+\n| 1 |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/regexp/','','https://mariadb.com/kb/en/regexp/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (630,36,'REGEXP_INSTR','Syntax\n------\n\nREGEXP_INSTR(subject, pattern)\n\nReturns the position of the first occurrence of the regular expression pattern\nin the string subject, or 0 if pattern was not found.\n\nThe positions start with 1 and are measured in characters (i.e. not in bytes),\nwhich is important for multi-byte character sets. You can cast a multi-byte\ncharacter set to BINARY to get offsets in bytes.\n\nThe function follows the case sensitivity rules of the effective collation.\nMatching is performed case insensitively for case insensitive collations, and\ncase sensitively for case sensitive collations and for binary data.\n\nThe collation case sensitivity can be overwritten using the (?i) and (?-i)\nPCRE flags.\n\nMariaDB uses the PCRE regular expression library for enhanced regular\nexpression performance, and REGEXP_INSTR was introduced as part of this\nenhancement.\n\nExamples\n--------\n\nSELECT REGEXP_INSTR(\'abc\',\'b\');\n-> 2\n\nSELECT REGEXP_INSTR(\'abc\',\'x\');\n-> 0\n\nSELECT REGEXP_INSTR(\'BJÖRN\',\'N\');\n-> 5\n\nCasting a multi-byte character set as BINARY to get offsets in bytes:\n\nSELECT REGEXP_INSTR(BINARY \'BJÖRN\',\'N\') AS cast_utf8_to_binary;\n-> 6\n\nCase sensitivity:\n\nSELECT REGEXP_INSTR(\'ABC\',\'b\');\n-> 2\n\nSELECT REGEXP_INSTR(\'ABC\' COLLATE utf8_bin,\'b\');\n-> 0\n\nSELECT REGEXP_INSTR(BINARY\'ABC\',\'b\');\n-> 0\n\nSELECT REGEXP_INSTR(\'ABC\',\'(?-i)b\');\n-> 0\n\nSELECT REGEXP_INSTR(\'ABC\' COLLATE utf8_bin,\'(?i)b\');\n-> 2\n\nURL: https://mariadb.com/kb/en/regexp_instr/','','https://mariadb.com/kb/en/regexp_instr/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (631,36,'REGEXP_REPLACE','Syntax\n------\n\nREGEXP_REPLACE(subject, pattern, replace)\n\nDescription\n-----------\n\nREGEXP_REPLACE returns the string subject with all occurrences of the regular\nexpression pattern replaced by the string replace. If no occurrences are\nfound, then subject is returned as is.\n\nThe replace string can have backreferences to the subexpressions in the form\n\\N, where N is a number from 1 to 9.\n\nThe function follows the case sensitivity rules of the effective collation.\nMatching is performed case insensitively for case insensitive collations, and\ncase sensitively for case sensitive collations and for binary data.\n\nThe collation case sensitivity can be overwritten using the (?i) and (?-i)\nPCRE flags.\n\nMariaDB uses the PCRE regular expression library for enhanced regular\nexpression performance, and REGEXP_REPLACE was introduced as part of this\nenhancement.\n\nThe default_regex_flags variable addresses the remaining compatibilities\nbetween PCRE and the old regex library.\n\nExamples\n--------\n\nSELECT REGEXP_REPLACE(\'ab12cd\',\'[0-9]\',\'\') AS remove_digits;\n-> abcd\n\nSELECT\nREGEXP_REPLACE(\'<html><head><title>title</title><body>body</body></htm>\',\n\'<.+?>\',\' \')\nAS strip_html;\n-> title body\n\nBackreferences to the subexpressions in the form \\N, where N is a number from\n1 to 9:\n\nSELECT REGEXP_REPLACE(\'James Bond\',\'^(.*) (.*)$\',\'\\\\2, \\\\1\') AS reorder_name;\n-> Bond, James\n\nCase insensitive and case sensitive matches:\n\nSELECT REGEXP_REPLACE(\'ABC\',\'b\',\'-\') AS case_insensitive;\n-> A-C\n\nSELECT REGEXP_REPLACE(\'ABC\' COLLATE utf8_bin,\'b\',\'-\') AS case_sensitive;\n-> ABC\n\nSELECT REGEXP_REPLACE(BINARY \'ABC\',\'b\',\'-\') AS binary_data;\n-> ABC\n\nOverwriting the collation case sensitivity using the (?i) and (?-i) PCRE flags.\n\nSELECT REGEXP_REPLACE(\'ABC\',\'(?-i)b\',\'-\') AS force_case_sensitive;\n-> ABC\n\nSELECT REGEXP_REPLACE(BINARY \'ABC\',\'(?i)b\',\'-\') AS force_case_insensitive;\n-> A-C\n\nURL: https://mariadb.com/kb/en/regexp_replace/','','https://mariadb.com/kb/en/regexp_replace/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (632,36,'REGEXP_SUBSTR','Syntax\n------\n\nREGEXP_SUBSTR(subject,pattern)\n\nDescription\n-----------\n\nReturns the part of the string subject that matches the regular expression\npattern, or an empty string if pattern was not found.\n\nThe function follows the case sensitivity rules of the effective collation.\nMatching is performed case insensitively for case insensitive collations, and\ncase sensitively for case sensitive collations and for binary data.\n\nThe collation case sensitivity can be overwritten using the (?i) and (?-i)\nPCRE flags.\n\nMariaDB uses the PCRE regular expression library for enhanced regular\nexpression performance, and REGEXP_SUBSTR was introduced as part of this\nenhancement.\n\nThe default_regex_flags variable addresses the remaining compatibilities\nbetween PCRE and the old regex library.\n\nExamples\n--------\n\nSELECT REGEXP_SUBSTR(\'ab12cd\',\'[0-9]+\');\n-> 12\n\nSELECT REGEXP_SUBSTR(\n \'See https://mariadb.org/en/foundation/ for details\',\n \'https?://[^/]*\');\n-> https://mariadb.org\n\nSELECT REGEXP_SUBSTR(\'ABC\',\'b\');\n-> B\n\nSELECT REGEXP_SUBSTR(\'ABC\' COLLATE utf8_bin,\'b\');\n->\n\nSELECT REGEXP_SUBSTR(BINARY\'ABC\',\'b\');\n->\n\nSELECT REGEXP_SUBSTR(\'ABC\',\'(?i)b\');\n-> B\n\nSELECT REGEXP_SUBSTR(\'ABC\' COLLATE utf8_bin,\'(?+i)b\');\n-> B\n\nURL: https://mariadb.com/kb/en/regexp_substr/','','https://mariadb.com/kb/en/regexp_substr/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (633,36,'ASCII','Syntax\n------\n\nASCII(str)\n\nDescription\n-----------\n\nReturns the numeric ASCII value of the leftmost character of the string\nargument. Returns 0 if the given string is empty and NULL if it is NULL.\n\nASCII() works for 8-bit characters.\n\nExamples\n--------\n\nSELECT ASCII(9);\n+----------+\n| ASCII(9) |\n+----------+\n| 57 |\n+----------+\n\nSELECT ASCII(\'9\');\n+------------+\n| ASCII(\'9\') |\n+------------+\n| 57 |\n+------------+\n\nSELECT ASCII(\'abc\');\n+--------------+\n| ASCII(\'abc\') |\n+--------------+\n| 97 |\n+--------------+\n\nURL: https://mariadb.com/kb/en/ascii/','','https://mariadb.com/kb/en/ascii/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (634,36,'BIN','Syntax\n------\n\nBIN(N)\n\nDescription\n-----------\n\nReturns a string representation of the binary value of the given longlong\n(that is, BIGINT) number. This is equivalent to CONV(N,10,2). The argument\nshould be positive. If it is a FLOAT, it will be truncated. Returns NULL if\nthe argument is NULL.\n\nExamples\n--------\n\nSELECT BIN(12);\n+---------+\n| BIN(12) |\n+---------+\n| 1100 |\n+---------+\n\nURL: https://mariadb.com/kb/en/bin/','','https://mariadb.com/kb/en/bin/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (635,36,'BINARY Operator','This page describes the BINARY operator. For details about the data type, see\nBinary Data Type.\n\nSyntax\n------\n\nBINARY\n\nDescription\n-----------\n\nThe BINARY operator casts the string following it to a binary string. This is\nan easy way to force a column comparison to be done byte by byte rather than\ncharacter by character. This causes the comparison to be case sensitive even\nif the column isn\'t defined as BINARY or BLOB.\n\nBINARY also causes trailing spaces to be significant.\n\nExamples\n--------\n\nSELECT \'a\' = \'A\';\n+-----------+\n| \'a\' = \'A\' |\n+-----------+\n| 1 |\n+-----------+\n\nSELECT BINARY \'a\' = \'A\';\n+------------------+\n| BINARY \'a\' = \'A\' |\n+------------------+\n| 0 |\n+------------------+\n\nSELECT \'a\' = \'a \';\n+------------+\n| \'a\' = \'a \' |\n+------------+\n| 1 |\n+------------+\n\nSELECT BINARY \'a\' = \'a \';\n+-------------------+\n| BINARY \'a\' = \'a \' |\n+-------------------+\n| 0 |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/binary-operator/','','https://mariadb.com/kb/en/binary-operator/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (636,36,'BIT_LENGTH','Syntax\n------\n\nBIT_LENGTH(str)\n\nDescription\n-----------\n\nReturns the length of the given string argument in bits. If the argument is\nnot a string, it will be converted to string. If the argument is NULL, it\nreturns NULL.\n\nExamples\n--------\n\nSELECT BIT_LENGTH(\'text\');\n+--------------------+\n| BIT_LENGTH(\'text\') |\n+--------------------+\n| 32 |\n+--------------------+\n\nSELECT BIT_LENGTH(\'\');\n+----------------+\n| BIT_LENGTH(\'\') |\n+----------------+\n| 0 |\n+----------------+\n\nCompatibility\n-------------\n\nPostgreSQL and Sybase support BIT_LENGTH().\n\nURL: https://mariadb.com/kb/en/bit_length/','','https://mariadb.com/kb/en/bit_length/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (637,36,'CAST','Syntax\n------\n\nCAST(expr AS type)\n\nDescription\n-----------\n\nThe CAST() function takes a value of one type and produces a value of another\ntype, similar to the CONVERT() function.\n\nThe type can be one of the following values:\n\n* BINARY\n* CHAR\n* DATE\n* DATETIME\n* DECIMAL[(M[,D])]\n* DOUBLE\n* FLOAT (from MariaDB 10.4.5)\n* INTEGER\nShort for SIGNED INTEGER\n\n* SIGNED [INTEGER]\n* UNSIGNED [INTEGER]\n* TIME\n* VARCHAR (in Oracle mode, from MariaDB 10.3)\n\nThe main difference between CAST and CONVERT() is that CONVERT(expr,type) is\nODBC syntax while CAST(expr as type) and CONVERT(... USING ...) are SQL92\nsyntax.\n\nIn MariaDB 10.4 and later, you can use the CAST() function with the INTERVAL\nkeyword.\n\nUntil MariaDB 5.5.31, X\'HHHH\', the standard SQL syntax for binary string\nliterals, erroneously worked in the same way as 0xHHHH. In 5.5.31 it was\nintentionally changed to behave as a string in all contexts (and never as a\nnumber).\n\nThis introduced an incompatibility with previous versions of MariaDB, and all\nversions of MySQL (see the example below).\n\nExamples\n--------\n\nSimple casts:\n\nSELECT CAST(\"abc\" AS BINARY);\nSELECT CAST(\"1\" AS UNSIGNED INTEGER);\nSELECT CAST(123 AS CHAR CHARACTER SET utf8)\n\nNote that when one casts to CHAR without specifying the character set, the\ncollation_connection character set collation will be used. When used with CHAR\nCHARACTER SET, the default collation for that character set will be used.\n\nSELECT COLLATION(CAST(123 AS CHAR));\n+------------------------------+\n| COLLATION(CAST(123 AS CHAR)) |\n+------------------------------+\n| latin1_swedish_ci |\n+------------------------------+\n\nSELECT COLLATION(CAST(123 AS CHAR CHARACTER SET utf8));\n+-------------------------------------------------+\n| COLLATION(CAST(123 AS CHAR CHARACTER SET utf8)) |\n+-------------------------------------------------+\n| utf8_general_ci |\n+-------------------------------------------------+\n\nIf you also want to change the collation, you have to use the COLLATE operator:\n\nSELECT COLLATION(CAST(123 AS CHAR CHARACTER SET utf8) \n COLLATE utf8_unicode_ci);\n+-------------------------------------------------------------------------+\n| COLLATION(CAST(123 AS CHAR CHARACTER SET utf8) COLLATE utf8_unicode_ci) |\n+-------------------------------------------------------------------------+\n| utf8_unicode_ci |\n+-------------------------------------------------------------------------+\n\nUsing CAST() to order an ENUM field as a CHAR rather than the internal\nnumerical value:\n\nCREATE TABLE enum_list (enum_field enum(\'c\',\'a\',\'b\'));\n\nINSERT INTO enum_list (enum_field) \nVALUES(\'c\'),(\'a\'),(\'c\'),(\'b\');\n\nSELECT * FROM enum_list \nORDER BY enum_field;\n+------------+\n| enum_field |\n+------------+\n| c |\n| c |\n| a |\n| b |\n+------------+\n\nSELECT * FROM enum_list \nORDER BY CAST(enum_field AS CHAR);\n+------------+\n| enum_field |\n+------------+\n| a |\n| b |\n| c |\n| c |\n+------------+\n\nFrom MariaDB 5.5.31, the following will trigger warnings, since x\'aa\' and\n\'X\'aa\' no longer behave as a number. Previously, and in all versions of MySQL,\nno warnings are triggered since they did erroneously behave as a number:\n\nSELECT CAST(0xAA AS UNSIGNED), CAST(x\'aa\' AS UNSIGNED), CAST(X\'aa\' AS\nUNSIGNED);\n+------------------------+-------------------------+-------------------------+\n| CAST(0xAA AS UNSIGNED) | CAST(x\'aa\' AS UNSIGNED) | CAST(X\'aa\' AS UNSIGNED) |\n+------------------------+-------------------------+-------------------------+\n| 170 | 0 | 0 |\n+------------------------+-------------------------+-------------------------+\n1 row in set, 2 warnings (0.00 sec)\n\nWarning (Code 1292): Truncated incorrect INTEGER value: \'\\xAA\'\nWarning (Code 1292): Truncated incorrect INTEGER value: \'\\xAA\'\n\nCasting to intervals:\n\nSELECT CAST(2019-01-04 INTERVAL AS DAY_SECOND(2)) AS \"Cast\";\n\n+-------------+\n| Cast |\n+-------------+\n| 00:20:17.00 |\n+-------------+\n\nURL: https://mariadb.com/kb/en/cast/','','https://mariadb.com/kb/en/cast/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (638,36,'CHAR Function','Syntax\n------\n\nCHAR(N,... [USING charset_name])\n\nDescription\n-----------\n\nCHAR() interprets each argument as an INT and returns a string consisting of\nthe characters given by the code values of those integers. NULL values are\nskipped. By default, CHAR() returns a binary string. To produce a string in a\ngiven character set, use the optional USING clause:\n\nSELECT CHARSET(CHAR(0x65)), CHARSET(CHAR(0x65 USING utf8));\n+---------------------+--------------------------------+\n| CHARSET(CHAR(0x65)) | CHARSET(CHAR(0x65 USING utf8)) |\n+---------------------+--------------------------------+\n| binary | utf8 |\n+---------------------+--------------------------------+\n\nIf USING is given and the result string is illegal for the given character\nset, a warning is issued. Also, if strict SQL mode is enabled, the result from\nCHAR() becomes NULL.\n\nExamples\n--------\n\nSELECT CHAR(77,97,114,\'105\',97,\'68\',66);\n+----------------------------------+\n| CHAR(77,97,114,\'105\',97,\'68\',66) |\n+----------------------------------+\n| MariaDB |\n+----------------------------------+\n\nSELECT CHAR(77,77.3,\'77.3\');\n+----------------------+\n| CHAR(77,77.3,\'77.3\') |\n+----------------------+\n| MMM |\n+----------------------+\n1 row in set, 1 warning (0.00 sec)\n\nWarning (Code 1292): Truncated incorrect INTEGER value: \'77.3\'\n\nURL: https://mariadb.com/kb/en/char-function/','','https://mariadb.com/kb/en/char-function/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (639,36,'CHAR_LENGTH','Syntax\n------\n\nCHAR_LENGTH(str)\nCHARACTER_LENGTH(str)\n\nDescription\n-----------\n\nReturns the length of the given string argument, measured in characters. A\nmulti-byte character counts as a single character. This means that for a\nstring containing five two-byte characters, LENGTH() (or OCTET_LENGTH() in\nOracle mode) returns 10, whereas CHAR_LENGTH() returns 5. If the argument is\nNULL, it returns NULL.\n\nIf the argument is not a string value, it is converted into a string.\n\nIt is synonymous with the CHARACTER_LENGTH() function.\n\nExamples\n--------\n\nSELECT CHAR_LENGTH(\'MariaDB\');\n+------------------------+\n| CHAR_LENGTH(\'MariaDB\') |\n+------------------------+\n| 7 |\n+------------------------+\n\nWhen Oracle mode from MariaDB 10.3 is not set:\n\nSELECT CHAR_LENGTH(\'π\'), LENGTH(\'π\'), LENGTHB(\'π\'), OCTET_LENGTH(\'π\');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH(\'π\') | LENGTH(\'π\') | LENGTHB(\'π\') | OCTET_LENGTH(\'π\') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 2 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nIn Oracle mode from MariaDB 10.3:\n\nSELECT CHAR_LENGTH(\'π\'), LENGTH(\'π\'), LENGTHB(\'π\'), OCTET_LENGTH(\'π\');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH(\'π\') | LENGTH(\'π\') | LENGTHB(\'π\') | OCTET_LENGTH(\'π\') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 1 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nURL: https://mariadb.com/kb/en/char_length/','','https://mariadb.com/kb/en/char_length/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (640,36,'CHR','MariaDB starting with 10.3.1\n----------------------------\nThe CHR() function was introduced in MariaDB 10.3.1 to provide Oracle\ncompatibility\n\nSyntax\n------\n\nCHR(N)\n\nDescription\n-----------\n\nCHR() interprets each argument N as an integer and returns a VARCHAR(1) string\nconsisting of the character given by the code values of the integer. The\ncharacter set and collation of the string are set according to the values of\nthe character_set_database and collation_database system variables.\n\nCHR() is similar to the CHAR() function, but only accepts a single argument.\n\nCHR() is available in all sql_modes.\n\nExamples\n--------\n\nSELECT CHR(67);\n+---------+\n| CHR(67) |\n+---------+\n| C |\n+---------+\n\nSELECT CHR(\'67\');\n+-----------+\n| CHR(\'67\') |\n+-----------+\n| C |\n+-----------+\n\nSELECT CHR(\'C\');\n+----------+\n| CHR(\'C\') |\n+----------+\n| |\n+----------+\n1 row in set, 1 warning (0.000 sec)\n\nSHOW WARNINGS;\n+---------+------+----------------------------------------+\n| Level | Code | Message |\n+---------+------+----------------------------------------+\n| Warning | 1292 | Truncated incorrect INTEGER value: \'C\' |\n+---------+------+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/chr/','','https://mariadb.com/kb/en/chr/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (641,36,'CONCAT','Syntax\n------\n\nCONCAT(str1,str2,...)\n\nDescription\n-----------\n\nReturns the string that results from concatenating the arguments. May have one\nor more arguments. If all arguments are non-binary strings, the result is a\nnon-binary string. If the arguments include any binary strings, the result is\na binary string. A numeric argument is converted to its equivalent binary\nstring form; if you want to avoid that, you can use an explicit type cast, as\nin this example:\n\nSELECT CONCAT(CAST(int_col AS CHAR), char_col);\n\nCONCAT() returns NULL if any argument is NULL.\n\nA NULL parameter hides all information contained in other parameters from the\nresult. Sometimes this is not desirable; to avoid this, you can:\n\n* Use the CONCAT_WS() function with an empty separator, because that function\nis NULL-safe.\n* Use IFNULL() to turn NULLs into empty strings.\n\nOracle Mode\n-----------\n\nMariaDB starting with 10.3\n--------------------------\nIn Oracle mode from MariaDB 10.3, CONCAT ignores NULL.\n\nExamples\n--------\n\nSELECT CONCAT(\'Ma\', \'ria\', \'DB\');\n+---------------------------+\n| CONCAT(\'Ma\', \'ria\', \'DB\') |\n+---------------------------+\n| MariaDB |\n+---------------------------+\n\nSELECT CONCAT(\'Ma\', \'ria\', NULL, \'DB\');\n+---------------------------------+\n| CONCAT(\'Ma\', \'ria\', NULL, \'DB\') |\n+---------------------------------+\n| NULL |\n+---------------------------------+\n\nSELECT CONCAT(42.0);\n+--------------+\n| CONCAT(42.0) |\n+--------------+\n| 42.0 |\n+--------------+\n\nUsing IFNULL() to handle NULLs:\n\nSELECT CONCAT(\'The value of @v is: \', IFNULL(@v, \'\'));\n+------------------------------------------------+\n| CONCAT(\'The value of @v is: \', IFNULL(@v, \'\')) |\n+------------------------------------------------+\n| The value of @v is: |\n+------------------------------------------------+\n\nIn Oracle mode, from MariaDB 10.3:\n\nSELECT CONCAT(\'Ma\', \'ria\', NULL, \'DB\');\n+---------------------------------+\n| CONCAT(\'Ma\', \'ria\', NULL, \'DB\') |\n+---------------------------------+\n| MariaDB |\n+---------------------------------+\n\nURL: https://mariadb.com/kb/en/concat/','','https://mariadb.com/kb/en/concat/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (642,36,'CONCAT_WS','Syntax\n------\n\nCONCAT_WS(separator,str1,str2,...)\n\nDescription\n-----------\n\nCONCAT_WS() stands for Concatenate With Separator and is a special form of\nCONCAT(). The first argument is the separator for the rest of the arguments.\nThe separator is added between the strings to be concatenated. The separator\ncan be a string, as can the rest of the arguments.\n\nIf the separator is NULL, the result is NULL; all other NULL values are\nskipped. This makes CONCAT_WS() suitable when you want to concatenate some\nvalues and avoid losing all information if one of them is NULL.\n\nExamples\n--------\n\nSELECT CONCAT_WS(\',\',\'First name\',\'Second name\',\'Last Name\');\n+-------------------------------------------------------+\n| CONCAT_WS(\',\',\'First name\',\'Second name\',\'Last Name\') |\n+-------------------------------------------------------+\n| First name,Second name,Last Name |\n+-------------------------------------------------------+\n\nSELECT CONCAT_WS(\'-\',\'Floor\',NULL,\'Room\');\n+------------------------------------+\n| CONCAT_WS(\'-\',\'Floor\',NULL,\'Room\') |\n+------------------------------------+\n| Floor-Room |\n+------------------------------------+\n\nIn some cases, remember to include a space in the separator string:\n\nSET @a = \'gnu\', @b = \'penguin\', @c = \'sea lion\';\nQuery OK, 0 rows affected (0.00 sec)\n\nSELECT CONCAT_WS(\', \', @a, @b, @c);\n+-----------------------------+\n| CONCAT_WS(\', \', @a, @b, @c) |\n+-----------------------------+\n| gnu, penguin, sea lion |\n+-----------------------------+\n\nUsing CONCAT_WS() to handle NULLs:\n\nSET @a = \'a\', @b = NULL, @c = \'c\';\n\nSELECT CONCAT_WS(\'\', @a, @b, @c);\n+---------------------------+\n| CONCAT_WS(\'\', @a, @b, @c) |\n+---------------------------+\n| ac |\n+---------------------------+\n\nURL: https://mariadb.com/kb/en/concat_ws/','','https://mariadb.com/kb/en/concat_ws/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (643,36,'CONVERT','Syntax\n------\n\nCONVERT(expr,type), CONVERT(expr USING transcoding_name)\n\nDescription\n-----------\n\nThe CONVERT() and CAST() functions take a value of one type and produce a\nvalue of another type.\n\nThe type can be one of the following values:\n\n* BINARY\n* CHAR\n* DATE\n* DATETIME\n* DECIMAL[(M[,D])]\n* DOUBLE\n* FLOAT (from MariaDB 10.4.5)\n* INTEGER\nShort for SIGNED INTEGER\n\n* SIGNED [INTEGER]\n* UNSIGNED [INTEGER]\n* TIME\n* VARCHAR (in Oracle mode, from MariaDB 10.3)\n\nNote that in MariaDB, INT and INTEGER are the same thing.\n\nBINARY produces a string with the BINARY data type. If the optional length is\ngiven, BINARY(N) causes the cast to use no more than N bytes of the argument.\nValues shorter than the given number in bytes are padded with 0x00 bytes to\nmake them equal the length value.\n\nCHAR(N) causes the cast to use no more than the number of characters given in\nthe argument.\n\nThe main difference between the CAST() and CONVERT() is that\nCONVERT(expr,type) is ODBC syntax while CAST(expr as type) and CONVERT(...\nUSING ...) are SQL92 syntax.\n\nCONVERT() with USING is used to convert data between different character sets.\nIn MariaDB, transcoding names are the same as the corresponding character set\nnames. For example, this statement converts the string \'abc\' in the default\ncharacter set to the corresponding string in the utf8 character set:\n\nSELECT CONVERT(\'abc\' USING utf8);\n\nExamples\n--------\n\nSELECT enum_col FROM tbl_name \nORDER BY CAST(enum_col AS CHAR);\n\nConverting a BINARY to string to permit the LOWER function to work:\n\nSET @x = \'AardVark\';\n\nSET @x = BINARY \'AardVark\';\n\nSELECT LOWER(@x), LOWER(CONVERT (@x USING latin1));\n+-----------+----------------------------------+\n| LOWER(@x) | LOWER(CONVERT (@x USING latin1)) |\n+-----------+----------------------------------+\n| AardVark | aardvark |\n+-----------+----------------------------------+\n\nURL: https://mariadb.com/kb/en/convert/','','https://mariadb.com/kb/en/convert/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (644,36,'ELT','Syntax\n------\n\nELT(N, str1[, str2, str3,...])\n\nDescription\n-----------\n\nTakes a numeric argument and a series of string arguments. Returns the string\nthat corresponds to the given numeric position. For instance, it returns str1\nif N is 1, str2 if N is 2, and so on. If the numeric argument is a FLOAT,\nMariaDB rounds it to the nearest INTEGER. If the numeric argument is less than\n1, greater than the total number of arguments, or not a number, ELT() returns\nNULL. It must have at least two arguments.\n\nIt is complementary to the FIELD() function.\n\nExamples\n--------\n\nSELECT ELT(1, \'ej\', \'Heja\', \'hej\', \'foo\');\n+------------------------------------+\n| ELT(1, \'ej\', \'Heja\', \'hej\', \'foo\') |\n+------------------------------------+\n| ej |\n+------------------------------------+\n\nSELECT ELT(4, \'ej\', \'Heja\', \'hej\', \'foo\');\n+------------------------------------+\n| ELT(4, \'ej\', \'Heja\', \'hej\', \'foo\') |\n+------------------------------------+\n| foo |\n+------------------------------------+\n\nURL: https://mariadb.com/kb/en/elt/','','https://mariadb.com/kb/en/elt/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (645,36,'EXPORT_SET','Syntax\n------\n\nEXPORT_SET(bits, on, off[, separator[, number_of_bits]])\n\nDescription\n-----------\n\nTakes a minimum of three arguments. Returns a string where each bit in the\ngiven bits argument is returned, with the string values given for on and off.\n\nBits are examined from right to left, (from low-order to high-order bits).\nStrings are added to the result from left to right, separated by a separator\nstring (defaults as \',\'). You can optionally limit the number of bits the\nEXPORT_SET() function examines using the number_of_bits option.\n\nIf any of the arguments are set as NULL, the function returns NULL.\n\nExamples\n--------\n\nSELECT EXPORT_SET(5,\'Y\',\'N\',\',\',4);\n+-----------------------------+\n| EXPORT_SET(5,\'Y\',\'N\',\',\',4) |\n+-----------------------------+\n| Y,N,Y,N |\n+-----------------------------+\n\nSELECT EXPORT_SET(6,\'1\',\'0\',\',\',10);\n+------------------------------+\n| EXPORT_SET(6,\'1\',\'0\',\',\',10) |\n+------------------------------+\n| 0,1,1,0,0,0,0,0,0,0 |\n+------------------------------+\n\nURL: https://mariadb.com/kb/en/export_set/','','https://mariadb.com/kb/en/export_set/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (646,36,'EXTRACTVALUE','Syntax\n------\n\nEXTRACTVALUE(xml_frag, xpath_expr)\n\nDescription\n-----------\n\nThe EXTRACTVALUE() function takes two string arguments: a fragment of XML\nmarkup and an XPath expression, (also known as a locator). It returns the text\n(That is, CDDATA), of the first text node which is a child of the element or\nelements matching the XPath expression.\n\nIn cases where a valid XPath expression does not match any text nodes in a\nvalid XML fragment, (including the implicit /text() expression), the\nEXTRACTVALUE() function returns an empty string.\n\nInvalid Arguments\n-----------------\n\nWhen either the XML fragment or the XPath expression is NULL, the\nEXTRACTVALUE() function returns NULL. When the XML fragment is invalid, it\nraises a warning Code 1525:\n\nWarning (Code 1525): Incorrect XML value: \'parse error at line 1 pos 11:\nunexpected END-OF-INPUT\'\n\nWhen the XPath value is invalid, it generates an Error 1105:\n\nERROR 1105 (HY000): XPATH syntax error: \')\'\n\nExplicit text() Expressions\n---------------------------\n\nThis function is the equivalent of performing a match using the XPath\nexpression after appending /text(). In other words:\n\nSELECT\n EXTRACTVALUE(\'<cases><case>example</case></cases>\', \'/cases/case\')\n AS \'Base Example\',\n EXTRACTVALUE(\'<cases><case>example</case></cases>\', \'/cases/case/text()\')\n AS \'text() Example\';\n+--------------+----------------+\n| Base Example | text() Example |\n+--------------+----------------+\n| example | example |\n+--------------+----------------+\n\nCount Matches\n-------------\n\nWhen EXTRACTVALUE() returns multiple matches, it returns the content of the\nfirst child text node of each matching element, in the matched order, as a\nsingle, space-delimited string.\n\nBy design, the EXTRACTVALUE() function makes no distinction between a match on\nan empty element and no match at all. If you need to determine whether no\nmatching element was found in the XML fragment or if an element was found that\ncontained no child text nodes, use the XPath count() function.\n\nFor instance, when looking for a value that exists, but contains no child text\nnodes, you would get a count of the number of matching instances:\n\nSELECT\n EXTRACTVALUE(\'<cases><case/></cases>\', \'/cases/case\')\n AS \'Empty Example\',\n EXTRACTVALUE(\'<cases><case/></cases>\', \'count(/cases/case)\')\n AS \'count() Example\';\n+---------------+-----------------+\n| Empty Example | count() Example |\n+---------------+-----------------+\n| | 1 |\n+---------------+-----------------+\n\nAlternatively, when looking for a value that doesn\'t exist, count() returns 0.\n\nSELECT\n EXTRACTVALUE(\'<cases><case/></cases>\', \'/cases/person\')\n AS \'No Match Example\',\n EXTRACTVALUE(\'<cases><case/></cases>\', \'count(/cases/person)\')\n AS \'count() Example\';\n+------------------+-----------------+\n| No Match Example | count() Example |\n+------------------+-----------------+\n| | 0|\n+------------------+-----------------+\n\nMatches\n-------\n\nImportant: The EXTRACTVALUE() function only returns CDDATA. It does not return\ntags that the element might contain or the text that these child elements\ncontain.\n\nSELECT\n\nEXTRACTVALUE(\'<cases><case>Person<email>x@example.com</email></case></cases>\',\n\'/cases\')\n AS Case;\n+--------+\n| Case |\n+--------+\n| Person |\n+--------+\n\nNote, in the above example, while the XPath expression matches to the parent\n<case> instance, it does not return the contained <email> tag or its content.\n\nExamples\n--------\n\nSELECT\n ExtractValue(\'<a>ccc<b>ddd</b></a>\', \'/a\') AS val1,\n ExtractValue(\'<a>ccc<b>ddd</b></a>\', \'/a/b\') AS val2,\n ExtractValue(\'<a>ccc<b>ddd</b></a>\', \'//b\') AS val3,\n ExtractValue(\'<a>ccc<b>ddd</b></a>\', \'/b\') AS val4,\n ExtractValue(\'<a>ccc<b>ddd</b><b>eee</b></a>\', \'//b\') AS val5;\n+------+------+------+------+---------+\n| val1 | val2 | val3 | val4 | val5 |\n+------+------+------+------+---------+\n| ccc | ddd | ddd | | ddd eee |\n+------+------+------+------+---------+\n\nURL: https://mariadb.com/kb/en/extractvalue/','','https://mariadb.com/kb/en/extractvalue/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (647,36,'FIELD','Syntax\n------\n\nFIELD(pattern, str1[,str2,...])\n\nDescription\n-----------\n\nReturns the index position of the string or number matching the given pattern.\nReturns 0 in the event that none of the arguments match the pattern. Raises an\nError 1582 if not given at least two arguments.\n\nWhen all arguments given to the FIELD() function are strings, they are treated\nas case-insensitive. When all the arguments are numbers, they are treated as\nnumbers. Otherwise, they are treated as doubles.\n\nIf the given pattern occurs more than once, the FIELD() function only returns\nthe index of the first instance. If the given pattern is NULL, the function\nreturns 0, as a NULL pattern always fails to match.\n\nThis function is complementary to the ELT() function.\n\nExamples\n--------\n\nSELECT FIELD(\'ej\', \'Hej\', \'ej\', \'Heja\', \'hej\', \'foo\') \n AS \'Field Results\';\n+---------------+\n| Field Results | \n+---------------+\n| 2 |\n+---------------+\n\nSELECT FIELD(\'fo\', \'Hej\', \'ej\', \'Heja\', \'hej\', \'foo\')\n AS \'Field Results\';\n+---------------+\n| Field Results | \n+---------------+\n| 0 |\n+---------------+\n\nSELECT FIELD(1, 2, 3, 4, 5, 1) AS \'Field Results\';\n+---------------+\n| Field Results |\n+---------------+\n| 5 |\n+---------------+\n\nSELECT FIELD(NULL, 2, 3) AS \'Field Results\';\n+---------------+\n| Field Results |\n+---------------+\n| 0 |\n+---------------+\n\nSELECT FIELD(\'fail\') AS \'Field Results\';\nError 1582 (42000): Incorrect parameter count in call\nto native function \'field\'\n\nURL: https://mariadb.com/kb/en/field/','','https://mariadb.com/kb/en/field/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (648,36,'FIND_IN_SET','Syntax\n------\n\nFIND_IN_SET(pattern, strlist)\n\nDescription\n-----------\n\nReturns the index position where the given pattern occurs in a string list.\nThe first argument is the pattern you want to search for. The second argument\nis a string containing comma-separated variables. If the second argument is of\nthe SET data-type, the function is optimized to use bit arithmetic.\n\nIf the pattern does not occur in the string list or if the string list is an\nempty string, the function returns 0. If either argument is NULL, the function\nreturns NULL. The function does not return the correct result if the pattern\ncontains a comma (\",\") character.\n\nExamples\n--------\n\nSELECT FIND_IN_SET(\'b\',\'a,b,c,d\') AS \"Found Results\";\n+---------------+\n| Found Results |\n+---------------+\n| 2 |\n+---------------+\n\nURL: https://mariadb.com/kb/en/find_in_set/','','https://mariadb.com/kb/en/find_in_set/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (649,36,'FORMAT','Syntax\n------\n\nFORMAT(num, decimal_position[, locale])\n\nDescription\n-----------\n\nFormats the given number for display as a string, adding separators to\nappropriate position and rounding the results to the given decimal position.\nFor instance, it would format 15233.345 to 15,233.35.\n\nIf the given decimal position is 0, it rounds to return no decimal point or\nfractional part. You can optionally specify a locale value to format numbers\nto the pattern appropriate for the given region.\n\nExamples\n--------\n\nSELECT FORMAT(1234567890.09876543210, 4) AS \'Format\';\n+--------------------+\n| Format |\n+--------------------+\n| 1,234,567,890.0988 |\n+--------------------+\n\nSELECT FORMAT(1234567.89, 4) AS \'Format\';\n+----------------+\n| Format |\n+----------------+\n| 1,234,567.8900 |\n+----------------+\n\nSELECT FORMAT(1234567.89, 0) AS \'Format\';\n+-----------+\n| Format |\n+-----------+\n| 1,234,568 |\n+-----------+\n\nSELECT FORMAT(123456789,2,\'rm_CH\') AS \'Format\';\n+----------------+\n| Format |\n+----------------+\n| 123\'456\'789,00 |\n+----------------+\n\nURL: https://mariadb.com/kb/en/format/','','https://mariadb.com/kb/en/format/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (650,36,'FROM_BASE64','Syntax\n------\n\nFROM_BASE64(str)\n\nDescription\n-----------\n\nDecodes the given base-64 encode string, returning the result as a binary\nstring. Returns NULL if the given string is NULL or if it\'s invalid.\n\nIt is the reverse of the TO_BASE64 function.\n\nThere are numerous methods to base-64 encode a string. MariaDB uses the\nfollowing:\n\n* It encodes alphabet value 64 as \'+\'.\n* It encodes alphabet value 63 as \'/\'.\n* It codes output in groups of four printable characters. Each three byte of\ndata encoded uses four characters. If the final group is incomplete, it pads\nthe difference with the \'=\' character.\n* It divides long output, adding a new line very 76 characters.\n* In decoding, it recognizes and ignores newlines, carriage returns, tabs and\nspace whitespace characters.\n\nSELECT TO_BASE64(\'Maria\') AS \'Input\';\n+-----------+\n| Input |\n+-----------+\n| TWFyaWE= |\n+-----------+\n\nSELECT FROM_BASE64(\'TWFyaWE=\') AS \'Output\';\n+--------+\n| Output |\n+--------+\n| Maria |\n+--------+\n\nURL: https://mariadb.com/kb/en/from_base64/','','https://mariadb.com/kb/en/from_base64/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (651,36,'HEX','Syntax\n------\n\nHEX(N_or_S)\n\nDescription\n-----------\n\nIf N_or_S is a number, returns a string representation of the hexadecimal\nvalue of N, where N is a longlong (BIGINT) number. This is equivalent to\nCONV(N,10,16).\n\nIf N_or_S is a string, returns a hexadecimal string representation of N_or_S\nwhere each byte of each character in N_or_S is converted to two hexadecimal\ndigits. If N_or_S is NULL, returns NULL. The inverse of this operation is\nperformed by the UNHEX() function.\n\nMariaDB starting with 10.5.0\n----------------------------\nHEX() with an INET6 argument returns a hexadecimal representation of the\nunderlying 16-byte binary string.\n\nExamples\n--------\n\nSELECT HEX(255);\n+----------+\n| HEX(255) |\n+----------+\n| FF |\n+----------+\n\nSELECT 0x4D617269614442;\n+------------------+\n| 0x4D617269614442 |\n+------------------+\n| MariaDB |\n+------------------+\n\nSELECT HEX(\'MariaDB\');\n+----------------+\n| HEX(\'MariaDB\') |\n+----------------+\n| 4D617269614442 |\n+----------------+\n\nFrom MariaDB 10.5.0:\n\nSELECT HEX(CAST(\'2001:db8::ff00:42:8329\' AS INET6));\n+----------------------------------------------+\n| HEX(CAST(\'2001:db8::ff00:42:8329\' AS INET6)) |\n+----------------------------------------------+\n| 20010DB8000000000000FF0000428329 |\n+----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/hex/','','https://mariadb.com/kb/en/hex/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (652,36,'INSTR','Syntax\n------\n\nINSTR(str,substr)\n\nDescription\n-----------\n\nReturns the position of the first occurrence of substring substr in string\nstr. This is the same as the two-argument form of LOCATE(), except that the\norder of the arguments is reversed.\n\nINSTR() performs a case-insensitive search.\n\nIf any argument is NULL, returns NULL.\n\nExamples\n--------\n\nSELECT INSTR(\'foobarbar\', \'bar\');\n+---------------------------+\n| INSTR(\'foobarbar\', \'bar\') |\n+---------------------------+\n| 4 |\n+---------------------------+\n\nSELECT INSTR(\'My\', \'Maria\');\n+----------------------+\n| INSTR(\'My\', \'Maria\') |\n+----------------------+\n| 0 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/instr/','','https://mariadb.com/kb/en/instr/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (653,36,'LCASE','Syntax\n------\n\nLCASE(str)\n\nDescription\n-----------\n\nLCASE() is a synonym for LOWER().\n\nURL: https://mariadb.com/kb/en/lcase/','','https://mariadb.com/kb/en/lcase/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (654,36,'LEFT','Syntax\n------\n\nLEFT(str,len)\n\nDescription\n-----------\n\nReturns the leftmost len characters from the string str, or NULL if any\nargument is NULL.\n\nExamples\n--------\n\nSELECT LEFT(\'MariaDB\', 5);\n+--------------------+\n| LEFT(\'MariaDB\', 5) |\n+--------------------+\n| Maria |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/left/','','https://mariadb.com/kb/en/left/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (655,36,'INSERT Function','Syntax\n------\n\nINSERT(str,pos,len,newstr)\n\nDescription\n-----------\n\nReturns the string str, with the substring beginning at position pos and len\ncharacters long replaced by the string newstr. Returns the original string if\npos is not within the length of the string. Replaces the rest of the string\nfrom position pos if len is not within the length of the rest of the string.\nReturns NULL if any argument is NULL.\n\nExamples\n--------\n\nSELECT INSERT(\'Quadratic\', 3, 4, \'What\');\n+-----------------------------------+\n| INSERT(\'Quadratic\', 3, 4, \'What\') |\n+-----------------------------------+\n| QuWhattic |\n+-----------------------------------+\n\nSELECT INSERT(\'Quadratic\', -1, 4, \'What\');\n+------------------------------------+\n| INSERT(\'Quadratic\', -1, 4, \'What\') |\n+------------------------------------+\n| Quadratic |\n+------------------------------------+\n\nSELECT INSERT(\'Quadratic\', 3, 100, \'What\');\n+-------------------------------------+\n| INSERT(\'Quadratic\', 3, 100, \'What\') |\n+-------------------------------------+\n| QuWhat |\n+-------------------------------------+\n\nURL: https://mariadb.com/kb/en/insert-function/','','https://mariadb.com/kb/en/insert-function/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (656,36,'LENGTH','Syntax\n------\n\nLENGTH(str)\n\nDescription\n-----------\n\nReturns the length of the string str.\n\nIn the default mode, when Oracle mode from MariaDB 10.3 is not set, the length\nis measured in bytes. In this case, a multi-byte character counts as multiple\nbytes. This means that for a string containing five two-byte characters,\nLENGTH() returns 10, whereas CHAR_LENGTH() returns 5.\n\nWhen running Oracle mode from MariaDB 10.3, the length is measured in\ncharacters, and LENGTH is a synonym for CHAR_LENGTH().\n\nIf str is not a string value, it is converted into a string. If str is NULL,\nthe function returns NULL.\n\nExamples\n--------\n\nSELECT LENGTH(\'MariaDB\');\n+-------------------+\n| LENGTH(\'MariaDB\') |\n+-------------------+\n| 7 |\n+-------------------+\n\nWhen Oracle mode from MariaDB 10.3 is not set:\n\nSELECT CHAR_LENGTH(\'π\'), LENGTH(\'π\'), LENGTHB(\'π\'), OCTET_LENGTH(\'π\');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH(\'π\') | LENGTH(\'π\') | LENGTHB(\'π\') | OCTET_LENGTH(\'π\') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 2 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nIn Oracle mode from MariaDB 10.3:\n\nSELECT CHAR_LENGTH(\'π\'), LENGTH(\'π\'), LENGTHB(\'π\'), OCTET_LENGTH(\'π\');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH(\'π\') | LENGTH(\'π\') | LENGTHB(\'π\') | OCTET_LENGTH(\'π\') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 1 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nURL: https://mariadb.com/kb/en/length/','','https://mariadb.com/kb/en/length/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (657,36,'LENGTHB','MariaDB starting with 10.3.1\n----------------------------\nIntroduced in MariaDB 10.3.1 as part of the Oracle compatibility enhancements.\n\nSyntax\n------\n\nLENGTHB(str)\n\nDescription\n-----------\n\nLENGTHB() returns the length of the given string, in bytes. When Oracle mode\nis not set, this is a synonym for LENGTH.\n\nA multi-byte character counts as multiple bytes. This means that for a string\ncontaining five two-byte characters, LENGTHB() returns 10, whereas\nCHAR_LENGTH() returns 5.\n\nIf str is not a string value, it is converted into a string. If str is NULL,\nthe function returns NULL.\n\nExamples\n--------\n\nWhen Oracle mode from MariaDB 10.3 is not set:\n\nSELECT CHAR_LENGTH(\'π\'), LENGTH(\'π\'), LENGTHB(\'π\'), OCTET_LENGTH(\'π\');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH(\'π\') | LENGTH(\'π\') | LENGTHB(\'π\') | OCTET_LENGTH(\'π\') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 2 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nIn Oracle mode from MariaDB 10.3:\n\nSELECT CHAR_LENGTH(\'π\'), LENGTH(\'π\'), LENGTHB(\'π\'), OCTET_LENGTH(\'π\');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH(\'π\') | LENGTH(\'π\') | LENGTHB(\'π\') | OCTET_LENGTH(\'π\') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 1 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nURL: https://mariadb.com/kb/en/lengthb/','','https://mariadb.com/kb/en/lengthb/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (658,36,'LIKE','Syntax\n------\n\nexpr LIKE pat [ESCAPE \'escape_char\']\nexpr NOT LIKE pat [ESCAPE \'escape_char\']\n\nDescription\n-----------\n\nTests whether expr matches the pattern pat. Returns either 1 (TRUE) or 0\n(FALSE). Both expr and pat may be any valid expression and are evaluated to\nstrings. Patterns may use the following wildcard characters:\n\n* % matches any number of characters, including zero.\n* _ matches any single character.\n\nUse NOT LIKE to test if a string does not match a pattern. This is equivalent\nto using the NOT operator on the entire LIKE expression.\n\nIf either the expression or the pattern is NULL, the result is NULL.\n\nLIKE performs case-insensitive substring matches if the collation for the\nexpression and pattern is case-insensitive. For case-sensitive matches,\ndeclare either argument to use a binary collation using COLLATE, or coerce\neither of them to a BINARY string using CAST. Use SHOW COLLATION to get a list\nof available collations. Collations ending in _bin are case-sensitive.\n\nNumeric arguments are coerced to binary strings.\n\nThe _ wildcard matches a single character, not byte. It will only match a\nmulti-byte character if it is valid in the expression\'s character set. For\nexample, _ will match _utf8\"€\", but it will not match _latin1\"€\" because the\nEuro sign is not a valid latin1 character. If necessary, use CONVERT to use\nthe expression in a different character set.\n\nIf you need to match the characters _ or %, you must escape them. By default,\nyou can prefix the wildcard characters the backslash character \\ to escape\nthem. The backslash is used both to encode special characters like newlines\nwhen a string is parsed as well as to escape wildcards in a pattern after\nparsing. Thus, to match an actual backslash, you sometimes need to\ndouble-escape it as \"\\\\\\\\\".\n\nTo avoid difficulties with the backslash character, you can change the\nwildcard escape character using ESCAPE in a LIKE expression. The argument to\nESCAPE must be a single-character string.\n\nExamples\n--------\n\nSelect the days that begin with \"T\":\n\nCREATE TABLE t1 (d VARCHAR(16));\nINSERT INTO t1 VALUES \n (\"Monday\"), (\"Tuesday\"), (\"Wednesday\"),\n (\"Thursday\"), (\"Friday\"), (\"Saturday\"), (\"Sunday\");\nSELECT * FROM t1 WHERE d LIKE \"T%\";\n\nSELECT * FROM t1 WHERE d LIKE \"T%\";\n+----------+\n| d |\n+----------+\n| Tuesday |\n| Thursday |\n+----------+\n\nSelect the days that contain the substring \"es\":\n\nSELECT * FROM t1 WHERE d LIKE \"%es%\";\n\nSELECT * FROM t1 WHERE d LIKE \"%es%\";\n+-----------+\n| d |\n+-----------+\n| Tuesday |\n| Wednesday |\n+-----------+\n\nSelect the six-character day names:\n\nSELECT * FROM t1 WHERE d like \"___day\";\n\nSELECT * FROM t1 WHERE d like \"___day\";\n+---------+\n| d |\n+---------+\n| Monday |\n| Friday |\n| Sunday |\n+---------+\n\nWith the default collations, LIKE is case-insensitive:\n\nSELECT * FROM t1 where d like \"t%\";\n\nSELECT * FROM t1 where d like \"t%\";\n+----------+\n| d |\n+----------+\n| Tuesday |\n| Thursday |\n+----------+\n\nUse COLLATE to specify a binary collation, forcing case-sensitive matches:\n\nSELECT * FROM t1 WHERE d like \"t%\" COLLATE latin1_bin;\n\nSELECT * FROM t1 WHERE d like \"t%\" COLLATE latin1_bin;\nEmpty set (0.00 sec)\n\nYou can include functions and operators in the expression to match. Select\ndates based on their day name:\n\nCREATE TABLE t2 (d DATETIME);\nINSERT INTO t2 VALUES\n (\"2007-01-30 21:31:07\"),\n (\"1983-10-15 06:42:51\"),\n (\"2011-04-21 12:34:56\"),\n (\"2011-10-30 06:31:41\"),\n (\"2011-01-30 14:03:25\"),\n (\"2004-10-07 11:19:34\");\nSELECT * FROM t2 WHERE DAYNAME(d) LIKE \"T%\";\n\nSELECT * FROM t2 WHERE DAYNAME(d) LIKE \"T%\";\n+------------------+\n| d |\n+------------------+\n| 2007-01-30 21:31 |\n| 2011-04-21 12:34 |\n| 2004-10-07 11:19 |\n+------------------+\n3 rows in set, 7 warnings (0.00 sec)\n\nOptimizing LIKE\n---------------\n\n* MariaDB can use indexes for LIKE on string columns in the case where the\nLIKE doesn\'t start with % or _.\n* Starting from MariaDB 10.0, one can set the\noptimizer_use_condition_selectivity variable to 5. If this is done, then the\noptimizer will read optimizer_selectivity_sampling_limit rows to calculate the\nselectivity of the LIKE expression before starting to calculate the query\nplan. This can help speed up some LIKE queries by providing the optimizer with\nmore information about your data.\n\nURL: https://mariadb.com/kb/en/like/','','https://mariadb.com/kb/en/like/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (659,36,'LOCATE','Syntax\n------\n\nLOCATE(substr,str), LOCATE(substr,str,pos)\n\nDescription\n-----------\n\nThe first syntax returns the position of the first occurrence of substring\nsubstr in string str. The second syntax returns the position of the first\noccurrence of substring substr in string str, starting at position pos.\nReturns 0 if substr is not in str.\n\nLOCATE() performs a case-insensitive search.\n\nIf any argument is NULL, returns NULL.\n\nINSTR() is the same as the two-argument form of LOCATE(), except that the\norder of the arguments is reversed.\n\nExamples\n--------\n\nSELECT LOCATE(\'bar\', \'foobarbar\');\n+----------------------------+\n| LOCATE(\'bar\', \'foobarbar\') |\n+----------------------------+\n| 4 |\n+----------------------------+\n\nSELECT LOCATE(\'My\', \'Maria\');\n+-----------------------+\n| LOCATE(\'My\', \'Maria\') |\n+-----------------------+\n| 0 |\n+-----------------------+\n\nSELECT LOCATE(\'bar\', \'foobarbar\', 5);\n+-------------------------------+\n| LOCATE(\'bar\', \'foobarbar\', 5) |\n+-------------------------------+\n| 7 |\n+-------------------------------+\n\nURL: https://mariadb.com/kb/en/locate/','','https://mariadb.com/kb/en/locate/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (660,36,'LOWER','Syntax\n------\n\nLOWER(str)\n\nDescription\n-----------\n\nReturns the string str with all characters changed to lowercase according to\nthe current character set mapping. The default is latin1 (cp1252 West\nEuropean).\n\nExamples\n--------\n\nSELECT LOWER(\'QUADRATICALLY\');\n+------------------------+\n| LOWER(\'QUADRATICALLY\') |\n+------------------------+\n| quadratically |\n+------------------------+\n\nLOWER() (and UPPER()) are ineffective when applied to binary strings (BINARY,\nVARBINARY, BLOB). To perform lettercase conversion, CONVERT the string to a\nnon-binary string:\n\nSET @str = BINARY \'North Carolina\';\n\nSELECT LOWER(@str), LOWER(CONVERT(@str USING latin1));\n+----------------+-----------------------------------+\n| LOWER(@str) | LOWER(CONVERT(@str USING latin1)) |\n+----------------+-----------------------------------+\n| North Carolina | north carolina |\n+----------------+-----------------------------------+\n\nURL: https://mariadb.com/kb/en/lower/','','https://mariadb.com/kb/en/lower/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (661,36,'LPAD','Syntax\n------\n\nLPAD(str, len [,padstr])\n\nDescription\n-----------\n\nReturns the string str, left-padded with the string padstr to a length of len\ncharacters. If str is longer than len, the return value is shortened to len\ncharacters. If padstr is omitted, the LPAD function pads spaces.\n\nPrior to MariaDB 10.3.1, the padstr parameter was mandatory.\n\nReturns NULL if given a NULL argument. If the result is empty (zero length),\nreturns either an empty string or, from MariaDB 10.3.6 with SQL_MODE=Oracle,\nNULL.\n\nThe Oracle mode version of the function can be accessed outside of Oracle mode\nby using LPAD_ORACLE as the function name.\n\nExamples\n--------\n\nSELECT LPAD(\'hello\',10,\'.\');\n+----------------------+\n| LPAD(\'hello\',10,\'.\') |\n+----------------------+\n| .....hello |\n+----------------------+\n\nSELECT LPAD(\'hello\',2,\'.\');\n+---------------------+\n| LPAD(\'hello\',2,\'.\') |\n+---------------------+\n| he |\n+---------------------+\n\nFrom MariaDB 10.3.1, with the pad string defaulting to space.\n\nSELECT LPAD(\'hello\',10);\n+------------------+\n| LPAD(\'hello\',10) |\n+------------------+\n| hello |\n+------------------+\n\nOracle mode version from MariaDB 10.3.6:\n\nSELECT LPAD(\'\',0),LPAD_ORACLE(\'\',0);\n+------------+-------------------+\n| LPAD(\'\',0) | LPAD_ORACLE(\'\',0) |\n+------------+-------------------+\n| | NULL |\n+------------+-------------------+\n\nURL: https://mariadb.com/kb/en/lpad/','','https://mariadb.com/kb/en/lpad/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (662,36,'LTRIM','Syntax\n------\n\nLTRIM(str)\n\nDescription\n-----------\n\nReturns the string str with leading space characters removed.\n\nReturns NULL if given a NULL argument. If the result is empty, returns either\nan empty string, or, from MariaDB 10.3.6 with SQL_MODE=Oracle, NULL.\n\nThe Oracle mode version of the function can be accessed outside of Oracle mode\nby using LTRIM_ORACLE as the function name.\n\nExamples\n--------\n\nSELECT QUOTE(LTRIM(\' MariaDB \'));\n+-------------------------------+\n| QUOTE(LTRIM(\' MariaDB \')) |\n+-------------------------------+\n| \'MariaDB \' |\n+-------------------------------+\n\nOracle mode version from MariaDB 10.3.6:\n\nSELECT LTRIM(\'\'),LTRIM_ORACLE(\'\');\n+-----------+------------------+\n| LTRIM(\'\') | LTRIM_ORACLE(\'\') |\n+-----------+------------------+\n| | NULL |\n+-----------+------------------+\n\nURL: https://mariadb.com/kb/en/ltrim/','','https://mariadb.com/kb/en/ltrim/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (663,36,'MAKE_SET','Syntax\n------\n\nMAKE_SET(bits,str1,str2,...)\n\nDescription\n-----------\n\nReturns a set value (a string containing substrings separated by \",\"\ncharacters) consisting of the strings that have the corresponding bit in bits\nset. str1 corresponds to bit 0, str2 to bit 1, and so on. NULL values in str1,\nstr2, ... are not appended to the result.\n\nExamples\n--------\n\nSELECT MAKE_SET(1,\'a\',\'b\',\'c\');\n+-------------------------+\n| MAKE_SET(1,\'a\',\'b\',\'c\') |\n+-------------------------+\n| a |\n+-------------------------+\n\nSELECT MAKE_SET(1 | 4,\'hello\',\'nice\',\'world\');\n+----------------------------------------+\n| MAKE_SET(1 | 4,\'hello\',\'nice\',\'world\') |\n+----------------------------------------+\n| hello,world |\n+----------------------------------------+\n\nSELECT MAKE_SET(1 | 4,\'hello\',\'nice\',NULL,\'world\');\n+---------------------------------------------+\n| MAKE_SET(1 | 4,\'hello\',\'nice\',NULL,\'world\') |\n+---------------------------------------------+\n| hello |\n+---------------------------------------------+\n\nSELECT QUOTE(MAKE_SET(0,\'a\',\'b\',\'c\'));\n+--------------------------------+\n| QUOTE(MAKE_SET(0,\'a\',\'b\',\'c\')) |\n+--------------------------------+\n| \'\' |\n+--------------------------------+\n\nURL: https://mariadb.com/kb/en/make_set/','','https://mariadb.com/kb/en/make_set/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (664,36,'MATCH AGAINST','Syntax\n------\n\nMATCH (col1,col2,...) AGAINST (expr [search_modifier])\n\nDescription\n-----------\n\nA special construct used to perform a fulltext search on a fulltext index.\n\nSee Fulltext Index Overview for a full description, and Full-text Indexes for\nmore articles on the topic.\n\nExamples\n--------\n\nCREATE TABLE ft_myisam(copy TEXT,FULLTEXT(copy)) ENGINE=MyISAM;\n\nINSERT INTO ft_myisam(copy) VALUES (\'Once upon a time\'), (\'There was a wicked\nwitch\'), \n (\'Who ate everybody up\');\n\nSELECT * FROM ft_myisam WHERE MATCH(copy) AGAINST(\'wicked\');\n+--------------------------+\n| copy |\n+--------------------------+\n| There was a wicked witch |\n+--------------------------+\n\nSELECT id, body, MATCH (title,body) AGAINST\n (\'Security implications of running MySQL as root\'\n IN NATURAL LANGUAGE MODE) AS score\n FROM articles WHERE MATCH (title,body) AGAINST\n (\'Security implications of running MySQL as root\'\n IN NATURAL LANGUAGE MODE);\n+----+-------------------------------------+-----------------+\n| id | body | score |\n+----+-------------------------------------+-----------------+\n| 4 | 1. Never run mysqld as root. 2. ... | 1.5219271183014 |\n| 6 | When configured properly, MySQL ... | 1.3114095926285 |\n+----+-------------------------------------+-----------------+\n\nURL: https://mariadb.com/kb/en/match-against/','','https://mariadb.com/kb/en/match-against/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (665,36,'MID','Syntax\n------\n\nMID(str,pos,len)\n\nDescription\n-----------\n\nMID(str,pos,len) is a synonym for SUBSTRING(str,pos,len).\n\nExamples\n--------\n\nSELECT MID(\'abcd\',4,1);\n+-----------------+\n| MID(\'abcd\',4,1) |\n+-----------------+\n| d |\n+-----------------+\n\nSELECT MID(\'abcd\',2,2);\n+-----------------+\n| MID(\'abcd\',2,2) |\n+-----------------+\n| bc |\n+-----------------+\n\nA negative starting position:\n\nSELECT MID(\'abcd\',-2,4);\n+------------------+\n| MID(\'abcd\',-2,4) |\n+------------------+\n| cd |\n+------------------+\n\nURL: https://mariadb.com/kb/en/mid/','','https://mariadb.com/kb/en/mid/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (666,36,'NATURAL_SORT_KEY','MariaDB starting with 10.7.0\n----------------------------\nNATURAL_SORT_KEY was added in MariaDB 10.7.0.\n\nSyntax\n------\n\nNATURAL_SORT_KEY(str)\n\nDescription\n-----------\n\nThe NATURAL_SORT_KEY function is used for sorting that is closer to natural\nsorting. Strings are sorted in alphabetical order, while numbers are treated\nin a way such that, for example, 10 is greater than 2, whereas in other forms\nof sorting, 2 would be greater than 10, just like z is greater than ya.\n\nThere are multiple natural sort implementations, differing in the way they\nhandle leading zeroes, fractions, i18n, negatives, decimals and so on.\n\nMariaDB\'s implementation ignores leading zeroes when performing the sort.\n\nYou can use also use NATURAL_SORT_KEY with generated columns. The value is not\nstored permanently in the table. When using a generated column, the virtual\ncolumn must be longer than the base column to cater for embedded numbers in\nthe string and MDEV-24582.\n\nExamples\n--------\n\nStrings and Numbers\n-------------------\n\nCREATE TABLE t1 (c TEXT);\n\nINSERT INTO t1 VALUES (\'b1\'),(\'a2\'),(\'a11\'),(\'a1\');\n\nSELECT c FROM t1;\n+------+\n| c |\n+------+\n| b1 |\n| a2 |\n| a11 |\n| a1 |\n+------+\n\nSELECT c FROM t1 ORDER BY c;\n+------+\n| c |\n+------+\n| a1 |\n| a11 |\n| a2 |\n| b1 |\n+------+\n\nUnsorted, regular sort and natural sort:\n\nTRUNCATE t1;\n\nINSERT INTO t1 VALUES \n (\'5.5.31\'),(\'10.7.0\'),(\'10.2.1\'),\n (\'10.1.22\'),(\'10.3.32\'),(\'10.2.12\');\n\nSELECT c FROM t1;\n+---------+\n| c |\n+---------+\n| 5.5.31 |\n| 10.7.0 |\n| 10.2.1 |\n| 10.1.22 |\n| 10.3.32 |\n| 10.2.12 |\n+---------+\n\nSELECT c FROM t1 ORDER BY c;\n+---------+\n| c |\n+---------+\n| 10.1.22 |\n| 10.2.1 |\n| 10.2.12 |\n| 10.3.32 |\n| 10.7.0 |\n| 5.5.31 |\n+---------+\n\nSELECT c FROM t1 ORDER BY NATURAL_SORT_KEY(c);\n+---------+\n| c |\n+---------+\n| 5.5.31 |\n| 10.1.22 |\n| 10.2.1 |\n| 10.2.12 |\n| 10.3.32 |\n| 10.7.0 |\n+---------+\n\nIPs\n---\n\nSorting IPs, unsorted, regular sort and natural sort::\n\nTRUNCATE t1;\n\nINSERT INTO t1 VALUES \n (\'192.167.3.1\'),(\'192.167.1.12\'),(\'100.200.300.400\'),\n (\'100.50.60.70\'),(\'100.8.9.9\'),(\'127.0.0.1\'),(\'0.0.0.0\');\n\nSELECT c FROM t1;\n+-----------------+\n| c |\n+-----------------+\n| 192.167.3.1 |\n| 192.167.1.12 |\n| 100.200.300.400 |\n| 100.50.60.70 |\n| 100.8.9.9 |\n| 127.0.0.1 |\n| 0.0.0.0 |\n+-----------------+\n\nSELECT c FROM t1 ORDER BY c;\n+-----------------+\n| c |\n+-----------------+\n| 0.0.0.0 |\n| 100.200.300.400 |\n| 100.50.60.70 |\n| 100.8.9.9 |\n| 127.0.0.1 |\n| 192.167.1.12 |\n| 192.167.3.1 |\n+-----------------+\n\nSELECT c FROM t1 ORDER BY NATURAL_SORT_KEY(c);\n+-----------------+\n| c |\n+-----------------+\n| 0.0.0.0 |\n| 100.8.9.9 |\n| 100.50.60.70 |\n| 100.200.300.400 |\n| 127.0.0.1 |\n| 192.167.1.12 |\n| 192.167.3.1 |\n+-----------------+\n\nGenerated Columns\n-----------------\n\nUsing with a generated column:\n\nCREATE TABLE t(c VARCHAR(3), k VARCHAR(4) AS (NATURAL_SORT_KEY(c)) INVISIBLE);\n\nINSERT INTO t(c) VALUES (\'b1\'),(\'a2\'),(\'a11\'),(\'a10\');\n\nSELECT * FROM t ORDER by k;\n+------+\n| c |\n+------+\n| a2 |\n| a10 |\n| a11 |\n| b1 |\n+------+\n\nNote that if the virtual column is not longer, results may not be as expected:\n\nCREATE TABLE t2(c VARCHAR(3), k VARCHAR(3) AS (NATURAL_SORT_KEY(c)) INVISIBLE);\n\nINSERT INTO t2(c) VALUES (\'b1\'),(\'a2\'),(\'a11\'),(\'a10\');\n\nSELECT * FROM t2 ORDER by k;\n+------+\n| c |\n+------+\n| a2 |\n| a11 |\n| a10 |\n| b1 |\n+------+\n\nLeading Zeroes\n--------------\n\nIgnoring leading zeroes can lead to undesirable results in certain contexts.\nFor example:\n\nCREATE TABLE t3 (a VARCHAR(4));\n\nINSERT INTO t3 VALUES \n (\'a1\'), (\'a001\'), (\'a10\'), (\'a001\'), (\'a10\'),\n (\'a01\'), (\'a01\'), (\'a01b\'), (\'a01b\'), (\'a1\');\n\nSELECT a FROM t3 ORDER BY a;\n+------+\n| a |\n+------+\n| a001 |\n| a001 |\n| a01 |\n| a01 |\n| a01b |\n| a01b |\n| a1 |\n| a1 |\n| a10 |\n| a10 |\n+------+\n10 rows in set (0.000 sec)\n\nSELECT a FROM t3 ORDER BY NATURAL_SORT_KEY(a);\n+------+\n| a |\n+------+\n| a1 |\n| a01 |\n| a01 |\n| a001 |\n| a001 |\n| a1 |\n| a01b |\n| a01b |\n| a10 |\n| a10 |\n+------+\n\nThis may not be what we were hoping for in a \'natural\' sort. A workaround is\nto sort by both NATURAL_SORT_KEY and regular sort.\n\nSELECT a FROM t3 ORDER BY NATURAL_SORT_KEY(a), a;\n+------+\n| a |\n+------+\n| a001 |\n| a001 |\n| a01 |\n| a01 |\n| a1 |\n| a1 |\n| a01b |\n| a01b |\n| a10 |\n| a10 |\n+------+\n\nURL: https://mariadb.com/kb/en/natural_sort_key/','','https://mariadb.com/kb/en/natural_sort_key/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (667,36,'NOT LIKE','Syntax\n------\n\nexpr NOT LIKE pat [ESCAPE \'escape_char\']\n\nDescription\n-----------\n\nThis is the same as NOT (expr LIKE pat [ESCAPE \'escape_char\']).\n\nURL: https://mariadb.com/kb/en/not-like/','','https://mariadb.com/kb/en/not-like/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (668,36,'OCTET_LENGTH','Syntax\n------\n\nOCTET_LENGTH(str)\n\nDescription\n-----------\n\nOCTET_LENGTH() returns the length of the given string, in octets (bytes). This\nis a synonym for LENGTHB(), and, when Oracle mode from MariaDB 10.3 is not\nset, a synonym for LENGTH().\n\nA multi-byte character counts as multiple bytes. This means that for a string\ncontaining five two-byte characters, OCTET_LENGTH() returns 10, whereas\nCHAR_LENGTH() returns 5.\n\nIf str is not a string value, it is converted into a string. If str is NULL,\nthe function returns NULL.\n\nExamples\n--------\n\nWhen Oracle mode from MariaDB 10.3 is not set:\n\nSELECT CHAR_LENGTH(\'π\'), LENGTH(\'π\'), LENGTHB(\'π\'), OCTET_LENGTH(\'π\');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH(\'π\') | LENGTH(\'π\') | LENGTHB(\'π\') | OCTET_LENGTH(\'π\') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 2 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nIn Oracle mode from MariaDB 10.3:\n\nSELECT CHAR_LENGTH(\'π\'), LENGTH(\'π\'), LENGTHB(\'π\'), OCTET_LENGTH(\'π\');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH(\'π\') | LENGTH(\'π\') | LENGTHB(\'π\') | OCTET_LENGTH(\'π\') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 1 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nURL: https://mariadb.com/kb/en/octet_length/','','https://mariadb.com/kb/en/octet_length/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (669,36,'ORD','Syntax\n------\n\nORD(str)\n\nDescription\n-----------\n\nIf the leftmost character of the string str is a multi-byte character, returns\nthe code for that character, calculated from the numeric values of its\nconstituent bytes using this formula:\n\n(1st byte code)\n+ (2nd byte code x 256)\n+ (3rd byte code x 256 x 256) ...\n\nIf the leftmost character is not a multi-byte character, ORD() returns the\nsame value as the ASCII() function.\n\nExamples\n--------\n\nSELECT ORD(\'2\');\n+----------+\n| ORD(\'2\') |\n+----------+\n| 50 |\n+----------+\n\nURL: https://mariadb.com/kb/en/ord/','','https://mariadb.com/kb/en/ord/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (670,36,'POSITION','Syntax\n------\n\nPOSITION(substr IN str)\n\nDescription\n-----------\n\nPOSITION(substr IN str) is a synonym for LOCATE(substr,str).\n\nIt\'s part of ODBC 3.0.\n\nURL: https://mariadb.com/kb/en/position/','','https://mariadb.com/kb/en/position/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (671,36,'QUOTE','Syntax\n------\n\nQUOTE(str)\n\nDescription\n-----------\n\nQuotes a string to produce a result that can be used as a properly escaped\ndata value in an SQL statement. The string is returned enclosed by single\nquotes and with each instance of single quote (\"\'\"), backslash (\"\\\"), ASCII\nNUL, and Control-Z preceded by a backslash. If the argument is NULL, the\nreturn value is the word \"NULL\" without enclosing single quotes.\n\nExamples\n--------\n\nSELECT QUOTE(\"Don\'t!\");\n+-----------------+\n| QUOTE(\"Don\'t!\") |\n+-----------------+\n| \'Don\\\'t!\' |\n+-----------------+\n\nSELECT QUOTE(NULL); \n+-------------+\n| QUOTE(NULL) |\n+-------------+\n| NULL |\n+-------------+\n\nURL: https://mariadb.com/kb/en/quote/','','https://mariadb.com/kb/en/quote/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (672,36,'REPEAT Function','Syntax\n------\n\nREPEAT(str,count)\n\nDescription\n-----------\n\nReturns a string consisting of the string str repeated count times. If count\nis less than 1, returns an empty string. Returns NULL if str or count are NULL.\n\nExamples\n--------\n\nSELECT QUOTE(REPEAT(\'MariaDB \',4));\n+------------------------------------+\n| QUOTE(REPEAT(\'MariaDB \',4)) |\n+------------------------------------+\n| \'MariaDB MariaDB MariaDB MariaDB \' |\n+------------------------------------+\n\nURL: https://mariadb.com/kb/en/repeat-function/','','https://mariadb.com/kb/en/repeat-function/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (673,36,'REPLACE Function','Syntax\n------\n\nREPLACE(str,from_str,to_str)\n\nDescription\n-----------\n\nReturns the string str with all occurrences of the string from_str replaced by\nthe string to_str. REPLACE() performs a case-sensitive match when searching\nfor from_str.\n\nExamples\n--------\n\nSELECT REPLACE(\'www.mariadb.org\', \'w\', \'Ww\');\n+---------------------------------------+\n| REPLACE(\'www.mariadb.org\', \'w\', \'Ww\') |\n+---------------------------------------+\n| WwWwWw.mariadb.org |\n+---------------------------------------+\n\nURL: https://mariadb.com/kb/en/replace-function/','','https://mariadb.com/kb/en/replace-function/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (674,36,'REVERSE','Syntax\n------\n\nREVERSE(str)\n\nDescription\n-----------\n\nReturns the string str with the order of the characters reversed.\n\nExamples\n--------\n\nSELECT REVERSE(\'desserts\');\n+---------------------+\n| REVERSE(\'desserts\') |\n+---------------------+\n| stressed |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/reverse/','','https://mariadb.com/kb/en/reverse/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (675,36,'RIGHT','Syntax\n------\n\nRIGHT(str,len)\n\nDescription\n-----------\n\nReturns the rightmost len characters from the string str, or NULL if any\nargument is NULL.\n\nExamples\n--------\n\nSELECT RIGHT(\'MariaDB\', 2);\n+---------------------+\n| RIGHT(\'MariaDB\', 2) |\n+---------------------+\n| DB |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/right/','','https://mariadb.com/kb/en/right/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (676,36,'RPAD','Syntax\n------\n\nRPAD(str, len [, padstr])\n\nDescription\n-----------\n\nReturns the string str, right-padded with the string padstr to a length of len\ncharacters. If str is longer than len, the return value is shortened to len\ncharacters. If padstr is omitted, the RPAD function pads spaces.\n\nPrior to MariaDB 10.3.1, the padstr parameter was mandatory.\n\nReturns NULL if given a NULL argument. If the result is empty (a length of\nzero), returns either an empty string, or, from MariaDB 10.3.6 with\nSQL_MODE=Oracle, NULL.\n\nThe Oracle mode version of the function can be accessed outside of Oracle mode\nby using RPAD_ORACLE as the function name.\n\nExamples\n--------\n\nSELECT RPAD(\'hello\',10,\'.\');\n+----------------------+\n| RPAD(\'hello\',10,\'.\') |\n+----------------------+\n| hello..... |\n+----------------------+\n\nSELECT RPAD(\'hello\',2,\'.\');\n+---------------------+\n| RPAD(\'hello\',2,\'.\') |\n+---------------------+\n| he |\n+---------------------+\n\nFrom MariaDB 10.3.1, with the pad string defaulting to space.\n\nSELECT RPAD(\'hello\',30);\n+--------------------------------+\n| RPAD(\'hello\',30) |\n+--------------------------------+\n| hello |\n+--------------------------------+\n\nOracle mode version from MariaDB 10.3.6:\n\nSELECT RPAD(\'\',0),RPAD_ORACLE(\'\',0);\n+------------+-------------------+\n| RPAD(\'\',0) | RPAD_ORACLE(\'\',0) |\n+------------+-------------------+\n| | NULL |\n+------------+-------------------+\n\nURL: https://mariadb.com/kb/en/rpad/','','https://mariadb.com/kb/en/rpad/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (677,36,'RTRIM','Syntax\n------\n\nRTRIM(str)\n\nDescription\n-----------\n\nReturns the string str with trailing space characters removed.\n\nReturns NULL if given a NULL argument. If the result is empty, returns either\nan empty string, or, from MariaDB 10.3.6 with SQL_MODE=Oracle, NULL.\n\nThe Oracle mode version of the function can be accessed outside of Oracle mode\nby using RTRIM_ORACLE as the function name.\n\nExamples\n--------\n\nSELECT QUOTE(RTRIM(\'MariaDB \'));\n+-----------------------------+\n| QUOTE(RTRIM(\'MariaDB \')) |\n+-----------------------------+\n| \'MariaDB\' |\n+-----------------------------+\n\nOracle mode version from MariaDB 10.3.6:\n\nSELECT RTRIM(\'\'),RTRIM_ORACLE(\'\');\n+-----------+------------------+\n| RTRIM(\'\') | RTRIM_ORACLE(\'\') |\n+-----------+------------------+\n| | NULL |\n+-----------+------------------+\n\nURL: https://mariadb.com/kb/en/rtrim/','','https://mariadb.com/kb/en/rtrim/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (678,36,'SFORMAT','MariaDB starting with 10.7.0\n----------------------------\nSFORMAT was added in MariaDB 10.7.0.\n\nDescription\n-----------\n\nThe SFORMAT function takes an input string and a formatting specification and\nreturns the string formatted using the rules the user passed in the\nspecification.\n\nIt uses the fmtlib library for Python-like (as well as Rust, C++20, etc)\nstring formatting.\n\nOnly fmtlib 7.0.0+ is supported.\n\nThere is no native support for temporal and decimal values:\n\n* TIME_RESULT is handled as STRING_RESULT\n* DECIMAL_RESULT as REAL_RESULT\n\nExamples\n--------\n\nSELECT SFORMAT(\"The answer is {}.\", 42);\n+----------------------------------+\n| SFORMAT(\"The answer is {}.\", 42) |\n+----------------------------------+\n| The answer is 42. |\n+----------------------------------+\n\nCREATE TABLE test_sformat(mdb_release char(6), mdev int, feature char(20));\n\nINSERT INTO test_sformat VALUES(\'10.7.0\', 25015, \'Python style sformat\'), \n (\'10.7.0\', 4958, \'UUID\');\n\nSELECT * FROM test_sformat;\n+-------------+-------+----------------------+\n| mdb_release | mdev | feature |\n+-------------+-------+----------------------+\n| 10.7.0 | 25015 | Python style sformat |\n| 10.7.0 | 4958 | UUID |\n+-------------+-------+----------------------+\n\nSELECT SFORMAT(\'MariaDB Server {} has a preview for MDEV-{} which is about\n{}\', \n mdb_release, mdev, feature) AS \'Preview Release Examples\'\n FROM test_sformat;\n+------------------------------------------------------------------------------\n---------+\n| Preview Release Examples \n |\n+------------------------------------------------------------------------------\n---------+\n| MariaDB Server 10.7.0 has a preview for MDEV-25015 which is about Python\nstyle sformat |\n| MariaDB Server 10.7.0 has a preview for MDEV-4958 which is about UUID \n |\n+------------------------------------------------------------------------------\n---------+\n\nURL: https://mariadb.com/kb/en/sformat/','','https://mariadb.com/kb/en/sformat/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (679,36,'SOUNDEX','Syntax\n------\n\nSOUNDEX(str)\n\nDescription\n-----------\n\nReturns a soundex string from str. Two strings that sound almost the same\nshould have identical soundex strings. A standard soundex string is four\ncharacters long, but the SOUNDEX() function returns an arbitrarily long\nstring. You can use SUBSTRING() on the result to get a standard soundex\nstring. All non-alphabetic characters in str are ignored. All international\nalphabetic characters outside the A-Z range are treated as vowels.\n\nImportant: When using SOUNDEX(), you should be aware of the following details:\n\n* This function, as currently implemented, is intended to work well with\n strings that are in the English language only. Strings in other languages may\n not produce reasonable results.\n\n* This function implements the original Soundex algorithm, not the more\npopular enhanced version (also described by D. Knuth). The difference is that\noriginal version discards vowels first and duplicates second, whereas the\nenhanced version discards duplicates first and vowels second.\n\nExamples\n--------\n\nSOUNDEX(\'Hello\');\n+------------------+\n| SOUNDEX(\'Hello\') |\n+------------------+\n| H400 |\n+------------------+\n\nSELECT SOUNDEX(\'MariaDB\');\n+--------------------+\n| SOUNDEX(\'MariaDB\') |\n+--------------------+\n| M631 |\n+--------------------+\n\nSELECT SOUNDEX(\'Knowledgebase\');\n+--------------------------+\n| SOUNDEX(\'Knowledgebase\') |\n+--------------------------+\n| K543212 |\n+--------------------------+\n\nSELECT givenname, surname FROM users WHERE SOUNDEX(givenname) =\nSOUNDEX(\"robert\");\n+-----------+---------+\n| givenname | surname |\n+-----------+---------+\n| Roberto | Castro |\n+-----------+---------+\n\nURL: https://mariadb.com/kb/en/soundex/','','https://mariadb.com/kb/en/soundex/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (680,36,'SOUNDS LIKE','Syntax\n------\n\nexpr1 SOUNDS LIKE expr2\n\nDescription\n-----------\n\nThis is the same as SOUNDEX(expr1) = SOUNDEX(expr2).\n\nExample\n-------\n\nSELECT givenname, surname FROM users WHERE givenname SOUNDS LIKE \"robert\";\n+-----------+---------+\n| givenname | surname |\n+-----------+---------+\n| Roberto | Castro |\n+-----------+---------+\n\nURL: https://mariadb.com/kb/en/sounds-like/','','https://mariadb.com/kb/en/sounds-like/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (681,36,'SPACE','Syntax\n------\n\nSPACE(N)\n\nDescription\n-----------\n\nReturns a string consisting of N space characters. If N is NULL, returns NULL.\n\nExamples\n--------\n\nSELECT QUOTE(SPACE(6));\n+-----------------+\n| QUOTE(SPACE(6)) |\n+-----------------+\n| \' \' |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/space/','','https://mariadb.com/kb/en/space/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (682,36,'STRCMP','Syntax\n------\n\nSTRCMP(expr1,expr2)\n\nDescription\n-----------\n\nSTRCMP() returns 0 if the strings are the same, -1 if the first argument is\nsmaller than the second according to the current sort order, and 1 if the\nstrings are otherwise not the same. Returns NULL is either argument is NULL.\n\nExamples\n--------\n\nSELECT STRCMP(\'text\', \'text2\');\n+-------------------------+\n| STRCMP(\'text\', \'text2\') |\n+-------------------------+\n| -1 |\n+-------------------------+\n\nSELECT STRCMP(\'text2\', \'text\');\n+-------------------------+\n| STRCMP(\'text2\', \'text\') |\n+-------------------------+\n| 1 |\n+-------------------------+\n\nSELECT STRCMP(\'text\', \'text\');\n+------------------------+\n| STRCMP(\'text\', \'text\') |\n+------------------------+\n| 0 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/strcmp/','','https://mariadb.com/kb/en/strcmp/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (683,36,'SUBSTR','Description\n-----------\n\nSUBSTR() is a synonym for SUBSTRING().\n\nURL: https://mariadb.com/kb/en/substr/','','https://mariadb.com/kb/en/substr/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (684,36,'SUBSTRING','Syntax\n------\n\nSUBSTRING(str,pos), \nSUBSTRING(str FROM pos), \nSUBSTRING(str,pos,len),\nSUBSTRING(str FROM pos FOR len)\n\nSUBSTR(str,pos), \nSUBSTR(str FROM pos), \nSUBSTR(str,pos,len),\nSUBSTR(str FROM pos FOR len)\n\nDescription\n-----------\n\nThe forms without a len argument return a substring from string str starting\nat position pos.\n\nThe forms with a len argument return a substring len characters long from\nstring str, starting at position pos.\n\nThe forms that use FROM are standard SQL syntax.\n\nIt is also possible to use a negative value for pos. In this case, the\nbeginning of the substring is pos characters from the end of the string,\nrather than the beginning. A negative value may be used for pos in any of the\nforms of this function.\n\nBy default, the position of the first character in the string from which the\nsubstring is to be extracted is reckoned as 1. For Oracle-compatibility, from\nMariaDB 10.3.3, when sql_mode is set to \'oracle\', position zero is treated as\nposition 1 (although the first character is still reckoned as 1).\n\nIf any argument is NULL, returns NULL.\n\nExamples\n--------\n\nSELECT SUBSTRING(\'Knowledgebase\',5);\n+------------------------------+\n| SUBSTRING(\'Knowledgebase\',5) |\n+------------------------------+\n| ledgebase |\n+------------------------------+\n\nSELECT SUBSTRING(\'MariaDB\' FROM 6);\n+-----------------------------+\n| SUBSTRING(\'MariaDB\' FROM 6) |\n+-----------------------------+\n| DB |\n+-----------------------------+\n\nSELECT SUBSTRING(\'Knowledgebase\',3,7);\n+--------------------------------+\n| SUBSTRING(\'Knowledgebase\',3,7) |\n+--------------------------------+\n| owledge |\n+--------------------------------+\n\nSELECT SUBSTRING(\'Knowledgebase\', -4);\n+--------------------------------+\n| SUBSTRING(\'Knowledgebase\', -4) |\n+--------------------------------+\n| base |\n+--------------------------------+\n\nSELECT SUBSTRING(\'Knowledgebase\', -8, 4);\n+-----------------------------------+\n| SUBSTRING(\'Knowledgebase\', -8, 4) |\n+-----------------------------------+\n| edge |\n+-----------------------------------+\n\nSELECT SUBSTRING(\'Knowledgebase\' FROM -8 FOR 4);\n+------------------------------------------+\n| SUBSTRING(\'Knowledgebase\' FROM -8 FOR 4) |\n+------------------------------------------+\n| edge |\n+------------------------------------------+\n\nOracle mode from MariaDB 10.3.3:\n\nSELECT SUBSTR(\'abc\',0,3);\n+-------------------+\n| SUBSTR(\'abc\',0,3) |\n+-------------------+\n| |\n+-------------------+\n\nSELECT SUBSTR(\'abc\',1,2);\n+-------------------+\n| SUBSTR(\'abc\',1,2) |\n+-------------------+\n| ab |\n+-------------------+\n\nSET sql_mode=\'oracle\';\n\nSELECT SUBSTR(\'abc\',0,3);\n+-------------------+\n| SUBSTR(\'abc\',0,3) |\n+-------------------+\n| abc |\n+-------------------+\n\nSELECT SUBSTR(\'abc\',1,2);\n+-------------------+\n| SUBSTR(\'abc\',1,2) |\n+-------------------+\n| ab |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/substring/','','https://mariadb.com/kb/en/substring/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (685,36,'SUBSTRING_INDEX','Syntax\n------\n\nSUBSTRING_INDEX(str,delim,count)\n\nDescription\n-----------\n\nReturns the substring from string str before count occurrences of the\ndelimiter delim. If count is positive, everything to the left of the final\ndelimiter (counting from the left) is returned. If count is negative,\neverything to the right of the final delimiter (counting from the right) is\nreturned. SUBSTRING_INDEX() performs a case-sensitive match when searching for\ndelim.\n\nIf any argument is NULL, returns NULL.\n\nFor example\n\nSUBSTRING_INDEX(\'www.mariadb.org\', \'.\', 2)\n\nmeans \"Return all of the characters up to the 2nd occurrence of .\"\n\nExamples\n--------\n\nSELECT SUBSTRING_INDEX(\'www.mariadb.org\', \'.\', 2);\n+--------------------------------------------+\n| SUBSTRING_INDEX(\'www.mariadb.org\', \'.\', 2) |\n+--------------------------------------------+\n| www.mariadb |\n+--------------------------------------------+\n\nSELECT SUBSTRING_INDEX(\'www.mariadb.org\', \'.\', -2);\n+---------------------------------------------+\n| SUBSTRING_INDEX(\'www.mariadb.org\', \'.\', -2) |\n+---------------------------------------------+\n| mariadb.org |\n+---------------------------------------------+\n\nURL: https://mariadb.com/kb/en/substring_index/','','https://mariadb.com/kb/en/substring_index/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (686,36,'TO_BASE64','Syntax\n------\n\nTO_BASE64(str)\n\nDescription\n-----------\n\nConverts the string argument str to its base-64 encoded form, returning the\nresult as a character string in the connection character set and collation.\n\nThe argument str will be converted to string first if it is not a string. A\nNULL argument will return a NULL result.\n\nThe reverse function, FROM_BASE64(), decodes an encoded base-64 string.\n\nThere are a numerous different methods to base-64 encode a string. The\nfollowing are used by MariaDB and MySQL:\n\n* Alphabet value 64 is encoded as \'+\'.\n* Alphabet value 63 is encoded as \'/\'.\n* Encoding output is made up of groups of four printable characters, with each\nthree bytes of data encoded using four characters. If the final group is not\ncomplete, it is padded with \'=\' characters to make up a length of four.\n* To divide long output, a newline is added after every 76 characters.\n* Decoding will recognize and ignore newlines, carriage returns, tabs, and\nspaces.\n\nExamples\n--------\n\nSELECT TO_BASE64(\'Maria\');\n+--------------------+\n| TO_BASE64(\'Maria\') |\n+--------------------+\n| TWFyaWE= |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/to_base64/','','https://mariadb.com/kb/en/to_base64/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (687,36,'TO_CHAR','MariaDB starting with 10.6.1\n----------------------------\nThe TO_CHAR function was introduced in MariaDB 10.6.1 to enhance Oracle\ncompatibility.\n\nSyntax\n------\n\nTO_CHAR(expr[, fmt])\n\nDescription\n-----------\n\nThe TO_CHAR function converts an expr of type date, datetime, time or\ntimestamp to a string. The optional fmt argument supports\nYYYY/YYY/YY/RRRR/RR/MM/MON/MONTH/MI/DD/DY/HH/HH12/HH24/SS and special\ncharacters. The default value is \"YYYY-MM-DD HH24:MI:SS\".\n\nIn Oracle, TO_CHAR can also be used to convert numbers to strings, but this is\nnot supported in MariaDB and will give an error.\n\nExamples\n--------\n\nSELECT TO_CHAR(\'1980-01-11 04:50:39\', \'YYYY-MM-DD\');\n+----------------------------------------------+\n| TO_CHAR(\'1980-01-11 04:50:39\', \'YYYY-MM-DD\') |\n+----------------------------------------------+\n| 1980-01-11 |\n+----------------------------------------------+\n\nSELECT TO_CHAR(\'1980-01-11 04:50:39\', \'HH24-MI-SS\');\n+----------------------------------------------+\n| TO_CHAR(\'1980-01-11 04:50:39\', \'HH24-MI-SS\') |\n+----------------------------------------------+\n| 04-50-39 |\n+----------------------------------------------+\n\nSELECT TO_CHAR(\'00-01-01 00:00:00\', \'YY-MM-DD HH24:MI:SS\');\n+-----------------------------------------------------+\n| TO_CHAR(\'00-01-01 00:00:00\', \'YY-MM-DD HH24:MI:SS\') |\n+-----------------------------------------------------+\n| 00-01-01 00:00:00 |\n+-----------------------------------------------------+\n\nSELECT TO_CHAR(\'99-12-31 23:59:59\', \'YY-MM-DD HH24:MI:SS\');\n+-----------------------------------------------------+\n| TO_CHAR(\'99-12-31 23:59:59\', \'YY-MM-DD HH24:MI:SS\') |\n+-----------------------------------------------------+\n| 99-12-31 23:59:59 |\n+-----------------------------------------------------+\n\nSELECT TO_CHAR(\'9999-12-31 23:59:59\', \'YY-MM-DD HH24:MI:SS\');\n+-------------------------------------------------------+\n| TO_CHAR(\'9999-12-31 23:59:59\', \'YY-MM-DD HH24:MI:SS\') |\n+-------------------------------------------------------+\n| 99-12-31 23:59:59 |\n+-------------------------------------------------------+\n\nSELECT TO_CHAR(\'21-01-03 08:30:00\', \'Y-MONTH-DY HH:MI:SS\');\n+-----------------------------------------------------+\n| TO_CHAR(\'21-01-03 08:30:00\', \'Y-MONTH-DY HH:MI:SS\') |\n+-----------------------------------------------------+\n| 1-January -Sun 08:30:00 |\n+-----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/to_char/','','https://mariadb.com/kb/en/to_char/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (688,36,'TRIM','Syntax\n------\n\nTRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str), TRIM([remstr FROM] str)\n\nFrom MariaDB 10.3.6\n\nTRIM_ORACLE([{BOTH | LEADING | TRAILING} [remstr] FROM] str), TRIM([remstr\nFROM] str)\n\nDescription\n-----------\n\nReturns the string str with all remstr prefixes or suffixes removed. If none\nof the specifiers BOTH, LEADING, or TRAILING is given, BOTH is assumed. remstr\nis optional and, if not specified, spaces are removed.\n\nReturns NULL if given a NULL argument. If the result is empty, returns either\nan empty string, or, from MariaDB 10.3.6 with SQL_MODE=Oracle, NULL.\nSQL_MODE=Oracle is not set by default.\n\nThe Oracle mode version of the function can be accessed in any mode by using\nTRIM_ORACLE as the function name.\n\nExamples\n--------\n\nSELECT TRIM(\' bar \')\\G\n*************************** 1. row ***************************\nTRIM(\' bar \'): bar\n\nSELECT TRIM(LEADING \'x\' FROM \'xxxbarxxx\')\\G\n*************************** 1. row ***************************\nTRIM(LEADING \'x\' FROM \'xxxbarxxx\'): barxxx\n\nSELECT TRIM(BOTH \'x\' FROM \'xxxbarxxx\')\\G\n*************************** 1. row ***************************\nTRIM(BOTH \'x\' FROM \'xxxbarxxx\'): bar\n\nSELECT TRIM(TRAILING \'xyz\' FROM \'barxxyz\')\\G\n*************************** 1. row ***************************\nTRIM(TRAILING \'xyz\' FROM \'barxxyz\'): barx\n\nFrom MariaDB 10.3.6, with SQL_MODE=Oracle not set:\n\nSELECT TRIM(\'\'),TRIM_ORACLE(\'\');\n+----------+-----------------+\n| TRIM(\'\') | TRIM_ORACLE(\'\') |\n+----------+-----------------+\n| | NULL |\n+----------+-----------------+\n\nFrom MariaDB 10.3.6, with SQL_MODE=Oracle set:\n\nSELECT TRIM(\'\'),TRIM_ORACLE(\'\');\n+----------+-----------------+\n| TRIM(\'\') | TRIM_ORACLE(\'\') |\n+----------+-----------------+\n| NULL | NULL |\n+----------+-----------------+\n\nURL: https://mariadb.com/kb/en/trim/','','https://mariadb.com/kb/en/trim/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (689,36,'UCASE','Syntax\n------\n\nUCASE(str)\n\nDescription\n-----------\n\nUCASE() is a synonym for UPPER().\n\nURL: https://mariadb.com/kb/en/ucase/','','https://mariadb.com/kb/en/ucase/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (690,36,'UNCOMPRESSED_LENGTH','Syntax\n------\n\nUNCOMPRESSED_LENGTH(compressed_string)\n\nDescription\n-----------\n\nReturns the length that the compressed string had before being compressed with\nCOMPRESS().\n\nUNCOMPRESSED_LENGTH() returns NULL or an incorrect result if the string is not\ncompressed.\n\nUntil MariaDB 10.3.1, returns MYSQL_TYPE_LONGLONG, or bigint(10), in all\ncases. From MariaDB 10.3.1, returns MYSQL_TYPE_LONG, or int(10), when the\nresult would fit within 32-bits.\n\nExamples\n--------\n\nSELECT UNCOMPRESSED_LENGTH(COMPRESS(REPEAT(\'a\',30)));\n+-----------------------------------------------+\n| UNCOMPRESSED_LENGTH(COMPRESS(REPEAT(\'a\',30))) |\n+-----------------------------------------------+\n| 30 |\n+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/uncompressed_length/','','https://mariadb.com/kb/en/uncompressed_length/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (691,36,'UNHEX','Syntax\n------\n\nUNHEX(str)\n\nDescription\n-----------\n\nPerforms the inverse operation of HEX(str). That is, it interprets each pair\nof hexadecimal digits in the argument as a number and converts it to the\ncharacter represented by the number. The resulting characters are returned as\na binary string.\n\nIf str is NULL, UNHEX() returns NULL.\n\nExamples\n--------\n\nSELECT HEX(\'MariaDB\');\n+----------------+\n| HEX(\'MariaDB\') |\n+----------------+\n| 4D617269614442 |\n+----------------+\n\nSELECT UNHEX(\'4D617269614442\');\n+-------------------------+\n| UNHEX(\'4D617269614442\') |\n+-------------------------+\n| MariaDB |\n+-------------------------+\n\nSELECT 0x4D617269614442;\n+------------------+\n| 0x4D617269614442 |\n+------------------+\n| MariaDB |\n+------------------+\n\nSELECT UNHEX(HEX(\'string\'));\n+----------------------+\n| UNHEX(HEX(\'string\')) |\n+----------------------+\n| string |\n+----------------------+\n\nSELECT HEX(UNHEX(\'1267\'));\n+--------------------+\n| HEX(UNHEX(\'1267\')) |\n+--------------------+\n| 1267 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/unhex/','','https://mariadb.com/kb/en/unhex/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (692,36,'UPDATEXML','Syntax\n------\n\nUpdateXML(xml_target, xpath_expr, new_xml)\n\nDescription\n-----------\n\nThis function replaces a single portion of a given fragment of XML markup\nxml_target with a new XML fragment new_xml, and then returns the changed XML.\nThe portion of xml_target that is replaced matches an XPath expression\nxpath_expr supplied by the user. If no expression matching xpath_expr is\nfound, or if multiple matches are found, the function returns the original\nxml_target XML fragment. All three arguments should be strings.\n\nExamples\n--------\n\nSELECT\n UpdateXML(\'<a><b>ccc</b><d></d></a>\', \'/a\', \'<e>fff</e>\') AS val1,\n UpdateXML(\'<a><b>ccc</b><d></d></a>\', \'/b\', \'<e>fff</e>\') AS val2,\n UpdateXML(\'<a><b>ccc</b><d></d></a>\', \'//b\', \'<e>fff</e>\') AS val3,\n UpdateXML(\'<a><b>ccc</b><d></d></a>\', \'/a/d\', \'<e>fff</e>\') AS val4,\n UpdateXML(\'<a><d></d><b>ccc</b><d></d></a>\', \'/a/d\', \'<e>fff</e>\') AS val5\n \\G\n*************************** 1. row ***************************\nval1: <e>fff</e>\nval2: <a><b>ccc</b><d></d></a>\nval3: <a><e>fff</e><d></d></a>\nval4: <a><b>ccc</b><e>fff</e></a>\nval5: <a><d></d><b>ccc</b><d></d></a>\n1 row in set (0.00 sec)\n\nURL: https://mariadb.com/kb/en/updatexml/','','https://mariadb.com/kb/en/updatexml/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (693,36,'UPPER','Syntax\n------\n\nUPPER(str)\n\nDescription\n-----------\n\nReturns the string str with all characters changed to uppercase according to\nthe current character set mapping. The default is latin1 (cp1252 West\nEuropean).\n\nSELECT UPPER(surname), givenname FROM users ORDER BY surname;\n+----------------+------------+\n| UPPER(surname) | givenname |\n+----------------+------------+\n| ABEL | Jacinto |\n| CASTRO | Robert |\n| COSTA | Phestos |\n| MOSCHELLA | Hippolytos |\n+----------------+------------+\n\nUPPER() is ineffective when applied to binary strings (BINARY, VARBINARY,\nBLOB). The description of LOWER() shows how to perform lettercase conversion\nof binary strings.\n\nURL: https://mariadb.com/kb/en/upper/','','https://mariadb.com/kb/en/upper/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (694,36,'WEIGHT_STRING','Syntax\n------\n\nWEIGHT_STRING(str [AS {CHAR|BINARY}(N)] [LEVEL levels] [flags])\n levels: N [ASC|DESC|REVERSE] [, N [ASC|DESC|REVERSE]] ...\n\nDescription\n-----------\n\nReturns a binary string representing the string\'s sorting and comparison\nvalue. A string with a lower result means that for sorting purposes the string\nappears before a string with a higher result.\n\nWEIGHT_STRING() is particularly useful when adding new collations, for testing\npurposes.\n\nIf str is a non-binary string (CHAR, VARCHAR or TEXT), WEIGHT_STRING returns\nthe string\'s collation weight. If str is a binary string (BINARY, VARBINARY or\nBLOB), the return value is simply the input value, since the weight for each\nbyte in a binary string is the byte value.\n\nWEIGHT_STRING() returns NULL if given a NULL input.\n\nThe optional AS clause permits casting the input string to a binary or\nnon-binary string, as well as to a particular length.\n\nAS BINARY(N) measures the length in bytes rather than characters, and right\npads with 0x00 bytes to the desired length.\n\nAS CHAR(N) measures the length in characters, and right pads with spaces to\nthe desired length.\n\nN has a minimum value of 1, and if it is less than the length of the input\nstring, the string is truncated without warning.\n\nThe optional LEVEL clause specifies that the return value should contain\nweights for specific collation levels. The levels specifier can either be a\nsingle integer, a comma-separated list of integers, or a range of integers\nseparated by a dash (whitespace is ignored). Integers can range from 1 to a\nmaximum of 6, dependent on the collation, and need to be listed in ascending\norder.\n\nIf the LEVEL clause is no provided, a default of 1 to the maximum for the\ncollation is assumed.\n\nIf the LEVEL is specified without using a range, an optional modifier is\npermitted.\n\nASC, the default, returns the weights without any modification.\n\nDESC returns bitwise-inverted weights.\n\nREVERSE returns the weights in reverse order.\n\nExamples\n--------\n\nThe examples below use the HEX() function to represent non-printable results\nin hexadecimal format.\n\nSELECT HEX(WEIGHT_STRING(\'x\'));\n+-------------------------+\n| HEX(WEIGHT_STRING(\'x\')) |\n+-------------------------+\n| 0058 |\n+-------------------------+\n\nSELECT HEX(WEIGHT_STRING(\'x\' AS BINARY(4)));\n+--------------------------------------+\n| HEX(WEIGHT_STRING(\'x\' AS BINARY(4))) |\n+--------------------------------------+\n| 78000000 |\n+--------------------------------------+\n\nSELECT HEX(WEIGHT_STRING(\'x\' AS CHAR(4)));\n+------------------------------------+\n| HEX(WEIGHT_STRING(\'x\' AS CHAR(4))) |\n+------------------------------------+\n| 0058002000200020 |\n+------------------------------------+\n\nSELECT HEX(WEIGHT_STRING(0xaa22ee LEVEL 1));\n+--------------------------------------+\n| HEX(WEIGHT_STRING(0xaa22ee LEVEL 1)) |\n+--------------------------------------+\n| AA22EE |\n+--------------------------------------+\n\nSELECT HEX(WEIGHT_STRING(0xaa22ee LEVEL 1 DESC));\n+-------------------------------------------+\n| HEX(WEIGHT_STRING(0xaa22ee LEVEL 1 DESC)) |\n+-------------------------------------------+\n| 55DD11 |\n+-------------------------------------------+\n\nSELECT HEX(WEIGHT_STRING(0xaa22ee LEVEL 1 REVERSE));\n+----------------------------------------------+\n| HEX(WEIGHT_STRING(0xaa22ee LEVEL 1 REVERSE)) |\n+----------------------------------------------+\n| EE22AA |\n+----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/weight_string/','','https://mariadb.com/kb/en/weight_string/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (695,36,'Type Conversion','Implicit type conversion takes place when MariaDB is using operands or\ndifferent types, in order to make the operands compatible.\n\nIt is best practice not to rely upon implicit conversion; rather use CAST to\nexplicitly convert types.\n\nRules for Conversion on Comparison\n----------------------------------\n\n* If either argument is NULL, the result of the comparison is NULL unless the\nNULL-safe <=> equality comparison operator is used.\n* If both arguments are integers, they are compared as integers.\n* If both arguments are strings, they are compared as strings.\n* If one argument is decimal and the other argument is decimal or integer,\nthey are compared as decimals.\n* If one argument is decimal and the other argument is a floating point, they\nare compared as floating point values.\n* If one argument is string and the other argument is integer, they are\ncompared as decimals. This conversion was added in MariaDB 10.3.36. Prior to\n10.3.36, this combination was compared as floating point values, which did not\nalways work well for huge 64-bit integers because of a possible precision loss\non conversion to double.\n* If a hexadecimal argument is not compared to a number, it is treated as a\nbinary string.\n* If a constant is compared to a TIMESTAMP or DATETIME, the constant is\nconverted to a timestamp, unless used as an argument to the IN function.\n* In other cases, arguments are compared as floating point, or real, numbers.\n\nNote that if a string column is being compared with a numeric value, MariaDB\nwill not use the index on the column, as there are numerous alternatives that\nmay evaluate as equal (see examples below).\n\nComparison Examples\n-------------------\n\nConverting a string to a number:\n\nSELECT 15+\'15\';\n+---------+\n| 15+\'15\' |\n+---------+\n| 30 |\n+---------+\n\nConverting a number to a string:\n\nSELECT CONCAT(15,\'15\');\n+-----------------+\n| CONCAT(15,\'15\') |\n+-----------------+\n| 1515 |\n+-----------------+\n\nFloating point number errors:\n\nSELECT \'9746718491924563214\' = 9746718491924563213;\n+---------------------------------------------+\n| \'9746718491924563214\' = 9746718491924563213 |\n+---------------------------------------------+\n| 1 |\n+---------------------------------------------+\n\nNumeric equivalence with strings:\n\nSELECT \'5\' = 5;\n+---------+\n| \'5\' = 5 |\n+---------+\n| 1 |\n+---------+\n\nSELECT \' 5\' = 5;\n+------------+\n| \' 5\' = 5 |\n+------------+\n| 1 |\n+------------+\n\nSELECT \' 5 \' = 5;\n+--------------+\n| \' 5 \' = 5 |\n+--------------+\n| 1 |\n+--------------+\n1 row in set, 1 warning (0.000 sec)\n\nSHOW WARNINGS;\n+-------+------+--------------------------------------------+\n| Level | Code | Message |\n+-------+------+--------------------------------------------+\n| Note | 1292 | Truncated incorrect DOUBLE value: \' 5 \' |\n+-------+------+--------------------------------------------+\n\nAs a result of the above, MariaDB cannot use the index when comparing a string\nwith a numeric value in the example below:\n\nCREATE TABLE t (a VARCHAR(10), b VARCHAR(10), INDEX idx_a (a));\n\nINSERT INTO t VALUES \n (\'1\', \'1\'), (\'2\', \'2\'), (\'3\', \'3\'),\n (\'4\', \'4\'), (\'5\', \'5\'), (\'1\', \'5\');\n\nEXPLAIN SELECT * FROM t WHERE a = \'3\' \\G\n*************************** 1. row ***************************\n id: 1\n select_type: SIMPLE\n table: t\n type: ref\npossible_keys: idx_a\n key: idx_a\n key_len: 13\n ref: const\n rows: 1\n Extra: Using index condition\n\nEXPLAIN SELECT * FROM t WHERE a = 3 \\G\n*************************** 1. row ***************************\n id: 1\n select_type: SIMPLE\n table: t\n type: ALL\npossible_keys: idx_a\n key: NULL\n key_len: NULL\n ref: NULL\n rows: 6\n Extra: Using where\n\nRules for Conversion on Dyadic Arithmetic Operations\n----------------------------------------------------\n\nImplicit type conversion also takes place on dyadic arithmetic operations\n(+,-,*,/). MariaDB chooses the minimum data type that is guaranteed to fit the\nresult and converts both arguments to the result data type.\n\nFor addition (+), subtraction (-) and multiplication (*), the result data type\nis chosen as follows:\n\n* If either of the arguments is an approximate number (float, double), the\nresult is double.\n* If either of the arguments is a string (char, varchar, text), the result is\ndouble.\n* If either of the arguments is a decimal number, the result is decimal.\n* If either of the arguments is of a temporal type with a non-zero fractional\nsecond precision (time(N), datetime(N), timestamp(N)), the result is decimal.\n* If either of the arguments is of a temporal type with a zero fractional\nsecond precision (time(0), date, datetime(0), timestamp(0)), the result may\nvary between int, int unsigned, bigint or bigint unsigned, depending on the\nexact data type combination.\n* If both arguments are integer numbers (tinyint, smallint, mediumint,\nbigint), the result may vary between int, int unsigned, bigint or bigint\nunsigned, depending of the exact data types and their signs.\n\nFor division (/), the result data type is chosen as follows:\n\n* If either of the arguments is an approximate number (float, double), the\nresult is double.\n* If either of the arguments is a string (char, varchar, text), the result is\ndouble.\n* Otherwise, the result is decimal.\n\nArithmetic Examples\n-------------------\n\nNote, the above rules mean that when an argument of a temporal data type\nappears in addition or subtraction, it\'s treated as a number by default.\n\nSELECT TIME\'10:20:30\' + 1;\n+--------------------+\n| TIME\'10:20:30\' + 1 |\n+--------------------+\n| 102031 |\n+--------------------+\n\nIn order to do temporal addition or subtraction instead, use the DATE_ADD() or\nDATE_SUB() functions, or an INTERVAL expression as the second argument:\n\nSELECT TIME\'10:20:30\' + INTERVAL 1 SECOND;\n+------------------------------------+\n| TIME\'10:20:30\' + INTERVAL 1 SECOND |\n+------------------------------------+\n| 10:20:31 |\n+------------------------------------+\n\nSELECT \"2.2\" + 3;\n+-----------+\n| \"2.2\" + 3 |\n+-----------+\n| 5.2 |\n+-----------+\n\nSELECT 2.2 + 3;\n+---------+\n| 2.2 + 3 |\n+---------+\n| 5.2 |\n+---------+\n\nSELECT 2.2 / 3;\n+---------+\n| 2.2 / 3 |\n+---------+\n| 0.73333 |\n+---------+\n\nSELECT \"2.2\" / 3;\n+--------------------+\n| \"2.2\" / 3 |\n+--------------------+\n| 0.7333333333333334 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/type-conversion/','','https://mariadb.com/kb/en/type-conversion/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (696,37,'_rowid','Syntax\n------\n\n_rowid\n\nDescription\n-----------\n\nThe _rowid pseudo column is mapped to the primary key in the related table.\nThis can be used as a replacement of the rowid pseudo column in other\ndatabases. Another usage is to simplify sql queries as one doesn\'t have to\nknow the name of the primary key.\n\nExamples\n--------\n\ncreate table t1 (a int primary key, b varchar(80));\ninsert into t1 values (1,\"one\"),(2,\"two\");\nselect * from t1 where _rowid=1;\n\n+---+------+\n| a | b |\n+---+------+\n| 1 | one |\n+---+------+\n\nupdate t1 set b=\"three\" where _rowid=2;\nselect * from t1 where _rowid>=1 and _rowid<=10;\n\n+---+-------+\n| a | b |\n+---+-------+\n| 1 | one |\n| 2 | three |\n+---+-------+\n\nURL: https://mariadb.com/kb/en/_rowid/','','https://mariadb.com/kb/en/_rowid/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (697,38,'ALTER TABLE','Syntax\n------\n\nALTER [ONLINE] [IGNORE] TABLE [IF EXISTS] tbl_name\n [WAIT n | NOWAIT]\n alter_specification [, alter_specification] ...\nalter_specification:\n table_option ...\n | ADD [COLUMN] [IF NOT EXISTS] col_name column_definition\n [FIRST | AFTER col_name ]\n | ADD [COLUMN] [IF NOT EXISTS] (col_name column_definition,...)\n | ADD {INDEX|KEY} [IF NOT EXISTS] [index_name]\n [index_type] (index_col_name,...) [index_option] ...\n | ADD [CONSTRAINT [symbol]] PRIMARY KEY\n [index_type] (index_col_name,...) [index_option] ...\n | ADD [CONSTRAINT [symbol]]\n UNIQUE [INDEX|KEY] [index_name]\n [index_type] (index_col_name,...) [index_option] ...\n | ADD FULLTEXT [INDEX|KEY] [index_name]\n (index_col_name,...) [index_option] ...\n | ADD SPATIAL [INDEX|KEY] [index_name]\n (index_col_name,...) [index_option] ...\n | ADD [CONSTRAINT [symbol]]\n FOREIGN KEY [IF NOT EXISTS] [index_name] (index_col_name,...)\n reference_definition\n | ADD PERIOD FOR SYSTEM_TIME (start_column_name, end_column_name)\n | ALTER [COLUMN] col_name SET DEFAULT literal | (expression)\n | ALTER [COLUMN] col_name DROP DEFAULT\n | ALTER {INDEX|KEY} index_name [NOT] INVISIBLE\n | CHANGE [COLUMN] [IF EXISTS] old_col_name new_col_name column_definition\n [FIRST|AFTER col_name]\n | MODIFY [COLUMN] [IF EXISTS] col_name column_definition\n [FIRST | AFTER col_name]\n | DROP [COLUMN] [IF EXISTS] col_name [RESTRICT|CASCADE]\n | DROP PRIMARY KEY\n | DROP {INDEX|KEY} [IF EXISTS] index_name\n | DROP FOREIGN KEY [IF EXISTS] fk_symbol\n | DROP CONSTRAINT [IF EXISTS] constraint_name\n | DISABLE KEYS\n | ENABLE KEYS\n | RENAME [TO] new_tbl_name\n | ORDER BY col_name [, col_name] ...\n | RENAME COLUMN old_col_name TO new_col_name\n | RENAME {INDEX|KEY} old_index_name TO new_index_name\n | CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]\n | [DEFAULT] CHARACTER SET [=] charset_name\n | [DEFAULT] COLLATE [=] collation_name\n | DISCARD TABLESPACE\n | IMPORT TABLESPACE\n | ALGORITHM [=] {DEFAULT|INPLACE|COPY|NOCOPY|INSTANT}\n | LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}\n | FORCE\n | partition_options\n | CONVERT TABLE normal_table TO partition_definition\n | CONVERT PARTITION partition_name TO TABLE tbl_name\n | ADD PARTITION [IF NOT EXISTS] (partition_definition)\n | DROP PARTITION [IF EXISTS] partition_names\n | COALESCE PARTITION number\n | REORGANIZE PARTITION [partition_names INTO (partition_definitions)]\n | ANALYZE PARTITION partition_names\n | CHECK PARTITION partition_names\n | OPTIMIZE PARTITION partition_names\n | REBUILD PARTITION partition_names\n | REPAIR PARTITION partition_names\n | EXCHANGE PARTITION partition_name WITH TABLE tbl_name\n | REMOVE PARTITIONING\n | ADD SYSTEM VERSIONING\n | DROP SYSTEM VERSIONING\nindex_col_name:\n col_name [(length)] [ASC | DESC]\nindex_type:\n USING {BTREE | HASH | RTREE}\nindex_option:\n [ KEY_BLOCK_SIZE [=] value\n | index_type\n | WITH PARSER parser_name\n | COMMENT \'string\'\n | CLUSTERING={YES| NO} ]\n [ IGNORED | NOT IGNORED ]\ntable_options:\n table_option [[,] table_option] ...\n\nDescription\n-----------\n\nALTER TABLE enables you to change the structure of an existing table. For\nexample, you can add or delete columns, create or destroy indexes, change the\ntype of existing columns, or rename columns or the table itself. You can also\nchange the comment for the table and the storage engine of the table.\n\nIf another connection is using the table, a metadata lock is active, and this\nstatement will wait until the lock is released. This is also true for\nnon-transactional tables.\n\nWhen adding a UNIQUE index on a column (or a set of columns) which have\nduplicated values, an error will be produced and the statement will be\nstopped. To suppress the error and force the creation of UNIQUE indexes,\ndiscarding duplicates, the IGNORE option can be specified. This can be useful\nif a column (or a set of columns) should be UNIQUE but it contains duplicate\nvalues; however, this technique provides no control on which rows are\npreserved and which are deleted. Also, note that IGNORE is accepted but\nignored in ALTER TABLE ... EXCHANGE PARTITION statements.\n\nThis statement can also be used to rename a table. For details see RENAME\nTABLE.\n\nWhen an index is created, the storage engine may use a configurable buffer in\nthe process. Incrementing the buffer speeds up the index creation. Aria and\nMyISAM allocate a buffer whose size is defined by aria_sort_buffer_size or\nmyisam_sort_buffer_size, also used for REPAIR TABLE. InnoDB allocates three\nbuffers whose size is defined by innodb_sort_buffer_size.\n\nPrivileges\n----------\n\nExecuting the ALTER TABLE statement generally requires at least the ALTER\nprivilege for the table or the database..\n\nIf you are renaming a table, then it also requires the DROP, CREATE and INSERT\nprivileges for the table or the database as well.\n\nOnline DDL\n----------\n\nOnline DDL is supported with the ALGORITHM and LOCK clauses.\n\nSee InnoDB Online DDL Overview for more information on online DDL with InnoDB.\n\nALTER ONLINE TABLE\n------------------\n\nALTER ONLINE TABLE also works for partitioned tables.\n\nOnline ALTER TABLE is available by executing the following:\n\nALTER ONLINE TABLE ...;\n\nThis statement has the following semantics:\n\nThis statement is equivalent to the following:\n\nALTER TABLE ... LOCK=NONE;\n\nSee the LOCK alter specification for more information.\n\nThis statement is equivalent to the following:\n\nALTER TABLE ... ALGORITHM=INPLACE;\n\nSee the ALGORITHM alter specification for more information.\n\nWAIT/NOWAIT\n-----------\n\nSet the lock wait timeout. See WAIT and NOWAIT.\n\nIF EXISTS\n---------\n\nThe IF EXISTS and IF NOT EXISTS clauses are available for the following:\n\nADD COLUMN [IF NOT EXISTS]\nADD INDEX [IF NOT EXISTS]\nADD FOREIGN KEY [IF NOT EXISTS]\nADD PARTITION [IF NOT EXISTS]\nCREATE INDEX [IF NOT EXISTS]\nDROP COLUMN [IF EXISTS]\nDROP INDEX [IF EXISTS]\nDROP FOREIGN KEY [IF EXISTS]\nDROP PARTITION [IF EXISTS]\nCHANGE COLUMN [IF EXISTS]\nMODIFY COLUMN [IF EXISTS]\nDROP INDEX [IF EXISTS]\nWhen IF EXISTS and IF NOT EXISTS are used in clauses, queries will not report\nerrors when the condition is triggered for that clause. A warning with the\nsame message text will be issued and the ALTER will move on to the next clause\nin the statement (or end if finished).\n\nMariaDB starting with 10.5.2\n----------------------------\nIf this is directive is used after ALTER ... TABLE, one will not get an error\nif the table doesn\'t exist.\n\nColumn Definitions\n------------------\n\nSee CREATE TABLE: Column Definitions for information about column definitions.\n\nIndex Definitions\n-----------------\n\nSee CREATE TABLE: Index Definitions for information about index definitions.\n\nThe CREATE INDEX and DROP INDEX statements can also be used to add or remove\nan index.\n\nCharacter Sets and Collations\n-----------------------------\n\nCONVERT TO CHARACTER SET charset_name [COLLATE collation_name]\n[DEFAULT] CHARACTER SET [=] charset_name\n[DEFAULT] COLLATE [=] collation_name\nSee Setting Character Sets and Collations for details on setting the character\nsets and collations.\n\nAlter Specifications\n--------------------\n\nTable Options\n-------------\n\nSee CREATE TABLE: Table Options for information about table options.\n\nADD COLUMN\n----------\n\n... ADD COLUMN [IF NOT EXISTS] (col_name column_definition,...)\nAdds a column to the table. The syntax is the same as in CREATE TABLE. If you\nare using IF NOT_EXISTS the column will not be added if it was not there\nalready. This is very useful when doing scripts to modify tables.\n\nThe FIRST and AFTER clauses affect the physical order of columns in the\ndatafile. Use FIRST to add a column in the first (leftmost) position, or AFTER\nfollowed by a column name to add the new column in any other position. Note\nthat, nowadays, the physical position of a column is usually irrelevant.\n\nSee also Instant ADD COLUMN for InnoDB.\n\nDROP COLUMN\n-----------\n\n... DROP COLUMN [IF EXISTS] col_name [CASCADE|RESTRICT]\nDrops the column from the table. If you are using IF EXISTS you will not get\nan error if the column didn\'t exist. If the column is part of any index, the\ncolumn will be dropped from them, except if you add a new column with\nidentical name at the same time. The index will be dropped if all columns from\nthe index were dropped. If the column was used in a view or trigger, you will\nget an error next time the view or trigger is accessed. Dropping a column that\nis part of a multi-column UNIQUE constraint is not permitted. For example:\n\nCREATE TABLE a (\n a int,\n b int,\n primary key (a,b)\n);\n\nALTER TABLE x DROP COLUMN a;\n[42000][1072] Key column \'A\' doesn\'t exist in table\n\nThe reason is that dropping column a would result in the new constraint that\nall values in column b be unique. In order to drop the column, an explicit\nDROP PRIMARY KEY and ADD PRIMARY KEY would be required. Up until MariaDB\n10.2.7, the column was dropped and the additional constraint applied,\nresulting in the following structure:\n\nALTER TABLE x DROP COLUMN a;\nQuery OK, 0 rows affected (0.46 sec)\n\nDESC x;\n+-------+---------+------+-----+---------+-------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+---------+------+-----+---------+-------+\n| b | int(11) | NO | PRI | NULL | |\n+-------+---------+------+-----+---------+-------+\n\nMariaDB starting with 10.4.0\n----------------------------\nMariaDB 10.4.0 supports instant DROP COLUMN. DROP COLUMN of an indexed column\nwould imply DROP INDEX (and in the case of a non-UNIQUE multi-column index,\npossibly ADD INDEX). These will not be allowed with ALGORITHM=INSTANT, but\nunlike before, they can be allowed with ALGORITHM=NOCOPY\n\nRESTRICT and CASCADE are allowed to make porting from other database systems\neasier. In MariaDB, they do nothing.\n\nMODIFY COLUMN\n-------------\n\nAllows you to modify the type of a column. The column will be at the same\nplace as the original column and all indexes on the column will be kept. Note\nthat when modifying column, you should specify all attributes for the new\ncolumn.\n\nCREATE TABLE t1 (a INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY((a));\nALTER TABLE t1 MODIFY a BIGINT UNSIGNED AUTO_INCREMENT;\n\nCHANGE COLUMN\n-------------\n\nWorks like MODIFY COLUMN except that you can also change the name of the\ncolumn. The column will be at the same place as the original column and all\nindex on the column will be kept.\n\nCREATE TABLE t1 (a INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(a));\nALTER TABLE t1 CHANGE a b BIGINT UNSIGNED AUTO_INCREMENT;\n\nALTER COLUMN\n------------\n\nThis lets you change column options.\n\nCREATE TABLE t1 (a INT UNSIGNED AUTO_INCREMENT, b varchar(50), PRIMARY KEY(a));\nALTER TABLE t1 ALTER b SET DEFAULT \'hello\';\n\nRENAME INDEX/KEY\n----------------\n\nMariaDB starting with 10.5.2\n----------------------------\nFrom MariaDB 10.5.2, it is possible to rename an index using the RENAME INDEX\n(or RENAME KEY) syntax, for example:\n\nALTER TABLE t1 RENAME INDEX i_old TO i_new;\n\nRENAME COLUMN\n-------------\n\nMariaDB starting with 10.5.2\n----------------------------\nFrom MariaDB 10.5.2, it is possible to rename a column using the RENAME COLUMN\nsyntax, for example:\n\nALTER TABLE t1 RENAME COLUMN c_old TO c_new;\n\nADD PRIMARY KEY\n---------------\n\nAdd a primary key.\n\nFor PRIMARY KEY indexes, you can specify a name for the index, but it is\nsilently ignored, and the name of the index is always PRIMARY.\n\nSee Getting Started with Indexes: Primary Key for more information.\n\nDROP PRIMARY KEY\n----------------\n\nDrop a primary key.\n\nFor PRIMARY KEY indexes, you can specify a name for the index, but it is\nsilently ignored, and the name of the index is always PRIMARY.\n\nSee Getting Started with Indexes: Primary Key for more information.\n\nADD FOREIGN KEY\n---------------\n\nAdd a foreign key.\n\nFor FOREIGN KEY indexes, a reference definition must be provided.\n\nFor FOREIGN KEY indexes, you can specify a name for the constraint, using the\nCONSTRAINT keyword. That name will be used in error messages.\n\nFirst, you have to specify the name of the target (parent) table and a column\nor a column list which must be indexed and whose values must match to the\nforeign key\'s values. The MATCH clause is accepted to improve the\ncompatibility with other DBMS\'s, but has no meaning in MariaDB. The ON DELETE\nand ON UPDATE clauses specify what must be done when a DELETE (or a REPLACE)\nstatements attempts to delete a referenced row from the parent table, and when\nan UPDATE statement attempts to modify the referenced foreign key columns in a\nparent table row, respectively. The following options are allowed:\n\n* RESTRICT: The delete/update operation is not performed. The statement\nterminates with a 1451 error (SQLSTATE \'2300\').\n* NO ACTION: Synonym for RESTRICT.\n* CASCADE: The delete/update operation is performed in both tables.\n* SET NULL: The update or delete goes ahead in the parent table, and the\ncorresponding foreign key fields in the child table are set to NULL. (They\nmust not be defined as NOT NULL for this to succeed).\n* SET DEFAULT: This option is implemented only for the legacy PBXT storage\nengine, which is disabled by default and no longer maintained. It sets the\nchild table\'s foreign key fields to their DEFAULT values when the referenced\nparent table key entries are updated or deleted.\n\nIf either clause is omitted, the default behavior for the omitted clause is\nRESTRICT.\n\nSee Foreign Keys for more information.\n\nDROP FOREIGN KEY\n----------------\n\nDrop a foreign key.\n\nSee Foreign Keys for more information.\n\nADD INDEX\n---------\n\nAdd a plain index.\n\nPlain indexes are regular indexes that are not unique, and are not acting as a\nprimary key or a foreign key. They are also not the \"specialized\" FULLTEXT or\nSPATIAL indexes.\n\nSee Getting Started with Indexes: Plain Indexes for more information.\n\nDROP INDEX\n----------\n\nDrop a plain index.\n\nPlain indexes are regular indexes that are not unique, and are not acting as a\nprimary key or a foreign key. They are also not the \"specialized\" FULLTEXT or\nSPATIAL indexes.\n\nSee Getting Started with Indexes: Plain Indexes for more information.\n\nADD UNIQUE INDEX\n----------------\n\nAdd a unique index.\n\nThe UNIQUE keyword means that the index will not accept duplicated values,','','https://mariadb.com/kb/en/alter-table/'); +update help_topic set description = CONCAT(description, '\nexcept for NULLs. An error will raise if you try to insert duplicate values in\na UNIQUE index.\n\nFor UNIQUE indexes, you can specify a name for the constraint, using the\nCONSTRAINT keyword. That name will be used in error messages.\n\nSee Getting Started with Indexes: Unique Index for more information.\n\nDROP UNIQUE INDEX\n-----------------\n\nDrop a unique index.\n\nThe UNIQUE keyword means that the index will not accept duplicated values,\nexcept for NULLs. An error will raise if you try to insert duplicate values in\na UNIQUE index.\n\nFor UNIQUE indexes, you can specify a name for the constraint, using the\nCONSTRAINT keyword. That name will be used in error messages.\n\nSee Getting Started with Indexes: Unique Index for more information.\n\nADD FULLTEXT INDEX\n------------------\n\nAdd a FULLTEXT index.\n\nSee Full-Text Indexes for more information.\n\nDROP FULLTEXT INDEX\n-------------------\n\nDrop a FULLTEXT index.\n\nSee Full-Text Indexes for more information.\n\nADD SPATIAL INDEX\n-----------------\n\nAdd a SPATIAL index.\n\nSee SPATIAL INDEX for more information.\n\nDROP SPATIAL INDEX\n------------------\n\nDrop a SPATIAL index.\n\nSee SPATIAL INDEX for more information.\n\nENABLE/ DISABLE KEYS\n--------------------\n\nDISABLE KEYS will disable all non unique keys for the table for storage\nengines that support this (at least MyISAM and Aria). This can be used to\nspeed up inserts into empty tables.\n\nENABLE KEYS will enable all disabled keys.\n\nRENAME TO\n---------\n\nRenames the table. See also RENAME TABLE.\n\nADD CONSTRAINT\n--------------\n\nModifies the table adding a constraint on a particular column or columns.\n\nALTER TABLE table_name \nADD CONSTRAINT [constraint_name] CHECK(expression);\nBefore a row is inserted or updated, all constraints are evaluated in the\norder they are defined. If any constraint fails, then the row will not be\nupdated. One can use most deterministic functions in a constraint, including\nUDF\'s.\n\nCREATE TABLE account_ledger (\n id INT PRIMARY KEY AUTO_INCREMENT,\n transaction_name VARCHAR(100),\n credit_account VARCHAR(100),\n credit_amount INT,\n debit_account VARCHAR(100),\n debit_amount INT);\n\nALTER TABLE account_ledger \nADD CONSTRAINT is_balanced \n CHECK((debit_amount + credit_amount) = 0);\n\nThe constraint_name is optional. If you don\'t provide one in the ALTER TABLE\nstatement, MariaDB auto-generates a name for you. This is done so that you can\nremove it later using DROP CONSTRAINT clause.\n\nYou can disable all constraint expression checks by setting the variable\ncheck_constraint_checks to OFF. You may find this useful when loading a table\nthat violates some constraints that you want to later find and fix in SQL.\n\nTo view constraints on a table, query information_schema.TABLE_CONSTRAINTS:\n\nSELECT CONSTRAINT_NAME, TABLE_NAME, CONSTRAINT_TYPE \nFROM information_schema.TABLE_CONSTRAINTS\nWHERE TABLE_NAME = \'account_ledger\';\n\n+-----------------+----------------+-----------------+\n| CONSTRAINT_NAME | TABLE_NAME | CONSTRAINT_TYPE |\n+-----------------+----------------+-----------------+\n| is_balanced | account_ledger | CHECK |\n+-----------------+----------------+-----------------+\n\nDROP CONSTRAINT\n---------------\n\nDROP CONSTRAINT for UNIQUE and FOREIGN KEY constraints was introduced in\nMariaDB 10.2.22 and MariaDB 10.3.13.\n\nDROP CONSTRAINT for CHECK constraints was introduced in MariaDB 10.2.1\n\nModifies the table, removing the given constraint.\n\nALTER TABLE table_name\nDROP CONSTRAINT constraint_name;\n\nWhen you add a constraint to a table, whether through a CREATE TABLE or ALTER\nTABLE...ADD CONSTRAINT statement, you can either set a constraint_name\nyourself, or allow MariaDB to auto-generate one for you. To view constraints\non a table, query information_schema.TABLE_CONSTRAINTS. For instance,\n\nCREATE TABLE t (\n a INT,\n b INT,\n c INT,\n CONSTRAINT CHECK(a > b),\n CONSTRAINT check_equals CHECK(a = c));\n\nSELECT CONSTRAINT_NAME, TABLE_NAME, CONSTRAINT_TYPE \nFROM information_schema.TABLE_CONSTRAINTS\nWHERE TABLE_NAME = \'t\';\n\n+-----------------+----------------+-----------------+\n| CONSTRAINT_NAME | TABLE_NAME | CONSTRAINT_TYPE |\n+-----------------+----------------+-----------------+\n| check_equals | t | CHECK |\n| CONSTRAINT_1 | t | CHECK |\n+-----------------+----------------+-----------------+\n\nTo remove a constraint from the table, issue an ALTER TABLE...DROP CONSTRAINT\nstatement. For example,\n\nALTER TABLE t DROP CONSTRAINT is_unique;\n\nADD SYSTEM VERSIONING\n---------------------\n\nAdd system versioning. See System-versioned tables.\n\nDROP SYSTEM VERSIONING\n----------------------\n\nDrop system versioning. See System-versioned tables.\n\nADD PERIOD FOR SYSTEM_TIME\n--------------------------\n\nSee System-versioned tables.\n\nFORCE\n-----\n\nALTER TABLE ... FORCE can force MariaDB to re-build the table.\n\nIn MariaDB 5.5 and before, this could only be done by setting the ENGINE table\noption to its old value. For example, for an InnoDB table, one could execute\nthe following:\n\nALTER TABLE tab_name ENGINE = InnoDB;\n\nThe FORCE option can be used instead. For example, :\n\nALTER TABLE tab_name FORCE;\n\nWith InnoDB, the table rebuild will only reclaim unused space (i.e. the space\npreviously used for deleted rows) if the innodb_file_per_table system variable\nis set to ON (the default). If the system variable is OFF, then the space will\nnot be reclaimed, but it will be-re-used for new data that\'s later added.\n\nCONVERT TABLE / CONVERT PARTITION\n---------------------------------\n\nCONVERT TABLE and CONVERT PARTITION was introduced in MariaDB 10.7.1.\n\nCONVERT PARTITION can be used to remove a partition from a table and make this\nan ordinary table. For example:\n\nALTER TABLE partitioned_table CONVERT PARTITION part1 TO TABLE normal_table;\n\nCONVERT PARTITION will take an existing table and move this to another table\nas its own partition with a specified partition definition. For example the\nfollowing moves normal_table to a partition of partitioned_table with a\ndefinition that its values, based on the PARTITION BY of the\npartitioned_table, are less than 12345.\n\nALTER TABLE partitioned_table CONVERT TABLE normal_table TO PARTITION part1\nVALUES LESS THAN (12345);\n\nEXCHANGE PARTITION\n------------------\n\nThis is used to exchange the contents of a partition with another table.\n\nThis is performed by swapping the tablespaces of the partition with the other\ntable.\n\nSee copying InnoDB\'s transportable tablespaces for more information.\n\nDISCARD TABLESPACE\n------------------\n\nThis is used to discard an InnoDB table\'s tablespace.\n\nSee copying InnoDB\'s transportable tablespaces for more information.\n\nIMPORT TABLESPACE\n-----------------\n\nThis is used to import an InnoDB table\'s tablespace. The tablespace should\nhave been copied from its original server after executing FLUSH TABLES FOR\nEXPORT.\n\nSee copying InnoDB\'s transportable tablespaces for more information.\n\nALTER TABLE ... IMPORT only applies to InnoDB tables. Most other popular\nstorage engines, such as Aria and MyISAM, will recognize their data files as\nsoon as they\'ve been placed in the proper directory under the datadir, and no\nspecial DDL is required to import them.\n\nALGORITHM\n---------\n\nThe ALTER TABLE statement supports the ALGORITHM clause. This clause is one of\nthe clauses that is used to implement online DDL. ALTER TABLE supports several\ndifferent algorithms. An algorithm can be explicitly chosen for an ALTER TABLE\noperation by setting the ALGORITHM clause. The supported values are:\n\n* ALGORITHM=DEFAULT - This implies the default behavior for the specific\nstatement, such as if no ALGORITHM clause is specified.\n* ALGORITHM=COPY\n* ALGORITHM=INPLACE\n* ALGORITHM=NOCOPY - This was added in MariaDB 10.3.7.\n* ALGORITHM=INSTANT - This was added in MariaDB 10.3.7.\n\nSee InnoDB Online DDL Overview: ALGORITHM for information on how the ALGORITHM\nclause affects InnoDB.\n\nALGORITHM=DEFAULT\n-----------------\n\nThe default behavior, which occurs if ALGORITHM=DEFAULT is specified, or if\nALGORITHM is not specified at all, usually only makes a copy if the operation\ndoesn\'t support being done in-place at all. In this case, the most efficient\navailable algorithm will usually be used.\n\nHowever, in MariaDB 10.3.6 and before, if the value of the old_alter_table\nsystem variable is set to ON, then the default behavior is to perform ALTER\nTABLE operations by making a copy of the table using the old algorithm.\n\nIn MariaDB 10.3.7 and later, the old_alter_table system variable is\ndeprecated. Instead, the alter_algorithm system variable defines the default\nalgorithm for ALTER TABLE operations.\n\nALGORITHM=COPY\n--------------\n\nALGORITHM=COPY is the name for the original ALTER TABLE algorithm from early\nMariaDB versions.\n\nWhen ALGORITHM=COPY is set, MariaDB essentially does the following operations:\n\n-- Create a temporary table with the new definition\nCREATE TEMPORARY TABLE tmp_tab (\n...\n);\n\n-- Copy the data from the original table\nINSERT INTO tmp_tab\n SELECT * FROM original_tab;\n\n-- Drop the original table\nDROP TABLE original_tab;\n\n-- Rename the temporary table, so that it replaces the original one\nRENAME TABLE tmp_tab TO original_tab;\n\nThis algorithm is very inefficient, but it is generic, so it works for all\nstorage engines.\n\nIf ALGORITHM=COPY is specified, then the copy algorithm will be used even if\nit is not necessary. This can result in a lengthy table copy. If multiple\nALTER TABLE operations are required that each require the table to be rebuilt,\nthen it is best to specify all operations in a single ALTER TABLE statement,\nso that the table is only rebuilt once.\n\nALGORITHM=INPLACE\n-----------------\n\nALGORITHM=COPY can be incredibly slow, because the whole table has to be\ncopied and rebuilt. ALGORITHM=INPLACE was introduced as a way to avoid this by\nperforming operations in-place and avoiding the table copy and rebuild, when\npossible.\n\nWhen ALGORITHM=INPLACE is set, the underlying storage engine uses\noptimizations to perform the operation while avoiding the table copy and\nrebuild. However, INPLACE is a bit of a misnomer, since some operations may\nstill require the table to be rebuilt for some storage engines. Regardless,\nseveral operations can be performed without a full copy of the table for some\nstorage engines.\n\nA more accurate name would have been ALGORITHM=ENGINE, where ENGINE refers to\nan \"engine-specific\" algorithm.\n\nIf an ALTER TABLE operation supports ALGORITHM=INPLACE, then it can be\nperformed using optimizations by the underlying storage engine, but it may\nrebuilt.\n\nSee InnoDB Online DDL Operations with ALGORITHM=INPLACE for more.\n\nALGORITHM=NOCOPY\n----------------\n\nALGORITHM=NOCOPY was introduced in MariaDB 10.3.7.\n\nALGORITHM=INPLACE can sometimes be surprisingly slow in instances where it has\nto rebuild the clustered index, because when the clustered index has to be\nrebuilt, the whole table has to be rebuilt. ALGORITHM=NOCOPY was introduced as\na way to avoid this.\n\nIf an ALTER TABLE operation supports ALGORITHM=NOCOPY, then it can be\nperformed without rebuilding the clustered index.\n\nIf ALGORITHM=NOCOPY is specified for an ALTER TABLE operation that does not\nsupport ALGORITHM=NOCOPY, then an error will be raised. In this case, raising\nan error is preferable, if the alternative is for the operation to rebuild the\nclustered index, and perform unexpectedly slowly.\n\nSee InnoDB Online DDL Operations with ALGORITHM=NOCOPY for more.\n\nALGORITHM=INSTANT\n-----------------\n\nALGORITHM=INSTANT was introduced in MariaDB 10.3.7.\n\nALGORITHM=INPLACE can sometimes be surprisingly slow in instances where it has\nto modify data files. ALGORITHM=INSTANT was introduced as a way to avoid this.\n\nIf an ALTER TABLE operation supports ALGORITHM=INSTANT, then it can be\nperformed without modifying any data files.\n\nIf ALGORITHM=INSTANT is specified for an ALTER TABLE operation that does not\nsupport ALGORITHM=INSTANT, then an error will be raised. In this case, raising\nan error is preferable, if the alternative is for the operation to modify data\nfiles, and perform unexpectedly slowly.\n\nSee InnoDB Online DDL Operations with ALGORITHM=INSTANT for more.\n\nLOCK\n----\n\nThe ALTER TABLE statement supports the LOCK clause. This clause is one of the\nclauses that is used to implement online DDL. ALTER TABLE supports several\ndifferent locking strategies. A locking strategy can be explicitly chosen for\nan ALTER TABLE operation by setting the LOCK clause. The supported values are:\n\n* DEFAULT: Acquire the least restrictive lock on the table that is supported\nfor the specific operation. Permit the maximum amount of concurrency that is\nsupported for the specific operation.\n* NONE: Acquire no lock on the table. Permit all concurrent DML. If this\nlocking strategy is not permitted for an operation, then an error is raised.\n* SHARED: Acquire a read lock on the table. Permit read-only concurrent DML.\nIf this locking strategy is not permitted for an operation, then an error is\nraised.\n* EXCLUSIVE: Acquire a write lock on the table. Do not permit concurrent DML.\n\nDifferent storage engines support different locking strategies for different\noperations. If a specific locking strategy is chosen for an ALTER TABLE\noperation, and that table\'s storage engine does not support that locking\nstrategy for that specific operation, then an error will be raised.\n\nIf the LOCK clause is not explicitly set, then the operation uses LOCK=DEFAULT.\n\nALTER ONLINE TABLE is equivalent to LOCK=NONE. Therefore, the ALTER ONLINE\nTABLE statement can be used to ensure that your ALTER TABLE operation allows\nall concurrent DML.\n\nSee InnoDB Online DDL Overview: LOCK for information on how the LOCK clause\naffects InnoDB.\n\nProgress Reporting\n------------------\n\nMariaDB provides progress reporting for ALTER TABLE statement for clients that\nsupport the new progress reporting protocol. For example, if you were using\nthe mariadb client, then the progress report might look like this::\n\nALTER TABLE test ENGINE=Aria;\nStage: 1 of 2 \'copy to tmp table\' 46% of stage\n\nThe progress report is also shown in the output of the SHOW PROCESSLIST\nstatement and in the contents of the information_schema.PROCESSLIST table.\n\nSee Progress Reporting for more information.\n') WHERE help_topic_id = 697; +update help_topic set description = CONCAT(description, '\nAborting ALTER TABLE Operations\n-------------------------------\n\nIf an ALTER TABLE operation is being performed and the connection is killed,\nthe changes will be rolled back in a controlled manner. The rollback can be a\nslow operation as the time it takes is relative to how far the operation has\nprogressed.\n\nAborting ALTER TABLE ... ALGORITHM=COPY was made faster in MariaDB 10.2.13 by\nremoving excessive undo logging (MDEV-11415). This significantly shortened the\ntime it takes to abort a running ALTER TABLE operation, compared with earlier\nreleases.\n\nAtomic ALTER TABLE\n------------------\n\nMariaDB starting with 10.6.1\n----------------------------\nFrom MariaDB 10.6, ALTER TABLE is atomic for most engines, including InnoDB,\nMyRocks, MyISAM and Aria (MDEV-25180). This means that if there is a crash\n(server down or power outage) during an ALTER TABLE operation, after recovery,\neither the old table and associated triggers and status will be intact, or the\nnew table will be active.\n\nIn older MariaDB versions one could get leftover #sql-alter..\',\n\'#sql-backup..\' or \'table_name.frm˝\' files if the system crashed during the\nALTER TABLE operation.\n\nSee Atomic DDL for more information.\n\nReplication\n-----------\n\nMariaDB starting with 10.8.1\n----------------------------\nBefore MariaDB 10.8.1, ALTER TABLE got fully executed on the primary first,\nand only then was it replicated and started executing on replicas. From\nMariaDB 10.8.1, ALTER TABLE gains an option to replicate sooner and begin\nexecuting on replicas when it merely starts executing on the primary, not when\nit finishes. This way the replication lag caused by a heavy ALTER TABLE can be\ncompletely eliminated (MDEV-11675).\n\nExamples\n--------\n\nAdding a new column:\n\nALTER TABLE t1 ADD x INT;\n\nDropping a column:\n\nALTER TABLE t1 DROP x;\n\nModifying the type of a column:\n\nALTER TABLE t1 MODIFY x bigint unsigned;\n\nChanging the name and type of a column:\n\nALTER TABLE t1 CHANGE a b bigint unsigned auto_increment;\n\nCombining multiple clauses in a single ALTER TABLE statement, separated by\ncommas:\n\nALTER TABLE t1 DROP x, ADD x2 INT, CHANGE y y2 INT;\n\nChanging the storage engine and adding a comment:\n\nALTER TABLE t1 \n ENGINE = InnoDB\n COMMENT = \'First of three tables containing usage info\';\n\nRebuilding the table (the previous example will also rebuild the table if it\nwas already InnoDB):\n\nALTER TABLE t1 FORCE;\n\nDropping an index:\n\nALTER TABLE rooms DROP INDEX u;\n\nAdding a unique index:\n\nALTER TABLE rooms ADD UNIQUE INDEX u(room_number);\n\nFrom MariaDB 10.5.3, adding a primary key for an application-time period table\nwith a WITHOUT OVERLAPS constraint:\n\nALTER TABLE rooms ADD PRIMARY KEY(room_number, p WITHOUT OVERLAPS);\n\nFrom MariaDB 10.8.1, ALTER query can be replicated faster with the setting of\n\nSET @@SESSION.binlog_alter_two_phase = true;\n\nprior the ALTER query. Binlog would contain two event groups\n\n| master-bin.000001 | 495 | Gtid | 1 | 537 | GTID\n0-1-2 START ALTER |\n| master-bin.000001 | 537 | Query | 1 | 655 | use\n`test`; alter table t add column b int, algorithm=inplace |\n| master-bin.000001 | 655 | Gtid | 1 | 700 | GTID\n0-1-3 COMMIT ALTER id=2 |\n| master-bin.000001 | 700 | Query | 1 | 835 | use\n`test`; alter table t add column b int, algorithm=inplace |\n\nof which the first one gets delivered to replicas before ALTER is taken to\nactual execution on the primary.\n\nURL: https://mariadb.com/kb/en/alter-table/') WHERE help_topic_id = 697; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (698,38,'ALTER DATABASE','Modifies a database, changing its overall characteristics.\n\nSyntax\n------\n\nALTER {DATABASE | SCHEMA} [db_name]\n alter_specification ...\nALTER {DATABASE | SCHEMA} db_name\n UPGRADE DATA DIRECTORY NAME\n\nalter_specification:\n [DEFAULT] CHARACTER SET [=] charset_name\n | [DEFAULT] COLLATE [=] collation_name\n | COMMENT [=] \'comment\'\n\nDescription\n-----------\n\nALTER DATABASE enables you to change the overall characteristics of a\ndatabase. These characteristics are stored in the db.opt file in the database\ndirectory. To use ALTER DATABASE, you need the ALTER privilege on the\ndatabase. ALTER SCHEMA is a synonym for ALTER DATABASE.\n\nThe CHARACTER SET clause changes the default database character set. The\nCOLLATE clause changes the default database collation. See Character Sets and\nCollations for more.\n\nYou can see what character sets and collations are available using,\nrespectively, the SHOW CHARACTER SET and SHOW COLLATION statements.\n\nChanging the default character set/collation of a database does not change the\ncharacter set/collation of any stored procedures or stored functions that were\npreviously created, and relied on the defaults. These need to be dropped and\nrecreated in order to apply the character set/collation changes.\n\nThe database name can be omitted from the first syntax, in which case the\nstatement applies to the default database.\n\nThe syntax that includes the UPGRADE DATA DIRECTORY NAME clause was added in\nMySQL 5.1.23. It updates the name of the directory associated with the\ndatabase to use the encoding implemented in MySQL 5.1 for mapping database\nnames to database directory names (see Identifier to File Name Mapping). This\nclause is for use under these conditions:\n\n* It is intended when upgrading MySQL to 5.1 or later from older versions.\n* It is intended to update a database directory name to the current encoding\nformat if the name contains special characters that need encoding.\n* The statement is used by mariadb-check (as invoked by mariadb-upgrade).\n\nFor example,if a database in MySQL 5.0 has a name of a-b-c, the name contains\ninstance of the `-\' character. In 5.0, the database directory is also named\na-b-c, which is not necessarily safe for all file systems. In MySQL 5.1 and\nup, the same database name is encoded as a@002db@002dc to produce a file\nsystem-neutral directory name.\n\nWhen a MySQL installation is upgraded to MySQL 5.1 or later from an older\nversion,the server displays a name such as a-b-c (which is in the old format)\nas #mysql50#a-b-c, and you must refer to the name using the #mysql50# prefix.\nUse UPGRADE DATA DIRECTORY NAME in this case to explicitly tell the server to\nre-encode the database directory name to the current encoding format:\n\nALTER DATABASE `#mysql50#a-b-c` UPGRADE DATA DIRECTORY NAME;\n\nAfter executing this statement, you can refer to the database as a-b-c without\nthe special #mysql50# prefix.\n\nCOMMENT\n-------\n\nMariaDB starting with 10.5.0\n----------------------------\nFrom MariaDB 10.5.0, it is possible to add a comment of a maximum of 1024\nbytes. If the comment length exceeds this length, a error/warning code 4144 is\nthrown. The database comment is also added to the db.opt file, as well as to\nthe information_schema.schemata table.\n\nExamples\n--------\n\nALTER DATABASE test CHARACTER SET=\'utf8\' COLLATE=\'utf8_bin\';\n\nFrom MariaDB 10.5.0:\n\nALTER DATABASE p COMMENT=\'Presentations\';\n\nURL: https://mariadb.com/kb/en/alter-database/','','https://mariadb.com/kb/en/alter-database/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (699,38,'ALTER EVENT','Modifies one or more characteristics of an existing event.\n\nSyntax\n------\n\nALTER\n [DEFINER = { user | CURRENT_USER }]\n EVENT event_name\n [ON SCHEDULE schedule]\n [ON COMPLETION [NOT] PRESERVE]\n [RENAME TO new_event_name]\n [ENABLE | DISABLE | DISABLE ON SLAVE]\n [COMMENT \'comment\']\n [DO sql_statement]\n\nDescription\n-----------\n\nThe ALTER EVENT statement is used to change one or more of the characteristics\nof an existing event without the need to drop and recreate it. The syntax for\neach of the DEFINER, ON SCHEDULE, ON COMPLETION, COMMENT, ENABLE / DISABLE,\nand DO clauses is exactly the same as when used with CREATE EVENT.\n\nThis statement requires the EVENT privilege. When a user executes a successful\nALTER EVENT statement, that user becomes the definer for the affected event.\n\n(In MySQL 5.1.11 and earlier, an event could be altered only by its definer,\nor by a user having the SUPER privilege.)\n\nALTER EVENT works only with an existing event:\n\nALTER EVENT no_such_event ON SCHEDULE EVERY \'2:3\' DAY_HOUR;\nERROR 1539 (HY000): Unknown event \'no_such_event\'\n\nExamples\n--------\n\nALTER EVENT myevent \n ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 2 HOUR\n DO\n UPDATE myschema.mytable SET mycol = mycol + 1;\n\nURL: https://mariadb.com/kb/en/alter-event/','','https://mariadb.com/kb/en/alter-event/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (700,38,'ALTER FUNCTION','Syntax\n------\n\nALTER FUNCTION func_name [characteristic ...]\n\ncharacteristic:\n { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }\n | SQL SECURITY { DEFINER | INVOKER }\n | COMMENT \'string\'\n\nDescription\n-----------\n\nThis statement can be used to change the characteristics of a stored function.\nMore than one change may be specified in an ALTER FUNCTION statement. However,\nyou cannot change the parameters or body of a stored function using this\nstatement; to make such changes, you must drop and re-create the function\nusing DROP FUNCTION and CREATE FUNCTION.\n\nYou must have the ALTER ROUTINE privilege for the function. (That privilege is\ngranted automatically to the function creator.) If binary logging is enabled,\nthe ALTER FUNCTION statement might also require the SUPER privilege, as\ndescribed in Binary Logging of Stored Routines.\n\nExample\n-------\n\nALTER FUNCTION hello SQL SECURITY INVOKER;\n\nURL: https://mariadb.com/kb/en/alter-function/','','https://mariadb.com/kb/en/alter-function/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (701,38,'ALTER LOGFILE GROUP','Syntax\n------\n\nALTER LOGFILE GROUP logfile_group\n ADD UNDOFILE \'file_name\'\n [INITIAL_SIZE [=] size]\n [WAIT]\n ENGINE [=] engine_name\n\nThe ALTER LOGFILE GROUP statement is not supported by MariaDB. It was\noriginally inherited from MySQL NDB Cluster. See MDEV-19295 for more\ninformation.\n\nURL: https://mariadb.com/kb/en/alter-logfile-group/','','https://mariadb.com/kb/en/alter-logfile-group/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (702,38,'ALTER PROCEDURE','Syntax\n------\n\nALTER PROCEDURE proc_name [characteristic ...]\n\ncharacteristic:\n { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }\n | SQL SECURITY { DEFINER | INVOKER }\n | COMMENT \'string\'\n\nDescription\n-----------\n\nThis statement can be used to change the characteristics of a stored\nprocedure. More than one change may be specified in an ALTER PROCEDURE\nstatement. However, you cannot change the parameters or body of a stored\nprocedure using this statement. To make such changes, you must drop and\nre-create the procedure using either CREATE OR REPLACE PROCEDURE (since\nMariaDB 10.1.3) or DROP PROCEDURE and CREATE PROCEDURE (MariaDB 10.1.2 and\nbefore).\n\nYou must have the ALTER ROUTINE privilege for the procedure. By default, that\nprivilege is granted automatically to the procedure creator. See Stored\nRoutine Privileges.\n\nExample\n-------\n\nALTER PROCEDURE simpleproc SQL SECURITY INVOKER;\n\nURL: https://mariadb.com/kb/en/alter-procedure/','','https://mariadb.com/kb/en/alter-procedure/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (703,38,'ALTER SERVER','Syntax\n------\n\nALTER SERVER server_name\n OPTIONS (option [, option] ...)\n\nDescription\n-----------\n\nAlters the server information for server_name, adjusting the specified options\nas per the CREATE SERVER command. The corresponding fields in the\nmysql.servers table are updated accordingly. This statement requires the SUPER\nprivilege or, from MariaDB 10.5.2, the FEDERATED ADMIN privilege.\n\nALTER SERVER is not written to the binary log, irrespective of the binary log\nformat being used. From MariaDB 10.1.13, Galera replicates the CREATE SERVER,\nALTER SERVER and DROP SERVER statements.\n\nExamples\n--------\n\nALTER SERVER s OPTIONS (USER \'sally\');\n\nURL: https://mariadb.com/kb/en/alter-server/','','https://mariadb.com/kb/en/alter-server/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (704,38,'ALTER TABLESPACE','The ALTER TABLESPACE statement is not supported by MariaDB. It was originally\ninherited from MySQL NDB Cluster. In MySQL 5.7 and later, the statement is\nalso supported for InnoDB. However, MariaDB has chosen not to include that\nspecific feature. See MDEV-19294 for more information.\n\nURL: https://mariadb.com/kb/en/alter-tablespace/','','https://mariadb.com/kb/en/alter-tablespace/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (705,38,'ALTER VIEW','Syntax\n------\n\nALTER\n [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]\n [DEFINER = { user | CURRENT_USER }]\n [SQL SECURITY { DEFINER | INVOKER }]\n VIEW view_name [(column_list)]\n AS select_statement\n [WITH [CASCADED | LOCAL] CHECK OPTION]\n\nDescription\n-----------\n\nThis statement changes the definition of a view, which must exist. The syntax\nis similar to that for CREATE VIEW and the effect is the same as for CREATE OR\nREPLACE VIEW if the view exists. This statement requires the CREATE VIEW and\nDROP privileges for the view, and some privilege for each column referred to\nin the SELECT statement. ALTER VIEW is allowed only to the definer or users\nwith the SUPER privilege.\n\nExample\n-------\n\nALTER VIEW v AS SELECT a, a*3 AS a2 FROM t;\n\nURL: https://mariadb.com/kb/en/alter-view/','','https://mariadb.com/kb/en/alter-view/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (706,38,'CREATE TABLE','Syntax\n------\n\nCREATE [OR REPLACE] [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name\n (create_definition,...) [table_options ]... [partition_options]\nCREATE [OR REPLACE] [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name\n [(create_definition,...)] [table_options ]... [partition_options]\n select_statement\nCREATE [OR REPLACE] [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name\n { LIKE old_table_name | (LIKE old_table_name) }\nselect_statement:\n [IGNORE | REPLACE] [AS] SELECT ... (Some legal select statement)\n\nDescription\n-----------\n\nUse the CREATE TABLE statement to create a table with the given name.\n\nIn its most basic form, the CREATE TABLE statement provides a table name\nfollowed by a list of columns, indexes, and constraints. By default, the table\nis created in the default database. Specify a database with db_name.tbl_name.\nIf you quote the table name, you must quote the database name and table name\nseparately as `db_name`.`tbl_name`. This is particularly useful for CREATE\nTABLE ... SELECT, because it allows to create a table into a database, which\ncontains data from other databases. See Identifier Qualifiers.\n\nIf a table with the same name exists, error 1050 results. Use IF NOT EXISTS to\nsuppress this error and issue a note instead. Use SHOW WARNINGS to see notes.\n\nThe CREATE TABLE statement automatically commits the current transaction,\nexcept when using the TEMPORARY keyword.\n\nFor valid identifiers to use as table names, see Identifier Names.\n\nNote: if the default_storage_engine is set to ColumnStore then it needs\nsetting on all UMs. Otherwise when the tables using the default engine are\nreplicated across UMs they will use the wrong engine. You should therefore not\nuse this option as a session variable with ColumnStore.\n\nMicrosecond precision can be between 0-6. If no precision is specified it is\nassumed to be 0, for backward compatibility reasons.\n\nPrivileges\n----------\n\nExecuting the CREATE TABLE statement requires the CREATE privilege for the\ntable or the database.\n\nCREATE OR REPLACE\n-----------------\n\nIf the OR REPLACE clause is used and the table already exists, then instead of\nreturning an error, the server will drop the existing table and replace it\nwith the newly defined table.\n\nThis syntax was originally added to make replication more robust if it has to\nrollback and repeat statements such as CREATE ... SELECT on replicas.\n\nCREATE OR REPLACE TABLE table_name (a int);\n\nis basically the same as:\n\nDROP TABLE IF EXISTS table_name;\nCREATE TABLE table_name (a int);\n\nwith the following exceptions:\n\n* If table_name was locked with LOCK TABLES it will continue to be locked\nafter the statement.\n* Temporary tables are only dropped if the TEMPORARY keyword was used. (With\nDROP TABLE, temporary tables are preferred to be dropped before normal\ntables).\n\nThings to be Aware of With CREATE OR REPLACE\n--------------------------------------------\n\n* The table is dropped first (if it existed), after that the CREATE is done.\nBecause of this, if the CREATE fails, then the table will not exist anymore\nafter the statement. If the table was used with LOCK TABLES it will be\nunlocked.\n* One can\'t use OR REPLACE together with IF EXISTS.\n* Slaves in replication will by default use CREATE OR REPLACE when replicating\nCREATE statements that don\'\'t use IF EXISTS. This can be changed by setting\nthe variable slave-ddl-exec-mode to STRICT.\n\nCREATE TABLE IF NOT EXISTS\n--------------------------\n\nIf the IF NOT EXISTS clause is used, then the table will only be created if a\ntable with the same name does not already exist. If the table already exists,\nthen a warning will be triggered by default.\n\nCREATE TEMPORARY TABLE\n----------------------\n\nUse the TEMPORARY keyword to create a temporary table that is only available\nto the current session. Temporary tables are dropped when the session ends.\nTemporary table names are specific to the session. They will not conflict with\nother temporary tables from other sessions even if they share the same name.\nThey will shadow names of non-temporary tables or views, if they are\nidentical. A temporary table can have the same name as a non-temporary table\nwhich is located in the same database. In that case, their name will reference\nthe temporary table when used in SQL statements. You must have the CREATE\nTEMPORARY TABLES privilege on the database to create temporary tables. If no\nstorage engine is specified, the default_tmp_storage_engine setting will\ndetermine the engine.\n\nROCKSDB temporary tables cannot be created by setting the\ndefault_tmp_storage_engine system variable, or using CREATE TEMPORARY TABLE\nLIKE. Before MariaDB 10.7, they could be specified, but would silently fail,\nand a MyISAM table would be created instead. From MariaDB 10.7 an error is\nreturned. Explicitly creating a temporary table with ENGINE=ROCKSDB has never\nbeen permitted.\n\nCREATE TABLE ... LIKE\n---------------------\n\nUse the LIKE clause instead of a full table definition to create a table with\nthe same definition as another table, including columns, indexes, and table\noptions. Foreign key definitions, as well as any DATA DIRECTORY or INDEX\nDIRECTORY table options specified on the original table, will not be created.\n\nCREATE TABLE ... SELECT\n-----------------------\n\nYou can create a table containing data from other tables using the CREATE ...\nSELECT statement. Columns will be created in the table for each field returned\nby the SELECT query.\n\nYou can also define some columns normally and add other columns from a SELECT.\nYou can also create columns in the normal way and assign them some values\nusing the query, this is done to force a certain type or other field\ncharacteristics. The columns that are not named in the query will be placed\nbefore the others. For example:\n\nCREATE TABLE test (a INT NOT NULL, b CHAR(10)) ENGINE=MyISAM\n SELECT 5 AS b, c, d FROM another_table;\n\nRemember that the query just returns data. If you want to use the same\nindexes, or the same columns attributes ([NOT] NULL, DEFAULT, AUTO_INCREMENT)\nin the new table, you need to specify them manually. Types and sizes are not\nautomatically preserved if no data returned by the SELECT requires the full\nsize, and VARCHAR could be converted into CHAR. The CAST() function can be\nused to forcee the new table to use certain types.\n\nAliases (AS) are taken into account, and they should always be used when you\nSELECT an expression (function, arithmetical operation, etc).\n\nIf an error occurs during the query, the table will not be created at all.\n\nIf the new table has a primary key or UNIQUE indexes, you can use the IGNORE\nor REPLACE keywords to handle duplicate key errors during the query. IGNORE\nmeans that the newer values must not be inserted an identical value exists in\nthe index. REPLACE means that older values must be overwritten.\n\nIf the columns in the new table are more than the rows returned by the query,\nthe columns populated by the query will be placed after other columns. Note\nthat if the strict SQL_MODE is on, and the columns that are not names in the\nquery do not have a DEFAULT value, an error will raise and no rows will be\ncopied.\n\nConcurrent inserts are not used during the execution of a CREATE ... SELECT.\n\nIf the table already exists, an error similar to the following will be\nreturned:\n\nERROR 1050 (42S01): Table \'t\' already exists\n\nIf the IF NOT EXISTS clause is used and the table exists, a note will be\nproduced instead of an error.\n\nTo insert rows from a query into an existing table, INSERT ... SELECT can be\nused.\n\nColumn Definitions\n------------------\n\ncreate_definition:\n { col_name column_definition | index_definition | period_definition | CHECK\n(expr) }\ncolumn_definition:\n data_type\n [NOT NULL | NULL] [DEFAULT default_value | (expression)]\n [ON UPDATE [NOW | CURRENT_TIMESTAMP] [(precision)]]\n [AUTO_INCREMENT] [ZEROFILL] [UNIQUE [KEY] | [PRIMARY] KEY]\n [INVISIBLE] [{WITH|WITHOUT} SYSTEM VERSIONING]\n [COMMENT \'string\'] [REF_SYSTEM_ID = value]\n [reference_definition]\n | data_type [GENERATED ALWAYS]\n AS { { ROW {START|END} } | { (expression) [VIRTUAL | PERSISTENT | STORED] } }\n [UNIQUE [KEY]] [COMMENT \'string\']\nconstraint_definition:\n CONSTRAINT [constraint_name] CHECK (expression)\nNote: Until MariaDB 10.4, MariaDB accepts the shortcut format with a\nREFERENCES clause only in ALTER TABLE and CREATE TABLE statements, but that\nsyntax does nothing. For example:\n\nCREATE TABLE b(for_key INT REFERENCES a(not_key));\n\nMariaDB simply parses it without returning any error or warning, for\ncompatibility with other DBMS\'s. Before MariaDB 10.2.1 this was also true for\nCHECK constraints. However, only the syntax described below creates foreign\nkeys.\n\nFrom MariaDB 10.5, MariaDB will attempt to apply the constraint. See Foreign\nKeys examples.\n\nEach definition either creates a column in the table or specifies and index or\nconstraint on one or more columns. See Indexes below for details on creating\nindexes.\n\nCreate a column by specifying a column name and a data type, optionally\nfollowed by column options. See Data Types for a full list of data types\nallowed in MariaDB.\n\nNULL and NOT NULL\n-----------------\n\nUse the NULL or NOT NULL options to specify that values in the column may or\nmay not be NULL, respectively. By default, values may be NULL. See also NULL\nValues in MariaDB.\n\nDEFAULT Column Option\n---------------------\n\nSpecify a default value using the DEFAULT clause. If you don\'t specify DEFAULT\nthen the following rules apply:\n\n* If the column is not defined with NOT NULL, AUTO_INCREMENT or TIMESTAMP, an\nexplicit DEFAULT NULL will be added.\nNote that in MySQL and in MariaDB before 10.1.6, you may get an explicit\nDEFAULT for primary key parts, if not specified with NOT NULL.\n\nThe default value will be used if you INSERT a row without specifying a value\nfor that column, or if you specify DEFAULT for that column. Before MariaDB\n10.2.1 you couldn\'t usually provide an expression or function to evaluate at\ninsertion time. You had to provide a constant default value instead. The one\nexception is that you may use CURRENT_TIMESTAMP as the default value for a\nTIMESTAMP column to use the current timestamp at insertion time.\n\nCURRENT_TIMESTAMP may also be used as the default value for a DATETIME\n\nYou can use most functions in DEFAULT. Expressions should have parentheses\naround them. If you use a non deterministic function in DEFAULT then all\ninserts to the table will be replicated in row mode. You can even refer to\nearlier columns in the DEFAULT expression (excluding AUTO_INCREMENT columns):\n\nCREATE TABLE t1 (a int DEFAULT (1+1), b int DEFAULT (a+1));\nCREATE TABLE t2 (a bigint primary key DEFAULT UUID_SHORT());\n\nThe DEFAULT clause cannot contain any stored functions or subqueries, and a\ncolumn used in the clause must already have been defined earlier in the\nstatement.\n\nIt is possible to assign BLOB or TEXT columns a DEFAULT value. In versions\nprior to MariaDB 10.2.1, assigning a default to these columns was not possible.\n\nYou can also use DEFAULT (NEXT VALUE FOR sequence)\n\nAUTO_INCREMENT Column Option\n----------------------------\n\nUse AUTO_INCREMENT to create a column whose value can can be set automatically\nfrom a simple counter. You can only use AUTO_INCREMENT on a column with an\ninteger type. The column must be a key, and there can only be one\nAUTO_INCREMENT column in a table. If you insert a row without specifying a\nvalue for that column (or if you specify 0, NULL, or DEFAULT as the value),\nthe actual value will be taken from the counter, with each insertion\nincrementing the counter by one. You can still insert a value explicitly. If\nyou insert a value that is greater than the current counter value, the counter\nis set based on the new value. An AUTO_INCREMENT column is implicitly NOT\nNULL. Use LAST_INSERT_ID to get the AUTO_INCREMENT value most recently used by\nan INSERT statement.\n\nZEROFILL Column Option\n----------------------\n\nIf the ZEROFILL column option is specified for a column using a numeric data\ntype, then the column will be set to UNSIGNED and the spaces used by default\nto pad the field are replaced with zeros. ZEROFILL is ignored in expressions\nor as part of a UNION. ZEROFILL is a non-standard MySQL and MariaDB\nenhancement.\n\nPRIMARY KEY Column Option\n-------------------------\n\nUse PRIMARY KEY to make a column a primary key. A primary key is a special\ntype of a unique key. There can be at most one primary key per table, and it\nis implicitly NOT NULL.\n\nSpecifying a column as a unique key creates a unique index on that column. See\nthe Index Definitions section below for more information.\n\nUNIQUE KEY Column Option\n------------------------\n\nUse UNIQUE KEY (or just UNIQUE) to specify that all values in the column must\nbe distinct from each other. Unless the column is NOT NULL, there may be\nmultiple rows with NULL in the column.\n\nSpecifying a column as a unique key creates a unique index on that column.\n\nSee the Index Definitions section below for more information.\n\nCOMMENT Column Option\n---------------------\n\nYou can provide a comment for each column using the COMMENT clause. The\nmaximum length is 1024 characters. Use the SHOW FULL COLUMNS statement to see\ncolumn comments.\n\nREF_SYSTEM_ID\n-------------\n\nREF_SYSTEM_ID can be used to specify Spatial Reference System IDs for spatial\ndata type columns. For example:\n\nCREATE TABLE t1(g GEOMETRY(9,4) REF_SYSTEM_ID=101);\n\nGenerated Columns\n-----------------\n\nA generated column is a column in a table that cannot explicitly be set to a\nspecific value in a DML query. Instead, its value is automatically generated\nbased on an expression. This expression might generate the value based on the\nvalues of other columns in the table, or it might generate the value by\ncalling built-in functions or user-defined functions (UDFs).\n\nThere are two types of generated columns:\n\n* PERSISTENT or STORED: This type\'s value is actually stored in the table.\n* VIRTUAL: This type\'s value is not stored at all. Instead, the value is\ngenerated dynamically when the table is queried. This type is the default.\n\nGenerated columns are also sometimes called computed columns or virtual\ncolumns.\n\nFor a complete description about generated columns and their limitations, see\nGenerated (Virtual and Persistent/Stored) Columns.\n\nCOMPRESSED','','https://mariadb.com/kb/en/create-table/'); +update help_topic set description = CONCAT(description, '\n----------\n\nCertain columns may be compressed. See Storage-Engine Independent Column\nCompression.\n\nINVISIBLE\n---------\n\nColumns may be made invisible, and hidden in certain contexts. See Invisible\nColumns.\n\nWITH SYSTEM VERSIONING Column Option\n------------------------------------\n\nColumns may be explicitly marked as included from system versioning. See\nSystem-versioned tables for details.\n\nWITHOUT SYSTEM VERSIONING Column Option\n---------------------------------------\n\nColumns may be explicitly marked as excluded from system versioning. See\nSystem-versioned tables for details.\n\nIndex Definitions\n-----------------\n\nindex_definition:\n {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option]\n...\n {{{|}}} {FULLTEXT|SPATIAL} [INDEX|KEY] [index_name] (index_col_name,...)\n[index_option] ...\n {{{|}}} [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...)\n[index_option] ...\n {{{|}}} [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type]\n(index_col_name,...) [index_option] ...\n {{{|}}} [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...)\nreference_definition\n\nindex_col_name:\n col_name [(length)] [ASC | DESC]\n\nindex_type:\n USING {BTREE | HASH | RTREE}\n\nindex_option:\n [ KEY_BLOCK_SIZE [=] value\n {{{|}}} index_type\n {{{|}}} WITH PARSER parser_name\n {{{|}}} COMMENT \'string\'\n {{{|}}} CLUSTERING={YES| NO} ]\n [ IGNORED | NOT IGNORED ]\n\nreference_definition:\n REFERENCES tbl_name (index_col_name,...)\n [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]\n [ON DELETE reference_option]\n [ON UPDATE reference_option]\n\nreference_option:\n RESTRICT | CASCADE | SET NULL | NO ACTION\n\nINDEX and KEY are synonyms.\n\nIndex names are optional, if not specified an automatic name will be assigned.\nIndex name are needed to drop indexes and appear in error messages when a\nconstraint is violated.\n\nIndex Categories\n----------------\n\nPlain Indexes\n-------------\n\nPlain indexes are regular indexes that are not unique, and are not acting as a\nprimary key or a foreign key. They are also not the \"specialized\" FULLTEXT or\nSPATIAL indexes.\n\nSee Getting Started with Indexes: Plain Indexes for more information.\n\nPRIMARY KEY\n-----------\n\nFor PRIMARY KEY indexes, you can specify a name for the index, but it is\nignored, and the name of the index is always PRIMARY. From MariaDB 10.3.18 and\nMariaDB 10.4.8, a warning is explicitly issued if a name is specified. Before\nthen, the name was silently ignored.\n\nSee Getting Started with Indexes: Primary Key for more information.\n\nUNIQUE\n------\n\nThe UNIQUE keyword means that the index will not accept duplicated values,\nexcept for NULLs. An error will raise if you try to insert duplicate values in\na UNIQUE index.\n\nFor UNIQUE indexes, you can specify a name for the constraint, using the\nCONSTRAINT keyword. That name will be used in error messages.\n\nMariaDB starting with 10.5\n--------------------------\nUnique, if index type is not specified, is normally a BTREE index that can\nalso be used by the optimizer to find rows. If the key is longer than the max\nkey length for the used storage engine, a HASH key will be created. This\nenables MariaDB to enforce uniqueness for any type or number of columns.\n\nSee Getting Started with Indexes: Unique Index for more information.\n\nFOREIGN KEY\n-----------\n\nFor FOREIGN KEY indexes, a reference definition must be provided.\n\nFor FOREIGN KEY indexes, you can specify a name for the constraint, using the\nCONSTRAINT keyword. That name will be used in error messages.\n\nFirst, you have to specify the name of the target (parent) table and a column\nor a column list which must be indexed and whose values must match to the\nforeign key\'s values. The MATCH clause is accepted to improve the\ncompatibility with other DBMS\'s, but has no meaning in MariaDB. The ON DELETE\nand ON UPDATE clauses specify what must be done when a DELETE (or a REPLACE)\nstatements attempts to delete a referenced row from the parent table, and when\nan UPDATE statement attempts to modify the referenced foreign key columns in a\nparent table row, respectively. The following options are allowed:\n\n* RESTRICT: The delete/update operation is not performed. The statement\nterminates with a 1451 error (SQLSTATE \'2300\').\n* NO ACTION: Synonym for RESTRICT.\n* CASCADE: The delete/update operation is performed in both tables.\n* SET NULL: The update or delete goes ahead in the parent table, and the\ncorresponding foreign key fields in the child table are set to NULL. (They\nmust not be defined as NOT NULL for this to succeed).\n* SET DEFAULT: This option is currently implemented only for the PBXT storage\nengine, which is disabled by default and no longer maintained. It sets the\nchild table\'s foreign key fields to their DEFAULT values when the referenced\nparent table key entries are updated or deleted.\n\nIf either clause is omitted, the default behavior for the omitted clause is\nRESTRICT.\n\nSee Foreign Keys for more information.\n\nFULLTEXT\n--------\n\nUse the FULLTEXT keyword to create full-text indexes.\n\nSee Full-Text Indexes for more information.\n\nSPATIAL\n-------\n\nUse the SPATIAL keyword to create geometric indexes.\n\nSee SPATIAL INDEX for more information.\n\nIndex Options\n-------------\n\nKEY_BLOCK_SIZE Index Option\n---------------------------\n\nThe KEY_BLOCK_SIZE index option is similar to the KEY_BLOCK_SIZE table option.\n\nWith the InnoDB storage engine, if you specify a non-zero value for the\nKEY_BLOCK_SIZE table option for the whole table, then the table will\nimplicitly be created with the ROW_FORMAT table option set to COMPRESSED.\nHowever, this does not happen if you just set the KEY_BLOCK_SIZE index option\nfor one or more indexes in the table. The InnoDB storage engine ignores the\nKEY_BLOCK_SIZE index option. However, the SHOW CREATE TABLE statement may\nstill report it for the index.\n\nFor information about the KEY_BLOCK_SIZE index option, see the KEY_BLOCK_SIZE\ntable option below.\n\nIndex Types\n-----------\n\nEach storage engine supports some or all index types. See Storage Engine Index\nTypes for details on permitted index types for each storage engine.\n\nDifferent index types are optimized for different kind of operations:\n\n* BTREE is the default type, and normally is the best choice. It is supported\nby all storage engines. It can be used to compare a column\'s value with a\nvalue using the =, >, >=, <, <=, BETWEEN, and LIKE operators. BTREE can also\nbe used to find NULL values. Searches against an index prefix are possible.\n* HASH is only supported by the MEMORY storage engine. HASH indexes can only\nbe used for =, <=, and >= comparisons. It can not be used for the ORDER BY\nclause. Searches against an index prefix are not possible.\n* RTREE is the default for SPATIAL indexes, but if the storage engine does not\nsupport it BTREE can be used.\n\nIndex columns names are listed between parenthesis. After each column, a\nprefix length can be specified. If no length is specified, the whole column\nwill be indexed. ASC and DESC can be specified for compatibility with are\nDBMS\'s, but have no meaning in MariaDB.\n\nWITH PARSER Index Option\n------------------------\n\nThe WITH PARSER index option only applies to FULLTEXT indexes and contains the\nfulltext parser name. The fulltext parser must be an installed plugin.\n\nCOMMENT Index Option\n--------------------\n\nA comment of up to 1024 characters is permitted with the COMMENT index option.\n\nThe COMMENT index option allows you to specify a comment with user-readable\ntext describing what the index is for. This information is not used by the\nserver itself.\n\nCLUSTERING Index Option\n-----------------------\n\nThe CLUSTERING index option is only valid for tables using the TokuDB storage\nengine.\n\nIGNORED / NOT IGNORED\n---------------------\n\nMariaDB starting with 10.6.0\n----------------------------\nFrom MariaDB 10.6.0, indexes can be specified to be ignored by the optimizer.\nSee Ignored Indexes.\n\nPeriods\n-------\n\nperiod_definition:\n PERIOD FOR SYSTEM_TIME (start_column_name, end_column_name)\nMariaDB supports a subset of the standard syntax for periods. At the moment\nit\'s only used for creating System-versioned tables. Both columns must be\ncreated, must be either of a TIMESTAMP(6) or BIGINT UNSIGNED type, and be\ngenerated as ROW START and ROW END accordingly. See System-versioned tables\nfor details.\n\nThe table must also have the WITH SYSTEM VERSIONING clause.\n\nConstraint Expressions\n----------------------\n\nNote: Before MariaDB 10.2.1, constraint expressions were accepted in the\nsyntax but ignored.\n\nMariaDB 10.2.1 introduced two ways to define a constraint:\n\n* CHECK(expression) given as part of a column definition.\n* CONSTRAINT [constraint_name] CHECK (expression)\n\nBefore a row is inserted or updated, all constraints are evaluated in the\norder they are defined. If any constraints fails, then the row will not be\nupdated. One can use most deterministic functions in a constraint, including\nUDFs.\n\ncreate table t1 (a int check(a>0) ,b int check (b> 0), constraint abc check\n(a>b));\n\nIf you use the second format and you don\'t give a name to the constraint, then\nthe constraint will get a auto generated name. This is done so that you can\nlater delete the constraint with ALTER TABLE DROP constraint_name.\n\nOne can disable all constraint expression checks by setting the variable\ncheck_constraint_checks to OFF. This is useful for example when loading a\ntable that violates some constraints that you want to later find and fix in\nSQL.\n\nSee CONSTRAINT for more information.\n\nTable Options\n-------------\n\nFor each individual table you create (or alter), you can set some table\noptions. The general syntax for setting options is:\n\n<OPTION_NAME> = <option_value>, [<OPTION_NAME> = <option_value> ...]\n\nThe equal sign is optional.\n\nSome options are supported by the server and can be used for all tables, no\nmatter what storage engine they use; other options can be specified for all\nstorage engines, but have a meaning only for some engines. Also, engines can\nextend CREATE TABLE with new options.\n\nIf the IGNORE_BAD_TABLE_OPTIONS SQL_MODE is enabled, wrong table options\ngenerate a warning; otherwise, they generate an error.\n\ntable_option: \n [STORAGE] ENGINE [=] engine_name\n | AUTO_INCREMENT [=] value\n | AVG_ROW_LENGTH [=] value\n | [DEFAULT] CHARACTER SET [=] charset_name\n | CHECKSUM [=] {0 | 1}\n | [DEFAULT] COLLATE [=] collation_name\n | COMMENT [=] \'string\'\n | CONNECTION [=] \'connect_string\'\n | DATA DIRECTORY [=] \'absolute path to directory\'\n | DELAY_KEY_WRITE [=] {0 | 1}\n | ENCRYPTED [=] {YES | NO}\n | ENCRYPTION_KEY_ID [=] value\n | IETF_QUOTES [=] {YES | NO}\n | INDEX DIRECTORY [=] \'absolute path to directory\'\n | INSERT_METHOD [=] { NO | FIRST | LAST }\n | KEY_BLOCK_SIZE [=] value\n | MAX_ROWS [=] value\n | MIN_ROWS [=] value\n | PACK_KEYS [=] {0 | 1 | DEFAULT}\n | PAGE_CHECKSUM [=] {0 | 1}\n | PAGE_COMPRESSED [=] {0 | 1}\n | PAGE_COMPRESSION_LEVEL [=] {0 .. 9}\n | PASSWORD [=] \'string\'\n | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT|PAGE}\n | SEQUENCE [=] {0|1}\n | STATS_AUTO_RECALC [=] {DEFAULT|0|1}\n | STATS_PERSISTENT [=] {DEFAULT|0|1}\n | STATS_SAMPLE_PAGES [=] {DEFAULT|value}\n | TABLESPACE tablespace_name\n | TRANSACTIONAL [=] {0 | 1}\n | UNION [=] (tbl_name[,tbl_name]...)\n | WITH SYSTEM VERSIONING\n\n[STORAGE] ENGINE\n----------------\n\n[STORAGE] ENGINE specifies a storage engine for the table. If this option is\nnot used, the default storage engine is used instead. That is, the\ndefault_storage_engine session option value if it is set, or the value\nspecified for the --default-storage-engine mysqld startup option, or the\ndefault storage engine, InnoDB. If the specified storage engine is not\ninstalled and active, the default value will be used, unless the\nNO_ENGINE_SUBSTITUTION SQL MODE is set (default). This is only true for CREATE\nTABLE, not for ALTER TABLE. For a list of storage engines that are present in\nyour server, issue a SHOW ENGINES.\n\nAUTO_INCREMENT\n--------------\n\nAUTO_INCREMENT specifies the initial value for the AUTO_INCREMENT primary key.\nThis works for MyISAM, Aria, InnoDB, MEMORY, and ARCHIVE tables. You can\nchange this option with ALTER TABLE, but in that case the new value must be\nhigher than the highest value which is present in the AUTO_INCREMENT column.\nIf the storage engine does not support this option, you can insert (and then\ndelete) a row having the wanted value - 1 in the AUTO_INCREMENT column.\n\nAVG_ROW_LENGTH\n--------------\n\nAVG_ROW_LENGTH is the average rows size. It only applies to tables using\nMyISAM and Aria storage engines that have the ROW_FORMAT table option set to\nFIXED format.\n\nMyISAM uses MAX_ROWS and AVG_ROW_LENGTH to decide the maximum size of a table\n(default: 256TB, or the maximum file size allowed by the system).\n\n[DEFAULT] CHARACTER SET/CHARSET\n-------------------------------\n\n[DEFAULT] CHARACTER SET (or [DEFAULT] CHARSET) is used to set a default\ncharacter set for the table. This is the character set used for all columns\nwhere an explicit character set is not specified. If this option is omitted or\nDEFAULT is specified, database\'s default character set will be used. See\nSetting Character Sets and Collations for details on setting the character\nsets.\n\nCHECKSUM/TABLE_CHECKSUM\n-----------------------\n\nCHECKSUM (or TABLE_CHECKSUM) can be set to 1 to maintain a live checksum for\nall table\'s rows. This makes write operations slower, but CHECKSUM TABLE will\nbe very fast. This option is only supported for MyISAM and Aria tables.\n\n[DEFAULT] COLLATE\n-----------------\n\n[DEFAULT] COLLATE is used to set a default collation for the table. This is\nthe collation used for all columns where an explicit character set is not\nspecified. If this option is omitted or DEFAULT is specified, database\'s\ndefault option will be used. See Setting Character Sets and Collations for\ndetails on setting the collations\n\nCOMMENT\n-------\n\nCOMMENT is a comment for the table. The maximum length is 2048 characters.\nAlso used to define table parameters when creating a Spider table.\n\nCONNECTION\n----------\n\nCONNECTION is used to specify a server name or a connection string for a\nSpider, CONNECT, Federated or FederatedX table.\n\nDATA DIRECTORY/INDEX DIRECTORY\n------------------------------\n') WHERE help_topic_id = 706; +update help_topic set description = CONCAT(description, '\nDATA DIRECTORY and INDEX DIRECTORY are supported for MyISAM and Aria, and DATA\nDIRECTORY is also supported by InnoDB if the innodb_file_per_table server\nsystem variable is enabled, but only in CREATE TABLE, not in ALTER TABLE. So,\ncarefully choose a path for InnoDB tables at creation time, because it cannot\nbe changed without dropping and re-creating the table. These options specify\nthe paths for data files and index files, respectively. If these options are\nomitted, the database\'s directory will be used to store data files and index\nfiles. Note that these table options do not work for partitioned tables (use\nthe partition options instead), or if the server has been invoked with the\n--skip-symbolic-links startup option. To avoid the overwriting of old files\nwith the same name that could be present in the directories, you can use the\n--keep_files_on_create option (an error will be issued if files already\nexist). These options are ignored if the NO_DIR_IN_CREATE SQL_MODE is enabled\n(useful for replication slaves). Also note that symbolic links cannot be used\nfor InnoDB tables.\n\nDATA DIRECTORY works by creating symlinks from where the table would normally\nhave been (inside the datadir) to where the option specifies. For security\nreasons, to avoid bypassing the privilege system, the server does not permit\nsymlinks inside the datadir. Therefore, DATA DIRECTORY cannot be used to\nspecify a location inside the datadir. An attempt to do so will result in an\nerror 1210 (HY000) Incorrect arguments to DATA DIRECTORY.\n\nDELAY_KEY_WRITE\n---------------\n\nDELAY_KEY_WRITE is supported by MyISAM and Aria, and can be set to 1 to speed\nup write operations. In that case, when data are modified, the indexes are not\nupdated until the table is closed. Writing the changes to the index file\naltogether can be much faster. However, note that this option is applied only\nif the delay_key_write server variable is set to \'ON\'. If it is \'OFF\' the\ndelayed index writes are always disabled, and if it is \'ALL\' the delayed index\nwrites are always used, disregarding the value of DELAY_KEY_WRITE.\n\nENCRYPTED\n---------\n\nThe ENCRYPTED table option can be used to manually set the encryption status\nof an InnoDB table. See InnoDB Encryption for more information.\n\nAria does not support the ENCRYPTED table option. See MDEV-18049.\n\nSee Data-at-Rest Encryption for more information.\n\nENCRYPTION_KEY_ID\n-----------------\n\nThe ENCRYPTION_KEY_ID table option can be used to manually set the encryption\nkey of an InnoDB table. See InnoDB Encryption for more information.\n\nAria does not support the ENCRYPTION_KEY_ID table option. See MDEV-18049.\n\nSee Data-at-Rest Encryption for more information.\n\nIETF_QUOTES\n-----------\n\nFor the CSV storage engine, the IETF_QUOTES option, when set to YES, enables\nIETF-compatible parsing of embedded quote and comma characters. Enabling this\noption for a table improves compatibility with other tools that use CSV, but\nis not compatible with MySQL CSV tables, or MariaDB CSV tables created without\nthis option. Disabled by default.\n\nINSERT_METHOD\n-------------\n\nINSERT_METHOD is only used with MERGE tables. This option determines in which\nunderlying table the new rows should be inserted. If you set it to \'NO\' (which\nis the default) no new rows can be added to the table (but you will still be\nable to perform INSERTs directly against the underlying tables). FIRST means\nthat the rows are inserted into the first table, and LAST means that thet are\ninserted into the last table.\n\nKEY_BLOCK_SIZE\n--------------\n\nKEY_BLOCK_SIZE is used to determine the size of key blocks, in bytes or\nkilobytes. However, this value is just a hint, and the storage engine could\nmodify or ignore it. If KEY_BLOCK_SIZE is set to 0, the storage engine\'s\ndefault value will be used.\n\nWith the InnoDB storage engine, if you specify a non-zero value for the\nKEY_BLOCK_SIZE table option for the whole table, then the table will\nimplicitly be created with the ROW_FORMAT table option set to COMPRESSED.\n\nMIN_ROWS/MAX_ROWS\n-----------------\n\nMIN_ROWS and MAX_ROWS let the storage engine know how many rows you are\nplanning to store as a minimum and as a maximum. These values will not be used\nas real limits, but they help the storage engine to optimize the table.\nMIN_ROWS is only used by MEMORY storage engine to decide the minimum memory\nthat is always allocated. MAX_ROWS is used to decide the minimum size for\nindexes.\n\nPACK_KEYS\n---------\n\nPACK_KEYS can be used to determine whether the indexes will be compressed. Set\nit to 1 to compress all keys. With a value of 0, compression will not be used.\nWith the DEFAULT value, only long strings will be compressed. Uncompressed\nkeys are faster.\n\nPAGE_CHECKSUM\n-------------\n\nPAGE_CHECKSUM is only applicable to Aria tables, and determines whether\nindexes and data should use page checksums for extra safety.\n\nPAGE_COMPRESSED\n---------------\n\nPAGE_COMPRESSED is used to enable InnoDB page compression for InnoDB tables.\n\nPAGE_COMPRESSION_LEVEL\n----------------------\n\nPAGE_COMPRESSION_LEVEL is used to set the compression level for InnoDB page\ncompression for InnoDB tables. The table must also have the PAGE_COMPRESSED\ntable option set to 1.\n\nValid values for PAGE_COMPRESSION_LEVEL are 1 (the best speed) through 9 (the\nbest compression), .\n\nPASSWORD\n--------\n\nPASSWORD is unused.\n\nRAID_TYPE\n---------\n\nRAID_TYPE is an obsolete option, as the raid support has been disabled since\nMySQL 5.0.\n\nROW_FORMAT\n----------\n\nThe ROW_FORMAT table option specifies the row format for the data file.\nPossible values are engine-dependent.\n\nSupported MyISAM Row Formats\n----------------------------\n\nFor MyISAM, the supported row formats are:\n\n* FIXED\n* DYNAMIC\n* COMPRESSED\n\nThe COMPRESSED row format can only be set by the myisampack command line tool.\n\nSee MyISAM Storage Formats for more information.\n\nSupported Aria Row Formats\n--------------------------\n\nFor Aria, the supported row formats are:\n\n* PAGE\n* FIXED\n* DYNAMIC.\n\nSee Aria Storage Formats for more information.\n\nSupported InnoDB Row Formats\n----------------------------\n\nFor InnoDB, the supported row formats are:\n\n* COMPACT\n* REDUNDANT\n* COMPRESSED\n* DYNAMIC.\n\nIf the ROW_FORMAT table option is set to FIXED for an InnoDB table, then the\nserver will either return an error or a warning depending on the value of the\ninnodb_strict_mode system variable. If the innodb_strict_mode system variable\nis set to OFF, then a warning is issued, and MariaDB will create the table\nusing the default row format for the specific MariaDB server version. If the\ninnodb_strict_mode system variable is set to ON, then an error will be raised.\n\nSee InnoDB Storage Formats for more information.\n\nOther Storage Engines and ROW_FORMAT\n------------------------------------\n\nOther storage engines do not support the ROW_FORMAT table option.\n\nSEQUENCE\n--------\n\nIf the table is a sequence, then it will have the SEQUENCE set to 1.\n\nSTATS_AUTO_RECALC\n-----------------\n\nSTATS_AUTO_RECALC indicates whether to automatically recalculate persistent\nstatistics (see STATS_PERSISTENT, below) for an InnoDB table. If set to 1,\nstatistics will be recalculated when more than 10% of the data has changed.\nWhen set to 0, stats will be recalculated only when an ANALYZE TABLE is run.\nIf set to DEFAULT, or left out, the value set by the innodb_stats_auto_recalc\nsystem variable applies. See InnoDB Persistent Statistics.\n\nSTATS_PERSISTENT\n----------------\n\nSTATS_PERSISTENT indicates whether the InnoDB statistics created by ANALYZE\nTABLE will remain on disk or not. It can be set to 1 (on disk), 0 (not on\ndisk, the pre-MariaDB 10 behavior), or DEFAULT (the same as leaving out the\noption), in which case the value set by the innodb_stats_persistent system\nvariable will apply. Persistent statistics stored on disk allow the statistics\nto survive server restarts, and provide better query plan stability. See\nInnoDB Persistent Statistics.\n\nSTATS_SAMPLE_PAGES\n------------------\n\nSTATS_SAMPLE_PAGES indicates how many pages are used to sample index\nstatistics. If 0 or DEFAULT, the default value, the innodb_stats_sample_pages\nvalue is used. See InnoDB Persistent Statistics.\n\nTRANSACTIONAL\n-------------\n\nTRANSACTIONAL is only applicable for Aria tables. In future Aria tables\ncreated with this option will be fully transactional, but currently this\nprovides a form of crash protection. See Aria Storage Engine for more details.\n\nUNION\n-----\n\nUNION must be specified when you create a MERGE table. This option contains a\ncomma-separated list of MyISAM tables which are accessed by the new table. The\nlist is enclosed between parenthesis. Example: UNION = (t1,t2)\n\nWITH SYSTEM VERSIONING\n----------------------\n\nWITH SYSTEM VERSIONING is used for creating System-versioned tables.\n\nPartitions\n----------\n\npartition_options:\n PARTITION BY\n { [LINEAR] HASH(expr)\n | [LINEAR] KEY(column_list)\n | RANGE(expr)\n | LIST(expr)\n | SYSTEM_TIME [INTERVAL time_quantity time_unit] [LIMIT num] }\n [PARTITIONS num]\n [SUBPARTITION BY\n { [LINEAR] HASH(expr)\n | [LINEAR] KEY(column_list) }\n [SUBPARTITIONS num]\n ]\n [(partition_definition [, partition_definition] ...)]\npartition_definition:\n PARTITION partition_name\n [VALUES {LESS THAN {(expr) | MAXVALUE} | IN (value_list)}]\n [[STORAGE] ENGINE [=] engine_name]\n [COMMENT [=] \'comment_text\' ]\n [DATA DIRECTORY [=] \'data_dir\']\n [INDEX DIRECTORY [=] \'index_dir\']\n [MAX_ROWS [=] max_number_of_rows]\n [MIN_ROWS [=] min_number_of_rows]\n [TABLESPACE [=] tablespace_name]\n [NODEGROUP [=] node_group_id]\n [(subpartition_definition [, subpartition_definition] ...)]\nsubpartition_definition:\n SUBPARTITION logical_name\n [[STORAGE] ENGINE [=] engine_name]\n [COMMENT [=] \'comment_text\' ]\n [DATA DIRECTORY [=] \'data_dir\']\n [INDEX DIRECTORY [=] \'index_dir\']\n [MAX_ROWS [=] max_number_of_rows]\n [MIN_ROWS [=] min_number_of_rows]\n [TABLESPACE [=] tablespace_name]\n [NODEGROUP [=] node_group_id]\nIf the PARTITION BY clause is used, the table will be partitioned. A partition\nmethod must be explicitly indicated for partitions and subpartitions.\nPartition methods are:\n\n* [LINEAR] HASH creates a hash key which will be used to read and write rows.\nThe partition function can be any valid SQL expression which returns an\nINTEGER number. Thus, it is possible to use the HASH method on an integer\ncolumn, or on functions which accept integer columns as an argument. However,\nVALUES LESS THAN and VALUES IN clauses can not be used with HASH. An example:\n\nCREATE TABLE t1 (a INT, b CHAR(5), c DATETIME)\n PARTITION BY HASH ( YEAR(c) );\n\n[LINEAR] HASH can be used for subpartitions, too.\n\n* [LINEAR] KEY is similar to HASH, but the index has an even distribution of\ndata. Also, the expression can only be a column or a list of columns. VALUES\nLESS THAN and VALUES IN clauses can not be used with KEY.\n* RANGE partitions the rows using on a range of values, using the VALUES LESS\nTHAN operator. VALUES IN is not allowed with RANGE. The partition function can\nbe any valid SQL expression which returns a single value.\n* LIST assigns partitions based on a table\'s column with a restricted set of\npossible values. It is similar to RANGE, but VALUES IN must be used for at\nleast 1 columns, and VALUES LESS THAN is disallowed.\n* SYSTEM_TIME partitioning is used for System-versioned tables to store\nhistorical data separately from current data.\n\nOnly HASH and KEY can be used for subpartitions, and they can be [LINEAR].\n\nIt is possible to define up to 1024 partitions and subpartitions.\n\nThe number of defined partitions can be optionally specified as PARTITION\ncount. This can be done to avoid specifying all partitions individually. But\nyou can also declare each individual partition and, additionally, specify a\nPARTITIONS count clause; in the case, the number of PARTITIONs must equal\ncount.\n\nAlso see Partitioning Types Overview.\n\nSequences\n---------\n\nCREATE TABLE can also be used to create a SEQUENCE. See CREATE SEQUENCE and\nSequence Overview.\n\nAtomic DDL\n----------\n\nMariaDB starting with 10.6.1\n----------------------------\nMariaDB 10.6.1 supports Atomic DDL. CREATE TABLE is atomic, except for CREATE\nOR REPLACE, which is only crash safe.\n\nExamples\n--------\n\ncreate table if not exists test (\na bigint auto_increment primary key,\nname varchar(128) charset utf8,\nkey name (name(32))\n) engine=InnoDB default charset latin1;\n\nThis example shows a couple of things:\n\n* Usage of IF NOT EXISTS; If the table already existed, it will not be\ncreated. There will not be any error for the client, just a warning.\n* How to create a PRIMARY KEY that is automatically generated.\n* How to specify a table-specific character set and another for a column.\n* How to create an index (name) that is only partly indexed (to save space).\n\nThe following clauses will work from MariaDB 10.2.1 only.\n\nCREATE TABLE t1(\n a int DEFAULT (1+1),\n b int DEFAULT (a+1),\n expires DATETIME DEFAULT(NOW() + INTERVAL 1 YEAR),\n x BLOB DEFAULT USER()\n);\n\nURL: https://mariadb.com/kb/en/create-table/') WHERE help_topic_id = 706; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (707,38,'DROP TABLE','Syntax\n------\n\nDROP [TEMPORARY] TABLE [IF EXISTS] [/*COMMENT TO SAVE*/]\n tbl_name [, tbl_name] ...\n [WAIT n|NOWAIT]\n [RESTRICT | CASCADE]\n\nDescription\n-----------\n\nDROP TABLE removes one or more tables. You must have the DROP privilege for\neach table. All table data and the table definition are removed, as well as\ntriggers associated to the table, so be careful with this statement! If any of\nthe tables named in the argument list do not exist, MariaDB returns an error\nindicating by name which non-existing tables it was unable to drop, but it\nalso drops all of the tables in the list that do exist.\n\nImportant: When a table is dropped, user privileges on the table are not\nautomatically dropped. See GRANT.\n\nIf another thread is using the table in an explicit transaction or an\nautocommit transaction, then the thread acquires a metadata lock (MDL) on the\ntable. The DROP TABLE statement will wait in the \"Waiting for table metadata\nlock\" thread state until the MDL is released. MDLs are released in the\nfollowing cases:\n\n* If an MDL is acquired in an explicit transaction, then the MDL will be\nreleased when the transaction ends.\n* If an MDL is acquired in an autocommit transaction, then the MDL will be\nreleased when the statement ends.\n* Transactional and non-transactional tables are handled the same.\n\nNote that for a partitioned table, DROP TABLE permanently removes the table\ndefinition, all of its partitions, and all of the data which was stored in\nthose partitions. It also removes the partitioning definition (.par) file\nassociated with the dropped table.\n\nFor each referenced table, DROP TABLE drops a temporary table with that name,\nif it exists. If it does not exist, and the TEMPORARY keyword is not used, it\ndrops a non-temporary table with the same name, if it exists. The TEMPORARY\nkeyword ensures that a non-temporary table will not accidentally be dropped.\n\nUse IF EXISTS to prevent an error from occurring for tables that do not exist.\nA NOTE is generated for each non-existent table when using IF EXISTS. See SHOW\nWARNINGS.\n\nIf a foreign key references this table, the table cannot be dropped. In this\ncase, it is necessary to drop the foreign key first.\n\nRESTRICT and CASCADE are allowed to make porting from other database systems\neasier. In MariaDB, they do nothing.\n\nThe comment before the table names (/*COMMENT TO SAVE*/) is stored in the\nbinary log. That feature can be used by replication tools to send their\ninternal messages.\n\nIt is possible to specify table names as db_name.tab_name. This is useful to\ndelete tables from multiple databases with one statement. See Identifier\nQualifiers for details.\n\nThe DROP privilege is required to use DROP TABLE on non-temporary tables. For\ntemporary tables, no privilege is required, because such tables are only\nvisible for the current session.\n\nNote: DROP TABLE automatically commits the current active transaction, unless\nyou use the TEMPORARY keyword.\n\nMariaDB starting with 10.5.4\n----------------------------\nFrom MariaDB 10.5.4, DROP TABLE reliably deletes table remnants inside a\nstorage engine even if the .frm file is missing. Before then, a missing .frm\nfile would result in the statement failing.\n\nMariaDB starting with 10.3.1\n----------------------------\n\nWAIT/NOWAIT\n-----------\n\nSet the lock wait timeout. See WAIT and NOWAIT.\n\nDROP TABLE in replication\n-------------------------\n\nDROP TABLE has the following characteristics in replication:\n\n* DROP TABLE IF EXISTS are always logged.\n* DROP TABLE without IF EXISTS for tables that don\'t exist are not written to\nthe binary log.\n* Dropping of TEMPORARY tables are prefixed in the log with TEMPORARY. These\ndrops are only logged when running statement or mixed mode replication.\n* One DROP TABLE statement can be logged with up to 3 different DROP\nstatements:\nDROP TEMPORARY TABLE list_of_non_transactional_temporary_tables\nDROP TEMPORARY TABLE list_of_transactional_temporary_tables\nDROP TABLE list_of_normal_tables\n\nDROP TABLE on the primary is treated on the replica as DROP TABLE IF EXISTS.\nYou can change that by setting slave-ddl-exec-mode to STRICT.\n\nDropping an Internal #sql-... Table\n-----------------------------------\n\nFrom MariaDB 10.6, DROP TABLE is atomic and the following does not apply.\nUntil MariaDB 10.5, if the mariadbd/mysqld process is killed during an ALTER\nTABLE you may find a table named #sql-... in your data directory. In MariaDB\n10.3, InnoDB tables with this prefix will be deleted automatically during\nstartup. From MariaDB 10.4, these temporary tables will always be deleted\nautomatically.\n\nIf you want to delete one of these tables explicitly you can do so by using\nthe following syntax:\n\nDROP TABLE `#mysql50##sql-...`;\n\nWhen running an ALTER TABLE…ALGORITHM=INPLACE that rebuilds the table, InnoDB\nwill create an internal #sql-ib table. Until MariaDB 10.3.2, for these tables,\nthe .frm file will be called something else. In order to drop such a table\nafter a server crash, you must rename the #sql*.frm file to match the\n#sql-ib*.ibd file.\n\nFrom MariaDB 10.3.3, the same name as the .frm file is used for the\nintermediate copy of the table. The #sql-ib names are used by TRUNCATE and\ndelayed DROP.\n\nFrom MariaDB 10.2.19 and MariaDB 10.3.10, the #sql-ib tables will be deleted\nautomatically.\n\nDropping All Tables in a Database\n---------------------------------\n\nThe best way to drop all tables in a database is by executing DROP DATABASE,\nwhich will drop the database itself, and all tables in it.\n\nHowever, if you want to drop all tables in the database, but you also want to\nkeep the database itself and any other non-table objects in it, then you would\nneed to execute DROP TABLE to drop each individual table. You can construct\nthese DROP TABLE commands by querying the TABLES table in the\ninformation_schema database. For example:\n\nSELECT CONCAT(\'DROP TABLE IF EXISTS `\', TABLE_SCHEMA, \'`.`\', TABLE_NAME, \'`;\')\nFROM information_schema.TABLES\nWHERE TABLE_SCHEMA = \'mydb\';\n\nAtomic DROP TABLE\n-----------------\n\nMariaDB starting with 10.6.1\n----------------------------\nFrom MariaDB 10.6, DROP TABLE for a single table is atomic (MDEV-25180) for\nmost engines, including InnoDB, MyRocks, MyISAM and Aria.\n\nThis means that if there is a crash (server down or power outage) during DROP\nTABLE, all tables that have been processed so far will be completely dropped,\nincluding related trigger files and status entries, and the binary log will\ninclude a DROP TABLE statement for the dropped tables. Tables for which the\ndrop had not started will be left intact.\n\nIn older MariaDB versions, there was a small chance that, during a server\ncrash happening in the middle of DROP TABLE, some storage engines that were\nusing multiple storage files, like MyISAM, could have only a part of its\ninternal files dropped.\n\nIn MariaDB 10.5, DROP TABLE was extended to be able to delete a table that was\nonly partly dropped (MDEV-11412) as explained above. Atomic DROP TABLE is the\nfinal piece to make DROP TABLE fully reliable.\n\nDropping multiple tables is crash-safe.\n\nSee Atomic DDL for more information.\n\nExamples\n--------\n\nDROP TABLE Employees, Customers;\n\nNotes\n-----\n\nBeware that DROP TABLE can drop both tables and sequences. This is mainly done\nto allow old tools like mariadb-dump (previously mysqldump) to work with\nsequences.\n\nURL: https://mariadb.com/kb/en/drop-table/','','https://mariadb.com/kb/en/drop-table/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (708,38,'RENAME TABLE','Syntax\n------\n\nRENAME TABLE[S] [IF EXISTS] tbl_name \n [WAIT n | NOWAIT]\n TO new_tbl_name\n [, tbl_name2 TO new_tbl_name2] ...\n\nDescription\n-----------\n\nThis statement renames one or more tables or views, but not the privileges\nassociated with them.\n\nIF EXISTS\n---------\n\nMariaDB starting with 10.5.2\n----------------------------\nIf this directive is used, one will not get an error if the table to be\nrenamed doesn\'t exist.\n\nThe rename operation is done atomically, which means that no other session can\naccess any of the tables while the rename is running. For example, if you have\nan existing table old_table, you can create another table new_table that has\nthe same structure but is empty, and then replace the existing table with the\nempty one as follows (assuming that backup_table does not already exist):\n\nCREATE TABLE new_table (...);\nRENAME TABLE old_table TO backup_table, new_table TO old_table;\n\ntbl_name can optionally be specified as db_name.tbl_name. See Identifier\nQualifiers. This allows to use RENAME to move a table from a database to\nanother (as long as they are on the same filesystem):\n\nRENAME TABLE db1.t TO db2.t;\n\nNote that moving a table to another database is not possible if it has some\ntriggers. Trying to do so produces the following error:\n\nERROR 1435 (HY000): Trigger in wrong schema\n\nAlso, views cannot be moved to another database:\n\nERROR 1450 (HY000): Changing schema from \'old_db\' to \'new_db\' is not allowed.\n\nMultiple tables can be renamed in a single statement. The presence or absence\nof the optional S (RENAME TABLE or RENAME TABLES) has no impact, whether a\nsingle or multiple tables are being renamed.\n\nIf a RENAME TABLE renames more than one table and one renaming fails, all\nrenames executed by the same statement are rolled back.\n\nRenames are always executed in the specified order. Knowing this, it is also\npossible to swap two tables\' names:\n\nRENAME TABLE t1 TO tmp_table,\n t2 TO t1,\n tmp_table TO t2;\n\nWAIT/NOWAIT\n-----------\n\nSet the lock wait timeout. See WAIT and NOWAIT.\n\nPrivileges\n----------\n\nExecuting the RENAME TABLE statement requires the DROP, CREATE and INSERT\nprivileges for the table or the database.\n\nAtomic RENAME TABLE\n-------------------\n\nMariaDB starting with 10.6.1\n----------------------------\nFrom MariaDB 10.6, RENAME TABLE is atomic for most engines, including InnoDB,\nMyRocks, MyISAM and Aria (MDEV-23842). This means that if there is a crash\n(server down or power outage) during RENAME TABLE, all tables will revert to\ntheir original names and any changes to trigger files will be reverted.\n\nIn older MariaDB version there was a small chance that, during a server crash\nhappening in the middle of RENAME TABLE, some tables could have been renamed\n(in the worst case partly) while others would not be renamed.\n\nSee Atomic DDL for more information.\n\nURL: https://mariadb.com/kb/en/rename-table/','','https://mariadb.com/kb/en/rename-table/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (709,38,'TRUNCATE TABLE','Syntax\n------\n\nTRUNCATE [TABLE] tbl_name\n [WAIT n | NOWAIT]\n\nDescription\n-----------\n\nTRUNCATE TABLE empties a table completely. It requires the DROP privilege. See\nGRANT.\n\ntbl_name can also be specified in the form db_name.tbl_name (see Identifier\nQualifiers).\n\nLogically, TRUNCATE TABLE is equivalent to a DELETE statement that deletes all\nrows, but there are practical differences under some circumstances.\n\nTRUNCATE TABLE will fail for an InnoDB table if any FOREIGN KEY constraints\nfrom other tables reference the table, returning the error:\n\nERROR 1701 (42000): Cannot truncate a table referenced in a foreign key\nconstraint\n\nForeign Key constraints between columns in the same table are permitted.\n\nFor an InnoDB table, if there are no FOREIGN KEY constraints, InnoDB performs\nfast truncation by dropping the original table and creating an empty one with\nthe same definition, which is much faster than deleting rows one by one. The\nAUTO_INCREMENT counter is reset by TRUNCATE TABLE, regardless of whether there\nis a FOREIGN KEY constraint.\n\nThe count of rows affected by TRUNCATE TABLE is accurate only when it is\nmapped to a DELETE statement.\n\nFor other storage engines, TRUNCATE TABLE differs from DELETE in the following\nways:\n\n* Truncate operations drop and re-create the table, which is much\n faster than deleting rows one by one, particularly for large tables.\n* Truncate operations cause an implicit commit.\n* Truncation operations cannot be performed if the session holds an\n active table lock.\n* Truncation operations do not return a meaningful value for the number\n of deleted rows. The usual result is \"0 rows affected,\" which should\n be interpreted as \"no information.\"\n* As long as the table format file tbl_name.frm is valid, the\n table can be re-created as an empty table\n with TRUNCATE TABLE, even if the data or index files have become\n corrupted.\n* The table handler does not remember the last\n used AUTO_INCREMENT value, but starts counting\n from the beginning. This is true even for MyISAM and InnoDB, which normally\n do not reuse sequence values.\n* When used with partitioned tables, TRUNCATE TABLE preserves\n the partitioning; that is, the data and index files are dropped and\n re-created, while the partition definitions (.par) file is\n unaffected.\n* Since truncation of a table does not make any use of DELETE,\n the TRUNCATE statement does not invoke ON DELETE triggers.\n* TRUNCATE TABLE will only reset the values in the Performance Schema summary\ntables to zero or null, and will not remove the rows.\n\nFor the purposes of binary logging and replication, TRUNCATE TABLE is treated\nas DROP TABLE followed by CREATE TABLE (DDL rather than DML).\n\nTRUNCATE TABLE does not work on views. Currently, TRUNCATE TABLE drops all\nhistorical records from a system-versioned table.\n\nWAIT/NOWAIT\n-----------\n\nSet the lock wait timeout. See WAIT and NOWAIT.\n\nOracle-mode\n-----------\n\nOracle-mode from MariaDB 10.3 permits the optional keywords REUSE STORAGE or\nDROP STORAGE to be used.\n\nTRUNCATE [TABLE] tbl_name [{DROP | REUSE} STORAGE] [WAIT n | NOWAIT]\n\nThese have no effect on the operation.\n\nPerformance\n-----------\n\nTRUNCATE TABLE is faster than DELETE, because it drops and re-creates a table.\n\nWith InnoDB, TRUNCATE TABLE is slower if innodb_file_per_table=ON is set (the\ndefault). This is because TRUNCATE TABLE unlinks the underlying tablespace\nfile, which can be an expensive operation. See MDEV-8069 for more details.\n\nThe performance issues with innodb_file_per_table=ON can be exacerbated in\ncases where the InnoDB buffer pool is very large and\ninnodb_adaptive_hash_index=ON is set. In that case, using DROP TABLE followed\nby CREATE TABLE instead of TRUNCATE TABLE may perform better. Setting\ninnodb_adaptive_hash_index=OFF (it defaults to ON before MariaDB 10.5) can\nalso help. In MariaDB 10.2 only, from MariaDB 10.2.19, this performance can\nalso be improved by setting innodb_safe_truncate=OFF. See MDEV-9459 for more\ndetails.\n\nSetting innodb_adaptive_hash_index=OFF can also improve TRUNCATE TABLE\nperformance in general. See MDEV-16796 for more details.\n\nURL: https://mariadb.com/kb/en/truncate-table/','','https://mariadb.com/kb/en/truncate-table/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (710,38,'CREATE DATABASE','Syntax\n------\n\nCREATE [OR REPLACE] {DATABASE | SCHEMA} [IF NOT EXISTS] db_name\n [create_specification] ...\n\ncreate_specification:\n [DEFAULT] CHARACTER SET [=] charset_name\n | [DEFAULT] COLLATE [=] collation_name\n | COMMENT [=] \'comment\'\n\nDescription\n-----------\n\nCREATE DATABASE creates a database with the given name. To use this statement,\nyou need the CREATE privilege for the database. CREATE SCHEMA is a synonym for\nCREATE DATABASE.\n\nFor valid identifiers to use as database names, see Identifier Names.\n\nOR REPLACE\n----------\n\nMariaDB starting with 10.1.3\n----------------------------\nThe OR REPLACE clause was added in MariaDB 10.1.3\n\nIf the optional OR REPLACE clause is used, it acts as a shortcut for:\n\nDROP DATABASE IF EXISTS db_name;\nCREATE DATABASE db_name ...;\n\nIF NOT EXISTS\n-------------\n\nWhen the IF NOT EXISTS clause is used, MariaDB will return a warning instead\nof an error if the specified database already exists.\n\nCOMMENT\n-------\n\nMariaDB starting with 10.5.0\n----------------------------\nFrom MariaDB 10.5.0, it is possible to add a comment of a maximum of 1024\nbytes. If the comment length exceeds this length, a error/warning code 4144 is\nthrown. The database comment is also added to the db.opt file, as well as to\nthe information_schema.schemata table.\n\nExamples\n--------\n\nCREATE DATABASE db1;\nQuery OK, 1 row affected (0.18 sec)\n\nCREATE DATABASE db1;\nERROR 1007 (HY000): Can\'t create database \'db1\'; database exists\n\nCREATE OR REPLACE DATABASE db1;\nQuery OK, 2 rows affected (0.00 sec)\n\nCREATE DATABASE IF NOT EXISTS db1;\nQuery OK, 1 row affected, 1 warning (0.01 sec)\n\nSHOW WARNINGS;\n+-------+------+----------------------------------------------+\n| Level | Code | Message |\n+-------+------+----------------------------------------------+\n| Note | 1007 | Can\'t create database \'db1\'; database exists |\n+-------+------+----------------------------------------------+\n\nSetting the character sets and collation. See Setting Character Sets and\nCollations for more details.\n\nCREATE DATABASE czech_slovak_names \n CHARACTER SET = \'keybcs2\'\n COLLATE = \'keybcs2_bin\';\n\nComments, from MariaDB 10.5.0:\n\nCREATE DATABASE presentations COMMENT \'Presentations for conferences\';\n\nURL: https://mariadb.com/kb/en/create-database/','','https://mariadb.com/kb/en/create-database/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (711,38,'CREATE EVENT','Syntax\n------\n\nCREATE [OR REPLACE]\n [DEFINER = { user | CURRENT_USER | role | CURRENT_ROLE }]\n EVENT\n [IF NOT EXISTS]\n event_name\n ON SCHEDULE schedule\n [ON COMPLETION [NOT] PRESERVE]\n [ENABLE | DISABLE | DISABLE ON SLAVE]\n [COMMENT \'comment\']\n DO sql_statement;\n\nschedule:\n AT timestamp [+ INTERVAL interval] ...\n | EVERY interval\n [STARTS timestamp [+ INTERVAL interval] ...]\n [ENDS timestamp [+ INTERVAL interval] ...]\n\ninterval:\n quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |\n WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |\n DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}\n\nDescription\n-----------\n\nThis statement creates and schedules a new event. It requires the EVENT\nprivilege for the schema in which the event is to be created.\n\nThe minimum requirements for a valid CREATE EVENT statement are as follows:\n\n* The keywords CREATE EVENT plus an event name, which uniquely identifies\n the event in the current schema. (Prior to MySQL 5.1.12, the event name\n needed to be unique only among events created by the same user on a given\n database.)\n* An ON SCHEDULE clause, which determines when and how often the event\n executes.\n* A DO clause, which contains the SQL statement to be executed by an\n event.\n\nHere is an example of a minimal CREATE EVENT statement:\n\nCREATE EVENT myevent\n ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR\n DO\n UPDATE myschema.mytable SET mycol = mycol + 1;\n\nThe previous statement creates an event named myevent. This event executes\nonce — one hour following its creation — by running an SQL statement that\nincrements the value of the myschema.mytable table\'s mycol column by 1.\n\nThe event_name must be a valid MariaDB identifier with a maximum length of 64\ncharacters. It may be delimited using back ticks, and may be qualified with\nthe name of a database schema. An event is associated with both a MariaDB user\n(the definer) and a schema, and its name must be unique among names of events\nwithin that schema. In general, the rules governing event names are the same\nas those for names of stored routines. See Identifier Names.\n\nIf no schema is indicated as part of event_name, the default (current) schema\nis assumed.\n\nFor valid identifiers to use as event names, see Identifier Names.\n\nOR REPLACE\n----------\n\nThe OR REPLACE clause was included in MariaDB 10.1.4. If used and the event\nalready exists, instead of an error being returned, the existing event will be\ndropped and replaced by the newly defined event.\n\nIF NOT EXISTS\n-------------\n\nIf the IF NOT EXISTS clause is used, MariaDB will return a warning instead of\nan error if the event already exists. Cannot be used together with OR REPLACE.\n\nON SCHEDULE\n-----------\n\nThe ON SCHEDULE clause can be used to specify when the event must be triggered.\n\nAT\n--\n\nIf you want to execute the event only once (one time event), you can use the\nAT keyword, followed by a timestamp. If you use CURRENT_TIMESTAMP, the event\nacts as soon as it is created. As a convenience, you can add one or more\nintervals to that timestamp. You can also specify a timestamp in the past, so\nthat the event is stored but not triggered, until you modify it via ALTER\nEVENT.\n\nThe following example shows how to create an event that will be triggered\ntomorrow at a certain time:\n\nCREATE EVENT example\nON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY + INTERVAL 3 HOUR\nDO something;\n\nYou can also specify that an event must be triggered at a regular interval\n(recurring event). In such cases, use the EVERY clause followed by the\ninterval.\n\nIf an event is recurring, you can specify when the first execution must happen\nvia the STARTS clause and a maximum time for the last execution via the ENDS\nclause. STARTS and ENDS clauses are followed by a timestamp and, optionally,\none or more intervals. The ENDS clause can specify a timestamp in the past, so\nthat the event is stored but not executed until you modify it via ALTER EVENT.\n\nIn the following example, next month a recurring event will be triggered\nhourly for a week:\n\nCREATE EVENT example\nON SCHEDULE EVERY 1 HOUR\nSTARTS CURRENT_TIMESTAMP + INTERVAL 1 MONTH\nENDS CURRENT_TIMESTAMP + INTERVAL 1 MONTH + INTERVAL 1 WEEK\nDO some_task;\n\nIntervals consist of a quantity and a time unit. The time units are the same\nused for other staments and time functions, except that you can\'t use\nmicroseconds for events. For simple time units, like HOUR or MINUTE, the\nquantity is an integer number, for example \'10 MINUTE\'. For composite time\nunits, like HOUR_MINUTE or HOUR_SECOND, the quantity must be a string with all\ninvolved simple values and their separators, for example \'2:30\' or \'2:30:30\'.\n\nON COMPLETION [NOT] PRESERVE\n----------------------------\n\nThe ON COMPLETION clause can be used to specify if the event must be deleted\nafter its last execution (that is, after its AT or ENDS timestamp is past). By\ndefault, events are dropped when they are expired. To explicitly state that\nthis is the desired behaviour, you can use ON COMPLETION NOT PRESERVE.\nInstead, if you want the event to be preserved, you can use ON COMPLETION\nPRESERVE.\n\nIn you specify ON COMPLETION NOT PRESERVE, and you specify a timestamp in the\npast for AT or ENDS clause, the event will be immediatly dropped. In such\ncases, you will get a Note 1558: \"Event execution time is in the past and ON\nCOMPLETION NOT PRESERVE is set. The event was dropped immediately after\ncreation\".\n\nENABLE/DISABLE/DISABLE ON SLAVE\n-------------------------------\n\nEvents are ENABLEd by default. If you want to stop MariaDB from executing an\nevent, you may specify DISABLE. When it is ready to be activated, you may\nenable it using ALTER EVENT. Another option is DISABLE ON SLAVE, which\nindicates that an event was created on a master and has been replicated to the\nslave, which is prevented from executing the event. If DISABLE ON SLAVE is\nspecifically set, the event will be disabled everywhere. It will not be\nexecuted on the mater or the slaves.\n\nCOMMENT\n-------\n\nThe COMMENT clause may be used to set a comment for the event. Maximum length\nfor comments is 64 characters. The comment is a string, so it must be quoted.\nTo see events comments, you can query the INFORMATION_SCHEMA.EVENTS table (the\ncolumn is named EVENT_COMMENT).\n\nExamples\n--------\n\nMinimal CREATE EVENT statement:\n\nCREATE EVENT myevent\n ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR\n DO\n UPDATE myschema.mytable SET mycol = mycol + 1;\n\nAn event that will be triggered tomorrow at a certain time:\n\nCREATE EVENT example\nON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY + INTERVAL 3 HOUR\nDO something;\n\nNext month a recurring event will be triggered hourly for a week:\n\nCREATE EVENT example\nON SCHEDULE EVERY 1 HOUR\nSTARTS CURRENT_TIMESTAMP + INTERVAL 1 MONTH\nENDS CURRENT_TIMESTAMP + INTERVAL 1 MONTH + INTERVAL 1 WEEK\nDO some_task;\n\nOR REPLACE and IF NOT EXISTS:\n\nCREATE EVENT myevent\n ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR\n DO\n UPDATE myschema.mytable SET mycol = mycol + 1;\nERROR 1537 (HY000): Event \'myevent\' already exists\n\nCREATE OR REPLACE EVENT myevent\n ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR\n DO\n UPDATE myschema.mytable SET mycol = mycol + 1;;\nQuery OK, 0 rows affected (0.00 sec)\n\nCREATE EVENT IF NOT EXISTS myevent\n ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR\n DO\n UPDATE myschema.mytable SET mycol = mycol + 1;\nQuery OK, 0 rows affected, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+-------+------+--------------------------------+\n| Level | Code | Message |\n+-------+------+--------------------------------+\n| Note | 1537 | Event \'myevent\' already exists |\n+-------+------+--------------------------------+\n\nURL: https://mariadb.com/kb/en/create-event/','','https://mariadb.com/kb/en/create-event/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (712,38,'CREATE FUNCTION','Syntax\n------\n\nCREATE [OR REPLACE]\n [DEFINER = {user | CURRENT_USER | role | CURRENT_ROLE }]\n [AGGREGATE] FUNCTION [IF NOT EXISTS] func_name ([func_parameter[,...]])\n RETURNS type\n [characteristic ...]\n RETURN func_body\nfunc_parameter:\n [ IN | OUT | INOUT | IN OUT ] param_name type\ntype:\n Any valid MariaDB data type\ncharacteristic:\n LANGUAGE SQL\n | [NOT] DETERMINISTIC\n | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }\n | SQL SECURITY { DEFINER | INVOKER }\n | COMMENT \'string\'\nfunc_body:\n Valid SQL procedure statement\n\nDescription\n-----------\n\nUse the CREATE FUNCTION statement to create a new stored function. You must\nhave the CREATE ROUTINE database privilege to use CREATE FUNCTION. A function\ntakes any number of arguments and returns a value from the function body. The\nfunction body can be any valid SQL expression as you would use, for example,\nin any select expression. If you have the appropriate privileges, you can call\nthe function exactly as you would any built-in function. See Security below\nfor details on privileges.\n\nYou can also use a variant of the CREATE FUNCTION statement to install a\nuser-defined function (UDF) defined by a plugin. See CREATE FUNCTION (UDF) for\ndetails.\n\nYou can use a SELECT statement for the function body by enclosing it in\nparentheses, exactly as you would to use a subselect for any other expression.\nThe SELECT statement must return a single value. If more than one column is\nreturned when the function is called, error 1241 results. If more than one row\nis returned when the function is called, error 1242 results. Use a LIMIT\nclause to ensure only one row is returned.\n\nYou can also replace the RETURN clause with a BEGIN...END compound statement.\nThe compound statement must contain a RETURN statement. When the function is\ncalled, the RETURN statement immediately returns its result, and any\nstatements after RETURN are effectively ignored.\n\nBy default, a function is associated with the current database. To associate\nthe function explicitly with a given database, specify the fully-qualified\nname as db_name.func_name when you create it. If the function name is the same\nas the name of a built-in function, you must use the fully qualified name when\nyou call it.\n\nThe parameter list enclosed within parentheses must always be present. If\nthere are no parameters, an empty parameter list of () should be used.\nParameter names are not case sensitive.\n\nEach parameter can be declared to use any valid data type, except that the\nCOLLATE attribute cannot be used.\n\nFor valid identifiers to use as function names, see Identifier Names.\n\nIN | OUT | INOUT | IN OUT\n-------------------------\n\nMariaDB starting with 10.8.0\n----------------------------\nThe function parameter qualifiers for IN, OUT, INOUT, and IN OUT were added in\na 10.8.0 preview release. Prior to 10.8.0 quantifiers were supported only in\nprocedures.\n\nOUT, INOUT and its equivalent IN OUT, are only valid if called from SET and\nnot SELECT. These quantifiers are especially useful for creating functions\nwith more than one return value. This allows functions to be more complex and\nnested.\n\nDELIMITER $$\nCREATE FUNCTION add_func3(IN a INT, IN b INT, OUT c INT) RETURNS INT\nBEGIN\n SET c = 100;\n RETURN a + b;\nEND;\n$$\nDELIMITER ;\n\nSET @a = 2;\nSET @b = 3;\nSET @c = 0;\nSET @res= add_func3(@a, @b, @c);\n\nSELECT add_func3(@a, @b, @c);\nERROR 4186 (HY000): OUT or INOUT argument 3 for function add_func3 is not\nallowed here\n\nDELIMITER $$\nCREATE FUNCTION add_func4(IN a INT, IN b INT, d INT) RETURNS INT\nBEGIN\n DECLARE c, res INT;\n SET res = add_func3(a, b, c) + d;\n if (c > 99) then\n return 3;\n else\n return res;\n end if;\nEND;\n$$\n\nDELIMITER ;\n\nSELECT add_func4(1,2,3);\n+------------------+\n| add_func4(1,2,3) |\n+------------------+\n| 3 |\n+------------------+\n\nAGGREGATE\n---------\n\nIt is possible to create stored aggregate functions as well. See Stored\nAggregate Functions for details.\n\nRETURNS\n-------\n\nThe RETURNS clause specifies the return type of the function. NULL values are\npermitted with all return types.\n\nWhat happens if the RETURN clause returns a value of a different type? It\ndepends on the SQL_MODE in effect at the moment of the function creation.\n\nIf the SQL_MODE is strict (STRICT_ALL_TABLES or STRICT_TRANS_TABLES flags are\nspecified), a 1366 error will be produced.\n\nOtherwise, the value is coerced to the proper type. For example, if a function\nspecifies an ENUM or SET value in the RETURNS clause, but the RETURN clause\nreturns an integer, the value returned from the function is the string for the\ncorresponding ENUM member of set of SET members.\n\nMariaDB stores the SQL_MODE system variable setting that is in effect at the\ntime a routine is created, and always executes the routine with this setting\nin force, regardless of the server SQL mode in effect when the routine is\ninvoked.\n\nLANGUAGE SQL\n------------\n\nLANGUAGE SQL is a standard SQL clause, and it can be used in MariaDB for\nportability. However that clause has no meaning, because SQL is the only\nsupported language for stored functions.\n\nA function is deterministic if it can produce only one result for a given list\nof parameters. If the result may be affected by stored data, server variables,\nrandom numbers or any value that is not explicitly passed, then the function\nis not deterministic. Also, a function is non-deterministic if it uses\nnon-deterministic functions like NOW() or CURRENT_TIMESTAMP(). The optimizer\nmay choose a faster execution plan if it known that the function is\ndeterministic. In such cases, you should declare the routine using the\nDETERMINISTIC keyword. If you want to explicitly state that the function is\nnot deterministic (which is the default) you can use the NOT DETERMINISTIC\nkeywords.\n\nIf you declare a non-deterministic function as DETERMINISTIC, you may get\nincorrect results. If you declare a deterministic function as NOT\nDETERMINISTIC, in some cases the queries will be slower.\n\nOR REPLACE\n----------\n\nIf the optional OR REPLACE clause is used, it acts as a shortcut for:\n\nDROP FUNCTION IF EXISTS function_name;\nCREATE FUNCTION function_name ...;\n\nwith the exception that any existing privileges for the function are not\ndropped.\n\nIF NOT EXISTS\n-------------\n\nIf the IF NOT EXISTS clause is used, MariaDB will return a warning instead of\nan error if the function already exists. Cannot be used together with OR\nREPLACE.\n\n[NOT] DETERMINISTIC\n-------------------\n\nThe [NOT] DETERMINISTIC clause also affects binary logging, because the\nSTATEMENT format can not be used to store or replicate non-deterministic\nstatements.\n\nCONTAINS SQL, NO SQL, READS SQL DATA, and MODIFIES SQL DATA are informative\nclauses that tell the server what the function does. MariaDB does not check in\nany way whether the specified clause is correct. If none of these clauses are\nspecified, CONTAINS SQL is used by default.\n\nMODIFIES SQL DATA\n-----------------\n\nMODIFIES SQL DATA means that the function contains statements that may modify\ndata stored in databases. This happens if the function contains statements\nlike DELETE, UPDATE, INSERT, REPLACE or DDL.\n\nREADS SQL DATA\n--------------\n\nREADS SQL DATA means that the function reads data stored in databases, but\ndoes not modify any data. This happens if SELECT statements are used, but\nthere no write operations are executed.\n\nCONTAINS SQL\n------------\n\nCONTAINS SQL means that the function contains at least one SQL statement, but\nit does not read or write any data stored in a database. Examples include SET\nor DO.\n\nNO SQL\n------\n\nNO SQL means nothing, because MariaDB does not currently support any language\nother than SQL.\n\nOracle Mode\n-----------\n\nA subset of Oracle\'s PL/SQL language is supported in addition to the\ntraditional SQL/PSM-based MariaDB syntax. See Oracle mode for details on\nchanges when running Oracle mode.\n\nSecurity\n--------\n\nYou must have the EXECUTE privilege on a function to call it. MariaDB\nautomatically grants the EXECUTE and ALTER ROUTINE privileges to the account\nthat called CREATE FUNCTION, even if the DEFINER clause was used.\n\nEach function has an account associated as the definer. By default, the\ndefiner is the account that created the function. Use the DEFINER clause to\nspecify a different account as the definer. You must have the SUPER privilege,\nor, from MariaDB 10.5.2, the SET USER privilege, to use the DEFINER clause.\nSee Account Names for details on specifying accounts.\n\nThe SQL SECURITY clause specifies what privileges are used when a function is\ncalled. If SQL SECURITY is INVOKER, the function body will be evaluated using\nthe privileges of the user calling the function. If SQL SECURITY is DEFINER,\nthe function body is always evaluated using the privileges of the definer\naccount. DEFINER is the default.\n\nThis allows you to create functions that grant limited access to certain data.\nFor example, say you have a table that stores some employee information, and\nthat you\'ve granted SELECT privileges only on certain columns to the user\naccount roger.\n\nCREATE TABLE employees (name TINYTEXT, dept TINYTEXT, salary INT);\nGRANT SELECT (name, dept) ON employees TO roger;\n\nTo allow the user the get the maximum salary for a department, define a\nfunction and grant the EXECUTE privilege:\n\nCREATE FUNCTION max_salary (dept TINYTEXT) RETURNS INT RETURN\n (SELECT MAX(salary) FROM employees WHERE employees.dept = dept);\nGRANT EXECUTE ON FUNCTION max_salary TO roger;\n\nSince SQL SECURITY defaults to DEFINER, whenever the user roger calls this\nfunction, the subselect will execute with your privileges. As long as you have\nprivileges to select the salary of each employee, the caller of the function\nwill be able to get the maximum salary for each department without being able\nto see individual salaries.\n\nCharacter sets and collations\n-----------------------------\n\nFunction return types can be declared to use any valid character set and\ncollation. If used, the COLLATE attribute needs to be preceded by a CHARACTER\nSET attribute.\n\nIf the character set and collation are not specifically set in the statement,\nthe database defaults at the time of creation will be used. If the database\ndefaults change at a later stage, the stored function character set/collation\nwill not be changed at the same time; the stored function needs to be dropped\nand recreated to ensure the same character set/collation as the database is\nused.\n\nExamples\n--------\n\nThe following example function takes a parameter, performs an operation using\nan SQL function, and returns the result.\n\nCREATE FUNCTION hello (s CHAR(20))\n RETURNS CHAR(50) DETERMINISTIC\n RETURN CONCAT(\'Hello, \',s,\'!\');\n\nSELECT hello(\'world\');\n+----------------+\n| hello(\'world\') |\n+----------------+\n| Hello, world! |\n+----------------+\n\nYou can use a compound statement in a function to manipulate data with\nstatements like INSERT and UPDATE. The following example creates a counter\nfunction that uses a temporary table to store the current value. Because the\ncompound statement contains statements terminated with semicolons, you have to\nfirst change the statement delimiter with the DELIMITER statement to allow the\nsemicolon to be used in the function body. See Delimiters in the mariadb\nclient for more.\n\nCREATE TEMPORARY TABLE counter (c INT);\nINSERT INTO counter VALUES (0);\nDELIMITER //\nCREATE FUNCTION counter () RETURNS INT\n BEGIN\n UPDATE counter SET c = c + 1;\n RETURN (SELECT c FROM counter LIMIT 1);\n END //\nDELIMITER ;\n\nCharacter set and collation:\n\nCREATE FUNCTION hello2 (s CHAR(20))\n RETURNS CHAR(50) CHARACTER SET \'utf8\' COLLATE \'utf8_bin\' DETERMINISTIC\n RETURN CONCAT(\'Hello, \',s,\'!\');\n\nURL: https://mariadb.com/kb/en/create-function/','','https://mariadb.com/kb/en/create-function/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (713,38,'CREATE INDEX','Syntax\n------\n\nCREATE [OR REPLACE] [UNIQUE|FULLTEXT|SPATIAL] INDEX \n [IF NOT EXISTS] index_name\n [index_type]\n ON tbl_name (index_col_name,...)\n [WAIT n | NOWAIT]\n [index_option]\n [algorithm_option | lock_option] ...\n\nindex_col_name:\n col_name [(length)] [ASC | DESC]\n\nindex_type:\n USING {BTREE | HASH | RTREE}\n\nindex_option:\n [ KEY_BLOCK_SIZE [=] value\n | index_type\n | WITH PARSER parser_name\n | COMMENT \'string\'\n | CLUSTERING={YES| NO} ]\n [ IGNORED | NOT IGNORED ]\n\nalgorithm_option:\n ALGORITHM [=] {DEFAULT|INPLACE|COPY|NOCOPY|INSTANT}\n\nlock_option:\n LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}\n\nDescription\n-----------\n\nThe CREATE INDEX statement is used to add indexes to a table. Indexes can be\ncreated at the same as the table, with the [[|create-table|CREATE TABLE]]\nstatement. In some cases, such as for InnoDB primary keys, doing so during\ncreation is preferable, as adding a primary key will involve rebuilding the\ntable.\n\nThe statement is mapped to an ALTER TABLE statement to create indexes. See\nALTER TABLE. CREATE INDEX cannot be used to create a PRIMARY KEY; use ALTER\nTABLE instead.\n\nIf another connection is using the table, a metadata lock is active, and this\nstatement will wait until the lock is released. This is also true for\nnon-transactional tables.\n\nAnother shortcut, DROP INDEX, allows the removal of an index.\n\nFor valid identifiers to use as index names, see Identifier Names.\n\nNote that KEY_BLOCK_SIZE is currently ignored in CREATE INDEX, although it is\nincluded in the output of SHOW CREATE TABLE.\n\nPrivileges\n----------\n\nExecuting the CREATE INDEX statement requires the INDEX privilege for the\ntable or the database.\n\nOnline DDL\n----------\n\nOnline DDL is supported with the ALGORITHM and LOCK clauses.\n\nSee InnoDB Online DDL Overview for more information on online DDL with InnoDB.\n\nCREATE OR REPLACE INDEX\n-----------------------\n\nIf the OR REPLACE clause is used and if the index already exists, then instead\nof returning an error, the server will drop the existing index and replace it\nwith the newly defined index.\n\nCREATE INDEX IF NOT EXISTS\n--------------------------\n\nIf the IF NOT EXISTS clause is used, then the index will only be created if an\nindex with the same name does not already exist. If the index already exists,\nthen a warning will be triggered by default.\n\nIndex Definitions\n-----------------\n\nSee CREATE TABLE: Index Definitions for information about index definitions.\n\nWAIT/NOWAIT\n-----------\n\nSet the lock wait timeout. See WAIT and NOWAIT.\n\nALGORITHM\n---------\n\nSee ALTER TABLE: ALGORITHM for more information.\n\nLOCK\n----\n\nSee ALTER TABLE: LOCK for more information.\n\nProgress Reporting\n------------------\n\nMariaDB provides progress reporting for CREATE INDEX statement for clients\nthat support the new progress reporting protocol. For example, if you were\nusing the mariadb client, then the progress report might look like this::\n\nCREATE INDEX i ON tab (num);\nStage: 1 of 2 \'copy to tmp table\' 46% of stage\n\nThe progress report is also shown in the output of the SHOW PROCESSLIST\nstatement and in the contents of the information_schema.PROCESSLIST table.\n\nSee Progress Reporting for more information.\n\nWITHOUT OVERLAPS\n----------------\n\nMariaDB starting with 10.5.3\n----------------------------\nThe WITHOUT OVERLAPS clause allows one to constrain a primary or unique index\nsuch that application-time periods cannot overlap.\n\nExamples\n--------\n\nCreating a unique index:\n\nCREATE UNIQUE INDEX HomePhone ON Employees(Home_Phone);\n\nOR REPLACE and IF NOT EXISTS:\n\nCREATE INDEX xi ON xx5 (x);\nQuery OK, 0 rows affected (0.03 sec)\n\nCREATE INDEX xi ON xx5 (x);\nERROR 1061 (42000): Duplicate key name \'xi\'\n\nCREATE OR REPLACE INDEX xi ON xx5 (x);\nQuery OK, 0 rows affected (0.03 sec)\n\nCREATE INDEX IF NOT EXISTS xi ON xx5 (x);\nQuery OK, 0 rows affected, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+-------+------+-------------------------+\n| Level | Code | Message |\n+-------+------+-------------------------+\n| Note | 1061 | Duplicate key name \'xi\' |\n+-------+------+-------------------------+\n\nFrom MariaDB 10.5.3, creating a unique index for an application-time period\ntable with a WITHOUT OVERLAPS constraint:\n\nCREATE UNIQUE INDEX u ON rooms (room_number, p WITHOUT OVERLAPS);\n\nURL: https://mariadb.com/kb/en/create-index/','','https://mariadb.com/kb/en/create-index/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (714,38,'CREATE PACKAGE','MariaDB starting with 10.3.5\n----------------------------\nOracle-style packages were introduced in MariaDB 10.3.5.\n\nSyntax\n------\n\nCREATE\n [ OR REPLACE]\n [DEFINER = { user | CURRENT_USER | role | CURRENT_ROLE }]\n PACKAGE [ IF NOT EXISTS ]\n [ db_name . ] package_name\n [ package_characteristic ... ]\n{ AS | IS }\n [ package_specification_element ... ]\nEND [ package_name ]\n\npackage_characteristic:\n COMMENT \'string\'\n | SQL SECURITY { DEFINER | INVOKER }\n\npackage_specification_element:\n FUNCTION_SYM package_specification_function ;\n | PROCEDURE_SYM package_specification_procedure ;\n\npackage_specification_function:\n func_name [ ( func_param [, func_param]... ) ]\n RETURNS func_return_type\n [ package_routine_characteristic... ]\n\npackage_specification_procedure:\n proc_name [ ( proc_param [, proc_param]... ) ]\n [ package_routine_characteristic... ]\n\nfunc_return_type:\n type\n\nfunc_param:\n param_name [ IN | OUT | INOUT | IN OUT ] type\n\nproc_param:\n param_name [ IN | OUT | INOUT | IN OUT ] type\n\ntype:\n Any valid MariaDB explicit or anchored data type\n\npackage_routine_characteristic:\n COMMENT \'string\'\n | LANGUAGE SQL\n | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }\n | SQL SECURITY { DEFINER | INVOKER }\n\nDescription\n-----------\n\nThe CREATE PACKAGE statement can be used when Oracle SQL_MODE is set.\n\nThe CREATE PACKAGE creates the specification for a stored package (a\ncollection of logically related stored objects). A stored package\nspecification declares public routines (procedures and functions) of the\npackage, but does not implement these routines.\n\nA package whose specification was created by the CREATE PACKAGE statement,\nshould later be implemented using the CREATE PACKAGE BODY statement.\n\nFunction parameter quantifiers IN | OUT | INOUT | IN OUT\n--------------------------------------------------------\n\nMariaDB starting with 10.8.0\n----------------------------\nThe function parameter quantifiers for IN, OUT, INOUT, and IN OUT where added\nin a 10.8.0 preview release. Prior to 10.8.0 quantifiers were supported only\nin procedures.\n\nOUT, INOUT and its equivalent IN OUT, are only valid if called from SET and\nnot SELECT. These quantifiers are especially useful for creating functions and\nprocedures with more than one return value. This allows functions and\nprocedures to be more complex and nested.\n\nExamples\n--------\n\nSET sql_mode=ORACLE;\nDELIMITER $$\nCREATE OR REPLACE PACKAGE employee_tools AS\n FUNCTION getSalary(eid INT) RETURN DECIMAL(10,2);\n PROCEDURE raiseSalary(eid INT, amount DECIMAL(10,2));\n PROCEDURE raiseSalaryStd(eid INT);\n PROCEDURE hire(ename TEXT, esalary DECIMAL(10,2));\nEND;\n$$\nDELIMITER ;\n\nURL: https://mariadb.com/kb/en/create-package/','','https://mariadb.com/kb/en/create-package/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (715,38,'CREATE PACKAGE BODY','MariaDB starting with 10.3.5\n----------------------------\nOracle-style packages were introduced in MariaDB 10.3.5.\n\nSyntax\n------\n\nCREATE [ OR REPLACE ]\n [DEFINER = { user | CURRENT_USER | role | CURRENT_ROLE }]\n PACKAGE BODY\n [ IF NOT EXISTS ]\n [ db_name . ] package_name\n [ package_characteristic... ]\n{ AS | IS }\n package_implementation_declare_section\n package_implementation_executable_section\nEND [ package_name]\n\npackage_implementation_declare_section:\n package_implementation_item_declaration\n [ package_implementation_item_declaration... ]\n [ package_implementation_routine_definition... ]\n | package_implementation_routine_definition\n [ package_implementation_routine_definition...]\n\npackage_implementation_item_declaration:\n variable_declaration ;\n\nvariable_declaration:\n variable_name[,...] type [:= expr ]\n\npackage_implementation_routine_definition:\n FUNCTION package_specification_function\n [ package_implementation_function_body ] ;\n | PROCEDURE package_specification_procedure\n [ package_implementation_procedure_body ] ;\n\npackage_implementation_function_body:\n { AS | IS } package_routine_body [func_name]\n\npackage_implementation_procedure_body:\n { AS | IS } package_routine_body [proc_name]\n\npackage_routine_body:\n [ package_routine_declarations ]\n BEGIN\n statements [ EXCEPTION exception_handlers ]\n END\n\npackage_routine_declarations:\n package_routine_declaration \';\' [package_routine_declaration \';\']...\n\npackage_routine_declaration:\n variable_declaration\n | condition_name CONDITION FOR condition_value\n | user_exception_name EXCEPTION\n | CURSOR_SYM cursor_name\n [ ( cursor_formal_parameters ) ]\n IS select_statement\n ;\n\npackage_implementation_executable_section:\n END\n | BEGIN\n statement ; [statement ; ]...\n [EXCEPTION exception_handlers]\n END\n\nexception_handlers:\n exception_handler [exception_handler...]\n\nexception_handler:\n WHEN_SYM condition_value [, condition_value]...\n THEN_SYM statement ; [statement ;]...\n\ncondition_value:\n condition_name\n | user_exception_name\n | SQLWARNING\n | SQLEXCEPTION\n | NOT FOUND\n | OTHERS_SYM\n | SQLSTATE [VALUE] sqlstate_value\n | mariadb_error_code\n\nDescription\n-----------\n\nThe CREATE PACKAGE BODY statement can be used when Oracle SQL_MODE is set.\n\nThe CREATE PACKAGE BODY statement creates the package body for a stored\npackage. The package specification must be previously created using the CREATE\nPACKAGE statement.\n\nA package body provides implementations of the package public routines and can\noptionally have:\n\n* package-wide private variables\n* package private routines\n* forward declarations for private routines\n* an executable initialization section\n\nExamples\n--------\n\nSET sql_mode=ORACLE;\nDELIMITER $$\nCREATE OR REPLACE PACKAGE employee_tools AS\n FUNCTION getSalary(eid INT) RETURN DECIMAL(10,2);\n PROCEDURE raiseSalary(eid INT, amount DECIMAL(10,2));\n PROCEDURE raiseSalaryStd(eid INT);\n PROCEDURE hire(ename TEXT, esalary DECIMAL(10,2));\nEND;\n$$\nCREATE PACKAGE BODY employee_tools AS\n -- package body variables\n stdRaiseAmount DECIMAL(10,2):=500;\n\n-- private routines\n PROCEDURE log (eid INT, ecmnt TEXT) AS\n BEGIN\n INSERT INTO employee_log (id, cmnt) VALUES (eid, ecmnt);\n END;\n\n-- public routines\n PROCEDURE hire(ename TEXT, esalary DECIMAL(10,2)) AS\n eid INT;\n BEGIN\n INSERT INTO employee (name, salary) VALUES (ename, esalary);\n eid:= last_insert_id();\n log(eid, \'hire \' || ename);\n END;\n\nFUNCTION getSalary(eid INT) RETURN DECIMAL(10,2) AS\n nSalary DECIMAL(10,2);\n BEGIN\n SELECT salary INTO nSalary FROM employee WHERE id=eid;\n log(eid, \'getSalary id=\' || eid || \' salary=\' || nSalary);\n RETURN nSalary;\n END;\n\nPROCEDURE raiseSalary(eid INT, amount DECIMAL(10,2)) AS\n BEGIN\n UPDATE employee SET salary=salary+amount WHERE id=eid;\n log(eid, \'raiseSalary id=\' || eid || \' amount=\' || amount);\n END;\n\nPROCEDURE raiseSalaryStd(eid INT) AS\n BEGIN\n raiseSalary(eid, stdRaiseAmount);\n log(eid, \'raiseSalaryStd id=\' || eid);\n END;\n\nBEGIN\n -- This code is executed when the current session\n -- accesses any of the package routines for the first time\n log(0, \'Session \' || connection_id() || \' \' || current_user || \' started\');\nEND;\n$$\n\nDELIMITER ;\n\nURL: https://mariadb.com/kb/en/create-package-body/','','https://mariadb.com/kb/en/create-package-body/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (716,38,'CREATE PROCEDURE','Syntax\n------\n\nCREATE\n [OR REPLACE]\n [DEFINER = { user | CURRENT_USER | role | CURRENT_ROLE }]\n PROCEDURE [IF NOT EXISTS] sp_name ([proc_parameter[,...]])\n [characteristic ...] routine_body\n\nproc_parameter:\n [ IN | OUT | INOUT ] param_name type\n\ntype:\n Any valid MariaDB data type\n\ncharacteristic:\n LANGUAGE SQL\n | [NOT] DETERMINISTIC\n | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }\n | SQL SECURITY { DEFINER | INVOKER }\n | COMMENT \'string\'\n\nroutine_body:\n Valid SQL procedure statement\n\nDescription\n-----------\n\nCreates a stored procedure. By default, a routine is associated with the\ndefault database. To associate the routine explicitly with a given database,\nspecify the name as db_name.sp_name when you create it.\n\nWhen the routine is invoked, an implicit USE db_name is performed (and undone\nwhen the routine terminates). The causes the routine to have the given default\ndatabase while it executes. USE statements within stored routines are\ndisallowed.\n\nWhen a stored procedure has been created, you invoke it by using the CALL\nstatement (see CALL).\n\nTo execute the CREATE PROCEDURE statement, it is necessary to have the CREATE\nROUTINE privilege. By default, MariaDB automatically grants the ALTER ROUTINE\nand EXECUTE privileges to the routine creator. See also Stored Routine\nPrivileges.\n\nThe DEFINER and SQL SECURITY clauses specify the security context to be used\nwhen checking access privileges at routine execution time, as described here.\nRequires the SUPER privilege, or, from MariaDB 10.5.2, the SET USER privilege.\n\nIf the routine name is the same as the name of a built-in SQL function, you\nmust use a space between the name and the following parenthesis when defining\nthe routine, or a syntax error occurs. This is also true when you invoke the\nroutine later. For this reason, we suggest that it is better to avoid re-using\nthe names of existing SQL functions for your own stored routines.\n\nThe IGNORE_SPACE SQL mode applies to built-in functions, not to stored\nroutines. It is always allowable to have spaces after a routine name,\nregardless of whether IGNORE_SPACE is enabled.\n\nThe parameter list enclosed within parentheses must always be present. If\nthere are no parameters, an empty parameter list of () should be used.\nParameter names are not case sensitive.\n\nEach parameter can be declared to use any valid data type, except that the\nCOLLATE attribute cannot be used.\n\nFor valid identifiers to use as procedure names, see Identifier Names.\n\nThings to be Aware of With CREATE OR REPLACE\n--------------------------------------------\n\n* One can\'t use OR REPLACE together with IF EXISTS.\n\nCREATE PROCEDURE IF NOT EXISTS\n------------------------------\n\nIf the IF NOT EXISTS clause is used, then the procedure will only be created\nif a procedure with the same name does not already exist. If the procedure\nalready exists, then a warning will be triggered by default.\n\nIN/OUT/INOUT\n------------\n\nEach parameter is an IN parameter by default. To specify otherwise for a\nparameter, use the keyword OUT or INOUT before the parameter name.\n\nAn IN parameter passes a value into a procedure. The procedure might modify\nthe value, but the modification is not visible to the caller when the\nprocedure returns. An OUT parameter passes a value from the procedure back to\nthe caller. Its initial value is NULL within the procedure, and its value is\nvisible to the caller when the procedure returns. An INOUT parameter is\ninitialized by the caller, can be modified by the procedure, and any change\nmade by the procedure is visible to the caller when the procedure returns.\n\nFor each OUT or INOUT parameter, pass a user-defined variable in the CALL\nstatement that invokes the procedure so that you can obtain its value when the\nprocedure returns. If you are calling the procedure from within another stored\nprocedure or function, you can also pass a routine parameter or local routine\nvariable as an IN or INOUT parameter.\n\nDETERMINISTIC/NOT DETERMINISTIC\n-------------------------------\n\nDETERMINISTIC and NOT DETERMINISTIC apply only to functions. Specifying\nDETERMINISTC or NON-DETERMINISTIC in procedures has no effect. The default\nvalue is NOT DETERMINISTIC. Functions are DETERMINISTIC when they always\nreturn the same value for the same input. For example, a truncate or substring\nfunction. Any function involving data, therefore, is always NOT DETERMINISTIC.\n\nCONTAINS SQL/NO SQL/READS SQL DATA/MODIFIES SQL DATA\n----------------------------------------------------\n\nCONTAINS SQL, NO SQL, READS SQL DATA, and MODIFIES SQL DATA are informative\nclauses that tell the server what the function does. MariaDB does not check in\nany way whether the specified clause is correct. If none of these clauses are\nspecified, CONTAINS SQL is used by default.\n\nMODIFIES SQL DATA means that the function contains statements that may modify\ndata stored in databases. This happens if the function contains statements\nlike DELETE, UPDATE, INSERT, REPLACE or DDL.\n\nREADS SQL DATA means that the function reads data stored in databases, but\ndoes not modify any data. This happens if SELECT statements are used, but\nthere no write operations are executed.\n\nCONTAINS SQL means that the function contains at least one SQL statement, but\nit does not read or write any data stored in a database. Examples include SET\nor DO.\n\nNO SQL means nothing, because MariaDB does not currently support any language\nother than SQL.\n\nThe routine_body consists of a valid SQL procedure statement. This can be a\nsimple statement such as SELECT or INSERT, or it can be a compound statement\nwritten using BEGIN and END. Compound statements can contain declarations,\nloops, and other control structure statements. See Programmatic and Compound\nStatements for syntax details.\n\nMariaDB allows routines to contain DDL statements, such as CREATE and DROP.\nMariaDB also allows stored procedures (but not stored functions) to contain\nSQL transaction statements such as COMMIT.\n\nFor additional information about statements that are not allowed in stored\nroutines, see Stored Routine Limitations.\n\nInvoking stored procedure from within programs\n----------------------------------------------\n\nFor information about invoking stored procedures from within programs written\nin a language that has a MariaDB/MySQL interface, see CALL.\n\nOR REPLACE\n----------\n\nIf the optional OR REPLACE clause is used, it acts as a shortcut for:\n\nDROP PROCEDURE IF EXISTS name;\nCREATE PROCEDURE name ...;\n\nwith the exception that any existing privileges for the procedure are not\ndropped.\n\nsql_mode\n--------\n\nMariaDB stores the sql_mode system variable setting that is in effect at the\ntime a routine is created, and always executes the routine with this setting\nin force, regardless of the server SQL mode in effect when the routine is\ninvoked.\n\nCharacter Sets and Collations\n-----------------------------\n\nProcedure parameters can be declared with any character set/collation. If the\ncharacter set and collation are not specifically set, the database defaults at\nthe time of creation will be used. If the database defaults change at a later\nstage, the stored procedure character set/collation will not be changed at the\nsame time; the stored procedure needs to be dropped and recreated to ensure\nthe same character set/collation as the database is used.\n\nOracle Mode\n-----------\n\nA subset of Oracle\'s PL/SQL language is supported in addition to the\ntraditional SQL/PSM-based MariaDB syntax. See Oracle mode for details on\nchanges when running Oracle mode.\n\nExamples\n--------\n\nThe following example shows a simple stored procedure that uses an OUT\nparameter. It uses the DELIMITER command to set a new delimiter for the\nduration of the process — see Delimiters in the mariadb client.\n\nDELIMITER //\n\nCREATE PROCEDURE simpleproc (OUT param1 INT)\n BEGIN\n SELECT COUNT(*) INTO param1 FROM t;\n END;\n//\n\nDELIMITER ;\n\nCALL simpleproc(@a);\n\nSELECT @a;\n+------+\n| @a |\n+------+\n| 1 |\n+------+\n\nCharacter set and collation:\n\nDELIMITER //\n\nCREATE PROCEDURE simpleproc2 (\n OUT param1 CHAR(10) CHARACTER SET \'utf8\' COLLATE \'utf8_bin\'\n)\n BEGIN\n SELECT CONCAT(\'a\'),f1 INTO param1 FROM t;\n END;\n//\n\nDELIMITER ;\n\nCREATE OR REPLACE:\n\nDELIMITER //\n\nCREATE PROCEDURE simpleproc2 (\n OUT param1 CHAR(10) CHARACTER SET \'utf8\' COLLATE \'utf8_bin\'\n)\n BEGIN\n SELECT CONCAT(\'a\'),f1 INTO param1 FROM t;\n END;\n//\nERROR 1304 (42000): PROCEDURE simpleproc2 already exists\n\nDELIMITER ;\n\nDELIMITER //\n\nCREATE OR REPLACE PROCEDURE simpleproc2 (\n OUT param1 CHAR(10) CHARACTER SET \'utf8\' COLLATE \'utf8_bin\'\n)\n BEGIN\n SELECT CONCAT(\'a\'),f1 INTO param1 FROM t;\n END;\n//\nERROR 1304 (42000): PROCEDURE simpleproc2 already exists\n\nDELIMITER ;\nQuery OK, 0 rows affected (0.03 sec)\n\nURL: https://mariadb.com/kb/en/create-procedure/','','https://mariadb.com/kb/en/create-procedure/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (717,38,'CREATE SERVER','Syntax\n------\n\nCREATE [OR REPLACE] SERVER [IF NOT EXISTS] server_name\n FOREIGN DATA WRAPPER wrapper_name\n OPTIONS (option [, option] ...)\n\noption:\n { HOST character-literal\n | DATABASE character-literal\n | USER character-literal\n | PASSWORD character-literal\n | SOCKET character-literal\n | OWNER character-literal\n | PORT numeric-literal }\n\nDescription\n-----------\n\nThis statement creates the definition of a server for use with the Spider,\nConnect, FEDERATED or FederatedX storage engine. The CREATE SERVER statement\ncreates a new row within the servers table within the mysql database. This\nstatement requires the SUPER privilege or, from MariaDB 10.5.2, the FEDERATED\nADMIN privilege.\n\nThe server_name should be a unique reference to the server. Server definitions\nare global within the scope of the server, it is not possible to qualify the\nserver definition to a specific database. server_name has a maximum length of\n64 characters (names longer than 64 characters are silently truncated), and is\ncase insensitive. You may specify the name as a quoted string.\n\nThe wrapper_name may be quoted with single quotes. Supported values are:\n\n* mysql\n* mariadb (in MariaDB 10.3 and later)\n\nFor each option you must specify either a character literal or numeric\nliteral. Character literals are UTF-8, support a maximum length of 64\ncharacters and default to a blank (empty) string. String literals are silently\ntruncated to 64 characters. Numeric literals must be a number between 0 and\n9999, default value is 0.\n\nNote: The OWNER option is currently not applied, and has no effect on the\nownership or operation of the server connection that is created.\n\nThe CREATE SERVER statement creates an entry in the mysql.servers table that\ncan later be used with the CREATE TABLE statement when creating a Spider,\nConnect, FederatedX or FEDERATED table. The options that you specify will be\nused to populate the columns in the mysql.servers table. The table columns are\nServer_name, Host, Db, Username, Password, Port and Socket.\n\nDROP SERVER removes a previously created server definition.\n\nCREATE SERVER is not written to the binary log, irrespective of the binary log\nformat being used. From MariaDB 10.1.13, Galera replicates the CREATE SERVER,\nALTER SERVER and DROP SERVER statements.\n\nFor valid identifiers to use as server names, see Identifier Names.\n\nOR REPLACE\n----------\n\nIf the optional OR REPLACE clause is used, it acts as a shortcut for:\n\nDROP SERVER IF EXISTS name;\nCREATE SERVER server_name ...;\n\nIF NOT EXISTS\n-------------\n\nIf the IF NOT EXISTS clause is used, MariaDB will return a warning instead of\nan error if the server already exists. Cannot be used together with OR REPLACE.\n\nExamples\n--------\n\nCREATE SERVER s\nFOREIGN DATA WRAPPER mysql\nOPTIONS (USER \'Remote\', HOST \'192.168.1.106\', DATABASE \'test\');\n\nOR REPLACE and IF NOT EXISTS:\n\nCREATE SERVER s \nFOREIGN DATA WRAPPER mysql \nOPTIONS (USER \'Remote\', HOST \'192.168.1.106\', DATABASE \'test\');\nERROR 1476 (HY000): The foreign server, s, you are trying to create already\nexists\n\nCREATE OR REPLACE SERVER s \nFOREIGN DATA WRAPPER mysql \nOPTIONS (USER \'Remote\', HOST \'192.168.1.106\', DATABASE \'test\');\nQuery OK, 0 rows affected (0.00 sec)\n\nCREATE SERVER IF NOT EXISTS s \nFOREIGN DATA WRAPPER mysql \nOPTIONS (USER \'Remote\', HOST \'192.168.1.106\', DATABASE \'test\');\nQuery OK, 0 rows affected, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+-------+------+---------------------------------------------------------------\n+\n| Level | Code | Message \n |\n+-------+------+---------------------------------------------------------------\n+\n| Note | 1476 | The foreign server, s, you are trying to create already\nexists |\n+-------+------+---------------------------------------------------------------\n+\n\nURL: https://mariadb.com/kb/en/create-server/','','https://mariadb.com/kb/en/create-server/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (718,38,'CREATE TABLESPACE','The CREATE TABLESPACE statement is not supported by MariaDB. It was originally\ninherited from MySQL NDB Cluster. In MySQL 5.7 and later, the statement is\nalso supported for InnoDB. However, MariaDB has chosen not to include that\nspecific feature. See MDEV-19294 for more information.\n\nURL: https://mariadb.com/kb/en/create-tablespace/','','https://mariadb.com/kb/en/create-tablespace/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (719,38,'CREATE TRIGGER','Syntax\n------\n\nCREATE [OR REPLACE]\n [DEFINER = { user | CURRENT_USER | role | CURRENT_ROLE }]\n TRIGGER [IF NOT EXISTS] trigger_name trigger_time trigger_event\n ON tbl_name FOR EACH ROW\n [{ FOLLOWS | PRECEDES } other_trigger_name ]\n trigger_stmt;\n\nDescription\n-----------\n\nThis statement creates a new trigger. A trigger is a named database object\nthat is associated with a table, and that activates when a particular event\noccurs for the table. The trigger becomes associated with the table named\ntbl_name, which must refer to a permanent table. You cannot associate a\ntrigger with a TEMPORARY table or a view.\n\nCREATE TRIGGER requires the TRIGGER privilege for the table associated with\nthe trigger.\n\nYou can have multiple triggers for the same trigger_time and trigger_event.\n\nFor valid identifiers to use as trigger names, see Identifier Names.\n\nOR REPLACE\n----------\n\nIf used and the trigger already exists, instead of an error being returned,\nthe existing trigger will be dropped and replaced by the newly defined trigger.\n\nDEFINER\n-------\n\nThe DEFINER clause determines the security context to be used when checking\naccess privileges at trigger activation time. Usage requires the SUPER\nprivilege, or, from MariaDB 10.5.2, the SET USER privilege.\n\nIF NOT EXISTS\n-------------\n\nIf the IF NOT EXISTS clause is used, the trigger will only be created if a\ntrigger of the same name does not exist. If the trigger already exists, by\ndefault a warning will be returned.\n\ntrigger_time\n------------\n\ntrigger_time is the trigger action time. It can be BEFORE or AFTER to indicate\nthat the trigger activates before or after each row to be modified.\n\ntrigger_event\n-------------\n\ntrigger_event indicates the kind of statement that activates the trigger. The\ntrigger_event can be one of the following:\n\n* INSERT: The trigger is activated whenever a new row is inserted into the\ntable; for example, through INSERT, LOAD DATA, and REPLACE statements.\n* UPDATE: The trigger is activated whenever a row is modified; for example,\nthrough UPDATE statements.\n* DELETE: The trigger is activated whenever a row is deleted from the table;\nfor example, through DELETE and REPLACE statements. However, DROP TABLE and\nTRUNCATE statements on the table do not activate this trigger, because they do\nnot use DELETE. Dropping a partition does not activate DELETE triggers, either.\n\nFOLLOWS/PRECEDES other_trigger_name\n-----------------------------------\n\nThe FOLLOWS other_trigger_name and PRECEDES other_trigger_name options were\nadded in MariaDB 10.2.3 as part of supporting multiple triggers per action\ntime. This is the same syntax used by MySQL 5.7, although MySQL 5.7 does not\nhave multi-trigger support.\n\nFOLLOWS adds the new trigger after another trigger while PRECEDES adds the new\ntrigger before another trigger. If neither option is used, the new trigger is\nadded last for the given action and time.\n\nFOLLOWS and PRECEDES are not stored in the trigger definition. However the\ntrigger order is guaranteed to not change over time. mariadb-dump and other\nbackup methods will not change trigger order. You can verify the trigger order\nfrom the ACTION_ORDER column in INFORMATION_SCHEMA.TRIGGERS table.\n\nSELECT trigger_name, action_order FROM information_schema.triggers \n WHERE event_object_table=\'t1\';\n\nAtomic DDL\n----------\n\nMariaDB starting with 10.6.1\n----------------------------\nMariaDB 10.6.1 supports Atomic DDL and CREATE TRIGGER is atomic.\n\nExamples\n--------\n\nCREATE DEFINER=`root`@`localhost` TRIGGER increment_animal\n AFTER INSERT ON animals FOR EACH ROW\n UPDATE animal_count SET animal_count.animals = animal_count.animals+1;\n\nOR REPLACE and IF NOT EXISTS\n\nCREATE DEFINER=`root`@`localhost` TRIGGER increment_animal\n AFTER INSERT ON animals FOR EACH ROW\n UPDATE animal_count SET animal_count.animals = animal_count.animals+1;\nERROR 1359 (HY000): Trigger already exists\n\nCREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER increment_animal\n AFTER INSERT ON animals FOR EACH ROW\n UPDATE animal_count SET animal_count.animals = animal_count.animals+1;\nQuery OK, 0 rows affected (0.12 sec)\n\nCREATE DEFINER=`root`@`localhost` TRIGGER IF NOT EXISTS increment_animal\n AFTER INSERT ON animals FOR EACH ROW\n UPDATE animal_count SET animal_count.animals = animal_count.animals+1;\nQuery OK, 0 rows affected, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+-------+------+------------------------+\n| Level | Code | Message |\n+-------+------+------------------------+\n| Note | 1359 | Trigger already exists |\n+-------+------+------------------------+\n1 row in set (0.00 sec)\n\nURL: https://mariadb.com/kb/en/create-trigger/','','https://mariadb.com/kb/en/create-trigger/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (720,38,'CREATE VIEW','Syntax\n------\n\nCREATE\n [OR REPLACE]\n [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]\n [DEFINER = { user | CURRENT_USER | role | CURRENT_ROLE }]\n [SQL SECURITY { DEFINER | INVOKER }]\n VIEW [IF NOT EXISTS] view_name [(column_list)]\n AS select_statement\n [WITH [CASCADED | LOCAL] CHECK OPTION]\n\nDescription\n-----------\n\nThe CREATE VIEW statement creates a new view, or replaces an existing one if\nthe OR REPLACE clause is given. If the view does not exist, CREATE OR REPLACE\nVIEW is the same as CREATE VIEW. If the view does exist, CREATE OR REPLACE\nVIEW is the same as ALTER VIEW.\n\nThe select_statement is a SELECT statement that provides the definition of the\nview. (When you select from the view, you select in effect using the SELECT\nstatement.) select_statement can select from base tables or other views.\n\nThe view definition is \"frozen\" at creation time, so changes to the underlying\ntables afterwards do not affect the view definition. For example, if a view is\ndefined as SELECT * on a table, new columns added to the table later do not\nbecome part of the view. A SHOW CREATE VIEW shows that such queries are\nrewritten and column names are included in the view definition.\n\nThe view definition must be a query that does not return errors at view\ncreation times. However, the base tables used by the views might be altered\nlater and the query may not be valid anymore. In this case, querying the view\nwill result in an error. CHECK TABLE helps in finding this kind of problems.\n\nThe ALGORITHM clause affects how MariaDB processes the view. The DEFINER and\nSQL SECURITY clauses specify the security context to be used when checking\naccess privileges at view invocation time. The WITH CHECK OPTION clause can be\ngiven to constrain inserts or updates to rows in tables referenced by the\nview. These clauses are described later in this section.\n\nThe CREATE VIEW statement requires the CREATE VIEW privilege for the view, and\nsome privilege for each column selected by the SELECT statement. For columns\nused elsewhere in the SELECT statement you must have the SELECT privilege. If\nthe OR REPLACE clause is present, you must also have the DROP privilege for\nthe view.\n\nA view belongs to a database. By default, a new view is created in the default\ndatabase. To create the view explicitly in a given database, specify the name\nas db_name.view_name when you create it.\n\nCREATE VIEW test.v AS SELECT * FROM t;\n\nBase tables and views share the same namespace within a database, so a\ndatabase cannot contain a base table and a view that have the same name.\n\nViews must have unique column names with no duplicates, just like base tables.\nBy default, the names of the columns retrieved by the SELECT statement are\nused for the view column names. To define explicit names for the view columns,\nthe optional column_list clause can be given as a list of comma-separated\nidentifiers. The number of names in column_list must be the same as the number\nof columns retrieved by the SELECT statement.\n\nMySQL until 5.1.28\n------------------\nPrior to MySQL 5.1.29, When you modify an existing view, the current view\ndefinition is backed up and saved. It is stored in that table\'s database\ndirectory, in a subdirectory named arc. The backup file for a view v is named\nv.frm-00001. If you alter the view again, the next backup is named\nv.frm-00002. The three latest view backup definitions are stored. Backed up\nview definitions are not preserved by mysqldump, or any other such programs,\nbut you can retain them using a file copy operation. However, they are not\nneeded for anything but to provide you with a backup of your previous view\ndefinition. It is safe to remove these backup definitions, but only while\nmysqld is not running. If you delete the arc subdirectory or its files while\nmysqld is running, you will receive an error the next time you try to alter\nthe view:\n\nMariaDB [test]> ALTER VIEW v AS SELECT * FROM t; \nERROR 6 (HY000): Error on delete of \'.\\test\\arc/v.frm-0004\' (Errcode: 2)\n\nColumns retrieved by the SELECT statement can be simple references to table\ncolumns. They can also be expressions that use functions, constant values,\noperators, and so forth.\n\nUnqualified table or view names in the SELECT statement are interpreted with\nrespect to the default database. A view can refer to tables or views in other\ndatabases by qualifying the table or view name with the proper database name.\n\nA view can be created from many kinds of SELECT statements. It can refer to\nbase tables or other views. It can use joins, UNION, and subqueries. The\nSELECT need not even refer to any tables. The following example defines a view\nthat selects two columns from another table, as well as an expression\ncalculated from those columns:\n\nCREATE TABLE t (qty INT, price INT);\n\nINSERT INTO t VALUES(3, 50);\n\nCREATE VIEW v AS SELECT qty, price, qty*price AS value FROM t;\n\nSELECT * FROM v;\n+------+-------+-------+\n| qty | price | value |\n+------+-------+-------+\n| 3 | 50 | 150 |\n+------+-------+-------+\n\nA view definition is subject to the following restrictions:\n\n* The SELECT statement cannot contain a subquery in the FROM clause.\n* The SELECT statement cannot refer to system or user variables.\n* Within a stored program, the definition cannot refer to program parameters\nor local variables.\n* The SELECT statement cannot refer to prepared statement parameters.\n* Any table or view referred to in the definition must exist. However, after a\nview has been created, it is possible to drop a table or view that the\ndefinition refers to. In this case, use of the view results in an error. To\ncheck a view definition for problems of this kind, use the CHECK TABLE\nstatement.\n* The definition cannot refer to a TEMPORARY table, and you cannot create a\nTEMPORARY view.\n* Any tables named in the view definition must exist at definition time.\n* You cannot associate a trigger with a view.\n* For valid identifiers to use as view names, see Identifier Names.\n\nORDER BY is allowed in a view definition, but it is ignored if you select from\na view using a statement that has its own ORDER BY.\n\nFor other options or clauses in the definition, they are added to the options\nor clauses of the statement that references the view, but the effect is\nundefined. For example, if a view definition includes a LIMIT clause, and you\nselect from the view using a statement that has its own LIMIT clause, it is\nundefined which limit applies. This same principle applies to options such as\nALL, DISTINCT, or SQL_SMALL_RESULT that follow the SELECT keyword, and to\nclauses such as INTO, FOR UPDATE, and LOCK IN SHARE MODE.\n\nThe PROCEDURE clause cannot be used in a view definition, and it cannot be\nused if a view is referenced in the FROM clause.\n\nIf you create a view and then change the query processing environment by\nchanging system variables, that may affect the results that you get from the\nview:\n\nCREATE VIEW v (mycol) AS SELECT \'abc\';\n\nSET sql_mode = \'\';\n\nSELECT \"mycol\" FROM v;\n+-------+\n| mycol |\n+-------+\n| mycol | \n+-------+\n\nSET sql_mode = \'ANSI_QUOTES\';\n\nSELECT \"mycol\" FROM v;\n+-------+\n| mycol |\n+-------+\n| abc | \n+-------+\n\nThe DEFINER and SQL SECURITY clauses determine which MariaDB account to use\nwhen checking access privileges for the view when a statement is executed that\nreferences the view. They were added in MySQL 5.1.2. The legal SQL SECURITY\ncharacteristic values are DEFINER and INVOKER. These indicate that the\nrequired privileges must be held by the user who defined or invoked the view,\nrespectively. The default SQL SECURITY value is DEFINER.\n\nIf a user value is given for the DEFINER clause, it should be a MariaDB\naccount in \'user_name\'@\'host_name\' format (the same format used in the GRANT\nstatement). The user_name and host_name values both are required. The definer\ncan also be given as CURRENT_USER or CURRENT_USER(). The default DEFINER value\nis the user who executes the CREATE VIEW statement. This is the same as\nspecifying DEFINER = CURRENT_USER explicitly.\n\nIf you specify the DEFINER clause, these rules determine the legal DEFINER\nuser values:\n\n* If you do not have the SUPER privilege, or, from MariaDB 10.5.2, the SET\nUSER privilege, the only legal user value is your own account, either\nspecified literally or by using CURRENT_USER. You cannot set the definer to\nsome other account.\n* If you have the SUPER privilege, or, from MariaDB 10.5.2, the SET USER\nprivilege, you can specify any syntactically legal account name. If the\naccount does not actually exist, a warning is generated.\n* If the SQL SECURITY value is DEFINER but the definer account does not exist\nwhen the view is referenced, an error occurs.\n\nWithin a view definition, CURRENT_USER returns the view\'s DEFINER value by\ndefault. For views defined with the SQL SECURITY INVOKER characteristic,\nCURRENT_USER returns the account for the view\'s invoker. For information about\nuser auditing within views, see\nhttp://dev.mysql.com/doc/refman/5.1/en/account-activity-auditing.html.\n\nWithin a stored routine that is defined with the SQL SECURITY DEFINER\ncharacteristic, CURRENT_USER returns the routine\'s DEFINER value. This also\naffects a view defined within such a program, if the view definition contains\na DEFINER value of CURRENT_USER.\n\nView privileges are checked like this:\n\n* At view definition time, the view creator must have the privileges needed to\nuse the top-level objects accessed by the view. For example, if the view\ndefinition refers to table columns, the creator must have privileges for the\ncolumns, as described previously. If the definition refers to a stored\nfunction, only the privileges needed to invoke the function can be checked.\nThe privileges required when the function runs can be checked only as it\nexecutes: For different invocations of the function, different execution paths\nwithin the function might be taken.\n* When a view is referenced, privileges for objects accessed by the view are\nchecked against the privileges held by the view creator or invoker, depending\non whether the SQL SECURITY characteristic is DEFINER or INVOKER, respectively.\n* If reference to a view causes execution of a stored function, privilege\nchecking for statements executed within the function depend on whether the\nfunction is defined with a SQL SECURITY characteristic of DEFINER or INVOKER.\nIf the security characteristic is DEFINER, the function runs with the\nprivileges of its creator. If the characteristic is INVOKER, the function runs\nwith the privileges determined by the view\'s SQL SECURITY characteristic.\n\nExample: A view might depend on a stored function, and that function might\ninvoke other stored routines. For example, the following view invokes a stored\nfunction f():\n\nCREATE VIEW v AS SELECT * FROM t WHERE t.id = f(t.name);\n\nSuppose that f() contains a statement such as this:\n\nIF name IS NULL then\n CALL p1();\nELSE\n CALL p2();\nEND IF;\n\nThe privileges required for executing statements within f() need to be checked\nwhen f() executes. This might mean that privileges are needed for p1() or\np2(), depending on the execution path within f(). Those privileges must be\nchecked at runtime, and the user who must possess the privileges is determined\nby the SQL SECURITY values of the view v and the function f().\n\nThe DEFINER and SQL SECURITY clauses for views are extensions to standard SQL.\nIn standard SQL, views are handled using the rules for SQL SECURITY INVOKER.\n\nIf you invoke a view that was created before MySQL 5.1.2, it is treated as\nthough it was created with a SQL SECURITY DEFINER clause and with a DEFINER\nvalue that is the same as your account. However, because the actual definer is\nunknown, MySQL issues a warning. To make the warning go away, it is sufficient\nto re-create the view so that the view definition includes a DEFINER clause.\n\nThe optional ALGORITHM clause is an extension to standard SQL. It affects how\nMariaDB processes the view. ALGORITHM takes three values: MERGE, TEMPTABLE, or\nUNDEFINED. The default algorithm is UNDEFINED if no ALGORITHM clause is\npresent. See View Algorithms for more information.\n\nSome views are updatable. That is, you can use them in statements such as\nUPDATE, DELETE, or INSERT to update the contents of the underlying table. For\na view to be updatable, there must be a one-to-one relationship between the\nrows in the view and the rows in the underlying table. There are also certain\nother constructs that make a view non-updatable. See Inserting and Updating\nwith Views.\n\nWITH CHECK OPTION\n-----------------\n\nThe WITH CHECK OPTION clause can be given for an updatable view to prevent\ninserts or updates to rows except those for which the WHERE clause in the\nselect_statement is true.\n\nIn a WITH CHECK OPTION clause for an updatable view, the LOCAL and CASCADED\nkeywords determine the scope of check testing when the view is defined in\nterms of another view. The LOCAL keyword restricts the CHECK OPTION only to\nthe view being defined. CASCADED causes the checks for underlying views to be\nevaluated as well. When neither keyword is given, the default is CASCADED.\n\nFor more information about updatable views and the WITH CHECK OPTION clause,\nsee Inserting and Updating with Views.\n\nIF NOT EXISTS\n-------------\n\nMariaDB starting with 10.1.3\n----------------------------\nThe IF NOT EXISTS clause was added in MariaDB 10.1.3\n\nWhen the IF NOT EXISTS clause is used, MariaDB will return a warning instead\nof an error if the specified view already exists. Cannot be used together with\nthe OR REPLACE clause.\n\nAtomic DDL\n----------\n\nMariaDB starting with 10.6.1\n----------------------------\nMariaDB 10.6.1 supports Atomic DDL and CREATE VIEW is atomic.\n\nExamples\n--------\n\nCREATE TABLE t (a INT, b INT) ENGINE = InnoDB;\n\nINSERT INTO t VALUES (1,1), (2,2), (3,3);\n\nCREATE VIEW v AS SELECT a, a*2 AS a2 FROM t;\n\nSELECT * FROM v;\n+------+------+\n| a | a2 |\n+------+------+\n| 1 | 2 |\n| 2 | 4 |\n| 3 | 6 |\n+------+------+\n\nOR REPLACE and IF NOT EXISTS:\n\nCREATE VIEW v AS SELECT a, a*2 AS a2 FROM t;\nERROR 1050 (42S01): Table \'v\' already exists\n\nCREATE OR REPLACE VIEW v AS SELECT a, a*2 AS a2 FROM t;\nQuery OK, 0 rows affected (0.04 sec)\n\nCREATE VIEW IF NOT EXISTS v AS SELECT a, a*2 AS a2 FROM t;\nQuery OK, 0 rows affected, 1 warning (0.01 sec)\n','','https://mariadb.com/kb/en/create-view/'); +update help_topic set description = CONCAT(description, '\nSHOW WARNINGS;\n+-------+------+--------------------------+\n| Level | Code | Message |\n+-------+------+--------------------------+\n| Note | 1050 | Table \'v\' already exists |\n+-------+------+--------------------------+\n\nURL: https://mariadb.com/kb/en/create-view/') WHERE help_topic_id = 720; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (721,38,'Generated (Virtual and Persistent/Stored) Columns','Syntax\n------\n\n<type> [GENERATED ALWAYS] AS ( <expression> )\n[VIRTUAL | PERSISTENT | STORED] [UNIQUE] [UNIQUE KEY] [COMMENT <text>]\n\nMariaDB\'s generated columns syntax is designed to be similar to the syntax for\nMicrosoft SQL Server\'s computed columns and Oracle Database\'s virtual columns.\nIn MariaDB 10.2 and later, the syntax is also compatible with the syntax for\nMySQL\'s generated columns.\n\nDescription\n-----------\n\nA generated column is a column in a table that cannot explicitly be set to a\nspecific value in a DML query. Instead, its value is automatically generated\nbased on an expression. This expression might generate the value based on the\nvalues of other columns in the table, or it might generate the value by\ncalling built-in functions or user-defined functions (UDFs).\n\nThere are two types of generated columns:\n\n* PERSISTENT (a.k.a. STORED): This type\'s value is actually stored in the\ntable.\n* VIRTUAL: This type\'s value is not stored at all. Instead, the value is\ngenerated dynamically when the table is queried. This type is the default.\n\nGenerated columns are also sometimes called computed columns or virtual\ncolumns.\n\nSupported Features\n------------------\n\nStorage Engine Support\n----------------------\n\n* Generated columns can only be used with storage engines which support them.\nIf you try to use a storage engine that does not support them, then you will\nsee an error similar to the following:\n\nERROR 1910 (HY000): TokuDB storage engine does not support computed columns\n\n* InnoDB, Aria, MyISAM and CONNECT support generated columns.\n\n* A column in a MERGE table can be built on a PERSISTENT generated column.\nHowever, a column in a MERGE table can not be defined as a VIRTUAL and\nPERSISTENT generated column.\n\nData Type Support\n-----------------\n\n* All data types are supported when defining generated columns.\n\n* Using the ZEROFILL column option is supported when defining generated\ncolumns.\n\n* Using the AUTO_INCREMENT column option is not supported when defining\ngenerated columns. Until MariaDB 10.2.25, it was supported, but this support\nwas removed, because it would not work correctly. See MDEV-11117.\n\nIndex Support\n-------------\n\n* Using a generated column as a table\'s primary key is not supported. See\nMDEV-5590 for more information. If you try to use one as a primary key, then\nyou will see an error similar to the following:\n\nERROR 1903 (HY000): Primary key cannot be defined upon a computed column\n\n* Using PERSISTENT generated columns as part of a foreign key is supported.\n\n* Referencing PERSISTENT generated columns as part of a foreign key is also\nsupported.\nHowever, using the ON UPDATE CASCADE, ON UPDATE SET NULL, or ON DELETE SET\nNULL clauses is not supported. If you try to use an unsupported clause, then\nyou will see an error similar to the following:\n\nERROR 1905 (HY000): Cannot define foreign key with ON UPDATE SET NULL clause\non a computed column\n\n* Defining indexes on both VIRTUAL and PERSISTENT generated columns is\nsupported.\nIf an index is defined on a generated column, then the optimizer considers\nusing it in the same way as indexes based on \"real\" columns.\n\nStatement Support\n-----------------\n\n* Generated columns are used in DML queries just as if they were \"real\"\ncolumns.\nHowever, VIRTUAL and PERSISTENT generated columns differ in how their data is\nstored.\nValues for PERSISTENT generated columns are generated whenever a DML queries\ninserts or updates the row with the special DEFAULT value. This generates the\ncolumns value, and it is stored in the table like the other \"real\" columns.\nThis value can be read by other DML queries just like the other \"real\" columns.\nValues for VIRTUAL generated columns are not stored in the table. Instead, the\nvalue is generated dynamically whenever the column is queried. If other\ncolumns in a row are queried, but the VIRTUAL generated column is not one of\nthe queried columns, then the column\'s value is not generated.\n\n* The SELECT statement supports generated columns.\n\n* Generated columns can be referenced in the INSERT, UPDATE, and DELETE\nstatements.\nHowever, VIRTUAL or PERSISTENT generated columns cannot be explicitly set to\nany other values than NULL or DEFAULT. If a generated column is explicitly set\nto any other value, then the outcome depends on whether strict mode is enabled\nin sql_mode. If it is not enabled, then a warning will be raised and the\ndefault generated value will be used instead. If it is enabled, then an error\nwill be raised instead.\n\n* The CREATE TABLE statement has limited support for generated columns.\nIt supports defining generated columns in a new table.\nIt supports using generated columns to partition tables.\nIt does not support using the versioning clauses with generated columns.\n\n* The ALTER TABLE statement has limited support for generated columns.\nIt supports the MODIFY and CHANGE clauses for PERSISTENT generated columns.\nIt does not support the MODIFY clause for VIRTUAL generated columns if\nALGORITHM is not set to COPY. See MDEV-15476 for more information.\nIt does not support the CHANGE clause for VIRTUAL generated columns if\nALGORITHM is not set to COPY. See MDEV-17035 for more information.\nIt does not support altering a table if ALGORITHM is not set to COPY if the\ntable has a VIRTUAL generated column that is indexed. See MDEV-14046 for more\ninformation.\nIt does not support adding a VIRTUAL generated column with the ADD clause if\nthe same statement is also adding other columns if ALGORITHM is not set to\nCOPY. See MDEV-17468 for more information.\nIt also does not support altering an existing column into a VIRTUAL generated\ncolumn.\nIt supports using generated columns to partition tables.\nIt does not support using the versioning clauses with generated columns.\n\n* The SHOW CREATE TABLE statement supports generated columns.\n\n* The DESCRIBE statement can be used to check whether a table has generated\ncolumns.\nYou can tell which columns are generated by looking for the ones where the\nExtra column is set to either VIRTUAL or PERSISTENT. For example:\n\nDESCRIBE table1;\n+-------+-------------+------+-----+---------+------------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+-------------+------+-----+---------+------------+\n| a | int(11) | NO | | NULL | |\n| b | varchar(32) | YES | | NULL | |\n| c | int(11) | YES | | NULL | VIRTUAL |\n| d | varchar(5) | YES | | NULL | PERSISTENT |\n+-------+-------------+------+-----+---------+------------+\n\n* Generated columns can be properly referenced in the NEW and OLD rows in\ntriggers.\n\n* Stored procedures support generated columns.\n\n* The HANDLER statement supports generated columns.\n\nExpression Support\n------------------\n\n* Most legal, deterministic expressions which can be calculated are supported\nin expressions for generated columns.\n\n* Most built-in functions are supported in expressions for generated columns.\nHowever, some built-in functions can\'t be supported for technical reasons. For\nexample, If you try to use an unsupported function in an expression, an error\nis generated similar to the following:\n\nERROR 1901 (HY000): Function or expression \'dayname()\' cannot be used in the\nGENERATED ALWAYS AS clause of `v`\n\n* Subqueries are not supported in expressions for generated columns because\nthe underlying data can change.\n\n* Using anything that depends on data outside the row is not supported in\nexpressions for generated columns.\n\n* Stored functions are not supported in expressions for generated columns. See\nMDEV-17587 for more information.\n\n* Non-deterministic built-in functions are supported in expressions for not\nindexed VIRTUAL generated columns.\n\n* Non-deterministic built-in functions are not supported in expressions for\nPERSISTENT or indexed VIRTUAL generated columns.\n\n* User-defined functions (UDFs) are supported in expressions for generated\ncolumns.\nHowever, MariaDB can\'t check whether a UDF is deterministic, so it is up to\nthe user to be sure that they do not use non-deterministic UDFs with VIRTUAL\ngenerated columns.\n\n* Defining a generated column based on other generated columns defined before\nit in the table definition is supported. For example:\n\nCREATE TABLE t1 (a int as (1), b int as (a));\n\n* However, defining a generated column based on other generated columns\ndefined after in the table definition is not supported in expressions for\ngeneration columns because generated columns are calculated in the order they\nare defined.\n\n* Using an expression that exceeds 255 characters in length is supported in\nexpressions for generated columns. The new limit for the entire table\ndefinition, including all expressions for generated columns, is 65,535 bytes.\n\n* Using constant expressions is supported in expressions for generated\ncolumns. For example:\n\nCREATE TABLE t1 (a int as (1));\n\nMaking Stored Values Consistent\n-------------------------------\n\nWhen a generated column is PERSISTENT or indexed, the value of the expression\nneeds to be consistent regardless of the SQL Mode flags in the current\nsession. If it is not, then the table will be seen as corrupted when the value\nthat should actually be returned by the computed expression and the value that\nwas previously stored and/or indexed using a different sql_mode setting\ndisagree.\n\nThere are currently two affected classes of inconsistencies: character padding\nand unsigned subtraction:\n\n* For a VARCHAR or TEXT generated column the length of the value returned can\nvary depending on the PAD_CHAR_TO_FULL_LENGTH sql_mode flag. To make the\nvalue consistent, create the generated column using an RTRIM() or RPAD()\nfunction. Alternately, create the generated column as a CHAR column so that\nits data is always fully padded.\n\n* If a SIGNED generated column is based on the subtraction of an UNSIGNED\nvalue, the resulting value can vary depending on how large the value is and\nthe NO_UNSIGNED_SUBTRACTION sql_mode flag. To make the value consistent, use\nCAST() to ensure that each UNSIGNED operand is SIGNED before the subtraction.\n\nMariaDB starting with 10.5\n--------------------------\nBeginning in MariaDB 10.5, there is a fatal error generated when trying to\ncreate a generated column whose value can change depending on the SQL Mode\nwhen its data is PERSISTENT or indexed.\n\nFor an existing generated column that has a potentially inconsistent value, a\nwarning about a bad expression is generated the first time it is used (if\nwarnings are enabled).\n\nBeginning in MariaDB 10.4.8, MariaDB 10.3.18, and MariaDB 10.2.27 a\npotentially inconsistent generated column outputs a warning when created or\nfirst used (without restricting their creation).\n\nHere is an example of two tables that would be rejected in MariaDB 10.5 and\nwarned about in the other listed versions:\n\nCREATE TABLE bad_pad (\n txt CHAR(5),\n -- CHAR -> VARCHAR or CHAR -> TEXT can\'t be persistent or indexed:\n vtxt VARCHAR(5) AS (txt) PERSISTENT\n);\n\nCREATE TABLE bad_sub (\n num1 BIGINT UNSIGNED,\n num2 BIGINT UNSIGNED,\n -- The resulting value can vary for some large values\n vnum BIGINT AS (num1 - num2) VIRTUAL,\n KEY(vnum)\n);\n\nThe warnings for the above tables look like this:\n\nWarning (Code 1901): Function or expression \'`txt`\' cannot be used in the\nGENERATED ALWAYS AS clause of `vtxt`\nWarning (Code 1105): Expression depends on the @@sql_mode value\nPAD_CHAR_TO_FULL_LENGTH\n\nWarning (Code 1901): Function or expression \'`num1` - `num2`\' cannot be used\nin the GENERATED ALWAYS AS clause of `vnum`\nWarning (Code 1105): Expression depends on the @@sql_mode value\nNO_UNSIGNED_SUBTRACTION\n\nTo work around the issue, force the padding or type to make the generated\ncolumn\'s expression return a consistent value. For example:\n\nCREATE TABLE good_pad (\n txt CHAR(5),\n -- Using RTRIM() or RPAD() makes the value consistent:\n vtxt VARCHAR(5) AS (RTRIM(txt)) PERSISTENT,\n -- When not persistent or indexed, it is OK for the value to vary by mode:\n vtxt2 VARCHAR(5) AS (txt) VIRTUAL,\n -- CHAR -> CHAR is always OK:\n txt2 CHAR(5) AS (txt) PERSISTENT\n);\n\nCREATE TABLE good_sub (\n num1 BIGINT UNSIGNED,\n num2 BIGINT UNSIGNED,\n -- The indexed value will always be consistent in this expression:\n vnum BIGINT AS (CAST(num1 AS SIGNED) - CAST(num2 AS SIGNED)) VIRTUAL,\n KEY(vnum)\n);\n\nMySQL Compatibility Support\n---------------------------\n\n* The STORED keyword is supported as an alias for the PERSISTENT keyword.\n\n* Tables created with MySQL 5.7 or later that contain MySQL\'s generated\ncolumns can be imported into MariaDB without a dump and restore.\n\nImplementation Differences\n--------------------------\n\nGenerated columns are subject to various constraints in other DBMSs that are\nnot present in MariaDB\'s implementation. Generated columns may also be called\ncomputed columns or virtual columns in different implementations. The various\ndetails for a specific implementation can be found in the documentation for\neach specific DBMS.\n\nImplementation Differences Compared to Microsoft SQL Server\n-----------------------------------------------------------\n\nMariaDB\'s generated columns implementation does not enforce the following\nrestrictions that are present in Microsoft SQL Server\'s computed columns\nimplementation:\n\n* MariaDB allows server variables in generated column expressions, including\nthose that change dynamically, such as warning_count.\n* MariaDB allows the CONVERT_TZ() function to be called with a named time zone\nas an argument, even though time zone names and time offsets are configurable.\n* MariaDB allows the CAST() function to be used with non-unicode character\nsets, even though character sets are configurable and differ between\nbinaries/versions.\n* MariaDB allows FLOAT expressions to be used in generated columns. Microsoft\nSQL Server considers these expressions to be \"imprecise\" due to potential\ncross-platform differences in floating-point implementations and precision.\n* Microsoft SQL Server requires the ARITHABORT mode to be set, so that\ndivision by zero returns an error, and not a NULL.\n* Microsoft SQL Server requires QUOTED_IDENTIFIER to be set in sql_mode. In\nMariaDB, if data is inserted without ANSI_QUOTES set in sql_mode, then it will','','https://mariadb.com/kb/en/generated-columns/'); +update help_topic set description = CONCAT(description, '\nbe processed and stored differently in a generated column that contains quoted\nidentifiers.\n\nMicrosoft SQL Server enforces the above restrictions by doing one of the\nfollowing things:\n\n* Refusing to create computed columns.\n* Refusing to allow updates to a table containing them.\n* Refusing to use an index over such a column if it can not be guaranteed that\nthe expression is fully deterministic.\n\nIn MariaDB, as long as the sql_mode, language, and other settings that were in\neffect during the CREATE TABLE remain unchanged, the generated column\nexpression will always be evaluated the same. If any of these things change,\nthen please be aware that the generated column expression might not be\nevaluated the same way as it previously was.\n\nIf you try to update a virtual column, you will get an error if the default\nstrict mode is enabled in sql_mode, or a warning otherwise.\n\nDevelopment History\n-------------------\n\nGenerated columns was originally developed by Andrey Zhakov. It was then\nmodified by Sanja Byelkin and Igor Babaev at Monty Program for inclusion in\nMariaDB. Monty did the work on MariaDB 10.2 to lift a some of the old\nlimitations.\n\nExamples\n--------\n\nHere is an example table that uses both VIRTUAL and PERSISTENT virtual columns:\n\nUSE TEST;\n\nCREATE TABLE table1 (\n a INT NOT NULL,\n b VARCHAR(32),\n c INT AS (a mod 10) VIRTUAL,\n d VARCHAR(5) AS (left(b,5)) PERSISTENT);\n\nIf you describe the table, you can easily see which columns are virtual by\nlooking in the \"Extra\" column:\n\nDESCRIBE table1;\n+-------+-------------+------+-----+---------+------------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+-------------+------+-----+---------+------------+\n| a | int(11) | NO | | NULL | |\n| b | varchar(32) | YES | | NULL | |\n| c | int(11) | YES | | NULL | VIRTUAL |\n| d | varchar(5) | YES | | NULL | PERSISTENT |\n+-------+-------------+------+-----+---------+------------+\n\nTo find out what function(s) generate the value of the virtual column you can\nuse SHOW CREATE TABLE:\n\nSHOW CREATE TABLE table1;\n\n| table1 | CREATE TABLE `table1` (\n `a` int(11) NOT NULL,\n `b` varchar(32) DEFAULT NULL,\n `c` int(11) AS (a mod 10) VIRTUAL,\n `d` varchar(5) AS (left(b,5)) PERSISTENT\n) ENGINE=MyISAM DEFAULT CHARSET=latin1 |\n\nIf you try to insert non-default values into a virtual column, you will\nreceive a warning and what you tried to insert will be ignored and the derived\nvalue inserted instead:\n\nWARNINGS;\nShow warnings enabled.\n\nINSERT INTO table1 VALUES (1, \'some text\',default,default);\nQuery OK, 1 row affected (0.00 sec)\n\nINSERT INTO table1 VALUES (2, \'more text\',5,default);\nQuery OK, 1 row affected, 1 warning (0.00 sec)\n\nWarning (Code 1645): The value specified for computed column \'c\' in table\n\'table1\' has been ignored.\n\nINSERT INTO table1 VALUES (123, \'even more text\',default,\'something\');\nQuery OK, 1 row affected, 2 warnings (0.00 sec)\n\nWarning (Code 1645): The value specified for computed column \'d\' in table\n\'table1\' has been ignored.\nWarning (Code 1265): Data truncated for column \'d\' at row 1\n\nSELECT * FROM table1;\n+-----+----------------+------+-------+\n| a | b | c | d |\n+-----+----------------+------+-------+\n| 1 | some text | 1 | some |\n| 2 | more text | 2 | more |\n| 123 | even more text | 3 | even |\n+-----+----------------+------+-------+\n3 rows in set (0.00 sec)\n\nIf the ZEROFILL clause is specified, it should be placed directly after the\ntype definition, before the AS (<expression>):\n\nCREATE TABLE table2 (a INT, b INT ZEROFILL AS (a*2) VIRTUAL);\nINSERT INTO table2 (a) VALUES (1);\n\nSELECT * FROM table2;\n+------+------------+\n| a | b |\n+------+------------+\n| 1 | 0000000002 |\n+------+------------+\n1 row in set (0.00 sec)\n\nYou can also use virtual columns to implement a \"poor man\'s partial index\".\nSee example at the end of Unique Index.\n\nURL: https://mariadb.com/kb/en/generated-columns/') WHERE help_topic_id = 721; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (722,38,'Invisible Columns','MariaDB starting with 10.3.3\n----------------------------\nInvisible columns (sometimes also called hidden columns) first appeared in\nMariaDB 10.3.3.\n\nColumns can be given an INVISIBLE attribute in a CREATE TABLE or ALTER TABLE\nstatement. These columns will then not be listed in the results of a SELECT *\nstatement, nor do they need to be assigned a value in an INSERT statement,\nunless INSERT explicitly mentions them by name.\n\nSince SELECT * does not return the invisible columns, new tables or views\ncreated in this manner will have no trace of the invisible columns. If\nspecifically referenced in the SELECT statement, the columns will be brought\ninto the view/new table, but the INVISIBLE attribute will not.\n\nInvisible columns can be declared as NOT NULL, but then require a DEFAULT\nvalue.\n\nIt is not possible for all columns in a table to be invisible.\n\nExamples\n--------\n\nCREATE TABLE t (x INT INVISIBLE);\nERROR 1113 (42000): A table must have at least 1 column\n\nCREATE TABLE t (x INT, y INT INVISIBLE, z INT INVISIBLE NOT NULL);\nERROR 4106 (HY000): Invisible column `z` must have a default value\n\nCREATE TABLE t (x INT, y INT INVISIBLE, z INT INVISIBLE NOT NULL DEFAULT 4);\n\nINSERT INTO t VALUES (1),(2);\n\nINSERT INTO t (x,y) VALUES (3,33);\n\nSELECT * FROM t;\n+------+\n| x |\n+------+\n| 1 |\n| 2 |\n| 3 |\n+------+\n\nSELECT x,y,z FROM t;\n+------+------+---+\n| x | y | z |\n+------+------+---+\n| 1 | NULL | 4 |\n| 2 | NULL | 4 |\n| 3 | 33 | 4 |\n+------+------+---+\n\nDESC t;\n+-------+---------+------+-----+---------+-----------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+---------+------+-----+---------+-----------+\n| x | int(11) | YES | | NULL | |\n| y | int(11) | YES | | NULL | INVISIBLE |\n| z | int(11) | NO | | 4 | INVISIBLE |\n+-------+---------+------+-----+---------+-----------+\n\nALTER TABLE t MODIFY x INT INVISIBLE, MODIFY y INT, MODIFY z INT NOT NULL\nDEFAULT 4;\n\nDESC t;\n+-------+---------+------+-----+---------+-----------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+---------+------+-----+---------+-----------+\n| x | int(11) | YES | | NULL | INVISIBLE |\n| y | int(11) | YES | | NULL | |\n| z | int(11) | NO | | 4 | |\n+-------+---------+------+-----+---------+-----------+\n\nCreating a view from a table with hidden columns:\n\nCREATE VIEW v1 AS SELECT * FROM t;\n\nDESC v1;\n+-------+---------+------+-----+---------+-------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+---------+------+-----+---------+-------+\n| y | int(11) | YES | | NULL | |\n| z | int(11) | NO | | 4 | |\n+-------+---------+------+-----+---------+-------+\n\nCREATE VIEW v2 AS SELECT x,y,z FROM t;\n\nDESC v2;\n+-------+---------+------+-----+---------+-------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+---------+------+-----+---------+-------+\n| x | int(11) | YES | | NULL | |\n| y | int(11) | YES | | NULL | |\n| z | int(11) | NO | | 4 | |\n+-------+---------+------+-----+---------+-------+\n\nAdding a Surrogate Primary Key:\n\ncreate table t1 (x bigint unsigned not null, y varchar(16), z text);\n\ninsert into t1 values (123, \'qq11\', \'ipsum\');\n\ninsert into t1 values (123, \'qq22\', \'lorem\');\n\nalter table t1 add pkid serial primary key invisible first;\n\ninsert into t1 values (123, \'qq33\', \'amet\');\n\nselect * from t1;\n+-----+------+-------+\n| x | y | z |\n+-----+------+-------+\n| 123 | qq11 | ipsum |\n| 123 | qq22 | lorem |\n| 123 | qq33 | amet |\n+-----+------+-------+\n\nselect pkid, z from t1;\n+------+-------+\n| pkid | z |\n+------+-------+\n| 1 | ipsum |\n| 2 | lorem |\n| 3 | amet |\n+------+-------+\n\nURL: https://mariadb.com/kb/en/invisible-columns/','','https://mariadb.com/kb/en/invisible-columns/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (723,38,'DROP DATABASE','Syntax\n------\n\nDROP {DATABASE | SCHEMA} [IF EXISTS] db_name\n\nDescription\n-----------\n\nDROP DATABASE drops all tables in the database and deletes the database. Be\nvery careful with this statement! To use DROP DATABASE, you need the DROP\nprivilege on the database. DROP SCHEMA is a synonym for DROP DATABASE.\n\nImportant: When a database is dropped, user privileges on the database are not\nautomatically dropped. See GRANT.\n\nIF EXISTS\n---------\n\nUse IF EXISTS to prevent an error from occurring for databases that do not\nexist. A NOTE is generated for each non-existent database when using IF\nEXISTS. See SHOW WARNINGS.\n\nAtomic DDL\n----------\n\nMariaDB starting with 10.6.1\n----------------------------\nMariaDB 10.6.1 supports Atomic DDL.\n\nDROP DATABASE is implemented as\n\nloop over all tables\n DROP TABLE table\n\nEach individual DROP TABLE is atomic while DROP DATABASE as a whole is\ncrash-safe.\n\nExamples\n--------\n\nDROP DATABASE bufg;\nQuery OK, 0 rows affected (0.39 sec)\n\nDROP DATABASE bufg;\nERROR 1008 (HY000): Can\'t drop database \'bufg\'; database doesn\'t exist\n\n\\W\nShow warnings enabled.\n\nDROP DATABASE IF EXISTS bufg;\nQuery OK, 0 rows affected, 1 warning (0.00 sec)\nNote (Code 1008): Can\'t drop database \'bufg\'; database doesn\'t exist\n\nURL: https://mariadb.com/kb/en/drop-database/','','https://mariadb.com/kb/en/drop-database/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (724,38,'DROP EVENT','Syntax\n------\n\nDROP EVENT [IF EXISTS] event_name\n\nDescription\n-----------\n\nThis statement drops the event named event_name. The event immediately ceases\nbeing active, and is deleted completely from the server.\n\nIf the event does not exist, the error ERROR 1517 (HY000): Unknown event\n\'event_name\' results. You can override this and cause the statement to\ngenerate a NOTE for non-existent events instead by using IF EXISTS. See SHOW\nWARNINGS.\n\nThis statement requires the EVENT privilege. In MySQL 5.1.11 and earlier, an\nevent could be dropped only by its definer, or by a user having the SUPER\nprivilege.\n\nExamples\n--------\n\nDROP EVENT myevent3;\n\nUsing the IF EXISTS clause:\n\nDROP EVENT IF EXISTS myevent3;\nQuery OK, 0 rows affected, 1 warning (0.01 sec)\n\nSHOW WARNINGS;\n+-------+------+-------------------------------+\n| Level | Code | Message |\n+-------+------+-------------------------------+\n| Note | 1305 | Event myevent3 does not exist |\n+-------+------+-------------------------------+\n\nURL: https://mariadb.com/kb/en/drop-event/','','https://mariadb.com/kb/en/drop-event/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (725,38,'DROP FUNCTION','Syntax\n------\n\nDROP FUNCTION [IF EXISTS] f_name\n\nDescription\n-----------\n\nThe DROP FUNCTION statement is used to drop a stored function or a\nuser-defined function (UDF). That is, the specified routine is removed from\nthe server, along with all privileges specific to the function. You must have\nthe ALTER ROUTINE privilege for the routine in order to drop it. If the\nautomatic_sp_privileges server system variable is set, both the ALTER ROUTINE\nand EXECUTE privileges are granted automatically to the routine creator - see\nStored Routine Privileges.\n\nIF EXISTS\n---------\n\nThe IF EXISTS clause is a MySQL/MariaDB extension. It prevents an error from\noccurring if the function does not exist. A NOTE is produced that can be\nviewed with SHOW WARNINGS.\n\nFor dropping a user-defined functions (UDF), see DROP FUNCTION UDF.\n\nExamples\n--------\n\nDROP FUNCTION hello;\nQuery OK, 0 rows affected (0.042 sec)\n\nDROP FUNCTION hello;\nERROR 1305 (42000): FUNCTION test.hello does not exist\n\nDROP FUNCTION IF EXISTS hello;\nQuery OK, 0 rows affected, 1 warning (0.000 sec)\n\nSHOW WARNINGS;\n+-------+------+------------------------------------+\n| Level | Code | Message |\n+-------+------+------------------------------------+\n| Note | 1305 | FUNCTION test.hello does not exist |\n+-------+------+------------------------------------+\n\nURL: https://mariadb.com/kb/en/drop-function/','','https://mariadb.com/kb/en/drop-function/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (726,38,'DROP INDEX','Syntax\n------\n\nDROP INDEX [IF EXISTS] index_name ON tbl_name \n [WAIT n |NOWAIT]\n\nDescription\n-----------\n\nDROP INDEX drops the index named index_name from the table tbl_name. This\nstatement is mapped to an ALTER TABLE statement to drop the index.\n\nIf another connection is using the table, a metadata lock is active, and this\nstatement will wait until the lock is released. This is also true for\nnon-transactional tables.\n\nSee ALTER TABLE.\n\nAnother shortcut, CREATE INDEX, allows the creation of an index.\n\nTo remove the primary key, `PRIMARY` must be specified as index_name. Note\nthat the quotes are necessary, because PRIMARY is a keyword.\n\nPrivileges\n----------\n\nExecuting the DROP INDEX statement requires the INDEX privilege for the table\nor the database.\n\nOnline DDL\n----------\n\nOnline DDL is used by default with InnoDB, when the drop index operation\nsupports it.\n\nSee InnoDB Online DDL Overview for more information on online DDL with InnoDB.\n\nDROP INDEX IF EXISTS ...\n------------------------\n\nIf the IF EXISTS clause is used, then MariaDB will return a warning instead of\nan error if the index does not exist.\n\nWAIT/NOWAIT\n-----------\n\nSets the lock wait timeout. See WAIT and NOWAIT.\n\nProgress Reporting\n------------------\n\nMariaDB provides progress reporting for DROP INDEX statement for clients that\nsupport the new progress reporting protocol. For example, if you were using\nthe mariadb client, then the progress report might look like this::\n\nURL: https://mariadb.com/kb/en/drop-index/','','https://mariadb.com/kb/en/drop-index/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (727,38,'DROP PACKAGE','MariaDB starting with 10.3.5\n----------------------------\nOracle-style packages were introduced in MariaDB 10.3.5.\n\nSyntax\n------\n\nDROP PACKAGE [IF EXISTS] [ db_name . ] package_name\n\nDescription\n-----------\n\nThe DROP PACKAGE statement can be used when Oracle SQL_MODE is set.\n\nThe DROP PACKAGE statement drops a stored package entirely:\n\n* Drops the package specification (earlier created using the CREATE PACKAGE\nstatement).\n* Drops the package implementation, if the implementation was already created\nusing the CREATE PACKAGE BODY statement.\n\nURL: https://mariadb.com/kb/en/drop-package/','','https://mariadb.com/kb/en/drop-package/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (728,38,'DROP PACKAGE BODY','MariaDB starting with 10.3.5\n----------------------------\nOracle-style packages were introduced in MariaDB 10.3.5.\n\nSyntax\n------\n\nDROP PACKAGE BODY [IF EXISTS] [ db_name . ] package_name\n\nDescription\n-----------\n\nThe DROP PACKAGE BODY statement can be used when Oracle SQL_MODE is set.\n\nThe DROP PACKAGE BODY statement drops the package body (i.e the\nimplementation), previously created using the CREATE PACKAGE BODY statement.\n\nNote, DROP PACKAGE BODY drops only the package implementation, but does not\ndrop the package specification. Use DROP PACKAGE to drop the package entirely\n(i.e. both implementation and specification).\n\nURL: https://mariadb.com/kb/en/drop-package-body/','','https://mariadb.com/kb/en/drop-package-body/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (729,38,'DROP PROCEDURE','Syntax\n------\n\nDROP PROCEDURE [IF EXISTS] sp_name\n\nDescription\n-----------\n\nThis statement is used to drop a stored procedure. That is, the specified\nroutine is removed from the server along with all privileges specific to the\nprocedure. You must have the ALTER ROUTINE privilege for the routine. If the\nautomatic_sp_privileges server system variable is set, that privilege and\nEXECUTE are granted automatically to the routine creator - see Stored Routine\nPrivileges.\n\nThe IF EXISTS clause is a MySQL/MariaDB extension. It prevents an error from\noccurring if the procedure or function does not exist. A NOTE is produced that\ncan be viewed with SHOW WARNINGS.\n\nWhile this statement takes effect immediately, threads which are executing a\nprocedure can continue execution.\n\nExamples\n--------\n\nDROP PROCEDURE simpleproc;\n\nIF EXISTS:\n\nDROP PROCEDURE simpleproc;\nERROR 1305 (42000): PROCEDURE test.simpleproc does not exist\n\nDROP PROCEDURE IF EXISTS simpleproc;\nQuery OK, 0 rows affected, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+-------+------+------------------------------------------+\n| Level | Code | Message |\n+-------+------+------------------------------------------+\n| Note | 1305 | PROCEDURE test.simpleproc does not exist |\n+-------+------+------------------------------------------+\n\nURL: https://mariadb.com/kb/en/drop-procedure/','','https://mariadb.com/kb/en/drop-procedure/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (730,38,'DROP SERVER','Syntax\n------\n\nDROP SERVER [ IF EXISTS ] server_name\n\nDescription\n-----------\n\nDrops the server definition for the server named server_name. The\ncorresponding row within the mysql.servers table will be deleted. This\nstatement requires the SUPER privilege or, from MariaDB 10.5.2, the FEDERATED\nADMIN privilege.\n\nDropping a server for a table does not affect any FederatedX, FEDERATED,\nConnect or Spider tables that used this connection information when they were\ncreated.\n\nDROP SERVER is not written to the binary log, irrespective of the binary log\nformat being used. From MariaDB 10.1.13, Galera replicates the CREATE SERVER,\nALTER SERVER and DROP SERVER statements.\n\nIF EXISTS\n---------\n\nIf the IF EXISTS clause is used, MariaDB will not return an error if the\nserver does not exist. Unlike all other statements, DROP SERVER IF EXISTS does\nnot issue a note if the server does not exist. See MDEV-9400.\n\nExamples\n--------\n\nDROP SERVER s;\n\nIF EXISTS:\n\nDROP SERVER s;\nERROR 1477 (HY000): The foreign server name you are trying to reference \n does not exist. Data source error: s\n\nDROP SERVER IF EXISTS s;\nQuery OK, 0 rows affected (0.00 sec)\n\nURL: https://mariadb.com/kb/en/drop-server/','','https://mariadb.com/kb/en/drop-server/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (731,38,'DROP TABLESPACE','The DROP TABLESPACE statement is not supported by MariaDB. It was originally\ninherited from MySQL NDB Cluster. In MySQL 5.7 and later, the statement is\nalso supported for InnoDB. However, MariaDB has chosen not to include that\nspecific feature. See MDEV-19294 for more information.\n\nURL: https://mariadb.com/kb/en/drop-tablespace/','','https://mariadb.com/kb/en/drop-tablespace/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (732,38,'DROP TRIGGER','Syntax\n------\n\nDROP TRIGGER [IF EXISTS] [schema_name.]trigger_name\n\nDescription\n-----------\n\nThis statement drops a trigger. The schema (database) name is optional. If the\nschema is omitted, the trigger is dropped from the default schema. Its use\nrequires the TRIGGER privilege for the table associated with the trigger.\n\nUse IF EXISTS to prevent an error from occurring for a trigger that does not\nexist. A NOTE is generated for a non-existent trigger when using IF EXISTS.\nSee SHOW WARNINGS.\n\nNote: Triggers for a table are also dropped if you drop the table.\n\nAtomic DDL\n----------\n\nMariaDB starting with 10.6.1\n----------------------------\nMariaDB 10.6.1 supports Atomic DDL and DROP TRIGGER is atomic.\n\nExamples\n--------\n\nDROP TRIGGER test.example_trigger;\n\nUsing the IF EXISTS clause:\n\nDROP TRIGGER IF EXISTS test.example_trigger;\nQuery OK, 0 rows affected, 1 warning (0.01 sec)\n\nSHOW WARNINGS;\n+-------+------+------------------------+\n| Level | Code | Message |\n+-------+------+------------------------+\n| Note | 1360 | Trigger does not exist |\n+-------+------+------------------------+\n\nURL: https://mariadb.com/kb/en/drop-trigger/','','https://mariadb.com/kb/en/drop-trigger/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (733,38,'DROP VIEW','Syntax\n------\n\nDROP VIEW [IF EXISTS]\n view_name [, view_name] ...\n [RESTRICT | CASCADE]\n\nDescription\n-----------\n\nDROP VIEW removes one or more views. You must have the DROP privilege for each\nview. If any of the views named in the argument list do not exist, MariaDB\nreturns an error indicating by name which non-existing views it was unable to\ndrop, but it also drops all of the views in the list that do exist.\n\nThe IF EXISTS clause prevents an error from occurring for views that don\'t\nexist. When this clause is given, a NOTE is generated for each non-existent\nview. See SHOW WARNINGS.\n\nRESTRICT and CASCADE, if given, are parsed and ignored.\n\nIt is possible to specify view names as db_name.view_name. This is useful to\ndelete views from multiple databases with one statement. See Identifier\nQualifiers for details.\n\nThe DROP privilege is required to use DROP TABLE on non-temporary tables. For\ntemporary tables, no privilege is required, because such tables are only\nvisible for the current session.\n\nIf a view references another view, it will be possible to drop the referenced\nview. However, the other view will reference a view which does not exist any\nmore. Thus, querying it will produce an error similar to the following:\n\nERROR 1356 (HY000): View \'db_name.view_name\' references invalid table(s) or \ncolumn(s) or function(s) or definer/invoker of view lack rights to use them\n\nThis problem is reported in the output of CHECK TABLE.\n\nNote that it is not necessary to use DROP VIEW to replace an existing view,\nbecause CREATE VIEW has an OR REPLACE clause.\n\nAtomic DDL\n----------\n\nMariaDB starting with 10.6.1\n----------------------------\nMariaDB 10.6.1 supports Atomic DDL and DROP VIEW for a singular view is\natomic. Dropping multiple views is crash-safe.\n\nExamples\n--------\n\nDROP VIEW v,v2;\n\nGiven views v and v2, but no view v3\n\nDROP VIEW v,v2,v3;\nERROR 1051 (42S02): Unknown table \'v3\'\n\nDROP VIEW IF EXISTS v,v2,v3;\nQuery OK, 0 rows affected, 1 warning (0.01 sec)\n\nSHOW WARNINGS;\n+-------+------+-------------------------+\n| Level | Code | Message |\n+-------+------+-------------------------+\n| Note | 1051 | Unknown table \'test.v3\' |\n+-------+------+-------------------------+\n\nURL: https://mariadb.com/kb/en/drop-view/','','https://mariadb.com/kb/en/drop-view/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (734,38,'CONSTRAINT','MariaDB supports the implementation of constraints at the table-level using\neither CREATE TABLE or ALTER TABLE statements. A table constraint restricts\nthe data you can add to the table. If you attempt to insert invalid data on a\ncolumn, MariaDB throws an error.\n\nSyntax\n------\n\n[CONSTRAINT [symbol]] constraint_expression\n\nconstraint_expression:\n | PRIMARY KEY [index_type] (index_col_name, ...) [index_option] ...\n | FOREIGN KEY [index_name] (index_col_name, ...)\n REFERENCES tbl_name (index_col_name, ...)\n [ON DELETE reference_option]\n [ON UPDATE reference_option]\n | UNIQUE [INDEX|KEY] [index_name]\n [index_type] (index_col_name, ...) [index_option] ...\n | CHECK (check_constraints)\n\nindex_type:\n USING {BTREE | HASH | RTREE}\n\nindex_col_name:\n col_name [(length)] [ASC | DESC]\n\nindex_option:\n | KEY_BLOCK_SIZE [=] value\n | index_type\n | WITH PARSER parser_name\n | COMMENT \'string\'\n | CLUSTERING={YES|NO}\n\nreference_option:\n RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT\n\nDescription\n-----------\n\nConstraints provide restrictions on the data you can add to a table. This\nallows you to enforce data integrity from MariaDB, rather than through\napplication logic. When a statement violates a constraint, MariaDB throws an\nerror.\n\nThere are four types of table constraints:\n\n+------------------------------------+---------------------------------------+\n| Constraint | Description |\n+------------------------------------+---------------------------------------+\n| PRIMARY KEY | Sets the column for referencing |\n| | rows. Values must be unique and not |\n| | null. |\n+------------------------------------+---------------------------------------+\n| FOREIGN KEY | Sets the column to reference the |\n| | primary key on another table. |\n+------------------------------------+---------------------------------------+\n| UNIQUE | Requires values in column or columns |\n| | only occur once in the table. |\n+------------------------------------+---------------------------------------+\n| CHECK | Checks whether the data meets the |\n| | given condition. |\n+------------------------------------+---------------------------------------+\n\nThe Information Schema TABLE_CONSTRAINTS Table contains information about\ntables that have constraints.\n\nFOREIGN KEY Constraints\n-----------------------\n\nInnoDB supports foreign key constraints. The syntax for a foreign key\nconstraint definition in InnoDB looks like this:\n\n[CONSTRAINT [symbol]] FOREIGN KEY\n [index_name] (index_col_name, ...)\n REFERENCES tbl_name (index_col_name,...)\n [ON DELETE reference_option]\n [ON UPDATE reference_option]\n\nreference_option:\n RESTRICT | CASCADE | SET NULL | NO ACTION\n\nThe Information Schema REFERENTIAL_CONSTRAINTS table has more information\nabout foreign keys.\n\nCHECK Constraints\n-----------------\n\nConstraints are enforced. Before MariaDB 10.2.1 constraint expressions were\naccepted in the syntax but ignored.\n\nYou can define constraints in 2 different ways:\n\n* CHECK(expression) given as part of a column definition.\n* CONSTRAINT [constraint_name] CHECK (expression)\n\nBefore a row is inserted or updated, all constraints are evaluated in the\norder they are defined. If any constraint expression returns false, then the\nrow will not be inserted or updated. One can use most deterministic functions\nin a constraint, including UDFs.\n\nCREATE TABLE t1 (a INT CHECK (a>2), b INT CHECK (b>2), CONSTRAINT a_greater\nCHECK (a>b));\n\nIf you use the second format and you don\'t give a name to the constraint, then\nthe constraint will get an automatically generated name. This is done so that\nyou can later delete the constraint with ALTER TABLE DROP constraint_name.\n\nOne can disable all constraint expression checks by setting the\ncheck_constraint_checks variable to OFF. This is useful for example when\nloading a table that violates some constraints that you want to later find and\nfix in SQL.\n\nReplication\n-----------\n\nIn row-based replication, only the master checks constraints, and failed\nstatements will not be replicated. In statement-based replication, the slaves\nwill also check constraints. Constraints should therefore be identical, as\nwell as deterministic, in a replication environment.\n\nAuto_increment\n--------------\n\nauto_increment columns are not permitted in check constraints. Before MariaDB\n10.2.6, they were permitted, but would not work correctly. See MDEV-11117.\n\nExamples\n--------\n\nCREATE TABLE product (category INT NOT NULL, id INT NOT NULL,\n price DECIMAL,\n PRIMARY KEY(category, id)) ENGINE=INNODB;\nCREATE TABLE customer (id INT NOT NULL,\n PRIMARY KEY (id)) ENGINE=INNODB;\nCREATE TABLE product_order (no INT NOT NULL AUTO_INCREMENT,\n product_category INT NOT NULL,\n product_id INT NOT NULL,\n customer_id INT NOT NULL,\n PRIMARY KEY(no),\n INDEX (product_category, product_id),\n FOREIGN KEY (product_category, product_id)\n REFERENCES product(category, id)\n ON UPDATE CASCADE ON DELETE RESTRICT,\n INDEX (customer_id),\n FOREIGN KEY (customer_id)\n REFERENCES customer(id)) ENGINE=INNODB;\n\nThe following examples will work from MariaDB 10.2.1 onwards.\n\nNumeric constraints and comparisons:\n\nCREATE TABLE t1 (a INT CHECK (a>2), b INT CHECK (b>2), CONSTRAINT a_greater\nCHECK (a>b));\n\nINSERT INTO t1(a) VALUES (1);\nERROR 4022 (23000): CONSTRAINT `a` failed for `test`.`t1`\n\nINSERT INTO t1(a,b) VALUES (3,4);\nERROR 4022 (23000): CONSTRAINT `a_greater` failed for `test`.`t1`\n\nINSERT INTO t1(a,b) VALUES (4,3);\nQuery OK, 1 row affected (0.04 sec)\n\nDropping a constraint:\n\nALTER TABLE t1 DROP CONSTRAINT a_greater;\n\nAdding a constraint:\n\nALTER TABLE t1 ADD CONSTRAINT a_greater CHECK (a>b);\n\nDate comparisons and character length:\n\nCREATE TABLE t2 (name VARCHAR(30) CHECK (CHAR_LENGTH(name)>2), start_date\nDATE, \n end_date DATE CHECK (start_date IS NULL OR end_date IS NULL OR\nstart_date<end_date));\n\nINSERT INTO t2(name, start_date, end_date) VALUES(\'Ione\', \'2003-12-15\',\n\'2014-11-09\');\nQuery OK, 1 row affected (0.04 sec)\n\nINSERT INTO t2(name, start_date, end_date) VALUES(\'Io\', \'2003-12-15\',\n\'2014-11-09\');\nERROR 4022 (23000): CONSTRAINT `name` failed for `test`.`t2`\n\nINSERT INTO t2(name, start_date, end_date) VALUES(\'Ione\', NULL, \'2014-11-09\');\nQuery OK, 1 row affected (0.04 sec)\n\nINSERT INTO t2(name, start_date, end_date) VALUES(\'Ione\', \'2015-12-15\',\n\'2014-11-09\');\nERROR 4022 (23000): CONSTRAINT `end_date` failed for `test`.`t2`\n\nA misplaced parenthesis:\n\nCREATE TABLE t3 (name VARCHAR(30) CHECK (CHAR_LENGTH(name>2)), start_date\nDATE, \n end_date DATE CHECK (start_date IS NULL OR end_date IS NULL OR\nstart_date<end_date));\nQuery OK, 0 rows affected (0.32 sec)\n\nINSERT INTO t3(name, start_date, end_date) VALUES(\'Io\', \'2003-12-15\',\n\'2014-11-09\');\nQuery OK, 1 row affected, 1 warning (0.04 sec)\n\nSHOW WARNINGS;\n+---------+------+----------------------------------------+\n| Level | Code | Message |\n+---------+------+----------------------------------------+\n| Warning | 1292 | Truncated incorrect DOUBLE value: \'Io\' |\n+---------+------+----------------------------------------+\n\nCompare the definition of table t2 to table t3. CHAR_LENGTH(name)>2 is very\ndifferent to CHAR_LENGTH(name>2) as the latter mistakenly performs a numeric\ncomparison on the name field, leading to unexpected results.\n\nURL: https://mariadb.com/kb/en/constraint/','','https://mariadb.com/kb/en/constraint/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (735,38,'Dynamic Columns','Dynamic columns allow one to store different sets of columns for each row in a\ntable. It works by storing a set of columns in a blob and having a small set\nof functions to manipulate it. Dynamic columns should be used when it is not\npossible to use regular columns. A typical use case is when one needs to store\nitems that may have many different attributes (like size, color, weight, etc),\nand the set of possible attributes is very large and/or unknown in advance. In\nthat case, attributes can be put into dynamic columns.\n\nDynamic Columns Basics\n----------------------\n\nThe table should have a blob column which will be used as storage for dynamic\ncolumns:\n\ncreate table assets (\n item_name varchar(32) primary key, -- A common attribute for all items\n dynamic_cols blob -- Dynamic columns will be stored here\n);\n\nOnce created, one can access dynamic columns via dynamic column functions:\n\nInsert a row with two dynamic columns: color=blue, size=XL\n\nINSERT INTO assets VALUES \n (\'MariaDB T-shirt\', COLUMN_CREATE(\'color\', \'blue\', \'size\', \'XL\'));\n\nInsert another row with dynamic columns: color=black, price=500\n\nINSERT INTO assets VALUES\n (\'Thinkpad Laptop\', COLUMN_CREATE(\'color\', \'black\', \'price\', 500));\n\nSelect dynamic column \'color\' for all items:\n\nSELECT item_name, COLUMN_GET(dynamic_cols, \'color\' as char) \n AS color FROM assets;\n+-----------------+-------+\n| item_name | color |\n+-----------------+-------+\n| MariaDB T-shirt | blue |\n| Thinkpad Laptop | black |\n+-----------------+-------+\n\nIt is possible to add and remove dynamic columns from a row:\n\n-- Remove a column:\nUPDATE assets SET dynamic_cols=COLUMN_DELETE(dynamic_cols, \"price\") \nWHERE COLUMN_GET(dynamic_cols, \'color\' as char)=\'black\';\n\n-- Add a column:\nUPDATE assets SET dynamic_cols=COLUMN_ADD(dynamic_cols, \'warranty\', \'3 years\')\nWHERE item_name=\'Thinkpad Laptop\';\n\nYou can also list all columns, or get them together with their values in JSON\nformat:\n\nSELECT item_name, column_list(dynamic_cols) FROM assets;\n+-----------------+---------------------------+\n| item_name | column_list(dynamic_cols) |\n+-----------------+---------------------------+\n| MariaDB T-shirt | `size`,`color` |\n| Thinkpad Laptop | `color`,`warranty` |\n+-----------------+---------------------------+\n\nSELECT item_name, COLUMN_JSON(dynamic_cols) FROM assets;\n+-----------------+----------------------------------------+\n| item_name | COLUMN_JSON(dynamic_cols) |\n+-----------------+----------------------------------------+\n| MariaDB T-shirt | {\"size\":\"XL\",\"color\":\"blue\"} |\n| Thinkpad Laptop | {\"color\":\"black\",\"warranty\":\"3 years\"} |\n+-----------------+----------------------------------------+\n\nDynamic Columns Reference\n-------------------------\n\nThe rest of this page is a complete reference of dynamic columns in MariaDB\n\nDynamic Columns Functions\n-------------------------\n\nCOLUMN_CREATE\n-------------\n\nCOLUMN_CREATE(column_nr, value [as type], [column_nr, value \n [as type]]...);\nCOLUMN_CREATE(column_name, value [as type], [column_name, value \n [as type]]...);\n\nReturn a dynamic columns blob that stores the specified columns with values.\n\nThe return value is suitable for\n\n* \nstoring in a table\nfurther modification with other dynamic columns functions\n\nThe as type part allows one to specify the value type. In most cases, this is\nredundant because MariaDB will be able to deduce the type of the value.\nExplicit type specification may be needed when the type of the value is not\napparent. For example, a literal \'2012-12-01\' has a CHAR type by default, one\nwill need to specify \'2012-12-01\' AS DATE to have it stored as a date. See the\nDatatypes section for further details. Note also MDEV-597.\n\nTypical usage:\n\n-- MariaDB 5.3+:\nINSERT INTO tbl SET dyncol_blob=COLUMN_CREATE(1 /*column id*/, \"value\");\n-- MariaDB 10.0.1+:\nINSERT INTO tbl SET dyncol_blob=COLUMN_CREATE(\"column_name\", \"value\");\n\nCOLUMN_ADD\n----------\n\nCOLUMN_ADD(dyncol_blob, column_nr, value [as type], \n [column_nr, value [as type]]...);\nCOLUMN_ADD(dyncol_blob, column_name, value [as type], \n [column_name, value [as type]]...);\n\nAdds or updates dynamic columns.\n\n* \ndyncol_blob must be either a valid dynamic columns blob (for example,\nCOLUMN_CREATE returns such blob), or an empty string.\ncolumn_name specifies the name of the column to be added. If dyncol_blob\nalready has a column with this name, it will be overwritten.\nvalue specifies the new value for the column. Passing a NULL value will cause\nthe column to be deleted.\nas type is optional. See #datatypes section for a discussion about types.\n\nThe return value is a dynamic column blob after the modifications.\n\nTypical usage:\n\n-- MariaDB 5.3+:\nUPDATE tbl SET dyncol_blob=COLUMN_ADD(dyncol_blob, 1 /*column id*/, \"value\") \n WHERE id=1;\n-- MariaDB 10.0.1+:\nUPDATE t1 SET dyncol_blob=COLUMN_ADD(dyncol_blob, \"column_name\", \"value\") \n WHERE id=1;\n\nNote: COLUMN_ADD() is a regular function (just like CONCAT()), hence, in order\nto update the value in the table you have to use the UPDATE ... SET\ndynamic_col=COLUMN_ADD(dynamic_col, ....) pattern.\n\nCOLUMN_GET\n----------\n\nCOLUMN_GET(dyncol_blob, column_nr as type);\nCOLUMN_GET(dyncol_blob, column_name as type);\n\nGet the value of a dynamic column by its name. If no column with the given\nname exists, NULL will be returned.\n\ncolumn_name as type requires that one specify the datatype of the dynamic\ncolumn they are reading.\n\nThis may seem counter-intuitive: why would one need to specify which datatype\nthey\'re retrieving? Can\'t the dynamic columns system figure the datatype from\nthe data being stored?\n\nThe answer is: SQL is a statically-typed language. The SQL interpreter needs\nto know the datatypes of all expressions before the query is run (for example,\nwhen one is using prepared statements and runs \"select COLUMN_GET(...)\", the\nprepared statement API requires the server to inform the client about the\ndatatype of the column being read before the query is executed and the server\ncan see what datatype the column actually has).\n\nSee the Datatypes section for more information about datatypes.\n\nCOLUMN_DELETE\n-------------\n\nCOLUMN_DELETE(dyncol_blob, column_nr, column_nr...);\nCOLUMN_DELETE(dyncol_blob, column_name, column_name...);\n\nDelete a dynamic column with the specified name. Multiple names can be given.\n\nThe return value is a dynamic column blob after the modification.\n\nCOLUMN_EXISTS\n-------------\n\nCOLUMN_EXISTS(dyncol_blob, column_nr);\nCOLUMN_EXISTS(dyncol_blob, column_name);\n\nCheck if a column with name column_name exists in dyncol_blob. If yes, return\n1, otherwise return 0.\n\nCOLUMN_LIST\n-----------\n\nCOLUMN_LIST(dyncol_blob);\n\nReturn a comma-separated list of column names. The names are quoted with\nbackticks.\n\nSELECT column_list(column_create(\'col1\',\'val1\',\'col2\',\'val2\'));\n+---------------------------------------------------------+\n| column_list(column_create(\'col1\',\'val1\',\'col2\',\'val2\')) |\n+---------------------------------------------------------+\n| `col1`,`col2` |\n+---------------------------------------------------------+\n\nCOLUMN_CHECK\n------------\n\nCOLUMN_CHECK(dyncol_blob);\n\nCheck if dyncol_blob is a valid packed dynamic columns blob. Return value of 1\nmeans the blob is valid, return value of 0 means it is not.\n\nRationale: Normally, one works with valid dynamic column blobs. Functions like\nCOLUMN_CREATE, COLUMN_ADD, COLUMN_DELETE always return valid dynamic column\nblobs. However, if a dynamic column blob is accidentally truncated, or\ntranscoded from one character set to another, it will be corrupted. This\nfunction can be used to check if a value in a blob field is a valid dynamic\ncolumn blob.\n\nNote: It is possible that a truncation cut a Dynamic Column \"clearly\" so that\nCOLUMN_CHECK will not notice the corruption, but in any case of truncation a\nwarning is issued during value storing.\n\nCOLUMN_JSON\n-----------\n\nCOLUMN_JSON(dyncol_blob);\n\nReturn a JSON representation of data in dyncol_blob.\n\nExample:\n\nSELECT item_name, COLUMN_JSON(dynamic_cols) FROM assets;\n+-----------------+----------------------------------------+\n| item_name | COLUMN_JSON(dynamic_cols) |\n+-----------------+----------------------------------------+\n| MariaDB T-shirt | {\"size\":\"XL\",\"color\":\"blue\"} |\n| Thinkpad Laptop | {\"color\":\"black\",\"warranty\":\"3 years\"} |\n+-----------------+----------------------------------------+\n\nLimitation: COLUMN_JSON will decode nested dynamic columns at a nesting level\nof not more than 10 levels deep. Dynamic columns that are nested deeper than\n10 levels will be shown as BINARY string, without encoding.\n\nNesting Dynamic Columns\n-----------------------\n\nIt is possible to use nested dynamic columns by putting one dynamic column\nblob inside another. The COLUMN_JSON function will display nested columns.\n\nSET @tmp= column_create(\'parent_column\', \n column_create(\'child_column\', 12345));\nQuery OK, 0 rows affected (0.00 sec)\n\nSELECT column_json(@tmp);\n+------------------------------------------+\n| column_json(@tmp) |\n+------------------------------------------+\n| {\"parent_column\":{\"child_column\":12345}} |\n+------------------------------------------+\n\nSELECT column_get(column_get(@tmp, \'parent_column\' AS char), \n \'child_column\' AS int);\n+------------------------------------------------------------------------------\n\n| column_get(column_get(@tmp, \'parent_column\' as char), \'child_column\' as int)\n|\n+------------------------------------------------------------------------------\n\n| 12345\n|\n+------------------------------------------------------------------------------\n\nIf you are trying to get a nested dynamic column as a string use \'as BINARY\'\nas the last argument of COLUMN_GET (otherwise problems with character set\nconversion and illegal symbols are possible):\n\nselect column_json( column_get(\n column_create(\'test1\',\n column_create(\'key1\',\'value1\',\'key2\',\'value2\',\'key3\',\'value3\')),\n \'test1\' as BINARY));\n\nDatatypes\n---------\n\nIn SQL, one needs to define the type of each column in a table. Dynamic\ncolumns do not provide any way to declare a type in advance (\"whenever there\nis a column \'weight\', it should be integer\" is not possible). However, each\nparticular dynamic column value is stored together with its datatype.\n\nThe set of possible datatypes is mostly the same as that used by the SQL CAST\nand CONVERT functions. However, note that there are currently some differences\n- see MDEV-597.\n\n+--------+----------------------------------------------+-------------------+\n| type | dynamic column internal type | description |\n+--------+----------------------------------------------+-------------------+\n| BINARY | DYN_COL_STRING | (variable length |\n| (N)] | | string with |\n| | | binary charset) |\n+--------+----------------------------------------------+-------------------+\n| CHAR[( | DYN_COL_STRING | (variable length |\n| )] | | string with |\n| | | charset) |\n+--------+----------------------------------------------+-------------------+\n| DATE | DYN_COL_DATE | (date - 3 bytes) |\n+--------+----------------------------------------------+-------------------+\n| DATETI | DYN_COL_DATETIME | (date and time |\n| E[(D)] | | (with |\n| | | microseconds) - |\n| | | 9 bytes) |\n+--------+----------------------------------------------+-------------------+\n| DECIMA | DYN_COL_DECIMAL | (variable length |\n| [(M[,D | | binary decimal |\n| )] | | representation |\n| | | with MariaDB |\n| | | limitation) |\n+--------+----------------------------------------------+-------------------+\n| DOUBLE | DYN_COL_DOUBLE | (64 bit |\n| (M,D)] | | double-precision |\n| | | floating point) |\n+--------+----------------------------------------------+-------------------+\n| INTEGE | DYN_COL_INT | (variable |\n| | | length, up to 64 |\n| | | bit signed |\n| | | integer) |\n+--------+----------------------------------------------+-------------------+\n| SIGNED | DYN_COL_INT | (variable |\n| [INTEG | | length, up to 64 |\n| R] | | bit signed |\n| | | integer) |\n+--------+----------------------------------------------+-------------------+\n| TIME[( | DYN_COL_TIME | (time (with |\n| )] | | microseconds, |\n| | | may be negative) |\n| | | - 6 bytes) |\n+--------+----------------------------------------------+-------------------+\n| UNSIGN | DYN_COL_UINT | (variable |\n| D | | length, up to |','','https://mariadb.com/kb/en/dynamic-columns/'); +update help_topic set description = CONCAT(description, '\n| [INTEG | | 64bit unsigned |\n| R] | | integer) |\n+--------+----------------------------------------------+-------------------+\n\nA Note About Lengths\n--------------------\n\nIf you\'re running queries like\n\nSELECT COLUMN_GET(blob, \'colname\' as CHAR) ...\n\nwithout specifying a maximum length (i.e. using #as CHAR#, not as CHAR(n)),\nMariaDB will report the maximum length of the resultset column to be\n53,6870,911 (bytes or characters?) for MariaDB 5.3-10.0.0 and 16,777,216 for\nMariaDB 10.0.1+. This may cause excessive memory usage in some client\nlibraries, because they try to pre-allocate a buffer of maximum resultset\nwidth. If you suspect you\'re hitting this problem, use CHAR(n) whenever you\'re\nusing COLUMN_GET in the select list.\n\nMariaDB 5.3 vs MariaDB 10.0\n---------------------------\n\nThe dynamic columns feature was introduced into MariaDB in two steps:\n\n* MariaDB 5.3 was the first version to support dynamic columns. Only numbers\n could be used as column names in this version.\n* In MariaDB 10.0.1, column names can be either numbers or strings.\n Also, the COLUMN_JSON and COLUMN_CHECK functions were added.\n\nSee also Dynamic Columns in MariaDB 10.\n\nClient-side API\n---------------\n\nIt is also possible to create or parse dynamic columns blobs on the client\nside. libmysql client library now includes an API for writing/reading dynamic\ncolumn blobs. See dynamic-columns-api for details.\n\nLimitations\n-----------\n\n+---------------------------------------------------+------------------------+\n| Description | Limit |\n+---------------------------------------------------+------------------------+\n| Max number of columns | 65535 |\n+---------------------------------------------------+------------------------+\n| Max total length of packed dynamic column | max_allowed_packet |\n| | (1G) |\n+---------------------------------------------------+------------------------+\n\nURL: https://mariadb.com/kb/en/dynamic-columns/') WHERE help_topic_id = 735; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (736,38,'Dynamic Columns from MariaDB 10','MariaDB starting with 10.0.1\n----------------------------\nMariaDB 10.0.1 introduced the following improvements to the dynamic columns\nfeature.\n\nColumn Name Support\n-------------------\n\nIt is possible to refer to column by names. Names can be used everywhere where\nin MariaDB 5.3 one could use only strings:\n\n* Create a dynamic column blob:\n\nCOLUMN_CREATE(\'int_col\', 123 as int, \'double_col\', 3.14 as double,\n\'string_col\', \'text-data\' as char);\n\n* Set a column value:\n\nCOLUMN_ADD(dyncol_blob, \'intcol\', 1234);\n\n* Get a column value:\n\nCOLUMN_GET(dynstr, \'column1\' as char(10));\n\n* Check whether a column exists\n\nCOLUMN_EXISTS(dyncol_blob, \'column_name\');\n\nChanges in Behavior\n-------------------\n\n* Column list output now includes quoting:\n\nselect column_list(column_create(1, 22, 2, 23));\n+------------------------------------------+\n| column_list(column_create(1, 22, 2, 23)) |\n+------------------------------------------+\n| `1`,`2` |\n+------------------------------------------+\nselect column_list(column_create(\'column1\', 22, \'column2\', 23)); \n+----------------------------------------------------------+\n| column_list(column_create(\'column1\', 22, \'column2\', 23)) |\n+----------------------------------------------------------+\n| `column1`,`column2` |\n+----------------------------------------------------------+\n\n* Column name interpretation has been changed so that the string now is not\nconverted to a number. So some \"magic\" tricks will not work any more, for\nexample, \"1test\" and \"1\" now become different column names:\n\nselect column_list(column_add(column_create(\'1a\', 22), \'1b\', 23));\n+------------------------------------------------------------+\n| column_list(column_add(column_create(\'1a\', 22), \'1b\', 23)) |\n+------------------------------------------------------------+\n| `1a`,`1b` |\n+------------------------------------------------------------+\n\n* Old behavior:\n\nselect column_list(column_add(column_create(\'1a\', 22), \'1b\', 23));\n+------------------------------------------------------------+\n| column_list(column_add(column_create(\'1a\', 22), \'1b\', 23)) |\n+------------------------------------------------------------+\n| 1 |\n+------------------------------------------------------------+\n\nNew Functions\n-------------\n\nThe following new functions have been added to dynamic columns in MariaDB 10\n\nCOLUMN_CHECK\n------------\n\nCOLUMN_CHECK is used to check a column\'s integrity. When it encounters an\nerror it does not return illegal format errors but returns false instead. It\nalso checks integrity more thoroughly and finds errors in the dynamic column\ninternal structures which might not be found by other functions.\n\nselect column_check(column_create(\'column1\', 22));\n+--------------------------------------------+\n| column_check(column_create(\'column1\', 22)) |\n+--------------------------------------------+\n| 1 |\n+--------------------------------------------+\nselect column_check(\'abracadabra\');\n+-----------------------------+\n| column_check(\'abracadabra\') |\n+-----------------------------+\n| 0 |\n+-----------------------------+\n\nCOLUMN_JSON\n-----------\n\nCOLUMN_JSON converts all dynamic column record content to a JSON object.\n\nselect column_json(column_create(\'column1\', 1, \'column2\', \"two\"));\n+------------------------------------------------------------+\n| column_json(column_create(\'column1\', 1, \'column2\', \"two\")) |\n+------------------------------------------------------------+\n| {\"column1\":1,\"column2\":\"two\"} |\n+------------------------------------------------------------+\n\nOther Changes\n-------------\n\n* All API functions has prefix mariadb_dyncol_ (old prefix dynamic_column_ is\ndepricated\n* API changed to be able to work with the new format (*_named functions).\n* Removed \'delete\' function because deleting could be done by adding NULL\nvalue.\n* \'Time\' and \'datetime\' in the new format are stored without microseconds if\nthey are 0.\n* New function added to API (except that two which are representing SQL level\nfunctions):\n\'Unpack\' the dynamic columns content to an arrays of values and names.\n3 functions to get any column value as string, integer (long long) or floating\npoint (double).\n\n* New type of \"dynamic column\" row added on the API level (in SQL level output\nit is a string but if you use dynamic column functions to construct object it\nwill be added as dynamic column value) which allow to add dynamic columns\ninside dynamic columns. JSON function represent such recursive constructions\ncorrectly but limit depth of representation as current implementation limit\n(internally depth of dynamic columns embedding is not limited).\n\nInterface with Cassandra\n------------------------\n\nCassandraSE is no longer actively being developed and has been removed in\nMariaDB 10.6. See MDEV-23024.\n\nSome internal changes were added to dynamic columns to allow them to serve as\nan interface to Apache Cassandra dynamic columns. The Cassandra engine may\npack all columns which were not mentioned in the MariaDB interface table\ndefinition and even bring changes in the dynamic column contents back to the\ncassandra columns family (the table analog in cassandra).\n\nURL: https://mariadb.com/kb/en/dynamic-columns-from-mariadb-10/','','https://mariadb.com/kb/en/dynamic-columns-from-mariadb-10/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (737,38,'MERGE','Description\n-----------\n\nThe MERGE storage engine, also known as the MRG_MyISAM engine, is a collection\nof identical MyISAM tables that can be used as one. \"Identical\" means that all\ntables have identical column and index information. You cannot merge MyISAM\ntables in which the columns are listed in a different order, do not have\nexactly the same columns, or have the indexes in different order. However, any\nor all of the MyISAM tables can be compressed with myisampack. Columns names\nand indexes names can be different, as long as data types and NULL/NOT NULL\nclauses are the same. Differences in table options such as AVG_ROW_LENGTH,\nMAX_ROWS, or PACK_KEYS do not matter.\n\nEach index in a MERGE table must match an index in underlying MyISAM tables,\nbut the opposite is not true. Also, a MERGE table cannot have a PRIMARY KEY or\nUNIQUE indexes, because it cannot enforce uniqueness over all underlying\ntables.\n\nThe following options are meaningful for MERGE tables:\n\n* UNION. This option specifies the list of the underlying MyISAM tables. The\nlist is enclosed between parentheses and separated with commas.\n* INSERT_METHOD. This options specifies whether, and how, INSERTs are allowed\nfor the table. Allowed values are: NO (INSERTs are not allowed), FIRST (new\nrows will be written into the first table specified in the UNION list), LAST\n(new rows will be written into the last table specified in the UNION list).\nThe default value is NO.\n\nIf you define a MERGE table with a definition which is different from the\nunderlying MyISAM tables, or one of the underlying tables is not MyISAM, the\nCREATE TABLE statement will not return any error. But any statement which\ninvolves the table will produce an error like the following:\n\nERROR 1168 (HY000): Unable to open underlying table which is differently\ndefined \n or of non-MyISAM type or doesn\'t exist\n\nA CHECK TABLE will show more information about the problem.\n\nThe error is also produced if the table is properly define, but an underlying\ntable\'s definition changes at some point in time.\n\nIf you try to insert a new row into a MERGE table with INSERT_METHOD=NO, you\nwill get an error like the following:\n\nERROR 1036 (HY000): Table \'tbl_name\' is read only\n\nIt is possible to build a MERGE table on MyISAM tables which have one or more\nvirtual columns. MERGE itself does not support virtual columns, thus such\ncolumns will be seen as regular columns. The data types and sizes will still\nneed to be identical, and they cannot be NOT NULL.\n\nExamples\n--------\n\nCREATE TABLE t1 (\n a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,\n message CHAR(20)) ENGINE=MyISAM;\n\nCREATE TABLE t2 (\n a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,\n message CHAR(20)) ENGINE=MyISAM;\n\nINSERT INTO t1 (message) VALUES (\'Testing\'),(\'table\'),(\'t1\');\n\nINSERT INTO t2 (message) VALUES (\'Testing\'),(\'table\'),(\'t2\');\n\nCREATE TABLE total (\n a INT NOT NULL AUTO_INCREMENT,\n message CHAR(20), INDEX(a))\n ENGINE=MERGE UNION=(t1,t2) INSERT_METHOD=LAST;\n\nSELECT * FROM total;\n+---+---------+\n| a | message |\n+---+---------+\n| 1 | Testing |\n| 2 | table |\n| 3 | t1 |\n| 1 | Testing |\n| 2 | table |\n| 3 | t2 |\n+---+---------+\n\nIn the following example, we\'ll create three MyISAM tables, and then a MERGE\ntable on them. However, one of them uses a different data type for the column\nb, so a SELECT will produce an error:\n\nCREATE TABLE t1 (\n a INT,\n b INT\n) ENGINE = MyISAM;\n\nCREATE TABLE t2 (\n a INT,\n b INT\n) ENGINE = MyISAM;\n\nCREATE TABLE t3 (\n a INT,\n b TINYINT\n) ENGINE = MyISAM;\n\nCREATE TABLE t_mrg (\n a INT,\n b INT\n) ENGINE = MERGE,UNION=(t1,t2,t3);\n\nSELECT * FROM t_mrg;\nERROR 1168 (HY000): Unable to open underlying table which is differently\ndefined\n or of non-MyISAM type or doesn\'t exist\n\nTo find out what\'s wrong, we\'ll use a CHECK TABLE:\n\nCHECK TABLE t_mrg\\G\n*************************** 1. row ***************************\n Table: test.t_mrg\n Op: check\nMsg_type: Error\nMsg_text: Table \'test.t3\' is differently defined or of non-MyISAM type or\ndoesn\'t exist\n*************************** 2. row ***************************\n Table: test.t_mrg\n Op: check\nMsg_type: Error\nMsg_text: Unable to open underlying table which is differently defined or of\nnon-MyISAM type or doesn\'t exist\n*************************** 3. row ***************************\n Table: test.t_mrg\n Op: check\nMsg_type: error\nMsg_text: Corrupt\n\nNow, we know that the problem is in t3\'s definition.\n\nURL: https://mariadb.com/kb/en/merge/','','https://mariadb.com/kb/en/merge/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (738,39,'Sequence Overview','This page is about sequence objects. For details about the storage engine, see\nSequence Storage Engine.\n\nIntroduction\n------------\n\nA sequence is an object that generates a sequence of numeric values, as\nspecified by the CREATE SEQUENCE statement.\n\nCREATE SEQUENCE will create a sequence that generates new values when called\nwith NEXT VALUE FOR sequence_name. It\'s an alternative to AUTO INCREMENT when\none wants to have more control of how the numbers are generated. As the\nSEQUENCE caches values (up to the CACHE value in the CREATE SEQUENCE\nstatement, by default 1000) it can in some cases be much faster than AUTO\nINCREMENT. Another benefit is that one can access the last value generated by\nall used sequences, which solves one of the limitations with LAST_INSERT_ID().\n\nCreating a Sequence\n-------------------\n\nThe CREATE SEQUENCE statement is used to create a sequence. Here is an example\nof a sequence starting at 100, incrementing by 10 each time:\n\nCREATE SEQUENCE s START WITH 100 INCREMENT BY 10;\n\nThe CREATE SEQUENCE statement, along with defaults, can be viewd with the SHOW\nCREATE SEQUENCE STATEMENT, for example:\n\nSHOW CREATE SEQUENCE s\\G\n*************************** 1. row ***************************\n Table: s\nCreate Table: CREATE SEQUENCE `s` start with 100 minvalue 1 maxvalue\n9223372036854775806 \n increment by 10 cache 1000 nocycle ENGINE=InnoDB\n\nUsing Sequence Objects\n----------------------\n\nTo get the next value from a sequence, use\n\nNEXT VALUE FOR sequence_name\n\nor\n\nNEXTVAL(sequence_name)\n\nor in Oracle mode (SQL_MODE=ORACLE)\n\nsequence_name.nextval\n\nFor retrieving the last value used by the current connection from a sequence\nuse:\n\nPREVIOUS VALUE FOR sequence_name\n\nor\n\nLASTVAL(sequence_name)\n\nor in Oracle mode (SQL_MODE=ORACLE)\n\nsequence_name.currval\n\nFor example:\n\nSELECT NEXTVAL(s);\n+------------+\n| NEXTVAL(s) |\n+------------+\n| 100 |\n+------------+\n\nSELECT NEXTVAL(s);\n+------------+\n| NEXTVAL(s) |\n+------------+\n| 110 |\n+------------+\n\nSELECT LASTVAL(s);\n+------------+\n| LASTVAL(s) |\n+------------+\n| 110 |\n+------------+\n\nUsing Sequences in DEFAULT\n--------------------------\n\nSequences can be used in DEFAULT:\n\ncreate sequence s1;\ncreate table t1 (a int primary key default (next value for s1), b int);\ninsert into t1 (b) values (1),(2);\nselect * from t1;\n+---+------+\n| a | b |\n+---+------+\n| 1 | 1 |\n| 2 | 2 |\n+---+------+\n\nChanging a Sequence\n-------------------\n\nThe ALTER SEQUENCE statement is used for changing sequences. For example, to\nrestart the sequence at another value:\n\nALTER SEQUENCE s RESTART 50;\n\nSELECT NEXTVAL(s);\n+------------+\n| NEXTVAL(s) |\n+------------+\n| 50 |\n+------------+\n\nThe SETVAL function can also be used to set the next value to be returned for\na SEQUENCE, for example:\n\nSELECT SETVAL(s, 100);\n+----------------+\n| SETVAL(s, 100) |\n+----------------+\n| 100 |\n+----------------+\n\nSETVAL can only be used to increase the sequence value. Attempting to set a\nlower value will fail, returning NULL:\n\nSELECT SETVAL(s, 50);\n+---------------+\n| SETVAL(s, 50) |\n+---------------+\n| NULL |\n+---------------+\n\nDropping a Sequence\n-------------------\n\nThe DROP SEQUENCE statement is used to drop a sequence, for example:\n\nDROP SEQUENCE s;\n\nReplication\n-----------\n\nIf one wants to use Sequences in a master-master setup or with Galera one\nshould use INCREMENT=0. This will tell the Sequence to use\nauto_increment_increment and auto_increment_offset to generate unique values\nfor each server.\n\nStandards Compliance\n--------------------\n\nMariaDB supports both ANSI SQL and Oracle syntax for sequences.\n\nHowever as SEQUENCE is implemented as a special kind of table, it uses the\nsame namespace as tables. The benefits are that sequences show up in SHOW\nTABLES, and one can also create a sequence with CREATE TABLE and drop it with\nDROP TABLE. One can SELECT from it as from any other table. This ensures that\nall old tools that work with tables should work with sequences.\n\nSince sequence objects act as regular tables in many contexts, they will be\naffected by LOCK TABLES. This is not the case in other DBMS, such as Oracle,\nwhere LOCK TABLE does not affect sequences.\n\nNotes\n-----\n\nOne of the goals with the Sequence implementation is that all old tools, such\nas mariadb-dump (previously mysqldump), should work unchanged, while still\nkeeping the normal usage of sequence standard compatibly.\n\nTo make this possible, sequence is currently implemented as a table with a few\nexclusive properties.\n\nThe special properties for sequence tables are:\n\n* A sequence table has always one row.\n* When one creates a sequence, either with CREATE TABLE or CREATE SEQUENCE,\none row will be inserted.\n* If one tries to insert into a sequence table, the single row will be\nupdated. This allows mariadb-dump to work but also gives the additional\nbenefit that one can change all properties of a sequence with a single insert.\nNew applications should of course also use ALTER SEQUENCE.\n* UPDATE or DELETE can\'t be performed on Sequence objects.\n* Doing a select on the sequence shows the current state of the sequence,\nexcept the values that are reserved in the cache. The next_value column shows\nthe next value not reserved by the cache.\n* FLUSH TABLES will close the sequence and the next sequence number generated\nwill be according to what\'s stored in the Sequence object. In effect, this\nwill discard the cached values.\n* A number of normal table operations work on Sequence tables. See next\nsection.\n\nTable Operations that Work with Sequences\n-----------------------------------------\n\n* SHOW CREATE TABLE sequence_name. This shows the table structure that is\nbehind the SEQUENCE including the field names that can be used with SELECT or\neven CREATE TABLE.\n* CREATE TABLE sequence-structure ... SEQUENCE=1\n* ALTER TABLE sequence RENAME TO sequence2\n* RENAME TABLE sequence_name TO new_sequence_name\n* DROP TABLE sequence_name. This is allowed mainly to get old tools like\nmariadb-dump to work with sequence tables.\n* SHOW TABLES\n\nImplementation\n--------------\n\nInternally, sequence tables are created as a normal table without rollback\n(the InnoDB, Aria and MySAM engines support this), wrapped by a sequence\nengine object. This allowed us to create sequences with almost no performance\nimpact for normal tables. (The cost is one \'if\' per insert if the binary log\nis enabled).\n\nUnderlying Table Structure\n--------------------------\n\nThe following example shows the table structure of sequences and how it can be\nused as a table. (Output of results are slightly edited to make them easier to\nread)\n\ncreate sequence t1;\nshow create sequence t1\\G\n*************************** 1. row ***************************\n CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806\n increment by 1 cache 1000 nocycle ENGINE=InnoDB\n\nshow create table t1\\G\n*************************** 1. row ***************************\nCreate Table: CREATE TABLE `t1` (\n `next_not_cached_value` bigint(21) NOT NULL,\n `minimum_value` bigint(21) NOT NULL,\n `maximum_value` bigint(21) NOT NULL,\n `start_value` bigint(21) NOT NULL COMMENT \'start value when sequences is\ncreated or value if RESTART is used\',\n `increment` bigint(21) NOT NULL COMMENT \'increment value\',\n `cache_size` bigint(21) unsigned NOT NULL,\n `cycle_option` tinyint(1) unsigned NOT NULL COMMENT \'0 if no cycles are\nallowed, 1 if the sequence should begin a new cycle when maximum_value is\npassed\',\n `cycle_count` bigint(21) NOT NULL COMMENT \'How many cycles have been done\'\n) ENGINE=InnoDB SEQUENCE=1\n\nselect * from t1\\G\nnext_not_cached_value: 1\n minimum_value: 1\n maximum_value: 9223372036854775806\n start_value: 1\n increment: 1\n cache_size: 1000\n cycle_option: 0\n cycle_count: 0\n\nThe cycle_count column is incremented every time the sequence wraps around.\n\nCredits\n-------\n\n* Thanks to Jianwe Zhao from Aliyun for his work on SEQUENCE in AliSQL, which\ngave ideas and inspiration for this work.\n* Thanks to Peter Gulutzan,who helped test and gave useful comments about the\nimplementation.\n\nURL: https://mariadb.com/kb/en/sequence-overview/','','https://mariadb.com/kb/en/sequence-overview/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (739,39,'CREATE SEQUENCE','Syntax\n------\n\nCREATE [OR REPLACE] [TEMPORARY] SEQUENCE [IF NOT EXISTS] sequence_name\n[ INCREMENT [ BY | = ] increment ]\n[ MINVALUE [=] minvalue | NO MINVALUE | NOMINVALUE ]\n[ MAXVALUE [=] maxvalue | NO MAXVALUE | NOMAXVALUE ]\n[ START [ WITH | = ] start ] \n[ CACHE [=] cache | NOCACHE ] [ CYCLE | NOCYCLE] \n[table_options]\nThe options for CREATE SEQUENCE can be given in any order, optionally followed\nby table_options.\n\ntable_options can be any of the normal table options in CREATE TABLE but the\nmost usable ones are ENGINE=... and COMMENT=.\n\nNOMAXVALUE and NOMINVALUE are there to allow one to create SEQUENCEs using the\nOracle syntax.\n\nDescription\n-----------\n\nCREATE SEQUENCE will create a sequence that generates new values when called\nwith NEXT VALUE FOR sequence_name. It\'s an alternative to AUTO INCREMENT when\none wants to have more control of how the numbers are generated. As the\nSEQUENCE caches values (up to CACHE) it can in some cases be much faster than\nAUTO INCREMENT. Another benefit is that one can access the last value\ngenerated by all used sequences, which solves one of the limitations with\nLAST_INSERT_ID().\n\nCREATE SEQUENCE requires the CREATE privilege.\n\nDROP SEQUENCE can be used to drop a sequence, and ALTER SEQUENCE to change it.\n\nArguments to Create\n-------------------\n\nThe following options may be used:\n\n+---------------+------------------------------+----------------------------+\n| Option | Default value | Description |\n+---------------+------------------------------+----------------------------+\n| INCREMENT | 1 | Increment to use for |\n| | | values. May be negative. |\n| | | Setting an increment of 0 |\n| | | causes the sequence to |\n| | | use the value of the |\n| | | auto_increment_increment |\n| | | system variable at the |\n| | | time of creation, which |\n| | | is always a positive |\n| | | number. (see MDEV-16035). |\n+---------------+------------------------------+----------------------------+\n| MINVALUE | 1 if INCREMENT > 0 and | Minimum value for the |\n| | -9223372036854775807 if | sequence |\n| | INCREMENT < 0 | |\n+---------------+------------------------------+----------------------------+\n| MAXVALUE | 9223372036854775806 if | Max value for sequence |\n| | INCREMENT > 0 and -1 if | |\n| | INCREMENT < 0 | |\n+---------------+------------------------------+----------------------------+\n| START | MINVALUE if INCREMENT > 0 | First value that the |\n| | and MAX_VALUE if INCREMENT< | sequence will generate |\n| | 0 | |\n+---------------+------------------------------+----------------------------+\n| CACHE | 1000 | Number of values that |\n| | | should be cached. 0 if no |\n| | | CACHE. The underlying |\n| | | table will be updated |\n| | | first time a new sequence |\n| | | number is generated and |\n| | | each time the cache runs |\n| | | out. |\n+---------------+------------------------------+----------------------------+\n\nIf CYCLE is used then the sequence should start again from MINVALUE after it\nhas run out of values. Default value is NOCYCLE.\n\nConstraints on Create Arguments\n-------------------------------\n\nTo be able to create a legal sequence, the following must hold:\n\n* MAXVALUE >= start\n* MAXVALUE > MINVALUE\n* START >= MINVALUE\n* MAXVALUE <= 9223372036854775806 (LONGLONG_MAX-1)\n* MINVALUE >= -9223372036854775807 (LONGLONG_MIN+1)\n\nNote that sequences can\'t generate the maximum/minimum 64 bit number because\nof the constraint of MINVALUE and MAXVALUE.\n\nAtomic DDL\n----------\n\nMariaDB starting with 10.6.1\n----------------------------\nMariaDB 10.6.1 supports Atomic DDL and CREATE SEQUENCE is atomic.\n\nExamples\n--------\n\nCREATE SEQUENCE s START WITH 100 INCREMENT BY 10;\n\nCREATE SEQUENCE s2 START WITH -100 INCREMENT BY -10;\n\nThe following statement fails, as the increment conflicts with the defaults\n\nCREATE SEQUENCE s3 START WITH -100 INCREMENT BY 10;\nERROR 4082 (HY000): Sequence \'test.s3\' values are conflicting\n\nThe sequence can be created by specifying workable minimum and maximum values:\n\nCREATE SEQUENCE s3 START WITH -100 INCREMENT BY 10 MINVALUE=-100 MAXVALUE=1000;\n\nURL: https://mariadb.com/kb/en/create-sequence/','','https://mariadb.com/kb/en/create-sequence/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (740,39,'ALTER SEQUENCE','Syntax\n------\n\nALTER SEQUENCE [IF EXISTS] sequence_name\n[ INCREMENT [ BY | = ] increment ]\n[ MINVALUE [=] minvalue | NO MINVALUE | NOMINVALUE ]\n[ MAXVALUE [=] maxvalue | NO MAXVALUE | NOMAXVALUE ]\n[ START [ WITH | = ] start ] [ CACHE [=] cache ] [ [ NO ] CYCLE ]\n[ RESTART [[WITH | =] restart]\n\nALTER SEQUENCE allows one to change any values for a SEQUENCE created with\nCREATE SEQUENCE.\n\nThe options for ALTER SEQUENCE can be given in any order.\n\nDescription\n-----------\n\nALTER SEQUENCE changes the parameters of an existing sequence generator. Any\nparameters not specifically set in the ALTER SEQUENCE command retain their\nprior settings.\n\nALTER SEQUENCE requires the ALTER privilege.\n\nArguments to ALTER SEQUENCE\n---------------------------\n\nThe following options may be used:\n\n+---------------+-------------------------------+---------------------------+\n| Option | Default value | Description |\n+---------------+-------------------------------+---------------------------+\n| INCREMENT | 1 | Increment to use for |\n| | | values. May be negative. |\n+---------------+-------------------------------+---------------------------+\n| MINVALUE | 1 if INCREMENT > 0 and | Minimum value for the |\n| | -9223372036854775807 if | sequence. |\n| | INCREMENT < 0 | |\n+---------------+-------------------------------+---------------------------+\n| MAXVALUE | 9223372036854775806 if | Max value for sequence. |\n| | INCREMENT > 0 and -1 if | |\n| | INCREMENT < 0 | |\n+---------------+-------------------------------+---------------------------+\n| START | MINVALUE if INCREMENT > 0 | First value that the |\n| | and MAX_VALUE if INCREMENT< 0 | sequence will generate. |\n+---------------+-------------------------------+---------------------------+\n| CACHE | 1000 | Number of values that |\n| | | should be cached. 0 if |\n| | | no CACHE. The |\n| | | underlying table will be |\n| | | updated first time a new |\n| | | sequence number is |\n| | | generated and each time |\n| | | the cache runs out. |\n+---------------+-------------------------------+---------------------------+\n| CYCLE | 0 (= NO CYCLE) | 1 if the sequence should |\n| | | start again from |\n| | | MINVALUE# after it has |\n| | | run out of values. |\n+---------------+-------------------------------+---------------------------+\n| RESTART | START if restart value not | If RESTART option is |\n| | is given | used, NEXT VALUE will |\n| | | return the restart value. |\n+---------------+-------------------------------+---------------------------+\n\nThe optional clause RESTART [ WITH restart ] sets the next value for the\nsequence. This is equivalent to calling the SETVAL() function with the is_used\nargument as 0. The specified value will be returned by the next call of\nnextval. Using RESTART with no restart value is equivalent to supplying the\nstart value that was recorded by CREATE SEQUENCE or last set by ALTER SEQUENCE\nSTART WITH.\n\nALTER SEQUENCE will not allow you to change the sequence so that it\'s\ninconsistent. For example:\n\nCREATE SEQUENCE s1;\nALTER SEQUENCE s1 MINVALUE 10;\nERROR 4061 (HY000): Sequence \'test.t1\' values are conflicting\n\nALTER SEQUENCE s1 MINVALUE 10 RESTART 10;\nERROR 4061 (HY000): Sequence \'test.t1\' values are conflicting\n\nALTER SEQUENCE s1 MINVALUE 10 START 10 RESTART 10;\n\nINSERT\n------\n\nTo allow SEQUENCE objects to be backed up by old tools, like mariadb-dump, one\ncan use SELECT to read the current state of a SEQUENCE object and use an\nINSERT to update the SEQUENCE object. INSERT is only allowed if all fields are\nspecified:\n\nCREATE SEQUENCE s1;\nINSERT INTO s1 VALUES(1000,10,2000,1005,1,1000,0,0);\nSELECT * FROM s1;\n\n+------------+-----------+-----------+-------+-----------+-------+-------+-----\n-+\n| next_value | min_value | max_value | start | increment | cache | cycle |\nround |\n+------------+-----------+-----------+-------+-----------+-------+-------+-----\n-+\n| 1000 | 10 | 2000 | 1005 | 1 | 1000 | 0 | \n0 |\n+------------+-----------+-----------+-------+-----------+-------+-------+-----\n-+\n\nSHOW CREATE SEQUENCE s1;\n+-------+----------------------------------------------------------------------\n---------------------------------------+\n| Table | Create Table \n |\n+-------+----------------------------------------------------------------------\n---------------------------------------+\n| s1 | CREATE SEQUENCE `s1` start with 1005 minvalue 10 maxvalue 2000\nincrement by 1 cache 1000 nocycle ENGINE=Aria |\n+-------+----------------------------------------------------------------------\n---------------------------------------+\n\nNotes\n-----\n\nALTER SEQUENCE will instantly affect all future SEQUENCE operations. This is\nin contrast to some other databases where the changes requested by ALTER\nSEQUENCE will not be seen until the sequence cache has run out.\n\nALTER SEQUENCE will take a full table lock of the sequence object during its\n(brief) operation. This ensures that ALTER SEQUENCE is replicated correctly.\nIf you only want to set the next sequence value to a higher value than\ncurrent, then you should use SETVAL() instead, as this is not blocking.\n\nIf you want to change storage engine, sequence comment or rename the sequence,\nyou can use ALTER TABLE for this.\n\nURL: https://mariadb.com/kb/en/alter-sequence/','','https://mariadb.com/kb/en/alter-sequence/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (741,39,'DROP SEQUENCE','Syntax\n------\n\nDROP [TEMPORARY] SEQUENCE [IF EXISTS] [/*COMMENT TO SAVE*/]\n sequence_name [, sequence_name] ...\n\nDescription\n-----------\n\nDROP SEQUENCE removes one or more sequences created with CREATE SEQUENCE. You\nmust have the DROP privilege for each sequence. MariaDB returns an error\nindicating by name which non-existing tables it was unable to drop, but it\nalso drops all of the tables in the list that do exist.\n\nImportant: When a table is dropped, user privileges on the table are not\nautomatically dropped. See GRANT.\n\nIf another connection is using the sequence, a metadata lock is active, and\nthis statement will wait until the lock is released. This is also true for\nnon-transactional tables.\n\nFor each referenced sequence, DROP SEQUENCE drops a temporary sequence with\nthat name, if it exists. If it does not exist, and the TEMPORARY keyword is\nnot used, it drops a non-temporary sequence with the same name, if it exists.\nThe TEMPORARY keyword ensures that a non-temporary sequence will not\naccidentally be dropped.\n\nUse IF EXISTS to prevent an error from occurring for sequences that do not\nexist. A NOTE is generated for each non-existent sequence when using IF\nEXISTS. See SHOW WARNINGS.\n\nDROP SEQUENCE requires the DROP privilege.\n\nNotes\n-----\n\nDROP SEQUENCE only removes sequences, not tables. However, DROP TABLE can\nremove both sequences and tables.\n\nURL: https://mariadb.com/kb/en/drop-sequence/','','https://mariadb.com/kb/en/drop-sequence/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (742,39,'NEXT VALUE for sequence_name','MariaDB starting with 10.3\n--------------------------\nSEQUENCEs were introduced in MariaDB 10.3\n\nSyntax\n------\n\nNEXT VALUE FOR sequence\n\nor\n\nNEXTVAL(sequence_name)\n\nor in Oracle mode (SQL_MODE=ORACLE)\n\nsequence_name.nextval\n\nNEXT VALUE FOR is ANSI SQL syntax while NEXTVAL() is PostgreSQL syntax.\n\nDescription\n-----------\n\nGenerate next value for a SEQUENCE.\n\n* You can greatly speed up NEXT VALUE by creating the sequence with the CACHE\noption. If not, every NEXT VALUE usage will cause changes in the stored\nSEQUENCE table.\n* When using NEXT VALUE the value will be reserved at once and will not be\nreused, except if the SEQUENCE was created with CYCLE. This means that when\nyou are using SEQUENCEs you have to expect gaps in the generated sequence\nnumbers.\n* If one updates the SEQUENCE with SETVAL() or ALTER SEQUENCE ... RESTART,\nNEXT VALUE FOR will notice this and start from the next requested value.\n* FLUSH TABLES will close the sequence and the next sequence number generated\nwill be according to what\'s stored in the SEQUENCE object. In effect, this\nwill discard the cached values.\n* A server restart (or closing the current connection) also causes a drop of\nall cached values. The cached sequence numbers are reserved only for the\ncurrent connection.\n* NEXT VALUE requires the INSERT privilege.\n\nMariaDB starting with 10.3.3\n----------------------------\n* You can also use NEXT VALUE FOR sequence for column DEFAULT.\n\nURL: https://mariadb.com/kb/en/next-value-for-sequence_name/','','https://mariadb.com/kb/en/next-value-for-sequence_name/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (743,39,'PREVIOUS VALUE FOR sequence_name','MariaDB starting with 10.3\n--------------------------\nSEQUENCEs were introduced in MariaDB 10.3.\n\nSyntax\n------\n\nPREVIOUS VALUE FOR sequence_name\n\nor\n\nLASTVAL(sequence_name)\n\nor in Oracle mode (SQL_MODE=ORACLE)\n\nsequence_name.currval\n\nPREVIOUS VALUE FOR is IBM DB2 syntax while LASTVAL() is PostgreSQL syntax.\n\nDescription\n-----------\n\nGet last value in the current connection generated from a sequence.\n\n* If the sequence has not yet been used by the connection, PREVIOUS VALUE FOR\nreturns NULL (the same thing applies with a new connection which doesn\'t see a\nlast value for an existing sequence).\n* If a SEQUENCE has been dropped and re-created then it\'s treated as a new\nSEQUENCE and PREVIOUS VALUE FOR will return NULL.\n* FLUSH TABLES has no effect on PREVIOUS VALUE FOR.\n* Previous values for all used sequences are stored per connection until\nconnection ends.\n* PREVIOUS VALUE FOR requires the SELECT privilege.\n\nExample\n-------\n\nCREATE SEQUENCE s START WITH 100 INCREMENT BY 10;\n\nSELECT PREVIOUS VALUE FOR s;\n+----------------------+\n| PREVIOUS VALUE FOR s |\n+----------------------+\n| NULL |\n+----------------------+\n\n# The function works for sequences only, if the table is used an error is\ngenerated\nSELECT PREVIOUS VALUE FOR t;\nERROR 4089 (42S02): \'test.t\' is not a SEQUENCE\n\n# Call the NEXT VALUE FOR s:\nSELECT NEXT VALUE FOR s;\n+------------------+\n| NEXT VALUE FOR s |\n+------------------+\n| 100 |\n+------------------+\n\nSELECT PREVIOUS VALUE FOR s;\n+----------------------+\n| PREVIOUS VALUE FOR s |\n+----------------------+\n| 100 |\n+----------------------+\n\nNow try to start the new connection and check that the last value is still\nNULL, before updating the value in the new connection after the output of the\nnew connection gets current value (110 in the example below). Note that first\nconnection cannot see this change and the result of last value still remains\nthe same (100 in the example above).\n\n$ .mysql -uroot test -e\"SELECT PREVIOUS VALUE FOR s; SELECT NEXT VALUE FOR s;\nSELECT PREVIOUS VALUE FOR s;\"\n+----------------------+\n| PREVIOUS VALUE FOR s |\n+----------------------+\n| NULL |\n+----------------------+\n+------------------+\n| NEXT VALUE FOR s |\n+------------------+\n| 110 |\n+------------------+\n+----------------------+\n| PREVIOUS VALUE FOR s |\n+----------------------+\n| 110 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/previous-value-for-sequence_name/','','https://mariadb.com/kb/en/previous-value-for-sequence_name/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (744,39,'SETVAL','MariaDB starting with 10.3.1\n----------------------------\nSEQUENCEs were introduced in MariaDB 10.3.\n\nSyntax\n------\n\nSETVAL(sequence_name, next_value, [is_used, [round]])\n\nDescription\n-----------\n\nSet the next value to be returned for a SEQUENCE.\n\nThis function is compatible with PostgreSQL syntax, extended with the round\nargument.\n\nIf the is_used argument is not given or is 1 or true, then the next used value\nwill one after the given value. If is_used is 0 or false then the next\ngenerated value will be the given value.\n\nIf round is used then it will set the round value (or the internal cycle\ncount, starting at zero) for the sequence. If round is not used, it\'s assumed\nto be 0.\n\nnext_value must be an integer literal.\n\nFor SEQUENCE tables defined with CYCLE (see CREATE SEQUENCE) one should use\nboth next_value and round to define the next value. In this case the current\nsequence value is defined to be round, next_value.\n\nThe result returned by SETVAL() is next_value or NULL if the given next_value\nand round is smaller than the current value.\n\nSETVAL() will not set the SEQUENCE value to a something that is less than its\ncurrent value. This is needed to ensure that SETVAL() is replication safe. If\nyou want to set the SEQUENCE to a smaller number use ALTER SEQUENCE.\n\nIf CYCLE is used, first round and then next_value are compared to see if the\nvalue is bigger than the current value.\n\nInternally, in the MariaDB server, SETVAL() is used to inform slaves that a\nSEQUENCE has changed value. The slave may get SETVAL() statements out of\norder, but this is ok as only the biggest one will have an effect.\n\nSETVAL requires the INSERT privilege.\n\nExamples\n--------\n\nSELECT setval(foo, 42); -- Next nextval will return 43\nSELECT setval(foo, 42, true); -- Same as above\nSELECT setval(foo, 42, false); -- Next nextval will return 42\n\nSETVAL setting higher and lower values on a sequence with an increment of 10:\n\nSELECT NEXTVAL(s);\n+------------+\n| NEXTVAL(s) |\n+------------+\n| 50 |\n+------------+\n\nSELECT SETVAL(s, 100);\n+----------------+\n| SETVAL(s, 100) |\n+----------------+\n| 100 |\n+----------------+\n\nSELECT NEXTVAL(s);\n+------------+\n| NEXTVAL(s) |\n+------------+\n| 110 |\n+------------+\n\nSELECT SETVAL(s, 50);\n+---------------+\n| SETVAL(s, 50) |\n+---------------+\n| NULL |\n+---------------+\n\nSELECT NEXTVAL(s);\n+------------+\n| NEXTVAL(s) |\n+------------+\n| 120 |\n+------------+\n\nExample demonstrating round:\n\nCREATE OR REPLACE SEQUENCE s1\n START WITH 1\n MINVALUE 1\n MAXVALUE 99\n INCREMENT BY 1\n CACHE 20\n CYCLE;\n\nSELECT SETVAL(s1, 99, 1, 0);\n+----------------------+\n| SETVAL(s1, 99, 1, 0) |\n+----------------------+\n| 99 |\n+----------------------+\n\nSELECT NEXTVAL(s1);\n+-------------+\n| NEXTVAL(s1) |\n+-------------+\n| 1 |\n+-------------+\n\nThe following statement returns NULL, as the given next_value and round is\nsmaller than the current value.\n\nSELECT SETVAL(s1, 99, 1, 0);\n+----------------------+\n| SETVAL(s1, 99, 1, 0) |\n+----------------------+\n| NULL |\n+----------------------+\n\nSELECT NEXTVAL(s1);\n+-------------+\n| NEXTVAL(s1) |\n+-------------+\n| 2 |\n+-------------+\n\nIncreasing the round from zero to 1 will allow next_value to be returned.\n\nSELECT SETVAL(s1, 99, 1, 1);\n+----------------------+\n| SETVAL(s1, 99, 1, 1) |\n+----------------------+\n| 99 |\n+----------------------+\n\nSELECT NEXTVAL(s1);\n+-------------+\n| NEXTVAL(s1) |\n+-------------+\n| 1 |\n+-------------+\n\nURL: https://mariadb.com/kb/en/setval/','','https://mariadb.com/kb/en/setval/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (745,40,'JSON_ARRAYAGG','MariaDB starting with 10.5.0\n----------------------------\nJSON_ARRAYAGG was added in MariaDB 10.5.0.\n\nSyntax\n------\n\nJSON_ARRAYAGG(column_or_expression)\n\nDescription\n-----------\n\nJSON_ARRAYAGG returns a JSON array containing an element for each value in a\ngiven set of JSON or SQL values. It acts on a column or an expression that\nevaluates to a single value.\n\nReturns NULL in the case of an error, or if the result contains no rows.\n\nJSON_ARRAYAGG cannot currently be used as a window function.\n\nThe full syntax is as follows:\n\nJSON_ARRAYAGG([DISTINCT] expr [,expr ...]\n [ORDER BY {unsigned_integer | col_name | expr}\n [ASC | DESC] [,col_name ...]]\n [LIMIT {[offset,] row_count | row_count OFFSET offset}])\n\nExamples\n--------\n\nCREATE TABLE t1 (a INT, b INT);\n\nINSERT INTO t1 VALUES (1, 1),(2, 1), (1, 1),(2, 1), (3, 2),(2, 2),(2, 2),(2,\n2);\n\nSELECT JSON_ARRAYAGG(a), JSON_ARRAYAGG(b) FROM t1;\n+-------------------+-------------------+\n| JSON_ARRAYAGG(a) | JSON_ARRAYAGG(b) |\n+-------------------+-------------------+\n| [1,2,1,2,3,2,2,2] | [1,1,1,1,2,2,2,2] |\n+-------------------+-------------------+\n\nSELECT JSON_ARRAYAGG(a), JSON_ARRAYAGG(b) FROM t1 GROUP BY b;\n+------------------+------------------+\n| JSON_ARRAYAGG(a) | JSON_ARRAYAGG(b) |\n+------------------+------------------+\n| [1,2,1,2] | [1,1,1,1] |\n| [3,2,2,2] | [2,2,2,2] |\n+------------------+------------------+\n\nURL: https://mariadb.com/kb/en/json_arrayagg/','','https://mariadb.com/kb/en/json_arrayagg/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (746,40,'JSON_OBJECTAGG','MariaDB starting with 10.5.0\n----------------------------\nJSON_OBJECTAGG was added in MariaDB 10.5.0.\n\nSyntax\n------\n\nJSON_OBJECTAGG(key, value)\n\nDescription\n-----------\n\nJSON_OBJECTAGG returns a JSON object containing key-value pairs. It takes two\nexpressions that evaluate to a single value, or two column names, as\narguments, the first used as a key, and the second as a value.\n\nReturns NULL in the case of an error, or if the result contains no rows.\n\nJSON_OBJECTAGG cannot currently be used as a window function.\n\nExamples\n--------\n\nselect * from t1;\n+------+-------+\n| a | b |\n+------+-------+\n| 1 | Hello |\n| 1 | World |\n| 2 | This |\n+------+-------+\n\nSELECT JSON_OBJECTAGG(a, b) FROM t1;\n+----------------------------------------+\n| JSON_OBJECTAGG(a, b) |\n+----------------------------------------+\n| {\"1\":\"Hello\", \"1\":\"World\", \"2\":\"This\"} |\n+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_objectagg/','','https://mariadb.com/kb/en/json_objectagg/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (747,40,'JSONPath Expressions','A number of JSON functions accept JSON Path expressions. MariaDB defines this\npath as follows:\n\nJSON Path Syntax\n----------------\n\npath : [\'lax\'] \'$\' [step]*\n\nThe path starts with an optional path mode. At the moment, MariaDB supports\nonly the \"lax\" mode, which is also the mode that is used when it is not\nexplicitly specified.\n\nThe $ symbol represents the context item. The search always starts from the\ncontext item; because of that, the path always starts with $.\n\nThen, it is followed by zero or more steps, which select element(s) in the\nJSON document. A step may be one of the following:\n\n* Object member selector\n* Array element selector\n* Wildcard selector\n\nObject Member Selector\n----------------------\n\nTo select member(s) in a JSON object, one can use one of the following:\n\n* .memberName selects the value of the member with name memberName.\n* .\"memberName\" - the same as above but allows one to select a member with a\nname that\'s not a valid identifier (that is, has space, dot, and/or other\ncharacters)\n* .* - selects the values of all members of the object.\n\nIf the current item is an array (instead of an object), nothing will be\nselected.\n\nArray Element Selector\n----------------------\n\nTo select elements of an array, one can use one of the following:\n\n* [N] selects element number N in the array. The elements are counted from\nzero.\n* [*] selects all elements in the array.\n\nIf the current item is an object (instead of an array), nothing will be\nselected.\n\nStarting from MariaDB server 10.9, JSON path also supports negative index in\narray, \'last\' keyword and range notation (\'to\' keyword) for accessing array\nelements. Negative index starts from -1.\n\n* [-N] selects n th element from end.\n* [last-N] selects n th element from the last element.\n* [M to N] selects range of elements starting from index M to N.\n\nExample:\n\nSET @json=\'{\n \"A\": [0,\n [1, 2, 3],\n [4, 5, 6],\n \"seven\",\n 0.8,\n true,\n false,\n \"eleven\",\n [12, [13, 14], {\"key1\":\"value1\"},[15]],\n true],\n \"B\": {\"C\": 1},\n \"D\": 2\n }\';\nSELECT JSON_EXTRACT(@json, \'$.A[-8][1]\');\n+--------------------------------------------------+\n| JSON_EXTRACT(@json, \'$.A[-8][1]\') |\n+--------------------------------------------------+\n| 5 |\n+--------------------------------------------------+\n\nSELECT JSON_EXTRACT(@json, \'$.A[last-7][1]\');\n+-----------------------------------------------+\n| SELECT JSON_EXTRACT(@json, \'$.A[last-7][1]\'); |\n+-----------------------------------------------+\n| 5 |\n+-----------------------------------------------+\n\nSET @json= \'[\n [1, {\"key1\": \"value1\"}, 3],\n [false, 5, 6],\n [7, 8, [9, {\"key2\": 2}, 11]],\n [15, 1.34, [14], [\"string1\", [16, {\"key1\":[1,2,3,[4,5,6]]}, 18]]],\n [19, 20],\n 21, 22\n ]\';\n\nSELECT JSON_EXTRACT(@json, \'$[0 to 3][2]\');\n+-----------------------------------------------+\n| JSON_EXTRACT(@json, \'$[0 to 3][2]\') |\n+-----------------------------------------------+\n| [3, 6, [9, {\"key2\": 2}, 11], [14]] |\n+-----------------------------------------------+\n\nThis will produce output for first index of eighth from last element of a two\ndimensional array.\n\nNote: In range notation, when M > N ( when M,N are greater than or equal to 0)\nor (size of array - M or size of array - N when M, N are less than 0), then it\nis treated as an impossible range and NULL is returned.\n\nSET @json= \'[1, 2, 3, 4, 5]\';\nSELECT JSON_EXTRACT(@json, \'$[4 to 2]\');\n+-----------------------------------+\n| JSON_EXTRACT(@json, \'$[4 to 2]\') |\n+-----------------------------------+\n| NULL |\n+-----------------------------------+\n\nWildcard\n--------\n\nThe wildcard step, **, recursively selects all child elements of the current\nelement. Both array elements and object members are selected.\n\nThe wildcard step must not be the last step in the JSONPath expression. It\nmust be followed by an array or object member selector step.\n\nFor example:\n\nselect json_extract(@json_doc, \'$**.price\');\n\nwill select all object members in the document that are named price, while\n\nselect json_extract(@json_doc, \'$**[2]\');\n\nwill select the second element in each of the arrays present in the document.\n\nCompatibility\n-------------\n\nMariaDB\'s JSONPath syntax supports a subset of JSON Path\'s definition in the\nSQL Standard. The most notable things not supported are the strict mode and\nfilters.\n\nMariaDB\'s JSONPath is close to MySQL\'s JSONPath. The wildcard step ( ** ) is a\nnon-standard extension that has the same meaning as in MySQL. The difference\nbetween MariaDB and MySQL\'s JSONPath is: MySQL doesn\'t allow one to specify\nthe mode explicitly (but uses lax mode implicitly).\n\nURL: https://mariadb.com/kb/en/jsonpath-expressions/','','https://mariadb.com/kb/en/jsonpath-expressions/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (748,40,'JSON_ARRAY','Syntax\n------\n\nJSON_ARRAY([value[, value2] ...])\n\nDescription\n-----------\n\nReturns a JSON array containing the listed values. The list can be empty.\n\nExample\n-------\n\nSELECT Json_Array(56, 3.1416, \'My name is \"Foo\"\', NULL);\n+--------------------------------------------------+\n| Json_Array(56, 3.1416, \'My name is \"Foo\"\', NULL) |\n+--------------------------------------------------+\n| [56, 3.1416, \"My name is \\\"Foo\\\"\", null] |\n+--------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_array/','','https://mariadb.com/kb/en/json_array/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (749,40,'JSON_ARRAY_APPEND','Syntax\n------\n\nJSON_ARRAY_APPEND(json_doc, path, value[, path, value] ...)\n\nDescription\n-----------\n\nAppends values to the end of the specified arrays within a JSON document,\nreturning the result, or NULL if any of the arguments are NULL.\n\nEvaluation is performed from left to right, with the resulting document from\nthe previous pair becoming the new value against which the next pair is\nevaluated.\n\nIf the json_doc is not a valid JSON document, or if any of the paths are not\nvalid, or contain a * or ** wildcard, an error is returned.\n\nExamples\n--------\n\nSET @json = \'[1, 2, [3, 4]]\';\n\nSELECT JSON_ARRAY_APPEND(@json, \'$[0]\', 5)\n+-------------------------------------+\n| JSON_ARRAY_APPEND(@json, \'$[0]\', 5) |\n+-------------------------------------+\n| [[1, 5], 2, [3, 4]] |\n+-------------------------------------+\n\nSELECT JSON_ARRAY_APPEND(@json, \'$[1]\', 6);\n+-------------------------------------+\n| JSON_ARRAY_APPEND(@json, \'$[1]\', 6) |\n+-------------------------------------+\n| [1, [2, 6], [3, 4]] |\n+-------------------------------------+\n\nSELECT JSON_ARRAY_APPEND(@json, \'$[1]\', 6, \'$[2]\', 7);\n+------------------------------------------------+\n| JSON_ARRAY_APPEND(@json, \'$[1]\', 6, \'$[2]\', 7) |\n+------------------------------------------------+\n| [1, [2, 6], [3, 4, 7]] |\n+------------------------------------------------+\n\nSELECT JSON_ARRAY_APPEND(@json, \'$\', 5);\n+----------------------------------+\n| JSON_ARRAY_APPEND(@json, \'$\', 5) |\n+----------------------------------+\n| [1, 2, [3, 4], 5] |\n+----------------------------------+\n\nSET @json = \'{\"A\": 1, \"B\": [2], \"C\": [3, 4]}\';\n\nSELECT JSON_ARRAY_APPEND(@json, \'$.B\', 5);\n+------------------------------------+\n| JSON_ARRAY_APPEND(@json, \'$.B\', 5) |\n+------------------------------------+\n| {\"A\": 1, \"B\": [2, 5], \"C\": [3, 4]} |\n+------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_array_append/','','https://mariadb.com/kb/en/json_array_append/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (750,40,'JSON_ARRAY_INSERT','Syntax\n------\n\nJSON_ARRAY_INSERT(json_doc, path, value[, path, value] ...)\n\nDescription\n-----------\n\nInserts a value into a JSON document, returning the modified document, or NULL\nif any of the arguments are NULL.\n\nEvaluation is performed from left to right, with the resulting document from\nthe previous pair becoming the new value against which the next pair is\nevaluated.\n\nIf the json_doc is not a valid JSON document, or if any of the paths are not\nvalid, or contain a * or ** wildcard, an error is returned.\n\nExamples\n--------\n\nSET @json = \'[1, 2, [3, 4]]\';\n\nSELECT JSON_ARRAY_INSERT(@json, \'$[0]\', 5);\n+-------------------------------------+\n| JSON_ARRAY_INSERT(@json, \'$[0]\', 5) |\n+-------------------------------------+\n| [5, 1, 2, [3, 4]] |\n+-------------------------------------+\n\nSELECT JSON_ARRAY_INSERT(@json, \'$[1]\', 6);\n+-------------------------------------+\n| JSON_ARRAY_INSERT(@json, \'$[1]\', 6) |\n+-------------------------------------+\n| [1, 6, 2, [3, 4]] |\n+-------------------------------------+\n\nSELECT JSON_ARRAY_INSERT(@json, \'$[1]\', 6, \'$[2]\', 7);\n+------------------------------------------------+\n| JSON_ARRAY_INSERT(@json, \'$[1]\', 6, \'$[2]\', 7) |\n+------------------------------------------------+\n| [1, 6, 7, 2, [3, 4]] |\n+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_array_insert/','','https://mariadb.com/kb/en/json_array_insert/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (751,40,'JSON_COMPACT','Syntax\n------\n\nJSON_COMPACT(json_doc)\n\nDescription\n-----------\n\nRemoves all unnecessary spaces so the json document is as short as possible.\n\nExample\n-------\n\nSET @j = \'{ \"A\": 1, \"B\": [2, 3]}\';\n\nSELECT JSON_COMPACT(@j), @j;\n+-------------------+------------------------+\n| JSON_COMPACT(@j) | @j |\n+-------------------+------------------------+\n| {\"A\":1,\"B\":[2,3]} | { \"A\": 1, \"B\": [2, 3]} |\n+-------------------+------------------------+\n\nURL: https://mariadb.com/kb/en/json_compact/','','https://mariadb.com/kb/en/json_compact/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (752,40,'JSON_CONTAINS','Syntax\n------\n\nJSON_CONTAINS(json_doc, val[, path])\n\nDescription\n-----------\n\nReturns whether or not the specified value is found in the given JSON document\nor, optionally, at the specified path within the document. Returns 1 if it\ndoes, 0 if not and NULL if any of the arguments are null. An error occurs if\nthe document or path is not valid, or contains the * or ** wildcards.\n\nExamples\n--------\n\nSET @json = \'{\"A\": 0, \"B\": {\"C\": 1}, \"D\": 2}\';\n\nSELECT JSON_CONTAINS(@json, \'2\', \'$.A\');\n+----------------------------------+\n| JSON_CONTAINS(@json, \'2\', \'$.A\') |\n+----------------------------------+\n| 0 |\n+----------------------------------+\n\nSELECT JSON_CONTAINS(@json, \'2\', \'$.D\');\n+----------------------------------+\n| JSON_CONTAINS(@json, \'2\', \'$.D\') |\n+----------------------------------+\n| 1 |\n+----------------------------------+\n\nSELECT JSON_CONTAINS(@json, \'{\"C\": 1}\', \'$.A\');\n+-----------------------------------------+\n| JSON_CONTAINS(@json, \'{\"C\": 1}\', \'$.A\') |\n+-----------------------------------------+\n| 0 |\n+-----------------------------------------+\n\nSELECT JSON_CONTAINS(@json, \'{\"C\": 1}\', \'$.B\');\n+-----------------------------------------+\n| JSON_CONTAINS(@json, \'{\"C\": 1}\', \'$.B\') |\n+-----------------------------------------+\n| 1 |\n+-----------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_contains/','','https://mariadb.com/kb/en/json_contains/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (753,40,'JSON_CONTAINS_PATH','Syntax\n------\n\nJSON_CONTAINS_PATH(json_doc, return_arg, path[, path] ...)\n\nDescription\n-----------\n\nIndicates whether the given JSON document contains data at the specified path\nor paths. Returns 1 if it does, 0 if not and NULL if any of the arguments are\nnull.\n\nThe return_arg can be one or all:\n\n* one - Returns 1 if at least one path exists within the JSON document. \n* all - Returns 1 only if all paths exist within the JSON document.\n\nExamples\n--------\n\nSET @json = \'{\"A\": 1, \"B\": [2], \"C\": [3, 4]}\';\n\nSELECT JSON_CONTAINS_PATH(@json, \'one\', \'$.A\', \'$.D\');\n+------------------------------------------------+\n| JSON_CONTAINS_PATH(@json, \'one\', \'$.A\', \'$.D\') |\n+------------------------------------------------+\n| 1 |\n+------------------------------------------------+\n1 row in set (0.00 sec)\n\nSELECT JSON_CONTAINS_PATH(@json, \'all\', \'$.A\', \'$.D\');\n+------------------------------------------------+\n| JSON_CONTAINS_PATH(@json, \'all\', \'$.A\', \'$.D\') |\n+------------------------------------------------+\n| 0 |\n+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_contains_path/','','https://mariadb.com/kb/en/json_contains_path/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (754,40,'JSON_DEPTH','Syntax\n------\n\nJSON_DEPTH(json_doc)\n\nDescription\n-----------\n\nReturns the maximum depth of the given JSON document, or NULL if the argument\nis null. An error will occur if the argument is an invalid JSON document.\n\n* Scalar values or empty arrays or objects have a depth of 1.\n* Arrays or objects that are not empty but contain only elements or member\nvalues of depth 1 will have a depth of 2.\n* In other cases, the depth will be greater than 2.\n\nExamples\n--------\n\nSELECT JSON_DEPTH(\'[]\'), JSON_DEPTH(\'true\'), JSON_DEPTH(\'{}\');\n+------------------+--------------------+------------------+\n| JSON_DEPTH(\'[]\') | JSON_DEPTH(\'true\') | JSON_DEPTH(\'{}\') |\n+------------------+--------------------+------------------+\n| 1 | 1 | 1 |\n+------------------+--------------------+------------------+\n\nSELECT JSON_DEPTH(\'[1, 2, 3]\'), JSON_DEPTH(\'[[], {}, []]\');\n+-------------------------+----------------------------+\n| JSON_DEPTH(\'[1, 2, 3]\') | JSON_DEPTH(\'[[], {}, []]\') |\n+-------------------------+----------------------------+\n| 2 | 2 |\n+-------------------------+----------------------------+\n\nSELECT JSON_DEPTH(\'[1, 2, [3, 4, 5, 6], 7]\');\n+---------------------------------------+\n| JSON_DEPTH(\'[1, 2, [3, 4, 5, 6], 7]\') |\n+---------------------------------------+\n| 3 |\n+---------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_depth/','','https://mariadb.com/kb/en/json_depth/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (755,40,'JSON_DETAILED','Syntax\n------\n\nJSON_DETAILED(json_doc[, tab_size])\nJSON_PRETTY(json_doc[, tab_size])\n\nDescription\n-----------\n\nRepresents JSON in the most understandable way emphasizing nested structures.\n\nJSON_PRETTY was added as an alias for JSON_DETAILED in MariaDB 10.10.3,\nMariaDB 10.9.5, MariaDB 10.8.7, MariaDB 10.7.8, MariaDB 10.6.12, MariaDB\n10.5.19 and MariaDB 10.4.28.\n\nExample\n-------\n\nSET @j = \'{ \"A\":1,\"B\":[2,3]}\';\n\nSELECT @j;\n+--------------------+\n| @j |\n+--------------------+\n| { \"A\":1,\"B\":[2,3]} |\n+--------------------+\n\nSELECT JSON_DETAILED(@j);\n+------------------------------------------------------------+\n| JSON_DETAILED(@j) |\n+------------------------------------------------------------+\n| {\n \"A\": 1,\n \"B\":\n [\n 2,\n 3\n ]\n} |\n+------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_detailed/','','https://mariadb.com/kb/en/json_detailed/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (756,40,'JSON_EQUALS','MariaDB starting with 10.7.0\n----------------------------\nJSON_EQUALS was added in MariaDB 10.7.0\n\nSyntax\n------\n\nJSON_EQUALS(json1, json2)\n\nDescription\n-----------\n\nChecks if there is equality between two json objects. Returns 1 if it there\nis, 0 if not, or NULL if any of the arguments are null.\n\nExamples\n--------\n\nSELECT JSON_EQUALS(\'{\"a\" :[1, 2, 3],\"b\":[4]}\', \'{\"b\":[4],\"a\":[1, 2, 3.0]}\');\n+------------------------------------------------------------------------+\n| JSON_EQUALS(\'{\"a\" :[1, 2, 3],\"b\":[4]}\', \'{\"b\":[4],\"a\":[1, 2, 3.0]}\') |\n+------------------------------------------------------------------------+\n| 1 |\n+------------------------------------------------------------------------+\n\nSELECT JSON_EQUALS(\'{\"a\":[1, 2, 3]}\', \'{\"a\":[1, 2, 3.01]}\');\n+------------------------------------------------------+\n| JSON_EQUALS(\'{\"a\":[1, 2, 3]}\', \'{\"a\":[1, 2, 3.01]}\') |\n+------------------------------------------------------+\n| 0 |\n+------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_equals/','','https://mariadb.com/kb/en/json_equals/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (757,40,'JSON_EXISTS','Syntax\n------\n\nDescription\n-----------\n\nDetermines whether a specified JSON value exists in the given data. Returns 1\nif found, 0 if not, or NULL if any of the inputs were NULL.\n\nExamples\n--------\n\nSELECT JSON_EXISTS(\'{\"key1\":\"xxxx\", \"key2\":[1, 2, 3]}\', \"$.key2\");\n+------------------------------------------------------------+\n| JSON_EXISTS(\'{\"key1\":\"xxxx\", \"key2\":[1, 2, 3]}\', \"$.key2\") |\n+------------------------------------------------------------+\n| 1 |\n+------------------------------------------------------------+\n\nSELECT JSON_EXISTS(\'{\"key1\":\"xxxx\", \"key2\":[1, 2, 3]}\', \"$.key3\");\n+------------------------------------------------------------+\n| JSON_EXISTS(\'{\"key1\":\"xxxx\", \"key2\":[1, 2, 3]}\', \"$.key3\") |\n+------------------------------------------------------------+\n| 0 |\n+------------------------------------------------------------+\n\nSELECT JSON_EXISTS(\'{\"key1\":\"xxxx\", \"key2\":[1, 2, 3]}\', \"$.key2[1]\");\n+---------------------------------------------------------------+\n| JSON_EXISTS(\'{\"key1\":\"xxxx\", \"key2\":[1, 2, 3]}\', \"$.key2[1]\") |\n+---------------------------------------------------------------+\n| 1 |\n+---------------------------------------------------------------+\n\nSELECT JSON_EXISTS(\'{\"key1\":\"xxxx\", \"key2\":[1, 2, 3]}\', \"$.key2[10]\");\n+----------------------------------------------------------------+\n| JSON_EXISTS(\'{\"key1\":\"xxxx\", \"key2\":[1, 2, 3]}\', \"$.key2[10]\") |\n+----------------------------------------------------------------+\n| 0 |\n+----------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_exists/','','https://mariadb.com/kb/en/json_exists/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (758,40,'JSON_EXTRACT','Syntax\n------\n\nJSON_EXTRACT(json_doc, path[, path] ...)\n\nDescription\n-----------\n\nExtracts data from a JSON document. The extracted data is selected from the\nparts matching the path arguments. Returns all matched values; either as a\nsingle matched value, or, if the arguments could return multiple values, a\nresult autowrapped as an array in the matching order.\n\nReturns NULL if no paths match or if any of the arguments are NULL.\n\nAn error will occur if any path argument is not a valid path, or if the\njson_doc argument is not a valid JSON document.\n\nThe path expression be a JSONPath expression as supported by MariaDB\n\nExamples\n--------\n\nSET @json = \'[1, 2, [3, 4]]\';\n\nSELECT JSON_EXTRACT(@json, \'$[1]\');\n+-----------------------------+\n| JSON_EXTRACT(@json, \'$[1]\') |\n+-----------------------------+\n| 2 |\n+-----------------------------+\n\nSELECT JSON_EXTRACT(@json, \'$[2]\');\n+-----------------------------+\n| JSON_EXTRACT(@json, \'$[2]\') |\n+-----------------------------+\n| [3, 4] |\n+-----------------------------+\n\nSELECT JSON_EXTRACT(@json, \'$[2][1]\');\n+--------------------------------+\n| JSON_EXTRACT(@json, \'$[2][1]\') |\n+--------------------------------+\n| 4 |\n+--------------------------------+\n\nURL: https://mariadb.com/kb/en/json_extract/','','https://mariadb.com/kb/en/json_extract/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (759,40,'JSON_INSERT','Syntax\n------\n\nJSON_INSERT(json_doc, path, val[, path, val] ...)\n\nDescription\n-----------\n\nInserts data into a JSON document, returning the resulting document or NULL if\neither of the json_doc or path arguments are null.\n\nAn error will occur if the JSON document is invalid, or if any of the paths\nare invalid or contain a * or ** wildcard.\n\nJSON_INSERT can only insert data while JSON_REPLACE can only update. JSON_SET\ncan update or insert data.\n\nExamples\n--------\n\nSET @json = \'{ \"A\": 0, \"B\": [1, 2]}\';\n\nSELECT JSON_INSERT(@json, \'$.C\', \'[3, 4]\');\n+--------------------------------------+\n| JSON_INSERT(@json, \'$.C\', \'[3, 4]\') |\n+--------------------------------------+\n| { \"A\": 0, \"B\": [1, 2], \"C\":\"[3, 4]\"} |\n+--------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_insert/','','https://mariadb.com/kb/en/json_insert/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (760,40,'JSON_KEYS','Syntax\n------\n\nJSON_KEYS(json_doc[, path])\n\nDescription\n-----------\n\nReturns the keys as a JSON array from the top-level value of a JSON object or,\nif the optional path argument is provided, the top-level keys from the path.\n\nExcludes keys from nested sub-objects in the top level value. The resulting\narray will be empty if the selected object is empty.\n\nReturns NULL if any of the arguments are null, a given path does not locate an\nobject, or if the json_doc argument is not an object.\n\nAn error will occur if JSON document is invalid, the path is invalid or if the\npath contains a * or ** wildcard.\n\nExamples\n--------\n\nSELECT JSON_KEYS(\'{\"A\": 1, \"B\": {\"C\": 2}}\');\n+--------------------------------------+\n| JSON_KEYS(\'{\"A\": 1, \"B\": {\"C\": 2}}\') |\n+--------------------------------------+\n| [\"A\", \"B\"] |\n+--------------------------------------+\n\nSELECT JSON_KEYS(\'{\"A\": 1, \"B\": 2, \"C\": {\"D\": 3}}\', \'$.C\');\n+-----------------------------------------------------+\n| JSON_KEYS(\'{\"A\": 1, \"B\": 2, \"C\": {\"D\": 3}}\', \'$.C\') |\n+-----------------------------------------------------+\n| [\"D\"] |\n+-----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_keys/','','https://mariadb.com/kb/en/json_keys/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (761,40,'JSON_LENGTH','Syntax\n------\n\nJSON_LENGTH(json_doc[, path])\n\nDescription\n-----------\n\nReturns the length of a JSON document, or, if the optional path argument is\ngiven, the length of the value within the document specified by the path.\n\nReturns NULL if any of the arguments argument are null or the path argument\ndoes not identify a value in the document.\n\nAn error will occur if the JSON document is invalid, the path is invalid or if\nthe path contains a * or ** wildcard.\n\nLength will be determined as follow:\n\n* A scalar\'s length is always 1.\n* If an array, the number of elements in the array.\n* If an object, the number of members in the object.\n\nThe length of nested arrays or objects are not counted.\n\nExamples\n--------\n\nURL: https://mariadb.com/kb/en/json_length/','','https://mariadb.com/kb/en/json_length/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (762,40,'JSON_LOOSE','Syntax\n------\n\nJSON_LOOSE(json_doc)\n\nDescription\n-----------\n\nAdds spaces to a JSON document to make it look more readable.\n\nExample\n-------\n\nSET @j = \'{ \"A\":1,\"B\":[2,3]}\';\n\nSELECT JSON_LOOSE(@j), @j;\n+-----------------------+--------------------+\n| JSON_LOOSE(@j) | @j |\n+-----------------------+--------------------+\n| {\"A\": 1, \"B\": [2, 3]} | { \"A\":1,\"B\":[2,3]} |\n+-----------------------+--------------------+\n\nURL: https://mariadb.com/kb/en/json_loose/','','https://mariadb.com/kb/en/json_loose/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (763,40,'JSON_MERGE','Syntax\n------\n\nJSON_MERGE(json_doc, json_doc[, json_doc] ...)\n\nDescription\n-----------\n\nMerges the given JSON documents.\n\nReturns the merged result,or NULL if any argument is NULL.\n\nAn error occurs if any of the arguments are not valid JSON documents.\n\nJSON_MERGE has been deprecated since MariaDB 10.2.25, MariaDB 10.3.16 and\nMariaDB 10.4.5. JSON_MERGE_PATCH is an RFC 7396-compliant replacement, and\nJSON_MERGE_PRESERVE is a synonym.\n\nExample\n-------\n\nSET @json1 = \'[1, 2]\';\nSET @json2 = \'[3, 4]\';\n\nSELECT JSON_MERGE(@json1,@json2);\n+---------------------------+\n| JSON_MERGE(@json1,@json2) |\n+---------------------------+\n| [1, 2, 3, 4] |\n+---------------------------+\n\nURL: https://mariadb.com/kb/en/json_merge/','','https://mariadb.com/kb/en/json_merge/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (764,40,'JSON_MERGE_PATCH','MariaDB starting with 10.3.16\n-----------------------------\nJSON_MERGE_PATCH was introduced in MariaDB 10.3.16 and MariaDB 10.4.5.\n\nSyntax\n------\n\nJSON_MERGE_PATCH(json_doc, json_doc[, json_doc] ...)\n\nDescription\n-----------\n\nMerges the given JSON documents, returning the merged result, or NULL if any\nargument is NULL.\n\nJSON_MERGE_PATCH is an RFC 7396-compliant replacement for JSON_MERGE, which\nhas been deprecated.\n\nExample\n-------\n\nSET @json1 = \'[1, 2]\';\nSET @json2 = \'[2, 3]\';\nSELECT JSON_MERGE_PATCH(@json1,@json2),JSON_MERGE_PRESERVE(@json1,@json2);\n+---------------------------------+------------------------------------+\n| JSON_MERGE_PATCH(@json1,@json2) | JSON_MERGE_PRESERVE(@json1,@json2) |\n+---------------------------------+------------------------------------+\n| [2, 3] | [1, 2, 2, 3] |\n+---------------------------------+------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_merge_patch/','','https://mariadb.com/kb/en/json_merge_patch/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (765,40,'JSON_MERGE_PRESERVE','MariaDB starting with 10.3.16\n-----------------------------\nJSON_MERGE_PRESERVE was introduced in MariaDB 10.3.16 and MariaDB 10.4.5.\n\nSyntax\n------\n\nJSON_MERGE_PRESERVE(json_doc, json_doc[, json_doc] ...)\n\nDescription\n-----------\n\nMerges the given JSON documents, returning the merged result, or NULL if any\nargument is NULL.\n\nJSON_MERGE_PRESERVE was introduced in MariaDB 10.2.25, MariaDB 10.3.16 and\nMariaDB 10.4.5 as a synonym for JSON_MERGE, which has been deprecated.\n\nExample\n-------\n\nSET @json1 = \'[1, 2]\';\nSET @json2 = \'[2, 3]\';\nSELECT JSON_MERGE_PATCH(@json1,@json2),JSON_MERGE_PRESERVE(@json1,@json2);\n+---------------------------------+------------------------------------+\n| JSON_MERGE_PATCH(@json1,@json2) | JSON_MERGE_PRESERVE(@json1,@json2) |\n+---------------------------------+------------------------------------+\n| [2, 3] | [1, 2, 2, 3] |\n+---------------------------------+------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_merge_preserve/','','https://mariadb.com/kb/en/json_merge_preserve/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (766,40,'JSON_NORMALIZE','MariaDB starting with 10.7.0\n----------------------------\nJSON_NORMALIZE was added in MariaDB 10.7.0.\n\nSyntax\n------\n\nJSON_NORMALIZE(json)\n\nDescription\n-----------\n\nRecursively sorts keys and removes spaces, allowing comparison of json\ndocuments for equality.\n\nExamples\n--------\n\nWe may wish our application to use the database to enforce a unique constraint\non the JSON contents, and we can do so using the JSON_NORMALIZE function in\ncombination with a unique key.\n\nFor example, if we have a table with a JSON column:\n\nCREATE TABLE t1 (\n id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,\n val JSON,\n /* other columns here */\n PRIMARY KEY (id)\n);\n\nAdd a unique constraint using JSON_NORMALIZE like this:\n\nALTER TABLE t1\n ADD COLUMN jnorm JSON AS (JSON_NORMALIZE(val)) VIRTUAL,\n ADD UNIQUE KEY (jnorm);\n\nWe can test this by first inserting a row as normal:\n\nINSERT INTO t1 (val) VALUES (\'{\"name\":\"alice\",\"color\":\"blue\"}\');\n\nAnd then seeing what happens with a different string which would produce the\nsame JSON object:\n\nINSERT INTO t1 (val) VALUES (\'{ \"color\": \"blue\", \"name\": \"alice\" }\');\nERROR 1062 (23000): Duplicate entry \'{\"color\":\"blue\",\"name\":\"alice\"}\' for key\n\'jnorm\'\n\nURL: https://mariadb.com/kb/en/json_normalize/','','https://mariadb.com/kb/en/json_normalize/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (767,40,'JSON_OBJECT','Syntax\n------\n\nJSON_OBJECT([key, value[, key, value] ...])\n\nDescription\n-----------\n\nReturns a JSON object containing the given key/value pairs. The key/value list\ncan be empty.\n\nAn error will occur if there are an odd number of arguments, or any key name\nis NULL.\n\nExample\n-------\n\nSELECT JSON_OBJECT(\"id\", 1, \"name\", \"Monty\");\n+---------------------------------------+\n| JSON_OBJECT(\"id\", 1, \"name\", \"Monty\") |\n+---------------------------------------+\n| {\"id\": 1, \"name\": \"Monty\"} |\n+---------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_object/','','https://mariadb.com/kb/en/json_object/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (768,40,'JSON_OVERLAPS','MariaDB starting with 10.9\n--------------------------\nJSON_OVERLAPS was added in MariaDB 10.9.\n\nSyntax\n------\n\nJSON_OVERLAPS(json_doc1, json_doc2)\n\nDescription\n-----------\n\nJSON_OVERLAPS() compares two json documents and returns true if they have at\nleast one common key-value pair between two objects, array element common\nbetween two arrays, or array element common with scalar if one of the\narguments is a scalar and other is an array. If two json documents are\nscalars, it returns true if they have same type and value.\n\nIf none of the above conditions are satisfied then it returns false.\n\nExamples\n--------\n\nSELECT JSON_OVERLAPS(\'false\', \'false\');\n+---------------------------------+\n| JSON_OVERLAPS(\'false\', \'false\') |\n+---------------------------------+\n| 1 |\n+---------------------------------+\n\nSELECT JSON_OVERLAPS(\'true\', \'[\"abc\", 1, 2, true, false]\');\n+----------------------------------------------------+\n| JSON_OVERLAPS(\'true\',\'[\"abc\", 1, 2, true, false]\') |\n+----------------------------------------------------+\n| 1 |\n+----------------------------------------------------+\n\nSELECT JSON_OVERLAPS(\'{\"A\": 1, \"B\": {\"C\":2}}\', \'{\"A\": 2, \"B\": {\"C\":2}}\') AS\nis_overlap;\n+---------------------+\n| is_overlap |\n+---------------------+\n| 1 |\n+---------------------+\n\nPartial match is considered as no-match.\n\nExamples\n--------\n\nSELECT JSON_OVERLAPS(\'[1, 2, true, false, null]\', \'[3, 4, [1]]\') AS is_overlap;\n+--------------------- +\n| is_overlap |\n+----------------------+\n| 0 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/json_overlaps/','','https://mariadb.com/kb/en/json_overlaps/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (769,40,'JSON_PRETTY','JSON_PRETTY was added as an alias for JSON_DETAILED in MariaDB 10.10.3,\nMariaDB 10.9.5, MariaDB 10.8.7, MariaDB 10.7.8, MariaDB 10.6.12, MariaDB\n10.5.19 and MariaDB 10.4.28.\n\nURL: https://mariadb.com/kb/en/json_pretty/','','https://mariadb.com/kb/en/json_pretty/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (770,40,'JSON_QUERY','Syntax\n------\n\nJSON_QUERY(json_doc, path)\n\nDescription\n-----------\n\nGiven a JSON document, returns an object or array specified by the path.\nReturns NULL if not given a valid JSON document, or if there is no match.\n\nExamples\n--------\n\nselect json_query(\'{\"key1\":{\"a\":1, \"b\":[1,2]}}\', \'$.key1\');\n+-----------------------------------------------------+\n| json_query(\'{\"key1\":{\"a\":1, \"b\":[1,2]}}\', \'$.key1\') |\n+-----------------------------------------------------+\n| {\"a\":1, \"b\":[1,2]} |\n+-----------------------------------------------------+\n\nselect json_query(\'{\"key1\":123, \"key1\": [1,2,3]}\', \'$.key1\');\n+-------------------------------------------------------+\n| json_query(\'{\"key1\":123, \"key1\": [1,2,3]}\', \'$.key1\') |\n+-------------------------------------------------------+\n| [1,2,3] |\n+-------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_query/','','https://mariadb.com/kb/en/json_query/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (771,40,'JSON_QUOTE','Syntax\n------\n\nJSON_QUOTE(json_value)\n\nDescription\n-----------\n\nQuotes a string as a JSON value, usually for producing valid JSON string\nliterals for inclusion in JSON documents. Wraps the string with double quote\ncharacters and escapes interior quotes and other special characters, returning\na utf8mb4 string.\n\nReturns NULL if the argument is NULL.\n\nExamples\n--------\n\nSELECT JSON_QUOTE(\'A\'), JSON_QUOTE(\"B\"), JSON_QUOTE(\'\"C\"\');\n+-----------------+-----------------+-------------------+\n| JSON_QUOTE(\'A\') | JSON_QUOTE(\"B\") | JSON_QUOTE(\'\"C\"\') |\n+-----------------+-----------------+-------------------+\n| \"A\" | \"B\" | \"\\\"C\\\"\" |\n+-----------------+-----------------+-------------------+\n\nURL: https://mariadb.com/kb/en/json_quote/','','https://mariadb.com/kb/en/json_quote/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (772,40,'JSON_REMOVE','Syntax\n------\n\nJSON_REMOVE(json_doc, path[, path] ...)\n\nDescription\n-----------\n\nRemoves data from a JSON document returning the result, or NULL if any of the\narguments are null. If the element does not exist in the document, no changes\nare made.\n\nThe function returns NULL and throws a warning if the JSON document is\ninvalid, the path is invalid, contains a range, or contains a * or ** wildcard.\n\nPath arguments are evaluated from left to right, with the result from the\nearlier evaluation being used as the value for the next.\n\nExamples\n--------\n\nSELECT JSON_REMOVE(\'{\"A\": 1, \"B\": 2, \"C\": {\"D\": 3}}\', \'$.C\');\n+-------------------------------------------------------+\n| JSON_REMOVE(\'{\"A\": 1, \"B\": 2, \"C\": {\"D\": 3}}\', \'$.C\') |\n+-------------------------------------------------------+\n| {\"A\": 1, \"B\": 2} |\n+-------------------------------------------------------+\n\nSELECT JSON_REMOVE(\'[\"A\", \"B\", [\"C\", \"D\"], \"E\"]\', \'$[1]\');\n+----------------------------------------------------+\n| JSON_REMOVE(\'[\"A\", \"B\", [\"C\", \"D\"], \"E\"]\', \'$[1]\') |\n+----------------------------------------------------+\n| [\"A\", [\"C\", \"D\"], \"E\"] |\n+----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_remove/','','https://mariadb.com/kb/en/json_remove/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (773,40,'JSON_REPLACE','Syntax\n------\n\nJSON_REPLACE(json_doc, path, val[, path, val] ...)\n\nDescription\n-----------\n\nReplaces existing values in a JSON document, returning the result, or NULL if\nany of the arguments are NULL.\n\nAn error will occur if the JSON document is invalid, the path is invalid or if\nthe path contains a * or ** wildcard.\n\nPaths and values are evaluated from left to right, with the result from the\nearlier evaluation being used as the value for the next.\n\nJSON_REPLACE can only update data, while JSON_INSERT can only insert. JSON_SET\ncan update or insert data.\n\nExamples\n--------\n\nSELECT JSON_REPLACE(\'{ \"A\": 1, \"B\": [2, 3]}\', \'$.B[1]\', 4);\n+-----------------------------------------------------+\n| JSON_REPLACE(\'{ \"A\": 1, \"B\": [2, 3]}\', \'$.B[1]\', 4) |\n+-----------------------------------------------------+\n| { \"A\": 1, \"B\": [2, 4]} |\n+-----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_replace/','','https://mariadb.com/kb/en/json_replace/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (774,40,'JSON_SCHEMA_VALID','MariaDB starting with 11.1\n--------------------------\nJSON_SCHEMA_VALID was introduced in MariaDB 11.1.\n\nSyntax\n------\n\nJSON_SCHEMA_VALID(schema, json);\n\nDescription\n-----------\n\nJSON_SCHEMA_VALID allows MariaDB to support JSON schema validation. If a given\njson is valid against a schema it returns true. When JSON does not validate\nagainst the schema, it does not return a message about which keyword it failed\nagainst and only returns false.\n\nThe function supports JSON Schema Draft 2020 with a few exceptions:\n\n* External resources are not supported\n* Hyper schema keywords are not supported\n* Formats like date, email etc are treated as annotations.\n\nExamples\n--------\n\nTo create validation rules for json field\n\nCREATE TABLE obj_table(val_obj JSON CHECK(JSON_SCHEMA_VALID(\'{\n \"type\":\"object\",\n \"properties\": {\n \"number1\":{\n \"type\":\"number\",\n \"maximum\":5,\n \"const\":4\n },\n \"string1\":{\n \"type\":\"string\",\n \"maxLength\":5,\n \"minLength\":3\n },\n \"object1\":{\n \"type\":\"object\",\n \"properties\":{\n \"key1\": {\"type\":\"string\"},\n \"key2\":{\"type\":\"array\"},\n \"key3\":{\"type\":\"number\", \"minimum\":3}\n },\n \"dependentRequired\": { \"key1\":[\"key3\"] }\n }\n },\n \"required\":[\"number1\",\"object1\"]\n }\', val_obj)));\n\nINSERT INTO obj_table VALUES(\n \'{\"number1\":4, \"string1\":\"abcd\",\n \"object1\":{\"key1\":\"val1\", \"key2\":[1,2,3, \"string1\"], \"key3\":4}}\'\n);\n\nINSERT INTO obj_table VALUES(\n \'{\"number1\":3, \"string1\":\"abcd\",\n \"object1\":{\"key1\":\"val1\", \"key2\":[1,2,3, \"string1\"], \"key3\":4}}\'\n);\nERROR 4025 (23000): CONSTRAINT `obj_table.val_obj` failed for\n`test`.`obj_table`\n\nSELECT * FROM obj_table;\n+------------------------------------------------------------------------------\n-------------------+\n| val_obj \n |\n+------------------------------------------------------------------------------\n-------------------+\n| {\"number1\":4, \"string1\":\"abcd\", \"object1\":{\"key1\":\"val1\", \"key2\":[1,2,3,\n\"string1\"], \"key3\":4}} |\n+------------------------------------------------------------------------------\n-------------------+\n\nSET @schema= \'{\n \"properties\" : {\n \"number1\":{ \"maximum\":10 },\n \"string1\" : { \"maxLength\": 3}\n }\n}\';\n\nSELECT JSON_SCHEMA_VALID(@schema, \'{ \"number1\":25, \"string1\":\"ab\" }\');\n+----------------------------------------------------------------+\n| JSON_SCHEMA_VALID(@schema, \'{ \"number1\":25, \"string1\":\"ab\" }\') |\n+----------------------------------------------------------------+\n| 0 |\n+----------------------------------------------------------------+\n\nSELECT JSON_SCHEMA_VALID(@schema, \'{ \"number1\":10, \"string1\":\"ab\" }\');\n+----------------------------------------------------------------+\n| JSON_SCHEMA_VALID(@schema, \'{ \"number1\":10, \"string1\":\"ab\" }\') |\n+----------------------------------------------------------------+\n| 1 |\n+----------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_schema_valid/','','https://mariadb.com/kb/en/json_schema_valid/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (775,40,'JSON_SEARCH','Syntax\n------\n\nJSON_SEARCH(json_doc, return_arg, search_str[, escape_char[, path] ...])\n\nDescription\n-----------\n\nReturns the path to the given string within a JSON document, or NULL if any of\njson_doc, search_str or a path argument is NULL; if the search string is not\nfound, or if no path exists within the document.\n\nA warning will occur if the JSON document is not valid, any of the path\narguments are not valid, if return_arg is neither one nor all, or if the\nescape character is not a constant. NULL will be returned.\n\nreturn_arg can be one of two values:\n\n* \'one: Terminates after finding the first match, so will return one path\nstring. If there is more than one match, it is undefined which is considered\nfirst.\n* all: Returns all matching path strings, without duplicates. Multiple strings\nare autowrapped as an array. The order is undefined.\n\nExamples\n--------\n\nSET @json = \'[\"A\", [{\"B\": \"1\"}], {\"C\":\"AB\"}, {\"D\":\"BC\"}]\';\n\nSELECT JSON_SEARCH(@json, \'one\', \'AB\');\n+---------------------------------+\n| JSON_SEARCH(@json, \'one\', \'AB\') |\n+---------------------------------+\n| \"$[2].C\" |\n+---------------------------------+\n\nURL: https://mariadb.com/kb/en/json_search/','','https://mariadb.com/kb/en/json_search/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (776,40,'JSON_SET','Syntax\n------\n\nJSON_SET(json_doc, path, val[, path, val] ...)\n\nDescription\n-----------\n\nUpdates or inserts data into a JSON document, returning the result, or NULL if\nany of the arguments are NULL or the optional path fails to find an object.\n\nAn error will occur if the JSON document is invalid, the path is invalid or if\nthe path contains a * or wildcard.\n\nJSON_SET can update or insert data, while JSON_REPLACE can only update, and\nJSON_INSERT only insert.\n\nExamples\n--------\n\nSELECT JSON_SET(Priv, \'$.locked\', \'true\') FROM mysql.global_priv\n\nURL: https://mariadb.com/kb/en/json_set/','','https://mariadb.com/kb/en/json_set/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (777,40,'JSON_TABLE','MariaDB starting with 10.6.0\n----------------------------\nJSON_TABLE was added in MariaDB 10.6.0.\n\nJSON_TABLE is a table function that converts JSON data into a relational form.\n\nSyntax\n------\n\nJSON_TABLE(json_doc, \n context_path COLUMNS (column_list)\n) [AS] alias\n\ncolumn_list:\n column[, column][, ...]\n\ncolumn:\n name FOR ORDINALITY\n | name type PATH path_str [on_empty] [on_error]\n | name type EXISTS PATH path_str\n | NESTED PATH path_str COLUMNS (column_list)\n\non_empty:\n {NULL | DEFAULT string | ERROR} ON EMPTY\n\non_error:\n {NULL | DEFAULT string | ERROR} ON ERROR\n\nDescription\n-----------\n\nJSON_TABLE can be used in contexts where a table reference can be used; in the\nFROM clause of a SELECT statement, and in multi-table UPDATE/DELETE statements.\n\njson_doc is the JSON document to extract data from. In the simplest case, it\nis a string literal containing JSON. In more complex cases it can be an\narbitrary expression returning JSON. The expression may have references to\ncolumns of other tables. However, one can only refer to tables that precede\nthis JSON_TABLE invocation. For RIGHT JOIN, it is assumed that its outer side\nprecedes the inner. All tables in outer selects are also considered preceding.\n\ncontext_path is a JSON Path expression pointing to a collection of nodes in\njson_doc that will be used as the source of rows.\n\nThe COLUMNS clause declares the names and types of the columns that JSON_TABLE\nreturns, as well as how the values of the columns are produced.\n\nColumn Definitions\n------------------\n\nThe following types of columns are supported:\n\nPath Columns\n------------\n\nname type PATH path_str [on_empty] [on_error]\n\nLocates the JSON node pointed to by path_str and returns its value. The\npath_str is evaluated using the current row source node as the context node.\n\nset @json=\'\n[\n {\"name\":\"Laptop\", \"color\":\"black\", \"price\":\"1000\"},\n {\"name\":\"Jeans\", \"color\":\"blue\"}\n]\';\n\nselect * from json_table(@json, \'$[*]\' \n columns(\n name varchar(10) path \'$.name\',\n color varchar(10) path \'$.color\',\n price decimal(8,2) path \'$.price\' )\n) as jt;\n+--------+-------+---------+\n| name | color | price |\n+--------+-------+---------+\n| Laptop | black | 1000.00 |\n| Jeans | blue | NULL |\n+--------+-------+---------+\n\nThe on_empty and on_error clauses specify the actions to be performed when the\nvalue was not found or there was an error condition. See the ON EMPTY and ON\nERROR clauses section for details.\n\nORDINALITY Columns\n------------------\n\nname FOR ORDINALITY\n\nCounts the rows, starting from 1.\n\nExample:\n\nset @json=\'\n[\n {\"name\":\"Laptop\", \"color\":\"black\"},\n {\"name\":\"Jeans\", \"color\":\"blue\"}\n]\';\n\nselect * from json_table(@json, \'$[*]\' \n columns(\n id for ordinality,\n name varchar(10) path \'$.name\')\n) as jt;\n+------+--------+\n| id | name |\n+------+--------+\n| 1 | Laptop |\n| 2 | Jeans |\n+------+--------+\n\nEXISTS PATH Columns\n-------------------\n\nname type EXISTS PATH path_str\n\nChecks whether the node pointed to by value_path exists. The value_path is\nevaluated using the current row source node as the context node.\n\nset @json=\'\n[\n {\"name\":\"Laptop\", \"color\":\"black\", \"price\":1000},\n {\"name\":\"Jeans\", \"color\":\"blue\"}\n]\';\n\nselect * from json_table(@json, \'$[*]\' \n columns(\n name varchar(10) path \'$.name\',\n has_price integer exists path \'$.price\')\n) as jt;\n+--------+-----------+\n| name | has_price |\n+--------+-----------+\n| Laptop | 1 |\n| Jeans | 0 |\n+--------+-----------+\n\nNESTED PATHs\n------------\n\nNESTED PATH converts nested JSON structures into multiple rows.\n\nNESTED PATH path COLUMNS (column_list)\n\nIt finds the sequence of JSON nodes pointed to by path and uses it to produce\nrows. For each found node, a row is generated with column values as specified\nby the NESTED PATH\'s COLUMNS clause. If path finds no nodes, only one row is\ngenerated with all columns having NULL values.\n\nFor example, consider a JSON document that contains an array of items, and\neach item, in turn, is expected to have an array of its available sizes:\n\nset @json=\'\n[\n {\"name\":\"Jeans\", \"sizes\": [32, 34, 36]},\n {\"name\":\"T-Shirt\", \"sizes\":[\"Medium\", \"Large\"]},\n {\"name\":\"Cellphone\"}\n]\';\n\nNESTED PATH allows one to produce a separate row for each size each item has:\n\nselect * from json_table(@json, \'$[*]\' \n columns(\n name varchar(10) path \'$.name\',\n nested path \'$.sizes[*]\' columns (\n size varchar(32) path \'$\'\n )\n )\n) as jt;\n+-----------+--------+\n| name | size |\n+-----------+--------+\n| Jeans | 32 |\n| Jeans | 34 |\n| Jeans | 36 |\n| T-Shirt | Medium |\n| T-Shirt | Large |\n| Cellphone | NULL |\n+-----------+--------+\n\nNESTED PATH clauses can be nested within one another. They can also be located\nnext to each other. In that case, the nested path clauses will produce records\none at a time. The ones that are not producing records will have all columns\nset to NULL.\n\nExample:\n\nset @json=\'\n[\n {\"name\":\"Jeans\", \"sizes\": [32, 34, 36], \"colors\":[\"black\", \"blue\"]}\n]\';\n\nselect * from json_table(@json, \'$[*]\' \n columns(\n name varchar(10) path \'$.name\',\n nested path \'$.sizes[*]\' columns (\n size varchar(32) path \'$\'\n ),\n nested path \'$.colors[*]\' columns (\n color varchar(32) path \'$\'\n )\n )\n) as jt;\n\n+-------+------+-------+\n| name | size | color |\n+-------+------+-------+\n| Jeans | 32 | NULL |\n| Jeans | 34 | NULL |\n| Jeans | 36 | NULL |\n| Jeans | NULL | black |\n| Jeans | NULL | blue |\n+-------+------+-------+\n\nON EMPTY and ON ERROR Clauses\n-----------------------------\n\nThe ON EMPTY clause specifies what will be done when the element specified by\nthe search path is missing in the JSON document.\n\non_empty:\n {NULL | DEFAULT string | ERROR} ON EMPTY\n\nWhen ON EMPTY clause is not present, NULL ON EMPTY is implied.\n\non_error:\n {NULL | DEFAULT string | ERROR} ON ERROR\n\nThe ON ERROR clause specifies what should be done if a JSON structure error\noccurs when trying to extract the value pointed to by the path expression. A\nJSON structure error here occurs only when one attempts to convert a JSON\nnon-scalar (array or object) into a scalar value. When the ON ERROR clause is\nnot present, NULL ON ERROR is implied.\n\nNote: A datatype conversion error (e.g. attempt to store a non-integer value\ninto an integer field, or a varchar column being truncated) is not considered\na JSON error and so will not trigger the ON ERROR behavior. It will produce\nwarnings, in the same way as CAST(value AS datatype) would.\n\nReplication\n-----------\n\nIn the current code, evaluation of JSON_TABLE is deterministic, that is, for a\ngiven input string JSON_TABLE will always produce the same set of rows in the\nsame order. However, one can think of JSON documents that one can consider\nidentical which will produce different output. In order to be future-proof and\nwithstand changes like:\n\n* sorting JSON object members by name (like MySQL does)\n* changing the way duplicate object members are handled\nthe function is marked as unsafe for statement-based replication.\n\nExtracting a Subdocument into a Column\n--------------------------------------\n\nMariaDB starting with 10.6.9\n----------------------------\nPrior to MariaDB 10.6.9, JSON_TABLE did not allow one to extract a JSON\n\"subdocument\" into a JSON column.\n\nSELECT * FROM JSON_TABLE(\'{\"foo\": [1,2,3,4]}\',\'$\' columns( jscol json path\n\'$.foo\') ) AS T;\n+-------+\n| jscol |\n+-------+\n| NULL |\n+-------+\n\nThis is supported from MariaDB 10.6.9:\n\nSELECT * FROM JSON_TABLE(\'{\"foo\": [1,2,3,4]}\',\'$\' columns( jscol json path\n\'$.foo\') ) AS T;\n+-----------+\n| jscol |\n+-----------+\n| [1,2,3,4] |\n+-----------+\n\nURL: https://mariadb.com/kb/en/json_table/','','https://mariadb.com/kb/en/json_table/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (778,40,'JSON_TYPE','Syntax\n------\n\nJSON_TYPE(json_val)\n\nDescription\n-----------\n\nReturns the type of a JSON value (as a string), or NULL if the argument is\nnull.\n\nAn error will occur if the argument is an invalid JSON value.\n\nThe following is a complete list of the possible return types:\n\n+-----------------------------------+-----------------+-----------------------+\n| Return type | Value | Example |\n+-----------------------------------+-----------------+-----------------------+\n| ARRAY | JSON array | [1, 2, {\"key\": |\n| | | \"value\"}] |\n+-----------------------------------+-----------------+-----------------------+\n| OBJECT | JSON object | {\"key\":\"value\"} |\n+-----------------------------------+-----------------+-----------------------+\n| BOOLEAN | JSON | true, false |\n| | true/false | |\n| | literals | |\n+-----------------------------------+-----------------+-----------------------+\n| DOUBLE | A number with | 1.2 |\n| | at least one | |\n| | floating point | |\n| | decimal. | |\n+-----------------------------------+-----------------+-----------------------+\n| INTEGER | A number | 1 |\n| | without a | |\n| | floating point | |\n| | decimal. | |\n+-----------------------------------+-----------------+-----------------------+\n| NULL | JSON null | null |\n| | literal (this | |\n| | is returned as | |\n| | a string, not | |\n| | to be confused | |\n| | with the SQL | |\n| | NULL value!) | |\n+-----------------------------------+-----------------+-----------------------+\n| STRING | JSON String | \"a sample string\" |\n+-----------------------------------+-----------------+-----------------------+\n\nExamples\n--------\n\nSELECT JSON_TYPE(\'{\"A\": 1, \"B\": 2, \"C\": 3}\');\n+---------------------------------------+\n| JSON_TYPE(\'{\"A\": 1, \"B\": 2, \"C\": 3}\') |\n+---------------------------------------+\n| OBJECT |\n+---------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_type/','','https://mariadb.com/kb/en/json_type/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (779,40,'JSON_UNQUOTE','Syntax\n------\n\nJSON_UNQUOTE(val)\n\nDescription\n-----------\n\nUnquotes a JSON value, returning a string, or NULL if the argument is null.\n\nAn error will occur if the given value begins and ends with double quotes and\nis an invalid JSON string literal.\n\nIf the given value is not a JSON string, value is passed through unmodified.\n\nCertain character sequences have special meanings within a string. Usually, a\nbackslash is ignored, but the escape sequences in the table below are\nrecognised by MariaDB, unless the SQL Mode is set to NO_BACKSLASH_ESCAPES SQL.\n\n+-----------------------------------------------+-----------------------------+\n| Escape sequence | Character |\n+-----------------------------------------------+-----------------------------+\n| \\\" | Double quote (\") |\n+-----------------------------------------------+-----------------------------+\n| \\b | Backslash |\n+-----------------------------------------------+-----------------------------+\n| \\f | Formfeed |\n+-----------------------------------------------+-----------------------------+\n| \\n | Newline (linefeed) |\n+-----------------------------------------------+-----------------------------+\n| \\r | Carriage return |\n+-----------------------------------------------+-----------------------------+\n| \\t | Tab |\n+-----------------------------------------------+-----------------------------+\n| \\\\ | Backslash (\\) |\n+-----------------------------------------------+-----------------------------+\n| \\uXXXX | UTF-8 bytes for Unicode |\n| | value XXXX |\n+-----------------------------------------------+-----------------------------+\n\nExamples\n--------\n\nSELECT JSON_UNQUOTE(\'\"Monty\"\');\n+-------------------------+\n| JSON_UNQUOTE(\'\"Monty\"\') |\n+-------------------------+\n| Monty |\n+-------------------------+\n\nWith the default SQL Mode:\n\nSELECT JSON_UNQUOTE(\'Si\\bng\\ting\');\n+-----------------------------+\n| JSON_UNQUOTE(\'Si\\bng\\ting\') |\n+-----------------------------+\n| Sng ing |\n+-----------------------------+\n\nSetting NO_BACKSLASH_ESCAPES:\n\nSET @@sql_mode = \'NO_BACKSLASH_ESCAPES\';\n\nSELECT JSON_UNQUOTE(\'Si\\bng\\ting\');\n+-----------------------------+\n| JSON_UNQUOTE(\'Si\\bng\\ting\') |\n+-----------------------------+\n| Si\\bng\\ting |\n+-----------------------------+\n\nURL: https://mariadb.com/kb/en/json_unquote/','','https://mariadb.com/kb/en/json_unquote/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (780,40,'JSON_VALID','Syntax\n------\n\nJSON_VALID(value)\n\nDescription\n-----------\n\nIndicates whether the given value is a valid JSON document or not. Returns 1\nif valid, 0 if not, and NULL if the argument is NULL.\n\nFrom MariaDB 10.4.3, the JSON_VALID function is automatically used as a CHECK\nconstraint for the JSON data type alias in order to ensure that a valid json\ndocument is inserted.\n\nExamples\n--------\n\nSELECT JSON_VALID(\'{\"id\": 1, \"name\": \"Monty\"}\');\n+------------------------------------------+\n| JSON_VALID(\'{\"id\": 1, \"name\": \"Monty\"}\') |\n+------------------------------------------+\n| 1 |\n+------------------------------------------+\n\nSELECT JSON_VALID(\'{\"id\": 1, \"name\": \"Monty\", \"oddfield\"}\');\n+------------------------------------------------------+\n| JSON_VALID(\'{\"id\": 1, \"name\": \"Monty\", \"oddfield\"}\') |\n+------------------------------------------------------+\n| 0 |\n+------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_valid/','','https://mariadb.com/kb/en/json_valid/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (781,40,'JSON_VALUE','Syntax\n------\n\nJSON_VALUE(json_doc, path)\n\nDescription\n-----------\n\nGiven a JSON document, returns the scalar specified by the path. Returns NULL\nif not given a valid JSON document, or if there is no match.\n\nExamples\n--------\n\nselect json_value(\'{\"key1\":123}\', \'$.key1\');\n+--------------------------------------+\n| json_value(\'{\"key1\":123}\', \'$.key1\') |\n+--------------------------------------+\n| 123 |\n+--------------------------------------+\n\nselect json_value(\'{\"key1\": [1,2,3], \"key1\":123}\', \'$.key1\');\n+-------------------------------------------------------+\n| json_value(\'{\"key1\": [1,2,3], \"key1\":123}\', \'$.key1\') |\n+-------------------------------------------------------+\n| 123 |\n+-------------------------------------------------------+\n\nIn the SET statement below, two escape characters are needed, as a single\nescape character would be applied by the SQL parser in the SET statement, and\nthe escaped character would not form part of the saved value.\n\nSET @json = \'{\"key1\":\"60\\\\\" Table\", \"key2\":\"1\"}\';\n\nSELECT JSON_VALUE(@json,\'$.key1\') AS Name , json_value(@json,\'$.key2\') as ID;\n+-----------+------+\n| Name | ID |\n+-----------+------+\n| 60\" Table | 1 |\n+-----------+------+\n\nURL: https://mariadb.com/kb/en/json_value/','','https://mariadb.com/kb/en/json_value/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (782,41,'Window Functions Overview','Introduction\n------------\n\nWindow functions allow calculations to be performed across a set of rows\nrelated to the current row.\n\nSyntax\n------\n\nfunction (expression) OVER (\n [ PARTITION BY expression_list ]\n [ ORDER BY order_list [ frame_clause ] ] )\n\nfunction:\n A valid window function\n\nexpression_list:\n expression | column_name [, expr_list ]\n\norder_list:\n expression | column_name [ ASC | DESC ]\n [, ... ]\n\nframe_clause:\n {ROWS | RANGE} {frame_border | BETWEEN frame_border AND frame_border}\n\nframe_border:\n | UNBOUNDED PRECEDING\n | UNBOUNDED FOLLOWING\n | CURRENT ROW\n | expr PRECEDING\n | expr FOLLOWING\n\nDescription\n-----------\n\nIn some ways, window functions are similar to aggregate functions in that they\nperform calculations across a set of rows. However, unlike aggregate\nfunctions, the output is not grouped into a single row.\n\nNon-aggregate window functions include\n\n* CUME_DIST\n* DENSE_RANK\n* FIRST_VALUE\n* LAG\n* LAST_VALUE\n* LEAD\n* MEDIAN\n* NTH_VALUE\n* NTILE\n* PERCENT_RANK\n* PERCENTILE_CONT\n* PERCENTILE_DISC\n* RANK, ROW_NUMBER\n\nAggregate functions that can also be used as window functions include\n\n* AVG\n* BIT_AND\n* BIT_OR\n* BIT_XOR\n* COUNT\n* MAX\n* MIN\n* STD\n* STDDEV\n* STDDEV_POP\n* STDDEV_SAMP\n* SUM\n* VAR_POP\n* VAR_SAMP\n* VARIANCE\n\nWindow function queries are characterised by the OVER keyword, following which\nthe set of rows used for the calculation is specified. By default, the set of\nrows used for the calculation (the \"window) is the entire dataset, which can\nbe ordered with the ORDER BY clause. The PARTITION BY clause is used to reduce\nthe window to a particular group within the dataset.\n\nFor example, given the following data:\n\nCREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87), (\'Tatiana\', \'Tuning\', 83);\n\nthe following two queries return the average partitioned by test and by name\nrespectively:\n\nSELECT name, test, score, AVG(score) OVER (PARTITION BY test) \n AS average_by_test FROM student;\n+---------+--------+-------+-----------------+\n| name | test | score | average_by_test |\n+---------+--------+-------+-----------------+\n| Chun | SQL | 75 | 65.2500 |\n| Chun | Tuning | 73 | 68.7500 |\n| Esben | SQL | 43 | 65.2500 |\n| Esben | Tuning | 31 | 68.7500 |\n| Kaolin | SQL | 56 | 65.2500 |\n| Kaolin | Tuning | 88 | 68.7500 |\n| Tatiana | SQL | 87 | 65.2500 |\n| Tatiana | Tuning | 83 | 68.7500 |\n+---------+--------+-------+-----------------+\n\nSELECT name, test, score, AVG(score) OVER (PARTITION BY name) \n AS average_by_name FROM student;\n+---------+--------+-------+-----------------+\n| name | test | score | average_by_name |\n+---------+--------+-------+-----------------+\n| Chun | SQL | 75 | 74.0000 |\n| Chun | Tuning | 73 | 74.0000 |\n| Esben | SQL | 43 | 37.0000 |\n| Esben | Tuning | 31 | 37.0000 |\n| Kaolin | SQL | 56 | 72.0000 |\n| Kaolin | Tuning | 88 | 72.0000 |\n| Tatiana | SQL | 87 | 85.0000 |\n| Tatiana | Tuning | 83 | 85.0000 |\n+---------+--------+-------+-----------------+\n\nIt is also possible to specify which rows to include for the window function\n(for example, the current row and all preceding rows). See Window Frames for\nmore details.\n\nScope\n-----\n\nWindow functions were introduced in SQL:2003, and their definition was\nexpanded in subsequent versions of the standard. The last expansion was in the\nlatest version of the standard, SQL:2011.\n\nMost database products support a subset of the standard, they implement some\nfunctions defined as late as in SQL:2011, and at the same time leave some\nparts of SQL:2008 unimplemented.\n\nMariaDB:\n\n* Supports ROWS and RANGE-type frames\nAll kinds of frame bounds are supported, including RANGE PRECEDING|FOLLOWING n\nframe bounds (unlike PostgreSQL or MS SQL Server)\nDoes not yet support DATE[TIME] datatype and arithmetic for RANGE-type frames\n(MDEV-9727)\n\n* Does not support GROUPS-type frames (it seems that no popular database\nsupports it, either)\n\n* Does not support frame exclusion (no other database seems to support it,\neither) (MDEV-9724)\n* Does not support explicit NULLS FIRST or NULLS LAST.\n* Does not support nested navigation in window functions (this is\nVALUE_OF(expr AT row_marker [, default_value) syntax)\n\n* The following window functions are supported:\n\"Streamable\" window functions: ROW_NUMBER, RANK, DENSE_RANK, \nWindow functions that can be streamed once the number of rows in partition is\nknown: PERCENT_RANK, CUME_DIST, NTILE\n\n* Aggregate functions that are currently supported as window functions are:\nCOUNT, SUM, AVG, BIT_OR, BIT_AND, BIT_XOR.\n* Aggregate functions with the DISTINCT specifier (e.g. COUNT( DISTINCT x))\nare not supported as window functions.\n\nLinks\n-----\n\n* MDEV-6115 is the main jira task for window functions development. Other\ntasks are are attached as sub-tasks\n* bb-10.2-mdev9543 is the feature tree for window functions. Development is\nongoing, and this tree has the newest changes.\n* Testcases are in mysql-test/t/win*.test\n\nExamples\n--------\n\nGiven the following sample data:\n\nCREATE TABLE users (\n email VARCHAR(30),\n first_name VARCHAR(30),\n last_name VARCHAR(30),\n account_type VARCHAR(30)\n);\n\nINSERT INTO users VALUES \n (\'admin@boss.org\', \'Admin\', \'Boss\', \'admin\'),\n (\'bob.carlsen@foo.bar\', \'Bob\', \'Carlsen\', \'regular\'),\n (\'eddie.stevens@data.org\', \'Eddie\', \'Stevens\', \'regular\'),\n (\'john.smith@xyz.org\', \'John\', \'Smith\', \'regular\'),\n (\'root@boss.org\', \'Root\', \'Chief\', \'admin\')\n\nFirst, let\'s order the records by email alphabetically, giving each an\nascending rnum value starting with 1. This will make use of the ROW_NUMBER\nwindow function:\n\nSELECT row_number() OVER (ORDER BY email) AS rnum,\n email, first_name, last_name, account_type\nFROM users ORDER BY email;\n+------+------------------------+------------+-----------+--------------+\n| rnum | email | first_name | last_name | account_type |\n+------+------------------------+------------+-----------+--------------+\n| 1 | admin@boss.org | Admin | Boss | admin |\n| 2 | bob.carlsen@foo.bar | Bob | Carlsen | regular |\n| 3 | eddie.stevens@data.org | Eddie | Stevens | regular |\n| 4 | john.smith@xyz.org | John | Smith | regular |\n| 5 | root@boss.org | Root | Chief | admin |\n+------+------------------------+------------+-----------+--------------\n\nWe can generate separate sequences based on account type, using the PARTITION\nBY clause:\n\nSELECT row_number() OVER (PARTITION BY account_type ORDER BY email) AS rnum, \n email, first_name, last_name, account_type\nFROM users ORDER BY account_type,email;\n+------+------------------------+------------+-----------+--------------+\n| rnum | email | first_name | last_name | account_type |\n+------+------------------------+------------+-----------+--------------+\n| 1 | admin@boss.org | Admin | Boss | admin |\n| 2 | root@boss.org | Root | Chief | admin |\n| 1 | bob.carlsen@foo.bar | Bob | Carlsen | regular |\n| 2 | eddie.stevens@data.org | Eddie | Stevens | regular |\n| 3 | john.smith@xyz.org | John | Smith | regular |\n+------+------------------------+------------+-----------+--------------+\n\nGiven the following structure and data, we want to find the top 5 salaries\nfrom each department.\n\nCREATE TABLE employee_salaries (dept VARCHAR(20), name VARCHAR(20), salary\nINT(11));\n\nINSERT INTO employee_salaries VALUES\n(\'Engineering\', \'Dharma\', 3500),\n(\'Engineering\', \'Binh\', 3000),\n(\'Engineering\', \'Adalynn\', 2800),\n(\'Engineering\', \'Samuel\', 2500),\n(\'Engineering\', \'Cveta\', 2200),\n(\'Engineering\', \'Ebele\', 1800),\n(\'Sales\', \'Carbry\', 500),\n(\'Sales\', \'Clytemnestra\', 400),\n(\'Sales\', \'Juraj\', 300),\n(\'Sales\', \'Kalpana\', 300),\n(\'Sales\', \'Svantepolk\', 250),\n(\'Sales\', \'Angelo\', 200);\n\nWe could do this without using window functions, as follows:\n\nselect dept, name, salary\nfrom employee_salaries as t1\nwhere (select count(t2.salary)\n from employee_salaries as t2\n where t1.name != t2.name and\n t1.dept = t2.dept and\n t2.salary > t1.salary) < 5\norder by dept, salary desc;\n\n+-------------+--------------+--------+\n| dept | name | salary |\n+-------------+--------------+--------+\n| Engineering | Dharma | 3500 |\n| Engineering | Binh | 3000 |\n| Engineering | Adalynn | 2800 |\n| Engineering | Samuel | 2500 |\n| Engineering | Cveta | 2200 |\n| Sales | Carbry | 500 |\n| Sales | Clytemnestra | 400 |\n| Sales | Juraj | 300 |\n| Sales | Kalpana | 300 |\n| Sales | Svantepolk | 250 |\n+-------------+--------------+--------+\n\nThis has a number of disadvantages:\n\n* if there is no index, the query could take a long time if the\nemployee_salary_table is large\n* Adding and maintaining indexes adds overhead, and even with indexes on dept\nand salary, each subquery execution adds overhead by performing a lookup\nthrough the index.\n\nLet\'s try achieve the same with window functions. First, generate a rank for\nall employees, using the RANK function.\n\nselect rank() over (partition by dept order by salary desc) as ranking,\n dept, name, salary\n from employee_salaries\n order by dept, ranking;\n+---------+-------------+--------------+--------+\n| ranking | dept | name | salary |\n+---------+-------------+--------------+--------+\n| 1 | Engineering | Dharma | 3500 |\n| 2 | Engineering | Binh | 3000 |\n| 3 | Engineering | Adalynn | 2800 |\n| 4 | Engineering | Samuel | 2500 |\n| 5 | Engineering | Cveta | 2200 |\n| 6 | Engineering | Ebele | 1800 |\n| 1 | Sales | Carbry | 500 |\n| 2 | Sales | Clytemnestra | 400 |\n| 3 | Sales | Juraj | 300 |\n| 3 | Sales | Kalpana | 300 |\n| 5 | Sales | Svantepolk | 250 |\n| 6 | Sales | Angelo | 200 |\n+---------+-------------+--------------+--------+\n\nEach department has a separate sequence of ranks due to the PARTITION BY\nclause. This particular sequence of values for rank() is given by the ORDER BY\nclause inside the window function’s OVER clause. Finally, to get our results\nin a readable format we order the data by dept and the newly generated ranking\ncolumn.\n\nNow, we need to reduce the results to find only the top 5 per department. Here\nis a common mistake:\n\nselect\nrank() over (partition by dept order by salary desc) as ranking,\ndept, name, salary\nfrom employee_salaries\nwhere ranking <= 5\norder by dept, ranking;\n\nERROR 1054 (42S22): Unknown column \'ranking\' in \'where clause\'\n\nTrying to filter only the first 5 values per department by putting a where\nclause in the statement does not work, due to the way window functions are\ncomputed. The computation of window functions happens after all WHERE, GROUP\nBY and HAVING clauses have been completed, right before ORDER BY, so the WHERE\nclause has no idea that the ranking column exists. It is only present after we\nhave filtered and grouped all the rows.\n\nTo counteract this problem, we need to wrap our query into a derived table. We\ncan then attach a where clause to it:\n\nselect *from (select rank() over (partition by dept order by salary desc) as\nranking,\n dept, name, salary\nfrom employee_salaries) as salary_ranks\nwhere (salary_ranks.ranking <= 5)\n order by dept, ranking;\n+---------+-------------+--------------+--------+\n| ranking | dept | name | salary |\n+---------+-------------+--------------+--------+\n| 1 | Engineering | Dharma | 3500 |\n| 2 | Engineering | Binh | 3000 |\n| 3 | Engineering | Adalynn | 2800 |\n| 4 | Engineering | Samuel | 2500 |\n| 5 | Engineering | Cveta | 2200 |\n| 1 | Sales | Carbry | 500 |\n| 2 | Sales | Clytemnestra | 400 |\n| 3 | Sales | Juraj | 300 |\n| 3 | Sales | Kalpana | 300 |\n| 5 | Sales | Svantepolk | 250 |\n+---------+-------------+--------------+--------+\n\nURL: https://mariadb.com/kb/en/window-functions-overview/','','https://mariadb.com/kb/en/window-functions-overview/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (783,41,'CUME_DIST','Syntax\n------\n\nCUME_DIST() OVER ( \n [ PARTITION BY partition_expression ]\n [ ORDER BY order_list ]\n)\n\nDescription\n-----------\n\nCUME_DIST() is a window function that returns the cumulative distribution of a\ngiven row. The following formula is used to calculate the value:\n\n(number of rows <= current row) / (total rows)\n\nExamples\n--------\n\ncreate table t1 (\n pk int primary key,\n a int,\n b int\n);\n\ninsert into t1 values\n( 1 , 0, 10),\n( 2 , 0, 10),\n( 3 , 1, 10),\n( 4 , 1, 10),\n( 8 , 2, 10),\n( 5 , 2, 20),\n( 6 , 2, 20),\n( 7 , 2, 20),\n( 9 , 4, 20),\n(10 , 4, 20);\n\nselect pk, a, b,\n rank() over (order by a) as rank,\n percent_rank() over (order by a) as pct_rank,\n cume_dist() over (order by a) as cume_dist\nfrom t1;\n+----+------+------+------+--------------+--------------+\n| pk | a | b | rank | pct_rank | cume_dist |\n+----+------+------+------+--------------+--------------+\n| 1 | 0 | 10 | 1 | 0.0000000000 | 0.2000000000 |\n| 2 | 0 | 10 | 1 | 0.0000000000 | 0.2000000000 |\n| 3 | 1 | 10 | 3 | 0.2222222222 | 0.4000000000 |\n| 4 | 1 | 10 | 3 | 0.2222222222 | 0.4000000000 |\n| 5 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 6 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 7 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 8 | 2 | 10 | 5 | 0.4444444444 | 0.8000000000 |\n| 9 | 4 | 20 | 9 | 0.8888888889 | 1.0000000000 |\n| 10 | 4 | 20 | 9 | 0.8888888889 | 1.0000000000 |\n+----+------+------+------+--------------+--------------+\n\nselect pk, a, b,\n percent_rank() over (order by pk) as pct_rank,\n cume_dist() over (order by pk) as cume_dist\nfrom t1 order by pk;\n+----+------+------+--------------+--------------+\n| pk | a | b | pct_rank | cume_dist |\n+----+------+------+--------------+--------------+\n| 1 | 0 | 10 | 0.0000000000 | 0.1000000000 |\n| 2 | 0 | 10 | 0.1111111111 | 0.2000000000 |\n| 3 | 1 | 10 | 0.2222222222 | 0.3000000000 |\n| 4 | 1 | 10 | 0.3333333333 | 0.4000000000 |\n| 5 | 2 | 20 | 0.4444444444 | 0.5000000000 |\n| 6 | 2 | 20 | 0.5555555556 | 0.6000000000 |\n| 7 | 2 | 20 | 0.6666666667 | 0.7000000000 |\n| 8 | 2 | 10 | 0.7777777778 | 0.8000000000 |\n| 9 | 4 | 20 | 0.8888888889 | 0.9000000000 |\n| 10 | 4 | 20 | 1.0000000000 | 1.0000000000 |\n+----+------+------+--------------+--------------+\n\nselect pk, a, b,\n percent_rank() over (partition by a order by a) as pct_rank,\n cume_dist() over (partition by a order by a) as cume_dist\nfrom t1;\n+----+------+------+--------------+--------------+\n| pk | a | b | pct_rank | cume_dist |\n+----+------+------+--------------+--------------+\n| 1 | 0 | 10 | 0.0000000000 | 1.0000000000 |\n| 2 | 0 | 10 | 0.0000000000 | 1.0000000000 |\n| 3 | 1 | 10 | 0.0000000000 | 1.0000000000 |\n| 4 | 1 | 10 | 0.0000000000 | 1.0000000000 |\n| 5 | 2 | 20 | 0.0000000000 | 1.0000000000 |\n| 6 | 2 | 20 | 0.0000000000 | 1.0000000000 |\n| 7 | 2 | 20 | 0.0000000000 | 1.0000000000 |\n| 8 | 2 | 10 | 0.0000000000 | 1.0000000000 |\n| 9 | 4 | 20 | 0.0000000000 | 1.0000000000 |\n| 10 | 4 | 20 | 0.0000000000 | 1.0000000000 |\n+----+------+------+--------------+--------------+\n\nURL: https://mariadb.com/kb/en/cume_dist/','','https://mariadb.com/kb/en/cume_dist/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (784,41,'DENSE_RANK','Syntax\n------\n\nDENSE_RANK() OVER (\n [ PARTITION BY partition_expression ]\n [ ORDER BY order_list ]\n)\n\nDescription\n-----------\n\nDENSE_RANK() is a window function that displays the number of a given row,\nstarting at one and following the ORDER BY sequence of the window function,\nwith identical values receiving the same result. Unlike the RANK() function,\nthere are no skipped values if the preceding results are identical. It is also\nsimilar to the ROW_NUMBER() function except that in that function, identical\nvalues will receive a different row number for each result.\n\nExamples\n--------\n\nThe distinction between DENSE_RANK(), RANK() and ROW_NUMBER():\n\nCREATE TABLE student(course VARCHAR(10), mark int, name varchar(10));\n\nINSERT INTO student VALUES \n (\'Maths\', 60, \'Thulile\'),\n (\'Maths\', 60, \'Pritha\'),\n (\'Maths\', 70, \'Voitto\'),\n (\'Maths\', 55, \'Chun\'),\n (\'Biology\', 60, \'Bilal\'),\n (\'Biology\', 70, \'Roger\');\n\nSELECT \n RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS rank,\n DENSE_RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS dense_rank,\n ROW_NUMBER() OVER (PARTITION BY course ORDER BY mark DESC) AS row_num,\n course, mark, name\nFROM student ORDER BY course, mark DESC;\n+------+------------+---------+---------+------+---------+\n| rank | dense_rank | row_num | course | mark | name |\n+------+------------+---------+---------+------+---------+\n| 1 | 1 | 1 | Biology | 70 | Roger |\n| 2 | 2 | 2 | Biology | 60 | Bilal |\n| 1 | 1 | 1 | Maths | 70 | Voitto |\n| 2 | 2 | 2 | Maths | 60 | Thulile |\n| 2 | 2 | 3 | Maths | 60 | Pritha |\n| 4 | 3 | 4 | Maths | 55 | Chun |\n+------+------------+---------+---------+------+---------+\n\nURL: https://mariadb.com/kb/en/dense_rank/','','https://mariadb.com/kb/en/dense_rank/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (785,41,'FIRST_VALUE','Syntax\n------\n\nFIRST_VALUE(expr) OVER (\n [ PARTITION BY partition_expression ]\n [ ORDER BY order_list ]\n)\n\nDescription\n-----------\n\nFIRST_VALUE returns the first result from an ordered set, or NULL if no such\nresult exists.\n\nExamples\n--------\n\nCREATE TABLE t1 (\n pk int primary key,\n a int,\n b int,\n c char(10),\n d decimal(10, 3),\n e real\n);\n\nINSERT INTO t1 VALUES\n( 1, 0, 1, \'one\', 0.1, 0.001),\n( 2, 0, 2, \'two\', 0.2, 0.002),\n( 3, 0, 3, \'three\', 0.3, 0.003),\n( 4, 1, 2, \'three\', 0.4, 0.004),\n( 5, 1, 1, \'two\', 0.5, 0.005),\n( 6, 1, 1, \'one\', 0.6, 0.006),\n( 7, 2, NULL, \'n_one\', 0.5, 0.007),\n( 8, 2, 1, \'n_two\', NULL, 0.008),\n( 9, 2, 2, NULL, 0.7, 0.009),\n(10, 2, 0, \'n_four\', 0.8, 0.010),\n(11, 2, 10, NULL, 0.9, NULL);\n\nSELECT pk, FIRST_VALUE(pk) OVER (ORDER BY pk) AS first_asc,\n LAST_VALUE(pk) OVER (ORDER BY pk) AS last_asc,\n FIRST_VALUE(pk) OVER (ORDER BY pk DESC) AS first_desc,\n LAST_VALUE(pk) OVER (ORDER BY pk DESC) AS last_desc\nFROM t1\nORDER BY pk DESC;\n\n+----+-----------+----------+------------+-----------+\n| pk | first_asc | last_asc | first_desc | last_desc |\n+----+-----------+----------+------------+-----------+\n| 11 | 1 | 11 | 11 | 11 |\n| 10 | 1 | 10 | 11 | 10 |\n| 9 | 1 | 9 | 11 | 9 |\n| 8 | 1 | 8 | 11 | 8 |\n| 7 | 1 | 7 | 11 | 7 |\n| 6 | 1 | 6 | 11 | 6 |\n| 5 | 1 | 5 | 11 | 5 |\n| 4 | 1 | 4 | 11 | 4 |\n| 3 | 1 | 3 | 11 | 3 |\n| 2 | 1 | 2 | 11 | 2 |\n| 1 | 1 | 1 | 11 | 1 |\n+----+-----------+----------+------------+-----------+\n\nCREATE OR REPLACE TABLE t1 (i int);\nINSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);\n\nSELECT i,\n FIRST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW and 1 FOLLOWING) AS\nf_1f,\n LAST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW and 1 FOLLOWING) AS\nl_1f,\n FIRST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS\nf_1p1f,\n LAST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS\nl_1p1f,\n FIRST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING) AS\nf_2p1p,\n LAST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING) AS\nl_2p1p,\n FIRST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN 1 FOLLOWING AND 2 FOLLOWING) AS\nf_1f2f,\n LAST_VALUE(i) OVER (ORDER BY i ROWS BETWEEN 1 FOLLOWING AND 2 FOLLOWING) AS\nl_1f2f\nFROM t1;\n\n+------+------+------+--------+--------+--------+--------+--------+--------+\n| i | f_1f | l_1f | f_1p1f | l_1p1f | f_2p1p | l_2p1p | f_1f2f | l_1f2f |\n+------+------+------+--------+--------+--------+--------+--------+--------+\n| 1 | 1 | 2 | 1 | 2 | NULL | NULL | 2 | 3 |\n| 2 | 2 | 3 | 1 | 3 | 1 | 1 | 3 | 4 |\n| 3 | 3 | 4 | 2 | 4 | 1 | 2 | 4 | 5 |\n| 4 | 4 | 5 | 3 | 5 | 2 | 3 | 5 | 6 |\n| 5 | 5 | 6 | 4 | 6 | 3 | 4 | 6 | 7 |\n| 6 | 6 | 7 | 5 | 7 | 4 | 5 | 7 | 8 |\n| 7 | 7 | 8 | 6 | 8 | 5 | 6 | 8 | 9 |\n| 8 | 8 | 9 | 7 | 9 | 6 | 7 | 9 | 10 |\n| 9 | 9 | 10 | 8 | 10 | 7 | 8 | 10 | 10 |\n| 10 | 10 | 10 | 9 | 10 | 8 | 9 | NULL | NULL |\n+------+------+------+--------+--------+--------+--------+--------+--------+\n\nURL: https://mariadb.com/kb/en/first_value/','','https://mariadb.com/kb/en/first_value/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (786,41,'LAG','Syntax\n------\n\nLAG (expr[, offset]) OVER ( \n [ PARTITION BY partition_expression ]\n < ORDER BY order_list >\n)\n\nDescription\n-----------\n\nThe LAG function accesses data from a previous row according to the ORDER BY\nclause without the need for a self-join. The specific row is determined by the\noffset (default 1), which specifies the number of rows behind the current row\nto use. An offset of 0 is the current row.\n\nExamples\n--------\n\nCREATE TABLE t1 (pk int primary key, a int, b int, c char(10), d decimal(10,\n3), e real);\n\nINSERT INTO t1 VALUES\n ( 1, 0, 1, \'one\', 0.1, 0.001),\n ( 2, 0, 2, \'two\', 0.2, 0.002),\n ( 3, 0, 3, \'three\', 0.3, 0.003),\n ( 4, 1, 2, \'three\', 0.4, 0.004),\n ( 5, 1, 1, \'two\', 0.5, 0.005),\n ( 6, 1, 1, \'one\', 0.6, 0.006),\n ( 7, 2, NULL, \'n_one\', 0.5, 0.007),\n ( 8, 2, 1, \'n_two\', NULL, 0.008),\n ( 9, 2, 2, NULL, 0.7, 0.009),\n (10, 2, 0, \'n_four\', 0.8, 0.010),\n (11, 2, 10, NULL, 0.9, NULL);\n\nSELECT pk, LAG(pk) OVER (ORDER BY pk) AS l,\n LAG(pk,1) OVER (ORDER BY pk) AS l1,\n LAG(pk,2) OVER (ORDER BY pk) AS l2,\n LAG(pk,0) OVER (ORDER BY pk) AS l0,\n LAG(pk,-1) OVER (ORDER BY pk) AS lm1,\n LAG(pk,-2) OVER (ORDER BY pk) AS lm2\nFROM t1;\n+----+------+------+------+------+------+------+\n| pk | l | l1 | l2 | l0 | lm1 | lm2 |\n+----+------+------+------+------+------+------+\n| 1 | NULL | NULL | NULL | 1 | 2 | 3 |\n| 2 | 1 | 1 | NULL | 2 | 3 | 4 |\n| 3 | 2 | 2 | 1 | 3 | 4 | 5 |\n| 4 | 3 | 3 | 2 | 4 | 5 | 6 |\n| 5 | 4 | 4 | 3 | 5 | 6 | 7 |\n| 6 | 5 | 5 | 4 | 6 | 7 | 8 |\n| 7 | 6 | 6 | 5 | 7 | 8 | 9 |\n| 8 | 7 | 7 | 6 | 8 | 9 | 10 |\n| 9 | 8 | 8 | 7 | 9 | 10 | 11 |\n| 10 | 9 | 9 | 8 | 10 | 11 | NULL |\n| 11 | 10 | 10 | 9 | 11 | NULL | NULL |\n+----+------+------+------+------+------+------+\n\nURL: https://mariadb.com/kb/en/lag/','','https://mariadb.com/kb/en/lag/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (787,41,'LEAD','Syntax\n------\n\nLEAD (expr[, offset]) OVER ( \n [ PARTITION BY partition_expression ]\n [ ORDER BY order_list ]\n)\n\nDescription\n-----------\n\nThe LEAD function accesses data from a following row in the same result set\nwithout the need for a self-join. The specific row is determined by the offset\n(default 1), which specifies the number of rows ahead the current row to use.\nAn offset of 0 is the current row.\n\nExample\n-------\n\nCREATE TABLE t1 (pk int primary key, a int, b int, c char(10), d decimal(10,\n3), e real);\n\nINSERT INTO t1 VALUES\n ( 1, 0, 1, \'one\', 0.1, 0.001),\n ( 2, 0, 2, \'two\', 0.2, 0.002),\n ( 3, 0, 3, \'three\', 0.3, 0.003),\n ( 4, 1, 2, \'three\', 0.4, 0.004),\n ( 5, 1, 1, \'two\', 0.5, 0.005),\n ( 6, 1, 1, \'one\', 0.6, 0.006),\n ( 7, 2, NULL, \'n_one\', 0.5, 0.007),\n ( 8, 2, 1, \'n_two\', NULL, 0.008),\n ( 9, 2, 2, NULL, 0.7, 0.009),\n (10, 2, 0, \'n_four\', 0.8, 0.010),\n (11, 2, 10, NULL, 0.9, NULL);\n\nSELECT pk, LEAD(pk) OVER (ORDER BY pk) AS l,\n LEAD(pk,1) OVER (ORDER BY pk) AS l1,\n LEAD(pk,2) OVER (ORDER BY pk) AS l2,\n LEAD(pk,0) OVER (ORDER BY pk) AS l0,\n LEAD(pk,-1) OVER (ORDER BY pk) AS lm1,\n LEAD(pk,-2) OVER (ORDER BY pk) AS lm2\nFROM t1;\n+----+------+------+------+------+------+------+\n| pk | l | l1 | l2 | l0 | lm1 | lm2 |\n+----+------+------+------+------+------+------+\n| 1 | 2 | 2 | 3 | 1 | NULL | NULL |\n| 2 | 3 | 3 | 4 | 2 | 1 | NULL |\n| 3 | 4 | 4 | 5 | 3 | 2 | 1 |\n| 4 | 5 | 5 | 6 | 4 | 3 | 2 |\n| 5 | 6 | 6 | 7 | 5 | 4 | 3 |\n| 6 | 7 | 7 | 8 | 6 | 5 | 4 |\n| 7 | 8 | 8 | 9 | 7 | 6 | 5 |\n| 8 | 9 | 9 | 10 | 8 | 7 | 6 |\n| 9 | 10 | 10 | 11 | 9 | 8 | 7 |\n| 10 | 11 | 11 | NULL | 10 | 9 | 8 |\n| 11 | NULL | NULL | NULL | 11 | 10 | 9 |\n+----+------+------+------+------+------+------+\n\nURL: https://mariadb.com/kb/en/lead/','','https://mariadb.com/kb/en/lead/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (788,41,'Median Window Function','MariaDB starting with 10.3.3\n----------------------------\nThe MEDIAN() window function was first introduced with in MariaDB 10.3.3.\n\nSyntax\n------\n\nMEDIAN(median expression) OVER (\n [ PARTITION BY partition_expression ]\n)\n\nDescription\n-----------\n\nMEDIAN() is a window function that returns the median value of a range of\nvalues.\n\nIt is a specific case of PERCENTILE_CONT, with an argument of 0.5 and the\nORDER BY column the one in MEDIAN\'s argument.\n\nMEDIAN(<median-arg>) OVER ( [ PARTITION BY partition_expression] )\n\nIs equivalent to:\n\nPERCENTILE_CONT(0.5) WITHIN \n GROUP (ORDER BY <median-arg>) OVER ( [ PARTITION BY partition_expression ])\n\nExamples\n--------\n\nCREATE TABLE book_rating (name CHAR(30), star_rating TINYINT);\n\nINSERT INTO book_rating VALUES (\'Lord of the Ladybirds\', 5);\nINSERT INTO book_rating VALUES (\'Lord of the Ladybirds\', 3);\nINSERT INTO book_rating VALUES (\'Lady of the Flies\', 1);\nINSERT INTO book_rating VALUES (\'Lady of the Flies\', 2);\nINSERT INTO book_rating VALUES (\'Lady of the Flies\', 5);\n\nSELECT name, median(star_rating) OVER (PARTITION BY name) FROM book_rating;\n+-----------------------+----------------------------------------------+\n| name | median(star_rating) OVER (PARTITION BY name) |\n+-----------------------+----------------------------------------------+\n| Lord of the Ladybirds | 4.0000000000 |\n| Lord of the Ladybirds | 4.0000000000 |\n| Lady of the Flies | 2.0000000000 |\n| Lady of the Flies | 2.0000000000 |\n| Lady of the Flies | 2.0000000000 |\n+-----------------------+----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/median/','','https://mariadb.com/kb/en/median/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (789,41,'NTH_VALUE','Syntax\n------\n\nNTH_VALUE (expr[, num_row]) OVER ( \n [ PARTITION BY partition_expression ]\n [ ORDER BY order_list ]\n)\n\nDescription\n-----------\n\nThe NTH_VALUE function returns the value evaluated at row number num_row of\nthe window frame, starting from 1, or NULL if the row does not exist.\n\nURL: https://mariadb.com/kb/en/nth_value/','','https://mariadb.com/kb/en/nth_value/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (790,41,'NTILE','Syntax\n------\n\nNTILE (expr) OVER ( \n [ PARTITION BY partition_expression ]\n [ ORDER BY order_list ]\n)\n\nDescription\n-----------\n\nNTILE() is a window function that returns an integer indicating which group a\ngiven row falls into. The number of groups is specified in the argument\n(expr), starting at one. Ordered rows in the partition are divided into the\nspecified number of groups with as equal a size as possible.\n\nExamples\n--------\n\ncreate table t1 (\n pk int primary key,\n a int,\n b int\n );\n\ninsert into t1 values\n (11 , 0, 10),\n (12 , 0, 10),\n (13 , 1, 10),\n (14 , 1, 10),\n (18 , 2, 10),\n (15 , 2, 20),\n (16 , 2, 20),\n (17 , 2, 20),\n (19 , 4, 20),\n (20 , 4, 20);\n\nselect pk, a, b,\n ntile(1) over (order by pk)\n from t1;\n+----+------+------+-----------------------------+\n| pk | a | b | ntile(1) over (order by pk) |\n+----+------+------+-----------------------------+\n| 11 | 0 | 10 | 1 |\n| 12 | 0 | 10 | 1 |\n| 13 | 1 | 10 | 1 |\n| 14 | 1 | 10 | 1 |\n| 15 | 2 | 20 | 1 |\n| 16 | 2 | 20 | 1 |\n| 17 | 2 | 20 | 1 |\n| 18 | 2 | 10 | 1 |\n| 19 | 4 | 20 | 1 |\n| 20 | 4 | 20 | 1 |\n+----+------+------+-----------------------------+\n\nselect pk, a, b,\n ntile(4) over (order by pk)\n from t1;\n+----+------+------+-----------------------------+\n| pk | a | b | ntile(4) over (order by pk) |\n+----+------+------+-----------------------------+\n| 11 | 0 | 10 | 1 |\n| 12 | 0 | 10 | 1 |\n| 13 | 1 | 10 | 1 |\n| 14 | 1 | 10 | 2 |\n| 15 | 2 | 20 | 2 |\n| 16 | 2 | 20 | 2 |\n| 17 | 2 | 20 | 3 |\n| 18 | 2 | 10 | 3 |\n| 19 | 4 | 20 | 4 |\n| 20 | 4 | 20 | 4 |\n+----+------+------+-----------------------------+\n\nURL: https://mariadb.com/kb/en/ntile/','','https://mariadb.com/kb/en/ntile/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (791,41,'PERCENT_RANK','Syntax\n------\n\nPERCENT_RANK() OVER (\n [ PARTITION BY partition_expression ]\n [ ORDER BY order_list ]\n)\n\nDescription\n-----------\n\nPERCENT_RANK() is a window function that returns the relative percent rank of\na given row. The following formula is used to calculate the percent rank:\n\n(rank - 1) / (number of rows in the window or partition - 1)\n\nExamples\n--------\n\ncreate table t1 (\n pk int primary key,\n a int,\n b int\n);\n\ninsert into t1 values\n( 1 , 0, 10),\n( 2 , 0, 10),\n( 3 , 1, 10),\n( 4 , 1, 10),\n( 8 , 2, 10),\n( 5 , 2, 20),\n( 6 , 2, 20),\n( 7 , 2, 20),\n( 9 , 4, 20),\n(10 , 4, 20);\n\nselect pk, a, b,\n rank() over (order by a) as rank,\n percent_rank() over (order by a) as pct_rank,\n cume_dist() over (order by a) as cume_dist\nfrom t1;\n+----+------+------+------+--------------+--------------+\n| pk | a | b | rank | pct_rank | cume_dist |\n+----+------+------+------+--------------+--------------+\n| 1 | 0 | 10 | 1 | 0.0000000000 | 0.2000000000 |\n| 2 | 0 | 10 | 1 | 0.0000000000 | 0.2000000000 |\n| 3 | 1 | 10 | 3 | 0.2222222222 | 0.4000000000 |\n| 4 | 1 | 10 | 3 | 0.2222222222 | 0.4000000000 |\n| 5 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 6 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 7 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 8 | 2 | 10 | 5 | 0.4444444444 | 0.8000000000 |\n| 9 | 4 | 20 | 9 | 0.8888888889 | 1.0000000000 |\n| 10 | 4 | 20 | 9 | 0.8888888889 | 1.0000000000 |\n+----+------+------+------+--------------+--------------+\n\nselect pk, a, b,\n percent_rank() over (order by pk) as pct_rank,\n cume_dist() over (order by pk) as cume_dist\nfrom t1 order by pk;\n+----+------+------+--------------+--------------+\n| pk | a | b | pct_rank | cume_dist |\n+----+------+------+--------------+--------------+\n| 1 | 0 | 10 | 0.0000000000 | 0.1000000000 |\n| 2 | 0 | 10 | 0.1111111111 | 0.2000000000 |\n| 3 | 1 | 10 | 0.2222222222 | 0.3000000000 |\n| 4 | 1 | 10 | 0.3333333333 | 0.4000000000 |\n| 5 | 2 | 20 | 0.4444444444 | 0.5000000000 |\n| 6 | 2 | 20 | 0.5555555556 | 0.6000000000 |\n| 7 | 2 | 20 | 0.6666666667 | 0.7000000000 |\n| 8 | 2 | 10 | 0.7777777778 | 0.8000000000 |\n| 9 | 4 | 20 | 0.8888888889 | 0.9000000000 |\n| 10 | 4 | 20 | 1.0000000000 | 1.0000000000 |\n+----+------+------+--------------+--------------+\n\nselect pk, a, b,\n percent_rank() over (partition by a order by a) as pct_rank,\n cume_dist() over (partition by a order by a) as cume_dist\nfrom t1;\n+----+------+------+--------------+--------------+\n| pk | a | b | pct_rank | cume_dist |\n+----+------+------+--------------+--------------+\n| 1 | 0 | 10 | 0.0000000000 | 1.0000000000 |\n| 2 | 0 | 10 | 0.0000000000 | 1.0000000000 |\n| 3 | 1 | 10 | 0.0000000000 | 1.0000000000 |\n| 4 | 1 | 10 | 0.0000000000 | 1.0000000000 |\n| 5 | 2 | 20 | 0.0000000000 | 1.0000000000 |\n| 6 | 2 | 20 | 0.0000000000 | 1.0000000000 |\n| 7 | 2 | 20 | 0.0000000000 | 1.0000000000 |\n| 8 | 2 | 10 | 0.0000000000 | 1.0000000000 |\n| 9 | 4 | 20 | 0.0000000000 | 1.0000000000 |\n| 10 | 4 | 20 | 0.0000000000 | 1.0000000000 |\n+----+------+------+--------------+--------------+\n\nURL: https://mariadb.com/kb/en/percent_rank/','','https://mariadb.com/kb/en/percent_rank/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (792,41,'PERCENTILE_CONT','MariaDB starting with 10.3.3\n----------------------------\nThe PERCENTILE_CONT() window function was first introduced with in MariaDB\n10.3.3.\n\nSyntax\n------\n\nDescription\n-----------\n\nPERCENTILE_CONT() (standing for continuous percentile) is a window function\nwhich returns a value which corresponds to the given fraction in the sort\norder. If required, it will interpolate between adjacent input items.\n\nEssentially, the following process is followed to find the value to return:\n\n* Get the number of rows in the partition, denoted by N\n* RN = p*(N-1), where p denotes the argument to the PERCENTILE_CONT function\n* calculate the FRN(floor row number) and CRN(column row number for the group(\nFRN= floor(RN) and CRN = ceil(RN))\n* look up rows FRN and CRN\n* If (CRN = FRN = RN) then the result is (value of expression from row at RN)\n* Otherwise the result is\n* (CRN - RN) * (value of expression for row at FRN) +\n* (RN - FRN) * (value of expression for row at CRN)\n\nThe MEDIAN function is a specific case of PERCENTILE_CONT, equivalent to\nPERCENTILE_CONT(0.5).\n\nExamples\n--------\n\nCREATE TABLE book_rating (name CHAR(30), star_rating TINYINT);\n\nINSERT INTO book_rating VALUES (\'Lord of the Ladybirds\', 5);\nINSERT INTO book_rating VALUES (\'Lord of the Ladybirds\', 3);\nINSERT INTO book_rating VALUES (\'Lady of the Flies\', 1);\nINSERT INTO book_rating VALUES (\'Lady of the Flies\', 2);\nINSERT INTO book_rating VALUES (\'Lady of the Flies\', 5);\n\nSELECT name, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY star_rating) \n OVER (PARTITION BY name) AS pc\n FROM book_rating;\n+-----------------------+--------------+\n| name | pc |\n+-----------------------+--------------+\n| Lord of the Ladybirds | 4.0000000000 |\n| Lord of the Ladybirds | 4.0000000000 |\n| Lady of the Flies | 2.0000000000 |\n| Lady of the Flies | 2.0000000000 |\n| Lady of the Flies | 2.0000000000 |\n+-----------------------+--------------+\n\nSELECT name, PERCENTILE_CONT(1) WITHIN GROUP (ORDER BY star_rating) \n OVER (PARTITION BY name) AS pc\n FROM book_rating;\n+-----------------------+--------------+\n| name | pc |\n+-----------------------+--------------+\n| Lord of the Ladybirds | 5.0000000000 |\n| Lord of the Ladybirds | 5.0000000000 |\n| Lady of the Flies | 5.0000000000 |\n| Lady of the Flies | 5.0000000000 |\n| Lady of the Flies | 5.0000000000 |\n+-----------------------+--------------+\n\nSELECT name, PERCENTILE_CONT(0) WITHIN GROUP (ORDER BY star_rating) \n OVER (PARTITION BY name) AS pc\n FROM book_rating;\n+-----------------------+--------------+\n| name | pc |\n+-----------------------+--------------+\n| Lord of the Ladybirds | 3.0000000000 |\n| Lord of the Ladybirds | 3.0000000000 |\n| Lady of the Flies | 1.0000000000 |\n| Lady of the Flies | 1.0000000000 |\n| Lady of the Flies | 1.0000000000 |\n+-----------------------+--------------+\n\nSELECT name, PERCENTILE_CONT(0.6) WITHIN GROUP (ORDER BY star_rating) \n OVER (PARTITION BY name) AS pc\n FROM book_rating;\n+-----------------------+--------------+\n| name | pc |\n+-----------------------+--------------+\n| Lord of the Ladybirds | 4.2000000000 |\n| Lord of the Ladybirds | 4.2000000000 |\n| Lady of the Flies | 2.6000000000 |\n| Lady of the Flies | 2.6000000000 |\n| Lady of the Flies | 2.6000000000 |\n+-----------------------+--------------+\n\nURL: https://mariadb.com/kb/en/percentile_cont/','','https://mariadb.com/kb/en/percentile_cont/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (793,41,'PERCENTILE_DISC','MariaDB starting with 10.3.3\n----------------------------\nThe PERCENTILE_DISC() window function was first introduced with in MariaDB\n10.3.3.\n\nSyntax\n------\n\nDescription\n-----------\n\nPERCENTILE_DISC() (standing for discrete percentile) is a window function\nwhich returns the first value in the set whose ordered position is the same or\nmore than the specified fraction.\n\nEssentially, the following process is followed to find the value to return:\n\n* Get the number of rows in the partition.\n* Walk through the partition, in order, until finding the the first row with\nCUME_DIST() >= function_argument.\n\nExamples\n--------\n\nCREATE TABLE book_rating (name CHAR(30), star_rating TINYINT);\n\nINSERT INTO book_rating VALUES (\'Lord of the Ladybirds\', 5);\nINSERT INTO book_rating VALUES (\'Lord of the Ladybirds\', 3);\nINSERT INTO book_rating VALUES (\'Lady of the Flies\', 1);\nINSERT INTO book_rating VALUES (\'Lady of the Flies\', 2);\nINSERT INTO book_rating VALUES (\'Lady of the Flies\', 5);\n\nSELECT name, PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY star_rating)\n OVER (PARTITION BY name) AS pc FROM book_rating;\n+-----------------------+------+\n| name | pc |\n+-----------------------+------+\n| Lord of the Ladybirds | 3 |\n| Lord of the Ladybirds | 3 |\n| Lady of the Flies | 2 |\n| Lady of the Flies | 2 |\n| Lady of the Flies | 2 |\n+-----------------------+------+\n5 rows in set (0.000 sec)\n\nSELECT name, PERCENTILE_DISC(0) WITHIN GROUP (ORDER BY star_rating) \n OVER (PARTITION BY name) AS pc FROM book_rating;\n+-----------------------+------+\n| name | pc |\n+-----------------------+------+\n| Lord of the Ladybirds | 3 |\n| Lord of the Ladybirds | 3 |\n| Lady of the Flies | 1 |\n| Lady of the Flies | 1 |\n| Lady of the Flies | 1 |\n+-----------------------+------+\n5 rows in set (0.000 sec)\n\nSELECT name, PERCENTILE_DISC(1) WITHIN GROUP (ORDER BY star_rating) \n OVER (PARTITION BY name) AS pc FROM book_rating;\n+-----------------------+------+\n| name | pc |\n+-----------------------+------+\n| Lord of the Ladybirds | 5 |\n| Lord of the Ladybirds | 5 |\n| Lady of the Flies | 5 |\n| Lady of the Flies | 5 |\n| Lady of the Flies | 5 |\n+-----------------------+------+\n5 rows in set (0.000 sec)\n\nSELECT name, PERCENTILE_DISC(0.6) WITHIN GROUP (ORDER BY star_rating) \n OVER (PARTITION BY name) AS pc FROM book_rating;\n+-----------------------+------+\n| name | pc |\n+-----------------------+------+\n| Lord of the Ladybirds | 5 |\n| Lord of the Ladybirds | 5 |\n| Lady of the Flies | 2 |\n| Lady of the Flies | 2 |\n| Lady of the Flies | 2 |\n+-----------------------+------\n\nURL: https://mariadb.com/kb/en/percentile_disc/','','https://mariadb.com/kb/en/percentile_disc/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (794,41,'RANK','Syntax\n------\n\nRANK() OVER (\n [ PARTITION BY partition_expression ]\n [ ORDER BY order_list ]\n)\n\nDescription\n-----------\n\nRANK() is a window function that displays the number of a given row, starting\nat one and following the ORDER BY sequence of the window function, with\nidentical values receiving the same result. It is similar to the ROW_NUMBER()\nfunction except that in that function, identical values will receive a\ndifferent row number for each result.\n\nExamples\n--------\n\nThe distinction between DENSE_RANK(), RANK() and ROW_NUMBER():\n\nCREATE TABLE student(course VARCHAR(10), mark int, name varchar(10));\n\nINSERT INTO student VALUES \n (\'Maths\', 60, \'Thulile\'),\n (\'Maths\', 60, \'Pritha\'),\n (\'Maths\', 70, \'Voitto\'),\n (\'Maths\', 55, \'Chun\'),\n (\'Biology\', 60, \'Bilal\'),\n (\'Biology\', 70, \'Roger\');\n\nSELECT \n RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS rank,\n DENSE_RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS dense_rank,\n ROW_NUMBER() OVER (PARTITION BY course ORDER BY mark DESC) AS row_num,\n course, mark, name\nFROM student ORDER BY course, mark DESC;\n+------+------------+---------+---------+------+---------+\n| rank | dense_rank | row_num | course | mark | name |\n+------+------------+---------+---------+------+---------+\n| 1 | 1 | 1 | Biology | 70 | Roger |\n| 2 | 2 | 2 | Biology | 60 | Bilal |\n| 1 | 1 | 1 | Maths | 70 | Voitto |\n| 2 | 2 | 2 | Maths | 60 | Thulile |\n| 2 | 2 | 3 | Maths | 60 | Pritha |\n| 4 | 3 | 4 | Maths | 55 | Chun |\n+------+------------+---------+---------+------+---------+\n\nURL: https://mariadb.com/kb/en/rank/','','https://mariadb.com/kb/en/rank/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (795,41,'ROW_NUMBER','Syntax\n------\n\nROW_NUMBER() OVER (\n [ PARTITION BY partition_expression ]\n [ ORDER BY order_list ]\n)\n\nDescription\n-----------\n\nROW_NUMBER() is a window function that displays the number of a given row,\nstarting at one and following the ORDER BY sequence of the window function,\nwith identical values receiving different row numbers. It is similar to the\nRANK() and DENSE_RANK() functions except that in that function, identical\nvalues will receive the same rank for each result.\n\nExamples\n--------\n\nThe distinction between DENSE_RANK(), RANK() and ROW_NUMBER():\n\nCREATE TABLE student(course VARCHAR(10), mark int, name varchar(10));\n\nINSERT INTO student VALUES \n (\'Maths\', 60, \'Thulile\'),\n (\'Maths\', 60, \'Pritha\'),\n (\'Maths\', 70, \'Voitto\'),\n (\'Maths\', 55, \'Chun\'),\n (\'Biology\', 60, \'Bilal\'),\n (\'Biology\', 70, \'Roger\');\n\nSELECT \n RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS rank,\n DENSE_RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS dense_rank,\n ROW_NUMBER() OVER (PARTITION BY course ORDER BY mark DESC) AS row_num,\n course, mark, name\nFROM student ORDER BY course, mark DESC;\n+------+------------+---------+---------+------+---------+\n| rank | dense_rank | row_num | course | mark | name |\n+------+------------+---------+---------+------+---------+\n| 1 | 1 | 1 | Biology | 70 | Roger |\n| 2 | 2 | 2 | Biology | 60 | Bilal |\n| 1 | 1 | 1 | Maths | 70 | Voitto |\n| 2 | 2 | 2 | Maths | 60 | Thulile |\n| 2 | 2 | 3 | Maths | 60 | Pritha |\n| 4 | 3 | 4 | Maths | 55 | Chun |\n+------+------------+---------+---------+------+---------+\n\nURL: https://mariadb.com/kb/en/row_number/','','https://mariadb.com/kb/en/row_number/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (796,41,'Aggregate Functions as Window Functions','It is possible to use aggregate functions as window functions. An aggregate\nfunction used as a window function must have the OVER clause. For example,\nhere\'s COUNT() used as a window function:\n\nselect COUNT(*) over (order by column) from table;\n\nMariaDB currently allows these aggregate functions to be used as window\nfunctions:\n\n* AVG\n* BIT_AND\n* BIT_OR\n* BIT_XOR\n* COUNT\n* JSON_ARRAYAGG\n* JSON_OBJECTAGG\n* MAX\n* MIN\n* STD\n* STDDEV\n* STDDEV_POP\n* STDDEV_SAMP\n* SUM\n* VAR_POP\n* VAR_SAMP\n* VARIANCE\n\nURL: https://mariadb.com/kb/en/aggregate-functions-as-window-functions/','','https://mariadb.com/kb/en/aggregate-functions-as-window-functions/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (797,41,'ColumnStore Window Functions','Introduction\n------------\n\nMariaDB ColumnStore provides support for window functions broadly following\nthe SQL 2003 specification. A window function allows for calculations relating\nto a window of data surrounding the current row in a result set. This\ncapability provides for simplified queries in support of common business\nquestions such as cumulative totals, rolling averages, and top 10 lists.\n\nAggregate functions are utilized for window functions however differ in\nbehavior from a group by query because the rows remain ungrouped. This\nprovides support for cumulative sums and rolling averages, for example.\n\nTwo key concepts for window functions are Partition and Frame:\n\n* A Partition is a group of rows, or window, that have the same value for a\nspecific column, for example a Partition can be created over a time period\nsuch as a quarter or lookup values.\n* The Frame for each row is a subset of the row\'s Partition. The frame\ntypically is dynamic allowing for a sliding frame of rows within the\nPartition. The Frame determines the range of rows for the windowing function.\nA Frame could be defined as the last X rows and next Y rows all the way up to\nthe entire Partition.\n\nWindow functions are applied after joins, group by, and having clauses are\ncalculated.\n\nSyntax\n------\n\nA window function is applied in the select clause using the following syntax:\n\nfunction_name ([expression [, expression ... ]]) OVER ( window_definition )\n\nwhere window_definition is defined as:\n\n[ PARTITION BY expression [, ...] ]\n[ ORDER BY expression [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] ]\n[ frame_clause ]\n\nPARTITION BY:\n\n* Divides the window result set into groups based on one or more expressions.\n* An expression may be a constant, column, and non window function expressions.\n* A query is not limited to a single partition by clause. Different partition\nclauses can be used across different window function applications.\n* The partition by columns do not need to be in the select list but do need to\nbe available from the query result set.\n* If there is no PARTITION BY clause, all rows of the result set define the\ngroup.\n\nORDER BY\n\n* Defines the ordering of values within the partition.\n* Can be ordered by multiple keys which may be a constant, column or non\nwindow function expression.\n* The order by columns do not need to be in the select list but need to be\navailable from the query result set.\n* Use of a select column alias from the query is not supported.\n* ASC (default) and DESC options allow for ordering ascending or descending.\n* NULLS FIRST and NULL_LAST options specify whether null values come first or\nlast in the ordering sequence. NULLS_FIRST is the default for ASC order, and\nNULLS_LAST is the default for DESC order.\n\nand the optional frame_clause is defined as:\n\n{ RANGE | ROWS } frame_start\n{ RANGE | ROWS } BETWEEN frame_start AND frame_end\n\nand the optional frame_start and frame_end are defined as (value being a\nnumeric expression):\n\nUNBOUNDED PRECEDING\nvalue PRECEDING\nCURRENT ROW\nvalue FOLLOWING\nUNBOUNDED FOLLOWING\n\nRANGE/ROWS:\n\n* Defines the windowing clause for calculating the set of rows that the\nfunction applies to for calculating a given rows window function result.\n* Requires an ORDER BY clause to define the row order for the window.\n* ROWS specify the window in physical units, i.e. result set rows and must be\na constant or expression evaluating to a positive numeric value.\n* RANGE specifies the window as a logical offset. If the the expression\nevaluates to a numeric value then the ORDER BY expression must be a numeric or\nDATE type. If the expression evaluates to an interval value then the ORDER BY\nexpression must be a DATE data type.\n* UNBOUNDED PRECEDING indicates the window starts at the first row of the\npartition.\n* UNBOUNDED FOLLOWING indicates the window ends at the last row of the\npartition.\n* CURRENT ROW specifies the window start or ends at the current row or value.\n* If omitted, the default is ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.\n\nSupported Functions\n-------------------\n\n+--------------------------------+-------------------------------------------+\n| Function | Description |\n+--------------------------------+-------------------------------------------+\n| AVG() | The average of all input values. |\n+--------------------------------+-------------------------------------------+\n| COUNT() | Number of input rows. |\n+--------------------------------+-------------------------------------------+\n| CUME_DIST() | Calculates the cumulative distribution, |\n| | or relative rank, of the current row to |\n| | other rows in the same partition. Number |\n| | of peer or preceding rows / number of |\n| | rows in partition. |\n+--------------------------------+-------------------------------------------+\n| DENSE_RANK() | Ranks items in a group leaving no gaps |\n| | in ranking sequence when there are ties. |\n+--------------------------------+-------------------------------------------+\n| FIRST_VALUE() | The value evaluated at the row that is |\n| | the first row of the window frame |\n| | (counting from 1); null if no such row. |\n+--------------------------------+-------------------------------------------+\n| LAG() | The value evaluated at the row that is |\n| | offset rows before the current row |\n| | within the partition; if there is no |\n| | such row, instead return default. Both |\n| | offset and default are evaluated with |\n| | respect to the current row. If omitted, |\n| | offset defaults to 1 and default to |\n| | null. LAG provides access to more than |\n| | one row of a table at the same time |\n| | without a self-join. Given a series of |\n| | rows returned from a query and a |\n| | position of the cursor, LAG provides |\n| | access to a row at a given physical |\n| | offset prior to that position. |\n+--------------------------------+-------------------------------------------+\n| LAST_VALUE() | The value evaluated at the row that is |\n| | the last row of the window frame |\n| | (counting from 1); null if no such row. |\n+--------------------------------+-------------------------------------------+\n| LEAD() | Provides access to a row at a given |\n| | physical offset beyond that position. |\n| | Returns value evaluated at the row that |\n| | is offset rows after the current row |\n| | within the partition; if there is no |\n| | such row, instead return default. Both |\n| | offset and default are evaluated with |\n| | respect to the current row. If omitted, |\n| | offset defaults to 1 and default to null. |\n+--------------------------------+-------------------------------------------+\n| MAX() | Maximum value of expression across all |\n| | input values. |\n+--------------------------------+-------------------------------------------+\n| MEDIAN() | An inverse distribution function that |\n| | assumes a continuous distribution model. |\n| | It takes a numeric or datetime value and |\n| | returns the middle value or an |\n| | interpolated value that would be the |\n| | middle value once the values are sorted. |\n| | Nulls are ignored in the calculation. |\n+--------------------------------+-------------------------------------------+\n| MIN() | Minimum value of expression across all |\n| | input values. |\n+--------------------------------+-------------------------------------------+\n| NTH_VALUE() | The value evaluated at the row that is |\n| | the nth row of the window frame |\n| | (counting from 1); null if no such row. |\n+--------------------------------+-------------------------------------------+\n| NTILE() | Divides an ordered data set into a |\n| | number of buckets indicated by expr and |\n| | assigns the appropriate bucket number to |\n| | each row. The buckets are numbered 1 |\n| | through expr. The expr value must |\n| | resolve to a positive constant for each |\n| | partition. Integer ranging from 1 to the |\n| | argument value, dividing the partition |\n| | as equally as possible. |\n+--------------------------------+-------------------------------------------+\n| PERCENT_RANK() | relative rank of the current row: (rank |\n| | - 1) / (total rows - 1). |\n+--------------------------------+-------------------------------------------+\n| PERCENTILE_CONT() | An inverse distribution function that |\n| | assumes a continuous distribution model. |\n| | It takes a percentile value and a sort |\n| | specification, and returns an |\n| | interpolated value that would fall into |\n| | that percentile value with respect to |\n| | the sort specification. Nulls are |\n| | ignored in the calculation. |\n+--------------------------------+-------------------------------------------+\n| PERCENTILE_DISC() | An inverse distribution function that |\n| | assumes a discrete distribution model. |\n| | It takes a percentile value and a sort |\n| | specification and returns an element |\n| | from the set. Nulls are ignored in the |\n| | calculation. |\n+--------------------------------+-------------------------------------------+\n| RANK() | rank of the current row with gaps; same |\n| | as row_number of its first peer. |\n+--------------------------------+-------------------------------------------+\n| ROW_NUMBER() | number of the current row within its |\n| | partition, counting from 1 |\n+--------------------------------+-------------------------------------------+\n| STDDEV() STDDEV_POP() | Computes the population standard |\n| | deviation and returns the square root of |\n| | the population variance. |\n+--------------------------------+-------------------------------------------+\n| STDDEV_SAMP() | Computes the cumulative sample standard |\n| | deviation and returns the square root of |\n| | the sample variance. |\n+--------------------------------+-------------------------------------------+\n| SUM() | Sum of expression across all input |\n| | values. |\n+--------------------------------+-------------------------------------------+\n| VARIANCE() VAR_POP() | Population variance of the input values |\n| | (square of the population standard |\n| | deviation). |\n+--------------------------------+-------------------------------------------+\n| VAR_SAMP() | Sample variance of the input values |\n| | (square of the sample standard |\n| | deviation). |\n+--------------------------------+-------------------------------------------+\n\nExamples\n--------\n\nExample Schema\n--------------\n\nThe examples are all based on the following simplified sales opportunity table:\n\ncreate table opportunities (\nid int,\naccountName varchar(20),\nname varchar(128),\nowner varchar(7),\namount decimal(10,2),\ncloseDate date,\nstageName varchar(11)\n) engine=columnstore;\n\nSome example values are (thanks to https://www.mockaroo.com for sample data\ngeneration):\n\n+----+---------------+------+--------+---------+-------------+-------------+\n| id | accountName | name | owner | amount | closeDate | stageName |\n+----+---------------+------+--------+---------+-------------+-------------+\n| 1 | Browseblab | Mult | Bob | 26444.8 | 2016-10-20 | Negotiating |','','https://mariadb.com/kb/en/window-functions-columnstore-window-functions/'); +update help_topic set description = CONCAT(description, '\n| | | -lat | | | | |\n| | | ral | | | | |\n| | | exec | | | | |\n| | | tive | | | | |\n| | | func | | | | |\n| | | ion | | | | |\n+----+---------------+------+--------+---------+-------------+-------------+\n| 2 | Mita | Orga | Maria | 477878. | 2016-11-28 | ClosedWon |\n| | | ic | | 1 | | |\n| | | dema | | | | |\n| | | d-dr | | | | |\n| | | ven | | | | |\n| | | benc | | | | |\n| | | mark | | | | |\n+----+---------------+------+--------+---------+-------------+-------------+\n| 3 | Miboo | De-e | Olivie | 80181.7 | 2017-01-05 | ClosedWon |\n| | | gine | | | | |\n| | | red | | | | |\n| | | hybr | | | | |\n| | | d | | | | |\n| | | grou | | | | |\n| | | ware | | | | |\n+----+---------------+------+--------+---------+-------------+-------------+\n| 4 | Youbridge | Ente | Chris | 946245. | 2016-07-02 | ClosedWon |\n| | | pris | | 9 | | |\n| | | -wid | | | | |\n| | | | | | | |\n| | | bott | | | | |\n| | | m-li | | | | |\n| | | e | | | | |\n| | | Grap | | | | |\n| | | ic | | | | |\n| | | Inte | | | | |\n| | | face | | | | |\n+----+---------------+------+--------+---------+-------------+-------------+\n| 5 | Skyba | Reve | Maria | 696241. | 2017-02-17 | Negotiating |\n| | | se-e | | 2 | | |\n| | | gine | | | | |\n| | | red | | | | |\n| | | fres | | | | |\n| | | -thi | | | | |\n| | | king | | | | |\n| | | stan | | | | |\n| | | ardi | | | | |\n| | | atio | | | | |\n| | | | | | | |\n+----+---------------+------+--------+---------+-------------+-------------+\n| 6 | Eayo | Fund | Bob | 765605. | 2016-08-27 | Prospecting |\n| | | ment | | 2 | | |\n| | | l | | | | |\n| | | well | | | | |\n| | | modu | | | | |\n| | | ated | | | | |\n| | | arti | | | | |\n| | | icia | | | | |\n| | | | | | | |\n| | | inte | | | | |\n| | | lige | | | | |\n| | | ce | | | | |\n+----+---------------+------+--------+---------+-------------+-------------+\n| 7 | Yotz | Exte | Chris | 319624. | 2017-01-06 | ClosedLost |\n| | | ded | | 0 | | |\n| | | seco | | | | |\n| | | dary | | | | |\n| | | infr | | | | |\n| | | stru | | | | |\n| | | ture | | | | |\n+----+---------------+------+--------+---------+-------------+-------------+\n| 8 | Oloo | Conf | Chris | 321016. | 2017-03-08 | ClosedLost |\n| | | gura | | 6 | | |\n| | | le | | | | |\n| | | web- | | | | |\n| | | nabl | | | | |\n| | | d | | | | |\n| | | data | | | | |\n| | | ware | | | | |\n| | | ouse | | | | |\n+----+---------------+------+--------+---------+-------------+-------------+\n| 9 | Kaymbo | Mult | Bob | 690881. | 2017-01-02 | Developing |\n| | | -lat | | 1 | | |\n| | | ral | | | | |\n| | | web- | | | | |\n| | | nabl | | | | |\n| | | d | | | | |\n| | | defi | | | | |\n| | | itio | | | | |\n| | | | | | | |\n+----+---------------+------+--------+---------+-------------+-------------+\n| 10 | Rhyloo | Publ | Chris | 965477. | 2016-11-07 | Prospecting |\n| | | c-ke | | 4 | | |\n| | | | | | | |\n| | | cohe | | | | |\n| | | ent | | | | |\n| | | infr | | | | |\n| | | stru | | | | |\n| | | ture | | | | |\n+----+---------------+------+--------+---------+-------------+-------------+\n\nThe schema, sample data, and queries are available as an attachment to this\narticle.\n\nCumulative Sum and Running Max Example\n--------------------------------------\n\nWindow functions can be used to achieve cumulative / running calculations on a\ndetail report. In this case a won opportunity report for a 7 day period adds\ncolumns to show the accumulated won amount as well as the current highest\nopportunity amount in preceding rows.\n\nselect owner, \naccountName, \nCloseDate, \namount, \nsum(amount) over (order by CloseDate rows between unbounded preceding and\ncurrent row) cumeWon, \nmax(amount) over (order by CloseDate rows between unbounded preceding and\ncurrent row) runningMax\nfrom opportunities \nwhere stageName=\'ClosedWon\' \nand closeDate >= \'2016-10-02\' and closeDate <= \'2016-10-09\' \norder by CloseDate;\n\nwith example results:\n\n+--------+---------------+-------------+---------+----------+--------------+\n| owner | accountName | CloseDate | amount | cumeWon | runningMax |\n+--------+---------------+-------------+---------+----------+--------------+\n| Bill | Babbleopia | 2016-10-02 | 437636. | 437636.4 | 437636.47 |\n| | | | 7 | | |\n+--------+---------------+-------------+---------+----------+--------------+\n| Bill | Thoughtworks | 2016-10-04 | 146086. | 583722.9 | 437636.47 |\n| | | | 1 | | |\n+--------+---------------+-------------+---------+----------+--------------+\n| Olivie | Devpulse | 2016-10-05 | 834235. | 1417958. | 834235.93 |\n| | | | 3 | 1 | |\n+--------+---------------+-------------+---------+----------+--------------+\n| Chris | Linkbridge | 2016-10-07 | 539977. | 2458738. | 834235.93 |\n| | | | 5 | 5 | |\n+--------+---------------+-------------+---------+----------+--------------+\n| Olivie | Trupe | 2016-10-07 | 500802. | 1918761. | 834235.93 |\n| | | | 9 | 0 | |\n+--------+---------------+-------------+---------+----------+--------------+\n| Bill | Latz | 2016-10-08 | 857254. | 3315993. | 857254.87 |\n| | | | 7 | 2 | |\n+--------+---------------+-------------+---------+----------+--------------+\n| Chris | Avamm | 2016-10-09 | 699566. | 4015560. | 857254.87 |\n| | | | 6 | 8 | |\n+--------+---------------+-------------+---------+----------+--------------+\n\nPartitioned Cumulative Sum and Running Max Example\n--------------------------------------------------\n\nThe above example can be partitioned, so that the window functions are over a\nparticular field grouping such as owner and accumulate within that grouping.\nThis is achieved by adding the syntax \"partition by <columns>\" in the window\nfunction clause.\n\nselect owner, \naccountName, \nCloseDate, \namount, \nsum(amount) over (partition by owner order by CloseDate rows between unbounded\npreceding and current row) cumeWon, \nmax(amount) over (partition by owner order by CloseDate rows between unbounded\npreceding and current row) runningMax \nfrom opportunities \nwhere stageName=\'ClosedWon\' \nand closeDate >= \'2016-10-02\' and closeDate <= \'2016-10-09\' \norder by owner, CloseDate;\n\nwith example results:\n\n+--------+---------------+-------------+---------+----------+--------------+\n| owner | accountName | CloseDate | amount | cumeWon | runningMax |\n+--------+---------------+-------------+---------+----------+--------------+\n| Bill | Babbleopia | 2016-10-02 | 437636. | 437636.4 | 437636.47 |\n| | | | 7 | | |\n+--------+---------------+-------------+---------+----------+--------------+\n| Bill | Thoughtworks | 2016-10-04 | 146086. | 583722.9 | 437636.47 |\n| | | | 1 | | |\n+--------+---------------+-------------+---------+----------+--------------+\n| Bill | Latz | 2016-10-08 | 857254. | 1440977. | 857254.87 |\n| | | | 7 | 5 | |\n+--------+---------------+-------------+---------+----------+--------------+\n| Chris | Linkbridge | 2016-10-07 | 539977. | 539977.4 | 539977.45 |\n| | | | 5 | | |\n+--------+---------------+-------------+---------+----------+--------------+\n| Chris | Avamm | 2016-10-09 | 699566. | 1239544. | 699566.86 |\n| | | | 6 | 1 | |\n+--------+---------------+-------------+---------+----------+--------------+\n| Olivie | Devpulse | 2016-10-05 | 834235. | 834235.9 | 834235.93 |\n| | | | 3 | | |\n+--------+---------------+-------------+---------+----------+--------------+\n| Olivie | Trupe | 2016-10-07 | 500802. | 1335038. | 834235.93 |\n| | | | 9 | 2 | |\n+--------+---------------+-------------+---------+----------+--------------+\n\nRanking / Top Results\n---------------------\n\nThe rank window function allows for ranking or assigning a numeric order value\nbased on the window function definition. Using the Rank() function will result\nin the same value for ties / equal values and the next rank value skipped. The\nDense_Rank() function behaves similarly except the next consecutive number is\nused after a tie rather than skipped. The Row_Number() function will provide a\nunique ordering value. The example query shows the Rank() function being\napplied to rank sales reps by the number of opportunities for Q4 2016.\n\nselect owner, \nwonCount, \nrank() over (order by wonCount desc) rank \nfrom (\n select owner,\n count(*) wonCount\n from opportunities\n where stageName=\'ClosedWon\'\n and closeDate >= \'2016-10-01\' and closeDate < \'2016-12-31\'\n group by owner\n) t\norder by rank;\n\nwith example results (note the query is technically incorrect by using\ncloseDate < \'2016-12-31\' however this creates a tie scenario for illustrative\npurposes):\n\n+----------------------+----------------------------------+------------------+\n| owner | wonCount | rank |\n+----------------------+----------------------------------+------------------+\n| Bill | 19 | 1 |\n+----------------------+----------------------------------+------------------+\n| Chris | 15 | 2 |') WHERE help_topic_id = 797; +update help_topic set description = CONCAT(description, '\n+----------------------+----------------------------------+------------------+\n| Maria | 14 | 3 |\n+----------------------+----------------------------------+------------------+\n| Bob | 14 | 3 |\n+----------------------+----------------------------------+------------------+\n| Olivier | 10 | 5 |\n+----------------------+----------------------------------+------------------+\n\nIf the dense_rank function is used the rank values would be 1,2,3,3,4 and for\nthe row_number function the values would be 1,2,3,4,5.\n\nFirst and Last Values\n---------------------\n\nThe first_value and last_value functions allow determining the first and last\nvalues of a given range. Combined with a group by this allows summarizing\nopening and closing values. The example shows a more complex case where\ndetailed information is presented for first and last opportunity by quarter.\n\nselect a.year, \na.quarter, \nf.accountName firstAccountName, \nf.owner firstOwner, \nf.amount firstAmount, \nl.accountName lastAccountName, \nl.owner lastOwner, \nl.amount lastAmount \nfrom (\n select year,\n quarter,\n min(firstId) firstId,\n min(lastId) lastId\n from (\n select year(closeDate) year,\n quarter(closeDate) quarter,\n first_value(id) over (partition by year(closeDate), quarter(closeDate)\norder by closeDate rows between unbounded preceding and current row) firstId, \n last_value(id) over (partition by year(closeDate), quarter(closeDate)\norder by closeDate rows between current row and unbounded following) lastId \n from opportunities where stageName=\'ClosedWon\'\n ) t\n group by year, quarter order by year,quarter\n) a \njoin opportunities f on a.firstId = f.id \njoin opportunities l on a.lastId = l.id \norder by year, quarter;\n\nwith example results:\n\n+----+------+------------+--------+---------+-----------+-------+--------+\n| ye | quar | firstAccou | firstO | firstAm | lastAccou | lastO | lastAm |\n| r | er | tName | ner | unt | tName | ner | unt |\n+----+------+------------+--------+---------+-----------+-------+--------+\n| 20 | 3 | Skidoo | Bill | 523295. | Skipstorm | Bill | 151420 |\n| 6 | | | | 7 | | | 86 |\n+----+------+------------+--------+---------+-----------+-------+--------+\n| 20 | 4 | Skimia | Chris | 961513. | Avamm | Maria | 112493 |\n| 6 | | | | 9 | | | 65 |\n+----+------+------------+--------+---------+-----------+-------+--------+\n| 20 | 1 | Yombu | Bob | 536875. | Skaboo | Chris | 270273 |\n| 7 | | | | 1 | | | 08 |\n+----+------+------------+--------+---------+-----------+-------+--------+\n\nPrior and Next Example\n----------------------\n\nSometimes it useful to understand the previous and next values in the context\nof a given row. The lag and lead window functions provide this capability. By\ndefault the offset is one providing the prior or next value but can also be\nprovided to get a larger offset. The example query is a report of\nopportunities by account name showing the opportunity amount, and the prior\nand next opportunity amount for that account by close date.\n\nselect accountName, \ncloseDate, \namount currentOppAmount, \nlag(amount) over (partition by accountName order by closeDate) priorAmount,\nlead(amount) over (partition by accountName order by closeDate) nextAmount \nfrom opportunities \norder by accountName, closeDate \nlimit 9;\n\nwith example results:\n\n+--------------+-----------+-------------------+--------------+-------------+\n| accountName | closeDate | currentOppAmount | priorAmount | nextAmount |\n+--------------+-----------+-------------------+--------------+-------------+\n| Abata | 2016-09-1 | 645098.45 | NULL | 161086.82 |\n| | | | | |\n+--------------+-----------+-------------------+--------------+-------------+\n| Abata | 2016-10-1 | 161086.82 | 645098.45 | 350235.75 |\n| | | | | |\n+--------------+-----------+-------------------+--------------+-------------+\n| Abata | 2016-12-1 | 350235.75 | 161086.82 | 878595.89 |\n| | | | | |\n+--------------+-----------+-------------------+--------------+-------------+\n| Abata | 2016-12-3 | 878595.89 | 350235.75 | 922322.39 |\n| | | | | |\n+--------------+-----------+-------------------+--------------+-------------+\n| Abata | 2017-01-2 | 922322.39 | 878595.89 | NULL |\n| | | | | |\n+--------------+-----------+-------------------+--------------+-------------+\n| Abatz | 2016-10-1 | 795424.15 | NULL | NULL |\n| | | | | |\n+--------------+-----------+-------------------+--------------+-------------+\n| Agimba | 2016-07-0 | 288974.84 | NULL | 914461.49 |\n| | | | | |\n+--------------+-----------+-------------------+--------------+-------------+\n| Agimba | 2016-09-0 | 914461.49 | 288974.84 | 176645.52 |\n| | | | | |\n+--------------+-----------+-------------------+--------------+-------------+\n| Agimba | 2016-09-2 | 176645.52 | 914461.49 | NULL |\n| | | | | |\n+--------------+-----------+-------------------+--------------+-------------+\n\nQuartiles Example\n-----------------\n\nThe NTile window function allows for breaking up a data set into portions\nassigned a numeric value to each portion of the range. NTile(4) breaks the\ndata up into quartiles (4 sets). The example query produces a report of all\nopportunities summarizing the quartile boundaries of amount values.\n\nselect t.quartile, \nmin(t.amount) min, \nmax(t.amount) max \nfrom (\n select amount,\n ntile(4) over (order by amount asc) quartile\n from opportunities\n where closeDate >= \'2016-10-01\' and closeDate <= \'2016-12-31\'\n ) t\ngroup by quartile \norder by quartile;\n\nWith example results:\n\n+-----------------------------------------+----------------+----------------+\n| quartile | min | max |\n+-----------------------------------------+----------------+----------------+\n| 1 | 6337.15 | 287634.01 |\n+-----------------------------------------+----------------+----------------+\n| 2 | 288796.14 | 539977.45 |\n+-----------------------------------------+----------------+----------------+\n| 3 | 540070.04 | 748727.51 |\n+-----------------------------------------+----------------+----------------+\n| 4 | 753670.77 | 998864.47 |\n+-----------------------------------------+----------------+----------------+\n\nPercentile Example\n------------------\n\nThe percentile functions have a slightly different syntax from other window\nfunctions as can be seen in the example below. These functions can be only\napplied against numeric values. The argument to the function is the percentile\nto evaluate. Following \'within group\' is the sort expression which indicates\nthe sort column and optionally order. Finally after \'over\' is an optional\npartition by clause, for no partition clause use \'over ()\'. The example below\nutilizes the value 0.5 to calculate the median opportunity amount in the rows.\nThe values differ sometimes because percentile_cont will return the average of\nthe 2 middle rows for an even data set while percentile_desc returns the first\nencountered in the sort.\n\nselect owner, \naccountName, \nCloseDate, \namount,\npercentile_cont(0.5) within group (order by amount) over (partition by owner)\npct_cont,\npercentile_disc(0.5) within group (order by amount) over (partition by owner)\npct_disc\nfrom opportunities \nwhere stageName=\'ClosedWon\' \nand closeDate >= \'2016-10-02\' and closeDate <= \'2016-10-09\' \norder by owner, CloseDate;\n\nWith example results:\n\n+--------+----------------+-------------+---------+------------+------------+\n| owner | accountName | CloseDate | amount | pct_cont | pct_disc |\n+--------+----------------+-------------+---------+------------+------------+\n| Bill | Babbleopia | 2016-10-02 | 437636. | 437636.470 | 437636.47 |\n| | | | 7 | 000000 | |\n+--------+----------------+-------------+---------+------------+------------+\n| Bill | Thoughtworks | 2016-10-04 | 146086. | 437636.470 | 437636.47 |\n| | | | 1 | 000000 | |\n+--------+----------------+-------------+---------+------------+------------+\n| Bill | Latz | 2016-10-08 | 857254. | 437636.470 | 437636.47 |\n| | | | 7 | 000000 | |\n+--------+----------------+-------------+---------+------------+------------+\n| Chris | Linkbridge | 2016-10-07 | 539977. | 619772.155 | 539977.45 |\n| | | | 5 | 000000 | |\n+--------+----------------+-------------+---------+------------+------------+\n| Chris | Avamm | 2016-10-09 | 699566. | 619772.155 | 539977.45 |\n| | | | 6 | 000000 | |\n+--------+----------------+-------------+---------+------------+------------+\n| Olivie | Devpulse | 2016-10-05 | 834235. | 667519.110 | 500802.29 |\n| | | | 3 | 000000 | |\n+--------+----------------+-------------+---------+------------+------------+\n| Olivie | Trupe | 2016-10-07 | 500802. | 667519.110 | 500802.29 |\n| | | | 9 | 000000 | |\n+--------+----------------+-------------+---------+------------+------------+\n\nURL: https://mariadb.com/kb/en/window-functions-columnstore-window-functions/') WHERE help_topic_id = 797; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (798,41,'Window Frames','Syntax\n------\n\nframe_clause:\n {ROWS | RANGE} {frame_border | BETWEEN frame_border AND frame_border}\n\nframe_border:\n | UNBOUNDED PRECEDING\n | UNBOUNDED FOLLOWING\n | CURRENT ROW\n | expr PRECEDING\n | expr FOLLOWING\n\nDescription\n-----------\n\nA basic overview of window functions is described in Window Functions\nOverview. Window frames expand this functionality by allowing the function to\ninclude a specified a number of rows around the current row.\n\nThese include:\n\n* All rows before the current row (UNBOUNDED PRECEDING), for example RANGE\nBETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\n* All rows after the current row (UNBOUNDED FOLLOWING), for example RANGE\nBETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING\n* A set number of rows before the current row (expr PRECEDING) for example\nRANGE BETWEEN 6 PRECEDING AND CURRENT ROW\n* A set number of rows after the current row (expr PRECEDING AND expr\nFOLLOWING) for example RANGE BETWEEN CURRENT ROW AND 2 FOLLOWING\n* A specified number of rows both before and after the current row, for\nexample RANGE BETWEEN 6 PRECEDING AND 3 FOLLOWING\n\nThe following functions operate on window frames:\n\n* AVG\n* BIT_AND\n* BIT_OR\n* BIT_XOR\n* COUNT\n* LEAD\n* MAX\n* MIN\n* NTILE\n* STD\n* STDDEV\n* STDDEV_POP\n* STDDEV_SAMP\n* SUM\n* VAR_POP\n* VAR_SAMP\n* VARIANCE\n\nWindow frames are determined by the frame_clause in the window function\nrequest.\n\nTake the following example:\n\nCREATE TABLE `student_test` (\n name char(10),\n test char(10),\n score tinyint(4)\n);\n\nINSERT INTO student_test VALUES \n (\'Chun\', \'SQL\', 75), (\'Chun\', \'Tuning\', 73),\n (\'Esben\', \'SQL\', 43), (\'Esben\', \'Tuning\', 31),\n (\'Kaolin\', \'SQL\', 56), (\'Kaolin\', \'Tuning\', 88),\n (\'Tatiana\', \'SQL\', 87);\n\nSELECT name, test, score, SUM(score) \n OVER () AS total_score\n FROM student_test;\n+---------+--------+-------+-------------+\n| name | test | score | total_score |\n+---------+--------+-------+-------------+\n| Chun | SQL | 75 | 453 |\n| Chun | Tuning | 73 | 453 |\n| Esben | SQL | 43 | 453 |\n| Esben | Tuning | 31 | 453 |\n| Kaolin | SQL | 56 | 453 |\n| Kaolin | Tuning | 88 | 453 |\n| Tatiana | SQL | 87 | 453 |\n+---------+--------+-------+-------------+\n\nBy not specifying an OVER clause, the SUM function is run over the entire\ndataset. However, if we specify an ORDER BY condition based on score (and\norder the entire result in the same way for clarity), the following result is\nreturned:\n\nSELECT name, test, score, SUM(score) \n OVER (ORDER BY score) AS total_score\n FROM student_test ORDER BY score;\n+---------+--------+-------+-------------+\n| name | test | score | total_score |\n+---------+--------+-------+-------------+\n| Esben | Tuning | 31 | 31 |\n| Esben | SQL | 43 | 74 |\n| Kaolin | SQL | 56 | 130 |\n| Chun | Tuning | 73 | 203 |\n| Chun | SQL | 75 | 278 |\n| Tatiana | SQL | 87 | 365 |\n| Kaolin | Tuning | 88 | 453 |\n+---------+--------+-------+-------------+\n\nThe total_score column represents a running total of the current row, and all\nprevious rows. The window frame in this example expands as the function\nproceeds.\n\nThe above query makes use of the default to define the window frame. It could\nbe written explicitly as follows:\n\nSELECT name, test, score, SUM(score) \n OVER (ORDER BY score RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS\ntotal_score \n FROM student_test ORDER BY score;\n+---------+--------+-------+-------------+\n| name | test | score | total_score |\n+---------+--------+-------+-------------+\n| Esben | Tuning | 31 | 31 |\n| Esben | SQL | 43 | 74 |\n| Kaolin | SQL | 56 | 130 |\n| Chun | Tuning | 73 | 203 |\n| Chun | SQL | 75 | 278 |\n| Tatiana | SQL | 87 | 365 |\n| Kaolin | Tuning | 88 | 453 |\n+---------+--------+-------+-------------+\n\nLet\'s look at some alternatives:\n\nFirstly, applying the window function to the current row and all following\nrows can be done with the use of UNBOUNDED FOLLOWING:\n\nSELECT name, test, score, SUM(score) \n OVER (ORDER BY score RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS\ntotal_score \n FROM student_test ORDER BY score;\n+---------+--------+-------+-------------+\n| name | test | score | total_score |\n+---------+--------+-------+-------------+\n| Esben | Tuning | 31 | 453 |\n| Esben | SQL | 43 | 422 |\n| Kaolin | SQL | 56 | 379 |\n| Chun | Tuning | 73 | 323 |\n| Chun | SQL | 75 | 250 |\n| Tatiana | SQL | 87 | 175 |\n| Kaolin | Tuning | 88 | 88 |\n+---------+--------+-------+-------------+\n\nIt\'s possible to specify a number of rows, rather than the entire unbounded\nfollowing or preceding set. The following example takes the current row, as\nwell as the previous row:\n\nSELECT name, test, score, SUM(score) \n OVER (ORDER BY score ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS\ntotal_score \n FROM student_test ORDER BY score;\n+---------+--------+-------+-------------+\n| name | test | score | total_score |\n+---------+--------+-------+-------------+\n| Esben | Tuning | 31 | 31 |\n| Esben | SQL | 43 | 74 |\n| Kaolin | SQL | 56 | 99 |\n| Chun | Tuning | 73 | 129 |\n| Chun | SQL | 75 | 148 |\n| Tatiana | SQL | 87 | 162 |\n| Kaolin | Tuning | 88 | 175 |\n+---------+--------+-------+-------------+\n\nThe current row and the following row:\n\nSELECT name, test, score, SUM(score) \n OVER (ORDER BY score ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS\ntotal_score \n FROM student_test ORDER BY score;\n+---------+--------+-------+-------------+\n| name | test | score | total_score |\n+---------+--------+-------+-------------+\n| Esben | Tuning | 31 | 74 |\n| Esben | SQL | 43 | 130 |\n| Kaolin | SQL | 56 | 172 |\n| Chun | Tuning | 73 | 204 |\n| Chun | SQL | 75 | 235 |\n| Tatiana | SQL | 87 | 250 |\n| Kaolin | Tuning | 88 | 175 |\n+---------+--------+-------+-------------+\n\nURL: https://mariadb.com/kb/en/window-frames/','','https://mariadb.com/kb/en/window-frames/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (799,42,'SPIDER_BG_DIRECT_SQL','Syntax\n------\n\nSPIDER_BG_DIRECT_SQL(\'sql\', \'tmp_table_list\', \'parameters\')\n\nDescription\n-----------\n\nExecutes the given SQL statement in the background on the remote server, as\ndefined in the parameters listing. If the query returns a result-set, it\nsttores the results in the given temporary table. When the given SQL statement\nexecutes successfully, this function returns the number of called UDF\'s. It\nreturns 0 when the given SQL statement fails.\n\nThis function is a UDF installed with the Spider storage engine.\n\nExamples\n--------\n\nSELECT SPIDER_BG_DIRECT_SQL(\'SELECT * FROM example_table\', \'\', \n \'srv \"node1\", port \"8607\"\') AS \"Direct Query\";\n+--------------+\n| Direct Query | \n+--------------+\n| 1 |\n+--------------+\n\nParameters\n----------\n\nerror_rw_mode\n-------------\n\n* Description: Returns empty results on network error.\n0 : Return error on getting network error.\n1: Return 0 records on getting network error.\n\n* Default Table Value: 0\n* DSN Parameter Name: erwm\n\nURL: https://mariadb.com/kb/en/spider_bg_direct_sql/','','https://mariadb.com/kb/en/spider_bg_direct_sql/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (800,42,'SPIDER_COPY_TABLES','Syntax\n------\n\nSPIDER_COPY_TABLES(spider_table_name, \n source_link_id, destination_link_id_list [,parameters])\n\nDescription\n-----------\n\nA UDF installed with the Spider Storage Engine, this function copies table\ndata from source_link_id to destination_link_id_list. The service does not\nneed to be stopped in order to copy.\n\nIf the Spider table is partitioned, the name must be of the format\ntable_name#P#partition_name. The partition name can be viewed in the\nmysql.spider_tables table, for example:\n\nSELECT table_name FROM mysql.spider_tables;\n+-------------+\n| table_name |\n+-------------+\n| spt_a#P#pt1 |\n| spt_a#P#pt2 |\n| spt_a#P#pt3 |\n+-------------+\n\nReturns 1 if the data was copied successfully, or 0 if copying the data failed.\n\nURL: https://mariadb.com/kb/en/spider_copy_tables/','','https://mariadb.com/kb/en/spider_copy_tables/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (801,42,'SPIDER_DIRECT_SQL','Syntax\n------\n\nSPIDER_DIRECT_SQL(\'sql\', \'tmp_table_list\', \'parameters\')\n\nDescription\n-----------\n\nA UDF installed with the Spider Storage Engine, this function is used to\nexecute the SQL string sql on the remote server, as defined in parameters. If\nany resultsets are returned, they are stored in the tmp_table_list.\n\nThe function returns 1 if the SQL executes successfully, or 0 if it fails.\n\nExamples\n--------\n\nSELECT SPIDER_DIRECT_SQL(\'SELECT * FROM s\', \'\', \'srv \"node1\", port \"8607\"\');\n+----------------------------------------------------------------------+\n| SPIDER_DIRECT_SQL(\'SELECT * FROM s\', \'\', \'srv \"node1\", port \"8607\"\') |\n+----------------------------------------------------------------------+\n| 1 |\n+----------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/spider_direct_sql/','','https://mariadb.com/kb/en/spider_direct_sql/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (802,42,'SPIDER_FLUSH_TABLE_MON_CACHE','Syntax\n------\n\nSPIDER_FLUSH_TABLE_MON_CACHE()\n\nDescription\n-----------\n\nA UDF installed with the Spider Storage Engine, this function is used for\nrefreshing monitoring server information. It returns a value of 1.\n\nExamples\n--------\n\nSELECT SPIDER_FLUSH_TABLE_MON_CACHE();\n+--------------------------------+\n| SPIDER_FLUSH_TABLE_MON_CACHE() |\n+--------------------------------+\n| 1 |\n+--------------------------------+\n\nURL: https://mariadb.com/kb/en/spider_flush_table_mon_cache/','','https://mariadb.com/kb/en/spider_flush_table_mon_cache/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (803,43,'COLUMN_ADD','Syntax\n------\n\nCOLUMN_ADD(dyncol_blob, column_nr, value [as type], [column_nr, value [as\ntype]]...);\nCOLUMN_ADD(dyncol_blob, column_name, value [as type], [column_name, value [as\ntype]]...);\n\nDescription\n-----------\n\nAdds or updates dynamic columns.\n\n* dyncol_blob must be either a valid dynamic columns blob (for example,\nCOLUMN_CREATE returns such blob), or an empty string.\n* column_name specifies the name of the column to be added. If dyncol_blob\nalready has a column with this name, it will be overwritten.\n* value specifies the new value for the column. Passing a NULL value will\ncause the column to be deleted.\n* as type is optional. See #datatypes section for a discussion about types.\n\nThe return value is a dynamic column blob after the modifications.\n\nExamples\n--------\n\nUPDATE t1 SET dyncol_blob=COLUMN_ADD(dyncol_blob, \"column_name\", \"value\")\nWHERE id=1;\n\nNote: COLUMN_ADD() is a regular function (just like CONCAT()), hence, in order\nto update the value in the table you have to use the UPDATE ... SET\ndynamic_col=COLUMN_ADD(dynamic_col, ....) pattern.\n\nURL: https://mariadb.com/kb/en/column_add/','','https://mariadb.com/kb/en/column_add/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (804,43,'COLUMN_CHECK','Syntax\n------\n\nCOLUMN_CHECK(dyncol_blob);\n\nDescription\n-----------\n\nCheck if dyncol_blob is a valid packed dynamic columns blob. Return value of 1\nmeans the blob is valid, return value of 0 means it is not.\n\nRationale: Normally, one works with valid dynamic column blobs. Functions like\nCOLUMN_CREATE, COLUMN_ADD, COLUMN_DELETE always return valid dynamic column\nblobs. However, if a dynamic column blob is accidentally truncated, or\ntranscoded from one character set to another, it will be corrupted. This\nfunction can be used to check if a value in a blob field is a valid dynamic\ncolumn blob.\n\nURL: https://mariadb.com/kb/en/column_check/','','https://mariadb.com/kb/en/column_check/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (805,43,'COLUMN_CREATE','Syntax\n------\n\nCOLUMN_CREATE(column_nr, value [as type], [column_nr, value [as type]]...);\nCOLUMN_CREATE(column_name, value [as type], [column_name, value [as type]]...);\n\nDescription\n-----------\n\nReturns a dynamic columns blob that stores the specified columns with values.\n\nThe return value is suitable for\n\n* storing in a table\n* further modification with other dynamic columns functions\n\nThe as type part allows one to specify the value type. In most cases, this is\nredundant because MariaDB will be able to deduce the type of the value.\nExplicit type specification may be needed when the type of the value is not\napparent. For example, a literal \'2012-12-01\' has a CHAR type by default, one\nwill need to specify \'2012-12-01\' AS DATE to have it stored as a date. See\nDynamic Columns:Datatypes for further details.\n\nExamples\n--------\n\nINSERT INTO tbl SET dyncol_blob=COLUMN_CREATE(\"column_name\", \"value\");\n\nURL: https://mariadb.com/kb/en/column_create/','','https://mariadb.com/kb/en/column_create/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (806,43,'COLUMN_DELETE','Syntax\n------\n\nCOLUMN_DELETE(dyncol_blob, column_nr, column_nr...);\nCOLUMN_DELETE(dyncol_blob, column_name, column_name...);\n\nDescription\n-----------\n\nDeletes a dynamic column with the specified name. Multiple names can be given.\nThe return value is a dynamic column blob after the modification.\n\nURL: https://mariadb.com/kb/en/column_delete/','','https://mariadb.com/kb/en/column_delete/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (807,43,'COLUMN_EXISTS','Syntax\n------\n\nCOLUMN_EXISTS(dyncol_blob, column_nr);\nCOLUMN_EXISTS(dyncol_blob, column_name);\n\nDescription\n-----------\n\nChecks if a column with name column_name exists in dyncol_blob. If yes, return\n1, otherwise return 0. See dynamic columns for more information.\n\nURL: https://mariadb.com/kb/en/column_exists/','','https://mariadb.com/kb/en/column_exists/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (808,43,'COLUMN_GET','Syntax\n------\n\nCOLUMN_GET(dyncol_blob, column_nr as type);\nCOLUMN_GET(dyncol_blob, column_name as type);\n\nDescription\n-----------\n\nGets the value of a dynamic column by its name. If no column with the given\nname exists, NULL will be returned.\n\ncolumn_name as type requires that one specify the datatype of the dynamic\ncolumn they are reading.\n\nThis may seem counter-intuitive: why would one need to specify which datatype\nthey\'re retrieving? Can\'t the dynamic columns system figure the datatype from\nthe data being stored?\n\nThe answer is: SQL is a statically-typed language. The SQL interpreter needs\nto know the datatypes of all expressions before the query is run (for example,\nwhen one is using prepared statements and runs \"select COLUMN_GET(...)\", the\nprepared statement API requires the server to inform the client about the\ndatatype of the column being read before the query is executed and the server\ncan see what datatype the column actually has).\n\nLengths\n-------\n\nIf you\'re running queries like:\n\nSELECT COLUMN_GET(blob, \'colname\' as CHAR) ...\n\nwithout specifying a maximum length (i.e. using as CHAR, not as CHAR(n)),\nMariaDB will report the maximum length of the resultset column to be\n16,777,216. This may cause excessive memory usage in some client libraries,\nbecause they try to pre-allocate a buffer of maximum resultset width. To avoid\nthis problem, use CHAR(n) whenever you\'re using COLUMN_GET in the select list.\n\nSee Dynamic Columns:Datatypes for more information about datatypes.\n\nURL: https://mariadb.com/kb/en/column_get/','','https://mariadb.com/kb/en/column_get/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (809,43,'COLUMN_JSON','Syntax\n------\n\nCOLUMN_JSON(dyncol_blob)\n\nDescription\n-----------\n\nReturns a JSON representation of data in dyncol_blob. Can also be used to\ndisplay nested columns. See dynamic columns for more information.\n\nExample\n-------\n\nselect item_name, COLUMN_JSON(dynamic_cols) from assets;\n+-----------------+----------------------------------------+\n| item_name | COLUMN_JSON(dynamic_cols) |\n+-----------------+----------------------------------------+\n| MariaDB T-shirt | {\"size\":\"XL\",\"color\":\"blue\"} |\n| Thinkpad Laptop | {\"color\":\"black\",\"warranty\":\"3 years\"} |\n+-----------------+----------------------------------------+\n\nLimitation: COLUMN_JSON will decode nested dynamic columns at a nesting level\nof not more than 10 levels deep. Dynamic columns that are nested deeper than\n10 levels will be shown as BINARY string, without encoding.\n\nURL: https://mariadb.com/kb/en/column_json/','','https://mariadb.com/kb/en/column_json/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (810,43,'COLUMN_LIST','Syntax\n------\n\nCOLUMN_LIST(dyncol_blob);\n\nDescription\n-----------\n\nReturns a comma-separated list of column names. The names are quoted with\nbackticks.\n\nSee dynamic columns for more information.\n\nURL: https://mariadb.com/kb/en/column_list/','','https://mariadb.com/kb/en/column_list/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (811,44,'WSREP_LAST_SEEN_GTID','MariaDB starting with 10.4.2\n----------------------------\nWSREP_LAST_SEEN_GTID was added as part of Galera 4 in MariaDB 10.4.2.\n\nSyntax\n------\n\nWSREP_LAST_SEEN_GTID()\n\nDescription\n-----------\n\nReturns the Global Transaction ID of the most recent write transaction\nobserved by the client.\n\nThe result can be useful to determine the transaction to provide to\nWSREP_SYNC_WAIT_UPTO_GTID for waiting and unblocking purposes.\n\nURL: https://mariadb.com/kb/en/wsrep_last_seen_gtid/','','https://mariadb.com/kb/en/wsrep_last_seen_gtid/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (812,44,'WSREP_LAST_WRITTEN_GTID','MariaDB starting with 10.4.2\n----------------------------\nWSREP_LAST_WRITTEN_GTID was added as part of Galera 4 in MariaDB 10.4.2.\n\nSyntax\n------\n\nWSREP_LAST_WRITTEN_GTID()\n\nDescription\n-----------\n\nReturns the Global Transaction ID of the most recent write transaction\nperformed by the client.\n\nURL: https://mariadb.com/kb/en/wsrep_last_written_gtid/','','https://mariadb.com/kb/en/wsrep_last_written_gtid/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (813,44,'WSREP_SYNC_WAIT_UPTO_GTID','MariaDB starting with 10.4.2\n----------------------------\nWSREP_SYNC_WAIT_UPTO_GTID was added as part of Galera 4 in MariaDB 10.4.2.\n\nSyntax\n------\n\nWSREP_SYNC_WAIT_UPTO_GTID(gtid[,timeout])\n\nDescription\n-----------\n\nBlocks the client until the transaction specified by the given Global\nTransaction ID is applied and committed by the node.\n\nThe optional timeout argument can be used to specify a block timeout in\nseconds. If not provided, the timeout will be indefinite.\n\nReturns the node that applied and committed the Global Transaction ID,\nER_LOCAL_WAIT_TIMEOUT if the function is timed out before this, or\nER_WRONG_ARGUMENTS if the function is given an invalid GTID.\n\nThe result from WSREP_LAST_SEEN_GTID can be useful to determine the\ntransaction to provide to WSREP_SYNC_WAIT_UPTO_GTID for waiting and unblocking\npurposes.\n\nURL: https://mariadb.com/kb/en/wsrep_sync_wait_upto_gtid/','','https://mariadb.com/kb/en/wsrep_sync_wait_upto_gtid/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (814,45,'System-Versioned Tables','MariaDB supports temporal data tables in the form of system-versioning tables\n(allowing you to query and operate on historic data, discussed below),\napplication-time periods (allow you to query and operate on a temporal range\nof data), and bitemporal tables (which combine both system-versioning and\napplication-time periods).\n\nSystem-Versioned Tables\n-----------------------\n\nSystem-versioned tables store the history of all changes, not only data which\nis currently valid. This allows data analysis for any point in time, auditing\nof changes and comparison of data from different points in time. Typical uses\ncases are:\n\n* Forensic analysis & legal requirements to store data for N years.\n* Data analytics (retrospective, trends etc.), e.g. to get your staff\ninformation as of one year ago.\n* Point-in-time recovery - recover a table state as of particular point in\ntime.\n\nSystem-versioned tables were first introduced in the SQL:2011 standard.\n\nCreating a System-Versioned Table\n---------------------------------\n\nThe CREATE TABLE syntax has been extended to permit creating a\nsystem-versioned table. To be system-versioned, according to SQL:2011, a table\nmust have two generated columns, a period, and a special table option clause:\n\nCREATE TABLE t(\n x INT,\n start_timestamp TIMESTAMP(6) GENERATED ALWAYS AS ROW START,\n end_timestamp TIMESTAMP(6) GENERATED ALWAYS AS ROW END,\n PERIOD FOR SYSTEM_TIME(start_timestamp, end_timestamp)\n) WITH SYSTEM VERSIONING;\n\nIn MariaDB one can also use a simplified syntax:\n\nCREATE TABLE t (\n x INT\n) WITH SYSTEM VERSIONING;\n\nIn the latter case no extra columns will be created and they won\'t clutter the\noutput of, say, SELECT * FROM t. The versioning information will still be\nstored, and it can be accessed via the pseudo-columns ROW_START and ROW_END:\n\nSELECT x, ROW_START, ROW_END FROM t;\n\nAdding or Removing System Versioning To/From a Table\n----------------------------------------------------\n\nAn existing table can be altered to enable system versioning for it.\n\nCREATE TABLE t(\n x INT\n);\n\nALTER TABLE t ADD SYSTEM VERSIONING;\n\nSHOW CREATE TABLE t\\G\n*************************** 1. row ***************************\n Table: t\nCreate Table: CREATE TABLE `t` (\n `x` int(11) DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING\n\nSimilarly, system versioning can be removed from a table:\n\nALTER TABLE t DROP SYSTEM VERSIONING;\n\nSHOW CREATE TABLE t\\G\n*************************** 1. row ***************************\n Table: t\nCreate Table: CREATE TABLE `t` (\n `x` int(11) DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=latin1\n\nOne can also add system versioning with all columns created explicitly:\n\nALTER TABLE t ADD COLUMN ts TIMESTAMP(6) GENERATED ALWAYS AS ROW START,\n ADD COLUMN te TIMESTAMP(6) GENERATED ALWAYS AS ROW END,\n ADD PERIOD FOR SYSTEM_TIME(ts, te),\n ADD SYSTEM VERSIONING;\n\nSHOW CREATE TABLE t\\G\n*************************** 1. row ***************************\n Table: t\nCreate Table: CREATE TABLE `t` (\n `x` int(11) DEFAULT NULL,\n `ts` timestamp(6) GENERATED ALWAYS AS ROW START,\n `te` timestamp(6) GENERATED ALWAYS AS ROW END,\n PERIOD FOR SYSTEM_TIME (`ts`, `te`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING\n\nInserting Data\n--------------\n\nWhen data is inserted into a system-versioned table, it is given a row_start\nvalue of the current timestamp, and a row_end value of\nFROM_UNIXTIME(2147483647.999999). The current timestamp can be adjusted by\nsetting the timestamp system variable, for example:\n\nSELECT NOW();\n+---------------------+\n| NOW() |\n+---------------------+\n| 2022-10-24 23:09:38 |\n+---------------------+\n\nINSERT INTO t VALUES(1);\n\nSET @@timestamp = UNIX_TIMESTAMP(\'2033-10-24\');\n\nINSERT INTO t VALUES(2);\n\nSET @@timestamp = default;\n\nINSERT INTO t VALUES(3);\n\nSELECT a,row_start,row_end FROM t;\n+------+----------------------------+----------------------------+\n| a | row_start | row_end |\n+------+----------------------------+----------------------------+\n| 1 | 2022-10-24 23:09:38.951347 | 2038-01-19 05:14:07.999999 |\n| 2 | 2033-10-24 00:00:00.000000 | 2038-01-19 05:14:07.999999 |\n| 3 | 2022-10-24 23:09:38.961857 | 2038-01-19 05:14:07.999999 |\n+------+----------------------------+----------------------------+\n\nQuerying Historical Data\n------------------------\n\nSELECT\n------\n\nTo query the historical data one uses the clause FOR SYSTEM_TIME directly\nafter the table name (before the table alias, if any). SQL:2011 provides three\nsyntactic extensions:\n\n* AS OF is used to see the table as it was at a specific point in time in the\npast:\n\nSELECT * FROM t FOR SYSTEM_TIME AS OF TIMESTAMP\'2016-10-09 08:07:06\';\n\n* BETWEEN start AND end will show all rows that were visible at any point\nbetween two specified points in time. It works inclusively, a row visible\nexactly at start or exactly at end will be shown too.\n\nSELECT * FROM t FOR SYSTEM_TIME BETWEEN (NOW() - INTERVAL 1 YEAR) AND NOW();\n\n* FROM start TO end will also show all rows that were visible at any point\nbetween two specified points in time, including start, but excluding end.\n\nSELECT * FROM t FOR SYSTEM_TIME FROM \'2016-01-01 00:00:00\' TO \'2017-01-01\n00:00:00\';\n\nAdditionally MariaDB implements a non-standard extension:\n\n* ALL will show all rows, historical and current.\n\nSELECT * FROM t FOR SYSTEM_TIME ALL;\n\nIf the FOR SYSTEM_TIME clause is not used, the table will show the current\ndata. This is usually the same as if one had specified FOR SYSTEM_TIME AS OF\nCURRENT_TIMESTAMP, unless one has adjusted the row_start value (until MariaDB\n10.11, only possible by setting the secure_timestamp variable). For example:\n\nCREATE OR REPLACE TABLE t (a int) WITH SYSTEM VERSIONING;\n\nSELECT NOW();\n+---------------------+\n| NOW() |\n+---------------------+\n| 2022-10-24 23:43:37 |\n+---------------------+\n\nINSERT INTO t VALUES (1);\n\nSET @@timestamp = UNIX_TIMESTAMP(\'2033-03-03\');\n\nINSERT INTO t VALUES (2);\n\nDELETE FROM t;\n\nSET @@timestamp = default;\n\nSELECT a, row_start, row_end FROM t FOR SYSTEM_TIME ALL;\n+------+----------------------------+----------------------------+\n| a | row_start | row_end |\n+------+----------------------------+----------------------------+\n| 1 | 2022-10-24 23:43:37.192725 | 2033-03-03 00:00:00.000000 |\n| 2 | 2033-03-03 00:00:00.000000 | 2033-03-03 00:00:00.000000 |\n+------+----------------------------+----------------------------+\n2 rows in set (0.000 sec)\n\nSELECT a, row_start, row_end FROM t FOR SYSTEM_TIME AS OF CURRENT_TIMESTAMP;\n+------+----------------------------+----------------------------+\n| a | row_start | row_end |\n+------+----------------------------+----------------------------+\n| 1 | 2022-10-24 23:43:37.192725 | 2033-03-03 00:00:00.000000 |\n+------+----------------------------+----------------------------+\n1 row in set (0.000 sec)\n\nSELECT a, row_start, row_end FROM t;\nEmpty set (0.001 sec)\n\nViews and Subqueries\n--------------------\n\nWhen a system-versioned tables is used in a view or in a subquery in the from\nclause, FOR SYSTEM_TIME can be used directly in the view or subquery body, or\n(non-standard) applied to the whole view when it\'s being used in a SELECT:\n\nCREATE VIEW v1 AS SELECT * FROM t FOR SYSTEM_TIME AS OF TIMESTAMP\'2016-10-09\n08:07:06\';\n\nOr\n\nCREATE VIEW v1 AS SELECT * FROM t;\nSELECT * FROM v1 FOR SYSTEM_TIME AS OF TIMESTAMP\'2016-10-09 08:07:06\';\n\nUse in Replication and Binary Logs\n----------------------------------\n\nTables that use system-versioning implicitly add the row_end column to the\nPrimary Key. While this is generally not an issue for most use cases, it can\nlead to problems when re-applying write statements from the binary log or in\nreplication environments, where a primary retries an SQL statement on the\nreplica.\n\nSpecifically, these writes include a value on the row_end column containing\nthe timestamp from when the write was initially made. The re-occurrence of the\nPrimary Key with the old system-versioning columns raises an error due to the\nduplication.\n\nTo mitigate this with MariaDB Replication, set the secure_timestamp system\nvariable to YES on the replica. When set, the replica uses its own system\nclock when applying to the row log, meaning that the primary can retry as many\ntimes as needed without causing a conflict. The retries generate new\nhistorical rows with new values for the row_start and row_end columns.\n\nTransaction-Precise History in InnoDB\n-------------------------------------\n\nA point in time when a row was inserted or deleted does not necessarily mean\nthat a change became visible at the same moment. With transactional tables, a\nrow might have been inserted in a long transaction, and became visible hours\nafter it was inserted.\n\nFor some applications — for example, when doing data analytics on one-year-old\ndata — this distinction does not matter much. For others — forensic analysis —\nit might be crucial.\n\nMariaDB supports transaction-precise history (only for the InnoDB storage\nengine) that allows seeing the data exactly as it would\'ve been seen by a new\nconnection doing a SELECT at the specified point in time — rows inserted\nbefore that point, but committed after will not be shown.\n\nTo use transaction-precise history, InnoDB needs to remember not timestamps,\nbut transaction identifier per row. This is done by creating generated columns\nas BIGINT UNSIGNED, not TIMESTAMP(6):\n\nCREATE TABLE t(\n x INT,\n start_trxid BIGINT UNSIGNED GENERATED ALWAYS AS ROW START,\n end_trxid BIGINT UNSIGNED GENERATED ALWAYS AS ROW END,\n PERIOD FOR SYSTEM_TIME(start_trxid, end_trxid)\n) WITH SYSTEM VERSIONING;\n\nThese columns must be specified explicitly, but they can be made INVISIBLE to\navoid cluttering SELECT * output.\n\nWhen one uses transaction-precise history, one can optionally use transaction\nidentifiers in the FOR SYSTEM_TIME clause:\n\nSELECT * FROM t FOR SYSTEM_TIME AS OF TRANSACTION 12345;\n\nThis will show the data, exactly as it was seen by the transaction with the\nidentifier 12345.\n\nStoring the History Separately\n------------------------------\n\nWhen the history is stored together with the current data, it increases the\nsize of the table, so current data queries — table scans and index searches —\nwill take more time, because they will need to skip over historical data. If\nmost queries on that table use only current data, it might make sense to store\nthe history separately, to reduce the overhead from versioning.\n\nThis is done by partitioning the table by SYSTEM_TIME. Because of the\npartition pruning optimization, all current data queries will only access one\npartition, the one that stores current data.\n\nThis example shows how to create such a partitioned table:\n\nCREATE TABLE t (x INT) WITH SYSTEM VERSIONING\n PARTITION BY SYSTEM_TIME (\n PARTITION p_hist HISTORY,\n PARTITION p_cur CURRENT\n );\n\nIn this example all history will be stored in the partition p_hist while all\ncurrent data will be in the partition p_cur. The table must have exactly one\ncurrent partition and at least one historical partition.\n\nPartitioning by SYSTEM_TIME also supports automatic partition rotation. One\ncan rotate historical partitions by time or by size. This example shows how to\nrotate partitions by size:\n\nCREATE TABLE t (x INT) WITH SYSTEM VERSIONING\n PARTITION BY SYSTEM_TIME LIMIT 100000 (\n PARTITION p0 HISTORY,\n PARTITION p1 HISTORY,\n PARTITION pcur CURRENT\n );\n\nMariaDB will start writing history rows into partition p0, and when it reaches\na size of 100000 rows, MariaDB will switch to partition p1. There are only two\nhistorical partitions, so when p1 overflows, MariaDB will issue a warning, but\nwill continue writing into it.\n\nSimilarly, one can rotate partitions by time:\n\nCREATE TABLE t (x INT) WITH SYSTEM VERSIONING\n PARTITION BY SYSTEM_TIME INTERVAL 1 WEEK (\n PARTITION p0 HISTORY,\n PARTITION p1 HISTORY,\n PARTITION p2 HISTORY,\n PARTITION pcur CURRENT\n );\n\nThis means that the history for the first week after the table was created\nwill be stored in p0. The history for the second week — in p1, and all later\nhistory will go into p2. One can see the exact rotation time for each\npartition in the INFORMATION_SCHEMA.PARTITIONS table.\n\nIt is possible to combine partitioning by SYSTEM_TIME and subpartitions:\n\nCREATE TABLE t (x INT) WITH SYSTEM VERSIONING\n PARTITION BY SYSTEM_TIME\n SUBPARTITION BY KEY (x)\n SUBPARTITIONS 4 (\n PARTITION ph HISTORY,\n PARTITION pc CURRENT\n );\n\nDefault Partitions\n------------------\n\nMariaDB starting with 10.5.0\n----------------------------\nSince partitioning by current and historical data is such a typical usecase,\nfrom MariaDB 10.5, it is possible to use a simplified statement to do so. For\nexample, instead of\n\nCREATE TABLE t (x INT) WITH SYSTEM VERSIONING \n PARTITION BY SYSTEM_TIME (\n PARTITION p0 HISTORY,\n PARTITION pn CURRENT\n);\n\nyou can use\n\nCREATE TABLE t (x INT) WITH SYSTEM VERSIONING \n PARTITION BY SYSTEM_TIME;\n\nYou can also specify the number of partitions, which is useful if you want to\nrotate history by time, for example:\n\nCREATE TABLE t (x INT) WITH SYSTEM VERSIONING \n PARTITION BY SYSTEM_TIME\n INTERVAL 1 MONTH\n PARTITIONS 12;\n\nSpecifying the number of partitions without specifying a rotation condition\nwill result in a warning:\n\nCREATE OR REPLACE TABLE t (x INT) WITH SYSTEM VERSIONING\n PARTITION BY SYSTEM_TIME PARTITIONS 12;\nQuery OK, 0 rows affected, 1 warning (0.518 sec)\n\nWarning (Code 4115): Maybe missing parameters: no rotation condition for\nmultiple HISTORY partitions.\n\nwhile specifying only 1 partition will result in an error:\n\nCREATE OR REPLACE TABLE t (x INT) WITH SYSTEM VERSIONING\n PARTITION BY SYSTEM_TIME PARTITIONS 1;\nERROR 4128 (HY000): Wrong partitions for `t`: must have at least one HISTORY\nand exactly one last CURRENT\n\nAutomatically Creating Partitions\n---------------------------------\n\nMariaDB starting with 10.9.1\n----------------------------\nFrom MariaDB 10.9.1, the AUTO keyword can be used to automatically create\nhistory partitions.\n\nFor example\n\nCREATE TABLE t1 (x int) WITH SYSTEM VERSIONING\n PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR AUTO;\n','','https://mariadb.com/kb/en/system-versioned-tables/'); +update help_topic set description = CONCAT(description, '\nCREATE TABLE t1 (x int) WITH SYSTEM VERSIONING\n PARTITION BY SYSTEM_TIME INTERVAL 1 MONTH\n STARTS \'2021-01-01 00:00:00\' AUTO PARTITIONS 12;\n\nCREATE TABLE t1 (x int) WITH SYSTEM VERSIONING\n PARTITION BY SYSTEM_TIME LIMIT 1000 AUTO;\n\nOr with explicit partitions:\n\nCREATE TABLE t1 (x int) WITH SYSTEM VERSIONING\n PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR AUTO\n (PARTITION p0 HISTORY, PARTITION pn CURRENT);\n\nTo disable or enable auto-creation one can use ALTER TABLE by adding or\nremoving AUTO from the partitioning specification:\n\nCREATE TABLE t1 (x int) WITH SYSTEM VERSIONING\n PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR AUTO;\n\n# Disables auto-creation:\nALTER TABLE t1 PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR;\n\n# Enables auto-creation:\nALTER TABLE t1 PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR AUTO;\n\nIf the rest of the partitioning specification is identical to CREATE TABLE, no\nrepartitioning will be done (for details see MDEV-27328).\n\nRemoving Old History\n--------------------\n\nBecause it stores all the history, a system-versioned table might grow very\nlarge over time. There are many options to trim down the space and remove the\nold history.\n\nOne can completely drop the versioning from the table and add it back again,\nthis will delete all the history:\n\nALTER TABLE t DROP SYSTEM VERSIONING;\nALTER TABLE t ADD SYSTEM VERSIONING;\n\nIt might be a rather time-consuming operation, though, as the table will need\nto be rebuilt, possibly twice (depending on the storage engine).\n\nAnother option would be to use partitioning and drop some of historical\npartitions:\n\nALTER TABLE t DROP PARTITION p0;\n\nNote, that one cannot drop a current partition or the only historical\npartition.\n\nAnd the third option; one can use a variant of the DELETE statement to prune\nthe history:\n\nDELETE HISTORY FROM t;\n\nor only old history up to a specific point in time:\n\nDELETE HISTORY FROM t BEFORE SYSTEM_TIME \'2016-10-09 08:07:06\';\n\nor to a specific transaction (with BEFORE SYSTEM_TIME TRANSACTION xxx).\n\nTo protect the integrity of the history, this statement requires a special\nDELETE HISTORY privilege.\n\nCurrently, using the DELETE HISTORY statement with a BEFORE SYSTEM_TIME\ngreater than the ROW_END of the active records (as a TIMESTAMP, this has a\nmaximum value of \'2038-01-19 03:14:07\' UTC) will result in the historical\nrecords being dropped, and the active records being deleted and moved to\nhistory. See MDEV-25468.\n\nPrior to MariaDB 10.4.5, the TRUNCATE TABLE statement drops all historical\nrecords from a system-versioned-table.\n\nFrom MariaDB 10.4.5, historic data is protected from TRUNCATE statements, as\nper the SQL standard, and an Error 4137 is instead raised:\n\nTRUNCATE t;\nERROR 4137 (HY000): System-versioned tables do not support TRUNCATE TABLE\n\nExcluding Columns From Versioning\n---------------------------------\n\nAnother MariaDB extension allows to version only a subset of columns in a\ntable. This is useful, for example, if you have a table with user information\nthat should be versioned, but one column is, let\'s say, a login counter that\nis incremented often and is not interesting to version. Such a column can be\nexcluded from versioning by declaring it WITHOUT VERSIONING\n\nCREATE TABLE t (\n x INT,\n y INT WITHOUT SYSTEM VERSIONING\n) WITH SYSTEM VERSIONING;\n\nA column can also be declared WITH VERSIONING, that will automatically make\nthe table versioned. The statement below is equivalent to the one above:\n\nCREATE TABLE t (\n x INT WITH SYSTEM VERSIONING,\n y INT\n);\n\nChanges in other sections: https://mariadb.com/kb/en/create-table/\nhttps://mariadb.com/kb/en/alter-table/ https://mariadb.com/kb/en/join-syntax/\nhttps://mariadb.com/kb/en/partitioning-types-overview/\nhttps://mariadb.com/kb/en/date-and-time-units/\nhttps://mariadb.com/kb/en/delete/ https://mariadb.com/kb/en/grant/\n\nthey all reference back to this page\n\nAlso, TODO:\n\n* limitations (size, speed, adding history to unique not nullable columns)\n\nSystem Variables\n----------------\n\nThere are a number of system variables related to system-versioned tables:\n\nsystem_versioning_alter_history\n-------------------------------\n\n* Description: SQL:2011 does not allow ALTER TABLE on system-versioned tables.\nWhen this variable is set to ERROR, an attempt to alter a system-versioned\ntable will result in an error. When this variable is set to KEEP, ALTER TABLE\nwill be allowed, but the history will become incorrect — querying historical\ndata will show the new table structure. This mode is still useful, for\nexample, when adding new columns to a table. Note that if historical data\ncontains or would contain nulls, attempting to ALTER these columns to be NOT\nNULL will return an error (or warning if strict_mode is not set).\n* Commandline: --system-versioning-alter-history=value\n* Scope: Global, Session\n* Dynamic: Yes\n* Type: Enum\n* Default Value: ERROR\n* Valid Values: ERROR, KEEP\n\nsystem_versioning_asof\n----------------------\n\n* Description: If set to a specific timestamp value, an implicit FOR\nSYSTEM_TIME AS OF clause will be applied to all queries. This is useful if one\nwants to do many queries for history at the specific point in time. Set it to\nDEFAULT to restore the default behavior. Has no effect on DML, so queries such\nas INSERT .. SELECT and REPLACE .. SELECT need to state AS OF explicitly.\n* Commandline: None\n* Scope: Global, Session\n* Dynamic: Yes\n* Type: Varchar\n* Default Value: DEFAULT\n\nsystem_versioning_innodb_algorithm_simple\n-----------------------------------------\n\n* Description: Never fully implemented and removed in the following release.\n* Commandline: --system-versioning-innodb-algorithm-simple[={0|1}]\n* Scope: Global, Session\n* Dynamic: Yes\n* Type: Boolean\n* Default Value: ON\n* Introduced: MariaDB 10.3.4\n* Removed: MariaDB 10.3.5\n\nsystem_versioning_insert_history\n--------------------------------\n\n* Description: Allows direct inserts into ROW_START and ROW_END columns if\nsecure_timestamp allows changing timestamp.\n* Commandline: --system-versioning-insert-history[={0|1}]\n* Scope: Global, Session\n* Dynamic: Yes\n* Type: Boolean\n* Default Value: OFF\n* Introduced: MariaDB 10.11.0\n\nLimitations\n-----------\n\n* Versioning clauses can not be applied to generated (virtual and persistent)\ncolumns.\n* Before MariaDB 10.11, mariadb-dump did not read historical rows from\nversioned tables, and so historical data would not be backed up. Also, a\nrestore of the timestamps would not be possible as they cannot be defined by\nan insert/a user. From MariaDB 10.11, use the -H or --dump-history options to\ninclude the history.\n\nURL: https://mariadb.com/kb/en/system-versioned-tables/') WHERE help_topic_id = 814; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (815,45,'Application-Time Periods','MariaDB starting with 10.4.3\n----------------------------\nSupport for application-time period-versioning was added in MariaDB 10.4.3.\n\nExtending system-versioned tables, MariaDB 10.4 supports application-time\nperiod tables. Time periods are defined by a range between two temporal\ncolumns. The columns must be of the same temporal data type, i.e. DATE,\nTIMESTAMP or DATETIME (TIME and YEAR are not supported), and of the same width.\n\nUsing time periods implicitly defines the two columns as NOT NULL. It also\nadds a constraint to check whether the first value is less than the second\nvalue. The constraint is invisible to SHOW CREATE TABLE statements. The name\nof this constraint is prefixed by the time period name, to avoid conflict with\nother constraints.\n\nCreating Tables with Time Periods\n---------------------------------\n\nTo create a table with a time period, use a CREATE TABLE statement with the\nPERIOD table option.\n\nCREATE TABLE t1(\n name VARCHAR(50),\n date_1 DATE,\n date_2 DATE,\n PERIOD FOR date_period(date_1, date_2));\n\nThis creates a table with a time_period period and populates the table with\nsome basic temporal values.\n\nExamples are available in the MariaDB Server source code, at\nmysql-test/suite/period/r/create.result.\n\nAdding and Removing Time Periods\n--------------------------------\n\nThe ALTER TABLE statement now supports syntax for adding and removing time\nperiods from a table. To add a period, use the ADD PERIOD clause.\n\nFor example:\n\nCREATE OR REPLACE TABLE rooms (\n room_number INT,\n guest_name VARCHAR(255),\n checkin DATE,\n checkout DATE\n );\n\nALTER TABLE rooms ADD PERIOD FOR p(checkin,checkout);\n\nTo remove a period, use the DROP PERIOD clause:\n\nALTER TABLE rooms DROP PERIOD FOR p;\n\nBoth ADD PERIOD and DROP PERIOD clauses include an option to handle whether\nthe period already exists:\n\nALTER TABLE rooms ADD PERIOD IF NOT EXISTS FOR p(checkin,checkout);\n\nALTER TABLE rooms DROP PERIOD IF EXISTS FOR p;\n\nDeletion by Portion\n-------------------\n\nYou can also remove rows that fall within certain time periods.\n\nWhen MariaDB executes a DELETE FOR PORTION statement, it removes the row:\n\n* When the row period falls completely within the delete period, it removes\nthe row.\n* When the row period overlaps the delete period, it shrinks the row, removing\nthe overlap from the first or second row period value.\n* When the delete period falls completely within the row period, it splits the\nrow into two rows. The first row runs from the starting row period to the\nstarting delete period. The second runs from the ending delete period to the\nending row period.\n\nTo test this, first populate the table with some data to operate on:\n\nCREATE TABLE t1(\n name VARCHAR(50),\n date_1 DATE,\n date_2 DATE,\n PERIOD FOR date_period(date_1, date_2));\n\nINSERT INTO t1 (name, date_1, date_2) VALUES\n (\'a\', \'1999-01-01\', \'2000-01-01\'),\n (\'b\', \'1999-01-01\', \'2018-12-12\'),\n (\'c\', \'1999-01-01\', \'2017-01-01\'),\n (\'d\', \'2017-01-01\', \'2019-01-01\');\n\nSELECT * FROM t1;\n+------+------------+------------+\n| name | date_1 | date_2 |\n+------+------------+------------+\n| a | 1999-01-01 | 2000-01-01 |\n| b | 1999-01-01 | 2018-12-12 |\n| c | 1999-01-01 | 2017-01-01 |\n| d | 2017-01-01 | 2019-01-01 |\n+------+------------+------------+\n\nThen, run the DELETE FOR PORTION statement:\n\nDELETE FROM t1\nFOR PORTION OF date_period\n FROM \'2001-01-01\' TO \'2018-01-01\';\nQuery OK, 3 rows affected (0.028 sec)\n\nSELECT * FROM t1 ORDER BY name;\n+------+------------+------------+\n| name | date_1 | date_2 |\n+------+------------+------------+\n| a | 1999-01-01 | 2000-01-01 |\n| b | 1999-01-01 | 2001-01-01 |\n| b | 2018-01-01 | 2018-12-12 |\n| c | 1999-01-01 | 2001-01-01 |\n| d | 2018-01-01 | 2019-01-01 |\n+------+------------+------------+\n\nHere:\n\n* a is unchanged, as the range falls entirely out of the specified portion to\nbe deleted.\n* b, with values ranging from 1999 to 2018, is split into two rows, 1999 to\n2000 and 2018-01 to 2018-12.\n* c, with values ranging from 1999 to 2017, where only the upper value falls\nwithin the portion to be deleted, has been shrunk to 1999 to 2001.\n* d, with values ranging from 2017 to 2019, where only the lower value falls\nwithin the portion to be deleted, has been shrunk to 2018 to 2019.\n\nThe DELETE FOR PORTION statement has the following restrictions\n\n* The FROM...TO clause must be constant\n* Multi-delete is not supported\n\nIf there are DELETE or INSERT triggers, it works as follows: any matched row\nis deleted, and then one or two rows are inserted. If the record is deleted\ncompletely, nothing is inserted.\n\nUpdating by Portion\n-------------------\n\nThe UPDATE syntax now supports UPDATE FOR PORTION, which modifies rows based\non their occurrence in a range:\n\nTo test it, first populate the table with some data:\n\nTRUNCATE t1;\n\nINSERT INTO t1 (name, date_1, date_2) VALUES\n (\'a\', \'1999-01-01\', \'2000-01-01\'),\n (\'b\', \'1999-01-01\', \'2018-12-12\'),\n (\'c\', \'1999-01-01\', \'2017-01-01\'),\n (\'d\', \'2017-01-01\', \'2019-01-01\');\n\nSELECT * FROM t1;\n+------+------------+------------+\n| name | date_1 | date_2 |\n+------+------------+------------+\n| a | 1999-01-01 | 2000-01-01 |\n| b | 1999-01-01 | 2018-12-12 |\n| c | 1999-01-01 | 2017-01-01 |\n| d | 2017-01-01 | 2019-01-01 |\n+------+------------+------------+\n\nThen run the update:\n\nUPDATE t1 FOR PORTION OF date_period\n FROM \'2000-01-01\' TO \'2018-01-01\'\nSET name = CONCAT(name,\'_original\');\n\nSELECT * FROM t1 ORDER BY name;\n+------------+------------+------------+\n| name | date_1 | date_2 |\n+------------+------------+------------+\n| a | 1999-01-01 | 2000-01-01 |\n| b | 1999-01-01 | 2000-01-01 |\n| b | 2018-01-01 | 2018-12-12 |\n| b_original | 2000-01-01 | 2018-01-01 |\n| c | 1999-01-01 | 2000-01-01 |\n| c_original | 2000-01-01 | 2017-01-01 |\n| d | 2018-01-01 | 2019-01-01 |\n| d_original | 2017-01-01 | 2018-01-01 |\n+------------+------------+------------+\n\n* a is unchanged, as the range falls entirely out of the specified portion to\nbe deleted.\n* b, with values ranging from 1999 to 2018, is split into two rows, 1999 to\n2000 and 2018-01 to 2018-12.\n* c, with values ranging from 1999 to 2017, where only the upper value falls\nwithin the portion to be deleted, has been shrunk to 1999 to 2001.\n* d, with values ranging from 2017 to 2019, where only the lower value falls\nwithin the portion to be deleted, has been shrunk to 2018 to 2019. \n* Original rows affected by the update have \"_original\" appended to the name.\n\nThe UPDATE FOR PORTION statement has the following limitations:\n\n* The operation cannot modify the two temporal columns used by the time period\n* The operation cannot reference period values in the SET expression\n* FROM...TO expressions must be constant\n\nWITHOUT OVERLAPS\n----------------\n\nMariaDB starting with 10.5.3\n----------------------------\nMariaDB 10.5 introduced a new clause, WITHOUT OVERLAPS, which allows one to\ncreate an index specifying that application time periods should not overlap.\n\nAn index constrained by WITHOUT OVERLAPS is required to be either a primary\nkey or a unique index.\n\nTake the following example, an application time period table for a booking\nsystem:\n\nCREATE OR REPLACE TABLE rooms (\n room_number INT,\n guest_name VARCHAR(255),\n checkin DATE,\n checkout DATE,\n PERIOD FOR p(checkin,checkout)\n );\n\nINSERT INTO rooms VALUES \n (1, \'Regina\', \'2020-10-01\', \'2020-10-03\'),\n (2, \'Cochise\', \'2020-10-02\', \'2020-10-05\'),\n (1, \'Nowell\', \'2020-10-03\', \'2020-10-07\'),\n (2, \'Eusebius\', \'2020-10-04\', \'2020-10-06\');\n\nOur system is not intended to permit overlapping bookings, so the fourth\nrecord above should not have been inserted. Using WITHOUT OVERLAPS in a unique\nindex (in this case based on a combination of room number and the application\ntime period) allows us to specify this constraint in the table definition.\n\nCREATE OR REPLACE TABLE rooms (\n room_number INT,\n guest_name VARCHAR(255),\n checkin DATE,\n checkout DATE,\n PERIOD FOR p(checkin,checkout),\n UNIQUE (room_number, p WITHOUT OVERLAPS)\n );\n\nINSERT INTO rooms VALUES \n (1, \'Regina\', \'2020-10-01\', \'2020-10-03\'),\n (2, \'Cochise\', \'2020-10-02\', \'2020-10-05\'),\n (1, \'Nowell\', \'2020-10-03\', \'2020-10-07\'),\n (2, \'Eusebius\', \'2020-10-04\', \'2020-10-06\');\nERROR 1062 (23000): Duplicate entry \'2-2020-10-06-2020-10-04\' for key\n\'room_number\'\n\nFurther Examples\n----------------\n\nThe implicit change from NULL to NOT NULL:\n\nCREATE TABLE `t2` (\n `id` int(11) DEFAULT NULL,\n `d1` datetime DEFAULT NULL,\n `d2` datetime DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n\nALTER TABLE t2 ADD PERIOD FOR p(d1,d2);\n\nSHOW CREATE TABLE t2\\G\n*************************** 1. row ***************************\n Table: t2\nCreate Table: CREATE TABLE `t2` (\n `id` int(11) DEFAULT NULL,\n `d1` datetime NOT NULL,\n `d2` datetime NOT NULL,\n PERIOD FOR `p` (`d1`, `d2`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1\n\nDue to this constraint, trying to add a time period where null data already\nexists will fail.\n\nCREATE OR REPLACE TABLE `t2` (\n `id` int(11) DEFAULT NULL,\n `d1` datetime DEFAULT NULL,\n `d2` datetime DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n\nINSERT INTO t2(id) VALUES(1);\n\nALTER TABLE t2 ADD PERIOD FOR p(d1,d2);\nERROR 1265 (01000): Data truncated for column \'d1\' at row 1\n\nURL: https://mariadb.com/kb/en/application-time-periods/','','https://mariadb.com/kb/en/application-time-periods/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (816,45,'Bitemporal Tables','MariaDB starting with 10.4.3\n----------------------------\nBitemporal tables are tables that use versioning both at the system and\napplication-time period levels.\n\nUsing Bitemporal Tables\n-----------------------\n\nTo create a bitemporal table, use:\n\nCREATE TABLE test.t3 (\n date_1 DATE,\n date_2 DATE,\n row_start TIMESTAMP(6) AS ROW START INVISIBLE,\n row_end TIMESTAMP(6) AS ROW END INVISIBLE,\n PERIOD FOR application_time(date_1, date_2),\n PERIOD FOR system_time(row_start, row_end))\nWITH SYSTEM VERSIONING;\n\nNote that, while system_time here is also a time period, it cannot be used in\nDELETE FOR PORTION or UPDATE FOR PORTION statements.\n\nDELETE FROM test.t3 \nFOR PORTION OF system_time \n FROM \'2000-01-01\' TO \'2018-01-01\';\nERROR 42000: You have an error in your SQL syntax; check the manual that\ncorresponds \n to your MariaDB server version for the right syntax to use near\n \'of system_time from \'2000-01-01\' to \'2018-01-01\'\' at line 1\n\nURL: https://mariadb.com/kb/en/bitemporal-tables/','','https://mariadb.com/kb/en/bitemporal-tables/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (817,46,'ST_AsGeoJSON','Syntax\n------\n\nST_AsGeoJSON(g[, max_decimals[, options]])\n\nDescription\n-----------\n\nReturns the given geometry g as a GeoJSON element. The optional max_decimals\nlimits the maximum number of decimals displayed.\n\nThe optional options flag can be set to 1 to add a bounding box to the output.\n\nExamples\n--------\n\nSELECT ST_AsGeoJSON(ST_GeomFromText(\'POINT(5.3 7.2)\'));\n+-------------------------------------------------+\n| ST_AsGeoJSON(ST_GeomFromText(\'POINT(5.3 7.2)\')) |\n+-------------------------------------------------+\n| {\"type\": \"Point\", \"coordinates\": [5.3, 7.2]} |\n+-------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/geojson-st_asgeojson/','','https://mariadb.com/kb/en/geojson-st_asgeojson/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (818,46,'ST_GeomFromGeoJSON','MariaDB starting with 10.2.4\n----------------------------\nST_GeomFromGeoJSON was added in MariaDB 10.2.4\n\nSyntax\n------\n\nST_GeomFromGeoJSON(g[, option])\n\nDescription\n-----------\n\nGiven a GeoJSON input g, returns a geometry object. The option specifies what\nto do if g contains geometries with coordinate dimensions higher than 2.\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| 1 | Return an error (the default) |\n+---------------------------+------------------------------------------------+\n| 2 - 4 | The document is accepted, but the coordinates |\n| | for higher coordinate dimensions are stripped |\n| | off. |\n+---------------------------+------------------------------------------------+\n\nNote that this function did not work correctly before MariaDB 10.2.8 - see\nMDEV-12180.\n\nExamples\n--------\n\nSET @j = \'{ \"type\": \"Point\", \"coordinates\": [5.3, 15.0]}\';\n\nSELECT ST_AsText(ST_GeomFromGeoJSON(@j));\n+-----------------------------------+\n| ST_AsText(ST_GeomFromGeoJSON(@j)) |\n+-----------------------------------+\n| POINT(5.3 15) |\n+-----------------------------------+\n\nURL: https://mariadb.com/kb/en/st_geomfromgeojson/','','https://mariadb.com/kb/en/st_geomfromgeojson/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (819,47,'Operator Precedence','The precedence is the order in which the SQL operators are evaluated.\n\nThe following list shows the SQL operator precedence. Operators that appear\nfirst in the list have a higher precedence. Operators which are listed\ntogether have the same precedence.\n\n* INTERVAL\n* BINARY, COLLATE\n* !\n* - (unary minus), [[bitwise-not|]] (unary bit inversion)\n* || (string concatenation)\n* ^\n* *, /, DIV, %, MOD\n* -, +\n* <<, >>\n* &\n* |\n* = (comparison), <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN\n* BETWEEN, CASE, WHEN, THEN, ELSE, END\n* NOT\n* &&, AND\n* XOR\n* || (logical or), OR\n* = (assignment), :=\n\nFunctions precedence is always higher than operators precedence.\n\nIn this page CASE refers to the CASE operator, not to the CASE statement.\n\nIf the HIGH_NOT_PRECEDENCE SQL_MODE is set, NOT has the same precedence as !.\n\nThe || operator\'s precedence, as well as its meaning, depends on the\nPIPES_AS_CONCAT SQL_MODE flag: if it is on, || can be used to concatenate\nstrings (like the CONCAT() function) and has a higher precedence.\n\nThe = operator\'s precedence depends on the context - it is higher when = is\nused as a comparison operator.\n\nParenthesis can be used to modify the operators precedence in an expression.\n\nShort-circuit evaluation\n------------------------\n\nThe AND, OR, && and || operators support short-circuit evaluation. This means\nthat, in some cases, the expression on the right of those operators is not\nevaluated, because its result cannot affect the result. In the following\ncases, short-circuit evaluation is used and x() is not evaluated:\n\n* FALSE AND x()\n* FALSE && x()\n* TRUE OR x()\n* TRUE || x()\n* NULL BETWEEN x() AND x()\n\nNote however that the short-circuit evaluation does not apply to NULL AND x().\nAlso, BETWEEN\'s right operands are not evaluated if the left operand is NULL,\nbut in all other cases all the operands are evaluated.\n\nThis is a speed optimization. Also, since functions can have side-effects,\nthis behavior can be used to choose whether execute them or not using a\nconcise syntax:\n\nSELECT some_function() OR log_error();\n\nURL: https://mariadb.com/kb/en/operator-precedence/','','https://mariadb.com/kb/en/operator-precedence/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (820,48,'Addition Operator (+)','Syntax\n------\n\n+\n\nDescription\n-----------\n\nAddition.\n\nIf both operands are integers, the result is calculated with BIGINT precision.\nIf either integer is unsigned, the result is also an unsigned integer.\n\nFor real or string operands, the operand with the highest precision determines\nthe result precision.\n\nExamples\n--------\n\nSELECT 3+5;\n+-----+\n| 3+5 |\n+-----+\n| 8 |\n+-----+\n\nURL: https://mariadb.com/kb/en/addition-operator/','','https://mariadb.com/kb/en/addition-operator/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (821,48,'Division Operator (/)','Syntax\n------\n\n/\n\nDescription\n-----------\n\nDivision operator. Dividing by zero will return NULL. By default, returns four\ndigits after the decimal. This is determined by the server system variable\ndiv_precision_increment which by default is four. It can be set from 0 to 30.\n\nDividing by zero returns NULL. If the ERROR_ON_DIVISION_BY_ZERO SQL_MODE is\nused (the default since MariaDB 10.2.4), a division by zero also produces a\nwarning.\n\nExamples\n--------\n\nSELECT 4/5;\n+--------+\n| 4/5 |\n+--------+\n| 0.8000 |\n+--------+\n\nSELECT 300/(2-2);\n+-----------+\n| 300/(2-2) |\n+-----------+\n| NULL |\n+-----------+\n\nSELECT 300/7;\n+---------+\n| 300/7 |\n+---------+\n| 42.8571 |\n+---------+\n\nChanging div_precision_increment for the session from the default of four to\nsix:\n\nSET div_precision_increment = 6;\n\nSELECT 300/7;\n+-----------+\n| 300/7 |\n+-----------+\n| 42.857143 |\n+-----------+\n\nSELECT 300/7;\n+-----------+\n| 300/7 |\n+-----------+\n| 42.857143 |\n+-----------+\n\nURL: https://mariadb.com/kb/en/division-operator/','','https://mariadb.com/kb/en/division-operator/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (822,48,'Modulo Operator (%)','Syntax\n------\n\nN % M\n\nDescription\n-----------\n\nModulo operator. Returns the remainder of N divided by M. See also MOD.\n\nExamples\n--------\n\nSELECT 1042 % 50;\n+-----------+\n| 1042 % 50 |\n+-----------+\n| 42 |\n+-----------+\n\nURL: https://mariadb.com/kb/en/modulo-operator/','','https://mariadb.com/kb/en/modulo-operator/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (823,48,'Multiplication Operator (*)','Syntax\n------\n\n*\n\nDescription\n-----------\n\nMultiplication operator.\n\nExamples\n--------\n\nSELECT 7*6;\n+-----+\n| 7*6 |\n+-----+\n| 42 |\n+-----+\n\nSELECT 1234567890*9876543210;\n+-----------------------+\n| 1234567890*9876543210 |\n+-----------------------+\n| -6253480962446024716 |\n+-----------------------+\n\nSELECT 18014398509481984*18014398509481984.0;\n+---------------------------------------+\n| 18014398509481984*18014398509481984.0 |\n+---------------------------------------+\n| 324518553658426726783156020576256.0 |\n+---------------------------------------+\n\nSELECT 18014398509481984*18014398509481984;\n+-------------------------------------+\n| 18014398509481984*18014398509481984 |\n+-------------------------------------+\n| 0 |\n+-------------------------------------+\n\nURL: https://mariadb.com/kb/en/multiplication-operator/','','https://mariadb.com/kb/en/multiplication-operator/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (824,48,'Subtraction Operator (-)','Syntax\n------\n\n-\n\nDescription\n-----------\n\nSubtraction. The operator is also used as the unary minus for changing sign.\n\nIf both operands are integers, the result is calculated with BIGINT precision.\nIf either integer is unsigned, the result is also an unsigned integer, unless\nthe NO_UNSIGNED_SUBTRACTION SQL_MODE is enabled, in which case the result is\nalways signed.\n\nFor real or string operands, the operand with the highest precision determines\nthe result precision.\n\nExamples\n--------\n\nSELECT 96-9;\n+------+\n| 96-9 |\n+------+\n| 87 |\n+------+\n\nSELECT 15-17;\n+-------+\n| 15-17 |\n+-------+\n| -2 |\n+-------+\n\nSELECT 3.66 + 1.333;\n+--------------+\n| 3.66 + 1.333 |\n+--------------+\n| 4.993 |\n+--------------+\n\nUnary minus:\n\nSELECT - (3+5);\n+---------+\n| - (3+5) |\n+---------+\n| -8 |\n+---------+\n\nURL: https://mariadb.com/kb/en/subtraction-operator-/','','https://mariadb.com/kb/en/subtraction-operator-/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (825,49,'CHANGE MASTER TO','The terms master and slave have historically been used in replication, but the\nterms terms primary and replica are now preferred. The old terms are used\nstill used in parts of the documentation, and in MariaDB commands, although\nMariaDB 10.5 has begun the process of renaming. The documentation process is\nongoing. See MDEV-18777 to follow progress on this effort.\n\nSyntax\n------\n\nCHANGE MASTER [\'connection_name\'] TO master_def [, master_def] ... \n [FOR CHANNEL \'channel_name\']\n\nmaster_def:\n MASTER_BIND = \'interface_name\'\n | MASTER_HOST = \'host_name\'\n | MASTER_USER = \'user_name\'\n | MASTER_PASSWORD = \'password\'\n | MASTER_PORT = port_num\n | MASTER_CONNECT_RETRY = interval\n | MASTER_HEARTBEAT_PERIOD = interval\n | MASTER_LOG_FILE = \'master_log_name\'\n | MASTER_LOG_POS = master_log_pos\n | RELAY_LOG_FILE = \'relay_log_name\'\n | RELAY_LOG_POS = relay_log_pos\n | MASTER_DELAY = interval\n | MASTER_SSL = {0|1}\n | MASTER_SSL_CA = \'ca_file_name\'\n | MASTER_SSL_CAPATH = \'ca_directory_name\'\n | MASTER_SSL_CERT = \'cert_file_name\'\n | MASTER_SSL_CRL = \'crl_file_name\'\n | MASTER_SSL_CRLPATH = \'crl_directory_name\'\n | MASTER_SSL_KEY = \'key_file_name\'\n | MASTER_SSL_CIPHER = \'cipher_list\'\n | MASTER_SSL_VERIFY_SERVER_CERT = {0|1}\n | MASTER_USE_GTID = {current_pos|slave_pos|no}\n | MASTER_DEMOTE_TO_SLAVE = bool\n | IGNORE_SERVER_IDS = (server_id_list)\n | DO_DOMAIN_IDS = ([N,..])\n | IGNORE_DOMAIN_IDS = ([N,..])\n\nDescription\n-----------\n\nThe CHANGE MASTER statement sets the options that a replica uses to connect to\nand replicate from a primary.\n\nMariaDB starting with 10.7.0\n----------------------------\nThe FOR CHANNEL keyword was added for MySQL compatibility. This is identical\nto using the channel_name directly after CHANGE MASTER.\n\nMulti-Source Replication\n------------------------\n\nIf you are using multi-source replication, then you need to specify a\nconnection name when you execute CHANGE MASTER. There are two ways to do this:\n\n* Setting the default_master_connection system variable prior to executing\nCHANGE MASTER.\n* Setting the connection_name parameter when executing CHANGE MASTER.\n\ndefault_master_connection\n-------------------------\n\nSET default_master_connection = \'gandalf\';\nSTOP SLAVE;\nCHANGE MASTER TO \n MASTER_PASSWORD=\'new3cret\';\nSTART SLAVE;\n\nconnection_name\n---------------\n\nSTOP SLAVE \'gandalf\';\nCHANGE MASTER \'gandalf\' TO \n MASTER_PASSWORD=\'new3cret\';\nSTART SLAVE \'gandalf\';\n\nOptions\n-------\n\nConnection Options\n------------------\n\nMASTER_USER\n-----------\n\nThe MASTER_USER option for CHANGE MASTER defines the user account that the\nreplica will use to connect to the primary.\n\nThis user account will need the REPLICATION SLAVE privilege (or, from MariaDB\n10.5.1, the REPLICATION REPLICA on the primary.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_USER=\'repl\',\n MASTER_PASSWORD=\'new3cret\';\nSTART SLAVE;\n\nThe maximum length of the MASTER_USER string is 96 characters until MariaDB\n10.5, and 128 characters from MariaDB 10.6.\n\nMASTER_PASSWORD\n---------------\n\nThe MASTER_PASSWORD option for CHANGE MASTER defines the password that the\nreplica will use to connect to the primary as the user account defined by the\nMASTER_USER option.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO \n MASTER_PASSWORD=\'new3cret\';\nSTART SLAVE;\n\nThe maximum length of the MASTER_PASSWORD string is 32 characters. The\neffective maximum length of the string depends on how many bytes are used per\ncharacter and can be up to 96 characters.\n\nDue to MDEV-29994, the password can be silently truncated to 41 characters\nwhen MariaDB is restarted. For this reason it is recommended to use a password\nthat is shorter than this.\n\nMASTER_HOST\n-----------\n\nThe MASTER_HOST option for CHANGE MASTER defines the hostname or IP address of\nthe primary.\n\nIf you set the value of the MASTER_HOST option to the empty string, then that\nis not the same as not setting the option\'s value at all. If you set the value\nof the MASTER_HOST option to the empty string, then the CHANGE MASTER command\nwill fail with an error. In MariaDB 5.3 and before, if you set the value of\nthe MASTER_HOST option to the empty string, then the CHANGE MASTER command\nwould succeed, but the subsequent START SLAVE command would fail.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_HOST=\'dbserver1.example.com\',\n MASTER_USER=\'repl\',\n MASTER_PASSWORD=\'new3cret\',\n MASTER_USE_GTID=slave_pos;\nSTART SLAVE;\n\nIf you set the value of the MASTER_HOST option in a CHANGE MASTER command,\nthen the replica assumes that the primary is different from before, even if\nyou set the value of this option to the same value it had previously. In this\nscenario, the replica will consider the old values for the primary\'s binary\nlog file name and position to be invalid for the new primary. As a side\neffect, if you do not explicitly set the values of the MASTER_LOG_FILE and\nMASTER_LOG_POS options in the statement, then the statement will be implicitly\nappended with MASTER_LOG_FILE=\'\' and MASTER_LOG_POS=4. However, if you enable\nGTID mode for replication by setting the MASTER_USE_GTID option to some value\nother than no in the statement, then these values will effectively be ignored\nanyway.\n\nReplicas cannot connect to primaries using Unix socket files or Windows named\npipes. The replica must connect to the primary using TCP/IP.\n\nThe maximum length of the MASTER_HOST string is 60 characters until MariaDB\n10.5, and 255 characters from MariaDB 10.6.\n\nMASTER_PORT\n-----------\n\nThe MASTER_PORT option for CHANGE MASTER defines the TCP/IP port of the\nprimary.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_HOST=\'dbserver1.example.com\',\n MASTER_PORT=3307,\n MASTER_USER=\'repl\',\n MASTER_PASSWORD=\'new3cret\',\n MASTER_USE_GTID=slave_pos;\nSTART SLAVE;\n\nIf you set the value of the MASTER_PORT option in a CHANGE MASTER command,\nthen the replica assumes that the primary is different from before, even if\nyou set the value of this option to the same value it had previously. In this\nscenario, the replica will consider the old values for the primary\'s binary\nlog file name and position to be invalid for the new primary. As a side\neffect, if you do not explicitly set the values of the MASTER_LOG_FILE and\nMASTER_LOG_POS options in the statement, then the statement will be implicitly\nappended with MASTER_LOG_FILE=\'\' and MASTER_LOG_POS=4. However, if you enable\nGTID mode for replication by setting the MASTER_USE_GTID option to some value\nother than no in the statement, then these values will effectively be ignored\nanyway.\n\nReplicas cannot connect to primaries using Unix socket files or Windows named\npipes. The replica must connect to the primary using TCP/IP.\n\nMASTER_CONNECT_RETRY\n--------------------\n\nThe MASTER_CONNECT_RETRY option for CHANGE MASTER defines how many seconds\nthat the replica will wait between connection retries. The default is 60.\n\nSTOP SLAVE;\nCHANGE MASTER TO \n MASTER_CONNECT_RETRY=20;\nSTART SLAVE;\n\nThe number of connection attempts is limited by the master_retry_count option.\nIt can be set either on the command-line or in a server option group in an\noption file prior to starting up the server. For example:\n\n[mariadb]\n...\nmaster_retry_count=4294967295\n\nMASTER_BIND\n-----------\n\nThe MASTER_BIND option for CHANGE MASTER is only supported by MySQL 5.6.2 and\nlater and by MySQL NDB Cluster 7.3.1 and later. This option is not supported\nby MariaDB. See MDEV-19248 for more information.\n\nThe MASTER_BIND option for CHANGE MASTER can be used on replicas that have\nmultiple network interfaces to choose which network interface the replica will\nuse to connect to the primary.\n\nMASTER_HEARTBEAT_PERIOD\n-----------------------\n\nThe MASTER_HEARTBEAT_PERIOD option for CHANGE MASTER can be used to set the\ninterval in seconds between replication heartbeats. Whenever the primary\'s\nbinary log is updated with an event, the waiting period for the next heartbeat\nis reset.\n\nThis option\'s interval argument has the following characteristics:\n\n* It is a decimal value with a range of 0 to 4294967 seconds.\n* It has a resolution of hundredths of a second.\n* Its smallest valid non-zero value is 0.001.\n* Its default value is the value of the slave_net_timeout system variable\ndivided by 2.\n* If it\'s set to 0, then heartbeats are disabled.\n\nHeartbeats are sent by the primary only if there are no unsent events in the\nbinary log file for a period longer than the interval.\n\nIf the RESET SLAVE statement is executed, then the heartbeat interval is reset\nto the default.\n\nIf the slave_net_timeout system variable is set to a value that is lower than\nthe current heartbeat interval, then a warning will be issued.\n\nTLS Options\n-----------\n\nThe TLS options are used for providing information about TLS. The options can\nbe set even on replicas that are compiled without TLS support. The TLS options\nare saved to either the default master.info file or the file that is\nconfigured by the master_info_file option, but these TLS options are ignored\nunless the replica supports TLS.\n\nSee Replication with Secure Connections for more information.\n\nMASTER_SSL\n----------\n\nThe MASTER_SSL option for CHANGE MASTER tells the replica whether to force TLS\nfor the connection. The valid values are 0 or 1. Required to be set to 1 for\nthe other MASTER_SSL* options to have any effect.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_SSL=1;\nSTART SLAVE;\n\nMASTER_SSL_CA\n-------------\n\nThe MASTER_SSL_CA option for CHANGE MASTER defines a path to a PEM file that\nshould contain one or more X509 certificates for trusted Certificate\nAuthorities (CAs) to use for TLS. This option requires that you use the\nabsolute path, not a relative path.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_SSL_CERT=\'/etc/my.cnf.d/certificates/server-cert.pem\',\n MASTER_SSL_KEY=\'/etc/my.cnf.d/certificates/server-key.pem\',\n MASTER_SSL_CA=\'/etc/my.cnf.d/certificates/ca.pem\',\n MASTER_SSL_VERIFY_SERVER_CERT=1;\nSTART SLAVE;\n\nSee Secure Connections Overview: Certificate Authorities (CAs) for more\ninformation.\n\nThe maximum length of MASTER_SSL_CA string is 511 characters.\n\nMASTER_SSL_CAPATH\n-----------------\n\nThe MASTER_SSL_CAPATH option for CHANGE MASTER defines a path to a directory\nthat contains one or more PEM files that should each contain one X509\ncertificate for a trusted Certificate Authority (CA) to use for TLS. This\noption requires that you use the absolute path, not a relative path. The\ndirectory specified by this option needs to be run through the openssl rehash\ncommand.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_SSL_CERT=\'/etc/my.cnf.d/certificates/server-cert.pem\',\n MASTER_SSL_KEY=\'/etc/my.cnf.d/certificates/server-key.pem\',\n MASTER_SSL_CAPATH=\'/etc/my.cnf.d/certificates/ca/\',\n MASTER_SSL_VERIFY_SERVER_CERT=1;\nSTART SLAVE;\n\nSee Secure Connections Overview: Certificate Authorities (CAs) for more\ninformation.\n\nThe maximum length of MASTER_SSL_CA_PATH string is 511 characters.\n\nMASTER_SSL_CERT\n---------------\n\nThe MASTER_SSL_CERT option for CHANGE MASTER defines a path to the X509\ncertificate file to use for TLS. This option requires that you use the\nabsolute path, not a relative path.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_SSL_CERT=\'/etc/my.cnf.d/certificates/server-cert.pem\',\n MASTER_SSL_KEY=\'/etc/my.cnf.d/certificates/server-key.pem\',\n MASTER_SSL_CA=\'/etc/my.cnf.d/certificates/ca.pem\',\n MASTER_SSL_VERIFY_SERVER_CERT=1;\nSTART SLAVE;\n\nThe maximum length of MASTER_SSL_CERT string is 511 characters.\n\nMASTER_SSL_CRL\n--------------\n\nThe MASTER_SSL_CRL option for CHANGE MASTER defines a path to a PEM file that\nshould contain one or more revoked X509 certificates to use for TLS. This\noption requires that you use the absolute path, not a relative path.\n\nThis option is only supported if the server was built with OpenSSL. If the\nserver was built with yaSSL, then this option is not supported. See TLS and\nCryptography Libraries Used by MariaDB for more information about which\nlibraries are used on which platforms.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_SSL_CERT=\'/etc/my.cnf.d/certificates/server-cert.pem\',\n MASTER_SSL_KEY=\'/etc/my.cnf.d/certificates/server-key.pem\',\n MASTER_SSL_CA=\'/etc/my.cnf.d/certificates/ca.pem\',\n MASTER_SSL_VERIFY_SERVER_CERT=1,\n MASTER_SSL_CRL=\'/etc/my.cnf.d/certificates/crl.pem\';\nSTART SLAVE;\n\nSee Secure Connections Overview: Certificate Revocation Lists (CRLs) for more\ninformation.\n\nThe maximum length of MASTER_SSL_CRL string is 511 characters.\n\nMASTER_SSL_CRLPATH\n------------------\n\nThe MASTER_SSL_CRLPATH option for CHANGE MASTER defines a path to a directory\nthat contains one or more PEM files that should each contain one revoked X509\ncertificate to use for TLS. This option requires that you use the absolute\npath, not a relative path. The directory specified by this variable needs to\nbe run through the openssl rehash command.\n\nThis option is only supported if the server was built with OpenSSL. If the\nserver was built with yaSSL, then this option is not supported. See TLS and\nCryptography Libraries Used by MariaDB for more information about which\nlibraries are used on which platforms.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_SSL_CERT=\'/etc/my.cnf.d/certificates/server-cert.pem\',\n MASTER_SSL_KEY=\'/etc/my.cnf.d/certificates/server-key.pem\',\n MASTER_SSL_CA=\'/etc/my.cnf.d/certificates/ca.pem\',\n MASTER_SSL_VERIFY_SERVER_CERT=1,\n MASTER_SSL_CRLPATH=\'/etc/my.cnf.d/certificates/crl/\';\nSTART SLAVE;\n\nSee Secure Connections Overview: Certificate Revocation Lists (CRLs) for more\ninformation.\n\nThe maximum length of MASTER_SSL_CRL_PATH string is 511 characters.\n\nMASTER_SSL_KEY\n--------------\n\nThe MASTER_SSL_KEY option for CHANGE MASTER defines a path to a private key\nfile to use for TLS. This option requires that you use the absolute path, not\na relative path.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_SSL_CERT=\'/etc/my.cnf.d/certificates/server-cert.pem\',\n MASTER_SSL_KEY=\'/etc/my.cnf.d/certificates/server-key.pem\',\n MASTER_SSL_CA=\'/etc/my.cnf.d/certificates/ca.pem\',\n MASTER_SSL_VERIFY_SERVER_CERT=1;\nSTART SLAVE;\n\nThe maximum length of MASTER_SSL_KEY string is 511 characters.\n','','https://mariadb.com/kb/en/change-master-to/'); +update help_topic set description = CONCAT(description, '\nMASTER_SSL_CIPHER\n-----------------\n\nThe MASTER_SSL_CIPHER option for CHANGE MASTER defines the list of permitted\nciphers or cipher suites to use for TLS. Besides cipher names, if MariaDB was\ncompiled with OpenSSL, this option could be set to \"SSLv3\" or \"TLSv1.2\" to\nallow all SSLv3 or all TLSv1.2 ciphers. Note that the TLSv1.3 ciphers cannot\nbe excluded when using OpenSSL, even by using this option. See Using TLSv1.3\nfor details.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_SSL_CERT=\'/etc/my.cnf.d/certificates/server-cert.pem\',\n MASTER_SSL_KEY=\'/etc/my.cnf.d/certificates/server-key.pem\',\n MASTER_SSL_CA=\'/etc/my.cnf.d/certificates/ca.pem\',\n MASTER_SSL_VERIFY_SERVER_CERT=1,\n MASTER_SSL_CIPHER=\'TLSv1.2\';\nSTART SLAVE;\n\nThe maximum length of MASTER_SSL_CIPHER string is 511 characters.\n\nMASTER_SSL_VERIFY_SERVER_CERT\n-----------------------------\n\nThe MASTER_SSL_VERIFY_SERVER_CERT option for CHANGE MASTER enables server\ncertificate verification. This option is disabled by default.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_SSL_CERT=\'/etc/my.cnf.d/certificates/server-cert.pem\',\n MASTER_SSL_KEY=\'/etc/my.cnf.d/certificates/server-key.pem\',\n MASTER_SSL_CA=\'/etc/my.cnf.d/certificates/ca.pem\',\n MASTER_SSL_VERIFY_SERVER_CERT=1;\nSTART SLAVE;\n\nSee Secure Connections Overview: Server Certificate Verification for more\ninformation.\n\nBinary Log Options\n------------------\n\nThese options are related to the binary log position on the primary.\n\nMASTER_LOG_FILE\n---------------\n\nThe MASTER_LOG_FILE option for CHANGE MASTER can be used along with\nMASTER_LOG_POS to specify the coordinates at which the replica\'s I/O thread\nshould begin reading from the primary\'s binary logs the next time the thread\nstarts.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_LOG_FILE=\'master2-bin.001\',\n MASTER_LOG_POS=4;\nSTART SLAVE;\n\nThe MASTER_LOG_FILE and MASTER_LOG_POS options cannot be specified if the\nRELAY_LOG_FILE and RELAY_LOG_POS options were also specified.\n\nThe MASTER_LOG_FILE and MASTER_LOG_POS options are effectively ignored if you\nenable GTID mode for replication by setting the MASTER_USE_GTID option to some\nvalue other than no in the statement.\n\nMASTER_LOG_POS\n--------------\n\nThe MASTER_LOG_POS option for CHANGE MASTER can be used along with\nMASTER_LOG_FILE to specify the coordinates at which the replica\'s I/O thread\nshould begin reading from the primary\'s binary logs the next time the thread\nstarts.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_LOG_FILE=\'master2-bin.001\',\n MASTER_LOG_POS=4;\nSTART SLAVE;\n\nThe MASTER_LOG_FILE and MASTER_LOG_POS options cannot be specified if the\nRELAY_LOG_FILE and RELAY_LOG_POS options were also specified.\n\nThe MASTER_LOG_FILE and MASTER_LOG_POS options are effectively ignored if you\nenable GTID mode for replication by setting the MASTER_USE_GTID option to some\nvalue other than no in the statement.\n\nRelay Log Options\n-----------------\n\nThese options are related to the relay log position on the replica.\n\nRELAY_LOG_FILE\n--------------\n\nThe RELAY_LOG_FILE option for CHANGE MASTER can be used along with the\nRELAY_LOG_POS option to specify the coordinates at which the replica\'s SQL\nthread should begin reading from the relay log the next time the thread starts.\n\nThe CHANGE MASTER statement usually deletes all relay log files. However, if\nthe RELAY_LOG_FILE and/or RELAY_LOG_POS options are specified, then existing\nrelay log files are kept.\n\nWhen you want to change the relay log position, you only need to stop the\nreplica\'s SQL thread. The replica\'s I/O thread can continue running. The STOP\nSLAVE and START SLAVE statements support the SQL_THREAD option for this\nscenario. For example:\n\nSTOP SLAVE SQL_THREAD;\nCHANGE MASTER TO\n RELAY_LOG_FILE=\'slave-relay-bin.006\',\n RELAY_LOG_POS=4025;\nSTART SLAVE SQL_THREAD;\n\nWhen the value of this option is changed, the metadata about the replica\'s SQL\nthread\'s position in the relay logs will also be changed in the relay-log.info\nfile or the file that is configured by the relay_log_info_file system variable.\n\nThe RELAY_LOG_FILE and RELAY_LOG_POS options cannot be specified if the\nMASTER_LOG_FILE and MASTER_LOG_POS options were also specified.\n\nRELAY_LOG_POS\n-------------\n\nThe RELAY_LOG_POS option for CHANGE MASTER can be used along with the\nRELAY_LOG_FILE option to specify the coordinates at which the replica\'s SQL\nthread should begin reading from the relay log the next time the thread starts.\n\nThe CHANGE MASTER statement usually deletes all relay log files. However, if\nthe RELAY_LOG_FILE and/or RELAY_LOG_POS options are specified, then existing\nrelay log files are kept.\n\nWhen you want to change the relay log position, you only need to stop the\nreplica\'s SQL thread. The replica\'s I/O thread can continue running. The STOP\nSLAVE and START SLAVE statements support the SQL_THREAD option for this\nscenario. For example:\n\nSTOP SLAVE SQL_THREAD;\nCHANGE MASTER TO\n RELAY_LOG_FILE=\'slave-relay-bin.006\',\n RELAY_LOG_POS=4025;\nSTART SLAVE SQL_THREAD;\n\nWhen the value of this option is changed, the metadata about the replica\'s SQL\nthread\'s position in the relay logs will also be changed in the relay-log.info\nfile or the file that is configured by the relay_log_info_file system variable.\n\nThe RELAY_LOG_FILE and RELAY_LOG_POS options cannot be specified if the\nMASTER_LOG_FILE and MASTER_LOG_POS options were also specified.\n\nGTID Options\n------------\n\nMASTER_USE_GTID\n---------------\n\nThe MASTER_USE_GTID option for CHANGE MASTER can be used to configure the\nreplica to use the global transaction ID (GTID) when connecting to a primary.\nThe possible values are:\n\n* current_pos - Replicate in GTID mode and use gtid_current_pos as the\nposition to start downloading transactions from the primary. Deprecated from\nMariaDB 10.10. Using to transition to primary can break the replication state\nif the replica executes local transactions due to actively updating\ngtid_current_pos with gtid_binlog_pos and gtid_slave_pos. Use the new, safe,\nMASTER_DEMOTE_TO_SLAVE=<bool> option instead.\n* slave_pos - Replicate in GTID mode and use gtid_slave_pos as the position to\nstart downloading transactions from the primary. From MariaDB 10.5.1,\nreplica_pos is an alias for slave_pos.\n* no - Don\'t replicate in GTID mode.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_USE_GTID = current_pos;\nSTART SLAVE;\n\nOr:\n\nSTOP SLAVE;\nSET GLOBAL gtid_slave_pos=\'0-1-153\';\nCHANGE MASTER TO\n MASTER_USE_GTID = slave_pos;\nSTART SLAVE;\n\nMASTER_DEMOTE_TO_SLAVE\n----------------------\n\nMariaDB starting with 10.10\n---------------------------\nUsed to transition a primary to become a replica. Replaces the old\nMASTER_USE_GTID=current_pos with a safe alternative by forcing users to set\nUsing_Gtid=Slave_Pos and merging gtid_binlog_pos into gtid_slave_pos once at\nCHANGE MASTER TO time. If gtid_slave_pos is more recent than gtid_binlog_pos\n(as in the case of chain replication), the replication state should be\npreserved.\n\nFor example:\n\nSTOP SLAVE;\nCHANGE MASTER TO\n MASTER_DEMOTE_TO_SLAVE = 1;\nSTART SLAVE;\n\nReplication Filter Options\n--------------------------\n\nAlso see Replication filters.\n\nIGNORE_SERVER_IDS\n-----------------\n\nThe IGNORE_SERVER_IDS option for CHANGE MASTER can be used to configure a\nreplica to ignore binary log events that originated from certain servers.\nFiltered binary log events will not get logged to the replica’s relay log, and\nthey will not be applied by the replica.\n\nThe option\'s value can be specified by providing a comma-separated list of\nserver_id values. For example:\n\nSTOP SLAVE;\nCHANGE MASTER TO \n IGNORE_SERVER_IDS = (3,5);\nSTART SLAVE;\n\nIf you would like to clear a previously set list, then you can set the value\nto an empty list. For example:\n\nSTOP SLAVE;\nCHANGE MASTER TO \n IGNORE_SERVER_IDS = ();\nSTART SLAVE;\n\nDO_DOMAIN_IDS\n-------------\n\nThe DO_DOMAIN_IDS option for CHANGE MASTER can be used to configure a replica\nto only apply binary log events if the transaction\'s GTID is in a specific\ngtid_domain_id value. Filtered binary log events will not get logged to the\nreplica’s relay log, and they will not be applied by the replica.\n\nThe option\'s value can be specified by providing a comma-separated list of\ngtid_domain_id values. Duplicate values are automatically ignored. For example:\n\nSTOP SLAVE;\nCHANGE MASTER TO \n DO_DOMAIN_IDS = (1,2);\nSTART SLAVE;\n\nIf you would like to clear a previously set list, then you can set the value\nto an empty list. For example:\n\nSTOP SLAVE;\nCHANGE MASTER TO \n DO_DOMAIN_IDS = ();\nSTART SLAVE;\n\nThe DO_DOMAIN_IDS option and the IGNORE_DOMAIN_IDS option cannot both be set\nto non-empty values at the same time. If you want to set the DO_DOMAIN_IDS\noption, and the IGNORE_DOMAIN_IDS option was previously set, then you need to\nclear the value of the IGNORE_DOMAIN_IDS option. For example:\n\nSTOP SLAVE;\nCHANGE MASTER TO \n IGNORE_DOMAIN_IDS = (),\n DO_DOMAIN_IDS = (1,2);\nSTART SLAVE;\n\nThe DO_DOMAIN_IDS option can only be specified if the replica is replicating\nin GTID mode. Therefore, the MASTER_USE_GTID option must also be set to some\nvalue other than no in order to use this option.\n\nIGNORE_DOMAIN_IDS\n-----------------\n\nThe IGNORE_DOMAIN_IDS option for CHANGE MASTER can be used to configure a\nreplica to ignore binary log events if the transaction\'s GTID is in a specific\ngtid_domain_id value. Filtered binary log events will not get logged to the\nreplica’s relay log, and they will not be applied by the replica.\n\nThe option\'s value can be specified by providing a comma-separated list of\ngtid_domain_id values. Duplicate values are automatically ignored. For example:\n\nSTOP SLAVE;\nCHANGE MASTER TO \n IGNORE_DOMAIN_IDS = (1,2);\nSTART SLAVE;\n\nIf you would like to clear a previously set list, then you can set the value\nto an empty list. For example:\n\nSTOP SLAVE;\nCHANGE MASTER TO \n IGNORE_DOMAIN_IDS = ();\nSTART SLAVE;\n\nThe DO_DOMAIN_IDS option and the IGNORE_DOMAIN_IDS option cannot both be set\nto non-empty values at the same time. If you want to set the IGNORE_DOMAIN_IDS\noption, and the DO_DOMAIN_IDS option was previously set, then you need to\nclear the value of the DO_DOMAIN_IDS option. For example:\n\nSTOP SLAVE;\nCHANGE MASTER TO \n DO_DOMAIN_IDS = (),\n IGNORE_DOMAIN_IDS = (1,2);\nSTART SLAVE;\n\nThe IGNORE_DOMAIN_IDS option can only be specified if the replica is\nreplicating in GTID mode. Therefore, the MASTER_USE_GTID option must also be\nset to some value other than no in order to use this option.\n\nDelayed Replication Options\n---------------------------\n\nMASTER_DELAY\n------------\n\nThe MASTER_DELAY option for CHANGE MASTER can be used to enable delayed\nreplication. This option specifies the time in seconds (at least) that a\nreplica should lag behind the primary up to a maximum value of 2147483647, or\nabout 68 years. Before executing an event, the replica will first wait, if\nnecessary, until the given time has passed since the event was created on the\nprimary. The result is that the replica will reflect the state of the primary\nsome time back in the past. The default is zero, no delay.\n\nSTOP SLAVE;\nCHANGE MASTER TO \n MASTER_DELAY=3600;\nSTART SLAVE;\n\nChanging Option Values\n----------------------\n\nIf you don\'t specify a given option when executing the CHANGE MASTER\nstatement, then the option keeps its old value in most cases. Most of the\ntime, there is no need to specify the options that do not need to change. For\nexample, if the password for the user account that the replica uses to connect\nto its primary has changed, but no other options need to change, then you can\njust change the MASTER_PASSWORD option by executing the following commands:\n\nSTOP SLAVE;\nCHANGE MASTER TO \n MASTER_PASSWORD=\'new3cret\';\nSTART SLAVE;\n\nThere are some cases where options are implicitly reset, such as when the\nMASTER_HOST and MASTER_PORT options are changed.\n\nOption Persistence\n------------------\n\nThe values of the MASTER_LOG_FILE and MASTER_LOG_POS options (i.e. the binary\nlog position on the primary) and most other options are written to either the\ndefault master.info file or the file that is configured by the\nmaster_info_file option. The replica\'s I/O thread keeps this binary log\nposition updated as it downloads events only when MASTER_USE_GTID option is\nset to NO. Otherwise the file is not updated on a per event basis.\n\nThe master_info_file option can be set either on the command-line or in a\nserver option group in an option file prior to starting up the server. For\nexample:\n\n[mariadb]\n...\nmaster_info_file=/mariadb/myserver1-master.info\n\nThe values of the RELAY_LOG_FILE and RELAY_LOG_POS options (i.e. the relay log\nposition) are written to either the default relay-log.info file or the file\nthat is configured by the relay_log_info_file system variable. The replica\'s\nSQL thread keeps this relay log position updated as it applies events.\n\nThe relay_log_info_file system variable can be set either on the command-line\nor in a server option group in an option file prior to starting up the server.\nFor example:\n\n[mariadb]\n...\nrelay_log_info_file=/mariadb/myserver1-relay-log.info\n\nGTID Persistence\n----------------\n\nIf the replica is replicating binary log events that contain GTIDs, then the\nreplica\'s SQL thread will write every GTID that it applies to the\nmysql.gtid_slave_pos table. This GTID can be inspected and modified through\nthe gtid_slave_pos system variable.\n\nIf the replica has the log_slave_updates system variable enabled and if the\nreplica has the binary log enabled, then every write by the replica\'s SQL\nthread will also go into the replica\'s binary log. This means that GTIDs of\nreplicated transactions would be reflected in the value of the gtid_binlog_pos\nsystem variable.\n\nCreating a Replica from a Backup\n--------------------------------\n\nThe CHANGE MASTER statement is useful for setting up a replica when you have a\nbackup of the primary and you also have the binary log position or GTID\nposition corresponding to the backup.\n\nAfter restoring the backup on the replica, you could execute something like\nthis to use the binary log position:\n\nCHANGE MASTER TO\n MASTER_LOG_FILE=\'master2-bin.001\',\n MASTER_LOG_POS=4;\nSTART SLAVE;\n') WHERE help_topic_id = 825; +update help_topic set description = CONCAT(description, '\nOr you could execute something like this to use the GTID position:\n\nSET GLOBAL gtid_slave_pos=\'0-1-153\';\nCHANGE MASTER TO\n MASTER_USE_GTID=slave_pos;\nSTART SLAVE;\n\nSee Setting up a Replication Slave with Mariabackup for more information on\nhow to do this with Mariabackup.\n\nExample\n-------\n\nThe following example changes the primary and primary\'s binary log\ncoordinates. This is used when you want to set up the replica to replicate the\nprimary:\n\nCHANGE MASTER TO\n MASTER_HOST=\'master2.mycompany.com\',\n MASTER_USER=\'replication\',\n MASTER_PASSWORD=\'bigs3cret\',\n MASTER_PORT=3306,\n MASTER_LOG_FILE=\'master2-bin.001\',\n MASTER_LOG_POS=4,\n MASTER_CONNECT_RETRY=10;\nSTART SLAVE;\n\nURL: https://mariadb.com/kb/en/change-master-to/') WHERE help_topic_id = 825; +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (826,49,'START SLAVE','The terms master and slave have historically been used in replication, but the\nterms terms primary and replica are now preferred. The old terms are used\nstill used in parts of the documentation, and in MariaDB commands, although\nMariaDB 10.5 has begun the process of renaming. The documentation process is\nongoing. See MDEV-18777 to follow progress on this effort.\n\nSyntax\n------\n\nSTART SLAVE [\"connection_name\"] [thread_type [, thread_type] ... ] [FOR\nCHANNEL \"connection_name\"]\nSTART SLAVE [\"connection_name\"] [SQL_THREAD] UNTIL \n MASTER_LOG_FILE = \'log_name\', MASTER_LOG_POS = log_pos [FOR CHANNEL\n\"connection_name\"]\nSTART SLAVE [\"connection_name\"] [SQL_THREAD] UNTIL\n RELAY_LOG_FILE = \'log_name\', RELAY_LOG_POS = log_pos [FOR CHANNEL\n\"connection_name\"]\nSTART SLAVE [\"connection_name\"] [SQL_THREAD] UNTIL\n MASTER_GTID_POS = <GTID position> [FOR CHANNEL \"connection_name\"]\nSTART ALL SLAVES [thread_type [, thread_type]]\n\nSTART REPLICA [\"connection_name\"] [thread_type [, thread_type] ... ] -- from\n10.5.1\nSTART REPLICA [\"connection_name\"] [SQL_THREAD] UNTIL \n MASTER_LOG_FILE = \'log_name\', MASTER_LOG_POS = log_pos -- from 10.5.1\nSTART REPLICA [\"connection_name\"] [SQL_THREAD] UNTIL\n RELAY_LOG_FILE = \'log_name\', RELAY_LOG_POS = log_pos -- from 10.5.1\nSTART REPLICA [\"connection_name\"] [SQL_THREAD] UNTIL\n MASTER_GTID_POS = <GTID position> -- from 10.5.1\nSTART ALL REPLICAS [thread_type [, thread_type]] -- from 10.5.1\n\nthread_type: IO_THREAD | SQL_THREAD\n\nDescription\n-----------\n\nSTART SLAVE (START REPLICA from MariaDB 10.5.1) with no thread_type options\nstarts both of the replica threads (see replication). The I/O thread reads\nevents from the primary server and stores them in the relay log. The SQL\nthread reads events from the relay log and executes them. START SLAVE requires\nthe SUPER privilege, or, from MariaDB 10.5.2, the REPLICATION SLAVE ADMIN\nprivilege.\n\nIf START SLAVE succeeds in starting the replica threads, it returns without\nany error. However, even in that case, it might be that the replica threads\nstart and then later stop (for example, because they do not manage to connect\nto the primary or read its binary log, or some other problem). START SLAVE\ndoes not warn you about this. You must check the replica\'s error log for error\nmessages generated by the replica threads, or check that they are running\nsatisfactorily with SHOW SLAVE STATUS (SHOW REPLICA STATUS from MariaDB\n10.5.1).\n\nSTART SLAVE UNTIL\n-----------------\n\nSTART SLAVE UNTIL refers to the SQL_THREAD replica position at which the\nSQL_THREAD replication will halt. If SQL_THREAD isn\'t specified both threads\nare started.\n\nSTART SLAVE UNTIL master_gtid_pos=xxx is also supported. See Global\nTransaction ID/START SLAVE UNTIL master_gtid_pos=xxx for more details.\n\nconnection_name\n---------------\n\nIf there is only one nameless primary, or the default primary (as specified by\nthe default_master_connection system variable) is intended, connection_name\ncan be omitted. If provided, the START SLAVE statement will apply to the\nspecified primary. connection_name is case-insensitive.\n\nMariaDB starting with 10.7.0\n----------------------------\nThe FOR CHANNEL keyword was added for MySQL compatibility. This is identical\nas using the channel_name directly after START SLAVE.\n\nSTART ALL SLAVES\n----------------\n\nSTART ALL SLAVES starts all configured replicas (replicas with master_host not\nempty) that were not started before. It will give a note for all started\nconnections. You can check the notes with SHOW WARNINGS.\n\nSTART REPLICA\n-------------\n\nMariaDB starting with 10.5.1\n----------------------------\nSTART REPLICA is an alias for START SLAVE from MariaDB 10.5.1.\n\nURL: https://mariadb.com/kb/en/start-replica/','','https://mariadb.com/kb/en/start-replica/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (827,49,'STOP SLAVE','The terms master and slave have historically been used in replication, but the\nterms terms primary and replica are now preferred. The old terms are used\nstill used in parts of the documentation, and in MariaDB commands, although\nMariaDB 10.5 has begun the process of renaming. The documentation process is\nongoing. See MDEV-18777 to follow progress on this effort.\n\nSyntax\n------\n\nSTOP SLAVE [\"connection_name\"] [thread_type [, thread_type] ... ] [FOR CHANNEL\n\"connection_name\"]\n\nSTOP ALL SLAVES [thread_type [, thread_type]]\n\nSTOP REPLICA [\"connection_name\"] [thread_type [, thread_type] ... ] -- from\n10.5.1\n\nSTOP ALL REPLICAS [thread_type [, thread_type]] -- from 10.5.1\n\nthread_type: IO_THREAD | SQL_THREAD\n\nDescription\n-----------\n\nStops the replica threads. STOP SLAVE requires the SUPER privilege, or, from\nMariaDB 10.5.2, the REPLICATION SLAVE ADMIN privilege.\n\nLike START SLAVE, this statement may be used with the IO_THREAD and SQL_THREAD\noptions to name the thread or threads to be stopped. In almost all cases, one\nnever need to use the thread_type options.\n\nSTOP SLAVE waits until any current replication event group affecting one or\nmore non-transactional tables has finished executing (if there is any such\nreplication group), or until the user issues a KILL QUERY or KILL CONNECTION\nstatement.\n\nNote that STOP SLAVE doesn\'t delete the connection permanently. Next time you\nexecute START SLAVE or the MariaDB server restarts, the replica connection is\nrestored with it\'s original arguments. If you want to delete a connection, you\nshould execute RESET SLAVE.\n\nSTOP ALL SLAVES\n---------------\n\nSTOP ALL SLAVES stops all your running replicas. It will give you a note for\nevery stopped connection. You can check the notes with SHOW WARNINGS.\n\nconnection_name\n---------------\n\nThe connection_name option is used for multi-source replication.\n\nIf there is only one nameless master, or the default master (as specified by\nthe default_master_connection system variable) is intended, connection_name\ncan be omitted. If provided, the STOP SLAVE statement will apply to the\nspecified master. connection_name is case-insensitive.\n\nMariaDB starting with 10.7.0\n----------------------------\nThe FOR CHANNEL keyword was added for MySQL compatibility. This is identical\nas using the channel_name directly after STOP SLAVE.\n\nSTOP REPLICA\n------------\n\nMariaDB starting with 10.5.1\n----------------------------\nSTOP REPLICA is an alias for STOP SLAVE from MariaDB 10.5.1.\n\nURL: https://mariadb.com/kb/en/stop-replica/','','https://mariadb.com/kb/en/stop-replica/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (828,49,'RESET REPLICA/SLAVE','The terms master and slave have historically been used in replication, but the\nterms terms primary and replica are now preferred. The old terms are used\nstill used in parts of the documentation, and in MariaDB commands, although\nMariaDB 10.5 has begun the process of renaming. The documentation process is\nongoing. See MDEV-18777 to follow progress on this effort.\n\nSyntax\n------\n\nRESET REPLICA [\"connection_name\"] [ALL] [FOR CHANNEL \"connection_name\"] --\nfrom MariaDB 10.5.1 \nRESET SLAVE [\"connection_name\"] [ALL] [FOR CHANNEL \"connection_name\"]\n\nDescription\n-----------\n\nRESET REPLICA/SLAVE makes the replica forget its replication position in the\nmaster\'s binary log. This statement is meant to be used for a clean start. It\ndeletes the master.info and relay-log.info files, all the relay log files, and\nstarts a new relay log file. To use RESET REPLICA/SLAVE, the replica threads\nmust be stopped (use STOP REPLICA/SLAVE if necessary).\n\nNote: All relay log files are deleted, even if they have not been completely\nexecuted by the slave SQL thread. (This is a condition likely to exist on a\nreplication slave if you have issued a STOP REPLICA/SLAVE statement or if the\nslave is highly loaded.)\n\nNote: RESET REPLICA does not reset the global gtid_slave_pos variable. This\nmeans that a replica server configured with CHANGE MASTER TO\nMASTER_USE_GTID=slave_pos will not receive events with GTIDs occurring before\nthe state saved in gtid_slave_pos. If the intent is to reprocess these events,\ngtid_slave_pos must be manually reset, e.g. by executing set global\ngtid_slave_pos=\"\".\n\nConnection information stored in the master.info file is immediately reset\nusing any values specified in the corresponding startup options. This\ninformation includes values such as master host, master port, master user, and\nmaster password. If the replica SQL thread was in the middle of replicating\ntemporary tables when it was stopped, and RESET REPLICA/SLAVE is issued, these\nreplicated temporary tables are deleted on the slave.\n\nThe ALL also resets the PORT, HOST, USER and PASSWORD parameters for the\nslave. If you are using a connection name, it will permanently delete it and\nit will not show up anymore in SHOW ALL REPLICAS/SLAVE STATUS.\n\nconnection_name\n---------------\n\nThe connection_name option is used for multi-source replication.\n\nIf there is only one nameless primary, or the default primary (as specified by\nthe default_master_connection system variable) is intended, connection_name\ncan be omitted. If provided, the RESET REPLICA/SLAVE statement will apply to\nthe specified primary. connection_name is case-insensitive.\n\nMariaDB starting with 10.7.0\n----------------------------\nThe FOR CHANNEL keyword was added for MySQL compatibility. This is identical\nas using the channel_name directly after RESET REPLICA.\n\nRESET REPLICA\n-------------\n\nMariaDB starting with 10.5.1\n----------------------------\nRESET REPLICA is an alias for RESET SLAVE from MariaDB 10.5.1.\n\nURL: https://mariadb.com/kb/en/reset-replica/','','https://mariadb.com/kb/en/reset-replica/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (829,49,'RESET MASTER','RESET MASTER [TO #]\n\nDeletes all binary log files listed in the index file, resets the binary log\nindex file to be empty, and creates a new binary log file with a suffix of\n.000001.\n\nIf TO # is given, then the first new binary log file will start from number #.\n\nThis statement is for use only when the master is started for the first time,\nand should never be used if any slaves are actively replicating from the\nbinary log.\n\nURL: https://mariadb.com/kb/en/reset-master/','','https://mariadb.com/kb/en/reset-master/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (830,50,'EXECUTE Statement','Syntax\n------\n\nEXECUTE stmt_name\n [USING expression[, expression] ...]\n\nMariaDB starting with 10.2.3\n----------------------------\nEXECUTE with expression as parameters was introduced in MariaDB 10.2.3. Before\nthat one could only use variables (@var_name) as parameters.\n\nDescription\n-----------\n\nAfter preparing a statement with PREPARE, you execute it with an EXECUTE\nstatement that refers to the prepared statement name. If the prepared\nstatement contains any parameter markers, you must supply a USING clause that\nlists user variables containing the values to be bound to the parameters.\nParameter values can be supplied only by user variables, and the USING clause\nmust name exactly as many variables as the number of parameter markers in the\nstatement.\n\nYou can execute a given prepared statement multiple times, passing different\nvariables to it or setting the variables to different values before each\nexecution.\n\nIf the specified statement has not been PREPAREd, an error similar to the\nfollowing is produced:\n\nERROR 1243 (HY000): Unknown prepared statement handler (stmt_name) given to\nEXECUTE\n\nExample\n-------\n\nSee example in PREPARE.\n\nURL: https://mariadb.com/kb/en/execute-statement/','','https://mariadb.com/kb/en/execute-statement/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (831,50,'PREPARE Statement','Syntax\n------\n\nPREPARE stmt_name FROM preparable_stmt\n\nDescription\n-----------\n\nThe PREPARE statement prepares a statement and assigns it a name, stmt_name,\nby which to refer to the statement later. Statement names are not case\nsensitive. preparable_stmt is either a string literal or a user variable (not\na local variable, an SQL expression or a subquery) that contains the text of\nthe statement. The text must represent a single SQL statement, not multiple\nstatements. Within the statement, \"?\" characters can be used as parameter\nmarkers to indicate where data values are to be bound to the query later when\nyou execute it. The \"?\" characters should not be enclosed within quotes, even\nif you intend to bind them to string values. Parameter markers can be used\nonly where expressions should appear, not for SQL keywords, identifiers, and\nso forth.\n\nThe scope of a prepared statement is the session within which it is created.\nOther sessions cannot see it.\n\nIf a prepared statement with the given name already exists, it is deallocated\nimplicitly before the new statement is prepared. This means that if the new\nstatement contains an error and cannot be prepared, an error is returned and\nno statement with the given name exists.\n\nPrepared statements can be PREPAREd and EXECUTEd in a stored procedure, but\nnot in a stored function or trigger. Also, even if the statement is PREPAREd\nin a procedure, it will not be deallocated when the procedure execution ends.\n\nA prepared statement can access user-defined variables, but not local\nvariables or procedure\'s parameters.\n\nIf the prepared statement contains a syntax error, PREPARE will fail. As a\nside effect, stored procedures can use it to check if a statement is valid.\nFor example:\n\nCREATE PROCEDURE `test_stmt`(IN sql_text TEXT)\nBEGIN\n DECLARE EXIT HANDLER FOR SQLEXCEPTION\n BEGIN\n SELECT CONCAT(sql_text, \' is not valid\');\n END;\n SET @SQL := sql_text;\n PREPARE stmt FROM @SQL;\n DEALLOCATE PREPARE stmt;\nEND;\n\nThe FOUND_ROWS() and ROW_COUNT() functions, if called immediatly after\nEXECUTE, return the number of rows read or affected by the prepared\nstatements; however, if they are called after DEALLOCATE PREPARE, they provide\ninformation about this statement. If the prepared statement produces errors or\nwarnings, GET DIAGNOSTICS return information about them. DEALLOCATE PREPARE\nshouldn\'t clear the diagnostics area, unless it produces an error.\n\nA prepared statement is executed with EXECUTE and released with DEALLOCATE\nPREPARE.\n\nThe max_prepared_stmt_count server system variable determines the number of\nallowed prepared statements that can be prepared on the server. If it is set\nto 0, prepared statements are not allowed. If the limit is reached, an error\nsimilar to the following will be produced:\n\nERROR 1461 (42000): Can\'t create more than max_prepared_stmt_count statements \n (current value: 0)\n\nOracle Mode\n-----------\n\nMariaDB starting with 10.3\n--------------------------\nIn Oracle mode from MariaDB 10.3, PREPARE stmt FROM \'SELECT :1, :2\' is used,\ninstead of ?.\n\nPermitted Statements\n--------------------\n\nMariaDB starting with 10.6.2\n----------------------------\nAll statements can be prepared, except PREPARE, EXECUTE, and DEALLOCATE / DROP\nPREPARE.\n\nPrior to this, not all statements can be prepared. Only the following SQL\ncommands are permitted:\n\n* ALTER TABLE\n* ANALYZE TABLE\n* BINLOG\n* CACHE INDEX\n* CALL\n* CHANGE MASTER\n* CHECKSUM {TABLE | TABLES}\n* COMMIT\n* {CREATE | DROP} DATABASE\n* {CREATE | DROP} INDEX\n* {CREATE | RENAME | DROP} TABLE\n* {CREATE | RENAME | DROP} USER\n* {CREATE | DROP} VIEW\n* DELETE\n* DESCRIBE\n* DO\n* EXPLAIN\n* FLUSH {TABLE | TABLES | TABLES WITH READ LOCK | HOSTS | PRIVILEGES | LOGS |\nSTATUS | \n MASTER | SLAVE | DES_KEY_FILE | USER_RESOURCES | QUERY CACHE |\nTABLE_STATISTICS | \n INDEX_STATISTICS | USER_STATISTICS | CLIENT_STATISTICS}\n* GRANT\n* INSERT\n* INSTALL {PLUGIN | SONAME}\n* HANDLER READ\n* KILL\n* LOAD INDEX INTO CACHE\n* OPTIMIZE TABLE\n* REPAIR TABLE\n* REPLACE\n* RESET {MASTER | SLAVE | QUERY CACHE}\n* REVOKE\n* ROLLBACK\n* SELECT\n* SET\n* SET GLOBAL SQL_SLAVE_SKIP_COUNTER\n* SET ROLE\n* SET SQL_LOG_BIN\n* SET TRANSACTION ISOLATION LEVEL\n* SHOW EXPLAIN\n* SHOW {DATABASES | TABLES | OPEN TABLES | TABLE STATUS | COLUMNS | INDEX |\nTRIGGERS | \n EVENTS | GRANTS | CHARACTER SET | COLLATION | ENGINES | PLUGINS [SONAME] |\nPRIVILEGES | \n PROCESSLIST | PROFILE | PROFILES | VARIABLES | STATUS | WARNINGS | ERRORS |\n TABLE_STATISTICS | INDEX_STATISTICS | USER_STATISTICS | CLIENT_STATISTICS |\nAUTHORS | \n CONTRIBUTORS}\n* SHOW CREATE {DATABASE | TABLE | VIEW | PROCEDURE | FUNCTION | TRIGGER |\nEVENT}\n* SHOW {FUNCTION | PROCEDURE} CODE\n* SHOW BINLOG EVENTS\n* SHOW SLAVE HOSTS\n* SHOW {MASTER | BINARY} LOGS\n* SHOW {MASTER | SLAVE | TABLES | INNODB | FUNCTION | PROCEDURE} STATUS\n* SLAVE {START | STOP}\n* TRUNCATE TABLE\n* SHUTDOWN\n* UNINSTALL {PLUGIN | SONAME}\n* UPDATE\n\nSynonyms are not listed here, but can be used. For example, DESC can be used\ninstead of DESCRIBE.\n\nCompound statements can be prepared too.\n\nNote that if a statement can be run in a stored routine, it will work even if\nit is called by a prepared statement. For example, SIGNAL can\'t be directly\nprepared. However, it is allowed in stored routines. If the x() procedure\ncontains SIGNAL, you can still prepare and execute the \'CALL x();\' prepared\nstatement.\n\nPREPARE supports most kinds of expressions as well, for example:\n\nPREPARE stmt FROM CONCAT(\'SELECT * FROM \', table_name);\n\nWhen PREPARE is used with a statement which is not supported, the following\nerror is produced:\n\nERROR 1295 (HY000): This command is not supported in the prepared statement\nprotocol yet\n\nExample\n-------\n\ncreate table t1 (a int,b char(10));\ninsert into t1 values (1,\"one\"),(2, \"two\"),(3,\"three\");\nprepare test from \"select * from t1 where a=?\";\nset @param=2;\nexecute test using @param;\n+------+------+\n| a | b |\n+------+------+\n| 2 | two |\n+------+------+\nset @param=3;\nexecute test using @param;\n+------+-------+\n| a | b |\n+------+-------+\n| 3 | three |\n+------+-------+\ndeallocate prepare test;\n\nSince identifiers are not permitted as prepared statements parameters,\nsometimes it is necessary to dynamically compose an SQL statement. This\ntechnique is called dynamic SQL). The following example shows how to use\ndynamic SQL:\n\nCREATE PROCEDURE test.stmt_test(IN tab_name VARCHAR(64))\nBEGIN\n SET @sql = CONCAT(\'SELECT COUNT(*) FROM \', tab_name);\n PREPARE stmt FROM @sql;\n EXECUTE stmt;\n DEALLOCATE PREPARE stmt;\nEND;\n\nCALL test.stmt_test(\'mysql.user\');\n+----------+\n| COUNT(*) |\n+----------+\n| 4 |\n+----------+\n\nUse of variables in prepared statements:\n\nPREPARE stmt FROM \'SELECT @x;\';\n\nSET @x = 1;\n\nEXECUTE stmt;\n+------+\n| @x |\n+------+\n| 1 |\n+------+\n\nSET @x = 0;\n\nEXECUTE stmt;\n+------+\n| @x |\n+------+\n| 0 |\n+------+\n\nDEALLOCATE PREPARE stmt;\n\nURL: https://mariadb.com/kb/en/prepare-statement/','','https://mariadb.com/kb/en/prepare-statement/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (832,50,'DEALLOCATE / DROP PREPARE','Syntax\n------\n\n{DEALLOCATE | DROP} PREPARE stmt_name\n\nDescription\n-----------\n\nTo deallocate a prepared statement produced with PREPARE, use a DEALLOCATE\nPREPARE statement that refers to the prepared statement name.\n\nA prepared statement is implicitly deallocated when a new PREPARE command is\nissued. In that case, there is no need to use DEALLOCATE.\n\nAttempting to execute a prepared statement after deallocating it results in an\nerror, as if it was not prepared at all:\n\nERROR 1243 (HY000): Unknown prepared statement handler (stmt_name) given to\nEXECUTE\n\nIf the specified statement has not been PREPAREd, an error similar to the\nfollowing will be produced:\n\nERROR 1243 (HY000): Unknown prepared statement handler (stmt_name) given to\nDEALLOCATE PREPARE\n\nExample\n-------\n\nSee example in PREPARE.\n\nURL: https://mariadb.com/kb/en/deallocate-drop-prepare/','','https://mariadb.com/kb/en/deallocate-drop-prepare/'); +insert into help_topic (help_topic_id,help_category_id,name,description,example,url) values (833,50,'EXECUTE IMMEDIATE','MariaDB starting with 10.2.3\n----------------------------\nEXECUTE IMMEDIATE was introduced in MariaDB 10.2.3.\n\nSyntax\n------\n\nEXECUTE IMMEDIATE statement\n\nDescription\n-----------\n\nEXECUTE IMMEDIATE executes a dynamic SQL statement created on the fly, which\ncan reduce performance overhead.\n\nFor example:\n\nEXECUTE IMMEDIATE \'SELECT 1\'\n\nwhich is shorthand for:\n\nprepare stmt from \"select 1\";\nexecute stmt;\ndeallocate prepare stmt;\n\nEXECUTE IMMEDIATE supports complex expressions as prepare source and\nparameters:\n\nEXECUTE IMMEDIATE CONCAT(\'SELECT COUNT(*) FROM \', \'t1\', \' WHERE a=?\') USING\n5+5;\n\nLimitations: subselects and stored function calls are not supported as a\nprepare source.\n\nThe following examples return an error:\n\nCREATE OR REPLACE FUNCTION f1() RETURNS VARCHAR(64) RETURN \'SELECT * FROM t1\';\nEXECUTE IMMEDIATE f1();\nERROR 1970 (42000): EXECUTE IMMEDIATE does not support subqueries or stored\nfunctions\n\nEXECUTE IMMEDIATE (SELECT \'SELECT * FROM t1\');\nERROR 1064 (42000): You have an error in your SQL syntax; check the manual\nthat \n corresponds to your MariaDB server version for the right syntax to use near\n \'SELECT \'SELECT * FROM t1\')\' at line 1\n\nCREATE OR REPLACE FUNCTION f1() RETURNS INT RETURN 10;\nEXECUTE IMMEDIATE \'SELECT * FROM t1 WHERE a=?\' USING f1();\nERROR 1970 (42000): EXECUTE..USING does not support subqueries or stored\nfunctions\n\nEXECUTE IMMEDIATE \'SELECT * FROM t1 WHERE a=?\' USING (SELECT 10);\nERROR 1064 (42000): You have an error in your SQL syntax; check the manual\nthat \n corresponds to your MariaDB server version for the right syntax to use near\n \'SELECT 10)\' at line 1\n\nOne can use a user or an SP variable as a workaround:\n\nCREATE OR REPLACE FUNCTION f1() RETURNS VARCHAR(64) RETURN \'SELECT * FROM t1\';\nSET @stmt=f1();\nEXECUTE IMMEDIATE @stmt;\n\nSET @stmt=(SELECT \'SELECT 1\');\nEXECUTE IMMEDIATE @stmt;\n\nCREATE OR REPLACE FUNCTION f1() RETURNS INT RETURN 10;\nSET @param=f1();\nEXECUTE IMMEDIATE \'SELECT * FROM t1 WHERE a=?\' USING @param;\n\nSET @param=(SELECT 10);\nEXECUTE IMMEDIATE \'SELECT * FROM t1 WHERE a=?\' USING @param;\n\nEXECUTE IMMEDIATE supports user variables and SP variables as OUT parameters\n\nDELIMITER $$\nCREATE OR REPLACE PROCEDURE p1(OUT a INT)\nBEGIN\n SET a:= 10;\nEND;\n$$\nDELIMITER ;\nSET @a=2;\nEXECUTE IMMEDIATE \'CALL p1(?)\' USING @a;\nSELECT @a;\n+------+\n| @a |\n+------+\n| 10 |\n+------+\n\nSimilar to PREPARE, EXECUTE IMMEDIATE is allowed in stored procedures but is\nnot allowed in stored functions.\n\nThis example uses EXECUTE IMMEDIATE inside a stored procedure:\n\nDELIMITER $$\nCREATE OR REPLACE PROCEDURE p1()\nBEGIN\n EXECUTE IMMEDIATE \'SELECT 1\';\nEND;\n$$\nDELIMITER ;\nCALL p1;\n+---+\n| 1 |\n+---+\n| 1 |\n+---+\n\nThis script returns an error:\n\nDELIMITER $$\nCREATE FUNCTION f1() RETURNS INT\nBEGIN\n EXECUTE IMMEDIATE \'DO 1\';\n RETURN 1;\nEND;\n$$\nERROR 1336 (0A000): Dynamic SQL is not allowed in stored function or trigger\n\nEXECUTE IMMEDIATE can use DEFAULT and IGNORE indicators as bind parameters:\n\nCREATE OR REPLACE TABLE t1 (a INT DEFAULT 10);\nEXECUTE IMMEDIATE \'INSERT INTO t1 VALUES (?)\' USING DEFAULT;\nSELECT * FROM t1;\n+------+\n| a |\n+------+\n| 10 |\n+------+\n\nEXECUTE IMMEDIATE increments the Com_execute_immediate status variable, as\nwell as the Com_stmt_prepare, Com_stmt_execute and Com_stmt_close status\nvariables.\n\nNote, EXECUTE IMMEDIATE does not increment the Com_execute_sql status\nvariable. Com_execute_sql is used only for PREPARE..EXECUTE.\n\nThis session screenshot demonstrates how EXECUTE IMMEDIATE affects status\nvariables:\n\nSELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME RLIKE \n (\'COM_(EXECUTE|STMT_PREPARE|STMT_EXECUTE|STMT_CLOSE)\');\n\n+-----------------------+----------------+\n| VARIABLE_NAME | VARIABLE_VALUE |\n+-----------------------+----------------+\n| COM_EXECUTE_IMMEDIATE | 0 |\n| COM_EXECUTE_SQL | 0 |\n| COM_STMT_CLOSE | 0 |\n| COM_STMT_EXECUTE | 0 |\n| COM_STMT_PREPARE | 0 |\n+-----------------------+----------------+\n\nEXECUTE IMMEDIATE \'SELECT 1\';\n+---+\n| 1 |\n+---+\n| 1 |\n+---+\n\nSELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME RLIKE \n (\'COM_(EXECUTE|STMT_PREPARE|STMT_EXECUTE|STMT_CLOSE)\');\n+-----------------------+----------------+\n| VARIABLE_NAME | VARIABLE_VALUE |\n+-----------------------+----------------+\n| COM_EXECUTE_IMMEDIATE | 1 |\n| COM_EXECUTE_SQL | 0 |\n| COM_STMT_CLOSE | 1 |\n| COM_STMT_EXECUTE | 1 |\n| COM_STMT_PREPARE | 1 |\n+-----------------------+----------------+\n\nURL: https://mariadb.com/kb/en/execute-immediate/','','https://mariadb.com/kb/en/execute-immediate/'); +insert into help_keyword values (1, 'work'); +insert into help_keyword values (2, 'locks'); +insert into help_keyword values (3, 'locking'); +insert into help_keyword values (4, 'drop'); +insert into help_keyword values (5, 'super'); +insert into help_keyword values (6, 'usage'); +insert into help_keyword values (7, 'binlog admin'); +insert into help_keyword values (8, 'binlog monitor'); +insert into help_keyword values (9, 'binlog replay'); +insert into help_keyword values (10, 'connection admin'); +insert into help_keyword values (11, 'federated admin'); +insert into help_keyword values (12, 'grant option'); +insert into help_keyword values (13, 'read_only admin'); +insert into help_keyword values (14, 'replica monitor'); +insert into help_keyword values (15, 'replication replica'); +insert into help_keyword values (16, 'roles'); +insert into help_keyword values (17, 'values'); +insert into help_keyword values (18, 'value'); +insert into help_keyword values (19, 'not'); +insert into help_keyword values (20, 'and'); +insert into help_keyword values (21, 'or'); +insert into help_keyword values (22, ':='); +insert into help_keyword values (23, 'assignment operator'); +insert into help_keyword values (24, '='); +insert into help_keyword values (25, '!='); +insert into help_keyword values (26, '<>'); +insert into help_keyword values (27, 'not equal'); +insert into help_keyword values (28, 'less than'); +insert into help_keyword values (29, 'less than or equal'); +insert into help_keyword values (30, 'NULL-safe equal'); +insert into help_keyword values (31, 'equal'); +insert into help_keyword values (32, 'greater than'); +insert into help_keyword values (33, 'greater than or equal'); +insert into help_keyword values (34, 'bitwise and'); +insert into help_keyword values (35, 'shift left'); +insert into help_keyword values (36, 'shift right'); +insert into help_keyword values (37, 'bitwise xor'); +insert into help_keyword values (38, 'bitwise or'); +insert into help_keyword values (39, 'bitwise not'); +insert into help_keyword values (40, 'returns'); +insert into help_keyword values (41, 'udfs'); +insert into help_keyword values (42, 'udf calling sequences'); +insert into help_keyword values (43, 'udf security'); +insert into help_keyword values (44, 'int1'); +insert into help_keyword values (45, 'int2'); +insert into help_keyword values (46, 'int3'); +insert into help_keyword values (47, 'integer'); +insert into help_keyword values (48, 'int4'); +insert into help_keyword values (49, 'int8'); +insert into help_keyword values (50, 'dec'); +insert into help_keyword values (51, 'numeric'); +insert into help_keyword values (52, 'fixed'); +insert into help_keyword values (53, 'number'); +insert into help_keyword values (54, 'real'); +insert into help_keyword values (55, 'double precision'); +insert into help_keyword values (56, 'nchar'); +insert into help_keyword values (57, 'long'); +insert into help_keyword values (58, 'long varchar'); +insert into help_keyword values (59, 'repeat'); +insert into help_keyword values (60, 'declare'); +insert into help_keyword values (61, 'cursor'); +insert into help_keyword values (62, 'show'); +insert into help_keyword values (63, 'columns'); +insert into help_keyword values (64, 'kill connection'); +insert into help_keyword values (65, 'kill query'); +insert into help_keyword values (66, 'delete returning'); +insert into help_keyword values (67, 'sql_big_result'); +insert into help_keyword values (68, 'minus'); +insert into help_keyword values (69, 'cte'); +insert into help_keyword values (70, 'insert returning'); +insert into help_keyword values (71, 'queries'); +insert into help_keyword values (72, 'query'); +insert into help_keyword values (73, 'explain format'); +insert into help_keyword values (74, 'explain format json'); +insert into help_keyword values (75, 'rlike'); +insert into help_keyword values (76, 'character_length'); +insert into help_keyword values (77, 'escape'); +insert into help_keyword values (78, 'mode'); +insert into help_keyword values (79, 'trim_oracle'); +insert into help_keyword values (80, 'schedule'); +insert into help_keyword values (81, 'row_format'); +insert into help_keyword values (82, 'starts'); +insert into help_keyword values (83, 'host'); +insert into help_keyword values (84, 'generated columns'); +insert into help_keyword values (85, 'virtual columns'); +insert into help_keyword values (86, 'computed columns'); +insert into help_keyword values (87, 'hidden columns'); +insert into help_keyword values (88, 'nextval'); +insert into help_keyword values (89, 'lastval'); +insert into help_keyword values (90, '+'); +insert into help_keyword values (91, 'addition operator'); +insert into help_keyword values (92, '/'); +insert into help_keyword values (93, 'division operator'); +insert into help_keyword values (94, '%'); +insert into help_keyword values (95, 'modulo operator'); +insert into help_keyword values (96, '*'); +insert into help_keyword values (97, 'multiplication operator'); +insert into help_keyword values (98, '-'); +insert into help_keyword values (99, 'subtraction operator'); +insert into help_keyword values (100, 'master_ssl_verify_cert'); +insert into help_keyword values (101, 'start replica'); +insert into help_keyword values (102, 'stop replica'); +insert into help_keyword values (103, 'reset slave'); +insert into help_keyword values (104, 'reset replica'); +insert into help_keyword values (105, 'drop prepare'); +insert into help_keyword values (106, 'deallocate prepare'); +insert into help_relation values (94, 1); +insert into help_relation values (98, 2); +insert into help_relation values (98, 3); +insert into help_relation values (100, 2); +insert into help_relation values (100, 3); +insert into help_relation values (102, 2); +insert into help_relation values (102, 3); +insert into help_relation values (107, 4); +insert into help_relation values (108, 5); +insert into help_relation values (108, 6); +insert into help_relation values (108, 7); +insert into help_relation values (108, 8); +insert into help_relation values (108, 9); +insert into help_relation values (108, 10); +insert into help_relation values (108, 11); +insert into help_relation values (108, 12); +insert into help_relation values (108, 13); +insert into help_relation values (108, 14); +insert into help_relation values (108, 15); +insert into help_relation values (113, 4); +insert into help_relation values (116, 16); +insert into help_relation values (117, 2); +insert into help_relation values (117, 3); +insert into help_relation values (149, 2); +insert into help_relation values (149, 3); +insert into help_relation values (154, 2); +insert into help_relation values (154, 3); +insert into help_relation values (159, 2); +insert into help_relation values (159, 3); +insert into help_relation values (163, 2); +insert into help_relation values (163, 3); +insert into help_relation values (164, 2); +insert into help_relation values (164, 3); +insert into help_relation values (169, 17); +insert into help_relation values (169, 18); +insert into help_relation values (170, 19); +insert into help_relation values (171, 20); +insert into help_relation values (173, 21); +insert into help_relation values (214, 22); +insert into help_relation values (214, 23); +insert into help_relation values (215, 23); +insert into help_relation values (215, 24); +insert into help_relation values (216, 25); +insert into help_relation values (216, 26); +insert into help_relation values (216, 27); +insert into help_relation values (217, 28); +insert into help_relation values (218, 29); +insert into help_relation values (219, 30); +insert into help_relation values (220, 31); +insert into help_relation values (221, 32); +insert into help_relation values (222, 33); +insert into help_relation values (236, 34); +insert into help_relation values (237, 35); +insert into help_relation values (238, 36); +insert into help_relation values (240, 37); +insert into help_relation values (241, 38); +insert into help_relation values (242, 39); +insert into help_relation values (253, 40); +insert into help_relation values (254, 4); +insert into help_relation values (255, 41); +insert into help_relation values (256, 42); +insert into help_relation values (257, 43); +insert into help_relation values (259, 44); +insert into help_relation values (261, 45); +insert into help_relation values (262, 46); +insert into help_relation values (263, 47); +insert into help_relation values (263, 48); +insert into help_relation values (264, 49); +insert into help_relation values (265, 50); +insert into help_relation values (265, 51); +insert into help_relation values (265, 52); +insert into help_relation values (265, 53); +insert into help_relation values (267, 54); +insert into help_relation values (267, 55); +insert into help_relation values (273, 56); +insert into help_relation values (280, 57); +insert into help_relation values (280, 58); +insert into help_relation values (310, 59); +insert into help_relation values (317, 60); +insert into help_relation values (317, 61); +insert into help_relation values (337, 62); +insert into help_relation values (338, 62); +insert into help_relation values (339, 63); +insert into help_relation values (339, 62); +insert into help_relation values (340, 62); +insert into help_relation values (341, 62); +insert into help_relation values (344, 2); +insert into help_relation values (344, 3); +insert into help_relation values (348, 62); +insert into help_relation values (349, 62); +insert into help_relation values (350, 62); +insert into help_relation values (351, 62); +insert into help_relation values (352, 62); +insert into help_relation values (353, 62); +insert into help_relation values (360, 62); +insert into help_relation values (362, 62); +insert into help_relation values (363, 62); +insert into help_relation values (364, 62); +insert into help_relation values (365, 62); +insert into help_relation values (366, 62); +insert into help_relation values (367, 62); +insert into help_relation values (368, 62); +insert into help_relation values (369, 62); +insert into help_relation values (370, 62); +insert into help_relation values (371, 62); +insert into help_relation values (372, 62); +insert into help_relation values (373, 62); +insert into help_relation values (374, 62); +insert into help_relation values (375, 62); +insert into help_relation values (376, 62); +insert into help_relation values (377, 62); +insert into help_relation values (378, 62); +insert into help_relation values (379, 62); +insert into help_relation values (380, 62); +insert into help_relation values (381, 62); +insert into help_relation values (382, 62); +insert into help_relation values (383, 62); +insert into help_relation values (384, 62); +insert into help_relation values (385, 62); +insert into help_relation values (386, 62); +insert into help_relation values (387, 62); +insert into help_relation values (388, 62); +insert into help_relation values (389, 62); +insert into help_relation values (390, 62); +insert into help_relation values (391, 62); +insert into help_relation values (392, 62); +insert into help_relation values (393, 62); +insert into help_relation values (394, 62); +insert into help_relation values (395, 62); +insert into help_relation values (396, 62); +insert into help_relation values (397, 62); +insert into help_relation values (398, 62); +insert into help_relation values (399, 62); +insert into help_relation values (400, 62); +insert into help_relation values (401, 62); +insert into help_relation values (402, 62); +insert into help_relation values (403, 62); +insert into help_relation values (404, 62); +insert into help_relation values (409, 64); +insert into help_relation values (409, 65); +insert into help_relation values (414, 62); +insert into help_relation values (415, 62); +insert into help_relation values (416, 66); +insert into help_relation values (420, 67); +insert into help_relation values (431, 68); +insert into help_relation values (437, 69); +insert into help_relation values (438, 69); +insert into help_relation values (439, 69); +insert into help_relation values (444, 2); +insert into help_relation values (444, 3); +insert into help_relation values (459, 70); +insert into help_relation values (466, 71); +insert into help_relation values (466, 72); +insert into help_relation values (472, 73); +insert into help_relation values (472, 74); +insert into help_relation values (629, 75); +insert into help_relation values (639, 76); +insert into help_relation values (658, 77); +insert into help_relation values (664, 78); +insert into help_relation values (672, 59); +insert into help_relation values (688, 79); +insert into help_relation values (697, 4); +insert into help_relation values (699, 80); +insert into help_relation values (706, 81); +insert into help_relation values (707, 4); +insert into help_relation values (711, 82); +insert into help_relation values (717, 83); +insert into help_relation values (721, 84); +insert into help_relation values (721, 85); +insert into help_relation values (721, 86); +insert into help_relation values (722, 87); +insert into help_relation values (723, 4); +insert into help_relation values (724, 4); +insert into help_relation values (725, 4); +insert into help_relation values (726, 4); +insert into help_relation values (727, 4); +insert into help_relation values (728, 4); +insert into help_relation values (729, 4); +insert into help_relation values (730, 4); +insert into help_relation values (732, 4); +insert into help_relation values (733, 4); +insert into help_relation values (741, 4); +insert into help_relation values (742, 88); +insert into help_relation values (743, 89); +insert into help_relation values (820, 90); +insert into help_relation values (820, 91); +insert into help_relation values (821, 92); +insert into help_relation values (821, 93); +insert into help_relation values (822, 94); +insert into help_relation values (822, 95); +insert into help_relation values (823, 96); +insert into help_relation values (823, 97); +insert into help_relation values (824, 98); +insert into help_relation values (824, 99); +insert into help_relation values (825, 100); +insert into help_relation values (826, 101); +insert into help_relation values (827, 102); +insert into help_relation values (828, 103); +insert into help_relation values (828, 104); +insert into help_relation values (832, 105); +insert into help_relation values (832, 106); +unlock tables; diff --git a/scripts/galera_new_cluster.sh b/scripts/galera_new_cluster.sh new file mode 100755 index 00000000..ac9dcf42 --- /dev/null +++ b/scripts/galera_new_cluster.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +if [ "${1}" = "-h" ] || [ "${1}" = "--help" ]; then + cat <<EOF + +Usage: ${0} + + The script galera_new_cluster is used to bootstrap new Galera Cluster, + when all the nodes are down. Run galera_new_cluster on the first node only. + On the remaining nodes simply run 'service @DAEMON_NAME@ start'. + + For more information on Galera Cluster configuration and usage see: + https://mariadb.com/kb/en/mariadb/getting-started-with-mariadb-galera-cluster/ + +EOF + exit 0 +fi + +systemctl set-environment _WSREP_NEW_CLUSTER='--wsrep-new-cluster' && \ + systemctl restart ${1:-mariadb} + +extcode=$? + +systemctl set-environment _WSREP_NEW_CLUSTER='' + +exit $extcode diff --git a/scripts/galera_recovery.sh b/scripts/galera_recovery.sh new file mode 100644 index 00000000..9ff5e4e5 --- /dev/null +++ b/scripts/galera_recovery.sh @@ -0,0 +1,117 @@ +#!/bin/sh + +# Copyright (c) 2016 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 Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ + + +# This script is intended to be executed by systemd. It starts mysqld with +# --wsrep-recover to recover from a non-graceful shutdown, determines the +# last stored global transaction ID and echoes it in --wsrep-start-position=XX +# format. The output is then captured and used by systemd to start mysqld. +# If the server was configured to start without wsrep, nothing is echoed. + +cmdline_args=$@ +user="@MYSQLD_USER@" +print_defaults="@bindir@/my_print_defaults" +log_file=$(mktemp /tmp/wsrep_recovery.XXXXXX) +euid=$(id -u) +recovered_pos="" +skipped="" +start_pos="" +start_pos_opt="" +ret=0 +wsrep_on=0 + +log () +{ + local msg="$1" + # Print all messages to stderr as we reserve stdout for printing + # --wsrep-start-position=XXXX. + echo "$msg" >&2 +} + +finish() +{ + rm -f "$log_file" +} + +trap finish EXIT + +parse_arguments() { + for arg do + val=`echo "$arg" | sed -e "s;--[^=]*=;;"` + case "$arg" in + --wsrep[-_]on) wsrep_on=1 ;; + --skip[-_]wsrep[-_]on) wsrep_on=0 ;; + --wsrep[-_]on=*) + if echo $val | grep -iq '\(ON\|1\)'; then + wsrep_on=1 + else + wsrep_on=0 + fi + ;; + esac + done +} + +wsrep_recover_position() { + # Redirect server's error log to the log file. + eval @sbindir@/mariadbd $cmdline_args --user=$user --wsrep_recover \ + --disable-log-error 2> "$log_file" + ret=$? + if [ $ret -ne 0 ]; then + # Something went wrong, let us also print the error log so that it + # shows up in systemctl status output as a hint to the user. + log "WSREP: Failed to start mysqld for wsrep recovery: '`cat $log_file`'" + exit 1 + fi + + # Parse server's error log for recovered position. The server prints + # "..skipping position recovery.." if started without wsrep. + + recovered_pos="$(grep 'WSREP: Recovered position:' $log_file)" + + if [ -z "$recovered_pos" ]; then + skipped="$(grep WSREP $log_file | grep 'skipping position recovery')" + if [ -z "$skipped" ]; then + log "WSREP: Failed to recover position: '`cat $log_file`'" + exit 1 + else + log "WSREP: Position recovery skipped." + fi + else + start_pos="$(echo $recovered_pos | sed 's/.*WSREP\:\ Recovered\ position://' \ + | sed 's/^[ \t]*//')" + log "WSREP: Recovered position $start_pos" + start_pos_opt="--wsrep_start_position=$start_pos" + fi +} + +# Safety checks +if [ -n "$log_file" -a -f "$log_file" ]; then + chmod 600 $log_file +else + log "WSREP: mktemp failed" +fi + +parse_arguments `$print_defaults $cmdline_args --loose-verbose --mysqld` + +# Perform wsrep position recovery if wsrep_on=1, skip otherwise. +if [ "$wsrep_on" -eq 1 ]; then + wsrep_recover_position +fi + +echo "$start_pos_opt" + diff --git a/scripts/maria_add_gis_sp.sql.in b/scripts/maria_add_gis_sp.sql.in new file mode 100644 index 00000000..682cf52d --- /dev/null +++ b/scripts/maria_add_gis_sp.sql.in @@ -0,0 +1,37 @@ +-- Copyright (C) 2014 MariaDB Ab. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA + +# This part creates stored procedures required by the OpenGIS standards. +# script is prepared to be run with the --bootstrap server option + +SET sql_mode=''; + +@ADD_GIS_SP_SET_DELIMITER@ + +DROP PROCEDURE IF EXISTS AddGeometryColumn; +DROP PROCEDURE IF EXISTS DropGeometryColumn; + +CREATE DEFINER=`mariadb.sys`@`localhost` PROCEDURE AddGeometryColumn(catalog varchar(64), t_schema varchar(64), + t_name varchar(64), geometry_column varchar(64), t_srid int) SQL SECURITY INVOKER +begin + set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' ADD ', geometry_column,' GEOMETRY REF_SYSTEM_ID=', t_srid); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end @ADD_GIS_SP_EOL@ + +CREATE DEFINER=`mariadb.sys`@`localhost` PROCEDURE DropGeometryColumn(catalog varchar(64), t_schema varchar(64), + t_name varchar(64), geometry_column varchar(64)) SQL SECURITY INVOKER +begin + set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' DROP ', geometry_column); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end @ADD_GIS_SP_EOL@ + +@ADD_GIS_SP_RESET_DELIMITER@ + diff --git a/scripts/mariadb-service-convert b/scripts/mariadb-service-convert new file mode 100755 index 00000000..ee7af1b3 --- /dev/null +++ b/scripts/mariadb-service-convert @@ -0,0 +1,82 @@ +#!/bin/bash +# Copyright (c) 2015, Daniel Black. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA +# +# PURPOSE: +# +# Used to generate a mariadb.service file based on the current mysql/mariadb settings +# +# This is to assist distro maintainers in migrating to systemd service definations from +# a user mysqld_safe settings in the my.cnf files. +# +# Redirect output to user directory like /etc/systemd/system/mariadb.service.d/migrated-from-my.cnf-settings.conf + +tz_old=$TZ + +. /usr/bin/mariadbd-safe --dry-run + +echo "# converted using $0" +echo "#" +echo + +echo '[Service]' + +echo + + +if [[ ( ! -z "$user" && "$user" != "root" && "$user" != "mysql" ) || "${SET_USER}" == 1 ]]; then + echo User=$user +fi + + +[ -n "${open_files}" ] && echo LimitNOFILE=$open_files +[ -n "${core_file_size}" ] && echo LimitCORE=$core_file_size +[[ "${niceness}" -gt 0 ]] && echo Nice=$niceness +[ "${TZ}" != "${tz_old}" ] && echo Environment=\"TZ=${TZ}\" + +if [ -n "$mysqld_ld_preload" ]; then + new_text="$mysqld_ld_preload" + [ -n "$LD_PRELOAD" ] && new_text="$new_text $LD_PRELOAD" + echo Environment=\"LD_PRELOAD=`shell_quote_string "$new_text"`\" +fi + +if [ -n "$mysqld_ld_library_path" ]; then + new_text="$mysqld_ld_library_path" + [ -n "$LD_LIBRARY_PATH" ] && new_text="$new_text:$LD_LIBRARY_PATH" + echo Environment=\"LD_LIBRARY_PATH=`shell_quote_string "$new_text"`\" +fi + +if [[ $want_syslog -eq 1 ]]; then + echo StandardOutput=syslog + echo StandardError=syslog + echo SyslogFacility=daemon + echo SyslogLevel=err + echo SyslogIdentifier=${syslog_tag_mysqld} +fi + +if [[ "${flush_caches}" -gt 0 ]]; then + echo ExecStartPre=/usr/bin/sync + echo ExecStartPre=/usr/sbin/sysctl -q -w vm.drop_caches=3 +fi + +if [[ "${numa_interleave}" -gt 0 ]]; then + echo + echo ExecStart=/usr/bin/numactl --interleave=all ${cmd} '${MYSQLD_OPTS}' + echo +fi + +if [ -n "${CRASH_SCRIPT}" ]; then + echo FailureAction=${CRASH_SCRIPT} +fi diff --git a/scripts/msql2mysql.sh b/scripts/msql2mysql.sh new file mode 100644 index 00000000..72a609fa --- /dev/null +++ b/scripts/msql2mysql.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# Copyright (C) 1979-2007 MySQL AB +# Use is subject to license terms +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1335 USA. + +@bindir@/replace msqlConnect mysql_connect msqlListDBs mysql_list_dbs msqlNumRows mysql_num_rows msqlFetchRow mysql_fetch_row msqlFetchField mysql_fetch_field msqlFreeResult mysql_free_result msqlListFields mysql_list_fields msqlListTables mysql_list_tables msqlErrMsg 'mysql_error(mysql)' msqlStoreResult mysql_store_result msqlQuery mysql_query msqlField mysql_field msqlSelect mysql_select msqlSelectDB mysql_select_db msqlNumFields mysql_num_fields msqlClose mysql_close msqlDataSeek mysql_data_seek m_field MYSQL_FIELD m_result MYSQL_RES m_row MYSQL_ROW msql mysql mSQL mySQL MSQL MYSQL msqlCreateDB mysql_create_db msqlDropDB mysql_drop_db msqlFieldSeek mysql_field_seek -- $* diff --git a/scripts/mysql_config.pl.in b/scripts/mysql_config.pl.in new file mode 100644 index 00000000..e161d4a1 --- /dev/null +++ b/scripts/mysql_config.pl.in @@ -0,0 +1,284 @@ +#!@PERL_PATH@ +# -*- cperl -*- +# +# Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA + +############################################################################## +# +# This script reports various configuration settings that may be needed +# when using the MySQL client library. +# +# This script try to match the shell script version as close as possible, +# but in addition being compatible with ActiveState Perl on Windows. +# +# All unrecognized arguments to this script are passed to mysqld. +# +# NOTE: This script will only be used on Windows until solved how to +# handle @LIBS@ and other strings inserted that might contain +# several arguments, possibly with spaces in them. +# +# NOTE: This script was deliberately written to be as close to the shell +# script as possible, to make the maintenance of both in parallel +# easier. +# +############################################################################## + +use File::Basename; +use Getopt::Long; +use Cwd; +use strict; + +my @exclude_cflags = + qw/DDBUG_OFF DSAFE_MUTEX DUNIV_MUST_NOT_INLINE DFORCE_INIT_OF_VARS + DEXTRA_DEBUG DHAVE_valgrind O O[0-9] xO[0-9] W[-A-Za-z]* + Xa xstrconst xc99=none + unroll2 ip mp restrict/; + +my @exclude_libs = qw/lmtmalloc static-libcxa i-static static-intel/; + +my $cwd = cwd(); +my $basedir; + +my $socket = '@MYSQL_UNIX_ADDR@'; +my $version = '@VERSION@'; + +sub which +{ + my $file = shift; + + my $IFS = $^O eq "MSWin32" ? ";" : ":"; + + foreach my $dir ( split($IFS, $ENV{PATH}) ) + { + if ( -f "$dir/$file" or -f "$dir/$file.exe" ) + { + return "$dir/$file"; + } + } + print STDERR "which: no $file in ($ENV{PATH})\n"; + exit 1; +} + +# ---------------------------------------------------------------------- +# If we can find the given directory relatively to where mysql_config is +# we should use this instead of the incompiled one. +# This is to ensure that this script also works with the binary MySQL +# version +# ---------------------------------------------------------------------- + +sub fix_path +{ + my $default = shift; + my @dirs = @_; + + foreach my $dirname ( @dirs ) + { + my $path = "$basedir/$dirname"; + if ( -d $path ) + { + return $path; + } + } + return $default; +} + +sub get_full_path +{ + my $file = shift; + + # if the file is a symlink, try to resolve it + if ( $^O ne "MSWin32" and -l $file ) + { + $file = readlink($file); + } + + if ( $file =~ m,^/, ) + { + # Do nothing, absolute path + } + elsif ( $file =~ m,/, ) + { + # Make absolute, and remove "/./" in path + $file = "$cwd/$file"; + $file =~ s,/\./,/,g; + } + else + { + # Find in PATH + $file = which($file); + } + + return $file; +} + +############################################################################## +# +# Form a command line that can handle spaces in paths and arguments +# +############################################################################## + +sub quote_options { + my @cmd; + foreach my $opt ( @_ ) + { + next unless $opt; # If undefined or empty, just skip + push(@cmd, "\"$opt\""); # Quote argument + } + return join(" ", @cmd); +} + +############################################################################## +# +# Main program +# +############################################################################## + +my $me = get_full_path($0); +$basedir = dirname(dirname($me)); # Remove "/bin/mysql_config" part + +my $ldata = '@localstatedir@'; +my $execdir = '@libexecdir@'; +my $bindir = '@bindir@'; + +# ---------------------------------------------------------------------- +# If installed, search for the compiled in directory first (might be "lib64") +# ---------------------------------------------------------------------- + +my $pkglibdir = fix_path('@pkglibdir@',"libmysql/relwithdebinfo", + "libmysql/release","libmysql/debug","lib/mysql","lib"); + +my $pkgincludedir = fix_path('@pkgincludedir@', "include/mysql", "include"); + +# Assume no argument with space in it +my @ldflags = split(" ",'@LDFLAGS@'); + +my $port; +if ( '@MYSQL_TCP_PORT_DEFAULT@' == 0 ) { + $port = 0; +} else { + $port = '@MYSQL_TCP_PORT@'; +} + +# ---------------------------------------------------------------------- +# Create options +# We intentionally add a space to the beginning and end of lib strings, simplifies replace later +# ---------------------------------------------------------------------- + +my (@lib_opts,@lib_r_opts,@lib_e_opts); +if ( $^O eq "MSWin32" ) +{ + my $linkpath = "$pkglibdir"; + # user32 is only needed for debug or embedded + my @winlibs = ("wsock32.lib","advapi32.lib","user32.lib"); + @lib_opts = ("$linkpath/mysqlclient.lib",@winlibs); + @lib_r_opts = @lib_opts; + @lib_e_opts = ("$linkpath/mysqlserver.lib",@winlibs); +} +else +{ + my $linkpath = "-L$pkglibdir @RPATH_OPTION@"; + @lib_opts = ($linkpath,"-lmysqlclient"); + @lib_r_opts = ($linkpath,"-lmysqlclient_r"); + @lib_e_opts = ($linkpath,"-lmysqld"); +} + +my $flags; +$flags->{libs} = + [@ldflags,@lib_opts,'@ZLIB_DEPS@','@NON_THREADED_LIBS@','@openssl_libs@','@STATIC_NSS_FLAGS@']; +$flags->{libs_r} = + [@ldflags,@lib_r_opts,'@ZLIB_DEPS@','@LIBS@','@openssl_libs@']; +$flags->{embedded_libs} = + [@ldflags,@lib_e_opts,'@CMAKE_DL_LIBS@','@ZLIB_DEPS@','@LIBS@','@WRAPLIBS@','@openssl_libs@']; + +$flags->{include} = ["-I$pkgincludedir"]; +$flags->{cflags} = [@{$flags->{include}},split(" ",'@CFLAGS@')]; + +# ---------------------------------------------------------------------- +# Remove some options that a client doesn't have to care about +# FIXME until we have a --cxxflags, we need to remove -Xa +# and -xstrconst to make --cflags usable for Sun Forte C++ +# ---------------------------------------------------------------------- + +my $filter = join("|", @exclude_cflags); +my @tmp = @{$flags->{cflags}}; # Copy the flag list +$flags->{cflags} = []; # Clear it +foreach my $cflag ( @tmp ) +{ + push(@{$flags->{cflags}}, $cflag) unless $cflag =~ m/^($filter)$/o; +} + +# Same for --libs(_r) +$filter = join("|", @exclude_libs); +foreach my $lib_type ( "libs","libs_r","embedded_libs" ) +{ + my @tmp = @{$flags->{$lib_type}}; # Copy the flag list + $flags->{$lib_type} = []; # Clear it + foreach my $lib ( @tmp ) + { + push(@{$flags->{$lib_type}}, $lib) unless $lib =~ m/^($filter)$/o; + } +} + +my $include = quote_options(@{$flags->{include}}); +my $cflags = quote_options(@{$flags->{cflags}}); +my $libs = quote_options(@{$flags->{libs}}); +my $libs_r = quote_options(@{$flags->{libs_r}}); +my $embedded_libs = quote_options(@{$flags->{embedded_libs}}); + +############################################################################## +# +# Usage information, output if no option is given +# +############################################################################## + +sub usage +{ + print <<EOF; +Usage: $0 [OPTIONS] +Options: + --cflags [$cflags] + --include [$include] + --libs [$libs] + --libs_r [$libs_r] + --socket [$socket] + --port [$port] + --version [$version] + --libmysqld-libs [$embedded_libs] +EOF + exit 0; +} + +@ARGV or usage(); + +############################################################################## +# +# Get options and output the values +# +############################################################################## + +GetOptions( + "cflags" => sub { print "$cflags\n" }, + "include" => sub { print "$include\n" }, + "libs" => sub { print "$libs\n" }, + "libs_r" => sub { print "$libs_r\n" }, + "socket" => sub { print "$socket\n" }, + "port" => sub { print "$port\n" }, + "version" => sub { print "$version\n" }, + "embedded-libs|embedded|libmysqld-libs" => + sub { print "$embedded_libs\n" }, + ) or usage(); + +exit 0 diff --git a/scripts/mysql_config.sh b/scripts/mysql_config.sh new file mode 100644 index 00000000..8f78beee --- /dev/null +++ b/scripts/mysql_config.sh @@ -0,0 +1,169 @@ +#!/bin/sh +# Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA + +# This script reports various configuration settings that may be needed +# when using the MariaDB client library. + +# +# If we can find the given directory relatively to where mysql_config is +# we should use this instead of the incompiled one. +# This is to ensure that this script also works with the binary MariaDB +# version + +fix_path () +{ + var=$1 + shift + for filename + do + path=$basedir/$filename + if [ -d "$path" ] ; + then + eval "$var"=$path + return + fi + done +} + +get_full_path () +{ + file=$1 + + # if the file is a symlink, try to resolve it + if [ -h $file ]; + then + file=`ls -l $file | awk '{ print $NF }'` + fi + + case $file in + /*) echo "$file";; + */*) tmp=`pwd`/$file; echo $tmp | sed -e 's;/\./;/;' ;; + *) command -v $file ;; + esac +} + +me=`get_full_path $0` + +# Script might have been renamed but assume mysql_<something>config<something> +basedir=`echo $me | sed -e 's;/bin/mysql_.*config.*;;'` + +ldata='@localstatedir@' +execdir='@libexecdir@' +bindir='@bindir@' + +# If installed, search for the compiled in directory first (might be "lib64") +pkglibdir='@pkglibdir@' +pkglibdir_rel=`echo $pkglibdir | sed -e "s;^$basedir/;;"` +fix_path pkglibdir $pkglibdir_rel @libsubdir@/mysql @libsubdir@ + +plugindir='@pkgplugindir@' +plugindir_rel=`echo $plugindir | sed -e "s;^$basedir/;;"` +fix_path plugindir $plugindir_rel @libsubdir@/mysql/plugin @libsubdir@/plugin + +pkgincludedir='@pkgincludedir@' +fix_path pkgincludedir include/mysql + +version='@VERSION@' +socket='@MYSQL_UNIX_ADDR@' + +if [ @MYSQL_TCP_PORT_DEFAULT@ -eq 0 ]; then + port=0 +else + port=@MYSQL_TCP_PORT@ +fi + +# Create options +libs="-L$pkglibdir @RPATH_OPTION@ @LIBS_FOR_CLIENTS@" +embedded_libs="-L$pkglibdir @RPATH_OPTION@ @EMB_LIBS_FOR_CLIENTS@" + +include="-I$pkgincludedir" +if [ "$basedir" != "/usr" ]; then + include="$include -I$pkgincludedir/.." +fi +cflags="$include @CFLAGS_FOR_CLIENTS@" + +mariadb_config="$basedir/bin/mariadb_config" +if test -x "$basedir/bin/mariadb_config"; then + cflags=`"$mariadb_config" --cflags` + include=`"$mariadb_config" --include` + libs=`"$mariadb_config" --libs` + plugindir=`"$mariadb_config" --plugindir` + socket=`"$mariadb_config" --socket` + port=`"$mariadb_config" --port` + version=`"$mariadb_config" --version` +fi + +usage () { + cat <<EOF +Usage: $0 [OPTIONS] +Options: + --cflags [$cflags] + --include [$include] + --libs [$libs] + --libs_r [$libs] + --plugindir [$plugindir] + --socket [$socket] + --port [$port] + --version [$version] + --libmysqld-libs [$embedded_libs] + --variable=VAR VAR is one of: + pkgincludedir [$pkgincludedir] + pkglibdir [$pkglibdir] + plugindir [$plugindir] +EOF + exit $1 +} + +if test $# -le 0; then usage 0 ; fi + +while test $# -gt 0; do + case $1 in + --cflags) echo "$cflags" ;; + --include) echo "$include" ;; + --libs) echo "$libs" ;; + --libs_r) echo "$libs" ;; + --plugindir) echo "$plugindir" ;; + --socket) echo "$socket" ;; + --port) echo "$port" ;; + --version) echo "$version" ;; + --embedded-libs | --embedded | --libmysqld-libs) echo "$embedded_libs" ;; + --variable=*) + var=`echo "$1" | sed 's,^[^=]*=,,'` + case "$var" in + pkgincludedir) echo "$pkgincludedir" ;; + pkglibdir) echo "$pkglibdir" ;; + plugindir) echo "$plugindir" ;; + *) usage 1 >&2 ;; + esac + ;; + *) usage 1 >&2 ;; + esac + + shift +done + +#echo "ldata: '"$ldata"'" +#echo "execdir: '"$execdir"'" +#echo "bindir: '"$bindir"'" +#echo "pkglibdir: '"$pkglibdir"'" +#echo "pkgincludedir: '"$pkgincludedir"'" +#echo "version: '"$version"'" +#echo "socket: '"$socket"'" +#echo "port: '"$port"'" +#echo "ldflags: '"$ldflags"'" +#echo "client_libs: '"$client_libs"'" + +exit 0 diff --git a/scripts/mysql_convert_table_format.sh b/scripts/mysql_convert_table_format.sh new file mode 100644 index 00000000..6b4d758a --- /dev/null +++ b/scripts/mysql_convert_table_format.sh @@ -0,0 +1,167 @@ +#!@PERL_PATH@ +# Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA + +# Convert given tables in a database to MYISAM + +use DBI; +use Getopt::Long; + +$opt_help=$opt_version=$opt_verbose=$opt_force=0; +$opt_user=$opt_database=$opt_password=undef; +$opt_host="localhost"; +$opt_socket=""; +$opt_engine="MYISAM"; +$opt_port=0; +$exit_status=0; + +GetOptions( + "e|engine|type=s" => \$opt_engine, + "f|force" => \$opt_force, + "help|?" => \$opt_help, + "h|host=s" => \$opt_host, + "p|password=s" => \$opt_password, + "u|user=s" => \$opt_user, + "v|verbose" => \$opt_verbose, + "V|version" => \$opt_version, + "S|socket=s" => \$opt_socket, + "P|port=i" => \$opt_port +) || usage(0); + +usage($opt_version) if ($#ARGV < 0 || $opt_help || $opt_version); + +$opt_database=shift(@ARGV); + +if (grep { /^$opt_engine$/i } qw(HEAP MEMORY BLACKHOLE)) +{ + print "Converting to '$opt_engine' would delete your data; aborting\n"; + exit(1); +} + +$connect_opt=""; +if ($opt_port) +{ + $connect_opt.= ";port=$opt_port"; +} +if (length($opt_socket)) +{ + $connect_opt.=";mariadb_socket=$opt_socket"; +} + +$dbh = DBI->connect("DBI:MariaDB:$opt_database:${opt_host}$connect_opt", + $opt_user, + $opt_password, + { PrintError => 0}) + || die "Can't connect to database $opt_database: $DBI::errstr\n"; + +my @tables; + +push(@ARGV, "%") if(!@ARGV); + +foreach $pattern (@ARGV) +{ + my ($sth,$row); + $sth=$dbh->prepare("SHOW TABLES LIKE ?"); + $rv= $sth->execute($pattern); + if(!int($rv)) + { + warn "Can't get tables matching '$pattern' from $opt_database; $DBI::errstr\n"; + exit(1) unless $opt_force; + } + while (($row = $sth->fetchrow_arrayref)) + { + push(@tables, $row->[0]); + } + $sth->finish; +} + +print "Converting tables:\n" if ($opt_verbose); +foreach $table (@tables) +{ + my ($sth,$row); + + # Check if table is already converted + $sth=$dbh->prepare("show table status like '$table'"); + if ($sth->execute && ($row = $sth->fetchrow_arrayref)) + { + if (uc($row->[1]) eq uc($opt_engine)) + { + print "$table already uses the '$opt_engine' engine; Ignored\n"; + next; + } + } + print "converting $table\n" if ($opt_verbose); + $table=~ s/`/``/g; + if (!$dbh->do("ALTER TABLE `$table` ENGINE=$opt_engine")) + { + print STDERR "Can't convert $table: Error $DBI::errstr\n"; + exit(1) if (!$opt_force); + $exit_status=1; + } +} + +$dbh->disconnect; +exit($exit_status); + + +sub usage +{ + my($version)=shift; + print "$0 version 1.1\n"; + exit(0) if ($version); + + print <<EOF; + +Conversion of a MariaDB tables to other storage engines + + Usage: $0 database [table[ table ...]] + If no tables has been specifed, all tables in the database will be converted. + You can also use wildcards, ie "my%" + + The following options are available: + +-f, --force + Continue even if there is some error. + +-?, --help + Shows this help + +-e, --engine=ENGINE + Converts tables to the given storage engine (Default: $opt_engine) + +-h, --host=HOST + Host name where the database server is located. (Default: $opt_host) + +-p, --password=PASSWORD + Password for the current user. + +-P, --port=PORT + TCP/IP port to connect to if host is not "localhost". + +-S, --socket=SOCKET + Socket to connect with. + +-u, --user=USER + User name to log into the SQL server. + +-v, --verbose + This is a test specific option that is only used when debugging a test. + Print more information about what is going on. + +-V, --version + Shows the version of this program. +EOF + exit(1); +} diff --git a/scripts/mysql_find_rows.sh b/scripts/mysql_find_rows.sh new file mode 100644 index 00000000..09bcc227 --- /dev/null +++ b/scripts/mysql_find_rows.sh @@ -0,0 +1,159 @@ +#!@PERL_PATH@ +# Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA + +$version="1.02"; + +use Getopt::Long; + +$opt_help=$opt_Information=$opt_skip_use_db=0; +$opt_regexp=$opt_dbregexp=".*"; +$opt_start_row=1; $opt_rows=9999999999; + +GetOptions("Information","help","regexp=s","start_row=i","rows=i", + "dbregexp=s", "skip-use-db") + || usage(); +usage() if ($opt_help || $opt_Information); + +$query=$search=$database=$set=""; $eoq=0; +while (<>) +{ + next if (length($query) == 0 && /^\#/); # Skip comments + $query.=search($_); + if ($eoq) + { + if ($query =~ /^use /i || $query =~ /^SET / || + ($query =~ /$opt_regexp/o && $database =~ /$opt_dbregexp/o)) + { + if ($opt_skip_use_db && $query =~ /^use /i) + { + $query=""; + next; + } + if ($opt_start_row <= 1) + { + if ($database) + { + print $database, $set; + $database=$set=""; + } + print $query; + last if (--$opt_rows == 0); + } + else + { + $opt_start_row--; + if ($query =~ /^use /) + { + $database=$query; + $set=""; + } + elsif ($query =~ /^SET/) + { + $set=$query; + } + else + { + $set=""; + } + } + } + $query=""; $search=""; $eoq=0; + } +} + +exit 0; + +sub search +{ + my($row)=shift; + my($i); + + for ($i=0 ; $i < length($row) ; $i++) + { + if (length($search)) + { + if (length($search) > 1) + { # Comment + next if (substr($row,$i,length($search)) ne $search); + $i+=length($search)-1; + $search=""; + } + elsif (substr($row,$i,1) eq '\\') # Escaped char in string + { + $i++; + } + elsif (substr($row,$i,1) eq $search) + { + if (substr($row,$i+1,1) eq $search) # Double " or ' + { + $i++; + } + else + { + $search=""; + } + } + next; + } + if (substr($row,$i,2) eq '/*') # Comment + { + $search="*/"; + $i++; + } + elsif (substr($row,$i,1) eq "'" || substr($row,$i,1) eq '"') + { + $search=substr($row,$i,1); + } + } + $eoq=1 if (!length($search) && $row =~ /;\s*$/); + return $row; +} + + +sub usage +{ + print <<EOF; +$0 Ver $version + +Prints all SQL queries that matches a regexp or contains a 'use +database' or 'set ..' command to stdout. A SQL query may contain +newlines. This is useful to find things in a MariaDB update log. + +$0 takes the following options: + +--help or --Information + Shows this help + +--regexp=# + Print queries that matches this. + +--start_row=# + Start output from this row (first row = 1) + +--skip-use-db + Don\'t include \'use database\' commands in the output. + +--rows=# + Quit after this many rows. + +Example: + +$0 --regexp "problem_table" < update.log + +$0 --regexp "problem_table" update-log.1 update-log.2 +EOF + exit(0); +} diff --git a/scripts/mysql_fix_extensions.sh b/scripts/mysql_fix_extensions.sh new file mode 100644 index 00000000..c0de813e --- /dev/null +++ b/scripts/mysql_fix_extensions.sh @@ -0,0 +1,34 @@ +#!@PERL_PATH@ + +# Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1335 USA + +# This is a utility for MariaDB. It is not needed by any standard part +# of MariaDB. + +# Usage: mysql_fix_extensions datadir +# does not work with RAID, with InnoDB or BDB tables +# makes .frm lowercase and .MYI/MYD/ISM/ISD uppercase +# useful when datafiles are copied from windows + +die "Usage: $0 datadir\n" unless -d $ARGV[0]; + +for $a (<$ARGV[0]/*/*.*>) { $_=$a; + s/\.frm$/.frm/i; + s/\.(is[md]|my[id])$/\U$&/i; + rename ($a, $_) || warn "Cannot rename $a => $_ : $!"; +} diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh new file mode 100644 index 00000000..31557b60 --- /dev/null +++ b/scripts/mysql_install_db.sh @@ -0,0 +1,714 @@ +#!/bin/sh +# Copyright (c) 2000, 2013, Oracle and/or its affiliates. +# Copyright (c) 2009, 2013, Monty Program Ab +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA + +# This scripts creates the MariaDB Server system tables +# +# All unrecognized arguments to this script are passed to mariadbd. + +basedir="" +builddir="" +ldata="@localstatedir@" +langdir="" +srcdir="" + +args="" +defaults="" +defaults_group_suffix="" +mysqld_opt="" +user="" +group="" +silent_startup="--silent-startup" +log_error="" + +force=0 +in_rpm=0 +ip_only=0 +cross_bootstrap=0 +auth_root_authentication_method=socket +auth_root_socket_user="" +skip_test_db=0 +extra_file="" + +dirname0=`dirname $0 2>/dev/null` +dirname0=`dirname $dirname0 2>/dev/null` + +usage() +{ + cat <<EOF +Usage: $0 [OPTIONS] + --auth-root-authentication-method=normal|socket + Chooses the authentication method for the created + initial root user. The historical behavior is 'normal' + to creates a root user that can login without password, + which can be insecure. The default behavior 'socket' + sets an invalid root password but allows the system root + user to login as MariaDB root without a password. + --auth-root-socket-user=user + Used with --auth-root-authentication-method=socket. It + specifies the name of the second MariaDB root account, + as well as of the system account allowed to access it. + Defaults to the value of --user. + --basedir=path The path to the MariaDB installation directory. + --builddir=path If using --srcdir with out-of-directory builds, you + will need to set this to the location of the build + directory where built files reside. + --cross-bootstrap For internal use. Used when building the MariaDB system + tables on a different host than the target. + --datadir=path The path to the MariaDB data directory. + --no-defaults Don't read default options from any option file. + --defaults-extra-file=name + Read this file after the global files are read. + --defaults-file=name Only read default options from the given file name. + --defaults-group-suffix=name + In addition to the given groups, read also groups with + this suffix + --force Causes mysql_install_db to run even if DNS does not + work. In that case, grant table entries that + normally use hostnames will use IP addresses. + --help Display this help and exit. + --ldata=path The path to the MariaDB data directory. Same as + --datadir. + --rpm For internal use. This option is used by RPM files + during the MariaDB installation process. + --skip-name-resolve Use IP addresses rather than hostnames when creating + grant table entries. This option can be useful if + your DNS does not work. + --skip-test-db Don't install a test database. + --srcdir=path The path to the MariaDB source directory. This option + uses the compiled binaries and support files within the + source tree, useful for if you don't want to install + MariaDB yet and just want to create the system tables. + --user=user_name The login username to use for running mariadbd. Files + and directories created by mariadbd will be owned by this + user. You must be root to use this option. By default + mariadbd runs using your current login name and files and + directories that it creates will be owned by you. + --group=group_name The login group to use for running mariadbd. Files and + directories created by mariadbd will be owned by this + group. You must be root to use this option. By default + mariadbd runs using your current group and files and + directories that it creates will be owned by you. + --extra-file=file Add user defined SQL file, to be executed following + regular database initialization. + +All other options are passed to the mariadbd program + +EOF + exit 1 +} + +s_echo() +{ + if test "$in_rpm" -eq 0 -a "$cross_bootstrap" -eq 0 + then + echo "$1" + fi +} + +link_to_help() +{ + echo + echo "The latest information about mysql_install_db is available at" + echo "https://mariadb.com/kb/en/installing-system-tables-mysql_install_db" +} + +parse_arg() +{ + echo "$1" | sed -e 's/^[^=]*=//' +} + +parse_arguments() +{ + # We only need to pass arguments through to the server if we don't + # handle them here. So, we collect unrecognized options (passed on + # the command line) into the args variable. + pick_args= + if test "$1" = PICK-ARGS-FROM-ARGV + then + pick_args=1 + shift + fi + + for arg + do + case "$arg" in + --force) force=1 ;; + --basedir=*) basedir=`parse_arg "$arg"` ;; + --builddir=*) builddir=`parse_arg "$arg"` ;; + --srcdir=*) srcdir=`parse_arg "$arg"` ;; + --ldata=*|--datadir=*|--data=*) ldata=`parse_arg "$arg"` ;; + --log[-_]error=*) + # Keep in the arguments passed to the server + args="$args $arg" + log_error=`parse_arg "$arg"` ;; + # Note that the user will be passed to mariadbd so that it runs + # as 'user' (crucial e.g. if log-bin=/some_other_path/ + # where a chown of datadir won't help) + --user=*) user=`parse_arg "$arg"` ;; + --group=*) group=`parse_arg "$arg"` ;; + --skip-name-resolve) ip_only=1 ;; + --verbose) verbose=1 ; silent_startup="" ;; + --rpm) in_rpm=1 ;; + --help) usage ;; + --no-defaults|--defaults-file=*|--defaults-extra-file=*) + defaults="$arg" ;; + --defaults-group-suffix=*) + defaults_group_suffix="$arg" ;; + + --cross-bootstrap|--windows) + # Used when building the MariaDB system tables on a different host than + # the target. The platform-independent files that are created in + # --datadir on the host can be copied to the target system. + # + # The most common use for this feature is in the Windows installer + # which will take the files from datadir and include them as part of + # the install package. See top-level 'dist-hook' make target. + # + # --windows is a deprecated alias + cross_bootstrap=1 ;; + --auth-root-authentication-method=normal) + auth_root_authentication_method=normal ;; + --auth-root-authentication-method=socket) + auth_root_authentication_method=socket ;; + --auth-root-authentication-method=*) + usage ;; + --auth-root-socket-user=*) + auth_root_socket_user="$(parse_arg "$arg")" ;; + --skip-test-db) skip_test_db=1 ;; + --extra-file=*) + extra_file="$(parse_arg "$arg")" ;; + + *) + if test -n "$pick_args" + then + # This sed command makes sure that any special chars are quoted, + # so the arg gets passed exactly to the server. + # XXX: This is broken; true fix requires using eval and proper + # quoting of every single arg ($basedir, $ldata, etc.) + #args="$args "`echo "$arg" | sed -e 's,\([^a-zA-Z0-9_.-]\),\\\\\1,g'` + args="$args $arg" + fi + ;; + esac + done +} + +# Try to find a specific file within --basedir which can either be a binary +# release or installed source directory and return the path. +find_in_dirs() +{ + case "$1" in + --dir) + return_dir=1; shift + ;; + esac + + file=$1; shift + + for dir in "$@" + do + if test -f "$dir/$file" + then + if test -n "$return_dir" + then + echo "$dir" + else + echo "$dir/$file" + fi + break + fi + done +} + +cannot_find_file() +{ + echo + echo "FATAL ERROR: Could not find $1" + + shift + if test $# -ne 0 + then + echo + echo "The following directories were searched:" + echo + for dir in "$@" + do + echo " $dir" + done + fi + + echo + echo "If you compiled from source, you need to either run 'make install' to" + echo "copy the software into the correct location ready for operation." + echo "If you don't want to do a full install, you can use the --srcdir" + echo "option to only install the mysql database and privilege tables." + echo + echo "If you are using a binary release, you must either be at the top" + echo "level of the extracted archive, or pass the --basedir option" + echo "pointing to that location." + link_to_help +} + +# Ok, let's go. We first need to parse arguments which are required by +# my_print_defaults so that we can execute it first, then later re-parse +# the command line to add any extra bits that we need. +parse_arguments "$@" + +# +# We can now find my_print_defaults. This script supports: +# +# --srcdir=path pointing to compiled source tree +# --basedir=path pointing to installed binary location +# +# or default to compiled-in locations. +# +if test -n "$srcdir" && test -n "$basedir" +then + echo "ERROR: Specify either --basedir or --srcdir, not both." + link_to_help + exit 1 +fi +if test -n "$srcdir" +then + # In an out-of-source build, builddir is not srcdir. Try to guess where + # builddir is by looking for my_print_defaults. + if test -z "$builddir" + then + if test -x "$dirname0/extra/my_print_defaults" + then + builddir="$dirname0" + else + builddir="$srcdir" + fi + fi + print_defaults="$builddir/extra/my_print_defaults" +elif test -n "$basedir" +then + print_defaults=`find_in_dirs my_print_defaults $basedir/bin $basedir/extra` + if test -z "$print_defaults" + then + cannot_find_file my_print_defaults $basedir/bin $basedir/extra + exit 1 + fi +elif test -n "$dirname0" -a -x "$dirname0/@bindir@/my_print_defaults" +then + print_defaults="$dirname0/@bindir@/my_print_defaults" +elif test -x "./extra/my_print_defaults" +then + srcdir="." + builddir="." + print_defaults="./extra/my_print_defaults" +else + print_defaults="@bindir@/my_print_defaults" +fi + +if test ! -x "$print_defaults" +then + cannot_find_file "$print_defaults" + exit 1 +fi + +# Now we can get arguments from the groups [mariadbd] and [mysql_install_db] +# in the my.cfg file, then re-run to merge with command line arguments. +parse_arguments `"$print_defaults" $defaults $defaults_group_suffix --mariadbd mysql_install_db mariadb-install-db` + +parse_arguments PICK-ARGS-FROM-ARGV "$@" + +rel_mysqld="$dirname0/@INSTALL_SBINDIR@/mariadbd" + +# Configure paths to support files +if test -n "$srcdir" +then + basedir="$builddir" + bindir="$basedir/client" + resolveip="$basedir/extra/resolveip" + mysqld="$basedir/sql/mariadbd" + langdir="$basedir/sql/share/english" + srcpkgdatadir="$srcdir/scripts" + buildpkgdatadir="$builddir/scripts" + plugindir="$builddir/plugin/auth_socket" + pamtooldir="$builddir/plugin/auth_pam" +elif test -n "$basedir" +then + bindir="$basedir/bin" # only used in the help text + resolveip=`find_in_dirs resolveip @resolveip_locations@` + if test -z "$resolveip" + then + cannot_find_file resolveip @resolveip_locations@ + exit 1 + fi + mysqld=`find_in_dirs mariadbd @mysqld_locations@` + if test -z "$mysqld" + then + cannot_find_file mariadbd @mysqld_locations@ + exit 1 + fi + langdir=`find_in_dirs --dir errmsg.sys @errmsg_locations@` + if test -z "$langdir" + then + cannot_find_file errmsg.sys @errmsg_locations@ + exit 1 + fi + srcpkgdatadir=`find_in_dirs --dir fill_help_tables.sql @pkgdata_locations@` + buildpkgdatadir=$srcpkgdatadir + if test -z "$srcpkgdatadir" + then + cannot_find_file fill_help_tables.sql @pkgdata_locations@ + exit 1 + fi + plugindir=`find_in_dirs --dir auth_pam.so $basedir/lib*/plugin $basedir/lib*/mysql/plugin $basedir/lib/*/mariadb19/plugin` + pamtooldir=$plugindir +# relative from where the script was run for a relocatable install +elif test -n "$dirname0" -a -x "$rel_mysqld" -a ! "$rel_mysqld" -ef "@sbindir@/mariadbd" +then + basedir="$dirname0" + bindir="$basedir/@INSTALL_BINDIR@" + resolveip="$bindir/resolveip" + mysqld="$rel_mysqld" + srcpkgdatadir="$basedir/@INSTALL_MYSQLSHAREDIR@" + buildpkgdatadir="$basedir/@INSTALL_MYSQLSHAREDIR@" + plugindir="$basedir/@INSTALL_PLUGINDIR@" + pamtooldir=$plugindir +else + basedir="@prefix@" + bindir="@bindir@" + resolveip="$bindir/resolveip" + mysqld="@sbindir@/mariadbd" + srcpkgdatadir="@pkgdatadir@" + buildpkgdatadir="@pkgdatadir@" + plugindir="@pkgplugindir@" + pamtooldir="@pkgplugindir@" +fi + +# Set up paths to SQL scripts required for bootstrap +fill_help_tables="$srcpkgdatadir/fill_help_tables.sql" +create_system_tables="$srcpkgdatadir/mysql_system_tables.sql" +create_system_tables2="$srcpkgdatadir/mysql_performance_tables.sql" +fill_system_tables="$srcpkgdatadir/mysql_system_tables_data.sql" +maria_add_gis_sp="$buildpkgdatadir/maria_add_gis_sp_bootstrap.sql" +mysql_test_db="$srcpkgdatadir/mysql_test_db.sql" +mysql_sys_schema="$buildpkgdatadir/mysql_sys_schema.sql" + +for f in "$fill_help_tables" "$create_system_tables" "$create_system_tables2" "$fill_system_tables" "$maria_add_gis_sp" "$mysql_test_db" "$mysql_sys_schema" +do + if test ! -f "$f" + then + cannot_find_file "$f" + exit 1 + fi +done + +# Verify extra file exists if it's not null +if test ! -z "$extra_file" -a ! -f "$extra_file" +then + cannot_find_file "$extra_file" + exit 1 +fi + +if test ! -x "$mysqld" +then + cannot_find_file "$mysqld" + exit 1 +fi + +if test -n "$langdir" +then + if test ! -f "$langdir/errmsg.sys" + then + cannot_find_file "$langdir/errmsg.sys" + exit 1 + fi + mysqld_opt="--lc-messages-dir=$langdir/.." +else + mysqld_opt="--lc-messages=en_US" +fi + + +# Try to determine the hostname +hostname=`@HOSTNAME@` + +# Check if hostname is valid +if test "$cross_bootstrap" -eq 0 -a "$in_rpm" -eq 0 -a "$force" -eq 0 +then + resolved=`"$resolveip" $hostname 2>&1` + if test $? -ne 0 + then + resolved=`"$resolveip" localhost 2>&1` + if test $? -ne 0 + then + echo "Neither host '$hostname' nor 'localhost' could be looked up with" + echo "'$resolveip'" + echo "Please configure the 'hostname' command to return a correct" + echo "hostname." + echo "If you want to solve this at a later stage, restart this script" + echo "with the --force option" + link_to_help + exit 1 + fi + echo "WARNING: The host '$hostname' could not be looked up with $resolveip." + echo "This probably means that your libc libraries are not 100 % compatible" + echo "with this binary MariaDB version. The MariaDB daemon, mariadbd, should work" + echo "normally with the exception that host name resolving will not work." + echo "This means that you should use IP addresses instead of hostnames" + echo "when specifying MariaDB privileges !" + fi +fi + +if test "$ip_only" -eq 1 +then + hostname=`echo "$resolved" | awk '/ /{print $6}'` +fi + +# Create database directories +for dir in "$ldata" +do + if test ! -d "$dir" + then + if ! `mkdir -p "$dir"` + then + echo "Fatal error Can't create database directory '$dir'" + link_to_help + exit 1 + fi + chmod 700 "$dir" + fi + if test -n "$user" + then + if test -z "$group" + then + chown $user $dir + else + chown $user:$group $dir + fi + if test $? -ne 0 + then + echo "Cannot change ownership of the database directories to the '$user'" + echo "user. Check that you have the necessary permissions and try again." + exit 1 + fi + fi +done + +if test -n "$user" +then + if test -z "$srcdir" -a "$in_rpm" -eq 0 -a -d "$pamtooldir/auth_pam_tool_dir" + then + chown 0 "$pamtooldir/auth_pam_tool_dir/auth_pam_tool" && \ + chmod 04755 "$pamtooldir/auth_pam_tool_dir/auth_pam_tool" + if test $? -ne 0 + then + echo "Couldn't set an owner to '$pamtooldir/auth_pam_tool_dir/auth_pam_tool'." + echo "It must be root, the PAM authentication plugin doesn't work otherwise.." + echo + fi + chown $user "$pamtooldir/auth_pam_tool_dir" && \ + chmod 0700 "$pamtooldir/auth_pam_tool_dir" + if test $? -ne 0 + then + echo "Cannot change ownership of the '$pamtooldir/auth_pam_tool_dir' directory" + echo "to the '$user' user. Check that you have the necessary permissions and try again." + echo + fi + fi + args="$args --user=$user" +fi + +#To be enabled if/when we enable --group as an option to mariadbd +#if test -n "$group" +#then +# args="$args --group=$group" +#fi + +if test -f "$ldata/mysql/user.frm" +then + echo "mysql.user table already exists!" + echo "Run mysql_upgrade, not mysql_install_db" + exit 0 +fi + +# When doing a "cross bootstrap" install, no reference to the current +# host should be added to the system tables. So we filter out any +# lines which contain the current host name. +if test $cross_bootstrap -eq 1 +then + filter_cmd_line="sed -e '/@current_hostname/d'" +else + filter_cmd_line="cat" +fi + +# Disable log error if the user don't have right to write/create the file +# This is common when a user tries to install a personal mariadbd server and +# the global config in /etc is using --log-error. +# The server will internally change log-error to stderr to stderr if it cannot +# write the the log file. This code only disables the error message from a not +# writable log-error, which can be confusing. +if test -n "$log_error" +then + if test \( -e "$log_error" -a \! -w "$log_error" \) -o \( ! -e "$log_error" -a ! -w "`dirname "$log_error"`" \) + then + if test -n "$verbose" + then + echo "resetting log-error '$log_error' because no write access" + fi + log_error="" + args="$args --skip-log-error" + fi +fi + +# Configure mariadbd command line +mysqld_bootstrap="${MYSQLD_BOOTSTRAP-$mysqld}" +mysqld_install_cmd_line() +{ + "$mysqld_bootstrap" $defaults $defaults_group_suffix "$mysqld_opt" --bootstrap $silent_startup\ + "--basedir=$basedir" "--datadir=$ldata" --log-warnings=0 --enforce-storage-engine="" \ + "--plugin-dir=${plugindir}" \ + $args --max_allowed_packet=8M \ + --net_buffer_length=16K +} + +# Use $auth_root_socket_user if explicitly specified. +# Otherwise use the owner of datadir - ${user:-$USER} +# Use 'root' as a fallback +auth_root_socket_user=${auth_root_socket_user:-${user:-${USER:-root}}} + +cat_sql() +{ + echo "create database if not exists mysql;" + echo "use mysql;" + + case "$auth_root_authentication_method" in + normal) + echo "SET @auth_root_socket=NULL;" + ;; + socket) + echo "SET @auth_root_socket='$auth_root_socket_user';" + ;; + esac + + cat "$create_system_tables" "$create_system_tables2" "$fill_system_tables" "$fill_help_tables" "$maria_add_gis_sp" "$mysql_sys_schema" + if test "$skip_test_db" -eq 0 + then + cat "$mysql_test_db" + fi + + # cat extra file if it's not null + if test ! -z "$extra_file" + then + cat "$extra_file" + fi +} + +# Create the system and help tables by passing them to "mariadbd --bootstrap" +s_echo "Installing MariaDB/MySQL system tables in '$ldata' ..." +if cat_sql | eval "$filter_cmd_line" | mysqld_install_cmd_line > /dev/null +then + printf "@VERSION@-MariaDB" > "$ldata/mysql_upgrade_info" + s_echo "OK" +else + log_file_place=$ldata + if test -n "$log_error" + then + log_file_place="$log_error or $log_file_place" + fi + echo + echo "Installation of system tables failed! Examine the logs in" + echo "$log_file_place for more information." + echo + echo "The problem could be conflicting information in an external" + echo "my.cnf files. You can ignore these by doing:" + echo + echo " shell> $0 --defaults-file=~/.my.cnf" + echo + echo "You can also try to start the mariadbd daemon with:" + echo + echo " shell> $mysqld --skip-grant-tables --general-log &" + echo + echo "and use the command line tool $bindir/mariadb" + echo "to connect to the mysql database and look at the grant tables:" + echo + echo " shell> $bindir/mariadb -u root mysql" + echo " MariaDB> show tables;" + echo + echo "Try '$mysqld --help' if you have problems with paths. Using" + echo "--general-log gives you a log in $ldata that may be helpful." + link_to_help + echo "You can find the latest source at https://downloads.mariadb.org and" + echo "the maria-discuss email list at https://launchpad.net/~maria-discuss" + echo + echo "Please check all of the above before submitting a bug report" + echo "at https://mariadb.org/jira" + echo + exit 1 +fi + +# Don't output verbose information if running inside bootstrap or using +# --srcdir for testing. In such cases, there's no end user looking at +# the screen. +if test "$cross_bootstrap" -eq 0 && test -z "$srcdir" +then + s_echo + s_echo "To start mariadbd at boot time you have to copy" + s_echo "support-files/mariadb.service to the right place for your system" + + if test "$auth_root_authentication_method" = normal + then + echo + echo + echo "PLEASE REMEMBER TO SET A PASSWORD FOR THE MariaDB root USER !" + echo "To do so, start the server, then issue the following command:" + echo + echo "'$bindir/mariadb-secure-installation'" + echo + echo "which will also give you the option of removing the test" + echo "databases and anonymous user created by default. This is" + echo "strongly recommended for production servers." + else + echo + echo + echo "Two all-privilege accounts were created." + echo "One is root@localhost, it has no password, but you need to" + echo "be system 'root' user to connect. Use, for example, sudo mysql" + echo "The second is $auth_root_socket_user@localhost, it has no password either, but" + echo "you need to be the system '$auth_root_socket_user' user to connect." + echo "After connecting you can set the password, if you would need to be" + echo "able to connect as any of these users with a password and without sudo" + fi + + echo + echo "See the MariaDB Knowledgebase at https://mariadb.com/kb" + + if test "$in_rpm" -eq 0 + then + echo + echo "You can start the MariaDB daemon with:" + echo "cd '$basedir' ; $bindir/mariadb-safe --datadir='$ldata'" + echo + echo "You can test the MariaDB daemon with mysql-test-run.pl" + echo "cd '$basedir/@INSTALL_MYSQLTESTDIR@' ; perl mariadb-test-run.pl" + fi + + echo + echo "Please report any problems at https://mariadb.org/jira" + echo + echo "The latest information about MariaDB is available at https://mariadb.org/." + echo + echo "Consider joining MariaDB's strong and vibrant community:" + echo "https://mariadb.org/get-involved/" + echo +fi + +exit 0 diff --git a/scripts/mysql_performance_tables.sql b/scripts/mysql_performance_tables.sql new file mode 100644 index 00000000..3a7d0ef5 --- /dev/null +++ b/scripts/mysql_performance_tables.sql @@ -0,0 +1,55 @@ +-- +-- PERFORMANCE SCHEMA INSTALLATION +-- Note that this script is also reused by mysql_upgrade, +-- so we have to be very careful here to not destroy any +-- existing database named 'performance_schema' if it +-- can contain user data. +-- In case of downgrade, it's ok to drop unknown tables +-- from a future version, as long as they belong to the +-- performance schema engine. +-- + +set @have_old_pfs= (select count(*) from information_schema.schemata where schema_name='performance_schema'); + +SET @cmd="SET @broken_tables = (select count(*) from information_schema.tables where engine != 'PERFORMANCE_SCHEMA' and table_schema='performance_schema')"; + +-- Work around for bug#49542 +SET @str = IF(@have_old_pfs = 1, @cmd, 'SET @broken_tables = 0'); +PREPARE stmt FROM @str; +EXECUTE stmt; +DROP PREPARE stmt; + +SET @cmd="SET @broken_views = (select count(*) from information_schema.views where table_schema='performance_schema')"; + +-- Work around for bug#49542 +SET @str = IF(@have_old_pfs = 1, @cmd, 'SET @broken_views = 0'); +PREPARE stmt FROM @str; +EXECUTE stmt; +DROP PREPARE stmt; + +SET @broken_routines = (select count(*) from mysql.proc where db='performance_schema'); + +SET @broken_events = (select count(*) from mysql.event where db='performance_schema'); + +SET @broken_pfs= (select @broken_tables + @broken_views + @broken_routines + @broken_events); + +-- +-- The performance schema database. +-- Only drop and create the database if this is safe (no broken_pfs). +-- This database is created, even in --without-perfschema builds, +-- so that the database name is always reserved by the MySQL implementation. +-- + +SET @cmd= "DROP DATABASE IF EXISTS performance_schema"; + +SET @str = IF(@broken_pfs = 0, @cmd, 'SET @dummy = 0'); +PREPARE stmt FROM @str; +EXECUTE stmt; +DROP PREPARE stmt; + +SET @cmd= "CREATE DATABASE performance_schema character set utf8mb3"; + +SET @str = IF(@broken_pfs = 0, @cmd, 'SET @dummy = 0'); +PREPARE stmt FROM @str; +EXECUTE stmt; +DROP PREPARE stmt; diff --git a/scripts/mysql_secure_installation.sh b/scripts/mysql_secure_installation.sh new file mode 100644 index 00000000..40d8e5d3 --- /dev/null +++ b/scripts/mysql_secure_installation.sh @@ -0,0 +1,577 @@ +#!/bin/sh + +# Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA + +config=".my.cnf.$$" +command=".mysql.$$" +output=".my.output.$$" + +trap "interrupt" 1 2 3 6 15 + +rootpass="" +echo_n= +echo_c= +basedir= +defaults_file= +defaults_extra_file= +no_defaults= + +parse_arg() +{ + echo "$1" | sed -e 's/^[^=]*=//' +} + +parse_arguments() +{ + # We only need to pass arguments through to the server if we don't + # handle them here. So, we collect unrecognized options (passed on + # the command line) into the args variable. + pick_args= + if test "$1" = PICK-ARGS-FROM-ARGV + then + pick_args=1 + shift + fi + + for arg + do + case "$arg" in + --basedir=*) basedir=`parse_arg "$arg"` ;; + --defaults-file=*) defaults_file="$arg" ;; + --defaults-extra-file=*) defaults_extra_file="$arg" ;; + --no-defaults) no_defaults="$arg" ;; + *) + if test -n "$pick_args" + then + # This sed command makes sure that any special chars are quoted, + # so the arg gets passed exactly to the server. + # XXX: This is broken; true fix requires using eval and proper + # quoting of every single arg ($basedir, $ldata, etc.) + #args="$args "`echo "$arg" | sed -e 's,\([^a-zA-Z0-9_.-]\),\\\\\1,g'` + args="$args $arg" + fi + ;; + esac + done +} + +# Try to find a specific file within --basedir which can either be a binary +# release or installed source directory and return the path. +find_in_basedir() +{ + return_dir=0 + found=0 + case "$1" in + --dir) + return_dir=1; shift + ;; + esac + + file=$1; shift + + for dir in "$@" + do + if test -f "$basedir/$dir/$file" + then + found=1 + if test $return_dir -eq 1 + then + echo "$basedir/$dir" + else + echo "$basedir/$dir/$file" + fi + break + fi + done + + if test $found -eq 0 + then + # Test if command is in PATH + $file --no-defaults --version > /dev/null 2>&1 + status=$? + if test $status -eq 0 + then + echo $file + fi + fi +} + +cannot_find_file() +{ + echo + echo "FATAL ERROR: Could not find $1" + + shift + if test $# -ne 0 + then + echo + echo "The following directories were searched:" + echo + for dir in "$@" + do + echo " $dir" + done + fi + + echo + echo "If you compiled from source, you need to run 'make install' to" + echo "copy the software into the correct location ready for operation." + echo + echo "If you are using a binary release, you must either be at the top" + echo "level of the extracted archive, or pass the --basedir option" + echo "pointing to that location." + echo +} + +# Ok, let's go. We first need to parse arguments which are required by +# my_print_defaults so that we can execute it first, then later re-parse +# the command line to add any extra bits that we need. +parse_arguments PICK-ARGS-FROM-ARGV "$@" + +# +# We can now find my_print_defaults. This script supports: +# +# --srcdir=path pointing to compiled source tree +# --basedir=path pointing to installed binary location +# +# or default to compiled-in locations. +# + +if test -n "$basedir" +then + print_defaults=`find_in_basedir my_print_defaults bin extra` + echo "print: $print_defaults" + if test -z "$print_defaults" + then + cannot_find_file my_print_defaults $basedir/bin $basedir/extra + exit 1 + fi + mysql_command=`find_in_basedir mariadb bin` + if test -z "$mysql_command" + then + cannot_find_file mariadb $basedir/bin + exit 1 + fi +else + print_defaults="@bindir@/my_print_defaults" + mysql_command="@bindir@/mariadb" +fi + +if test ! -x "$print_defaults" +then + cannot_find_file "$print_defaults" + exit 1 +fi + +if test ! -x "$mysql_command" +then + cannot_find_file "$mysql_command" + exit 1 +fi + +# Now we can get arguments from the group [client] and [client-server] +# in the my.cfg file, then re-run to merge with command line arguments. +parse_arguments `$print_defaults $defaults_file $defaults_extra_file $no_defaults client client-server client-mariadb` +parse_arguments PICK-ARGS-FROM-ARGV "$@" + +set_echo_compat() { + case `echo "testing\c"`,`echo -n testing` in + *c*,-n*) echo_n= echo_c= ;; + *c*,*) echo_n=-n echo_c= ;; + *) echo_n= echo_c='\c' ;; + esac +} + +validate_reply () { + ret=0 + if [ -z "$1" ]; then + reply=y + return $ret + fi + case $1 in + y|Y|yes|Yes|YES) reply=y ;; + n|N|no|No|NO) reply=n ;; + *) ret=1 ;; + esac + return $ret +} + +prepare() { + touch $config $command + chmod 600 $config $command +} + +do_query() { + echo "$1" >$command + #sed 's,^,> ,' < $command # Debugging + $mysql_command --defaults-file=$config $defaults_extra_file $no_defaults $args <$command >$output + return $? +} + +# Simple escape mechanism (\-escape any ' and \), suitable for two contexts: +# - single-quoted SQL strings +# - single-quoted option values on the right hand side of = in my.cnf +# +# These two contexts don't handle escapes identically. SQL strings allow +# quoting any character (\C => C, for any C), but my.cnf parsing allows +# quoting only \, ' or ". For example, password='a\b' quotes a 3-character +# string in my.cnf, but a 2-character string in SQL. +# +# This simple escape works correctly in both places. +basic_single_escape () { + # The quoting on this sed command is a bit complex. Single-quoted strings + # don't allow *any* escape mechanism, so they cannot contain a single + # quote. The string sed gets (as argv[1]) is: s/\(['\]\)/\\\1/g + # + # Inside a character class, \ and ' are not special, so the ['\] character + # class is balanced and contains two characters. + echo "$1" | sed 's/\(['"'"'\]\)/\\\1/g' +} + +# +# create a simple my.cnf file to be able to pass the root password to the mysql +# client without putting it on the command line +# +make_config() { + echo "# mysql_secure_installation config file" >$config + echo "[mysql]" >>$config + echo "user=root" >>$config + esc_pass=`basic_single_escape "$rootpass"` + echo "password='$esc_pass'" >>$config + #sed 's,^,> ,' < $config # Debugging + + if test -n "$defaults_file" + then + dfile=`parse_arg "$defaults_file"` + cat "$dfile" >>$config + fi +} + +get_root_password() { + status=1 + while [ $status -eq 1 ]; do + stty -echo + echo $echo_n "Enter current password for root (enter for none): $echo_c" + read password + echo + stty echo + if [ "x$password" = "x" ]; then + emptypass=1 + else + emptypass=0 + fi + rootpass=$password + make_config + do_query "show create user root@localhost" + status=$? + done + if grep -q unix_socket $output; then + emptypass=0 + fi + echo "OK, successfully used password, moving on..." + echo +} + +set_root_password() { + stty -echo + echo $echo_n "New password: $echo_c" + read password1 + echo + echo $echo_n "Re-enter new password: $echo_c" + read password2 + echo + stty echo + + if [ "$password1" != "$password2" ]; then + echo "Sorry, passwords do not match." + echo + return 1 + fi + + if [ "$password1" = "" ]; then + echo "Sorry, you can't use an empty password here." + echo + return 1 + fi + + esc_pass=`basic_single_escape "$password1"` + do_query "UPDATE mysql.global_priv SET priv=json_set(priv, '$.plugin', 'mysql_native_password', '$.authentication_string', PASSWORD('$esc_pass')) WHERE User='root';" + if [ $? -eq 0 ]; then + echo "Password updated successfully!" + echo "Reloading privilege tables.." + reload_privilege_tables + if [ $? -eq 1 ]; then + clean_and_exit + fi + echo + rootpass=$password1 + make_config + else + echo "Password update failed!" + clean_and_exit + fi + + return 0 +} + +remove_anonymous_users() { + do_query "DELETE FROM mysql.global_priv WHERE User='';" + if [ $? -eq 0 ]; then + echo " ... Success!" + else + echo " ... Failed!" + clean_and_exit + fi + + return 0 +} + +remove_remote_root() { + do_query "DELETE FROM mysql.global_priv WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');" + if [ $? -eq 0 ]; then + echo " ... Success!" + else + echo " ... Failed!" + fi +} + +remove_test_database() { + echo " - Dropping test database..." + do_query "DROP DATABASE IF EXISTS test;" + if [ $? -eq 0 ]; then + echo " ... Success!" + else + echo " ... Failed! Not critical, keep moving..." + fi + + echo " - Removing privileges on test database..." + do_query "DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'" + if [ $? -eq 0 ]; then + echo " ... Success!" + else + echo " ... Failed! Not critical, keep moving..." + fi + + return 0 +} + +reload_privilege_tables() { + do_query "FLUSH PRIVILEGES;" + if [ $? -eq 0 ]; then + echo " ... Success!" + return 0 + else + echo " ... Failed!" + return 1 + fi +} + +interrupt() { + echo + echo "Aborting!" + echo + cleanup + stty echo + exit 1 +} + +cleanup() { + echo "Cleaning up..." + rm -f $config $command $output +} + +# Remove the files before exiting. +clean_and_exit() { + cleanup + exit 1 +} + +# The actual script starts here + +prepare +set_echo_compat + +echo +echo "NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB" +echo " SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!" +echo +echo "In order to log into MariaDB to secure it, we'll need the current" +echo "password for the root user. If you've just installed MariaDB, and" +echo "haven't set the root password yet, you should just press enter here." +echo + +get_root_password + + +# +# Set the root password +# + +echo "Setting the root password or using the unix_socket ensures that nobody" +echo "can log into the MariaDB root user without the proper authorisation." +echo + +while true ; do + if [ $emptypass -eq 1 ]; then + echo $echo_n "Enable unix_socket authentication? [Y/n] $echo_c" + else + echo "You already have your root account protected, so you can safely answer 'n'." + echo + echo $echo_n "Switch to unix_socket authentication [Y/n] $echo_c" + fi + read reply + validate_reply $reply && break +done + +if [ "$reply" = "n" ]; then + echo " ... skipping." +else + emptypass=0 + do_query "UPDATE mysql.global_priv SET priv=json_set(priv, '$.password_last_changed', UNIX_TIMESTAMP(), '$.plugin', 'mysql_native_password', '$.authentication_string', 'invalid', '$.auth_or', json_array(json_object(), json_object('plugin', 'unix_socket'))) WHERE User='root';" + if [ $? -eq 0 ]; then + echo "Enabled successfully!" + echo "Reloading privilege tables.." + reload_privilege_tables + if [ $? -eq 1 ]; then + clean_and_exit + fi + echo + else + echo "Failed!" + clean_and_exit + fi +fi +echo + +while true ; do + if [ $emptypass -eq 1 ]; then + echo $echo_n "Set root password? [Y/n] $echo_c" + else + echo "You already have your root account protected, so you can safely answer 'n'." + echo + echo $echo_n "Change the root password? [Y/n] $echo_c" + fi + read reply + validate_reply $reply && break +done + +if [ "$reply" = "n" ]; then + echo " ... skipping." +else + status=1 + while [ $status -eq 1 ]; do + set_root_password + status=$? + done +fi +echo + + +# +# Remove anonymous users +# + +echo "By default, a MariaDB installation has an anonymous user, allowing anyone" +echo "to log into MariaDB without having to have a user account created for" +echo "them. This is intended only for testing, and to make the installation" +echo "go a bit smoother. You should remove them before moving into a" +echo "production environment." +echo + +while true ; do + echo $echo_n "Remove anonymous users? [Y/n] $echo_c" + read reply + validate_reply $reply && break +done +if [ "$reply" = "n" ]; then + echo " ... skipping." +else + remove_anonymous_users +fi +echo + + +# +# Disallow remote root login +# + +echo "Normally, root should only be allowed to connect from 'localhost'. This" +echo "ensures that someone cannot guess at the root password from the network." +echo +while true ; do + echo $echo_n "Disallow root login remotely? [Y/n] $echo_c" + read reply + validate_reply $reply && break +done +if [ "$reply" = "n" ]; then + echo " ... skipping." +else + remove_remote_root +fi +echo + + +# +# Remove test database +# + +echo "By default, MariaDB comes with a database named 'test' that anyone can" +echo "access. This is also intended only for testing, and should be removed" +echo "before moving into a production environment." +echo + +while true ; do + echo $echo_n "Remove test database and access to it? [Y/n] $echo_c" + read reply + validate_reply $reply && break +done + +if [ "$reply" = "n" ]; then + echo " ... skipping." +else + remove_test_database +fi +echo + + +# +# Reload privilege tables +# + +echo "Reloading the privilege tables will ensure that all changes made so far" +echo "will take effect immediately." +echo + +while true ; do + echo $echo_n "Reload privilege tables now? [Y/n] $echo_c" + read reply + validate_reply $reply && break +done + +if [ "$reply" = "n" ]; then + echo " ... skipping." +else + reload_privilege_tables +fi +echo + +cleanup + +echo +echo "All done! If you've completed all of the above steps, your MariaDB" +echo "installation should now be secure." +echo +echo "Thanks for using MariaDB!" diff --git a/scripts/mysql_setpermission.sh b/scripts/mysql_setpermission.sh new file mode 100644 index 00000000..b3c9c27c --- /dev/null +++ b/scripts/mysql_setpermission.sh @@ -0,0 +1,706 @@ +#!@PERL_PATH@ +## Emacs, this is -*- perl -*- mode? :-) + +# Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1335 USA + +## +## Permission setter for MySQL +## +## mady by Luuk de Boer (luuk@wxs.nl) 1998. +## it's made under GPL ...:-)) +## +## +############################################################################ +## History +## +## 1.0 first start of the program +## 1.1 some changes from monty and after that +## initial release in mysql 3.22.10 (nov 1998) +## 1.2 begin screen now in a loop + quit is using 0 instead of 9 +## after ideas of Paul DuBois. +## 1.2a Add Grant, References, Index and Alter privilege handling (Monty) +## 1.3 Applied patch provided by Martin Mokrejs <mmokrejs@natur.cuni.cz> +## (General code cleanup, use the GRANT statement instead of updating +## the privilege tables directly, added option to revoke privileges) +## 1.4 Remove option 6 which attempted to erroneously grant global privileges + +#### TODO +# +# empty ... suggestions ... mail them to me ... + + +$version="1.4"; + +use DBI; +use Getopt::Long; +use strict; +use vars qw($dbh $sth $hostname $opt_user $opt_password $opt_help $opt_host + $opt_socket $opt_port $host $version); + +my $sqlhost = ""; +my $user = ""; + +$dbh=$host=$opt_user= $opt_password= $opt_help= $opt_host= $opt_socket= ""; +$opt_port=3306; + +read_my_cnf(); # Read options from ~/.my.cnf + +GetOptions("user=s","password=s","help","host=s","socket=s","port=i"); + +usage() if ($opt_help); # the help function + +## User may have put the port with the host. + +if ($opt_host =~ s/:(\d+)$//) +{ + $opt_port = $1; +} + +if ($opt_host eq '') +{ + $sqlhost = "localhost"; +} +else +{ + $sqlhost = $opt_host; +} + +# ask for a password if no password is set already +if ($opt_password eq '') +{ + system "stty -echo"; + print "Password for user $opt_user to connect to MariaDB: "; + $opt_password = <STDIN>; + chomp($opt_password); + system "stty echo"; + print "\n"; +} + +## Socket takes precedence. +my $dsn; +my $prefix= 'mysql'; + +if (eval {DBI->install_driver("MariaDB")}) { + $dsn ="DBI:MariaDB:;"; + $prefix= 'mariadb'; +} +else { + $dsn = "DBI:mysql:;"; +} + +if ($opt_socket and -S $opt_socket) +{ + $dsn .= "${prefix}_socket=$opt_socket"; +} +else +{ + $dsn .= "host=$sqlhost"; + if ($sqlhost ne "localhost") + { + $dsn .= ";port=$opt_port"; + } +} + +# make the connection to MariaDB +$dbh= DBI->connect($dsn,$opt_user,$opt_password, { RaiseError => 1, PrintError => 0}) || + die("Can't make a connection to the MariaDB server.\n The error: $DBI::errstr"); + +# the start of the program +&q1(); +exit(0); # the end... + +##### +# below all subroutines of the program +##### + +### +# the beginning of the program +### +sub q1 { # first question ... + my ($answer,$end); + while (! $end) { + print "#"x70; + print "\n"; + print "## Welcome to the permission setter $version for MariaDB.\n"; + print "## made by Luuk de Boer\n"; + print "#"x70; + print "\n"; + print "What would you like to do:\n"; + print " 1. Set password for an existing user.\n"; + print " 2. Create a database + user privilege for that database\n"; + print " and host combination (user can only do SELECT)\n"; + print " 3. Create/append user privilege for an existing database\n"; + print " and host combination (user can only do SELECT)\n"; + print " 4. Create/append broader user privileges for an existing\n"; + print " database and host combination\n"; + print " (user can do SELECT,INSERT,UPDATE,DELETE)\n"; + print " 5. Create/append quite extended user privileges for an\n"; + print " existing database and host combination (user can do\n"; + print " SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,\n"; + print " LOCK TABLES,CREATE TEMPORARY TABLES)\n"; + print " 6. Create/append full privileges for an existing database\n"; + print " and host combination (user has FULL privilege)\n"; + print " 7. Remove all privileges for for an existing database and\n"; + print " host combination.\n"; + print " (user will have all permission fields set to N)\n"; + print " 0. exit this program\n"; + print "\nMake your choice [1,2,3,4,5,6,7,0]: "; + while (<STDIN>) { + $answer = $_; + chomp($answer); + if ($answer =~ /^[1234567]$/) { + if ($answer == 1) { + setpwd(); + } elsif ($answer =~ /^[234567]$/) { + addall($answer); + } else { + print "Sorry, something went wrong. With such option number you should not get here.\n\n"; + $end = 1; + } + } elsif ($answer == 0) { + print "We hope we can help you next time \n\n"; + $end = 1; + } else { + print "Your answer was $answer\n"; + print "and that's wrong .... Try again\n"; + } + last; + } + } +} + +### +# set a password for a user +### +sub setpwd +{ + my ($user,$pass,$host) = ""; + print "\n\nSetting a (new) password for a user.\n"; + + $user = user(); + $pass = newpass($user); + $host = hosts($user); + + print "#"x70; + print "\n\n"; + print "That was it ... here is an overview of what you gave to me:\n"; + print "The username : $user\n"; +# print "The password : $pass\n"; + print "The host : $host\n"; + print "#"x70; + print "\n\n"; + print "Are you pretty sure you would like to implement this [yes/no]: "; + my $no = <STDIN>; + chomp($no); + if ($no =~ /n/i) + { + print "Okay .. that was it then ... See ya\n\n"; + return(0); + } + else + { + print "Okay ... let's go then ...\n\n"; + } + $user = $dbh->quote($user); + $host = $dbh->quote($host); + if ($pass eq '') + { + $pass = "''"; + } + else + { + $pass = "PASSWORD(". $dbh->quote($pass) . ")"; + } + my $uh= "$user@$host"; + my $sth = $dbh->prepare("set password for $uh =$pass") || die $dbh->errstr; + $sth->execute || die $dbh->errstr; + $sth->finish; + print "The password is set for user $user.\n\n"; + +} + +### +# all things which will be added are done here +### +sub addall { + my ($todo) = @_; + my ($answer,$good,$db,$user,$pass,$host,$priv); + + if ($todo == 2) { + $db = newdatabase(); + } else { + $db = database(); + } + + $user = newuser(); + $pass = newpass("$user"); + $host = newhosts(); + + print "#"x70; + print "\n\n"; + print "That was it ... here is an overview of what you gave to me:\n"; + print "The database name : $db\n"; + print "The username : $user\n"; +# print "The password : $pass\n"; + print "The host(s) : $host\n"; + print "#"x70; + print "\n\n"; + print "Are you pretty sure you would like to implement this [yes/no]: "; + my $no = <STDIN>; + chomp($no); + if ($no =~ /n/i) { + print "Okay .. that was it then ... See ya\n\n"; + return(0); + } else { + print "Okay ... let's go then ...\n\n"; + } + + if ($todo == 2) { + # create the database + if ($db) { + my $sth = $dbh->do("CREATE DATABASE $db") || $dbh->errstr; + } else { + print STDERR "What do you want? You wanted to create new database and add new user, right?\n"; + die "But then specify databasename, please\n"; + } + } + + if ( ( !$todo ) or not ( $todo =~ m/^[2-7]$/ ) ) { + print STDERR "Sorry, select option $todo isn't known inside the program .. See ya\n"; + quit(); + } + + my @hosts = split(/,/,$host); + if (!$user) { + die "username not specified: $user\n"; + } + if (!$db) { + die "databasename is not specified nor *\n"; + } + foreach $host (@hosts) { + # user privileges: SELECT + if (($todo == 2) || ($todo == 3)) { + $sth = $dbh->do("GRANT SELECT ON $db.* TO \'$user\'@\'$host\' IDENTIFIED BY \'$pass\'") || die $dbh->errstr; + } elsif ($todo == 4) { + # user privileges: SELECT,INSERT,UPDATE,DELETE + $sth = $dbh->do("GRANT SELECT,INSERT,UPDATE,DELETE ON $db.* TO \'$user\'@\'$host\' IDENTIFIED BY \'$pass\'") || die $dbh->errstr; + } elsif ($todo == 5) { + # user privileges: SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,LOCK TABLES,CREATE TEMPORARY TABLES + $sth = $dbh->do("GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,LOCK TABLES,CREATE TEMPORARY TABLES ON $db.* TO \'$user\'@\'$host\' IDENTIFIED BY \'$pass\'") || die $dbh->errstr; + } elsif ($todo == 6) { + # all privileges + $sth = $dbh->do("GRANT ALL ON $db.* TO \'$user\'\@\'$host\' IDENTIFIED BY \'$pass\'") || die $dbh->errstr; + } elsif ($todo == 7) { + # all privileges set to N + $sth = $dbh->do("REVOKE ALL ON $db.* FROM \'$user\'\@\'$host\'") || die $dbh->errstr; + } + } + print "Everything is inserted and mysql privileges have been reloaded.\n\n"; +} + +### +# ask for a new database name +### +sub newdatabase { + my ($answer,$good,$db); + print "\n\nWhich database would you like to add: "; + while (<STDIN>) { + $answer = $_; + $good = 0; + chomp($answer); + if ($answer) { + my $sth = $dbh->prepare("SHOW DATABASES") || die $dbh->errstr; + $sth->execute || die $dbh->errstr; + while (my @r = $sth->fetchrow_array) { + if ($r[0] eq $answer) { + print "\n\nSorry, this database name is already in use; try something else: "; + $good = 1; + } + } + } else { + print "You must type something ...\nTry again: "; + next; + } + last if ($good == 0); + } + $db = $answer; + print "The new database $db will be created\n"; + return($db); +} + +### +# select a database +### +sub database { + my ($answer,$good,$db); + print "\n\nWhich database from existing databases would you like to select: \n"; + print "You can choose from: \n"; + my $sth = $dbh->prepare("show databases") || die $dbh->errstr; + $sth->execute || die $dbh->errstr; + while (my @r = $sth->fetchrow_array) { + print " - $r[0] \n"; + } + print "Which database will it be (case sensitive). Type * for any: \n"; + while (<STDIN>) { + $answer = $_; + $good = 0; + chomp($answer); + if ($answer) { + if ($answer eq "*") { + print "OK, the user entry will NOT be limited to any database"; + return("*"); + } + my $sth = $dbh->prepare("show databases") || die $dbh->errstr; + $sth->execute || die $dbh->errstr; + while (my @r = $sth->fetchrow_array) { + if ($r[0] eq $answer) { + $good = 1; + $db = $r[0]; + last; + } + } + } else { + print "Type either database name or * meaning any databasename. That means"; + print " any of those above but also any which will be created in future!"; + print " This option gives a user chance to operate on databse mysql, which"; + print " contains privilege settings. That is really risky!\n"; + next; + } + if ($good == 1) { + last; + } else { + print "You must select one from the list.\nTry again: "; + next; + } + } + print "The database $db will be used.\n"; + return($db); +} + +### +# ask for a new username +### +sub newuser +{ + my $user = ""; + my $answer = ""; + + print "\nWhat username is to be created: "; + while(<STDIN>) + { + $answer = $_; + chomp($answer); + if ($answer) + { + $user = $answer; + } + else + { + print "You must type something ...\nTry again: "; + next; + } + last; + } + print "Username = $user\n"; + return($user); +} + +### +# ask for a user which is already in the user table +### +sub user +{ + my ($answer,$user); + + print "\nFor which user do you want to specify a password: "; + while(<STDIN>) + { + $answer = $_; + chomp($answer); + if ($answer) + { + my $sth = $dbh->prepare("select User from mysql.user where User = '$answer'") || die $dbh->errstr; + $sth->execute || die $dbh->errstr; + my @r = $sth->fetchrow_array; + if ($r[0]) + { + $user = $r[0]; + } + else + { + print "Sorry, user $answer isn't known in the user table.\nTry again: "; + next; + } + } + else + { + print "You must type something ...\nTry again: "; + next; + } + last; + } + print "Username = $user\n"; + return($user); +} + +### +# ask for a new password +### +sub newpass +{ + my ($user) = @_; + my ($pass,$answer,$good,$yes); + + print "Would you like to set a password for $user [y/n]: "; + $yes = <STDIN>; + chomp($yes); + if ($yes =~ /y/) + { + system "stty -echo"; + print "What password do you want to specify for $user: "; + while(<STDIN>) + { + $answer = $_; + chomp($answer); + system "stty echo"; + print "\n"; + if ($answer) + { + system "stty -echo"; + print "Type the password again: "; + my $second = <STDIN>; + chomp($second); + system "stty echo"; + print "\n"; + if ($answer ne $second) + { + print "Passwords aren't the same; we begin from scratch again.\n"; + system "stty -echo"; + print "Password please: "; + next; + } + else + { + $pass = $answer; + } + } + else + { + print "You must type something ...\nTry again: "; + next; + } + last; + } +# print "The password for $user is $pass.\n"; + } + else + { + print "We won't set a password so the user doesn't have to use it\n"; + $pass = ""; + } + return($pass); +} + +### +# ask for new hosts +### +sub newhosts +{ + my ($host,$answer,$good); + + print "We now need to know from what host(s) the user will connect.\n"; + print "Keep in mind that % means 'from any host' ...\n"; + print "The host please: "; + while(<STDIN>) + { + $answer = $_; + chomp($answer); + if ($answer) + { + $host .= ",$answer"; + print "Would you like to add another host [yes/no]: "; + my $yes = <STDIN>; + chomp($yes); + if ($yes =~ /y/i) + { + print "Okay, give us the host please: "; + next; + } + else + { + print "Okay we keep it with this ...\n"; + } + } + else + { + print "You must type something ...\nTry again: "; + next; + } + last; + } + $host =~ s/^,//; + print "The following host(s) will be used: $host.\n"; + return($host); +} + +### +# ask for a host which is already in the user table +### +sub hosts +{ + my ($user) = @_; + my ($answer,$good,$host); + + print "We now need to know which host for $user we have to change.\n"; + print "Choose from the following hosts: \n"; + $user = $dbh->quote($user); + my $sth = $dbh->prepare("select Host,User from mysql.user where User = $user") || die $dbh->errstr; + $sth->execute || die $dbh->errstr; + while (my @r = $sth->fetchrow_array) + { + print " - $r[0] \n"; + } + print "The host please (case sensitive): "; + while(<STDIN>) + { + $answer = $_; + chomp($answer); + if ($answer) + { + $sth = $dbh->prepare("select Host,User from mysql.user where Host = '$answer' and User = $user") || die $dbh->errstr; + $sth->execute || die $dbh->errstr; + my @r = $sth->fetchrow_array; + if ($r[0]) + { + $host = $answer; + last; + } + else + { + print "You have to select a host from the list ...\nTry again: "; + next; + } + } + else + { + print "You have to type something ...\nTry again: "; + next; + } + last; + } + print "The following host will be used: $host.\n"; + return($host); +} + +### +# a nice quit (first disconnect and then exit +### +sub quit +{ + $dbh->disconnect; + exit(0); +} + +### +# Read variables password, port and socket from .my.cnf under the client +# or perl groups +### + +sub read_my_cnf +{ + open(TMP,$ENV{'HOME'} . "/.my.cnf") || return 1; + while (<TMP>) + { + if (/^\[(client|perl)\]/i) + { + print "Options read from mycnf:\n"; + while ((defined($_=<TMP>)) && !/^\[\w+\]/) + { + next if /^\s*($|#)/; ## skip blanks and comments + print $_; + if (/^host\s*=\s*(\S+)/i) + { + $opt_host = $1; + } + elsif (/^user\s*=\s*(\S+)/i) + { + $opt_user = $1; + } + elsif (/^password\s*=\s*(\S+)/i) + { + $opt_password = $1; + } + elsif (/^port\s*=\s*(\S+)/i) + { + $opt_port = $1; + } + elsif (/^socket\s*=\s*(\S+)/i) + { + $opt_socket = $1; + } + } + print "------------------------\n"; + } + } + close(TMP); +} + +### +# the help text +### +sub usage +{ + print <<EOL; +---------------------------------------------------------------------- + The permission setter for MariaDB. + version: $version + + made by: Luuk de Boer <luuk\@wxs.nl> +---------------------------------------------------------------------- + +The permission setter is a little program which can help you add users +or databases or change passwords in MariaDB. Keep in mind that we don't +check permissions which already been set in MariaDB. So if you can't +connect to MariaDB using the permission you just added, take a look at +the permissions which have already been set in MariaDB. + +The permission setter first reads your .my.cnf file in your Home +directory if it exists. + +Options for the permission setter: + +--help : print this help message and exit. + +The options shown below are used for making the connection to the MariaDB +server. Keep in mind that the permissions for the user specified via +these options must be sufficient to add users / create databases / set +passwords. + +--user : is the username to connect with. +--password : the password of the username. +--host : the host to connect to. +--socket : the socket to connect to. +--port : the port number of the host to connect to. + +If you don't give a password and no password is set in your .my.cnf +file, then the permission setter will ask for a password. + + +EOL +exit(0); +} diff --git a/scripts/mysql_system_tables.sql b/scripts/mysql_system_tables.sql new file mode 100644 index 00000000..a3f6824c --- /dev/null +++ b/scripts/mysql_system_tables.sql @@ -0,0 +1,340 @@ +-- Copyright (c) 2007, 2018, Oracle and/or its affiliates. +-- Copyright (c) 2008, 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 Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA + +-- +-- The system tables of MySQL Server +-- + +set sql_mode=''; + +set @orig_storage_engine=@@default_storage_engine; +set default_storage_engine=Aria; + +set system_versioning_alter_history=keep; + +set @have_innodb= (select count(engine) from information_schema.engines where engine='INNODB' and support != 'NO'); +SET @innodb_or_aria=IF(@have_innodb <> 0, 'InnoDB', 'Aria'); + +CREATE TABLE IF NOT EXISTS db ( Host char(255) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(128) binary DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Event_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, Delete_history_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, PRIMARY KEY /*Host */(Host,Db,User), KEY User (User) ) engine=Aria transactional=1 CHARACTER SET utf8mb3 COLLATE utf8mb3_bin comment='Database privileges'; + +-- Remember for later if db table already existed +set @had_db_table= @@warning_count != 0; + +CREATE TABLE IF NOT EXISTS global_priv (Host char(255) binary DEFAULT '', User char(128) binary DEFAULT '', Priv JSON NOT NULL DEFAULT '{}' CHECK(JSON_VALID(Priv)), PRIMARY KEY (Host,User)) engine=Aria transactional=1 CHARACTER SET utf8mb3 COLLATE utf8mb3_bin comment='Users and global privileges'; + +set @exists_user_view= EXISTS (SELECT * FROM information_schema.VIEWS WHERE TABLE_CATALOG = 'def' and TABLE_SCHEMA = 'mysql' and TABLE_NAME='user'); + +set @exists_user_view_by_root= EXISTS (SELECT * FROM information_schema.VIEWS WHERE TABLE_CATALOG = 'def' and TABLE_SCHEMA = 'mysql' and TABLE_NAME='user' and DEFINER = 'mariadb.sys@localhost'); + +set @need_sys_user_creation= (( NOT @exists_user_view) OR @exists_user_view_by_root); + +CREATE TEMPORARY TABLE tmp_user_sys LIKE global_priv; +INSERT INTO tmp_user_sys (Host,User,Priv) VALUES ('localhost','mariadb.sys','{"access":0,"plugin":"mysql_native_password","authentication_string":"","account_locked":true,"password_last_changed":0}'); +INSERT IGNORE INTO global_priv SELECT * FROM tmp_user_sys WHERE 0 <> @need_sys_user_creation; +DROP TABLE tmp_user_sys; + +CREATE DEFINER='mariadb.sys'@'localhost' SQL SECURITY DEFINER VIEW IF NOT EXISTS user AS SELECT + Host, + User, + IF(JSON_VALUE(Priv, '$.plugin') IN ('mysql_native_password', 'mysql_old_password'), IFNULL(JSON_VALUE(Priv, '$.authentication_string'), ''), '') AS Password, + IF(JSON_VALUE(Priv, '$.access') & 1, 'Y', 'N') AS Select_priv, + IF(JSON_VALUE(Priv, '$.access') & 2, 'Y', 'N') AS Insert_priv, + IF(JSON_VALUE(Priv, '$.access') & 4, 'Y', 'N') AS Update_priv, + IF(JSON_VALUE(Priv, '$.access') & 8, 'Y', 'N') AS Delete_priv, + IF(JSON_VALUE(Priv, '$.access') & 16, 'Y', 'N') AS Create_priv, + IF(JSON_VALUE(Priv, '$.access') & 32, 'Y', 'N') AS Drop_priv, + IF(JSON_VALUE(Priv, '$.access') & 64, 'Y', 'N') AS Reload_priv, + IF(JSON_VALUE(Priv, '$.access') & 128, 'Y', 'N') AS Shutdown_priv, + IF(JSON_VALUE(Priv, '$.access') & 256, 'Y', 'N') AS Process_priv, + IF(JSON_VALUE(Priv, '$.access') & 512, 'Y', 'N') AS File_priv, + IF(JSON_VALUE(Priv, '$.access') & 1024, 'Y', 'N') AS Grant_priv, + IF(JSON_VALUE(Priv, '$.access') & 2048, 'Y', 'N') AS References_priv, + IF(JSON_VALUE(Priv, '$.access') & 4096, 'Y', 'N') AS Index_priv, + IF(JSON_VALUE(Priv, '$.access') & 8192, 'Y', 'N') AS Alter_priv, + IF(JSON_VALUE(Priv, '$.access') & 16384, 'Y', 'N') AS Show_db_priv, + IF(JSON_VALUE(Priv, '$.access') & 32768, 'Y', 'N') AS Super_priv, + IF(JSON_VALUE(Priv, '$.access') & 65536, 'Y', 'N') AS Create_tmp_table_priv, + IF(JSON_VALUE(Priv, '$.access') & 131072, 'Y', 'N') AS Lock_tables_priv, + IF(JSON_VALUE(Priv, '$.access') & 262144, 'Y', 'N') AS Execute_priv, + IF(JSON_VALUE(Priv, '$.access') & 524288, 'Y', 'N') AS Repl_slave_priv, + IF(JSON_VALUE(Priv, '$.access') & 1048576, 'Y', 'N') AS Repl_client_priv, + IF(JSON_VALUE(Priv, '$.access') & 2097152, 'Y', 'N') AS Create_view_priv, + IF(JSON_VALUE(Priv, '$.access') & 4194304, 'Y', 'N') AS Show_view_priv, + IF(JSON_VALUE(Priv, '$.access') & 8388608, 'Y', 'N') AS Create_routine_priv, + IF(JSON_VALUE(Priv, '$.access') & 16777216, 'Y', 'N') AS Alter_routine_priv, + IF(JSON_VALUE(Priv, '$.access') & 33554432, 'Y', 'N') AS Create_user_priv, + IF(JSON_VALUE(Priv, '$.access') & 67108864, 'Y', 'N') AS Event_priv, + IF(JSON_VALUE(Priv, '$.access') & 134217728, 'Y', 'N') AS Trigger_priv, + IF(JSON_VALUE(Priv, '$.access') & 268435456, 'Y', 'N') AS Create_tablespace_priv, + IF(JSON_VALUE(Priv, '$.access') & 536870912, 'Y', 'N') AS Delete_history_priv, + ELT(IFNULL(JSON_VALUE(Priv, '$.ssl_type'), 0) + 1, '', 'ANY','X509', 'SPECIFIED') AS ssl_type, + IFNULL(JSON_VALUE(Priv, '$.ssl_cipher'), '') AS ssl_cipher, + IFNULL(JSON_VALUE(Priv, '$.x509_issuer'), '') AS x509_issuer, + IFNULL(JSON_VALUE(Priv, '$.x509_subject'), '') AS x509_subject, + CAST(IFNULL(JSON_VALUE(Priv, '$.max_questions'), 0) AS UNSIGNED) AS max_questions, + CAST(IFNULL(JSON_VALUE(Priv, '$.max_updates'), 0) AS UNSIGNED) AS max_updates, + CAST(IFNULL(JSON_VALUE(Priv, '$.max_connections'), 0) AS UNSIGNED) AS max_connections, + CAST(IFNULL(JSON_VALUE(Priv, '$.max_user_connections'), 0) AS SIGNED) AS max_user_connections, + IFNULL(JSON_VALUE(Priv, '$.plugin'), '') AS plugin, + IFNULL(JSON_VALUE(Priv, '$.authentication_string'), '') AS authentication_string, + IF(IFNULL(JSON_VALUE(Priv, '$.password_last_changed'), 1) = 0, 'Y', 'N') AS password_expired, + ELT(IFNULL(JSON_VALUE(Priv, '$.is_role'), 0) + 1, 'N', 'Y') AS is_role, + IFNULL(JSON_VALUE(Priv, '$.default_role'), '') AS default_role, + CAST(IFNULL(JSON_VALUE(Priv, '$.max_statement_time'), 0.0) AS DECIMAL(12,6)) AS max_statement_time + FROM global_priv; + +-- Remember for later if user table already existed +set @had_user_table= @@warning_count != 0; + +CREATE TABLE IF NOT EXISTS roles_mapping ( Host char(255) binary DEFAULT '' NOT NULL, User char(128) binary DEFAULT '' NOT NULL, Role char(128) binary DEFAULT '' NOT NULL, Admin_option enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, UNIQUE (Host, User, Role)) engine=Aria transactional=1 CHARACTER SET utf8mb3 COLLATE utf8mb3_bin comment='Granted roles'; + +CREATE TABLE IF NOT EXISTS func ( name char(64) binary DEFAULT '' NOT NULL, ret tinyint(1) DEFAULT '0' NOT NULL, dl char(128) DEFAULT '' NOT NULL, type enum ('function','aggregate') COLLATE utf8mb3_general_ci NOT NULL, PRIMARY KEY (name) ) engine=Aria transactional=1 CHARACTER SET utf8mb3 COLLATE utf8mb3_bin comment='User defined functions'; + + +CREATE TABLE IF NOT EXISTS plugin ( name varchar(64) DEFAULT '' NOT NULL, dl varchar(128) DEFAULT '' NOT NULL, PRIMARY KEY (name) ) engine=Aria transactional=1 CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci comment='MySQL plugins'; + + +CREATE TABLE IF NOT EXISTS servers ( Server_name char(64) NOT NULL DEFAULT '', Host varchar(2048) NOT NULL DEFAULT '', Db char(64) NOT NULL DEFAULT '', Username char(128) NOT NULL DEFAULT '', Password char(64) NOT NULL DEFAULT '', Port INT(4) NOT NULL DEFAULT '0', Socket char(64) NOT NULL DEFAULT '', Wrapper char(64) NOT NULL DEFAULT '', Owner varchar(512) NOT NULL DEFAULT '', PRIMARY KEY (Server_name)) engine=Aria transactional=1 CHARACTER SET utf8mb3 comment='MySQL Foreign Servers table'; + + +CREATE TABLE IF NOT EXISTS tables_priv ( Host char(255) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(128) binary DEFAULT '' NOT NULL, Table_name char(64) binary DEFAULT '' NOT NULL, Grantor varchar(384) DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger','Delete versioning rows') COLLATE utf8mb3_general_ci DEFAULT '' NOT NULL, Column_priv set('Select','Insert','Update','References') COLLATE utf8mb3_general_ci DEFAULT '' NOT NULL, PRIMARY KEY (Host,Db,User,Table_name), KEY Grantor (Grantor) ) engine=Aria transactional=1 CHARACTER SET utf8mb3 COLLATE utf8mb3_bin comment='Table privileges'; + +CREATE TEMPORARY TABLE tmp_user_sys LIKE tables_priv; +INSERT INTO tmp_user_sys (Host,Db,User,Table_name,Grantor,Timestamp,Table_priv) VALUES ('localhost','mysql','mariadb.sys','global_priv','root@localhost','0','Select,Delete'); +INSERT IGNORE INTO tables_priv SELECT * FROM tmp_user_sys WHERE 0 <> @need_sys_user_creation; +DROP TABLE tmp_user_sys; + +CREATE TABLE IF NOT EXISTS columns_priv ( Host char(255) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(128) binary DEFAULT '' NOT NULL, Table_name char(64) binary DEFAULT '' NOT NULL, Column_name char(64) binary DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, Column_priv set('Select','Insert','Update','References') COLLATE utf8mb3_general_ci DEFAULT '' NOT NULL, PRIMARY KEY (Host,Db,User,Table_name,Column_name) ) engine=Aria transactional=1 CHARACTER SET utf8mb3 COLLATE utf8mb3_bin comment='Column privileges'; + + +CREATE TABLE IF NOT EXISTS help_topic ( help_topic_id int unsigned not null, name char(64) not null, help_category_id smallint unsigned not null, description text not null, example text not null, url text not null, primary key (help_topic_id), unique index (name) ) engine=Aria transactional=0 CHARACTER SET utf8mb3 comment='help topics'; + + +CREATE TABLE IF NOT EXISTS help_category ( help_category_id smallint unsigned not null, name char(64) not null, parent_category_id smallint unsigned null, url text not null, primary key (help_category_id), unique index (name) ) engine=Aria transactional=0 CHARACTER SET utf8mb3 comment='help categories'; + + +CREATE TABLE IF NOT EXISTS help_relation ( help_topic_id int unsigned not null references help_topic, help_keyword_id int unsigned not null references help_keyword, primary key (help_keyword_id, help_topic_id) ) engine=Aria transactional=0 CHARACTER SET utf8mb3 comment='keyword-topic relation'; + + +CREATE TABLE IF NOT EXISTS help_keyword ( help_keyword_id int unsigned not null, name char(64) not null, primary key (help_keyword_id), unique index (name) ) engine=Aria transactional=0 CHARACTER SET utf8mb3 comment='help keywords'; + + +CREATE TABLE IF NOT EXISTS time_zone_name ( Name char(64) NOT NULL, Time_zone_id int unsigned NOT NULL, PRIMARY KEY /*Name*/ (Name) ) engine=Aria transactional=1 CHARACTER SET utf8mb3 comment='Time zone names'; + + +CREATE TABLE IF NOT EXISTS time_zone ( Time_zone_id int unsigned NOT NULL auto_increment, Use_leap_seconds enum('Y','N') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, PRIMARY KEY /*TzId*/ (Time_zone_id) ) engine=Aria transactional=1 CHARACTER SET utf8mb3 comment='Time zones'; + + +CREATE TABLE IF NOT EXISTS time_zone_transition ( Time_zone_id int unsigned NOT NULL, Transition_time bigint signed NOT NULL, Transition_type_id int unsigned NOT NULL, PRIMARY KEY /*TzIdTranTime*/ (Time_zone_id, Transition_time) ) engine=Aria transactional=1 CHARACTER SET utf8mb3 comment='Time zone transitions'; + + +CREATE TABLE IF NOT EXISTS time_zone_transition_type ( Time_zone_id int unsigned NOT NULL, Transition_type_id int unsigned NOT NULL, `Offset` int signed DEFAULT 0 NOT NULL, Is_DST tinyint unsigned DEFAULT 0 NOT NULL, Abbreviation char(8) DEFAULT '' NOT NULL, PRIMARY KEY /*TzIdTrTId*/ (Time_zone_id, Transition_type_id) ) engine=Aria transactional=1 CHARACTER SET utf8mb3 comment='Time zone transition types'; + + +CREATE TABLE IF NOT EXISTS time_zone_leap_second ( Transition_time bigint signed NOT NULL, Correction int signed NOT NULL, PRIMARY KEY /*TranTime*/ (Transition_time) ) engine=Aria transactional=1 CHARACTER SET utf8mb3 comment='Leap seconds information for time zones'; + +CREATE TABLE IF NOT EXISTS proc (db char(64) collate utf8mb3_bin DEFAULT '' NOT NULL, name char(64) DEFAULT '' NOT NULL, type enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') NOT NULL, specific_name char(64) DEFAULT '' NOT NULL, language enum('SQL') DEFAULT 'SQL' NOT NULL, sql_data_access enum( 'CONTAINS_SQL', 'NO_SQL', 'READS_SQL_DATA', 'MODIFIES_SQL_DATA') DEFAULT 'CONTAINS_SQL' NOT NULL, is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL, security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL, param_list blob NOT NULL, returns longblob NOT NULL, body longblob NOT NULL, definer varchar(384) collate utf8mb3_bin DEFAULT '' NOT NULL, created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, modified timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', sql_mode set( 'REAL_AS_FLOAT', 'PIPES_AS_CONCAT', 'ANSI_QUOTES', 'IGNORE_SPACE', 'IGNORE_BAD_TABLE_OPTIONS', 'ONLY_FULL_GROUP_BY', 'NO_UNSIGNED_SUBTRACTION', 'NO_DIR_IN_CREATE', 'POSTGRESQL', 'ORACLE', 'MSSQL', 'DB2', 'MAXDB', 'NO_KEY_OPTIONS', 'NO_TABLE_OPTIONS', 'NO_FIELD_OPTIONS', 'MYSQL323', 'MYSQL40', 'ANSI', 'NO_AUTO_VALUE_ON_ZERO', 'NO_BACKSLASH_ESCAPES', 'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES', 'NO_ZERO_IN_DATE', 'NO_ZERO_DATE', 'INVALID_DATES', 'ERROR_FOR_DIVISION_BY_ZERO', 'TRADITIONAL', 'NO_AUTO_CREATE_USER', 'HIGH_NOT_PRECEDENCE', 'NO_ENGINE_SUBSTITUTION', 'PAD_CHAR_TO_FULL_LENGTH', 'EMPTY_STRING_IS_NULL', 'SIMULTANEOUS_ASSIGNMENT', 'TIME_ROUND_FRACTIONAL') DEFAULT '' NOT NULL, comment text collate utf8mb3_bin NOT NULL, character_set_client char(32) collate utf8mb3_bin, collation_connection char(64) collate utf8mb3_bin, db_collation char(64) collate utf8mb3_bin, body_utf8 longblob, aggregate enum('NONE', 'GROUP') DEFAULT 'NONE' NOT NULL, PRIMARY KEY (db,name,type)) engine=Aria transactional=1 character set utf8mb3 comment='Stored Procedures'; + +CREATE TABLE IF NOT EXISTS procs_priv ( Host char(255) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(128) binary DEFAULT '' NOT NULL, Routine_name char(64) COLLATE utf8mb3_general_ci DEFAULT '' NOT NULL, Routine_type enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') NOT NULL, Grantor varchar(384) DEFAULT '' NOT NULL, Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8mb3_general_ci DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (Host,Db,User,Routine_name,Routine_type), KEY Grantor (Grantor) ) engine=Aria transactional=1 CHARACTER SET utf8mb3 COLLATE utf8mb3_bin comment='Procedure privileges'; + + +-- Create general_log if CSV is enabled. +SET @have_csv = (SELECT support FROM information_schema.engines WHERE engine = 'CSV'); +SET @str = IF (@have_csv = 'YES', 'CREATE TABLE IF NOT EXISTS general_log (event_time TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, user_host MEDIUMTEXT NOT NULL, thread_id BIGINT(21) UNSIGNED NOT NULL, server_id INTEGER UNSIGNED NOT NULL, command_type VARCHAR(64) NOT NULL, argument MEDIUMTEXT NOT NULL) engine=CSV CHARACTER SET utf8mb3 comment="General log"', 'SET @dummy = 0'); + +PREPARE stmt FROM @str; +EXECUTE stmt; +DROP PREPARE stmt; + +-- Create slow_log if CSV is enabled. + +SET @str = IF (@have_csv = 'YES', 'CREATE TABLE IF NOT EXISTS slow_log (start_time TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, user_host MEDIUMTEXT NOT NULL, query_time TIME(6) NOT NULL, lock_time TIME(6) NOT NULL, rows_sent BIGINT UNSIGNED NOT NULL, rows_examined BIGINT UNSIGNED NOT NULL, db VARCHAR(512) NOT NULL, last_insert_id INTEGER NOT NULL, insert_id INTEGER NOT NULL, server_id INTEGER UNSIGNED NOT NULL, sql_text MEDIUMTEXT NOT NULL, thread_id BIGINT(21) UNSIGNED NOT NULL, rows_affected BIGINT UNSIGNED NOT NULL) engine=CSV CHARACTER SET utf8mb3 comment="Slow log"', 'SET @dummy = 0'); + +PREPARE stmt FROM @str; +EXECUTE stmt; +DROP PREPARE stmt; + +CREATE TABLE IF NOT EXISTS event ( db char(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL default '', name char(64) CHARACTER SET utf8mb3 NOT NULL default '', body longblob NOT NULL, definer varchar(384) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL default '', execute_at DATETIME default NULL, interval_value int(11) default NULL, interval_field ENUM('YEAR','QUARTER','MONTH','DAY','HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR','DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND','DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND','SECOND_MICROSECOND') default NULL, created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, modified TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00', last_executed DATETIME default NULL, starts DATETIME default NULL, ends DATETIME default NULL, status ENUM('ENABLED','DISABLED','SLAVESIDE_DISABLED') NOT NULL default 'ENABLED', on_completion ENUM('DROP','PRESERVE') NOT NULL default 'DROP', sql_mode set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','IGNORE_BAD_TABLE_OPTIONS','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH','EMPTY_STRING_IS_NULL','SIMULTANEOUS_ASSIGNMENT','TIME_ROUND_FRACTIONAL') DEFAULT '' NOT NULL, comment char(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL default '', originator INTEGER UNSIGNED NOT NULL, time_zone char(64) CHARACTER SET latin1 NOT NULL DEFAULT 'SYSTEM', character_set_client char(32) collate utf8mb3_bin, collation_connection char(64) collate utf8mb3_bin, db_collation char(64) collate utf8mb3_bin, body_utf8 longblob, PRIMARY KEY (db, name) ) engine=Aria transactional=1 DEFAULT CHARSET=utf8mb3 COMMENT 'Events'; + +SET @create_innodb_table_stats="CREATE TABLE IF NOT EXISTS innodb_table_stats ( + database_name VARCHAR(64) NOT NULL, + table_name VARCHAR(199) NOT NULL, + last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + n_rows BIGINT UNSIGNED NOT NULL, + clustered_index_size BIGINT UNSIGNED NOT NULL, + sum_of_other_index_sizes BIGINT UNSIGNED NOT NULL, + PRIMARY KEY (database_name, table_name) +) ENGINE=INNODB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0"; + +SET @create_innodb_index_stats="CREATE TABLE IF NOT EXISTS innodb_index_stats ( + database_name VARCHAR(64) NOT NULL, + table_name VARCHAR(199) NOT NULL, + index_name VARCHAR(64) NOT NULL, + last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + /* there are at least: + stat_name='size' + stat_name='n_leaf_pages' + stat_name='n_diff_pfx%' */ + stat_name VARCHAR(64) NOT NULL, + stat_value BIGINT UNSIGNED NOT NULL, + sample_size BIGINT UNSIGNED, + stat_description VARCHAR(1024) NOT NULL, + PRIMARY KEY (database_name, table_name, index_name, stat_name) +) ENGINE=INNODB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0"; + +SET @create_transaction_registry="CREATE TABLE IF NOT EXISTS transaction_registry ( + transaction_id BIGINT UNSIGNED NOT NULL, + commit_id BIGINT UNSIGNED NOT NULL, + begin_timestamp TIMESTAMP(6) NOT NULL DEFAULT '0000-00-00 00:00:00.000000', + commit_timestamp TIMESTAMP(6) NOT NULL DEFAULT '0000-00-00 00:00:00.000000', + isolation_level ENUM('READ-UNCOMMITTED', 'READ-COMMITTED', + 'REPEATABLE-READ', 'SERIALIZABLE') NOT NULL, + PRIMARY KEY (transaction_id), + UNIQUE KEY (commit_id), + INDEX (begin_timestamp), + INDEX (commit_timestamp, transaction_id) +) ENGINE=INNODB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0"; + +SET @str=IF(@have_innodb <> 0, @create_innodb_table_stats, "SET @dummy = 0"); +PREPARE stmt FROM @str; +EXECUTE stmt; +DROP PREPARE stmt; + +SET @str=IF(@have_innodb <> 0, @create_innodb_index_stats, "SET @dummy = 0"); +PREPARE stmt FROM @str; +EXECUTE stmt; +DROP PREPARE stmt; + +SET @str=IF(@have_innodb <> 0, @create_transaction_registry, "SET @dummy = 0"); +PREPARE stmt FROM @str; +EXECUTE stmt; +DROP PREPARE stmt; + +SET @cmd="CREATE TABLE IF NOT EXISTS slave_relay_log_info ( + Number_of_lines INTEGER UNSIGNED NOT NULL COMMENT 'Number of lines in the file or rows in the table. Used to version table definitions.', + Relay_log_name TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL COMMENT 'The name of the current relay log file.', + Relay_log_pos BIGINT UNSIGNED NOT NULL COMMENT 'The relay log position of the last executed event.', + Master_log_name TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL COMMENT 'The name of the master binary log file from which the events in the relay log file were read.', + Master_log_pos BIGINT UNSIGNED NOT NULL COMMENT 'The master log position of the last executed event.', + Sql_delay INTEGER NOT NULL COMMENT 'The number of seconds that the slave must lag behind the master.', + Number_of_workers INTEGER UNSIGNED NOT NULL, + Id INTEGER UNSIGNED NOT NULL COMMENT 'Internal Id that uniquely identifies this record.', + PRIMARY KEY(Id)) DEFAULT CHARSET=utf8mb3 STATS_PERSISTENT=0 COMMENT 'Relay Log Information'"; + +SET @str=CONCAT(@cmd, ' ENGINE=', @innodb_or_aria); +-- Don't create the table; MariaDB will have another implementation +#PREPARE stmt FROM @str; +#EXECUTE stmt; +#DROP PREPARE stmt; + +SET @cmd= "CREATE TABLE IF NOT EXISTS slave_master_info ( + Number_of_lines INTEGER UNSIGNED NOT NULL COMMENT 'Number of lines in the file.', + Master_log_name TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL COMMENT 'The name of the master binary log currently being read from the master.', + Master_log_pos BIGINT UNSIGNED NOT NULL COMMENT 'The master log position of the last read event.', + Host CHAR(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin COMMENT 'The host name of the master.', + User_name TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin COMMENT 'The user name used to connect to the master.', + User_password TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin COMMENT 'The password used to connect to the master.', + Port INTEGER UNSIGNED NOT NULL COMMENT 'The network port used to connect to the master.', + Connect_retry INTEGER UNSIGNED NOT NULL COMMENT 'The period (in seconds) that the slave will wait before trying to reconnect to the master.', + Enabled_ssl BOOLEAN NOT NULL COMMENT 'Indicates whether the server supports SSL connections.', + Ssl_ca TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin COMMENT 'The file used for the Certificate Authority (CA) certificate.', + Ssl_capath TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin COMMENT 'The path to the Certificate Authority (CA) certificates.', + Ssl_cert TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin COMMENT 'The name of the SSL certificate file.', + Ssl_cipher TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin COMMENT 'The name of the cipher in use for the SSL connection.', + Ssl_key TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin COMMENT 'The name of the SSL key file.', + Ssl_verify_server_cert BOOLEAN NOT NULL COMMENT 'Whether to verify the server certificate.', + Heartbeat FLOAT NOT NULL COMMENT '', + Bind TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin COMMENT 'Displays which interface is employed when connecting to the MySQL server', + Ignored_server_ids TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin COMMENT 'The number of server IDs to be ignored, followed by the actual server IDs', + Uuid TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin COMMENT 'The master server uuid.', + Retry_count BIGINT UNSIGNED NOT NULL COMMENT 'Number of reconnect attempts, to the master, before giving up.', + Ssl_crl TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin COMMENT 'The file used for the Certificate Revocation List (CRL)', + Ssl_crlpath TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin COMMENT 'The path used for Certificate Revocation List (CRL) files', + Enabled_auto_position BOOLEAN NOT NULL COMMENT 'Indicates whether GTIDs will be used to retrieve events from the master.', + PRIMARY KEY(Host, Port)) DEFAULT CHARSET=utf8mb3 STATS_PERSISTENT=0 COMMENT 'Master Information'"; + +SET @str=CONCAT(@cmd, ' ENGINE=', @innodb_or_aria); +-- Don't create the table; MariaDB will have another implementation +#PREPARE stmt FROM @str; +#EXECUTE stmt; +#DROP PREPARE stmt; + +SET @cmd= "CREATE TABLE IF NOT EXISTS slave_worker_info ( + Id INTEGER UNSIGNED NOT NULL, + Relay_log_name TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + Relay_log_pos BIGINT UNSIGNED NOT NULL, + Master_log_name TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + Master_log_pos BIGINT UNSIGNED NOT NULL, + Checkpoint_relay_log_name TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + Checkpoint_relay_log_pos BIGINT UNSIGNED NOT NULL, + Checkpoint_master_log_name TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + Checkpoint_master_log_pos BIGINT UNSIGNED NOT NULL, + Checkpoint_seqno INT UNSIGNED NOT NULL, + Checkpoint_group_size INTEGER UNSIGNED NOT NULL, + Checkpoint_group_bitmap BLOB NOT NULL, + PRIMARY KEY(Id)) DEFAULT CHARSET=utf8mb3 STATS_PERSISTENT=0 COMMENT 'Worker Information'"; + +SET @str=CONCAT(@cmd, ' ENGINE=', @innodb_or_aria); +-- Don't create the table; MariaDB will have another implementation +#PREPARE stmt FROM @str; +#EXECUTE stmt; +#DROP PREPARE stmt; + +CREATE TABLE IF NOT EXISTS proxies_priv (Host char(255) binary DEFAULT '' NOT NULL, User char(128) binary DEFAULT '' NOT NULL, Proxied_host char(255) binary DEFAULT '' NOT NULL, Proxied_user char(128) binary DEFAULT '' NOT NULL, With_grant BOOL DEFAULT 0 NOT NULL, Grantor varchar(384) DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY /*Host*/ (Host,User,Proxied_host,Proxied_user), KEY Grantor (Grantor) ) engine=Aria transactional=1 CHARACTER SET utf8mb3 COLLATE utf8mb3_bin comment='User proxy privileges'; + +-- Remember for later if proxies_priv table already existed +set @had_proxies_priv_table= @@warning_count != 0; + +-- The following needs to be done both for new installations +-- and for upgrades +CREATE TEMPORARY TABLE tmp_proxies_priv LIKE proxies_priv; +INSERT INTO tmp_proxies_priv VALUES ('localhost', 'root', '', '', TRUE, '', now()); +REPLACE INTO tmp_proxies_priv SELECT 'localhost',IFNULL(@auth_root_socket, 'root'), '', '', TRUE, '', now() FROM DUAL; +INSERT INTO proxies_priv SELECT * FROM tmp_proxies_priv WHERE @had_proxies_priv_table=0; +DROP TABLE tmp_proxies_priv; + +-- +-- Tables unique for MariaDB +-- + +CREATE TABLE IF NOT EXISTS table_stats (db_name varchar(64) NOT NULL, table_name varchar(64) NOT NULL, cardinality bigint(21) unsigned DEFAULT NULL, PRIMARY KEY (db_name,table_name) ) engine=Aria transactional=0 CHARACTER SET utf8mb3 COLLATE utf8mb3_bin comment='Statistics on Tables'; + +CREATE TABLE IF NOT EXISTS column_stats (db_name varchar(64) NOT NULL, table_name varchar(64) NOT NULL, column_name varchar(64) NOT NULL, min_value varbinary(255) DEFAULT NULL, max_value varbinary(255) DEFAULT NULL, nulls_ratio decimal(12,4) DEFAULT NULL, avg_length decimal(12,4) DEFAULT NULL, avg_frequency decimal(12,4) DEFAULT NULL, hist_size tinyint unsigned, hist_type enum('SINGLE_PREC_HB','DOUBLE_PREC_HB','JSON_HB'), histogram longblob, PRIMARY KEY (db_name,table_name,column_name) ) engine=Aria transactional=0 CHARACTER SET utf8mb3 COLLATE utf8mb3_bin comment='Statistics on Columns'; + +CREATE TABLE IF NOT EXISTS index_stats (db_name varchar(64) NOT NULL, table_name varchar(64) NOT NULL, index_name varchar(64) NOT NULL, prefix_arity int(11) unsigned NOT NULL, avg_frequency decimal(12,4) DEFAULT NULL, PRIMARY KEY (db_name,table_name,index_name,prefix_arity) ) engine=Aria transactional=0 CHARACTER SET utf8mb3 COLLATE utf8mb3_bin comment='Statistics on Indexes'; + +-- Note: This definition must be kept in sync with the one used in +-- build_gtid_pos_create_query() in sql/slave.cc +SET @cmd= "CREATE TABLE IF NOT EXISTS gtid_slave_pos ( + domain_id INT UNSIGNED NOT NULL, + sub_id BIGINT UNSIGNED NOT NULL, + server_id INT UNSIGNED NOT NULL, + seq_no BIGINT UNSIGNED NOT NULL, + PRIMARY KEY (domain_id, sub_id)) CHARSET=latin1 +COMMENT='Replication slave GTID position'"; +SET @str=CONCAT(@cmd, ' ENGINE=', @innodb_or_aria); +PREPARE stmt FROM @str; +EXECUTE stmt; +DROP PREPARE stmt; + +set default_storage_engine=@orig_storage_engine; + +-- +-- Drop some tables not used anymore in MariaDB +-- + +drop table if exists mysql.ndb_binlog_index; +drop table if exists mysql.host; diff --git a/scripts/mysql_system_tables_data.sql b/scripts/mysql_system_tables_data.sql new file mode 100644 index 00000000..85489e78 --- /dev/null +++ b/scripts/mysql_system_tables_data.sql @@ -0,0 +1,54 @@ +-- Copyright (c) 2007, 2013, Oracle and/or its affiliates. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA + +-- +-- The initial data for system tables of MySQL Server +-- + +-- When setting up a "cross bootstrap" database (e.g., creating data on a Unix +-- host which will later be included in a Windows zip file), any lines +-- containing "@current_hostname" are filtered out by mysql_install_db. + +-- Get the hostname, if the hostname has any wildcard character like "_" or "%" +-- add escape character in front of wildcard character to convert "_" or "%" to +-- a plain character +SELECT LOWER( REPLACE((SELECT REPLACE(@@hostname,'_','\_')),'%','\%') )INTO @current_hostname; +SELECT '{"access":18446744073709551615}' INTO @all_privileges; +SELECT '{"access":18446744073709551615,"plugin":"mysql_native_password","authentication_string":"invalid","auth_or":[{},{"plugin":"unix_socket"}]}' into @all_with_auth; + +-- Fill "global_priv" table with default users allowing root access +-- from local machine if "global_priv" table didn't exist before +CREATE TEMPORARY TABLE tmp_user_nopasswd LIKE global_priv; +CREATE TEMPORARY TABLE tmp_user_socket LIKE global_priv; +-- Classic passwordless root account. +INSERT INTO tmp_user_nopasswd VALUES ('localhost','root',@all_privileges); +REPLACE INTO tmp_user_nopasswd SELECT @current_hostname,'root',@all_privileges FROM dual WHERE @current_hostname != 'localhost'; +REPLACE INTO tmp_user_nopasswd VALUES ('127.0.0.1','root',@all_privileges); +REPLACE INTO tmp_user_nopasswd VALUES ('::1','root',@all_privileges); +-- More secure root account using unix socket auth. +INSERT INTO tmp_user_socket VALUES ('localhost', 'root',@all_with_auth); +REPLACE INTO tmp_user_socket VALUES ('localhost',IFNULL(@auth_root_socket, 'root'),@all_with_auth); +IF @auth_root_socket is not null THEN + IF not exists(select 1 from information_schema.plugins where plugin_name='unix_socket') THEN + INSTALL SONAME 'auth_socket'; END IF; END IF; + +INSERT INTO global_priv SELECT * FROM tmp_user_nopasswd WHERE @had_user_table=0 AND @auth_root_socket IS NULL; +INSERT INTO global_priv SELECT * FROM tmp_user_socket WHERE @had_user_table=0 AND @auth_root_socket IS NOT NULL; + +CREATE TEMPORARY TABLE tmp_proxies_priv LIKE proxies_priv; +INSERT INTO tmp_proxies_priv SELECT Host, User, '', '', TRUE, '', now() FROM tmp_user_nopasswd WHERE Host != 'localhost' AND @auth_root_socket IS NULL; +REPLACE INTO tmp_proxies_priv SELECT @current_hostname, IFNULL(@auth_root_socket, 'root'), '', '', TRUE, '', now() FROM DUAL WHERE @current_hostname != 'localhost'; +INSERT INTO proxies_priv SELECT * FROM tmp_proxies_priv WHERE @had_proxies_priv_table=0; +DROP TABLE tmp_user_nopasswd, tmp_user_socket, tmp_proxies_priv; diff --git a/scripts/mysql_system_tables_fix.sql b/scripts/mysql_system_tables_fix.sql new file mode 100644 index 00000000..2b4a678d --- /dev/null +++ b/scripts/mysql_system_tables_fix.sql @@ -0,0 +1,861 @@ +-- Copyright (C) 2003, 2013 Oracle and/or its affiliates. +-- Copyright (C) 2010, 2023, 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 Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA + +# This part converts any old privilege tables to privilege tables suitable +# for current version of MariaDB + +# You can safely ignore all 'Duplicate column' and 'Unknown column' errors +# because these just mean that your tables are already up to date. +# This script is safe to run even if your tables are already up to date! + +# Warning message(s) produced for a statement can be printed by explicitly +# adding a 'SHOW WARNINGS' after the statement. + +set sql_mode=''; +set sql_safe_updates='OFF'; +set default_storage_engine=Aria; +set enforce_storage_engine=NULL; +set alter_algorithm='DEFAULT'; +set use_stat_tables='NEVER'; + + +-- +-- Upgrade mysql.column_stats table early because its quite noisy otherwise +-- + +ALTER TABLE column_stats + modify min_value varbinary(255) DEFAULT NULL, + modify max_value varbinary(255) DEFAULT NULL, + modify hist_type enum('SINGLE_PREC_HB','DOUBLE_PREC_HB','JSON_HB'), + modify histogram longblob, + ENGINE=Aria transactional=0; + +set @have_innodb= (select count(engine) from information_schema.engines where engine='INNODB' and support != 'NO'); + +# MDEV-21873: 10.2 to 10.3 upgrade doesn't remove semi-sync reference from +# mysql.plugin table. +# As per suggested fix, check INFORMATION_SCHEMA.PLUGINS +# and if semisync plugins aren't there, delete them from mysql.plugin. +DELETE FROM mysql.plugin WHERE name="rpl_semi_sync_master" AND NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME="rpl_semi_sync_master"); +DELETE FROM mysql.plugin WHERE name="rpl_semi_sync_slave" AND NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME="rpl_semi_sync_slave"); + +-- +-- Ensure that all tables are of type Aria and transactional +-- + +ALTER TABLE user ENGINE=Aria transactional=1; +ALTER TABLE db ENGINE=Aria transactional=1; +ALTER TABLE func ENGINE=Aria transactional=1; +ALTER TABLE procs_priv ENGINE=Aria transactional=1; +ALTER TABLE tables_priv ENGINE=Aria transactional=1; +ALTER TABLE columns_priv ENGINE=Aria transactional=1; +ALTER TABLE roles_mapping ENGINE=Aria transactional=1; +ALTER TABLE plugin ENGINE=Aria transactional=1; +ALTER TABLE servers ENGINE=Aria transactional=1; +ALTER TABLE time_zone_name ENGINE=Aria transactional=1; +ALTER TABLE time_zone ENGINE=Aria transactional=1; +ALTER TABLE time_zone_transition ENGINE=Aria transactional=1; +ALTER TABLE time_zone_transition_type ENGINE=Aria transactional=1; +ALTER TABLE time_zone_leap_second ENGINE=Aria transactional=1; +ALTER TABLE proc ENGINE=Aria transactional=1; +ALTER TABLE event ENGINE=Aria transactional=1; +ALTER TABLE proxies_priv ENGINE=Aria transactional=1; + +-- The following tables doesn't have to be transactional +ALTER TABLE help_topic ENGINE=Aria transactional=0; +ALTER TABLE help_category ENGINE=Aria transactional=0; +ALTER TABLE help_relation ENGINE=Aria transactional=0; +ALTER TABLE help_keyword ENGINE=Aria transactional=0; +ALTER TABLE table_stats ENGINE=Aria transactional=0; +ALTER TABLE index_stats ENGINE=Aria transactional=0; + +ALTER TABLE user add File_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL; + +# Detect whether or not we had the Grant_priv column +SET @hadGrantPriv:=0; +SELECT @hadGrantPriv:=1 FROM user WHERE Grant_priv IS NOT NULL; + +ALTER TABLE user add Grant_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + add References_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + add Index_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + add Alter_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL; +ALTER TABLE db add Grant_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + add References_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + add Index_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + add Alter_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL; + +# Fix privileges for old tables +UPDATE user SET Grant_priv=File_priv,References_priv=Create_priv,Index_priv=Create_priv,Alter_priv=Create_priv WHERE @hadGrantPriv = 0; +UPDATE db SET References_priv=Create_priv,Index_priv=Create_priv,Alter_priv=Create_priv WHERE @hadGrantPriv = 0; +# +# The second alter changes ssl_type to new 4.0.2 format +# Adding columns needed by GRANT .. REQUIRE (openssl) + +ALTER TABLE user +ADD ssl_type enum('','ANY','X509', 'SPECIFIED') DEFAULT '' NOT NULL, +ADD ssl_cipher BLOB NOT NULL, +ADD x509_issuer BLOB NOT NULL, +ADD x509_subject BLOB NOT NULL; +ALTER TABLE user MODIFY ssl_type enum('','ANY','X509', 'SPECIFIED') DEFAULT '' NOT NULL; + +# +# tables_priv +# +ALTER TABLE tables_priv + ADD KEY Grantor (Grantor); + +ALTER TABLE tables_priv + MODIFY Host char(255) NOT NULL default '', + MODIFY Db char(64) NOT NULL default '', + MODIFY User char(128) binary NOT NULL default '', + MODIFY Table_name char(64) NOT NULL default '', + MODIFY Grantor varchar(384) COLLATE utf8mb3_bin NOT NULL default '', + ENGINE=Aria, + CONVERT TO CHARACTER SET utf8mb3 COLLATE utf8mb3_bin; + +ALTER TABLE tables_priv + MODIFY Column_priv set('Select','Insert','Update','References') + COLLATE utf8mb3_general_ci DEFAULT '' NOT NULL, + MODIFY Table_priv set('Select','Insert','Update','Delete','Create', + 'Drop','Grant','References','Index','Alter', + 'Create View','Show view','Trigger','Delete versioning rows') + COLLATE utf8mb3_general_ci DEFAULT '' NOT NULL, + COMMENT='Table privileges'; + +# +# columns_priv +# +# +# Name change of Type -> Column_priv from MySQL 3.22.12 +# +ALTER TABLE columns_priv + CHANGE Type Column_priv set('Select','Insert','Update','References') + COLLATE utf8mb3_general_ci DEFAULT '' NOT NULL; + +ALTER TABLE columns_priv + MODIFY Host char(255) NOT NULL default '', + MODIFY Db char(64) NOT NULL default '', + MODIFY User char(128) binary NOT NULL default '', + MODIFY Table_name char(64) NOT NULL default '', + MODIFY Column_name char(64) NOT NULL default '', + ENGINE=Aria, + CONVERT TO CHARACTER SET utf8mb3 COLLATE utf8mb3_bin, + COMMENT='Column privileges'; + +ALTER TABLE columns_priv + MODIFY Column_priv set('Select','Insert','Update','References') + COLLATE utf8mb3_general_ci DEFAULT '' NOT NULL; + +# +# Add the new 'type' column to the func table. +# + +ALTER TABLE func add type enum ('function','aggregate') COLLATE utf8mb3_general_ci NOT NULL; + +# +# Change the user,db and host tables to current format +# + +# Detect whether we had Show_db_priv +SET @hadShowDbPriv:=0; +SELECT @hadShowDbPriv:=1 FROM user WHERE Show_db_priv IS NOT NULL; + +ALTER TABLE user +ADD Show_db_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Alter_priv, +ADD Super_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Show_db_priv, +ADD Create_tmp_table_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Super_priv, +ADD Lock_tables_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Create_tmp_table_priv, +ADD Execute_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Lock_tables_priv, +ADD Repl_slave_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Execute_priv, +ADD Repl_client_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Repl_slave_priv; + +# Convert privileges so that users have similar privileges as before + +UPDATE user SET Show_db_priv= Select_priv, Super_priv=Process_priv, Execute_priv=Process_priv, Create_tmp_table_priv='Y', Lock_tables_priv='Y', Repl_slave_priv=file_priv, Repl_client_priv=File_priv where user<>"" AND @hadShowDbPriv = 0; + + +# Add fields that can be used to limit number of questions and connections +# for some users. + +ALTER TABLE user +ADD max_questions int(11) NOT NULL DEFAULT 0 AFTER x509_subject, +ADD max_updates int(11) unsigned NOT NULL DEFAULT 0 AFTER max_questions, +ADD max_connections int(11) unsigned NOT NULL DEFAULT 0 AFTER max_updates; + + +# +# Add Create_tmp_table_priv and Lock_tables_priv to db and host +# + +ALTER TABLE db +ADD Create_tmp_table_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, +ADD Lock_tables_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL; + +alter table user change max_questions max_questions int(11) unsigned DEFAULT 0 NOT NULL; + + +alter table db comment='Database privileges'; +alter table user comment='Users and global privileges'; +alter table func comment='User defined functions'; + +# Convert all tables to UTF-8 with binary collation +# and reset all char columns to correct width +ALTER TABLE user + MODIFY Host char(255) NOT NULL default '', + MODIFY User char(128) binary NOT NULL default '', + ENGINE=Aria, CONVERT TO CHARACTER SET utf8mb3 COLLATE utf8mb3_bin; + +# In MySQL 5.7.6 the Password column is removed. Recreate it to preserve the number +# of columns MariaDB expects in the user table. +ALTER TABLE user + ADD Password char(41) character set latin1 collate latin1_bin NOT NULL default '' AFTER User; + +# In MySQL the Unix socket authentication plugin has a different name. Thus the +# references to it need to be renamed in the user table. Thanks to the WHERE +# clauses this applies only to MySQL->MariaDB upgrades and nothing else. +UPDATE user + SET plugin='unix_socket' WHERE plugin='auth_socket'; +DELETE FROM plugin + WHERE name='auth_socket'; + +ALTER TABLE user + MODIFY Password char(41) character set latin1 collate latin1_bin NOT NULL default '', + MODIFY Select_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Insert_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Update_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Delete_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Create_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Drop_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Reload_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Shutdown_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Process_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY File_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Grant_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY References_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Index_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Alter_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Show_db_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Super_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Create_tmp_table_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Lock_tables_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Execute_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Repl_slave_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Repl_client_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8mb3_general_ci DEFAULT '' NOT NULL; + +ALTER TABLE db + MODIFY Host char(255) NOT NULL default '', + MODIFY Db char(64) NOT NULL default '', + MODIFY User char(128) binary NOT NULL default '', + ENGINE=Aria, CONVERT TO CHARACTER SET utf8mb3 COLLATE utf8mb3_bin; +ALTER TABLE db + MODIFY Select_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Insert_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Update_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Delete_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Create_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Drop_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Grant_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY References_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Index_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Alter_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Create_tmp_table_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL, + MODIFY Lock_tables_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL; + + +ALTER TABLE func + ENGINE=Aria, CONVERT TO CHARACTER SET utf8mb3 COLLATE utf8mb3_bin; +ALTER TABLE func + MODIFY type enum ('function','aggregate') COLLATE utf8mb3_general_ci NOT NULL; + +# +# Modify log tables. +# + +SET @old_log_state = @@global.general_log; +SET GLOBAL general_log = 'OFF'; +ALTER TABLE general_log + MODIFY event_time TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + MODIFY user_host MEDIUMTEXT NOT NULL, + MODIFY server_id INTEGER UNSIGNED NOT NULL, + MODIFY command_type VARCHAR(64) NOT NULL, + MODIFY argument MEDIUMTEXT NOT NULL, + MODIFY thread_id BIGINT(21) UNSIGNED NOT NULL; +SET GLOBAL general_log = @old_log_state; + +SET @old_log_state = @@global.log_slow_query; +SET GLOBAL log_slow_query = 'OFF'; +ALTER TABLE slow_log + ADD COLUMN thread_id BIGINT(21) UNSIGNED NOT NULL AFTER sql_text; +ALTER TABLE slow_log + ADD COLUMN rows_affected BIGINT UNSIGNED NOT NULL AFTER thread_id; +ALTER TABLE slow_log + MODIFY start_time TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + MODIFY user_host MEDIUMTEXT NOT NULL, + MODIFY query_time TIME(6) NOT NULL, + MODIFY lock_time TIME(6) NOT NULL, + MODIFY rows_sent BIGINT UNSIGNED NOT NULL, + MODIFY rows_examined BIGINT UNSIGNED NOT NULL, + MODIFY db VARCHAR(512) NOT NULL, + MODIFY last_insert_id INTEGER NOT NULL, + MODIFY insert_id INTEGER NOT NULL, + MODIFY server_id INTEGER UNSIGNED NOT NULL, + MODIFY sql_text MEDIUMTEXT NOT NULL, + MODIFY thread_id BIGINT(21) UNSIGNED NOT NULL; +SET GLOBAL log_slow_query = @old_log_state; + +ALTER TABLE plugin + MODIFY name varchar(64) COLLATE utf8mb3_general_ci NOT NULL DEFAULT '', + MODIFY dl varchar(128) COLLATE utf8mb3_general_ci NOT NULL DEFAULT '', + CONVERT TO CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci; + +# +# Detect whether we had Create_view_priv +# +SET @hadCreateViewPriv:=0; +SELECT @hadCreateViewPriv:=1 FROM user WHERE Create_view_priv IS NOT NULL; + +# +# Create VIEWs privileges (v5.0) +# +ALTER TABLE db ADD Create_view_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Lock_tables_priv; +ALTER TABLE db MODIFY Create_view_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Lock_tables_priv; + + +ALTER TABLE user ADD Create_view_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Repl_client_priv; +ALTER TABLE user MODIFY Create_view_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Repl_client_priv; + +# +# Show VIEWs privileges (v5.0) +# +ALTER TABLE db ADD Show_view_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Create_view_priv; +ALTER TABLE db MODIFY Show_view_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Create_view_priv; + +ALTER TABLE user ADD Show_view_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Create_view_priv; +ALTER TABLE user MODIFY Show_view_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Create_view_priv; + +# +# Assign create/show view privileges to people who have create provileges +# +UPDATE user SET Create_view_priv=Create_priv, Show_view_priv=Create_priv where user<>"" AND @hadCreateViewPriv = 0; + +# +# +# +SET @hadCreateRoutinePriv:=0; +SELECT @hadCreateRoutinePriv:=1 FROM user WHERE Create_routine_priv IS NOT NULL; + +# +# Create PROCEDUREs privileges (v5.0) +# +ALTER TABLE db ADD Create_routine_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Show_view_priv; +ALTER TABLE db MODIFY Create_routine_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Show_view_priv; + +ALTER TABLE user ADD Create_routine_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Show_view_priv; +ALTER TABLE user MODIFY Create_routine_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Show_view_priv; + +# +# Alter PROCEDUREs privileges (v5.0) +# +ALTER TABLE db ADD Alter_routine_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Create_routine_priv; +ALTER TABLE db MODIFY Alter_routine_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Create_routine_priv; + +ALTER TABLE user ADD Alter_routine_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Create_routine_priv; +ALTER TABLE user MODIFY Alter_routine_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Create_routine_priv; + +ALTER TABLE db ADD Execute_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Alter_routine_priv; +ALTER TABLE db MODIFY Execute_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Alter_routine_priv; + +# +# Assign create/alter routine privileges to people who have create privileges +# +UPDATE user SET Create_routine_priv=Create_priv, Alter_routine_priv=Alter_priv where user<>"" AND @hadCreateRoutinePriv = 0; +UPDATE db SET Create_routine_priv=Create_priv, Alter_routine_priv=Alter_priv, Execute_priv=Select_priv where user<>"" AND @hadCreateRoutinePriv = 0; + +# +# Add max_user_connections resource limit +# this is signed in MariaDB so that if one sets it's to -1 then the user +# can't connect anymore. +# +ALTER TABLE user ADD max_user_connections int(11) DEFAULT '0' NOT NULL AFTER max_connections; +ALTER TABLE user MODIFY max_user_connections int(11) DEFAULT '0' NOT NULL AFTER max_connections; + +# +# user.Create_user_priv +# + +SET @hadCreateUserPriv:=0; +SELECT @hadCreateUserPriv:=1 FROM user WHERE Create_user_priv IS NOT NULL; + +ALTER TABLE user ADD Create_user_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Alter_routine_priv; +ALTER TABLE user MODIFY Create_user_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Alter_routine_priv; +UPDATE user LEFT JOIN db USING (Host,User) SET Create_user_priv='Y' + WHERE @hadCreateUserPriv = 0 AND + (user.Grant_priv = 'Y' OR db.Grant_priv = 'Y'); + +# +# procs_priv +# + +ALTER TABLE procs_priv + ENGINE=Aria, + CONVERT TO CHARACTER SET utf8mb3 COLLATE utf8mb3_bin; + +ALTER TABLE procs_priv + MODIFY Proc_priv set('Execute','Alter Routine','Grant') + COLLATE utf8mb3_general_ci DEFAULT '' NOT NULL; + +ALTER IGNORE TABLE procs_priv + MODIFY Routine_name char(64) + COLLATE utf8mb3_general_ci DEFAULT '' NOT NULL; + +ALTER TABLE procs_priv + ADD Routine_type enum('FUNCTION','PROCEDURE') + COLLATE utf8mb3_general_ci NOT NULL AFTER Routine_name; + +ALTER TABLE procs_priv + MODIFY Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP AFTER Proc_priv; + +# +# proc +# + +# Correct the name fields to not binary, and expand sql_data_access +ALTER TABLE proc MODIFY name char(64) DEFAULT '' NOT NULL, + MODIFY specific_name char(64) DEFAULT '' NOT NULL, + MODIFY sql_data_access + enum('CONTAINS_SQL', + 'NO_SQL', + 'READS_SQL_DATA', + 'MODIFIES_SQL_DATA' + ) DEFAULT 'CONTAINS_SQL' NOT NULL, + MODIFY body longblob NOT NULL, + MODIFY returns longblob NOT NULL, + MODIFY sql_mode + set('REAL_AS_FLOAT', + 'PIPES_AS_CONCAT', + 'ANSI_QUOTES', + 'IGNORE_SPACE', + 'IGNORE_BAD_TABLE_OPTIONS', + 'ONLY_FULL_GROUP_BY', + 'NO_UNSIGNED_SUBTRACTION', + 'NO_DIR_IN_CREATE', + 'POSTGRESQL', + 'ORACLE', + 'MSSQL', + 'DB2', + 'MAXDB', + 'NO_KEY_OPTIONS', + 'NO_TABLE_OPTIONS', + 'NO_FIELD_OPTIONS', + 'MYSQL323', + 'MYSQL40', + 'ANSI', + 'NO_AUTO_VALUE_ON_ZERO', + 'NO_BACKSLASH_ESCAPES', + 'STRICT_TRANS_TABLES', + 'STRICT_ALL_TABLES', + 'NO_ZERO_IN_DATE', + 'NO_ZERO_DATE', + 'INVALID_DATES', + 'ERROR_FOR_DIVISION_BY_ZERO', + 'TRADITIONAL', + 'NO_AUTO_CREATE_USER', + 'HIGH_NOT_PRECEDENCE', + 'NO_ENGINE_SUBSTITUTION', + 'PAD_CHAR_TO_FULL_LENGTH', + 'EMPTY_STRING_IS_NULL', + 'SIMULTANEOUS_ASSIGNMENT', + 'TIME_ROUND_FRACTIONAL' + ) DEFAULT '' NOT NULL, + DEFAULT CHARACTER SET utf8mb3; + +# Correct the character set and collation +# Reset some fields after the conversion +ALTER TABLE proc CONVERT TO CHARACTER SET utf8mb3, + MODIFY db char(64) binary DEFAULT '' NOT NULL, + MODIFY definer varchar(384) binary DEFAULT '' NOT NULL, + MODIFY comment text binary NOT NULL; + +ALTER TABLE proc ADD character_set_client + char(32) collate utf8mb3_bin DEFAULT NULL + AFTER comment; +ALTER TABLE proc MODIFY character_set_client + char(32) collate utf8mb3_bin DEFAULT NULL; + +ALTER TABLE proc MODIFY type enum('FUNCTION', + 'PROCEDURE', + 'PACKAGE', + 'PACKAGE BODY') NOT NULL; + +ALTER TABLE procs_priv MODIFY Routine_type enum('FUNCTION', + 'PROCEDURE', + 'PACKAGE', + 'PACKAGE BODY') NOT NULL; + +SELECT CASE WHEN COUNT(*) > 0 THEN +CONCAT ("WARNING: NULL values of the 'character_set_client' column ('mysql.proc' table) have been updated with a default value (", @@character_set_client, "). Please verify if necessary.") +ELSE NULL +END +AS value FROM proc WHERE character_set_client IS NULL; + +UPDATE proc SET character_set_client = @@character_set_client + WHERE character_set_client IS NULL; + +ALTER TABLE proc ADD collation_connection + char(64) collate utf8mb3_bin DEFAULT NULL + AFTER character_set_client; +ALTER TABLE proc MODIFY collation_connection + char(64) collate utf8mb3_bin DEFAULT NULL; + +SELECT CASE WHEN COUNT(*) > 0 THEN +CONCAT ("WARNING: NULL values of the 'collation_connection' column ('mysql.proc' table) have been updated with a default value (", @@collation_connection, "). Please verify if necessary.") +ELSE NULL +END +AS value FROM proc WHERE collation_connection IS NULL; + +UPDATE proc SET collation_connection = @@collation_connection + WHERE collation_connection IS NULL; + +ALTER TABLE proc ADD db_collation + char(64) collate utf8mb3_bin DEFAULT NULL + AFTER collation_connection; +ALTER TABLE proc MODIFY db_collation + char(64) collate utf8mb3_bin DEFAULT NULL; + +SELECT CASE WHEN COUNT(*) > 0 THEN +CONCAT ("WARNING: NULL values of the 'db_collation' column ('mysql.proc' table) have been updated with default values. Please verify if necessary.") +ELSE NULL +END +AS value FROM proc WHERE db_collation IS NULL; + +UPDATE proc AS p SET db_collation = + ( SELECT DEFAULT_COLLATION_NAME + FROM INFORMATION_SCHEMA.SCHEMATA + WHERE SCHEMA_NAME = p.db) + WHERE db_collation IS NULL; + +ALTER TABLE proc ADD body_utf8 longblob DEFAULT NULL + AFTER db_collation; +ALTER TABLE proc MODIFY body_utf8 longblob DEFAULT NULL; + +# Change comment from char(64) to text +ALTER TABLE proc MODIFY comment + text collate utf8mb3_bin NOT NULL; + +# MDEV-7773: Stored Aggregate Functions +ALTER TABLE proc ADD aggregate enum('NONE', 'GROUP') DEFAULT 'NONE' NOT NULL + AFTER body_utf8; + +# Update definer of Add/DropGeometryColumn procedures to 'mariadb.sys' +# To consider the scenarios in MDEV-23102, only update the definer when it's 'root' +UPDATE proc SET Definer = 'mariadb.sys@localhost' WHERE Definer = 'root@localhost' AND Name = 'AddGeometryColumn'; +UPDATE proc SET Definer = 'mariadb.sys@localhost' WHERE Definer = 'root@localhost' AND Name = 'DropGeometryColumn'; + +# +# EVENT privilege +# +SET @hadEventPriv := 0; +SELECT @hadEventPriv :=1 FROM user WHERE Event_priv IS NOT NULL; + +ALTER TABLE user ADD Event_priv enum('N','Y') character set utf8mb3 DEFAULT 'N' NOT NULL AFTER Create_user_priv; +ALTER TABLE user MODIFY Event_priv enum('N','Y') character set utf8mb3 DEFAULT 'N' NOT NULL AFTER Create_user_priv; + +UPDATE user SET Event_priv=Super_priv WHERE @hadEventPriv = 0; + +ALTER TABLE db ADD Event_priv enum('N','Y') character set utf8mb3 DEFAULT 'N' NOT NULL; +ALTER TABLE db MODIFY Event_priv enum('N','Y') character set utf8mb3 DEFAULT 'N' NOT NULL; + +# +# EVENT table +# +ALTER TABLE event DROP PRIMARY KEY, ADD PRIMARY KEY(db, name); +# Add sql_mode column just in case. +ALTER TABLE event ADD sql_mode set ('IGNORE_BAD_TABLE_OPTIONS') AFTER on_completion; +# Update list of sql_mode values. +ALTER TABLE event MODIFY sql_mode + set('REAL_AS_FLOAT', + 'PIPES_AS_CONCAT', + 'ANSI_QUOTES', + 'IGNORE_SPACE', + 'IGNORE_BAD_TABLE_OPTIONS', + 'ONLY_FULL_GROUP_BY', + 'NO_UNSIGNED_SUBTRACTION', + 'NO_DIR_IN_CREATE', + 'POSTGRESQL', + 'ORACLE', + 'MSSQL', + 'DB2', + 'MAXDB', + 'NO_KEY_OPTIONS', + 'NO_TABLE_OPTIONS', + 'NO_FIELD_OPTIONS', + 'MYSQL323', + 'MYSQL40', + 'ANSI', + 'NO_AUTO_VALUE_ON_ZERO', + 'NO_BACKSLASH_ESCAPES', + 'STRICT_TRANS_TABLES', + 'STRICT_ALL_TABLES', + 'NO_ZERO_IN_DATE', + 'NO_ZERO_DATE', + 'INVALID_DATES', + 'ERROR_FOR_DIVISION_BY_ZERO', + 'TRADITIONAL', + 'NO_AUTO_CREATE_USER', + 'HIGH_NOT_PRECEDENCE', + 'NO_ENGINE_SUBSTITUTION', + 'PAD_CHAR_TO_FULL_LENGTH', + 'EMPTY_STRING_IS_NULL', + 'SIMULTANEOUS_ASSIGNMENT', + 'TIME_ROUND_FRACTIONAL' + ) DEFAULT '' NOT NULL AFTER on_completion; +ALTER TABLE event MODIFY name char(64) CHARACTER SET utf8mb3 NOT NULL default ''; +ALTER TABLE event MODIFY db CHAR(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL DEFAULT ''; +ALTER TABLE event MODIFY comment CHAR(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL DEFAULT ''; + + +ALTER TABLE event ADD COLUMN originator INT UNSIGNED NOT NULL AFTER comment; +ALTER TABLE event MODIFY COLUMN originator INT UNSIGNED NOT NULL; + +ALTER TABLE event MODIFY COLUMN status ENUM('ENABLED','DISABLED','SLAVESIDE_DISABLED') NOT NULL default 'ENABLED'; + +ALTER TABLE event ADD COLUMN time_zone char(64) CHARACTER SET latin1 + NOT NULL DEFAULT 'SYSTEM' AFTER originator; + +ALTER TABLE event ADD character_set_client + char(32) collate utf8mb3_bin DEFAULT NULL + AFTER time_zone; +ALTER TABLE event MODIFY character_set_client + char(32) collate utf8mb3_bin DEFAULT NULL; + +ALTER TABLE event ADD collation_connection + char(64) collate utf8mb3_bin DEFAULT NULL + AFTER character_set_client; +ALTER TABLE event MODIFY collation_connection + char(64) collate utf8mb3_bin DEFAULT NULL; + +ALTER TABLE event ADD db_collation + char(64) collate utf8mb3_bin DEFAULT NULL + AFTER collation_connection; +ALTER TABLE event MODIFY db_collation + char(64) collate utf8mb3_bin DEFAULT NULL; + +ALTER TABLE event ADD body_utf8 longblob DEFAULT NULL + AFTER db_collation; +ALTER TABLE event MODIFY body_utf8 longblob DEFAULT NULL; + +alter table event MODIFY definer varchar(384) collate utf8mb3_bin NOT NULL DEFAULT ''; + +# Enable event scheduler if the event table was not up to date before. +set global event_scheduler=original; + +# +# TRIGGER privilege +# + +SET @hadTriggerPriv := 0; +SELECT @hadTriggerPriv :=1 FROM user WHERE Trigger_priv IS NOT NULL; + +ALTER TABLE user ADD Trigger_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Event_priv; +ALTER TABLE user MODIFY Trigger_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Event_priv; + +ALTER TABLE db ADD Trigger_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL; +ALTER TABLE db MODIFY Trigger_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL; + +UPDATE user SET Trigger_priv=Super_priv WHERE @hadTriggerPriv = 0; + +# +# user.Create_tablespace_priv +# + +SET @hadCreateTablespacePriv := 0; +SELECT @hadCreateTablespacePriv :=1 FROM user WHERE Create_tablespace_priv IS NOT NULL; + +ALTER TABLE user ADD Create_tablespace_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Trigger_priv; +ALTER TABLE user MODIFY Create_tablespace_priv enum('N','Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER Trigger_priv; + +UPDATE user SET Create_tablespace_priv = Super_priv WHERE @hadCreateTablespacePriv = 0; + +# +# System versioning +# + +ALTER TABLE user change Truncate_versioning_priv Delete_history_priv enum('N','Y') COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'N'; +ALTER TABLE db change Truncate_versioning_priv Delete_history_priv enum('N','Y') COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'N'; + +SET @had_user_delete_history_priv := 0; +SELECT @had_user_delete_history_priv :=1 FROM user WHERE Delete_history_priv IS NOT NULL; + +ALTER TABLE user add Delete_history_priv enum('N','Y') COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'N' after Create_tablespace_priv; +ALTER TABLE user modify Delete_history_priv enum('N','Y') COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'N'; +ALTER TABLE db add Delete_history_priv enum('N','Y') COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'N' after Trigger_priv; +ALTER TABLE db modify Delete_history_priv enum('N','Y') COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'N'; + +UPDATE user SET Delete_history_priv = Super_priv WHERE @had_user_delete_history_priv = 0; + +ALTER TABLE user ADD plugin char(64) CHARACTER SET latin1 DEFAULT '' NOT NULL AFTER max_user_connections, + ADD authentication_string TEXT NOT NULL AFTER plugin; +ALTER TABLE user CHANGE auth_string authentication_string TEXT NOT NULL; + +ALTER TABLE user ADD password_expired ENUM('N', 'Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER authentication_string; +ALTER TABLE user ADD password_last_changed timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP after password_expired; +ALTER TABLE user ADD password_lifetime smallint unsigned DEFAULT NULL after password_last_changed; +ALTER TABLE user ADD account_locked enum('N', 'Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL after password_lifetime; +ALTER TABLE user ADD is_role enum('N', 'Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER account_locked; +ALTER TABLE user ADD default_role char(128) binary DEFAULT '' NOT NULL AFTER is_role; +ALTER TABLE user ADD max_statement_time decimal(12,6) DEFAULT 0 NOT NULL AFTER default_role; + +-- Somewhere above, we ran ALTER TABLE user .... CONVERT TO CHARACTER SET utf8mb3 COLLATE utf8mb3_bin. +-- we want password_expired column to have collation utf8mb3_general_ci. +-- Order columns correctly that were not ordered until MDEV-23201 (ff8ffef3e1915d7a9caa07d9461cd8d47c4baf98) + +ALTER TABLE user MODIFY plugin char(64) CHARACTER SET latin1 DEFAULT '' NOT NULL AFTER max_user_connections, + MODIFY authentication_string TEXT NOT NULL AFTER plugin, + MODIFY password_expired ENUM('N', 'Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER authentication_string, + MODIFY is_role enum('N', 'Y') COLLATE utf8mb3_general_ci DEFAULT 'N' NOT NULL AFTER password_expired, + MODIFY default_role char(80) binary DEFAULT '' NOT NULL AFTER is_role, + MODIFY max_statement_time decimal(12,6) DEFAULT 0 NOT NULL AFTER default_role, +-- MDEV-24122 formerly mysql5.7 users may have the following columns password_last_changed, +-- password_lifetime and account_locked. Ensure they are beyond the end of the user columns +-- used by MariaDB. MariaDB-10.4 will use these in the creation of mysql.global_priv. +-- password_last_changed has a DEFAULT/ON UPDATE of CURRENT_TIMESTAMP to keep track of +-- time until 10.4 added. + MODIFY IF EXISTS password_last_changed timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP AFTER max_statement_time, + MODIFY IF EXISTS password_lifetime smallint unsigned DEFAULT NULL AFTER password_last_changed, + MODIFY IF EXISTS account_locked enum('N', 'Y') CHARACTER SET utf8mb3 DEFAULT 'N' NOT NULL after password_lifetime; + +-- Checking for any duplicate hostname and username combination are exists. +-- If exits we will throw error. +DELIMITER // +BEGIN NOT ATOMIC + SET @duplicate_hosts=(SELECT count(*) FROM mysql.user GROUP BY user, lower(host) HAVING count(*) > 1 LIMIT 1); + IF @duplicate_hosts > 1 THEN + SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Multiple accounts exist for @user_name, @host_name that differ only in Host lettercase; remove all except one of them'; + END IF; +END // +DELIMITER ; +-- Get warnings (if any) +SHOW WARNINGS; + +# Convering the host name to lower case for existing users +UPDATE user SET host=LOWER( host ) WHERE LOWER( host ) <> host; + +DELIMITER // +if @have_innodb then + # fix bad data when upgrading from unfixed InnoDB (MDEV-13360) + delete from innodb_index_stats where length(table_name) > 64; + delete from innodb_table_stats where length(table_name) > 64; + + # update table_name and timestamp fields in the innodb stat tables + alter table innodb_index_stats modify last_update timestamp not null default current_timestamp on update current_timestamp, modify table_name varchar(199); + alter table innodb_table_stats modify last_update timestamp not null default current_timestamp on update current_timestamp, modify table_name varchar(199); + + alter table innodb_index_stats drop foreign key if exists innodb_index_stats_ibfk_1; +end if // +DELIMITER ; + +# MDEV-4332 longer user names +alter table user modify User char(128) binary not null default ''; +alter table db modify User char(128) binary not null default ''; +alter table tables_priv modify User char(128) binary not null default ''; +alter table columns_priv modify User char(128) binary not null default ''; +alter table procs_priv modify User char(128) binary not null default ''; +alter table proc modify definer varchar(384) collate utf8mb3_bin not null default ''; +alter table proxies_priv modify User char(128) COLLATE utf8mb3_bin not null default ''; +alter table proxies_priv modify Proxied_user char(128) COLLATE utf8mb3_bin not null default ''; +alter table proxies_priv modify Grantor varchar(384) COLLATE utf8mb3_bin not null default ''; +alter table servers modify Username char(128) not null default ''; +alter table procs_priv modify Grantor varchar(384) COLLATE utf8mb3_bin not null default ''; +alter table tables_priv modify Grantor varchar(384) COLLATE utf8mb3_bin not null default ''; + +# Activate the new, possible modified privilege tables +# This should not be needed, but gives us some extra testing that the above +# changes was correct + +flush privileges; + +-- +-- Upgrade help tables +-- + +ALTER TABLE help_category MODIFY url TEXT NOT NULL; +ALTER TABLE help_topic MODIFY url TEXT NOT NULL; + +DELIMITER // +IF 'BASE TABLE' = (select table_type from information_schema.tables where table_schema=database() and table_name='user') THEN + CREATE TABLE IF NOT EXISTS global_priv (Host char(255) binary DEFAULT '', User char(128) binary DEFAULT '', Priv JSON NOT NULL DEFAULT '{}' CHECK(JSON_VALID(Priv)), PRIMARY KEY Host (Host,User)) engine=Aria transactional=1 CHARACTER SET utf8mb3 COLLATE utf8mb3_bin comment='Users and global privileges' + SELECT Host, User, JSON_COMPACT(JSON_OBJECT('access', + 1*('Y'=Select_priv)+ + 2*('Y'=Insert_priv)+ + 4*('Y'=Update_priv)+ + 8*('Y'=Delete_priv)+ + 16*('Y'=Create_priv)+ + 32*('Y'=Drop_priv)+ + 64*('Y'=Reload_priv)+ + 128*('Y'=Shutdown_priv)+ + 256*('Y'=Process_priv)+ + 512*('Y'=File_priv)+ + 1024*('Y'=Grant_priv)+ + 2048*('Y'=References_priv)+ + 4096*('Y'=Index_priv)+ + 8192*('Y'=Alter_priv)+ + 16384*('Y'=Show_db_priv)+ + 32768*('Y'=Super_priv)+ + 65536*('Y'=Create_tmp_table_priv)+ + 131072*('Y'=Lock_tables_priv)+ + 262144*('Y'=Execute_priv)+ + 524288*('Y'=Repl_slave_priv)+ + 1048576*('Y'=Repl_client_priv)+ + 2097152*('Y'=Create_view_priv)+ + 4194304*('Y'=Show_view_priv)+ + 8388608*('Y'=Create_routine_priv)+ + 16777216*('Y'=Alter_routine_priv)+ + 33554432*('Y'=Create_user_priv)+ + 67108864*('Y'=Event_priv)+ + 134217728*('Y'=Trigger_priv)+ + 268435456*('Y'=Create_tablespace_priv)+ + 536870912*('Y'=Delete_history_priv), + 'ssl_type', ssl_type-1, + 'ssl_cipher', ssl_cipher, + 'x509_issuer', x509_issuer, + 'x509_subject', x509_subject, + 'max_questions', max_questions, + 'max_updates', max_updates, + 'max_connections', max_connections, + 'max_user_connections', max_user_connections, + 'max_statement_time', max_statement_time, + 'plugin', if(plugin>'',plugin,if(length(password)=16,'mysql_old_password','mysql_native_password')), + 'authentication_string', if(plugin>'' and authentication_string>'',authentication_string,password), + 'password_last_changed', if(password_expired='Y', 0, if(password_last_changed, UNIX_TIMESTAMP(password_last_changed), UNIX_TIMESTAMP())), + 'password_lifetime', ifnull(password_lifetime, -1), + 'account_locked', 'Y'=account_locked, + 'default_role', default_role, + 'is_role', 'Y'=is_role)) as Priv + FROM user; + DROP TABLE user; +END IF// + +IF 1 = (SELECT count(*) FROM information_schema.VIEWS WHERE TABLE_CATALOG = 'def' and TABLE_SCHEMA = 'mysql' and TABLE_NAME='user' and (DEFINER = 'root@localhost' or (DEFINER = 'mariadb.sys@localhost' and VIEW_DEFINITION LIKE "%'N' AS `password_expired`%"))) THEN + DROP VIEW IF EXISTS mysql.user; +END IF// + +DELIMITER ; + +# MDEV-22683 - upgrade Host and Owner of servers +ALTER TABLE servers + MODIFY Host varchar(2048) NOT NULL DEFAULT '', + MODIFY Owner varchar(512) NOT NULL DEFAULT ''; diff --git a/scripts/mysql_test_data_timezone.sql b/scripts/mysql_test_data_timezone.sql new file mode 100644 index 00000000..8d07d413 --- /dev/null +++ b/scripts/mysql_test_data_timezone.sql @@ -0,0 +1,21 @@ +-- Copyright (C) 2007 MySQL AB +-- Use is subject to license terms +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA + +INSERT INTO time_zone_name (Name, Time_Zone_id) VALUES ('MET', 1), ('UTC', 2), ('Universal', 2), ('Europe/Moscow',3), ('leap/Europe/Moscow',4), ('Japan', 5); +INSERT INTO time_zone (Time_zone_id, Use_leap_seconds) VALUES (1,'N'), (2,'N'), (3,'N'), (4,'Y'), (5,'N'); +INSERT INTO time_zone_transition (Time_zone_id, Transition_time, Transition_type_id) VALUES (1, -1693706400, 0) ,(1, -1680483600, 1) ,(1, -1663455600, 2) ,(1, -1650150000, 3) ,(1, -1632006000, 2) ,(1, -1618700400, 3) ,(1, -938905200, 2) ,(1, -857257200, 3) ,(1, -844556400, 2) ,(1, -828226800, 3) ,(1, -812502000, 2) ,(1, -796777200, 3) ,(1, 228877200, 2) ,(1, 243997200, 3) ,(1, 260326800, 2) ,(1, 276051600, 3) ,(1, 291776400, 2) ,(1, 307501200, 3) ,(1, 323830800, 2) ,(1, 338950800, 3) ,(1, 354675600, 2) ,(1, 370400400, 3) ,(1, 386125200, 2) ,(1, 401850000, 3) ,(1, 417574800, 2) ,(1, 433299600, 3) ,(1, 449024400, 2) ,(1, 465354000, 3) ,(1, 481078800, 2) ,(1, 496803600, 3) ,(1, 512528400, 2) ,(1, 528253200, 3) ,(1, 543978000, 2) ,(1, 559702800, 3) ,(1, 575427600, 2) ,(1, 591152400, 3) ,(1, 606877200, 2) ,(1, 622602000, 3) ,(1, 638326800, 2) ,(1, 654656400, 3) ,(1, 670381200, 2) ,(1, 686106000, 3) ,(1, 701830800, 2) ,(1, 717555600, 3) ,(1, 733280400, 2) ,(1, 749005200, 3) ,(1, 764730000, 2) ,(1, 780454800, 3) ,(1, 796179600, 2) ,(1, 811904400, 3) ,(1, 828234000, 2) ,(1, 846378000, 3) ,(1, 859683600, 2) ,(1, 877827600, 3) ,(1, 891133200, 2) ,(1, 909277200, 3) ,(1, 922582800, 2) ,(1, 941331600, 3) ,(1, 954032400, 2) ,(1, 972781200, 3) ,(1, 985482000, 2) ,(1, 1004230800, 3) ,(1, 1017536400, 2) ,(1, 1035680400, 3) ,(1, 1048986000, 2) ,(1, 1067130000, 3) ,(1, 1080435600, 2) ,(1, 1099184400, 3) ,(1, 1111885200, 2) ,(1, 1130634000, 3) ,(1, 1143334800, 2) ,(1, 1162083600, 3) ,(1, 1174784400, 2) ,(1, 1193533200, 3) ,(1, 1206838800, 2) ,(1, 1224982800, 3) ,(1, 1238288400, 2) ,(1, 1256432400, 3) ,(1, 1269738000, 2) ,(1, 1288486800, 3) ,(1, 1301187600, 2) ,(1, 1319936400, 3) ,(1, 1332637200, 2) ,(1, 1351386000, 3) ,(1, 1364691600, 2) ,(1, 1382835600, 3) ,(1, 1396141200, 2) ,(1, 1414285200, 3) ,(1, 1427590800, 2) ,(1, 1445734800, 3) ,(1, 1459040400, 2) ,(1, 1477789200, 3) ,(1, 1490490000, 2) ,(1, 1509238800, 3) ,(1, 1521939600, 2) ,(1, 1540688400, 3) ,(1, 1553994000, 2) ,(1, 1572138000, 3) ,(1, 1585443600, 2) ,(1, 1603587600, 3) ,(1, 1616893200, 2) ,(1, 1635642000, 3) ,(1, 1648342800, 2) ,(1, 1667091600, 3) ,(1, 1679792400, 2) ,(1, 1698541200, 3) ,(1, 1711846800, 2) ,(1, 1729990800, 3) ,(1, 1743296400, 2) ,(1, 1761440400, 3) ,(1, 1774746000, 2) ,(1, 1792890000, 3) ,(1, 1806195600, 2) ,(1, 1824944400, 3) ,(1, 1837645200, 2) ,(1, 1856394000, 3) ,(1, 1869094800, 2) ,(1, 1887843600, 3) ,(1, 1901149200, 2) ,(1, 1919293200, 3) ,(1, 1932598800, 2) ,(1, 1950742800, 3) ,(1, 1964048400, 2) ,(1, 1982797200, 3) ,(1, 1995498000, 2) ,(1, 2014246800, 3) ,(1, 2026947600, 2) ,(1, 2045696400, 3) ,(1, 2058397200, 2) ,(1, 2077146000, 3) ,(1, 2090451600, 2) ,(1, 2108595600, 3) ,(1, 2121901200, 2) ,(1, 2140045200, 3) ,(3, -1688265000, 2) ,(3, -1656819048, 1) ,(3, -1641353448, 2) ,(3, -1627965048, 3) ,(3, -1618716648, 1) ,(3, -1596429048, 3) ,(3, -1593829848, 5) ,(3, -1589860800, 4) ,(3, -1542427200, 5) ,(3, -1539493200, 6) ,(3, -1525323600, 5) ,(3, -1522728000, 4) ,(3, -1491188400, 7) ,(3, -1247536800, 4) ,(3, 354920400, 5) ,(3, 370728000, 4) ,(3, 386456400, 5) ,(3, 402264000, 4) ,(3, 417992400, 5) ,(3, 433800000, 4) ,(3, 449614800, 5) ,(3, 465346800, 8) ,(3, 481071600, 9) ,(3, 496796400, 8) ,(3, 512521200, 9) ,(3, 528246000, 8) ,(3, 543970800, 9) ,(3, 559695600, 8) ,(3, 575420400, 9) ,(3, 591145200, 8) ,(3, 606870000, 9) ,(3, 622594800, 8) ,(3, 638319600, 9) ,(3, 654649200, 8) ,(3, 670374000, 10) ,(3, 686102400, 11) ,(3, 695779200, 8) ,(3, 701812800, 5) ,(3, 717534000, 4) ,(3, 733273200, 9) ,(3, 748998000, 8) ,(3, 764722800, 9) ,(3, 780447600, 8) ,(3, 796172400, 9) ,(3, 811897200, 8) ,(3, 828226800, 9) ,(3, 846370800, 8) ,(3, 859676400, 9) ,(3, 877820400, 8) ,(3, 891126000, 9) ,(3, 909270000, 8) ,(3, 922575600, 9) ,(3, 941324400, 8) ,(3, 954025200, 9) ,(3, 972774000, 8) ,(3, 985474800, 9) ,(3, 1004223600, 8) ,(3, 1017529200, 9) ,(3, 1035673200, 8) ,(3, 1048978800, 9) ,(3, 1067122800, 8) ,(3, 1080428400, 9) ,(3, 1099177200, 8) ,(3, 1111878000, 9) ,(3, 1130626800, 8) ,(3, 1143327600, 9) ,(3, 1162076400, 8) ,(3, 1174777200, 9) ,(3, 1193526000, 8) ,(3, 1206831600, 9) ,(3, 1224975600, 8) ,(3, 1238281200, 9) ,(3, 1256425200, 8) ,(3, 1269730800, 9) ,(3, 1288479600, 8) ,(3, 1301180400, 9) ,(3, 1319929200, 8) ,(3, 1332630000, 9) ,(3, 1351378800, 8) ,(3, 1364684400, 9) ,(3, 1382828400, 8) ,(3, 1396134000, 9) ,(3, 1414278000, 8) ,(3, 1427583600, 9) ,(3, 1445727600, 8) ,(3, 1459033200, 9) ,(3, 1477782000, 8) ,(3, 1490482800, 9) ,(3, 1509231600, 8) ,(3, 1521932400, 9) ,(3, 1540681200, 8) ,(3, 1553986800, 9) ,(3, 1572130800, 8) ,(3, 1585436400, 9) ,(3, 1603580400, 8) ,(3, 1616886000, 9) ,(3, 1635634800, 8) ,(3, 1648335600, 9) ,(3, 1667084400, 8) ,(3, 1679785200, 9) ,(3, 1698534000, 8) ,(3, 1711839600, 9) ,(3, 1729983600, 8) ,(3, 1743289200, 9) ,(3, 1761433200, 8) ,(3, 1774738800, 9) ,(3, 1792882800, 8) ,(3, 1806188400, 9) ,(3, 1824937200, 8) ,(3, 1837638000, 9) ,(3, 1856386800, 8) ,(3, 1869087600, 9) ,(3, 1887836400, 8) ,(3, 1901142000, 9) ,(3, 1919286000, 8) ,(3, 1932591600, 9) ,(3, 1950735600, 8) ,(3, 1964041200, 9) ,(3, 1982790000, 8) ,(3, 1995490800, 9) ,(3, 2014239600, 8) ,(3, 2026940400, 9) ,(3, 2045689200, 8) ,(3, 2058390000, 9) ,(3, 2077138800, 8) ,(3, 2090444400, 9) ,(3, 2108588400, 8) ,(3, 2121894000, 9) ,(3, 2140038000, 8) ,(4, -1688265000, 2) ,(4, -1656819048, 1) ,(4, -1641353448, 2) ,(4, -1627965048, 3) ,(4, -1618716648, 1) ,(4, -1596429048, 3) ,(4, -1593829848, 5) ,(4, -1589860800, 4) ,(4, -1542427200, 5) ,(4, -1539493200, 6) ,(4, -1525323600, 5) ,(4, -1522728000, 4) ,(4, -1491188400, 7) ,(4, -1247536800, 4) ,(4, 354920409, 5) ,(4, 370728010, 4) ,(4, 386456410, 5) ,(4, 402264011, 4) ,(4, 417992411, 5) ,(4, 433800012, 4) ,(4, 449614812, 5) ,(4, 465346812, 8) ,(4, 481071612, 9) ,(4, 496796413, 8) ,(4, 512521213, 9) ,(4, 528246013, 8) ,(4, 543970813, 9) ,(4, 559695613, 8) ,(4, 575420414, 9) ,(4, 591145214, 8) ,(4, 606870014, 9) ,(4, 622594814, 8) ,(4, 638319615, 9) ,(4, 654649215, 8) ,(4, 670374016, 10) ,(4, 686102416, 11) ,(4, 695779216, 8) ,(4, 701812816, 5) ,(4, 717534017, 4) ,(4, 733273217, 9) ,(4, 748998018, 8) ,(4, 764722818, 9) ,(4, 780447619, 8) ,(4, 796172419, 9) ,(4, 811897219, 8) ,(4, 828226820, 9) ,(4, 846370820, 8) ,(4, 859676420, 9) ,(4, 877820421, 8) ,(4, 891126021, 9) ,(4, 909270021, 8) ,(4, 922575622, 9) ,(4, 941324422, 8) ,(4, 954025222, 9) ,(4, 972774022, 8) ,(4, 985474822, 9) ,(4, 1004223622, 8) ,(4, 1017529222, 9) ,(4, 1035673222, 8) ,(4, 1048978822, 9) ,(4, 1067122822, 8) ,(4, 1080428422, 9) ,(4, 1099177222, 8) ,(4, 1111878022, 9) ,(4, 1130626822, 8) ,(4, 1143327622, 9) ,(4, 1162076422, 8) ,(4, 1174777222, 9) ,(4, 1193526022, 8) ,(4, 1206831622, 9) ,(4, 1224975622, 8) ,(4, 1238281222, 9) ,(4, 1256425222, 8) ,(4, 1269730822, 9) ,(4, 1288479622, 8) ,(4, 1301180422, 9) ,(4, 1319929222, 8) ,(4, 1332630022, 9) ,(4, 1351378822, 8) ,(4, 1364684422, 9) ,(4, 1382828422, 8) ,(4, 1396134022, 9) ,(4, 1414278022, 8) ,(4, 1427583622, 9) ,(4, 1445727622, 8) ,(4, 1459033222, 9) ,(4, 1477782022, 8) ,(4, 1490482822, 9) ,(4, 1509231622, 8) ,(4, 1521932422, 9) ,(4, 1540681222, 8) ,(4, 1553986822, 9) ,(4, 1572130822, 8) ,(4, 1585436422, 9) ,(4, 1603580422, 8) ,(4, 1616886022, 9) ,(4, 1635634822, 8) ,(4, 1648335622, 9) ,(4, 1667084422, 8) ,(4, 1679785222, 9) ,(4, 1698534022, 8) ,(4, 1711839622, 9) ,(4, 1729983622, 8) ,(4, 1743289222, 9) ,(4, 1761433222, 8) ,(4, 1774738822, 9) ,(4, 1792882822, 8) ,(4, 1806188422, 9) ,(4, 1824937222, 8) ,(4, 1837638022, 9) ,(4, 1856386822, 8) ,(4, 1869087622, 9) ,(4, 1887836422, 8) ,(4, 1901142022, 9) ,(4, 1919286022, 8) ,(4, 1932591622, 9) ,(4, 1950735622, 8) ,(4, 1964041222, 9) ,(4, 1982790022, 8) ,(4, 1995490822, 9) ,(4, 2014239622, 8) ,(4, 2026940422, 9) ,(4, 2045689222, 8) ,(4, 2058390022, 9) ,(4, 2077138822, 8) ,(4, 2090444422, 9) ,(4, 2108588422, 8) ,(4, 2121894022, 9) ,(4, 2140038022, 8) ,(5, -1009875600, 1); +INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, `Offset`, Is_DST, Abbreviation) VALUES (1, 0, 7200, 1, 'MEST') ,(1, 1, 3600, 0, 'MET') ,(1, 2, 7200, 1, 'MEST') ,(1, 3, 3600, 0, 'MET') ,(2, 0, 0, 0, 'UTC') ,(3, 0, 9000, 0, 'MMT') ,(3, 1, 12648, 1, 'MST') ,(3, 2, 9048, 0, 'MMT') ,(3, 3, 16248, 1, 'MDST') ,(3, 4, 10800, 0, 'MSK') ,(3, 5, 14400, 1, 'MSD') ,(3, 6, 18000, 1, 'MSD') ,(3, 7, 7200, 0, 'EET') ,(3, 8, 10800, 0, 'MSK') ,(3, 9, 14400, 1, 'MSD') ,(3, 10, 10800, 1, 'EEST') ,(3, 11, 7200, 0, 'EET') ,(4, 0, 9000, 0, 'MMT') ,(4, 1, 12648, 1, 'MST') ,(4, 2, 9048, 0, 'MMT') ,(4, 3, 16248, 1, 'MDST') ,(4, 4, 10800, 0, 'MSK') ,(4, 5, 14400, 1, 'MSD') ,(4, 6, 18000, 1, 'MSD') ,(4, 7, 7200, 0, 'EET') ,(4, 8, 10800, 0, 'MSK') ,(4, 9, 14400, 1, 'MSD') ,(4, 10, 10800, 1, 'EEST') ,(4, 11, 7200, 0, 'EET') ,(5, 0, 32400, 0, 'CJT') ,(5, 1, 32400, 0, 'JST'); +INSERT INTO time_zone_leap_second (Transition_time, Correction) VALUES (78796800, 1) ,(94694401, 2) ,(126230402, 3) ,(157766403, 4) ,(189302404, 5) ,(220924805, 6) ,(252460806, 7) ,(283996807, 8) ,(315532808, 9) ,(362793609, 10) ,(394329610, 11) ,(425865611, 12) ,(489024012, 13) ,(567993613, 14) ,(631152014, 15) ,(662688015, 16) ,(709948816, 17) ,(741484817, 18) ,(773020818, 19) ,(820454419, 20) ,(867715220, 21) ,(915148821, 22); diff --git a/scripts/mysql_test_db.sql b/scripts/mysql_test_db.sql new file mode 100644 index 00000000..c83f2c44 --- /dev/null +++ b/scripts/mysql_test_db.sql @@ -0,0 +1,32 @@ +-- Copyright (c) 2018 MariaDB Foundation +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +CREATE DATABASE IF NOT EXISTS test CHARACTER SET latin1 COLLATE latin1_swedish_ci; + +--- Fill "db" table with default grants for anyone to +--- access database 'test' and 'test_%' if "db" table didn't exist +INSERT INTO mysql.global_priv VALUES ('', 'PUBLIC', '{"access":0,"is_role":true}'); +CREATE TEMPORARY TABLE tmp_db LIKE db; +INSERT INTO tmp_db VALUES ('','test','PUBLIC','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y','Y','Y'); +INSERT INTO tmp_db VALUES ('','test\_%','PUBLIC','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y','Y','Y'); +INSERT INTO db SELECT * FROM tmp_db WHERE @had_db_table=0; +DROP TABLE tmp_db; + +-- Anonymous user with no privileges. +CREATE TEMPORARY TABLE tmp_user_anonymous LIKE global_priv; +INSERT INTO tmp_user_anonymous (host,user) VALUES ('localhost',''); +INSERT INTO tmp_user_anonymous (host,user) SELECT @current_hostname,'' FROM dual WHERE @current_hostname != 'localhost'; +INSERT INTO global_priv SELECT * FROM tmp_user_anonymous WHERE @had_user_table=0; +DROP TABLE tmp_user_anonymous; diff --git a/scripts/mysqlaccess.conf b/scripts/mysqlaccess.conf new file mode 100644 index 00000000..faf47da5 --- /dev/null +++ b/scripts/mysqlaccess.conf @@ -0,0 +1,45 @@ +# ------------------------------------------------------------------------- # +# MySQLaccess version 2.0p2 # +# (c) Yves.Carlier@rug.ac.be, 1997 # +# # +# *** Configuration file *** # +# # +# -Default values read by mysqlaccess during initialisation. # +# This file is looked for in # +# 1) the current directory # +# 2) /etc/ # +# -Options given on the command-line override the values given in here # +# -Given options can't be overruled by empty/blanc options!! # +# ------------------------------------------------------------------------- # + + +# ----------------# +# Global settings # +# --------------- # + #$Param{'host'} = ''; + $Param{'user'} = 'nobody'; + $Param{'db'} = 'test'; + $Param{'password'} = 'foobar'; + $Param{'debug'} = 0; + +# --------------------------# +# Settings for Command-line # +# ------------------------- # +if ($CMD) { + $Param{'superuser'} = 'root'; + $Param{'rhost'} = 'localhost'; + $Param{'spassword'} = ''; + $Param{'brief'} = 1; +} + +# ---------------------# +# Settings for CGI-BIN # +# -------------------- # +if ($CGI) { + $Param{'superuser'} = 'root'; + $Param{'rhost'} = 'localhost'; + $Param{'spassword'} = ''; + $Param{'table'} = 1; +} + +1; #to make require happy diff --git a/scripts/mysqlaccess.sh b/scripts/mysqlaccess.sh new file mode 100644 index 00000000..c9b1b72d --- /dev/null +++ b/scripts/mysqlaccess.sh @@ -0,0 +1,3265 @@ +#!@PERL_PATH@ + +# Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1335 USA + +# **************************** +package MySQLaccess; +#use strict; +use File::Temp qw(tempfile tmpnam); +use Fcntl; + +BEGIN { + # **************************** + # static information... + $VERSION = "2.10, 13 Sep 2019"; + $0 =~ m%/([^/]+)$%o; + $script = $1; + $script = 'MySQLAccess' unless $script; + $script_conf = "$script.conf"; + $script_log = $ENV{'HOME'}."/$script.log"; + + # **************************** + # information on MariaDB + $MYSQL = '@bindir@/mariadb'; # path to mariadb executable + $SERVER = '3.21'; + $MYSQL_OPT = ' --batch --unbuffered'; + $ACCESS_DB = 'mysql'; # name of DB with grant-tables + $ACCESS_H = 'host'; # + $ACCESS_U = 'user'; # + $ACCESS_D = 'db'; # + # Add/Edit privileges + $ACCESS_H_TMP = 'host_tmp'; + $ACCESS_U_TMP = 'user_tmp'; + $ACCESS_D_TMP = 'db_tmp'; + $ACCESS_H_BCK = 'host_backup'; + $ACCESS_U_BCK = 'user_backup'; + $ACCESS_D_BCK = 'db_backup'; + $DIFF = '/usr/bin/diff'; + $MYSQLDUMP = '@bindir@/mariadb-dump'; + #path to mariadb-dump executable + + $MYSQLADMIN= 'http://foobar.com/MySQLadmin'; + #URL of CGI for manipulating + #the temporary grant-tables +} + +END { + unlink $MYSQL_CNF if defined $MYSQL_CNF and not $DEBUG; +} + +$INFO = <<"_INFO"; +-------------------------------------------------------------------------- + mysqlaccess (Version $VERSION) + ~~~~~~~~~~~ + Copyright (C) 1997,1998 Yves.Carlier\@rug.ac.be + University of Ghent (RUG), Belgium + Administratieve Informatieverwerking (AIV) + + report the access-privileges for a USER from a HOST to a DB + + Many thanks go to <monty\@mysql.com> and <psmith\@BayNetworks.COM> + for their suggestions, debugging and patches. + + use `$script -?' to get more information on available options. + + From version 2.0x, $script can also be used through a WEB-browser + if it is ran as a CGI-script. (See the release-notes) + +-------------------------------------------------------------------------- +_INFO + +$OPTIONS = <<_OPTIONS; + +Usage: $script [host [user [db]]] OPTIONS + + -?, --help display this helpscreen and exit + -v, --version print information on the program `$script' + + -u, --user=# username for logging in to the db + -p, --password=# validate password for user + -h, --host=# name or IP-number of the host + -d, --db=# name of the database + + -U, --superuser=# connect as superuser + -P, --spassword=# password for superuser + -H, --rhost=# remote MariaDB-server to connect to + --old_server connect to old MariaDB-server (before v3.21) which + does not yet know how to handle full where clauses. + + -b, --brief single-line tabular report + -t, --table report in table-format + + --relnotes print release-notes + --plan print suggestions/ideas for future releases + --howto some examples of how to run `$script' + --debug=N enter debuglevel N (0..3) + + --copy reload temporary grant-tables from original ones + --preview show differences in privileges after making + changes in (temporary) grant-tables + --commit copy grant-rules from temporary tables to grant-tables + (!don't forget to do an mysqladmin reload) + --rollback undo the last changes to the grant-tables. + + Note: + At least the user and the db must be given (even with wildcards) + If no host is given, `localhost' is assumed + Wilcards (*,?,%,_) are allowed for host, user and db, but be sure + to escape them from your shell!! (ie type \\* or '*') +_OPTIONS + +$RELEASE = <<'_RELEASE'; + +Release Notes: +------------- + 0.1-beta1: internal + - first trial. + + 0.1-beta2: (1997-02-27) + - complete rewrite of the granting-rules, based on the documentation + found in de FAQ. + - IP-number and name for a host are equiv. + + 0.1-beta3: (1997-03-10) + - more information + - 'localhost' and the name/ip of the local machine are now equiv. + + 0.1-beta4: (1997-03-11) + - inform the user if he has not enough priv. to read the mysql db + + 1.0-beta1: (1997-03-12) + suggestions by Monty: + - connect as superuser with superpassword. + - mysqlaccess could also notice if all tables are empty. This means + that all user have full access! + - It would be nice if one could optionally start mysqlaccess without + any options just the arguments 'user db' or 'host user db', where + host is 'localhost' if one uses only two arguments. + + 1.0-beta2: (1997-03-14) + - bugfix: translation to reg.expr of \_ and \%. + - bugfix: error in matching regular expression and string given + by user which resulted in + 'test_123' being matched with 'test' + + 1.0-beta3: (1997-03-14) + - bugfix: the user-field should not be treated as a sql-regexpr, + but as a plain string. + - bugfix: the host-table should not be used if the host isn't empty in db + or if the host isn't emty in user + (Monty) + + 1.0-beta4: (1997-03-14) + - bugfix: in an expression "$i = $j or $k", the '=' binds tighter than the or + which results in problems... + (by Monty) + - running mysqlaccess with "perl -w" gives less warnings... ;-) + + 1.0-beta5: (1997-04-04) + - bugfix: The table sorting was only being applied to the "user" table; all + the tables need to be sorted. Rewrote the sort algorithm, and + the table walk algorithm (no temp file anymore), and various + other cleanups. I believe the access calculation is 100% correct. + (by Paul D. Smith <psmith\@baynetworks.com>) + - Allow the debug level to be set on the cmd line with --debug=N. + (by Paul D. Smith <psmith\@baynetworks.com>) + - More -w cleanups; should be totally -w-clean. + (by Paul D. Smith <psmith\@baynetworks.com>) + + 1.1-beta1: (1997-04-xx) + 1.1-beta2: (1997-04-11) + - new options: + --all_users : report access-rights for all possible users + --all_dbs : report access-rights for all possible dbs + --all_hosts : report access-rights for all possible hosts + --brief : as brief as possible, don't mention notes,warnings and rules + --password : validate password for user + - layout: long messages are wrapped on the report. + - functionality: + more descriptive notes and warnings + wildcards (*,?) are allowed in the user,host and db options + setting xxxx=* is equiv to using option --all_xxxx + note: make sure you escape your wildcards, so they don't get + interpreted by the shell. use \* or '*' + - bugfix: Fieldnames which should be skipped on the output can now have + a first capital letter. + - bugfix: any option with a '.' (eg ip-number) was interpreted as + a wildcard-expression. + - bugfix: When no entry was found in the db-table, the default accessrights are + N, instead of the faulty Y in a previous version. + + 1.1-beta-3 : (1997-04-xx) + 1.1-beta-4 : (1997-04-xx) + 1.1-beta-5 : (1997-04-xx) + 1.1 : (1997-04-28) + - new options: + --rhost : name of mysql-server to connect to + --plan : print suggestions/ideas for future releases + --relnotes : display release-notes + --howto : display examples on how to use mysqlaccess + --brief : single-line tabular output + - functionality/bugfix: + * removed options --all_users,--all_dbs,--all_hosts, which + were redundant with the wildcard-expressions for the corresponding + options. They made the processing of the commandline too painful + and confusing ;-) + (suggested by psmith) + * redefined the option --brief, which now gives a single-line + tabular output + * Now we check if the right version of the mysql-client is used, + since we might use an option not yet implemented in an + older version (--unbuffered, since 3.0.18) + Also the error-messages the mysql-client reports are + better interpreted ;-) + * Wildcards can now be given following the SQL-expression + (%,_) and the Regular-expression (*,?) syntax. + - speed: we now open a bidirectional pipe to the mysql-client, and keep + it open throughout the whole run. Queries are written to, + and the answers read from the pipe. + (suggested by monty) + - bugfixes: + * the Rules were not properly reset over iterations + * when in different tables the field-names were not identical, + eg. Select_priv and select_priv, they were considered as + definitions of 2 different access-rights. + * the IP-number of a host with a name containing wildcards should + not be searched for in Name2IP and IP2Name. + * various other small things, pointed out by <monty> and <psmith> + + 1.2 : (1997-05-13) + - bugfix: + * Fixed bug in acl with anonymous user: Now if one gets accepted by the + user table as a empty user name, the user name is set to '' when + checking against the 'db' and 'host' tables. (Bug fixed in MySQL3.20.19) + + 1.2-1 : (1997-xx-xx) + - bugfix: + * hashes should be initialized with () instead of {} <psmith> + * "my" variable $name masks earlier declaration in same scope, + using perl 5.004 <????> + + 1.2-2 : (1997-06-10) + + 2.0p1-3 : (1997-10-xx) + - new + * packages + * log-file for debug-output : /tmp/mysqlaccess.log + * default values are read from a configuration file $script.conf + first this file is looked for in the current directory; if not + found it is looked for in @sysconfdir@ + Note that when default-values are given, these can't get overridden + by empty (blanc) values! + * CGI-BIN version with HTML and forms interface. Simply place the + script in an ScriptAliased directory, make the configuration file + available in the that directory or in @sysconfdir@, and point your browser + to the right URL. + * copy the grant-rules to temporary tables, where you are safe to + play with them. + * preview changes in privileges after changing grant-rules, + before taking them into production + * copy the new grant-rules from the temporary tables back to the + grant-tables. + * Undo all changes made in the grant-tables (1-level undo). + -new options: + * --table : as opposite of the --brief option. + * --copy : (re)load temporary grant-tables from original ones. + * --preview : preview changes in privileges after changing + some or more entries in the grant-tables. + * --commit : copy grant-rules from temporary tables to grant-tables + (!don't forget to do an mysqladmin reload) + * --rollback: undo the last changes to the grant-tables. + + - bugfix: + * if the table db is empty, mysqlaccess freezed + (by X Zhu <X.Zhu@Bradford.ac.uk>) + + 2.0 : (1997-10-09) + - fixed some "-w" warnings. + - complain when certain programs and paths can't be found. + + 2.01 : (1997-12-12) + - bugfix: + * rules for db-table where not calculated and reported correctly. + 2.02 : (1998-01-xx) + - bugfix: + * Privileges of the user-table were not AND-ed properly with the + other privileges. (reported by monty) + - new option: + * --old_server: mysqlaccess will now use a full where clause when + retrieving information from the MySQL-server. If + you are connecting to an old server (before v3.21) + then use the option --old_server. + 2.03 : (1998-02-27) + - bugfix: + * in Host::MatchTemplate: incorrect match if host-field was left empty. + + 2.04-alpha1 : (2000-02-11) + Closes vulnerability due to former implementation requiring passwords + to be passed on the command line. + - functionality + Option values for --password -p -spassword -P may now be omitted from + command line, in which case the values will be prompted for. + (fix supplied by Steve Harvey <sgh@vex.net>) + + 2.05: (2000-02-17) Monty + Moved the log file from /tmp to ~ + + 2.06: Don't print '+++USING FULL WHERE CLAUSE+++' + +_RELEASE + +$TODO = <<_TODO; + + Plans: + ----- + -a full where clause is use now. How can we handle older servers? + -add some more functionality for DNS. + -select the warnings more carefuly. + >> I think that the warnings should either be enhanced to _really_ + >> understand and report real problems accurately, or restricted to + >> only printing things that it knows with 100% certainty. <psmith) + >> Why do I have both '%' and 'any_other_host' in there? Isn't that + >> the same thing? I think it's because I have an actual host '%' in + >> one of my tables. Probably the script should catch that and not + >> duplicate output. <psmith> + +_TODO + +# From the FAQ: the Grant-algorithm +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# The host table is mainly to maintain a list of "secure" servers. +# At TCX hosts contain a list of all machines on local network. These are granted +# all privileges. +# Technically the user grant is calculated by: +# +# 1.First sort all entries by host by putting host without wildcards first, +# after this host with wildcards and entries with host = ". +# Under each host sort user by the same criterias. +# 2.Get grant for user from the "db" table. +# 3.If hostname is "empty" for the found entry, AND the privileges with +# the privileges for the host in "host" table. +# (Remove all which is not "Y" in both) +# 4.OR (add) the privileges for the user from the "user" table. +# (add all privileges which is "Y" in "user") +# +# When matching, use the first found match. +# +# ----------------------------------------------------------------------------------- + +$HOWTO = <<_HOWTO; + +Examples of how to call $script: +~~~~~~~~ +1)Calling $script with 2 arguments: + + \$ $script root mysql + ->report rights of user root logged on at the local host in db mysql + + Access-rights + for USER 'root', from HOST 'localhost', to DB 'mysql' + +-----------------+---+ +-----------------+---+ + | select_priv | Y | | drop_priv | Y | + | insert_priv | Y | | reload_priv | Y | + | update_priv | Y | | shutdown_priv | Y | + | delete_priv | Y | | process_priv | Y | + | create_priv | Y | | file_priv | Y | + +-----------------+---+ +-----------------+---+ + BEWARE: Everybody can access your DB as user 'root' + : WITHOUT supplying a password. Be very careful about it!! + + The following rules are used: + db : 'No matching rule' + host : 'Not processed: host-field is not empty in db-table.' + user : 'localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y' + +2)Calling $script with 3 arguments: + + \$ $script foo.bar nobody Foo + ->report rights of user root logged in at machine foobar to db Foo + + Access-rights + for USER 'nobody', from HOST 'foo.bar', to DB 'Foo' + +-----------------+---+ +-----------------+---+ + | select_priv | Y | | drop_priv | N | + | insert_priv | Y | | reload_priv | N | + | update_priv | Y | | shutdown_priv | N | + | delete_priv | Y | | process_priv | N | + | create_priv | N | | file_priv | N | + +-----------------+---+ +-----------------+---+ + BEWARE: Everybody can access your DB as user 'nobody' + : WITHOUT supplying a password. Be very careful about it!! + + The following rules are used: + db : 'foo.bar','Foo','nobody','Y','Y','Y','N','N','N' + host : 'Not processed: host-field is not empty in db-table.' + user : 'foo.bar','nobody','','N','N','N','Y','N','N','N','N','N','N' + +3)Using wildcards: + + \$ $script \\* nobody Foo --brief + ->report access-rights of user nobody from all machines to db Foo, + and use a matrix-report. + + Sel Ins Upd Del Crea Drop Reld Shut Proc File Host,User,DB + ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -------------------- + Y Y Y Y N N N N N N localhost,nobody,Foo + N N N N N N N N N N %,nobody,Foo + N N N N N N N N N N any_other_host,nobody,Foo + +_HOWTO + + +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # +# START OF THE PROGRAM # +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # + +use Getopt::Long; +use Sys::Hostname; +use IPC::Open3; + + +# **************************** +# debugging flag +# can be set to 0,1,2,3 +# a higher value gives more info +# ! this can also be set on the command-line + $DEBUG = 0; + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>8 +# Normally nothing should be changed beneeth this line + + +# **************************** +# no caching on STDOUT + $|=1; + + $MYSQL_CNF = tmpnam(); + %MYSQL_CNF = (client => { }, + mysql => { }, + mysqldump => { }, + ); + + + +$NEW_USER = 'ANY_NEW_USER'; +$NEW_DB = 'ANY_NEW_DB' ; + + +# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # +# mysqlaccess: # +# ~~~~~~~~~~~ # +# Lets get to it, # +# and start the program by processing the parameters # +# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # + +($CMD,$CGI) = GetMode(); + +# **************************** +# the copyright message should +# always be printed (once) +MySQLaccess::Report::Print_Header(); + +# ***************************** +# Read configuration-file + MySQLaccess::Debug::Print(1, "Reading configuration file..."); + if (-f "@sysconfdir@/$script_conf") { + print "Configuration file '$script_conf' is found in '@sysconfdir@/'\n"; + require "@sysconfdir@/$script_conf"; + } + elsif (-f "@prefix@/$script_conf") { + print "Configuration file '$script_conf' is found in '@prefix@/'\n"; + require "@prefix@/$script_conf"; + } + elsif (-f "./$script_conf") { + print "\nERROR! Configuration file '$script_conf' is found in the current "; + print "directory.\nThe permissible locations for this file are either "; + print "@sysconfdir@/ or @prefix@/\n"; + print "Please move it to one of these locations and retry.\n\n"; + exit 0; + } + + +# **************************** +# Read in all parameters +if ($MySQLaccess::CMD) { #command-line version + # ---------------------------- + # Get options from commandline + $Getopt::Long::ignorecase=0; #case sensitive options + if ( grep(/\-\?/,@ARGV) ) { MySQLaccess::Report::Print_Usage(); exit 0; } + GetOptions("help" => \$Param{'help'} + ,"host|h=s" => \$Param{'host'} + ,"user|u=s" => \$Param{'user'} + ,"password|p:s" => \$Param{'password'} + ,"db|d=s" => \$Param{'db'} + ,"superuser|U=s" => \$Param{'superuser'} + ,"spassword|P:s" => \$Param{'spassword'} + ,"rhost|H=s" => \$Param{'rhost'} + ,"old_server" => \$Param{'old_server'} + ,"debug=i" => \$Param{'DEBUG'} + ,"brief|b" => \$Param{'brief'} + ,"table|t" => \$Param{'table'} + ,"relnotes" => \$Param{'relnotes'} + ,"plan" => \$Param{'plan'} + ,"howto" => \$Param{'howto'} + ,"version|v" => \$Param{'version'} + ,"preview" => \$Param{'preview'} + ,"copy" => \$Param{'copy'} + ,"commit" => \$Param{'commit'} + ,'rollback' => \$Param{'rollback'} + ); + + # ----------------------------- + # set DEBUG + $DEBUG = $Param{'DEBUG'} if ($Param{'DEBUG'}>=$DEBUG); + + # ----------------------------- + # check for things which aren't + # declared as options: + # 2 arguments: (user,db) -> ('localhost','user','db') + if ($#ARGV == 1) { + MySQLaccess::Debug::Print(2,"$script called with 2 arguments:"); + $Param{'host'} = $Param{'host'} || 'localhost'; + $Param{'user'} = $ARGV[0] || $Param{'user'}; + $Param{'db'} = $ARGV[1] || $Param{'db'}; + } + # 3 arguments: (host,user,db) + if ($#ARGV == 2) { + MySQLaccess::Debug::Print(2,"$script called with 3 arguments:"); + $Param{'host'} = $ARGV[0] || $Param{'host'}; + $Param{'user'} = $ARGV[1] || $Param{'user'}; + $Param{'db'} = $ARGV[2] || $Param{'db'}; + } + + # ------------------------------------- + # prompt for user password if requested + if ( defined($Param{'password'}) && length($Param{'password'}) == 0 ) { + $Param{'password'} = PromptPass( + "Password for MySQL user $Param{'user'}: "); + } +} +if ($MySQLaccess::CGI) { #CGI-version + require CGI; + $Q = new CGI; + $Param{'help'} = $Q->param('help') ; + $Param{'host'} = $Q->param('host') || $Q->param('h') || $Param{'host'}; + $Param{'user'} = $Q->param('user') || $Q->param('u') || $Param{'user'}; + $Param{'db'} = $Q->param('db') || $Q->param('d') || $Param{'db'}; + $Param{'password'} = $Q->param('password') || $Q->param('p') || $Param{'password'}; + $Param{'superuser'} = $Q->param('superuser') || $Q->param('U') || $Param{'superuser'}; + $Param{'spassword'} = $Q->param('spassword') || $Q->param('P') || $Param{'spassword'}; + $Param{'rhost'} = $Q->param('rhost') || $Q->param('H') || $Param{'rhost'}; + $Param{'old_server'}= $Q->param('old_server')|| $Param{'old_server'}; + $Param{'debug'} = $Q->param('debug') || $Param{'debug'}; + $Param{'brief'} = $Q->param('brief') || $Param{'brief'}; + $Param{'table'} = $Q->param('table') || $Param{'table'}; + $Param{'relnotes'} = $Q->param('relnotes'); + $Param{'plan'} = $Q->param('plan'); + $Param{'howto'} = $Q->param('howto'); + $Param{'version'} = $Q->param('version') ? $Q->param('version') : $Q->param('v'); + $Param{'edit'} = $Q->param('edit'); + $Param{'preview'} = $Q->param('preview'); + $Param{'copy'} = $Q->param('copy'); + $Param{'commit'} = $Q->param('commit'); + $Param{'rollback'} = $Q->param('rollback'); + # ----------------------------- + # set DEBUG + $DEBUG = $Q->param('debug') if ($Q->param('debug')>=$DEBUG); +} + +# ---------------------- +# brief and table-format +# exclude each-other +# table-format is preferred +if (defined($Param{'table'})) { undef($Param{'brief'}); } +if (defined($Param{'preview'}) or + defined($Param{'copy'}) or + defined($Param{'commit'}) or + defined($Param{'rollback'}) ) { $Param{'edit'}='on'; } + + +# ---------------------- +# if no host is given +# assume we mean 'localhost' +if (!defined($Param{'host'})) { $Param{'host'}='localhost'; } + +# ---------------------- +# perform some checks +# -> eliminate 'broken pipe' error +push(@MySQLaccess::Grant::Error,'not_found_mysql') if !(-x $MYSQL); +push(@MySQLaccess::Grant::Error,'not_found_diff') if !(-x $DIFF); +push(@MySQLaccess::Grant::Error,'not_found_mysqldump') if !(-x $MYSQLDUMP); +if (@MySQLaccess::Grant::Error) { + MySQLaccess::Report::Print_Error_Messages() ; + exit 0; +} + +#----------------------- +# get info/help if necc. +$print_usage=1; +if ( defined($Param{'version'}) ) { + MySQLaccess::Report::Print_Version(); + $print_usage=0; + MySQLaccess::Report::Print_Footer(); + MySQLaccess::DB::CloseConnection(); + exit 0; +# exit 0; +} +if ( defined($Param{'relnotes'}) ) { + MySQLaccess::Report::Print_Relnotes(); + $print_usage=0; + MySQLaccess::Report::Print_Footer(); + MySQLaccess::DB::CloseConnection(); + exit 0; +# exit 0; +} +if ( defined($Param{'plan'}) ) { + MySQLaccess::Report::Print_Plans(); + $print_usage=0; + MySQLaccess::Report::Print_Footer(); + MySQLaccess::DB::CloseConnection(); + exit 0; +# exit 0; +} +if ( defined($Param{'howto'}) ) { + MySQLaccess::Report::Print_HowTo(); + $print_usage=0; + MySQLaccess::Report::Print_Footer(); + MySQLaccess::DB::CloseConnection(); + exit 0; +# exit 0; +} + +# ----------------------------- +# generate a help-screen in CMD-mode +# or a blanc form in CGI-mode +if ( defined($Param{'help'}) + or !defined($Param{'user'}) + or !defined($Param{'host'}) + or !defined($Param{'db'}) + ) { + push(@MySQLaccess::Grant::Error,'user_required') unless defined($Param{'user'}); + push(@MySQLaccess::Grant::Error,'db_required') unless defined($Param{'db'}); + push(@MySQLaccess::Grant::Error,'host_required') unless defined($Param{'host'}); + MySQLaccess::Report::Print_Usage() if $print_usage; + exit 0; +} + + +# ---------------------------- +# get hostname and local-ip +# for localhost +$localhost = MySQLaccess::Host::LocalHost(); +$local_ip = MySQLaccess::Host::Name2IP($localhost); +$MySQLaccess::Host::localhost = MySQLaccess::Host::LocalHost(); +$MySQLaccess::Host::local_ip = MySQLaccess::Host::Name2IP($localhost); +MySQLaccess::Debug::Print(3, "localhost name=$localhost, ip=$local_ip"); + +#----------------------------------- +# version of MySQL-server to connect +# to determine use of full where clause +$MySQLaccess::Host::SERVER = $Param{'old_server'} ? '3.20' : $SERVER; + +#--------------------------------- +# create the config file for mysql and mysqldump +# to avoid passing authentication info on the command line +# +MergeConfigFiles(); +die "Unsafe config file found: $unsafeConfig\n" if $unsafeConfig; +if (defined($Param{'superuser'})) { + $MYSQL_CNF{'mysql'}{'user'} = $Param{'superuser'}; + $MYSQL_CNF{'mysqldump'}{'user'} = $Param{'superuser'}; +} +if (defined($Param{'spassword'})) { + if ( $CMD && length($Param{'spassword'}) == 0 ) { + $Param{'spassword'} = + PromptPass("Password for MySQL superuser $Param{'superuser'}: "); + } + if ( length($Param{'spassword'}) > 0 ) { + $MYSQL_CNF{'mysql'}{'password'} = $Param{'spassword'}; + $MYSQL_CNF{'mysqldump'}{'password'} = $Param{'spassword'}; + } +} +WriteTempConfigFile(); + +#--------------------------------- +# Inform user if he has not enough +# privileges to read the access-db +if ( $nerror=MySQLaccess::DB::OpenConnection() ) { + MySQLaccess::Report::Print_Error_Access($nerror); + exit 0; +} + +# ----------------------- +# Read MySQL ACL-files +if ($nerror=MySQLaccess::Grant::ReadTables()) { + MySQLaccess::Report::Print_Error_Access($nerror); + exit 0; +}; +if ($Param{'edit'} and $nerror=MySQLaccess::Grant::ReadTables('tmp')) { + MySQLaccess::Report::Print_Error_Access($nerror); + exit 0; +} + +#--------------------------------- +# reload temporay grant-tables +# with data from original ones +if ( defined($Param{'copy'}) ) { + $nerror=MySQLaccess::DB::LoadTmpTables(); + if ($nerror) { + MySQLaccess::Report::Print_Error_Access($nerror); + exit 0; + } + my $msg = "The grant-rules are copied from the grant-tables to\n" + . "the temporary tables."; + MySQLaccess::Report::Print_Message([$msg]); +# MySQLaccess::Report::Print_Footer(); +# MySQLaccess::DB::CloseConnection(); +# exit 0; +} + + +#--------------------------------- +# preview result of changes in the +# grant-tables +if ( defined($Param{'preview'}) ) { + $aref=MySQLaccess::Grant::Diff_Privileges(); + MySQLaccess::Report::Print_Diff_ACL($aref); +# MySQLaccess::Report::Print_Footer(); +# MySQLaccess::DB::CloseConnection(); +# exit 0; +} + + +#--------------------------------- +# reload grant-tables +# with data from temporary tables +if ( defined($Param{'commit'}) ) { + if ($nerror = MySQLaccess::DB::CommitGrantTables()) { + MySQLaccess::Report::Print_Error_Access($nerror); + exit 0; + } + my $msg = "The grant-rules have been copied from the temporary tables\n" + . "to the grant-tables."; + my $msg1= "Don't forget to do an 'mysqladmin reload' before these\n" + . "changes take effect."; + my $msg2= "A backup-version of your original grant-rules are saved in the\n" + . "backup-tables, so you can always perform a 1-level rollback."; + MySQLaccess::Report::Print_Message([$msg,$msg1,$msg2]); +# MySQLaccess::Report::Print_Footer(); +# MySQLaccess::DB::CloseConnection(); +# exit 0; +} + +#--------------------------------- +# restore previous grant-rules +# with data from backup tables +if ( defined($Param{'rollback'}) ) { + if ($nerror = MySQLaccess::DB::RollbackGrantTables()) { + MySQLaccess::Report::Print_Error_Access($nerror); + exit 0; + } + my $msg = "The old grant-rules have been copied back from the backup tables\n" + . "to the grant-tables."; + my $msg1= "Don't forget to do an 'mysqladmin reload' before these\n" + . "changes take effect."; + MySQLaccess::Report::Print_Message([$msg,$msg1]); +# MySQLaccess::Report::Print_Footer(); +# MySQLaccess::DB::CloseConnection(); +# exit 0; +} +#---------------------------------- +# show edit-taskbar +if ( defined($Param{'edit'})) { + if ($MySQLaccess::CGI ) { + MySQLaccess::Report::Print_Edit(); + $print_usage=0; + MySQLaccess::Report::Print_Footer(); + MySQLaccess::DB::CloseConnection(); + exit 0; + } + else { + MySQLaccess::Report::Print_Edit(); + $print_usage=0; + MySQLaccess::Report::Print_Footer(); + MySQLaccess::DB::CloseConnection(); + exit 0; + } +} + + +# ----------------------------- +# Build list of users,dbs,hosts +# to process... +@all_dbs = @{MySQLaccess::DB::Get_All_dbs($Param{'db'})}; +@all_users = @{MySQLaccess::DB::Get_All_users($Param{'user'})}; +@all_hosts = @{MySQLaccess::DB::Get_All_hosts($Param{'host'})}; +#if EDIT-mode +#@all_dbs_tmp = @{MySQLaccess::DB::Get_All_dbs($Param{'db'},'tmp')}; +#@all_users_tmp = @{MySQLaccess::DB::Get_All_users($Param{'user'},'tmp')}; +#@all_hosts_tmp = @{MySQLaccess::DB::Get_All_hosts($Param{'host'},'tmp')}; + +# ----------------------------- +# Report access-rights for each +# tuple (host,user,db) +#$headers=0; +my %Access = (); +foreach $host (@all_hosts) { + foreach $user (@all_users) { + foreach $db (@all_dbs) { + MySQLaccess::Grant::Initialize(); + %Access = MySQLaccess::Grant::Get_Access_Rights($host,$user,$db); + MySQLaccess::Report::Print_Access_rights($host,$user,$db,\%Access); + } + } +} + +# ----------------------------- +# End script +MySQLaccess::Report::Print_Footer(); +MySQLaccess::DB::CloseConnection(); +exit 0; + +############################################################# +# FUNCTIONS # +############### +sub GetMode { + my $cmd=0; + my $cgi=0; + if (defined($ENV{'HTTP_HOST'})) { $cmd=0; $cgi=1; } + else { $cmd=1; $cgi=0; } + return ($cmd,$cgi); +} + +# ================================ +# sub PromptPass +# prompt tty for a password +# ================================ +sub PromptPass { + my ($prompt) = @_; + my $password; + $ENV{PATH} = "/bin:/usr/bin"; + $ENV{IFS} = " \t\n"; + $ENV{SHELL} = "/bin/sh"; + system "stty -echo"; + print $prompt; + chomp($password = <STDIN>); + print "\n"; + system "stty echo"; + $password; +} + +# ================================= +# sub CheckUnsafeFile +# tell if a config file containing a password is unsafe +# ================================= +sub CheckUnsafeFile { + my ($fname) = @_; + my ($dev, $ino, $mode, $nlink, + $uid, $gid, $rdev, $size, + $atime, $mtime, $ctime, $blksize, $blocks) = stat($fname); + + if ( $uid != $< ) { # unsafe if owned by other than current user + return 1; + } + if ( $mode & 066 ) { # unsafe if accessible by other + return 1; + } + $fname =~ s#/[^/]+$##; + if ( (length $fname) > 0 ) { + return CheckUnsafeDir($fname); + } + return 0; +} + +# ================================= +# sub CheckUnsafeDir +# tell if a directory is unsafe +# ================================= +sub CheckUnsafeDir { + my ($fname) = @_; + my ($dev, $ino, $mode, $nlink, + $uid, $gid, $rdev, $size, + $atime, $mtime, $ctime, $blksize, $blocks) = stat($fname); + + # not owned by me or root + if ( ($uid != $<) && ($uid != 0) ) { + return 1; + } + if ( $mode & 022 ) { # unsafe if writable by other + return 1 unless $mode & 01000; # but sticky bit ok + } + $fname =~ s#/[^/]+$##; + if ( (length $fname) > 0 ) { + return CheckUnsafeDir($fname); + } + return 0; +} + +# ================================= +# sub MergeConfigFile +# merge data from .cnf file +# ================================= +sub MergeConfigFile { + my ($fname) = @_; + my ($group, $item, $value); + if ( open CNF, $fname ) { + while (<CNF>) { + s/^\s+//; + next if /^[#;]/; + if ( /\[\s*(\w+)\s*]/ ) { + $group = $1; + $group =~ tr/A-Z/a-z/; + if ( !exists $MYSQL_CNF{$group} ) { + undef $group; + } + } elsif ( defined $group ) { + ($item, $value) = /((?:\w|-)+)\s*=\s*(\S+)/; + # don't unquote backslashes as we just write it back out + if ( defined $item ) { + if ( $item =~ /^password$/ ) { + if ( CheckUnsafeFile($fname) ) { + $unsafeConfig = $fname; + } + } + if ( $group eq 'client' || $group eq "client-server") { + $MYSQL_CNF{'mysql'}{$item} = $value; + $MYSQL_CNF{'mysqldump'}{$item} = $value; + } else { + $MYSQL_CNF{$group}{$item} = $value; + } + } + } + } + close(CNF); + } +} + +# ================================= +# sub MergeConfigFiles +# merge options from config files +# NOTE: really should do two separate merges for each +# client to exactly duplicate order of resulting argument lists +# ================================= +sub MergeConfigFiles { + my ($name,$pass,$uid,$gid,$quota,$comment,$gcos,$dir,$shell) = getpwuid $<; + MergeConfigFile("@prefix@/my.cnf"); + MergeConfigFile("@sysconfdir@/my.cnf"); + MergeConfigFile("$dir/.my.cnf"); +} + +# ================================= +# sub WriteTempConfigFile +# write +# ================================= +sub WriteTempConfigFile { + sysopen CNFFILE, $MYSQL_CNF, O_RDWR|O_CREAT|O_EXCL, 0700 + or die "sysopen $MYSQL_CNF: $!"; + + # groups may be in any order, generic groups such as [client] assumed + # here to be empty + foreach $group (keys %MYSQL_CNF) { + print CNFFILE "[$group]\n"; + foreach $item (keys %{$MYSQL_CNF{$group}}) { + if ( defined $MYSQL_CNF{$group}{$item} ) { + print CNFFILE "$item=$MYSQL_CNF{$group}{$item}\n"; + } else { + print CNFFILE "$item\n"; + } + } + print CNFFILE "\n"; + } + close(CNFFILE); +} + +###################################################################### +package MySQLaccess::DB; +########### +BEGIN { + $DEBUG = 2; + $DEBUG = $MySQLaccess::DEBUG unless ($DEBUG); + # Error-messages from the MySQL client + %ACCESS_ERR= ('Access_denied' => 'Access denied' + ,'Dbaccess_denied' => 'Access to database denied' + ,'Unrecognized_option' => 'unrecognized option' + ,'Unknown_table' => "Can't find file:" + ,'unknown_error' => '^ERROR:' + ); +} +# ###################################### +# Connecting to the MYSQL DB +# ====================================== +# sub OpenConnection +# Open an connection to the mysql-db +# questions to MYSQL_Q +# answers from MYSQL_A +# ====================================== +sub OpenConnection { + my $pid; + MySQLaccess::Debug::Print(2,"OpenConnection:"); + + # check path to mysql-client executable + if (! -f $MySQLaccess::MYSQL) { + if ($MySQLaccess::CMD) { die "Could not find MySQL-client '$MySQLaccess::MYSQL'"; } + if ($MySQLaccess::CGI) { + print "<center>\n<font color=Red>\n"; + print "ERROR: Could not find MySQL-client '$MySQLaccess::MYSQL'"; + print "</center>\n</font>\n"; + exit 0; + } + } + + # path to mysql executable + my $connect = "$MySQLaccess::MYSQL --defaults-file=$MySQLaccess::MYSQL_CNF"; + $connect .= " $MySQLaccess::MYSQL_OPT"; + # superuser, spassword transmitted via defaults-file + if (defined($MySQLaccess::Param{'rhost'})) { $connect .= " --host=$MySQLaccess::Param{'rhost'}"; } + # other options?? + + # grant-database + $connect .= " $MySQLaccess::ACCESS_DB"; + + # open connection (not using /bin/sh -c) + MySQLaccess::Debug::Print(2,"Connecting to: $connect"); + $pid=IPC::Open3::open3(\*MYSQL_Q,\*MYSQL_A,"",split /\s+/,$connect); + MySQLaccess::Debug::Print(2,"PID of open pipe: $pid"); + + # check connection + print MYSQL_Q "select 'ok';\n"; + $answer = <MYSQL_A>; #answer from mysql + MySQLaccess::Debug::Print(2,"Answer: $answer\n"); + foreach $nerror (sort(keys(%ACCESS_ERR))) { + MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}"); + if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) { + MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]"); + return $nerror; + } + } + +if (0) { + # check server-version + print MYSQL_Q "select 'ok';\n"; + $answer = <MYSQL_A>; #answer from mysql + MySQLaccess::Debug::Print(2,"Answer: $answer\n"); + foreach $nerror (sort(keys(%ACCESS_ERR))) { + MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}"); + if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) { + MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]"); + return $nerror; + } + } +} + + my $skip=<MYSQL_A>; + return 0; +} + +# ====================================== +# sub CloseConnection +# Close the connection to the mysql-db +# ====================================== +sub CloseConnection { + close MYSQL_Q; + close MYSQL_A; +} + +# =========================================================== +# sub CreateTable($table) +# Create temporary/backup table +# =========================================================== +sub CreateTable { + my $pid; + my ($table,$force) = @_; + my %tables = ( $MySQLaccess::ACCESS_U_TMP => $MySQLaccess::ACCESS_U, + $MySQLaccess::ACCESS_H_TMP => $MySQLaccess::ACCESS_H, + $MySQLaccess::ACCESS_D_TMP => $MySQLaccess::ACCESS_D, + $MySQLaccess::ACCESS_U_BCK => $MySQLaccess::ACCESS_U, + $MySQLaccess::ACCESS_H_BCK => $MySQLaccess::ACCESS_H, + $MySQLaccess::ACCESS_D_BCK => $MySQLaccess::ACCESS_D, + $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_BCK, + $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_BCK, + $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_BCK, + ); + my $tbl; + my $query=""; + my $delim; + my $skip; + my $create; + my @known_tables=(); + +# print STDERR "CreateTable($table)\n"; + MySQLaccess::Debug::Print(1,"CreateTable($table):"); + + ## error-handling + return 'Unknown_table' unless defined($tables{$table}); + + ## build list of known/existing tables; + ## if 'force' existing table is dropped first + if (defined($force) and $force) { + @known_tables = Show_Tables(); + if (grep(/^$table$/,@known_tables)) { + $query = "DROP TABLE $table;"; + } + } + + ## path to mysqldump executable + my $connect = $MySQLaccess::MYSQLDUMP; + $connect .= " --defaults-file=$MySQLaccess::MYSQL_CNF --no-data"; + # superuser, spassword transmitted via defaults-file + if (defined($MySQLaccess::Param{'rhost'})) { $connect .= " --host=$MySQLaccess::Param{'rhost'}"; } + $connect .= " $MySQLaccess::ACCESS_DB"; + $connect .= " $tables{$table}"; + + + ## get creation-data for original table + $create = ''; + my $mysqldump = $connect; + $mysqldump =~ s/ \$TABLE / $tbl /; + + # open connection (not using /bin/sh -c) + MySQLaccess::Debug::Print(2,"Connecting to: $connect"); + $pid=IPC::Open3::open3(\*DONTCARE,\*CREATE,"",split /\s+/,$mysqldump); + MySQLaccess::Debug::Print(2,"PID of open pipe: $pid"); + #open(CREATE,"$mysqldump"); + @create = <CREATE>; + $create = "@create"; + foreach $nerror (sort(keys(%ACCESS_ERR))) { + MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}"); + if (grep(/$ACCESS_ERR{$nerror}/i,$create)) { + MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]"); + return $nerror; + } + } + close(CREATE); + close(DONTCARE); + + ## manipulate result for creation-data for temporary table + $create =~ s/CREATE TABLE $tables{$table} \(/CREATE TABLE $table \(/; + + ## recreate temporary table + $query .= "$create\n"; + $query .= "select 'ok';"; + + ## execute query + print MYSQL_Q "$query\n"; +# print STDERR $query; + + $answer = <MYSQL_A>; #answer from mysql +# print STDERR "A>",$answer; + MySQLaccess::Debug::Print(2,"Answer: $answer\n"); + foreach $nerror (sort(keys(%ACCESS_ERR))) { +# print STDERR "->$nerror?"; + MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}"); + if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) { +# print STDERR "Yes!"; + MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]"); + return $nerror; + } + } + + $delim = <MYSQL_A>; # read header + if ($delim ne "ok\n") { + while (($line=<MYSQL_A>) ne "ok\n") + { MySQLaccess::Debug::Print(3," A> $line"); } + $skip = <MYSQL_A>; # skip result 'ok' + } +# print STDERR "CreateTable done\n"; + return 0; +} + + +# =========================================================== +# sub CopyTable() +# Copy the structure and the data of a table to another table +# =========================================================== +sub CopyTable { + my ($from,$to,$force) = @_; + my @known_tables = Show_Tables(); + my $query = ""; + my $nerror= 0; + my $skip; + +# print STDERR "CopyTable($from,$to)\n"; + MySQLaccess::Debug::Print(1,"MySQLaccess::DB::CopyTable($from,$to)"); + + ## error-handling + if (!grep(/^$from$/,@known_tables)) { return 'Unknown_table'; } + + ## copy structure + ## if forced + if (defined($force) and $force) { + return $nerror if ($nerror=CreateTable($to,$force)); +# print STDERR "Structure copied\n"; + } + + ## copy data + $query .= "DELETE FROM $to;"; + $query .= "INSERT INTO $to SELECT * FROM $from;"; + $query .= "SELECT 'ok';\n"; + MySQLaccess::Debug::Print(2,"Query: $query"); + + ## execute query + print MYSQL_Q "$query\n"; +# print STDERR $query; + + ## check for errors... + my $answer = <MYSQL_A>; #answer from mysql +# print STDERR $answer; + MySQLaccess::Debug::Print(2,"Answer: $answer\n"); + foreach $nerror (sort(keys(%ACCESS_ERR))) { + MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}"); + if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) { + MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]"); + return $nerror; + } + } + + my $delim = <MYSQL_A>; # read header +# print STDERR $delim; + if ($delim ne "ok\n") { + while (($line=<MYSQL_A>) ne "ok\n") + { MySQLaccess::Debug::Print(3," A> $line"); } + $skip = <MYSQL_A>; # skip result 'ok' + } + + return 0; +} + +# =========================================================== +# sub LoadTmpTables() +# (Re)load temporary tables with entries of ACL-tables +# =========================================================== +sub LoadTmpTables { + my %tables = ( $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_TMP, + $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_TMP, + $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_TMP, + ); + my $tbl; + my $nerror; + +# print STDERR "LoadTmpTables:\n"; + MySQLaccess::Debug::Print(1,"LoadTmpTables():"); + foreach $tbl (keys(%tables)) { +# print STDERR "$tbl -> $tables{$tbl}\n"; + MySQLaccess::Debug::Print(2,"Loading table $tbl -> $tables{$tbl}."); + return $nerror if ($nerror=CopyTable($tbl,$tables{$tbl},'force')); + } + return 0; +} + +# =========================================================== +# sub BackupGrantTables() +# Make a backup of the original grant-tables +# =========================================================== +sub BackupGrantTables { + my %tables = ( $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_BCK, + $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_BCK, + $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_BCK, + ); + my $tbl; + my $nerror; + +# print STDERR "BackupGrantTables:\n"; + MySQLaccess::Debug::Print(1,"BackupGrantTables():"); + foreach $tbl (keys(%tables)) { +# print STDERR "$tbl -> $tables{$tbl}\n"; + MySQLaccess::Debug::Print(2,"Backup table $tbl -> $tables{$tbl}."); + return $nerror if ($nerror=CopyTable($tbl,$tables{$tbl},'force')); + } + return 0; +} + +# =========================================================== +# sub RollbackGrantTables() +# Rollback the backup of the grant-tables +# =========================================================== +sub RollbackGrantTables { + my %tables = ( $MySQLaccess::ACCESS_U_BCK => $MySQLaccess::ACCESS_U, + $MySQLaccess::ACCESS_H_BCK => $MySQLaccess::ACCESS_H, + $MySQLaccess::ACCESS_D_BCK => $MySQLaccess::ACCESS_D, + ); + my $tbl; + my $nerror; + +# print STDERR "RollbackGrantTables:\n"; + MySQLaccess::Debug::Print(1,"RollbackGrantTables():"); + foreach $tbl (keys(%tables)) { +# print STDERR "$tbl -> $tables{$tbl}\n"; + MySQLaccess::Debug::Print(2,"Rollback table $tbl -> $tables{$tbl}."); + return $nerror if ($nerror=CopyTable($tbl,$tables{$tbl},'force')); + } + return 0; +} + + +# =========================================================== +# sub CommitGrantTables() +# Copy grant-rules from temporary tables to the ACL-tables +# =========================================================== +sub CommitGrantTables { + my %tables = ( $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_TMP, + $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_TMP, + $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_TMP, + ); + my $tbl; + my $query; + my $delim; + my $skip; + my $create; + + print STDERR "CommitGrantTables()\n"; + MySQLaccess::Debug::Print(1,"CommitGrantTables():"); + + ## Make backup of original grant-tables + MySQLaccess::Debug::Print(2,"Making backup of original grant-tables..."); + BackupGrantTables(); + + ## Copy data from temporay tables to grant-tables + foreach $tbl (keys(%tables)) { + print STDERR "$tbl -> $tables{$tbl}\n"; + MySQLaccess::Debug::Print(2,"Loading data $tables{$tbl} -> $tbl."); + return $nerror if ($nerror=CopyTable($tables{$tbl},$tbl)); + } + return 0; +} + + +# =========================================================== +# sub Show_Fields($table): +# return (a reference to) a hash which holds the names +# of all relevant grant-fields, with their index in the record, +# and (a reference to) an array which holds the fieldnames. +# =========================================================== +sub Show_Fields { + my ($table) = @_; + my %skip = ('host' => [0,1] + ,'user' => [0,1,2] + ,'db' => [0,1,2] + ); + my %Struct = (); + my @Struct = (); + my $query = "show fields from $table;select 'ok';\n"; + my $i=0; + my $line; + +#print STDERR $query; + MySQLaccess::Debug::Print(1,"Show_Fields($table):"); + MySQLaccess::Debug::Print(2,"SQL: $query"); + + print MYSQL_Q "$query"; + my $skip = <MYSQL_A>; #skip header + while (($line=<MYSQL_A>) ne "ok\n") + { +#print STDERR ">",$line; + chop($line); + MySQLaccess::Debug::Print(2," $table>: $line"); + my ($field,$type,$null,$key,$default,$extra) = split(' ',$line); + $field = ucfirst($field); + MySQLaccess::Debug::Print(3, " <split: $field - $type - $null - $key - $default - $extra"); + if (! grep(/$i/,@{$skip{$table}}) ){ + $Struct{$field} = $i; #hash + push(@Struct,$field); #array + MySQLaccess::Debug::Print(3," ==> added column[$i]: $field ($Struct{$field})"); + } + else { + MySQLaccess::Debug::Print(3," ==> skipped column[$i], value=[$field]"); + } + $i++; + } + + $skip=<MYSQL_A>; # Get ok row (found already ok header) + + MySQLaccess::Debug::Print(2, "Array:"); + foreach $field (@Struct) { MySQLaccess::Debug::Print(2,"+ $field"); } + MySQLaccess::Debug::Print(2,"Hash:"); + foreach $field (keys(%Struct)) { MySQLaccess::Debug::Print(2,"+ $field -> $Struct{$field}"); } + + return (\%Struct,\@Struct); +} + +# =========================================================== +# sub Show_Tables(): +# return (a reference to) an array which holds all +# known tables. +# =========================================================== +sub Show_Tables { + my @Tables = (); + my $query = "show tables;select 'ok';\n"; + my $i=0; + my $line; + + MySQLaccess::Debug::Print(1,"Show_Tables():"); + MySQLaccess::Debug::Print(2,"SQL: $query"); + + print MYSQL_Q "$query"; + my $skip = <MYSQL_A>; #skip header + while (($line=<MYSQL_A>) ne "ok\n") + { + chop($line); + push(@Tables,$line); #array + MySQLaccess::Debug::Print(3," ==> added table: $line"); + } + + $skip=<MYSQL_A>; # Get ok row (found already ok header) + + MySQLaccess::Debug::Print(2, "Array:"); + foreach $tbl (@Tables) { MySQLaccess::Debug::Print(2,"+ $tbl"); } + + return @Tables; +} + +# ====================================== +# sub Validate_Password($passwd,$host,$user,$encpw) +# Validate the given password +# for user '$user' +# connecting from host '$host' +# ====================================== +sub Validate_Password { + my ($password,$host,$user,$encpw) = @_; + my $valid=0; + + MySQLaccess::Debug::Print(1,"Validate_Password($password,$host,$user,$encpw)"); + my $sql = "select host,user,password from user having " + ."host='$host' and user='$user' and password='$encpw' " + ."and password=PASSWORD('$password');\n"; + $sql .= "select 'ok';\n"; + MySQLaccess::Debug::Print(2,"SQL = $sql"); + print MYSQL_Q "$sql"; + + # if password is valid, at least 1 row returns before we read 'ok' + while ( ($line=<MYSQL_A>) ne "ok\n") { + MySQLaccess::Debug::Print(2," A> $line"); + $valid = defined($line); + } + my $skip = <MYSQL_A>; # read 'ok' + + return $valid; +} + + +# ========================================================== +# sub Sort_fields: (rewritten by psmith) +# Build the query for an ordered list of entries +# ========================================================== +sub Sort_fields { + my ($start, $end, $sofar, $this, @rest) = (@_); + my @where = ("((FIELD not like '\\%') AND (FIELD <> ''))", + "((FIELD like '%\\%%') OR (FIELD like '%\\_%'))", + "(FIELD = '')"); + my $res = ''; + + $this or return ("$start $sofar $end"); + + $sofar .= ' AND ' if $sofar; + + foreach $w (@where) { + my $f = $w; + $f =~ s/FIELD/$this/g; + + $res .= Sort_fields($start, $end, "$sofar$f", @rest); + } + + return ($res); +} + +# =========================================================== +# sub Sort_table: (rewritten by psmith) +# return all entries in the given table, +# in an ordered fashion +# =========================================================== +sub Sort_table { + my ($tbl, @order) = @_; + my @res=(); + + # as long as there's no full where clause (Distrib 3.20)... + # use having :-( + # NOTE: this clause WILL NOT work on 3.21, because of the + # order of 'ORDER BY' and 'HAVING' + my $start = "SELECT *,UCASE(host) as ucase_host FROM $tbl "; + $start .= 'ORDER BY ' . join(',', @order) ." HAVING "; + my $end = ";\n"; + + # server version 3.21 has a full where clause :-) + if ($MySQLaccess::Host::SERVER >= '3.21') { + # print "+++USING FULL WHERE CLAUSE+++\n"; + $start = "SELECT *,UCASE(host) as ucase_host FROM $tbl WHERE "; + $end = ' ORDER BY ' . join(',', @order) . ";\n"; + } + + MySQLaccess::Debug::Print(1,"Sort_table():"); + MySQLaccess::Debug::Print(2,"Sorting table $tbl by `@order'"); + + my $tmp; + foreach $tmp (@order) + { + $tmp="UCASE(host)" if ($tmp eq "ucase_host"); + } + my $query = Sort_fields($start, $end, '', @order); + $query .= "select 'ok';\n"; + MySQLaccess::Debug::Print(2,"Query: $query"); + + print MYSQL_Q "$query\n"; + + my $delim = <MYSQL_A>; # read header + MySQLaccess::Debug::Print(3," A> $delim"); + if ($delim ne "ok\n") { + if ($delim =~ /^ERROR/) { + push(@MySQLaccess::Grant::Error,'use_old_server'); + MySQLaccess::Report::Print_Error_Messages() ; + exit 1; + } + while (($line=<MYSQL_A>) ne "ok\n") + { + MySQLaccess::Debug::Print(3," A> $line"); + push(@res,$line); + } + } + my $skip = <MYSQL_A>; # skip result 'ok' + + # remove columnheaders from output + @res = grep(!/^\Q$delim\E$/, @res); + # remove trailing \n from each returned record + chomp(@res); + # each record has 1 field to much : ucase_host + @res = grep { /(.*)\t.*$/; $_ = $1; } @res; + + MySQLaccess::Debug::Print(2,"Result of sorted table $tbl:"); + foreach $line (@res) { MySQLaccess::Debug::Print(2," >>$line"); } + return @res; +} + +# =========================================================== +# sub Get_All_db(template): +# return all db the grant-tables are working on, +# which conform to the template +# =========================================================== +sub Get_All_dbs { + my ($template,$tmp) = @_; + my @db=(); + my $aref; + + # working with temporary tables or production tables + if (defined($tmp) and $tmp) { + $aref = \@MySQLaccess::Grant::sorted_db_tmp_table ; + } + else { + $aref = \@MySQLaccess::Grant::sorted_db_table; + } + + MySQLaccess::Debug::Print(1," template=[$template]"); + + # get all db for which access-rights can be calculated, + # which conform to the template. + # !! these db's don't have to exist yet, so it's not + # enough to look which db already exist on the system + $reg_expr = $template; + if ($template =~ /[\*\?]/) { + $reg_expr =~ tr/*?/%_/; + #$reg_expr = MySQLaccess::Wildcards::Wild2Reg($template); + } + $reg_expr = MySQLaccess::Wildcards::SQL2Reg("$reg_expr"); + + if ( ! ($template =~ /[\*\?%_]/) ) { + push(@db,$template); + return \@db; + } + + MySQLaccess::Debug::Print(2,"#Reading db-table..."); + foreach $record (@{$aref}) { #MySQLaccess::Grant::sorted_db_table) { + my @record=split(/\t/,$record); + my $db = $record[1]; + MySQLaccess::Debug::Print(2,"> $db "); + if ( (!grep(/$db/i,@db)) and ($db =~/$reg_expr/i) ) { + push(@db,$db); + MySQLaccess::Debug::Print(2,"added"); + } + else { + MySQLaccess::Debug::Print(2,"skipped"); + } + } + # if no rule is found for a certain db in the db-table, + # the rights of the user are used, so we should inform + # the user for + if (!grep(/^%$/,@db)) { push(@db,"$MySQLaccess::NEW_DB"); } + return \@db; +} + +# =========================================================== +# sub Get_All_users(template): +# return all users the grant-tables are working on, +# which conform to the template +# =========================================================== +sub Get_All_users { + ($template,$tmp) = @_; # nog verder uitwerken!!! + my @user=(); + my $aref; + + # working with temporary tables or production tables + if (defined($tmp) and $tmp) { + $aref = \@MySQLaccess::Grant::sorted_user_tmp_table ; + } + else { + $aref = \@MySQLaccess::Grant::sorted_user_table; + } + + MySQLaccess::Debug::Print(1,"Debug Get_All_users:"); + # get all db for which access-rights can be calculated. + # !! these db's don't have to exist yet, so it's not + # enough to look which db already exist on the system + $reg_expr = $template; + if ($template =~ /[\*\?]/) { + $reg_expr =~ tr/*?/%_/; + #$reg_expr = MySQLaccess::Wildcards::Wild2Reg($template); + } + $reg_expr = MySQLaccess::Wildcards::SQL2Reg("$reg_expr"); + + if ( ! ($template =~ /[\*\?%_]/) ) { + push(@user,$template); + return \@user; + } + + MySQLaccess::Debug::Print(2,"#Reading user-table..."); + foreach $record (@{$aref}) { #MySQLaccess::Grant::sorted_user_table) { + my @record=split(/\t/,$record); + my $user = $record[1]; + MySQLaccess::Debug::Print(2,"> $user "); + if ( (!grep(/$user/,@user)) and ($user=~/$reg_expr/)) { + push(@user,$user); + MySQLaccess::Debug::Print(2, "added"); + } + else { + MySQLaccess::Debug::Print(2, "skipped"); + } + } + # Any user means also: + # - the 'empty' user, ie without supplying a username + # - any user still to be defined/created + #push(@user,''); #without_suplying_a_username + push(@user,"$MySQLaccess::NEW_USER"); + #push(@Warnings,'minimum_priv'); + return \@user; +} + +# =========================================================== +# sub Get_All_hosts(template): +# return all hosts the grant-tables are working on, +# which conform to the template +# =========================================================== +sub Get_All_hosts { + my ($template,$tmp) = @_; + my @host=(); + my $aref; + my $aref1; + + # working with temporary tables or production tables + if (defined($tmp) and $tmp) { + $aref = \@MySQLaccess::Grant::sorted_host_tmp_table ; + $aref1= \@MySQLaccess::Grant::sorted_db_tmp_table ; + } + else { + $aref = \@MySQLaccess::Grant::sorted_host_table; + $aref1= \@MySQLaccess::Grant::sorted_db_table ; + } + + MySQLaccess::Debug::Print(1, "Debug Get_All_hosts:"); + # get all db for which access-rights can be calculated. + # !! these db's don't have to exist yet, so it's not + # enough to look which db already exist on the system + $reg_expr = $template; + if ($template =~ /[\*\?]/) { + $reg_expr =~ tr/*?/%_/; + #$reg_expr = MySQLaccess::Wildcards::Wild2Reg($template); + } + $reg_expr = MySQLaccess::Wildcards::SQL2Reg("$reg_expr"); + + if ( ! ($template =~ /[\*\?%_]/) ) { + push(@host,$template); + return \@host; + } + + MySQLaccess::Debug::Print(1, "#Reading db-table..."); + foreach $record (@{$aref1}) { #MySQLaccess::Grant::sorted_db_table) { + my @record=split(/\t/,$record); + my $host = $record[0]; + MySQLaccess::Debug::Print(2, "> $host "); + if (! grep(/$host/i,@host)) { + push(@host,$host); + MySQLaccess::Debug::Print(2, "added"); + } + else { + MySQLaccess::Debug::Print(2, "skipped"); + } + } + MySQLaccess::Debug::Print(1, "#Reading host-table..."); + foreach $record (@{$aref}) { + my @record=split(/\t/,$record); + my $host = $record[0]; + MySQLaccess::Debug::Print(2, "> $host "); + if ( (!grep(/$host/,@host)) and ($host=~/$reg_expr/)) { + push(@host,$host); + MySQLaccess::Debug::Print(2, "added"); + } + else { + MySQLaccess::Debug::Print(2, "skipped"); + } + } + # DOUBT: + #print "#Reading user-table...\n" if ($DEBUG>1); + #foreach $record (@MySQLaccess::Grant::sorted_user_table) { + # my @record=split(/\t/,$record); + # my $host = $record[0]; + # print "> $host " if ($DEBUG>2); + # if ( (!grep(/$host/,@host)) and ($host=~/$reg_expr/)) { + # push(@host,$host); + # print "added\n" if ($DEBUG>2); + # } + # else { + # print "skipped\n" if ($DEBUG>2); + # } + #} + # Any host also means: + # - any host still to be defined/created + #push(@host,"any_other_host"); + + @host = sort(@host); + return \@host; +} + + +########################################################################## +package MySQLaccess::Grant; +############## +BEGIN { + $DEBUG = 0; + $DEBUG = $MySQLaccess::DEBUG unless ($DEBUG); +} + + + +# =========================================================== +# sub Diff_Privileges() +# Calculate diff between temporary and original grant-tables +# =========================================================== +sub Diff_Privileges { + my @before=(); + my @after =(); + my @diffs =(); + + # ----------------------------- + # Build list of users,dbs,hosts + # to process... + my @all_dbs = @{MySQLaccess::DB::Get_All_dbs('*')}; + my @all_users = @{MySQLaccess::DB::Get_All_users('*')}; + my @all_hosts = @{MySQLaccess::DB::Get_All_hosts('*')}; + #if EDIT-mode + my @all_dbs_tmp = @{MySQLaccess::DB::Get_All_dbs('*','tmp')}; + my @all_users_tmp = @{MySQLaccess::DB::Get_All_users('*','tmp')}; + my @all_hosts_tmp = @{MySQLaccess::DB::Get_All_hosts('*','tmp')}; + + + my %Access; + # ------------------------------------ + # Build list of priv. for grant-tables + foreach $host (@all_hosts) { + foreach $user (@all_users) { + foreach $db (@all_dbs) { + MySQLaccess::Grant::Initialize(); + %Access = MySQLaccess::Grant::Get_Access_Rights($host,$user,$db); + push(@before,MySQLaccess::Report::Raw_Report($host,$user,$db,\%Access)); + } + } + } + + # ---------------------------------- + # Build list of priv. for tmp-tables + foreach $host (@all_hosts_tmp) { + foreach $user (@all_users_tmp) { + foreach $db (@all_dbs_tmp) { + MySQLaccess::Grant::Initialize('tmp'); + %Access = MySQLaccess::Grant::Get_Access_Rights($host,$user,$db,'tmp'); + push(@after,MySQLaccess::Report::Raw_Report($host,$user,$db,\%Access)); + } + } + } + + # ---------------------------------- + # Write results to temp-file to make + # DIFF + @before = sort(@before); + @after = sort(@after); + + ($hb, $before) = tempfile("$MySQLaccess::script.XXXXXX") or + push(@MySQLaccess::Report::Errors,"Can't create temporary file: $!"); + ($ha, $after) = tempfile("$MySQLaccess::script.XXXXXX") or + push(@MySQLaccess::Report::Errors,"Can't create temporary file: $!"); + + print $hb join("\n",@before); + print $ha join("\n",@after); + close $hb; + close $ha; + + # ---------------------------------- + # compute difference + my $cmd="$MySQLaccess::DIFF $before $after |"; + open(DIFF,"$cmd"); + @diffs = <DIFF>; + @diffs = grep(/[<>]/,@diffs); + chomp(@diffs); + close(DIFF); + + # ---------------------------------- + # cleanup temp. files + unlink($before); + unlink($after); + + return \@diffs; +} + +# =========================================================== +# sub Initialize() +# +# =========================================================== +sub Initialize { + %MySQLaccess::Grant::Access = %{Default_Access_Rights()}; + @MySQLaccess::Grant::Errors = (); + @MySQLaccess::Grant::Warnings = (); + @MySQLaccess::Grant::Notes = (); + # ----- + # rules + $MySQLaccess::Grant::Rules{'user'} = 'no_rule_found'; + $MySQLaccess::Grant::Rules{'db'} = 'no_rule_found'; + $MySQLaccess::Grant::Rules{'host'} = 'no_equiv_host'; + $MySQLaccess::Grant::full_access = 1; + + $MySQLaccess::Grant::process_host_table = 0; + return 1; +} + +# =========================================================== +# sub ReadTables() +# +# =========================================================== +sub ReadTables { + my ($tmp) = @_; + my ($HOST,$DB,$USER); + my @tables; + + # build list of available tables + @tables = MySQLaccess::DB::Show_Tables(); + + # reading production grant-tables or temporary tables? + $tmp = (defined($tmp) and $tmp) ? 1 : 0; + if ($tmp) { #reading temporary tables + $HOST=$MySQLaccess::ACCESS_H_TMP; + $DB =$MySQLaccess::ACCESS_D_TMP; + $USER=$MySQLaccess::ACCESS_U_TMP; + + # ---------------------------- + # do tables exist? + if (!grep(/$HOST/,@tables)) { MySQLaccess::DB::CreateTable($HOST); } + if (!grep(/$USER/,@tables)) { MySQLaccess::DB::CreateTable($USER); } + if (!grep(/$DB/,@tables)) { MySQLaccess::DB::CreateTable($DB); } + + MySQLaccess::Debug::Print(1,"Finding fields in tmp-ACL files:"); + # ----------------------------- + # Get record-layout + my ($h1,$h2) = MySQLaccess::DB::Show_Fields($HOST); + my ($d1,$d2) = MySQLaccess::DB::Show_Fields($DB); + my ($u1,$u2) = MySQLaccess::DB::Show_Fields($USER); + %MySQLaccess::Grant::H_tmp = %{$h1}; @MySQLaccess::Grant::H_tmp = @{$h2}; + %MySQLaccess::Grant::D_tmp = %{$d1}; @MySQLaccess::Grant::D_tmp = @{$d2}; + %MySQLaccess::Grant::U_tmp = %{$u1}; @MySQLaccess::Grant::U_tmp = @{$u2}; + +# @MySQLaccess::Grant::Privileges_tmp=@{Make_Privlist()}; +# + MySQLaccess::Debug::Print(1, "Reading sorted temp-tables:"); + @MySQLaccess::Grant::sorted_db_tmp_table = MySQLaccess::DB::Sort_table($DB, 'ucase_host', 'user', 'db'); + @MySQLaccess::Grant::sorted_host_tmp_table= MySQLaccess::DB::Sort_table($HOST, 'ucase_host', 'db'); + @MySQLaccess::Grant::sorted_user_tmp_table= defined($MySQLaccess::Param{'password'}) ? + MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user', 'password'): + MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user'); + } + else { #reading production grant-tables + $HOST=$MySQLaccess::ACCESS_H; + $DB =$MySQLaccess::ACCESS_D; + $USER=$MySQLaccess::ACCESS_U; + + MySQLaccess::Debug::Print(1,"Finding fields in ACL files:"); + # ----------------------------- + # Get record-layout + my ($h1,$h2) = MySQLaccess::DB::Show_Fields($HOST); + my ($d1,$d2) = MySQLaccess::DB::Show_Fields($DB); + my ($u1,$u2) = MySQLaccess::DB::Show_Fields($USER); + %MySQLaccess::Grant::H = %{$h1}; @MySQLaccess::Grant::H = @{$h2}; + %MySQLaccess::Grant::D = %{$d1}; @MySQLaccess::Grant::D = @{$d2}; + %MySQLaccess::Grant::U = %{$u1}; @MySQLaccess::Grant::U = @{$u2}; + + @MySQLaccess::Grant::Privileges=@{Make_Privlist()}; + + MySQLaccess::Debug::Print(1, "Reading sorted tables:"); + @MySQLaccess::Grant::sorted_db_table = MySQLaccess::DB::Sort_table($DB, 'ucase_host', 'user', 'db'); + @MySQLaccess::Grant::sorted_host_table= MySQLaccess::DB::Sort_table($HOST, 'ucase_host', 'db'); + @MySQLaccess::Grant::sorted_user_table= defined($MySQLaccess::Param{'password'}) ? + MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user', 'password'): + MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user'); + } + + return 0; +} + +# =========================================================== +# sub Get_Access_Rights(host,user,db) +# report the access_rights for the tuple ($host,$user,$db). +# =========================================================== +sub Get_Access_Rights { + local ($host,$user,$db,$tmp) = @_; + + my $aref_user; + my $aref_host; + my $aref_db; + # working with temporary tables or production tables + if (defined($tmp) and $tmp) { + $aref_user = \@MySQLaccess::Grant::sorted_user_tmp_table; + $aref_host = \@MySQLaccess::Grant::sorted_host_tmp_table; + $aref_db = \@MySQLaccess::Grant::sorted_db_tmp_table; + } + else { + $aref_user = \@MySQLaccess::Grant::sorted_user_table; + $aref_host = \@MySQLaccess::Grant::sorted_host_table; + $aref_db = \@MySQLaccess::Grant::sorted_db_table; + } + + + my ($refrecord,$refgrant); + my ($_host_,$_user_,$encpw_); + my %_Access_; + + MySQLaccess::Debug::Print(1, "for ($host,$user,$db):"); + + # ****************************************************************************** + # Create default access-rights + # default access-rights are no access at all!! + + + # ****************************************************************************** + # get hostname for IP-address + # get IP-address for hostname + local $host_name = MySQLaccess::Host::IP2Name($host); + local $host_ip = MySQLaccess::Host::Name2IP($host); + + MySQLaccess::Debug::Print(3,"host=$host, hostname=$host_name, host-ip =$host_ip"); + MySQLaccess::Debug::Print(3,"user=$user"); + MySQLaccess::Debug::Print(3,"db =$db"); + + # *********************************************************************** + # retrieve information on USER + # check all records in mysql::user for matches with the tuple (host,user) + # *********************************************************************** + # 4.OR (add) the privileges for the user from the "user" table. + # (add all privileges which is "Y" in "user") + ($refrecord,$refgrant) = Get_grant_from_user($host,$user,$aref_user); + ($_host_,$_user_,$encpw_) = @{$refrecord}; + %_access_ = %{$refgrant}; + + foreach $field (keys(%U)) { ##only priv. set in user-table + $MySQLaccess::Grant::Access{$field} = ($MySQLaccess::Grant::Access{$field} or $_access_{$field}); + } + + if ($_user_ eq $MySQLaccess::NEW_USER) { + push(@Warnings,'minimum_priv'); + } + if ($_user_ ne $user) { + $user=$_user_; + push(@Warnings,'anonymous_access'); + } + + # ******************************************************* + # Validate password if this has been asked to do + # ******************************************************* + if (defined($password)) { + $valid = Validate_Password($password,$_host_,$_user_,$_encpw_,$aref_user); + if (!$valid) { push(@Errors,'invalid_password'); } + else { push(@Notes,'valid_password'); } + } + + # ****************************************************************************** + # retrieve information on DB + # check all records in mysql::db for matches with the triple (host,db,user) + # first match is used. + # ****************************************************************************** + # 2.Get grant for user from the "db" table. + + ($refrecord,$refgrant)=Get_grant_from_db($host,$db,$user,$aref_db); #set process_host_table + ($_host_,$_user_,$encpw_) = @{$refrecord}; + %_access_ = %{$refgrant}; + + foreach $field (keys(%D)) { ##only priv. set in db-table + $MySQLaccess::Grant::Access{$field} = ($MySQLaccess::Grant::Access{$field} or $_access_{$field}); + } + + # *********************************************************************** + # retrieve information on HOST + # check all records in mysql::host for matches with the tuple (host,db) + # + # ' The host table is mainly to maintain a list of "secure" servers. ' + # *********************************************************************** + # 3.If hostname is "empty" for the found entry, AND the privileges with + # the privileges for the host in "host" table. + # (Remove all which is not "Y" in both) + + if ($MySQLaccess::Grant::process_host_table) { + ($refrecord,$refgrant)=Get_grant_from_host($host,$db,$aref_host); + ($_host_,$_user_,$encpw_) = @{$refrecord}; + %_access_ = %{$refgrant}; + + foreach $field (keys(%H)) { ##only priv. set in host-table + $MySQLaccess::Grant::Access{$field} = ($MySQLaccess::Grant::Access{$field} and $_access_{$field}); + } + } + + MySQLaccess::Debug::Print(1,"done for ($host,$user,$db)"); + return %MySQLaccess::Grant::Access; +} + +# #################################### +# FINDING THE RIGHT GRANT-RULE +# ========================================================== +# sub Get_grant_from_user: +# ========================================================== +sub Get_grant_from_user { + my ($host,$user,$aref) = @_; + + MySQLaccess::Debug::Print(1, ""); + MySQLaccess::Debug::Print(1, "(host=$host,user=$user)"); + + my %Access_user = %{Default_Access_Rights()}; + + my $rule_found=0; + my @record = (); + my $record; + + foreach $record (@{$aref}) { + $MySQLaccess::Grant::full_access=0; + MySQLaccess::Debug::Print(3, "Record= $record"); + @record=split(/\t/,$record); + + # check host and db + # with possible wildcards in field + # replace mysql-wildcards by reg-wildcards + my $host_tpl = MySQLaccess::Wildcards::SQL2Reg($record[0]); + my $user_tpl = $record[1]; #user field isn't pattern-matched!! + my $passwd = $record[2]; + + MySQLaccess::Debug::Print(3, "=>host_tpl : read=$record[0] -> converted=$host_tpl"); + MySQLaccess::Debug::Print(3, "=>user_tpl : read=$record[1] -> $user_tpl"); + MySQLaccess::Debug::Print(3, "=>password : read=$record[2] -> $passwd"); + + + if ( MySQLaccess::Host::MatchTemplate($host,$host_tpl) and + MySQLaccess::Wildcards::MatchTemplate($user_tpl,$user) + ) + { + MySQLaccess::Debug::Print(2, "FOUND!!"); + if ($passwd eq '') { push(@Warnings,'insecure_user'); } + else { push(@Notes,'password_required'); } + + foreach $field (keys(%U)) { + $Access_user{$field} = $MySQLaccess::Report::Answer{$record[$U{$field}]}; + } + #print "\n" if $DEBUG; + $MySQLaccess::Grant::Rules{'user'} = $record; + $rule_found=1; + last; + } + } + + # ------------------------------- + # setting privileges to user-priv + MySQLaccess::Debug::Print(2, "Rights after parsing user-table..:"); + if (! $rule_found ) { + @record=(); + MySQLaccess::Debug::Print(2, "NO record found in the user-table!!"); + } + else { + MySQLaccess::Debug::Print(2, "Selected record=@record"); + MySQLaccess::Debug::Print(2, "<=?=> $record"); + } + + MySQLaccess::Debug::Print(1, "returning @record"); + + return (\@record,\%Access_user); #matching record in user-table +} + +# ========================================================== +# sub Get_grant_from_db: +# ========================================================== +sub Get_grant_from_db { + my ($host,$db,$user,$aref) = @_; + + MySQLaccess::Debug::Print(1, "(host=$host,user=$user,db=$db)"); + + my %Access_db = %{Default_Access_Rights()}; + my $rule_found=0; + + foreach $record (@{$aref}) { + $full_access=0; + MySQLaccess::Debug::Print(2, "Read db: $record"); + @record=split(/\t/,$record); + + # check host and db + # with possible wildcards in field + # replace mysql-wildcards by reg-wildcards + my $host_tpl = MySQLaccess::Wildcards::SQL2Reg($record[0]); + my $db_tpl = MySQLaccess::Wildcards::SQL2Reg($record[1]); + my $user_tpl = $record[2]; #user field isn't pattern matched!! + MySQLaccess::Debug::Print(3, "=>host_tpl : read=$record[0] -> converted=$host_tpl"); + MySQLaccess::Debug::Print(3, "=>db_tpl : read=$record[1] -> $db_tpl"); + MySQLaccess::Debug::Print(3, "=>user_tpl : read=$record[2] -> $user_tpl"); + + if ( ( MySQLaccess::Host::Is_localhost($host_tpl) + or MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_name) + or MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_ip) ) + and ( MySQLaccess::Wildcards::MatchTemplate($db_tpl,$db) ) + and ( MySQLaccess::Wildcards::MatchTemplate($user_tpl,$user) ) ) { + + $MySQLaccess::Grant::process_host_table = ($record[0] eq ''); + + if ($user_tpl eq '') { push(@Warnings,'public_database'); } + + foreach $field (keys(%D)) { + $Access_db{$field} = $MySQLaccess::Report::Answer{$record[$D{$field}]}; + } + $rule_found=1; + $MySQLaccess::Grant::Rules{'db'} = $record; + last; + } + } + + # ------------------------------- + # setting privileges to db-priv + MySQLaccess::Debug::Print(2, "Rights after parsing db-table..:"); + if (! $rule_found ) { + MySQLaccess::Debug::Print(2, "NO rule found in db-table => no access granted!!"); + } + + return (\@record,\%Access_db); +} + +# ========================================================== +# sub Get_grant_from_host: +# ========================================================== +sub Get_grant_from_host { + my ($host,$db,$aref) = @_; + + MySQLaccess::Debug::Print(1, "Get_grant_from_host()"); + + my %Access_host = %{Default_Access_Rights()}; + + # the host-table doesn't have to be processed if the host-field + # in the db-table isn't empty + if (!$MySQLaccess::Grant::process_host_table) { + MySQLaccess::Debug::Print(2, ">> Host-table doesn't have to be processed!!"); + $MySQLaccess::Grant::Rules{'host'} = 'no_equiv_host'; + return ([],\%Access_host); + } + + my $rule_found=0; + my @record = (); + + foreach $record (@{$aref}) { + $full_access=0; + MySQLaccess::Debug::Print(2, "host: $record"); + @record=split(/\t/,$record); + + # check host and db + # with possible wildcards in field + # replace mysql-wildcards by reg-wildcards + my $host_tpl = MySQLaccess::Wildcards::SQL2Reg($record[0]); + my $db_tpl = MySQLaccess::Wildcards::SQL2Reg($record[1]); + MySQLaccess::Debug::Print(3, "=>host_tpl : $record[0] -> $host_tpl"); + MySQLaccess::Debug::Print(3, "=>db_tpl : $record[1] -> $db_tpl"); + + if ( ( MySQLaccess::Host::Is_localhost($host_tpl) + or MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_name) + or MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_ip) ) + and ( MySQLaccess::Wildcards::MatchTemplate($db_tpl,$db) ) ) { + + $MySQLaccess::Grant::Rules{'host'} = $record; + $rule_found=1; + foreach $field (keys(%H)) { + $Access_host{$field} = $MySQLaccess::Report::Answer{$record[$H{$field}]}; + } + last; + } + } + + # ------------------------------- + # setting privileges to host-priv + MySQLaccess::Debug::Print(2, "Rights after parsing host-table..:"); + if (! $rule_found ) { + @record=(); + MySQLaccess::Debug::Print(2, "NO restrictions found in the host-table!!"); + } + + # -------------------------------- + # debugging access-rights in db + + return (\@record,\%Access_host); #matching record in host-table +} + + + +# =========================================================== +# sub Default_Access_Rights(): +# return (a reference to) a hash which holds all default +# priviliges currently defined in the grant-tables. +# =========================================================== +sub Default_Access_Rights { + my %right = (); + + MySQLaccess::Debug::Print(2, "Debug Default_Access_Rights():"); + # add entry for all fields in the HOST-table + foreach $field (keys(%MySQLaccess::Grant::H)) { + $right{$field}='0' unless (defined($right{$field})); + } + # add entry for all fields in the DB-table + foreach $field (keys(%MySQLaccess::Grant::D)) { + $right{$field}='0' unless (defined($right{$field})); + } + # add entry for all fields in the USER-table + foreach $field (keys(%MySQLaccess::Grant::U)) { + $right{$field}='0' unless (defined($right{$field})); + } + # -------------- + # debugging info + foreach $field (keys(%right)) { MySQLaccess::Debug::Print(3, sprintf("> %15s : %1s",$field,$right{$field})); } + + return \%right; +} + +# ====================================== +# sub Make_Privlist +# Make an ordered list of the privileges +# that should be reported +# ====================================== +sub Make_Privlist { + # layout: + #'select_priv', 'create_priv', + #'insert_priv', 'drop_priv', + #'update_priv', 'reload_priv', + #'delete_priv', 'process_priv', + #'file_priv', 'shutdown_priv'); + my $right; + my @privlist=(); + foreach $right (@U) { + if (! grep(/$right/,@privlist)) { push(@privlist,$right); } + }; + foreach $right (@D) { + if (! grep(/$right/,@privlist)) { push(@privlist,$right); } + }; + foreach $right (@H) { + if (! grep(/$right/,@privlist)) { push(@privlist,$right); } + }; +# print "Privileges:\n"; +# foreach $field (@privlist) { print " > $field\n"; } + return \@privlist; +} + + + +######################################################################## +package MySQLaccess::Report; +use Exporter (); +@EXPORT = qw(&Print_Header()); +BEGIN { + $FORM = $ENV{'SCRIPT_NAME'}; + $DEBUG = 0; + $DEBUG = $MySQLaccess::DEBUG unless ($DEBUG); + + # translation-table for poss. answers + %Answer = ('Y' => 1 , 'N' => 0 + , 1 => 'Y', 0 => 'N' + ,'?' => '?', '' => '?' + ); + $headers = 0; + $separator = 0; + +# **************************** +# Notes and warnings +%MESSAGES = ( + 'insecure_user' + => "Everybody can access your DB as user `\$user' from host `\$host'\n" + ."WITHOUT supplying a password.\n" + ."Be very careful about it!!" + ,'password_required' + => "A password is required for user `\$user' :-(" + ,'invalid_password' + => "The password '\$password' for user `\$user' is invalid :-P" + , 'valid_password' + => "You supplied the right password for user `\$user' :-)" + ,'public_database' + => "Any user with the appropriate permissions has access to your DB!\n" + ."Check your users!" + ,'full_access' + => "All grant-tables are empty, which gives full access to ALL users !!" + ,'no_rule_found' + => "No matching rule" + ,'no_equiv_host' + => "Not processed: host-field is not empty in db-table." + ,'least_priv' + => "If the final priveliges of the user are more then you gave the user,\n" + ."check the priveliges in the db-table `\$db'." + ,'minimum_priv' + => "The privileges for any new user are AT LEAST\n" + ."the ones shown in the table above,\n" + ."since these are the privileges of the db `\$db'.\n" + ,'not_found_mysql' + => "The MySQL client program <$MySQLaccess::MYSQL> could not be found.\n" + ."+ Check your path, or\n" + ."+ edit the source of this script to point \$MYSQL to the mysql client.\n" + ,'not_found_mysqldump' + => "The MySQL dump program <$MySQLaccess::MYSQLDUMP> could not be found.\n" + ."+ Check your path, or\n" + ."+ edit the source of this script to point \$MYSQLDUMP to the mysqldump program.\n" + ,'not_found_diff' + => "The diff program <$MySQLaccess::DIFF> could not be found.\n" + ."+ Check your path, or\n" + ."+ edit the source of this script to point \$DIFF to the diff program.\n" + ,'Unrecognized_option' + => "Sorry,\n" + ."You are using an old version of the mysql-program,\n" + ."which does not yet implement a neccessary option.\n" + ."\n" + ."You need at least Version 6.2 of the mysql-client,\n" + ."which was build in MySQL v3.0.18, to use this version\n" + ."of `$MySQLaccess::script'." + ,'Access_denied' + => "Sorry,\n" + ."An error occurred when trying to connect to the database\n" + ."with the grant-tables:\n" + ."* Maybe YOU do not have READ-access to this database?\n" + ."* If you used the -U option, you may have supplied an invalid username?\n" + ." for the superuser?\n" + ."* If you used the -U option, it may be possible you have to supply\n" + ." a superuser-password to, with the -P option?\n" + ."* If you used the -P option, you may have supplied an invalid password?\n" + ,'Dbaccess_denied' + => "Sorry,\n" + ."An error occurred when trying to connect to the database\n" + ."with the grant-tables. (dbaccess denied)\n" + ,'Unknown_tmp_table' + => "Sorry,\n" + ."An error occurred when trying to work with the temporary tables in the database\n" + ."with the grant-tables. (One of the temporary tables does not exist)\n" + ,'Unknown_table' + => "Sorry,\n" + ."An error occurred when trying to work with some tables in the database\n" + ."with the grant-tables. (table does not exist)\n" + ,'use_old_server' + => "Sorry,\n" + ."An error occurred when executing an SQL statement.\n" + ."You might consider altering the use of the parameter `--old_server' when \n" + ."calling `$MySQLaccess::script'." + ,'unknown_error' + => "Sorry,\n" + ."An error occurred when trying to connect to the database\n" + ."with the grant-tables. (unknown error)\n" + ,'anonymous_access' + => "Accessing the db as an anonymous user.\n" + ."Your username has no relevance\n" + ,'user_required' + => "You have to supply a userid." + ,'db_required' + => "You have to supply the name of a database." + ,'host_required' + => "You have to supply the name of a host." + ); + + +} +# ===================================== +# sub Print_Header: +# print header info +# ===================================== +sub Print_Header { + if ($MySQLaccess::CMD) { #command-line mode + print "$MySQLaccess::script Version $MySQLaccess::VERSION\n" + ."By RUG-AIV, by Yves Carlier (Yves.Carlier\@rug.ac.be)\n" + ."Changes by Steve Harvey (sgh\@vex.net)\n" + ."This software comes with ABSOLUTELY NO WARRANTY.\n"; + } + if ($MySQLaccess::CGI) { #CGI-BIN mode + print "content-type: text/html\n\n" + . "<HTML>\n" + ."<HEAD>\n" + ."<TITLE>MySQLaccess</TITLE>\n" + ."</HEAD>\n" + ."<BODY>\n" + ."<H1>$MySQLaccess::script Version $MySQLaccess::VERSION</H1>\n" + ."<CENTER>\n<ADDRESS>\n" + ."By RUG-AIV, by Yves Carlier (<a href=mailto:Yves.Carlier\@rug.ac.be>Yves.Carlier\@rug.ac.be</a>)<BR>\n" + ."Changes by Steve Harvey (<a href=mailto:sgh\@vex.net>sgh\@vex.net</a>)<BR>\n" + ."This software comes with ABSOLUTELY NO WARRANTY.<BR>\n" + ."</ADDRESS>\n</CENTER>\n" + ."<HR>\n"; + Print_Taskbar(); + print "<HR>\n"; + } + return 1; +} + +# ===================================== +# sub Print_Footer: +# print footer info +# ===================================== +sub Print_Footer { + if ($MySQLaccess::CMD) { #command-line mode + print "\n" + ."BUGs can be reported at https://jira.mariadb.org\n"; + } + if ($MySQLaccess::CGI) { #CGI-BIN mode + if ($MySQLaccess::Param{'brief'}) { + print "</table>\n"; #close table in brief-output + } + print "<HR>\n" + ."<ADDRESS>\n" + ."BUGs can be reported at <a href=\"https://jira.mariadb.org\">MariaDB JIRA</a><BR>\n" +# ."Don't forget to mention the version $VERSION!<BR>\n" + ."</ADDRESS>\n" + ."</BODY>\n" + ."</HTML>\n"; + } + return 1; +} + +# ===================================== +# sub Print_Taskbar: +# print taskbar on STDOUT +# ===================================== +sub Print_Taskbar { + print "<CENTER>\n" + ."[<a href=$FORM?relnotes=on>Release Notes</a>] \n" + ."[<a href=$FORM?version=on>Version</a>] \n" + ."[<a href=$FORM?plan=on>Future Plans</a>] \n" + ."[<a href=$FORM?howto=on>Examples</a>] \n" + ."[<a href=$FORM?help=on>New check</a>] \n" + ."[<a href=$FORM?edit=on>Change/edit ACL</a>] \n" + ."</CENTER>\n"; + return 1; +} + +# ===================================== +# sub Print_Form: +# print CGI-form +# ===================================== +sub Print_Form { +print <<EOForm; +<center> +<!-- Quering --> +<FORM method=POST action=$FORM> + +<table border width="100%" > +<tr> + <th>MySQL server</th> + <th>User information</th> + <th>Reports</th> + </tr> + +<tr> + <td valign=top> + <table> + <tr> + <td halign=right><b>Host</b><br><font size=-2>(Host on which MySQL-server resides.)</font></td> + <td valign=top><INPUT name=rhost type=text size=15 maxlength=15 value="$MySQLaccess::Param{'rhost'}"></td> + </tr> + <tr> + <td halign=right><b>Superuser</b><br><font size=-2>(User which has <font color="Red">read-access</font> to grant-tables.)</font></td> + <td valign=top><INPUT name=superuser type=text size=15 maxlength=15 value="$MySQLaccess::Param{'superuser'}"></td> + </tr> + <tr> + <td halign=right><b>Password</b><br><font size=-2>(of Superuser.)</font></td> + <td valign=top><INPUT name=spassword type=password size=15 maxlength=15 value="$MySQLaccess::Param{'spassword'}"></td> + </tr> + </table> + </td> + + <td valign=top> + <table> + <tr> + <td halign=right><b><font color=Red>User</font></b><br><font size=-2>(Userid used to connect to MySQL-database.)</font></td> + <td halign=top><INPUT name=user type=text size=15 maxlength=15 value="$MySQLaccess::Param{'user'}"></td> + </tr> + <tr> + <td halign=right><b>Password</b><br><font size=-2>(Password user has to give to get access to MySQL-database.)</font></td> + <td valign=top><INPUT name=password type=password size=15 maxlength=15 value="$MySQLaccess::Param{'password'}"></td> + </tr> + <tr> + <td halign=right><b><font color=Red>Database</font></b><br><font size=-2>(Name of MySQL-database user tries to connect to.</font><br><font size=-2>Wildcards <font color="Green">(*,?,%,_)</font> are allowed.)</font></td> + <td valign=top><INPUT name=db type=text size=15 maxlength=15 value="$MySQLaccess::Param{'db'}"></td> + </tr> + <tr> + <td halign=right><b>Host</b><br><font size=-2>(Host from where the user is trying to connect to MySQL-database.</font><br><font size=-2>Wildcards <font color="Green">(*,?,%,_)</font> are allowed.)</font></td> + <td valign=top><INPUT name=host type=text size=15 maxlength=15 value="$MySQLaccess::Param{'host'}"></td> + </tr> + </table> + </td> + + <td valign=center> + <table cellspacing=5 cellpadding=2 cols=1 height="100%"> + <tr align=center> + <td halign=right><INPUT type=submit name=brief value="Brief"><br> + <INPUT type=submit name=table value="Tabular"></td> + </tr> + <tr align=center> + <td></td> + </tr> + <tr align=center> + <td halign=right><INPUT type=reset value="Clear"></td> + </tr> + </table> + </td> + </tr> + +</table> +</form> + + +</BODY> +</HTML> +EOForm + return 1; +} + +# ===================================== +# sub Print_Usage: +# print some information on STDOUT +# ===================================== +sub Print_Usage { + Print_Error_Messages(); + if ($MySQLaccess::CMD) { #command-line mode + Print_Options(); + } + if ($MySQLaccess::CGI) { #CGI-BIN mode + Print_Form(); + } + return 1; +} + +# ====================================== +# sub Print_Version: +# ====================================== +sub Print_Version { + if ($MySQLaccess::CMD) { + print $MySQLaccess::INFO; + } + if ($MySQLaccess::CGI) { + print "<PRE>\n"; + print $MySQLaccess::INFO; + print "</PRE>\n"; + } + return 1; +} + +# ====================================== +# sub Print_Relnotes: +# ====================================== +sub Print_Relnotes { + if ($MySQLaccess::CMD) { + print $MySQLaccess::RELEASE; + } + if ($MySQLaccess::CGI) { + print "<PRE>\n"; + print $MySQLaccess::RELEASE; + print "</PRE>\n"; + } + return 1; +} + +# ====================================== +# sub Print_Plans: +# ====================================== +sub Print_Plans { + if ($MySQLaccess::CMD) { + print $MySQLaccess::TODO; + } + if ($MySQLaccess::CGI) { + print "<PRE>\n"; + print $MySQLaccess::TODO; + print "</PRE>\n"; + } + return 1; +} + +# ====================================== +# sub Print_HowTo: +# ====================================== +sub Print_HowTo { + if ($MySQLaccess::CMD) { + print $MySQLaccess::HOWTO; + } + if ($MySQLaccess::CGI) { + print "<PRE>\n"; + print $MySQLaccess::HOWTO; + print "</PRE>\n"; + } + return 1; +} + +# ====================================== +# sub Print_Options: +# ====================================== +sub Print_Options { + if ($MySQLaccess::CGI) { print "<PRE>\n"; } + print $MySQLaccess::OPTIONS; + if ($MySQLaccess::CGI) { print "</PRE>\n"; } + return 1; +} + +# ====================================== +# sub Print_Error_Access: +# ====================================== +sub Print_Error_Access { + my ($error) = @_; + print "\n"; + if ($MySQLaccess::CGI) { print "<font color=Red>\n<PRE>\n"; } + print $MESSAGES{$error}; + if ($MySQLaccess::CGI) { print "</PRE>\n</font>\n"; } + print "\n"; + return 1; +} + +# ====================================== +# sub Print_Error_Messages: +# ====================================== +sub Print_Error_Messages { +# my ($error) = @_; + print "\n"; + if ($MySQLaccess::CGI) { print "<font color=Red>\n<center>\n"; } + foreach $error (@MySQLaccess::Grant::Error) { + print $MESSAGES{$error}; + print $MySQLaccess::CGI ? "<br>\n" : "\n"; + } + if ($MySQLaccess::CGI) { print "</center>\n</font>\n"; } + print "\n"; + return 1; +} + +# ====================================== +# sub Print_Message: +# ====================================== +sub Print_Message { + my ($aref) = @_; + my @messages = @{$aref}; + print "\n"; + if ($MySQLaccess::CGI) { print "<font color=DarkGreen>\n<center>\n"; } + foreach $msg (@messages) { + print $msg; + print $MySQLaccess::CGI ? "<br>\n" : "\n"; + } + if ($MySQLaccess::CGI) { print "</center>\n</font>\n"; } + print "\n"; + return 1; +} + +# ====================================== +# sub Print_Edit: +# ====================================== +sub Print_Edit { + print "\n"; + if (!$MySQLaccess::CGI) { + print "Note: Editing the temporary tables is NOT supported in CMD-line mode!\n"; + return 0; + } + print "<CENTER>\n" + ."<form action=$FORM method=GET>\n" + ."<table width=90% border>\n" + ."<tr>\n" + ." <td><input type=checkbox name=copy value=on> Copy grant-rules to temporary tables<br></td>\n" + ." <td rowspan=5 align=center valign=center><input type=submit value=Go></td>\n" + ."</tr>\n" + ."<tr>\n" + ." <td> Edit temporary tables with external application:<br>" + ." <a href=\"$MySQLaccess::MYSQLADMIN\">$MySQLaccess::MYSQLADMIN</a></td>\n" + ."</tr>\n" + ."<tr>\n" + ." <td><input type=checkbox name=preview value=on> Preview changes made in temporary tables</td>\n" + ."</tr>\n" + ."<tr>\n" + ." <td><input type=checkbox name=commit value=on> Make changes permanent</td>\n" + ."</tr>\n" + ."<tr>\n" + ." <td><input type=checkbox name=rollback value=on> Restore previous grand-rules</td>\n" + ."</tr>\n" + ."<tr>\n" + ." <td colspan=2 align=center><font size=-2 color=Red>You need write,delete and drop-privileges to perform the above actions</font></td>\n" + ."</tr>\n" + ."</table>\n" + ."</form>\n" + ."</CENTER>\n"; + + return 1; +} + + +# ====================================== +# sub Print_Access_rights: +# print the access-rights on STDOUT +# ====================================== +sub Print_Access_rights { + my ($host,$user,$db,$refhash) = @_; + + if (defined($MySQLaccess::Param{'brief'})) { +# if ($MySQLaccess::CGI) { print "<PRE>\n"; } + Matrix_Report($host,$user,$db,$refhash); +# if ($MySQLaccess::CGI) { print "</PRE>\n"; } + } + else { + Tabular_Report($host,$user,$db,$refhash); + $MySQLaccess::Report::separator = $MySQLaccess::CGI ? "<hr>" : "-"x80; + } + return 1; +} + +# ====================================== +# sub Print_Diff_ACL: +# print the diff. in the grants before and after +# ====================================== +sub Print_Diff_ACL { + my ($aref) = @_; + my @diffs = @{$aref}; + my %block = ( '<' => 'Before', + '>' => 'After', + ); + my %color = ( '<' => 'Green', + '>' => 'Red', + ); + my $curblock = ''; + + # ----------------------------- + # create column-headers + foreach $field (@MySQLaccess::Grant::Privileges) { + push(@headers,substr($field,0,4)); + } + + if ($MySQLaccess::CMD) { + print "\n"; + print "Differences in access-rights BEFORE and AFTER changes in grant-tables\n"; +# print "---------------------------------------------------------------------\n"; + my $line1=""; + my $line2=""; + $line1 .= sprintf("| %-30s|",'Host,User,DB'); + $line2 .= sprintf("+-%-30s+",'-' x 30); + foreach $header (@headers) { + $line1 .= sprintf("%-4s|",$header); + $line2 .= sprintf("%s+",'----'); + } + print "$line2\n"; + print "$line1\n"; + print "$line2\n"; + + $format = "format STDOUT = \n" + . "^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< " . " @|||" x 10 ."\n" + . '$host_user_db,@priv' . "\n" + . ".\n"; +#print $format; + eval $format; + } + if ($MySQLaccess::CGI) { + print "<table border width=100%>\n"; + print "<tr>\n"; + print "<th colspan=11>"; + print "Differences in access-rights <font color=$color{'<'}>BEFORE</font> " + ."and <font color=$color{'>'}>AFTER</font> changes to grant-tables</font>\n"; + print "</th>"; + print "</tr>\n"; + print "<tr>\n"; + $line1 .= sprintf("<th>%-20s</th>",'Host, User, DB'); + foreach $header (@headers) { + $line1 .= sprintf("<th>%-4s</th>",$header); + } + print "$line1</tr>\n"; + } + + foreach $line (@diffs) { + $type = substr($line,0,1); + $line = substr($line,1); + ($host,$user,$db,@priv) = split(/,/,$line); + if ($MySQLaccess::CMD) { + if ($type ne $curblock) { + $curblock = $type; + print $block{$curblock},":\n"; + } + #print "$line\n"; + write; + } + if ($MySQLaccess::CGI) { + if ($type ne $curblock) { + $curblock = $type; + print "<tr><td><b>$block{$curblock}<b></td></tr>\n"; + } + $line1="<td><font color=$color{$type}>$host, $user, $db</font></td>"; + foreach $field (@priv) { + $line1 .= sprintf("<td align=center><font color=$color{$type}>%-4s</font></td>",$field); + } + print "<tr>$line1</tr>\n"; + } + } + print "\n"; + if ($MySQLaccess::CMD) { + print "---------------------------------------------------------------------\n"; + } + if ($MySQLaccess::CGI) { + print "</table><br>"; + } + + + return 1; +} + +# ====================================== +# sub Tabular_Report +# Tabular report, +# suitable for 1 triple (host,db,user) +# ====================================== +sub Tabular_Report { + my ($host,$user,$db,$a) = @_; + my $column=2; + + # ----------------------------- + # separator + if ($MySQLaccess::Report::separator) { print "$MySQLaccess::Report::separator\n"; } + + # ----------------------------- + # print table of access-rights + my $rows = int(@MySQLaccess::Grant::Privileges/2); #round up + my @table=(); + $j=0; + for $i (0 .. $rows-1) { + $table[$j]=$MySQLaccess::Grant::Privileges[$i]; + $j = $j+2; + } + $j=1; + for $i ($rows .. $#MySQLaccess::Grant::Privileges) { + $table[$j]=$MySQLaccess::Grant::Privileges[$i]; + $j = $j+2; + } + if ($MySQLaccess::CMD) { + print "\n"; + print "Access-rights\n"; + print "for USER '$user', from HOST '$host', to DB '$db'\n"; + } + if ($MySQLaccess::CGI) { + print "<table border width=100%>\n"; + print "<tr>\n"; + } + if ($MySQLaccess::CGI) { + print "<th colspan=5>"; + print "<font color=Red>Access-rights</font>\n"; + print "for USER '<font color=Green>$user</font>', from HOST '<font color=Green>$host</font>', to DB '<font color=Green>$db</font>'\n"; + print "</th>"; + print "</tr>\n"; + print "<tr>\n"; + } + if ($MySQLaccess::CMD) { + print "\t+-----------------+---+\t+-----------------+---+"; + } + foreach $field (@table) { + if ($MySQLaccess::CMD) { + if ($column==2) { print "\n\t"; $column=1;} + else { print "\t"; $column=2;} + printf "| %-15s | %s |",$field,$Answer{$a->{$field}}; + } + if ($MySQLaccess::CGI) { + if ($column==2) { print "</tr>\n<tr>\n"; $column=1;} + else { print "<td width=10%></td>"; $column=2;} + printf " <td width=35%><b>%-15s</b></td><td width=10%>%s</td>\n",$field,$Answer{$a->{$field}}; + } + } + print "\n"; + if ($MySQLaccess::CMD) { + print "\t+-----------------+---+\t+-----------------+---+\n"; + } + if ($MySQLaccess::CGI) { + print "</tr>\n</table><br>"; + } + + # --------------- + # print notes: + foreach $note (@MySQLaccess::Grant::Notes) { + my $message = $MESSAGES{$note}; + $message =~ s/\$user/$user/g; + $message =~ s/\$db/$db/g; + $message =~ s/\$host/$host/g; + $message =~ s/\$password/$password/g; + $PREFIX='NOTE'; + if ($MySQLaccess::CMD) { + my @lines = split(/\n/,$message); + foreach $line (@lines) { + print "$PREFIX:\t $line\n"; + $PREFIX=' '; + } + } + if ($MySQLaccess::CGI) { + print "<b>$PREFIX:</b> $message<br>\n"; + } + } + + # --------------- + # print warnings: + foreach $warning (@MySQLaccess::Grant::Warnings) { + my $message = $MESSAGES{$warning}; + $message =~ s/\$user/$user/g; + $message =~ s/\$db/$db/g; + $message =~ s/\$host/$host/g; + $message =~ s/\$password/$password/g; + $PREFIX='BEWARE'; + if ($MySQLaccess::CMD) { + my @lines = split(/\n/,$message); + foreach $line (@lines) { + print "$PREFIX:\t $line\n"; + $PREFIX=' '; + } + } + if ($MySQLaccess::CGI) { + print "<b>$PREFIX:</b> $message<br>\n"; + } + } + + # --------------- + # print errors: + foreach $error (@MySQLaccess::Grant::Errors) { + my $message = $MESSAGES{$error}; + $message =~ s/\$user/$user/g; + $message =~ s/\$db/$db/g; + $message =~ s/\$host/$host/g; + $message =~ s/\$password/$password/g; + $PREFIX='ERROR'; + if ($MySQLaccess::CMD) { + my @lines = split(/\n/,$message); + foreach $line (@lines) { + print "$PREFIX:\t $line\n"; + $PREFIX=' '; + } + } + if ($MySQLaccess::CGI) { + print "<b>$PREFIX:</b> $message<br>\n"; + } + } + + # --------------- + # inform if there are no rules ==> full access for everyone. + if ($MySQLaccess::Grant::full_access) { print "$MESSAGES{'full_access'}\n"; } + + # --------------- + # print the rules used + print "\n"; + if ($MySQLaccess::CMD) { + print "The following rules are used:\n"; + foreach $field (sort(keys(%MySQLaccess::Grant::Rules))) { + my $rule = (defined($MESSAGES{$MySQLaccess::Grant::Rules{$field}}) ? $MESSAGES{$MySQLaccess::Grant::Rules{$field}} : $MySQLaccess::Grant::Rules{$field}); + $rule =~ s/\t/','/g; + printf " %-5s : '%s'\n",$field,$rule; + } + } + if ($MySQLaccess::CGI) { + print "<br>\n"; + print "<table border width=100%>\n"; + print "<tr><th colspan=2>The following rules are used:</th></tr>\n"; + foreach $field (sort(keys(%MySQLaccess::Grant::Rules))) { + my $rule = (defined($MESSAGES{$MySQLaccess::Grant::Rules{$field}}) ? $MESSAGES{$MySQLaccess::Grant::Rules{$field}} : $MySQLaccess::Grant::Rules{$field}); + $rule =~ s/\t/','/g; + printf "<tr><th>%-5s</th><td>'%s'</td></tr>\n",$field,$rule; + } + print "</table>\n"; + } + + return 1; +} + +# ====================================== +# sub Matrix_Report: +# single-line output foreach triple, +# no notes,warnings,... +# ====================================== +sub Matrix_Report { + my ($host,$user,$db,$a) = @_; + my @headers = (); + + if (! $headers) { + # ----------------------------- + # create column-headers + foreach $field (@MySQLaccess::Grant::Privileges) { + push(@headers,substr($field,0,4)); + } + + # ----------------------------- + # print column-headers + print "\n"; + if ($MySQLaccess::CMD) { + my $line1=""; + my $line2=""; + foreach $header (@headers) { + $line1 .= sprintf("%-4s ",$header); + $line2 .= sprintf("%s ",'----'); + } + $line1 .= sprintf("| %-20s",'Host,User,DB'); + $line2 .= sprintf("+ %-20s",'-' x 20); + print "$line1\n"; + print "$line2\n"; + } + if ($MySQLaccess::CGI) { + print "<table width=100% border>\n"; + my $line1="<tr>"; + foreach $header (@headers) { + $line1 .= sprintf("<th>%-4s</th>",$header); + } + $line1 .= sprintf("<th>%-20s</th>",'Host, User, DB'); + print "$line1</tr>\n"; + } + + # ---------------------------- + # column-headers should only be + # printed once. + $MySQLaccess::Report::headers=1; + } + + # ------------------------ + # print access-information + if ($MySQLaccess::CMD) { + foreach $field (@MySQLaccess::Grant::Privileges) { + printf " %-2s ",$Answer{$a->{$field}}; + } + printf "| %-20s",join(',',$host,$user,$db); + print "\n"; + } + if ($MySQLaccess::CGI) { + print "<tr>"; + foreach $field (@MySQLaccess::Grant::Privileges) { + printf "<td align=center>%-2s</td>",$Answer{$a->{$field}}; + } + printf "<td><b>%-20s</b></td>",join(', ',$host,$user,$db); + print "</tr>\n"; + } + + return 1; +} + + +# ====================================== +# sub Raw_Report: +# single-line output foreach triple, +# no notes,warnings,... +# ====================================== +sub Raw_Report { + my ($host,$user,$db,$a) = @_; + my @headers = (); + my $string = ""; + + # ------------------------ + # print access-information + $string = "$host,$user,$db,"; + foreach $field (@MySQLaccess::Grant::Privileges) { + $string .= $Answer{$a->{$field}} . ","; + } + return $string; +} + + +####################################################################### +package MySQLaccess::Wildcards; +BEGIN { + $DEBUG = 0; + $DEBUG = $MySQLaccess::DEBUG unless ($DEBUG); +} +# ############################################ +# SQL, WILDCARDS and REGULAR EXPRESSIONS +# ============================================ +# translage SQL-expressions to Reg-expressions +# ============================================ +sub SQL2Reg { + my ($expr) = @_; + my $expr_o = $expr; + $expr =~ s/\./\\./g; + $expr =~ s/\\%/\002/g; + $expr =~ s/%/.*/g; + $expr =~ s/\002/%/g; + $expr =~ s/\\_/\002/g; + $expr =~ s/_/.+/g; + $expr =~ s/\002/_/g; + MySQLaccess::Debug::Print(2,"$expr_o --> $expr"); + return $expr; +} + +# translage WILDcards to Reg-expressions +# ============================================ +sub Wild2Reg { + my ($expr) = @_; + my $expr_o = $expr; + $expr =~ s/\./\\./g; + $expr =~ s/\\\*/\002/g; + $expr =~ s/\*/.*/g; + $expr =~ s/\002/*/g; + $expr =~ s/\\\?/\002/g; + $expr =~ s/\?/.+/g; + $expr =~ s/\002/?/g; + MySQLaccess::Debug::Print(2,"$expr_o --> $expr"); + return $expr; +} + +# ============================================= +# match a given string with a template +# ============================================= +sub MatchTemplate { + my ($tpl,$string) = @_; + my $match=0; + if ($string=~ /^$tpl$/ or $tpl eq '') { $match=1; } + else { $match=0;} + MySQLaccess::Debug::Print(2,"($tpl,$string) --> $match"); + return $match; +} + +####################################################################### +package MySQLaccess::Host; +BEGIN { + $localhost = undef; + $DEBUG = 2; + $DEBUG = $MySQLaccess::DEBUG unless ($DEBUG); +} +# ====================================== +# sub IP2Name +# return the Name with the corr. IP-nmbr +# (no aliases yet!!) +# ====================================== +sub IP2Name { + my ($ip) = @_; + my $ip_o = $ip; + if ($ip !~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/o) { + MySQLaccess::Debug::Print(3,"'$ip' is not an ip-number, returning IP=$ip"); + return $ip; + } + MySQLaccess::Debug::Print(4,"IP=$ip split up => $1.$2.$3.$4"); + $ip = pack "C4",$1,$2,$3,$4; + MySQLaccess::Debug::Print(4,"IP packed -> >>$ip<<\n"); + my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyaddr($ip, AF_INET); + MySQLaccess::Debug::Print(3,"IP=$ip_o => hostname=$name"); + MySQLaccess::Debug::Print(4,"aliases=$aliases"); + MySQLaccess::Debug::Print(4,"addrtype=$addrtype - length=$length"); + return ($name || $ip); + #return ($name || undef); +} + +# ====================================== +# sub Name2IP +# return the IP-number of the host +# ====================================== +sub Name2IP { + my ($name) = @_; + if ($name =~ /[%_]/) { + MySQLaccess::Debug::Print(3,"'$name' contains SQL-wildcards, returning name=$name"); + return $name; + } + my ($_name,$aliases,$addrtype,$length,@addrs) = gethostbyname($name); + my ($a,$b,$c,$d) = unpack('C4',$addrs[0]); + my $ip = "$a.$b.$c.$d"; + MySQLaccess::Debug::Print(3,"hostname=$name => IP=$ip"); + MySQLaccess::Debug::Print(4,"aliases=$aliases"); + MySQLaccess::Debug::Print(4,"addrtype=$addrtype - length=$length"); + #if ($ip ne "") { return "$ip"; } + #else { return undef; } + return ($ip || $name); +} + +# ======================================== +# sub LocalHost +# some special action has to be taken for +# the localhost +# ======================================== +sub LocalHost { + if (!defined($MySQLaccess::Host::localhost)) { + $MySQLaccess::Host::localhost = Sys::Hostname::hostname(); + MySQLaccess::Debug::Print(3,"Setting package variable \$localhost=$MySQLaccess::Host::localhost"); + } + my $host = $localhost; + MySQLaccess::Debug::Print(3,"localhost = $host"); + return $host; +} + +# ======================================== +# check if the given hostname (or ip) +# corresponds with the localhost +# ======================================== +sub Is_localhost { + my ($host_tpl) = @_; + my $isit = 0; + if (($MySQLaccess::host_name eq $localhost) or ($MySQLaccess::host_ip eq $local_ip)) { + MySQLaccess::Debug::Print(2,"Checking for localhost"); + MySQLaccess::Debug::Print(3,"because ($MySQLaccess::host_name EQ $localhost) AND ($MySQLaccess::host_ip EQ $local_ip)"); + $isit = ( 'localhost' =~ /$host_tpl/ ) ? 1 : 0; + MySQLaccess::Debug::Print(3," 'localhost' =?= $host_tpl -> $isit"); + return $isit; + } + else { + MySQLaccess::Debug::Print(4,"Not checking for localhost"); + MySQLaccess::Debug::Print(4,"because ($MySQLaccess::host_name != $localhost) AND ($MySQLaccess::host_ip != $local_ip)"); + return 0; + } +} + + +# ========================================= +# check if host (IP or name) can be matched +# on the template. +# ========================================= +sub MatchTemplate { + my ($host,$tpl) = @_; + my $match = 0; + + MySQLaccess::Debug::Print(1, "($host) =?= ($tpl)"); + + my $host_name = IP2Name($host); + my $host_ip = Name2IP($host); + + MySQLaccess::Debug::Print(2, "name=$host_name ; ip=$host_ip"); + $match = (MySQLaccess::Wildcards::MatchTemplate($tpl,$host_name) or + MySQLaccess::Wildcards::MatchTemplate($tpl,$host_ip)); + + MySQLaccess::Debug::Print(2, "($host_name,$host_ip) =?= ($tpl): $ncount"); + + return $match; +} + +######################################################################## +package MySQLaccess::Debug; +BEGIN { + my $dbg_file = "$MySQLaccess::script_log"; + open(DEBUG,"> $dbg_file") or warn "Could not open outputfile $dbg_file for debugging-info\n"; + select DEBUG; + $| = 1; + select STDOUT; +} +# ========================================= +# Print debugging information on STDERR +# ========================================= +sub Print { + my ($level,$mesg) = @_; + my ($pack,$file,$line,$subname,$hasargs,$wantarray) = caller(1); + my ($PACK) = split('::',$subname); + my $DEBUG = ${$PACK."::DEBUG"} ? ${$PACK."::DEBUG"} : $MySQLaccess::DEBUG ; + my ($sec,$min,$hour) = localtime(); + print DEBUG "[$hour:$min:$sec $subname] $mesg\n" if ($DEBUG>=$level); +} + diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh new file mode 100644 index 00000000..9a1f3920 --- /dev/null +++ b/scripts/mysqld_multi.sh @@ -0,0 +1,960 @@ +#!@PERL_PATH@ + +# Copyright (c) 2000, 2017, Oracle and/or its affiliates. +# Copyright (c) 2010, 2017, MariaDB Corporation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1335 USA + +use Getopt::Long; +use POSIX qw(strftime getcwd); +use File::Path qw(mkpath); + +$|=1; +$VER="3.0"; + +my @defaults_options; # Leading --no-defaults, --defaults-file, etc. + +$opt_example = 0; +$opt_help = 0; +$opt_log = undef(); +$opt_mysqladmin = "@bindir@/mariadb-admin"; +$opt_mysqld = "@sbindir@/mariadbd"; +$opt_no_log = 0; +$opt_password = undef(); +$opt_tcp_ip = 0; +$opt_user = "root"; +$opt_version = 0; +$opt_silent = 0; +$opt_verbose = 0; +$opt_wsrep_new_cluster = 0; + +my $my_print_defaults_exists= 1; +my $logdir= undef(); + +my ($mysqld, $mysqladmin, $groupids, $homedir, $my_progname); + +$homedir = $ENV{HOME}; +$my_progname = $0; +$my_progname =~ s/.*[\/]//; + + +if (defined($ENV{UMASK})) { + my $UMASK = $ENV{UMASK}; + my $m; + my $fmode = "0640"; + + if(($UMASK =~ m/[^0246]/) || ($UMASK =~ m/^[^0]/) || (length($UMASK) != 4)) { + printf("UMASK must be a 3-digit mode with an additional leading 0 to indicate octal.\n"); + printf("The first digit will be corrected to 6, the others may be 0, 2, 4, or 6.\n"); } + else { + $fmode= substr $UMASK, 2, 2; + $fmode= "06${fmode}"; } + + if($fmode != $UMASK) { + printf("UMASK corrected from $UMASK to $fmode ...\n"); } + + $fmode= oct($fmode); + + umask($fmode); +} + + +main(); + +#### +#### main sub routine +#### + +sub main +{ + my $flag_exit= 0; + + if (!defined(my_which(my_print_defaults))) + { + # We can't throw out yet, since --version, --help, or --example may + # have been given + print "WARNING: my_print_defaults command not found.\n"; + print "Please make sure you have this command available and\n"; + print "in your path. The command is available from the latest\n"; + print "MariaDB distribution.\n"; + $my_print_defaults_exists= 0; + } + + # Remove leading defaults options from @ARGV + while (@ARGV > 0) + { + last unless $ARGV[0] =~ + /^--(?:no-defaults$|(?:defaults-file|defaults-extra-file)=)/; + push @defaults_options, (shift @ARGV); + } + + foreach (@defaults_options) + { + $_ = quote_shell_word($_); + } + + # Add [mysqld_multi] options to front of @ARGV, ready for GetOptions() + unshift @ARGV, defaults_for_group('mysqld_multi'); + + # We've already handled --no-defaults, --defaults-file, etc. + if (!GetOptions("help", "example", "version", "mysqld=s", "mysqladmin=s", + "user=s", "password=s", "log=s", "no-log", + "tcp-ip", "silent", "verbose", "wsrep-new-cluster")) + { + $flag_exit= 1; + } + usage() if ($opt_help); + + if ($opt_verbose && $opt_silent) + { + print "Both --verbose and --silent have been given. Some of the warnings "; + print "will be disabled\nand some will be enabled.\n\n"; + } + + init_log() if (!defined($opt_log)); + $groupids = $ARGV[1]; + if ($opt_version) + { + print "$my_progname version $VER by Jani Tolonen\n"; + exit(0); + } + example() if ($opt_example); + if ($flag_exit) + { + print "Error with an option, see $my_progname --help for more info.\n"; + exit(1); + } + if (!defined(my_which(my_print_defaults))) + { + print "ABORT: Can't find command 'my_print_defaults'.\n"; + print "This command is available from the latest MariaDB\n"; + print "distribution. Please make sure you have the command\n"; + print "in your PATH.\n"; + exit(1); + } + usage() if (!defined($ARGV[0]) || + (!($ARGV[0] =~ m/^start$/i) && + !($ARGV[0] =~ m/^stop$/i) && + !($ARGV[0] =~ m/^reload$/i) && + !($ARGV[0] =~ m/^report$/i))); + + if (!$opt_no_log) + { + w2log("$my_progname log file version $VER; run: ", + "$opt_log", 1, 0); + } + else + { + print "$my_progname log file version $VER; run: "; + print strftime "%a %b %e %H:%M:%S %Y", localtime; + print "\n"; + } + if (($ARGV[0] =~ m/^start$/i) || ($ARGV[0] =~ m/^reload$/i)) + { + if (!defined(($mysqld= my_which($opt_mysqld))) && $opt_verbose) + { + print "WARNING: Couldn't find the default mysqld binary.\n"; + print "Tried: $opt_mysqld\n"; + print "This is OK, if you are using option \"mysqld=...\" in "; + print "groups [mysqldN] separately for each.\n\n"; + } + if ($ARGV[0] =~ m/^start$/i) { + start_mysqlds(); + } elsif ($ARGV[0] =~ m/^reload$/i) { + reload_mysqlds(); + } + } + else + { + if (!defined(($mysqladmin= my_which($opt_mysqladmin))) && $opt_verbose) + { + print "WARNING: Couldn't find the default mysqladmin binary.\n"; + print "Tried: $opt_mysqladmin\n"; + print "This is OK, if you are using option \"mysqladmin=...\" in "; + print "groups [mysqldN] separately for each.\n\n"; + } + if ($ARGV[0] =~ m/^report$/i) + { + report_mysqlds(); + } + else + { + stop_mysqlds(); + } + } +} + +# +# Quote word for shell +# + +sub quote_shell_word +{ + my ($option)= @_; + + $option =~ s!([^\w=./-])!\\$1!g; + return $option; +} + +#### +#### get options for a group +#### + +sub defaults_for_group +{ + my ($group) = @_; + + return () unless $my_print_defaults_exists; + + my $com= join ' ', 'my_print_defaults', @defaults_options, $group; + my @defaults = `$com`; + chomp @defaults; + return @defaults; +} + +#### +#### Init log file. Check for appropriate place for log file, in the following +#### order: my_print_defaults mysqld datadir, @localstatedir@ +#### + +sub init_log +{ + foreach my $opt (defaults_for_group('--mysqld')) + { + if ($opt =~ m/^--datadir=(.*)/ && -d "$1" && -w "$1") + { + $logdir= $1; + } + } + if (!defined($logdir)) + { + $logdir= "@localstatedir@" if (-d "@localstatedir@" && -w "@localstatedir@"); + } + if (!defined($logdir)) + { + # Log file was not specified and we could not log to a standard place, + # so log file be disabled for now. + if (!$opt_silent) + { + print "WARNING: Log file disabled. Maybe directory or file isn't writable?\n"; + } + $opt_no_log= 1; + } + else + { + $opt_log= "$logdir/mysqld_multi.log"; + } +} + +#### +#### Report living and not running MariaDB servers +#### + +sub report_mysqlds +{ + my (@groups, $com, $i, @options, $pec); + + print "Reporting MariaDB servers\n"; + if (!$opt_no_log) + { + w2log("\nReporting MariaDB servers","$opt_log",0,0); + } + @groups = &find_groups($groupids); + for ($i = 0; defined($groups[$i]); $i++) + { + $com= get_mysqladmin_options($i, @groups); + $com.= " ping >> /dev/null 2>&1"; + system($com); + $pec = $? >> 8; + if ($pec) + { + print "MariaDB server from group: $groups[$i] is not running\n"; + if (!$opt_no_log) + { + w2log("MariaDB server from group: $groups[$i] is not running", + "$opt_log", 0, 0); + } + } + else + { + print "MariaDB server from group: $groups[$i] is running\n"; + if (!$opt_no_log) + { + w2log("MariaDB server from group: $groups[$i] is running", + "$opt_log", 0, 0); + } + } + } + if (!$i) + { + print "No groups to be reported (check your GNRs)\n"; + if (!$opt_no_log) + { + w2log("No groups to be reported (check your GNRs)", "$opt_log", 0, 0); + } + } +} + +#### +#### start multiple servers +#### + +sub start_mysqlds() +{ + my (@groups, $com, $tmp, $i, @options, $j, $mysqld_found, $suffix_found, $info_sent); + + $suffix_found= 0; + + if (!$opt_no_log) + { + w2log("\nStarting MariaDB servers\n","$opt_log",0,0); + } + else + { + print "\nStarting MariaDB servers\n"; + } + @groups = &find_groups($groupids); + for ($i = 0; defined($groups[$i]); $i++) + { + @options = defaults_for_group($groups[$i]); + + $basedir_found= 0; # The default + $mysqld_found= 1; # The default + $mysqld_found= 0 if (!length($mysqld)); + $com= "$mysqld"; + + for ($j = 0, $tmp= ""; defined($options[$j]); $j++) + { + if ("--datadir=" eq substr($options[$j], 0, 10)) { + $datadir = $options[$j]; + $datadir =~ s/\-\-datadir\=//; + eval { mkpath($datadir) }; + if ($@) { + print "FATAL ERROR: Cannot create data directory $datadir: $!\n"; + exit(1); + } + if (! -d $datadir."/mysql") { + if (-w $datadir) { + print "\n\nInstalling new database in $datadir\n\n"; + $install_cmd="@bindir@/mysql_install_db "; + $install_cmd.="--user=mysql "; + $install_cmd.="--datadir=$datadir"; + system($install_cmd); + } else { + print "\n"; + print "FATAL ERROR: Tried to create mysqld under group [$groups[$i]],\n"; + print "but the data directory is not writable.\n"; + print "data directory used: $datadir\n"; + exit(1); + } + } + + if (! -d $datadir."/mysql") { + print "\n"; + print "FATAL ERROR: Tried to start mysqld under group [$groups[$i]],\n"; + print "but no data directory was found or could be created.\n"; + print "data directory used: $datadir\n"; + exit(1); + } + } + + if ("--mysqladmin=" eq substr($options[$j], 0, 13)) + { + # catch this and ignore + } + elsif ("--mysqld=" eq substr($options[$j], 0, 9)) + { + $options[$j]=~ s/\-\-mysqld\=//; + $com= $options[$j]; + $mysqld_found= 1; + } + elsif ("--basedir=" eq substr($options[$j], 0, 10)) + { + $basedir= $options[$j]; + $basedir =~ s/^--basedir=//; + $basedir_found= 1; + $options[$j]= quote_shell_word($options[$j]); + $tmp.= " $options[$j]"; + } + elsif ("--defaults-group-suffix=" eq substr($options[$j], 0, 24)) + { + $suffix_found= 1; + } + else + { + $options[$j]= quote_shell_word($options[$j]); + $tmp.= " $options[$j]"; + } + } + if ($opt_verbose && $com =~ m/\/(mariadbd-safe)$/ && !$info_sent) + { + print "WARNING: $1 is being used to start mariadbd. In this case you "; + print "may need to pass\n\"ledir=...\" under groups [mysqldN] to "; + print "$1 in order to find the actual mysqld binary.\n"; + print "ledir (library executable directory) should be the path to the "; + print "wanted mysqld binary.\n\n"; + $info_sent= 1; + } + + if (!$suffix_found) + { + $com.= " --defaults-group-suffix="; + $com.= substr($groups[$i],6); + } + + $com.= $tmp; + + if ($opt_wsrep_new_cluster) { + $com.= " --wsrep-new-cluster"; + } + + $com.= " >> $opt_log 2>&1" if (!$opt_no_log); + $com.= " &"; + if (!$mysqld_found) + { + print "\n"; + print "FATAL ERROR: Tried to start mysqld under group [$groups[$i]], "; + print "but no mysqld binary was found.\n"; + print "Please add \"mysqld=...\" in group [mysqld_multi], or add it to "; + print "group [$groups[$i]] separately.\n"; + exit(1); + } + if ($basedir_found) + { + $curdir=getcwd(); + chdir($basedir) or die "Can't change to datadir $basedir"; + } + system($com); + if ($basedir_found) + { + chdir($curdir) or die "Can't change back to original dir $curdir"; + } + } + if (!$i && !$opt_no_log) + { + w2log("No MariaDB servers to be started (check your GNRs)", + "$opt_log", 0, 0); + } +} + +#### +#### reload multiple servers +#### + +sub reload_mysqlds() +{ + my (@groups, $com, $tmp, $i, @options, $j); + + if (!$opt_no_log) + { + w2log("\nReloading MySQL servers\n","$opt_log",0,0); + } + else + { + print "\nReloading MySQL servers\n"; + } + @groups = &find_groups($groupids); + for ($i = 0; defined($groups[$i]); $i++) + { + $mysqld_server = $mysqld; + @options = defaults_for_group($groups[$i]); + + for ($j = 0, $tmp= ""; defined($options[$j]); $j++) + { + if ("--mysqladmin=" eq substr($options[$j], 0, 13)) + { + # catch this and ignore + } + elsif ("--mysqld=" eq substr($options[$j], 0, 9)) + { + $options[$j] =~ s/\-\-mysqld\=//; + $mysqld_server = $options[$j]; + } + elsif ("--pid-file=" eq substr($options[$j], 0, 11)) + { + $options[$j] =~ s/\-\-pid-file\=//; + $pid_file = $options[$j]; + } + } + $com = "killproc -p $pid_file -HUP $mysqld_server"; + system($com); + + $com = "touch $pid_file"; + system($com); + } + if (!$i && !$opt_no_log) + { + w2log("No MySQL servers to be reloaded (check your GNRs)", + "$opt_log", 0, 0); + } +} + +### +#### stop multiple servers +#### + +sub stop_mysqlds() +{ + my (@groups, $com, $i, @options); + + if (!$opt_no_log) + { + w2log("\nStopping MariaDB servers\n","$opt_log",0,0); + } + else + { + print "\nStopping MariaDB servers\n"; + } + @groups = &find_groups($groupids); + for ($i = 0; defined($groups[$i]); $i++) + { + $com= get_mysqladmin_options($i, @groups); + $com.= " shutdown"; + $com.= " >> $opt_log 2>&1" if (!$opt_no_log); + $com.= " &"; + system($com); + } + if (!$i && !$opt_no_log) + { + w2log("No MariaDB servers to be stopped (check your GNRs)", + "$opt_log", 0, 0); + } +} + +#### +#### Sub function for mysqladmin option parsing +#### + +sub get_mysqladmin_options +{ + my ($i, @groups)= @_; + my ($mysqladmin_found, $com, $tmp, $j); + + @options = defaults_for_group($groups[$i]); + + $mysqladmin_found= 1; # The default + $mysqladmin_found= 0 if (!length($mysqladmin)); + $com = "$mysqladmin"; + $tmp = " -u $opt_user"; + if (defined($opt_password)) { + my $pw= $opt_password; + # Protect single quotes in password + $pw =~ s/'/'"'"'/g; + $tmp.= " -p'$pw'"; + } + $tmp.= $opt_tcp_ip ? " -h 127.0.0.1" : ""; + for ($j = 0; defined($options[$j]); $j++) + { + if ("--mysqladmin=" eq substr($options[$j], 0, 13)) + { + $options[$j]=~ s/\-\-mysqladmin\=//; + $com= $options[$j]; + $mysqladmin_found= 1; + } + elsif ((($options[$j] =~ m/^(\-\-socket\=)(.*)$/) && !$opt_tcp_ip) || + ($options[$j] =~ m/^(\-\-port\=)(.*)$/)) + { + $tmp.= " $options[$j]"; + } + } + if (!$mysqladmin_found) + { + print "\n"; + print "FATAL ERROR: Tried to use mysqladmin in group [$groups[$i]], "; + print "but no mysqladmin binary was found.\n"; + print "Please add \"mysqladmin=...\" in group [mysqld_multi], or "; + print "in group [$groups[$i]].\n"; + exit(1); + } + $com.= $tmp; + return $com; +} + +# Return a list of option files which can be opened. Similar, but not +# identical, to behavior of my_search_option_files() +# TODO implement and use my_print_defaults --list-groups instead +sub list_defaults_files +{ + my %opt; + foreach (@defaults_options) + { + return () if /^--no-defaults$/; + $opt{$1} = $2 if /^--defaults-(extra-file|file)=(.*)$/; + } + + return ($opt{file}) if exists $opt{file}; + + my @dirs; + + # same rule as in mysys/my_default.c + if ('@sysconfdir@') { + push @dirs, '@sysconfdir@/my.cnf'; + } else { + push @dirs, '/etc/my.cnf', '/etc/mysql/my.cnf'; + } + push @dirs, "$ENV{MYSQL_HOME}/my.cnf" if $ENV{MYSQL_HOME}; + push @dirs, $opt{'extra-file'} if $opt{'extra-file'}; + push @dirs, "$ENV{HOME}/.my.cnf" if $ENV{HOME}; + + return @dirs; +} + + +# Takes a specification of GNRs (see --help), and returns a list of matching +# groups which actually are mentioned in a relevant config file +sub find_groups +{ + my ($raw_gids) = @_; + + my %gids; + my @groups; + + if (defined($raw_gids)) + { + # Make a hash of the wanted group ids + foreach my $raw_gid (split ',', $raw_gids) + { + # Match 123 or 123-456 + my ($start, $end) = ($raw_gid =~ /^\s*(\d+)(?:\s*-\s*(\d+))?\s*$/); + $end = $start if not defined $end; + if (not defined $start or $end < $start or $start < 0) + { + print "ABORT: Bad GNR: $raw_gid; see $my_progname --help\n"; + exit(1); + } + + foreach my $i ($start .. $end) + { + # Use $i + 0 to normalize numbers (002 + 0 -> 2) + $gids{$i + 0}= 1; + } + } + } + + my %seen; + my @defaults_files = list_defaults_files(); + while (@defaults_files) + { + my $file = shift @defaults_files; + next unless defined $file and not $seen{$file}++ and open CONF, '<', $file; + + while (<CONF>) + { + if (/^\s*\[\s*(mysqld)(\d+)\s*\]\s*$/) + { + #warn "Found a group: $1$2\n"; + # Use $2 + 0 to normalize numbers (002 + 0 -> 2) + if (not defined($raw_gids) or $gids{$2 + 0}) + { + push @groups, "$1$2"; + } + } + elsif (/^\s*!include\s+(\S.*?)\s*$/) + { + push @defaults_files, $1; + } + elsif (/^\s*!includedir\s+(\S.*?)\s*$/) + { + push @defaults_files, <$1/*.cnf>; + } + } + + close CONF; + } + return @groups; +} + +#### +#### w2log: Write to a logfile. +#### 1.arg: append to the log file (given string, or from a file. if a file, +#### file will be read from $opt_logdir) +#### 2.arg: logfile -name (w2log assumes that the logfile is in $opt_logdir). +#### 3.arg. 0 | 1, if true, print current date to the logfile. 3. arg will +#### be ignored, if 1. arg is a file. +#### 4.arg. 0 | 1, if true, first argument is a file, else a string +#### + +sub w2log +{ + my ($msg, $file, $date_flag, $is_file)= @_; + my (@data); + + open (LOGFILE, ">>$opt_log") + or die "FATAL: w2log: Couldn't open log file: $opt_log\n"; + + if ($is_file) + { + open (FROMFILE, "<$msg") && (@data=<FROMFILE>) && + close(FROMFILE) + or die "FATAL: w2log: Couldn't open file: $msg\n"; + foreach my $line (@data) + { + print LOGFILE "$line"; + } + } + else + { + print LOGFILE "$msg"; + print LOGFILE strftime "%a %b %e %H:%M:%S %Y", localtime if ($date_flag); + print LOGFILE "\n"; + } + close (LOGFILE); + return; +} + +#### +#### my_which is used, because we can't assume that every system has the +#### which -command. my_which can take only one argument at a time. +#### Return values: requested system command with the first found path, +#### or undefined, if not found. +#### + +sub my_which +{ + my ($command) = @_; + my (@paths, $path); + + # If the argument is not 'my_print_defaults' then it would be of the format + # <absolute_path>/<program> + return $command if ($command ne 'my_print_defaults' && -f $command && + -x $command); + + @paths = split(':', $ENV{'PATH'}); + foreach $path (@paths) + { + $path .= "/$command"; + return $path if (-f $path && -x $path); + } + return undef(); +} + + +#### +#### example +#### + +sub example +{ + print <<EOF; +# This is an example of a my.cnf file for $my_progname. +# Usually this file is located in home dir ~/.my.cnf or @sysconfdir@/my.cnf +# +# SOME IMPORTANT NOTES FOLLOW: +# +# 1.COMMON USER +# +# Make sure that the MariaDB user, who is stopping the mysqld services, has +# the same password to all MariaDB servers being accessed by $my_progname. +# This user needs to have the 'Shutdown_priv' -privilege, but for security +# reasons should have no other privileges. It is advised that you create a +# common 'multi_admin' user for all MariaDB servers being controlled by +# $my_progname. Here is an example how to do it: +# +# GRANT SHUTDOWN ON *.* TO multi_admin\@localhost IDENTIFIED BY 'password' +# +# You will need to apply the above to all MariaDB servers that are being +# controlled by $my_progname. 'multi_admin' will shutdown the servers +# using 'mysqladmin' -binary, when '$my_progname stop' is being called. +# +# 2.PID-FILE +# +# If you are using mariadbd-safe to start mariadbd, make sure that every +# MariaDB server has a separate pid-file. In order to use mariadbd-safe +# via $my_progname, you need to use two options: +# +# mysqld=/path/to/mariadbd-safe +# ledir=/path/to/mariadbd-binary/ +# +# ledir (library executable directory), is an option that only mariadbd-safe +# accepts, so you will get an error if you try to pass it to mysqld directly. +# For this reason you might want to use the above options within [mysqld#] +# group directly. +# +# 3.DATA DIRECTORY +# +# It is NOT advised to run many MariaDB servers within the same data directory. +# You can do so, but please make sure to understand and deal with the +# underlying caveats. In short they are: +# - Speed penalty +# - Risk of table/data corruption +# - Data synchronising problems between the running servers +# - Heavily media (disk) bound +# - Relies on the system (external) file locking +# - Is not applicable with all table types. (Such as InnoDB) +# Trying so will end up with undesirable results. +# +# 4.TCP/IP Port +# +# Every server requires one and it must be unique. +# +# 5.[mysqld#] Groups +# +# In the example below the first and the fifth mysqld group was +# intentionally left out. You may have 'gaps' in the config file. This +# gives you more flexibility. +# +# 6.MariaDB Server User +# +# You can pass the user=... option inside [mysqld#] groups. This +# can be very handy in some cases, but then you need to run $my_progname +# as UNIX root. +# +# 7.A Start-up Manage Script for $my_progname +# +# In the recent MariaDB distributions you can find a file called +# mysqld_multi.server.sh. It is a wrapper for $my_progname. This can +# be used to start and stop multiple servers during boot and shutdown. +# +# You can place the file in /etc/init.d/mysqld_multi.server.sh and +# make the needed symbolic links to it from various run levels +# (as per Linux/Unix standard). You may even replace the +# /etc/init.d/mysql.server script with it. +# +# Before using, you must create a my.cnf file either in @prefix@/my.cnf +# or /root/.my.cnf and add the [mysqld_multi] and [mysqld#] groups. +# +# The script can be found from support-files/mysqld_multi.server.sh +# in MariaDB distribution. (Verify the script before using) +# + +[mysqld_multi] +mysqld = @bindir@/mariadbd-safe +mysqladmin = @bindir@/mariadb-admin +user = multi_admin +password = my_password + +[mysqld2] +socket = /tmp/mysql.sock2 +port = 3307 +pid-file = @localstatedir@2/hostname.pid2 +datadir = @localstatedir@2 +language = @datadir@/mysql/english +user = unix_user1 + +[mysqld3] +mysqld = /path/to/mariadbd-safe +ledir = /path/to/mariadbd-binary/ +mysqladmin = /path/to/mariadb-admin +socket = /tmp/mysql.sock3 +port = 3308 +pid-file = @localstatedir@3/hostname.pid3 +datadir = @localstatedir@3 +language = @datadir@/mysql/swedish +user = unix_user2 + +[mysqld4] +socket = /tmp/mysql.sock4 +port = 3309 +pid-file = @localstatedir@4/hostname.pid4 +datadir = @localstatedir@4 +language = @datadir@/mysql/estonia +user = unix_user3 + +[mysqld6] +socket = /tmp/mysql.sock6 +port = 3311 +pid-file = @localstatedir@6/hostname.pid6 +datadir = @localstatedir@6 +language = @datadir@/mysql/japanese +user = unix_user4 +EOF + exit(0); +} + +#### +#### usage +#### + +sub usage +{ + print <<EOF; +$my_progname version $VER by Jani Tolonen + +Description: +$my_progname can be used to start, reload, or stop any number of separate +mysqld processes running in different TCP/IP ports and UNIX sockets. + +$my_progname can read group [mysqld_multi] from my.cnf file. You may +want to put options mysqld=... and mysqladmin=... there. Since +version 2.10 these options can also be given under groups [mysqld#], +which gives more control over different versions. One can have the +default mysqld and mysqladmin under group [mysqld_multi], but this is +not mandatory. Please note that if mysqld or mysqladmin is missing +from both [mysqld_multi] and [mysqld#], a group that is tried to be +used, $my_progname will abort with an error. + +$my_progname will search for groups named [mysqld#] from my.cnf (or +the given --defaults-extra-file=...), where '#' can be any positive +integer starting from 1. These groups should be the same as the regular +[mysqld] group, but with those port, socket and any other options +that are to be used with each separate mysqld process. The number +in the group name has another function; it can be used for starting, +reloading, stopping, or reporting any specific mysqld server. + +Usage: $my_progname [OPTIONS] {start|reload|stop|report} [GNR,GNR,GNR...] +or $my_progname [OPTIONS] {start|reload|stop|report} [GNR-GNR,GNR,GNR-GNR,...] + +The GNR means the group number. You can start, reload, stop or report any GNR, +or several of them at the same time. (See --example) The GNRs list can +be comma separated or a dash combined. The latter means that all the +GNRs between GNR1-GNR2 will be affected. Without GNR argument all the +groups found will either be started, reloaded, stopped, or reported. Note that +syntax for specifying GNRs must appear without spaces. + +Options: + +These options must be given before any others: +--no-defaults Do not read any defaults file +--defaults-file=... Read only this configuration file, do not read the + standard system-wide and user-specific files +--defaults-extra-file=... Read this configuration file in addition to the + standard system-wide and user-specific files +Using: @{[join ' ', @defaults_options]} + +--example Give an example of a config file with extra information. +--help Print this help and exit. +--log=... Log file. Full path to and the name for the log file. NOTE: + If the file exists, everything will be appended. + Using: $opt_log +--mysqladmin=... mysqladmin binary to be used for a server shutdown. + Since version 2.10 this can be given within groups [mysqld#] + Using: $mysqladmin +--mysqld=... mariadbd binary to be used. Note that you can give mariadbd-safe + to this option also. The options are passed to mysqld. Just + make sure you have mariadbd in your PATH or fix mariadbd-safe. + Using: $mysqld + Please note: Since mysqld_multi version 2.3 you can also + give this option inside groups [mysqld#] in ~/.my.cnf, + where '#' stands for an integer (number) of the group in + question. This will be recognised as a special option and + will not be passed to the mysqld. This will allow one to + start different mysqld versions with mysqld_multi. +--no-log Print to stdout instead of the log file. By default the log + file is turned on. +--password=... Password for mysqladmin user. +--silent Disable warnings. +--tcp-ip Connect to the MariaDB server(s) via the TCP/IP port instead + of the UNIX socket. This affects stopping and reporting. + If a socket file is missing, the server may still be + running, but can be accessed only via the TCP/IP port. + By default connecting is done via the UNIX socket. +--user=... mysqladmin user. Using: $opt_user +--verbose Be more verbose. +--version Print the version number and exit. +--wsrep-new-cluster Bootstrap a cluster. +EOF + exit(0); +} diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh new file mode 100644 index 00000000..34a2de1c --- /dev/null +++ b/scripts/mysqld_safe.sh @@ -0,0 +1,1087 @@ +#!/bin/sh +# Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB +# This file is public domain and comes with NO WARRANTY of any kind +# +# Script to start the MySQL daemon and restart it if it dies unexpectedly +# +# This should be executed in the MySQL base directory if you are using a +# binary installation that is not installed in its compile-time default +# location +# +# mysql.server works by first doing a cd to the base directory and from there +# executing mysqld_safe + +# Initialize script globals +KILL_MYSQLD=1; +MYSQLD= +niceness=0 +nowatch=0 +mysqld_ld_preload= +mysqld_ld_library_path= +flush_caches=0 +numa_interleave=0 +wsrep_on=0 +dry_run=0 +defaults_group_suffix= + +# Initial logging status: error log is not open, and not using syslog +logging=init +want_syslog=0 +syslog_tag= +user='@MYSQLD_USER@' +group='@MYSQLD_GROUP@' +pid_file= +err_log= +err_log_base= +skip_err_log=0 + +syslog_tag_mysqld=mysqld +syslog_tag_mysqld_safe=mysqld_safe + +trap '' 1 2 3 15 # we shouldn't let anyone kill us + +# MySQL-specific environment variable. First off, it's not really a umask, +# it's the desired mode. Second, it follows umask(2), not umask(3) in that +# octal needs to be explicit. Our shell might be a proper sh without printf, +# multiple-base arithmetic, and binary arithmetic, so this will get ugly. +# We reject decimal values to keep things at least half-sane. +umask 007 # fallback +UMASK="${UMASK-0640}" +fmode=`echo "$UMASK" | sed -e 's/[^0246]//g'` +octalp=`echo "$fmode"|cut -c1` +fmlen=`echo "$fmode"|wc -c|sed -e 's/ //g'` +if [ "x$octalp" != "x0" -o "x$UMASK" != "x$fmode" -o "x$fmlen" != "x5" ] +then + fmode=0640 + echo "UMASK must be a 3-digit mode with an additional leading 0 to indicate octal." >&2 + echo "The first digit will be corrected to 6, the others may be 0, 2, 4, or 6." >&2 +fi +fmode=`echo "$fmode"|cut -c3-4` +fmode="6$fmode" +if [ "x$UMASK" != "x0$fmode" ] +then + echo "UMASK corrected from $UMASK to 0$fmode ..." +fi + +defaults= +case "$1" in + --no-defaults|--defaults-file=*|--defaults-extra-file=*) + defaults="$1"; shift + ;; +esac + +usage () { + cat <<EOF +Usage: $0 [OPTIONS] + --no-defaults Don't read the system defaults file + --defaults-file=FILE Use the specified defaults file + --defaults-extra-file=FILE Also use defaults from the specified file + --defaults-group-suffix=X Additionally read default groups with X appended + as a suffix + --ledir=DIRECTORY Look for mysqld in the specified directory + --open-files-limit=LIMIT Limit the number of open files + --crash-script=FILE Script to call when mysqld crashes + --core-file-size=LIMIT Limit core files to the specified size + --timezone=TZ Set the system timezone + --malloc-lib=LIB Preload shared library LIB if available + --mysqld=FILE Use the specified file as mysqld + --mysqld-version=VERSION Use "mysqld-VERSION" as mysqld + --dry-run Simulate the start to detect errors but don't start + --nice=NICE Set the scheduling priority of mysqld + --no-auto-restart Exit after starting mysqld + --nowatch Exit after starting mysqld + --plugin-dir=DIR Plugins are under DIR or DIR/VERSION, if + VERSION is given + --skip-kill-mysqld Don't try to kill stray mysqld processes + --syslog Log messages to syslog with 'logger' + --skip-syslog Log messages to error log (default) + --syslog-tag=TAG Pass -t "mysqld-TAG" to 'logger' + --flush-caches Flush and purge buffers/caches before + starting the server + --numa-interleave Run mysqld with its memory interleaved + on all NUMA nodes + +All other options are passed to the mysqld program. + +EOF + exit 1 +} + +find_in_bin() { + if test -x "$MY_BASEDIR_VERSION/bin/$1" + then + echo "$MY_BASEDIR_VERSION/bin/$1" + elif test -x "@bindir@/$1" + then + echo "@bindir@/$1" + else + echo "$1" + fi +} + +log_generic () { + [ $dry_run -eq 1 ] && return + priority="$1" + shift + + msg="`date +'%y%m%d %H:%M:%S'` mysqld_safe $*" + echo "$msg" + case $logging in + init) ;; # Just echo the message, don't save it anywhere + file) + if [ "$helper_exist" -eq "0" ]; then + echo "$msg" | "$helper" "$user" log "$err_log" + fi + ;; + syslog) logger -t "$syslog_tag_mysqld_safe" -p "$priority" "$*" ;; + *) + echo "Internal program error (non-fatal):" \ + " unknown logging method '$logging'" >&2 + ;; + esac +} + +log_error () { + log_generic daemon.error "$@" >&2 +} + +log_notice () { + log_generic daemon.notice "$@" +} + +eval_log_error () { + local cmd="$1" + case $logging in + file) + if [ "$helper_exist" -eq "0" ]; then + cmd="$cmd 2>&1 | "`shell_quote_string "$helper"`" $user log "`shell_quote_string "$err_log"` + fi + ;; + syslog) + # mysqld often prefixes its messages with a timestamp, which is + # redundant when logging to syslog (which adds its own timestamp) + # However, we don't strip the timestamp with sed here, because + # sed buffers output (only GNU sed supports a -u (unbuffered) option) + # which means that messages may not get sent to syslog until the + # mysqld process quits. + cmd="$cmd 2>&1 | logger -t '$syslog_tag_mysqld' -p daemon.error" + ;; + *) + echo "Internal program error (non-fatal):" \ + " unknown logging method '$logging'" >&2 + ;; + esac + + if test $nowatch -eq 1 + then + # We'd prefer to exec $cmd here, but SELinux needs to be fixed first + #/usr/bin/logger "Running mysqld: $cmd" + eval "$cmd &" + exit 0 + else + #echo "Running mysqld: [$cmd]" + eval "$cmd" + fi +} + +shell_quote_string() { + # This sed command makes sure that any special chars are quoted, + # so the arg gets passed exactly to the server. + echo "$1" | sed -e 's,\([^a-zA-Z0-9/_.=-]\),\\\1,g' +} + +wsrep_pick_url() { + [ $# -eq 0 ] && return 0 + + log_error "WSREP: 'wsrep_urls' is DEPRECATED! Use wsrep_cluster_address to specify multiple addresses instead." + + if ! command -v nc >/dev/null + then + log_error "ERROR: nc tool not found in PATH! Make sure you have it installed." + return 1 + fi + + local url + # Assuming URL in the form scheme://host:port + # If host and port are not NULL, the liveness of URL is assumed to be tested + # If port part is absent, the url is returned literally and unconditionally + # If every URL has port but none is reachable, nothing is returned + for url in `echo $@ | sed s/,/\ /g` 0; do + local host=`echo $url | cut -d \: -f 2 | sed s/^\\\/\\\///` + local port=`echo $url | cut -d \: -f 3` + [ -z "$port" ] && break + nc -z "$host" $port >/dev/null && break + done + + if [ "$url" == "0" ]; then + log_error "ERROR: none of the URLs in '$@' is reachable." + return 1 + fi + + echo $url +} + +# Run mysqld with --wsrep-recover and parse recovered position from log. +# Position will be stored in wsrep_start_position_opt global. +wsrep_start_position_opt="" +wsrep_recover_position() { + local mysqld_cmd="$@" + local euid=$(id -u) + local ret=0 + + local wr_logfile=$(mktemp /tmp/wsrep_recovery.XXXXXX) + + # safety checks + if [ -z $wr_logfile ]; then + log_error "WSREP: mktemp failed" + return 1 + fi + + if [ -f $wr_logfile ]; then + # NOTE! Do not change ownership of the temporary file, as on newer kernel + # versions fs.protected_regular is set to '2' and redirecting output with > + # as root to a file not owned by root will fail with "Permission denied" + chmod 600 $wr_logfile + else + log_error "WSREP: mktemp failed" + return 1 + fi + + local wr_pidfile="$DATADIR/"`@HOSTNAME@`"-recover.pid" + + local wr_options="--disable-log-error --pid-file='$wr_pidfile'" + + log_notice "WSREP: Running position recovery with $wr_options" + + eval "$mysqld_cmd --wsrep_recover $wr_options 2> $wr_logfile" + + if [ ! -s "$wr_logfile" ]; then + log_error "Log file $wr_logfile was empty, cannot proceed. Is system running fs.protected_regular?" + exit 1 + fi + + local rp="$(grep 'WSREP: Recovered position:' $wr_logfile)" + if [ -z "$rp" ]; then + local skipped="$(grep WSREP $wr_logfile | grep 'skipping position recovery')" + if [ -z "$skipped" ]; then + log_error "WSREP: Failed to recover position: '`cat $wr_logfile`'" + ret=1 + else + log_notice "WSREP: Position recovery skipped" + fi + else + local start_pos="$(echo $rp | sed 's/.*WSREP\:\ Recovered\ position://' \ + | sed 's/^[ \t]*//')" + log_notice "WSREP: Recovered position $start_pos" + wsrep_start_position_opt="--wsrep_start_position=$start_pos" + fi + + if [ $ret -eq 0 ] ; then + local wr_logfile_permanent="$DATADIR/wsrep_recovery.ok" + else + local wr_logfile_permanent="$DATADIR/wsrep_recovery.fail" + fi + touch $wr_logfile_permanent + [ "$euid" = "0" ] && chown $user $wr_logfile_permanent + chmod 600 $wr_logfile_permanent + cat "$wr_logfile" >> $wr_logfile_permanent + rm -f "$wr_logfile" + + return $ret +} + +parse_arguments() { + for arg do + val=`echo "$arg" | sed -e "s;--[^=]*=;;"` + case "$arg" in + # these get passed explicitly to mysqld + --basedir=*) MY_BASEDIR_VERSION="$val" ;; + --datadir=*|--data=*) DATADIR="$val" ;; + --pid[-_]file=*) pid_file="$val" ;; + --plugin[-_]dir=*) PLUGIN_DIR="$val" ;; + --user=*) user="$val"; SET_USER=1 ;; + --group=*) group="$val"; SET_USER=1 ;; + --log[-_]basename=*|--hostname=*|--loose[-_]log[-_]basename=*) + pid_file="$val.pid"; + err_log_base="$val"; + ;; + + # these might have been set in a [mysqld_safe] section of my.cnf + # they are added to mysqld command line to override settings from my.cnf + --skip[-_]log[-_]error) + err_log=; + skip_err_log=1; + ;; + --log[-_]error=*) + err_log="$val"; + skip_err_log=0; + ;; + --port=*) mysql_tcp_port="$val" ;; + --socket=*) mysql_unix_port="$val" ;; + + # mysqld_safe-specific options - must be set in my.cnf ([mysqld_safe])! + --core[-_]file[-_]size=*) core_file_size="$val" ;; + --ledir=*) ledir="$val" ;; + --malloc[-_]lib=*) set_malloc_lib "$val" ;; + --crash[-_]script=*) crash_script="$val" ;; + --mysqld=*) MYSQLD="$val" ;; + --mysqld[-_]version=*) + if test -n "$val" + then + MYSQLD="mysqld-$val" + PLUGIN_VARIANT="/$val" + else + MYSQLD="mysqld" + fi + ;; + --dry[-_]run) dry_run=1 ;; + --nice=*) niceness="$val" ;; + --nowatch|--no[-_]watch|--no[-_]auto[-_]restart) nowatch=1 ;; + --open[-_]files[-_]limit=*) open_files="$val" ;; + --skip[-_]kill[-_]mysqld*) KILL_MYSQLD=0 ;; + --syslog) want_syslog=1 ;; + --skip[-_]syslog) want_syslog=0 ;; + --syslog[-_]tag=*) syslog_tag="$val" ;; + --timezone=*) TZ="$val"; export TZ; ;; + --flush[-_]caches) flush_caches=1 ;; + --numa[-_]interleave) numa_interleave=1 ;; + --wsrep[-_]on) + wsrep_on=1 + append_arg_to_args "$arg" + ;; + --skip[-_]wsrep[-_]on) + wsrep_on=0 + append_arg_to_args "$arg" + ;; + --wsrep[-_]on=*) + if echo $val | grep -iq '\(ON\|1\)'; then + wsrep_on=1 + else + wsrep_on=0 + fi + append_arg_to_args "$arg" + ;; + --wsrep[-_]urls=*) wsrep_urls="$val"; ;; + --wsrep[-_]provider=*) + if test -n "$val" && test "$val" != "none" + then + wsrep_restart=1 + fi + append_arg_to_args "$arg" + ;; + + --defaults-group-suffix=*) defaults_group_suffix="$arg" ;; + + --help) usage ;; + + *) + case "$unrecognized_handling" in + collect) append_arg_to_args "$arg" ;; + complain) log_error "unknown option '$arg'" ;; + esac + esac + done +} + + +# Add a single shared library to the list of libraries which will be added to +# LD_PRELOAD for mysqld +# +# Since LD_PRELOAD is a space-separated value (for historical reasons), if a +# shared lib's path contains spaces, that path will be prepended to +# LD_LIBRARY_PATH and stripped from the lib value. +add_mysqld_ld_preload() { + lib_to_add="$1" + log_notice "Adding '$lib_to_add' to LD_PRELOAD for mysqld" + + case "$lib_to_add" in + *' '*) + # Must strip path from lib, and add it to LD_LIBRARY_PATH + lib_file=`basename "$lib_to_add"` + case "$lib_file" in + *' '*) + # The lib file itself has a space in its name, and can't + # be used in LD_PRELOAD + log_error "library name '$lib_to_add' contains spaces and can not be used with LD_PRELOAD" + exit 1 + ;; + esac + lib_path=`dirname "$lib_to_add"` + lib_to_add="$lib_file" + [ -n "$mysqld_ld_library_path" ] && mysqld_ld_library_path="$mysqld_ld_library_path:" + mysqld_ld_library_path="$mysqld_ld_library_path$lib_path" + ;; + esac + + # LD_PRELOAD is a space-separated + [ -n "$mysqld_ld_preload" ] && mysqld_ld_preload="$mysqld_ld_preload " + mysqld_ld_preload="${mysqld_ld_preload}$lib_to_add" +} + + +# Returns LD_PRELOAD (and LD_LIBRARY_PATH, if needed) text, quoted to be +# suitable for use in the eval that calls mysqld. +# +# All values in mysqld_ld_preload are prepended to LD_PRELOAD. +mysqld_ld_preload_text() { + text= + + if [ -n "$mysqld_ld_preload" ]; then + new_text="$mysqld_ld_preload" + [ -n "$LD_PRELOAD" ] && new_text="$new_text $LD_PRELOAD" + text="${text}LD_PRELOAD="`shell_quote_string "$new_text"`' ' + fi + + if [ -n "$mysqld_ld_library_path" ]; then + new_text="$mysqld_ld_library_path" + [ -n "$LD_LIBRARY_PATH" ] && new_text="$new_text:$LD_LIBRARY_PATH" + text="${text}LD_LIBRARY_PATH="`shell_quote_string "$new_text"`' ' + fi + + echo "$text" +} + +# set_malloc_lib LIB +# - If LIB is empty, do nothing and return +# - If LIB starts with 'tcmalloc' or 'jemalloc', look for the shared library +# using `ldconfig`. +# tcmalloc is part of the Google perftools project. +# - If LIB is an absolute path, assume it is a malloc shared library +# +# Put LIB in mysqld_ld_preload, which will be added to LD_PRELOAD when +# running mysqld. See ld.so for details. +set_malloc_lib() { + malloc_lib="$1" + if expr "$malloc_lib" : "\(tcmalloc\|jemalloc\)" > /dev/null ; then + export PATH=$PATH:/sbin + if ! command -v ldconfig > /dev/null 2>&1 + then + log_error "ldconfig command not found, required for ldconfig -p" + exit 1 + fi + # format from ldconfig: + # "libjemalloc.so.1 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libjemalloc.so.1" + libmalloc_path="$(ldconfig -p | sed -n "/lib${malloc_lib}/p" | cut -d '>' -f2)" + + if [ -z "$libmalloc_path" ]; then + log_error "no shared library for lib$malloc_lib.so.[0-9] found." + exit 1 + fi + + for f in $libmalloc_path; do + if [ -f "$f" ]; then + malloc_lib=$f # get the first path if many + break + fi + done + fi + # Allow --malloc-lib='' to override other settings + [ -z "$malloc_lib" ] && return + + case "$malloc_lib" in + /*) + if [ ! -r "$malloc_lib" ]; then + log_error "--malloc-lib '$malloc_lib' can not be read and will not be used" + exit 1 + fi + ;; + *) + log_error "--malloc-lib must be an absolute path, 'tcmalloc' or " \ + "'jemalloc'; ignoring value '$malloc_lib'" + exit 1 + ;; + esac + add_mysqld_ld_preload "$malloc_lib" +} + + +# +# First, try to find BASEDIR and ledir (where mysqld is) +# + +MY_PWD=`dirname $0` +MY_PWD=`cd "$MY_PWD"/.. && pwd` +# Check for the directories we would expect from a binary release install +if test -n "$MY_BASEDIR_VERSION" -a -d "$MY_BASEDIR_VERSION" +then + # BASEDIR is already overridden on command line. Do not re-set. + + # Use BASEDIR to discover le. + if test -x "$MY_BASEDIR_VERSION/libexec/mariadbd" + then + ledir="$MY_BASEDIR_VERSION/libexec" + elif test -x "$MY_BASEDIR_VERSION/sbin/mariadbd" + then + ledir="$MY_BASEDIR_VERSION/sbin" + else + ledir="$MY_BASEDIR_VERSION/bin" + fi +elif test -x "$MY_PWD/bin/mariadbd" +then + MY_BASEDIR_VERSION="$MY_PWD" # Where bin, share and data are + ledir="$MY_PWD/bin" # Where mysqld is +# Check for the directories we would expect from a source install +elif test -x "$MY_PWD/libexec/mariadbd" +then + MY_BASEDIR_VERSION="$MY_PWD" # Where libexec, share and var are + ledir="$MY_PWD/libexec" # Where mysqld is +elif test -x "$MY_PWD/sbin/mariadbd" +then + MY_BASEDIR_VERSION="$MY_PWD" # Where sbin, share and var are + ledir="$MY_PWD/sbin" # Where mysqld is +# Since we didn't find anything, used the compiled-in defaults +else + MY_BASEDIR_VERSION='@prefix@' + ledir='@libexecdir@' +fi + +helper=`find_in_bin mariadbd-safe-helper` + +print_defaults=`find_in_bin my_print_defaults` +# Check if helper exists +command -v $helper --help >/dev/null 2>&1 +helper_exist=$? +# +# Second, try to find the data directory +# + +# Try where the binary installs put it +if test -d $MY_BASEDIR_VERSION/data/mysql +then + DATADIR=$MY_BASEDIR_VERSION/data +# Next try where the source installs put it +elif test -d $MY_BASEDIR_VERSION/var/mysql +then + DATADIR=$MY_BASEDIR_VERSION/var +# Or just give up and use our compiled-in default +else + DATADIR=@localstatedir@ +fi + +if test -z "$MYSQL_HOME" +then + if test -r "$DATADIR/my.cnf" + then + log_error "WARNING: Found $DATADIR/my.cnf +The data directory is not a valid location for my.cnf, please move it to +$MY_BASEDIR_VERSION/my.cnf" + fi + MYSQL_HOME=$MY_BASEDIR_VERSION +fi +export MYSQL_HOME + +append_arg_to_args () { + args="$args "`shell_quote_string "$1"` +} + +args= + +# Get first arguments from the my.cnf file, groups [mysqld] and [server] +# (and related) and then merge with the command line arguments + +SET_USER=2 +parse_arguments `$print_defaults $defaults --loose-verbose --mysqld` +if test $SET_USER -eq 2 +then + SET_USER=0 +fi + +# If arguments come from [mysqld_safe] section of my.cnf +# we complain about unrecognized options +unrecognized_handling=complain +parse_arguments `$print_defaults $defaults --loose-verbose mysqld_safe safe_mysqld mariadb_safe mariadbd-safe` + +# We only need to pass arguments through to the server if we don't +# handle them here. So, we collect unrecognized options (passed on +# the command line) into the args variable. +unrecognized_handling=collect +parse_arguments "$@" + + +# +# Try to find the plugin directory +# + +# Use user-supplied argument +if [ -n "${PLUGIN_DIR}" ]; then + plugin_dir="${PLUGIN_DIR}" +else + # Try to find plugin dir relative to basedir + for dir in lib64/mysql/plugin lib64/plugin lib/mysql/plugin lib/plugin + do + if [ -d "${MY_BASEDIR_VERSION}/${dir}" ]; then + plugin_dir="${MY_BASEDIR_VERSION}/${dir}" + break + fi + done + # Give up and use compiled-in default + if [ -z "${plugin_dir}" ]; then + plugin_dir='@pkgplugindir@' + fi +fi +plugin_dir="${plugin_dir}${PLUGIN_VARIANT}" + +# Determine what logging facility to use + +# Ensure that 'logger' exists, if it's requested +if [ $want_syslog -eq 1 ] +then + if ! command -v logger > /dev/null + then + log_error "--syslog requested, but no 'logger' program found. Please ensure that 'logger' is in your PATH, or do not specify the --syslog option to mysqld_safe." + exit 1 + fi +fi + +if [ $skip_err_log -eq 1 ] +then + append_arg_to_args "--skip-log-error" +fi + +if [ -n "$err_log" -o $want_syslog -eq 0 ] +then + if [ -n "$err_log" ] + then + # mysqld adds ".err" if there is no extension on the --log-error + # argument; must match that here, or mysqld_safe will write to a + # different log file than mysqld + + # mysqld does not add ".err" to "--log-error=foo."; it considers a + # trailing "." as an extension + + if expr "$err_log" : '.*\.[^/]*$' > /dev/null + then + : + else + err_log="$err_log".err + fi + + case "$err_log" in + /* ) ;; + * ) err_log="$DATADIR/$err_log" ;; + esac + else + if [ -n "$err_log_base" ] + then + err_log=$err_log_base.err + case "$err_log" in + /* ) ;; + * ) err_log="$DATADIR/$err_log" ;; + esac + else + err_log=$DATADIR/`@HOSTNAME@`.err + fi + fi + + append_arg_to_args "--log-error=$err_log" + + if [ $want_syslog -eq 1 ] + then + # User explicitly asked for syslog, so warn that it isn't used + log_error "Can't log to error log and syslog at the same time. Remove all --log-error configuration options for --syslog to take effect." + want_syslog=0 + fi + + # Log to err_log file + log_notice "Logging to '$err_log'." + logging=file + +else + if [ -n "$syslog_tag" ] + then + # Sanitize the syslog tag + syslog_tag=`echo "$syslog_tag" | sed -e 's/[^a-zA-Z0-9_-]/_/g'` + syslog_tag_mysqld_safe="${syslog_tag_mysqld_safe}-$syslog_tag" + syslog_tag_mysqld="${syslog_tag_mysqld}-$syslog_tag" + fi + log_notice "Logging to syslog." + logging=syslog +fi + +USER_OPTION="" +if test -w / -o "$USER" = "root" +then + if test "$user" != "root" -o $SET_USER = 1 + then + USER_OPTION="--user=$user" + # To be used if/when we enable --system-group as an option to mysqld + GROUP_OPTION="--group=$group" + fi + if test -n "$open_files" + then + ulimit -n $open_files + fi +fi + +if test -n "$open_files" +then + append_arg_to_args "--open-files-limit=$open_files" +fi + +safe_mysql_unix_port=${mysql_unix_port:-${MYSQL_UNIX_PORT:-@MYSQL_UNIX_ADDR@}} +# Make sure that directory for $safe_mysql_unix_port exists +mysql_unix_port_dir=`dirname $safe_mysql_unix_port` +if [ ! -d $mysql_unix_port_dir -a $dry_run -eq 0 ] +then + if ! mkdir -p $mysql_unix_port_dir + then + log_error "Fatal error Can't create database directory '$mysql_unix_port'" + exit 1 + fi + if [ "$user" -a "$group" ]; then + chown $user:$group $mysql_unix_port_dir + else + [ "$user" ] && chown $user $mysql_unix_port_dir + [ "$group" ] && chgrp $group $mysql_unix_port_dir + fi + chmod 755 $mysql_unix_port_dir +fi + +# If the user doesn't specify a binary, we assume name "mariadbd" +if test -z "$MYSQLD" +then + MYSQLD=mariadbd +fi + +if test ! -x "$ledir/$MYSQLD" +then + log_error "The file $ledir/$MYSQLD +does not exist or is not executable. Please cd to the mysql installation +directory and restart this script from there as follows: +./bin/mysqld_safe& +See https://mariadb.com/kb/en/mysqld_safe for more information" + exit 1 +fi + +if test -z "$pid_file" +then + pid_file="`@HOSTNAME@`.pid" +fi +# MariaDB wants pid file without datadir +append_arg_to_args "--pid-file=$pid_file" +case "$pid_file" in + /* ) ;; + * ) pid_file="$DATADIR/$pid_file" ;; +esac + +if test -n "$mysql_unix_port" +then + append_arg_to_args "--socket=$mysql_unix_port" +fi +if test -n "$mysql_tcp_port" +then + append_arg_to_args "--port=$mysql_tcp_port" +fi + +if test $niceness -eq 0 +then + NOHUP_NICENESS="nohup" +else + NOHUP_NICENESS="nohup nice -$niceness" +fi + +# Using nice with no args to get the niceness level is GNU-specific. +# This check could be extended for other operating systems (e.g., +# BSD could use "nohup sh -c 'ps -o nice -p $$' | tail -1"). +# But, it also seems that GNU nohup is the only one which messes +# with the priority, so this is okay. +if nohup nice > /dev/null 2>&1 +then + normal_niceness=`nice` + nohup_niceness=`nohup nice 2>/dev/null` + + numeric_nice_values=1 + for val in $normal_niceness $nohup_niceness + do + case "$val" in + -[0-9] | -[0-9][0-9] | -[0-9][0-9][0-9] | \ + [0-9] | [0-9][0-9] | [0-9][0-9][0-9] ) + ;; + * ) + numeric_nice_values=0 ;; + esac + done + + if test $numeric_nice_values -eq 1 + then + nice_value_diff=`expr $nohup_niceness - $normal_niceness` + if test $? -eq 0 && test $nice_value_diff -gt 0 && \ + nice --$nice_value_diff echo testing > /dev/null 2>&1 + then + # nohup increases the priority (bad), and we are permitted + # to lower the priority with respect to the value the user + # might have been given + niceness=`expr $niceness - $nice_value_diff` + NOHUP_NICENESS="nice -$niceness nohup" + fi + fi +else + if nohup echo testing > /dev/null 2>&1 + then + : + else + # nohup doesn't work on this system + NOHUP_NICENESS="" + fi +fi + +# Try to set the core file size (even if we aren't root) because many systems +# don't specify a hard limit on core file size. +if test -n "$core_file_size" +then + ulimit -c $core_file_size +fi + +# +# If there exists an old pid file, check if the daemon is already running +# Note: The switches to 'ps' may depend on your operating system +if test -f "$pid_file" && [ $dry_run -eq 0 ] +then + PID=`cat "$pid_file"` + if @CHECK_PID@ + then + if @FIND_PROC@ + then # The pid contains a mysqld process + log_error "A mysqld process already exists" + exit 1 + fi + fi + rm -f "$pid_file" + if test -f "$pid_file" + then + log_error "Fatal error: Can't remove the pid file: +$pid_file +Please remove it manually and start $0 again; +mysqld daemon not started" + exit 1 + fi +fi + +# +# Flush and purge buffers/caches. +# + +if @TARGET_LINUX@ && test $flush_caches -eq 1 +then + # Locate sync, ensure it exists. + if ! command -v sync > /dev/null + then + log_error "sync command not found, required for --flush-caches" + exit 1 + # Flush file system buffers. + elif ! sync + then + # Huh, the sync() function is always successful... + log_error "sync failed, check if sync is properly installed" + fi + + # Locate sysctl, ensure it exists. + if ! command -v sysctl > /dev/null + then + log_error "sysctl command not found, required for --flush-caches" + exit 1 + # Purge page cache, dentries and inodes. + elif ! sysctl -q -w vm.drop_caches=3 + then + log_error "sysctl failed, check the error message for details" + exit 1 + fi +elif test $flush_caches -eq 1 +then + log_error "--flush-caches is not supported on this platform" + exit 1 +fi + +# +# Uncomment the following lines if you want all tables to be automatically +# checked and repaired during startup. You should add sensible key_buffer +# and sort_buffer values to my.cnf to improve check performance or require +# less disk space. +# Alternatively, you can start mysqld with the "myisam-recover" option. See +# the manual for details. +# +# echo "Checking tables in $DATADIR" +# $MY_BASEDIR_VERSION/bin/myisamchk --silent --force --fast --medium-check $DATADIR/*/*.MYI +# $MY_BASEDIR_VERSION/bin/isamchk --silent --force $DATADIR/*/*.ISM + +# Does this work on all systems? +#if type ulimit | grep "shell builtin" > /dev/null +#then +# ulimit -n 256 > /dev/null 2>&1 # Fix for BSD and FreeBSD systems +#fi + +cmd="`mysqld_ld_preload_text`$NOHUP_NICENESS" +[ $dry_run -eq 1 ] && cmd='' + +# +# Set mysqld's memory interleave policy. +# + +if @TARGET_LINUX@ && test $numa_interleave -eq 1 +then + # Locate numactl, ensure it exists. + if ! command -v numactl > /dev/null + then + log_error "numactl command not found, required for --numa-interleave" + exit 1 + # Attempt to run a command, ensure it works. + elif ! numactl --interleave=all true + then + log_error "numactl failed, check if numactl is properly installed" + fi + + # Launch mysqld with numactl. + [ $dry_run -eq 0 ] && cmd="$cmd numactl --interleave=all" +elif test $numa_interleave -eq 1 +then + log_error "--numa-interleave is not supported on this platform" + exit 1 +fi + +for i in "$ledir/$MYSQLD" "$defaults_group_suffix" "$defaults" "--basedir=$MY_BASEDIR_VERSION" \ + "--datadir=$DATADIR" "--plugin-dir=$plugin_dir" "$USER_OPTION" +do + cmd="$cmd "`shell_quote_string "$i"` +done +cmd="$cmd $args" + +if [ $dry_run -eq 1 ] +then + # RETURN or EXIT depending if the script is being sourced or not. + (return 2> /dev/null) && return || exit +fi + + +# Avoid 'nohup: ignoring input' warning +test -n "$NOHUP_NICENESS" && cmd="$cmd < /dev/null" +log_notice "Starting $MYSQLD daemon with databases from $DATADIR" + +# variable to track the current number of "fast" (a.k.a. subsecond) restarts +fast_restart=0 +# maximum number of restarts before trottling kicks in +max_fast_restarts=5 +# flag whether a usable sleep command exists +have_sleep=1 + +# close stdout and stderr, everything goes to $logging now +if expr "${-}" : '.*x' > /dev/null +then + : +else + exec 1>/dev/null + exec 2>/dev/null +fi + +# maximum number of wsrep restarts +max_wsrep_restarts=0 + +while true +do + rm -f "$pid_file" # Some extra safety + + start_time=`date +%M%S` + + # Perform wsrep position recovery if wsrep_on=1, skip otherwise. + if test $wsrep_on -eq 1 + then + # this sets wsrep_start_position_opt + wsrep_recover_position "$cmd" + + [ $? -ne 0 ] && exit 1 # + + [ -n "$wsrep_urls" ] && url=`wsrep_pick_url $wsrep_urls` # check connect address + + if [ -z "$url" ] + then + eval_log_error "$cmd $wsrep_start_position_opt" + else + eval_log_error "$cmd $wsrep_start_position_opt --wsrep_cluster_address=$url" + fi + else + eval_log_error "$cmd" + fi + end_time=`date +%M%S` + + if test ! -f "$pid_file" # This is removed if normal shutdown + then + break + fi + + + # sanity check if time reading is sane and there's sleep + if test $end_time -gt 0 -a $have_sleep -gt 0 + then + # throttle down the fast restarts + if test $end_time -eq $start_time + then + fast_restart=`expr $fast_restart + 1` + if test $fast_restart -ge $max_fast_restarts + then + log_notice "The server is respawning too fast. Sleeping for 1 second." + sleep 1 + sleep_state=$? + if test $sleep_state -gt 0 + then + log_notice "The server is respawning too fast and no working sleep command. Turning off trottling." + have_sleep=0 + fi + + fast_restart=0 + fi + else + fast_restart=0 + fi + fi + + if @TARGET_LINUX@ && test $KILL_MYSQLD -eq 1 + then + # Test if one process was hanging. + # This is only a fix for Linux (running as base 3 mysqld processes) + # but should work for the rest of the servers. + # The only thing is ps x => redhat 5 gives warnings when using ps -x. + # kill -9 is used or the process won't react on the kill. + numofproces=`ps xaww | grep -v "grep" | grep "$ledir/$MYSQLD\>" | grep -c "pid-file=$pid_file"` + + log_notice "Number of processes running now: $numofproces" + I=1 + while test "$I" -le "$numofproces" + do + PROC=`ps xaww | grep "$ledir/$MYSQLD\>" | grep -v "grep" | grep "pid-file=$pid_file" | sed -n '$p'` + + for T in $PROC + do + break + done + # echo "TEST $I - $T **" + if kill -9 $T + then + log_error "$MYSQLD process hanging, pid $T - killed" + else + break + fi + I=`expr $I + 1` + done + fi + + if [ -n "$wsrep_restart" ] + then + if [ $wsrep_restart -le $max_wsrep_restarts ] + then + wsrep_restart=`expr $wsrep_restart + 1` + log_notice "WSREP: sleeping 15 seconds before restart" + sleep 15 + else + log_notice "WSREP: not restarting wsrep node automatically" + break + fi + fi + + log_notice "mysqld restarted" + if test -n "$crash_script" + then + crash_script_output=`$crash_script 2>&1` + log_error "$crash_script_output" + fi +done + +log_notice "mysqld from pid file $pid_file ended" diff --git a/scripts/mysqldumpslow.sh b/scripts/mysqldumpslow.sh new file mode 100644 index 00000000..5c46587e --- /dev/null +++ b/scripts/mysqldumpslow.sh @@ -0,0 +1,236 @@ +#!@PERL_PATH@ + +# Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1335 USA + +# mysqldumpslow - parse and summarize the MySQL slow query log + +# Original version by Tim Bunce, sometime in 2000. +# Further changes by Tim Bunce, 8th March 2001. +# Handling of strings with \ and double '' by Monty 11 Aug 2001. + +use strict; +use Getopt::Long; + +# t=time, l=lock time, r=rows, a=rows affected +# at, al, ar and aa are the corresponding averages + +my %opt = ( + s => 'at', + h => '*', +); + +GetOptions(\%opt, + 'v|verbose+',# verbose + 'help+', # write usage info + 'd|debug+', # debug + 's=s', # what to sort by (aa, ae, al, ar, at, a, c, e, l, r, t) + 'r!', # reverse the sort order (largest last instead of first) + 't=i', # just show the top n queries + 'a!', # don't abstract all numbers to N and strings to 'S' + 'n=i', # abstract numbers with at least n digits within names + 'g=s', # grep: only consider stmts that include this string + 'h=s', # hostname/basename of db server for *-slow.log filename (can be wildcard) + 'i=s', # name of server instance (if using mysql.server startup script) + 'l!', # don't subtract lock time from total time +) or usage("bad option"); + +$opt{'help'} and usage(); + +unless (@ARGV) { + my $defaults = `my_print_defaults --mysqld`; + + my $datadir = ($defaults =~ m/--datadir=(.*)/g)[-1]; + if (!$datadir or $opt{i}) { + # determine the datadir from the instances section of /etc/my.cnf, if any + my $instances = `my_print_defaults instances`; + die "Can't determine datadir from 'my_print_defaults instances' output: $defaults" + unless $instances; + my @instances = ($instances =~ m/^--(\w+)-/mg); + die "No -i 'instance_name' specified to select among known instances: @instances.\n" + unless $opt{i}; + die "Instance '$opt{i}' is unknown (known instances: @instances)\n" + unless grep { $_ eq $opt{i} } @instances; + $datadir = ($instances =~ m/--$opt{i}-datadir=(.*)/g)[-1] + or die "Can't determine --$opt{i}-datadir from 'my_print_defaults instances' output: $instances"; + warn "datadir=$datadir\n" if $opt{v}; + } + + my $slowlog = ($defaults =~ m/--log[-_]slow[-_]queries=(.*)/g)[-1]; + if (!$slowlog) + { + $slowlog = ($defaults =~ m/--slow[-_]query[-_]log[-_]file=(.*)/g)[-1]; + } + if ( $slowlog ) + { + @ARGV = ($slowlog); + die "Can't find '$slowlog'\n" unless @ARGV; + } + else + { + if (!$opt{h}) + { + $opt{h}= ($defaults =~ m/--log[-_]basename=(.*)/g)[-1]; + } + @ARGV = <$datadir/$opt{h}-slow.log>; + die "Can't find '$datadir/$opt{h}-slow.log'\n" unless @ARGV; + } +} + +warn "\nReading mysql slow query log from @ARGV\n"; + +my @pending; +my %stmt; +$/ = ";\n#"; # read entire statements using paragraph mode +while ( defined($_ = shift @pending) or defined($_ = <>) ) { + warn "[[$_]]\n" if $opt{d}; # show raw paragraph being read + + my @chunks = split /^\/.*Version.*started with[\000-\377]*?Time.*Id.*Command.*Argument.*\n/m; + if (@chunks > 1) { + unshift @pending, map { length($_) ? $_ : () } @chunks; + warn "<<".join(">>\n<<",@chunks).">>" if $opt{d}; + next; + } + + s/^#? Time: \d{6}\s+\d+:\d+:\d+.*\n//; + my ($user,$host) = s/^#? User\@Host:\s+(\S+)\s+\@\s+(\S+).*\n// ? ($1,$2) : ('',''); + + s/^# Thread_id: [0-9]+\s+Schema: .*\s+QC_hit:.*[^\n]+\n//; + s/^# Query_time: ([0-9.]+)\s+Lock_time: ([0-9.]+)\s+Rows_sent: ([0-9.]+)\s+Rows_examined: ([0-9.]+).*\n//; + my ($t, $l, $r, $e) = ($1, $2, $3, $4); + s/^# Rows_affected: ([0-9.]+).*\n//; + my ($a) = ($1); + + $t -= $l unless $opt{l}; + + # remove fluff that mysqld writes to log when it (re)starts: + s!^/.*Version.*started with:.*\n!!mg; + s!^Tcp port: \d+ Unix socket: \S+\n!!mg; + s!^Time.*Id.*Command.*Argument.*\n!!mg; + + # Remove optimizer info + s!^# QC_Hit: \S+\s+Full_scan: \S+\s+Full_join: \S+\s+Tmp_table: \S+\s+Tmp_table_on_disk: \S+[^\n]+\n!!mg; + s!^# Filesort: \S+\s+Filesort_on_disk: \S+[^\n]+\n!!mg; + s!^# Full_scan: \S+\s+Full_join: \S+[^\n]+\n!!mg; + + s/^use \w+;\n//; # not consistently added + s/^SET timestamp=\d+;\n//; + + s/^[ ]*\n//mg; # delete blank lines + s/^[ ]*/ /mg; # normalize leading whitespace + s/\s*;\s*(#\s*)?$//; # remove trailing semicolon(+newline-hash) + + next if $opt{g} and !m/$opt{g}/io; + + unless ($opt{a}) { + s/\b\d+\b/N/g; + s/\b0x[0-9A-Fa-f]+\b/N/g; + s/''/'S'/g; + s/""/"S"/g; + s/(\\')//g; + s/(\\")//g; + s/'[^']+'/'S'/g; + s/"[^"]+"/"S"/g; + # -n=8: turn log_20001231 into log_NNNNNNNN + s/([a-z_]+)(\d{$opt{n},})/$1.('N' x length($2))/ieg if $opt{n}; + # abbreviate massive "in (...)" statements and similar + s!(([NS],){100,})!sprintf("$2,{repeated %d times}",length($1)/2)!eg; + } + + my $s = $stmt{$_} ||= { users=>{}, hosts=>{} }; + $s->{c} += 1; + $s->{t} += $t; + $s->{l} += $l; + $s->{r} += $r; + $s->{e} += $e; + $s->{a} += $a; + $s->{users}->{$user}++ if $user; + $s->{hosts}->{$host}++ if $host; + + warn "{{$_}}\n\n" if $opt{d}; # show processed statement string +} + +foreach (keys %stmt) { + my $v = $stmt{$_} || die; + my ($c, $t, $l, $r, $e, $a) = @{ $v }{qw(c t l r e a)}; + $v->{at} = $t / $c; + $v->{al} = $l / $c; + $v->{ar} = $r / $c; + $v->{ae} = $e / $c; + $v->{aa} = $a / $c; +} + +my @sorted = sort { $stmt{$b}->{$opt{s}} <=> $stmt{$a}->{$opt{s}} } keys %stmt; +@sorted = @sorted[0 .. $opt{t}-1] if $opt{t}; +@sorted = reverse @sorted if $opt{r}; + +foreach (@sorted) { + my $v = $stmt{$_} || die; + my ($c, $t, $at, $l, $al, $r, $ar, $e, $ae, $a, $aa) = @{ $v }{qw(c t at l al r ar e ae a aa)}; + my @users = keys %{$v->{users}}; + my $user = (@users==1) ? $users[0] : sprintf "%dusers",scalar @users; + my @hosts = keys %{$v->{hosts}}; + my $host = (@hosts==1) ? $hosts[0] : sprintf "%dhosts",scalar @hosts; + printf "Count: %d Time=%.2fs (%ds) Lock=%.2fs (%ds) Rows_sent=%.1f (%d), Rows_examined=%.1f (%d), Rows_affected=%.1f (%d), $user\@$host\n%s\n\n", + $c, $at,$t, $al,$l, $ar,$r, $ae, $e, $aa, $a, $_; +} + +sub usage { + my $str= shift; + my $text= <<HERE; +Usage: mysqldumpslow [ OPTS... ] [ LOGS... ] + +Parse and summarize the MySQL slow query log. Options are + + --verbose verbose + --debug debug + --help write this text to standard output + + -v verbose + -d debug + -s ORDER what to sort by (aa, ae, al, ar, at, a, c, e, l, r, t), 'at' is default + aa: average rows affected + ae: aggregated rows examined + al: average lock time + ar: average rows sent + at: average query time + a: rows affected + c: count + e: rows examined + l: lock time + r: rows sent + t: query time + -r reverse the sort order (largest last instead of first) + -t NUM just show the top n queries + -a don't abstract all numbers to N and strings to 'S' + -n NUM abstract numbers with at least n digits within names + -g PATTERN grep: only consider stmts that include this string + -h HOSTNAME hostname of db server for *-slow.log filename (can be wildcard), + default is '*', i.e. match all + -i NAME name of server instance (if using mysql.server startup script) + -l don't subtract lock time from total time + +HERE + if ($str) { + print STDERR "ERROR: $str\n\n"; + print STDERR $text; + exit 1; + } else { + print $text; + exit 0; + } +} diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh new file mode 100644 index 00000000..44abcfec --- /dev/null +++ b/scripts/mysqlhotcopy.sh @@ -0,0 +1,1161 @@ +#!@PERL_PATH@ + +# Copyright (c) 2000, 2017, Oracle and/or its affiliates. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1335 USA + +use strict; +use Getopt::Long; +use Data::Dumper; +use File::Basename; +use File::Path; +use DBI; +use Sys::Hostname; +use File::Copy; +use File::Temp qw(tempfile); + +=head1 NAME + +mysqlhotcopy - fast on-line hot-backup utility for local MySQL databases and tables + +=head1 SYNOPSIS + + mysqlhotcopy db_name + + mysqlhotcopy --suffix=_copy db_name_1 ... db_name_n + + mysqlhotcopy db_name_1 ... db_name_n /path/to/new_directory + + mysqlhotcopy db_name./regex/ + + mysqlhotcopy db_name./^\(foo\|bar\)/ + + mysqlhotcopy db_name./~regex/ + + mysqlhotcopy db_name_1./regex_1/ db_name_1./regex_2/ ... db_name_n./regex_n/ /path/to/new_directory + + mysqlhotcopy --method='scp -Bq -i /usr/home/foo/.ssh/identity' --user=root --password=secretpassword \ + db_1./^nice_table/ user@some.system.dom:~/path/to/new_directory + +WARNING: THIS PROGRAM IS STILL IN BETA. Comments/patches welcome. + +=cut + +# Documentation continued at end of file + +# fix CORE::GLOBAL::die to return a predictable exit code +BEGIN { *CORE::GLOBAL::die= sub { warn @_; exit 1; }; } + +my $VERSION = "1.23"; + +my $opt_tmpdir = $ENV{TMPDIR} || "/tmp"; + +my $OPTIONS = <<"_OPTIONS"; + +$0 Ver $VERSION + +Usage: $0 db_name[./table_regex/] [new_db_name | directory] + + -?, --help display this help-screen and exit + -u, --user=# user for database login if not current user + -p, --password=# password to use when connecting to server (if not set + in my.cnf, which is recommended) + -h, --host=# hostname for local server when connecting over TCP/IP + -P, --port=# port to use when connecting to local server with TCP/IP + -S, --socket=# socket to use when connecting to local server + --old_server connect to old MySQL-server (before v5.5) which + doesn't have FLUSH TABLES WITH READ LOCK fully implemented. + + --allowold don\'t abort if target dir already exists (rename it _old) + --addtodest don\'t rename target dir if it exists, just add files to it + --keepold don\'t delete previous (now renamed) target when done + --noindices don\'t include full index files in copy + --method=# method for copy (only "cp" currently supported) + + -q, --quiet be silent except for errors + --debug enable debug + -n, --dryrun report actions without doing them + + --regexp=# copy all databases with names matching regexp + --suffix=# suffix for names of copied databases + --checkpoint=# insert checkpoint entry into specified db.table + --flushlog flush logs once all tables are locked + --resetmaster reset the binlog once all tables are locked + --resetslave reset the master.info once all tables are locked + --tmpdir=# temporary directory (instead of $opt_tmpdir) + --record_log_pos=# record slave and master status in specified db.table + --chroot=# base directory of chroot jail in which mysqld operates + + Try \'perldoc $0\' for more complete documentation +_OPTIONS + +sub usage { + die @_, $OPTIONS; +} + +# Do not initialize user or password options; that way, any user/password +# options specified in option files will be used. If no values are specified +# at all, the defaults will be used (login name, no password). + +my %opt = ( + noindices => 0, + allowold => 0, # for safety + keepold => 0, + method => "cp", + flushlog => 0, +); +Getopt::Long::Configure(qw(no_ignore_case)); # disambiguate -p and -P +GetOptions( \%opt, + "help", + "host|h=s", + "user|u=s", + "password|p=s", + "port|P=s", + "socket|S=s", + "old_server", + "allowold!", + "keepold!", + "addtodest!", + "noindices!", + "method=s", + "debug", + "quiet|q", + "mv!", + "regexp=s", + "suffix=s", + "checkpoint=s", + "record_log_pos=s", + "flushlog", + "resetmaster", + "resetslave", + "tmpdir|t=s", + "dryrun|n", + "chroot=s", +) or usage("Invalid option"); + +# @db_desc +# ========== +# a list of hash-refs containing: +# +# 'src' - name of the db to copy +# 't_regex' - regex describing tables in src +# 'target' - destination directory of the copy +# 'tables' - array-ref to list of tables in the db +# 'files' - array-ref to list of files to be copied +# 'index' - array-ref to list of indexes to be copied +# + +my @db_desc = (); +my $tgt_name = undef; + +usage("") if ($opt{help}); + +if ( $opt{regexp} || $opt{suffix} || @ARGV > 2 ) { + $tgt_name = pop @ARGV unless ( exists $opt{suffix} ); + @db_desc = map { s{^([^\.]+)\./(.+)/$}{$1}; { 'src' => $_, 't_regex' => ( $2 ? $2 : '.*' ) } } @ARGV; +} +else { + usage("Database name to hotcopy not specified") unless ( @ARGV ); + + $ARGV[0] =~ s{^([^\.]+)\./(.+)/$}{$1}; + @db_desc = ( { 'src' => $ARGV[0], 't_regex' => ( $2 ? $2 : '.*' ) } ); + + if ( @ARGV == 2 ) { + $tgt_name = $ARGV[1]; + } + else { + $opt{suffix} = "_copy"; + } +} + +my %mysqld_vars; +my $start_time = time; +$opt_tmpdir= $opt{tmpdir} if $opt{tmpdir}; +$0 = $1 if $0 =~ m:/([^/]+)$:; +$opt{quiet} = 0 if $opt{debug}; +$opt{allowold} = 1 if $opt{keepold}; + +# --- connect to the database --- +my $dsn; +$dsn = ";host=" . (defined($opt{host}) ? $opt{host} : "localhost"); +$dsn .= ";port=$opt{port}" if $opt{port}; +$dsn .= ";mariadb_socket=$opt{socket}" if $opt{socket}; + +# use mariadb_read_default_group=mysqlhotcopy so that [client] and +# [mysqlhotcopy] groups will be read from standard options files. + +my $dbh = DBI->connect("DBI:MariaDB:$dsn;mariadb_read_default_group=mysqlhotcopy", + $opt{user}, $opt{password}, +{ + RaiseError => 1, + PrintError => 0, + AutoCommit => 1, +}); + +# --- check that checkpoint table exists if specified --- +if ( $opt{checkpoint} ) { + $opt{checkpoint} = quote_names( $opt{checkpoint} ); + eval { $dbh->do( qq{ select time_stamp, src, dest, msg + from $opt{checkpoint} where 1 != 1} ); + }; + + die "Error accessing Checkpoint table ($opt{checkpoint}): $@" + if ( $@ ); +} + +# --- check that log_pos table exists if specified --- +if ( $opt{record_log_pos} ) { + $opt{record_log_pos} = quote_names( $opt{record_log_pos} ); + + eval { $dbh->do( qq{ select host, time_stamp, log_file, log_pos, master_host, master_log_file, master_log_pos + from $opt{record_log_pos} where 1 != 1} ); + }; + + die "Error accessing log_pos table ($opt{record_log_pos}): $@" + if ( $@ ); +} + +# --- get variables from database --- +my $sth_vars = $dbh->prepare("show variables like 'datadir'"); +$sth_vars->execute; +while ( my ($var,$value) = $sth_vars->fetchrow_array ) { + $mysqld_vars{ $var } = $value; +} +my $datadir = $mysqld_vars{'datadir'} + || die "datadir not in mysqld variables"; + $datadir= $opt{chroot}.$datadir if ($opt{chroot}); +$datadir =~ s:/$::; + + +# --- get target path --- +my ($tgt_dirname, $to_other_database); +$to_other_database=0; +if (defined($tgt_name) && $tgt_name =~ m:^\w+$: && @db_desc <= 1) +{ + $tgt_dirname = "$datadir/$tgt_name"; + $to_other_database=1; +} +elsif (defined($tgt_name) && ($tgt_name =~ m:/: || $tgt_name eq '.')) { + $tgt_dirname = $tgt_name; +} +elsif ( $opt{suffix} ) { + print "Using copy suffix '$opt{suffix}'\n" unless $opt{quiet}; +} +else +{ + $tgt_name="" if (!defined($tgt_name)); + die "Target '$tgt_name' doesn't look like a database name or directory path.\n"; +} + +# --- resolve database names from regexp --- +if ( defined $opt{regexp} ) { + my $t_regex = '.*'; + if ( $opt{regexp} =~ s{^/(.+)/\./(.+)/$}{$1} ) { + $t_regex = $2; + } + + my $sth_dbs = $dbh->prepare("show databases"); + $sth_dbs->execute; + while ( my ($db_name) = $sth_dbs->fetchrow_array ) { + next if $db_name =~ m/^information_schema$/i; + push @db_desc, { 'src' => $db_name, 't_regex' => $t_regex } if ( $db_name =~ m/$opt{regexp}/o ); + } +} + +# --- get list of tables and views to hotcopy --- + +my $hc_locks = ""; +my $hc_tables = ""; +my $hc_base_tables = ""; +my $hc_views = ""; +my $num_base_tables = 0; +my $num_views = 0; +my $num_tables = 0; +my $num_files = 0; + +foreach my $rdb ( @db_desc ) { + my $db = $rdb->{src}; + my @dbh_base_tables = get_list_of_tables( $db ); + my @dbh_views = get_list_of_views( $db ); + + ## filter out certain system non-lockable tables. + ## keep in sync with mysqldump. + if ($db =~ m/^mysql$/i) + { + @dbh_base_tables = grep + { !/^(apply_status|schema|general_log|slow_log|transaction_registry)$/ } @dbh_base_tables + } + + ## generate regex for tables/files + my $t_regex; + my $negated; + if ($rdb->{t_regex}) { + $t_regex = $rdb->{t_regex}; ## assign temporary regex + $negated = $t_regex =~ s/^~//; ## note and remove negation operator + + $t_regex = qr/$t_regex/; ## make regex string from + ## user regex + + ## filter (out) tables specified in t_regex + print "Filtering tables with '$t_regex'\n" if $opt{debug}; + @dbh_base_tables = ( $negated + ? grep { $_ !~ $t_regex } @dbh_base_tables + : grep { $_ =~ $t_regex } @dbh_base_tables ); + + ## filter (out) views specified in t_regex + print "Filtering tables with '$t_regex'\n" if $opt{debug}; + @dbh_views = ( $negated + ? grep { $_ !~ $t_regex } @dbh_views + : grep { $_ =~ $t_regex } @dbh_views ); + } + + ## Now concatenate the base table and view arrays. + my @dbh_tables = (@dbh_base_tables, @dbh_views); + + ## get list of files to copy + my $db_dir = "$datadir/$db"; + opendir(DBDIR, $db_dir ) + or die "Cannot open dir '$db_dir': $!"; + + my %db_files; + + while ( defined( my $name = readdir DBDIR ) ) { + $db_files{$name} = $1 if ( $name =~ /(.+)\.\w+$/ ); + } + closedir( DBDIR ); + + unless( keys %db_files ) { + warn "'$db' is an empty database\n"; + } + + ## filter (out) files specified in t_regex + my @db_files; + if ($rdb->{t_regex}) { + @db_files = ($negated + ? grep { $db_files{$_} !~ $t_regex } keys %db_files + : grep { $db_files{$_} =~ $t_regex } keys %db_files ); + } + else { + @db_files = keys %db_files; + } + + @db_files = sort @db_files; + + my @index_files=(); + + ## remove indices unless we're told to keep them + if ($opt{noindices}) { + @index_files= grep { /\.(ISM|MYI)$/ } @db_files; + @db_files = grep { not /\.(ISM|MYI)$/ } @db_files; + } + + $rdb->{files} = [ @db_files ]; + $rdb->{index} = [ @index_files ]; + my @hc_base_tables = map { quote_names("$db.$_") } @dbh_base_tables; + my @hc_views = map { quote_names("$db.$_") } @dbh_views; + + my @hc_tables = (@hc_base_tables, @hc_views); + $rdb->{tables} = [ @hc_tables ]; + + $hc_locks .= ", " if ( length $hc_locks && @hc_tables ); + $hc_locks .= join ", ", map { "$_ READ" } @hc_tables; + + $hc_base_tables .= ", " if ( length $hc_base_tables && @hc_base_tables ); + $hc_base_tables .= join ", ", @hc_base_tables; + $hc_views .= ", " if ( length $hc_views && @hc_views ); + $hc_views .= join " READ, ", @hc_views; + + @hc_tables = (@hc_base_tables, @hc_views); + + $num_base_tables += scalar @hc_base_tables; + $num_views += scalar @hc_views; + $num_tables += $num_base_tables + $num_views; + $num_files += scalar @{$rdb->{files}}; +} + +# --- resolve targets for copies --- + +if (defined($tgt_name) && length $tgt_name ) { + # explicit destination directory specified + + # GNU `cp -r` error message + die "copying multiple databases, but last argument ($tgt_dirname) is not a directory\n" + if ( @db_desc > 1 && !(-e $tgt_dirname && -d $tgt_dirname ) ); + + if ($to_other_database) + { + foreach my $rdb ( @db_desc ) { + $rdb->{target} = "$tgt_dirname"; + } + } + elsif ($opt{method} =~ /^scp\b/) + { # we have to trust scp to hit the target + foreach my $rdb ( @db_desc ) { + $rdb->{target} = "$tgt_dirname/$rdb->{src}"; + } + } + else + { + die "Last argument ($tgt_dirname) is not a directory\n" + if (!(-e $tgt_dirname && -d $tgt_dirname ) ); + foreach my $rdb ( @db_desc ) { + $rdb->{target} = "$tgt_dirname/$rdb->{src}"; + } + } + } +else { + die "Error: expected \$opt{suffix} to exist" unless ( exists $opt{suffix} ); + + foreach my $rdb ( @db_desc ) { + $rdb->{target} = "$datadir/$rdb->{src}$opt{suffix}"; + } +} + +print Dumper( \@db_desc ) if ( $opt{debug} ); + +# --- bail out if all specified databases are empty --- + +die "No tables to hot-copy" unless ( length $hc_locks ); + +# --- create target directories if we are using 'cp' --- + +my @existing = (); + +if ($opt{method} =~ /^cp\b/) +{ + foreach my $rdb ( @db_desc ) { + push @existing, $rdb->{target} if ( -d $rdb->{target} ); + } + + if ( @existing && !($opt{allowold} || $opt{addtodest}) ) + { + $dbh->disconnect(); + die "Can't hotcopy to '", join( "','", @existing ), "' because directory\nalready exist and the --allowold or --addtodest options were not given.\n" + } +} + +retire_directory( @existing ) if @existing && !$opt{addtodest}; + +foreach my $rdb ( @db_desc ) { + my $tgt_dirpath = "$rdb->{target}"; + # Remove trailing slashes (needed for Mac OS X) + substr($tgt_dirpath, 1) =~ s|/+$||; + if ( $opt{dryrun} ) { + print "mkdir $tgt_dirpath, 0750\n"; + } + elsif ($opt{method} =~ /^scp\b/) { + ## assume it's there? + ## ... + } + else { + mkdir($tgt_dirpath, 0750) or die "Can't create '$tgt_dirpath': $!\n" + unless -d $tgt_dirpath; + my @f_info= stat "$datadir/$rdb->{src}"; + chown $f_info[4], $f_info[5], $tgt_dirpath; + } +} + +############################## +# --- PERFORM THE HOT-COPY --- +# +# Note that we try to keep the time between the LOCK and the UNLOCK +# as short as possible, and only start when we know that we should +# be able to complete without error. + +# read lock all the tables we'll be copying +# in order to get a consistent snapshot of the database + +if ( $opt{checkpoint} || $opt{record_log_pos} ) { + # convert existing READ lock on checkpoint and/or log_pos table into WRITE lock + foreach my $table ( grep { defined } ( $opt{checkpoint}, $opt{record_log_pos} ) ) { + $hc_locks .= ", $table WRITE" + unless ( $hc_locks =~ s/$table\s+READ/$table WRITE/ ); + } +} + +my $hc_started = time; # count from time lock is granted + +if ( $opt{dryrun} ) { + if ( $opt{old_server} ) { + print "LOCK TABLES $hc_locks\n"; + print "FLUSH TABLES /*!32323 $hc_tables */\n"; + } + else { + # Lock base tables and views separately. + print "FLUSH TABLES $hc_base_tables WITH READ LOCK\n" + if ( $hc_base_tables ); + print "LOCK TABLES $hc_views READ\n" if ( $hc_views ); + } + + print "FLUSH LOGS\n" if ( $opt{flushlog} ); + print "RESET MASTER\n" if ( $opt{resetmaster} ); + print "RESET SLAVE\n" if ( $opt{resetslave} ); +} +else { + my $start = time; + if ( $opt{old_server} ) { + $dbh->do("LOCK TABLES $hc_locks"); + printf "Locked $num_tables tables in %d seconds.\n", time-$start unless $opt{quiet}; + $hc_started = time; # count from time lock is granted + + # flush tables to make on-disk copy up to date + $start = time; + $dbh->do("FLUSH TABLES /*!32323 $hc_tables */"); + printf "Flushed tables ($hc_tables) in %d seconds.\n", time-$start unless $opt{quiet}; + } + else { + # Lock base tables and views separately, as 'FLUSH TABLES <tbl_name> + # ... WITH READ LOCK' (introduced in 5.5) would fail for views. + # Also, flush tables to make on-disk copy up to date + $dbh->do("FLUSH TABLES $hc_base_tables WITH READ LOCK") + if ( $hc_base_tables ); + printf "Flushed $num_base_tables tables with read lock ($hc_base_tables) in %d seconds.\n", + time-$start unless $opt{quiet}; + + $start = time; + $dbh->do("LOCK TABLES $hc_views READ") if ( $hc_views ); + printf "Locked $num_views views ($hc_views) in %d seconds.\n", + time-$start unless $opt{quiet}; + + $hc_started = time; # count from time lock is granted + } + $dbh->do( "FLUSH LOGS" ) if ( $opt{flushlog} ); + $dbh->do( "RESET MASTER" ) if ( $opt{resetmaster} ); + $dbh->do( "RESET SLAVE" ) if ( $opt{resetslave} ); + + if ( $opt{record_log_pos} ) { + record_log_pos( $dbh, $opt{record_log_pos} ); + $dbh->do("FLUSH TABLES /*!32323 $hc_tables */"); + } +} + +my @failed = (); + +foreach my $rdb ( @db_desc ) +{ + my @files = map { "$datadir/$rdb->{src}/$_" } @{$rdb->{files}}; + next unless @files; + + eval { copy_files($opt{method}, \@files, $rdb->{target}); }; + push @failed, "$rdb->{src} -> $rdb->{target} failed: $@" + if ( $@ ); + + @files = @{$rdb->{index}}; + if ($rdb->{index}) + { + copy_index($opt{method}, \@files, + "$datadir/$rdb->{src}", $rdb->{target} ); + } + + if ( $opt{checkpoint} ) { + my $msg = ( $@ ) ? "Failed: $@" : "Succeeded"; + + eval { + $dbh->do( qq{ insert into $opt{checkpoint} (src, dest, msg) + VALUES ( '$rdb->{src}', '$rdb->{target}', '$msg' ) + } ); + }; + + if ( $@ ) { + warn "Failed to update checkpoint table: $@\n"; + } + } +} + +if ( $opt{dryrun} ) { + print "UNLOCK TABLES\n"; + if ( @existing && !$opt{keepold} ) { + my @oldies = map { $_ . '_old' } @existing; + print "rm -rf @oldies\n" + } + $dbh->disconnect(); + exit(0); +} +else { + $dbh->do("UNLOCK TABLES"); +} + +my $hc_dur = time - $hc_started; +printf "Unlocked tables.\n" unless $opt{quiet}; + +# +# --- HOT-COPY COMPLETE --- +########################### + +$dbh->disconnect; + +if ( @failed ) { + # hotcopy failed - cleanup + # delete any @targets + # rename _old copy back to original + + my @targets = (); + foreach my $rdb ( @db_desc ) { + push @targets, $rdb->{target} if ( -d $rdb->{target} ); + } + print "Deleting @targets \n" if $opt{debug}; + + print "Deleting @targets \n" if $opt{debug}; + rmtree([@targets]); + if (@existing) { + print "Restoring @existing from back-up\n" if $opt{debug}; + foreach my $dir ( @existing ) { + rename("${dir}_old", $dir ) + or warn "Can't rename ${dir}_old to $dir: $!\n"; + } + } + + die join( "\n", @failed ); +} +else { + # hotcopy worked + # delete _old unless $opt{keepold} + + if ( @existing && !$opt{keepold} ) { + my @oldies = map { $_ . '_old' } @existing; + print "Deleting previous copy in @oldies\n" if $opt{debug}; + rmtree([@oldies]); + } + + printf "$0 copied %d tables (%d files) in %d second%s (%d seconds overall).\n", + $num_tables, $num_files, + $hc_dur, ($hc_dur==1)?"":"s", time - $start_time + unless $opt{quiet}; +} + +exit 0; + + +# --- + +sub copy_files { + my ($method, $files, $target) = @_; + my @cmd; + print "Copying ".@$files." files...\n" unless $opt{quiet}; + + if ($method =~ /^s?cp\b/) # cp or scp with optional flags + { + my $cp = $method; + # add option to preserve mod time etc of copied files + # not critical, but nice to have + $cp.= " -p" if $^O =~ m/^(solaris|linux|freebsd|darwin)$/; + + # add recursive option for scp + $cp.= " -r" if $^O =~ /m^(solaris|linux|freebsd|darwin)$/ && $method =~ /^scp\b/; + + # perform the actual copy + safe_system( $cp, (map { "'$_'" } @$files), "'$target'" ); + } + else + { + die "Can't use unsupported method '$method'\n"; + } +} + +# +# Copy only the header of the index file +# + +sub copy_index +{ + my ($method, $files, $source, $target) = @_; + + print "Copying indices for ".@$files." files...\n" unless $opt{quiet}; + foreach my $file (@$files) + { + my $from="$source/$file"; + my $to="$target/$file"; + my $buff; + open(INPUT, "<$from") || die "Can't open file $from: $!\n"; + binmode(INPUT, ":raw"); + my $length=read INPUT, $buff, 2048; + die "Can't read index header from $from\n" if ($length < 1024); + close INPUT; + + if ( $opt{dryrun} ) + { + print "$opt{method}-header $from $to\n"; + } + elsif ($opt{method} eq 'cp') + { + open(OUTPUT,">$to") || die "Can\'t create file $to: $!\n"; + if (syswrite(OUTPUT,$buff) != length($buff)) + { + die "Error when writing data to $to: $!\n"; + } + close OUTPUT || die "Error on close of $to: $!\n"; + } + elsif ($opt{method} =~ /^scp\b/) + { + my ($fh, $tmp)= tempfile('mysqlhotcopy-XXXXXX', DIR => $opt_tmpdir) or + die "Can\'t create/open file in $opt_tmpdir\n"; + if (syswrite($fh,$buff) != length($buff)) + { + die "Error when writing data to $tmp: $!\n"; + } + close $fh || die "Error on close of $tmp: $!\n"; + safe_system("$opt{method} $tmp $to"); + unlink $tmp; + } + else + { + die "Can't use unsupported method '$opt{method}'\n"; + } + } +} + + +sub safe_system { + my @sources= @_; + my $method= shift @sources; + my $target= pop @sources; + ## @sources = list of source file names + + ## We have to deal with very long command lines, otherwise they may generate + ## "Argument list too long". + ## With 10000 tables the command line can be around 1MB, much more than 128kB + ## which is the common limit on Linux (can be read from + ## /usr/src/linux/include/linux/binfmts.h + ## see http://www.linuxjournal.com/article.php?sid=6060). + + my $chunk_limit= 100 * 1024; # 100 kB + my @chunk= (); + my $chunk_length= 0; + foreach (@sources) { + push @chunk, $_; + $chunk_length+= length($_); + if ($chunk_length > $chunk_limit) { + safe_simple_system($method, @chunk, $target); + @chunk=(); + $chunk_length= 0; + } + } + if ($chunk_length > 0) { # do not forget last small chunk + safe_simple_system($method, @chunk, $target); + } +} + +sub safe_simple_system { + my @cmd= @_; + + if ( $opt{dryrun} ) { + print "@cmd\n"; + } + else { + ## for some reason system fails but backticks works ok for scp... + print "Executing '@cmd'\n" if $opt{debug}; + my $cp_status = system "@cmd > /dev/null"; + if ($cp_status != 0) { + warn "Executing command failed ($cp_status). Trying backtick execution...\n"; + ## try something else + `@cmd` || die "Error: @cmd failed ($?) while copying files.\n"; + } + } +} + +sub retire_directory { + my ( @dir ) = @_; + + foreach my $dir ( @dir ) { + my $tgt_oldpath = $dir . '_old'; + if ( $opt{dryrun} ) { + print "rmtree $tgt_oldpath\n" if ( -d $tgt_oldpath ); + print "rename $dir, $tgt_oldpath\n"; + next; + } + + if ( -d $tgt_oldpath ) { + print "Deleting previous 'old' hotcopy directory ('$tgt_oldpath')\n" unless $opt{quiet}; + rmtree([$tgt_oldpath],0,1); + } + rename($dir, $tgt_oldpath) + or die "Can't rename $dir=>$tgt_oldpath: $!\n"; + print "Existing hotcopy directory renamed to '$tgt_oldpath'\n" unless $opt{quiet}; + } +} + +sub record_log_pos { + my ( $dbh, $table_name ) = @_; + + eval { + my ($file,$position) = get_row( $dbh, "show master status" ); + die "master status is undefined" if !defined $file || !defined $position; + + my $row_hash = get_row_hash( $dbh, "show slave status" ); + my ($master_host, $log_file, $log_pos ); + if ( $dbh->{mariadb_serverinfo} =~ /^3\.23/ ) { + ($master_host, $log_file, $log_pos ) + = @{$row_hash}{ qw / Master_Host Log_File Pos / }; + } else { + ($master_host, $log_file, $log_pos ) + = @{$row_hash}{ qw / Master_Host Relay_Master_Log_File Exec_Master_Log_Pos / }; + } + my $hostname = hostname(); + + $dbh->do( qq{ replace into $table_name + set host=?, log_file=?, log_pos=?, + master_host=?, master_log_file=?, master_log_pos=? }, + undef, + $hostname, $file, $position, + $master_host, $log_file, $log_pos ); + + }; + + if ( $@ ) { + warn "Failed to store master position: $@\n"; + } +} + +sub get_row { + my ( $dbh, $sql ) = @_; + + my $sth = $dbh->prepare($sql); + $sth->execute; + return $sth->fetchrow_array(); +} + +sub get_row_hash { + my ( $dbh, $sql ) = @_; + + my $sth = $dbh->prepare($sql); + $sth->execute; + return $sth->fetchrow_hashref(); +} + +sub get_list_of_tables { + my ( $db ) = @_; + + my $tables = + eval { + $dbh->selectall_arrayref('SHOW FULL TABLES FROM ' . + $dbh->quote_identifier($db) . + ' WHERE Table_type = \'BASE TABLE\'') + } || []; + warn "Unable to retrieve list of tables in $db: $@" if $@; + + return (map { $_->[0] } @$tables); +} + +sub get_list_of_views { + my ( $db ) = @_; + + my $views = + eval { + $dbh->selectall_arrayref('SHOW FULL TABLES FROM ' . + $dbh->quote_identifier($db) . + ' WHERE Table_type = \'VIEW\'') + } || []; + warn "Unable to retrieve list of views in $db: $@" if $@; + + return (map { $_->[0] } @$views); +} + +sub quote_names { + my ( $name ) = @_; + # given a db.table name, add quotes + + my ($db, $table, @cruft) = split( /\./, $name ); + die "Invalid db.table name '$name'" if (@cruft || !defined $db || !defined $table ); + + # Earlier versions of DBD return table name non-quoted, + # such as DBD-2.1012 and the newer ones, such as DBD-2.9002 + # returns it quoted. Let's have a support for both. + $table=~ s/\`//g; + return "`$db`.`$table`"; +} + +__END__ + +=head1 DESCRIPTION + +mysqlhotcopy is designed to make stable copies of live MySQL databases. + +Here "live" means that the database server is running and the database +may be in active use. And "stable" means that the copy will not have +any corruptions that could occur if the table files were simply copied +without first being locked and flushed from within the server. + +=head1 OPTIONS + +=over 4 + +=item --checkpoint checkpoint-table + +As each database is copied, an entry is written to the specified +checkpoint-table. This has the happy side-effect of updating the +MySQL update-log (if it is switched on) giving a good indication of +where roll-forward should begin for backup+rollforward schemes. + +The name of the checkpoint table should be supplied in database.table format. +The checkpoint-table must contain at least the following fields: + +=over 4 + + time_stamp timestamp not null + src varchar(32) + dest varchar(60) + msg varchar(255) + +=back + +=item --record_log_pos log-pos-table + +Just before the database files are copied, update the record in the +log-pos-table from the values returned from "show master status" and +"show slave status". The master status values are stored in the +log_file and log_pos columns, and establish the position in the binary +logs that any slaves of this host should adopt if initialised from +this dump. The slave status values are stored in master_host, +master_log_file, and master_log_pos, corresponding to the coordinates +of the next to the last event the slave has executed. The slave or its +siblings can connect to the master next time and request replication +starting from the recorded values. + +The name of the log-pos table should be supplied in database.table format. +A sample log-pos table definition: + +=over 4 + +CREATE TABLE log_pos ( + host varchar(60) NOT null, + time_stamp timestamp NOT NULL, + log_file varchar(32) default NULL, + log_pos int(11) default NULL, + master_host varchar(60) NULL, + master_log_file varchar(32) NULL, + master_log_pos int NULL, + + PRIMARY KEY (host) +); + +=back + + +=item --suffix suffix + +Each database is copied back into the originating datadir under +a new name. The new name is the original name with the suffix +appended. + +If only a single db_name is supplied and the --suffix flag is not +supplied, then "--suffix=_copy" is assumed. + +=item --allowold + +Move any existing version of the destination to a backup directory for +the duration of the copy. If the copy successfully completes, the backup +directory is deleted - unless the --keepold flag is set. If the copy fails, +the backup directory is restored. + +The backup directory name is the original name with "_old" appended. +Any existing versions of the backup directory are deleted. + +=item --keepold + +Behaves as for the --allowold, with the additional feature +of keeping the backup directory after the copy successfully completes. + +=item --addtodest + +Don't rename target directory if it already exists, just add the +copied files into it. + +This is most useful when backing up a database with many large +tables and you don't want to have all the tables locked for the +whole duration. + +In this situation, I<if> you are happy for groups of tables to be +backed up separately (and thus possibly not be logically consistent +with one another) then you can run mysqlhotcopy several times on +the same database each with different db_name./table_regex/. +All but the first should use the --addtodest option so the tables +all end up in the same directory. + +=item --flushlog + +Rotate the log files by executing "FLUSH LOGS" after all tables are +locked, and before they are copied. + +=item --resetmaster + +Reset the bin-log by executing "RESET MASTER" after all tables are +locked, and before they are copied. Useful if you are recovering a +slave in a replication setup. + +=item --resetslave + +Reset the master.info by executing "RESET SLAVE" after all tables are +locked, and before they are copied. Useful if you are recovering a +server in a mutual replication setup. + +=item --regexp pattern + +Copy all databases with names matching the pattern. + +=item --regexp /pattern1/./pattern2/ + +Copy all tables with names matching pattern2 from all databases with +names matching pattern1. For example, to select all tables which +names begin with 'bar' from all databases which names end with 'foo': + + mysqlhotcopy --indices --method=cp --regexp /foo$/./^bar/ + +=item db_name./pattern/ + +Copy only tables matching pattern. Shell metacharacters ( (, ), |, !, +etc.) have to be escaped (e.g., \). For example, to select all tables +in database db1 whose names begin with 'foo' or 'bar': + + mysqlhotcopy --indices --method=cp db1./^\(foo\|bar\)/ + +=item db_name./~pattern/ + +Copy only tables not matching pattern. For example, to copy tables +that do not begin with foo nor bar: + + mysqlhotcopy --indices --method=cp db1./~^\(foo\|bar\)/ + +=item -?, --help + +Display help-screen and exit. + +=item -u, --user=# + +User for database login if not current user. + +=item -p, --password=# + +Password to use when connecting to the server. Note that you are strongly +encouraged *not* to use this option as every user would be able to see the +password in the process list. Instead use the '[mysqlhotcopy]' section in +one of the config files, normally /etc/my.cnf or your personal ~/.my.cnf. +(See the chapter 'my.cnf Option Files' in the manual.) + +=item -h, -h, --host=# + +Hostname for local server when connecting over TCP/IP. By specifying this +different from 'localhost' will trigger mysqlhotcopy to use TCP/IP connection. + +=item -P, --port=# + +Port to use when connecting to MySQL server with TCP/IP. This is only used +when using the --host option. + +=item -S, --socket=# + +UNIX domain socket to use when connecting to local server. + +=item --old_server + +Use old server (pre v5.5) commands. + +=item --noindices + +Don\'t include index files in copy. Only up to the first 2048 bytes +are copied; You can restore the indexes with isamchk -r or myisamchk -r +on the backup. + +=item --method=# + +Method for copy (only "cp" currently supported). Alpha support for +"scp" was added in November 2000. Your experience with the scp method +will vary with your ability to understand how scp works. 'man scp' +and 'man ssh' are your friends. + +The destination directory _must exist_ on the target machine using the +scp method. --keepold and --allowold are meaningless with scp. +Liberal use of the --debug option will help you figure out what\'s +really going on when you do an scp. + +Note that using scp will lock your tables for a _long_ time unless +your network connection is _fast_. If this is unacceptable to you, +use the 'cp' method to copy the tables to some temporary area and then +scp or rsync the files at your leisure. + +=item -q, --quiet + +Be silent except for errors. + +=item --debug + +Debug messages are displayed. + +=item -n, --dryrun + +Display commands without actually doing them. + +=back + +=head1 WARRANTY + +This software is free and comes without warranty of any kind. You +should never trust backup software without studying the code yourself. +Study the code inside this script and only rely on it if I<you> believe +that it does the right thing for you. + +Patches adding bug fixes, documentation and new features are welcome. +Please send these to internals@lists.mysql.com. + +=head1 TO DO + +Extend the individual table copy to allow multiple subsets of tables +to be specified on the command line: + + mysqlhotcopy db newdb t1 t2 /^foo_/ : t3 /^bar_/ : + + +where ":" delimits the subsets, the /^foo_/ indicates all tables +with names beginning with "foo_" and the "+" indicates all tables +not copied by the previous subsets. + +'newdb' is either the name of the new database, or the full path name +of the new database file. The database should not already exist. + +Add option to lock each table in turn for people who don\'t need +cross-table integrity. + +Add option to FLUSH STATUS just before UNLOCK TABLES. + +Add support for other copy methods (e.g., tar to single file?). + +Add support for forthcoming MySQL ``RAID'' table subdirectory layouts. + +=head1 AUTHOR + +Tim Bunce + +Martin Waite - Added checkpoint, flushlog, regexp and dryrun options. + Fixed cleanup of targets when hotcopy fails. + Added --record_log_pos. + RAID tables are now copied (don't know if this works over scp). + +Ralph Corderoy - Added synonyms for commands. + +Scott Wiersdorf - Added table regex and scp support. + +Monty - Working --noindex (copy only first 2048 bytes of index file). + Fixes for --method=scp. + +Ask Bjoern Hansen - Cleanup code to fix a few bugs and enable -w again. + +Emil S. Hansen - Added resetslave and resetmaster. + +Jeremy D. Zawodny - Removed deprecated DBI calls. Fixed bug which +resulted in nothing being copied when a regexp was specified but no +database name(s). + +Martin Waite - Fix to handle database name that contains space. + +Paul DuBois - Remove end '/' from directory names. diff --git a/scripts/mytop.sh b/scripts/mytop.sh new file mode 100644 index 00000000..65bfb8c9 --- /dev/null +++ b/scripts/mytop.sh @@ -0,0 +1,2697 @@ +#!/usr/bin/env perl +# +# $Id: mytop,v 1.99-maria6 2019/10/22 14:53:51 jweisbuch Exp $ + +=pod + +=head1 NAME + +mytop - display MariaDB/MySQL server performance info like `top' + +=cut + +## most of the POD is at the bottom of the file + +use 5.005; +use strict; +use warnings; +use DBI; +use Getopt::Long; +use Socket; +use List::Util qw(min max); +use File::Basename; + +$main::VERSION = "1.99-maria6"; +my $path_for_script = dirname($0); + +$| = 1; +$0 = 'mytop'; + +my $WIN = ($^O eq 'MSWin32') ? 1 : 0; + +## Test for color support. + +eval { require Term::ANSIColor; }; + +my $HAS_COLOR = $@ ? 0 : 1; + +$HAS_COLOR = 0 if $WIN; + +## Test of Time::HiRes support + +eval { require Time::HiRes }; + +my $HAS_TIME = $@ ? 0 : 1; + +my $debug = 0; + +## Try to lower our priority (which, who, pri) + +setpriority(0,0,10) unless $WIN; + +## Prototypes + +sub Clear(); +sub GetData(); +sub GetQPS(); +sub FullQueryInfo($); +sub Explain($); +sub PrintTable(@); +sub PrintHelp(); +sub Sum(@); +sub commify($); +sub make_short($); +sub Hashes($); +sub Execute($); +sub StringOrRegex($); +sub GetInnoDBStatus(); +sub GetCmdSummary(); +sub GetShowVariables(); +sub GetShowStatus(); +sub cmd_s; +sub cmd_S; +sub cmd_q; + +## Default Config Values + +my %config = ( + batchmode => 0, + color => 1, + db => '', + database => '', + delay => 5, + filter_user => qr/.?/, + filter_db => qr/.?/, + filter_host => qr/.?/, + filter_state => qr/.?/, + header => 1, + help => 0, + host => 'localhost', + idle => 1, + long => 120, + long_nums => 0, + mode => 'top', + prompt => 0, + pass => '', + password => '', + port => 3306, + resolve => 0, + slow => 10, ## slow query time + socket => '', + sort => 1, ## default or reverse sort ("s") + user => 'root', + fullqueries => 0, ## shows untruncated queries + usercol_width => 8, ## User column width + dbcol_width => 9, ## DB column width + hide_progress => 0 ## hide the "%" column when available +); + +my %qcache = (); ## The query cache--used for full query info support. +my %ucache = (); ## The user cache--used for full killing by user +my %dbcache = (); ## The db cache. This should be merged at some point. +my %statcache = (); ## The show status cache for GetShowStatus() + +my (%STATUS, %OLD_STATUS); # header stuff. + +my $CLEAR = $WIN ? '': `clear`; + +## Term::ReadKey values + +my $RM_RESET = 0; +my $RM_NOBLKRD = 3; ## using 4 traps Ctrl-C :-( + +## Add options from .my.cnf first + +my $my_print_defaults; +if (!defined($my_print_defaults=my_which("my_print_defaults"))) +{ + print "Warning: Can't find my_print_defaults. Please add it to your PATH!\n"; + exit(1); +} + +unshift @ARGV, split "\n", `$my_print_defaults client mytop`; + +## Read the user's config file, if it exists. + +my $config = "$ENV{HOME}/.mytop"; + +if (-e $config) +{ + if (open CFG, "<$config") + { + while (<CFG>) + { + next if /^\s*($|#)/; ## skip blanks and comments + + chomp; + + if (/(\S+)\s*=\s*(.*\S)/) + { + $config{lc $1} = $2 if exists $config{lc $1}; + } + } + close CFG; + } + ## map database/password onto db/pass + ## short version gets precedence for historical reasons + $config{'db'} = $config{'database'} unless $config{'db'}; + $config{'pass'} = $config{'password'} unless $config{'pass'}; +} + +## Command-line args. + +use vars qw($opt_foo); + +Getopt::Long::Configure('no_ignore_case', 'bundling'); + +GetOptions( + "color!" => \$config{color}, + "user|u=s" => \$config{user}, + "pass|password|p=s" => \$config{pass}, + "database|db|d=s" => \$config{db}, + "host|h=s" => \$config{host}, + "port|P=i" => \$config{port}, + "socket|S=s" => \$config{socket}, + "delay|s=i" => \$config{delay}, + "batch|batchmode|b" => \$config{batchmode}, + "header!" => \$config{header}, + "idle|i!" => \$config{idle}, + "resolve|r!" => \$config{resolve}, + "prompt!" => \$config{prompt}, + "long=i" => \$config{long}, + "long_nums!" => \$config{long_nums}, + "mode|m=s" => \$config{mode}, + "slow=i" => \$config{slow}, + "sort=s" => \$config{sort}, + "fullqueries|L!" => \$config{fullqueries}, + "usercol_width=i" => \$config{usercol_width}, + "dbcol_width=i" => \$config{dbcol_width}, + "hide_progress|a!" => \$config{hide_progress} +); + +## User may have put the port with the host. + +if ($config{host} =~ s/:(\d+)$//) +{ + $config{port} = $1; +} + +## Don't use Term::ReadKey unless running interactively. + +if (not $config{batchmode}) +{ + require Term::ReadKey; + Term::ReadKey->import(); +} + +## User may want to disable color. + +if ($HAS_COLOR and not $config{color}) +{ + $HAS_COLOR = 0; +} + +if ($HAS_COLOR) +{ + import Term::ANSIColor ':constants'; +} +else +{ + *RESET = sub { }; + *YELLOW = sub { }; + *RED = sub { }; + *MAGENTA = sub { }; + *GREEN = sub { }; + *BLUE = sub { }; + *WHITE = sub { }; + *BOLD = sub { }; +} + +my $RESET = RESET() || ''; +my $YELLOW = YELLOW() || ''; +my $RED = RED() || ''; +my $MAGENTA = MAGENTA() || ''; +my $GREEN = GREEN() || ''; +my $BLUE = BLUE() || ''; +my $WHITE = WHITE() || ''; +my $BOLD = BOLD() || ''; + +## Connect + +my $dsn; + +## Socket takes precedence. +my $prefix= 'mysql'; +if (eval {DBI->install_driver("MariaDB")}) { + $dsn = "DBI:MariaDB:database=$config{db};mariadb_read_default_group=mytop;"; + $prefix= 'mariadb' +} else { + $dsn = "DBI:mysql:database=$config{db};mysql_read_default_group=mytop;"; +} + +if ($config{socket} and -S $config{socket}) +{ + $dsn .= "${prefix}_socket=$config{socket}"; +} +else +{ + $dsn .= "host=$config{host};port=$config{port}"; +} + +if ($config{prompt}) +{ + print "Password: "; + ReadMode(2); + chomp($config{pass} = <STDIN>); + ReadMode(0); + print "\n"; +} + +my $dbh = DBI->connect($dsn, $config{user}, $config{pass}, + { PrintError => 0 }); + +if (not ref $dbh) +{ + my $Error = <<EODIE +Cannot connect to MariaDB/MySQL server. Please check the: + + * database you specified "$config{db}" (default is "") + * username you specified "$config{user}" (default is "root") + * password you specified "$config{pass}" (default is "") + * hostname you specified "$config{host}" (default is "localhost") + * port you specified "$config{port}" (default is 3306) + * socket you specified "$config{socket}" (default is "") + +The options my be specified on the command-line or in a ~/.mytop or +~/.my.cnf config file. See the manual (perldoc mytop) for details. + +Here's the exact error from DBI. It might help you debug: + +$DBI::errstr + +EODIE +; + + die $Error; + +} + +ReadMode($RM_RESET) unless $config{batchmode}; + +## Get static data + +my $db_version; +my $db_release; +my $server = "MySQL"; +my $have_query_cache; + +my @variables = Hashes("SHOW VARIABLES"); + +foreach (@variables) +{ + if ($_->{Variable_name} eq "version") + { + $db_version = $_->{Value}; + $db_version =~ /^(\d+)/; + $db_release = $1; + $server = "MariaDB" if ($db_version =~ /maria/i); + # Get the version number only + $db_version = $1 if($db_version =~ m/(.*?)-/); + next; + } + if ($_->{Variable_name} eq "have_query_cache") + { + if ($_->{Value} ne 'NO') + { + $have_query_cache = 1; + } + else + { + $have_query_cache = 0; + } + next; + } +} + +my ($has_is_processlist, $has_time_ms, $has_progress); +$has_is_processlist = $has_time_ms = $has_progress = 0; + +## Check if the server has the INFORMATION_SCHEMA.PROCESSLIST table +## for backward compatibility +$has_is_processlist = Execute("SELECT /*mytop*/ 1 FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_SCHEMA = 'information_schema' AND + TABLE_NAME = 'PROCESSLIST';")->rows; +if ($has_is_processlist == 1) +{ + ## Check if the server has the TIME_MS column on the I_S.PROCESSLIST table + ## If it is the case, it will fetch the query time with decimal precision + ## for queries that has been running for less than 10k seconds + $has_time_ms = Execute("SELECT /*mytop*/ 1 FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = 'information_schema' AND + TABLE_NAME = 'PROCESSLIST' AND + COLUMN_NAME = 'TIME_MS';")->rows; + if ($has_time_ms == 1) + { + ## Check if the server has the STAGE column on the I_S.PROCESSLIST + ## table (MariaDB) to retreive query completion information + $has_progress = Execute("SELECT /*mytop*/ 1 FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = 'information_schema' AND + TABLE_NAME = 'PROCESSLIST' AND + COLUMN_NAME = 'STAGE';")->rows; + } +} + +######################################################################### +## +## The main loop +## +######################################################################### + +ReadMode($RM_NOBLKRD) unless $config{batchmode}; + +while (1) +{ + my $key; + + if ($config{mode} eq 'qps') + { + GetQPS(); + $key = ReadKey(1); + + next unless $key; + + if ($key =~ /t/i) + { + $config{mode} = 'top'; + } + if ($key =~ /q/) + { + cmd_q(); + } + next; + } + if ($config{mode} eq 'top') + { + GetData(); + last if $config{batchmode}; + $key = ReadKey($config{delay}); + next unless $key; + } + elsif ($config{mode} eq 'cmd') + { + GetCmdSummary(); + last if $config{batchmode}; + $key = ReadKey($config{delay}); + next unless $key; + } + elsif ($config{mode} eq 'innodb') + { + GetInnoDBStatus(); + last if $config{batchmode}; + print "InnoDB Status [hit t to exit this mode or q to exit the application]\n"; + $key = ReadKey($config{delay}); + next unless $key; + } + elsif ($config{mode} eq 'status') + { + GetShowStatus(); + last if $config{batchmode}; + $key = ReadKey($config{delay}); + next unless $key; + } + + ## + ## keystroke command processing (if we get this far) + ## + + if ($key eq '!') + { + Execute("STOP /*mytop*/ SLAVE;"); + Execute("SET /*mytop*/ GLOBAL sql_slave_skip_counter=1"); + Execute("START /*mytop*/ SLAVE"); + } + + # t - top + + if ($key =~ /t/i) + { + $config{mode} = 'top'; + } + + ## q - quit + + if ($key eq 'q') + { + cmd_q(); + } + + if ($key eq 'D') + { + require Data::Dumper; + print Data::Dumper::Dumper([\%config]); + ReadKey(0); + } + + ## l - change long running hightling + + if ($key eq 'l') + { + cmd_l(); + next; + } + + ## m - mode switch to qps + + if ($key eq 'm') + { + $config{mode} = 'qps'; + Clear() unless $config{batchmode}; + print "Queries Per Second [hit t to exit this mode or q to exit the application]\n"; + next; + } + + ## c - mode switch to command summary + + if ($key eq 'c') + { + $config{mode} = 'cmd'; + Clear() unless $config{batchmode}; + print "Command Summary\n"; + next; + } + + ## C - change Color on and off + + if ($key eq 'C') + { + if ($HAS_COLOR) + { + $HAS_COLOR = 0; + } + else + { + $HAS_COLOR = 1; + } + } + + ## s - seconds of delay + + if ($key eq 's') + { + cmd_s(); + next; + } + + if ($key eq 'S') + { + cmd_S(); + next; + } + + ## R - resolve hostnames + if ($key eq 'R') + { + if ($config{resolve}) + { + $config{resolve} = 0; + } + else + { + $config{resolve} = 1; + } + } + + ## t - username based filter + + if ($key eq 't') + { + ReadMode($RM_RESET); + print RED(), "Which state (blank for all, /.../ for regex): ", RESET(); + $config{filter_state} = StringOrRegex(ReadLine(0)); + ReadMode($RM_NOBLKRD); + next; + } + + ## u - username based filter + + if ($key eq 'u') + { + ReadMode($RM_RESET); + print RED(), "Which user (blank for all, /.../ for regex): ", RESET(); + $config{filter_user} = StringOrRegex(ReadLine(0)); + ReadMode($RM_NOBLKRD); + next; + } + + ## d - database name based filter + + if ($key eq 'd') + { + ReadMode($RM_RESET); + print RED(), "Which database (blank for all, /.../ for regex): ", + RESET(); + $config{filter_db} = StringOrRegex(ReadLine(0)); + ReadMode($RM_NOBLKRD); + next; + } + + ## h - hostname based filter + + if ($key eq 'h') + { + ReadMode($RM_RESET); + print RED(), "Which hostname (blank for all, /.../ for regex): ", + RESET(); + $config{filter_host} = StringOrRegex(ReadLine(0)); + ReadMode($RM_NOBLKRD); + next; + } + + ## E - Show full Replication Error + + if ($key eq 'E') + { + my ($data) = Hashes('SHOW /*mytop*/ SLAVE STATUS'); + Clear(); + print "Error is: $data->{Last_Error}\n"; + print RED(), "-- paused. press any key to resume --", RESET(); + ReadKey(0); + next; + } + ## F - remove all filters + + if ($key eq 'F') + { + $config{filter_host} = qr/.?/; + $config{filter_db} = qr/.?/; + $config{filter_user} = qr/.?/; + $config{filter_state} = qr/.?/; + print RED(), "-- display unfiltered --", RESET(); + sleep 1; + next; + } + + ## p - pause + + if ($key eq 'p') + { + print RED(), "-- paused. press any key to resume --", RESET(); + ReadKey(0); + next; + } + + ## i - idle toggle + + if ($key =~ /i/) + { + if ($config{idle}) + { + $config{idle} = 0; + $config{sort} = 1; + print RED(), "-- idle (sleeping) processed filtered --", RESET(); + sleep 1; + } + else + { + $config{idle} = 1; + $config{sort} = 0; + print RED(), "-- idle (sleeping) processed unfiltered --", RESET(); + sleep 1; + } + } + + ## I - InnoDB status + + if ($key =~ 'I') + { + $config{mode} = 'innodb'; + Clear() unless $config{batchmode}; + print "InnoDB Status\n"; + next; + } + + ## o - sort order + + if ($key =~ /o/) + { + if ($config{sort}) + { + $config{sort} = 0; + print RED(), "-- sort order reversed --", RESET(); + sleep 1; + } + else + { + $config{sort} = 1; + print RED(), "-- sort order reversed --", RESET(); + sleep 1; + } + } + + ## ? - help + + if ($key eq '?') + { + Clear(); + PrintHelp(); + ReadKey(0); + next; + } + + ## k - kill + + if ($key eq 'k') + { + ReadMode($RM_RESET); + + print RED(), "Thread id to kill: ", RESET(); + my $id = ReadLine(0); + + $id =~ s/\s//g; + + if ($id =~ /^\d+$/) + { + Execute("KILL /*mytop*/ $id"); + } + else + { + print RED(), "-- invalid thread id --", RESET(); + sleep 1; + } + + ReadMode($RM_NOBLKRD); + next; + } + + ## K - kill based on a username + if ($key =~ /K/) + { + ReadMode($RM_RESET); + + print RED(), "User to kill: ", RESET(); + my $user = ReadLine(0); + + $user =~ s/\s//g; + + if ($user =~ /^\S+$/) + { + for my $pid (keys %ucache) + { + next unless $ucache{$pid} eq $user; + Execute("KILL /*mytop*/ $pid"); + select(undef, undef, undef, 0.2); + } + } + else + { + print RED(), "-- invalid thread id --", RESET(); + sleep 1; + } + + ReadMode($RM_NOBLKRD); + } + + ## f - full info + + if ($key =~ /f/) + { + ReadMode($RM_RESET); + print RED(), "Full query for which thread id: ", RESET(); + my $id = ReadLine(0); + chomp $id; + FullQueryInfo($id); + ReadMode($RM_NOBLKRD); + print RED(), "-- paused. press any key to resume or (e) to explain --", + RESET(); + my $key = ReadKey(0); + + if ($key eq 'e') + { + Explain($id); + print RED(), "-- paused. press any key to resume --", RESET(); + ReadKey(0); + } + + next; + } + + ## e - explain + + if ($key =~ /e/) + { + ReadMode($RM_RESET); + print RED(), "Explain which query (id): ", RESET(); + my $id = ReadLine(0); + chomp $id; + Explain($id); + ReadMode($RM_NOBLKRD); + print RED(), "-- paused. press any key to resume --", RESET(); + ReadKey(0); + next; + } + + ## r - reset status counters + + if ($key =~ /r/) + { + Execute("FLUSH /*mytop*/ STATUS"); + print RED(), "-- counters reset --", RESET(); + sleep 1; + next; + } + + ## H - header toggle + + if ($key eq 'H') + { + if ($config{header}) + { + $config{header} = 0; + } + else + { + $config{header}++; + } + } + + ## # - magic debug key + + if ($key eq '#') + { + $debug = 1; + } + + if ($key eq 'V') + { + GetShowVariables(); + print RED(), "-- paused. press any key to resume --", RESET(); + ReadKey(0); + } + + ## M - switch to SHOW STATUS mode + + if ($key eq 'M') + { + $config{mode} = 'status'; + } + + ## L - full queries toggle + + if ($key eq 'L') + { + if ($config{fullqueries}) + { + $config{fullqueries} = 0; + print RED(), "-- full queries OFF --", RESET(); + sleep 1; + } + else + { + $config{fullqueries} = 1; + print RED(), "-- full queries ON --", RESET(); + sleep 1; + } + } + + ## w - change columns width for the "User" and "Database" columns + + if ($key eq 'w') + { + ReadMode($RM_RESET); + print RED(), "Width for the 'User' column (the actual value is ". + $config{usercol_width}."): "; + my $readWidth = ReadLine(0); + chomp($readWidth); + if (defined($readWidth) && $readWidth ne "") + { + if ($readWidth > 4 && $readWidth < 60) + { + $config{usercol_width} = $readWidth; + } + else + { + print RED(), "-- Invalid value ($readWidth), the previous value". + "has been kept, press a key to resume --"; + ReadKey(0); + } + } + print RESET(), RED(), "Width for the 'DB' column (the actual value is ". + $config{dbcol_width}."): ", RESET(); + $readWidth = ReadLine(0); + chomp($readWidth); + if (defined($readWidth) && $readWidth ne "") + { + if ($readWidth > 2 && $readWidth < 60) + { + $config{dbcol_width} = $readWidth + } + else + { + print RED(), "-- Invalid value ($readWidth), the previous value". + "has been kept, press a key to resume --", RESET(); + ReadKey(0); + } + } + undef $readWidth; + ReadMode($RM_NOBLKRD); + next; + } + + ## a - progress column toggle (the column is only displayed + ## if progress information are available from the processlist) + + if ($key eq 'a') + { + if ($config{hide_progress}) + { + $config{hide_progress} = 0; + print RED(), "-- progress display ON --", RESET(); + sleep 1; + } + else + { + $config{hide_progress} = 1; + print RED(), "-- progress display OFF --", RESET(); + sleep 1; + } + } + +} + +ReadMode($RM_RESET) unless $config{batchmode}; + +exit; + +####################################################################### + +sub Clear() +{ + if (not $WIN) + { + print "$CLEAR" + } + else + { + print "\n" x 90; ## dumb hack for now. Anyone know how to + ## clear the screen in dos window on a Win32 + ## system?? + } +} + +my $last_time; + +sub GetData() +{ + ## Get terminal info + my $now_time; + %qcache = (); ## recycle memory + %dbcache = (); + + my ($width, $height, $wpx, $hpx, $lines_left); + + if (not $config{batchmode}) + { + ($width, $height, $wpx, $hpx) = GetTerminalSize(); + $lines_left = $height - 2; + } + else + { + $height = 999_999; ## I hope you don't have more than that! + $lines_left = 999_999; + $width = 80; + } + + ## + ## Header stuff. + ## + if ($config{header}) + { + my @recs = ""; + if ($db_release > 4) + { + @recs = Hashes("SHOW /*mytop*/ GLOBAL STATUS"); + } + else + { + @recs = Hashes("SHOW /*mytop*/ STATUS"); + } + + ## if the server died or we lost connectivity + if (not @recs) + { + ReadMode($RM_RESET); + exit 1; + } + + ## get high-res or low-res time + my ($t_delta); + + if ($HAS_TIME) + { + $now_time = Time::HiRes::gettimeofday(); + } + else + { + $now_time = time; + } + + if ($last_time and $last_time != $now_time) + { + $t_delta = $now_time - $last_time; + } + + %OLD_STATUS = %STATUS; + # Set some status that may not exist in all versions + $STATUS{Handler_tmp_write} = 0; + $STATUS{Handler_tmp_update} = 0; + $STATUS{Rows_tmp_read} = 0; + + foreach my $ref (@recs) + { + my $key = $ref->{Variable_name}; + my $val = $ref->{Value}; + + $STATUS{$key} = $val; + } + + ## Compute Key Cache Hit Stats + + $STATUS{Key_read_requests} ||= 1; ## can't divide by zero next + + my $cache_hits_percent = (100-($STATUS{Key_reads}/$STATUS{Key_read_requests}) * 100); + $cache_hits_percent = sprintf("%2.2f",$cache_hits_percent); + + ## Query Cache info for <= Ver. 4.1 + ## + ## mysql> show status like 'qcache%'; + ## +-------------------------+----------+ + ## | Variable_name | Value | + ## +-------------------------+----------+ + ## | Qcache_queries_in_cache | 81 | + ## | Qcache_inserts | 4961668 | + ## | Qcache_hits | 1374170 | + ## | Qcache_not_cached | 5656249 | + ## | Qcache_free_memory | 33164800 | + ## | Qcache_free_blocks | 2 | + ## | Qcache_total_blocks | 168 | + ## +-------------------------+----------+ + ## + ## Query Cache info for => Ver. 5.0 + ## + ## mysql> show status like 'qcache%'; + ## +-------------------------+------------+ + ## | Variable_name | Value | + ## +-------------------------+------------+ + ## | Qcache_free_blocks | 37652 | + ## | Qcache_free_memory | 110289712 | + ## | Qcache_hits | 1460617356 | + ## | Qcache_inserts | 390563495 | + ## | Qcache_lowmem_prunes | 6414172 | + ## | Qcache_not_cached | 93002420 | + ## | Qcache_queries_in_cache | 66558 | + ## | Qcache_total_blocks | 192031 | + ## +-------------------------+------------+ + + my $query_cache_hits = 0; + my $query_cache_hits_per_sec = 0; + my $now_query_cache_hits_per_sec = 0; + + if ($have_query_cache) + { + $query_cache_hits = $STATUS{Qcache_hits}; + $query_cache_hits_per_sec = $STATUS{Qcache_hits} / $STATUS{Uptime}; + + if (defined $last_time and $last_time != $now_time) + { + my $q_delta = $STATUS{Qcache_hits} - $OLD_STATUS{Qcache_hits}; + $now_query_cache_hits_per_sec = sprintf "%.2f", $q_delta / $t_delta; + } + } + + my $l; + if (-e "/proc/loadavg") + { + ## To avoid warnings if the OS is not Linux + open (my $fh, "<", "/proc/loadavg"); + ## Only the first 3 values are interresting + $l = join(" ", (split /\s+/, <$fh>)[0..2]); + close $fh; + } + + $last_time = $now_time; + + ## Server Uptime in meaningful terms... + + my $time = $STATUS{Uptime}; + my ($d,$h,$m,$s) = (0, 0, 0, 0); + + $d += int($time / (60*60*24)); $time -= $d * (60*60*24); + $h += int($time / (60*60)); $time -= $h * (60*60); + $m += int($time / (60)); $time -= $m * (60); + $s += int($time); + + my $uptime = sprintf("%d+%02d:%02d:%02d", $d, $h, $m, $s); + + ## Queries per second... + + my $avg_queries_per_sec = sprintf("%.2f", $STATUS{Questions} / $STATUS{Uptime}); + my $num_queries = $STATUS{Questions}; + + my @t = localtime(time); + + my $current_time = sprintf "[%02d:%02d:%02d]", $t[2], $t[1], $t[0]; + + my $host_width = length("$server $db_version on $config{host}"); + my $up_width = $width - $host_width - 1; + Clear() unless $config{batchmode}; + print RESET(); + + printf "%-.${host_width}s %${up_width}s\n", + "$server $db_version on $config{host}", + defined($l) ? "load ($l) up $uptime $current_time" : "up $uptime $current_time"; + $lines_left--; + + + printf " Queries: %-7s qps: %4.0f Slow: %7s Se/In/Up/De(%%): %02.0f/%02.0f/%02.0f/%02.0f\n", + make_short( $STATUS{Questions} ), # q total + $STATUS{Questions} / $STATUS{Uptime}, # qps, average + make_short( $STATUS{Slow_queries} ), # slow + + # hmm. a Qcache hit is really a select and should be counted. + 100 * ($STATUS{Com_select} + ($STATUS{Qcache_hits}||0) ) / $STATUS{Questions}, + 100 * ($STATUS{Com_insert} + $STATUS{Com_replace} ) / $STATUS{Questions}, + 100 * ($STATUS{Com_update} ) / $STATUS{Questions}, + 100 * $STATUS{Com_delete} / $STATUS{Questions}; + + $lines_left--; + + if ($t_delta) + { + my $q_diff = ( $STATUS{Questions} - $OLD_STATUS{Questions} ); +# print("q_diff: $STATUS{Questions} - $OLD_STATUS{Questions} / $t_delta = $q_diff\n"); + + printf(" Sorts: %6.0f qps now: %4.0f Slow qps: %3.1f Threads: %4.0f (%4.0f/%4.0f) %02.0f/%02.0f/%02.0f/%02.0f\n", + ( $STATUS{Sort_rows} - $OLD_STATUS{Sort_rows} ) / $t_delta, + + ( $STATUS{Questions} - $OLD_STATUS{Questions} ) / $t_delta, + ( # slow now (qps) + ($STATUS{Slow_queries} ) ? + ( $STATUS{Slow_queries} - $OLD_STATUS{Slow_queries} ) / $t_delta : + 0 + ), + $STATUS{Threads_connected}, + $STATUS{Threads_running}, + $STATUS{Threads_cached}, + + (100 * ($STATUS{Com_select} - $OLD_STATUS{Com_select} + + ($STATUS{Qcache_hits}||0) - ($OLD_STATUS{Qcache_hits}||0) + ) ) / ($q_diff ), + (100 * ($STATUS{Com_insert} - $OLD_STATUS{Com_insert} + + $STATUS{Com_replace} - $OLD_STATUS{Com_replace} + ) ) / ($q_diff ), + (100 * ($STATUS{Com_update} - $OLD_STATUS{Com_update}) ) / ($q_diff ), + (100 * ($STATUS{Com_delete} - $OLD_STATUS{Com_delete}) ) / ($q_diff ), + ); + } + else + { + print "\n"; + } + $lines_left--; + + if ($have_query_cache and $STATUS{Com_select} and $query_cache_hits) + { + printf(" Cache Hits: %-5s Hits/s: %4.1f Hits now: %5.1f Ratio: ", + make_short($STATUS{Qcache_hits}), # cache hits + $STATUS{Qcache_hits} / $STATUS{Uptime}, # hits / sec + ($t_delta) ? ($STATUS{Qcache_hits} - $OLD_STATUS{Qcache_hits}) / $t_delta : 0, # Hits Now + ); + + my ($Ratio) = 100 * ($STATUS{Qcache_hits}) / ($STATUS{Qcache_hits} + $STATUS{Com_select} ); + if ($HAS_COLOR) + { + print YELLOW() if ($Ratio < 80.0); + print RED() if ($Ratio < 50.0); + print MAGENTA() if ($Ratio < 20.0); + } + printf("%4.1f%% ",$Ratio); + if ($HAS_COLOR) + { + print RESET(); + } + + print " Ratio now: "; + my ($Ratio_now) = ($t_delta) ? # ratio now + 100 * ($STATUS{Qcache_hits} - $OLD_STATUS{Qcache_hits} ) / + ( ($STATUS{Com_select} + $STATUS{Qcache_hits} - + ($OLD_STATUS{Qcache_hits} + $OLD_STATUS{Com_select}) + ) || 1) : 0; + if ($HAS_COLOR) + { + print GREEN() if ($Ratio_now >= 80.0); + print YELLOW() if ($Ratio_now < 80.0); + print RED() if ($Ratio_now < 50.0); + print MAGENTA() if ($Ratio_now < 20.0); + } + printf("%4.1f%% \n",$Ratio_now); + if ($HAS_COLOR) + { + print RESET(); + } + $lines_left--; + } + + if ($t_delta) + { + my $rows_read; + if (defined($STATUS{Rows_read})) + { + $rows_read= $STATUS{Rows_read} - $OLD_STATUS{Rows_read}; + } + else + { + $rows_read= + ($STATUS{Handler_read_first} + $STATUS{Handler_read_key} + + $STATUS{Handler_read_next} + $STATUS{Handler_read_prev} + + $STATUS{Handler_read_rnd} + $STATUS{Handler_read_rnd_next} - + $OLD_STATUS{Handler_read_first} - $OLD_STATUS{Handler_read_key} - + $OLD_STATUS{Handler_read_next} - $OLD_STATUS{Handler_read_prev} - + $OLD_STATUS{Handler_read_rnd} - $OLD_STATUS{Handler_read_rnd_next}); + } + printf(" Handler: (R/W/U/D) %5d/%5d/%5d/%5d Tmp: R/W/U: %5d/%5d/%5d\n", + $rows_read/$t_delta, + ($STATUS{Handler_write} - $OLD_STATUS{Handler_write}) / + $t_delta, + ($STATUS{Handler_update} - $OLD_STATUS{Handler_update}) / + $t_delta, + ($STATUS{Handler_delete} - $OLD_STATUS{Handler_delete}) / + $t_delta, + ($STATUS{Rows_tmp_read} - $OLD_STATUS{Rows_tmp_read}) / + $t_delta, + ($STATUS{Handler_tmp_write} + -$OLD_STATUS{Handler_tmp_write})/$t_delta, + ($STATUS{Handler_tmp_update} - + $OLD_STATUS{Handler_tmp_update})/$t_delta); + } + else + { + print "\n"; + } + + $lines_left--; + + printf(" MyISAM Key Cache Efficiency: %2.1f%% Bps in/out: %5s/%5s ", + $cache_hits_percent, + make_short($STATUS{Bytes_received} / $STATUS{Uptime} ), + make_short($STATUS{Bytes_sent} / $STATUS{Uptime})); + printf("Now in/out: %5s/%5s", + make_short(($STATUS{Bytes_received} - $OLD_STATUS{Bytes_received}) / $t_delta ), + make_short(($STATUS{Bytes_sent} - $OLD_STATUS{Bytes_sent}) / $t_delta )) + if ($t_delta); + print "\n"; + + $lines_left--; + + my ($data) = Hashes('SHOW /*mytop*/ GLOBAL VARIABLES LIKE "read_only"'); + if ($data->{Value} ne "OFF") + { + print RED() if ($HAS_COLOR) ; + print " ReadOnly"; + RESET() if ($HAS_COLOR); + } + + ($data) = Hashes('SHOW /*mytop*/ SLAVE STATUS'); + if (defined($data->{Master_Host})) + { + if (defined($data->{Seconds_Behind_Master})) + { + if ($HAS_COLOR) + { + print GREEN(); + print YELLOW() if ($data->{Seconds_Behind_Master} > 60); + print MAGENTA() if ($data->{Seconds_Behind_Master} > 360); + } + } + print " Replication "; + print "IO:$data->{Slave_IO_Running} "; + print "SQL:$data->{Slave_SQL_Running} "; + print RESET() if ($HAS_COLOR); + + if (defined($data->{Seconds_Behind_Master})) + { + if ($HAS_COLOR) + { + print GREEN(); + print YELLOW() if ($data->{Seconds_Behind_Master} > 60); + print MAGENTA() if ($data->{Seconds_Behind_Master} > 360); + } + print "Delay: $data->{Seconds_Behind_Master} sec."; + } + else + { + my $free = $width - 45; + my $Err = substr $data->{Last_Error},0 ,$free; + printf(" ERR: %-${free}s", $Err) if ($Err ne ""); + } + print WHITE() if ($HAS_COLOR); + print "\n"; + $lines_left--; + } + print "\n"; + } + + if (not $config{batchmode} and not $config{header}) + { + Clear(); + print RESET(); + } + + ## + ## Threads + ## + + my $proc_cmd; ## Query used to fetch the processlist + my $time_format = "6d"; + + if ($has_is_processlist == 1) + { + if ($has_time_ms == 1) + { + $time_format = "6.6s"; + if ($has_progress == 1) + { + ## To have a computed value of "Progress" like the + ## "SHOW PROCESSLIST" one, the Progress column of the query + ## must be replaced by : + ## "CASE WHEN Max_Stage < 2 THEN Progress ELSE + ## (Stage-1)/Max_Stage*100+Progress/Max_Stage END AS Progress" + $proc_cmd = "SELECT /*mytop*/ Id, User, Host, db, Command, + CASE WHEN TIME > 10000 THEN Time ELSE + ROUND(TIME_MS/1000, 1) END AS Time, + State, Info, Progress, Stage, Max_Stage + FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE ID != CONNECTION_ID();"; + } + else + { + $proc_cmd = "SELECT /*mytop*/ Id, User, Host, db, Command, + CASE WHEN TIME > 10000 THEN Time ELSE + ROUND(TIME_MS/1000, 1) END AS Time, + State, Info FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE ID != CONNECTION_ID();"; + } + } + else + { + $proc_cmd = "SELECT /*mytop*/ Id, User, Host, db, Command, Time, + State, Info FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE ID != CONNECTION_ID();"; + } + } + else + { + $proc_cmd = "SHOW /*mytop*/ FULL PROCESSLIST;"; + } + + ## Minimal width values for columns with a dynamic width + if ($config{usercol_width} < 4) { $config{usercol_width} = 4; } + if ($config{dbcol_width} < 2) { $config{dbcol_width} = 2; } + + my @sz = (9, $config{usercol_width}, 15, $config{dbcol_width}, 6, 6, 8); + if ($has_progress == 1 && !$config{hide_progress}) { push @sz, 5; }; + my $used = scalar(@sz) + Sum(@sz); + undef(@sz); + + ## If the terminal width <= 80, the state column will have a width of 6 + ## chars else it will be between 6 and 15 depending on the terminal width + my $state = $width <= 80 ? 6 : int(min(6+($width-80)/3, 15)); + ## $free = The number of chars between the beginning of the "Query" + ## column and the end of the line + my $free = $width - $used - ($state - 6); + my $format= "%9s %$config{usercol_width}s %15s %$config{dbcol_width}s %6s "; + if ($has_progress == 1 && !$config{hide_progress}) { $format .= "%5s "; } + $format .= "%6s %${state}s %-.${free}s\n"; + + my $format2 = "%9d %$config{usercol_width}.$config{usercol_width}s %15.15s %$config{dbcol_width}.$config{dbcol_width}s %${time_format} "; + if ($has_progress == 1 && !$config{hide_progress}) { $format2 .= "%5.1f "; } + $format2 .= "%6.6s %${state}.${state}s "; + if ($config{fullqueries}) + { + $format2 .= "%-${free}s\n"; + } + else + { + $format2 .= "%-${free}.${free}s\n"; + } + + print BOLD() if ($HAS_COLOR); + + if ($has_progress == 1 && !$config{hide_progress}) + { + printf $format, + 'Id','User','Host/IP','DB','Time', '%', 'Cmd', 'State', 'Query'; + } + else + { + printf $format, + 'Id','User','Host/IP','DB','Time', 'Cmd', 'State', 'Query'; + } + + print RESET() if ($HAS_COLOR); + + ## Id User Host DB + if ($has_progress == 1 && !$config{hide_progress}) + { + printf $format, + '--','----','-------','--','----', '-', '---', '-----', '----------'; + } + else + { + printf $format, + '--','----','-------','--','----', '---', '-----', '----------'; + } + + $lines_left -= 2; + + my @data = Hashes($proc_cmd); + + foreach my $thread (@data) + { + last if not $lines_left; + + ## Drop Domain Name, unless it looks like an IP address. If + ## it's an IP, we'll strip the port number because it's rarely + ## interesting. + + my $is_ip = 0; + + if ($thread->{Host} =~ /^(\d{1,3}\.){3}(\d{1,3})(:\d+)?$/) + { + $thread->{Host} =~ s/:.*$//; + $is_ip = 1; + } + else + { + $thread->{Host} =~ s/^([^.]+).*/$1/; + } + + ## Otherwise, look up the IP (if resolve is set) and strip the + ## name + if ($is_ip and $config{resolve}) + { + $thread->{Host} =~ s/:\d+$//; + my $host = gethostbyaddr(inet_aton($thread->{Host}), AF_INET); + if ($host) + { + ## Only the hostname part of the DNS is kept + $host =~ s/^([^.]+).*/$1/; + } + $thread->{Host} = $host; + } + + ## Fix possible undefs + + $thread->{db} ||= ''; + $thread->{Info} ||= ''; + $thread->{Time} ||= 0 ; + $thread->{Id} ||= 0 ; + $thread->{User} ||= ''; + $thread->{Command} ||= ''; + $thread->{Host} ||= ''; + $thread->{State} ||= ""; + $thread->{Progress} ||= 0; + + ## Alter double hyphen comments so they don't break + ## the query when newlines are removed - http://freshmeat.net/users/jerjones + $thread->{Info} =~ s~\s--(.*)$~ /* $1 */ ~mg; + + ## Normalize spaces -- mostly disabled for now. This can + ## break EXPLAIN if you try to explain a mangled query. It + ## may be re-enabled later as an option. + + ## Replace newlines and carriage returns with a space + $thread->{Info} =~ tr/\n\r/ /; + + ## Leading space removal + $thread->{Info} =~ s/^\s*//; + + ## Strip non printing control symbols + $thread->{Info} =~ tr/[[:cntrl:]]//; + + ## Collpase whitespace + $thread->{Info} =~ s/\s+/ /g; + + ## Trailing space removal + $thread->{Info} =~ s/\s$//; + + ## Put the first letter of the query uppercase for a better readability + ## with long State strings + $thread->{Info} = ucfirst $thread->{Info}; + + ## Stow it in the cache + $qcache{$thread->{Id}} = $thread->{Info}; + $dbcache{$thread->{Id}} = $thread->{db}; + $ucache{$thread->{Id}} = $thread->{User}; + + ## If Progress information is available and a multi-stage query is + ## running, the actual stage and the total number of stages of the + ## thread are shown at the beginning of the State column + if ($has_progress == 1 && $thread->{Max_Stage} && $thread->{Max_Stage} > 1) + { + $thread->{State} = $thread->{Stage}."/". + $thread->{Max_Stage}." ".$thread->{State}; + } + } + + ## Sort by idle time (closest thing to CPU usage I can think of). + + my @sorted; + + if (not $config{sort}) + { + @sorted = sort { $a->{Time} <=> $b->{Time} } @data + } + else + { + @sorted = sort { $b->{Time} <=> $a->{Time} } @data + } + + foreach my $thread (@sorted) + { + ## Check to see if we can skip out. + ## We skip out if we know the given line doesn't match. + + next if (($thread->{Command} eq "Sleep") + and + (not $config{idle})); + + next if (($thread->{Command} eq "Binlog Dump") + and + (not $config{idle})); + + next if (($thread->{Command} eq "Daemon") + and + (not $config{idle})); + + next if ($thread->{User} !~ $config{filter_user}); + next if ($thread->{db} !~ $config{filter_db}); + next if ($thread->{Host} !~ $config{filter_host}); + next if ($thread->{State} !~ $config{filter_state}); + + ## Otherwise, print. + + my $smInfo; + + if ($thread->{Info}) + { + if ($config{fullqueries}) + { + $smInfo = $thread->{Info}; + if (length($smInfo) > $free) + { + $lines_left -= int((length($smInfo) - $free)/$width) + 1; + } + } + else + { + $smInfo = substr $thread->{Info}, 0, $free; + } + } +# if ($thread->{State}) +# { +# $smInfo = substr $thread->{State}, 0, $free; +# } + else + { + $smInfo = ""; + } + + $lines_left--; + if ($lines_left < 0) + { + print WHITE(), "-- Truncated query list -- "; + last; + } + + if ($HAS_COLOR) + { + print YELLOW() if $thread->{Command} eq 'Query'; + print WHITE() if $thread->{Command} eq 'Sleep'; + print GREEN() if $thread->{Command} eq 'Connect'; + print BOLD() if $thread->{Time} > $config{slow}; + print MAGENTA() if $thread->{Time} > $config{long}; + } + + if ($has_progress == 1 && !$config{hide_progress}) + { + printf $format2, + $thread->{Id}, $thread->{User}, $thread->{Host}, $thread->{db}, + $thread->{Time}, $thread->{Progress}, $thread->{Command}, + $thread->{State}, $smInfo; + } + else + { + printf $format2, + $thread->{Id}, $thread->{User}, $thread->{Host}, $thread->{db}, + $thread->{Time}, $thread->{Command}, $thread->{State}, $smInfo; + } + + print RESET() if $HAS_COLOR; + } + +} + +########################################################################### + +my $questions; + +sub GetQPS() +{ + my ($data) = Hashes('SHOW /*mytop*/ STATUS LIKE "Questions"'); + my $num = $data->{Value}; + + if (not defined $questions) ## first time? + { + $questions = $num; + return; + } + + my $qps = $num - $questions; + $questions = $num; + print "$qps\n"; +} + +########################################################################### + +sub GetInnoDBStatus() +{ + if (not $config{pager}) + { + if (not $config{pager} = my_which('less')) + { + $config{pager} = my_which('more'); + } + } + + my @data = Hashes("SHOW /*mytop*/ ENGINE INNODB STATUS"); + + open P, "|$config{pager}" or die "$!"; + print keys %{$data[0]}; + print $data[0]->{Status},"\n"; + close P; +} + +########################################################################### + +my %prev_data; + +sub GetCmdSummary() +{ + my ($width, $height, $wpx, $hpx, $lines_left); + + if (not $config{batchmode}) + { + ($width, $height, $wpx, $hpx) = GetTerminalSize(); + + $lines_left = $height - 2; + } + else + { + $height = 999_999; ## I hope you don't have more than that! + $lines_left = 999_999; + $width = 80; + } + + ## Variable_name and Value pairs come back... + my @data = Hashes("SHOW /*mytop*/ STATUS LIKE 'Com\\_%'"); + my %cmd_data; + my %cmd_delta; + my %cmd_pct; + my %cmd_delta_pct; + my $total; + my $delta_total; + + for my $item (@data) + { + next unless $item->{Value}; + $item->{Variable_name} =~ s/^Com_//; + $item->{Variable_name} =~ s/_/ /g; + $cmd_data{$item->{Variable_name}} = $item->{Value}; + $total += $item->{Value}; + } + + ## Populate other stats + + for my $item (keys %cmd_data) + { + $cmd_delta{$item} = $cmd_data{$item} - + ($prev_data{$item} || $cmd_data{$item} - 1); + + $delta_total += $cmd_delta{$item}; + + $cmd_pct{$item} = int(($cmd_data{$item} / $total) * 100); + } + + for my $item (keys %cmd_data) + { + $cmd_delta_pct{$item} = int(($cmd_delta{$item} / $delta_total) * 100); + } + + + ## Display + + Clear() unless $config{batchmode}; + print RESET(); + printf "%18s %10s %4s | %5s %4s\n", 'Command', 'Total', 'Pct', 'Last', 'Pct'; + printf "%18s %10s %4s | %5s %4s\n", '-------', '-----', '---', '----', '---'; + $lines_left -= 2; + + for my $item (sort { $cmd_data{$b} <=> $cmd_data{$a} } keys %cmd_data) + { + printf "%18s %10d %4s | %5d %4s\n", + $item, + $cmd_data{$item}, + $cmd_pct{$item} . "%", + $cmd_delta{$item}, + $cmd_delta_pct{$item} . "%"; + + last if not $lines_left; + $lines_left -= 1; + } + + %prev_data = %cmd_data; +} + +########################################################################### + +sub GetShowVariables() +{ + if (not $config{pager}) + { + if (not $config{pager} = my_which('less')) + { + $config{pager} = my_which('more'); + } + } + + my @rows = Hashes("SHOW /*mytop*/ VARIABLES"); + + open P, "|$config{pager}" or die "$!"; + + for my $row (@rows) + { + my $name = $row->{Variable_name}; + my $value = $row->{Value}; + printf P "%32s: %s\n", $name, $value; + } + + close P; +} + +########################################################################### + +sub GetShowStatus() +{ + Clear() unless $config{batchmode}; + my @rows = Hashes("SHOW /*mytop*/ STATUS"); + + printf "%32s %10s %10s Toggle idle with 'i'\n", 'Counter', 'Total', 'Change'; + printf "%32s %10s %10s\n", '-------', '-----', '------'; + + for my $row (@rows) + { + my $name = $row->{Variable_name}; + my $value = $row->{Value}; + my $old = $statcache{$name}; + my $delta = 0; + + next if $name =~ m/^Com_/; ## skip Com_ stats + next if $value =~ m/^[^0-9]*$/; ## skip non-numeric + + ## TODO: if Qcache is off, we should skip Qcache_ values + + if ($HAS_COLOR and defined $old and $old =~ /^\d/) + { + if ($value > $old) + { + print YELLOW(); + $delta = $value - $old; + } + elsif ($value < $old) + { + print RED(); + $delta = $value - $old; + } + + if (not $config{idle} and $value == $old) + { + ## filter unchanging stats, maybe + print RESET(); + next; + } + } + + printf "%32s: %10s %10s\n", $name, $value, $delta; + print RESET() if $HAS_COLOR; + + $statcache{$name} = $value; + } + +} + +########################################################################### + +sub FullQueryInfo($) +{ + my $id = shift; + + if (not exists $qcache{$id} or not defined $qcache{$id}) + { + print "*** Invalid id. ***\n"; + return; + } + + my $sql = $qcache{$id}; + print $CLEAR; + print "Thread $id was executing following query:\n\n"; + print YELLOW(), $sql,"\n\n", RESET(); +} + +########################################################################### + +sub Explain($) +{ + my $id = shift; + + if (not exists $qcache{$id} or not defined $qcache{$id}) + { + print "*** Invalid id. ***\n"; + return; + } + + my $sql = $qcache{$id}; + my $db = $dbcache{$id}; + + Execute("USE /*mytop*/ $db"); + my @info = Hashes("EXPLAIN $sql"); + print $CLEAR; + print "EXPLAIN $sql:\n\n"; + PrintTable(@info); +} + +########################################################################### + +sub PrintTable(@) +{ + my $cnt = 1; + my @cols = qw(table type possible_keys key key_len ref rows Extra); + + for my $row (@_) + { + print "*** row $cnt ***\n"; + for my $key (@cols) + { + my $val = $row->{$key} || 'NULL'; + printf "%15s: %s\n", $key, $val; + } + $cnt++; + } +} + +########################################################################### + +sub StringOrRegex($) +{ + my $input = shift; + chomp $input; + if (defined $input) + { + ## regex, strip /.../ and use via qr// + if ($input =~ m{^/} and $input =~ m{/$}) + { + $input =~ s{^/}{} if $config{filter_user}; + $input =~ s{/$}{} if $config{filter_user}; + $input = qr/$input/; + } + + + ## reset to match anything + elsif ($input eq '') + { + $input = qr/.*/; + } + + ## string, build a simple regex + else + { + $input = '^' . $input . '$'; + $input = qr/$input/; + } + } + + ## reset to match anything + else + { + $input = qr/.*/; + } + return $input; +} + +########################################################################### + +sub cmd_l +{ + ReadMode($RM_RESET); + + print RED(), "Seconds for long queries: ", RESET(); + my $secs = ReadLine(0); + + if ($secs =~ /^\s*(\d+)/) + { + $config{long} = $1; + if ($config{long} < 1) + { + $config{long} = 1; + } + } + ReadMode($RM_NOBLKRD); +} + +sub cmd_s +{ + ReadMode($RM_RESET); + + print RED(), "Seconds of Delay: ", RESET(); + my $secs = ReadLine(0); + + if ($secs =~ /^\s*(\d+)/) + { + $config{delay} = $1; + if ($config{delay} < 1) + { + $config{delay} = 1; + } + } + ReadMode($RM_NOBLKRD); +} + +sub cmd_S +{ + ReadMode($RM_RESET); + + print RED(), "Seconds for Slow queries: ", RESET(); + my $secs = ReadLine(0); + + if ($secs =~ /^\s*(\d+)/) + { + $config{slow} = $1; + if ($config{slow} < 1) + { + $config{slow} = 1; + } + } + ReadMode($RM_NOBLKRD); +} + +sub cmd_q +{ + ReadMode($RM_RESET); + print "\n"; + exit; +} + +sub trim($) +{ + my $string = shift; + $string =~ s/^\s+//; + $string =~ s/\s+$//; + return $string; +} + +########################################################################### + +sub PrintHelp() +{ + my $help = qq[Help for mytop version $main::VERSION by Jeremy D. Zawodny <${YELLOW}Jeremy\@Zawodny.com${RESET}> + with updates by Mark Grennan <${YELLOW}mark\@grennan.com${RESET}> and Jean Weisbuch <${YELLOW}jean\@phpnet.org${RESET}> + + ? - display this screen + # - debug mode (toggle) + c - command summary view (based on Com_* counters) + C - turn color on and off + d - show only a specific database + e - explain the query that a thread is running + E - display current replication error + f - show full query info for a given thread + F - unfilter the display + h - show only a specifc host's connections + H - toggle the mytop header + i - toggle the display of idle (sleeping) threads + I - show innodb status + k - kill a thread + p - pause the display + l - change long running queries hightlighing + m - switch [mode] to qps (queries/sec) scrolling view + M - switch [mode] to status + o - reverse the sort order (toggle) + q - quit + r - reset the status counters (via FLUSH STATUS on your server) + R - change reverse IP lookup + s - change the delay between screen updates + S - change slow query hightlighting + t - switch to thread view (default) + u - show only a specific user + V - show variables + : - enter a command (not yet implemented) + ! - Skip an error that has stopped replications (at your own risk) + L - show full queries (do not strip to terminal width) + w - adjust the User and DB columns width + a - toggle the progress column + +Base version from ${GREEN}http://www.mysqlfanboy.com/mytop-3${RESET} +This version comes as part of the ${GREEN}MariaDB${RESET} distribution. +]; + + print $help; +} + +sub Sum(@) +{ + my $sum; + while (my $val = shift @_) { $sum += $val; } + return $sum; +} + +## A useful routine from perlfaq + +sub commify($) +{ + local $_ = shift; + return 0 unless defined $_; + 1 while s/^([-+]?\d+)(\d{3})/$1,$2/; + return $_; +} + +## Compact numeric representation (10,000 -> 10.0k) + +sub make_short($) +{ + my $number = shift; + return commify($number) if $config{long_nums}; + my $n = 0; + while ($number > 1_025) { $number /= 1024; $n++; }; + return sprintf "%.1f%s", $number, ('','k','M','G', 'T')[$n]; +} + + +## Run a query and return the records has an array of hashes. + +sub Hashes($) +{ + my $sql = shift; + my @records; + + if (my $sth = Execute($sql)) + { + while (my $ref = $sth->fetchrow_hashref) + { + print "record\n" if $debug; + push @records, $ref; + } + } + return @records; +} + +## Execute an SQL query and return the statement handle. + +sub Execute($) +{ + my $sql = shift; + + $sql =~ s/\n/ /sg; + + my $sth = $dbh->prepare($sql); + + if (not $sth) { ReadMode($RM_RESET); die $DBI::errstr; } + + my $ReturnCode = $sth->execute; + + if (not $ReturnCode) + { + if ($debug) + { + print "query failed\n"; + sleep 10; + } + return undef; + } + + return $sth; +} + +#### +#### my_which is used, because we can't assume that every system has the +#### which command. my_which can take only one argument at a time. +#### Return values: requested system command with the first found path, +#### or undefined, if not found. +#### + +sub my_which +{ + my ($command) = @_; + my (@paths, $path); + + return $command if (-f $command && -x $command); + + ## Check first if this is a source distribution, then if this binary distribution and last in the path + + push @paths, "./extra"; + push @paths, $path_for_script; + push @paths, split(':', $ENV{'PATH'}); + + foreach $path (@paths) + { + $path .= "/$command"; + return $path if (-f $path && -x $path); + } + return undef(); +} + +=pod + +=head1 SYNOPSIS + +B<mytop> [options] + +=head1 AVAILABILITY + +Base version from B<http://www.mysqlfanboy.com/mytop-3>. + +This version comes as part of the B<MariaDB> distribution. See B<https://mariadb.org/>. + +And older (the original) version B<mytop> is available from +http://www.mysqlfanboy.com/mytop-3/ it B<might> also be on CPAN as +well. + +=head1 REQUIREMENTS + +In order for B<mytop> to function properly, you must have the +following: + + * Perl 5.005 or newer + * Getopt::Long + * DBI and DBD::MariaDB or DBD::mysql + * Term::ReadKey from CPAN + +Most systems are likely to have all of those installed--except for +Term::ReadKey. You will need to pick that up from the CPAN. You can +pick up Term::ReadKey here: + + http://search.cpan.org/search?dist=TermReadKey + +And you obviously need access to a MariaDB server with the necessary +security to run the I<SHOW PROCESSLIST> and I<SHOW STATUS> commands. + +If you are a Windows user, using ActiveState's Perl, you can use PPM +(the Perl Package Manager) to install the MariaDB/MySQL and Term::ReadKey +modules. + +=head2 Optional Color Support + +In additon, if you want a color B<mytop> (recommended), install +Term::ANSIColor from the CPAN: + + http://search.cpan.org/search?dist=ANSIColor + +Once you do, B<mytop> will automatically use it. However, color is not +yet working on Windows. Patches welcome. :-) + +=head2 Optional Hi-Res Timing + +If you want B<mytop> to provide more accurate real-time +queries-per-second statistics, install the Time::HiRes module from +CPAN. B<mytop> will automatically notice that you have it and use it +rather than the standard timing mechanism. + +=head2 Platforms + +B<mytop> is known to work on: + + * Linux (2.2.x, 2.4.x) + * FreeBSD (2.2, 3.x, 4.x) + * Mac OS X + * BSDI 4.x + * Solaris 2.x + * Windows NT 4.x (ActivePerl) + +If you find that it works on another platform, please let me +know. Given that it is all Perl code, I expect it to be rather +portable to Unix and Unix-like systems. Heck, it I<might> even work on +Win32 systems. + +=head1 DESCRIPTION + +Help is always welcome in improving this software. Feel free to +contact the author (see L<"AUTHOR"> below) with bug reports, fixes, +suggestions, and comments. Additionally L<"BUGS"> will provide a list +of things this software is not able to do yet. + +Having said that, here are the details on how it works and what you can +do with it. + +=head2 The Basics + +B<mytop> was inspired by the system monitoring tool B<top>. I +routinely use B<top> on Linux, FreeBSD, and Solaris. You are likely to +notice features from each of them here. + +B<mytop> will connect to a MariaDB server and periodically run the +I<SHOW PROCESSLIST> and I<SHOW STATUS> commands and attempt to +summarize the information from them in a useful format. + +=head2 The Display + +The B<mytop> display screen is really broken into two parts. The top 4 +lines (header) contain summary information about your MariaDB +server. For example, you might see something like: + +MariaDB 10.5.0 on localhost load (3.89 3.86 3.91) up 7+23:56:31 [16:33:01] + Queries: 353.4M qps: 531 Slow: 4.5k Se/In/Up/De(%): 87/02/02/00 + Sorts: 2390 qps now: 651 Slow qps: 0.0 Threads: 11 ( 1/ 13) 88/01/03/00 + Handler: (R/W/U/D) 82138/ 5884/ 20/ 1 Tmp: R/W/U: 13623/29501/ 79 + MyISAM Key Cache Efficiency: 99.9% Bps in/out: 157.4k/ 2.2M Now in/out: 554.8k/ 2.6M + +The first line identifies the hostname of the server (localhost) and +the version of MariaDB it is running. The right hand side shows the +uptime of the MariaDB server process in days+hours:minutes:seconds +format (much like FreeBSD's top) as well as the current time. + +The second line displays the total number of queries the server has +processed, the average number of queries per second, the number of +slow queries, and the percentage of Select, Insert, Update, and Delete +queries. + +The third real-time values. First is the number of queries per second, +then the number of slow queries, followed by query precentages (like +on the previous line). + +And the fourth line displays key buffer efficiency (how often keys are +read from the buffer rather than disk) and the number of bytes that +MariaDB has sent and received, both over all and in the last cycle. + +You can toggle the header by hitting B<H> when running B<mytop>. + +The second part of the display lists as many threads as can fit on +screen. By default they are sorted according to their idle time (least +idle first). The display looks like: + + Id User Host Dbase Time Cmd Query or State + -- ---- ---- ----- ---- --- -------------- + 61 jzawodn localhost music 0 Query show processlist + +As you can see, the thread id, username, host from which the user is +connecting, database to which the user is connected, number of seconds +of idle time, the command the thread is executing, and the query info +are all displayed. + +Often times the query info is what you are really interested in, so it +is good to run B<mytop> in an xterm that is wider than the normal 80 +columns if possible. + +The thread display color-codes the threads if you have installed color +support. The current color scheme only works well in a window with a +dark (like black) background. The colors are selected according to the +C<Command> column of the display: + + Query - Yellow + Sleep - White + Connect - Green + Slow - Bright + Long - Magenta + +Those are purely arbitrary and will be customizable in a future +release. If they annoy you just start B<mytop> with the B<--nocolor> +flag or adjust your config file appropriately. + +=head2 Arguments + +B<mytop> handles long and short command-line arguments. Not all +options have both long and short formats, however. The long arguments +have two dashes `--'. Short arguments only have one '-'. + +=over + +=item B<-u> or B<--user> username + +Username to use when logging in to the MariaDB server. Default: ``B<root>''. + +=item B<-p> or B<--pass> or B<--password> I<password> + +Password to use when logging in to the MariaDB server. Default: none. + +WARNING: This is insecure as the password is visible for anyone. +See B<--prompt> instead! + +=item B<-h> or B<--host> I<hostname>[B<:>I<port>] + +Hostname of the MariaDB server. The hostname may be followed by an +option port number. Note that the port is specified separate from the +host when using a config file. Default: ``B<localhost>''. + +=item B<--port> or B<-P> I<port> + +If you're running MariaDB on a non-standard port, use this to specify +the port number. Default: B<3306>. + +=item B<-s> or B<--delay> I<seconds> + +How long between display refreshes. Default: B<5> + +=item B<-d> or B<--db> or B<--database> I<database> + +Use if you'd like B<mytop> to connect to a specific database by +default. Default: none. + +=item B<-b> or B<--batch> or B<--batchmode> + +In batch mode, mytop runs only once, does not clear the screen, and +places no limit on the number of lines it will print. This is suitable +for running periodically (perhaps from B<cron>) to capture the +information into a file for later viewing. You might use batch mode in +a CGI script to occasionally display your MariaDB server status on the +web. + +Default: unset. + +=item B<-S> or B<--socket> I</path/to/socket> + +If you're running B<mytop> on the same host as MariaDB/MySQL, you may wish to +have it use the MariaDB/MySQL socket directly rather than a standard TCP/IP +connection. If you do,just specify one. + +Note that specifying a socket will make B<mytop> ignore any host +and/or port that you might have specified. If the socket does not +exist (or the file specified is not a socket), this option will be +ignored and B<mytop> will use the hostname and port number instead. + +Default: none. + +=item B<--header> or B<--noheader> + +Specify if you want the header to display or not. You can toggle this +with the B<h> key while B<mytop> is running. + +Default: header. + +=item B<--color> or B<--nocolor> + +Specify if you want a color display. This has no effect if you don't +have color support available. + +Default: If you have color support, B<mytop> will try color unless you +tell it not to. + +=item B<-i> or B<--idle> or B<--noi> or B<--noidle> + +Specify if you want idle (sleeping) threads to appear in the list. If +sleeping threads are omitted, the default sorting order is reversed so +that the longest running queries appear at the top of the list. + +Default: idle. + +=item B<--prompt> or B<--noprompt> + +Specify if you want to be prompted to type in your database password. +This provides a little bit more security since it not only prevents +the password from viewable in a process list, but also doesn't require +the password to be stored in plain text in your C<~/.mytop> config file. +You will B<only> be prompted if a password has not been specified in +your config file or through another command line option. + +Default: noprompt. + +=item B<--resolve> + +If you have skip-resolve set on MariaDB (to keep it from doing a reverse +DNS lookup on each inbound connection), mytop can replace IP addresses +with hostnames but toggling this option. + +Default: noresolve + +=item B<--long> or B<--nolong> + +For large numbers print all digits (e.g. 10.000) instead of using a more +compact approximation (e.g. 10.0k). + +Default: nolong. + +=item B<-m> or B<--mode> I<mode> + +Specify initial mode B<qps>(queries/second), B<top>(overview), +B<cmd>(command summary), B<innodb>(InnoDB status) or B<status>(). + +Default: B<top> + +=item B<--sort> or B<--nosort> + +Reverse sort order from ascending to descending using Idle time. + +Default: nosort. + + +=back + +Command-line arguments will always take precedence over config file +options. That happens because the config file is read I<BEFORE> the +command-line arguments are applied. + +=head2 Config File + +Instead of always using bulky command-line parameters, you can also +use a config files for the default value of your options. + +mytop will first read the [client] and [mytop] sections from your +my.cnf files. After that it will read the (C<~/.mytop>) file from your +home directory (if present). These are read I<before> any of your +command-line arguments are processed, so your command-line arguments +will override directives in the config file. + + +Here is a sample config file C<~/.mytop> which implements the defaults +described above. + + user=root + pass= + host=localhost + db=test + delay=5 + port=3306 + slow=10 + socket= + batchmode=0 + header=1 + color=1 + idle=1 + long=120 + +Using a config file will help to ensure that your database password +isn't visible to users on the command-line. Just make sure that the +permissions on C<~/.mytop> are such that others cannot read it (unless +you want them to, of course). + +You may have white space on either side of the C<=> in lines of the +config file. + +=head2 Shortcut Keys + +The following keys perform various actions while B<mytop> is +running. Those which have not been implemented are listed as +such. They are included to give the user idea of what is coming. + +=over + +=item B<?> + +Display help. + +=item B<c> + +Show "command counters" based on the Com_* values in SHOW STATUS. +This is a new feature. Feedback welcome. + +=item B<C> + +Turn display color on and off. Default is on. + +=item B<d> + +Show only threads connected to a particular database. + +=item B<f> + +Given a thread id, display the entire query that thread was (and still +may be) running. + +=item B<F> + +Disable all filtering (host, user, and db). + +=item B<h> + +Only show queries from a particular host. + +=item B<H> + +Toggle the header display. You can also specify either C<header=0> or +C<header=1> in your config file to set the default behavior. + +=item B<i> + +Toggle the display of idle (sleeping) threads. If sleeping threads are +filtered, the default sorting order is reversed so that the longest +running queries appear at the top of the list. + +=item B<I> + +Switch to InnoDB Status mode. The output of "SHOW ENGINE INNODB STATUS" will +be displayed every cycle. In a future version, this may actually +summarize that data rather than producing raw output. + +=item B<k> + +Kill a thread. + +=item B<m> + +Toggle modes. Currently this switches from `top' mode to `qps' +(Queries Per Second Mode). In this mode, mytop will write out one +integer per second. The number written reflects the number of queries +executed by the server in the previous one second interval. + +More modes may be added in the future. + +=item B<o> + +Reverse the default sort order. + +=item B<p> + +Pause display. + +=item B<q> + +Quit B<mytop> + +=item B<r> + +Reset the server's status counters via a I<FLUSH STATUS> command. + +=item B<R> + +Togle IP reverse lookup. Default is on. + +=item B<s> + +Change the sleep time (number of seconds between display refreshes). + +=item B<S> + +Set the number of seconds a query will need to run before it is +considered old and will be highlighted. + +=item B<u> + +Show only threads owned by a giver user. + +=back + +The B<s> key has a command-line counterpart: B<-s>. + +The B<h> key has two command-line counterparts: B<--header> and +B<--noheader>. + +=head1 BUGS + +This is more of a BUGS + WishList. + +Some performance information is not available when talking to a +version 3.22.x MySQL server. Additional information (about threads +mostly) was added to the output of I<SHOW STATUS> in MySQL 3.23.x and +B<mytop> makes use of it. If the information is not available, you +will simply see zeros where the real numbers should be. + +Simply running this program will increase your overall counters (such +as the number of queries run). But you may or may not view that as a +bug. + +B<mytop> consumes too much CPU time when running (verified on older +versions of Linux and FreeBSD). It's likely a problem related to +Term::ReadKey. I haven't had time to investigate yet, so B<mytop> now +automatically lowers its priority when you run it. You may also think +about running B<mytop> on another workstation instead of your database +server. However, C<mytop> on Solaris does B<not> have this problem. +Newer versions of Linux and FreeBSD seem to have fixed this. + +You can't specify the maximum number of threads to list. If you have +many threads and a tall xterm, B<mytop> will always try to display as +many as it can fit. + +The size of most of the columns in the display has a small maximum +width. If you have fairly long database/user/host names the display +may appear odd. I have no good idea as to how best to deal with that +yet. Suggestions are welcome. + +It'd be nice if you could just add B<mytop> configuration directives +in your C<my.cnf> file instead of having a separate config file. + +You should be able to specify the columns you'd like to see in the +display and the order in which they appear. If you only have one +username that connects to your database, it's probably not worth +having the User column appear, for example. + +=head1 AUTHOR + +mytop was developed and is maintained by Jeremy D. Zawodny +(Jeremy@Zawodny.com). + +If you wish to e-mail me regarding this software, B<PLEASE> subscribe +to the B<mytop> mailing list. See the B<mytop> homepage for details. + +=head1 DISCLAIMER + +While I use this software in my job at Yahoo!, I am solely responsible +for it. Yahoo! does not necessarily support this software in any +way. It is merely a personal idea which happened to be very useful in +my job. + +=head1 SEE ALSO + +Please check the MariaDB manual if you're not sure where some of the +output of B<mytop> is coming from. + +=head1 COPYRIGHT + +Copyright (C) 2000-2010, Jeremy D. Zawodny. + +=head1 CREDITS + +Fix a bug. Add a feature. See your name here! + +Many thanks go to these fine folks: + +=over + +=item Jean Weisbuch (jean@phpnet.org) + +Added --fullqueries and --sort options, dynamic user and database columns +width, reading of .my.cnf, state/progress column that can be disabled +dynamically (when available) and various small fixes. + +=item Michael "Monty" Widenius <monty@askmonty.org> + +Fixed a couple of minor bugs that gave warnings on startup. +Added support for MariaDB (show MariaDB at top and % done). +Cut long server version names to display width. +Made 'State' length dynamic. + +=item Mark Grennan (mark@grennan.com) www.linuxfangoy.com + +Added updates for MySQL 5.x. Added 'S' (slow) highlighting. +Added 'C' to turn on and off Color. Added 'l' command to change +color for long running queries. Fixed a few documentation issues. +Monitors Slave status. Added color to Queue hit ratio. +Added number of rows sorted per second. +Created release 1.7. + +=item Sami Ahlroos (sami@avis-net.de) + +Suggested the idle/noidle stuff. + +=item Jan Willamowius (jan@janhh.shnet.org) + +Minor bug report. Documentation fixes. + +=item Alex Osipov (alex@acky.net) + +Long command-line options, Unix socket support. + +=item Stephane Enten (tuf@grolier.fr) + +Suggested batch mode. + +=item Richard Ellerbrock (richarde@eskom.co.za) + +Bug reports and usability suggestions. + +=item William R. Mattil (wrm@newton.irngtx.tel.gte.com) + +Bug report about empty passwords not working. + +=item Benjamin Pflugmann (philemon@spin.de) + +Suggested -P command-line flag as well as other changes. + +=item Justin Mecham <justin@aspect.net> + +Suggested setting $0 to `mytop'. + +=item Thorsten Kunz <thorsten.kunz@de.tiscali.com> + +Provided a fix for cases when we try remove the domain name from the +display even if it is actually an IP address. + +=item Sasha Pachev <sasha@mysql.com> + +Provided the idea of real-time queries per second in the main display. + +=item Paul DuBois <paul@snake.net> + +Pointed out some option-handling bugs. + +=item Mike Wexler <mwexler@tias.com> + +Suggested that we don't mangle (normalize) whitespace in query info by +default. + +=item Mark Zweifel <markez@yahoo-inc.com> + +Make the --idle command-line argument negatable. + +=item Axel Schwenke <schwenke@jobpilot.de> + +Noticed the incorrect formula for query cache hit percentages in +version 1.2. + +=item Steven Roussey <sroussey@network54.com> + +Supplied a patch to help filter binary junk in queries so that +terminals don't freak out. + +=item Jon R. Luini <falcon@chime.com> + +Supplied a patch that formed the basis for C<--prompt> support. +Sean Leach <sleach@wiggum.com> submitted a similar patch. + +=item Yogish Baliga <baliga@yahoo-inc.com> + +Supplied a patch that formed the basis for C<--resolve> support. + +=item Per Andreas Buer <perbu@linpro.no> + +Supplied an excellent patch to tidy up the top display. This includes +showing most values in short form, such as 10k rather than 10000. + +=back + +See the Changes file on the B<mytop> distribution page for more +details on what has changed. + +=head1 LICENSE + +B<mytop> is licensed under the GNU General Public License version +2. For the full license information, please visit +http://www.gnu.org/copyleft/gpl.html + +=cut + +__END__ diff --git a/scripts/sys_schema/CMakeLists.txt b/scripts/sys_schema/CMakeLists.txt new file mode 100644 index 00000000..ccb268cc --- /dev/null +++ b/scripts/sys_schema/CMakeLists.txt @@ -0,0 +1,177 @@ +IF(TARGET perfschema) +SET(files +${CMAKE_CURRENT_SOURCE_DIR}/before_setup.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/version.sql +${CMAKE_CURRENT_SOURCE_DIR}/tables/sys_config.sql +${CMAKE_CURRENT_SOURCE_DIR}/tables/sys_config_data_57.sql +${CMAKE_CURRENT_SOURCE_DIR}/triggers/sys_config_insert_set_user.sql +${CMAKE_CURRENT_SOURCE_DIR}/triggers/sys_config_update_set_user.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/extract_schema_from_file_name.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/extract_table_from_file_name.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/format_bytes.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/format_path_57.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/format_statement.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/format_time.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/list_add.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/list_drop.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/ps_is_account_enabled.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/ps_is_consumer_enabled.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/ps_is_instrument_default_enabled.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/ps_is_instrument_default_timed.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/ps_is_thread_instrumented.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/ps_thread_id.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/ps_thread_account.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/ps_thread_stack.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/ps_thread_trx_info.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/quote_identifier.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/sys_get_config.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/version_major.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/version_minor.sql +${CMAKE_CURRENT_SOURCE_DIR}/functions/version_patch.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/i_s/innodb_buffer_stats_by_schema.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/i_s/x_innodb_buffer_stats_by_schema.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/i_s/innodb_buffer_stats_by_table.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/i_s/x_innodb_buffer_stats_by_table.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/i_s/innodb_lock_waits.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/i_s/x_innodb_lock_waits.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/i_s/schema_object_overview.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/i_s/schema_auto_increment_columns.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/i_s/x_schema_flattened_keys.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/i_s/schema_redundant_indexes.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/ps_check_lost_instrumentation_57.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/latest_file_io.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_latest_file_io.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/io_by_thread_by_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_io_by_thread_by_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/io_global_by_file_by_bytes.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_io_global_by_file_by_bytes.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/io_global_by_file_by_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_io_global_by_file_by_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/io_global_by_wait_by_bytes.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_io_global_by_wait_by_bytes.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/io_global_by_wait_by_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_io_global_by_wait_by_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/memory_by_user_by_current_bytes.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_memory_by_user_by_current_bytes.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/memory_by_host_by_current_bytes.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_memory_by_host_by_current_bytes.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/memory_by_thread_by_current_bytes.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_memory_by_thread_by_current_bytes.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/memory_global_by_current_bytes.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_memory_global_by_current_bytes.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/memory_global_total.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_memory_global_total.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/schema_index_statistics.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_schema_index_statistics.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_ps_schema_table_statistics_io.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/schema_table_statistics.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_schema_table_statistics.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/schema_table_statistics_with_buffer.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_schema_table_statistics_with_buffer.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/schema_tables_with_full_table_scans.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_schema_tables_with_full_table_scans.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/schema_unused_indexes.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/schema_table_lock_waits.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_schema_table_lock_waits.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/statement_analysis.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_statement_analysis.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/statements_with_errors_or_warnings.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_statements_with_errors_or_warnings.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/statements_with_full_table_scans.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_statements_with_full_table_scans.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_ps_digest_avg_latency_distribution.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_ps_digest_95th_percentile_by_avg_us.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/statements_with_runtimes_in_95th_percentile.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_statements_with_runtimes_in_95th_percentile.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/statements_with_sorting.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_statements_with_sorting.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/statements_with_temp_tables.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_statements_with_temp_tables.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/user_summary_by_file_io_type.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_user_summary_by_file_io_type.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/user_summary_by_file_io.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_user_summary_by_file_io.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/user_summary_by_statement_type.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_user_summary_by_statement_type.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/user_summary_by_statement_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_user_summary_by_statement_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/user_summary_by_stages.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_user_summary_by_stages.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/user_summary_57.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_user_summary_57.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/host_summary_by_file_io_type.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_host_summary_by_file_io_type.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/host_summary_by_file_io.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_host_summary_by_file_io.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/host_summary_by_statement_type.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_host_summary_by_statement_type.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/host_summary_by_statement_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_host_summary_by_statement_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/host_summary_by_stages.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_host_summary_by_stages.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/host_summary_57.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_host_summary_57.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/wait_classes_global_by_avg_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_wait_classes_global_by_avg_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/wait_classes_global_by_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_wait_classes_global_by_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/waits_by_user_by_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_waits_by_user_by_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/waits_by_host_by_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_waits_by_host_by_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/waits_global_by_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_waits_global_by_latency.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/metrics.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/processlist_57.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_processlist_57.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/sessions.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/x_sessions.sql +${CMAKE_CURRENT_SOURCE_DIR}/views/p_s/session_ssl_status.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/create_synonym_db.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/execute_prepared_stmt.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/diagnostics.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_statement_avg_latency_histogram.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_trace_statement_digest.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_trace_thread.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_disable_background_threads.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_disable_consumer.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_disable_instrument.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_disable_thread.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_enable_background_threads.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_enable_consumer.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_enable_instrument.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_enable_thread.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_reload_saved.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_reset_to_default_57_before.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_reset_to_default_57.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_reset_to_default_57_after.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_save.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_show_disabled.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_show_disabled_consumers.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_show_disabled_instruments.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_show_enabled.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_show_enabled_consumers.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_setup_show_enabled_instruments.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/ps_truncate_all_tables.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/statement_performance_analyzer.sql +${CMAKE_CURRENT_SOURCE_DIR}/procedures/table_exists.sql +${CMAKE_CURRENT_SOURCE_DIR}/after_setup.sql +) +ELSE() +SET(files + ${CMAKE_CURRENT_SOURCE_DIR}/before_setup.sql + ${CMAKE_CURRENT_SOURCE_DIR}/tables/sys_config.sql + ${CMAKE_CURRENT_SOURCE_DIR}/tables/sys_config_data_57.sql + ${CMAKE_CURRENT_SOURCE_DIR}/triggers/sys_config_insert_set_user.sql + ${CMAKE_CURRENT_SOURCE_DIR}/triggers/sys_config_update_set_user.sql + ${CMAKE_CURRENT_SOURCE_DIR}/after_setup.sql) +ENDIF() + +SET_PROPERTY(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${files}) +SET(CMAKE_CONFIGURABLE_FILE_CONTENT) + +FOREACH(f ${files}) + FILE(READ ${f} content) + SET(CMAKE_CONFIGURABLE_FILE_CONTENT "${CMAKE_CONFIGURABLE_FILE_CONTENT}${content}\n") +ENDFOREACH() +CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/cmake/configurable_file_content.in ${CMAKE_BINARY_DIR}/scripts/mysql_sys_schema.sql) diff --git a/scripts/sys_schema/COPYING b/scripts/sys_schema/COPYING new file mode 100644 index 00000000..d511905c --- /dev/null +++ b/scripts/sys_schema/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/scripts/sys_schema/LICENSE b/scripts/sys_schema/LICENSE new file mode 100644 index 00000000..a98b6b45 --- /dev/null +++ b/scripts/sys_schema/LICENSE @@ -0,0 +1,14 @@ +Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/scripts/sys_schema/NEWS.md b/scripts/sys_schema/NEWS.md new file mode 100644 index 00000000..7aeefb7e --- /dev/null +++ b/scripts/sys_schema/NEWS.md @@ -0,0 +1,218 @@ +# Change history for the MySQL sys schema + +## 1.5.1 (07/07/16) + +### Improvements + +* A `quote_identifier` function was added, which can be used to properly backtick identifier names +* The `Tls_version` column was added to the output from the `mysql.slave_master_info` table, from the `diagnostics` procedure (backported from 5.7 upstream change) + +### Bug Fixes + +* MySQL Bug #77853 / Oracle Bug #21512106 - The `format_path` function did not consider directory boundaries when comparing variables to paths - it now does. Also fixed to no longer translate backslashes within Windows paths to forward slash +* Oracle Bug #21663578 - Fixed an instability within the sysschema.v_schema_tables_with_full_table_scans test +* Oracle Bug #21970078 - The host_summary view could fail with a division by zero error +* MySQL Bug #78874 / Oracle Bug #22066096 - The `ps_setup_show_enabled` procedure showed all rows for the `performance_schema.setup_objects` table, rather than only those that are enabled +* MySQL Bug #80569 / Oracle Bug #22848110 - The `max_latency` column for the `host_summary_by_statement_latency` view incorrectly showed the SUM of latency +* MySQL Bug #80833 / Oracle Bug #22988461 - The `pages_hashed` and `pages_old` columns within the `innodb_buffer_stats_by_schema` and `innodb_buffer_stats_by_table` views were calculated incorrectly (**Contributed by Tsubasa Tanaka**) +* MySQL Bug #78823 / Oracle Bug #22011361 - The `create_synonym_db` procedure failed when using reserved words as the synonym name (this change also introduced the `quote_identifier` function mentioned above **Contriubuted by Paul Dubois**) +* MySQL Bug #81564 / Oracle Bug #23335880 - The `ps_setup_show_enabled` and `ps_setup_show_disabled` procedures were fixed to: +** Show `user@host` instead of `host@user` for accounts +** Fixed the column header for `disabled_users` within `ps_setup_show_disabled` +** Explicitly ordered all output for test stability +** Show disabled users for 5.7.6+ +* Oracle Bug #21970806 - The `sysschema.fn_ps_thread_trx_info` test was unstable +* Oracle Bug #23621189 - The `ps_trace_statement_digest` procedure ran EXPLAIN incorrectly in certain cases (such as on a SHOW statement, no query being specified, or not having a full qualified table), the procedure now catches these issues and ignores them + +## 1.5.0 (11/09/15) + +### Improvements + +* The `format_bytes` function now shows no decimal places when outputting a simple bytes value +* The `processlist`/`x$processlist` views where improved, changes include: + * The `pid` and `program_name` of the connection are shown, if set within the `performance_schema.session_connect_attrs` table (**Contributed by Daniël van Eeden**) + * Issue #50 - The current statement progress is reported via the new stage progress reporting within Performance Schema stages within 5.7 (such as ALTER TABLE progress reporting) + * Issue #60 - A new `statement_latency` column was added to all versions, which reports the current statement latency with picosecond precision from the `performance_schema.events_statements_current` table, when enabled + * Some transaction information was exposed, with the `trx_latency` (for the current or last transaction depending on `trx_state`), `trx_state` (ACTIVE, COMMITTED, ROLLED BACK), and `trx_autocommit` (YES/NO) columns +* A new `metrics` view has been added. On 5.7 this provides a union view of the performance_schema.global_status and information_schema.innodb_metrics tables, along with P_S memory and the current time, as a single metrics output. On 5.6 it provides a union view of the information_schema.global_status and information_schema.innodb_metrics tables, along with the current time. (**Contributed by Jesper Wisborg Krogh**) +* New `session`/`x$session` views have been added, which give the same output as the `processlist` view counterparts, but filtered to only show foreground connections (**Contributed by Morgan Tocker**) +* A new `session_ssl_status` view was added, which shows the SSL version, ciper and session resuse statistics for each connection (**Contributed by Daniël van Eeden**) +* A new `schema_auto_increment_columns` view was added, that shows statistics on each auto_incrment within the instance, including the `auto_increment_ratio`, so you can easily monitor how full specific auto_increment columns are (**Contributed by Shlomi Noach**) +* A new `schema_redundant_indexes` view was added, that shows indexes made redundant (or duplicated) by other more dominant indexes. Also includes the the helper view `x$schema_flattened_keys`. (**Contributed by Shlomi Noach**) +* New `schema_table_lock_waits`/`x$schema_table_lock_waits` views have been added, which show any sessions that are waiting for table level metadata locks, and the sessions that are blocking them. Resolves Git Issue #57, inspired by the suggestion from Daniël van Eeden +* The `innodb_lock_waits` view had the following columns added to it, following a manually merged contribution from Shlomi Noach for a similar view + * `wait_age_secs` - the current row lock wait time in seconds + * `sql_kill_blocking_query` - the "KILL QUERY <connection_id>" command to run to kill the blocking session current statement + * `sql_kill_blocking_connection` - the "KILL <connection_id" command to run to kill the blocking session +* A new `table_exists` procedure was added, which checks for the existence of table, and if it exists, returns the type (BASE TABLE, VIEW, TEMPORARY) (**Contributed by Jesper Wisborg Krogh**) +* A new `execute_prepared_stmt()` procedure was added, which takes a SQL statement as an input variable and executes it as a prepared statement (**Contributed by Jesper Wisborg Krogh**) +* A new `statement_performance_analyzer()` procedure was added, that allows reporting on the statements that are have been running over snapshot periods (**Contributed by Jesper Wisborg Krogh**) +* A new `diagnostics()` procedure was added, which creates a large diagnostics report based upon most of the new instrumentation now available, computed over a configurable number of snapshot intervals (**Contributed by Jesper Wisborg Krogh**) +* A 5.7 specific `ps_trace_thread()` procedure was added, which now shows the hierarchy of transactions and stored routines, as well as statements, stages and waits, if enabled +* Added a new `ps_thread_account()` stored function, that returns the "user@host" account for a given Performance Schema thread id +* Added a new `ps_thread_trx_info()` stored function which outputs, for a given thread id, the transactions, and statements that those transactions have executed, as a JSON object +* Added new `list_add()` and `list_drop()` stored functions, that take a string csv list, and either add or remove items from that list respectively. Can be used to easily update variables that take such lists, like `sql_mode`. +* The `ps_thread_id` stored function now returns the thread id for the current connection if NULL is passed for the in_connection_id parameter +* Added a new `version_major()` stored function, which returns the major version of MySQL Server (**Contributed by Jesper Wisborg Krogh**) +* Added a new `version_minor()` stored function, which returns the minor (release series) version of MySQL Server (**Contributed by Jesper Wisborg Krogh**) +* Added a new `version_patch()` stored function, which returns the patch release version of MySQL Server (**Contributed by Jesper Wisborg Krogh**) +* The `ps_is_account_enabled` function was updated to take a VARCHAR(32) user input on 5.7, as a part of WL#2284 +* The generate_sql_file.sh script had a number of improvements: + * Generated files are now output in to a "gen" directory, that is ignored by git + * Added using a new default "mysql.sys@localhost" user (that has the account locked) for the MySQL 5.7+ integration as the DEFINER for all objects + * Added a warning to the top of the generated integration file to also submit changes to the sys project + * Improved the the option of skipping binary logs, so that all routines can load as well - those that used SET sql_log_bin will now select a warning when being used instead of setting the option + +### Bug Fixes + +* Git Issue #51 - Fixed the `generate_sql_file.sh` script to also replace the definer in the before_setup.sql output +* Git Issue #52 - Removed apostrophe from the `format_statement` function comment because TOAD no likey +* Git Issue #56 - Installation failed on 5.6 with ONLY_FULL_GROUP_BY enabled +* Git Issue #76 - Fixes for the new show_compatibility_56 variable. 5.7 versions of the `format_path()` function and `ps_check_lost_instrumentation` view were added, that use performance_schema.global_status/global_variables instead of information_schema.global_status/global_variables +* Git Issue #79 - Fixed grammar within `statements_with_runtimes_in_95th_percentile` view descriptions +* Oracle Bug #21484593 / Oracle Bug #21281955 - The `format_path()` function incorrectly took and returned a VARCHAR(260) instead of VARCHAR(512) (as the underlying is exposed as in Performance Schema) causing sporadic test failures +* Oracle Bug #21550271 - Fixed the `ps_setup_reset_to_default` for 5.7 with the addition of the new `history` column on the `performance_schema.setup_actors` table +* Oracle Bug #21550054 - It is possible that the views can show data that overflows when aggregating very large values, reset all statistics before each test to ensure no overflows +* Oracle Bug #21647101 - Fixed the `ps_is_instrument_default_enabed` and `ps_is_instrument_default_timed` to take in to account the new instruments added within 5.7 +* MySQL Bug #77848 - Added the missing ps_setup_instruments_cleanup.inc +* Fixed the `ps_setup_reset_to_default()` procedure to also set the new `ENABLED` column within `performance_schema.setup_actors` within 5.7 +* The `user_summary_by_file_io`/`x$user_summary_by_file_io` and `host_summary_by_file_io`/`x$host_summary_by_file_io` tables were incorrectly aggregating all wait events, not just `wait/io/file/%` + +### Implementation Details + +* Tests were improved via 5.7 integration +* Template files were added for stored procedures and functions +* Improved the sys_config_cleanup.inc procedure in tests to be able to reset the sys_config table completely (including the set_by column to NULL). The triggers can now be set to not update the column by setting the @sys.ignore_sys_config_triggers user variable to true + +## 1.4.0 (09/03/2015) + +### Backwards Incompatible Changes + +* The `memory_global_by_current_allocated` views were renamed to `memory_global_by_current_bytes` for consistency with the other memory views +* The `ps_setup_enable_consumers` procedure was renamed to `ps_setup_disable_consumer` for naming consistency (everything is now singular, not plural) +* The `format_time` function displayed values in minutes incorrectly, it now rounds to minutes, and uses an 'm' suffix, like the rest of the units + +### Improvements + +* The beginnings of a mysql-test suite have been added +* The `innodb_lock_waits`/`x$innodb_lock_waits` views were improved (**Contributions by both Jesper Wisborg Krogh and Mark Matthews**) + * Added the `wait_started`, `wait_age`, `waiting_trx_started` `waiting_trx_age`, `waiting_trx_rows_locked` and `waiting_trx_rows_modified` columns for waiting transactions + * Added the `blocking_trx_started`, `blocking_trx_age`, `blocking_trx_rows_locked` and `blocking_trx_rows_modified` for blocking transactions + * Order the result set so the oldest lock waits are first + * The `waiting_table` and `waiting_index` were always the same as the `blocking_table` and `blocking_index`. So the blocking_% columns have been removed and the waiting_% columns have been renamed to locked_% + * The `waiting_lock_type` and `blocking_lock_type` were also always the same. So these were removed and replaced with a single `locked_type` column + * Renamed the `waiting_thread` and `blocking_thread` to `waiting_pid` and `blocking_pid` respectively to avoid confusion with the threads from the Performance Schema. +* Added the `sys_get_config` function, used to get configuration parameters from the `sys_config` table - primarily from other sys objects, but can be used individually (**Contributed by Jesper Wisborg Krogh**) +* Add an option to generate_sql_file.sh to generate a mysql_install_db / mysqld --initialize format friendly file +* Added the `ps_is_thread_instrumented` function, to check whether a specified thread is instrumented within Performance Schema +* Added the `ps_is_consumer_enabled` function, to check whether a specified consumer is enabled within Performance Schema (**Contributed by Jesper Wisborg Krogh**) +* Added some further replacements to the `format_path` function (`slave_load_tmpdir`, `innodb_data_home_dir`, `innodb_log_group_home_dir` and `innodb_undo_directory`) + +### Bug Fixes + +* The 5.6 `host_summary` and `x$host_summary` views incorrectly had the column with `COUNT(DISTINCT accounts.user)` named `unique_hosts` instead of `unique_users` (**Contributed by Jesper Wisborg Krogh**) +* Both the `format_time` and `format_bytes` took a BIGINT as input, and output VARCHAR, but BIGINT could be too small for aggregated values for the inputs. Now both functions both use TEXT as their input (Issue #34, Issue #38) +* The `format_time` function displayed values in minutes incorrectly, it now rounds to minutes, and uses an 'm' suffix, like the rest of the units +* The `sys_config` related triggers had no DEFINER clause set +* The `ps_setup_disable_thread` procedure always disabled the current thread and was ignoring the connection id given as an argument (**Contributed by Jesper Wisborg Krogh**) +* The `ps_trace_thread` procedure had an incorrect calculation of how long the procedure has been running (**Contributed by Jesper Wisborg Krogh**) + +### Implementation Details + +Various changes were made to allow better generation of integration sql files: + +* The formatting for all comments has been standardized on -- line comments. C-style /* comments */ have been removed + * Issue #35 had one instance of this resolved in this release (**Contributed by Joe Grasse**), but the entire code base has now been done +* Each object has been created within it's own file. No longer do x$ views live with their non-x$ counterparts +* DELIMITERs were standardized to $$ + +## 1.3.0 (23/10/2014) + +### Improvements + +* Added an `innodb_lock_waits` set of views, showing each thread that is waiting on a lock within InnoDB, and the blocking thread lock information (**Contributed by Jesper Wisborg Krogh**) + +### Bug Fixes + +* Fixed broken `host_summary_by_stages` views, broken with a last minute change before the 1.2.0 release that went unnoticed (facepalm) + +## 1.2.0 (22/10/2014) + +### Backwards Incompatible Changes + +* The `host_summary_by_stages` and `user_summary_by_stages` `wait_sum` and `wait_avg` columns were renamed to `total_latency` and `avg_latency` respectively, for consistency. +* The `host_summary_by_file_io_type` and `user_summary_by_file_io_type `latency` column was renamed to `total_latency`, for consistency. + +### Improvements + +* Made the truncation length for the `format_statement` view configurable + * This includes adding a new persistent `sys_config` table to store the new variable - `statement_truncate_len` - see the README for usage +* Added `total_latency` to the `schema_tables_with_full_table_scans` view, and added an x$ counterpart +* Added `innodb_buffer_free` to the `schema_table_statistics_with_buffer` view, to summarize how much free space is allocated per table in the buffer pool +* The `schema_unused_indexes` view now ignores indexes named `PRIMARY` (primary keys) +* Added `rows_affected` and `rows_affected_avg` stats to the `statement_analysis` views +* The `statements_with_full_table_scans` view now ignores any SQL that starts with `SHOW` +* Added a script, `generate_sql_file.sh`, that can be used to generate a single SQL file, also allowing substitution of the MySQL user to use, and/or whether the `SET sql_log_bin ...` statements should be omitted. + * This is useful for those using RDS, where the root@localhost user is not accessible, and sql_log_bin is disabled (Issue #5) +* Added a set of `memory_by_thread_by_current_bytes` views, that summarize memory usage per thread with MySQL 5.7's memory instrumentation +* Improved each of the host specific views to return aggregate values for `background` threads, instead of ignoring them, in the same way as the user summary views + +### Bug Fixes + +* Added the missing `memory_by_host` view for MySQL 5.7 +* Added missing space for hour notation within the `format_time` function +* Fixed views affected by MySQL 5.7 ONLY_FULL_GROUP_BY and functional dependency changes + +## 1.1.0 (04/09/2014) + +### Improvements + +* Added host summary views, which have the same structure as the user summary views, but aggregated by host instead (**Contributed by Arnaud Adant**) + * `host_summary` + * `host_summary_by_file_io_type` + * `host_summary_by_file_io` + * `host_summary_by_statement_type` + * `host_summary_by_statement_latency` + * `host_summary_by_stages` + * `waits_by_host_by_latency` + +* Added functions which return instruments are either enabled, or timed by default (#15) (**Contributed by Jesper Wisborg Krogh**) + * `ps_is_instrument_default_enabled` + * `ps_is_instrument_default_timed` + +* Added a `ps_thread_id` function, which returns the thread_id value exposed within performance_schema for the current connection (**Contributed by Jesper Wisborg Krogh**) +* Improved each of the user specific views to return aggregate values for `background` threads, instead of ignoring them (**Contributed by Joe Grasse**) +* Optimized the `schema_table_statistics` and `schema_table_statistics_with_buffer` views, to use a new view that will get materialized (`x$ps_schema_table_statistics_io`), along with the changes to the RETURN types for `extract_schema_from_file_name` and `extract_table_from_file_name`, this results in a significant performance improvement - in one test changing the run time from 14 minutes to 20 seconds. (**Conceived by Roy Lyseng, Mark Leith and Jesper Wisborg Krogh, implemented and contributed by Jesper Wisborg Krogh**) + +### Bug Fixes + +* Removed unintentially committed sys_56_rds.sql file (See Issue #5, which is still outstanding) +* Fixed the `ps_trace_statement_digest` and `ps_trace_thread` procedures to properly set sql_log_bin, and reset the thread INSTRUMENTED value correctly (**Contributed by Jesper Wisborg Krogh**) +* Removed various sql_log_bin disabling from other procedures that no longer require it - DML against the performance_schema data is no longer replicated (**Contributed by Jesper Wisborg Krogh**) +* Fixed EXPLAIN within `ps_trace_statement_digest` procedure (**Contributed by Jesper Wisborg Krogh**) +* Fixed the datatype for the `thd_id` variable within the `ps_thread_stack` procedure (**Contributed by Jesper Wisborg Krogh**) +* Fixed datatypes used for temporary tables within the `ps_trace_statement_digest` procedure (**Contributed by Jesper Wisborg Krogh**) +* Fixed the RETURN datatype `extract_schema_from_file_name` and `extract_table_from_file_name` to return a VARCHAR(64) (**Contributed by Jesper Wisborg Krogh**) +* Added events_transactions_current to the default enabled consumers in 5.7 (#25) + +## 1.0.1 (23/05/2014) + +### Improvements + +* Added procedures to enable / disable Performance Schema consumers. (**Contributed by the MySQL QA Team**) + * `ps_setup_disable_consumers(<LIKE string>)` allows disabling any consumers matching the LIKE string. + * `ps_setup_enable_consumers(<LIKE string>)` allows enabling any consumers matching the LIKE string. + +* Added procedures to show both enabled and disbled consumers or instruments individually, these are more useful for tooling than the `ps_setup_show_enabled`/`ps_setup_show_disabled` procedures which show all configuration in multiple result sets. (**Contributed by the MySQL QA Team**) + * `ps_setup_show_disabled_consumers` shows only disabled consumers. + * `ps_setup_show_disabled_instruments` shows only disabled instruments. + * `ps_setup_show_enabled_consumers` shows only enabled consumers. + * `ps_setup_show_enabled_instruments` shows only enabled instruments. + +### Bug Fixes + +* Running the installation scripts sometimes failed because of the comment format. (#1) (**Contributed by Joe Grasse**) +* Some views did not work with the ERROR_FOR_DIVISION_BY_ZERO SQL mode. (#6) (**Contributed by Joe Grasse**) +* On Windows the `ps_thread_stack()` stored function failed to escape file path backslashes correctly within the JSON output. + +## 1.0.0 (11/04/2014) diff --git a/scripts/sys_schema/README.md b/scripts/sys_schema/README.md new file mode 100644 index 00000000..3c90f41f --- /dev/null +++ b/scripts/sys_schema/README.md @@ -0,0 +1,5438 @@ +# The MySQL sys schema + +A collection of views, functions and procedures to help MySQL administrators get insight in to MySQL Database usage. + +There are install files available for 5.6 and 5.7 respectively. To load these, you must position yourself within the directory that you downloaded to, as these top level files SOURCE individual files that are shared across versions in most cases (though not all). + +## Overview of objects + +### Tables + +#### sys_config + +##### Description + +Holds configuration options for the sys schema. This is a persistent table, with the configuration persisting across upgrades (new options are added with `INSERT IGNORE`). + +Its structure is as follows: + +```SQL ++----------+--------------+------+-----+-------------------+-----------------------------+ +| Field | Type | Null | Key | Default | Extra | ++----------+--------------+------+-----+-------------------+-----------------------------+ +| variable | varchar(128) | NO | PRI | NULL | | +| value | varchar(128) | YES | | NULL | | +| set_time | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | +| set_by | varchar(128) | YES | | NULL | | ++----------+--------------+------+-----+-------------------+-----------------------------+ +``` + +Note, when functions check for configuration options, they first check whether a similar named user variable exists with a value, and if this is not set then pull the configuration option from this table in to that named user variable. This is done for performance reasons (to not continually `SELECT` from the table), however this comes with the side effect that once inited, the values last with the session, somewhat like how session variables are inited from global variables. If the values within this table are changed, they will not take effect until the user logs in again. + +##### Options included + +| Variable | Default Value | Description | +| ------------------------------------ | ------------- | ------------------------------------------------------------------------------ | +| statement_truncate_len | 64 | Sets the size to truncate statements to, for the `format_statement()` function. | +| statement_performance_analyzer.limit | 100 | The maximum number of rows to include for the views that does not have a built-in limit (e.g. the 95th percentile view). If not set the limit is 100. | +| statement_performance_analyzer.view | NULL | Used together with the 'custom' view. If the value contains a space, it is considered a query, otherwise it must be an existing view querying the performance_schema.events_statements_summary_by_digest table. | +| diagnostics.allow_i_s_tables | OFF | Specifies whether it is allowed to do table scan queries on information_schema.TABLES for the `diagnostics` procedure. | +| diagnostics.include_raw | OFF | Set to 'ON' to include the raw data (e.g. the original output of "SELECT * FROM sys.metrics") for the `diagnostics` procedure.| +| ps_thread_trx_info.max_length | 65535 | Sets the maximum output length for JSON object output by the `ps_thread_trx_info()` function. | + +### Views + +Many of the views in the sys schema have both a command line user friendly format output, as well as tooling friendly versions of any view that contains formatted output duplicated as an x$ table. + +The examples below show output for only the formatted views, and note where there is an x$ counterpart available. + +#### host_summary / x$host_summary + +##### Description + +Summarizes statement activity, file IO and connections by host. + +When the host found is NULL, it is assumed to be a "background" thread. + +##### Structures (5.7) + +```SQL +mysql> desc host_summary; ++------------------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------------------+---------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| statements | decimal(64,0) | YES | | NULL | | +| statement_latency | text | YES | | NULL | | +| statement_avg_latency | text | YES | | NULL | | +| table_scans | decimal(65,0) | YES | | NULL | | +| file_ios | decimal(64,0) | YES | | NULL | | +| file_io_latency | text | YES | | NULL | | +| current_connections | decimal(41,0) | YES | | NULL | | +| total_connections | decimal(41,0) | YES | | NULL | | +| unique_users | bigint(21) | NO | | 0 | | +| current_memory | text | YES | | NULL | | +| total_memory_allocated | text | YES | | NULL | | ++------------------------+---------------+------+-----+---------+-------+ +12 rows in set (0.15 sec) + +mysql> desc x$host_summary; ++------------------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------------------+---------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| statements | decimal(64,0) | YES | | NULL | | +| statement_latency | decimal(64,0) | YES | | NULL | | +| statement_avg_latency | decimal(65,4) | YES | | NULL | | +| table_scans | decimal(65,0) | YES | | NULL | | +| file_ios | decimal(64,0) | YES | | NULL | | +| file_io_latency | decimal(64,0) | YES | | NULL | | +| current_connections | decimal(41,0) | YES | | NULL | | +| total_connections | decimal(41,0) | YES | | NULL | | +| unique_users | bigint(21) | NO | | 0 | | +| current_memory | decimal(63,0) | YES | | NULL | | +| total_memory_allocated | decimal(64,0) | YES | | NULL | | ++------------------------+---------------+------+-----+---------+-------+ +12 rows in set (0.00 sec) +``` + +##### Example + +```SQL + mysql> select * from host_summary; + +------+------------+-------------------+-----------------------+-------------+----------+-----------------+---------------------+-------------------+--------------+ + | host | statements | statement_latency | statement_avg_latency | table_scans | file_ios | file_io_latency | current_connections | total_connections | unique_users | + +------+------------+-------------------+-----------------------+-------------+----------+-----------------+---------------------+-------------------+--------------+ + | hal1 | 2924 | 00:03:59.53 | 81.92 ms | 82 | 54702 | 55.61 s | 1 | 1 | 1 | + +------+------------+-------------------+-----------------------+-------------+----------+-----------------+---------------------+-------------------+--------------+ +``` + +#### host_summary_by_file_io / x$host_summary_by_file_io + +##### Description + +Summarizes file IO totals per host. + +When the host found is NULL, it is assumed to be a "background" thread. + +##### Structures + +```SQL +mysql> desc host_summary_by_file_io; ++------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------+---------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| ios | decimal(42,0) | YES | | NULL | | +| io_latency | text | YES | | NULL | | ++------------+---------------+------+-----+---------+-------+ +3 rows in set (0.00 sec) + +mysql> desc x$host_summary_by_file_io; ++------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------+---------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| ios | decimal(42,0) | YES | | NULL | | +| io_latency | decimal(42,0) | YES | | NULL | | ++------------+---------------+------+-----+---------+-------+ +3 rows in set (0.06 sec) +``` + +##### Example + +```SQL + mysql> select * from host_summary_by_file_io; + +------------+-------+------------+ + | host | ios | io_latency | + +------------+-------+------------+ + | hal1 | 26457 | 21.58 s | + | hal2 | 1189 | 394.21 ms | + +------------+-------+------------+ +``` + +#### host_summary_by_file_io_type / x$host_summary_by_file_io_type + +##### Description + +Summarizes file IO by event type per host. + +When the host found is NULL, it is assumed to be a "background" thread. + +##### Structures + +```SQL +mysql> desc host_summary_by_file_io_type; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| event_name | varchar(128) | NO | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +5 rows in set (0.70 sec) + +mysql> desc x$host_summary_by_file_io_type; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| event_name | varchar(128) | NO | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| max_latency | bigint(20) unsigned | NO | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +5 rows in set (0.01 sec) +``` + +##### Example + +```SQL + mysql> select * from host_summary_by_file_io_type; + +------------+--------------------------------------+-------+---------------+-------------+ + | host | event_name | total | total_latency | max_latency | + +------------+--------------------------------------+-------+---------------+-------------+ + | hal1 | wait/io/file/sql/FRM | 871 | 168.15 ms | 18.48 ms | + | hal1 | wait/io/file/innodb/innodb_data_file | 173 | 129.56 ms | 34.09 ms | + | hal1 | wait/io/file/innodb/innodb_log_file | 20 | 77.53 ms | 60.66 ms | + | hal1 | wait/io/file/myisam/dfile | 40 | 6.54 ms | 4.58 ms | + | hal1 | wait/io/file/mysys/charset | 3 | 4.79 ms | 4.71 ms | + | hal1 | wait/io/file/myisam/kfile | 67 | 4.38 ms | 300.04 us | + | hal1 | wait/io/file/sql/ERRMSG | 5 | 2.72 ms | 1.69 ms | + | hal1 | wait/io/file/sql/pid | 3 | 266.30 us | 185.47 us | + | hal1 | wait/io/file/sql/casetest | 5 | 246.81 us | 150.19 us | + | hal1 | wait/io/file/sql/global_ddl_log | 2 | 21.24 us | 18.59 us | + | hal2 | wait/io/file/sql/file_parser | 1422 | 4.80 s | 135.14 ms | + | hal2 | wait/io/file/sql/FRM | 865 | 85.82 ms | 9.81 ms | + | hal2 | wait/io/file/myisam/kfile | 1073 | 37.14 ms | 15.79 ms | + | hal2 | wait/io/file/myisam/dfile | 2991 | 25.53 ms | 5.25 ms | + | hal2 | wait/io/file/sql/dbopt | 20 | 1.07 ms | 153.07 us | + | hal2 | wait/io/file/sql/misc | 4 | 59.71 us | 33.75 us | + | hal2 | wait/io/file/archive/data | 1 | 13.91 us | 13.91 us | + +------------+--------------------------------------+-------+---------------+-------------+ + ``` + +#### host_summary_by_stages / x$host_summary_by_stages + +##### Description + +Summarizes stages by host, ordered by host and total latency per stage. + +When the host found is NULL, it is assumed to be a "background" thread. + +##### Structures + +```SQL +mysql> desc host_summary_by_stages; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| event_name | varchar(128) | NO | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| avg_latency | text | YES | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +5 rows in set (0.06 sec) + +mysql> desc x$host_summary_by_stages; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| event_name | varchar(128) | NO | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| avg_latency | bigint(20) unsigned | NO | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +5 rows in set (0.81 sec) +``` + +##### Example + +```SQL + mysql> select * from host_summary_by_stages; + +------+--------------------------------+-------+---------------+-------------+ + | host | event_name | total | total_latency | avg_latency | + +------+--------------------------------+-------+---------------+-------------+ + | hal | stage/sql/Opening tables | 889 | 1.97 ms | 2.22 us | + | hal | stage/sql/Creating sort index | 4 | 1.79 ms | 446.30 us | + | hal | stage/sql/init | 10 | 312.27 us | 31.23 us | + | hal | stage/sql/checking permissions | 10 | 300.62 us | 30.06 us | + | hal | stage/sql/freeing items | 5 | 85.89 us | 17.18 us | + | hal | stage/sql/statistics | 5 | 79.15 us | 15.83 us | + | hal | stage/sql/preparing | 5 | 69.12 us | 13.82 us | + | hal | stage/sql/optimizing | 5 | 53.11 us | 10.62 us | + | hal | stage/sql/Sending data | 5 | 44.66 us | 8.93 us | + | hal | stage/sql/closing tables | 5 | 37.54 us | 7.51 us | + | hal | stage/sql/System lock | 5 | 34.28 us | 6.86 us | + | hal | stage/sql/query end | 5 | 24.37 us | 4.87 us | + | hal | stage/sql/end | 5 | 8.60 us | 1.72 us | + | hal | stage/sql/Sorting result | 5 | 8.33 us | 1.67 us | + | hal | stage/sql/executing | 5 | 5.37 us | 1.07 us | + | hal | stage/sql/cleaning up | 5 | 4.60 us | 919.00 ns | + +------+--------------------------------+-------+---------------+-------------+ +``` + +#### host_summary_by_statement_latency / x$host_summary_by_statement_latency + +##### Description + +Summarizes overall statement statistics by host. + +When the host found is NULL, it is assumed to be a "background" thread. + +##### Structures + +```SQL +mysql> desc host_summary_by_statement_latency; ++---------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| total | decimal(42,0) | YES | | NULL | | +| total_latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | +| lock_latency | text | YES | | NULL | | +| rows_sent | decimal(42,0) | YES | | NULL | | +| rows_examined | decimal(42,0) | YES | | NULL | | +| rows_affected | decimal(42,0) | YES | | NULL | | +| full_scans | decimal(43,0) | YES | | NULL | | ++---------------+---------------+------+-----+---------+-------+ +9 rows in set (0.29 sec) + +mysql> desc x$host_summary_by_statement_latency; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| total | decimal(42,0) | YES | | NULL | | +| total_latency | decimal(42,0) | YES | | NULL | | +| max_latency | bigint(20) unsigned | YES | | NULL | | +| lock_latency | decimal(42,0) | YES | | NULL | | +| rows_sent | decimal(42,0) | YES | | NULL | | +| rows_examined | decimal(42,0) | YES | | NULL | | +| rows_affected | decimal(42,0) | YES | | NULL | | +| full_scans | decimal(43,0) | YES | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +9 rows in set (0.00 sec) +``` + +##### Example + +```SQL + mysql> select * from host_summary_by_statement_latency; + +------+-------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ + | host | total | total_latency | max_latency | lock_latency | rows_sent | rows_examined | rows_affected | full_scans | + +------+-------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ + | hal | 3381 | 00:02:09.13 | 1.48 s | 1.07 s | 1151 | 93947 | 150 | 91 | + +------+-------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +``` + +#### host_summary_by_statement_type / x$host_summary_by_statement_type + +##### Description + +Summarizes the types of statements executed by each host. + +When the host found is NULL, it is assumed to be a "background" thread. + +##### Structures + +```SQL +mysql> desc host_summary_by_statement_type; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| statement | varchar(128) | YES | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | +| lock_latency | text | YES | | NULL | | +| rows_sent | bigint(20) unsigned | NO | | NULL | | +| rows_examined | bigint(20) unsigned | NO | | NULL | | +| rows_affected | bigint(20) unsigned | NO | | NULL | | +| full_scans | bigint(21) unsigned | NO | | 0 | | ++---------------+---------------------+------+-----+---------+-------+ +10 rows in set (0.30 sec) + +mysql> desc x$host_summary_by_statement_type; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| statement | varchar(128) | YES | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| max_latency | bigint(20) unsigned | NO | | NULL | | +| lock_latency | bigint(20) unsigned | NO | | NULL | | +| rows_sent | bigint(20) unsigned | NO | | NULL | | +| rows_examined | bigint(20) unsigned | NO | | NULL | | +| rows_affected | bigint(20) unsigned | NO | | NULL | | +| full_scans | bigint(21) unsigned | NO | | 0 | | ++---------------+---------------------+------+-----+---------+-------+ +10 rows in set (0.76 sec) +``` + +##### Example + +```SQL + mysql> select * from host_summary_by_statement_type; + +------+----------------------+--------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ + | host | statement | total | total_latency | max_latency | lock_latency | rows_sent | rows_examined | rows_affected | full_scans | + +------+----------------------+--------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ + | hal | create_view | 2063 | 00:05:04.20 | 463.58 ms | 1.42 s | 0 | 0 | 0 | 0 | + | hal | select | 174 | 40.87 s | 28.83 s | 858.13 ms | 5212 | 157022 | 0 | 82 | + | hal | stmt | 6645 | 15.31 s | 491.78 ms | 0 ps | 0 | 0 | 7951 | 0 | + | hal | call_procedure | 17 | 4.78 s | 1.02 s | 37.94 ms | 0 | 0 | 19 | 0 | + | hal | create_table | 19 | 3.04 s | 431.71 ms | 0 ps | 0 | 0 | 0 | 0 | + ... + +------+----------------------+--------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +``` + +#### innodb_buffer_stats_by_schema / x$innodb_buffer_stats_by_schema + +##### Description + +Summarizes the output of the INFORMATION_SCHEMA.INNODB_BUFFER_PAGE table, aggregating by schema. + +##### Structures + +```SQL +mysql> desc innodb_buffer_stats_by_schema; ++---------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------+------+-----+---------+-------+ +| object_schema | text | YES | | NULL | | +| allocated | text | YES | | NULL | | +| data | text | YES | | NULL | | +| pages | bigint(21) | NO | | 0 | | +| pages_hashed | bigint(21) | NO | | 0 | | +| pages_old | bigint(21) | NO | | 0 | | +| rows_cached | decimal(44,0) | YES | | NULL | | ++---------------+---------------+------+-----+---------+-------+ +7 rows in set (0.08 sec) + +mysql> desc x$innodb_buffer_stats_by_schema; ++---------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------+------+-----+---------+-------+ +| object_schema | text | YES | | NULL | | +| allocated | decimal(43,0) | YES | | NULL | | +| data | decimal(43,0) | YES | | NULL | | +| pages | bigint(21) | NO | | 0 | | +| pages_hashed | bigint(21) | NO | | 0 | | +| pages_old | bigint(21) | NO | | 0 | | +| rows_cached | decimal(44,0) | NO | | 0 | | ++---------------+---------------+------+-----+---------+-------+ +7 rows in set (0.12 sec) +```` + +##### Example + +```SQL +mysql> select * from innodb_buffer_stats_by_schema; ++--------------------------+------------+------------+-------+--------------+-----------+-------------+ +| object_schema | allocated | data | pages | pages_hashed | pages_old | rows_cached | ++--------------------------+------------+------------+-------+--------------+-----------+-------------+ +| mem30_trunk__instruments | 1.69 MiB | 510.03 KiB | 108 | 108 | 108 | 3885 | +| InnoDB System | 688.00 KiB | 351.62 KiB | 43 | 43 | 43 | 862 | +| mem30_trunk__events | 80.00 KiB | 21.61 KiB | 5 | 5 | 5 | 229 | ++--------------------------+------------+------------+-------+--------------+-----------+-------------+ +``` + +#### innodb_buffer_stats_by_table / x$innodb_buffer_stats_by_table + +##### Description + +Summarizes the output of the INFORMATION_SCHEMA.INNODB_BUFFER_PAGE table, aggregating by schema and table name. + +##### Structures + +```SQL +mysql> desc innodb_buffer_stats_by_table; ++---------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------+------+-----+---------+-------+ +| object_schema | text | YES | | NULL | | +| object_name | text | YES | | NULL | | +| allocated | text | YES | | NULL | | +| data | text | YES | | NULL | | +| pages | bigint(21) | NO | | 0 | | +| pages_hashed | bigint(21) | NO | | 0 | | +| pages_old | bigint(21) | NO | | 0 | | +| rows_cached | decimal(44,0) | YES | | NULL | | ++---------------+---------------+------+-----+---------+-------+ +8 rows in set (0.09 sec) + +mysql> desc x$innodb_buffer_stats_by_table; ++---------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------+------+-----+---------+-------+ +| object_schema | text | YES | | NULL | | +| object_name | text | YES | | NULL | | +| allocated | decimal(43,0) | YES | | NULL | | +| data | decimal(43,0) | YES | | NULL | | +| pages | bigint(21) | NO | | 0 | | +| pages_hashed | bigint(21) | NO | | 0 | | +| pages_old | bigint(21) | NO | | 0 | | +| rows_cached | decimal(44,0) | NO | | 0 | | ++---------------+---------------+------+-----+---------+-------+ +8 rows in set (0.18 sec) +``` + +##### Example + +```SQL +mysql> select * from innodb_buffer_stats_by_table; ++--------------------------+------------------------------------+------------+-----------+-------+--------------+-----------+-------------+ +| object_schema | object_name | allocated | data | pages | pages_hashed | pages_old | rows_cached | ++--------------------------+------------------------------------+------------+-----------+-------+--------------+-----------+-------------+ +| InnoDB System | SYS_COLUMNS | 128.00 KiB | 98.97 KiB | 8 | 8 | 8 | 1532 | +| InnoDB System | SYS_FOREIGN | 128.00 KiB | 55.48 KiB | 8 | 8 | 8 | 172 | +| InnoDB System | SYS_TABLES | 128.00 KiB | 56.18 KiB | 8 | 8 | 8 | 365 | +| InnoDB System | SYS_INDEXES | 112.00 KiB | 76.16 KiB | 7 | 7 | 7 | 1046 | +| mem30_trunk__instruments | agentlatencytime | 96.00 KiB | 28.83 KiB | 6 | 6 | 6 | 252 | +| mem30_trunk__instruments | binlogspaceusagedata | 96.00 KiB | 22.54 KiB | 6 | 6 | 6 | 196 | +| mem30_trunk__instruments | connectionsdata | 96.00 KiB | 36.68 KiB | 6 | 6 | 6 | 276 | +| mem30_trunk__instruments | connectionsmaxdata | 96.00 KiB | 31.88 KiB | 6 | 6 | 6 | 271 | +| mem30_trunk__instruments | cpuaverage | 96.00 KiB | 14.32 KiB | 6 | 6 | 6 | 55 | +| mem30_trunk__instruments | diskiototaldata | 96.00 KiB | 42.71 KiB | 6 | 6 | 6 | 152 | +| mem30_trunk__instruments | innodbopenfilesdata | 96.00 KiB | 32.61 KiB | 6 | 6 | 6 | 266 | +| mem30_trunk__instruments | innodbrowlocktimestatisticsdata | 96.00 KiB | 32.16 KiB | 6 | 6 | 6 | 261 | +| mem30_trunk__instruments | myisamkeybufferusagedata | 96.00 KiB | 25.99 KiB | 6 | 6 | 6 | 232 | +| mem30_trunk__instruments | mysqlprocessactivity | 96.00 KiB | 31.99 KiB | 6 | 6 | 6 | 252 | +| mem30_trunk__instruments | querycacheaveragefreeblocksizedata | 96.00 KiB | 27.00 KiB | 6 | 6 | 6 | 237 | +| mem30_trunk__instruments | querycacheaveragequerysizedata | 96.00 KiB | 38.29 KiB | 6 | 6 | 6 | 315 | +| mem30_trunk__instruments | querycachefragmentationdata | 96.00 KiB | 27.00 KiB | 6 | 6 | 6 | 237 | +| mem30_trunk__instruments | querycachememorydata | 96.00 KiB | 32.58 KiB | 6 | 6 | 6 | 278 | +| mem30_trunk__instruments | querycachequeriesincachedata | 96.00 KiB | 27.15 KiB | 6 | 6 | 6 | 238 | +| mem30_trunk__instruments | ramusagedata | 96.00 KiB | 15.02 KiB | 6 | 6 | 6 | 59 | +| mem30_trunk__instruments | slaverelaylogspaceusagedata | 96.00 KiB | 28.28 KiB | 6 | 6 | 6 | 249 | +| mem30_trunk__instruments | swapusagedata | 96.00 KiB | 15.02 KiB | 6 | 6 | 6 | 59 | +| InnoDB System | SYS_FIELDS | 80.00 KiB | 49.78 KiB | 5 | 5 | 5 | 1147 | +| InnoDB System | SYS_DATAFILES | 32.00 KiB | 3.97 KiB | 2 | 2 | 2 | 60 | +| InnoDB System | SYS_FOREIGN_COLS | 32.00 KiB | 7.43 KiB | 2 | 2 | 2 | 83 | +| InnoDB System | SYS_TABLESPACES | 32.00 KiB | 3.65 KiB | 2 | 2 | 2 | 56 | +| InnoDB System | SYS_IBUF_TABLE | 16.00 KiB | 0 bytes | 1 | 1 | 1 | 0 | ++--------------------------+------------------------------------+------------+-----------+-------+--------------+-----------+-------------+ +``` + +#### innodb_lock_waits / x$innodb_lock_waits + +##### Description + +Gives a snapshot of which InnoDB locks transactions are waiting for. +The lock waits are ordered by the age of the lock descending. + +##### Structures + +```SQL +mysql> desc sys.innodb_lock_waits; ++------------------------------+---------------------+------+-----+---------------------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------------------------+---------------------+------+-----+---------------------+-------+ +| wait_started | datetime | YES | | NULL | | +| wait_age | time | YES | | NULL | | +| wait_age_secs | bigint(21) | YES | | NULL | | +| locked_table | varchar(1024) | NO | | | | +| locked_index | varchar(1024) | YES | | NULL | | +| locked_type | varchar(32) | NO | | | | +| waiting_trx_id | varchar(18) | NO | | | | +| waiting_trx_started | datetime | NO | | 0000-00-00 00:00:00 | | +| waiting_trx_age | time | YES | | NULL | | +| waiting_trx_rows_locked | bigint(21) unsigned | NO | | 0 | | +| waiting_trx_rows_modified | bigint(21) unsigned | NO | | 0 | | +| waiting_pid | bigint(21) unsigned | NO | | 0 | | +| waiting_query | longtext | YES | | NULL | | +| waiting_lock_id | varchar(81) | NO | | | | +| waiting_lock_mode | varchar(32) | NO | | | | +| blocking_trx_id | varchar(18) | NO | | | | +| blocking_pid | bigint(21) unsigned | NO | | 0 | | +| blocking_query | longtext | YES | | NULL | | +| blocking_lock_id | varchar(81) | NO | | | | +| blocking_lock_mode | varchar(32) | NO | | | | +| blocking_trx_started | datetime | NO | | 0000-00-00 00:00:00 | | +| blocking_trx_age | time | YES | | NULL | | +| blocking_trx_rows_locked | bigint(21) unsigned | NO | | 0 | | +| blocking_trx_rows_modified | bigint(21) unsigned | NO | | 0 | | +| sql_kill_blocking_query | varchar(32) | YES | | NULL | | +| sql_kill_blocking_connection | varchar(26) | YES | | NULL | | ++------------------------------+---------------------+------+-----+---------------------+-------+ +26 rows in set (0.01 sec) + +mysql> desc sys.x$innodb_lock_waits; ++------------------------------+---------------------+------+-----+---------------------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------------------------+---------------------+------+-----+---------------------+-------+ +| wait_started | datetime | YES | | NULL | | +| wait_age | time | YES | | NULL | | +| wait_age_secs | bigint(21) | YES | | NULL | | +| locked_table | varchar(1024) | NO | | | | +| locked_index | varchar(1024) | YES | | NULL | | +| locked_type | varchar(32) | NO | | | | +| waiting_trx_id | varchar(18) | NO | | | | +| waiting_trx_started | datetime | NO | | 0000-00-00 00:00:00 | | +| waiting_trx_age | time | YES | | NULL | | +| waiting_trx_rows_locked | bigint(21) unsigned | NO | | 0 | | +| waiting_trx_rows_modified | bigint(21) unsigned | NO | | 0 | | +| waiting_pid | bigint(21) unsigned | NO | | 0 | | +| waiting_query | varchar(1024) | YES | | NULL | | +| waiting_lock_id | varchar(81) | NO | | | | +| waiting_lock_mode | varchar(32) | NO | | | | +| blocking_trx_id | varchar(18) | NO | | | | +| blocking_pid | bigint(21) unsigned | NO | | 0 | | +| blocking_query | varchar(1024) | YES | | NULL | | +| blocking_lock_id | varchar(81) | NO | | | | +| blocking_lock_mode | varchar(32) | NO | | | | +| blocking_trx_started | datetime | NO | | 0000-00-00 00:00:00 | | +| blocking_trx_age | time | YES | | NULL | | +| blocking_trx_rows_locked | bigint(21) unsigned | NO | | 0 | | +| blocking_trx_rows_modified | bigint(21) unsigned | NO | | 0 | | +| sql_kill_blocking_query | varchar(32) | YES | | NULL | | +| sql_kill_blocking_connection | varchar(26) | YES | | NULL | | ++------------------------------+---------------------+------+-----+---------------------+-------+ +26 rows in set (0.02 sec) +``` + +##### Example + +```SQL +mysql> SELECT * FROM innodb_lock_waits\G +*************************** 1. row *************************** + wait_started: 2014-11-11 13:39:20 + wait_age: 00:00:07 + wait_age_secs: 7 + locked_table: `db1`.`t1` + locked_index: PRIMARY + locked_type: RECORD + waiting_trx_id: 867158 + waiting_trx_started: 2014-11-11 13:39:15 + waiting_trx_age: 00:00:12 + waiting_trx_rows_locked: 0 + waiting_trx_rows_modified: 0 + waiting_pid: 3 + waiting_query: UPDATE t1 SET val = val + 1 WHERE id = 2 + waiting_lock_id: 867158:2363:3:3 + waiting_lock_mode: X + blocking_trx_id: 867157 + blocking_pid: 4 + blocking_query: UPDATE t1 SET val = val + 1 + SLEEP(10) WHERE id = 2 + blocking_lock_id: 867157:2363:3:3 + blocking_lock_mode: X + blocking_trx_started: 2014-11-11 13:39:11 + blocking_trx_age: 00:00:16 + blocking_trx_rows_locked: 1 + blocking_trx_rows_modified: 1 + sql_kill_blocking_query: KILL QUERY 4 +sql_kill_blocking_connection: KILL 4 +``` + +#### io_by_thread_by_latency / x$io_by_thread_by_latency + +##### Description + +Shows the top IO consumers by thread, ordered by total latency. + +##### Structures + +```SQL +mysql> desc io_by_thread_by_latency; ++----------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++----------------+---------------------+------+-----+---------+-------+ +| user | varchar(128) | YES | | NULL | | +| total | decimal(42,0) | YES | | NULL | | +| total_latency | text | YES | | NULL | | +| min_latency | text | YES | | NULL | | +| avg_latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | +| thread_id | bigint(20) unsigned | NO | | NULL | | +| processlist_id | bigint(20) unsigned | YES | | NULL | | ++----------------+---------------------+------+-----+---------+-------+ +8 rows in set (0.14 sec) + +mysql> desc x$io_by_thread_by_latency; ++----------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++----------------+---------------------+------+-----+---------+-------+ +| user | varchar(128) | YES | | NULL | | +| total | decimal(42,0) | YES | | NULL | | +| total_latency | decimal(42,0) | YES | | NULL | | +| min_latency | bigint(20) unsigned | YES | | NULL | | +| avg_latency | decimal(24,4) | YES | | NULL | | +| max_latency | bigint(20) unsigned | YES | | NULL | | +| thread_id | bigint(20) unsigned | NO | | NULL | | +| processlist_id | bigint(20) unsigned | YES | | NULL | | ++----------------+---------------------+------+-----+---------+-------+ +8 rows in set (0.03 sec) +``` + +##### Example + +```SQL +mysql> select * from io_by_thread_by_latency; ++---------------------+-------+---------------+-------------+-------------+-------------+-----------+----------------+ +| user | total | total_latency | min_latency | avg_latency | max_latency | thread_id | processlist_id | ++---------------------+-------+---------------+-------------+-------------+-------------+-----------+----------------+ +| root@localhost | 11580 | 18.01 s | 429.78 ns | 1.12 ms | 181.07 ms | 25 | 6 | +| main | 1358 | 1.31 s | 475.02 ns | 2.27 ms | 350.70 ms | 1 | NULL | +| page_cleaner_thread | 654 | 147.44 ms | 588.12 ns | 225.44 us | 46.41 ms | 18 | NULL | +| io_write_thread | 131 | 107.75 ms | 8.60 us | 822.55 us | 27.69 ms | 8 | NULL | +| io_write_thread | 46 | 47.07 ms | 10.64 us | 1.02 ms | 16.90 ms | 9 | NULL | +| io_write_thread | 71 | 46.99 ms | 9.11 us | 661.81 us | 17.04 ms | 11 | NULL | +| io_log_thread | 20 | 21.01 ms | 14.25 us | 1.05 ms | 7.08 ms | 3 | NULL | +| srv_master_thread | 13 | 17.60 ms | 8.49 us | 1.35 ms | 9.99 ms | 16 | NULL | +| srv_purge_thread | 4 | 1.81 ms | 34.31 us | 452.45 us | 1.02 ms | 17 | NULL | +| io_write_thread | 19 | 951.39 us | 9.75 us | 50.07 us | 297.47 us | 10 | NULL | +| signal_handler | 3 | 218.03 us | 21.64 us | 72.68 us | 154.84 us | 19 | NULL | ++---------------------+-------+---------------+-------------+-------------+-------------+-----------+----------------+ +``` + +#### io_global_by_file_by_bytes / x$io_global_by_file_by_bytes + +##### Description + +Shows the top global IO consumers by bytes usage by file. + +##### Structures + +```SQL +mysql> desc io_global_by_file_by_bytes; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| file | varchar(512) | YES | | NULL | | +| count_read | bigint(20) unsigned | NO | | NULL | | +| total_read | text | YES | | NULL | | +| avg_read | text | YES | | NULL | | +| count_write | bigint(20) unsigned | NO | | NULL | | +| total_written | text | YES | | NULL | | +| avg_write | text | YES | | NULL | | +| total | text | YES | | NULL | | +| write_pct | decimal(26,2) | NO | | 0.00 | | ++---------------+---------------------+------+-----+---------+-------+ +9 rows in set (0.15 sec) + +mysql> desc x$io_global_by_file_by_bytes; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| file | varchar(512) | NO | | NULL | | +| count_read | bigint(20) unsigned | NO | | NULL | | +| total_read | bigint(20) | NO | | NULL | | +| avg_read | decimal(23,4) | NO | | 0.0000 | | +| count_write | bigint(20) unsigned | NO | | NULL | | +| total_written | bigint(20) | NO | | NULL | | +| avg_write | decimal(23,4) | NO | | 0.0000 | | +| total | bigint(21) | NO | | 0 | | +| write_pct | decimal(26,2) | NO | | 0.00 | | ++---------------+---------------------+------+-----+---------+-------+ +9 rows in set (0.14 sec) +``` + +##### Example + +```SQL +mysql> SELECT * FROM io_global_by_file_by_bytes LIMIT 5; ++--------------------------------------------+------------+------------+-----------+-------------+---------------+-----------+------------+-----------+ +| file | count_read | total_read | avg_read | count_write | total_written | avg_write | total | write_pct | ++--------------------------------------------+------------+------------+-----------+-------------+---------------+-----------+------------+-----------+ +| @@datadir/ibdata1 | 147 | 4.27 MiB | 29.71 KiB | 3 | 48.00 KiB | 16.00 KiB | 4.31 MiB | 1.09 | +| @@datadir/mysql/proc.MYD | 347 | 85.35 KiB | 252 bytes | 111 | 19.08 KiB | 176 bytes | 104.43 KiB | 18.27 | +| @@datadir/ib_logfile0 | 6 | 68.00 KiB | 11.33 KiB | 8 | 4.00 KiB | 512 bytes | 72.00 KiB | 5.56 | +| /opt/mysql/5.5.33/share/english/errmsg.sys | 3 | 43.68 KiB | 14.56 KiB | 0 | 0 bytes | 0 bytes | 43.68 KiB | 0.00 | +| /opt/mysql/5.5.33/share/charsets/Index.xml | 1 | 17.89 KiB | 17.89 KiB | 0 | 0 bytes | 0 bytes | 17.89 KiB | 0.00 | ++--------------------------------------------+------------+------------+-----------+-------------+---------------+-----------+------------+-----------+ +``` + +#### io_global_by_file_by_latency / x$io_global_by_file_by_latency + +##### Description + +Shows the top global IO consumers by latency by file. + +##### Structures + +```SQL +mysql> desc io_global_by_file_by_latency; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| file | varchar(512) | YES | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| count_read | bigint(20) unsigned | NO | | NULL | | +| read_latency | text | YES | | NULL | | +| count_write | bigint(20) unsigned | NO | | NULL | | +| write_latency | text | YES | | NULL | | +| count_misc | bigint(20) unsigned | NO | | NULL | | +| misc_latency | text | YES | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +9 rows in set (0.00 sec) + +mysql> desc x$io_global_by_file_by_latency; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| file | varchar(512) | NO | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| count_read | bigint(20) unsigned | NO | | NULL | | +| read_latency | bigint(20) unsigned | NO | | NULL | | +| count_write | bigint(20) unsigned | NO | | NULL | | +| write_latency | bigint(20) unsigned | NO | | NULL | | +| count_misc | bigint(20) unsigned | NO | | NULL | | +| misc_latency | bigint(20) unsigned | NO | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +9 rows in set (0.07 sec) +``` + +##### Example + +```SQL +mysql> select * from io_global_by_file_by_latency limit 5; ++-----------------------------------------------------------+-------+---------------+------------+--------------+-------------+---------------+------------+--------------+ +| file | total | total_latency | count_read | read_latency | count_write | write_latency | count_misc | misc_latency | ++-----------------------------------------------------------+-------+---------------+------------+--------------+-------------+---------------+------------+--------------+ +| @@datadir/sys/wait_classes_global_by_avg_latency_raw.frm~ | 24 | 451.99 ms | 0 | 0 ps | 4 | 108.07 us | 20 | 451.88 ms | +| @@datadir/sys/innodb_buffer_stats_by_schema_raw.frm~ | 24 | 379.84 ms | 0 | 0 ps | 4 | 108.88 us | 20 | 379.73 ms | +| @@datadir/sys/io_by_thread_by_latency_raw.frm~ | 24 | 379.46 ms | 0 | 0 ps | 4 | 101.37 us | 20 | 379.36 ms | +| @@datadir/ibtmp1 | 53 | 373.45 ms | 0 | 0 ps | 48 | 246.08 ms | 5 | 127.37 ms | +| @@datadir/sys/statement_analysis_raw.frm~ | 24 | 353.14 ms | 0 | 0 ps | 4 | 94.96 us | 20 | 353.04 ms | ++-----------------------------------------------------------+-------+---------------+------------+--------------+-------------+---------------+------------+--------------+ +``` + +#### io_global_by_wait_by_bytes / x$io_global_by_wait_by_bytes + +##### Description + +Shows the top global IO consumer classes by bytes usage. + +##### Structures + +```SQL +mysql> desc io_global_by_wait_by_bytes; ++-----------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-----------------+---------------------+------+-----+---------+-------+ +| event_name | varchar(128) | YES | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| min_latency | text | YES | | NULL | | +| avg_latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | +| count_read | bigint(20) unsigned | NO | | NULL | | +| total_read | text | YES | | NULL | | +| avg_read | text | YES | | NULL | | +| count_write | bigint(20) unsigned | NO | | NULL | | +| total_written | text | YES | | NULL | | +| avg_written | text | YES | | NULL | | +| total_requested | text | YES | | NULL | | ++-----------------+---------------------+------+-----+---------+-------+ +13 rows in set (0.02 sec) + +mysql> desc x$io_global_by_wait_by_bytes; ++-----------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-----------------+---------------------+------+-----+---------+-------+ +| event_name | varchar(128) | YES | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| min_latency | bigint(20) unsigned | NO | | NULL | | +| avg_latency | bigint(20) unsigned | NO | | NULL | | +| max_latency | bigint(20) unsigned | NO | | NULL | | +| count_read | bigint(20) unsigned | NO | | NULL | | +| total_read | bigint(20) | NO | | NULL | | +| avg_read | decimal(23,4) | NO | | 0.0000 | | +| count_write | bigint(20) unsigned | NO | | NULL | | +| total_written | bigint(20) | NO | | NULL | | +| avg_written | decimal(23,4) | NO | | 0.0000 | | +| total_requested | bigint(21) | NO | | 0 | | ++-----------------+---------------------+------+-----+---------+-------+ +13 rows in set (0.01 sec) +``` + +##### Example + +```SQL +mysql> select * from io_global_by_wait_by_bytes; ++--------------------+--------+---------------+-------------+-------------+-------------+------------+------------+-----------+-------------+---------------+-------------+-----------------+ +| event_name | total | total_latency | min_latency | avg_latency | max_latency | count_read | total_read | avg_read | count_write | total_written | avg_written | total_requested | ++--------------------+--------+---------------+-------------+-------------+-------------+------------+------------+-----------+-------------+---------------+-------------+-----------------+ +| myisam/dfile | 163681 | 983.13 ms | 379.08 ns | 6.01 us | 22.06 ms | 68737 | 127.31 MiB | 1.90 KiB | 1012221 | 121.52 MiB | 126 bytes | 248.83 MiB | +| myisam/kfile | 1775 | 375.13 ms | 1.02 us | 211.34 µs | 35.15 ms | 54066 | 9.97 MiB | 193 bytes | 428257 | 12.40 MiB | 30 bytes | 22.37 MiB | +| sql/FRM | 57889 | 8.40 s | 19.44 ns | 145.05 us | 336.71 ms | 8009 | 2.60 MiB | 341 bytes | 14675 | 2.91 MiB | 208 bytes | 5.51 MiB | +| sql/global_ddl_log | 164 | 75.96 ms | 5.72 us | 463.19 µs | 7.43 ms | 20 | 80.00 KiB | 4.00 KiB | 76 | 304.00 KiB | 4.00 KiB | 384.00 KiB | +| sql/file_parser | 419 | 601.37 ms | 1.96 us | 1.44 ms | 37.14 ms | 66 | 42.01 KiB | 652 bytes | 64 | 226.98 KiB | 3.55 KiB | 268.99 KiB | +| sql/binlog | 190 | 6.79 s | 1.56 us | 35.76 ms | 4.21 s | 52 | 60.54 KiB | 1.16 KiB | 0 | 0 bytes | 0 bytes | 60.54 KiB | +| sql/ERRMSG | 5 | 2.03 s | 8.61 us | 405.40 ms | 2.03 s | 3 | 51.82 KiB | 17.27 KiB | 0 | 0 bytes | 0 bytes | 51.82 KiB | +| mysys/charset | 3 | 196.52 us | 17.61 µs | 65.51 µs | 137.33 µs | 1 | 17.83 KiB | 17.83 KiB | 0 | 0 bytes | 0 bytes | 17.83 KiB | +| sql/partition | 81 | 18.87 ms | 888.08 ns | 232.92 us | 4.67 ms | 66 | 2.75 KiB | 43 bytes | 8 | 288 bytes | 36 bytes | 3.04 KiB | +| sql/dbopt | 329166 | 26.95 s | 2.06 us | 81.89 µs | 178.71 ms | 0 | 0 bytes | 0 bytes | 9 | 585 bytes | 65 bytes | 585 bytes | +| sql/relaylog | 7 | 1.18 ms | 838.84 ns | 168.30 us | 892.70 µs | 0 | 0 bytes | 0 bytes | 1 | 120 bytes | 120 bytes | 120 bytes | +| mysys/cnf | 5 | 171.61 us | 303.26 ns | 34.32 µs | 115.21 µs | 3 | 56 bytes | 19 bytes | 0 | 0 bytes | 0 bytes | 56 bytes | +| sql/pid | 3 | 220.55 us | 29.29 µs | 73.52 µs | 143.11 µs | 0 | 0 bytes | 0 bytes | 1 | 5 bytes | 5 bytes | 5 bytes | +| sql/casetest | 1 | 121.19 us | 121.19 µs | 121.19 µs | 121.19 µs | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | 0 bytes | +| sql/binlog_index | 5 | 593.47 us | 1.07 µs | 118.69 µs | 535.90 µs | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | 0 bytes | +| sql/misc | 23 | 2.73 ms | 65.14 us | 118.50 µs | 255.31 µs | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | 0 bytes | ++--------------------+--------+---------------+-------------+-------------+-------------+------------+------------+-----------+-------------+---------------+-------------+-----------------+ +``` + +#### io_global_by_wait_by_latency / x$io_global_by_wait_by_latency + +##### Description + +Shows the top global IO consumers by latency. + +##### Structures + +```SQL +mysql> desc io_global_by_wait_by_latency; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| event_name | varchar(128) | YES | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| avg_latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | +| read_latency | text | YES | | NULL | | +| write_latency | text | YES | | NULL | | +| misc_latency | text | YES | | NULL | | +| count_read | bigint(20) unsigned | NO | | NULL | | +| total_read | text | YES | | NULL | | +| avg_read | text | YES | | NULL | | +| count_write | bigint(20) unsigned | NO | | NULL | | +| total_written | text | YES | | NULL | | +| avg_written | text | YES | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +14 rows in set (0.19 sec) + +mysql> desc x$io_global_by_wait_by_latency; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| event_name | varchar(128) | YES | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| avg_latency | bigint(20) unsigned | NO | | NULL | | +| max_latency | bigint(20) unsigned | NO | | NULL | | +| read_latency | bigint(20) unsigned | NO | | NULL | | +| write_latency | bigint(20) unsigned | NO | | NULL | | +| misc_latency | bigint(20) unsigned | NO | | NULL | | +| count_read | bigint(20) unsigned | NO | | NULL | | +| total_read | bigint(20) | NO | | NULL | | +| avg_read | decimal(23,4) | NO | | 0.0000 | | +| count_write | bigint(20) unsigned | NO | | NULL | | +| total_written | bigint(20) | NO | | NULL | | +| avg_written | decimal(23,4) | NO | | 0.0000 | | ++---------------+---------------------+------+-----+---------+-------+ +14 rows in set (0.01 sec) +``` + +##### Example + +```SQL +mysql> SELECT * FROM io_global_by_wait_by_latency; ++-------------------------+-------+---------------+-------------+-------------+--------------+---------------+--------------+------------+------------+-----------+-------------+---------------+-------------+ +| event_name | total | total_latency | avg_latency | max_latency | read_latency | write_latency | misc_latency | count_read | total_read | avg_read | count_write | total_written | avg_written | ++-------------------------+-------+---------------+-------------+-------------+--------------+---------------+--------------+------------+------------+-----------+-------------+---------------+-------------+ +| sql/file_parser | 5433 | 30.20 s | 5.56 ms | 203.65 ms | 22.08 ms | 24.89 ms | 30.16 s | 24 | 6.18 KiB | 264 bytes | 737 | 2.15 MiB | 2.99 KiB | +| innodb/innodb_data_file | 1344 | 1.52 s | 1.13 ms | 350.70 ms | 203.82 ms | 450.96 ms | 868.21 ms | 147 | 2.30 MiB | 16.00 KiB | 1001 | 53.61 MiB | 54.84 KiB | +| innodb/innodb_log_file | 828 | 893.48 ms | 1.08 ms | 30.11 ms | 16.32 ms | 705.89 ms | 171.27 ms | 6 | 68.00 KiB | 11.33 KiB | 413 | 2.19 MiB | 5.42 KiB | +| myisam/kfile | 7642 | 242.34 ms | 31.71 us | 19.27 ms | 73.60 ms | 23.48 ms | 145.26 ms | 758 | 135.63 KiB | 183 bytes | 4386 | 232.52 KiB | 54 bytes | +| myisam/dfile | 12540 | 223.47 ms | 17.82 us | 32.50 ms | 87.76 ms | 16.97 ms | 118.74 ms | 5390 | 4.49 MiB | 873 bytes | 1448 | 2.65 MiB | 1.88 KiB | +| csv/metadata | 8 | 28.98 ms | 3.62 ms | 20.15 ms | 399.27 us | 0 ps | 28.58 ms | 2 | 70 bytes | 35 bytes | 0 | 0 bytes | 0 bytes | +| mysys/charset | 3 | 24.24 ms | 8.08 ms | 24.15 ms | 24.15 ms | 0 ps | 93.18 us | 1 | 17.31 KiB | 17.31 KiB | 0 | 0 bytes | 0 bytes | +| sql/ERRMSG | 5 | 20.43 ms | 4.09 ms | 19.31 ms | 20.32 ms | 0 ps | 103.20 us | 3 | 58.97 KiB | 19.66 KiB | 0 | 0 bytes | 0 bytes | +| mysys/cnf | 5 | 11.37 ms | 2.27 ms | 11.28 ms | 11.29 ms | 0 ps | 78.22 us | 3 | 56 bytes | 19 bytes | 0 | 0 bytes | 0 bytes | +| sql/dbopt | 57 | 4.04 ms | 70.92 us | 843.70 us | 0 ps | 186.43 us | 3.86 ms | 0 | 0 bytes | 0 bytes | 7 | 431 bytes | 62 bytes | +| csv/data | 4 | 411.55 us | 102.89 us | 234.89 us | 0 ps | 0 ps | 411.55 us | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | +| sql/misc | 22 | 340.38 us | 15.47 us | 33.77 us | 0 ps | 0 ps | 340.38 us | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | +| archive/data | 39 | 277.86 us | 7.12 us | 16.18 us | 0 ps | 0 ps | 277.86 us | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | +| sql/pid | 3 | 218.03 us | 72.68 us | 154.84 us | 0 ps | 21.64 us | 196.39 us | 0 | 0 bytes | 0 bytes | 1 | 6 bytes | 6 bytes | +| sql/casetest | 5 | 197.15 us | 39.43 us | 126.31 us | 0 ps | 0 ps | 197.15 us | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | +| sql/global_ddl_log | 2 | 14.60 us | 7.30 us | 12.12 us | 0 ps | 0 ps | 14.60 us | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | ++-------------------------+-------+---------------+-------------+-------------+--------------+---------------+--------------+------------+------------+-----------+-------------+---------------+-------------+ +``` + +#### latest_file_io / x$latest_file_io + +##### Description + +Shows the latest file IO, by file / thread. + +##### Structures + +```SQL +mysql> desc latest_file_io; ++-----------+--------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-----------+--------------+------+-----+---------+-------+ +| thread | varchar(149) | YES | | NULL | | +| file | varchar(512) | YES | | NULL | | +| latency | text | YES | | NULL | | +| operation | varchar(32) | NO | | NULL | | +| requested | text | YES | | NULL | | ++-----------+--------------+------+-----+---------+-------+ +5 rows in set (0.10 sec) + +mysql> desc x$latest_file_io; ++-----------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-----------+---------------------+------+-----+---------+-------+ +| thread | varchar(149) | YES | | NULL | | +| file | varchar(512) | YES | | NULL | | +| latency | bigint(20) unsigned | YES | | NULL | | +| operation | varchar(32) | NO | | NULL | | +| requested | bigint(20) | YES | | NULL | | ++-----------+---------------------+------+-----+---------+-------+ +5 rows in set (0.05 sec) +``` + +##### Example + +```SQL +mysql> select * from latest_file_io limit 5; ++----------------------+----------------------------------------+------------+-----------+-----------+ +| thread | file | latency | operation | requested | ++----------------------+----------------------------------------+------------+-----------+-----------+ +| msandbox@localhost:1 | @@tmpdir/#sqlcf28_1_4e.MYI | 9.26 us | write | 124 bytes | +| msandbox@localhost:1 | @@tmpdir/#sqlcf28_1_4e.MYI | 4.00 us | write | 2 bytes | +| msandbox@localhost:1 | @@tmpdir/#sqlcf28_1_4e.MYI | 56.34 us | close | NULL | +| msandbox@localhost:1 | @@tmpdir/#sqlcf28_1_4e.MYD | 53.93 us | close | NULL | +| msandbox@localhost:1 | @@tmpdir/#sqlcf28_1_4e.MYI | 104.05 ms | delete | NULL | ++----------------------+----------------------------------------+------------+-----------+-----------+ +``` + +#### memory_by_host_by_current_bytes / x$memory_by_host_by_current_bytes + +##### Description + +Summarizes memory use by host using the 5.7 Performance Schema instrumentation. + +When the host found is NULL, it is assumed to be a local "background" thread. + +##### Structures + +```SQL +mysql> desc memory_by_host_by_current_bytes; ++--------------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++--------------------+---------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| current_count_used | decimal(41,0) | YES | | NULL | | +| current_allocated | text | YES | | NULL | | +| current_avg_alloc | text | YES | | NULL | | +| current_max_alloc | text | YES | | NULL | | +| total_allocated | text | YES | | NULL | | ++--------------------+---------------+------+-----+---------+-------+ +6 rows in set (0.24 sec) + +mysql> desc x$memory_by_host_by_current_bytes; ++--------------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++--------------------+---------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| current_count_used | decimal(41,0) | YES | | NULL | | +| current_allocated | decimal(41,0) | YES | | NULL | | +| current_avg_alloc | decimal(45,4) | NO | | 0.0000 | | +| current_max_alloc | bigint(20) | YES | | NULL | | +| total_allocated | decimal(42,0) | YES | | NULL | | ++--------------------+---------------+------+-----+---------+-------+ +6 rows in set (0.28 sec) +``` + +##### Example + +```SQL +mysql> select * from memory_by_host_by_current_bytes WHERE host IS NOT NULL; + +------------+--------------------+-------------------+-------------------+-------------------+-----------------+ + | host | current_count_used | current_allocated | current_avg_alloc | current_max_alloc | total_allocated | + +------------+--------------------+-------------------+-------------------+-------------------+-----------------+ + | background | 2773 | 10.84 MiB | 4.00 KiB | 8.00 MiB | 30.69 MiB | + | localhost | 1509 | 809.30 KiB | 549 bytes | 176.38 KiB | 83.59 MiB | + +------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +``` + +#### memory_by_thread_by_current_bytes / x$memory_by_thread_by_current_bytes + +##### Description + +Summarizes memory use by user using the 5.7 Performance Schema instrumentation. + +The user columns shows either the background or foreground user name appropriately. + +##### Structures + +```SQL +mysql> desc memory_by_thread_by_current_bytes; ++--------------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++--------------------+---------------------+------+-----+---------+-------+ +| thread_id | bigint(20) unsigned | NO | | NULL | | +| user | varchar(128) | YES | | NULL | | +| current_count_used | decimal(41,0) | YES | | NULL | | +| current_allocated | text | YES | | NULL | | +| current_avg_alloc | text | YES | | NULL | | +| current_max_alloc | text | YES | | NULL | | +| total_allocated | text | YES | | NULL | | ++--------------------+---------------------+------+-----+---------+-------+ +7 rows in set (0.49 sec) + +mysql> desc x$memory_by_thread_by_current_bytes; ++--------------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++--------------------+---------------------+------+-----+---------+-------+ +| thread_id | bigint(20) unsigned | NO | | NULL | | +| user | varchar(128) | YES | | NULL | | +| current_count_used | decimal(41,0) | YES | | NULL | | +| current_allocated | decimal(41,0) | YES | | NULL | | +| current_avg_alloc | decimal(45,4) | NO | | 0.0000 | | +| current_max_alloc | bigint(20) | YES | | NULL | | +| total_allocated | decimal(42,0) | YES | | NULL | | ++--------------------+---------------------+------+-----+---------+-------+ +7 rows in set (0.25 sec) +``` + +##### Example + +```SQL +mysql> select * from sys.memory_by_thread_by_current_bytes limit 5; ++-----------+----------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +| thread_id | user | current_count_used | current_allocated | current_avg_alloc | current_max_alloc | total_allocated | ++-----------+----------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +| 1 | sql/main | 29333 | 166.02 MiB | 5.80 KiB | 131.13 MiB | 196.00 MiB | +| 55 | root@localhost | 175 | 1.04 MiB | 6.09 KiB | 350.86 KiB | 67.37 MiB | +| 58 | root@localhost | 236 | 368.13 KiB | 1.56 KiB | 312.05 KiB | 130.34 MiB | +| 904 | root@localhost | 32 | 18.00 KiB | 576 bytes | 16.00 KiB | 6.68 MiB | +| 970 | root@localhost | 12 | 16.80 KiB | 1.40 KiB | 16.00 KiB | 1.20 MiB | ++-----------+----------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +``` + +#### memory_by_user_by_current_bytes / x$memory_by_user_by_current_bytes + +##### Description + +Summarizes memory use by user using the 5.7 Performance Schema instrumentation. + +When the user found is NULL, it is assumed to be a "background" thread. + +##### Structures + +```SQL +mysql> desc memory_by_user_by_current_bytes; ++--------------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++--------------------+---------------+------+-----+---------+-------+ +| user | varchar(32) | YES | | NULL | | +| current_count_used | decimal(41,0) | YES | | NULL | | +| current_allocated | text | YES | | NULL | | +| current_avg_alloc | text | YES | | NULL | | +| current_max_alloc | text | YES | | NULL | | +| total_allocated | text | YES | | NULL | | ++--------------------+---------------+------+-----+---------+-------+ +6 rows in set (0.06 sec) + +mysql> desc x$memory_by_user_by_current_bytes; ++--------------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++--------------------+---------------+------+-----+---------+-------+ +| user | varchar(32) | YES | | NULL | | +| current_count_used | decimal(41,0) | YES | | NULL | | +| current_allocated | decimal(41,0) | YES | | NULL | | +| current_avg_alloc | decimal(45,4) | NO | | 0.0000 | | +| current_max_alloc | bigint(20) | YES | | NULL | | +| total_allocated | decimal(42,0) | YES | | NULL | | ++--------------------+---------------+------+-----+---------+-------+ +6 rows in set (0.12 sec) +``` + +##### Example + +```SQL +mysql> select * from memory_by_user_by_current_bytes; ++------+--------------------+-------------------+-------------------+-------------------+-----------------+ +| user | current_count_used | current_allocated | current_avg_alloc | current_max_alloc | total_allocated | ++------+--------------------+-------------------+-------------------+-------------------+-----------------+ +| root | 1401 | 1.09 MiB | 815 bytes | 334.97 KiB | 42.73 MiB | +| mark | 201 | 496.08 KiB | 2.47 KiB | 334.97 KiB | 5.50 MiB | ++------+--------------------+-------------------+-------------------+-------------------+-----------------+ +``` + +#### memory_global_by_current_bytes / x$memory_global_by_current_bytes + +##### Description + +Shows the current memory usage within the server globally broken down by allocation type. + +##### Structures + +```SQL +mysql> desc memory_global_by_current_bytes; ++-------------------+--------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------------+--------------+------+-----+---------+-------+ +| event_name | varchar(128) | NO | | NULL | | +| current_count | bigint(20) | NO | | NULL | | +| current_alloc | text | YES | | NULL | | +| current_avg_alloc | text | YES | | NULL | | +| high_count | bigint(20) | NO | | NULL | | +| high_alloc | text | YES | | NULL | | +| high_avg_alloc | text | YES | | NULL | | ++-------------------+--------------+------+-----+---------+-------+ +7 rows in set (0.08 sec) + +mysql> desc x$memory_global_by_current_bytes; ++-------------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------------+---------------+------+-----+---------+-------+ +| event_name | varchar(128) | NO | | NULL | | +| current_count | bigint(20) | NO | | NULL | | +| current_alloc | bigint(20) | NO | | NULL | | +| current_avg_alloc | decimal(23,4) | NO | | 0.0000 | | +| high_count | bigint(20) | NO | | NULL | | +| high_alloc | bigint(20) | NO | | NULL | | +| high_avg_alloc | decimal(23,4) | NO | | 0.0000 | | ++-------------------+---------------+------+-----+---------+-------+ +7 rows in set (0.16 sec) +``` + +##### Example + +```SQL +mysql> select * from memory_global_by_current_bytes; ++----------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+ +| event_name | current_count | current_alloc | current_avg_alloc | high_count | high_alloc | high_avg_alloc | ++----------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+ +| memory/sql/TABLE_SHARE::mem_root | 269 | 568.21 KiB | 2.11 KiB | 339 | 706.04 KiB | 2.08 KiB | +| memory/sql/TABLE | 214 | 366.56 KiB | 1.71 KiB | 245 | 481.13 KiB | 1.96 KiB | +| memory/sql/sp_head::main_mem_root | 32 | 334.97 KiB | 10.47 KiB | 421 | 9.73 MiB | 23.66 KiB | +| memory/sql/Filesort_buffer::sort_keys | 1 | 255.89 KiB | 255.89 KiB | 1 | 256.00 KiB | 256.00 KiB | +| memory/mysys/array_buffer | 82 | 121.66 KiB | 1.48 KiB | 1124 | 852.55 KiB | 777 bytes | +... ++----------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+ +``` + +#### memory_global_total / x$memory_global_total + +##### Description + +Shows the total memory usage within the server globally. + +##### Structures + +```SQL +mysql> desc memory_global_total; ++-----------------+------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-----------------+------+------+-----+---------+-------+ +| total_allocated | text | YES | | NULL | | ++-----------------+------+------+-----+---------+-------+ +1 row in set (0.07 sec) + +mysql> desc x$memory_global_total; ++-----------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-----------------+---------------+------+-----+---------+-------+ +| total_allocated | decimal(41,0) | YES | | NULL | | ++-----------------+---------------+------+-----+---------+-------+ +1 row in set (0.00 sec) +``` + +##### Example + +```SQL +mysql> select * from memory_global_total; ++-----------------+ +| total_allocated | ++-----------------+ +| 458.44 MiB | ++-----------------+ +``` + +#### metrics + +##### Description + +Creates a union of the following information: + + * performance_schema.global_status (information_schema.GLOBAL_STATUS in MySQL 5.6) + * information_schema.INNODB_METRICS + * Performance Schema global memory usage information (only in MySQL 5.7) + * Current time + +In MySQL 5.7 it is required that performance_schema = ON, though there is no requirements to which +instruments and consumers that are enabled. See also the description of the Enabled column below. + +For view has the following columns: + + * Variable_name: The name of the variable + * Variable_value: The value of the variable + * Type: The type of the variable. This will depend on the source, e.g. Global Status, InnoDB Metrics - ..., etc. + * Enabled: Whether the variable is enabled or not. Possible values are 'YES', 'NO', 'PARTIAL'. + PARTIAL is currently only supported for the memory usage variables and means some but not all of the memory/% instruments are enabled. + +##### Structures + +```SQL +mysql> DESC metrics; ++----------------+--------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++----------------+--------------+------+-----+---------+-------+ +| Variable_name | varchar(193) | YES | | NULL | | +| Variable_value | text | YES | | NULL | | +| Type | varchar(210) | YES | | NULL | | +| Enabled | varchar(7) | NO | | | | ++----------------+--------------+------+-----+---------+-------+ +4 rows in set (0.00 sec) + +mysq> DESC metrics_56; ++----------------+--------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++----------------+--------------+------+-----+---------+-------+ +| Variable_name | varchar(193) | YES | | NULL | | +| Variable_value | text | YES | | NULL | | +| Type | varchar(210) | YES | | NULL | | +| Enabled | varchar(7) | NO | | | | ++----------------+--------------+------+-----+---------+-------+ +4 rows in set (0.01 sec) +``` + +##### Example + +```SQL +mysql> SELECT * FROM metrics; ++-----------------------------------------------+-------------------------...+--------------------------------------+---------+ +| Variable_name | Variable_value ...| Type | Enabled | ++-----------------------------------------------+-------------------------...+--------------------------------------+---------+ +| aborted_clients | 0 ...| Global Status | YES | +| aborted_connects | 0 ...| Global Status | YES | +| binlog_cache_disk_use | 0 ...| Global Status | YES | +| binlog_cache_use | 0 ...| Global Status | YES | +| binlog_stmt_cache_disk_use | 0 ...| Global Status | YES | +| binlog_stmt_cache_use | 0 ...| Global Status | YES | +| bytes_received | 217081 ...| Global Status | YES | +| bytes_sent | 27257 ...| Global Status | YES | +... +| innodb_rwlock_x_os_waits | 0 ...| InnoDB Metrics - server | YES | +| innodb_rwlock_x_spin_rounds | 2723 ...| InnoDB Metrics - server | YES | +| innodb_rwlock_x_spin_waits | 1 ...| InnoDB Metrics - server | YES | +| trx_active_transactions | 0 ...| InnoDB Metrics - transaction | NO | +... +| trx_rseg_current_size | 0 ...| InnoDB Metrics - transaction | NO | +| trx_rseg_history_len | 4 ...| InnoDB Metrics - transaction | YES | +| trx_rw_commits | 0 ...| InnoDB Metrics - transaction | NO | +| trx_undo_slots_cached | 0 ...| InnoDB Metrics - transaction | NO | +| trx_undo_slots_used | 0 ...| InnoDB Metrics - transaction | NO | +| memory_current_allocated | 138244216 ...| Performance Schema | PARTIAL | +| memory_total_allocated | 138244216 ...| Performance Schema | PARTIAL | +| NOW() | 2015-05-31 13:27:50.382 ...| System Time | YES | +| UNIX_TIMESTAMP() | 1433042870.382 ...| System Time | YES | ++-----------------------------------------------+-------------------------...+--------------------------------------+---------+ +412 rows in set (0.02 sec) +``` + +#### processlist / x$processlist + +##### Description + +A detailed non-blocking processlist view to replace [INFORMATION_SCHEMA. | SHOW FULL] PROCESSLIST. + +Performs less locking than the legacy sources, whilst giving extra information. + +The output includes both background threads and user connections by default. See also `session` / `x$session` +for a view that contains only user session information. + +##### Structures (5.7) + +```SQL +mysql> desc processlist; ++------------------------+------------------------------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------------------+------------------------------------------+------+-----+---------+-------+ +| thd_id | bigint(20) unsigned | NO | | NULL | | +| conn_id | bigint(20) unsigned | YES | | NULL | | +| user | varchar(128) | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| command | varchar(16) | YES | | NULL | | +| state | varchar(64) | YES | | NULL | | +| time | bigint(20) | YES | | NULL | | +| current_statement | longtext | YES | | NULL | | +| statement_latency | text | YES | | NULL | | +| progress | decimal(26,2) | YES | | NULL | | +| lock_latency | text | YES | | NULL | | +| rows_examined | bigint(20) unsigned | YES | | NULL | | +| rows_sent | bigint(20) unsigned | YES | | NULL | | +| rows_affected | bigint(20) unsigned | YES | | NULL | | +| tmp_tables | bigint(20) unsigned | YES | | NULL | | +| tmp_disk_tables | bigint(20) unsigned | YES | | NULL | | +| full_scan | varchar(3) | NO | | | | +| last_statement | longtext | YES | | NULL | | +| last_statement_latency | text | YES | | NULL | | +| current_memory | text | YES | | NULL | | +| last_wait | varchar(128) | YES | | NULL | | +| last_wait_latency | text | YES | | NULL | | +| source | varchar(64) | YES | | NULL | | +| trx_latency | text | YES | | NULL | | +| trx_state | enum('ACTIVE','COMMITTED','ROLLED BACK') | YES | | NULL | | +| trx_autocommit | enum('YES','NO') | YES | | NULL | | +| pid | varchar(1024) | YES | | NULL | | +| program_name | varchar(1024) | YES | | NULL | | ++------------------------+------------------------------------------+------+-----+---------+-------+ +28 rows in set (0.04 sec) + +mysql> desc x$processlist; ++------------------------+------------------------------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------------------+------------------------------------------+------+-----+---------+-------+ +| thd_id | bigint(20) unsigned | NO | | NULL | | +| conn_id | bigint(20) unsigned | YES | | NULL | | +| user | varchar(128) | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| command | varchar(16) | YES | | NULL | | +| state | varchar(64) | YES | | NULL | | +| time | bigint(20) | YES | | NULL | | +| current_statement | longtext | YES | | NULL | | +| statement_latency | bigint(20) unsigned | YES | | NULL | | +| progress | decimal(26,2) | YES | | NULL | | +| lock_latency | bigint(20) unsigned | YES | | NULL | | +| rows_examined | bigint(20) unsigned | YES | | NULL | | +| rows_sent | bigint(20) unsigned | YES | | NULL | | +| rows_affected | bigint(20) unsigned | YES | | NULL | | +| tmp_tables | bigint(20) unsigned | YES | | NULL | | +| tmp_disk_tables | bigint(20) unsigned | YES | | NULL | | +| full_scan | varchar(3) | NO | | | | +| last_statement | longtext | YES | | NULL | | +| last_statement_latency | bigint(20) unsigned | YES | | NULL | | +| current_memory | decimal(41,0) | YES | | NULL | | +| last_wait | varchar(128) | YES | | NULL | | +| last_wait_latency | varchar(20) | YES | | NULL | | +| source | varchar(64) | YES | | NULL | | +| trx_latency | bigint(20) unsigned | YES | | NULL | | +| trx_state | enum('ACTIVE','COMMITTED','ROLLED BACK') | YES | | NULL | | +| trx_autocommit | enum('YES','NO') | YES | | NULL | | +| pid | varchar(1024) | YES | | NULL | | +| program_name | varchar(1024) | YES | | NULL | | ++------------------------+------------------------------------------+------+-----+---------+-------+ +28 rows in set (0.01 sec) +``` + +##### Example + +```SQL +mysql> select * from sys.processlist where conn_id is not null and command != 'daemon' and conn_id != connection_id()\G +*************************** 1. row *************************** + thd_id: 44524 + conn_id: 44502 + user: msandbox@localhost + db: test + command: Query + state: alter table (flush) + time: 18 + current_statement: alter table t1 add column g int + statement_latency: 18.45 s + progress: 98.84 + lock_latency: 265.43 ms + rows_examined: 0 + rows_sent: 0 + rows_affected: 0 + tmp_tables: 0 + tmp_disk_tables: 0 + full_scan: NO + last_statement: NULL +last_statement_latency: NULL + current_memory: 664.06 KiB + last_wait: wait/io/file/innodb/innodb_data_file + last_wait_latency: 1.07 us + source: fil0fil.cc:5146 + trx_latency: NULL + trx_state: NULL + trx_autocommit: NULL + pid: 4212 + program_name: mysql +``` + +#### ps_check_lost_instrumentation + +##### Description + +Used to check whether Performance Schema is not able to monitor all runtime data - only returns variables that have lost instruments + +##### Structure + +```SQL +mysql> desc ps_check_lost_instrumentation; ++----------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++----------------+---------------+------+-----+---------+-------+ +| variable_name | varchar(64) | NO | | | | +| variable_value | varchar(1024) | YES | | NULL | | ++----------------+---------------+------+-----+---------+-------+ +2 rows in set (0.09 sec) +``` + +##### Example + +```SQL +mysql> select * from ps_check_lost_instrumentation; ++----------------------------------------+----------------+ +| variable_name | variable_value | ++----------------------------------------+----------------+ +| Performance_schema_file_handles_lost | 101223 | +| Performance_schema_file_instances_lost | 1231 | ++----------------------------------------+----------------+ +``` + +#### schema_auto_increment_columns + +##### Description + +Present current auto_increment usage/capacity in all tables. + +##### Structures + +```SQL +mysql> desc schema_auto_increment_columns; ++----------------------+------------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++----------------------+------------------------+------+-----+---------+-------+ +| table_schema | varchar(64) | NO | | | | +| table_name | varchar(64) | NO | | | | +| column_name | varchar(64) | NO | | | | +| data_type | varchar(64) | NO | | | | +| column_type | longtext | NO | | NULL | | +| is_signed | int(1) | NO | | 0 | | +| is_unsigned | int(1) | NO | | 0 | | +| max_value | bigint(21) unsigned | YES | | NULL | | +| auto_increment | bigint(21) unsigned | YES | | NULL | | +| auto_increment_ratio | decimal(25,4) unsigned | YES | | NULL | | ++----------------------+------------------------+------+-----+---------+-------+ +``` + +##### Example + +```SQL +mysql> select * from schema_auto_increment_columns limit 5; ++-------------------+-------------------+-------------+-----------+-------------+-----------+-------------+---------------------+----------------+----------------------+ +| table_schema | table_name | column_name | data_type | column_type | is_signed | is_unsigned | max_value | auto_increment | auto_increment_ratio | ++-------------------+-------------------+-------------+-----------+-------------+-----------+-------------+---------------------+----------------+----------------------+ +| test | t1 | i | tinyint | tinyint(4) | 1 | 0 | 127 | 34 | 0.2677 | +| mem__advisor_text | template_meta | hib_id | int | int(11) | 1 | 0 | 2147483647 | 516 | 0.0000 | +| mem__advisors | advisor_schedules | schedule_id | int | int(11) | 1 | 0 | 2147483647 | 249 | 0.0000 | +| mem__advisors | app_identity_path | hib_id | int | int(11) | 1 | 0 | 2147483647 | 251 | 0.0000 | +| mem__bean_config | plists | id | bigint | bigint(20) | 1 | 0 | 9223372036854775807 | 1 | 0.0000 | ++-------------------+-------------------+-------------+-----------+-------------+-----------+-------------+---------------------+----------------+----------------------+ +``` + +#### schema_index_statistics / x$schema_index_statistics + +##### Description + +Statistics around indexes. + +Ordered by the total wait time descending - top indexes are most contended. + +##### Structures + +```SQL +mysql> desc schema_index_statistics; ++----------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++----------------+---------------------+------+-----+---------+-------+ +| table_schema | varchar(64) | YES | | NULL | | +| table_name | varchar(64) | YES | | NULL | | +| index_name | varchar(64) | YES | | NULL | | +| rows_selected | bigint(20) unsigned | NO | | NULL | | +| select_latency | text | YES | | NULL | | +| rows_inserted | bigint(20) unsigned | NO | | NULL | | +| insert_latency | text | YES | | NULL | | +| rows_updated | bigint(20) unsigned | NO | | NULL | | +| update_latency | text | YES | | NULL | | +| rows_deleted | bigint(20) unsigned | NO | | NULL | | +| delete_latency | text | YES | | NULL | | ++----------------+---------------------+------+-----+---------+-------+ +11 rows in set (0.17 sec) + +mysql> desc x$schema_index_statistics; ++----------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++----------------+---------------------+------+-----+---------+-------+ +| table_schema | varchar(64) | YES | | NULL | | +| table_name | varchar(64) | YES | | NULL | | +| index_name | varchar(64) | YES | | NULL | | +| rows_selected | bigint(20) unsigned | NO | | NULL | | +| select_latency | bigint(20) unsigned | NO | | NULL | | +| rows_inserted | bigint(20) unsigned | NO | | NULL | | +| insert_latency | bigint(20) unsigned | NO | | NULL | | +| rows_updated | bigint(20) unsigned | NO | | NULL | | +| update_latency | bigint(20) unsigned | NO | | NULL | | +| rows_deleted | bigint(20) unsigned | NO | | NULL | | +| delete_latency | bigint(20) unsigned | NO | | NULL | | ++----------------+---------------------+------+-----+---------+-------+ +11 rows in set (0.42 sec) +``` + +##### Example + +```SQL +mysql> select * from schema_index_statistics limit 5; ++------------------+-------------+------------+---------------+----------------+---------------+----------------+--------------+----------------+--------------+----------------+ +| table_schema | table_name | index_name | rows_selected | select_latency | rows_inserted | insert_latency | rows_updated | update_latency | rows_deleted | delete_latency | ++------------------+-------------+------------+---------------+----------------+---------------+----------------+--------------+----------------+--------------+----------------+ +| mem | mysqlserver | PRIMARY | 6208 | 108.27 ms | 0 | 0 ps | 5470 | 1.47 s | 0 | 0 ps | +| mem | innodb | PRIMARY | 4666 | 76.27 ms | 0 | 0 ps | 4454 | 571.47 ms | 0 | 0 ps | +| mem | connection | PRIMARY | 1064 | 20.98 ms | 0 | 0 ps | 1064 | 457.30 ms | 0 | 0 ps | +| mem | environment | PRIMARY | 5566 | 151.17 ms | 0 | 0 ps | 694 | 252.57 ms | 0 | 0 ps | +| mem | querycache | PRIMARY | 1698 | 27.99 ms | 0 | 0 ps | 1698 | 371.72 ms | 0 | 0 ps | ++------------------+-------------+------------+---------------+----------------+---------------+----------------+--------------+----------------+--------------+----------------+ +``` + +#### schema_object_overview + +##### Description + +Shows an overview of the types of objects within each schema + +Note: On instances with a large numbers of objects, this could take some time to execute, and may not be recommended. + +##### Structure + +```SQL +mysql> desc schema_object_overview; ++-------------+-------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------+-------------+------+-----+---------+-------+ +| db | varchar(64) | NO | | | | +| object_type | varchar(64) | NO | | | | +| count | bigint(21) | NO | | 0 | | ++-------------+-------------+------+-----+---------+-------+ +3 rows in set (0.08 sec) +``` + +##### Example + +```SQL +mysql> select * from schema_object_overview; ++--------------------+---------------+-------+ +| db | object_type | count | ++--------------------+---------------+-------+ +| information_schema | SYSTEM VIEW | 60 | +| mysql | BASE TABLE | 31 | +| mysql | INDEX (BTREE) | 69 | +| performance_schema | BASE TABLE | 76 | +| sys | BASE TABLE | 1 | +| sys | FUNCTION | 12 | +| sys | INDEX (BTREE) | 1 | +| sys | PROCEDURE | 22 | +| sys | TRIGGER | 2 | +| sys | VIEW | 91 | ++--------------------+---------------+-------+ +10 rows in set (1.58 sec) +``` + +#### schema_table_statistics / x$schema_table_statistics + +##### Description + +Statistics around tables. + +Ordered by the total wait time descending - top tables are most contended. + +Also includes the helper view (used by schema_table_statistics_with_buffer as well): + +* x$ps_schema_table_statistics_io + +##### Structures + +```SQL +mysql> desc schema_table_statistics; ++-------------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------------+---------------------+------+-----+---------+-------+ +| table_schema | varchar(64) | YES | | NULL | | +| table_name | varchar(64) | YES | | NULL | | +| total_latency | text | YES | | NULL | | +| rows_fetched | bigint(20) unsigned | NO | | NULL | | +| fetch_latency | text | YES | | NULL | | +| rows_inserted | bigint(20) unsigned | NO | | NULL | | +| insert_latency | text | YES | | NULL | | +| rows_updated | bigint(20) unsigned | NO | | NULL | | +| update_latency | text | YES | | NULL | | +| rows_deleted | bigint(20) unsigned | NO | | NULL | | +| delete_latency | text | YES | | NULL | | +| io_read_requests | decimal(42,0) | YES | | NULL | | +| io_read | text | YES | | NULL | | +| io_read_latency | text | YES | | NULL | | +| io_write_requests | decimal(42,0) | YES | | NULL | | +| io_write | text | YES | | NULL | | +| io_write_latency | text | YES | | NULL | | +| io_misc_requests | decimal(42,0) | YES | | NULL | | +| io_misc_latency | text | YES | | NULL | | ++-------------------+---------------------+------+-----+---------+-------+ +19 rows in set (0.12 sec) + +mysql> desc x$schema_table_statistics; ++-------------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------------+---------------------+------+-----+---------+-------+ +| table_schema | varchar(64) | YES | | NULL | | +| table_name | varchar(64) | YES | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| rows_fetched | bigint(20) unsigned | NO | | NULL | | +| fetch_latency | bigint(20) unsigned | NO | | NULL | | +| rows_inserted | bigint(20) unsigned | NO | | NULL | | +| insert_latency | bigint(20) unsigned | NO | | NULL | | +| rows_updated | bigint(20) unsigned | NO | | NULL | | +| update_latency | bigint(20) unsigned | NO | | NULL | | +| rows_deleted | bigint(20) unsigned | NO | | NULL | | +| delete_latency | bigint(20) unsigned | NO | | NULL | | +| io_read_requests | decimal(42,0) | YES | | NULL | | +| io_read | decimal(41,0) | YES | | NULL | | +| io_read_latency | decimal(42,0) | YES | | NULL | | +| io_write_requests | decimal(42,0) | YES | | NULL | | +| io_write | decimal(41,0) | YES | | NULL | | +| io_write_latency | decimal(42,0) | YES | | NULL | | +| io_misc_requests | decimal(42,0) | YES | | NULL | | +| io_misc_latency | decimal(42,0) | YES | | NULL | | ++-------------------+---------------------+------+-----+---------+-------+ +19 rows in set (0.13 sec) + +mysql> desc x$ps_schema_table_statistics_io; ++---------------------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------------------+---------------+------+-----+---------+-------+ +| table_schema | varchar(64) | YES | | NULL | | +| table_name | varchar(64) | YES | | NULL | | +| count_read | decimal(42,0) | YES | | NULL | | +| sum_number_of_bytes_read | decimal(41,0) | YES | | NULL | | +| sum_timer_read | decimal(42,0) | YES | | NULL | | +| count_write | decimal(42,0) | YES | | NULL | | +| sum_number_of_bytes_write | decimal(41,0) | YES | | NULL | | +| sum_timer_write | decimal(42,0) | YES | | NULL | | +| count_misc | decimal(42,0) | YES | | NULL | | +| sum_timer_misc | decimal(42,0) | YES | | NULL | | ++---------------------------+---------------+------+-----+---------+-------+ +10 rows in set (0.10 sec) +``` + +##### Example + +```SQL +mysql> select * from schema_table_statistics\G +*************************** 1. row *************************** + table_schema: sys + table_name: sys_config + total_latency: 0 ps + rows_fetched: 0 + fetch_latency: 0 ps + rows_inserted: 0 + insert_latency: 0 ps + rows_updated: 0 + update_latency: 0 ps + rows_deleted: 0 + delete_latency: 0 ps + io_read_requests: 8 + io_read: 2.28 KiB + io_read_latency: 727.32 us +io_write_requests: 0 + io_write: 0 bytes + io_write_latency: 0 ps + io_misc_requests: 10 + io_misc_latency: 126.88 us +``` + +#### schema_redundant_indexes / x$schema_flattened_keys + +##### Description + +Shows indexes which are made redundant (or duplicate) by other (dominant) keys. + +Also includes the the helper view `x$schema_flattened_keys`. + +##### Structures + +```SQL +mysql> desc sys.schema_redundant_indexes; ++----------------------------+--------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++----------------------------+--------------+------+-----+---------+-------+ +| table_schema | varchar(64) | NO | | | | +| table_name | varchar(64) | NO | | | | +| redundant_index_name | varchar(64) | NO | | | | +| redundant_index_columns | text | YES | | NULL | | +| redundant_index_non_unique | bigint(1) | YES | | NULL | | +| dominant_index_name | varchar(64) | NO | | | | +| dominant_index_columns | text | YES | | NULL | | +| dominant_index_non_unique | bigint(1) | YES | | NULL | | +| subpart_exists | int(1) | NO | | 0 | | +| sql_drop_index | varchar(223) | YES | | NULL | | ++----------------------------+--------------+------+-----+---------+-------+ +10 rows in set (0.00 sec) + +mysql> desc sys.x$schema_flattened_keys; ++----------------+-------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++----------------+-------------+------+-----+---------+-------+ +| table_schema | varchar(64) | NO | | | | +| table_name | varchar(64) | NO | | | | +| index_name | varchar(64) | NO | | | | +| non_unique | bigint(1) | YES | | NULL | | +| subpart_exists | bigint(1) | YES | | NULL | | +| index_columns | text | YES | | NULL | | ++----------------+-------------+------+-----+---------+-------+ +6 rows in set (0.00 sec) +``` + +##### Example + +```SQL +mysql> select * from sys.schema_redundant_indexes\G +*************************** 1. row *************************** + table_schema: test + table_name: rkey + redundant_index_name: j + redundant_index_columns: j +redundant_index_non_unique: 1 + dominant_index_name: j_2 + dominant_index_columns: j,k + dominant_index_non_unique: 1 + subpart_exists: 0 + sql_drop_index: ALTER TABLE `test`.`rkey` DROP INDEX `j` +1 row in set (0.20 sec) + +mysql> SHOW CREATE TABLE test.rkey\G +*************************** 1. row *************************** + Table: rkey +Create Table: CREATE TABLE `rkey` ( + `i` int(11) NOT NULL, + `j` int(11) DEFAULT NULL, + `k` int(11) DEFAULT NULL, + PRIMARY KEY (`i`), + KEY `j` (`j`), + KEY `j_2` (`j`,`k`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +1 row in set (0.06 sec) +``` + +#### schema_table_lock_waits / x$schema_table_lock_waits + +##### Description + +Shows sessions that are blocked waiting on table metadata locks, and who is blocking them. + +##### Structures + +```SQL +mysql> desc schema_table_lock_waits; ++------------------------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------------------------+---------------------+------+-----+---------+-------+ +| object_schema | varchar(64) | YES | | NULL | | +| object_name | varchar(64) | YES | | NULL | | +| waiting_thread_id | bigint(20) unsigned | NO | | NULL | | +| waiting_pid | bigint(20) unsigned | YES | | NULL | | +| waiting_account | text | YES | | NULL | | +| waiting_lock_type | varchar(32) | NO | | NULL | | +| waiting_lock_duration | varchar(32) | NO | | NULL | | +| waiting_query | longtext | YES | | NULL | | +| waiting_query_secs | bigint(20) | YES | | NULL | | +| waiting_query_rows_affected | bigint(20) unsigned | YES | | NULL | | +| waiting_query_rows_examined | bigint(20) unsigned | YES | | NULL | | +| blocking_thread_id | bigint(20) unsigned | NO | | NULL | | +| blocking_pid | bigint(20) unsigned | YES | | NULL | | +| blocking_account | text | YES | | NULL | | +| blocking_lock_type | varchar(32) | NO | | NULL | | +| blocking_lock_duration | varchar(32) | NO | | NULL | | +| sql_kill_blocking_query | varchar(31) | YES | | NULL | | +| sql_kill_blocking_connection | varchar(25) | YES | | NULL | | ++------------------------------+---------------------+------+-----+---------+-------+ +18 rows in set (0.15 sec) + +mysql> desc x$schema_table_lock_waits; ++------------------------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------------------------+---------------------+------+-----+---------+-------+ +| object_schema | varchar(64) | YES | | NULL | | +| object_name | varchar(64) | YES | | NULL | | +| waiting_thread_id | bigint(20) unsigned | NO | | NULL | | +| waiting_pid | bigint(20) unsigned | YES | | NULL | | +| waiting_account | text | YES | | NULL | | +| waiting_lock_type | varchar(32) | NO | | NULL | | +| waiting_lock_duration | varchar(32) | NO | | NULL | | +| waiting_query | longtext | YES | | NULL | | +| waiting_query_secs | bigint(20) | YES | | NULL | | +| waiting_query_rows_affected | bigint(20) unsigned | YES | | NULL | | +| waiting_query_rows_examined | bigint(20) unsigned | YES | | NULL | | +| blocking_thread_id | bigint(20) unsigned | NO | | NULL | | +| blocking_pid | bigint(20) unsigned | YES | | NULL | | +| blocking_account | text | YES | | NULL | | +| blocking_lock_type | varchar(32) | NO | | NULL | | +| blocking_lock_duration | varchar(32) | NO | | NULL | | +| sql_kill_blocking_query | varchar(31) | YES | | NULL | | +| sql_kill_blocking_connection | varchar(25) | YES | | NULL | | ++------------------------------+---------------------+------+-----+---------+-------+ +18 rows in set (0.03 sec) +``` + +##### Example + +```SQL +mysql> select * from sys.schema_table_lock_waits\G +*************************** 1. row *************************** + object_schema: test + object_name: t + waiting_thread_id: 43 + waiting_pid: 21 + waiting_account: msandbox@localhost + waiting_lock_type: SHARED_UPGRADABLE + waiting_lock_duration: TRANSACTION + waiting_query: alter table test.t add foo int + waiting_query_secs: 988 + waiting_query_rows_affected: 0 + waiting_query_rows_examined: 0 + blocking_thread_id: 42 + blocking_pid: 20 + blocking_account: msandbox@localhost + blocking_lock_type: SHARED_NO_READ_WRITE + blocking_lock_duration: TRANSACTION + sql_kill_blocking_query: KILL QUERY 20 +sql_kill_blocking_connection: KILL 20 +``` + +#### schema_table_statistics_with_buffer / x$schema_table_statistics_with_buffer + +##### Description + +Statistics around tables. + +Ordered by the total wait time descending - top tables are most contended. + +More statistics such as caching stats for the InnoDB buffer pool with InnoDB tables + +Uses the x$ps_schema_table_statistics_io helper view from schema_table_statistics. + +##### Structures + +```SQL +mysql> desc schema_table_statistics_with_buffer; ++----------------------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++----------------------------+---------------------+------+-----+---------+-------+ +| table_schema | varchar(64) | YES | | NULL | | +| table_name | varchar(64) | YES | | NULL | | +| rows_fetched | bigint(20) unsigned | NO | | NULL | | +| fetch_latency | text | YES | | NULL | | +| rows_inserted | bigint(20) unsigned | NO | | NULL | | +| insert_latency | text | YES | | NULL | | +| rows_updated | bigint(20) unsigned | NO | | NULL | | +| update_latency | text | YES | | NULL | | +| rows_deleted | bigint(20) unsigned | NO | | NULL | | +| delete_latency | text | YES | | NULL | | +| io_read_requests | decimal(42,0) | YES | | NULL | | +| io_read | text | YES | | NULL | | +| io_read_latency | text | YES | | NULL | | +| io_write_requests | decimal(42,0) | YES | | NULL | | +| io_write | text | YES | | NULL | | +| io_write_latency | text | YES | | NULL | | +| io_misc_requests | decimal(42,0) | YES | | NULL | | +| io_misc_latency | text | YES | | NULL | | +| innodb_buffer_allocated | text | YES | | NULL | | +| innodb_buffer_data | text | YES | | NULL | | +| innodb_buffer_free | text | YES | | NULL | | +| innodb_buffer_pages | bigint(21) | YES | | 0 | | +| innodb_buffer_pages_hashed | bigint(21) | YES | | 0 | | +| innodb_buffer_pages_old | bigint(21) | YES | | 0 | | +| innodb_buffer_rows_cached | decimal(44,0) | YES | | 0 | | ++----------------------------+---------------------+------+-----+---------+-------+ +25 rows in set (0.05 sec) + +mysql> desc x$schema_table_statistics_with_buffer; ++----------------------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++----------------------------+---------------------+------+-----+---------+-------+ +| table_schema | varchar(64) | YES | | NULL | | +| table_name | varchar(64) | YES | | NULL | | +| rows_fetched | bigint(20) unsigned | NO | | NULL | | +| fetch_latency | bigint(20) unsigned | NO | | NULL | | +| rows_inserted | bigint(20) unsigned | NO | | NULL | | +| insert_latency | bigint(20) unsigned | NO | | NULL | | +| rows_updated | bigint(20) unsigned | NO | | NULL | | +| update_latency | bigint(20) unsigned | NO | | NULL | | +| rows_deleted | bigint(20) unsigned | NO | | NULL | | +| delete_latency | bigint(20) unsigned | NO | | NULL | | +| io_read_requests | decimal(42,0) | YES | | NULL | | +| io_read | decimal(41,0) | YES | | NULL | | +| io_read_latency | decimal(42,0) | YES | | NULL | | +| io_write_requests | decimal(42,0) | YES | | NULL | | +| io_write | decimal(41,0) | YES | | NULL | | +| io_write_latency | decimal(42,0) | YES | | NULL | | +| io_misc_requests | decimal(42,0) | YES | | NULL | | +| io_misc_latency | decimal(42,0) | YES | | NULL | | +| innodb_buffer_allocated | decimal(43,0) | YES | | NULL | | +| innodb_buffer_data | decimal(43,0) | YES | | NULL | | +| innodb_buffer_free | decimal(44,0) | YES | | NULL | | +| innodb_buffer_pages | bigint(21) | YES | | 0 | | +| innodb_buffer_pages_hashed | bigint(21) | YES | | 0 | | +| innodb_buffer_pages_old | bigint(21) | YES | | 0 | | +| innodb_buffer_rows_cached | decimal(44,0) | YES | | 0 | | ++----------------------------+---------------------+------+-----+---------+-------+ +25 rows in set (0.17 sec) +``` + +##### Example + +```SQL +mysql> select * from schema_table_statistics_with_buffer limit 1\G +*************************** 1. row *************************** + table_schema: mem + table_name: mysqlserver + rows_fetched: 27087 + fetch_latency: 442.72 ms + rows_inserted: 2 + insert_latency: 185.04 us + rows_updated: 5096 + update_latency: 1.39 s + rows_deleted: 0 + delete_latency: 0 ps + io_read_requests: 2565 + io_read_bytes: 1121627 + io_read_latency: 10.07 ms + io_write_requests: 1691 + io_write_bytes: 128383 + io_write_latency: 14.17 ms + io_misc_requests: 2698 + io_misc_latency: 433.66 ms + innodb_buffer_pages: 19 + innodb_buffer_pages_hashed: 19 + innodb_buffer_pages_old: 19 +innodb_buffer_bytes_allocated: 311296 + innodb_buffer_bytes_data: 1924 + innodb_buffer_rows_cached: 2 +``` + +#### schema_tables_with_full_table_scans / x$schema_tables_with_full_table_scans + +##### Description + +Finds tables that are being accessed by full table scans ordering by the number of rows scanned descending. + +##### Structures + +```SQL +mysql> desc schema_tables_with_full_table_scans; ++-------------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------------+---------------------+------+-----+---------+-------+ +| object_schema | varchar(64) | YES | | NULL | | +| object_name | varchar(64) | YES | | NULL | | +| rows_full_scanned | bigint(20) unsigned | NO | | NULL | | +| latency | text | YES | | NULL | | ++-------------------+---------------------+------+-----+---------+-------+ +4 rows in set (0.02 sec) + +mysql> desc x$schema_tables_with_full_table_scans; ++-------------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------------+---------------------+------+-----+---------+-------+ +| object_schema | varchar(64) | YES | | NULL | | +| object_name | varchar(64) | YES | | NULL | | +| rows_full_scanned | bigint(20) unsigned | NO | | NULL | | +| latency | bigint(20) unsigned | NO | | NULL | | ++-------------------+---------------------+------+-----+---------+-------+ +4 rows in set (0.03 sec) +``` + +##### Example + +```SQL +mysql> select * from schema_tables_with_full_table_scans limit 5; ++--------------------+--------------------------------+-------------------+-----------+ +| object_schema | object_name | rows_full_scanned | latency | ++--------------------+--------------------------------+-------------------+-----------+ +| mem30__instruments | fsstatistics | 10207042 | 13.10 s | +| mem30__instruments | preparedstatementapidata | 436428 | 973.27 ms | +| mem30__instruments | mysqlprocessactivity | 411702 | 282.07 ms | +| mem30__instruments | querycachequeriesincachedata | 374011 | 767.15 ms | +| mem30__instruments | rowaccessesdata | 322321 | 1.55 s | ++--------------------+--------------------------------+-------------------+-----------+ +``` + +#### schema_unused_indexes + +##### Description + +Finds indexes that have had no events against them (and hence, no usage). + +To trust whether the data from this view is representative of your workload, you should ensure that the server has been up for a representative amount of time before using it. + +PRIMARY (key) indexes are ignored. + +##### Structure + +```SQL +mysql> desc schema_unused_indexes; ++---------------+-------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+-------------+------+-----+---------+-------+ +| object_schema | varchar(64) | YES | | NULL | | +| object_name | varchar(64) | YES | | NULL | | +| index_name | varchar(64) | YES | | NULL | | ++---------------+-------------+------+-----+---------+-------+ +3 rows in set (0.09 sec) +``` + +##### Example + +```SQL +mysql> select * from schema_unused_indexes limit 5; ++--------------------+---------------------+--------------------+ +| object_schema | object_name | index_name | ++--------------------+---------------------+--------------------+ +| mem30__bean_config | plists | path | +| mem30__config | group_selections | name | +| mem30__config | notification_groups | name | +| mem30__config | user_form_defaults | FKC1AEF1F9E7EE2CFB | +| mem30__enterprise | whats_new_entries | entryId | ++--------------------+---------------------+--------------------+ +``` + +#### session / x$session + +##### Description + +A detailed non-blocking processlist view to replace [INFORMATION_SCHEMA. | SHOW FULL] PROCESSLIST. + +Performs less locking than the legacy sources, whilst giving extra information. + +The output of this view is restricted to threads from user sessions. See also processlist / x$processlist which contains both user and background threads. + +##### Structures (5.7) + +```SQL +mysql> desc session; ++------------------------+------------------------------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------------------+------------------------------------------+------+-----+---------+-------+ +| thd_id | bigint(20) unsigned | NO | | NULL | | +| conn_id | bigint(20) unsigned | YES | | NULL | | +| user | varchar(128) | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| command | varchar(16) | YES | | NULL | | +| state | varchar(64) | YES | | NULL | | +| time | bigint(20) | YES | | NULL | | +| current_statement | longtext | YES | | NULL | | +| statement_latency | text | YES | | NULL | | +| progress | decimal(26,2) | YES | | NULL | | +| lock_latency | text | YES | | NULL | | +| rows_examined | bigint(20) unsigned | YES | | NULL | | +| rows_sent | bigint(20) unsigned | YES | | NULL | | +| rows_affected | bigint(20) unsigned | YES | | NULL | | +| tmp_tables | bigint(20) unsigned | YES | | NULL | | +| tmp_disk_tables | bigint(20) unsigned | YES | | NULL | | +| full_scan | varchar(3) | NO | | | | +| last_statement | longtext | YES | | NULL | | +| last_statement_latency | text | YES | | NULL | | +| current_memory | text | YES | | NULL | | +| last_wait | varchar(128) | YES | | NULL | | +| last_wait_latency | text | YES | | NULL | | +| source | varchar(64) | YES | | NULL | | +| trx_latency | text | YES | | NULL | | +| trx_state | enum('ACTIVE','COMMITTED','ROLLED BACK') | YES | | NULL | | +| trx_autocommit | enum('YES','NO') | YES | | NULL | | +| pid | varchar(1024) | YES | | NULL | | +| program_name | varchar(1024) | YES | | NULL | | ++------------------------+------------------------------------------+------+-----+---------+-------+ +28 rows in set (0.00 sec) + +mysql> desc x$session; ++------------------------+------------------------------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------------------+------------------------------------------+------+-----+---------+-------+ +| thd_id | bigint(20) unsigned | NO | | NULL | | +| conn_id | bigint(20) unsigned | YES | | NULL | | +| user | varchar(128) | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| command | varchar(16) | YES | | NULL | | +| state | varchar(64) | YES | | NULL | | +| time | bigint(20) | YES | | NULL | | +| current_statement | longtext | YES | | NULL | | +| statement_latency | bigint(20) unsigned | YES | | NULL | | +| progress | decimal(26,2) | YES | | NULL | | +| lock_latency | bigint(20) unsigned | YES | | NULL | | +| rows_examined | bigint(20) unsigned | YES | | NULL | | +| rows_sent | bigint(20) unsigned | YES | | NULL | | +| rows_affected | bigint(20) unsigned | YES | | NULL | | +| tmp_tables | bigint(20) unsigned | YES | | NULL | | +| tmp_disk_tables | bigint(20) unsigned | YES | | NULL | | +| full_scan | varchar(3) | NO | | | | +| last_statement | longtext | YES | | NULL | | +| last_statement_latency | bigint(20) unsigned | YES | | NULL | | +| current_memory | decimal(41,0) | YES | | NULL | | +| last_wait | varchar(128) | YES | | NULL | | +| last_wait_latency | varchar(20) | YES | | NULL | | +| source | varchar(64) | YES | | NULL | | +| trx_latency | bigint(20) unsigned | YES | | NULL | | +| trx_state | enum('ACTIVE','COMMITTED','ROLLED BACK') | YES | | NULL | | +| trx_autocommit | enum('YES','NO') | YES | | NULL | | +| pid | varchar(1024) | YES | | NULL | | +| program_name | varchar(1024) | YES | | NULL | | ++------------------------+------------------------------------------+------+-----+---------+-------+ +28 rows in set (0.00 sec) +``` + +##### Example + +```SQL +mysql> select * from sys.session\G +*************************** 1. row *************************** + thd_id: 24 + conn_id: 2 + user: root@localhost + db: sys + command: Query + state: Sending data + time: 0 + current_statement: select * from sys.session + statement_latency: 137.22 ms + progress: NULL + lock_latency: 33.75 ms + rows_examined: 0 + rows_sent: 0 + rows_affected: 0 + tmp_tables: 4 + tmp_disk_tables: 1 + full_scan: YES + last_statement: NULL +last_statement_latency: NULL + current_memory: 3.26 MiB + last_wait: wait/synch/mutex/innodb/file_format_max_mutex + last_wait_latency: 64.09 ns + source: trx0sys.cc:778 + trx_latency: 7.88 s + trx_state: ACTIVE + trx_autocommit: NO + pid: 4212 + program_name: mysql +``` + +#### session_ssl_status + +##### Description + +Shows SSL version, cipher and the count of re-used SSL sessions per connection + +##### Structures + +```SQL +mysql> desc sys.session_ssl_status; ++---------------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------------+---------------------+------+-----+---------+-------+ +| thread_id | bigint(20) unsigned | NO | | NULL | | +| ssl_version | varchar(1024) | YES | | NULL | | +| ssl_cipher | varchar(1024) | YES | | NULL | | +| ssl_sessions_reused | varchar(1024) | YES | | NULL | | ++---------------------+---------------------+------+-----+---------+-------+ +4 rows in set (0.00 sec) +``` + +##### Example + +```SQL +mysql> select * from session_ssl_status; ++-----------+-------------+--------------------+---------------------+ +| thread_id | ssl_version | ssl_cipher | ssl_sessions_reused | ++-----------+-------------+--------------------+---------------------+ +| 26 | TLSv1 | DHE-RSA-AES256-SHA | 0 | +| 27 | TLSv1 | DHE-RSA-AES256-SHA | 0 | +| 28 | TLSv1 | DHE-RSA-AES256-SHA | 0 | ++-----------+-------------+--------------------+---------------------+ +3 rows in set (0.00 sec) +``` + +#### statement_analysis / x$statement_analysis + +##### Description + +Lists a normalized statement view with aggregated statistics, mimics the MySQL Enterprise Monitor Query Analysis view, ordered by the total execution time per normalized statement + +##### Structures + +```SQL +mysql> desc statement_analysis; ++-------------------+---------------------+------+-----+---------------------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------------+---------------------+------+-----+---------------------+-------+ +| query | longtext | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| full_scan | varchar(1) | NO | | | | +| exec_count | bigint(20) unsigned | NO | | NULL | | +| err_count | bigint(20) unsigned | NO | | NULL | | +| warn_count | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | +| avg_latency | text | YES | | NULL | | +| lock_latency | text | YES | | NULL | | +| rows_sent | bigint(20) unsigned | NO | | NULL | | +| rows_sent_avg | decimal(21,0) | NO | | 0 | | +| rows_examined | bigint(20) unsigned | NO | | NULL | | +| rows_examined_avg | decimal(21,0) | NO | | 0 | | +| rows_affected | bigint(20) unsigned | NO | | NULL | | +| rows_affected_avg | decimal(21,0) | NO | | 0 | | +| tmp_tables | bigint(20) unsigned | NO | | NULL | | +| tmp_disk_tables | bigint(20) unsigned | NO | | NULL | | +| rows_sorted | bigint(20) unsigned | NO | | NULL | | +| sort_merge_passes | bigint(20) unsigned | NO | | NULL | | +| digest | varchar(32) | YES | | NULL | | +| first_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| last_seen | timestamp | NO | | 0000-00-00 00:00:00 | | ++-------------------+---------------------+------+-----+---------------------+-------+ +23 rows in set (0.26 sec) + +mysql> desc x$statement_analysis; ++-------------------+---------------------+------+-----+---------------------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------------+---------------------+------+-----+---------------------+-------+ +| query | longtext | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| full_scan | varchar(1) | NO | | | | +| exec_count | bigint(20) unsigned | NO | | NULL | | +| err_count | bigint(20) unsigned | NO | | NULL | | +| warn_count | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| max_latency | bigint(20) unsigned | NO | | NULL | | +| avg_latency | bigint(20) unsigned | NO | | NULL | | +| lock_latency | bigint(20) unsigned | NO | | NULL | | +| rows_sent | bigint(20) unsigned | NO | | NULL | | +| rows_sent_avg | decimal(21,0) | NO | | 0 | | +| rows_examined | bigint(20) unsigned | NO | | NULL | | +| rows_examined_avg | decimal(21,0) | NO | | 0 | | +| rows_affected | bigint(20) unsigned | NO | | NULL | | +| rows_affected_avg | decimal(21,0) | NO | | 0 | | +| tmp_tables | bigint(20) unsigned | NO | | NULL | | +| tmp_disk_tables | bigint(20) unsigned | NO | | NULL | | +| rows_sorted | bigint(20) unsigned | NO | | NULL | | +| sort_merge_passes | bigint(20) unsigned | NO | | NULL | | +| digest | varchar(32) | YES | | NULL | | +| first_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| last_seen | timestamp | NO | | 0000-00-00 00:00:00 | | ++-------------------+---------------------+------+-----+---------------------+-------+ +23 rows in set (0.27 sec) +``` + +##### Example + +```SQL +mysql> select * from statement_analysis limit 1\G +*************************** 1. row *************************** + query: SELECT * FROM `schema_object_o ... MA` , `information_schema` ... + db: sys + full_scan: * + exec_count: 2 + err_count: 0 + warn_count: 0 + total_latency: 16.75 s + max_latency: 16.57 s + avg_latency: 8.38 s + lock_latency: 16.69 s + rows_sent: 84 + rows_sent_avg: 42 + rows_examined: 20012 +rows_examined_avg: 10006 + rows_affected: 0 +rows_affected_avg: 0 + tmp_tables: 378 + tmp_disk_tables: 66 + rows_sorted: 168 +sort_merge_passes: 0 + digest: 54f9bd520f0bbf15db0c2ed93386bec9 + first_seen: 2014-03-07 13:13:41 + last_seen: 2014-03-07 13:13:48 +``` + +#### statements_with_errors_or_warnings / x$statements_with_errors_or_warnings + +##### Description + +Lists all normalized statements that have raised errors or warnings. + +##### Structures + +```SQL +mysql> desc statements_with_errors_or_warnings; ++-------------+---------------------+------+-----+---------------------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------+---------------------+------+-----+---------------------+-------+ +| query | longtext | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| exec_count | bigint(20) unsigned | NO | | NULL | | +| errors | bigint(20) unsigned | NO | | NULL | | +| error_pct | decimal(27,4) | NO | | 0.0000 | | +| warnings | bigint(20) unsigned | NO | | NULL | | +| warning_pct | decimal(27,4) | NO | | 0.0000 | | +| first_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| last_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| digest | varchar(32) | YES | | NULL | | ++-------------+---------------------+------+-----+---------------------+-------+ +10 rows in set (0.55 sec) + +mysql> desc x$statements_with_errors_or_warnings; ++-------------+---------------------+------+-----+---------------------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------+---------------------+------+-----+---------------------+-------+ +| query | longtext | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| exec_count | bigint(20) unsigned | NO | | NULL | | +| errors | bigint(20) unsigned | NO | | NULL | | +| error_pct | decimal(27,4) | NO | | 0.0000 | | +| warnings | bigint(20) unsigned | NO | | NULL | | +| warning_pct | decimal(27,4) | NO | | 0.0000 | | +| first_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| last_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| digest | varchar(32) | YES | | NULL | | ++-------------+---------------------+------+-----+---------------------+-------+ +10 rows in set (0.25 sec) +``` + +##### Example + +```SQL +mysql> select * from statements_with_errors_or_warnings LIMIT 1\G +*************************** 1. row *************************** + query: CREATE OR REPLACE ALGORITHM = ... _delete` AS `rows_deleted` ... + db: sys + exec_count: 2 + errors: 1 + error_pct: 50.0000 + warnings: 0 +warning_pct: 0.0000 + first_seen: 2014-03-07 12:56:54 + last_seen: 2014-03-07 13:01:01 + digest: 943a788859e623d5f7798ba0ae0fd8a9 +``` + +#### statements_with_full_table_scans / x$statements_with_full_table_scans + +##### Description + +Lists all normalized statements that use have done a full table scan ordered by number the percentage of times a full scan was done, then by the statement latency. + +This view ignores SHOW statements, as these always cause a full table scan, and there is nothing that can be done about this. + +##### Structures + +```SQL +mysql> desc statements_with_full_table_scans; ++--------------------------+------------------------+------+-----+---------------------+-------+ +| Field | Type | Null | Key | Default | Extra | ++--------------------------+------------------------+------+-----+---------------------+-------+ +| query | longtext | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| exec_count | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| no_index_used_count | bigint(20) unsigned | NO | | NULL | | +| no_good_index_used_count | bigint(20) unsigned | NO | | NULL | | +| no_index_used_pct | decimal(24,0) | NO | | 0 | | +| rows_sent | bigint(20) unsigned | NO | | NULL | | +| rows_examined | bigint(20) unsigned | NO | | NULL | | +| rows_sent_avg | decimal(21,0) unsigned | YES | | NULL | | +| rows_examined_avg | decimal(21,0) unsigned | YES | | NULL | | +| first_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| last_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| digest | varchar(32) | YES | | NULL | | ++--------------------------+------------------------+------+-----+---------------------+-------+ +14 rows in set (0.04 sec) + +mysql> desc x$statements_with_full_table_scans; ++--------------------------+------------------------+------+-----+---------------------+-------+ +| Field | Type | Null | Key | Default | Extra | ++--------------------------+------------------------+------+-----+---------------------+-------+ +| query | longtext | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| exec_count | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| no_index_used_count | bigint(20) unsigned | NO | | NULL | | +| no_good_index_used_count | bigint(20) unsigned | NO | | NULL | | +| no_index_used_pct | decimal(24,0) | NO | | 0 | | +| rows_sent | bigint(20) unsigned | NO | | NULL | | +| rows_examined | bigint(20) unsigned | NO | | NULL | | +| rows_sent_avg | decimal(21,0) unsigned | YES | | NULL | | +| rows_examined_avg | decimal(21,0) unsigned | YES | | NULL | | +| first_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| last_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| digest | varchar(32) | YES | | NULL | | ++--------------------------+------------------------+------+-----+---------------------+-------+ +14 rows in set (0.14 sec) +``` + +##### Example + +```SQL +mysql> select * from statements_with_full_table_scans limit 1\G +*************************** 1. row *************************** + query: SELECT * FROM `schema_tables_w ... ex_usage` . `COUNT_READ` DESC + db: sys + exec_count: 1 + total_latency: 88.20 ms + no_index_used_count: 1 +no_good_index_used_count: 0 + no_index_used_pct: 100 + rows_sent: 0 + rows_examined: 1501 + rows_sent_avg: 0 + rows_examined_avg: 1501 + first_seen: 2014-03-07 13:58:20 + last_seen: 2014-03-07 13:58:20 + digest: 64baecd5c1e1e1651a6b92e55442a288 +``` + +#### statements_with_runtimes_in_95th_percentile / x$statements_with_runtimes_in_95th_percentile + +##### Description + +Lists all statements whose average runtime, in microseconds, is in the top 95th percentile. + +Also includes two helper views: + +* x$ps_digest_avg_latency_distribution +* x$ps_digest_95th_percentile_by_avg_us + +##### Structures + +```SQL +mysql> desc statements_with_runtimes_in_95th_percentile; ++-------------------+---------------------+------+-----+---------------------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------------+---------------------+------+-----+---------------------+-------+ +| query | longtext | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| full_scan | varchar(1) | NO | | | | +| exec_count | bigint(20) unsigned | NO | | NULL | | +| err_count | bigint(20) unsigned | NO | | NULL | | +| warn_count | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | +| avg_latency | text | YES | | NULL | | +| rows_sent | bigint(20) unsigned | NO | | NULL | | +| rows_sent_avg | decimal(21,0) | NO | | 0 | | +| rows_examined | bigint(20) unsigned | NO | | NULL | | +| rows_examined_avg | decimal(21,0) | NO | | 0 | | +| first_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| last_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| digest | varchar(32) | YES | | NULL | | ++-------------------+---------------------+------+-----+---------------------+-------+ +16 rows in set (0.11 sec) + +mysql> desc x$statements_with_runtimes_in_95th_percentile; ++-------------------+---------------------+------+-----+---------------------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------------+---------------------+------+-----+---------------------+-------+ +| query | longtext | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| full_scan | varchar(1) | NO | | | | +| exec_count | bigint(20) unsigned | NO | | NULL | | +| err_count | bigint(20) unsigned | NO | | NULL | | +| warn_count | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| max_latency | bigint(20) unsigned | NO | | NULL | | +| avg_latency | bigint(20) unsigned | NO | | NULL | | +| rows_sent | bigint(20) unsigned | NO | | NULL | | +| rows_sent_avg | decimal(21,0) | NO | | 0 | | +| rows_examined | bigint(20) unsigned | NO | | NULL | | +| rows_examined_avg | decimal(21,0) | NO | | 0 | | +| first_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| last_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| digest | varchar(32) | YES | | NULL | | ++-------------------+---------------------+------+-----+---------------------+-------+ +16 rows in set (0.00 sec) + +mysql> desc x$ps_digest_avg_latency_distribution; ++--------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++--------+---------------+------+-----+---------+-------+ +| cnt | bigint(21) | NO | | 0 | | +| avg_us | decimal(21,0) | YES | | NULL | | ++--------+---------------+------+-----+---------+-------+ +2 rows in set (0.10 sec) + +mysql> desc x$ps_digest_95th_percentile_by_avg_us; ++------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------+---------------+------+-----+---------+-------+ +| avg_us | decimal(21,0) | YES | | NULL | | +| percentile | decimal(46,4) | NO | | 0.0000 | | ++------------+---------------+------+-----+---------+-------+ +2 rows in set (0.15 sec) +``` + +##### Example + +```SQL +mysql> select * from statements_with_runtimes_in_95th_percentile\G +*************************** 1. row *************************** + query: SELECT * FROM `schema_object_o ... MA` , `information_schema` ... + db: sys + full_scan: * + exec_count: 2 + err_count: 0 + warn_count: 0 + total_latency: 16.75 s + max_latency: 16.57 s + avg_latency: 8.38 s + rows_sent: 84 + rows_sent_avg: 42 + rows_examined: 20012 +rows_examined_avg: 10006 + first_seen: 2014-03-07 13:13:41 + last_seen: 2014-03-07 13:13:48 + digest: 54f9bd520f0bbf15db0c2ed93386bec9 +``` + +#### statements_with_sorting / x$statements_with_sorting + +##### Description + +Lists all normalized statements that have done sorts, ordered by total_latency descending. + +##### Structures + +```SQL +mysql> desc statements_with_sorting; ++-------------------+---------------------+------+-----+---------------------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------------+---------------------+------+-----+---------------------+-------+ +| query | longtext | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| exec_count | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| sort_merge_passes | bigint(20) unsigned | NO | | NULL | | +| avg_sort_merges | decimal(21,0) | NO | | 0 | | +| sorts_using_scans | bigint(20) unsigned | NO | | NULL | | +| sort_using_range | bigint(20) unsigned | NO | | NULL | | +| rows_sorted | bigint(20) unsigned | NO | | NULL | | +| avg_rows_sorted | decimal(21,0) | NO | | 0 | | +| first_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| last_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| digest | varchar(32) | YES | | NULL | | ++-------------------+---------------------+------+-----+---------------------+-------+ +13 rows in set (0.01 sec) + +mysql> desc x$statements_with_sorting; ++-------------------+---------------------+------+-----+---------------------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------------+---------------------+------+-----+---------------------+-------+ +| query | longtext | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| exec_count | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| sort_merge_passes | bigint(20) unsigned | NO | | NULL | | +| avg_sort_merges | decimal(21,0) | NO | | 0 | | +| sorts_using_scans | bigint(20) unsigned | NO | | NULL | | +| sort_using_range | bigint(20) unsigned | NO | | NULL | | +| rows_sorted | bigint(20) unsigned | NO | | NULL | | +| avg_rows_sorted | decimal(21,0) | NO | | 0 | | +| first_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| last_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| digest | varchar(32) | YES | | NULL | | ++-------------------+---------------------+------+-----+---------------------+-------+ +13 rows in set (0.04 sec) +``` + +##### Example + +```SQL +mysql> select * from statements_with_sorting limit 1\G +*************************** 1. row *************************** + query: SELECT * FROM `schema_object_o ... MA` , `information_schema` ... + db: sys + exec_count: 2 + total_latency: 16.75 s +sort_merge_passes: 0 + avg_sort_merges: 0 +sorts_using_scans: 12 + sort_using_range: 0 + rows_sorted: 168 + avg_rows_sorted: 84 + first_seen: 2014-03-07 13:13:41 + last_seen: 2014-03-07 13:13:48 + digest: 54f9bd520f0bbf15db0c2ed93386bec9 +``` + +#### statements_with_temp_tables / x$statements_with_temp_tables + +##### Description + +Lists all normalized statements that use temporary tables ordered by number of on disk temporary tables descending first, then by the number of memory tables. + +##### Structures + +```SQL +mysql> desc statements_with_temp_tables; ++--------------------------+---------------------+------+-----+---------------------+-------+ +| Field | Type | Null | Key | Default | Extra | ++--------------------------+---------------------+------+-----+---------------------+-------+ +| query | longtext | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| exec_count | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| memory_tmp_tables | bigint(20) unsigned | NO | | NULL | | +| disk_tmp_tables | bigint(20) unsigned | NO | | NULL | | +| avg_tmp_tables_per_query | decimal(21,0) | NO | | 0 | | +| tmp_tables_to_disk_pct | decimal(24,0) | NO | | 0 | | +| first_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| last_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| digest | varchar(32) | YES | | NULL | | ++--------------------------+---------------------+------+-----+---------------------+-------+ +11 rows in set (0.30 sec) + +mysql> desc x$statements_with_temp_tables; ++--------------------------+---------------------+------+-----+---------------------+-------+ +| Field | Type | Null | Key | Default | Extra | ++--------------------------+---------------------+------+-----+---------------------+-------+ +| query | longtext | YES | | NULL | | +| db | varchar(64) | YES | | NULL | | +| exec_count | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| memory_tmp_tables | bigint(20) unsigned | NO | | NULL | | +| disk_tmp_tables | bigint(20) unsigned | NO | | NULL | | +| avg_tmp_tables_per_query | decimal(21,0) | NO | | 0 | | +| tmp_tables_to_disk_pct | decimal(24,0) | NO | | 0 | | +| first_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| last_seen | timestamp | NO | | 0000-00-00 00:00:00 | | +| digest | varchar(32) | YES | | NULL | | ++--------------------------+---------------------+------+-----+---------------------+-------+ +11 rows in set (0.05 sec) +``` + +##### Example + +```SQL +mysql> select * from statements_with_temp_tables limit 1\G +*************************** 1. row *************************** + query: SELECT * FROM `schema_object_o ... MA` , `information_schema` ... + db: sys + exec_count: 2 + total_latency: 16.75 s + memory_tmp_tables: 378 + disk_tmp_tables: 66 +avg_tmp_tables_per_query: 189 + tmp_tables_to_disk_pct: 17 + first_seen: 2014-03-07 13:13:41 + last_seen: 2014-03-07 13:13:48 + digest: 54f9bd520f0bbf15db0c2ed93386bec9 +``` + +#### user_summary / x$user_summary + +##### Description + +Summarizes statement activity, file IO and connections by user. + +When the user found is NULL, it is assumed to be a "background" thread. + +##### Structures (5.7) + +```SQL +mysql> desc user_summary; ++------------------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------------------+---------------+------+-----+---------+-------+ +| user | varchar(32) | YES | | NULL | | +| statements | decimal(64,0) | YES | | NULL | | +| statement_latency | text | YES | | NULL | | +| statement_avg_latency | text | YES | | NULL | | +| table_scans | decimal(65,0) | YES | | NULL | | +| file_ios | decimal(64,0) | YES | | NULL | | +| file_io_latency | text | YES | | NULL | | +| current_connections | decimal(41,0) | YES | | NULL | | +| total_connections | decimal(41,0) | YES | | NULL | | +| unique_hosts | bigint(21) | NO | | 0 | | +| current_memory | text | YES | | NULL | | +| total_memory_allocated | text | YES | | NULL | | ++------------------------+---------------+------+-----+---------+-------+ +12 rows in set (0.00 sec) + +mysql> desc x$user_summary; ++------------------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------------------+---------------+------+-----+---------+-------+ +| user | varchar(32) | YES | | NULL | | +| statements | decimal(64,0) | YES | | NULL | | +| statement_latency | decimal(64,0) | YES | | NULL | | +| statement_avg_latency | decimal(65,4) | NO | | 0.0000 | | +| table_scans | decimal(65,0) | YES | | NULL | | +| file_ios | decimal(64,0) | YES | | NULL | | +| file_io_latency | decimal(64,0) | YES | | NULL | | +| current_connections | decimal(41,0) | YES | | NULL | | +| total_connections | decimal(41,0) | YES | | NULL | | +| unique_hosts | bigint(21) | NO | | 0 | | +| current_memory | decimal(63,0) | YES | | NULL | | +| total_memory_allocated | decimal(64,0) | YES | | NULL | | ++------------------------+---------------+------+-----+---------+-------+ +12 rows in set (0.01 sec) +``` + +##### Example + +```SQL +mysql> select * from user_summary\G +*************************** 1. row *************************** + user: root + statements: 4981 + statement_latency: 26.54 s + statement_avg_latency: 5.33 ms + table_scans: 74 + file_ios: 7792 + file_io_latency: 40.08 s + current_connections: 1 + total_connections: 2 + unique_hosts: 1 + current_memory: 3.57 MiB +total_memory_allocated: 83.37 MiB +*************************** 2. row *************************** + user: background + statements: 0 + statement_latency: 0 ps + statement_avg_latency: 0 ps + table_scans: 0 + file_ios: 1618 + file_io_latency: 4.78 s + current_connections: 21 + total_connections: 23 + unique_hosts: 0 + current_memory: 165.94 MiB +total_memory_allocated: 197.29 MiB +``` + +#### user_summary_by_file_io / x$user_summary_by_file_io + +##### Description + +Summarizes file IO totals per user. + +When the user found is NULL, it is assumed to be a "background" thread. + +##### Structures + +```SQL +mysql> desc user_summary_by_file_io; ++------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------+---------------+------+-----+---------+-------+ +| user | varchar(32) | YES | | NULL | | +| ios | decimal(42,0) | YES | | NULL | | +| io_latency | text | YES | | NULL | | ++------------+---------------+------+-----+---------+-------+ +3 rows in set (0.20 sec) + +mysql> desc x$user_summary_by_file_io; ++------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------+---------------+------+-----+---------+-------+ +| user | varchar(32) | YES | | NULL | | +| ios | decimal(42,0) | YES | | NULL | | +| io_latency | decimal(42,0) | YES | | NULL | | ++------------+---------------+------+-----+---------+-------+ +3 rows in set (0.02 sec) +``` + +##### Example + +```SQL +mysql> select * from user_summary_by_file_io; ++------------+-------+------------+ +| user | ios | io_latency | ++------------+-------+------------+ +| root | 26457 | 21.58 s | +| background | 1189 | 394.21 ms | ++------------+-------+------------+ +``` + +#### user_summary_by_file_io_type / x$user_summary_by_file_io_type + +##### Description + +Summarizes file IO by event type per user. + +When the user found is NULL, it is assumed to be a "background" thread. + +##### Structures + +```SQL +mysql> desc user_summary_by_file_io_type; ++-------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------+---------------------+------+-----+---------+-------+ +| user | varchar(32) | YES | | NULL | | +| event_name | varchar(128) | NO | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | ++-------------+---------------------+------+-----+---------+-------+ +5 rows in set (0.02 sec) + +mysql> desc x$user_summary_by_file_io_type; ++-------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------+---------------------+------+-----+---------+-------+ +| user | varchar(32) | YES | | NULL | | +| event_name | varchar(128) | NO | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| latency | bigint(20) unsigned | NO | | NULL | | +| max_latency | bigint(20) unsigned | NO | | NULL | | ++-------------+---------------------+------+-----+---------+-------+ +5 rows in set (0.00 sec) +``` + +##### Example + +```SQL +mysql> select * from user_summary_by_file_io_type; ++------------+--------------------------------------+-------+-----------+-------------+ +| user | event_name | total | latency | max_latency | ++------------+--------------------------------------+-------+-----------+-------------+ +| background | wait/io/file/innodb/innodb_data_file | 1434 | 3.29 s | 147.56 ms | +| background | wait/io/file/sql/FRM | 910 | 286.61 ms | 32.92 ms | +| background | wait/io/file/sql/relaylog | 9 | 252.28 ms | 144.17 ms | +| background | wait/io/file/sql/binlog | 56 | 193.73 ms | 153.72 ms | +| background | wait/io/file/sql/binlog_index | 22 | 183.02 ms | 81.83 ms | +| background | wait/io/file/innodb/innodb_log_file | 20 | 117.17 ms | 36.53 ms | +| background | wait/io/file/sql/relaylog_index | 9 | 50.15 ms | 48.04 ms | +| background | wait/io/file/sql/ERRMSG | 5 | 35.41 ms | 31.78 ms | +| background | wait/io/file/myisam/kfile | 67 | 18.14 ms | 9.00 ms | +| background | wait/io/file/mysys/charset | 3 | 7.46 ms | 4.13 ms | +| background | wait/io/file/sql/casetest | 5 | 6.01 ms | 5.86 ms | +| background | wait/io/file/sql/pid | 3 | 5.96 ms | 3.06 ms | +| background | wait/io/file/myisam/dfile | 43 | 980.38 us | 152.46 us | +| background | wait/io/file/mysys/cnf | 5 | 154.97 us | 58.87 us | +| background | wait/io/file/sql/global_ddl_log | 2 | 18.64 us | 16.40 us | +| root | wait/io/file/sql/file_parser | 11048 | 48.79 s | 201.11 ms | +| root | wait/io/file/innodb/innodb_data_file | 4699 | 3.02 s | 46.93 ms | +| root | wait/io/file/sql/FRM | 10403 | 2.38 s | 61.72 ms | +| root | wait/io/file/myisam/dfile | 22143 | 726.77 ms | 308.79 ms | +| root | wait/io/file/myisam/kfile | 6213 | 435.35 ms | 88.76 ms | +| root | wait/io/file/sql/dbopt | 159 | 130.86 ms | 15.46 ms | +| root | wait/io/file/csv/metadata | 8 | 86.60 ms | 50.32 ms | +| root | wait/io/file/sql/binlog | 15 | 38.79 ms | 9.40 ms | +| root | wait/io/file/sql/misc | 21 | 22.33 ms | 15.30 ms | +| root | wait/io/file/csv/data | 4 | 297.46 us | 111.93 us | +| root | wait/io/file/archive/data | 3 | 54.10 us | 40.74 us | ++------------+--------------------------------------+-------+-----------+-------------+ +``` + +#### user_summary_by_stages / x$user_summary_by_stages + +##### Description + +Summarizes stages by user, ordered by user and total latency per stage. + +When the user found is NULL, it is assumed to be a "background" thread. + +##### Structures + +```SQL +mysql> desc user_summary_by_stages; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| user | varchar(32) | YES | | NULL | | +| event_name | varchar(128) | NO | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| avg_latency | text | YES | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +5 rows in set (0.01 sec) + +mysql> desc x$user_summary_by_stages; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| user | varchar(16) | YES | | NULL | | +| event_name | varchar(128) | NO | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| avg_latency | bigint(20) unsigned | NO | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +5 rows in set (0.05 sec) +``` + +##### Example + +```SQL +mysql> select * from user_summary_by_stages; ++------+--------------------------------+-------+---------------+-------------+ +| user | event_name | total | total_latency | avg_latency | ++------+--------------------------------+-------+---------------+-------------+ +| root | stage/sql/Opening tables | 889 | 1.97 ms | 2.22 us | +| root | stage/sql/Creating sort index | 4 | 1.79 ms | 446.30 us | +| root | stage/sql/init | 10 | 312.27 us | 31.23 us | +| root | stage/sql/checking permissions | 10 | 300.62 us | 30.06 us | +| root | stage/sql/freeing items | 5 | 85.89 us | 17.18 us | +| root | stage/sql/statistics | 5 | 79.15 us | 15.83 us | +| root | stage/sql/preparing | 5 | 69.12 us | 13.82 us | +| root | stage/sql/optimizing | 5 | 53.11 us | 10.62 us | +| root | stage/sql/Sending data | 5 | 44.66 us | 8.93 us | +| root | stage/sql/closing tables | 5 | 37.54 us | 7.51 us | +| root | stage/sql/System lock | 5 | 34.28 us | 6.86 us | +| root | stage/sql/query end | 5 | 24.37 us | 4.87 us | +| root | stage/sql/end | 5 | 8.60 us | 1.72 us | +| root | stage/sql/Sorting result | 5 | 8.33 us | 1.67 us | +| root | stage/sql/executing | 5 | 5.37 us | 1.07 us | +| root | stage/sql/cleaning up | 5 | 4.60 us | 919.00 ns | ++------+--------------------------------+-------+---------------+-------------+ +``` + +#### user_summary_by_statement_latency / x$user_summary_by_statement_latency + +##### Description + +Summarizes overall statement statistics by user. + +When the user found is NULL, it is assumed to be a "background" thread. + +##### Structures + +```SQL +mysql> desc user_summary_by_statement_latency; ++---------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------+------+-----+---------+-------+ +| user | varchar(32) | YES | | NULL | | +| total | decimal(42,0) | YES | | NULL | | +| total_latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | +| lock_latency | text | YES | | NULL | | +| rows_sent | decimal(42,0) | YES | | NULL | | +| rows_examined | decimal(42,0) | YES | | NULL | | +| rows_affected | decimal(42,0) | YES | | NULL | | +| full_scans | decimal(43,0) | YES | | NULL | | ++---------------+---------------+------+-----+---------+-------+ +9 rows in set (0.00 sec) + +mysql> desc x$user_summary_by_statement_latency; ++---------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------+------+-----+---------+-------+ +| user | varchar(32) | YES | | NULL | | +| total | decimal(42,0) | YES | | NULL | | +| total_latency | decimal(42,0) | YES | | NULL | | +| max_latency | decimal(42,0) | YES | | NULL | | +| lock_latency | decimal(42,0) | YES | | NULL | | +| rows_sent | decimal(42,0) | YES | | NULL | | +| rows_examined | decimal(42,0) | YES | | NULL | | +| rows_affected | decimal(42,0) | YES | | NULL | | +| full_scans | decimal(43,0) | YES | | NULL | | ++---------------+---------------+------+-----+---------+-------+ +9 rows in set (0.28 sec) +``` + +##### Example + +```SQL +mysql> select * from user_summary_by_statement_latency; ++------+-------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +| user | total | total_latency | max_latency | lock_latency | rows_sent | rows_examined | rows_affected | full_scans | ++------+-------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +| root | 3381 | 00:02:09.13 | 1.48 s | 1.07 s | 1151 | 93947 | 150 | 91 | ++------+-------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +``` + +#### user_summary_by_statement_type / x$user_summary_by_statement_type + +##### Description + +Summarizes the types of statements executed by each user. + +When the user found is NULL, it is assumed to be a "background" thread. + +##### Structures + +```SQL +mysql> desc user_summary_by_statement_type; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| user | varchar(32) | YES | | NULL | | +| statement | varchar(128) | YES | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | +| lock_latency | text | YES | | NULL | | +| rows_sent | bigint(20) unsigned | NO | | NULL | | +| rows_examined | bigint(20) unsigned | NO | | NULL | | +| rows_affected | bigint(20) unsigned | NO | | NULL | | +| full_scans | bigint(21) unsigned | NO | | 0 | | ++---------------+---------------------+------+-----+---------+-------+ +10 rows in set (0.21 sec) + +mysql> desc x$user_summary_by_statement_type; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| user | varchar(32) | YES | | NULL | | +| statement | varchar(128) | YES | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| max_latency | bigint(20) unsigned | NO | | NULL | | +| lock_latency | bigint(20) unsigned | NO | | NULL | | +| rows_sent | bigint(20) unsigned | NO | | NULL | | +| rows_examined | bigint(20) unsigned | NO | | NULL | | +| rows_affected | bigint(20) unsigned | NO | | NULL | | +| full_scans | bigint(21) unsigned | NO | | 0 | | ++---------------+---------------------+------+-----+---------+-------+ +10 rows in set (0.37 sec) +``` + +##### Example + +```SQL +mysql> select * from user_summary_by_statement_type; ++------+------------------+-------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +| user | statement | total | total_latency | max_latency | lock_latency | rows_sent | rows_examined | rows_affected | full_scans | ++------+------------------+-------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +| root | create_view | 1332 | 00:03:39.08 | 677.76 ms | 494.56 ms | 0 | 0 | 0 | 0 | +| root | select | 88 | 20.13 s | 16.57 s | 17.40 s | 1804 | 77285 | 0 | 48 | +| root | drop_db | 16 | 6.83 s | 1.14 s | 5.73 s | 0 | 0 | 953 | 0 | +| root | drop_view | 392 | 1.70 s | 739.49 ms | 0 ps | 0 | 0 | 0 | 0 | +| root | show_databases | 16 | 1.37 s | 587.44 ms | 1.31 ms | 400 | 400 | 0 | 16 | +| root | show_tables | 34 | 676.78 ms | 167.04 ms | 3.46 ms | 1087 | 1087 | 0 | 34 | +| root | create_db | 22 | 334.90 ms | 38.93 ms | 0 ps | 0 | 0 | 22 | 0 | +| root | create_procedure | 352 | 250.02 ms | 21.90 ms | 165.17 ms | 0 | 0 | 0 | 0 | +| root | drop_function | 176 | 122.44 ms | 69.18 ms | 87.24 ms | 0 | 0 | 0 | 0 | +| root | create_function | 176 | 76.12 ms | 1.36 ms | 49.50 ms | 0 | 0 | 0 | 0 | +| root | drop_procedure | 352 | 67.41 ms | 1.57 ms | 36.22 ms | 0 | 0 | 0 | 0 | +| root | update | 2 | 41.75 ms | 35.96 ms | 35.52 ms | 0 | 557 | 338 | 0 | +| root | error | 3 | 17.22 ms | 17.05 ms | 0 ps | 0 | 0 | 0 | 0 | +| root | set_option | 88 | 8.02 ms | 1.63 ms | 0 ps | 0 | 0 | 0 | 0 | +| root | call_procedure | 2 | 2.98 ms | 2.29 ms | 95.00 us | 0 | 0 | 0 | 0 | +| root | Init DB | 22 | 1.07 ms | 117.65 us | 0 ps | 0 | 0 | 0 | 0 | +| root | show_status | 1 | 408.69 us | 408.69 us | 102.00 us | 23 | 23 | 0 | 1 | ++------+------------------+-------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +``` + +#### wait_classes_global_by_avg_latency / x$wait_classes_global_by_avg_latency + +##### Description + +Lists the top wait classes by average latency, ignoring idle (this may be very large). + +##### Structures + +```SQL +mysql> desc wait_classes_global_by_avg_latency; ++---------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------+------+-----+---------+-------+ +| event_class | varchar(128) | YES | | NULL | | +| total | decimal(42,0) | YES | | NULL | | +| total_latency | text | YES | | NULL | | +| min_latency | text | YES | | NULL | | +| avg_latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | ++---------------+---------------+------+-----+---------+-------+ +6 rows in set (0.11 sec) + +mysql> desc x$wait_classes_global_by_avg_latency; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| event_class | varchar(128) | YES | | NULL | | +| total | decimal(42,0) | YES | | NULL | | +| total_latency | decimal(42,0) | YES | | NULL | | +| min_latency | bigint(20) unsigned | YES | | NULL | | +| avg_latency | decimal(46,4) | NO | | 0.0000 | | +| max_latency | bigint(20) unsigned | YES | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +6 rows in set (0.02 sec) +``` + +##### Example + +```SQL +mysql> select * from wait_classes_global_by_avg_latency where event_class != 'idle'; ++-------------------+--------+---------------+-------------+-------------+-------------+ +| event_class | total | total_latency | min_latency | avg_latency | max_latency | ++-------------------+--------+---------------+-------------+-------------+-------------+ +| wait/io/file | 543123 | 44.60 s | 19.44 ns | 82.11 us | 4.21 s | +| wait/io/table | 22002 | 766.60 ms | 148.72 ns | 34.84 us | 44.97 ms | +| wait/io/socket | 79613 | 967.17 ms | 0 ps | 12.15 us | 27.10 ms | +| wait/lock/table | 35409 | 18.68 ms | 65.45 ns | 527.51 ns | 969.88 us | +| wait/synch/rwlock | 37935 | 4.61 ms | 21.38 ns | 121.61 ns | 34.65 us | +| wait/synch/mutex | 390622 | 18.60 ms | 19.44 ns | 47.61 ns | 10.32 us | ++-------------------+--------+---------------+-------------+-------------+-------------+ +``` + +#### wait_classes_global_by_latency / x$wait_classes_global_by_latency + +##### Description + +Lists the top wait classes by total latency, ignoring idle (this may be very large). + +##### Structures + +```SQL +mysql> desc wait_classes_global_by_latency; ++---------------+---------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------+------+-----+---------+-------+ +| event_class | varchar(128) | YES | | NULL | | +| total | decimal(42,0) | YES | | NULL | | +| total_latency | text | YES | | NULL | | +| min_latency | text | YES | | NULL | | +| avg_latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | ++---------------+---------------+------+-----+---------+-------+ +6 rows in set (0.00 sec) + +mysql> desc x$wait_classes_global_by_latency; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| event_class | varchar(128) | YES | | NULL | | +| total | decimal(42,0) | YES | | NULL | | +| total_latency | decimal(42,0) | YES | | NULL | | +| min_latency | bigint(20) unsigned | YES | | NULL | | +| avg_latency | decimal(46,4) | NO | | 0.0000 | | +| max_latency | bigint(20) unsigned | YES | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +6 rows in set (0.02 sec) +``` + +##### Example + +```SQL +mysql> select * from wait_classes_global_by_latency; ++-------------------+--------+---------------+-------------+-------------+-------------+ +| event_class | total | total_latency | min_latency | avg_latency | max_latency | ++-------------------+--------+---------------+-------------+-------------+-------------+ +| wait/io/file | 550470 | 46.01 s | 19.44 ns | 83.58 us | 4.21 s | +| wait/io/socket | 228833 | 2.71 s | 0 ps | 11.86 us | 29.93 ms | +| wait/io/table | 64063 | 1.89 s | 99.79 ns | 29.43 us | 68.07 ms | +| wait/lock/table | 76029 | 47.19 ms | 65.45 ns | 620.74 ns | 969.88 us | +| wait/synch/mutex | 635925 | 34.93 ms | 19.44 ns | 54.93 ns | 107.70 us | +| wait/synch/rwlock | 61287 | 7.62 ms | 21.38 ns | 124.37 ns | 34.65 us | ++-------------------+--------+---------------+-------------+-------------+-------------+ +``` + +#### waits_by_user_by_latency / x$waits_by_user_by_latency + +##### Description + +Lists the top wait events per user by their total latency, ignoring idle (this may be very large) per user. + +##### Structures + +```SQL +mysql> desc waits_by_user_by_latency; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| user | varchar(32) | YES | | NULL | | +| event | varchar(128) | NO | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| avg_latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +6 rows in set (0.00 sec) + +mysql> desc x$waits_by_user_by_latency; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| user | varchar(32) | YES | | NULL | | +| event | varchar(128) | NO | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| avg_latency | bigint(20) unsigned | NO | | NULL | | +| max_latency | bigint(20) unsigned | NO | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +6 rows in set (0.30 sec) +``` + +##### Example + +```SQL +mysql> select * from waits_by_user_by_latency; ++------+-----------------------------------------------------+--------+---------------+-------------+-------------+ +| user | event | total | total_latency | avg_latency | max_latency | ++------+-----------------------------------------------------+--------+---------------+-------------+-------------+ +| root | wait/io/file/sql/file_parser | 13743 | 00:01:00.46 | 4.40 ms | 231.88 ms | +| root | wait/io/file/innodb/innodb_data_file | 4699 | 3.02 s | 643.38 us | 46.93 ms | +| root | wait/io/file/sql/FRM | 11462 | 2.60 s | 226.83 us | 61.72 ms | +| root | wait/io/file/myisam/dfile | 26776 | 746.70 ms | 27.89 us | 308.79 ms | +| root | wait/io/file/myisam/kfile | 7126 | 462.66 ms | 64.93 us | 88.76 ms | +| root | wait/io/file/sql/dbopt | 179 | 137.58 ms | 768.59 us | 15.46 ms | +| root | wait/io/file/csv/metadata | 8 | 86.60 ms | 10.82 ms | 50.32 ms | +| root | wait/synch/mutex/mysys/IO_CACHE::append_buffer_lock | 798080 | 66.46 ms | 82.94 ns | 161.03 us | +| root | wait/io/file/sql/binlog | 19 | 49.11 ms | 2.58 ms | 9.40 ms | +| root | wait/io/file/sql/misc | 26 | 22.38 ms | 860.80 us | 15.30 ms | +| root | wait/io/file/csv/data | 4 | 297.46 us | 74.37 us | 111.93 us | +| root | wait/synch/rwlock/sql/MDL_lock::rwlock | 944 | 287.86 us | 304.62 ns | 874.64 ns | +| root | wait/io/file/archive/data | 4 | 82.71 us | 20.68 us | 40.74 us | +| root | wait/synch/mutex/myisam/MYISAM_SHARE::intern_lock | 60 | 12.21 us | 203.20 ns | 512.72 ns | +| root | wait/synch/mutex/innodb/trx_mutex | 81 | 5.93 us | 73.14 ns | 252.59 ns | ++------+-----------------------------------------------------+--------+---------------+-------------+-------------+ +``` + +#### waits_by_host_by_latency / x$waits_by_host_by_latency + +##### Description + +Lists the top wait events per host by their total latency, ignoring idle (this may be very large) per host. + +##### Structures + +```SQL +mysql> desc waits_by_host_by_latency; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| event | varchar(128) | NO | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| avg_latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +6 rows in set (0.36 sec) + +mysql> desc x$waits_by_host_by_latency; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| host | varchar(60) | YES | | NULL | | +| event | varchar(128) | NO | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| avg_latency | bigint(20) unsigned | NO | | NULL | | +| max_latency | bigint(20) unsigned | NO | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +6 rows in set (0.25 sec) +``` + +##### Example + +```SQL + mysql> select * from waits_by_host_by_latency; + +------+-----------------------------------------------------+--------+---------------+-------------+-------------+ + | host | event | total | total_latency | avg_latency | max_latency | + +------+-----------------------------------------------------+--------+---------------+-------------+-------------+ + | hal1 | wait/io/file/sql/file_parser | 13743 | 00:01:00.46 | 4.40 ms | 231.88 ms | + | hal1 | wait/io/file/innodb/innodb_data_file | 4699 | 3.02 s | 643.38 us | 46.93 ms | + | hal1 | wait/io/file/sql/FRM | 11462 | 2.60 s | 226.83 us | 61.72 ms | + | hal1 | wait/io/file/myisam/dfile | 26776 | 746.70 ms | 27.89 us | 308.79 ms | + | hal1 | wait/io/file/myisam/kfile | 7126 | 462.66 ms | 64.93 us | 88.76 ms | + | hal1 | wait/io/file/sql/dbopt | 179 | 137.58 ms | 768.59 us | 15.46 ms | + | hal1 | wait/io/file/csv/metadata | 8 | 86.60 ms | 10.82 ms | 50.32 ms | + | hal1 | wait/synch/mutex/mysys/IO_CACHE::append_buffer_lock | 798080 | 66.46 ms | 82.94 ns | 161.03 us | + | hal1 | wait/io/file/sql/binlog | 19 | 49.11 ms | 2.58 ms | 9.40 ms | + | hal1 | wait/io/file/sql/misc | 26 | 22.38 ms | 860.80 us | 15.30 ms | + | hal1 | wait/io/file/csv/data | 4 | 297.46 us | 74.37 us | 111.93 us | + | hal1 | wait/synch/rwlock/sql/MDL_lock::rwlock | 944 | 287.86 us | 304.62 ns | 874.64 ns | + | hal1 | wait/io/file/archive/data | 4 | 82.71 us | 20.68 us | 40.74 us | + | hal1 | wait/synch/mutex/myisam/MYISAM_SHARE::intern_lock | 60 | 12.21 us | 203.20 ns | 512.72 ns | + | hal1 | wait/synch/mutex/innodb/trx_mutex | 81 | 5.93 us | 73.14 ns | 252.59 ns | + +------+-----------------------------------------------------+--------+---------------+-------------+-------------+ +``` + +#### waits_global_by_latency / x$waits_global_by_latency + +##### Description + +Lists the top wait events by their total latency, ignoring idle (this may be very large). + +##### Structures + +```SQL +mysql> desc waits_global_by_latency; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| events | varchar(128) | NO | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | text | YES | | NULL | | +| avg_latency | text | YES | | NULL | | +| max_latency | text | YES | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +5 rows in set (0.01 sec) + +mysql> desc x$waits_global_by_latency; ++---------------+---------------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------------+---------------------+------+-----+---------+-------+ +| events | varchar(128) | NO | | NULL | | +| total | bigint(20) unsigned | NO | | NULL | | +| total_latency | bigint(20) unsigned | NO | | NULL | | +| avg_latency | bigint(20) unsigned | NO | | NULL | | +| max_latency | bigint(20) unsigned | NO | | NULL | | ++---------------+---------------------+------+-----+---------+-------+ +5 rows in set (0.03 sec) +``` + +##### Example + +```SQL +mysql> select * from waits_global_by_latency; ++-----------------------------------------------------+---------+---------------+-------------+-------------+ +| events | total | total_latency | avg_latency | max_latency | ++-----------------------------------------------------+---------+---------------+-------------+-------------+ +| wait/io/file/sql/file_parser | 14936 | 00:01:06.64 | 4.46 ms | 231.88 ms | +| wait/io/file/innodb/innodb_data_file | 6133 | 6.31 s | 1.03 ms | 147.56 ms | +| wait/io/file/sql/FRM | 12677 | 2.83 s | 223.37 us | 40.86 ms | +| wait/io/file/myisam/dfile | 28446 | 754.40 ms | 26.52 us | 308.79 ms | +| wait/io/file/myisam/kfile | 7572 | 491.17 ms | 64.87 us | 88.76 ms | +| wait/io/file/sql/relaylog | 9 | 252.28 ms | 28.03 ms | 144.17 ms | +| wait/io/file/sql/binlog | 76 | 242.87 ms | 3.20 ms | 153.72 ms | +| wait/io/file/sql/binlog_index | 21 | 173.07 ms | 8.24 ms | 81.83 ms | +| wait/io/file/sql/dbopt | 184 | 149.52 ms | 812.62 us | 15.46 ms | +| wait/io/file/innodb/innodb_log_file | 20 | 117.17 ms | 5.86 ms | 36.53 ms | +| wait/synch/mutex/mysys/IO_CACHE::append_buffer_lock | 1197128 | 99.27 ms | 82.56 ns | 161.03 us | +| wait/io/file/csv/metadata | 8 | 86.60 ms | 10.82 ms | 50.32 ms | +| wait/io/file/sql/relaylog_index | 10 | 60.10 ms | 6.01 ms | 48.04 ms | +| wait/io/file/sql/ERRMSG | 5 | 35.41 ms | 7.08 ms | 31.78 ms | +| wait/io/file/sql/misc | 28 | 22.40 ms | 800.06 us | 15.30 ms | +| wait/io/file/mysys/charset | 3 | 7.46 ms | 2.49 ms | 4.13 ms | +| wait/io/file/sql/casetest | 5 | 6.01 ms | 1.20 ms | 5.86 ms | +| wait/io/file/sql/pid | 3 | 5.96 ms | 1.99 ms | 3.06 ms | +| wait/synch/rwlock/sql/MDL_lock::rwlock | 1396 | 420.58 us | 301.22 ns | 874.64 ns | +| wait/io/file/csv/data | 4 | 297.46 us | 74.37 us | 111.93 us | +| wait/io/file/mysys/cnf | 5 | 154.97 us | 30.99 us | 58.87 us | +| wait/io/file/archive/data | 4 | 82.71 us | 20.68 us | 40.74 us | +| wait/synch/mutex/myisam/MYISAM_SHARE::intern_lock | 90 | 19.23 us | 213.38 ns | 576.81 ns | +| wait/io/file/sql/global_ddl_log | 2 | 18.64 us | 9.32 us | 16.40 us | +| wait/synch/mutex/innodb/trx_mutex | 108 | 8.23 us | 76.15 ns | 365.69 ns | ++-----------------------------------------------------+---------+---------------+-------------+-------------+ +``` + +### Functions + +#### extract_schema_from_file_name + +##### Description + +Takes a raw file path, and attempts to extract the schema name from it. + +Useful for when interacting with Performance Schema data concerning IO statistics, for example. + +Currently relies on the fact that a table data file will be within a specified database directory (will not work with partitions or tables that specify an individual DATA_DIRECTORY). + +##### Parameters + +* path (VARCHAR(512)): The full file path to a data file to extract the schema name from. + +##### Returns + +VARCHAR(64) + +##### Example +```SQL +mysql> SELECT sys.extract_schema_from_file_name('/var/lib/mysql/employees/employee.ibd'); ++----------------------------------------------------------------------------+ +| sys.extract_schema_from_file_name('/var/lib/mysql/employees/employee.ibd') | ++----------------------------------------------------------------------------+ +| employees | ++----------------------------------------------------------------------------+ +1 row in set (0.00 sec) +``` + +#### extract_table_from_file_name + +##### Description + +Takes a raw file path, and extracts the table name from it. + +Useful for when interacting with Performance Schema data concerning IO statistics, for example. + +##### Parameters + +* path (VARCHAR(512)): The full file path to a data file to extract the table name from. + +##### Returns + +VARCHAR(64) + +##### Example +```SQL +mysql> SELECT sys.extract_table_from_file_name('/var/lib/mysql/employees/employee.ibd'); ++---------------------------------------------------------------------------+ +| sys.extract_table_from_file_name('/var/lib/mysql/employees/employee.ibd') | ++---------------------------------------------------------------------------+ +| employee | ++---------------------------------------------------------------------------+ +1 row in set (0.02 sec) +``` + +#### format_bytes + +##### Description + +Takes a raw bytes value, and converts it to a human readable format. + +##### Parameters + +* bytes (TEXT): A raw bytes value. + +##### Returns + +TEXT + +##### Example +```SQL +mysql> SELECT sys.format_bytes(2348723492723746) AS size; ++----------+ +| size | ++----------+ +| 2.09 PiB | ++----------+ +1 row in set (0.00 sec) + +mysql> SELECT sys.format_bytes(2348723492723) AS size; ++----------+ +| size | ++----------+ +| 2.14 TiB | ++----------+ +1 row in set (0.00 sec) + +mysql> SELECT sys.format_bytes(23487234) AS size; ++-----------+ +| size | ++-----------+ +| 22.40 MiB | ++-----------+ +1 row in set (0.00 sec) +``` + +#### format_path + +##### Description + +Takes a raw path value, and strips out the datadir or tmpdir replacing with @@datadir and @@tmpdir respectively. + +Also normalizes the paths across operating systems, so backslashes on Windows are converted to forward slashes. + +##### Parameters + +* path (VARCHAR(512)): The raw file path value to format. + +##### Returns + +VARCHAR(512) CHARSET UTF8 + +##### Example +```SQL +mysql> select @@datadir; ++-----------------------------------------------+ +| @@datadir | ++-----------------------------------------------+ +| /Users/mark/sandboxes/SmallTree/AMaster/data/ | ++-----------------------------------------------+ +1 row in set (0.06 sec) + +mysql> select format_path('/Users/mark/sandboxes/SmallTree/AMaster/data/mysql/proc.MYD') AS path; ++--------------------------+ +| path | ++--------------------------+ +| @@datadir/mysql/proc.MYD | ++--------------------------+ +1 row in set (0.03 sec) +``` + +#### format_statement + +##### Description + +Formats a normalized statement, truncating it if it is > 64 characters long by default. + +To configure the length to truncate the statement to by default, update the `statement_truncate_len` variable with `sys_config` table to a different value. Alternatively, to change it just for just your particular session, use `SET @sys.statement_truncate_len := <some new value>`. + +Useful for printing statement related data from Performance Schema from the command line. + +##### Parameters + +* statement (LONGTEXT): The statement to format. + +##### Returns + +LONGTEXT + +##### Example +```SQL +mysql> SELECT sys.format_statement(digest_text) + -> FROM performance_schema.events_statements_summary_by_digest + -> ORDER by sum_timer_wait DESC limit 5; ++-------------------------------------------------------------------+ +| sys.format_statement(digest_text) | ++-------------------------------------------------------------------+ +| CREATE SQL SECURITY INVOKER VI ... KE ? AND `variable_value` > ? | +| CREATE SQL SECURITY INVOKER VI ... ait` IS NOT NULL , `esc` . ... | +| CREATE SQL SECURITY INVOKER VI ... ait` IS NOT NULL , `sys` . ... | +| CREATE SQL SECURITY INVOKER VI ... , `compressed_size` ) ) DESC | +| CREATE SQL SECURITY INVOKER VI ... LIKE ? ORDER BY `timer_start` | ++-------------------------------------------------------------------+ +5 rows in set (0.00 sec) +``` + +#### format_time + +##### Description + +Takes a raw picoseconds value, and converts it to a human readable form. + +Picoseconds are the precision that all latency values are printed in within Performance Schema, however are not user friendly when wanting to scan output from the command line. + +##### Parameters + +* picoseconds (TEXT): The raw picoseconds value to convert. + +##### Returns + +TEXT + +##### Example +```SQL +mysql> select format_time(342342342342345); ++------------------------------+ +| format_time(342342342342345) | ++------------------------------+ +| 00:05:42 | ++------------------------------+ +1 row in set (0.00 sec) + +mysql> select format_time(342342342); ++------------------------+ +| format_time(342342342) | ++------------------------+ +| 342.34 us | ++------------------------+ +1 row in set (0.00 sec) + +mysql> select format_time(34234); + +--------------------+ +| format_time(34234) | ++--------------------+ +| 34.23 ns | ++--------------------+ +1 row in set (0.00 sec) +``` + +#### list_add + +##### Description + +Takes a list, and a value to add to the list, and returns the resulting list. + +Useful for altering certain session variables, like sql_mode or optimizer_switch for instance. + +##### Parameters + +in_list (TEXT): The comma separated list to add a value to + +in_add_value (TEXT): The value to add to the input list + +##### Returns + +TEXT + +##### Example + +```SQL +mysql> select @@sql_mode; ++-----------------------------------------------------------------------------------+ +| @@sql_mode | ++-----------------------------------------------------------------------------------+ +| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | ++-----------------------------------------------------------------------------------+ +1 row in set (0.00 sec) + +mysql> set sql_mode = sys.list_add(@@sql_mode, 'ANSI_QUOTES'); +Query OK, 0 rows affected (0.06 sec) + +mysql> select @@sql_mode; ++-----------------------------------------------------------------------------------------------+ +| @@sql_mode | ++-----------------------------------------------------------------------------------------------+ +| ANSI_QUOTES,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | ++-----------------------------------------------------------------------------------------------+ +1 row in set (0.00 sec) +``` + +#### list_drop + +##### Description + +Takes a list, and a value to attempt to remove from the list, and returns the resulting list. + +Useful for altering certain session variables, like sql_mode or optimizer_switch for instance. + +##### Parameters + +in_list (TEXT): The comma separated list to drop a value from + +in_drop_value (TEXT): The value to drop from the input list + +##### Returns + +TEXT + +##### Example + +```SQL +mysql> select @@sql_mode; ++-----------------------------------------------------------------------------------------------+ +| @@sql_mode | ++-----------------------------------------------------------------------------------------------+ +| ANSI_QUOTES,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | ++-----------------------------------------------------------------------------------------------+ +1 row in set (0.00 sec) + +mysql> set sql_mode = sys.list_drop(@@sql_mode, 'ONLY_FULL_GROUP_BY'); +Query OK, 0 rows affected (0.03 sec) + +mysql> select @@sql_mode; ++----------------------------------------------------------------------------+ +| @@sql_mode | ++----------------------------------------------------------------------------+ +| ANSI_QUOTES,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | ++----------------------------------------------------------------------------+ +1 row in set (0.00 sec) +``` + +#### ps_is_account_enabled + +##### Description + +Determines whether instrumentation of an account is enabled within Performance Schema. + +##### Parameters + +* in_host VARCHAR(60): The hostname of the account to check. +* in_user VARCHAR(32): The username of the account to check. + +##### Returns + +ENUM('YES', 'NO') + +##### Example +```SQL +mysql> SELECT sys.ps_is_account_enabled('localhost', 'root'); ++------------------------------------------------+ +| sys.ps_is_account_enabled('localhost', 'root') | ++------------------------------------------------+ +| YES | ++------------------------------------------------+ +1 row in set (0.01 sec) +``` + +#### ps_is_consumer_enabled + +##### Description + +Determines whether a consumer is enabled (taking the consumer hierarchy into consideration) within the Performance Schema. + +##### Parameters + +* in_consumer VARCHAR(64): The name of the consumer to check. + +##### Returns + +ENUM('YES', 'NO') + +##### Example +```SQL +mysql> SELECT sys.ps_is_consumer_enabled('events_stages_history'); ++-----------------------------------------------------+ +| sys.ps_is_consumer_enabled('events_stages_history') | ++-----------------------------------------------------+ +| NO | ++-----------------------------------------------------+ +1 row in set (0.00 sec) +``` + +#### ps_is_instrument_default_enabled + +##### Description + +Returns whether an instrument is enabled by default in this version of MySQL. + +##### Parameters + +* in_instrument VARCHAR(128): The instrument to check. + +##### Returns + +ENUM('YES', 'NO') + +##### Example +```SQL +mysql> SELECT sys.ps_is_instrument_default_enabled('statement/sql/select'); ++--------------------------------------------------------------+ +| sys.ps_is_instrument_default_enabled('statement/sql/select') | ++--------------------------------------------------------------+ +| YES | ++--------------------------------------------------------------+ +1 row in set (0.00 sec) +``` + +#### ps_is_instrument_default_timed + +##### Description + +Returns whether an instrument is timed by default in this version of MySQL. + +##### Parameters + +* in_instrument VARCHAR(128): The instrument to check. + +##### Returns + +ENUM('YES', 'NO') + +##### Example +```SQL +mysql> SELECT sys.ps_is_instrument_default_timed('statement/sql/select'); ++------------------------------------------------------------+ +| sys.ps_is_instrument_default_timed('statement/sql/select') | ++------------------------------------------------------------+ +| YES | ++------------------------------------------------------------+ +1 row in set (0.00 sec) +``` + +#### ps_is_thread_instrumented + +##### Description + +Checks whether the provided connection id is instrumented within Performance Schema. + +##### Parameters + +* in_connection_id (BIGINT UNSIGNED): the id of the connection to check. + +##### Returns + +ENUM('YES', 'NO', 'UNKNOWN') + +##### Example +```SQL +mysql> SELECT sys.ps_is_thread_instrumented(CONNECTION_ID()); ++------------------------------------------------+ +| sys.ps_is_thread_instrumented(CONNECTION_ID()) | ++------------------------------------------------+ +| YES | ++------------------------------------------------+ +1 row in set (0.10 sec) +``` + +#### ps_thread_id + +##### Description + +Return the Performance Schema THREAD_ID for the specified connection ID. + +##### Parameters + +* in_connection_id (BIGINT UNSIGNED): The id of the connection to return the thread id for. If NULL, the current connection thread id is returned. + +##### Returns + +BIGINT UNSIGNED + +##### Example +```SQL +mysql> SELECT sys.ps_thread_id(79); ++----------------------+ +| sys.ps_thread_id(79) | ++----------------------+ +| 98 | ++----------------------+ +1 row in set (0.00 sec) + +mysql> SELECT sys.ps_thread_id(CONNECTION_ID()); ++-----------------------------------+ +| sys.ps_thread_id(CONNECTION_ID()) | ++-----------------------------------+ +| 98 | ++-----------------------------------+ +1 row in set (0.00 sec) +``` + +#### ps_thread_stack + +##### Description + +Outputs a JSON formatted stack of all statements, stages and events within Performance Schema for the specified thread. + +##### Parameters + +* thd_id (BIGINT): The id of the thread to trace. This should match the thread_id column from the performance_schema.threads table. + +##### Example + +(line separation added for output) + +```SQL + mysql> SELECT sys.ps_thread_stack(37, FALSE) AS thread_stack\G +*************************** 1. row *************************** +thread_stack: {"rankdir": "LR","nodesep": "0.10","stack_created": "2014-02-19 13:39:03", +"mysql_version": "5.7.3-m13","mysql_user": "root@localhost","events": +[{"nesting_event_id": "0", "event_id": "10", "timer_wait": 256.35, "event_info": +"sql/select", "wait_info": "select @@version_comment limit 1\nerrors: 0\nwarnings: 0\nlock time: +... +``` + +#### ps_thread_trx_info + +##### Description + +Returns a JSON object with info on the given thread's current transaction, and the statements it has already executed, derived from the `performance_schema.events_transactions_current` and `performance_schema.events_statements_history` tables (so the consumers for these also have to be enabled within Performance Schema to get full data in the object). + +When the output exceeds the default truncation length (65535), a JSON error object is returned, such as: + +`{ "error": "Trx info truncated: Row 6 was cut by GROUP_CONCAT()" }` + +Similar error objects are returned for other warnings/and exceptions raised when calling the function. + +The max length of the output of this function can be controlled with the `ps_thread_trx_info.max_length` variable set via `sys_config`, or the `@sys.ps_thread_trx_info.max_length` user variable, as appropriate. + +##### Parameters + +* in_thread_id (BIGINT UNSIGNED): The id of the thread to return the transaction info for. + +##### Example + +```SQL +SELECT sys.ps_thread_trx_info(48)\G +*************************** 1. row *************************** +sys.ps_thread_trx_info(48): [ + { + "time": "790.70 us", + "state": "COMMITTED", + "mode": "READ WRITE", + "autocommitted": "NO", + "gtid": "AUTOMATIC", + "isolation": "REPEATABLE READ", + "statements_executed": [ + { + "sql_text": "INSERT INTO info VALUES (1, \'foo\')", + "time": "471.02 us", + "schema": "trx", + "rows_examined": 0, + "rows_affected": 1, + "rows_sent": 0, + "tmp_tables": 0, + "tmp_disk_tables": 0, + "sort_rows": 0, + "sort_merge_passes": 0 + }, + { + "sql_text": "COMMIT", + "time": "254.42 us", + "schema": "trx", + "rows_examined": 0, + "rows_affected": 0, + "rows_sent": 0, + "tmp_tables": 0, + "tmp_disk_tables": 0, + "sort_rows": 0, + "sort_merge_passes": 0 + } + ] + }, + { + "time": "426.20 us", + "state": "COMMITTED", + "mode": "READ WRITE", + "autocommitted": "NO", + "gtid": "AUTOMATIC", + "isolation": "REPEATABLE READ", + "statements_executed": [ + { + "sql_text": "INSERT INTO info VALUES (2, \'bar\')", + "time": "107.33 us", + "schema": "trx", + "rows_examined": 0, + "rows_affected": 1, + "rows_sent": 0, + "tmp_tables": 0, + "tmp_disk_tables": 0, + "sort_rows": 0, + "sort_merge_passes": 0 + }, + { + "sql_text": "COMMIT", + "time": "213.23 us", + "schema": "trx", + "rows_examined": 0, + "rows_affected": 0, + "rows_sent": 0, + "tmp_tables": 0, + "tmp_disk_tables": 0, + "sort_rows": 0, + "sort_merge_passes": 0 + } + ] + } +] +1 row in set (0.03 sec) +``` + +#### quote_identifier + +##### Description + +Takes an unquoted identifier (schema name, table name, etc.) and +returns the identifier quoted with backticks. + +##### Parameters + +* in_identifier (TEXT): The identifier to quote. + +##### Returns + +TEXT + +##### Example +```SQL +mysql> SELECT sys.quote_identifier('my_identifier') AS Identifier; ++-----------------+ +| Identifier | ++-----------------+ +| `my_identifier` | ++-----------------+ +1 row in set (0.00 sec) + +mysql> SELECT sys.quote_identifier('my`idenfier') AS Identifier; ++----------------+ +| Identifier | ++----------------+ +| `my``idenfier` | ++----------------+ +1 row in set (0.00 sec) +``` + +#### sys_get_config + +##### Description + +Returns the value for the requested variable using the following logic: + +1. If the option exists in sys.sys_config return the value from there. +2. Else fall back on the provided default value. + +Notes for using sys_get_config(): + +* If the default value argument to sys_get_config() is NULL and case 2. is reached, NULL is returned. + It is then expected that the caller is able to handle NULL for the given configuration option. +* The convention is to name the user variables @sys.<name of variable>. It is <name of variable> that + is stored in the sys_config table and is what is expected as the argument to sys_get_config(). +* If you want to check whether the configuration option has already been set and if not assign with + the return value of sys_get_config() you can use IFNULL(...) (see example below). However this should + not be done inside a loop (e.g. for each row in a result set) as for repeated calls where assignment + is only needed in the first iteration using IFNULL(...) is expected to be significantly slower than + using an IF (...) THEN ... END IF; block (see example below). + +##### Parameters + +* in_variable_name (VARCHAR(128)): The name of the config option to return the value for. +* in_default_value (VARCHAR(128)): The default value to return if the variable does not exist in sys.sys_config. + +##### Returns + +VARCHAR(128) + +##### Example +```SQL +-- Get the configuration value from sys.sys_config falling back on 128 if the option is not present in the table. +mysql> SELECT sys.sys_get_config('statement_truncate_len', 128) AS Value; ++-------+ +| Value | ++-------+ +| 64 | ++-------+ +1 row in set (0.00 sec) + +-- Check whether the option is already set, if not assign - IFNULL(...) one liner example. +mysql> SET @sys.statement_truncate_len = IFNULL(@sys.statement_truncate_len, sys.sys_get_config('statement_truncate_len', 64)); +Query OK, 0 rows affected (0.00 sec) + +-- Check whether the option is already set, if not assign - IF ... THEN ... END IF example. +IF (@sys.statement_truncate_len IS NULL) THEN + SET @sys.statement_truncate_len = sys.sys_get_config('statement_truncate_len', 64); +END IF; +``` + +#### version_major + +##### Description + +Returns the major version of MySQL Server. + +##### Returns + +TINYINT UNSIGNED + +##### Example +```SQL +mysql> SELECT VERSION(), sys.version_major(); ++--------------------------------------+---------------------+ +| VERSION() | sys.version_major() | ++--------------------------------------+---------------------+ +| 5.7.9-enterprise-commercial-advanced | 5 | ++--------------------------------------+---------------------+ +1 row in set (0.00 sec) +``` + +#### version_minor + +##### Description + +Returns the minor (release series) version of MySQL Server. + +##### Returns + +TINYINT UNSIGNED + +##### Example +```SQL +mysql> SELECT VERSION(), sys.server_minor(); ++--------------------------------------+---------------------+ +| VERSION() | sys.version_minor() | ++--------------------------------------+---------------------+ +| 5.7.9-enterprise-commercial-advanced | 7 | ++--------------------------------------+---------------------+ +1 row in set (0.00 sec) +``` + +#### version_patch + +##### Description + +Returns the patch release version of MySQL Server. + +##### Returns + +TINYINT UNSIGNED + +##### Example +```SQL +mysql> SELECT VERSION(), sys.version_patch(); ++--------------------------------------+---------------------+ +| VERSION() | sys.version_patch() | ++--------------------------------------+---------------------+ +| 5.7.9-enterprise-commercial-advanced | 9 | ++--------------------------------------+---------------------+ +1 row in set (0.00 sec) +``` + + +### Procedures + +#### create_synonym_db + +##### Description + +Takes a source database name and synonym name, and then creates the synonym database with views that point to all of the tables within the source database. + +Useful for creating a "ps" synonym for "performance_schema", or "is" instead of "information_schema", for example. + +##### Parameters + +* in_db_name (VARCHAR(64)): +** The database name that you would like to create a synonym for. +* in_synonym (VARCHAR(64)): +** The database synonym name. + +##### Example +```SQL +mysql> SHOW DATABASES; ++--------------------+ +| Database | ++--------------------+ +| information_schema | +| mysql | +| performance_schema | +| sys | +| test | ++--------------------+ +5 rows in set (0.00 sec) + +mysql> CALL sys.create_synonym_db('performance_schema', 'ps'); ++---------------------------------------+ +| summary | ++---------------------------------------+ +| Created 74 views in the `ps` database | ++---------------------------------------+ +1 row in set (8.57 sec) + +Query OK, 0 rows affected (8.57 sec) + +mysql> SHOW DATABASES; ++--------------------+ +| Database | ++--------------------+ +| information_schema | +| mysql | +| performance_schema | +| ps | +| sys | +| test | ++--------------------+ +6 rows in set (0.00 sec) + +mysql> SHOW FULL TABLES FROM ps; ++-----------------------------------------+------------+ +| Tables_in_ps | Table_type | ++-----------------------------------------+------------+ +| accounts | VIEW | +| cond_instances | VIEW | +| events_stages_current | VIEW | +| events_stages_history | VIEW | +... +``` + +#### diagnostics + +##### Description + +Create a report of the current status of the server for diagnostics purposes. Data collected includes (some items depends on versions and settings): + +* The GLOBAL VARIABLES +* Several sys schema views including metrics or equivalent (depending on version and settings) +* Queries in the 95th percentile +* Several ndbinfo views for MySQL Cluster +* Replication (both master and slave) information. + +Some of the sys schema views are calculated as initial (optional), overall, delta: + +* The initial view is the content of the view at the start of this procedure. + This output will be the same as the the start values used for the delta view. + The initial view is included if @sys.diagnostics.include_raw = 'ON'. +* The overall view is the content of the view at the end of this procedure. + This output is the same as the end values used for the delta view. + The overall view is always included. +* The delta view is the difference from the beginning to the end. Note that for min and max values + they are simply the min or max value from the end view respectively, so does not necessarily reflect + the minimum/maximum value in the monitored period. + Note: except for the metrics view the delta is only calculation between the first and last outputs. + +Requires the SUPER privilege for "SET sql_log_bin = 0;". + +Versions supported: +* MySQL 5.6: 5.6.10 and later +* MySQL 5.7: 5.7.9 and later + +Some configuration options are supported: + +* sys.diagnostics.allow_i_s_tables + Specifies whether it is allowed to do table scan queries on information_schema.TABLES. This can be expensive if there + are many tables. Set to 'ON' to allow, 'OFF' to not allow. + Default is 'OFF'. + +* sys.diagnostics.include_raw + Set to 'ON' to include the raw data (e.g. the original output of "SELECT * FROM sys.metrics"). + Use this to get the initial values of the various views. + Default is 'OFF'. + +* sys.statement_truncate_len + How much of queries in the process list output to include. + Default is 64. + +* sys.debug + Whether to provide debugging output. + Default is 'OFF'. Set to 'ON' to include. + +##### Parameters + +* in_max_runtime (INT UNSIGNED): +The maximum time to keep collecting data. +Use NULL to get the default which is 60 seconds, otherwise enter a value greater than 0. +* in_interval (INT UNSIGNED): +How long to sleep between data collections. +Use NULL to get the default which is 30 seconds, otherwise enter a value greater than 0. +* in_auto_config (ENUM('current', 'medium', 'full')) +Automatically enable Performance Schema instruments and consumers. +NOTE: The more that are enabled, the more impact on the performance. +If another setting the 'current' is chosen, the current settings +are restored at the end of the procedure. +Supported values are: +** current - use the current settings. +** medium - enable some settings. +** full - enables all settings. This will have a big impact on the + performance - be careful using this option. + +##### Example +```SQL +mysql> TEE diag.out; +mysql> CALL sys.diagnostics(120, 30, 'current'); +... +mysql> NOTEE; +``` + +#### ps_setup_disable_background_threads + +##### Description + +Disable all background thread instrumentation within Performance Schema. + +##### Parameters + +None. + +##### Example +```SQL +mysql> CALL sys.ps_setup_disable_background_threads(); ++--------------------------------+ +| summary | ++--------------------------------+ +| Disabled 18 background threads | ++--------------------------------+ +1 row in set (0.00 sec) +``` + +#### execute_prepared_stmt + +##### Description + +Takes the query in the argument and executes it using a prepared statement. The prepared statement is deallocated, +so the procedure is mainly useful for executing one off dynamically created queries. + +The sys_execute_prepared_stmt prepared statement name is used for the query and is required not to exist. + +##### Parameters + +* in_query (longtext CHARACTER SET UTF8): +** The query to execute. + +The following configuration option is supported: + + * sys.debug + Whether to provide debugging output. + Default is 'OFF'. Set to 'ON' to include. + +##### Example +```SQL +mysql> CALL sys.execute_prepared_stmt('SELECT * FROM sys.sys_config'); ++------------------------+-------+---------------------+--------+ +| variable | value | set_time | set_by | ++------------------------+-------+---------------------+--------+ +| statement_truncate_len | 64 | 2015-06-30 13:06:00 | NULL | ++------------------------+-------+---------------------+--------+ +1 row in set (0.00 sec) + +Query OK, 0 rows affected (0.00 sec) +``` + +#### ps_setup_disable_consumer + +##### Description + +Disables consumers within Performance Schema matching the input pattern. + +##### Parameters + +* consumer (VARCHAR(128)): A LIKE pattern match (using "%consumer%") of consumers to disable + +##### Example + +To disable all consumers: +```SQL +mysql> CALL sys.ps_setup_disable_consumer(''); ++--------------------------+ +| summary | ++--------------------------+ +| Disabled 15 consumers | ++--------------------------+ +1 row in set (0.02 sec) +``` + +To disable just the event_stage consumers: +```SQL +mysql> CALL sys.ps_setup_disable_consumer('stage'); ++------------------------+ +| summary | ++------------------------+ +| Disabled 3 consumers | ++------------------------+ +1 row in set (0.00 sec) +``` + +#### ps_setup_disable_instrument + +##### Description + +Disables instruments within Performance Schema matching the input pattern. + +##### Parameters + +* in_pattern (VARCHAR(128)): A LIKE pattern match (using "%in_pattern%") of events to disable + +##### Example + +To disable all mutex instruments: +```SQL +mysql> CALL sys.ps_setup_disable_instrument('wait/synch/mutex'); ++--------------------------+ +| summary | ++--------------------------+ +| Disabled 155 instruments | ++--------------------------+ +1 row in set (0.02 sec) +``` +To disable just a specific TCP/IP based network IO instrument: +```SQL +mysql> CALL sys.ps_setup_disable_instrument('wait/io/socket/sql/server_tcpip_socket'); ++------------------------+ +| summary | ++------------------------+ +| Disabled 1 instruments | ++------------------------+ +1 row in set (0.00 sec) +``` +To disable all instruments: +```SQL +mysql> CALL sys.ps_setup_disable_instrument(''); ++--------------------------+ +| summary | ++--------------------------+ +| Disabled 547 instruments | ++--------------------------+ +1 row in set (0.01 sec) +``` + +#### ps_setup_disable_thread + +##### Description + +Disable the given connection/thread in Performance Schema. + +##### Parameters + +* in_connection_id (BIGINT): The connection ID (PROCESSLIST_ID from performance_schema.threads or the ID shown within SHOW PROCESSLIST) + +##### Example +```SQL +mysql> CALL sys.ps_setup_disable_thread(3); ++-------------------+ +| summary | ++-------------------+ +| Disabled 1 thread | ++-------------------+ +1 row in set (0.01 sec) +``` +To disable the current connection: +```SQL +mysql> CALL sys.ps_setup_disable_thread(CONNECTION_ID()); ++-------------------+ +| summary | ++-------------------+ +| Disabled 1 thread | ++-------------------+ +1 row in set (0.00 sec) +``` + +#### ps_setup_enable_background_threads + +##### Description + +Enable all background thread instrumentation within Performance Schema. + +##### Parameters + +None. + +##### Example +```SQL +mysql> CALL sys.ps_setup_enable_background_threads(); ++-------------------------------+ +| summary | ++-------------------------------+ +| Enabled 18 background threads | ++-------------------------------+ +1 row in set (0.00 sec) +``` + +#### ps_setup_enable_consumer + +##### Description + +Enables consumers within Performance Schema matching the input pattern. + +##### Parameters + +* consumer (VARCHAR(128)): A LIKE pattern match (using "%consumer%") of consumers to enable + +##### Example + +To enable all consumers: +```SQL +mysql> CALL sys.ps_setup_enable_consumer(''); ++-------------------------+ +| summary | ++-------------------------+ +| Enabled 10 consumers | ++-------------------------+ +1 row in set (0.02 sec) +``` + +To enable just "waits" consumers: +```SQL +mysql> CALL sys.ps_setup_enable_consumer('waits'); ++-----------------------+ +| summary | ++-----------------------+ +| Enabled 3 consumers | ++-----------------------+ +1 row in set (0.00 sec) +``` + +#### ps_setup_enable_instrument + +##### Description + +Enables instruments within Performance Schema matching the input pattern. + +##### Parameters + + +* in_pattern (VARCHAR(128)): A LIKE pattern match (using "%in_pattern%") of events to enable + +##### Example + +To enable all mutex instruments: +```SQL +mysql> CALL sys.ps_setup_enable_instrument('wait/synch/mutex'); ++-------------------------+ +| summary | ++-------------------------+ +| Enabled 155 instruments | ++-------------------------+ +1 row in set (0.02 sec) +``` +To enable just a specific TCP/IP based network IO instrument: +```SQL +mysql> CALL sys.ps_setup_enable_instrument('wait/io/socket/sql/server_tcpip_socket'); ++-----------------------+ +| summary | ++-----------------------+ +| Enabled 1 instruments | ++-----------------------+ +1 row in set (0.00 sec) +``` +To enable all instruments: +```SQL +mysql> CALL sys.ps_setup_enable_instrument(''); ++-------------------------+ +| summary | ++-------------------------+ +| Enabled 547 instruments | ++-------------------------+ +1 row in set (0.01 sec) +``` + +#### ps_setup_enable_thread + +##### Description + +Enable the given connection/thread in Performance Schema. + +##### Parameters + + +* in_connection_id (BIGINT): The connection ID (PROCESSLIST_ID from performance_schema.threads or the ID shown within SHOW PROCESSLIST) + +##### Example +```SQL +mysql> CALL sys.ps_setup_enable_thread(3); ++------------------+ +| summary | ++------------------+ +| Enabled 1 thread | ++------------------+ +1 row in set (0.01 sec) +``` +To enable the current connection: +```SQL +mysql> CALL sys.ps_setup_enable_thread(CONNECTION_ID()); ++------------------+ +| summary | ++------------------+ +| Enabled 1 thread | ++------------------+ +1 row in set (0.00 sec) +``` + +#### ps_setup_reload_saved + +##### Description + +Reloads a saved Performance Schema configuration, so that you can alter the setup for debugging purposes, but restore it to a previous state. + +Use the companion procedure - ps_setup_save(), to save a configuration. + +Requires the SUPER privilege for "SET sql_log_bin = 0;". + +##### Parameters + +None. + +##### Example +```SQL +mysql> CALL sys.ps_setup_save(); +Query OK, 0 rows affected (0.08 sec) + +mysql> UPDATE performance_schema.setup_instruments SET enabled = 'YES', timed = 'YES'; +Query OK, 547 rows affected (0.40 sec) +Rows matched: 784 Changed: 547 Warnings: 0 + +/* Run some tests that need more detailed instrumentation here */ + +mysql> CALL sys.ps_setup_reload_saved(); +Query OK, 0 rows affected (0.32 sec) +``` + +#### ps_setup_reset_to_default + +##### Description + +Resets the Performance Schema setup to the default settings. + +##### Parameters + +* in_verbose (BOOLEAN): Whether to print each setup stage (including the SQL) whilst running. + +##### Example +```SQL +mysql> CALL sys.ps_setup_reset_to_default(true)\G +*************************** 1. row *************************** +status: Resetting: setup_actors +DELETE +FROM performance_schema.setup_actors +WHERE NOT (HOST = '%' AND USER = '%' AND ROLE = '%') +1 row in set (0.00 sec) + +*************************** 1. row *************************** +status: Resetting: setup_actors +INSERT IGNORE INTO performance_schema.setup_actors +VALUES ('%', '%', '%') +1 row in set (0.00 sec) +... + +mysql> CALL sys.ps_setup_reset_to_default(false)\G +Query OK, 0 rows affected (0.00 sec) +``` + +#### ps_setup_save + +##### Description + +Saves the current configuration of Performance Schema, so that you can alter the setup for debugging purposes, but restore it to a previous state. + +Use the companion procedure - ps_setup_reload_saved(), to restore the saved config. + +The named lock "sys.ps_setup_save" is taken before the current configuration is saved. If the attempt to get the named lock times out, an error occurs. + +The lock is released after the settings have been restored by calling ps_setup_reload_saved(). + +Requires the SUPER privilege for "SET sql_log_bin = 0;". + +##### Parameters + +* in_timeout (INT): The timeout in seconds used when trying to obtain the lock. A negative timeout means infinite timeout. + +##### Example +```SQL +mysql> CALL sys.ps_setup_save(-1); +Query OK, 0 rows affected (0.08 sec) + +mysql> UPDATE performance_schema.setup_instruments + -> SET enabled = 'YES', timed = 'YES'; +Query OK, 547 rows affected (0.40 sec) +Rows matched: 784 Changed: 547 Warnings: 0 + +/* Run some tests that need more detailed instrumentation here */ + +mysql> CALL sys.ps_setup_reload_saved(); +Query OK, 0 rows affected (0.32 sec) +``` + +#### ps_setup_show_disabled + +##### Description + +Shows all currently disable Performance Schema configuration. + +Disabled users is only available for MySQL 5.7.6 and later. +In earlier versions it was only possible to enable users. + +##### Parameters + +* in_show_instruments (BOOLEAN): Whether to print disabled instruments (can print many items) +* in_show_threads (BOOLEAN): Whether to print disabled threads + +##### Example +```SQL +mysql> CALL sys.ps_setup_show_disabled(TRUE, TRUE); ++----------------------------+ +| performance_schema_enabled | ++----------------------------+ +| 1 | ++----------------------------+ +1 row in set (0.00 sec) + ++--------------------+ +| disabled_users | ++--------------------+ +| 'mark'@'localhost' | ++--------------------+ +1 row in set (0.00 sec) + ++-------------+----------------------+---------+-------+ +| object_type | objects | enabled | timed | ++-------------+----------------------+---------+-------+ +| EVENT | mysql.% | NO | NO | +| EVENT | performance_schema.% | NO | NO | +| EVENT | information_schema.% | NO | NO | +| FUNCTION | mysql.% | NO | NO | +| FUNCTION | performance_schema.% | NO | NO | +| FUNCTION | information_schema.% | NO | NO | +| PROCEDURE | mysql.% | NO | NO | +| PROCEDURE | performance_schema.% | NO | NO | +| PROCEDURE | information_schema.% | NO | NO | +| TABLE | mysql.% | NO | NO | +| TABLE | performance_schema.% | NO | NO | +| TABLE | information_schema.% | NO | NO | +| TRIGGER | mysql.% | NO | NO | +| TRIGGER | performance_schema.% | NO | NO | +| TRIGGER | information_schema.% | NO | NO | ++-------------+----------------------+---------+-------+ +15 rows in set (0.00 sec) + ++----------------------------------+ +| disabled_consumers | ++----------------------------------+ +| events_stages_current | +| events_stages_history | +| events_stages_history_long | +| events_statements_history | +| events_statements_history_long | +| events_transactions_history | +| events_transactions_history_long | +| events_waits_current | +| events_waits_history | +| events_waits_history_long | ++----------------------------------+ +10 rows in set (0.00 sec) + +Empty set (0.00 sec) + ++---------------------------------------------------------------------------------------+-------+ +| disabled_instruments | timed | ++---------------------------------------------------------------------------------------+-------+ +| wait/synch/mutex/sql/TC_LOG_MMAP::LOCK_tc | NO | +| wait/synch/mutex/sql/LOCK_des_key_file | NO | +| wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_commit | NO | +... +| memory/sql/servers_cache | NO | +| memory/sql/udf_mem | NO | +| wait/lock/metadata/sql/mdl | NO | ++---------------------------------------------------------------------------------------+-------+ +547 rows in set (0.00 sec) + +Query OK, 0 rows affected (0.01 sec) +``` + +#### ps_setup_show_disabled_consumers + +##### Description + +Shows all currently disabled consumers. + +##### Parameters + +None + +##### Example + +```SQL +mysql> CALL sys.ps_setup_show_disabled_consumers(); + ++---------------------------+ +| disabled_consumers | ++---------------------------+ +| events_statements_current | +| global_instrumentation | +| thread_instrumentation | +| statements_digest | ++---------------------------+ +4 rows in set (0.05 sec) +``` + +#### ps_setup_show_disabled_instruments + +##### Description + +Shows all currently disabled instruments. + +##### Parameters + +None + +##### Example + +```SQL +mysql> CALL sys.ps_setup_show_disabled_instruments(); +``` + +#### ps_setup_show_enabled + +##### Description + +Shows all currently enabled Performance Schema configuration. + +##### Parameters + +* in_show_instruments (BOOLEAN): Whether to print enabled instruments (can print many items) +* in_show_threads (BOOLEAN): Whether to print enabled threads + +##### Example +```SQL +mysql> CALL sys.ps_setup_show_enabled(TRUE, TRUE); ++----------------------------+ +| performance_schema_enabled | ++----------------------------+ +| 1 | ++----------------------------+ +1 row in set (0.00 sec) + ++---------------+ +| enabled_users | ++---------------+ +| '%'@'%' | ++---------------+ +1 row in set (0.01 sec) + ++-------------+---------+---------+-------+ +| object_type | objects | enabled | timed | ++-------------+---------+---------+-------+ +| EVENT | %.% | YES | YES | +| FUNCTION | %.% | YES | YES | +| PROCEDURE | %.% | YES | YES | +| TABLE | %.% | YES | YES | +| TRIGGER | %.% | YES | YES | ++-------------+---------+---------+-------+ +5 rows in set (0.01 sec) + ++---------------------------+ +| enabled_consumers | ++---------------------------+ +| events_statements_current | +| global_instrumentation | +| thread_instrumentation | +| statements_digest | ++---------------------------+ +4 rows in set (0.05 sec) + ++---------------------------------+-------------+ +| enabled_threads | thread_type | ++---------------------------------+-------------+ +| sql/main | BACKGROUND | +| sql/thread_timer_notifier | BACKGROUND | +| innodb/io_ibuf_thread | BACKGROUND | +| innodb/io_log_thread | BACKGROUND | +| innodb/io_read_thread | BACKGROUND | +| innodb/io_read_thread | BACKGROUND | +| innodb/io_write_thread | BACKGROUND | +| innodb/io_write_thread | BACKGROUND | +| innodb/page_cleaner_thread | BACKGROUND | +| innodb/srv_lock_timeout_thread | BACKGROUND | +| innodb/srv_error_monitor_thread | BACKGROUND | +| innodb/srv_monitor_thread | BACKGROUND | +| innodb/srv_master_thread | BACKGROUND | +| innodb/srv_purge_thread | BACKGROUND | +| innodb/srv_worker_thread | BACKGROUND | +| innodb/srv_worker_thread | BACKGROUND | +| innodb/srv_worker_thread | BACKGROUND | +| innodb/buf_dump_thread | BACKGROUND | +| innodb/dict_stats_thread | BACKGROUND | +| sql/signal_handler | BACKGROUND | +| sql/compress_gtid_table | FOREGROUND | +| root@localhost | FOREGROUND | ++---------------------------------+-------------+ +22 rows in set (0.01 sec) + ++-------------------------------------+-------+ +| enabled_instruments | timed | ++-------------------------------------+-------+ +| wait/io/file/sql/map | YES | +| wait/io/file/sql/binlog | YES | +... +| statement/com/Error | YES | +| statement/com/ | YES | +| idle | YES | ++-------------------------------------+-------+ +210 rows in set (0.08 sec) + +Query OK, 0 rows affected (0.89 sec) +``` + +#### ps_setup_show_enabled_consumers + +##### Description + +Shows all currently enabled consumers. + +##### Parameters + +None + +##### Example + +```SQL +mysql> CALL sys.ps_setup_show_enabled_consumers(); + ++---------------------------+ +| enabled_consumers | ++---------------------------+ +| events_statements_current | +| global_instrumentation | +| thread_instrumentation | +| statements_digest | ++---------------------------+ +4 rows in set (0.05 sec) +``` + +#### ps_setup_show_enabled_instruments + +##### Description + +Shows all currently enabled instruments. + +##### Parameters + +None + +##### Example + +```SQL +mysql> CALL sys.ps_setup_show_enabled_instruments(); +``` + +#### ps_statement_avg_latency_histogram + +##### Description + +Outputs a textual histogram graph of the average latency values across all normalized queries tracked within the Performance Schema events_statements_summary_by_digest table. + +Can be used to show a very high level picture of what kind of latency distribution statements running within this instance have. + +##### Parameters + +None. + +##### Example +```SQL +mysql> CALL sys.ps_statement_avg_latency_histogram()\G +*************************** 1. row *************************** +Performance Schema Statement Digest Average Latency Histogram: + + . = 1 unit + * = 2 units + # = 3 units + +(0 - 38ms) 240 | ################################################################################ +(38 - 77ms) 38 | ...................................... +(77 - 115ms) 3 | ... +(115 - 154ms) 62 | ******************************* +(154 - 192ms) 3 | ... +(192 - 231ms) 0 | +(231 - 269ms) 0 | +(269 - 307ms) 0 | +(307 - 346ms) 0 | +(346 - 384ms) 1 | . +(384 - 423ms) 1 | . +(423 - 461ms) 0 | +(461 - 499ms) 0 | +(499 - 538ms) 0 | +(538 - 576ms) 0 | +(576 - 615ms) 1 | . + + Total Statements: 350; Buckets: 16; Bucket Size: 38 ms; +``` + +#### ps_trace_statement_digest + +##### Description + +Traces all instrumentation within Performance Schema for a specific Statement Digest. + +When finding a statement of interest within the performance_schema.events_statements_summary_by_digest table, feed the DIGEST MD5 value in to this procedure, set how long to poll for, and at what interval to poll, and it will generate a report of all statistics tracked within Performance Schema for that digest for the interval. + +It will also attempt to generate an EXPLAIN for the longest running example of the digest during the interval. + +Note this may fail, as: + +* Performance Schema truncates long SQL_TEXT values (and hence the EXPLAIN will fail due to parse errors) +* the default schema is sys (so tables that are not fully qualified in the query may not be found) +* some queries such as SHOW are not supported in EXPLAIN. + +When the EXPLAIN fails, the error will be ignored and no EXPLAIN output generated. + +Requires the SUPER privilege for "SET sql_log_bin = 0;". + +##### Parameters + +* in_digest VARCHAR(32): The statement digest identifier you would like to analyze +* in_runtime (INT): The number of seconds to run analysis for +* in_interval (DECIMAL(2,2)): The interval (in seconds, may be fractional) at which to try and take snapshots +* in_start_fresh (BOOLEAN): Whether to TRUNCATE the events_statements_history_long and events_stages_history_long tables before starting +* in_auto_enable (BOOLEAN): Whether to automatically turn on required consumers + +##### Example +```SQL +mysql> call ps_analyze_statement_digest('891ec6860f98ba46d89dd20b0c03652c', 10, 0.1, true, true); ++--------------------+ +| SUMMARY STATISTICS | ++--------------------+ +| SUMMARY STATISTICS | ++--------------------+ +1 row in set (9.11 sec) + ++------------+-----------+-----------+-----------+---------------+------------+------------+ +| executions | exec_time | lock_time | rows_sent | rows_examined | tmp_tables | full_scans | ++------------+-----------+-----------+-----------+---------------+------------+------------+ +| 21 | 4.11 ms | 2.00 ms | 0 | 21 | 0 | 0 | ++------------+-----------+-----------+-----------+---------------+------------+------------+ +1 row in set (9.11 sec) + ++------------------------------------------+-------+-----------+ +| event_name | count | latency | ++------------------------------------------+-------+-----------+ +| stage/sql/checking query cache for query | 16 | 724.37 us | +| stage/sql/statistics | 16 | 546.92 us | +| stage/sql/freeing items | 18 | 520.11 us | +| stage/sql/init | 51 | 466.80 us | +... +| stage/sql/cleaning up | 18 | 11.92 us | +| stage/sql/executing | 16 | 6.95 us | ++------------------------------------------+-------+-----------+ +17 rows in set (9.12 sec) + ++---------------------------+ +| LONGEST RUNNING STATEMENT | ++---------------------------+ +| LONGEST RUNNING STATEMENT | ++---------------------------+ +1 row in set (9.16 sec) + ++-----------+-----------+-----------+-----------+---------------+------------+-----------+ +| thread_id | exec_time | lock_time | rows_sent | rows_examined | tmp_tables | full_scan | ++-----------+-----------+-----------+-----------+---------------+------------+-----------+ +| 166646 | 618.43 us | 1.00 ms | 0 | 1 | 0 | 0 | ++-----------+-----------+-----------+-----------+---------------+------------+-----------+ +1 row in set (9.16 sec) + +// Truncated for clarity... ++-----------------------------------------------------------------+ +| sql_text | ++-----------------------------------------------------------------+ +| select hibeventhe0_.id as id1382_, hibeventhe0_.createdTime ... | ++-----------------------------------------------------------------+ +1 row in set (9.17 sec) + ++------------------------------------------+-----------+ +| event_name | latency | ++------------------------------------------+-----------+ +| stage/sql/init | 8.61 us | +| stage/sql/Waiting for query cache lock | 453.23 us | +| stage/sql/init | 331.07 ns | +| stage/sql/checking query cache for query | 43.04 us | +... +| stage/sql/freeing items | 30.46 us | +| stage/sql/cleaning up | 662.13 ns | ++------------------------------------------+-----------+ + 18 rows in set (9.23 sec) + ++----+-------------+--------------+-------+---------------+-----------+---------+-------------+------+-------+ +| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | ++----+-------------+--------------+-------+---------------+-----------+---------+-------------+------+-------+ +| 1 | SIMPLE | hibeventhe0_ | const | fixedTime | fixedTime | 775 | const,const | 1 | NULL | ++----+-------------+--------------+-------+---------------+-----------+---------+-------------+------+-------+ +1 row in set (9.27 sec) + +Query OK, 0 rows affected (9.28 sec) +``` + +#### ps_trace_thread + +##### Description + +Dumps all data within Performance Schema for an instrumented thread, to create a DOT formatted graph file. + +Each resultset returned from the procedure should be used for a complete graph + +Requires the SUPER privilege for "SET sql_log_bin = 0;". + +##### Parameters + +* in_thread_id (INT): The thread that you would like a stack trace for +* in_outfile (VARCHAR(255)): The filename the dot file will be written to +* in_max_runtime (DECIMAL(20,2)): The maximum time to keep collecting data. Use NULL to get the default which is 60 seconds. +* in_interval (DECIMAL(20,2)): How long to sleep between data collections. Use NULL to get the default which is 1 second. +* in_start_fresh (BOOLEAN): Whether to reset all Performance Schema data before tracing. +* in_auto_setup (BOOLEAN): Whether to disable all other threads and enable all consumers/instruments. This will also reset the settings at the end of the run. +* in_debug (BOOLEAN): Whether you would like to include file:lineno in the graph + +##### Example +```SQL +mysql> CALL sys.ps_trace_thread(25, CONCAT('/tmp/stack-', REPLACE(NOW(), ' ', '-'), '.dot'), NULL, NULL, TRUE, TRUE, TRUE); ++-------------------+ +| summary | ++-------------------+ +| Disabled 1 thread | ++-------------------+ +1 row in set (0.00 sec) + ++---------------------------------------------+ +| Info | ++---------------------------------------------+ +| Data collection starting for THREAD_ID = 25 | ++---------------------------------------------+ +1 row in set (0.03 sec) + ++-----------------------------------------------------------+ +| Info | ++-----------------------------------------------------------+ +| Stack trace written to /tmp/stack-2014-02-16-21:18:41.dot | ++-----------------------------------------------------------+ +1 row in set (60.07 sec) + ++-------------------------------------------------------------------+ +| Convert to PDF | ++-------------------------------------------------------------------+ +| dot -Tpdf -o /tmp/stack_25.pdf /tmp/stack-2014-02-16-21:18:41.dot | ++-------------------------------------------------------------------+ +1 row in set (60.07 sec) + ++-------------------------------------------------------------------+ +| Convert to PNG | ++-------------------------------------------------------------------+ +| dot -Tpng -o /tmp/stack_25.png /tmp/stack-2014-02-16-21:18:41.dot | ++-------------------------------------------------------------------+ +1 row in set (60.07 sec) + ++------------------+ +| summary | ++------------------+ +| Enabled 1 thread | ++------------------+ +1 row in set (60.32 sec) +``` + +#### ps_truncate_all_tables + +##### Description + +Truncates all summary tables within Performance Schema, resetting all aggregated instrumentation as a snapshot. + +##### Parameters + +* in_verbose (BOOLEAN): Whether to print each TRUNCATE statement before running + +##### Example +```SQL +mysql> CALL sys.ps_truncate_all_tables(false); ++---------------------+ +| summary | ++---------------------+ +| Truncated 44 tables | ++---------------------+ +1 row in set (0.10 sec) +``` + +#### statement_performance_analyzer + +##### Description +Create a report of the statements running on the server. + +The views are calculated based on the overall and/or delta activity. + +Requires the SUPER privilege for "SET sql_log_bin = 0;". + +The following configuration options are supported: + + * sys.statement_performance_analyzer.limit + The maximum number of rows to include for the views that does not have a built-in limit (e.g. the 95th percentile view). + If not set the limit is 100. + + * sys.statement_performance_analyzer.view + Used together with the 'custom' view. If the value contains a space, it is considered a query, otherwise it must be + an existing view querying the performance_schema.events_statements_summary_by_digest table. There cannot be any limit + clause including in the query or view definition if @sys.statement_performance_analyzer.limit > 0. + If specifying a view, use the same format as for in_table. + + * sys.debug + Whether to provide debugging output. + Default is 'OFF'. Set to 'ON' to include. + +##### Parameters + +* in_action (ENUM('snapshot', 'overall', 'delta', 'create_tmp', 'create_table', 'save', 'cleanup')): + The action to take. Supported actions are: + - snapshot Store a snapshot. The default is to make a snapshot of the current content of + performance_schema.events_statements_summary_by_digest, but by setting in_table + this can be overwritten to copy the content of the specified table. + The snapshot is stored in the sys.tmp_digests temporary table. + - overall Generate analyzis based on the content specified by in_table. For the overall analyzis, + in_table can be NOW() to use a fresh snapshot. This will overwrite an existing snapshot. + Use NULL for in_table to use the existing snapshot. If in_table IS NULL and no snapshot + exists, a new will be created. + See also in_views and @sys.statement_performance_analyzer.limit. + - delta Generate a delta analysis. The delta will be calculated between the reference table in + in_table and the snapshot. An existing snapshot must exist. + The action uses the sys.tmp_digests_delta temporary table. + See also in_views and @sys.statement_performance_analyzer.limit. + - create_table Create a regular table suitable for storing the snapshot for later use, e.g. for + calculating deltas. + - create_tmp Create a temporary table suitable for storing the snapshot for later use, e.g. for + calculating deltas. + - save Save the snapshot in the table specified by in_table. The table must exists and have + the correct structure. + If no snapshot exists, a new is created. + - cleanup Remove the temporary tables used for the snapshot and delta. + +* in_table (VARCHAR(129)): + The table argument used for some actions. Use the format 'db1.t1' or 't1' without using any backticks (`) + for quoting. Periods (.) are not supported in the database and table names. + + The meaning of the table for each action supporting the argument is: + + - snapshot The snapshot is created based on the specified table. Set to NULL or NOW() to use + the current content of performance_schema.events_statements_summary_by_digest. + - overall The table with the content to create the overall analyzis for. The following values + can be used: + - A table name - use the content of that table. + - NOW() - create a fresh snapshot and overwrite the existing snapshot. + - NULL - use the last stored snapshot. + - delta The table name is mandatory and specified the reference view to compare the currently + stored snapshot against. If no snapshot exists, a new will be created. + - create_table The name of the regular table to create. + - create_tmp The name of the temporary table to create. + - save The name of the table to save the currently stored snapshot into. + +* in_views (SET ('with_runtimes_in_95th_percentile', 'analysis', 'with_errors_or_warnings', + 'with_full_table_scans', 'with_sorting', 'with_temp_tables', 'custom')) + Which views to include: + + - with_runtimes_in_95th_percentile Based on the sys.statements_with_runtimes_in_95th_percentile view + - analysis Based on the sys.statement_analysis view + - with_errors_or_warnings Based on the sys.statements_with_errors_or_warnings view + - with_full_table_scans Based on the sys.statements_with_full_table_scans view + - with_sorting Based on the sys.statements_with_sorting view + - with_temp_tables Based on the sys.statements_with_temp_tables view + - custom Use a custom view. This view must be specified in @sys.statement_performance_analyzer.view to an existing view or a query + + Default is to include all except 'custom'. + +##### Example +```SQL +-- To create a report with the queries in the 95th percentile since last truncate of performance_schema.events_statements_summary_by_digest and the delta for a 1 minute period: +-- +-- 1. Create a temporary table to store the initial snapshot. +-- 2. Create the initial snapshot. +-- 3. Save the initial snapshot in the temporary table. +-- 4. Wait one minute. +-- 5. Create a new snapshot. +-- 6. Perform analyzis based on the new snapshot. +-- 7. Perform analyzis based on the delta between the initial and new snapshots. + +mysql> CALL sys.statement_performance_analyzer('create_tmp', 'mydb.tmp_digests_ini', NULL); +Query OK, 0 rows affected (0.08 sec) + +mysql> CALL sys.statement_performance_analyzer('snapshot', NULL, NULL); +Query OK, 0 rows affected (0.02 sec) + +mysql> CALL sys.statement_performance_analyzer('save', 'mydb.tmp_digests_ini', NULL); +Query OK, 0 rows affected (0.00 sec) + +mysql> DO SLEEP(60); +Query OK, 0 rows affected (1 min 0.00 sec) + +mysql> CALL sys.statement_performance_analyzer('snapshot', NULL, NULL); +Query OK, 0 rows affected (0.02 sec) + +mysql> CALL sys.statement_performance_analyzer('overall', NULL, 'with_runtimes_in_95th_percentile'); ++-----------------------------------------+ +| Next Output | ++-----------------------------------------+ +| Queries with Runtime in 95th Percentile | ++-----------------------------------------+ +1 row in set (0.05 sec) + +... + +mysql> CALL sys.statement_performance_analyzer('delta', 'mydb.tmp_digests_ini', 'with_runtimes_in_95th_percentile'); ++-----------------------------------------+ +| Next Output | ++-----------------------------------------+ +| Queries with Runtime in 95th Percentile | ++-----------------------------------------+ +1 row in set (0.03 sec) + +... + + +-- To create an overall report of the 95th percentile queries and the top 10 queries with full table scans: + +mysql> CALL sys.statement_performance_analyzer('snapshot', NULL, NULL); +Query OK, 0 rows affected (0.01 sec) + +mysql> SET @sys.statement_performance_analyzer.limit = 10; +Query OK, 0 rows affected (0.00 sec) + +mysql> CALL sys.statement_performance_analyzer('overall', NULL, 'with_runtimes_in_95th_percentile,with_full_table_scans'); ++-----------------------------------------+ +| Next Output | ++-----------------------------------------+ +| Queries with Runtime in 95th Percentile | ++-----------------------------------------+ +1 row in set (0.01 sec) + +... + ++-------------------------------------+ +| Next Output | ++-------------------------------------+ +| Top 10 Queries with Full Table Scan | ++-------------------------------------+ +1 row in set (0.09 sec) + +... + + +-- Use a custom view showing the top 10 query sorted by total execution time refreshing the view every minute using +-- the watch command in Linux. + +mysql> CREATE OR REPLACE VIEW mydb.my_statements AS + -> SELECT sys.format_statement(DIGEST_TEXT) AS query, + -> SCHEMA_NAME AS db, + -> COUNT_STAR AS exec_count, + -> sys.format_time(SUM_TIMER_WAIT) AS total_latency, + -> sys.format_time(AVG_TIMER_WAIT) AS avg_latency, + -> ROUND(IFNULL(SUM_ROWS_SENT / NULLIF(COUNT_STAR, 0), 0)) AS rows_sent_avg, + -> ROUND(IFNULL(SUM_ROWS_EXAMINED / NULLIF(COUNT_STAR, 0), 0)) AS rows_examined_avg, + -> ROUND(IFNULL(SUM_ROWS_AFFECTED / NULLIF(COUNT_STAR, 0), 0)) AS rows_affected_avg, + -> DIGEST AS digest + -> FROM performance_schema.events_statements_summary_by_digest + -> ORDER BY SUM_TIMER_WAIT DESC; +Query OK, 0 rows affected (0.01 sec) + +mysql> CALL sys.statement_performance_analyzer('create_table', 'mydb.digests_prev', NULL); +Query OK, 0 rows affected (0.10 sec) + +shell$ watch -n 60 "mysql sys --table -e \" +> SET @sys.statement_performance_analyzer.view = 'mydb.my_statements'; +> SET @sys.statement_performance_analyzer.limit = 10; +> CALL statement_performance_analyzer('snapshot', NULL, NULL); +> CALL statement_performance_analyzer('delta', 'mydb.digests_prev', 'custom'); +> CALL statement_performance_analyzer('save', 'mydb.digests_prev', NULL); +> \"" + +Every 60.0s: mysql sys --table -e " ... Mon Dec 22 10:58:51 2014 + ++----------------------------------+ +| Next Output | ++----------------------------------+ +| Top 10 Queries Using Custom View | ++----------------------------------+ ++-------------------+-------+------------+---------------+-------------+---------------+-------------------+-------------------+----------------------------------+ +| query | db | exec_count | total_latency | avg_latency | rows_sent_avg | rows_examined_avg | rows_affected_avg | digest | ++-------------------+-------+------------+---------------+-------------+---------------+-------------------+-------------------+----------------------------------+ +... +``` + +#### table_exists + +##### Description +Tests whether the table specified in in_db and in_table exists either as a regular +table, or as a temporary table. The returned value corresponds to the table that +will be used, so if there's both a temporary and a permanent table with the given +name, then 'TEMPORARY' will be returned. + +##### Parameters + +* in_db (VARCHAR(64)): The database name to check for the existence of the table in. + +* in_table (VARCHAR(64)): The name of the table to check the existence of. + +* out_exists ENUM('', 'BASE TABLE', 'VIEW', 'TEMPORARY'): The return value: whether the table exists. The value is one of: + - '' - the table does not exist neither as a base table, view, nor temporary table. + - 'BASE TABLE' - the table name exists as a permanent base table table. + - 'VIEW' - the table name exists as a view. + - 'TEMPORARY' - the table name exists as a temporary table. + +##### Example +```SQL +mysql> CREATE DATABASE db1; +Query OK, 1 row affected (0.07 sec) + +mysql> use db1; +Database changed +mysql> CREATE TABLE t1 (id INT PRIMARY KEY); +Query OK, 0 rows affected (0.08 sec) + +mysql> CREATE TABLE t2 (id INT PRIMARY KEY); +Query OK, 0 rows affected (0.08 sec) + +mysql> CREATE view v_t1 AS SELECT * FROM t1; +Query OK, 0 rows affected (0.00 sec) + +mysql> CREATE TEMPORARY TABLE t1 (id INT PRIMARY KEY); +Query OK, 0 rows affected (0.00 sec) + +mysql> CALL sys.table_exists('db1', 't1', @exists); SELECT @exists; +Query OK, 0 rows affected (0.00 sec) + ++------------+ +| @exists | ++------------+ +| TEMPORARY | ++------------+ +1 row in set (0.00 sec) + +mysql> CALL sys.table_exists('db1', 't2', @exists); SELECT @exists; +Query OK, 0 rows affected (0.00 sec) + ++------------+ +| @exists | ++------------+ +| BASE TABLE | ++------------+ +1 row in set (0.01 sec) + +mysql> CALL sys.table_exists('db1', 'v_t1', @exists); SELECT @exists; +Query OK, 0 rows affected (0.00 sec) + ++---------+ +| @exists | ++---------+ +| VIEW | ++---------+ +1 row in set (0.00 sec) + +mysql> CALL sys.table_exists('db1', 't3', @exists); SELECT @exists; +Query OK, 0 rows affected (0.01 sec) + ++---------+ +| @exists | ++---------+ +| | ++---------+ +1 row in set (0.00 sec) +``` diff --git a/scripts/sys_schema/after_setup.sql b/scripts/sys_schema/after_setup.sql new file mode 100644 index 00000000..833f84c4 --- /dev/null +++ b/scripts/sys_schema/after_setup.sql @@ -0,0 +1,18 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +SET @@sql_log_bin = @sql_log_bin; +use mysql; + diff --git a/scripts/sys_schema/before_setup.sql b/scripts/sys_schema/before_setup.sql new file mode 100644 index 00000000..c0634d69 --- /dev/null +++ b/scripts/sys_schema/before_setup.sql @@ -0,0 +1,22 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +SET NAMES utf8; +SET @sql_log_bin = @@sql_log_bin; +SET sql_log_bin = 0; + +CREATE DATABASE IF NOT EXISTS sys DEFAULT CHARACTER SET utf8; + +USE sys; diff --git a/scripts/sys_schema/functions/extract_schema_from_file_name.sql b/scripts/sys_schema/functions/extract_schema_from_file_name.sql new file mode 100644 index 00000000..92c127f9 --- /dev/null +++ b/scripts/sys_schema/functions/extract_schema_from_file_name.sql @@ -0,0 +1,66 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS extract_schema_from_file_name; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION extract_schema_from_file_name ( + path VARCHAR(512) + ) + RETURNS VARCHAR(64) + COMMENT ' + Description + ----------- + + Takes a raw file path, and attempts to extract the schema name from it. + + Useful for when interacting with Performance Schema data + concerning IO statistics, for example. + + Currently relies on the fact that a table data file will be within a + specified database directory (will not work with partitions or tables + that specify an individual DATA_DIRECTORY). + + Parameters + ----------- + + path (VARCHAR(512)): + The full file path to a data file to extract the schema name from. + + Returns + ----------- + + VARCHAR(64) + + Example + ----------- + + mysql> SELECT sys.extract_schema_from_file_name(\'/var/lib/mysql/employees/employee.ibd\'); + +----------------------------------------------------------------------------+ + | sys.extract_schema_from_file_name(\'/var/lib/mysql/employees/employee.ibd\') | + +----------------------------------------------------------------------------+ + | employees | + +----------------------------------------------------------------------------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + NO SQL +BEGIN + RETURN LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REPLACE(path, '\\', '/'), '/', -2), '/', 1), 64); +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/extract_table_from_file_name.sql b/scripts/sys_schema/functions/extract_table_from_file_name.sql new file mode 100644 index 00000000..54f92568 --- /dev/null +++ b/scripts/sys_schema/functions/extract_table_from_file_name.sql @@ -0,0 +1,62 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS extract_table_from_file_name; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION extract_table_from_file_name ( + path VARCHAR(512) + ) + RETURNS VARCHAR(64) + COMMENT ' + Description + ----------- + + Takes a raw file path, and extracts the table name from it. + + Useful for when interacting with Performance Schema data + concerning IO statistics, for example. + + Parameters + ----------- + + path (VARCHAR(512)): + The full file path to a data file to extract the table name from. + + Returns + ----------- + + VARCHAR(64) + + Example + ----------- + + mysql> SELECT sys.extract_table_from_file_name(\'/var/lib/mysql/employees/employee.ibd\'); + +---------------------------------------------------------------------------+ + | sys.extract_table_from_file_name(\'/var/lib/mysql/employees/employee.ibd\') | + +---------------------------------------------------------------------------+ + | employee | + +---------------------------------------------------------------------------+ + 1 row in set (0.02 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + NO SQL +BEGIN + RETURN LEFT(SUBSTRING_INDEX(REPLACE(SUBSTRING_INDEX(REPLACE(path, '\\', '/'), '/', -1), '@0024', '$'), '.', 1), 64); +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/format_bytes.sql b/scripts/sys_schema/functions/format_bytes.sql new file mode 100644 index 00000000..361aa39a --- /dev/null +++ b/scripts/sys_schema/functions/format_bytes.sql @@ -0,0 +1,84 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS format_bytes; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION format_bytes ( + -- We feed in and return TEXT here, as aggregates of + -- bytes can return numbers larger than BIGINT UNSIGNED + bytes TEXT + ) + RETURNS TEXT + COMMENT ' + Description + ----------- + + Takes a raw bytes value, and converts it to a human readable format. + + Parameters + ----------- + + bytes (TEXT): + A raw bytes value. + + Returns + ----------- + + TEXT + + Example + ----------- + + mysql> SELECT sys.format_bytes(2348723492723746) AS size; + +----------+ + | size | + +----------+ + | 2.09 PiB | + +----------+ + 1 row in set (0.00 sec) + + mysql> SELECT sys.format_bytes(2348723492723) AS size; + +----------+ + | size | + +----------+ + | 2.14 TiB | + +----------+ + 1 row in set (0.00 sec) + + mysql> SELECT sys.format_bytes(23487234) AS size; + +-----------+ + | size | + +-----------+ + | 22.40 MiB | + +-----------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + NO SQL +BEGIN + IF bytes IS NULL THEN RETURN NULL; + ELSEIF bytes >= 1125899906842624 THEN RETURN CONCAT(ROUND(bytes / 1125899906842624, 2), ' PiB'); + ELSEIF bytes >= 1099511627776 THEN RETURN CONCAT(ROUND(bytes / 1099511627776, 2), ' TiB'); + ELSEIF bytes >= 1073741824 THEN RETURN CONCAT(ROUND(bytes / 1073741824, 2), ' GiB'); + ELSEIF bytes >= 1048576 THEN RETURN CONCAT(ROUND(bytes / 1048576, 2), ' MiB'); + ELSEIF bytes >= 1024 THEN RETURN CONCAT(ROUND(bytes / 1024, 2), ' KiB'); + ELSE RETURN CONCAT(ROUND(bytes, 0), ' bytes'); + END IF; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/format_path.sql b/scripts/sys_schema/functions/format_path.sql new file mode 100644 index 00000000..426bfb1d --- /dev/null +++ b/scripts/sys_schema/functions/format_path.sql @@ -0,0 +1,111 @@ +-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS format_path; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION format_path ( + in_path VARCHAR(512) + ) + RETURNS VARCHAR(512) CHARSET UTF8 + COMMENT ' + Description + ----------- + + Takes a raw path value, and strips out the datadir or tmpdir + replacing with @@datadir and @@tmpdir respectively. + + Also normalizes the paths across operating systems, so backslashes + on Windows are converted to forward slashes + + Parameters + ----------- + + path (VARCHAR(512)): + The raw file path value to format. + + Returns + ----------- + + VARCHAR(512) CHARSET UTF8 + + Example + ----------- + + mysql> select @@datadir; + +-----------------------------------------------+ + | @@datadir | + +-----------------------------------------------+ + | /Users/mark/sandboxes/SmallTree/AMaster/data/ | + +-----------------------------------------------+ + 1 row in set (0.06 sec) + + mysql> select format_path(\'/Users/mark/sandboxes/SmallTree/AMaster/data/mysql/proc.MYD\') AS path; + +--------------------------+ + | path | + +--------------------------+ + | @@datadir/mysql/proc.MYD | + +--------------------------+ + 1 row in set (0.03 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + NO SQL +BEGIN + DECLARE v_path VARCHAR(512); + DECLARE v_undo_dir VARCHAR(1024); + DECLARE v_innodb_data_home_dir VARCHAR(1024); + DECLARE v_innodb_log_group_home_dir VARCHAR(1024); + + DECLARE path_separator CHAR(1) DEFAULT '/'; + + IF @@global.version_compile_os LIKE 'win%' THEN + SET path_separator = '\\'; + END IF; + + -- OSX hides /private/ in variables, but Performance Schema does not + IF in_path LIKE '/private/%' THEN + SET v_path = REPLACE(in_path, '/private', ''); + ELSE + SET v_path = in_path; + END IF; + + -- @@global.innodb_undo_directory is only set when separate undo logs are used + SET v_undo_dir = IFNULL((SELECT VARIABLE_VALUE FROM information_schema.global_variables WHERE VARIABLE_NAME = 'innodb_undo_directory'), ''); + SET v_innodb_data_home_dir= IFNULL((SELECT VARIABLE_VALUE FROM information_schema.global_variables WHERE VARIABLE_NAME = 'innodb_data_home_dir'), ''); + SET v_innodb_log_group_home_dir= IFNULL((SELECT VARIABLE_VALUE FROM information_schema.global_variables WHERE VARIABLE_NAME = 'innodb_log_group_home_dir'), ''); + IF v_path IS NULL THEN + RETURN NULL; + ELSEIF v_path LIKE CONCAT(@@global.datadir, IF(SUBSTRING(@@global.datadir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN + SET v_path = REPLACE(v_path, @@global.datadir, CONCAT('@@datadir', IF(SUBSTRING(@@global.datadir, -1) = path_separator, path_separator, ''))); + ELSEIF v_path LIKE CONCAT(@@global.tmpdir, IF(SUBSTRING(@@global.tmpdir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN + SET v_path = REPLACE(v_path, @@global.tmpdir, CONCAT('@@tmpdir', IF(SUBSTRING(@@global.tmpdir, -1) = path_separator, path_separator, ''))); +# ELSEIF v_path LIKE CONCAT(@@global.slave_load_tmpdir, IF(SUBSTRING(@@global.slave_load_tmpdir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN +# SET v_path = REPLACE(v_path, @@global.slave_load_tmpdir, CONCAT('@@slave_load_tmpdir', IF(SUBSTRING(@@global.slave_load_tmpdir, -1) = path_separator, path_separator, ''))); + ELSEIF v_path LIKE CONCAT(v_innodb_data_home_dir, IF(SUBSTRING(v_innodb_data_home_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN + SET v_path = REPLACE(v_path, v_innodb_data_home_dir, CONCAT('@@innodb_data_home_dir', IF(SUBSTRING(v_innodb_data_home_dir, -1) = path_separator, path_separator, ''))); + ELSEIF v_path LIKE CONCAT(v_innodb_log_group_home_dir, IF(SUBSTRING(v_innodb_log_group_home_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN + SET v_path = REPLACE(v_path, v_innodb_log_group_home_dir, CONCAT('@@innodb_log_group_home_dir', IF(SUBSTRING(v_innodb_log_group_home_dir, -1) = path_separator, path_separator, ''))); + ELSEIF v_path LIKE CONCAT(v_undo_dir, IF(SUBSTRING(v_undo_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN + SET v_path = REPLACE(v_path, v_undo_dir, CONCAT('@@innodb_undo_directory', IF(SUBSTRING(v_undo_dir, -1) = path_separator, path_separator, ''))); + ELSEIF v_path LIKE CONCAT(@@global.basedir, IF(SUBSTRING(@@global.basedir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN + SET v_path = REPLACE(v_path, @@global.basedir, CONCAT('@@basedir', IF(SUBSTRING(@@global.basedir, -1) = path_separator, path_separator, ''))); + END IF; + + RETURN v_path; +END$$ + +DELIMITER ;
\ No newline at end of file diff --git a/scripts/sys_schema/functions/format_path_57.sql b/scripts/sys_schema/functions/format_path_57.sql new file mode 100644 index 00000000..2bb8b723 --- /dev/null +++ b/scripts/sys_schema/functions/format_path_57.sql @@ -0,0 +1,136 @@ +-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS format_path; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION format_path ( + in_path VARCHAR(512) + ) + RETURNS VARCHAR(512) CHARSET UTF8 + COMMENT ' + Description + ----------- + + Takes a raw path value, and strips out the datadir or tmpdir + replacing with @@datadir and @@tmpdir respectively. + + Also normalizes the paths across operating systems, so backslashes + on Windows are converted to forward slashes + + Parameters + ----------- + + path (VARCHAR(512)): + The raw file path value to format. + + Returns + ----------- + + VARCHAR(512) CHARSET UTF8 + + Example + ----------- + + mysql> select @@datadir; + +-----------------------------------------------+ + | @@datadir | + +-----------------------------------------------+ + | /Users/mark/sandboxes/SmallTree/AMaster/data/ | + +-----------------------------------------------+ + 1 row in set (0.06 sec) + + mysql> select format_path(\'/Users/mark/sandboxes/SmallTree/AMaster/data/mysql/proc.MYD\') AS path; + +--------------------------+ + | path | + +--------------------------+ + | @@datadir/mysql/proc.MYD | + +--------------------------+ + 1 row in set (0.03 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + NO SQL +BEGIN + DECLARE v_dir VARCHAR(1024); + DECLARE v_path VARCHAR(512); + + DECLARE path_separator CHAR(1) DEFAULT '/'; + + IF @@global.version_compile_os LIKE 'win%' THEN + SET path_separator = '\\'; + END IF; + + -- OSX hides /private/ in variables, but Performance Schema does not + IF in_path LIKE '/private/%' THEN + SET v_path = REPLACE(in_path, '/private', ''); + ELSE + SET v_path = in_path; + END IF; + + -- @@global.innodb_undo_directory is only set when separate undo logs are used + + SET v_dir= IFNULL((SELECT VARIABLE_VALUE FROM information_schema.global_variables WHERE VARIABLE_NAME = 'innodb_data_home_dir'), ''); + + IF v_path IS NULL THEN + RETURN NULL; + END IF; + + IF v_path LIKE CONCAT(@@global.datadir, IF(SUBSTRING(@@global.datadir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN + SET v_path = REPLACE(v_path, @@global.datadir, CONCAT('@@datadir', IF(SUBSTRING(@@global.datadir, -1) = path_separator, path_separator, ''))); + RETURN v_path; + END IF; + + IF v_path LIKE CONCAT(@@global.tmpdir, IF(SUBSTRING(@@global.tmpdir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN + SET v_path = REPLACE(v_path, @@global.tmpdir, CONCAT('@@tmpdir', IF(SUBSTRING(@@global.tmpdir, -1) = path_separator, path_separator, ''))); + RETURN v_path; + END IF; + + + SET v_dir= IFNULL((SELECT VARIABLE_VALUE FROM information_schema.global_variables WHERE VARIABLE_NAME = 'innodb_data_home_dir'), ''); + IF v_path LIKE CONCAT(v_dir, IF(SUBSTRING(v_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN + SET v_path = REPLACE(v_path, v_dir, CONCAT('@@innodb_data_home_dir', IF(SUBSTRING(v_dir, -1) = path_separator, path_separator, ''))); + RETURN v_path; + END IF; + + SET v_dir= IFNULL((SELECT VARIABLE_VALUE FROM information_schema.global_variables WHERE VARIABLE_NAME = 'innodb_log_group_home_dir'), ''); + IF v_path LIKE CONCAT(v_dir, IF(SUBSTRING(v_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN + SET v_path = REPLACE(v_path, v_dir, CONCAT('@@innodb_log_group_home_dir', IF(SUBSTRING(v_dir, -1) = path_separator, path_separator, ''))); + RETURN v_path; + END IF; + + SET v_dir= IFNULL((SELECT VARIABLE_VALUE FROM information_schema.global_variables WHERE VARIABLE_NAME = 'slave_load_tmpdir'), ''); + IF v_path LIKE CONCAT(v_dir, IF(SUBSTRING(v_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN + SET v_path = REPLACE(v_path, v_dir, CONCAT('@@slave_load_tmpdir', IF(SUBSTRING(v_dir, -1) = path_separator, path_separator, ''))); + RETURN v_path; + END IF; + + + SET v_dir = IFNULL((SELECT VARIABLE_VALUE FROM information_schema.global_variables WHERE VARIABLE_NAME = 'innodb_undo_directory'), ''); + IF v_path LIKE CONCAT(v_dir, IF(SUBSTRING(v_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN + SET v_path = REPLACE(v_path, v_dir, CONCAT('@@innodb_undo_directory', IF(SUBSTRING(v_dir, -1) = path_separator, path_separator, ''))); + RETURN v_path; + END IF; + + IF v_path LIKE CONCAT(@@global.basedir, IF(SUBSTRING(@@global.basedir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN + SET v_path = REPLACE(v_path, @@global.basedir, CONCAT('@@basedir', IF(SUBSTRING(@@global.basedir, -1) = path_separator, path_separator, ''))); + RETURN v_path; + END IF; + + RETURN v_path; +END$$ + +DELIMITER ;
\ No newline at end of file diff --git a/scripts/sys_schema/functions/format_statement.sql b/scripts/sys_schema/functions/format_statement.sql new file mode 100644 index 00000000..8e434b24 --- /dev/null +++ b/scripts/sys_schema/functions/format_statement.sql @@ -0,0 +1,81 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS format_statement; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION format_statement ( + statement LONGTEXT + ) + RETURNS LONGTEXT + COMMENT ' + Description + ----------- + + Formats a normalized statement, truncating it if it is > 64 characters long by default. + + To configure the length to truncate the statement to by default, update the `statement_truncate_len` + variable with `sys_config` table to a different value. Alternatively, to change it just for just + your particular session, use `SET @sys.statement_truncate_len := <some new value>`. + + Useful for printing statement related data from Performance Schema from + the command line. + + Parameters + ----------- + + statement (LONGTEXT): + The statement to format. + + Returns + ----------- + + LONGTEXT + + Example + ----------- + + mysql> SELECT sys.format_statement(digest_text) + -> FROM performance_schema.events_statements_summary_by_digest + -> ORDER by sum_timer_wait DESC limit 5; + +-------------------------------------------------------------------+ + | sys.format_statement(digest_text) | + +-------------------------------------------------------------------+ + | CREATE SQL SECURITY INVOKER VI ... KE ? AND `variable_value` > ? | + | CREATE SQL SECURITY INVOKER VI ... ait` IS NOT NULL , `esc` . ... | + | CREATE SQL SECURITY INVOKER VI ... ait` IS NOT NULL , `sys` . ... | + | CREATE SQL SECURITY INVOKER VI ... , `compressed_size` ) ) DESC | + | CREATE SQL SECURITY INVOKER VI ... LIKE ? ORDER BY `timer_start` | + +-------------------------------------------------------------------+ + 5 rows in set (0.00 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + NO SQL +BEGIN + -- Check if we have the configured length, if not, init it + IF @sys.statement_truncate_len IS NULL THEN + SET @sys.statement_truncate_len = sys_get_config('statement_truncate_len', 64); + END IF; + + IF CHAR_LENGTH(statement) > @sys.statement_truncate_len THEN + RETURN REPLACE(CONCAT(LEFT(statement, (@sys.statement_truncate_len/2)-2), ' ... ', RIGHT(statement, (@sys.statement_truncate_len/2)-2)), '\n', ' '); + ELSE + RETURN REPLACE(statement, '\n', ' '); + END IF; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/format_time.sql b/scripts/sys_schema/functions/format_time.sql new file mode 100644 index 00000000..f828f791 --- /dev/null +++ b/scripts/sys_schema/functions/format_time.sql @@ -0,0 +1,91 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS format_time; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION format_time ( + -- We feed in and return TEXT here, as aggregates of + -- picoseconds can return numbers larger than BIGINT UNSIGNED + picoseconds TEXT + ) + RETURNS TEXT CHARSET UTF8 + COMMENT ' + Description + ----------- + + Takes a raw picoseconds value, and converts it to a human readable form. + + Picoseconds are the precision that all latency values are printed in + within Performance Schema, however are not user friendly when wanting + to scan output from the command line. + + Parameters + ----------- + + picoseconds (TEXT): + The raw picoseconds value to convert. + + Returns + ----------- + + TEXT + + Example + ----------- + + mysql> select format_time(342342342342345); + +------------------------------+ + | format_time(342342342342345) | + +------------------------------+ + | 00:05:42 | + +------------------------------+ + 1 row in set (0.00 sec) + + mysql> select format_time(342342342); + +------------------------+ + | format_time(342342342) | + +------------------------+ + | 342.34 us | + +------------------------+ + 1 row in set (0.00 sec) + + mysql> select format_time(34234); + +--------------------+ + | format_time(34234) | + +--------------------+ + | 34.23 ns | + +--------------------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + NO SQL +BEGIN + IF picoseconds IS NULL THEN RETURN NULL; + ELSEIF picoseconds >= 604800000000000000 THEN RETURN CONCAT(ROUND(picoseconds / 604800000000000000, 2), ' w'); + ELSEIF picoseconds >= 86400000000000000 THEN RETURN CONCAT(ROUND(picoseconds / 86400000000000000, 2), ' d'); + ELSEIF picoseconds >= 3600000000000000 THEN RETURN CONCAT(ROUND(picoseconds / 3600000000000000, 2), ' h'); + ELSEIF picoseconds >= 60000000000000 THEN RETURN CONCAT(ROUND(picoseconds / 60000000000000, 2), ' m'); + ELSEIF picoseconds >= 1000000000000 THEN RETURN CONCAT(ROUND(picoseconds / 1000000000000, 2), ' s'); + ELSEIF picoseconds >= 1000000000 THEN RETURN CONCAT(ROUND(picoseconds / 1000000000, 2), ' ms'); + ELSEIF picoseconds >= 1000000 THEN RETURN CONCAT(ROUND(picoseconds / 1000000, 2), ' us'); + ELSEIF picoseconds >= 1000 THEN RETURN CONCAT(ROUND(picoseconds / 1000, 2), ' ns'); + ELSE RETURN CONCAT(picoseconds, ' ps'); + END IF; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/list_add.sql b/scripts/sys_schema/functions/list_add.sql new file mode 100644 index 00000000..6079fbc5 --- /dev/null +++ b/scripts/sys_schema/functions/list_add.sql @@ -0,0 +1,90 @@ +-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS list_add; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION list_add ( + in_list TEXT, + in_add_value TEXT + ) + RETURNS TEXT + COMMENT ' + Description + ----------- + + Takes a list, and a value to add to the list, and returns the resulting list. + + Useful for altering certain session variables, like sql_mode or optimizer_switch for instance. + + Parameters + ----------- + + in_list (TEXT): + The comma separated list to add a value to + + in_add_value (TEXT): + The value to add to the input list + + Returns + ----------- + + TEXT + + Example + -------- + + mysql> select @@sql_mode; + +-----------------------------------------------------------------------------------+ + | @@sql_mode | + +-----------------------------------------------------------------------------------+ + | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | + +-----------------------------------------------------------------------------------+ + 1 row in set (0.00 sec) + + mysql> set sql_mode = sys.list_add(@@sql_mode, ''ANSI_QUOTES''); + Query OK, 0 rows affected (0.06 sec) + + mysql> select @@sql_mode; + +-----------------------------------------------------------------------------------------------+ + | @@sql_mode | + +-----------------------------------------------------------------------------------------------+ + | ANSI_QUOTES,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | + +-----------------------------------------------------------------------------------------------+ + 1 row in set (0.00 sec) + + ' + SQL SECURITY INVOKER + DETERMINISTIC + CONTAINS SQL +BEGIN + + IF (in_add_value IS NULL) THEN + SIGNAL SQLSTATE '02200' + SET MESSAGE_TEXT = 'Function sys.list_add: in_add_value input variable should not be NULL', + MYSQL_ERRNO = 1138; + END IF; + + IF (in_list IS NULL OR LENGTH(in_list) = 0) THEN + -- return the new value as a single value list + RETURN in_add_value; + END IF; + + RETURN (SELECT CONCAT(TRIM(BOTH ',' FROM TRIM(in_list)), ',', in_add_value)); + +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/list_drop.sql b/scripts/sys_schema/functions/list_drop.sql new file mode 100644 index 00000000..eccce7ed --- /dev/null +++ b/scripts/sys_schema/functions/list_drop.sql @@ -0,0 +1,91 @@ +-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS list_drop; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION list_drop ( + in_list TEXT, + in_drop_value TEXT + ) + RETURNS TEXT + COMMENT ' + Description + ----------- + + Takes a list, and a value to attempt to remove from the list, and returns the resulting list. + + Useful for altering certain session variables, like sql_mode or optimizer_switch for instance. + + Parameters + ----------- + + in_list (TEXT): + The comma separated list to drop a value from + + in_drop_value (TEXT): + The value to drop from the input list + + Returns + ----------- + + TEXT + + Example + -------- + + mysql> select @@sql_mode; + +-----------------------------------------------------------------------------------------------+ + | @@sql_mode | + +-----------------------------------------------------------------------------------------------+ + | ANSI_QUOTES,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | + +-----------------------------------------------------------------------------------------------+ + 1 row in set (0.00 sec) + + mysql> set sql_mode = sys.list_drop(@@sql_mode, ''ONLY_FULL_GROUP_BY''); + Query OK, 0 rows affected (0.03 sec) + + mysql> select @@sql_mode; + +----------------------------------------------------------------------------+ + | @@sql_mode | + +----------------------------------------------------------------------------+ + | ANSI_QUOTES,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | + +----------------------------------------------------------------------------+ + 1 row in set (0.00 sec) + + ' + SQL SECURITY INVOKER + DETERMINISTIC + CONTAINS SQL +BEGIN + + IF (in_drop_value IS NULL) THEN + SIGNAL SQLSTATE '02200' + SET MESSAGE_TEXT = 'Function sys.list_drop: in_drop_value input variable should not be NULL', + MYSQL_ERRNO = 1138; + END IF; + + IF (in_list IS NULL OR LENGTH(in_list) = 0) THEN + -- return the list as it was passed in + RETURN in_list; + END IF; + + -- ensure that leading / trailing commas are remove, support values with either spaces or not between commas + RETURN (SELECT TRIM(BOTH ',' FROM REPLACE(REPLACE(CONCAT(',', in_list), CONCAT(',', in_drop_value), ''), CONCAT(', ', in_drop_value), ''))); + +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/ps_is_account_enabled.sql b/scripts/sys_schema/functions/ps_is_account_enabled.sql new file mode 100644 index 00000000..a4bcecc4 --- /dev/null +++ b/scripts/sys_schema/functions/ps_is_account_enabled.sql @@ -0,0 +1,69 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS ps_is_account_enabled; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION ps_is_account_enabled ( + in_host VARCHAR(60), + in_user VARCHAR(16) + ) + RETURNS ENUM('YES', 'NO') + COMMENT ' + Description + ----------- + + Determines whether instrumentation of an account is enabled + within Performance Schema. + + Parameters + ----------- + + in_host VARCHAR(60): + The hostname of the account to check. + in_user (VARCHAR(16)): + The username of the account to check. + + Returns + ----------- + + ENUM(\'YES\', \'NO\', \'PARTIAL\') + + Example + ----------- + + mysql> SELECT sys.ps_is_account_enabled(\'localhost\', \'root\'); + +------------------------------------------------+ + | sys.ps_is_account_enabled(\'localhost\', \'root\') | + +------------------------------------------------+ + | YES | + +------------------------------------------------+ + 1 row in set (0.01 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + READS SQL DATA +BEGIN + RETURN IF(EXISTS(SELECT 1 + FROM performance_schema.setup_actors + WHERE (`HOST` = '%' OR in_host LIKE `HOST`) + AND (`USER` = '%' OR `USER` = in_user) + ), + 'YES', 'NO' + ); +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/ps_is_account_enabled_57.sql b/scripts/sys_schema/functions/ps_is_account_enabled_57.sql new file mode 100644 index 00000000..12480716 --- /dev/null +++ b/scripts/sys_schema/functions/ps_is_account_enabled_57.sql @@ -0,0 +1,70 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS ps_is_account_enabled; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION ps_is_account_enabled ( + in_host VARCHAR(60), + in_user VARCHAR(32) + ) + RETURNS ENUM('YES', 'NO') + COMMENT ' + Description + ----------- + + Determines whether instrumentation of an account is enabled + within Performance Schema. + + Parameters + ----------- + + in_host VARCHAR(60): + The hostname of the account to check. + in_user VARCHAR(32): + The username of the account to check. + + Returns + ----------- + + ENUM(\'YES\', \'NO\', \'PARTIAL\') + + Example + ----------- + + mysql> SELECT sys.ps_is_account_enabled(\'localhost\', \'root\'); + +------------------------------------------------+ + | sys.ps_is_account_enabled(\'localhost\', \'root\') | + +------------------------------------------------+ + | YES | + +------------------------------------------------+ + 1 row in set (0.01 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + READS SQL DATA +BEGIN + RETURN IF(EXISTS(SELECT 1 + FROM performance_schema.setup_actors + WHERE (`HOST` = '%' OR in_host LIKE `HOST`) + AND (`USER` = '%' OR `USER` = in_user) + AND (`ENABLED` = 'YES') + ), + 'YES', 'NO' + ); +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/ps_is_consumer_enabled.sql b/scripts/sys_schema/functions/ps_is_consumer_enabled.sql new file mode 100644 index 00000000..c9290a9c --- /dev/null +++ b/scripts/sys_schema/functions/ps_is_consumer_enabled.sql @@ -0,0 +1,76 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS ps_is_consumer_enabled; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION ps_is_consumer_enabled ( + in_consumer varchar(64) + ) + RETURNS enum('YES', 'NO') + COMMENT ' + Description + ----------- + + Determines whether a consumer is enabled (taking the consumer hierarchy into consideration) + within the Performance Schema. + + Parameters + ----------- + + in_consumer VARCHAR(64): + The name of the consumer to check. + + Returns + ----------- + + ENUM(\'YES\', \'NO\') + + Example + ----------- + + mysql> SELECT sys.ps_is_consumer_enabled(\'events_stages_history\'); + +-----------------------------------------------------+ + | sys.ps_is_consumer_enabled(\'events_stages_history\') | + +-----------------------------------------------------+ + | NO | + +-----------------------------------------------------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + READS SQL DATA +BEGIN + RETURN ( + SELECT (CASE + WHEN c.NAME = 'global_instrumentation' THEN c.ENABLED + WHEN c.NAME = 'thread_instrumentation' THEN IF(cg.ENABLED = 'YES' AND c.ENABLED = 'YES', 'YES', 'NO') + WHEN c.NAME LIKE '%\_digest' THEN IF(cg.ENABLED = 'YES' AND c.ENABLED = 'YES', 'YES', 'NO') + WHEN c.NAME LIKE '%\_current' THEN IF(cg.ENABLED = 'YES' AND ct.ENABLED = 'YES' AND c.ENABLED = 'YES', 'YES', 'NO') + ELSE IF(cg.ENABLED = 'YES' AND ct.ENABLED = 'YES' AND c.ENABLED = 'YES' + AND ( SELECT cc.ENABLED FROM performance_schema.setup_consumers cc WHERE NAME = CONCAT(SUBSTRING_INDEX(c.NAME, '_', 2), '_current') + ) = 'YES', 'YES', 'NO') + END) AS IsEnabled + FROM performance_schema.setup_consumers c + INNER JOIN performance_schema.setup_consumers cg + INNER JOIN performance_schema.setup_consumers ct + WHERE cg.NAME = 'global_instrumentation' + AND ct.NAME = 'thread_instrumentation' + AND c.NAME = in_consumer + ); +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/ps_is_instrument_default_enabled.sql b/scripts/sys_schema/functions/ps_is_instrument_default_enabled.sql new file mode 100644 index 00000000..2d79a161 --- /dev/null +++ b/scripts/sys_schema/functions/ps_is_instrument_default_enabled.sql @@ -0,0 +1,76 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS ps_is_instrument_default_enabled; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION ps_is_instrument_default_enabled ( + in_instrument VARCHAR(128) + ) + RETURNS ENUM('YES', 'NO') + COMMENT ' + Description + ----------- + + Returns whether an instrument is enabled by default in this version of MySQL. + + Parameters + ----------- + + in_instrument VARCHAR(128): + The instrument to check. + + Returns + ----------- + + ENUM(\'YES\', \'NO\') + + Example + ----------- + + mysql> SELECT sys.ps_is_instrument_default_enabled(\'statement/sql/select\'); + +--------------------------------------------------------------+ + | sys.ps_is_instrument_default_enabled(\'statement/sql/select\') | + +--------------------------------------------------------------+ + | YES | + +--------------------------------------------------------------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + READS SQL DATA +BEGIN + DECLARE v_enabled ENUM('YES', 'NO'); + + -- Currently the same in all versions + SET v_enabled = IF(in_instrument LIKE 'wait/io/file/%' + OR in_instrument LIKE 'wait/io/table/%' + OR in_instrument LIKE 'statement/%' + OR in_instrument LIKE 'memory/performance_schema/%' + OR in_instrument IN ('wait/lock/table/sql/handler', 'idle') + /*!50707 + OR in_instrument LIKE 'stage/innodb/%' + OR in_instrument = 'stage/sql/copy to tmp table' + */ + , + 'YES', + 'NO' + ); + + RETURN v_enabled; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/ps_is_instrument_default_timed.sql b/scripts/sys_schema/functions/ps_is_instrument_default_timed.sql new file mode 100644 index 00000000..d78e324d --- /dev/null +++ b/scripts/sys_schema/functions/ps_is_instrument_default_timed.sql @@ -0,0 +1,75 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS ps_is_instrument_default_timed; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION ps_is_instrument_default_timed ( + in_instrument VARCHAR(128) + ) + RETURNS ENUM('YES', 'NO') + COMMENT ' + Description + ----------- + + Returns whether an instrument is timed by default in this version of MySQL. + + Parameters + ----------- + + in_instrument VARCHAR(128): + The instrument to check. + + Returns + ----------- + + ENUM(\'YES\', \'NO\') + + Example + ----------- + + mysql> SELECT sys.ps_is_instrument_default_timed(\'statement/sql/select\'); + +------------------------------------------------------------+ + | sys.ps_is_instrument_default_timed(\'statement/sql/select\') | + +------------------------------------------------------------+ + | YES | + +------------------------------------------------------------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + READS SQL DATA +BEGIN + DECLARE v_timed ENUM('YES', 'NO'); + + -- Currently the same in all versions + SET v_timed = IF(in_instrument LIKE 'wait/io/file/%' + OR in_instrument LIKE 'wait/io/table/%' + OR in_instrument LIKE 'statement/%' + OR in_instrument IN ('wait/lock/table/sql/handler', 'idle') + /*!50707 + OR in_instrument LIKE 'stage/innodb/%' + OR in_instrument = 'stage/sql/copy to tmp table' + */ + , + 'YES', + 'NO' + ); + + RETURN v_timed; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/ps_is_thread_instrumented.sql b/scripts/sys_schema/functions/ps_is_thread_instrumented.sql new file mode 100644 index 00000000..06388312 --- /dev/null +++ b/scripts/sys_schema/functions/ps_is_thread_instrumented.sql @@ -0,0 +1,72 @@ +-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS ps_is_thread_instrumented; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION ps_is_thread_instrumented ( + in_connection_id BIGINT UNSIGNED + ) RETURNS ENUM('YES', 'NO', 'UNKNOWN') + COMMENT ' + Description + ----------- + + Checks whether the provided connection id is instrumented within Performance Schema. + + Parameters + ----------- + + in_connection_id (BIGINT UNSIGNED): + The id of the connection to check. + + Returns + ----------- + + ENUM(\'YES\', \'NO\', \'UNKNOWN\') + + Example + ----------- + + mysql> SELECT sys.ps_is_thread_instrumented(CONNECTION_ID()); + +------------------------------------------------+ + | sys.ps_is_thread_instrumented(CONNECTION_ID()) | + +------------------------------------------------+ + | YES | + +------------------------------------------------+ + ' + + SQL SECURITY INVOKER + NOT DETERMINISTIC + READS SQL DATA +BEGIN + DECLARE v_enabled ENUM('YES', 'NO', 'UNKNOWN'); + + IF (in_connection_id IS NULL) THEN + RETURN NULL; + END IF; + + SELECT INSTRUMENTED INTO v_enabled + FROM performance_schema.threads + WHERE PROCESSLIST_ID = in_connection_id; + + IF (v_enabled IS NULL) THEN + RETURN 'UNKNOWN'; + ELSE + RETURN v_enabled; + END IF; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/ps_thread_account.sql b/scripts/sys_schema/functions/ps_thread_account.sql new file mode 100644 index 00000000..f91e8c66 --- /dev/null +++ b/scripts/sys_schema/functions/ps_thread_account.sql @@ -0,0 +1,71 @@ +-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS ps_thread_account; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION ps_thread_account ( + in_thread_id BIGINT UNSIGNED + ) RETURNS TEXT + COMMENT ' + Description + ----------- + + Return the user@host account for the given Performance Schema thread id. + + Parameters + ----------- + + in_thread_id (BIGINT UNSIGNED): + The id of the thread to return the account for. + + Example + ----------- + + mysql> select thread_id, processlist_user, processlist_host from performance_schema.threads where type = ''foreground''; + +-----------+------------------+------------------+ + | thread_id | processlist_user | processlist_host | + +-----------+------------------+------------------+ + | 23 | NULL | NULL | + | 30 | root | localhost | + | 31 | msandbox | localhost | + | 32 | msandbox | localhost | + +-----------+------------------+------------------+ + 4 rows in set (0.00 sec) + + mysql> select sys.ps_thread_account(31); + +---------------------------+ + | sys.ps_thread_account(31) | + +---------------------------+ + | msandbox@localhost | + +---------------------------+ + 1 row in set (0.00 sec) + ' + + SQL SECURITY INVOKER + NOT DETERMINISTIC + READS SQL DATA +BEGIN + RETURN (SELECT IF( + type = 'FOREGROUND', + CONCAT(processlist_user, '@', processlist_host), + type + ) AS account + FROM `performance_schema`.`threads` + WHERE thread_id = in_thread_id); +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/ps_thread_id.sql b/scripts/sys_schema/functions/ps_thread_id.sql new file mode 100644 index 00000000..f344e6e1 --- /dev/null +++ b/scripts/sys_schema/functions/ps_thread_id.sql @@ -0,0 +1,66 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS ps_thread_id; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION ps_thread_id ( + in_connection_id BIGINT UNSIGNED + ) RETURNS BIGINT UNSIGNED + COMMENT ' + Description + ----------- + + Return the Performance Schema THREAD_ID for the specified connection ID. + + Parameters + ----------- + + in_connection_id (BIGINT UNSIGNED): + The id of the connection to return the thread id for. If NULL, the current + connection thread id is returned. + + Example + ----------- + + mysql> SELECT sys.ps_thread_id(79); + +----------------------+ + | sys.ps_thread_id(79) | + +----------------------+ + | 98 | + +----------------------+ + 1 row in set (0.00 sec) + + mysql> SELECT sys.ps_thread_id(CONNECTION_ID()); + +-----------------------------------+ + | sys.ps_thread_id(CONNECTION_ID()) | + +-----------------------------------+ + | 98 | + +-----------------------------------+ + 1 row in set (0.00 sec) + ' + + SQL SECURITY INVOKER + NOT DETERMINISTIC + READS SQL DATA +BEGIN + RETURN (SELECT THREAD_ID + FROM `performance_schema`.`threads` + WHERE PROCESSLIST_ID = IFNULL(in_connection_id, CONNECTION_ID()) + ); +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/ps_thread_stack.sql b/scripts/sys_schema/functions/ps_thread_stack.sql new file mode 100644 index 00000000..12b09bd6 --- /dev/null +++ b/scripts/sys_schema/functions/ps_thread_stack.sql @@ -0,0 +1,171 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS ps_thread_stack; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION ps_thread_stack ( + thd_id BIGINT UNSIGNED, + debug BOOLEAN + ) +RETURNS LONGTEXT CHARSET latin1 + COMMENT ' + Description + ----------- + + Outputs a JSON formatted stack of all statements, stages and events + within Performance Schema for the specified thread. + + Parameters + ----------- + + thd_id (BIGINT UNSIGNED): + The id of the thread to trace. This should match the thread_id + column from the performance_schema.threads table. + in_verbose (BOOLEAN): + Include file:lineno information in the events. + + Example + ----------- + + (line separation added for output) + + mysql> SELECT sys.ps_thread_stack(37, FALSE) AS thread_stack\\G + *************************** 1. row *************************** + thread_stack: {"rankdir": "LR","nodesep": "0.10","stack_created": "2014-02-19 13:39:03", + "mysql_version": "5.7.3-m13","mysql_user": "root@localhost","events": + [{"nesting_event_id": "0", "event_id": "10", "timer_wait": 256.35, "event_info": + "sql/select", "wait_info": "select @@version_comment limit 1\\nerrors: 0\\nwarnings: 0\\nlock time: + ... + ' +SQL SECURITY INVOKER +NOT DETERMINISTIC +READS SQL DATA +BEGIN + + DECLARE json_objects LONGTEXT; + + /*!50602 + -- Do not track the current thread, it will kill the stack + UPDATE performance_schema.threads + SET instrumented = 'NO' + WHERE processlist_id = CONNECTION_ID(); + */ + + SET SESSION group_concat_max_len=@@global.max_allowed_packet; + + -- Select the entire stack of events + SELECT GROUP_CONCAT(CONCAT( '{' + , CONCAT_WS( ', ' + , CONCAT('"nesting_event_id": "', IF(nesting_event_id IS NULL, '0', nesting_event_id), '"') + , CONCAT('"event_id": "', event_id, '"') + -- Convert from picoseconds to microseconds + , CONCAT( '"timer_wait": ', ROUND(timer_wait/1000000, 2)) + , CONCAT( '"event_info": "' + , CASE + WHEN event_name NOT LIKE 'wait/io%' THEN REPLACE(SUBSTRING_INDEX(event_name, '/', -2), '\\', '\\\\') + WHEN event_name NOT LIKE 'wait/io/file%' OR event_name NOT LIKE 'wait/io/socket%' THEN REPLACE(SUBSTRING_INDEX(event_name, '/', -4), '\\', '\\\\') + ELSE event_name + END + , '"' + ) + -- Always dump the extra wait information gathered for statements + , CONCAT( '"wait_info": "', IFNULL(wait_info, ''), '"') + -- If debug is enabled, add the file:lineno information for waits + , CONCAT( '"source": "', IF(true AND event_name LIKE 'wait%', IFNULL(wait_info, ''), ''), '"') + -- Depending on the type of event, name it appropriately + , CASE + WHEN event_name LIKE 'wait/io/file%' THEN '"event_type": "io/file"' + WHEN event_name LIKE 'wait/io/table%' THEN '"event_type": "io/table"' + WHEN event_name LIKE 'wait/io/socket%' THEN '"event_type": "io/socket"' + WHEN event_name LIKE 'wait/synch/mutex%' THEN '"event_type": "synch/mutex"' + WHEN event_name LIKE 'wait/synch/cond%' THEN '"event_type": "synch/cond"' + WHEN event_name LIKE 'wait/synch/rwlock%' THEN '"event_type": "synch/rwlock"' + WHEN event_name LIKE 'wait/lock%' THEN '"event_type": "lock"' + WHEN event_name LIKE 'statement/%' THEN '"event_type": "stmt"' + WHEN event_name LIKE 'stage/%' THEN '"event_type": "stage"' + WHEN event_name LIKE '%idle%' THEN '"event_type": "idle"' + ELSE '' + END + ) + , '}' + ) + ORDER BY event_id ASC SEPARATOR ',') event + INTO json_objects + FROM ( + /*!50600 + -- Select all statements, with the extra tracing information available + (SELECT thread_id, event_id, event_name, timer_wait, timer_start, nesting_event_id, + CONCAT(sql_text, '\\n', + 'errors: ', errors, '\\n', + 'warnings: ', warnings, '\\n', + 'lock time: ', ROUND(lock_time/1000000, 2),'us\\n', + 'rows affected: ', rows_affected, '\\n', + 'rows sent: ', rows_sent, '\\n', + 'rows examined: ', rows_examined, '\\n', + 'tmp tables: ', created_tmp_tables, '\\n', + 'tmp disk tables: ', created_tmp_disk_tables, '\\n', + 'select scan: ', select_scan, '\\n', + 'select full join: ', select_full_join, '\\n', + 'select full range join: ', select_full_range_join, '\\n', + 'select range: ', select_range, '\\n', + 'select range check: ', select_range_check, '\\n', + 'sort merge passes: ', sort_merge_passes, '\\n', + 'sort rows: ', sort_rows, '\\n', + 'sort range: ', sort_range, '\\n', + 'sort scan: ', sort_scan, '\\n', + 'no index used: ', IF(no_index_used, 'TRUE', 'FALSE'), '\\n', + 'no good index used: ', IF(no_good_index_used, 'TRUE', 'FALSE'), '\\n' + ) AS wait_info + FROM performance_schema.events_statements_history_long WHERE thread_id = thd_id) + UNION + -- Select all stages + (SELECT thread_id, event_id, event_name, timer_wait, timer_start, nesting_event_id, null AS wait_info + FROM performance_schema.events_stages_history_long WHERE thread_id = thd_id) + UNION */ + -- Select all events, adding information appropriate to the event + (SELECT thread_id, event_id, + CONCAT(event_name , + IF(event_name NOT LIKE 'wait/synch/mutex%', IFNULL(CONCAT(' - ', operation), ''), ''), + IF(number_of_bytes IS NOT NULL, CONCAT(' ', number_of_bytes, ' bytes'), ''), + IF(event_name LIKE 'wait/io/file%', '\\n', ''), + IF(object_schema IS NOT NULL, CONCAT('\\nObject: ', object_schema, '.'), ''), + IF(object_name IS NOT NULL, + IF (event_name LIKE 'wait/io/socket%', + -- Print the socket if used, else the IP:port as reported + CONCAT(IF (object_name LIKE ':0%', @@socket, object_name)), + object_name), + ''), + /*!50600 IF(index_name IS NOT NULL, CONCAT(' Index: ', index_name), ''),*/'\\n' + ) AS event_name, + timer_wait, timer_start, nesting_event_id, source AS wait_info + FROM performance_schema.events_waits_history_long WHERE thread_id = thd_id)) events + ORDER BY event_id; + + RETURN CONCAT('{', + CONCAT_WS(',', + '"rankdir": "LR"', + '"nodesep": "0.10"', + CONCAT('"stack_created": "', NOW(), '"'), + CONCAT('"mysql_version": "', VERSION(), '"'), + CONCAT('"mysql_user": "', CURRENT_USER(), '"'), + CONCAT('"events": [', IFNULL(json_objects,''), ']') + ), + '}'); + +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/ps_thread_trx_info.sql b/scripts/sys_schema/functions/ps_thread_trx_info.sql new file mode 100644 index 00000000..12ab6aef --- /dev/null +++ b/scripts/sys_schema/functions/ps_thread_trx_info.sql @@ -0,0 +1,233 @@ +-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS ps_thread_trx_info; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION ps_thread_trx_info ( + in_thread_id BIGINT UNSIGNED + ) RETURNS LONGTEXT + COMMENT ' + Description + ----------- + + Returns a JSON object with info on the given threads current transaction, + and the statements it has already executed, derived from the + performance_schema.events_transactions_current and + performance_schema.events_statements_history tables (so the consumers + for these also have to be enabled within Performance Schema to get full + data in the object). + + When the output exceeds the default truncation length (65535), a JSON error + object is returned, such as: + + { "error": "Trx info truncated: Row 6 was cut by GROUP_CONCAT()" } + + Similar error objects are returned for other warnings/and exceptions raised + when calling the function. + + The max length of the output of this function can be controlled with the + ps_thread_trx_info.max_length variable set via sys_config, or the + @sys.ps_thread_trx_info.max_length user variable, as appropriate. + + Parameters + ----------- + + in_thread_id (BIGINT UNSIGNED): + The id of the thread to return the transaction info for. + + Example + ----------- + + SELECT sys.ps_thread_trx_info(48)\\G + *************************** 1. row *************************** + sys.ps_thread_trx_info(48): [ + { + "time": "790.70 us", + "state": "COMMITTED", + "mode": "READ WRITE", + "autocommitted": "NO", + "gtid": "AUTOMATIC", + "isolation": "REPEATABLE READ", + "statements_executed": [ + { + "sql_text": "INSERT INTO info VALUES (1, \'foo\')", + "time": "471.02 us", + "schema": "trx", + "rows_examined": 0, + "rows_affected": 1, + "rows_sent": 0, + "tmp_tables": 0, + "tmp_disk_tables": 0, + "sort_rows": 0, + "sort_merge_passes": 0 + }, + { + "sql_text": "COMMIT", + "time": "254.42 us", + "schema": "trx", + "rows_examined": 0, + "rows_affected": 0, + "rows_sent": 0, + "tmp_tables": 0, + "tmp_disk_tables": 0, + "sort_rows": 0, + "sort_merge_passes": 0 + } + ] + }, + { + "time": "426.20 us", + "state": "COMMITTED", + "mode": "READ WRITE", + "autocommitted": "NO", + "gtid": "AUTOMATIC", + "isolation": "REPEATABLE READ", + "statements_executed": [ + { + "sql_text": "INSERT INTO info VALUES (2, \'bar\')", + "time": "107.33 us", + "schema": "trx", + "rows_examined": 0, + "rows_affected": 1, + "rows_sent": 0, + "tmp_tables": 0, + "tmp_disk_tables": 0, + "sort_rows": 0, + "sort_merge_passes": 0 + }, + { + "sql_text": "COMMIT", + "time": "213.23 us", + "schema": "trx", + "rows_examined": 0, + "rows_affected": 0, + "rows_sent": 0, + "tmp_tables": 0, + "tmp_disk_tables": 0, + "sort_rows": 0, + "sort_merge_passes": 0 + } + ] + } + ] + 1 row in set (0.03 sec) + ' + + SQL SECURITY INVOKER + NOT DETERMINISTIC + READS SQL DATA +BEGIN + DECLARE v_output LONGTEXT DEFAULT '{}'; + DECLARE v_msg_text TEXT DEFAULT ''; + DECLARE v_signal_msg TEXT DEFAULT ''; + DECLARE v_mysql_errno INT; + DECLARE v_max_output_len BIGINT; + -- Capture warnings/errors such as group_concat truncation + -- and report as JSON error objects + DECLARE EXIT HANDLER FOR SQLWARNING, SQLEXCEPTION + BEGIN + GET DIAGNOSTICS CONDITION 1 + v_msg_text = MESSAGE_TEXT, + v_mysql_errno = MYSQL_ERRNO; + + IF v_mysql_errno = 1260 THEN + SET v_signal_msg = CONCAT('{ "error": "Trx info truncated: ', v_msg_text, '" }'); + ELSE + SET v_signal_msg = CONCAT('{ "error": "', v_msg_text, '" }'); + END IF; + + RETURN v_signal_msg; + END; + + -- Set configuration options + IF (@sys.ps_thread_trx_info.max_length IS NULL) THEN + SET @sys.ps_thread_trx_info.max_length = sys.sys_get_config('ps_thread_trx_info.max_length', 65535); + END IF; + + IF (@sys.ps_thread_trx_info.max_length != @@session.group_concat_max_len) THEN + SET @old_group_concat_max_len = @@session.group_concat_max_len; + -- Convert to int value for the SET, and give some surrounding space + SET v_max_output_len = (@sys.ps_thread_trx_info.max_length - 5); + SET SESSION group_concat_max_len = v_max_output_len; + END IF; + + SET v_output = ( + SELECT CONCAT('[', IFNULL(GROUP_CONCAT(trx_info ORDER BY event_id), ''), '\n]') AS trx_info + FROM (SELECT trxi.thread_id, + trxi.event_id, + GROUP_CONCAT( + IFNULL( + CONCAT('\n {\n', + ' "time": "', IFNULL(sys.format_time(trxi.timer_wait), ''), '",\n', + ' "state": "', IFNULL(trxi.state, ''), '",\n', + ' "mode": "', IFNULL(trxi.access_mode, ''), '",\n', + ' "autocommitted": "', IFNULL(trxi.autocommit, ''), '",\n', + ' "gtid": "', IFNULL(trxi.gtid, ''), '",\n', + ' "isolation": "', IFNULL(trxi.isolation_level, ''), '",\n', + ' "statements_executed": [', IFNULL(s.stmts, ''), IF(s.stmts IS NULL, ' ]\n', '\n ]\n'), + ' }' + ), + '') + ORDER BY event_id) AS trx_info + + FROM ( + (SELECT thread_id, event_id, timer_wait, state,access_mode, autocommit, gtid, isolation_level + FROM performance_schema.events_transactions_current + WHERE thread_id = in_thread_id + AND end_event_id IS NULL) + UNION + (SELECT thread_id, event_id, timer_wait, state,access_mode, autocommit, gtid, isolation_level + FROM performance_schema.events_transactions_history + WHERE thread_id = in_thread_id) + ) AS trxi + LEFT JOIN (SELECT thread_id, + nesting_event_id, + GROUP_CONCAT( + IFNULL( + CONCAT('\n {\n', + ' "sql_text": "', IFNULL(sys.format_statement(REPLACE(sql_text, '\\', '\\\\')), ''), '",\n', + ' "time": "', IFNULL(sys.format_time(timer_wait), ''), '",\n', + ' "schema": "', IFNULL(current_schema, ''), '",\n', + ' "rows_examined": ', IFNULL(rows_examined, ''), ',\n', + ' "rows_affected": ', IFNULL(rows_affected, ''), ',\n', + ' "rows_sent": ', IFNULL(rows_sent, ''), ',\n', + ' "tmp_tables": ', IFNULL(created_tmp_tables, ''), ',\n', + ' "tmp_disk_tables": ', IFNULL(created_tmp_disk_tables, ''), ',\n', + ' "sort_rows": ', IFNULL(sort_rows, ''), ',\n', + ' "sort_merge_passes": ', IFNULL(sort_merge_passes, ''), '\n', + ' }'), '') ORDER BY event_id) AS stmts + FROM performance_schema.events_statements_history + WHERE sql_text IS NOT NULL + AND thread_id = in_thread_id + GROUP BY thread_id, nesting_event_id + ) AS s + ON trxi.thread_id = s.thread_id + AND trxi.event_id = s.nesting_event_id + WHERE trxi.thread_id = in_thread_id + GROUP BY trxi.thread_id, trxi.event_id + ) trxs + GROUP BY thread_id + ); + + IF (@old_group_concat_max_len IS NOT NULL) THEN + SET SESSION group_concat_max_len = @old_group_concat_max_len; + END IF; + + RETURN v_output; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/quote_identifier.sql b/scripts/sys_schema/functions/quote_identifier.sql new file mode 100644 index 00000000..b661e5c7 --- /dev/null +++ b/scripts/sys_schema/functions/quote_identifier.sql @@ -0,0 +1,71 @@ +-- Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS quote_identifier; + +DELIMITER $$ + +-- https://dev.mysql.com/doc/refman/5.7/en/identifiers.html +-- Maximum supported length for any of the current identifiers in 5.7.5+ is 256 characters. +-- Before that, user variables could have any length. +-- +-- Based on Paul Dubois' suggestion in Bug #78823/Bug #22011361. +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION quote_identifier(in_identifier TEXT) + RETURNS TEXT CHARSET UTF8 + COMMENT ' + Description + ----------- + + Takes an unquoted identifier (schema name, table name, etc.) and + returns the identifier quoted with backticks. + + Parameters + ----------- + + in_identifier (TEXT): + The identifier to quote. + + Returns + ----------- + + TEXT + + Example + ----------- + + mysql> SELECT sys.quote_identifier(''my_identifier'') AS Identifier; + +-----------------+ + | Identifier | + +-----------------+ + | `my_identifier` | + +-----------------+ + 1 row in set (0.00 sec) + + mysql> SELECT sys.quote_identifier(''my`idenfier'') AS Identifier; + +----------------+ + | Identifier | + +----------------+ + | `my``idenfier` | + +----------------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + NO SQL +BEGIN + RETURN CONCAT('`', REPLACE(in_identifier, '`', '``'), '`'); +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/sys_get_config.sql b/scripts/sys_schema/functions/sys_get_config.sql new file mode 100644 index 00000000..9c0c9011 --- /dev/null +++ b/scripts/sys_schema/functions/sys_get_config.sql @@ -0,0 +1,99 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS sys_get_config; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION sys_get_config ( + in_variable_name VARCHAR(128), + in_default_value VARCHAR(128) + ) + RETURNS VARCHAR(128) + COMMENT ' + Description + ----------- + + Returns the value for the requested variable using the following logic: + + 1. If the option exists in sys.sys_config return the value from there. + 2. Else fall back on the provided default value. + + Notes for using sys_get_config(): + + * If the default value argument to sys_get_config() is NULL and case 2. is reached, NULL is returned. + It is then expected that the caller is able to handle NULL for the given configuration option. + * The convention is to name the user variables @sys.<name of variable>. It is <name of variable> that + is stored in the sys_config table and is what is expected as the argument to sys_get_config(). + * If you want to check whether the configuration option has already been set and if not assign with + the return value of sys_get_config() you can use IFNULL(...) (see example below). However this should + not be done inside a loop (e.g. for each row in a result set) as for repeated calls where assignment + is only needed in the first iteration using IFNULL(...) is expected to be significantly slower than + using an IF (...) THEN ... END IF; block (see example below). + + Parameters + ----------- + + in_variable_name (VARCHAR(128)): + The name of the config option to return the value for. + + in_default_value (VARCHAR(128)): + The default value to return if the variable does not exist in sys.sys_config. + + Returns + ----------- + + VARCHAR(128) + + Example + ----------- + + -- Get the configuration value from sys.sys_config falling back on 128 if the option is not present in the table. + mysql> SELECT sys.sys_get_config(''statement_truncate_len'', 128) AS Value; + +-------+ + | Value | + +-------+ + | 64 | + +-------+ + 1 row in set (0.00 sec) + + -- Check whether the option is already set, if not assign - IFNULL(...) one liner example. + mysql> SET @sys.statement_truncate_len = IFNULL(@sys.statement_truncate_len, sys.sys_get_config(''statement_truncate_len'', 64)); + Query OK, 0 rows affected (0.00 sec) + + -- Check whether the option is already set, if not assign - IF ... THEN ... END IF example. + IF (@sys.statement_truncate_len IS NULL) THEN + SET @sys.statement_truncate_len = sys.sys_get_config(''statement_truncate_len'', 64); + END IF; + ' + SQL SECURITY INVOKER + DETERMINISTIC + READS SQL DATA +BEGIN + DECLARE v_value VARCHAR(128) DEFAULT NULL; + DECLARE old_val INTEGER DEFAULT NULL; + + -- Check if we have the variable in the sys.sys_config table + SET v_value = (SELECT value FROM sys.sys_config WHERE variable = in_variable_name); + + -- Protection against the variable not existing in sys_config + IF (v_value IS NULL) THEN + SET v_value = in_default_value; + END IF; + + RETURN v_value; +END $$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/version_major.sql b/scripts/sys_schema/functions/version_major.sql new file mode 100644 index 00000000..8e44d8cf --- /dev/null +++ b/scripts/sys_schema/functions/version_major.sql @@ -0,0 +1,51 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS version_major; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION version_major () + RETURNS TINYINT UNSIGNED + COMMENT ' + Description + ----------- + + Returns the major version of MySQL Server. + + Returns + ----------- + + TINYINT UNSIGNED + + Example + ----------- + + mysql> SELECT VERSION(), sys.version_major(); + +--------------------------------------+---------------------+ + | VERSION() | sys.version_major() | + +--------------------------------------+---------------------+ + | 5.7.9-enterprise-commercial-advanced | 5 | + +--------------------------------------+---------------------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + NO SQL +BEGIN + RETURN SUBSTRING_INDEX(SUBSTRING_INDEX(VERSION(), '-', 1), '.', 1); +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/version_minor.sql b/scripts/sys_schema/functions/version_minor.sql new file mode 100644 index 00000000..6d8f654d --- /dev/null +++ b/scripts/sys_schema/functions/version_minor.sql @@ -0,0 +1,51 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS version_minor; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION version_minor () + RETURNS TINYINT UNSIGNED + COMMENT ' + Description + ----------- + + Returns the minor (release series) version of MySQL Server. + + Returns + ----------- + + TINYINT UNSIGNED + + Example + ----------- + + mysql> SELECT VERSION(), sys.server_minor(); + +--------------------------------------+---------------------+ + | VERSION() | sys.version_minor() | + +--------------------------------------+---------------------+ + | 5.7.9-enterprise-commercial-advanced | 7 | + +--------------------------------------+---------------------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + NO SQL +BEGIN + RETURN SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(VERSION(), '-', 1), '.', 2), '.', -1); +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/functions/version_patch.sql b/scripts/sys_schema/functions/version_patch.sql new file mode 100644 index 00000000..156b5678 --- /dev/null +++ b/scripts/sys_schema/functions/version_patch.sql @@ -0,0 +1,51 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS version_patch; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION version_patch () + RETURNS TINYINT UNSIGNED + COMMENT ' + Description + ----------- + + Returns the patch release version of MySQL Server. + + Returns + ----------- + + TINYINT UNSIGNED + + Example + ----------- + + mysql> SELECT VERSION(), sys.version_patch(); + +--------------------------------------+---------------------+ + | VERSION() | sys.version_patch() | + +--------------------------------------+---------------------+ + | 5.7.9-enterprise-commercial-advanced | 9 | + +--------------------------------------+---------------------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + NO SQL +BEGIN + RETURN SUBSTRING_INDEX(SUBSTRING_INDEX(VERSION(), '-', 1), '.', -1); +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/generate_sql_file.sh b/scripts/sys_schema/generate_sql_file.sh new file mode 100644 index 00000000..3005d926 --- /dev/null +++ b/scripts/sys_schema/generate_sql_file.sh @@ -0,0 +1,239 @@ +#!/bin/bash +# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +OS=`uname` +SYSDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +GENDIR=$SYSDIR/gen +PWD=$( pwd ) + +# Grab the current sys version +SYSVERSIONTMP=`cat views/version.sql | grep 'AS sys_version' | awk '{print $2}'` +SYSVERSION=`echo "${SYSVERSIONTMP//\'}"` + +MYSQLUSER="'root'@'localhost'" + +if [ $OS == "Darwin" ] ; +then + SED_R="sed -E" +else + SED_R="sed -r" +fi + +USAGE=" +Options: +================ + + v: The version of MySQL to build the sys schema for, either '56' or '57' + + b: Whether to omit any lines that deal with sql_log_bin (useful for RDS) + + m: Whether to generate a mysql_install_db / mysqld --initialize formatted file + + u: The user to set as the owner of the objects (useful for RDS) + +Examples: +================ + +Generate a MySQL 5.7 SQL file that uses the 'mark'@'localhost' user: + + $0 -v 57 -u \"'mark'@'localhost'\" + +Generate a MySQL 5.6 SQL file for RDS: + + $0 -v 56 -b -u CURRENT_USER + +Generate a MySQL 5.7 initialize / bootstrap file: + + $0 -v 57 -m +" + +# Grab options +while getopts ":v:bhmu:" opt; do + case $opt in + b) + SKIPBINLOG=true + ;; + h) + echo $"$USAGE" + exit 0 + ;; + m) + MYSQLCOMPAT=true + # Bundled mysql expects the mysql.sys user to be used + MYSQLUSER="'mysql.sys'@'localhost'" + ;; + u) + if [ -z "$MYSQLCOMPAT" ] ; + then + MYSQLUSER="${OPTARG}" + fi + ;; + v) + if [ $OPTARG == "56" ] || [ $OPTARG == "57" ] ; + then + MYSQLVERSION=$OPTARG + else + echo "Invalid -v option, please run again with either '-v 56' or '-v 57'" + exit 1 + fi + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 + echo $"$USAGE" + exit 1 + ;; + :) + echo "Option -$OPTARG requires an argument." >&2 + echo $"$USAGE" + exit 1 + ;; + esac +done + +# Check required options +if [[ -z "$MYSQLVERSION" ]] ; +then + echo " -v (MySQL Version) parameter required, please run again with either '-v 56' or '-v 57'" + echo $"$USAGE" + exit 1 +fi + +# Create the gen directory +if [[ ! -d $GENDIR ]] ; +then + mkdir $GENDIR +fi + +# Create output file name +if [[ ! -z "$MYSQLCOMPAT" ]] ; +then + OUTPUTFILE="mysql_sys_schema.sql" +else + OUTPUTFILE="sys_${SYSVERSION}_${MYSQLVERSION}_inline.sql" +fi + +# Create the initial output file +if [[ ! -z "$MYSQLCOMPAT" ]] ; +then + # Pre-process all the files in a copied temp directory + if [[ ! -d $GENDIR/tmpgen ]] ; + then + mkdir $GENDIR/tmpgen + fi + cd $GENDIR/tmpgen + rm -rf * + cp -r $SYSDIR/after_setup.sql $SYSDIR/tables $SYSDIR/triggers $SYSDIR/functions $SYSDIR/views $SYSDIR/procedures . + + # Switch user if requested + # Remove individual copyrights + # Replace newlines in COMMENTs with literal \n + # Drop added trailing \n <sad panda> + # Remove DELIMITER commands + # Replace $$ delimiter with ; + # Remove leading spaces + # Remove -- line comments *after removing leading spaces* + for file in `find . -name '*.sql'`; do + # The 5.6 MEM/WB integration should still use the root@localhost user + if [ ! $MYSQLVERSION == "56" ] ; + then + sed -i -e "s/'root'@'localhost'/$MYSQLUSER/g" $file + fi + sed -i -e "/Copyright/,/51 Franklin St/d" $file + sed -i -e "/^ *COMMENT/,/^ *'/{G;s/\n/\\\n/g;}" $file + sed -i -e "s/ '\\\n/ '/g" $file + sed -i -e "/^DELIMITER/d" $file + sed -i -e "s/\\$\\$/;/g" $file + sed -i -e "s/^ *//g" $file + sed -i -e "/^--/d" $file + done + + # Start the output file from a non-removed copyright file + sed -e "s/^/-- /" $SYSDIR/LICENSE > $OUTPUTFILE + echo "" >> $OUTPUTFILE + echo "--" >> $OUTPUTFILE + echo "-- WARNING: THIS IS A GENERATED FILE, CHANGES NEED TO BE MADE ON THE UPSTREAM MYSQL-SYS REPOSITORY AS WELL" >> $OUTPUTFILE + echo "-- PLEASE SUBMIT A PULL REQUEST TO https://github.com/mysql/mysql-sys" >> $OUTPUTFILE + echo "--" >> $OUTPUTFILE + echo "" >> $OUTPUTFILE + + # Add the expected user + # Note this currently only works with 5.7 mysql.user structure + if [ ! $MYSQLVERSION == "56" ] ; + then + echo "REPLACE INTO mysql.user VALUES ('localhost','mysql.sys','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','','','','',0,0,0,0,'mysql_native_password','*THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE','N',CURRENT_TIMESTAMP,NULL,'Y');" >> $OUTPUTFILE + echo "" >> $OUTPUTFILE + echo "REPLACE INTO mysql.db VALUES ('localhost','sys','mysql.sys','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','Y');" >> $OUTPUTFILE + echo "" >> $OUTPUTFILE + echo "REPLACE INTO mysql.tables_priv VALUES ('localhost','sys','mysql.sys','sys_config','root@localhost', CURRENT_TIMESTAMP, 'Select', '');" >> $OUTPUTFILE + echo "" >> $OUTPUTFILE + echo "FLUSH PRIVILEGES;" >> $OUTPUTFILE + echo "" >> $OUTPUTFILE + fi + + # Put in the contents of before_setup.sql, though don't collapse lines + sed -e "/sql_log_bin/d;s/'root'@'localhost'/$MYSQLUSER/g;/Copyright/,/51 Franklin St/d" $SYSDIR/before_setup.sql >> $OUTPUTFILE + + # Add the rest of the files in install file order, removing new lines along the way + cat "$SYSDIR/sys_$MYSQLVERSION.sql" | tr -d '\r' | grep 'SOURCE' | grep -v before_setup | grep -v after_setup | $SED_R 's .{8} ' | sed 's/^/./' > "./sys_$MYSQLVERSION.sql" + while read file; do + # First try and get a DROP command + grep -E '(^DROP PROCEDURE|^DROP FUNCTION|^DROP TRIGGER)' $file >> $OUTPUTFILE + # And remove any that may exist (but keep DROP TEMPORARY TABLE) + sed -i -e "/^DROP PROCEDURE/d;/^DROP FUNCTION/d;/^DROP TRIGGER/d" $file + echo "" >> $OUTPUTFILE + # Then collapse the rest of the file + cat $file | tr '\n' ' ' >> $OUTPUTFILE + echo "" >> $OUTPUTFILE + echo "" >> $OUTPUTFILE + done < "./sys_$MYSQLVERSION.sql" + + # Does essentially nothing right now, but may in future + sed -e "/Copyright/,/51 Franklin St/d;/sql_log_bin/d" $SYSDIR/after_setup.sql >> $OUTPUTFILE + + # Remove final leading and trailing spaces + sed -i '' -e "s/^ *//g" $OUTPUTFILE + sed -i '' -e "s/[ \t]*$//g" $OUTPUTFILE + # Remove more than one empty line + sed -i '' -e "/^$/N;/^\n$/D" $OUTPUTFILE + + mv $OUTPUTFILE $GENDIR/ + cd $GENDIR/ + rm -rf $GENDIR/tmpgen +else + sed -e "s/^/-- /" $SYSDIR/LICENSE > $GENDIR/$OUTPUTFILE + cat "$SYSDIR/sys_$MYSQLVERSION.sql" | tr -d '\r' | grep 'SOURCE' | $SED_R 's .{8} ' | sed "s/^/$(echo $SYSDIR | sed -e 's/[]\/$*.^|[]/\\&/g')/g" \ + | xargs sed -e "/Copyright/,/51 Franklin St/d;s/'root'@'localhost'/$MYSQLUSER/g" >> $GENDIR/$OUTPUTFILE +fi + +# Check if sql_log_bin lines should be removed +if [[ ! -z "$SKIPBINLOG" ]] ; +then + LOGWARNING="WARNING: Using a routine that could cause binary log events, but disabling of binary logging has been removed" + sed -i '' -e "s/^[ \s]*SET sql_log_bin = 0/SELECT \"$LOGWARNING\"/g" $GENDIR/$OUTPUTFILE + sed -i '' -e "s/\sSET sql_log_bin = @log_bin;/SET @log_bin = NULL;/g" $GENDIR/$OUTPUTFILE + SKIPBINLOG="disabled" +else + SKIPBINLOG="enabled" +fi + +cd $PWD + +# Print summary +echo $" + Wrote file: $GENDIR/$OUTPUTFILE +Object Definer: $MYSQLUSER + sql_log_bin: $SKIPBINLOG + " diff --git a/scripts/sys_schema/procedures/create_synonym_db.sql b/scripts/sys_schema/procedures/create_synonym_db.sql new file mode 100644 index 00000000..e373a9b4 --- /dev/null +++ b/scripts/sys_schema/procedures/create_synonym_db.sql @@ -0,0 +1,187 @@ +-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS create_synonym_db; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE create_synonym_db ( + IN in_db_name VARCHAR(64), + IN in_synonym VARCHAR(64) + ) + COMMENT ' + Description + ----------- + + Takes a source database name and synonym name, and then creates the + synonym database with views that point to all of the tables within + the source database. + + Useful for creating a "ps" synonym for "performance_schema", + or "is" instead of "information_schema", for example. + + Parameters + ----------- + + in_db_name (VARCHAR(64)): + The database name that you would like to create a synonym for. + in_synonym (VARCHAR(64)): + The database synonym name. + + Example + ----------- + + mysql> SHOW DATABASES; + +--------------------+ + | Database | + +--------------------+ + | information_schema | + | mysql | + | performance_schema | + | sys | + | test | + +--------------------+ + 5 rows in set (0.00 sec) + + mysql> CALL sys.create_synonym_db(\'performance_schema\', \'ps\'); + +---------------------------------------+ + | summary | + +---------------------------------------+ + | Created 74 views in the `ps` database | + +---------------------------------------+ + 1 row in set (8.57 sec) + + Query OK, 0 rows affected (8.57 sec) + + mysql> SHOW DATABASES; + +--------------------+ + | Database | + +--------------------+ + | information_schema | + | mysql | + | performance_schema | + | ps | + | sys | + | test | + +--------------------+ + 6 rows in set (0.00 sec) + + mysql> SHOW FULL TABLES FROM ps; + +------------------------------------------------------+------------+ + | Tables_in_ps | Table_type | + +------------------------------------------------------+------------+ + | accounts | VIEW | + | cond_instances | VIEW | + | events_stages_current | VIEW | + | events_stages_history | VIEW | + ... + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + DECLARE v_done bool DEFAULT FALSE; + DECLARE v_db_name_check VARCHAR(64); + DECLARE v_db_err_msg TEXT; + DECLARE v_table VARCHAR(64); + DECLARE v_views_created INT DEFAULT 0; + DECLARE v_table_exists ENUM('', 'BASE TABLE', 'VIEW', 'TEMPORARY') DEFAULT ''; + DECLARE v_temp_table TEXT; + + DECLARE c_table_names CURSOR FOR + SELECT TABLE_NAME + FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_SCHEMA = in_db_name; + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE; + + -- Check if the source database exists + SELECT SCHEMA_NAME INTO v_db_name_check + FROM INFORMATION_SCHEMA.SCHEMATA + WHERE SCHEMA_NAME = in_db_name; + + IF v_db_name_check IS NULL THEN + SET v_db_err_msg = CONCAT('Unknown database ', in_db_name); + SIGNAL SQLSTATE 'HY000' + SET MESSAGE_TEXT = v_db_err_msg; + END IF; + + -- Check if a database of the synonym name already exists + SELECT SCHEMA_NAME INTO v_db_name_check + FROM INFORMATION_SCHEMA.SCHEMATA + WHERE SCHEMA_NAME = in_synonym; + + IF v_db_name_check = in_synonym THEN + SET v_db_err_msg = CONCAT('Can\'t create database ', in_synonym, '; database exists'); + SIGNAL SQLSTATE 'HY000' + SET MESSAGE_TEXT = v_db_err_msg; + END IF; + + -- All good, create the database and views + SET @create_db_stmt := CONCAT('CREATE DATABASE ', sys.quote_identifier(in_synonym)); + PREPARE create_db_stmt FROM @create_db_stmt; + EXECUTE create_db_stmt; + DEALLOCATE PREPARE create_db_stmt; + + SET v_done = FALSE; + OPEN c_table_names; + c_table_names: LOOP + FETCH c_table_names INTO v_table; + IF v_done THEN + LEAVE c_table_names; + END IF; + + -- Check does temporary table shadows the base table. If it is so, terminate. + CALL sys.table_exists(in_db_name, v_table, v_table_exists); + IF (v_table_exists = 'TEMPORARY') THEN + SET v_temp_table = + CONCAT( + 'Table', + sys.quote_identifier(in_db_name), + '.', + sys.quote_identifier(v_table), + 'shadows base table. View cannot be created! Terminating!'); + SIGNAL SQLSTATE 'HY000' + SET MESSAGE_TEXT = v_temp_table; + LEAVE c_table_names; + END IF; + + SET @create_view_stmt = CONCAT( + 'CREATE SQL SECURITY INVOKER VIEW ', + sys.quote_identifier(in_synonym), + '.', + sys.quote_identifier(v_table), + ' AS SELECT * FROM ', + sys.quote_identifier(in_db_name), + '.', + sys.quote_identifier(v_table) + ); + PREPARE create_view_stmt FROM @create_view_stmt; + EXECUTE create_view_stmt; + DEALLOCATE PREPARE create_view_stmt; + + SET v_views_created = v_views_created + 1; + END LOOP; + CLOSE c_table_names; + + SELECT CONCAT( + 'Created ', v_views_created, ' view', + IF(v_views_created != 1, 's', ''), ' in the ', + sys.quote_identifier(in_synonym), ' database' + ) AS summary; + +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/diagnostics.sql b/scripts/sys_schema/procedures/diagnostics.sql new file mode 100644 index 00000000..2e79c5c1 --- /dev/null +++ b/scripts/sys_schema/procedures/diagnostics.sql @@ -0,0 +1,1064 @@ +-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS diagnostics; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE diagnostics ( + IN in_max_runtime int unsigned, IN in_interval int unsigned, + IN in_auto_config enum ('current', 'medium', 'full') + ) + COMMENT ' + Description + ----------- + + Create a report of the current status of the server for diagnostics purposes. Data collected includes (some items depends on versions and settings): + + * The GLOBAL VARIABLES + * Several sys schema views including metrics or equivalent (depending on version and settings) + * Queries in the 95th percentile + * Several ndbinfo views for MySQL Cluster + * Replication (both master and slave) information. + + Some of the sys schema views are calculated as initial (optional), overall, delta: + + * The initial view is the content of the view at the start of this procedure. + This output will be the same as the the start values used for the delta view. + The initial view is included if @sys.diagnostics.include_raw = ''ON''. + * The overall view is the content of the view at the end of this procedure. + This output is the same as the end values used for the delta view. + The overall view is always included. + * The delta view is the difference from the beginning to the end. Note that for min and max values + they are simply the min or max value from the end view respectively, so does not necessarily reflect + the minimum/maximum value in the monitored period. + Note: except for the metrics views the delta is only calculation between the first and last outputs. + + Requires the SUPER privilege for "SET sql_log_bin = 0;". + + Versions supported: + * MySQL 5.6: 5.6.10 and later + * MySQL 5.7: 5.7.9 and later + + Parameters + ----------- + + in_max_runtime (INT UNSIGNED): + The maximum time to keep collecting data. + Use NULL to get the default which is 60 seconds, otherwise enter a value greater than 0. + in_interval (INT UNSIGNED): + How long to sleep between data collections. + Use NULL to get the default which is 30 seconds, otherwise enter a value greater than 0. + in_auto_config (ENUM(''current'', ''medium'', ''full'')) + Automatically enable Performance Schema instruments and consumers. + NOTE: The more that are enabled, the more impact on the performance. + Supported values are: + * current - use the current settings. + * medium - enable some settings. + * full - enables all settings. This will have a big impact on the + performance - be careful using this option. + If another setting the ''current'' is chosen, the current settings + are restored at the end of the procedure. + + + Configuration Options + ---------------------- + + sys.diagnostics.allow_i_s_tables + Specifies whether it is allowed to do table scan queries on information_schema.TABLES. This can be expensive if there + are many tables. Set to ''ON'' to allow, ''OFF'' to not allow. + Default is ''OFF''. + + sys.diagnostics.include_raw + Set to ''ON'' to include the raw data (e.g. the original output of "SELECT * FROM sys.metrics"). + Use this to get the initial values of the various views. + Default is ''OFF''. + + sys.statement_truncate_len + How much of queries in the process list output to include. + Default is 64. + + sys.debug + Whether to provide debugging output. + Default is ''OFF''. Set to ''ON'' to include. + + + Example + -------- + + To create a report and append it to the file diag.out: + + mysql> TEE diag.out; + mysql> CALL sys.diagnostics(120, 30, ''current''); + ... + mysql> NOTEE; + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + READS SQL DATA +BEGIN + DECLARE v_start, v_runtime, v_iter_start, v_sleep DECIMAL(20,2) DEFAULT 0.0; + DECLARE v_has_innodb, v_has_ndb, v_has_ps, v_has_replication, v_has_ps_replication VARCHAR(8) CHARSET utf8 DEFAULT 'NO'; + DECLARE v_this_thread_enabled, v_has_ps_vars, v_has_metrics ENUM('YES', 'NO'); + DECLARE v_table_name, v_banner VARCHAR(64) CHARSET utf8; + DECLARE v_sql_status_summary_select, v_sql_status_summary_delta, v_sql_status_summary_from, v_no_delta_names TEXT; + DECLARE v_output_time, v_output_time_prev DECIMAL(20,3) UNSIGNED; + DECLARE v_output_count, v_count, v_old_group_concat_max_len INT UNSIGNED DEFAULT 0; + -- The width of each of the status outputs in the summery + DECLARE v_status_summary_width TINYINT UNSIGNED DEFAULT 50; + DECLARE v_done BOOLEAN DEFAULT FALSE; + -- Do not include the following ndbinfo views: + -- 'blocks' Static + -- 'config_params' Static + -- 'dict_obj_types' Static + -- 'disk_write_speed_base' Can generate lots of output - only include aggregate views here + -- 'memory_per_fragment' Can generate lots of output + -- 'memoryusage' Handled separately + -- 'operations_per_fragment' Can generate lots of output + -- 'threadblocks' Only needed once + DECLARE c_ndbinfo CURSOR FOR + SELECT TABLE_NAME + FROM information_schema.TABLES + WHERE TABLE_SCHEMA = 'ndbinfo' + AND TABLE_NAME NOT IN ( + 'blocks', + 'config_params', + 'dict_obj_types', + 'disk_write_speed_base', + 'memory_per_fragment', + 'memoryusage', + 'operations_per_fragment', + 'threadblocks' + ); + DECLARE c_sysviews_w_delta CURSOR FOR + SELECT table_name + FROM tmp_sys_views_delta + ORDER BY table_name; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE; + + -- Do not track the current thread - no reason to clutter the output + SELECT INSTRUMENTED INTO v_this_thread_enabled FROM performance_schema.threads WHERE PROCESSLIST_ID = CONNECTION_ID(); + IF (v_this_thread_enabled = 'YES') THEN + CALL sys.ps_setup_disable_thread(CONNECTION_ID()); + END IF; + + -- Check options are sane + IF (in_max_runtime < in_interval) THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = 'in_max_runtime must be greater than or equal to in_interval'; + END IF; + IF (in_max_runtime = 0) THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = 'in_max_runtime must be greater than 0'; + END IF; + IF (in_interval = 0) THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = 'in_interval must be greater than 0'; + END IF; + + -- Set configuration options + IF (@sys.diagnostics.allow_i_s_tables IS NULL) THEN + SET @sys.diagnostics.allow_i_s_tables = sys.sys_get_config('diagnostics.allow_i_s_tables', 'OFF'); + END IF; + IF (@sys.diagnostics.include_raw IS NULL) THEN + SET @sys.diagnostics.include_raw = sys.sys_get_config('diagnostics.include_raw' , 'OFF'); + END IF; + IF (@sys.debug IS NULL) THEN + SET @sys.debug = sys.sys_get_config('debug' , 'OFF'); + END IF; + IF (@sys.statement_truncate_len IS NULL) THEN + SET @sys.statement_truncate_len = sys.sys_get_config('statement_truncate_len' , '64' ); + END IF; + + -- Temporary table are used - disable sql_log_bin if necessary to prevent them replicating + SET @log_bin := @@sql_log_bin; + IF (@log_bin = 1) THEN + SET sql_log_bin = 0; + END IF; + + -- Some metrics variables doesn't make sense in delta and rate calculations even if they are numeric + -- as they really are more like settings or "current" status. + SET v_no_delta_names = CONCAT('s%{COUNT}.Variable_name NOT IN (', + '''innodb_buffer_pool_pages_total'', ', + '''innodb_page_size'', ', + '''last_query_cost'', ', + '''last_query_partial_plans'', ', + '''qcache_total_blocks'', ', + '''slave_last_heartbeat'', ', + '''ssl_ctx_verify_depth'', ', + '''ssl_ctx_verify_mode'', ', + '''ssl_session_cache_size'', ', + '''ssl_verify_depth'', ', + '''ssl_verify_mode'', ', + '''ssl_version'', ', + '''buffer_flush_lsn_avg_rate'', ', + '''buffer_flush_pct_for_dirty'', ', + '''buffer_flush_pct_for_lsn'', ', + '''buffer_pool_pages_total'', ', + '''lock_row_lock_time_avg'', ', + '''lock_row_lock_time_max'', ', + '''innodb_page_size''', + ')'); + + IF (in_auto_config <> 'current') THEN + IF (@sys.debug = 'ON') THEN + SELECT CONCAT('Updating Performance Schema configuration to ', in_auto_config) AS 'Debug'; + END IF; + CALL sys.ps_setup_save(0); + + IF (in_auto_config = 'medium') THEN + -- Enable all consumers except %history and %history_long + UPDATE performance_schema.setup_consumers + SET ENABLED = 'YES' + WHERE NAME NOT LIKE '%\_history%'; + + -- Enable all instruments except wait/synch/% + UPDATE performance_schema.setup_instruments + SET ENABLED = 'YES', + TIMED = 'YES' + WHERE NAME NOT LIKE 'wait/synch/%'; + ELSEIF (in_auto_config = 'full') THEN + UPDATE performance_schema.setup_consumers + SET ENABLED = 'YES'; + + UPDATE performance_schema.setup_instruments + SET ENABLED = 'YES', + TIMED = 'YES'; + END IF; + + -- Enable all threads except this one + UPDATE performance_schema.threads + SET INSTRUMENTED = 'YES' + WHERE PROCESSLIST_ID <> CONNECTION_ID(); + END IF; + + SET v_start = UNIX_TIMESTAMP(NOW(2)), + in_interval = IFNULL(in_interval, 30), + in_max_runtime = IFNULL(in_max_runtime, 60); + + -- Get a quick ref with hostname, server UUID, and the time for the report. + SET v_banner = REPEAT( + '-', + LEAST( + GREATEST( + 36, + CHAR_LENGTH(VERSION()), + CHAR_LENGTH(@@global.version_comment), + CHAR_LENGTH(@@global.version_compile_os), + CHAR_LENGTH(@@global.version_compile_machine), + CHAR_LENGTH(@@global.socket), + CHAR_LENGTH(@@global.datadir) + ), + 64 + ) + ); + SELECT 'Hostname' AS 'Name', @@global.hostname AS 'Value' + UNION ALL + SELECT 'Port' AS 'Name', @@global.port AS 'Value' + UNION ALL + SELECT 'Socket' AS 'Name', @@global.socket AS 'Value' + UNION ALL + SELECT 'Datadir' AS 'Name', @@global.datadir AS 'Value' + UNION ALL + SELECT REPEAT('-', 23) AS 'Name', v_banner AS 'Value' + UNION ALL + SELECT 'MySQL Version' AS 'Name', VERSION() AS 'Value' + UNION ALL + SELECT 'Sys Schema Version' AS 'Name', (SELECT sys_version FROM sys.version) AS 'Value' + UNION ALL + SELECT 'Version Comment' AS 'Name', @@global.version_comment AS 'Value' + UNION ALL + SELECT 'Version Compile OS' AS 'Name', @@global.version_compile_os AS 'Value' + UNION ALL + SELECT 'Version Compile Machine' AS 'Name', @@global.version_compile_machine AS 'Value' + UNION ALL + SELECT REPEAT('-', 23) AS 'Name', v_banner AS 'Value' + UNION ALL + SELECT 'UTC Time' AS 'Name', UTC_TIMESTAMP() AS 'Value' + UNION ALL + SELECT 'Local Time' AS 'Name', NOW() AS 'Value' + UNION ALL + SELECT 'Time Zone' AS 'Name', @@global.time_zone AS 'Value' + UNION ALL + SELECT 'System Time Zone' AS 'Name', @@global.system_time_zone AS 'Value' + UNION ALL + SELECT 'Time Zone Offset' AS 'Name', TIMEDIFF(NOW(), UTC_TIMESTAMP()) AS 'Value'; + + -- Are the InnoDB, NDBCluster, and Performance Schema storage engines present? + SET v_has_innodb = IFNULL((SELECT SUPPORT FROM information_schema.ENGINES WHERE ENGINE = 'InnoDB'), 'NO'), + v_has_ndb = IFNULL((SELECT SUPPORT FROM information_schema.ENGINES WHERE ENGINE = 'NDBCluster'), 'NO'), + v_has_ps = IFNULL((SELECT SUPPORT FROM information_schema.ENGINES WHERE ENGINE = 'PERFORMANCE_SCHEMA'), 'NO'), + v_has_ps_replication = IF(v_has_ps = 'YES' + AND EXISTS(SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'performance_schema' AND TABLE_NAME = 'replication_applier_status'), + 'YES', + 'NO' + ), + v_has_replication = 'MAYBE', + v_has_metrics = IF(v_has_ps = 'YES' OR (sys.version_major() = 5 AND sys.version_minor() = 6), 'YES', 'NO'), + v_has_ps_vars = 'NO'; + + -- 5.7.7 introduced the possibility to get SHOW [GLOBAL|SESSION] VARIABLES and SHOW [GLOBAL|SESSION] STATUS + -- from the Performance Schema. But it's optional whether it's enabled. + -- 5.7.9 changes so the Performance Schema tables always work. + -- Note that @@global.show_compatibility_56 = OFF will only actually work if the Performance Schema is enabled in <=5.7.8, + -- however except overriding the global value there is nothing that can be done about it. + -- v_has_ps_vars defaults to NO + /*!50707 SET v_has_ps_vars = IF(@@global.show_compatibility_56, 'NO', 'YES');*/ + /*!50709 SET v_has_ps_vars = 'YES';*/ + + IF (@sys.debug = 'ON') THEN + SELECT v_has_innodb AS 'Has_InnoDB', v_has_ndb AS 'Has_NDBCluster', + v_has_ps AS 'Has_Performance_Schema', v_has_ps_vars AS 'Has_P_S_SHOW_Variables', + v_has_metrics AS 'Has_metrics', + v_has_ps_replication 'AS Has_P_S_Replication', v_has_replication AS 'Has_Replication'; + END IF; + + IF (v_has_innodb IN ('DEFAULT', 'YES')) THEN + -- Need to use prepared statement as just having the query as a plain command + -- will generate an error if the InnoDB storage engine is not present + SET @sys.diagnostics.sql = 'SHOW ENGINE InnoDB STATUS'; + PREPARE stmt_innodb_status FROM @sys.diagnostics.sql; + END IF; + + IF (v_has_ps = 'YES') THEN + -- Need to use prepared statement as just having the query as a plain command + -- will generate an error if the InnoDB storage engine is not present + SET @sys.diagnostics.sql = 'SHOW ENGINE PERFORMANCE_SCHEMA STATUS'; + PREPARE stmt_ps_status FROM @sys.diagnostics.sql; + END IF; + + IF (v_has_ndb IN ('DEFAULT', 'YES')) THEN + -- Need to use prepared statement as just having the query as a plain command + -- will generate an error if the NDBCluster storage engine is not present + SET @sys.diagnostics.sql = 'SHOW ENGINE NDBCLUSTER STATUS'; + PREPARE stmt_ndbcluster_status FROM @sys.diagnostics.sql; + END IF; + + SET @sys.diagnostics.sql_gen_query_template = 'SELECT CONCAT( + ''SELECT '', + GROUP_CONCAT( + CASE WHEN (SUBSTRING(TABLE_NAME, 3), COLUMN_NAME) IN ( + (''io_global_by_file_by_bytes'', ''total''), + (''io_global_by_wait_by_bytes'', ''total_requested'') + ) + THEN CONCAT(''sys.format_bytes('', COLUMN_NAME, '') AS '', COLUMN_NAME) + WHEN SUBSTRING(COLUMN_NAME, -8) = ''_latency'' + THEN CONCAT(''sys.format_time('', COLUMN_NAME, '') AS '', COLUMN_NAME) + WHEN SUBSTRING(COLUMN_NAME, -7) = ''_memory'' OR SUBSTRING(COLUMN_NAME, -17) = ''_memory_allocated'' + OR ((SUBSTRING(COLUMN_NAME, -5) = ''_read'' OR SUBSTRING(COLUMN_NAME, -8) = ''_written'' OR SUBSTRING(COLUMN_NAME, -6) = ''_write'') AND SUBSTRING(COLUMN_NAME, 1, 6) <> ''COUNT_'') + THEN CONCAT(''sys.format_bytes('', COLUMN_NAME, '') AS '', COLUMN_NAME) + ELSE COLUMN_NAME + END + ORDER BY ORDINAL_POSITION + SEPARATOR '',\n '' + ), + ''\n FROM tmp_'', SUBSTRING(TABLE_NAME FROM 3), ''_%{OUTPUT}'' + ) AS Query INTO @sys.diagnostics.sql_select + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = ''sys'' AND TABLE_NAME = ? + GROUP BY TABLE_NAME'; + + SET @sys.diagnostics.sql_gen_query_delta = 'SELECT CONCAT( + ''SELECT '', + GROUP_CONCAT( + CASE WHEN FIND_IN_SET(COLUMN_NAME, diag.pk) + THEN COLUMN_NAME + WHEN diag.TABLE_NAME = ''io_global_by_file_by_bytes'' AND COLUMN_NAME = ''write_pct'' + THEN CONCAT(''IFNULL(ROUND(100-(((e.total_read-IFNULL(s.total_read, 0))'', + ''/NULLIF(((e.total_read-IFNULL(s.total_read, 0))+(e.total_written-IFNULL(s.total_written, 0))), 0))*100), 2), 0.00) AS '', + COLUMN_NAME) + WHEN (diag.TABLE_NAME, COLUMN_NAME) IN ( + (''io_global_by_file_by_bytes'', ''total''), + (''io_global_by_wait_by_bytes'', ''total_requested'') + ) + THEN CONCAT(''sys.format_bytes(e.'', COLUMN_NAME, ''-IFNULL(s.'', COLUMN_NAME, '', 0)) AS '', COLUMN_NAME) + WHEN SUBSTRING(COLUMN_NAME, 1, 4) IN (''max_'', ''min_'') AND SUBSTRING(COLUMN_NAME, -8) = ''_latency'' + THEN CONCAT(''sys.format_time(e.'', COLUMN_NAME, '') AS '', COLUMN_NAME) + WHEN COLUMN_NAME = ''avg_latency'' + THEN CONCAT(''sys.format_time((e.total_latency - IFNULL(s.total_latency, 0))'', + ''/NULLIF(e.total - IFNULL(s.total, 0), 0)) AS '', COLUMN_NAME) + WHEN SUBSTRING(COLUMN_NAME, -12) = ''_avg_latency'' + THEN CONCAT(''sys.format_time((e.'', SUBSTRING(COLUMN_NAME FROM 1 FOR CHAR_LENGTH(COLUMN_NAME)-12), ''_latency - IFNULL(s.'', SUBSTRING(COLUMN_NAME FROM 1 FOR CHAR_LENGTH(COLUMN_NAME)-12), ''_latency, 0))'', + ''/NULLIF(e.'', SUBSTRING(COLUMN_NAME FROM 1 FOR CHAR_LENGTH(COLUMN_NAME)-12), ''s - IFNULL(s.'', SUBSTRING(COLUMN_NAME FROM 1 FOR CHAR_LENGTH(COLUMN_NAME)-12), ''s, 0), 0)) AS '', COLUMN_NAME) + WHEN SUBSTRING(COLUMN_NAME, -8) = ''_latency'' + THEN CONCAT(''sys.format_time(e.'', COLUMN_NAME, '' - IFNULL(s.'', COLUMN_NAME, '', 0)) AS '', COLUMN_NAME) + WHEN COLUMN_NAME IN (''avg_read'', ''avg_write'', ''avg_written'') + THEN CONCAT(''sys.format_bytes(IFNULL((e.total_'', IF(COLUMN_NAME = ''avg_read'', ''read'', ''written''), ''-IFNULL(s.total_'', IF(COLUMN_NAME = ''avg_read'', ''read'', ''written''), '', 0))'', + ''/NULLIF(e.count_'', IF(COLUMN_NAME = ''avg_read'', ''read'', ''write''), ''-IFNULL(s.count_'', IF(COLUMN_NAME = ''avg_read'', ''read'', ''write''), '', 0), 0), 0)) AS '', + COLUMN_NAME) + WHEN SUBSTRING(COLUMN_NAME, -7) = ''_memory'' OR SUBSTRING(COLUMN_NAME, -17) = ''_memory_allocated'' + OR ((SUBSTRING(COLUMN_NAME, -5) = ''_read'' OR SUBSTRING(COLUMN_NAME, -8) = ''_written'' OR SUBSTRING(COLUMN_NAME, -6) = ''_write'') AND SUBSTRING(COLUMN_NAME, 1, 6) <> ''COUNT_'') + THEN CONCAT(''sys.format_bytes(e.'', COLUMN_NAME, '' - IFNULL(s.'', COLUMN_NAME, '', 0)) AS '', COLUMN_NAME) + ELSE CONCAT(''(e.'', COLUMN_NAME, '' - IFNULL(s.'', COLUMN_NAME, '', 0)) AS '', COLUMN_NAME) + END + ORDER BY ORDINAL_POSITION + SEPARATOR '',\n '' + ), + ''\n FROM tmp_'', diag.TABLE_NAME, ''_end e + LEFT OUTER JOIN tmp_'', diag.TABLE_NAME, ''_start s USING ('', diag.pk, '')'' + ) AS Query INTO @sys.diagnostics.sql_select + FROM tmp_sys_views_delta diag + INNER JOIN information_schema.COLUMNS c ON c.TABLE_NAME = CONCAT(''x$'', diag.TABLE_NAME) + WHERE c.TABLE_SCHEMA = ''sys'' AND diag.TABLE_NAME = ? + GROUP BY diag.TABLE_NAME'; + + IF (v_has_ps = 'YES') THEN + -- Create temporary table with the ORDER BY clauses. Will be required both for the initial (if included) and end queries + DROP TEMPORARY TABLE IF EXISTS tmp_sys_views_delta; + CREATE TEMPORARY TABLE tmp_sys_views_delta ( + TABLE_NAME varchar(64) NOT NULL, + order_by text COMMENT 'ORDER BY clause for the initial and overall views', + order_by_delta text COMMENT 'ORDER BY clause for the delta views', + where_delta text COMMENT 'WHERE clause to use for delta views to only include rows with a "count" > 0', + limit_rows int unsigned COMMENT 'The maximum number of rows to include for the view', + pk varchar(128) COMMENT 'Used with the FIND_IN_SET() function so use comma separated list without whitespace', + PRIMARY KEY (TABLE_NAME) + ); + + -- %{OUTPUT} will be replace by the suffix used for the output. + IF (@sys.debug = 'ON') THEN + SELECT 'Populating tmp_sys_views_delta' AS 'Debug'; + END IF; + INSERT INTO tmp_sys_views_delta + VALUES ('host_summary' , '%{TABLE}.statement_latency DESC', + '(e.statement_latency-IFNULL(s.statement_latency, 0)) DESC', + '(e.statements - IFNULL(s.statements, 0)) > 0', NULL, 'host'), + ('host_summary_by_file_io' , '%{TABLE}.io_latency DESC', + '(e.io_latency-IFNULL(s.io_latency, 0)) DESC', + '(e.ios - IFNULL(s.ios, 0)) > 0', NULL, 'host'), + ('host_summary_by_file_io_type' , '%{TABLE}.host, %{TABLE}.total_latency DESC', + 'e.host, (e.total_latency-IFNULL(s.total_latency, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'host,event_name'), + ('host_summary_by_stages' , '%{TABLE}.host, %{TABLE}.total_latency DESC', + 'e.host, (e.total_latency-IFNULL(s.total_latency, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'host,event_name'), + ('host_summary_by_statement_latency' , '%{TABLE}.total_latency DESC', + '(e.total_latency-IFNULL(s.total_latency, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'host'), + ('host_summary_by_statement_type' , '%{TABLE}.host, %{TABLE}.total_latency DESC', + 'e.host, (e.total_latency-IFNULL(s.total_latency, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'host,statement'), + ('io_by_thread_by_latency' , '%{TABLE}.total_latency DESC', + '(e.total_latency-IFNULL(s.total_latency, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'user,thread_id,processlist_id'), + ('io_global_by_file_by_bytes' , '%{TABLE}.total DESC', + '(e.total-IFNULL(s.total, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', 100, 'file'), + ('io_global_by_file_by_latency' , '%{TABLE}.total_latency DESC', + '(e.total_latency-IFNULL(s.total_latency, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', 100, 'file'), + ('io_global_by_wait_by_bytes' , '%{TABLE}.total_requested DESC', + '(e.total_requested-IFNULL(s.total_requested, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'event_name'), + ('io_global_by_wait_by_latency' , '%{TABLE}.total_latency DESC', + '(e.total_latency-IFNULL(s.total_latency, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'event_name'), + ('schema_index_statistics' , '(%{TABLE}.select_latency+%{TABLE}.insert_latency+%{TABLE}.update_latency+%{TABLE}.delete_latency) DESC', + '((e.select_latency+e.insert_latency+e.update_latency+e.delete_latency)-IFNULL(s.select_latency+s.insert_latency+s.update_latency+s.delete_latency, 0)) DESC', + '((e.rows_selected+e.insert_latency+e.rows_updated+e.rows_deleted)-IFNULL(s.rows_selected+s.rows_inserted+s.rows_updated+s.rows_deleted, 0)) > 0', + 100, 'table_schema,table_name,index_name'), + ('schema_table_statistics' , '%{TABLE}.total_latency DESC', + '(e.total_latency-IFNULL(s.total_latency, 0)) DESC', + '(e.total_latency-IFNULL(s.total_latency, 0)) > 0', 100, 'table_schema,table_name'), + ('schema_tables_with_full_table_scans', '%{TABLE}.rows_full_scanned DESC', + '(e.rows_full_scanned-IFNULL(s.rows_full_scanned, 0)) DESC', + '(e.rows_full_scanned-IFNULL(s.rows_full_scanned, 0)) > 0', 100, 'object_schema,object_name'), + ('user_summary' , '%{TABLE}.statement_latency DESC', + '(e.statement_latency-IFNULL(s.statement_latency, 0)) DESC', + '(e.statements - IFNULL(s.statements, 0)) > 0', NULL, 'user'), + ('user_summary_by_file_io' , '%{TABLE}.io_latency DESC', + '(e.io_latency-IFNULL(s.io_latency, 0)) DESC', + '(e.ios - IFNULL(s.ios, 0)) > 0', NULL, 'user'), + ('user_summary_by_file_io_type' , '%{TABLE}.user, %{TABLE}.latency DESC', + 'e.user, (e.latency-IFNULL(s.latency, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'user,event_name'), + ('user_summary_by_stages' , '%{TABLE}.user, %{TABLE}.total_latency DESC', + 'e.user, (e.total_latency-IFNULL(s.total_latency, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'user,event_name'), + ('user_summary_by_statement_latency' , '%{TABLE}.total_latency DESC', + '(e.total_latency-IFNULL(s.total_latency, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'user'), + ('user_summary_by_statement_type' , '%{TABLE}.user, %{TABLE}.total_latency DESC', + 'e.user, (e.total_latency-IFNULL(s.total_latency, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'user,statement'), + ('wait_classes_global_by_avg_latency' , 'IFNULL(%{TABLE}.total_latency / NULLIF(%{TABLE}.total, 0), 0) DESC', + 'IFNULL((e.total_latency-IFNULL(s.total_latency, 0)) / NULLIF((e.total - IFNULL(s.total, 0)), 0), 0) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'event_class'), + ('wait_classes_global_by_latency' , '%{TABLE}.total_latency DESC', + '(e.total_latency-IFNULL(s.total_latency, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'event_class'), + ('waits_by_host_by_latency' , '%{TABLE}.host, %{TABLE}.total_latency DESC', + 'e.host, (e.total_latency-IFNULL(s.total_latency, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'host,event'), + ('waits_by_user_by_latency' , '%{TABLE}.user, %{TABLE}.total_latency DESC', + 'e.user, (e.total_latency-IFNULL(s.total_latency, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'user,event'), + ('waits_global_by_latency' , '%{TABLE}.total_latency DESC', + '(e.total_latency-IFNULL(s.total_latency, 0)) DESC', + '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'events') + ; + END IF; + + + SELECT ' + +======================= + + Configuration + +======================= + +' AS ''; + -- Get the configuration. + SELECT 'GLOBAL VARIABLES' AS 'The following output is:'; + IF (v_has_ps_vars = 'YES') THEN + SELECT LOWER(VARIABLE_NAME) AS Variable_name, VARIABLE_VALUE AS Variable_value FROM performance_schema.global_variables ORDER BY VARIABLE_NAME; + ELSE + SELECT LOWER(VARIABLE_NAME) AS Variable_name, VARIABLE_VALUE AS Variable_value FROM information_schema.GLOBAL_VARIABLES ORDER BY VARIABLE_NAME; + END IF; + + IF (v_has_ps = 'YES') THEN + -- Overview of the Performance Schema dynamic settings used for this report. + SELECT 'Performance Schema Setup - Actors' AS 'The following output is:'; + SELECT * FROM performance_schema.setup_actors; + + SELECT 'Performance Schema Setup - Consumers' AS 'The following output is:'; + SELECT NAME AS Consumer, ENABLED, sys.ps_is_consumer_enabled(NAME) AS COLLECTS + FROM performance_schema.setup_consumers; + + SELECT 'Performance Schema Setup - Instruments' AS 'The following output is:'; + SELECT SUBSTRING_INDEX(NAME, '/', 2) AS 'InstrumentClass', + ROUND(100*SUM(IF(ENABLED = 'YES', 1, 0))/COUNT(*), 2) AS 'EnabledPct', + ROUND(100*SUM(IF(TIMED = 'YES', 1, 0))/COUNT(*), 2) AS 'TimedPct' + FROM performance_schema.setup_instruments + GROUP BY SUBSTRING_INDEX(NAME, '/', 2) + ORDER BY SUBSTRING_INDEX(NAME, '/', 2); + + SELECT 'Performance Schema Setup - Objects' AS 'The following output is:'; + SELECT * FROM performance_schema.setup_objects; + + SELECT 'Performance Schema Setup - Threads' AS 'The following output is:'; + SELECT `TYPE` AS ThreadType, COUNT(*) AS 'Total', ROUND(100*SUM(IF(INSTRUMENTED = 'YES', 1, 0))/COUNT(*), 2) AS 'InstrumentedPct' + FROM performance_schema.threads + GROUP BY TYPE; + END IF; + + + IF (v_has_replication = 'NO') THEN + SELECT 'No Replication Configured' AS 'Replication Status'; + ELSE + -- No guarantee that replication is actually configured, but we can't really know + SELECT CONCAT('Replication Configured: ', v_has_replication, ' - Performance Schema Replication Tables: ', v_has_ps_replication) AS 'Replication Status'; + + IF (v_has_ps_replication = 'YES') THEN + SELECT 'Replication - Connection Configuration' AS 'The following output is:'; + SELECT * FROM performance_schema.replication_connection_configuration/*!50706 ORDER BY CHANNEL_NAME*/; + END IF; + + IF (v_has_ps_replication = 'YES') THEN + SELECT 'Replication - Applier Configuration' AS 'The following output is:'; + SELECT * FROM performance_schema.replication_applier_configuration ORDER BY CHANNEL_NAME; + END IF; + END IF; + + + IF (v_has_ndb IN ('DEFAULT', 'YES')) THEN + SELECT 'Cluster Thread Blocks' AS 'The following output is:'; + SELECT * FROM ndbinfo.threadblocks; + END IF; + + -- For a number of sys views as well as events_statements_summary_by_digest, + -- just get the start data and then at the end output the overall and delta values + IF (v_has_ps = 'YES') THEN + IF (@sys.diagnostics.include_raw = 'ON') THEN + SELECT ' + +======================== + + Initial Status + +======================== + +' AS ''; + END IF; + + DROP TEMPORARY TABLE IF EXISTS tmp_digests_start; + CALL sys.statement_performance_analyzer('create_tmp', 'tmp_digests_start', NULL); + CALL sys.statement_performance_analyzer('snapshot', NULL, NULL); + CALL sys.statement_performance_analyzer('save', 'tmp_digests_start', NULL); + + -- Loop over the sys views where deltas should be calculated. + IF (@sys.diagnostics.include_raw = 'ON') THEN + SET @sys.diagnostics.sql = REPLACE(@sys.diagnostics.sql_gen_query_template, '%{OUTPUT}', 'start'); + IF (@sys.debug = 'ON') THEN + SELECT 'The following query will be used to generate the query for each sys view' AS 'Debug'; + SELECT @sys.diagnostics.sql AS 'Debug'; + END IF; + PREPARE stmt_gen_query FROM @sys.diagnostics.sql; + END IF; + SET v_done = FALSE; + OPEN c_sysviews_w_delta; + c_sysviews_w_delta_loop: LOOP + FETCH c_sysviews_w_delta INTO v_table_name; + IF v_done THEN + LEAVE c_sysviews_w_delta_loop; + END IF; + + IF (@sys.debug = 'ON') THEN + SELECT CONCAT('The following queries are for storing the initial content of ', v_table_name) AS 'Debug'; + END IF; + + CALL sys.execute_prepared_stmt(CONCAT('DROP TEMPORARY TABLE IF EXISTS `tmp_', v_table_name, '_start`')); + CALL sys.execute_prepared_stmt(CONCAT('CREATE TEMPORARY TABLE `tmp_', v_table_name, '_start` SELECT * FROM `sys`.`x$', v_table_name, '`')); + + IF (@sys.diagnostics.include_raw = 'ON') THEN + SET @sys.diagnostics.table_name = CONCAT('x$', v_table_name); + EXECUTE stmt_gen_query USING @sys.diagnostics.table_name; + -- If necessary add ORDER BY and LIMIT + SELECT CONCAT(@sys.diagnostics.sql_select, + IF(order_by IS NOT NULL, CONCAT('\n ORDER BY ', REPLACE(order_by, '%{TABLE}', CONCAT('tmp_', v_table_name, '_start'))), ''), + IF(limit_rows IS NOT NULL, CONCAT('\n LIMIT ', limit_rows), '') + ) + INTO @sys.diagnostics.sql_select + FROM tmp_sys_views_delta + WHERE TABLE_NAME = v_table_name; + SELECT CONCAT('Initial ', v_table_name) AS 'The following output is:'; + CALL sys.execute_prepared_stmt(@sys.diagnostics.sql_select); + END IF; + END LOOP; + CLOSE c_sysviews_w_delta; + + IF (@sys.diagnostics.include_raw = 'ON') THEN + DEALLOCATE PREPARE stmt_gen_query; + END IF; + END IF; + + -- If in_include_status_summary is TRUE then a temporary table is required to store the data + SET v_sql_status_summary_select = 'SELECT Variable_name', + v_sql_status_summary_delta = '', + v_sql_status_summary_from = ''; + + -- Start the loop + REPEAT + SET v_output_count = v_output_count + 1; + IF (v_output_count > 1) THEN + -- Don't sleep on the first execution + SET v_sleep = in_interval-(UNIX_TIMESTAMP(NOW(2))-v_iter_start); + SELECT NOW() AS 'Time', CONCAT('Going to sleep for ', v_sleep, ' seconds. Please do not interrupt') AS 'The following output is:'; + DO SLEEP(in_interval); + END IF; + SET v_iter_start = UNIX_TIMESTAMP(NOW(2)); + + SELECT NOW(), CONCAT('Iteration Number ', IFNULL(v_output_count, 'NULL')) AS 'The following output is:'; + + -- Even in 5.7 there is no way to get all the info from SHOW MASTER|SLAVE STATUS using the Performance Schema or + -- other tables, so include them even though they are no longer optimal solutions and if present get the additional + -- information from the other tables available. + IF (@@log_bin = 1) THEN + SELECT 'SHOW MASTER STATUS' AS 'The following output is:'; + SHOW MASTER STATUS; + END IF; + + IF (v_has_replication <> 'NO') THEN + SELECT 'SHOW SLAVE STATUS' AS 'The following output is:'; + SHOW SLAVE STATUS; + END IF; + + -- We need one table per output as a temporary table cannot be opened twice in the same query, and we need to + -- join the outputs in the summary at the end. + SET v_table_name = CONCAT('tmp_metrics_', v_output_count); + CALL sys.execute_prepared_stmt(CONCAT('DROP TEMPORARY TABLE IF EXISTS ', v_table_name)); + + -- Currently information_schema.GLOBAL_STATUS has VARIABLE_VALUE as varchar(1024) + CALL sys.execute_prepared_stmt(CONCAT('CREATE TEMPORARY TABLE ', v_table_name, ' ( + Variable_name VARCHAR(193) NOT NULL, + Variable_value VARCHAR(1024), + Type VARCHAR(100) NOT NULL, + Enabled ENUM(''YES'', ''NO'', ''PARTIAL'') NOT NULL, + PRIMARY KEY (Type, Variable_name) +) ENGINE = InnoDB DEFAULT CHARSET=utf8')); + + IF (v_has_metrics) THEN + SET @sys.diagnostics.sql = CONCAT( + 'INSERT INTO ', v_table_name, + ' SELECT Variable_name, REPLACE(Variable_value, ''\n'', ''\\\\n'') AS Variable_value, Type, Enabled FROM sys.metrics' + ); + ELSE + -- 5.7+ and the Performance Schema disabled. Use information_schema.GLOBAL_STATUS instead like in 5.6. + SET @sys.diagnostics.sql = CONCAT( + 'INSERT INTO ', v_table_name, + '(SELECT LOWER(VARIABLE_NAME) AS Variable_name, REPLACE(VARIABLE_VALUE, ''\n'', ''\\\\n'') AS Variable_value, + ''Global Status'' AS Type, ''YES'' AS Enabled + FROM performance_schema.global_status +) UNION ALL ( +SELECT NAME AS Variable_name, COUNT AS Variable_value, + CONCAT(''InnoDB Metrics - '', SUBSYSTEM) AS Type, + IF(STATUS = ''enabled'', ''YES'', ''NO'') AS Enabled + FROM information_schema.INNODB_METRICS + -- Deduplication - some variables exists both in GLOBAL_STATUS and INNODB_METRICS + -- Keep the one from GLOBAL_STATUS as it is always enabled and it''s more likely to be used for existing tools. + WHERE NAME NOT IN ( + ''lock_row_lock_time'', ''lock_row_lock_time_avg'', ''lock_row_lock_time_max'', ''lock_row_lock_waits'', + ''buffer_pool_reads'', ''buffer_pool_read_requests'', ''buffer_pool_write_requests'', ''buffer_pool_wait_free'', + ''buffer_pool_read_ahead'', ''buffer_pool_read_ahead_evicted'', ''buffer_pool_pages_total'', ''buffer_pool_pages_misc'', + ''buffer_pool_pages_data'', ''buffer_pool_bytes_data'', ''buffer_pool_pages_dirty'', ''buffer_pool_bytes_dirty'', + ''buffer_pool_pages_free'', ''buffer_pages_created'', ''buffer_pages_written'', ''buffer_pages_read'', + ''buffer_data_reads'', ''buffer_data_written'', ''file_num_open_files'', + ''os_log_bytes_written'', ''os_log_fsyncs'', ''os_log_pending_fsyncs'', ''os_log_pending_writes'', + ''log_waits'', ''log_write_requests'', ''log_writes'', ''innodb_dblwr_writes'', ''innodb_dblwr_pages_written'', ''innodb_page_size'') +) UNION ALL ( +SELECT ''NOW()'' AS Variable_name, NOW(3) AS Variable_value, ''System Time'' AS Type, ''YES'' AS Enabled +) UNION ALL ( +SELECT ''UNIX_TIMESTAMP()'' AS Variable_name, ROUND(UNIX_TIMESTAMP(NOW(3)), 3) AS Variable_value, ''System Time'' AS Type, ''YES'' AS Enabled +) + ORDER BY Type, Variable_name;' + ); + END IF; + CALL sys.execute_prepared_stmt(@sys.diagnostics.sql); + + -- Prepare the query to retrieve the summary + CALL sys.execute_prepared_stmt( + CONCAT('SELECT Variable_value INTO @sys.diagnostics.output_time FROM ', v_table_name, ' WHERE Type = ''System Time'' AND Variable_name = ''UNIX_TIMESTAMP()''') + ); + SET v_output_time = @sys.diagnostics.output_time; + + -- Limit each value to v_status_summary_width chars (when v_has_ndb = TRUE the values can be very wide - refer to the output here for the full values) + -- v_sql_status_summary_select, v_sql_status_summary_delta, v_sql_status_summary_from + SET v_sql_status_summary_select = CONCAT(v_sql_status_summary_select, ', + CONCAT( + LEFT(s', v_output_count, '.Variable_value, ', v_status_summary_width, '), + IF(', REPLACE(v_no_delta_names, '%{COUNT}', v_output_count), ' AND s', v_output_count, '.Variable_value REGEXP ''^[0-9]+(\\\\.[0-9]+)?$'', CONCAT('' ('', ROUND(s', v_output_count, '.Variable_value/', v_output_time, ', 2), ''/sec)''), '''') + ) AS ''Output ', v_output_count, ''''), + v_sql_status_summary_from = CONCAT(v_sql_status_summary_from, ' +', + IF(v_output_count = 1, ' FROM ', ' INNER JOIN '), + v_table_name, ' s', v_output_count, + IF (v_output_count = 1, '', ' USING (Type, Variable_name)')); + IF (v_output_count > 1) THEN + SET v_sql_status_summary_delta = CONCAT(v_sql_status_summary_delta, ', + IF(', REPLACE(v_no_delta_names, '%{COUNT}', v_output_count), ' AND s', (v_output_count-1), '.Variable_value REGEXP ''^[0-9]+(\\\\.[0-9]+)?$'' AND s', v_output_count, '.Variable_value REGEXP ''^[0-9]+(\\\\.[0-9]+)?$'', + CONCAT(IF(s', (v_output_count-1), '.Variable_value REGEXP ''^[0-9]+\\\\.[0-9]+$'' OR s', v_output_count, '.Variable_value REGEXP ''^[0-9]+\\\\.[0-9]+$'', + ROUND((s', v_output_count, '.Variable_value-s', (v_output_count-1), '.Variable_value), 2), + (s', v_output_count, '.Variable_value-s', (v_output_count-1), '.Variable_value) + ), + '' ('', ROUND((s', v_output_count, '.Variable_value-s', (v_output_count-1), '.Variable_value)/(', v_output_time, '-', v_output_time_prev, '), 2), ''/sec)'' + ), + '''' + ) AS ''Delta (', (v_output_count-1), ' -> ', v_output_count, ')'''); + END IF; + + SET v_output_time_prev = v_output_time; + + IF (@sys.diagnostics.include_raw = 'ON') THEN + IF (v_has_metrics) THEN + SELECT 'SELECT * FROM sys.metrics' AS 'The following output is:'; + ELSE + SELECT 'sys.metrics equivalent' AS 'The following output is:'; + END IF; + -- Ensures that the output here is the same as the one used in the status summary at the end + CALL sys.execute_prepared_stmt(CONCAT('SELECT Type, Variable_name, Enabled, Variable_value FROM ', v_table_name, ' ORDER BY Type, Variable_name')); + END IF; + + -- InnoDB + IF (v_has_innodb IN ('DEFAULT', 'YES')) THEN + SELECT 'SHOW ENGINE INNODB STATUS' AS 'The following output is:'; + EXECUTE stmt_innodb_status; + SELECT 'InnoDB - Transactions' AS 'The following output is:'; + SELECT * FROM information_schema.INNODB_TRX; + END IF; + + -- NDBCluster + IF (v_has_ndb IN ('DEFAULT', 'YES')) THEN + SELECT 'SHOW ENGINE NDBCLUSTER STATUS' AS 'The following output is:'; + EXECUTE stmt_ndbcluster_status; + + SELECT 'ndbinfo.memoryusage' AS 'The following output is:'; + SELECT node_id, memory_type, sys.format_bytes(used) AS used, used_pages, sys.format_bytes(total) AS total, total_pages, + ROUND(100*(used/total), 2) AS 'Used %' + FROM ndbinfo.memoryusage; + + -- Loop over the ndbinfo tables (except memoryusage which was handled separately above). + -- The exact tables available are version dependent, so get the list from the Information Schema. + SET v_done = FALSE; + OPEN c_ndbinfo; + c_ndbinfo_loop: LOOP + FETCH c_ndbinfo INTO v_table_name; + IF v_done THEN + LEAVE c_ndbinfo_loop; + END IF; + + SELECT CONCAT('SELECT * FROM ndbinfo.', v_table_name) AS 'The following output is:'; + CALL sys.execute_prepared_stmt(CONCAT('SELECT * FROM `ndbinfo`.`', v_table_name, '`')); + END LOOP; + CLOSE c_ndbinfo; + + SELECT * FROM information_schema.FILES; + END IF; + + SELECT 'SELECT * FROM sys.processlist' AS 'The following output is:'; + SELECT processlist.* FROM sys.processlist; + + IF (v_has_ps = 'YES') THEN + -- latest_file_io + IF (sys.ps_is_consumer_enabled('events_waits_history_long') = 'YES') THEN + SELECT 'SELECT * FROM sys.latest_file_io' AS 'The following output is:'; + SELECT * FROM sys.latest_file_io; + END IF; + + -- current memory usage + IF (EXISTS(SELECT 1 FROM performance_schema.setup_instruments WHERE NAME LIKE 'memory/%' AND ENABLED = 'YES')) THEN + SELECT 'SELECT * FROM sys.memory_by_host_by_current_bytes' AS 'The following output is:'; + SELECT * FROM sys.memory_by_host_by_current_bytes; + + SELECT 'SELECT * FROM sys.memory_by_thread_by_current_bytes' AS 'The following output is:'; + SELECT * FROM sys.memory_by_thread_by_current_bytes; + + SELECT 'SELECT * FROM sys.memory_by_user_by_current_bytes' AS 'The following output is:'; + SELECT * FROM sys.memory_by_user_by_current_bytes; + + SELECT 'SELECT * FROM sys.memory_global_by_current_bytes' AS 'The following output is:'; + SELECT * FROM sys.memory_global_by_current_bytes; + END IF; + END IF; + + SET v_runtime = (UNIX_TIMESTAMP(NOW(2)) - v_start); + UNTIL (v_runtime + in_interval >= in_max_runtime) END REPEAT; + + -- Get Performance Schema status + IF (v_has_ps = 'YES') THEN + SELECT 'SHOW ENGINE PERFORMANCE_SCHEMA STATUS' AS 'The following output is:'; + EXECUTE stmt_ps_status; + END IF; + + -- Deallocate prepared statements + IF (v_has_innodb IN ('DEFAULT', 'YES')) THEN + DEALLOCATE PREPARE stmt_innodb_status; + END IF; + IF (v_has_ps = 'YES') THEN + DEALLOCATE PREPARE stmt_ps_status; + END IF; + IF (v_has_ndb IN ('DEFAULT', 'YES')) THEN + DEALLOCATE PREPARE stmt_ndbcluster_status; + END IF; + + + SELECT ' + +============================ + + Schema Information + +============================ + +' AS ''; + + SELECT COUNT(*) AS 'Total Number of Tables' FROM information_schema.TABLES; + + -- The cost of information_schema.TABLES.DATA_LENGTH depends mostly on the number of tables + IF (@sys.diagnostics.allow_i_s_tables = 'ON') THEN + SELECT 'Storage Engine Usage' AS 'The following output is:'; + SELECT ENGINE, COUNT(*) AS NUM_TABLES, + sys.format_bytes(SUM(DATA_LENGTH)) AS DATA_LENGTH, + sys.format_bytes(SUM(INDEX_LENGTH)) AS INDEX_LENGTH, + sys.format_bytes(SUM(DATA_LENGTH+INDEX_LENGTH)) AS TOTAL + FROM information_schema.TABLES + GROUP BY ENGINE; + + SELECT 'Schema Object Overview' AS 'The following output is:'; + SELECT * FROM sys.schema_object_overview; + + SELECT 'Tables without a PRIMARY KEY' AS 'The following output is:'; + SELECT TABLES.TABLE_SCHEMA, ENGINE, COUNT(*) AS NumTables + FROM information_schema.TABLES + LEFT OUTER JOIN information_schema.STATISTICS ON STATISTICS.TABLE_SCHEMA = TABLES.TABLE_SCHEMA + AND STATISTICS.TABLE_NAME = TABLES.TABLE_NAME + AND STATISTICS.INDEX_NAME = 'PRIMARY' + WHERE STATISTICS.TABLE_NAME IS NULL + AND TABLES.TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys') + AND TABLES.TABLE_TYPE = 'BASE TABLE' + GROUP BY TABLES.TABLE_SCHEMA, ENGINE; + END IF; + + IF (v_has_ps = 'YES') THEN + SELECT 'Unused Indexes' AS 'The following output is:'; + SELECT object_schema, COUNT(*) AS NumUnusedIndexes + FROM performance_schema.table_io_waits_summary_by_index_usage + WHERE index_name IS NOT NULL + AND count_star = 0 + AND object_schema NOT IN ('mysql', 'sys') + AND index_name != 'PRIMARY' + GROUP BY object_schema; + END IF; + + IF (v_has_ps = 'YES') THEN + SELECT ' + +========================= + + Overall Status + +========================= + +' AS ''; + + SELECT 'CALL sys.ps_statement_avg_latency_histogram()' AS 'The following output is:'; + CALL sys.ps_statement_avg_latency_histogram(); + + CALL sys.statement_performance_analyzer('snapshot', NULL, NULL); + CALL sys.statement_performance_analyzer('overall', NULL, 'with_runtimes_in_95th_percentile'); + + SET @sys.diagnostics.sql = REPLACE(@sys.diagnostics.sql_gen_query_template, '%{OUTPUT}', 'end'); + IF (@sys.debug = 'ON') THEN + SELECT 'The following query will be used to generate the query for each sys view' AS 'Debug'; + SELECT @sys.diagnostics.sql AS 'Debug'; + END IF; + PREPARE stmt_gen_query FROM @sys.diagnostics.sql; + + SET v_done = FALSE; + OPEN c_sysviews_w_delta; + c_sysviews_w_delta_loop: LOOP + FETCH c_sysviews_w_delta INTO v_table_name; + IF v_done THEN + LEAVE c_sysviews_w_delta_loop; + END IF; + + IF (@sys.debug = 'ON') THEN + SELECT CONCAT('The following queries are for storing the final content of ', v_table_name) AS 'Debug'; + END IF; + + CALL sys.execute_prepared_stmt(CONCAT('DROP TEMPORARY TABLE IF EXISTS `tmp_', v_table_name, '_end`')); + CALL sys.execute_prepared_stmt(CONCAT('CREATE TEMPORARY TABLE `tmp_', v_table_name, '_end` SELECT * FROM `sys`.`x$', v_table_name, '`')); + + IF (@sys.diagnostics.include_raw = 'ON') THEN + SET @sys.diagnostics.table_name = CONCAT('x$', v_table_name); + EXECUTE stmt_gen_query USING @sys.diagnostics.table_name; + -- If necessary add ORDER BY and LIMIT + SELECT CONCAT(@sys.diagnostics.sql_select, + IF(order_by IS NOT NULL, CONCAT('\n ORDER BY ', REPLACE(order_by, '%{TABLE}', CONCAT('tmp_', v_table_name, '_end'))), ''), + IF(limit_rows IS NOT NULL, CONCAT('\n LIMIT ', limit_rows), '') + ) + INTO @sys.diagnostics.sql_select + FROM tmp_sys_views_delta + WHERE TABLE_NAME = v_table_name; + SELECT CONCAT('Overall ', v_table_name) AS 'The following output is:'; + CALL sys.execute_prepared_stmt(@sys.diagnostics.sql_select); + END IF; + END LOOP; + CLOSE c_sysviews_w_delta; + + DEALLOCATE PREPARE stmt_gen_query; + + + SELECT ' + +====================== + + Delta Status + +====================== + +' AS ''; + + CALL sys.statement_performance_analyzer('delta', 'tmp_digests_start', 'with_runtimes_in_95th_percentile'); + CALL sys.statement_performance_analyzer('cleanup', NULL, NULL); + + DROP TEMPORARY TABLE tmp_digests_start; + + -- @sys.diagnostics.sql_gen_query_delta is defined near the to together with @sys.diagnostics.sql_gen_query_template + IF (@sys.debug = 'ON') THEN + SELECT 'The following query will be used to generate the query for each sys view delta' AS 'Debug'; + SELECT @sys.diagnostics.sql_gen_query_delta AS 'Debug'; + END IF; + PREPARE stmt_gen_query_delta FROM @sys.diagnostics.sql_gen_query_delta; + + SET v_old_group_concat_max_len = @@session.group_concat_max_len; + SET @@session.group_concat_max_len = 2048; + SET v_done = FALSE; + OPEN c_sysviews_w_delta; + c_sysviews_w_delta_loop: LOOP + FETCH c_sysviews_w_delta INTO v_table_name; + IF v_done THEN + LEAVE c_sysviews_w_delta_loop; + END IF; + + SET @sys.diagnostics.table_name = v_table_name; + EXECUTE stmt_gen_query_delta USING @sys.diagnostics.table_name; + -- If necessary add WHERE, ORDER BY, and LIMIT + SELECT CONCAT(@sys.diagnostics.sql_select, + IF(where_delta IS NOT NULL, CONCAT('\n WHERE ', where_delta), ''), + IF(order_by_delta IS NOT NULL, CONCAT('\n ORDER BY ', order_by_delta), ''), + IF(limit_rows IS NOT NULL, CONCAT('\n LIMIT ', limit_rows), '') + ) + INTO @sys.diagnostics.sql_select + FROM tmp_sys_views_delta + WHERE TABLE_NAME = v_table_name; + + SELECT CONCAT('Delta ', v_table_name) AS 'The following output is:'; + CALL sys.execute_prepared_stmt(@sys.diagnostics.sql_select); + + CALL sys.execute_prepared_stmt(CONCAT('DROP TEMPORARY TABLE `tmp_', v_table_name, '_end`')); + CALL sys.execute_prepared_stmt(CONCAT('DROP TEMPORARY TABLE `tmp_', v_table_name, '_start`')); + END LOOP; + CLOSE c_sysviews_w_delta; + SET @@session.group_concat_max_len = v_old_group_concat_max_len; + + DEALLOCATE PREPARE stmt_gen_query_delta; + DROP TEMPORARY TABLE tmp_sys_views_delta; + END IF; + + IF (v_has_metrics) THEN + SELECT 'SELECT * FROM sys.metrics' AS 'The following output is:'; + ELSE + SELECT 'sys.metrics equivalent' AS 'The following output is:'; + END IF; + CALL sys.execute_prepared_stmt( + CONCAT(v_sql_status_summary_select, v_sql_status_summary_delta, ', Type, s1.Enabled', v_sql_status_summary_from, + ' + ORDER BY Type, Variable_name' + ) + ); + + -- Remove all the metrics temporary tables again + SET v_count = 0; + WHILE (v_count < v_output_count) DO + SET v_count = v_count + 1; + SET v_table_name = CONCAT('tmp_metrics_', v_count); + CALL sys.execute_prepared_stmt(CONCAT('DROP TEMPORARY TABLE IF EXISTS ', v_table_name)); + END WHILE; + + IF (in_auto_config <> 'current') THEN + CALL sys.ps_setup_reload_saved(); + SET sql_log_bin = @log_bin; + END IF; + + -- Reset the @sys.diagnostics.% user variables internal to this procedure + SET @sys.diagnostics.output_time = NULL, + @sys.diagnostics.sql = NULL, + @sys.diagnostics.sql_gen_query_delta = NULL, + @sys.diagnostics.sql_gen_query_template = NULL, + @sys.diagnostics.sql_select = NULL, + @sys.diagnostics.table_name = NULL; + + -- Restore INSTRUMENTED for this thread + IF (v_this_thread_enabled = 'YES') THEN + CALL sys.ps_setup_enable_thread(CONNECTION_ID()); + END IF; + + IF (@log_bin = 1) THEN + SET sql_log_bin = @log_bin; + END IF; +END$$ + +DELIMITER ;
\ No newline at end of file diff --git a/scripts/sys_schema/procedures/execute_prepared_stmt.sql b/scripts/sys_schema/procedures/execute_prepared_stmt.sql new file mode 100644 index 00000000..8e975b90 --- /dev/null +++ b/scripts/sys_schema/procedures/execute_prepared_stmt.sql @@ -0,0 +1,89 @@ +-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS execute_prepared_stmt; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE execute_prepared_stmt ( + IN in_query longtext CHARACTER SET UTF8 + ) + COMMENT ' + Description + ----------- + + Takes the query in the argument and executes it using a prepared statement. The prepared statement is deallocated, + so the procedure is mainly useful for executing one off dynamically created queries. + + The sys_execute_prepared_stmt prepared statement name is used for the query and is required not to exist. + + + Parameters + ----------- + + in_query (longtext CHARACTER SET UTF8): + The query to execute. + + + Configuration Options + ---------------------- + + sys.debug + Whether to provide debugging output. + Default is ''OFF''. Set to ''ON'' to include. + + + Example + -------- + + mysql> CALL sys.execute_prepared_stmt(''SELECT * FROM sys.sys_config''); + +------------------------+-------+---------------------+--------+ + | variable | value | set_time | set_by | + +------------------------+-------+---------------------+--------+ + | statement_truncate_len | 64 | 2015-06-30 13:06:00 | NULL | + +------------------------+-------+---------------------+--------+ + 1 row in set (0.00 sec) + + Query OK, 0 rows affected (0.00 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + READS SQL DATA +BEGIN + -- Set configuration options + IF (@sys.debug IS NULL) THEN + SET @sys.debug = sys.sys_get_config('debug', 'OFF'); + END IF; + + -- Verify the query exists + -- The shortest possible query is "DO 1" + IF (in_query IS NULL OR LENGTH(in_query) < 4) THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = "The @sys.execute_prepared_stmt.sql must contain a query"; + END IF; + + SET @sys.execute_prepared_stmt.sql = in_query; + + IF (@sys.debug = 'ON') THEN + SELECT @sys.execute_prepared_stmt.sql AS 'Debug'; + END IF; + PREPARE sys_execute_prepared_stmt FROM @sys.execute_prepared_stmt.sql; + EXECUTE sys_execute_prepared_stmt; + DEALLOCATE PREPARE sys_execute_prepared_stmt; + + SET @sys.execute_prepared_stmt.sql = NULL; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_disable_background_threads.sql b/scripts/sys_schema/procedures/ps_setup_disable_background_threads.sql new file mode 100644 index 00000000..0c316bc7 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_disable_background_threads.sql @@ -0,0 +1,54 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_disable_background_threads; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_disable_background_threads () + COMMENT ' + Description + ----------- + + Disable all background thread instrumentation within Performance Schema. + + Parameters + ----------- + + None. + + Example + ----------- + + mysql> CALL sys.ps_setup_disable_background_threads(); + +--------------------------------+ + | summary | + +--------------------------------+ + | Disabled 18 background threads | + +--------------------------------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + UPDATE performance_schema.threads + SET instrumented = 'NO' + WHERE type = 'BACKGROUND'; + + SELECT CONCAT('Disabled ', @rows := ROW_COUNT(), ' background thread', IF(@rows != 1, 's', '')) AS summary; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_disable_consumer.sql b/scripts/sys_schema/procedures/ps_setup_disable_consumer.sql new file mode 100644 index 00000000..bdebd62e --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_disable_consumer.sql @@ -0,0 +1,70 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_disable_consumer; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_disable_consumer ( + IN consumer VARCHAR(128) + ) + COMMENT ' + Description + ----------- + + Disables consumers within Performance Schema + matching the input pattern. + + Parameters + ----------- + + consumer (VARCHAR(128)): + A LIKE pattern match (using "%consumer%") of consumers to disable + + Example + ----------- + + To disable all consumers: + + mysql> CALL sys.ps_setup_disable_consumer(\'\'); + +--------------------------+ + | summary | + +--------------------------+ + | Disabled 15 consumers | + +--------------------------+ + 1 row in set (0.02 sec) + + To disable just the event_stage consumers: + + mysql> CALL sys.ps_setup_disable_comsumers(\'stage\'); + +------------------------+ + | summary | + +------------------------+ + | Disabled 3 consumers | + +------------------------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + UPDATE performance_schema.setup_consumers + SET enabled = 'NO' + WHERE name LIKE CONCAT('%', consumer, '%'); + + SELECT CONCAT('Disabled ', @rows := ROW_COUNT(), ' consumer', IF(@rows != 1, 's', '')) AS summary; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_disable_instrument.sql b/scripts/sys_schema/procedures/ps_setup_disable_instrument.sql new file mode 100644 index 00000000..14fe4d86 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_disable_instrument.sql @@ -0,0 +1,80 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_disable_instrument; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_disable_instrument ( + IN in_pattern VARCHAR(128) + ) + COMMENT ' + Description + ----------- + + Disables instruments within Performance Schema + matching the input pattern. + + Parameters + ----------- + + in_pattern (VARCHAR(128)): + A LIKE pattern match (using "%in_pattern%") of events to disable + + Example + ----------- + + To disable all mutex instruments: + + mysql> CALL sys.ps_setup_disable_instrument(\'wait/synch/mutex\'); + +--------------------------+ + | summary | + +--------------------------+ + | Disabled 155 instruments | + +--------------------------+ + 1 row in set (0.02 sec) + + To disable just a specific TCP/IP based network IO instrument: + + mysql> CALL sys.ps_setup_disable_instrument(\'wait/io/socket/sql/server_tcpip_socket\'); + +------------------------+ + | summary | + +------------------------+ + | Disabled 1 instruments | + +------------------------+ + 1 row in set (0.00 sec) + + To disable all instruments: + + mysql> CALL sys.ps_setup_disable_instrument(\'\'); + +--------------------------+ + | summary | + +--------------------------+ + | Disabled 547 instruments | + +--------------------------+ + 1 row in set (0.01 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + UPDATE performance_schema.setup_instruments + SET enabled = 'NO', timed = 'NO' + WHERE name LIKE CONCAT('%', in_pattern, '%'); + + SELECT CONCAT('Disabled ', @rows := ROW_COUNT(), ' instrument', IF(@rows != 1, 's', '')) AS summary; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_disable_thread.sql b/scripts/sys_schema/procedures/ps_setup_disable_thread.sql new file mode 100644 index 00000000..fe0bb862 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_disable_thread.sql @@ -0,0 +1,68 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_disable_thread; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_disable_thread ( + IN in_connection_id BIGINT + ) + COMMENT ' + Description + ----------- + + Disable the given connection/thread in Performance Schema. + + Parameters + ----------- + + in_connection_id (BIGINT): + The connection ID (PROCESSLIST_ID from performance_schema.threads + or the ID shown within SHOW PROCESSLIST) + + Example + ----------- + + mysql> CALL sys.ps_setup_disable_thread(3); + +-------------------+ + | summary | + +-------------------+ + | Disabled 1 thread | + +-------------------+ + 1 row in set (0.01 sec) + + To disable the current connection: + + mysql> CALL sys.ps_setup_disable_thread(CONNECTION_ID()); + +-------------------+ + | summary | + +-------------------+ + | Disabled 1 thread | + +-------------------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + UPDATE performance_schema.threads + SET instrumented = 'NO' + WHERE processlist_id = in_connection_id; + + SELECT CONCAT('Disabled ', @rows := ROW_COUNT(), ' thread', IF(@rows != 1, 's', '')) AS summary; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_enable_background_threads.sql b/scripts/sys_schema/procedures/ps_setup_enable_background_threads.sql new file mode 100644 index 00000000..ddca06b1 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_enable_background_threads.sql @@ -0,0 +1,54 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_enable_background_threads; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_enable_background_threads () + COMMENT ' + Description + ----------- + + Enable all background thread instrumentation within Performance Schema. + + Parameters + ----------- + + None. + + Example + ----------- + + mysql> CALL sys.ps_setup_enable_background_threads(); + +-------------------------------+ + | summary | + +-------------------------------+ + | Enabled 18 background threads | + +-------------------------------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + UPDATE performance_schema.threads + SET instrumented = 'YES' + WHERE type = 'BACKGROUND'; + + SELECT CONCAT('Enabled ', @rows := ROW_COUNT(), ' background thread', IF(@rows != 1, 's', '')) AS summary; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_enable_consumer.sql b/scripts/sys_schema/procedures/ps_setup_enable_consumer.sql new file mode 100644 index 00000000..66138604 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_enable_consumer.sql @@ -0,0 +1,74 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_enable_consumer; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_enable_consumer ( + IN consumer VARCHAR(128) + ) + COMMENT ' + Description + ----------- + + Enables consumers within Performance Schema + matching the input pattern. + + Parameters + ----------- + + consumer (VARCHAR(128)): + A LIKE pattern match (using "%consumer%") of consumers to enable + + Example + ----------- + + To enable all consumers: + + mysql> CALL sys.ps_setup_enable_consumer(\'\'); + +-------------------------+ + | summary | + +-------------------------+ + | Enabled 10 consumers | + +-------------------------+ + 1 row in set (0.02 sec) + + Query OK, 0 rows affected (0.02 sec) + + To enable just "waits" consumers: + + mysql> CALL sys.ps_setup_enable_consumer(\'waits\'); + +-----------------------+ + | summary | + +-----------------------+ + | Enabled 3 consumers | + +-----------------------+ + 1 row in set (0.00 sec) + + Query OK, 0 rows affected (0.00 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + UPDATE performance_schema.setup_consumers + SET enabled = 'YES' + WHERE name LIKE CONCAT('%', consumer, '%'); + + SELECT CONCAT('Enabled ', @rows := ROW_COUNT(), ' consumer', IF(@rows != 1, 's', '')) AS summary; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_enable_instrument.sql b/scripts/sys_schema/procedures/ps_setup_enable_instrument.sql new file mode 100644 index 00000000..964307de --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_enable_instrument.sql @@ -0,0 +1,86 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_enable_instrument; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_enable_instrument ( + IN in_pattern VARCHAR(128) + ) + COMMENT ' + Description + ----------- + + Enables instruments within Performance Schema + matching the input pattern. + + Parameters + ----------- + + in_pattern (VARCHAR(128)): + A LIKE pattern match (using "%in_pattern%") of events to enable + + Example + ----------- + + To enable all mutex instruments: + + mysql> CALL sys.ps_setup_enable_instrument(\'wait/synch/mutex\'); + +-------------------------+ + | summary | + +-------------------------+ + | Enabled 155 instruments | + +-------------------------+ + 1 row in set (0.02 sec) + + Query OK, 0 rows affected (0.02 sec) + + To enable just a specific TCP/IP based network IO instrument: + + mysql> CALL sys.ps_setup_enable_instrument(\'wait/io/socket/sql/server_tcpip_socket\'); + +-----------------------+ + | summary | + +-----------------------+ + | Enabled 1 instruments | + +-----------------------+ + 1 row in set (0.00 sec) + + Query OK, 0 rows affected (0.00 sec) + + To enable all instruments: + + mysql> CALL sys.ps_setup_enable_instrument(\'\'); + +-------------------------+ + | summary | + +-------------------------+ + | Enabled 547 instruments | + +-------------------------+ + 1 row in set (0.01 sec) + + Query OK, 0 rows affected (0.01 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + UPDATE performance_schema.setup_instruments + SET enabled = 'YES', timed = 'YES' + WHERE name LIKE CONCAT('%', in_pattern, '%'); + + SELECT CONCAT('Enabled ', @rows := ROW_COUNT(), ' instrument', IF(@rows != 1, 's', '')) AS summary; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_enable_thread.sql b/scripts/sys_schema/procedures/ps_setup_enable_thread.sql new file mode 100644 index 00000000..15385fc8 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_enable_thread.sql @@ -0,0 +1,68 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_enable_thread; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_enable_thread ( + IN in_connection_id BIGINT + ) + COMMENT ' + Description + ----------- + + Enable the given connection/thread in Performance Schema. + + Parameters + ----------- + + in_connection_id (BIGINT): + The connection ID (PROCESSLIST_ID from performance_schema.threads + or the ID shown within SHOW PROCESSLIST) + + Example + ----------- + + mysql> CALL sys.ps_setup_enable_thread(3); + +------------------+ + | summary | + +------------------+ + | Enabled 1 thread | + +------------------+ + 1 row in set (0.01 sec) + + To enable the current connection: + + mysql> CALL sys.ps_setup_enable_thread(CONNECTION_ID()); + +------------------+ + | summary | + +------------------+ + | Enabled 1 thread | + +------------------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + UPDATE performance_schema.threads + SET instrumented = 'YES' + WHERE processlist_id = in_connection_id; + + SELECT CONCAT('Enabled ', @rows := ROW_COUNT(), ' thread', IF(@rows != 1, 's', '')) AS summary; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_reload_saved.sql b/scripts/sys_schema/procedures/ps_setup_reload_saved.sql new file mode 100644 index 00000000..38d463b1 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_reload_saved.sql @@ -0,0 +1,146 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_reload_saved; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_reload_saved () + COMMENT ' + Description + ----------- + + Reloads a saved Performance Schema configuration, + so that you can alter the setup for debugging purposes, + but restore it to a previous state. + + Use the companion procedure - ps_setup_save(), to + save a configuration. + + Requires the SUPER privilege for "SET sql_log_bin = 0;". + + Parameters + ----------- + + None. + + Example + ----------- + + mysql> CALL sys.ps_setup_save(); + Query OK, 0 rows affected (0.08 sec) + + mysql> UPDATE performance_schema.setup_instruments SET enabled = \'YES\', timed = \'YES\'; + Query OK, 547 rows affected (0.40 sec) + Rows matched: 784 Changed: 547 Warnings: 0 + + /* Run some tests that need more detailed instrumentation here */ + + mysql> CALL sys.ps_setup_reload_saved(); + Query OK, 0 rows affected (0.32 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + DECLARE v_done bool DEFAULT FALSE; + DECLARE v_lock_result INT; + DECLARE v_lock_used_by BIGINT; + DECLARE v_signal_message TEXT; + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + SIGNAL SQLSTATE VALUE '90001' + SET MESSAGE_TEXT = 'An error occurred, was sys.ps_setup_save() run before this procedure?'; + END; + + SET @log_bin := @@sql_log_bin; + SET sql_log_bin = 0; + + SELECT IS_USED_LOCK('sys.ps_setup_save') INTO v_lock_used_by; + + IF (v_lock_used_by != CONNECTION_ID()) THEN + SET v_signal_message = CONCAT('The sys.ps_setup_save lock is currently owned by ', v_lock_used_by); + SIGNAL SQLSTATE VALUE '90002' + SET MESSAGE_TEXT = v_signal_message; + END IF; + + DELETE FROM performance_schema.setup_actors; + INSERT INTO performance_schema.setup_actors SELECT * FROM tmp_setup_actors; + + BEGIN + -- Workaround for http://bugs.mysql.com/bug.php?id=70025 + DECLARE v_name varchar(64); + DECLARE v_enabled enum('YES', 'NO'); + DECLARE c_consumers CURSOR FOR SELECT NAME, ENABLED FROM tmp_setup_consumers; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE; + + SET v_done = FALSE; + OPEN c_consumers; + c_consumers_loop: LOOP + FETCH c_consumers INTO v_name, v_enabled; + IF v_done THEN + LEAVE c_consumers_loop; + END IF; + + UPDATE performance_schema.setup_consumers + SET ENABLED = v_enabled + WHERE NAME = v_name; + END LOOP; + CLOSE c_consumers; + END; + + UPDATE performance_schema.setup_instruments + INNER JOIN tmp_setup_instruments USING (NAME) + SET performance_schema.setup_instruments.ENABLED = tmp_setup_instruments.ENABLED, + performance_schema.setup_instruments.TIMED = tmp_setup_instruments.TIMED; + BEGIN + -- Workaround for http://bugs.mysql.com/bug.php?id=70025 + DECLARE v_thread_id bigint unsigned; + DECLARE v_instrumented enum('YES', 'NO'); + DECLARE c_threads CURSOR FOR SELECT THREAD_ID, INSTRUMENTED FROM tmp_threads; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE; + + SET v_done = FALSE; + OPEN c_threads; + c_threads_loop: LOOP + FETCH c_threads INTO v_thread_id, v_instrumented; + IF v_done THEN + LEAVE c_threads_loop; + END IF; + + UPDATE performance_schema.threads + SET INSTRUMENTED = v_instrumented + WHERE THREAD_ID = v_thread_id; + END LOOP; + CLOSE c_threads; + END; + + UPDATE performance_schema.threads + SET INSTRUMENTED = IF(PROCESSLIST_USER IS NOT NULL, + sys.ps_is_account_enabled(PROCESSLIST_HOST, PROCESSLIST_USER), + 'YES') + WHERE THREAD_ID NOT IN (SELECT THREAD_ID FROM tmp_threads); + + DROP TEMPORARY TABLE tmp_setup_actors; + DROP TEMPORARY TABLE tmp_setup_consumers; + DROP TEMPORARY TABLE tmp_setup_instruments; + DROP TEMPORARY TABLE tmp_threads; + + SELECT RELEASE_LOCK('sys.ps_setup_save') INTO v_lock_result; + + SET sql_log_bin = @log_bin; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_reset_to_default.sql b/scripts/sys_schema/procedures/ps_setup_reset_to_default.sql new file mode 100644 index 00000000..b626fae8 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_reset_to_default.sql @@ -0,0 +1,148 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_reset_to_default; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_reset_to_default ( + IN in_verbose BOOLEAN + ) + COMMENT ' + Description + ----------- + + Resets the Performance Schema setup to the default settings. + + Parameters + ----------- + + in_verbose (BOOLEAN): + Whether to print each setup stage (including the SQL) whilst running. + + Example + ----------- + + mysql> CALL sys.ps_setup_reset_to_default(true)\\G + *************************** 1. row *************************** + status: Resetting: setup_actors + DELETE + FROM performance_schema.setup_actors + WHERE NOT (HOST = \'%\' AND USER = \'%\' AND ROLE = \'%\') + 1 row in set (0.00 sec) + + *************************** 1. row *************************** + status: Resetting: setup_actors + INSERT IGNORE INTO performance_schema.setup_actors + VALUES (\'%\', \'%\', \'%\') + 1 row in set (0.00 sec) + ... + + mysql> CALL sys.ps_setup_reset_to_default(false)\\G + Query OK, 0 rows affected (0.00 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + SET @query = 'DELETE + FROM performance_schema.setup_actors + WHERE NOT (HOST = ''%'' AND USER = ''%'' AND ROLE = ''%'')'; + + IF (in_verbose) THEN + SELECT CONCAT('Resetting: setup_actors\n', REPLACE(@query, ' ', '')) AS status; + END IF; + + PREPARE reset_stmt FROM @query; + EXECUTE reset_stmt; + DEALLOCATE PREPARE reset_stmt; + + SET @query = 'INSERT IGNORE INTO performance_schema.setup_actors + VALUES (''%'', ''%'', ''%'')'; + + IF (in_verbose) THEN + SELECT CONCAT('Resetting: setup_actors\n', REPLACE(@query, ' ', '')) AS status; + END IF; + + PREPARE reset_stmt FROM @query; + EXECUTE reset_stmt; + DEALLOCATE PREPARE reset_stmt; + + SET @query = 'UPDATE performance_schema.setup_instruments + SET ENABLED = sys.ps_is_instrument_default_enabled(NAME), + TIMED = sys.ps_is_instrument_default_timed(NAME)'; + + IF (in_verbose) THEN + SELECT CONCAT('Resetting: setup_instruments\n', REPLACE(@query, ' ', '')) AS status; + END IF; + + PREPARE reset_stmt FROM @query; + EXECUTE reset_stmt; + DEALLOCATE PREPARE reset_stmt; + + SET @query = 'UPDATE performance_schema.setup_consumers + SET ENABLED = IF(NAME IN (''events_statements_current'', ''global_instrumentation'', ''thread_instrumentation'', ''statements_digest''), ''YES'', ''NO'')'; + + IF (in_verbose) THEN + SELECT CONCAT('Resetting: setup_consumers\n', REPLACE(@query, ' ', '')) AS status; + END IF; + + PREPARE reset_stmt FROM @query; + EXECUTE reset_stmt; + DEALLOCATE PREPARE reset_stmt; + + SET @query = 'DELETE + FROM performance_schema.setup_objects + WHERE NOT (OBJECT_TYPE = ''TABLE'' AND OBJECT_NAME = ''%'' + AND (OBJECT_SCHEMA = ''mysql'' AND ENABLED = ''NO'' AND TIMED = ''NO'' ) + OR (OBJECT_SCHEMA = ''performance_schema'' AND ENABLED = ''NO'' AND TIMED = ''NO'' ) + OR (OBJECT_SCHEMA = ''information_schema'' AND ENABLED = ''NO'' AND TIMED = ''NO'' ) + OR (OBJECT_SCHEMA = ''%'' AND ENABLED = ''YES'' AND TIMED = ''YES''))'; + + IF (in_verbose) THEN + SELECT CONCAT('Resetting: setup_objects\n', REPLACE(@query, ' ', '')) AS status; + END IF; + + PREPARE reset_stmt FROM @query; + EXECUTE reset_stmt; + DEALLOCATE PREPARE reset_stmt; + + SET @query = 'INSERT IGNORE INTO performance_schema.setup_objects + VALUES (''TABLE'', ''mysql'' , ''%'', ''NO'' , ''NO'' ), + (''TABLE'', ''performance_schema'', ''%'', ''NO'' , ''NO'' ), + (''TABLE'', ''information_schema'', ''%'', ''NO'' , ''NO'' ), + (''TABLE'', ''%'' , ''%'', ''YES'', ''YES'')'; + + IF (in_verbose) THEN + SELECT CONCAT('Resetting: setup_objects\n', REPLACE(@query, ' ', '')) AS status; + END IF; + + PREPARE reset_stmt FROM @query; + EXECUTE reset_stmt; + DEALLOCATE PREPARE reset_stmt; + + SET @query = 'UPDATE performance_schema.threads + SET INSTRUMENTED = ''YES'''; + + IF (in_verbose) THEN + SELECT CONCAT('Resetting: threads\n', REPLACE(@query, ' ', '')) AS status; + END IF; + + PREPARE reset_stmt FROM @query; + EXECUTE reset_stmt; + DEALLOCATE PREPARE reset_stmt; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_reset_to_default_57.sql b/scripts/sys_schema/procedures/ps_setup_reset_to_default_57.sql new file mode 100644 index 00000000..9f2ea468 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_reset_to_default_57.sql @@ -0,0 +1,165 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_reset_to_default; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_reset_to_default ( + IN in_verbose BOOLEAN + ) + COMMENT ' + Description + ----------- + + Resets the Performance Schema setup to the default settings. + + Parameters + ----------- + + in_verbose (BOOLEAN): + Whether to print each setup stage (including the SQL) whilst running. + + Example + ----------- + + mysql> CALL sys.ps_setup_reset_to_default(true)\\G + *************************** 1. row *************************** + status: Resetting: setup_actors + DELETE + FROM performance_schema.setup_actors + WHERE NOT (HOST = \'%\' AND USER = \'%\' AND ROLE = \'%\') + 1 row in set (0.00 sec) + + *************************** 1. row *************************** + status: Resetting: setup_actors + INSERT IGNORE INTO performance_schema.setup_actors + VALUES (\'%\', \'%\', \'%\') + 1 row in set (0.00 sec) + ... + + mysql> CALL sys.ps_setup_reset_to_default(false)\\G + Query OK, 0 rows affected (0.00 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + SET @query = 'DELETE + FROM performance_schema.setup_actors + WHERE NOT (HOST = ''%'' AND USER = ''%'' AND ROLE = ''%'')'; + + IF (in_verbose) THEN + SELECT CONCAT('Resetting: setup_actors\n', REPLACE(@query, ' ', '')) AS status; + END IF; + + PREPARE reset_stmt FROM @query; + EXECUTE reset_stmt; + DEALLOCATE PREPARE reset_stmt; + + SET @query = 'INSERT IGNORE INTO performance_schema.setup_actors + VALUES (''%'', ''%'', ''%'', ''YES'', ''YES'')'; + + IF (in_verbose) THEN + SELECT CONCAT('Resetting: setup_actors\n', REPLACE(@query, ' ', '')) AS status; + END IF; + + PREPARE reset_stmt FROM @query; + EXECUTE reset_stmt; + DEALLOCATE PREPARE reset_stmt; + + SET @query = 'UPDATE performance_schema.setup_instruments + SET ENABLED = sys.ps_is_instrument_default_enabled(NAME), + TIMED = sys.ps_is_instrument_default_timed(NAME)'; + + IF (in_verbose) THEN + SELECT CONCAT('Resetting: setup_instruments\n', REPLACE(@query, ' ', '')) AS status; + END IF; + + PREPARE reset_stmt FROM @query; + EXECUTE reset_stmt; + DEALLOCATE PREPARE reset_stmt; + + SET @query = 'UPDATE performance_schema.setup_consumers + SET ENABLED = IF(NAME IN (''events_statements_current'', ''events_transactions_current'', ''global_instrumentation'', ''thread_instrumentation'', ''statements_digest''), ''YES'', ''NO'')'; + + IF (in_verbose) THEN + SELECT CONCAT('Resetting: setup_consumers\n', REPLACE(@query, ' ', '')) AS status; + END IF; + + PREPARE reset_stmt FROM @query; + EXECUTE reset_stmt; + DEALLOCATE PREPARE reset_stmt; + + SET @query = 'DELETE + FROM performance_schema.setup_objects + WHERE NOT (OBJECT_TYPE IN (''EVENT'', ''FUNCTION'', ''PROCEDURE'', ''TABLE'', ''TRIGGER'') AND OBJECT_NAME = ''%'' + AND (OBJECT_SCHEMA = ''mysql'' AND ENABLED = ''NO'' AND TIMED = ''NO'' ) + OR (OBJECT_SCHEMA = ''performance_schema'' AND ENABLED = ''NO'' AND TIMED = ''NO'' ) + OR (OBJECT_SCHEMA = ''information_schema'' AND ENABLED = ''NO'' AND TIMED = ''NO'' ) + OR (OBJECT_SCHEMA = ''%'' AND ENABLED = ''YES'' AND TIMED = ''YES''))'; + + IF (in_verbose) THEN + SELECT CONCAT('Resetting: setup_objects\n', REPLACE(@query, ' ', '')) AS status; + END IF; + + PREPARE reset_stmt FROM @query; + EXECUTE reset_stmt; + DEALLOCATE PREPARE reset_stmt; + + SET @query = 'INSERT IGNORE INTO performance_schema.setup_objects + VALUES (''EVENT'' , ''mysql'' , ''%'', ''NO'' , ''NO'' ), + (''EVENT'' , ''performance_schema'', ''%'', ''NO'' , ''NO'' ), + (''EVENT'' , ''information_schema'', ''%'', ''NO'' , ''NO'' ), + (''EVENT'' , ''%'' , ''%'', ''YES'', ''YES''), + (''FUNCTION'' , ''mysql'' , ''%'', ''NO'' , ''NO'' ), + (''FUNCTION'' , ''performance_schema'', ''%'', ''NO'' , ''NO'' ), + (''FUNCTION'' , ''information_schema'', ''%'', ''NO'' , ''NO'' ), + (''FUNCTION'' , ''%'' , ''%'', ''YES'', ''YES''), + (''PROCEDURE'', ''mysql'' , ''%'', ''NO'' , ''NO'' ), + (''PROCEDURE'', ''performance_schema'', ''%'', ''NO'' , ''NO'' ), + (''PROCEDURE'', ''information_schema'', ''%'', ''NO'' , ''NO'' ), + (''PROCEDURE'', ''%'' , ''%'', ''YES'', ''YES''), + (''TABLE'' , ''mysql'' , ''%'', ''NO'' , ''NO'' ), + (''TABLE'' , ''performance_schema'', ''%'', ''NO'' , ''NO'' ), + (''TABLE'' , ''information_schema'', ''%'', ''NO'' , ''NO'' ), + (''TABLE'' , ''%'' , ''%'', ''YES'', ''YES''), + (''TRIGGER'' , ''mysql'' , ''%'', ''NO'' , ''NO'' ), + (''TRIGGER'' , ''performance_schema'', ''%'', ''NO'' , ''NO'' ), + (''TRIGGER'' , ''information_schema'', ''%'', ''NO'' , ''NO'' ), + (''TRIGGER'' , ''%'' , ''%'', ''YES'', ''YES'')'; + + IF (in_verbose) THEN + SELECT CONCAT('Resetting: setup_objects\n', REPLACE(@query, ' ', '')) AS status; + END IF; + + PREPARE reset_stmt FROM @query; + EXECUTE reset_stmt; + DEALLOCATE PREPARE reset_stmt; + + SET @query = 'UPDATE performance_schema.threads + SET INSTRUMENTED = ''YES'''; + + IF (in_verbose) THEN + SELECT CONCAT('Resetting: threads\n', REPLACE(@query, ' ', '')) AS status; + END IF; + + PREPARE reset_stmt FROM @query; + EXECUTE reset_stmt; + DEALLOCATE PREPARE reset_stmt; +END$$ + +DELIMITER ; + diff --git a/scripts/sys_schema/procedures/ps_setup_reset_to_default_57_after.sql b/scripts/sys_schema/procedures/ps_setup_reset_to_default_57_after.sql new file mode 100644 index 00000000..f2c41b01 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_reset_to_default_57_after.sql @@ -0,0 +1,16 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +SET @@session.sql_mode = @old_sql_mode; diff --git a/scripts/sys_schema/procedures/ps_setup_reset_to_default_57_before.sql b/scripts/sys_schema/procedures/ps_setup_reset_to_default_57_before.sql new file mode 100644 index 00000000..37001886 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_reset_to_default_57_before.sql @@ -0,0 +1,17 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- Because of bug 11750980/bug 41686, set the sql_mode to '' +SET @old_sql_mode = @@session.sql_mode, @@session.sql_mode = ''; diff --git a/scripts/sys_schema/procedures/ps_setup_save.sql b/scripts/sys_schema/procedures/ps_setup_save.sql new file mode 100644 index 00000000..b7843ecd --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_save.sql @@ -0,0 +1,97 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_save; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_save ( + IN in_timeout INT + ) + COMMENT ' + Description + ----------- + + Saves the current configuration of Performance Schema, + so that you can alter the setup for debugging purposes, + but restore it to a previous state. + + Use the companion procedure - ps_setup_reload_saved(), to + restore the saved config. + + The named lock "sys.ps_setup_save" is taken before the + current configuration is saved. If the attempt to get the named + lock times out, an error occurs. + + The lock is released after the settings have been restored by + calling ps_setup_reload_saved(). + + Requires the SUPER privilege for "SET sql_log_bin = 0;". + + Parameters + ----------- + + in_timeout INT + The timeout in seconds used when trying to obtain the lock. + A negative timeout means infinite timeout. + + Example + ----------- + + mysql> CALL sys.ps_setup_save(-1); + Query OK, 0 rows affected (0.08 sec) + + mysql> UPDATE performance_schema.setup_instruments + -> SET enabled = \'YES\', timed = \'YES\'; + Query OK, 547 rows affected (0.40 sec) + Rows matched: 784 Changed: 547 Warnings: 0 + + /* Run some tests that need more detailed instrumentation here */ + + mysql> CALL sys.ps_setup_reload_saved(); + Query OK, 0 rows affected (0.32 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + DECLARE v_lock_result INT; + + SET @log_bin := @@sql_log_bin; + SET sql_log_bin = 0; + + SELECT GET_LOCK('sys.ps_setup_save', in_timeout) INTO v_lock_result; + + IF v_lock_result THEN + DROP TEMPORARY TABLE IF EXISTS tmp_setup_actors; + DROP TEMPORARY TABLE IF EXISTS tmp_setup_consumers; + DROP TEMPORARY TABLE IF EXISTS tmp_setup_instruments; + DROP TEMPORARY TABLE IF EXISTS tmp_threads; + + CREATE TEMPORARY TABLE tmp_setup_actors AS SELECT * FROM performance_schema.setup_actors; + CREATE TEMPORARY TABLE tmp_setup_consumers AS SELECT * FROM performance_schema.setup_consumers; + CREATE TEMPORARY TABLE tmp_setup_instruments AS SELECT * FROM performance_schema.setup_instruments; + CREATE TEMPORARY TABLE tmp_threads (THREAD_ID bigint unsigned NOT NULL PRIMARY KEY, INSTRUMENTED enum('YES','NO') NOT NULL); + + INSERT INTO tmp_threads SELECT THREAD_ID, INSTRUMENTED FROM performance_schema.threads; + ELSE + SIGNAL SQLSTATE VALUE '90000' + SET MESSAGE_TEXT = 'Could not lock the sys.ps_setup_save user lock, another thread has a saved configuration'; + END IF; + + SET sql_log_bin = @log_bin; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_show_disabled.sql b/scripts/sys_schema/procedures/ps_setup_show_disabled.sql new file mode 100644 index 00000000..82c69840 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_show_disabled.sql @@ -0,0 +1,163 @@ +-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_show_disabled; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_show_disabled ( + IN in_show_instruments BOOLEAN, + IN in_show_threads BOOLEAN + ) + COMMENT ' + Description + ----------- + + Shows all currently disable Performance Schema configuration. + + Disabled users is only available for MySQL 5.7.6 and later. + In earlier versions it was only possible to enable users. + + Parameters + ----------- + + in_show_instruments (BOOLEAN): + Whether to print disabled instruments (can print many items) + + in_show_threads (BOOLEAN): + Whether to print disabled threads + + Example + ----------- + + mysql> CALL sys.ps_setup_show_disabled(TRUE, TRUE); + +----------------------------+ + | performance_schema_enabled | + +----------------------------+ + | 1 | + +----------------------------+ + 1 row in set (0.00 sec) + + +--------------------+ + | disabled_users | + +--------------------+ + | \'mark\'@\'localhost\' | + +--------------------+ + 1 row in set (0.00 sec) + + +-------------+----------------------+---------+-------+ + | object_type | objects | enabled | timed | + +-------------+----------------------+---------+-------+ + | EVENT | mysql.% | NO | NO | + | EVENT | performance_schema.% | NO | NO | + | EVENT | information_schema.% | NO | NO | + | FUNCTION | mysql.% | NO | NO | + | FUNCTION | performance_schema.% | NO | NO | + | FUNCTION | information_schema.% | NO | NO | + | PROCEDURE | mysql.% | NO | NO | + | PROCEDURE | performance_schema.% | NO | NO | + | PROCEDURE | information_schema.% | NO | NO | + | TABLE | mysql.% | NO | NO | + | TABLE | performance_schema.% | NO | NO | + | TABLE | information_schema.% | NO | NO | + | TRIGGER | mysql.% | NO | NO | + | TRIGGER | performance_schema.% | NO | NO | + | TRIGGER | information_schema.% | NO | NO | + +-------------+----------------------+---------+-------+ + 15 rows in set (0.00 sec) + + +----------------------------------+ + | disabled_consumers | + +----------------------------------+ + | events_stages_current | + | events_stages_history | + | events_stages_history_long | + | events_statements_history | + | events_statements_history_long | + | events_transactions_history | + | events_transactions_history_long | + | events_waits_current | + | events_waits_history | + | events_waits_history_long | + +----------------------------------+ + 10 rows in set (0.00 sec) + + Empty set (0.00 sec) + + +---------------------------------------------------------------------------------------+-------+ + | disabled_instruments | timed | + +---------------------------------------------------------------------------------------+-------+ + | wait/synch/mutex/sql/TC_LOG_MMAP::LOCK_tc | NO | + | wait/synch/mutex/sql/LOCK_des_key_file | NO | + | wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_commit | NO | + ... + | memory/sql/servers_cache | NO | + | memory/sql/udf_mem | NO | + | wait/lock/metadata/sql/mdl | NO | + +---------------------------------------------------------------------------------------+-------+ + 547 rows in set (0.00 sec) + + Query OK, 0 rows affected (0.01 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + READS SQL DATA +BEGIN + SELECT @@performance_schema AS performance_schema_enabled; + + -- In 5.7.6 and later the setup_actors table has an ENABLED column to + -- specify whether the actor is enabled. Before that all actors matched + -- in the setup_actors table were enabled. + -- So only execute the query in 5.7.6+ + /*!50706 + SELECT CONCAT('\'', user, '\'@\'', host, '\'') AS disabled_users + FROM performance_schema.setup_actors + WHERE enabled = 'NO' + ORDER BY disabled_users; + */ + + SELECT object_type, + CONCAT(object_schema, '.', object_name) AS objects, + enabled, + timed + FROM performance_schema.setup_objects + WHERE enabled = 'NO' + ORDER BY object_type, objects; + + SELECT name AS disabled_consumers + FROM performance_schema.setup_consumers + WHERE enabled = 'NO' + ORDER BY disabled_consumers; + + IF (in_show_threads) THEN + SELECT IF(name = 'thread/sql/one_connection', + CONCAT(processlist_user, '@', processlist_host), + REPLACE(name, 'thread/', '')) AS disabled_threads, + TYPE AS thread_type + FROM performance_schema.threads + WHERE INSTRUMENTED = 'NO' + ORDER BY disabled_threads; + END IF; + + IF (in_show_instruments) THEN + SELECT name AS disabled_instruments, + timed + FROM performance_schema.setup_instruments + WHERE enabled = 'NO' + ORDER BY disabled_instruments; + END IF; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_show_disabled_consumers.sql b/scripts/sys_schema/procedures/ps_setup_show_disabled_consumers.sql new file mode 100644 index 00000000..4c913efd --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_show_disabled_consumers.sql @@ -0,0 +1,57 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_show_disabled_consumers; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_show_disabled_consumers () + COMMENT ' + Description + ----------- + + Shows all currently disabled consumers. + + Parameters + ----------- + + None + + Example + ----------- + + mysql> CALL sys.ps_setup_show_disabled_consumers(); + + +---------------------------+ + | disabled_consumers | + +---------------------------+ + | events_statements_current | + | global_instrumentation | + | thread_instrumentation | + | statements_digest | + +---------------------------+ + 4 rows in set (0.05 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + READS SQL DATA +BEGIN + SELECT name AS disabled_consumers + FROM performance_schema.setup_consumers + WHERE enabled = 'NO' + ORDER BY disabled_consumers; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_show_disabled_instruments.sql b/scripts/sys_schema/procedures/ps_setup_show_disabled_instruments.sql new file mode 100644 index 00000000..45fe7c08 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_show_disabled_instruments.sql @@ -0,0 +1,47 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_show_disabled_instruments; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_show_disabled_instruments () + COMMENT ' + Description + ----------- + + Shows all currently disabled instruments. + + Parameters + ----------- + + None + + Example + ----------- + + mysql> CALL sys.ps_setup_show_disabled_instruments(); + ' + SQL SECURITY INVOKER + DETERMINISTIC + READS SQL DATA +BEGIN + SELECT name AS disabled_instruments, timed + FROM performance_schema.setup_instruments + WHERE enabled = 'NO' + ORDER BY disabled_instruments; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_show_enabled.sql b/scripts/sys_schema/procedures/ps_setup_show_enabled.sql new file mode 100644 index 00000000..8e7c0506 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_show_enabled.sql @@ -0,0 +1,166 @@ +-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_show_enabled; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_show_enabled ( + IN in_show_instruments BOOLEAN, + IN in_show_threads BOOLEAN + ) + COMMENT ' + Description + ----------- + + Shows all currently enabled Performance Schema configuration. + + Parameters + ----------- + + in_show_instruments (BOOLEAN): + Whether to print enabled instruments (can print many items) + + in_show_threads (BOOLEAN): + Whether to print enabled threads + + Example + ----------- + + mysql> CALL sys.ps_setup_show_enabled(TRUE, TRUE); + +----------------------------+ + | performance_schema_enabled | + +----------------------------+ + | 1 | + +----------------------------+ + 1 row in set (0.00 sec) + + +---------------+ + | enabled_users | + +---------------+ + | \'%\'@\'%\' | + +---------------+ + 1 row in set (0.01 sec) + + +-------------+---------+---------+-------+ + | object_type | objects | enabled | timed | + +-------------+---------+---------+-------+ + | EVENT | %.% | YES | YES | + | FUNCTION | %.% | YES | YES | + | PROCEDURE | %.% | YES | YES | + | TABLE | %.% | YES | YES | + | TRIGGER | %.% | YES | YES | + +-------------+---------+---------+-------+ + 5 rows in set (0.01 sec) + + +---------------------------+ + | enabled_consumers | + +---------------------------+ + | events_statements_current | + | global_instrumentation | + | thread_instrumentation | + | statements_digest | + +---------------------------+ + 4 rows in set (0.05 sec) + + +---------------------------------+-------------+ + | enabled_threads | thread_type | + +---------------------------------+-------------+ + | sql/main | BACKGROUND | + | sql/thread_timer_notifier | BACKGROUND | + | innodb/io_ibuf_thread | BACKGROUND | + | innodb/io_log_thread | BACKGROUND | + | innodb/io_read_thread | BACKGROUND | + | innodb/io_read_thread | BACKGROUND | + | innodb/io_write_thread | BACKGROUND | + | innodb/io_write_thread | BACKGROUND | + | innodb/page_cleaner_thread | BACKGROUND | + | innodb/srv_lock_timeout_thread | BACKGROUND | + | innodb/srv_error_monitor_thread | BACKGROUND | + | innodb/srv_monitor_thread | BACKGROUND | + | innodb/srv_master_thread | BACKGROUND | + | innodb/srv_purge_thread | BACKGROUND | + | innodb/srv_worker_thread | BACKGROUND | + | innodb/srv_worker_thread | BACKGROUND | + | innodb/srv_worker_thread | BACKGROUND | + | innodb/buf_dump_thread | BACKGROUND | + | innodb/dict_stats_thread | BACKGROUND | + | sql/signal_handler | BACKGROUND | + | sql/compress_gtid_table | FOREGROUND | + | root@localhost | FOREGROUND | + +---------------------------------+-------------+ + 22 rows in set (0.01 sec) + + +-------------------------------------+-------+ + | enabled_instruments | timed | + +-------------------------------------+-------+ + | wait/io/file/sql/map | YES | + | wait/io/file/sql/binlog | YES | + ... + | statement/com/Error | YES | + | statement/com/ | YES | + | idle | YES | + +-------------------------------------+-------+ + 210 rows in set (0.08 sec) + + Query OK, 0 rows affected (0.89 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + READS SQL DATA +BEGIN + SELECT @@performance_schema AS performance_schema_enabled; + + -- In 5.7.6 and later the setup_actors table has an ENABLED column to + -- specify whether the actor is enabled. Before that all actors matched + -- in the setup_actors table were enabled. + SELECT CONCAT('\'', user, '\'@\'', host, '\'') AS enabled_users + FROM performance_schema.setup_actors + WHERE enabled = 'YES' + ORDER BY enabled_users; + + SELECT object_type, + CONCAT(object_schema, '.', object_name) AS objects, + enabled, + timed + FROM performance_schema.setup_objects + WHERE enabled = 'YES' + ORDER BY object_type, objects; + + SELECT name AS enabled_consumers + FROM performance_schema.setup_consumers + WHERE enabled = 'YES' + ORDER BY enabled_consumers; + + IF (in_show_threads) THEN + SELECT IF(name = 'thread/sql/one_connection', + CONCAT(processlist_user, '@', processlist_host), + REPLACE(name, 'thread/', '')) AS enabled_threads, + TYPE AS thread_type + FROM performance_schema.threads + WHERE INSTRUMENTED = 'YES' AND name <> 'thread/innodb/thread_pool_thread' + ORDER BY enabled_threads; + END IF; + + IF (in_show_instruments) THEN + SELECT name AS enabled_instruments, + timed + FROM performance_schema.setup_instruments + WHERE enabled = 'YES' + ORDER BY enabled_instruments; + END IF; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_show_enabled_consumers.sql b/scripts/sys_schema/procedures/ps_setup_show_enabled_consumers.sql new file mode 100644 index 00000000..57ec2b75 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_show_enabled_consumers.sql @@ -0,0 +1,57 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_show_enabled_consumers; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_show_enabled_consumers () + COMMENT ' + Description + ----------- + + Shows all currently enabled consumers. + + Parameters + ----------- + + None + + Example + ----------- + + mysql> CALL sys.ps_setup_show_enabled_consumers(); + + +---------------------------+ + | enabled_consumers | + +---------------------------+ + | events_statements_current | + | global_instrumentation | + | thread_instrumentation | + | statements_digest | + +---------------------------+ + 4 rows in set (0.05 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + READS SQL DATA +BEGIN + SELECT name AS enabled_consumers + FROM performance_schema.setup_consumers + WHERE enabled = 'YES' + ORDER BY enabled_consumers; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_setup_show_enabled_instruments.sql b/scripts/sys_schema/procedures/ps_setup_show_enabled_instruments.sql new file mode 100644 index 00000000..d8cfb108 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_setup_show_enabled_instruments.sql @@ -0,0 +1,47 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_setup_show_enabled_instruments; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_show_enabled_instruments () + COMMENT ' + Description + ----------- + + Shows all currently enabled instruments. + + Parameters + ----------- + + None + + Example + ----------- + + mysql> CALL sys.ps_setup_show_enabled_instruments(); + ' + SQL SECURITY INVOKER + DETERMINISTIC + READS SQL DATA +BEGIN + SELECT name AS enabled_instruments, timed + FROM performance_schema.setup_instruments + WHERE enabled = 'YES' + ORDER BY enabled_instruments; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_statement_avg_latency_histogram.sql b/scripts/sys_schema/procedures/ps_statement_avg_latency_histogram.sql new file mode 100644 index 00000000..e57cbc1d --- /dev/null +++ b/scripts/sys_schema/procedures/ps_statement_avg_latency_histogram.sql @@ -0,0 +1,230 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_statement_avg_latency_histogram; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_statement_avg_latency_histogram () + COMMENT ' + Description + ----------- + + Outputs a textual histogram graph of the average latency values + across all normalized queries tracked within the Performance Schema + events_statements_summary_by_digest table. + + Can be used to show a very high level picture of what kind of + latency distribution statements running within this instance have. + + Parameters + ----------- + + None. + + Example + ----------- + + mysql> CALL sys.ps_statement_avg_latency_histogram()\\G + *************************** 1. row *************************** + Performance Schema Statement Digest Average Latency Histogram: + + . = 1 unit + * = 2 units + # = 3 units + + (0 - 38ms) 240 | ################################################################################ + (38 - 77ms) 38 | ...................................... + (77 - 115ms) 3 | ... + (115 - 154ms) 62 | ******************************* + (154 - 192ms) 3 | ... + (192 - 231ms) 0 | + (231 - 269ms) 0 | + (269 - 307ms) 0 | + (307 - 346ms) 0 | + (346 - 384ms) 1 | . + (384 - 423ms) 1 | . + (423 - 461ms) 0 | + (461 - 499ms) 0 | + (499 - 538ms) 0 | + (538 - 576ms) 0 | + (576 - 615ms) 1 | . + + Total Statements: 350; Buckets: 16; Bucket Size: 38 ms; + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + READS SQL DATA +BEGIN +SELECT CONCAT('\n', + '\n . = 1 unit', + '\n * = 2 units', + '\n # = 3 units\n', + @label := CONCAT(@label_inner := CONCAT('\n(0 - ', + ROUND((@bucket_size := (SELECT ROUND((MAX(avg_us) - MIN(avg_us)) / (@buckets := 16)) AS size + FROM sys.x$ps_digest_avg_latency_distribution)) / (@unit_div := 1000)), + (@unit := 'ms'), ')'), + REPEAT(' ', (@max_label_size := ((1 + LENGTH(ROUND((@bucket_size * 15) / @unit_div)) + 3 + LENGTH(ROUND(@bucket_size * 16) / @unit_div)) + 1)) - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us <= @bucket_size), 0)), + REPEAT(' ', (@max_label_len := (@max_label_size + LENGTH((@total_queries := (SELECT SUM(cnt) FROM sys.x$ps_digest_avg_latency_distribution)))) + 1) - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < (@one_unit := 40), '.', IF(@count_in_bucket < (@two_unit := 80), '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + + @label := CONCAT(@label_inner := CONCAT('\n(', ROUND(@bucket_size / @unit_div), ' - ', ROUND((@bucket_size * 2) / @unit_div), @unit, ')'), + REPEAT(' ', @max_label_size - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us > @bucket_size AND b1.avg_us <= @bucket_size * 2), 0)), + REPEAT(' ', @max_label_len - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 2) / @unit_div), ' - ', ROUND((@bucket_size * 3) / @unit_div), @unit, ')'), + REPEAT(' ', @max_label_size - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us > @bucket_size * 2 AND b1.avg_us <= @bucket_size * 3), 0)), + REPEAT(' ', @max_label_len - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 3) / @unit_div), ' - ', ROUND((@bucket_size * 4) / @unit_div), @unit, ')'), + REPEAT(' ', @max_label_size - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us > @bucket_size * 3 AND b1.avg_us <= @bucket_size * 4), 0)), + REPEAT(' ', @max_label_len - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 4) / @unit_div), ' - ', ROUND((@bucket_size * 5) / @unit_div), @unit, ')'), + REPEAT(' ', @max_label_size - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us > @bucket_size * 4 AND b1.avg_us <= @bucket_size * 5), 0)), + REPEAT(' ', @max_label_len - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 5) / @unit_div), ' - ', ROUND((@bucket_size * 6) / @unit_div), @unit, ')'), + REPEAT(' ', @max_label_size - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us > @bucket_size * 5 AND b1.avg_us <= @bucket_size * 6), 0)), + REPEAT(' ', @max_label_len - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 6) / @unit_div), ' - ', ROUND((@bucket_size * 7) / @unit_div), @unit, ')'), + REPEAT(' ', @max_label_size - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us > @bucket_size * 6 AND b1.avg_us <= @bucket_size * 7), 0)), + REPEAT(' ', @max_label_len - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 7) / @unit_div), ' - ', ROUND((@bucket_size * 8) / @unit_div), @unit, ')'), + REPEAT(' ', @max_label_size - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us > @bucket_size * 7 AND b1.avg_us <= @bucket_size * 8), 0)), + REPEAT(' ', @max_label_len - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 8) / @unit_div), ' - ', ROUND((@bucket_size * 9) / @unit_div), @unit, ')'), + REPEAT(' ', @max_label_size - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us > @bucket_size * 8 AND b1.avg_us <= @bucket_size * 9), 0)), + REPEAT(' ', @max_label_len - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 9) / @unit_div), ' - ', ROUND((@bucket_size * 10) / @unit_div), @unit, ')'), + REPEAT(' ', @max_label_size - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us > @bucket_size * 9 AND b1.avg_us <= @bucket_size * 10), 0)), + REPEAT(' ', @max_label_len - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 10) / @unit_div), ' - ', ROUND((@bucket_size * 11) / @unit_div), @unit, ')'), + REPEAT(' ', @max_label_size - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us > @bucket_size * 10 AND b1.avg_us <= @bucket_size * 11), 0)), + REPEAT(' ', @max_label_len - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 11) / @unit_div), ' - ', ROUND((@bucket_size * 12) / @unit_div), @unit, ')'), + REPEAT(' ', @max_label_size - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us > @bucket_size * 11 AND b1.avg_us <= @bucket_size * 12), 0)), + REPEAT(' ', @max_label_len - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 12) / @unit_div), ' - ', ROUND((@bucket_size * 13) / @unit_div), @unit, ')'), + REPEAT(' ', @max_label_size - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us > @bucket_size * 12 AND b1.avg_us <= @bucket_size * 13), 0)), + REPEAT(' ', @max_label_len - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 13) / @unit_div), ' - ', ROUND((@bucket_size * 14) / @unit_div), @unit, ')'), + REPEAT(' ', @max_label_size - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us > @bucket_size * 13 AND b1.avg_us <= @bucket_size * 14), 0)), + REPEAT(' ', @max_label_len - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 14) / @unit_div), ' - ', ROUND((@bucket_size * 15) / @unit_div), @unit, ')'), + REPEAT(' ', @max_label_size - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us > @bucket_size * 14 AND b1.avg_us <= @bucket_size * 15), 0)), + REPEAT(' ', @max_label_len - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 15) / @unit_div), ' - ', ROUND((@bucket_size * 16) / @unit_div), @unit, ')'), + REPEAT(' ', @max_label_size - LENGTH(@label_inner)), + @count_in_bucket := IFNULL((SELECT SUM(cnt) + FROM sys.x$ps_digest_avg_latency_distribution AS b1 + WHERE b1.avg_us > @bucket_size * 15 AND b1.avg_us <= @bucket_size * 16), 0)), + REPEAT(' ', @max_label_len - LENGTH(@label)), '| ', + IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')), + IF(@count_in_bucket < @one_unit, @count_in_bucket, + IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''), + + '\n\n Total Statements: ', @total_queries, '; Buckets: ', @buckets , '; Bucket Size: ', ROUND(@bucket_size / @unit_div) , ' ', @unit, ';\n' + + ) AS `Performance Schema Statement Digest Average Latency Histogram`; + +END $$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_trace_statement_digest.sql b/scripts/sys_schema/procedures/ps_trace_statement_digest.sql new file mode 100644 index 00000000..f9bb4d3b --- /dev/null +++ b/scripts/sys_schema/procedures/ps_trace_statement_digest.sql @@ -0,0 +1,324 @@ +-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_trace_statement_digest; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_trace_statement_digest ( + IN in_digest VARCHAR(32), + IN in_runtime INT, + IN in_interval DECIMAL(2,2), + IN in_start_fresh BOOLEAN, + IN in_auto_enable BOOLEAN + ) + COMMENT ' + Description + ----------- + + Traces all instrumentation within Performance Schema for a specific + Statement Digest. + + When finding a statement of interest within the + performance_schema.events_statements_summary_by_digest table, feed + the DIGEST MD5 value in to this procedure, set how long to poll for, + and at what interval to poll, and it will generate a report of all + statistics tracked within Performance Schema for that digest for the + interval. + + It will also attempt to generate an EXPLAIN for the longest running + example of the digest during the interval. Note this may fail, as: + + * Performance Schema truncates long SQL_TEXT values (and hence the + EXPLAIN will fail due to parse errors) + * the default schema is sys (so tables that are not fully qualified + in the query may not be found) + * some queries such as SHOW are not supported in EXPLAIN. + + When the EXPLAIN fails, the error will be ignored and no EXPLAIN + output generated. + + Requires the SUPER privilege for "SET sql_log_bin = 0;". + + Parameters + ----------- + + in_digest (VARCHAR(32)): + The statement digest identifier you would like to analyze + in_runtime (INT): + The number of seconds to run analysis for + in_interval (DECIMAL(2,2)): + The interval (in seconds, may be fractional) at which to try + and take snapshots + in_start_fresh (BOOLEAN): + Whether to TRUNCATE the events_statements_history_long and + events_stages_history_long tables before starting + in_auto_enable (BOOLEAN): + Whether to automatically turn on required consumers + + Example + ----------- + + mysql> call ps_trace_statement_digest(\'891ec6860f98ba46d89dd20b0c03652c\', 10, 0.1, true, true); + +--------------------+ + | SUMMARY STATISTICS | + +--------------------+ + | SUMMARY STATISTICS | + +--------------------+ + 1 row in set (9.11 sec) + + +------------+-----------+-----------+-----------+---------------+------------+------------+ + | executions | exec_time | lock_time | rows_sent | rows_examined | tmp_tables | full_scans | + +------------+-----------+-----------+-----------+---------------+------------+------------+ + | 21 | 4.11 ms | 2.00 ms | 0 | 21 | 0 | 0 | + +------------+-----------+-----------+-----------+---------------+------------+------------+ + 1 row in set (9.11 sec) + + +------------------------------------------+-------+-----------+ + | event_name | count | latency | + +------------------------------------------+-------+-----------+ + | stage/sql/checking query cache for query | 16 | 724.37 us | + | stage/sql/statistics | 16 | 546.92 us | + | stage/sql/freeing items | 18 | 520.11 us | + | stage/sql/init | 51 | 466.80 us | + ... + | stage/sql/cleaning up | 18 | 11.92 us | + | stage/sql/executing | 16 | 6.95 us | + +------------------------------------------+-------+-----------+ + 17 rows in set (9.12 sec) + + +---------------------------+ + | LONGEST RUNNING STATEMENT | + +---------------------------+ + | LONGEST RUNNING STATEMENT | + +---------------------------+ + 1 row in set (9.16 sec) + + +-----------+-----------+-----------+-----------+---------------+------------+-----------+ + | thread_id | exec_time | lock_time | rows_sent | rows_examined | tmp_tables | full_scan | + +-----------+-----------+-----------+-----------+---------------+------------+-----------+ + | 166646 | 618.43 us | 1.00 ms | 0 | 1 | 0 | 0 | + +-----------+-----------+-----------+-----------+---------------+------------+-----------+ + 1 row in set (9.16 sec) + + // Truncated for clarity... + +-----------------------------------------------------------------+ + | sql_text | + +-----------------------------------------------------------------+ + | select hibeventhe0_.id as id1382_, hibeventhe0_.createdTime ... | + +-----------------------------------------------------------------+ + 1 row in set (9.17 sec) + + +------------------------------------------+-----------+ + | event_name | latency | + +------------------------------------------+-----------+ + | stage/sql/init | 8.61 us | + | stage/sql/Waiting for query cache lock | 453.23 us | + | stage/sql/init | 331.07 ns | + | stage/sql/checking query cache for query | 43.04 us | + ... + | stage/sql/freeing items | 30.46 us | + | stage/sql/cleaning up | 662.13 ns | + +------------------------------------------+-----------+ + 18 rows in set (9.23 sec) + + +----+-------------+--------------+-------+---------------+-----------+---------+-------------+------+-------+ + | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | + +----+-------------+--------------+-------+---------------+-----------+---------+-------------+------+-------+ + | 1 | SIMPLE | hibeventhe0_ | const | fixedTime | fixedTime | 775 | const,const | 1 | NULL | + +----+-------------+--------------+-------+---------------+-----------+---------+-------------+------+-------+ + 1 row in set (9.27 sec) + + Query OK, 0 rows affected (9.28 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + + DECLARE v_start_fresh BOOLEAN DEFAULT false; + DECLARE v_auto_enable BOOLEAN DEFAULT false; + DECLARE v_explain BOOLEAN DEFAULT true; + DECLARE v_this_thread_enabed ENUM('YES', 'NO'); + DECLARE v_runtime INT DEFAULT 0; + DECLARE v_start INT DEFAULT 0; + DECLARE v_found_stmts INT; + + SET @log_bin := @@sql_log_bin; + SET sql_log_bin = 0; + + -- Do not track the current thread, it will kill the stack + SELECT INSTRUMENTED INTO v_this_thread_enabed FROM performance_schema.threads WHERE PROCESSLIST_ID = CONNECTION_ID(); + CALL sys.ps_setup_disable_thread(CONNECTION_ID()); + + DROP TEMPORARY TABLE IF EXISTS stmt_trace; + CREATE TEMPORARY TABLE stmt_trace ( + thread_id BIGINT UNSIGNED, + timer_start BIGINT UNSIGNED, + event_id BIGINT UNSIGNED, + sql_text longtext, + timer_wait BIGINT UNSIGNED, + lock_time BIGINT UNSIGNED, + errors BIGINT UNSIGNED, + mysql_errno INT, + rows_sent BIGINT UNSIGNED, + rows_affected BIGINT UNSIGNED, + rows_examined BIGINT UNSIGNED, + created_tmp_tables BIGINT UNSIGNED, + created_tmp_disk_tables BIGINT UNSIGNED, + no_index_used BIGINT UNSIGNED, + PRIMARY KEY (thread_id, timer_start) + ); + + DROP TEMPORARY TABLE IF EXISTS stmt_stages; + CREATE TEMPORARY TABLE stmt_stages ( + event_id BIGINT UNSIGNED, + stmt_id BIGINT UNSIGNED, + event_name VARCHAR(128), + timer_wait BIGINT UNSIGNED, + PRIMARY KEY (event_id) + ); + + SET v_start_fresh = in_start_fresh; + IF v_start_fresh THEN + TRUNCATE TABLE performance_schema.events_statements_history_long; + TRUNCATE TABLE performance_schema.events_stages_history_long; + END IF; + + SET v_auto_enable = in_auto_enable; + IF v_auto_enable THEN + CALL sys.ps_setup_save(0); + + UPDATE performance_schema.threads + SET INSTRUMENTED = IF(PROCESSLIST_ID IS NOT NULL, 'YES', 'NO'); + + -- Only the events_statements_history_long and events_stages_history_long tables and their ancestors are needed + UPDATE performance_schema.setup_consumers + SET ENABLED = 'YES' + WHERE NAME NOT LIKE '%\_history' + AND NAME NOT LIKE 'events_wait%' + AND NAME NOT LIKE 'events_transactions%' + AND NAME <> 'statements_digest'; + + UPDATE performance_schema.setup_instruments + SET ENABLED = 'YES', + TIMED = 'YES' + WHERE NAME LIKE 'statement/%' OR NAME LIKE 'stage/%'; + END IF; + + WHILE v_runtime < in_runtime DO + SELECT UNIX_TIMESTAMP() INTO v_start; + + INSERT IGNORE INTO stmt_trace + SELECT thread_id, timer_start, event_id, sql_text, timer_wait, lock_time, errors, mysql_errno, + rows_sent, rows_affected, rows_examined, created_tmp_tables, created_tmp_disk_tables, no_index_used + FROM performance_schema.events_statements_history_long + WHERE digest = in_digest; + + INSERT IGNORE INTO stmt_stages + SELECT stages.event_id, stmt_trace.event_id, + stages.event_name, stages.timer_wait + FROM performance_schema.events_stages_history_long AS stages + JOIN stmt_trace ON stages.nesting_event_id = stmt_trace.event_id; + + SELECT SLEEP(in_interval) INTO @sleep; + SET v_runtime = v_runtime + (UNIX_TIMESTAMP() - v_start); + END WHILE; + + SELECT "SUMMARY STATISTICS"; + + SELECT COUNT(*) executions, + sys.format_time(SUM(timer_wait)) AS exec_time, + sys.format_time(SUM(lock_time)) AS lock_time, + SUM(rows_sent) AS rows_sent, + SUM(rows_affected) AS rows_affected, + SUM(rows_examined) AS rows_examined, + SUM(created_tmp_tables) AS tmp_tables, + SUM(no_index_used) AS full_scans + FROM stmt_trace; + + SELECT event_name, + COUNT(*) as count, + sys.format_time(SUM(timer_wait)) as latency + FROM stmt_stages + GROUP BY event_name + ORDER BY SUM(timer_wait) DESC; + + SELECT "LONGEST RUNNING STATEMENT"; + + SELECT thread_id, + sys.format_time(timer_wait) AS exec_time, + sys.format_time(lock_time) AS lock_time, + rows_sent, + rows_affected, + rows_examined, + created_tmp_tables AS tmp_tables, + no_index_used AS full_scan + FROM stmt_trace + ORDER BY timer_wait DESC LIMIT 1; + + SELECT sql_text + FROM stmt_trace + ORDER BY timer_wait DESC LIMIT 1; + + SELECT sql_text, event_id INTO @sql, @sql_id + FROM stmt_trace + ORDER BY timer_wait DESC LIMIT 1; + + IF (@sql_id IS NOT NULL) THEN + SELECT event_name, + sys.format_time(timer_wait) as latency + FROM stmt_stages + WHERE stmt_id = @sql_id + ORDER BY event_id; + END IF; + + DROP TEMPORARY TABLE stmt_trace; + DROP TEMPORARY TABLE stmt_stages; + + IF (@sql IS NOT NULL) THEN + SET @stmt := CONCAT("EXPLAIN FORMAT=JSON ", @sql); + BEGIN + -- Not all queries support EXPLAIN, so catch the cases that are + -- not supported. Currently that includes cases where the table + -- is not fully qualified and is not in the default schema for this + -- procedure as it's not possible to change the default schema inside + -- a procedure. + -- + -- Errno = 1064: You have an error in your SQL syntax + -- Errno = 1146: Table '...' doesn't exist + DECLARE CONTINUE HANDLER FOR 1064, 1146 SET v_explain = false; + + PREPARE explain_stmt FROM @stmt; + END; + + IF (v_explain) THEN + EXECUTE explain_stmt; + DEALLOCATE PREPARE explain_stmt; + END IF; + END IF; + + IF v_auto_enable THEN + CALL sys.ps_setup_reload_saved(); + END IF; + -- Restore INSTRUMENTED for this thread + IF (v_this_thread_enabed = 'YES') THEN + CALL sys.ps_setup_enable_thread(CONNECTION_ID()); + END IF; + + SET sql_log_bin = @log_bin; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_trace_thread.sql b/scripts/sys_schema/procedures/ps_trace_thread.sql new file mode 100644 index 00000000..1a2ede79 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_trace_thread.sql @@ -0,0 +1,321 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_trace_thread; + +DELIMITER $$ +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_trace_thread ( + IN in_thread_id BIGINT UNSIGNED, + IN in_outfile VARCHAR(255), + IN in_max_runtime DECIMAL(20,2), + IN in_interval DECIMAL(20,2), + IN in_start_fresh BOOLEAN, + IN in_auto_setup BOOLEAN, + IN in_debug BOOLEAN + ) + COMMENT ' + Description + ----------- + + Dumps all data within Performance Schema for an instrumented thread, + to create a DOT formatted graph file. + + Each resultset returned from the procedure should be used for a complete graph + + Requires the SUPER privilege for "SET sql_log_bin = 0;". + + Parameters + ----------- + + in_thread_id (BIGINT UNSIGNED): + The thread that you would like a stack trace for + in_outfile (VARCHAR(255)): + The filename the dot file will be written to + in_max_runtime (DECIMAL(20,2)): + The maximum time to keep collecting data. + Use NULL to get the default which is 60 seconds. + in_interval (DECIMAL(20,2)): + How long to sleep between data collections. + Use NULL to get the default which is 1 second. + in_start_fresh (BOOLEAN): + Whether to reset all Performance Schema data before tracing. + in_auto_setup (BOOLEAN): + Whether to disable all other threads and enable all consumers/instruments. + This will also reset the settings at the end of the run. + in_debug (BOOLEAN): + Whether you would like to include file:lineno in the graph + + Example + ----------- + + mysql> CALL sys.ps_trace_thread(25, CONCAT(\'/tmp/stack-\', REPLACE(NOW(), \' \', \'-\'), \'.dot\'), NULL, NULL, TRUE, TRUE, TRUE); + +-------------------+ + | summary | + +-------------------+ + | Disabled 1 thread | + +-------------------+ + 1 row in set (0.00 sec) + + +---------------------------------------------+ + | Info | + +---------------------------------------------+ + | Data collection starting for THREAD_ID = 25 | + +---------------------------------------------+ + 1 row in set (0.03 sec) + + +-----------------------------------------------------------+ + | Info | + +-----------------------------------------------------------+ + | Stack trace written to /tmp/stack-2014-02-16-21:18:41.dot | + +-----------------------------------------------------------+ + 1 row in set (60.07 sec) + + +-------------------------------------------------------------------+ + | Convert to PDF | + +-------------------------------------------------------------------+ + | dot -Tpdf -o /tmp/stack_25.pdf /tmp/stack-2014-02-16-21:18:41.dot | + +-------------------------------------------------------------------+ + 1 row in set (60.07 sec) + + +-------------------------------------------------------------------+ + | Convert to PNG | + +-------------------------------------------------------------------+ + | dot -Tpng -o /tmp/stack_25.png /tmp/stack-2014-02-16-21:18:41.dot | + +-------------------------------------------------------------------+ + 1 row in set (60.07 sec) + + +------------------+ + | summary | + +------------------+ + | Enabled 1 thread | + +------------------+ + 1 row in set (60.32 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + DECLARE v_done bool DEFAULT FALSE; + DECLARE v_start, v_runtime DECIMAL(20,2) DEFAULT 0.0; + DECLARE v_min_event_id bigint unsigned DEFAULT 0; + DECLARE v_this_thread_enabed ENUM('YES', 'NO'); + DECLARE v_event longtext; + DECLARE c_stack CURSOR FOR + SELECT CONCAT(IF(nesting_event_id IS NOT NULL, CONCAT(nesting_event_id, ' -> '), ''), + event_id, '; ', event_id, ' [label="', + -- Convert from picoseconds to microseconds + '(', sys.format_time(timer_wait), ') ', + IF (event_name NOT LIKE 'wait/io%', + SUBSTRING_INDEX(event_name, '/', -2), + IF (event_name NOT LIKE 'wait/io/file%' OR event_name NOT LIKE 'wait/io/socket%', + SUBSTRING_INDEX(event_name, '/', -4), + event_name) + ), + -- Always dump the extra wait information gathered for statements + IF (event_name LIKE 'statement/%', IFNULL(CONCAT('\\n', wait_info), ''), ''), + -- If debug is enabled, add the file:lineno information for waits + IF (in_debug AND event_name LIKE 'wait%', wait_info, ''), + '", ', + -- Depending on the type of event, style appropriately + CASE WHEN event_name LIKE 'wait/io/file%' THEN + 'shape=box, style=filled, color=red' + WHEN event_name LIKE 'wait/io/table%' THEN + 'shape=box, style=filled, color=green' + WHEN event_name LIKE 'wait/io/socket%' THEN + 'shape=box, style=filled, color=yellow' + WHEN event_name LIKE 'wait/synch/mutex%' THEN + 'style=filled, color=lightskyblue' + WHEN event_name LIKE 'wait/synch/cond%' THEN + 'style=filled, color=darkseagreen3' + WHEN event_name LIKE 'wait/synch/rwlock%' THEN + 'style=filled, color=orchid' + WHEN event_name LIKE 'wait/lock%' THEN + 'shape=box, style=filled, color=tan' + WHEN event_name LIKE 'statement/%' THEN + CONCAT('shape=box, style=bold', + -- Style statements depending on COM vs SQL + CASE WHEN event_name LIKE 'statement/com/%' THEN + ' style=filled, color=darkseagreen' + ELSE + -- Use long query time from the server to + -- flag long running statements in red + IF((timer_wait/1000000000000) > @@log_slow_query_time, + ' style=filled, color=red', + ' style=filled, color=lightblue') + END + ) + WHEN event_name LIKE 'stage/%' THEN + 'style=filled, color=slategray3' + -- IDLE events are on their own, call attention to them + WHEN event_name LIKE '%idle%' THEN + 'shape=box, style=filled, color=firebrick3' + ELSE '' END, + '];\n' + ) event, event_id + FROM ( + -- Select all statements, with the extra tracing information available + (SELECT thread_id, event_id, event_name, timer_wait, timer_start, nesting_event_id, + CONCAT(sql_text, '\\n', + 'errors: ', errors, '\\n', + 'warnings: ', warnings, '\\n', + 'lock time: ', sys.format_time(lock_time),'\\n', + 'rows affected: ', rows_affected, '\\n', + 'rows sent: ', rows_sent, '\\n', + 'rows examined: ', rows_examined, '\\n', + 'tmp tables: ', created_tmp_tables, '\\n', + 'tmp disk tables: ', created_tmp_disk_tables, '\\n' + 'select scan: ', select_scan, '\\n', + 'select full join: ', select_full_join, '\\n', + 'select full range join: ', select_full_range_join, '\\n', + 'select range: ', select_range, '\\n', + 'select range check: ', select_range_check, '\\n', + 'sort merge passes: ', sort_merge_passes, '\\n', + 'sort rows: ', sort_rows, '\\n', + 'sort range: ', sort_range, '\\n', + 'sort scan: ', sort_scan, '\\n', + 'no index used: ', IF(no_index_used, 'TRUE', 'FALSE'), '\\n', + 'no good index used: ', IF(no_good_index_used, 'TRUE', 'FALSE'), '\\n' + ) AS wait_info + FROM performance_schema.events_statements_history_long + WHERE thread_id = in_thread_id AND event_id > v_min_event_id) + UNION + -- Select all stages + (SELECT thread_id, event_id, event_name, timer_wait, timer_start, nesting_event_id, null AS wait_info + FROM performance_schema.events_stages_history_long + WHERE thread_id = in_thread_id AND event_id > v_min_event_id) + UNION + -- Select all events, adding information appropriate to the event + (SELECT thread_id, event_id, + CONCAT(event_name, + IF(event_name NOT LIKE 'wait/synch/mutex%', IFNULL(CONCAT(' - ', operation), ''), ''), + IF(number_of_bytes IS NOT NULL, CONCAT(' ', number_of_bytes, ' bytes'), ''), + IF(event_name LIKE 'wait/io/file%', '\\n', ''), + IF(object_schema IS NOT NULL, CONCAT('\\nObject: ', object_schema, '.'), ''), + IF(object_name IS NOT NULL, + IF (event_name LIKE 'wait/io/socket%', + -- Print the socket if used, else the IP:port as reported + CONCAT('\\n', IF (object_name LIKE ':0%', @@socket, object_name)), + object_name), + '' + ), + IF(index_name IS NOT NULL, CONCAT(' Index: ', index_name), ''), '\\n' + ) AS event_name, + timer_wait, timer_start, nesting_event_id, source AS wait_info + FROM performance_schema.events_waits_history_long + WHERE thread_id = in_thread_id AND event_id > v_min_event_id) + ) events + ORDER BY event_id; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE; + + SET @log_bin := @@sql_log_bin; + SET sql_log_bin = 0; + + -- Do not track the current thread, it will kill the stack + SELECT INSTRUMENTED INTO v_this_thread_enabed FROM performance_schema.threads WHERE PROCESSLIST_ID = CONNECTION_ID(); + CALL sys.ps_setup_disable_thread(CONNECTION_ID()); + + IF (in_auto_setup) THEN + CALL sys.ps_setup_save(0); + + -- Ensure only the thread to create the stack trace for is instrumented and that we instrument everything. + DELETE FROM performance_schema.setup_actors; + + UPDATE performance_schema.threads + SET INSTRUMENTED = IF(THREAD_ID = in_thread_id, 'YES', 'NO'); + + -- only the %_history_long tables and it ancestors are needed + UPDATE performance_schema.setup_consumers + SET ENABLED = 'YES' + WHERE NAME NOT LIKE '%\_history'; + + UPDATE performance_schema.setup_instruments + SET ENABLED = 'YES', + TIMED = 'YES'; + END IF; + + IF (in_start_fresh) THEN + TRUNCATE performance_schema.events_statements_history_long; + TRUNCATE performance_schema.events_stages_history_long; + TRUNCATE performance_schema.events_waits_history_long; + END IF; + + DROP TEMPORARY TABLE IF EXISTS tmp_events; + CREATE TEMPORARY TABLE tmp_events ( + event_id bigint unsigned NOT NULL, + event longblob, + PRIMARY KEY (event_id) + ); + + -- Print headers for a .dot file + INSERT INTO tmp_events VALUES (0, CONCAT('digraph events { rankdir=LR; nodesep=0.10;\n', + '// Stack created .....: ', NOW(), '\n', + '// MySQL version .....: ', VERSION(), '\n', + '// MySQL hostname ....: ', @@hostname, '\n', + '// MySQL port ........: ', @@port, '\n', + '// MySQL socket ......: ', @@socket, '\n', + '// MySQL user ........: ', CURRENT_USER(), '\n')); + + SELECT CONCAT('Data collection starting for THREAD_ID = ', in_thread_id) AS 'Info'; + + SET v_min_event_id = 0, + v_start = UNIX_TIMESTAMP(), + in_interval = IFNULL(in_interval, 1.00), + in_max_runtime = IFNULL(in_max_runtime, 60.00); + + WHILE (v_runtime < in_max_runtime + AND (SELECT INSTRUMENTED FROM performance_schema.threads WHERE THREAD_ID = in_thread_id) = 'YES') DO + SET v_done = FALSE; + OPEN c_stack; + c_stack_loop: LOOP + FETCH c_stack INTO v_event, v_min_event_id; + IF v_done THEN + LEAVE c_stack_loop; + END IF; + + IF (LENGTH(v_event) > 0) THEN + INSERT INTO tmp_events VALUES (v_min_event_id, v_event); + END IF; + END LOOP; + CLOSE c_stack; + + SELECT SLEEP(in_interval) INTO @sleep; + SET v_runtime = (UNIX_TIMESTAMP() - v_start); + END WHILE; + + INSERT INTO tmp_events VALUES (v_min_event_id+1, '}'); + + SET @query = CONCAT('SELECT event FROM tmp_events ORDER BY event_id INTO OUTFILE ''', in_outfile, ''' FIELDS ESCAPED BY '''' LINES TERMINATED BY '''''); + PREPARE stmt_output FROM @query; + EXECUTE stmt_output; + DEALLOCATE PREPARE stmt_output; + + SELECT CONCAT('Stack trace written to ', in_outfile) AS 'Info'; + SELECT CONCAT('dot -Tpdf -o /tmp/stack_', in_thread_id, '.pdf ', in_outfile) AS 'Convert to PDF'; + SELECT CONCAT('dot -Tpng -o /tmp/stack_', in_thread_id, '.png ', in_outfile) AS 'Convert to PNG'; + DROP TEMPORARY TABLE tmp_events; + + -- Reset the settings for the performance schema + IF (in_auto_setup) THEN + CALL sys.ps_setup_reload_saved(); + END IF; + -- Restore INSTRUMENTED for this thread + IF (v_this_thread_enabed = 'YES') THEN + CALL sys.ps_setup_enable_thread(CONNECTION_ID()); + END IF; + + SET sql_log_bin = @log_bin; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_trace_thread_57.sql b/scripts/sys_schema/procedures/ps_trace_thread_57.sql new file mode 100644 index 00000000..33dc7961 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_trace_thread_57.sql @@ -0,0 +1,340 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_trace_thread; + +DELIMITER $$ +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_trace_thread ( + IN in_thread_id BIGINT UNSIGNED, + IN in_outfile VARCHAR(255), + IN in_max_runtime DECIMAL(20,2), + IN in_interval DECIMAL(20,2), + IN in_start_fresh BOOLEAN, + IN in_auto_setup BOOLEAN, + IN in_debug BOOLEAN + ) + COMMENT ' + Description + ----------- + + Dumps all data within Performance Schema for an instrumented thread, + to create a DOT formatted graph file. + + Each resultset returned from the procedure should be used for a complete graph + + Requires the SUPER privilege for "SET sql_log_bin = 0;". + + Parameters + ----------- + + in_thread_id (BIGINT UNSIGNED): + The thread that you would like a stack trace for + in_outfile (VARCHAR(255)): + The filename the dot file will be written to + in_max_runtime (DECIMAL(20,2)): + The maximum time to keep collecting data. + Use NULL to get the default which is 60 seconds. + in_interval (DECIMAL(20,2)): + How long to sleep between data collections. + Use NULL to get the default which is 1 second. + in_start_fresh (BOOLEAN): + Whether to reset all Performance Schema data before tracing. + in_auto_setup (BOOLEAN): + Whether to disable all other threads and enable all consumers/instruments. + This will also reset the settings at the end of the run. + in_debug (BOOLEAN): + Whether you would like to include file:lineno in the graph + + Example + ----------- + + mysql> CALL sys.ps_trace_thread(25, CONCAT(\'/tmp/stack-\', REPLACE(NOW(), \' \', \'-\'), \'.dot\'), NULL, NULL, TRUE, TRUE, TRUE); + +-------------------+ + | summary | + +-------------------+ + | Disabled 1 thread | + +-------------------+ + 1 row in set (0.00 sec) + + +---------------------------------------------+ + | Info | + +---------------------------------------------+ + | Data collection starting for THREAD_ID = 25 | + +---------------------------------------------+ + 1 row in set (0.03 sec) + + +-----------------------------------------------------------+ + | Info | + +-----------------------------------------------------------+ + | Stack trace written to /tmp/stack-2014-02-16-21:18:41.dot | + +-----------------------------------------------------------+ + 1 row in set (60.07 sec) + + +-------------------------------------------------------------------+ + | Convert to PDF | + +-------------------------------------------------------------------+ + | dot -Tpdf -o /tmp/stack_25.pdf /tmp/stack-2014-02-16-21:18:41.dot | + +-------------------------------------------------------------------+ + 1 row in set (60.07 sec) + + +-------------------------------------------------------------------+ + | Convert to PNG | + +-------------------------------------------------------------------+ + | dot -Tpng -o /tmp/stack_25.png /tmp/stack-2014-02-16-21:18:41.dot | + +-------------------------------------------------------------------+ + 1 row in set (60.07 sec) + + +------------------+ + | summary | + +------------------+ + | Enabled 1 thread | + +------------------+ + 1 row in set (60.32 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + MODIFIES SQL DATA +BEGIN + DECLARE v_done bool DEFAULT FALSE; + DECLARE v_start, v_runtime DECIMAL(20,2) DEFAULT 0.0; + DECLARE v_min_event_id bigint unsigned DEFAULT 0; + DECLARE v_this_thread_enabed ENUM('YES', 'NO'); + DECLARE v_event longtext; + DECLARE c_stack CURSOR FOR + SELECT CONCAT(IF(nesting_event_id IS NOT NULL, CONCAT(nesting_event_id, ' -> '), ''), + event_id, '; ', event_id, ' [label="', + -- Convert from picoseconds to microseconds + '(', sys.format_time(timer_wait), ') ', + IF (event_name NOT LIKE 'wait/io%', + SUBSTRING_INDEX(event_name, '/', -2), + IF (event_name NOT LIKE 'wait/io/file%' OR event_name NOT LIKE 'wait/io/socket%', + SUBSTRING_INDEX(event_name, '/', -4), + event_name) + ), + -- Always dump the extra wait information gathered for transactions and statements + IF (event_name LIKE 'transaction', IFNULL(CONCAT('\\n', wait_info), ''), ''), + IF (event_name LIKE 'statement/%', IFNULL(CONCAT('\\n', wait_info), ''), ''), + -- If debug is enabled, add the file:lineno information for waits + IF (in_debug AND event_name LIKE 'wait%', wait_info, ''), + '", ', + -- Depending on the type of event, style appropriately + CASE WHEN event_name LIKE 'wait/io/file%' THEN + 'shape=box, style=filled, color=red' + WHEN event_name LIKE 'wait/io/table%' THEN + 'shape=box, style=filled, color=green' + WHEN event_name LIKE 'wait/io/socket%' THEN + 'shape=box, style=filled, color=yellow' + WHEN event_name LIKE 'wait/synch/mutex%' THEN + 'style=filled, color=lightskyblue' + WHEN event_name LIKE 'wait/synch/cond%' THEN + 'style=filled, color=darkseagreen3' + WHEN event_name LIKE 'wait/synch/rwlock%' THEN + 'style=filled, color=orchid' + WHEN event_name LIKE 'wait/synch/sxlock%' THEN + 'style=filled, color=palevioletred' + WHEN event_name LIKE 'wait/lock%' THEN + 'shape=box, style=filled, color=tan' + WHEN event_name LIKE 'statement/%' THEN + CONCAT('shape=box, style=bold', + -- Style statements depending on COM vs SQL + CASE WHEN event_name LIKE 'statement/com/%' THEN + ' style=filled, color=darkseagreen' + ELSE + -- Use long query time from the server to + -- flag long running statements in red + IF((timer_wait/1000000000000) > @@log_slow_query_time, + ' style=filled, color=red', + ' style=filled, color=lightblue') + END + ) + WHEN event_name LIKE 'transaction' THEN + 'shape=box, style=filled, color=lightblue3' + WHEN event_name LIKE 'stage/%' THEN + 'style=filled, color=slategray3' + -- IDLE events are on their own, call attention to them + WHEN event_name LIKE '%idle%' THEN + 'shape=box, style=filled, color=firebrick3' + ELSE '' END, + '];\n' + ) event, event_id + FROM ( + -- Select all transactions + (SELECT thread_id, event_id, event_name, timer_wait, timer_start, nesting_event_id, + CONCAT('trx_id: ', IFNULL(trx_id, ''), '\\n', + 'gtid: ', IFNULL(gtid, ''), '\\n', + 'state: ', state, '\\n', + 'mode: ', access_mode, '\\n', + 'isolation: ', isolation_level, '\\n', + 'autocommit: ', autocommit, '\\n', + 'savepoints: ', number_of_savepoints, '\\n' + ) AS wait_info + FROM performance_schema.events_transactions_history_long + WHERE thread_id = in_thread_id AND event_id > v_min_event_id) + UNION + -- Select all statements, with the extra tracing information available + (SELECT thread_id, event_id, event_name, timer_wait, timer_start, nesting_event_id, + CONCAT('statement: ', sql_text, '\\n', + 'errors: ', errors, '\\n', + 'warnings: ', warnings, '\\n', + 'lock time: ', sys.format_time(lock_time),'\\n', + 'rows affected: ', rows_affected, '\\n', + 'rows sent: ', rows_sent, '\\n', + 'rows examined: ', rows_examined, '\\n', + 'tmp tables: ', created_tmp_tables, '\\n', + 'tmp disk tables: ', created_tmp_disk_tables, '\\n' + 'select scan: ', select_scan, '\\n', + 'select full join: ', select_full_join, '\\n', + 'select full range join: ', select_full_range_join, '\\n', + 'select range: ', select_range, '\\n', + 'select range check: ', select_range_check, '\\n', + 'sort merge passes: ', sort_merge_passes, '\\n', + 'sort rows: ', sort_rows, '\\n', + 'sort range: ', sort_range, '\\n', + 'sort scan: ', sort_scan, '\\n', + 'no index used: ', IF(no_index_used, 'TRUE', 'FALSE'), '\\n', + 'no good index used: ', IF(no_good_index_used, 'TRUE', 'FALSE'), '\\n' + ) AS wait_info + FROM performance_schema.events_statements_history_long + WHERE thread_id = in_thread_id AND event_id > v_min_event_id) + UNION + -- Select all stages + (SELECT thread_id, event_id, event_name, timer_wait, timer_start, nesting_event_id, null AS wait_info + FROM performance_schema.events_stages_history_long + WHERE thread_id = in_thread_id AND event_id > v_min_event_id) + UNION + -- Select all events, adding information appropriate to the event + (SELECT thread_id, event_id, + CONCAT(event_name, + IF(event_name NOT LIKE 'wait/synch/mutex%', IFNULL(CONCAT(' - ', operation), ''), ''), + IF(number_of_bytes IS NOT NULL, CONCAT(' ', number_of_bytes, ' bytes'), ''), + IF(event_name LIKE 'wait/io/file%', '\\n', ''), + IF(object_schema IS NOT NULL, CONCAT('\\nObject: ', object_schema, '.'), ''), + IF(object_name IS NOT NULL, + IF (event_name LIKE 'wait/io/socket%', + -- Print the socket if used, else the IP:port as reported + CONCAT('\\n', IF (object_name LIKE ':0%', @@socket, object_name)), + object_name), + '' + ), + IF(index_name IS NOT NULL, CONCAT(' Index: ', index_name), ''), '\\n' + ) AS event_name, + timer_wait, timer_start, nesting_event_id, source AS wait_info + FROM performance_schema.events_waits_history_long + WHERE thread_id = in_thread_id AND event_id > v_min_event_id) + ) events + ORDER BY event_id; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE; + + SET @log_bin := @@sql_log_bin; + SET sql_log_bin = 0; + + -- Do not track the current thread, it will kill the stack + SELECT INSTRUMENTED INTO v_this_thread_enabed FROM performance_schema.threads WHERE PROCESSLIST_ID = CONNECTION_ID(); + CALL sys.ps_setup_disable_thread(CONNECTION_ID()); + + IF (in_auto_setup) THEN + CALL sys.ps_setup_save(0); + + -- Ensure only the thread to create the stack trace for is instrumented and that we instrument everything. + DELETE FROM performance_schema.setup_actors; + + UPDATE performance_schema.threads + SET INSTRUMENTED = IF(THREAD_ID = in_thread_id, 'YES', 'NO'); + + -- only the %_history_long tables and it ancestors are needed + UPDATE performance_schema.setup_consumers + SET ENABLED = 'YES' + WHERE NAME NOT LIKE '%\_history'; + + UPDATE performance_schema.setup_instruments + SET ENABLED = 'YES', + TIMED = 'YES'; + END IF; + + IF (in_start_fresh) THEN + TRUNCATE performance_schema.events_transactions_history_long; + TRUNCATE performance_schema.events_statements_history_long; + TRUNCATE performance_schema.events_stages_history_long; + TRUNCATE performance_schema.events_waits_history_long; + END IF; + + DROP TEMPORARY TABLE IF EXISTS tmp_events; + CREATE TEMPORARY TABLE tmp_events ( + event_id bigint unsigned NOT NULL, + event longblob, + PRIMARY KEY (event_id) + ); + + -- Print headers for a .dot file + INSERT INTO tmp_events VALUES (0, CONCAT('digraph events { rankdir=LR; nodesep=0.10;\n', + '// Stack created .....: ', NOW(), '\n', + '// MySQL version .....: ', VERSION(), '\n', + '// MySQL hostname ....: ', @@hostname, '\n', + '// MySQL port ........: ', @@port, '\n', + '// MySQL socket ......: ', @@socket, '\n', + '// MySQL user ........: ', CURRENT_USER(), '\n')); + + SELECT CONCAT('Data collection starting for THREAD_ID = ', in_thread_id) AS 'Info'; + + SET v_min_event_id = 0, + v_start = UNIX_TIMESTAMP(), + in_interval = IFNULL(in_interval, 1.00), + in_max_runtime = IFNULL(in_max_runtime, 60.00); + + WHILE (v_runtime < in_max_runtime + AND (SELECT INSTRUMENTED FROM performance_schema.threads WHERE THREAD_ID = in_thread_id) = 'YES') DO + SET v_done = FALSE; + OPEN c_stack; + c_stack_loop: LOOP + FETCH c_stack INTO v_event, v_min_event_id; + IF v_done THEN + LEAVE c_stack_loop; + END IF; + + IF (LENGTH(v_event) > 0) THEN + INSERT INTO tmp_events VALUES (v_min_event_id, v_event); + END IF; + END LOOP; + CLOSE c_stack; + + SELECT SLEEP(in_interval) INTO @sleep; + SET v_runtime = (UNIX_TIMESTAMP() - v_start); + END WHILE; + + INSERT INTO tmp_events VALUES (v_min_event_id+1, '}'); + + SET @query = CONCAT('SELECT event FROM tmp_events ORDER BY event_id INTO OUTFILE ''', in_outfile, ''' FIELDS ESCAPED BY '''' LINES TERMINATED BY '''''); + PREPARE stmt_output FROM @query; + EXECUTE stmt_output; + DEALLOCATE PREPARE stmt_output; + + SELECT CONCAT('Stack trace written to ', in_outfile) AS 'Info'; + SELECT CONCAT('dot -Tpdf -o /tmp/stack_', in_thread_id, '.pdf ', in_outfile) AS 'Convert to PDF'; + SELECT CONCAT('dot -Tpng -o /tmp/stack_', in_thread_id, '.png ', in_outfile) AS 'Convert to PNG'; + DROP TEMPORARY TABLE tmp_events; + + -- Reset the settings for the performance schema + IF (in_auto_setup) THEN + CALL sys.ps_setup_reload_saved(); + END IF; + -- Restore INSTRUMENTED for this thread + IF (v_this_thread_enabed = 'YES') THEN + CALL sys.ps_setup_enable_thread(CONNECTION_ID()); + END IF; + + SET sql_log_bin = @log_bin; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/ps_truncate_all_tables.sql b/scripts/sys_schema/procedures/ps_truncate_all_tables.sql new file mode 100644 index 00000000..42d904f5 --- /dev/null +++ b/scripts/sys_schema/procedures/ps_truncate_all_tables.sql @@ -0,0 +1,90 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS ps_truncate_all_tables; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_truncate_all_tables ( + IN in_verbose BOOLEAN + ) + COMMENT ' + Description + ----------- + + Truncates all summary tables within Performance Schema, + resetting all aggregated instrumentation as a snapshot. + + Parameters + ----------- + + in_verbose (BOOLEAN): + Whether to print each TRUNCATE statement before running + + Example + ----------- + + mysql> CALL sys.ps_truncate_all_tables(false); + +---------------------+ + | summary | + +---------------------+ + | Truncated 44 tables | + +---------------------+ + 1 row in set (0.10 sec) + + Query OK, 0 rows affected (0.10 sec) + ' + SQL SECURITY INVOKER + DETERMINISTIC + MODIFIES SQL DATA +BEGIN + DECLARE v_done INT DEFAULT FALSE; + DECLARE v_total_tables INT DEFAULT 0; + DECLARE v_ps_table VARCHAR(64); + DECLARE ps_tables CURSOR FOR + SELECT table_name + FROM INFORMATION_SCHEMA.TABLES + WHERE table_schema = 'performance_schema' + AND (table_name LIKE '%summary%' + OR table_name LIKE '%history%'); + DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE; + + OPEN ps_tables; + + ps_tables_loop: LOOP + FETCH ps_tables INTO v_ps_table; + IF v_done THEN + LEAVE ps_tables_loop; + END IF; + + SET @truncate_stmt := CONCAT('TRUNCATE TABLE performance_schema.', v_ps_table); + IF in_verbose THEN + SELECT CONCAT('Running: ', @truncate_stmt) AS status; + END IF; + + PREPARE truncate_stmt FROM @truncate_stmt; + EXECUTE truncate_stmt; + DEALLOCATE PREPARE truncate_stmt; + + SET v_total_tables = v_total_tables + 1; + END LOOP; + + CLOSE ps_tables; + + SELECT CONCAT('Truncated ', v_total_tables, ' tables') AS summary; + +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/procedures/statement_performance_analyzer.sql b/scripts/sys_schema/procedures/statement_performance_analyzer.sql new file mode 100644 index 00000000..f98596ef --- /dev/null +++ b/scripts/sys_schema/procedures/statement_performance_analyzer.sql @@ -0,0 +1,723 @@ +-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS statement_performance_analyzer; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE statement_performance_analyzer ( + IN in_action ENUM('snapshot', 'overall', 'delta', 'create_table', 'create_tmp', 'save', 'cleanup'), + IN in_table VARCHAR(129), + IN in_views SET ('with_runtimes_in_95th_percentile', 'analysis', 'with_errors_or_warnings', 'with_full_table_scans', 'with_sorting', 'with_temp_tables', 'custom') + ) + COMMENT ' + Description + ----------- + + Create a report of the statements running on the server. + + The views are calculated based on the overall and/or delta activity. + + Requires the SUPER privilege for "SET sql_log_bin = 0;". + + Parameters + ----------- + + in_action (ENUM(''snapshot'', ''overall'', ''delta'', ''create_tmp'', ''create_table'', ''save'', ''cleanup'')): + The action to take. Supported actions are: + * snapshot Store a snapshot. The default is to make a snapshot of the current content of + performance_schema.events_statements_summary_by_digest, but by setting in_table + this can be overwritten to copy the content of the specified table. + The snapshot is stored in the sys.tmp_digests temporary table. + * overall Generate analyzis based on the content specified by in_table. For the overall analyzis, + in_table can be NOW() to use a fresh snapshot. This will overwrite an existing snapshot. + Use NULL for in_table to use the existing snapshot. If in_table IS NULL and no snapshot + exists, a new will be created. + See also in_views and @sys.statement_performance_analyzer.limit. + * delta Generate a delta analysis. The delta will be calculated between the reference table in + in_table and the snapshot. An existing snapshot must exist. + The action uses the sys.tmp_digests_delta temporary table. + See also in_views and @sys.statement_performance_analyzer.limit. + * create_table Create a regular table suitable for storing the snapshot for later use, e.g. for + calculating deltas. + * create_tmp Create a temporary table suitable for storing the snapshot for later use, e.g. for + calculating deltas. + * save Save the snapshot in the table specified by in_table. The table must exists and have + the correct structure. + If no snapshot exists, a new is created. + * cleanup Remove the temporary tables used for the snapshot and delta. + + in_table (VARCHAR(129)): + The table argument used for some actions. Use the format ''db1.t1'' or ''t1'' without using any backticks (`) + for quoting. Periods (.) are not supported in the database and table names. + + The meaning of the table for each action supporting the argument is: + + * snapshot The snapshot is created based on the specified table. Set to NULL or NOW() to use + the current content of performance_schema.events_statements_summary_by_digest. + * overall The table with the content to create the overall analyzis for. The following values + can be used: + - A table name - use the content of that table. + - NOW() - create a fresh snapshot and overwrite the existing snapshot. + - NULL - use the last stored snapshot. + * delta The table name is mandatory and specified the reference view to compare the currently + stored snapshot against. If no snapshot exists, a new will be created. + * create_table The name of the regular table to create. + * create_tmp The name of the temporary table to create. + * save The name of the table to save the currently stored snapshot into. + + in_views (SET (''with_runtimes_in_95th_percentile'', ''analysis'', ''with_errors_or_warnings'', + ''with_full_table_scans'', ''with_sorting'', ''with_temp_tables'', ''custom'')) + Which views to include: + + * with_runtimes_in_95th_percentile Based on the sys.statements_with_runtimes_in_95th_percentile view + * analysis Based on the sys.statement_analysis view + * with_errors_or_warnings Based on the sys.statements_with_errors_or_warnings view + * with_full_table_scans Based on the sys.statements_with_full_table_scans view + * with_sorting Based on the sys.statements_with_sorting view + * with_temp_tables Based on the sys.statements_with_temp_tables view + * custom Use a custom view. This view must be specified in @sys.statement_performance_analyzer.view to an existing view or a query + + Default is to include all except ''custom''. + + + Configuration Options + ---------------------- + + sys.statement_performance_analyzer.limit + The maximum number of rows to include for the views that does not have a built-in limit (e.g. the 95th percentile view). + If not set the limit is 100. + + sys.statement_performance_analyzer.view + Used together with the ''custom'' view. If the value contains a space, it is considered a query, otherwise it must be + an existing view querying the performance_schema.events_statements_summary_by_digest table. There cannot be any limit + clause including in the query or view definition if @sys.statement_performance_analyzer.limit > 0. + If specifying a view, use the same format as for in_table. + + sys.debug + Whether to provide debugging output. + Default is ''OFF''. Set to ''ON'' to include. + + + Example + -------- + + To create a report with the queries in the 95th percentile since last truncate of performance_schema.events_statements_summary_by_digest + and the delta for a 1 minute period: + + 1. Create a temporary table to store the initial snapshot. + 2. Create the initial snapshot. + 3. Save the initial snapshot in the temporary table. + 4. Wait one minute. + 5. Create a new snapshot. + 6. Perform analyzis based on the new snapshot. + 7. Perform analyzis based on the delta between the initial and new snapshots. + + mysql> CALL sys.statement_performance_analyzer(''create_tmp'', ''mydb.tmp_digests_ini'', NULL); + Query OK, 0 rows affected (0.08 sec) + + mysql> CALL sys.statement_performance_analyzer(''snapshot'', NULL, NULL); + Query OK, 0 rows affected (0.02 sec) + + mysql> CALL sys.statement_performance_analyzer(''save'', ''mydb.tmp_digests_ini'', NULL); + Query OK, 0 rows affected (0.00 sec) + + mysql> DO SLEEP(60); + Query OK, 0 rows affected (1 min 0.00 sec) + + mysql> CALL sys.statement_performance_analyzer(''snapshot'', NULL, NULL); + Query OK, 0 rows affected (0.02 sec) + + mysql> CALL sys.statement_performance_analyzer(''overall'', NULL, ''with_runtimes_in_95th_percentile''); + +-----------------------------------------+ + | Next Output | + +-----------------------------------------+ + | Queries with Runtime in 95th Percentile | + +-----------------------------------------+ + 1 row in set (0.05 sec) + + ... + + mysql> CALL sys.statement_performance_analyzer(''delta'', ''mydb.tmp_digests_ini'', ''with_runtimes_in_95th_percentile''); + +-----------------------------------------+ + | Next Output | + +-----------------------------------------+ + | Queries with Runtime in 95th Percentile | + +-----------------------------------------+ + 1 row in set (0.03 sec) + + ... + + + To create an overall report of the 95th percentile queries and the top 10 queries with full table scans: + + mysql> CALL sys.statement_performance_analyzer(''snapshot'', NULL, NULL); + Query OK, 0 rows affected (0.01 sec) + + mysql> SET @sys.statement_performance_analyzer.limit = 10; + Query OK, 0 rows affected (0.00 sec) + + mysql> CALL sys.statement_performance_analyzer(''overall'', NULL, ''with_runtimes_in_95th_percentile,with_full_table_scans''); + +-----------------------------------------+ + | Next Output | + +-----------------------------------------+ + | Queries with Runtime in 95th Percentile | + +-----------------------------------------+ + 1 row in set (0.01 sec) + + ... + + +-------------------------------------+ + | Next Output | + +-------------------------------------+ + | Top 10 Queries with Full Table Scan | + +-------------------------------------+ + 1 row in set (0.09 sec) + + ... + + + Use a custom view showing the top 10 query sorted by total execution time refreshing the view every minute using + the watch command in Linux. + + mysql> CREATE OR REPLACE VIEW mydb.my_statements AS + -> SELECT sys.format_statement(DIGEST_TEXT) AS query, + -> SCHEMA_NAME AS db, + -> COUNT_STAR AS exec_count, + -> sys.format_time(SUM_TIMER_WAIT) AS total_latency, + -> sys.format_time(AVG_TIMER_WAIT) AS avg_latency, + -> ROUND(IFNULL(SUM_ROWS_SENT / NULLIF(COUNT_STAR, 0), 0)) AS rows_sent_avg, + -> ROUND(IFNULL(SUM_ROWS_EXAMINED / NULLIF(COUNT_STAR, 0), 0)) AS rows_examined_avg, + -> ROUND(IFNULL(SUM_ROWS_AFFECTED / NULLIF(COUNT_STAR, 0), 0)) AS rows_affected_avg, + -> DIGEST AS digest + -> FROM performance_schema.events_statements_summary_by_digest + -> ORDER BY SUM_TIMER_WAIT DESC; + Query OK, 0 rows affected (0.01 sec) + + mysql> CALL sys.statement_performance_analyzer(''create_table'', ''mydb.digests_prev'', NULL); + Query OK, 0 rows affected (0.10 sec) + + shell$ watch -n 60 "mysql sys --table -e \" + > SET @sys.statement_performance_analyzer.view = ''mydb.my_statements''; + > SET @sys.statement_performance_analyzer.limit = 10; + > CALL statement_performance_analyzer(''snapshot'', NULL, NULL); + > CALL statement_performance_analyzer(''delta'', ''mydb.digests_prev'', ''custom''); + > CALL statement_performance_analyzer(''save'', ''mydb.digests_prev'', NULL); + > \"" + + Every 60.0s: mysql sys --table -e " ... Mon Dec 22 10:58:51 2014 + + +----------------------------------+ + | Next Output | + +----------------------------------+ + | Top 10 Queries Using Custom View | + +----------------------------------+ + +-------------------+-------+------------+---------------+-------------+---------------+-------------------+-------------------+----------------------------------+ + | query | db | exec_count | total_latency | avg_latency | rows_sent_avg | rows_examined_avg | rows_affected_avg | digest | + +-------------------+-------+------------+---------------+-------------+---------------+-------------------+-------------------+----------------------------------+ + ... + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + CONTAINS SQL +BEGIN + DECLARE v_table_exists, v_tmp_digests_table_exists, v_custom_view_exists ENUM('', 'BASE TABLE', 'VIEW', 'TEMPORARY') DEFAULT ''; + DECLARE v_this_thread_enabled ENUM('YES', 'NO'); + DECLARE v_force_new_snapshot BOOLEAN DEFAULT FALSE; + DECLARE v_digests_table VARCHAR(133); + DECLARE v_quoted_table, v_quoted_custom_view VARCHAR(133) DEFAULT ''; + DECLARE v_table_db, v_table_name, v_custom_db, v_custom_name VARCHAR(64); + DECLARE v_digest_table_template, v_checksum_ref, v_checksum_table text; + DECLARE v_sql longtext; + -- Maximum supported length for MESSAGE_TEXT with the SIGNAL command is 128 chars. + DECLARE v_error_msg VARCHAR(128); + + + -- Don't instrument this thread + SELECT INSTRUMENTED INTO v_this_thread_enabled FROM performance_schema.threads WHERE PROCESSLIST_ID = CONNECTION_ID(); + IF (v_this_thread_enabled = 'YES') THEN + CALL sys.ps_setup_disable_thread(CONNECTION_ID()); + END IF; + + -- Temporary table are used - disable sql_log_bin if necessary to prevent them replicating + SET @log_bin := @@sql_log_bin; + IF (@log_bin = 1) THEN + SET sql_log_bin = 0; + END IF; + + + -- Set configuration options + IF (@sys.statement_performance_analyzer.limit IS NULL) THEN + SET @sys.statement_performance_analyzer.limit = sys.sys_get_config('statement_performance_analyzer.limit', '100'); + END IF; + IF (@sys.debug IS NULL) THEN + SET @sys.debug = sys.sys_get_config('debug' , 'OFF'); + END IF; + + + -- If in_table is set, break in_table into a db and table component and check whether it exists + -- in_table = NOW() is considered like it's not set. + IF (in_table = 'NOW()') THEN + SET v_force_new_snapshot = TRUE, + in_table = NULL; + ELSEIF (in_table IS NOT NULL) THEN + IF (NOT INSTR(in_table, '.')) THEN + -- No . in the table name - use current database + -- DATABASE() will be the database of the procedure + SET v_table_db = DATABASE(), + v_table_name = in_table; + ELSE + SET v_table_db = SUBSTRING_INDEX(in_table, '.', 1); + SET v_table_name = SUBSTRING(in_table, CHAR_LENGTH(v_table_db)+2); + END IF; + + SET v_quoted_table = CONCAT('`', v_table_db, '`.`', v_table_name, '`'); + + IF (@sys.debug = 'ON') THEN + SELECT CONCAT('in_table is: db = ''', v_table_db, ''', table = ''', v_table_name, '''') AS 'Debug'; + END IF; + + IF (v_table_db = DATABASE() AND (v_table_name = 'tmp_digests' OR v_table_name = 'tmp_digests_delta')) THEN + SET v_error_msg = CONCAT('Invalid value for in_table: ', v_quoted_table, ' is reserved table name.'); + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = v_error_msg; + END IF; + + CALL sys.table_exists(v_table_db, v_table_name, v_table_exists); + IF (@sys.debug = 'ON') THEN + SELECT CONCAT('v_table_exists = ', v_table_exists) AS 'Debug'; + END IF; + + IF (v_table_exists = 'BASE TABLE') THEN + -- Verify that the table has the correct table definition + -- This can only be done for base tables as temporary aren't in information_schema.COLUMNS. + -- This also minimises the risk of using a production table. + SET v_checksum_ref = ( + SELECT GROUP_CONCAT(CONCAT(COLUMN_NAME, COLUMN_TYPE) ORDER BY ORDINAL_POSITION) AS Checksum + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = 'performance_schema' AND TABLE_NAME = 'events_statements_summary_by_digest' + ), + v_checksum_table = ( + SELECT GROUP_CONCAT(CONCAT(COLUMN_NAME, COLUMN_TYPE) ORDER BY ORDINAL_POSITION) AS Checksum + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = v_table_db AND TABLE_NAME = v_table_name + ); + + IF (v_checksum_ref <> v_checksum_table) THEN + -- The table does not have the correct definition, so abandon + SET v_error_msg = CONCAT('The table ', + IF(CHAR_LENGTH(v_quoted_table) > 93, CONCAT('...', SUBSTRING(v_quoted_table, -90)), v_quoted_table), + ' has the wrong definition.'); + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = v_error_msg; + END IF; + END IF; + END IF; + + + IF (in_views IS NULL OR in_views = '') THEN + -- Set to default + SET in_views = 'with_runtimes_in_95th_percentile,analysis,with_errors_or_warnings,with_full_table_scans,with_sorting,with_temp_tables'; + END IF; + + + -- Validate settings + CALL sys.table_exists(DATABASE(), 'tmp_digests', v_tmp_digests_table_exists); + IF (@sys.debug = 'ON') THEN + SELECT CONCAT('v_tmp_digests_table_exists = ', v_tmp_digests_table_exists) AS 'Debug'; + END IF; + + CASE + WHEN in_action IN ('snapshot', 'overall') THEN + -- in_table must be NULL, NOW(), or an existing table + IF (in_table IS NOT NULL) THEN + IF (NOT v_table_exists IN ('TEMPORARY', 'BASE TABLE')) THEN + SET v_error_msg = CONCAT('The ', in_action, ' action requires in_table to be NULL, NOW() or specify an existing table.', + ' The table ', + IF(CHAR_LENGTH(v_quoted_table) > 16, CONCAT('...', SUBSTRING(v_quoted_table, -13)), v_quoted_table), + ' does not exist.'); + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = v_error_msg; + END IF; + END IF; + + WHEN in_action IN ('delta', 'save') THEN + -- in_table must be an existing table + IF (v_table_exists NOT IN ('TEMPORARY', 'BASE TABLE')) THEN + SET v_error_msg = CONCAT('The ', in_action, ' action requires in_table to be an existing table.', + IF(in_table IS NOT NULL, CONCAT(' The table ', + IF(CHAR_LENGTH(v_quoted_table) > 39, CONCAT('...', SUBSTRING(v_quoted_table, -36)), v_quoted_table), + ' does not exist.'), '')); + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = v_error_msg; + END IF; + + IF (in_action = 'delta' AND v_tmp_digests_table_exists <> 'TEMPORARY') THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = 'An existing snapshot generated with the statement_performance_analyzer() must exist.'; + END IF; + WHEN in_action = 'create_tmp' THEN + -- in_table must not exists as a temporary table + IF (v_table_exists = 'TEMPORARY') THEN + SET v_error_msg = CONCAT('Cannot create the table ', + IF(CHAR_LENGTH(v_quoted_table) > 72, CONCAT('...', SUBSTRING(v_quoted_table, -69)), v_quoted_table), + ' as it already exists.'); + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = v_error_msg; + END IF; + + WHEN in_action = 'create_table' THEN + -- in_table must not exists at all + IF (v_table_exists <> '') THEN + SET v_error_msg = CONCAT('Cannot create the table ', + IF(CHAR_LENGTH(v_quoted_table) > 52, CONCAT('...', SUBSTRING(v_quoted_table, -49)), v_quoted_table), + ' as it already exists', + IF(v_table_exists = 'TEMPORARY', ' as a temporary table.', '.')); + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = v_error_msg; + END IF; + + WHEN in_action = 'cleanup' THEN + -- doesn't use any of the arguments + DO (SELECT 1); + ELSE + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = 'Unknown action. Supported actions are: cleanup, create_table, create_tmp, delta, overall, save, snapshot'; + END CASE; + + SET v_digest_table_template = 'CREATE %{TEMPORARY}TABLE %{TABLE_NAME} ( + `SCHEMA_NAME` varchar(64) DEFAULT NULL, + `DIGEST` varchar(32) DEFAULT NULL, + `DIGEST_TEXT` longtext, + `COUNT_STAR` bigint(20) unsigned NOT NULL, + `SUM_TIMER_WAIT` bigint(20) unsigned NOT NULL, + `MIN_TIMER_WAIT` bigint(20) unsigned NOT NULL, + `AVG_TIMER_WAIT` bigint(20) unsigned NOT NULL, + `MAX_TIMER_WAIT` bigint(20) unsigned NOT NULL, + `SUM_LOCK_TIME` bigint(20) unsigned NOT NULL, + `SUM_ERRORS` bigint(20) unsigned NOT NULL, + `SUM_WARNINGS` bigint(20) unsigned NOT NULL, + `SUM_ROWS_AFFECTED` bigint(20) unsigned NOT NULL, + `SUM_ROWS_SENT` bigint(20) unsigned NOT NULL, + `SUM_ROWS_EXAMINED` bigint(20) unsigned NOT NULL, + `SUM_CREATED_TMP_DISK_TABLES` bigint(20) unsigned NOT NULL, + `SUM_CREATED_TMP_TABLES` bigint(20) unsigned NOT NULL, + `SUM_SELECT_FULL_JOIN` bigint(20) unsigned NOT NULL, + `SUM_SELECT_FULL_RANGE_JOIN` bigint(20) unsigned NOT NULL, + `SUM_SELECT_RANGE` bigint(20) unsigned NOT NULL, + `SUM_SELECT_RANGE_CHECK` bigint(20) unsigned NOT NULL, + `SUM_SELECT_SCAN` bigint(20) unsigned NOT NULL, + `SUM_SORT_MERGE_PASSES` bigint(20) unsigned NOT NULL, + `SUM_SORT_RANGE` bigint(20) unsigned NOT NULL, + `SUM_SORT_ROWS` bigint(20) unsigned NOT NULL, + `SUM_SORT_SCAN` bigint(20) unsigned NOT NULL, + `SUM_NO_INDEX_USED` bigint(20) unsigned NOT NULL, + `SUM_NO_GOOD_INDEX_USED` bigint(20) unsigned NOT NULL, + `FIRST_SEEN` timestamp NULL DEFAULT NULL, + `LAST_SEEN` timestamp NULL DEFAULT NULL, + INDEX (SCHEMA_NAME, DIGEST) +) DEFAULT CHARSET=utf8'; + + -- Do the action + -- The actions snapshot, ... requires a fresh snapshot - create it now + IF (v_force_new_snapshot + OR in_action = 'snapshot' + OR (in_action = 'overall' AND in_table IS NULL) + OR (in_action = 'save' AND v_tmp_digests_table_exists <> 'TEMPORARY') + ) THEN + IF (v_tmp_digests_table_exists = 'TEMPORARY') THEN + IF (@sys.debug = 'ON') THEN + SELECT 'DROP TEMPORARY TABLE IF EXISTS tmp_digests' AS 'Debug'; + END IF; + DROP TEMPORARY TABLE IF EXISTS tmp_digests; + END IF; + CALL sys.execute_prepared_stmt(REPLACE(REPLACE(v_digest_table_template, '%{TEMPORARY}', 'TEMPORARY '), '%{TABLE_NAME}', 'tmp_digests')); + + SET v_sql = CONCAT('INSERT INTO tmp_digests SELECT * FROM ', + IF(in_table IS NULL OR in_action = 'save', 'performance_schema.events_statements_summary_by_digest', v_quoted_table)); + CALL sys.execute_prepared_stmt(v_sql); + END IF; + + -- Go through the remaining actions + IF (in_action IN ('create_table', 'create_tmp')) THEN + IF (in_action = 'create_table') THEN + CALL sys.execute_prepared_stmt(REPLACE(REPLACE(v_digest_table_template, '%{TEMPORARY}', ''), '%{TABLE_NAME}', v_quoted_table)); + ELSE + CALL sys.execute_prepared_stmt(REPLACE(REPLACE(v_digest_table_template, '%{TEMPORARY}', 'TEMPORARY '), '%{TABLE_NAME}', v_quoted_table)); + END IF; + ELSEIF (in_action = 'save') THEN + CALL sys.execute_prepared_stmt(CONCAT('DELETE FROM ', v_quoted_table)); + CALL sys.execute_prepared_stmt(CONCAT('INSERT INTO ', v_quoted_table, ' SELECT * FROM tmp_digests')); + ELSEIF (in_action = 'cleanup') THEN + DROP TEMPORARY TABLE IF EXISTS sys.tmp_digests; + DROP TEMPORARY TABLE IF EXISTS sys.tmp_digests_delta; + ELSEIF (in_action IN ('overall', 'delta')) THEN + -- These are almost the same - for delta calculate the delta in tmp_digests_delta and use that instead of tmp_digests. + -- And overall allows overriding the table to use. + IF (in_action = 'overall') THEN + IF (in_table IS NULL) THEN + SET v_digests_table = 'tmp_digests'; + ELSE + SET v_digests_table = v_quoted_table; + END IF; + ELSE + SET v_digests_table = 'tmp_digests_delta'; + DROP TEMPORARY TABLE IF EXISTS tmp_digests_delta; + CREATE TEMPORARY TABLE tmp_digests_delta LIKE tmp_digests; + SET v_sql = CONCAT('INSERT INTO tmp_digests_delta +SELECT `d_end`.`SCHEMA_NAME`, + `d_end`.`DIGEST`, + `d_end`.`DIGEST_TEXT`, + `d_end`.`COUNT_STAR`-IFNULL(`d_start`.`COUNT_STAR`, 0) AS ''COUNT_STAR'', + `d_end`.`SUM_TIMER_WAIT`-IFNULL(`d_start`.`SUM_TIMER_WAIT`, 0) AS ''SUM_TIMER_WAIT'', + `d_end`.`MIN_TIMER_WAIT` AS ''MIN_TIMER_WAIT'', + IFNULL((`d_end`.`SUM_TIMER_WAIT`-IFNULL(`d_start`.`SUM_TIMER_WAIT`, 0))/NULLIF(`d_end`.`COUNT_STAR`-IFNULL(`d_start`.`COUNT_STAR`, 0), 0), 0) AS ''AVG_TIMER_WAIT'', + `d_end`.`MAX_TIMER_WAIT` AS ''MAX_TIMER_WAIT'', + `d_end`.`SUM_LOCK_TIME`-IFNULL(`d_start`.`SUM_LOCK_TIME`, 0) AS ''SUM_LOCK_TIME'', + `d_end`.`SUM_ERRORS`-IFNULL(`d_start`.`SUM_ERRORS`, 0) AS ''SUM_ERRORS'', + `d_end`.`SUM_WARNINGS`-IFNULL(`d_start`.`SUM_WARNINGS`, 0) AS ''SUM_WARNINGS'', + `d_end`.`SUM_ROWS_AFFECTED`-IFNULL(`d_start`.`SUM_ROWS_AFFECTED`, 0) AS ''SUM_ROWS_AFFECTED'', + `d_end`.`SUM_ROWS_SENT`-IFNULL(`d_start`.`SUM_ROWS_SENT`, 0) AS ''SUM_ROWS_SENT'', + `d_end`.`SUM_ROWS_EXAMINED`-IFNULL(`d_start`.`SUM_ROWS_EXAMINED`, 0) AS ''SUM_ROWS_EXAMINED'', + `d_end`.`SUM_CREATED_TMP_DISK_TABLES`-IFNULL(`d_start`.`SUM_CREATED_TMP_DISK_TABLES`, 0) AS ''SUM_CREATED_TMP_DISK_TABLES'', + `d_end`.`SUM_CREATED_TMP_TABLES`-IFNULL(`d_start`.`SUM_CREATED_TMP_TABLES`, 0) AS ''SUM_CREATED_TMP_TABLES'', + `d_end`.`SUM_SELECT_FULL_JOIN`-IFNULL(`d_start`.`SUM_SELECT_FULL_JOIN`, 0) AS ''SUM_SELECT_FULL_JOIN'', + `d_end`.`SUM_SELECT_FULL_RANGE_JOIN`-IFNULL(`d_start`.`SUM_SELECT_FULL_RANGE_JOIN`, 0) AS ''SUM_SELECT_FULL_RANGE_JOIN'', + `d_end`.`SUM_SELECT_RANGE`-IFNULL(`d_start`.`SUM_SELECT_RANGE`, 0) AS ''SUM_SELECT_RANGE'', + `d_end`.`SUM_SELECT_RANGE_CHECK`-IFNULL(`d_start`.`SUM_SELECT_RANGE_CHECK`, 0) AS ''SUM_SELECT_RANGE_CHECK'', + `d_end`.`SUM_SELECT_SCAN`-IFNULL(`d_start`.`SUM_SELECT_SCAN`, 0) AS ''SUM_SELECT_SCAN'', + `d_end`.`SUM_SORT_MERGE_PASSES`-IFNULL(`d_start`.`SUM_SORT_MERGE_PASSES`, 0) AS ''SUM_SORT_MERGE_PASSES'', + `d_end`.`SUM_SORT_RANGE`-IFNULL(`d_start`.`SUM_SORT_RANGE`, 0) AS ''SUM_SORT_RANGE'', + `d_end`.`SUM_SORT_ROWS`-IFNULL(`d_start`.`SUM_SORT_ROWS`, 0) AS ''SUM_SORT_ROWS'', + `d_end`.`SUM_SORT_SCAN`-IFNULL(`d_start`.`SUM_SORT_SCAN`, 0) AS ''SUM_SORT_SCAN'', + `d_end`.`SUM_NO_INDEX_USED`-IFNULL(`d_start`.`SUM_NO_INDEX_USED`, 0) AS ''SUM_NO_INDEX_USED'', + `d_end`.`SUM_NO_GOOD_INDEX_USED`-IFNULL(`d_start`.`SUM_NO_GOOD_INDEX_USED`, 0) AS ''SUM_NO_GOOD_INDEX_USED'', + `d_end`.`FIRST_SEEN`, + `d_end`.`LAST_SEEN` + FROM tmp_digests d_end + LEFT OUTER JOIN ', v_quoted_table, ' d_start ON `d_start`.`DIGEST` = `d_end`.`DIGEST` + AND (`d_start`.`SCHEMA_NAME` = `d_end`.`SCHEMA_NAME` + OR (`d_start`.`SCHEMA_NAME` IS NULL AND `d_end`.`SCHEMA_NAME` IS NULL) + ) + WHERE `d_end`.`COUNT_STAR`-IFNULL(`d_start`.`COUNT_STAR`, 0) > 0'); + CALL sys.execute_prepared_stmt(v_sql); + END IF; + + IF (FIND_IN_SET('with_runtimes_in_95th_percentile', in_views)) THEN + SELECT 'Queries with Runtime in 95th Percentile' AS 'Next Output'; + + DROP TEMPORARY TABLE IF EXISTS tmp_digest_avg_latency_distribution1; + DROP TEMPORARY TABLE IF EXISTS tmp_digest_avg_latency_distribution2; + DROP TEMPORARY TABLE IF EXISTS tmp_digest_95th_percentile_by_avg_us; + + CREATE TEMPORARY TABLE tmp_digest_avg_latency_distribution1 ( + cnt bigint unsigned NOT NULL, + avg_us decimal(21,0) NOT NULL, + PRIMARY KEY (avg_us) + ) ENGINE=InnoDB; + + SET v_sql = CONCAT('INSERT INTO tmp_digest_avg_latency_distribution1 +SELECT COUNT(*) cnt, + ROUND(avg_timer_wait/1000000) AS avg_us + FROM ', v_digests_table, ' + GROUP BY avg_us'); + CALL sys.execute_prepared_stmt(v_sql); + + CREATE TEMPORARY TABLE tmp_digest_avg_latency_distribution2 LIKE tmp_digest_avg_latency_distribution1; + INSERT INTO tmp_digest_avg_latency_distribution2 SELECT * FROM tmp_digest_avg_latency_distribution1; + + CREATE TEMPORARY TABLE tmp_digest_95th_percentile_by_avg_us ( + avg_us decimal(21,0) NOT NULL, + percentile decimal(46,4) NOT NULL, + PRIMARY KEY (avg_us) + ) ENGINE=InnoDB; + + SET v_sql = CONCAT('INSERT INTO tmp_digest_95th_percentile_by_avg_us +SELECT s2.avg_us avg_us, + IFNULL(SUM(s1.cnt)/NULLIF((SELECT COUNT(*) FROM ', v_digests_table, '), 0), 0) percentile + FROM tmp_digest_avg_latency_distribution1 AS s1 + JOIN tmp_digest_avg_latency_distribution2 AS s2 ON s1.avg_us <= s2.avg_us + GROUP BY s2.avg_us +HAVING percentile > 0.95 + ORDER BY percentile + LIMIT 1'); + CALL sys.execute_prepared_stmt(v_sql); + + SET v_sql = + REPLACE( + REPLACE( + (SELECT VIEW_DEFINITION + FROM information_schema.VIEWS + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'statements_with_runtimes_in_95th_percentile' + ), + '`performance_schema`.`events_statements_summary_by_digest`', + v_digests_table + ), + 'sys.x$ps_digest_95th_percentile_by_avg_us', + '`sys`.`x$ps_digest_95th_percentile_by_avg_us`' + ); + CALL sys.execute_prepared_stmt(v_sql); + + DROP TEMPORARY TABLE tmp_digest_avg_latency_distribution1; + DROP TEMPORARY TABLE tmp_digest_avg_latency_distribution2; + DROP TEMPORARY TABLE tmp_digest_95th_percentile_by_avg_us; + END IF; + + IF (FIND_IN_SET('analysis', in_views)) THEN + SELECT CONCAT('Top ', @sys.statement_performance_analyzer.limit, ' Queries Ordered by Total Latency') AS 'Next Output'; + SET v_sql = + REPLACE( + (SELECT VIEW_DEFINITION + FROM information_schema.VIEWS + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'statement_analysis' + ), + '`performance_schema`.`events_statements_summary_by_digest`', + v_digests_table + ); + IF (@sys.statement_performance_analyzer.limit > 0) THEN + SET v_sql = CONCAT(v_sql, ' LIMIT ', @sys.statement_performance_analyzer.limit); + END IF; + CALL sys.execute_prepared_stmt(v_sql); + END IF; + + IF (FIND_IN_SET('with_errors_or_warnings', in_views)) THEN + SELECT CONCAT('Top ', @sys.statement_performance_analyzer.limit, ' Queries with Errors') AS 'Next Output'; + SET v_sql = + REPLACE( + (SELECT VIEW_DEFINITION + FROM information_schema.VIEWS + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'statements_with_errors_or_warnings' + ), + '`performance_schema`.`events_statements_summary_by_digest`', + v_digests_table + ); + IF (@sys.statement_performance_analyzer.limit > 0) THEN + SET v_sql = CONCAT(v_sql, ' LIMIT ', @sys.statement_performance_analyzer.limit); + END IF; + CALL sys.execute_prepared_stmt(v_sql); + END IF; + + IF (FIND_IN_SET('with_full_table_scans', in_views)) THEN + SELECT CONCAT('Top ', @sys.statement_performance_analyzer.limit, ' Queries with Full Table Scan') AS 'Next Output'; + SET v_sql = + REPLACE( + (SELECT VIEW_DEFINITION + FROM information_schema.VIEWS + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'statements_with_full_table_scans' + ), + '`performance_schema`.`events_statements_summary_by_digest`', + v_digests_table + ); + IF (@sys.statement_performance_analyzer.limit > 0) THEN + SET v_sql = CONCAT(v_sql, ' LIMIT ', @sys.statement_performance_analyzer.limit); + END IF; + CALL sys.execute_prepared_stmt(v_sql); + END IF; + + IF (FIND_IN_SET('with_sorting', in_views)) THEN + SELECT CONCAT('Top ', @sys.statement_performance_analyzer.limit, ' Queries with Sorting') AS 'Next Output'; + SET v_sql = + REPLACE( + (SELECT VIEW_DEFINITION + FROM information_schema.VIEWS + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'statements_with_sorting' + ), + '`performance_schema`.`events_statements_summary_by_digest`', + v_digests_table + ); + IF (@sys.statement_performance_analyzer.limit > 0) THEN + SET v_sql = CONCAT(v_sql, ' LIMIT ', @sys.statement_performance_analyzer.limit); + END IF; + CALL sys.execute_prepared_stmt(v_sql); + END IF; + + IF (FIND_IN_SET('with_temp_tables', in_views)) THEN + SELECT CONCAT('Top ', @sys.statement_performance_analyzer.limit, ' Queries with Internal Temporary Tables') AS 'Next Output'; + SET v_sql = + REPLACE( + (SELECT VIEW_DEFINITION + FROM information_schema.VIEWS + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'statements_with_temp_tables' + ), + '`performance_schema`.`events_statements_summary_by_digest`', + v_digests_table + ); + IF (@sys.statement_performance_analyzer.limit > 0) THEN + SET v_sql = CONCAT(v_sql, ' LIMIT ', @sys.statement_performance_analyzer.limit); + END IF; + CALL sys.execute_prepared_stmt(v_sql); + END IF; + + IF (FIND_IN_SET('custom', in_views)) THEN + SELECT CONCAT('Top ', @sys.statement_performance_analyzer.limit, ' Queries Using Custom View') AS 'Next Output'; + + IF (@sys.statement_performance_analyzer.view IS NULL) THEN + SET @sys.statement_performance_analyzer.view = sys.sys_get_config('statement_performance_analyzer.view', NULL); + END IF; + IF (@sys.statement_performance_analyzer.view IS NULL) THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = 'The @sys.statement_performance_analyzer.view user variable must be set with the view or query to use.'; + END IF; + + IF (NOT INSTR(@sys.statement_performance_analyzer.view, ' ')) THEN + -- No spaces, so can't be a query + IF (NOT INSTR(@sys.statement_performance_analyzer.view, '.')) THEN + -- No . in the table name - use current database + -- DATABASE() will be the database of the procedure + SET v_custom_db = DATABASE(), + v_custom_name = @sys.statement_performance_analyzer.view; + ELSE + SET v_custom_db = SUBSTRING_INDEX(@sys.statement_performance_analyzer.view, '.', 1); + SET v_custom_name = SUBSTRING(@sys.statement_performance_analyzer.view, CHAR_LENGTH(v_custom_db)+2); + END IF; + + CALL sys.table_exists(v_custom_db, v_custom_name, v_custom_view_exists); + IF (v_custom_view_exists <> 'VIEW') THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = 'The @sys.statement_performance_analyzer.view user variable is set but specified neither an existing view nor a query.'; + END IF; + + SET v_sql = + REPLACE( + (SELECT VIEW_DEFINITION + FROM information_schema.VIEWS + WHERE TABLE_SCHEMA = v_custom_db AND TABLE_NAME = v_custom_name + ), + '`performance_schema`.`events_statements_summary_by_digest`', + v_digests_table + ); + ELSE + SET v_sql = REPLACE(@sys.statement_performance_analyzer.view, '`performance_schema`.`events_statements_summary_by_digest`', v_digests_table); + END IF; + + IF (@sys.statement_performance_analyzer.limit > 0) THEN + SET v_sql = CONCAT(v_sql, ' LIMIT ', @sys.statement_performance_analyzer.limit); + END IF; + + CALL sys.execute_prepared_stmt(v_sql); + END IF; + END IF; + + -- Restore INSTRUMENTED for this thread + IF (v_this_thread_enabled = 'YES') THEN + CALL sys.ps_setup_enable_thread(CONNECTION_ID()); + END IF; + + IF (@log_bin = 1) THEN + SET sql_log_bin = @log_bin; + END IF; +END$$ + +DELIMITER ;
\ No newline at end of file diff --git a/scripts/sys_schema/procedures/table_exists.sql b/scripts/sys_schema/procedures/table_exists.sql new file mode 100644 index 00000000..0f764032 --- /dev/null +++ b/scripts/sys_schema/procedures/table_exists.sql @@ -0,0 +1,201 @@ +-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS table_exists; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE table_exists ( + IN in_db VARCHAR(64), IN in_table VARCHAR(64), + OUT out_exists ENUM('', 'BASE TABLE', 'VIEW', 'TEMPORARY', 'SEQUENCE', 'SYSTEM VIEW') + ) + COMMENT ' + Description + ----------- + + Tests whether the table specified in in_db and in_table exists either as a regular + table, or as a temporary table. The returned value corresponds to the table that + will be used, so if there''s both a temporary and a permanent table with the given + name, then ''TEMPORARY'' will be returned. + + Parameters + ----------- + + in_db (VARCHAR(64)): + The database name to check for the existence of the table in. + + in_table (VARCHAR(64)): + The name of the table to check the existence of. + + out_exists ENUM('''', ''BASE TABLE'', ''VIEW'', ''TEMPORARY''): + The return value: whether the table exists. The value is one of: + * '''' - the table does not exist neither as a base table, view, sequence nor temporary table. + * ''BASE TABLE'' - the table name exists as a permanent base table table. + * ''VIEW'' - the table name exists as a view. + * ''TEMPORARY'' - the table name exists as a temporary table. + * ''SEQUENCE'' - the table name exists as a sequence. + * ''SYSTEM VIEW'' - the table name exists as a system view. + + Example + -------- + + mysql> CREATE DATABASE db1; + Query OK, 1 row affected (0.07 sec) + + mysql> use db1; + Database changed + mysql> CREATE TABLE t1 (id INT PRIMARY KEY); + Query OK, 0 rows affected (0.08 sec) + + mysql> CREATE TABLE t2 (id INT PRIMARY KEY); + Query OK, 0 rows affected (0.08 sec) + + mysql> CREATE view v_t1 AS SELECT * FROM t1; + Query OK, 0 rows affected (0.00 sec) + + mysql> CREATE TEMPORARY TABLE t1 (id INT PRIMARY KEY); + Query OK, 0 rows affected (0.00 sec) + + mysql> CALL sys.table_exists(''db1'', ''t1'', @exists); SELECT @exists; + Query OK, 0 rows affected (0.00 sec) + + +------------+ + | @exists | + +------------+ + | TEMPORARY | + +------------+ + 1 row in set (0.00 sec) + + mysql> CALL sys.table_exists(''db1'', ''t2'', @exists); SELECT @exists; + Query OK, 0 rows affected (0.00 sec) + + +------------+ + | @exists | + +------------+ + | BASE TABLE | + +------------+ + 1 row in set (0.01 sec) + + mysql> CALL sys.table_exists(''db1'', ''v_t1'', @exists); SELECT @exists; + Query OK, 0 rows affected (0.00 sec) + + +---------+ + | @exists | + +---------+ + | VIEW | + +---------+ + 1 row in set (0.00 sec) + + MariaDB [sys]> CALL sys.table_exists(''db1'', ''s'', @exists); SELECT @exists; + Query OK, 0 rows affected (0.006 sec) + + +----------+ + | @exists | + +----------+ + | SEQUENCE | + +----------+ + 1 row in set (0.000 sec) + + MariaDB [sys]> CALL table_exists(''information_schema'', ''user_variables'', @exists); SELECT @exists; + Query OK, 0 rows affected (0.003 sec) + + +-------------+ + | @exists | + +-------------+ + | SYSTEM VIEW | + +-------------+ + 1 row in set (0.001 sec) + + mysql> CALL sys.table_exists(''db1'', ''t3'', @exists); SELECT @exists; + Query OK, 0 rows affected (0.01 sec) + + +---------+ + | @exists | + +---------+ + | | + +---------+ + 1 row in set (0.00 sec) + ' + SQL SECURITY INVOKER + NOT DETERMINISTIC + CONTAINS SQL +BEGIN + DECLARE v_error BOOLEAN DEFAULT FALSE; + DECLARE db_quoted VARCHAR(64); + DECLARE table_quoted VARCHAR(64); + DECLARE v_table_type VARCHAR(16) DEFAULT ''; + DECLARE v_system_db BOOLEAN + DEFAULT LOWER(in_db) IN ('information_schema', 'performance_schema'); + DECLARE CONTINUE HANDLER FOR 1050 SET v_error = TRUE; + DECLARE CONTINUE HANDLER FOR 1146 SET v_error = TRUE; + + SET out_exists = ''; + SET db_quoted = sys.quote_identifier(in_db); + SET table_quoted = sys.quote_identifier(in_table); + + -- Verify whether the table name exists as a normal table + IF (EXISTS(SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = in_db AND TABLE_NAME = in_table)) THEN + -- Unfortunately the only way to determine whether there is also a temporary table is to try to create + -- a temporary table with the same name. If it succeeds the table didn't exist as a temporary table. + IF v_system_db = FALSE THEN + SET @sys.tmp.table_exists.SQL = CONCAT('CREATE TEMPORARY TABLE ', + db_quoted, + '.', + table_quoted, + '(id INT PRIMARY KEY)'); + PREPARE stmt_create_table FROM @sys.tmp.table_exists.SQL; + EXECUTE stmt_create_table; + DEALLOCATE PREPARE stmt_create_table; + + -- The temporary table was created, i.e. it didn't exist. Remove it again so we don't leave garbage around. + SET @sys.tmp.table_exists.SQL = CONCAT('DROP TEMPORARY TABLE ', + db_quoted, + '.', + table_quoted); + PREPARE stmt_drop_table FROM @sys.tmp.table_exists.SQL; + EXECUTE stmt_drop_table; + DEALLOCATE PREPARE stmt_drop_table; + END IF; + IF (v_error) THEN + SET out_exists = 'TEMPORARY'; + ELSE + SET v_table_type = (SELECT TABLE_TYPE FROM information_schema.TABLES WHERE TABLE_SCHEMA = in_db AND TABLE_NAME = in_table); + -- Don't fail on table_type='SYSTEM VERSIONED' + -- but return 'BASE TABLE' for compatibility with existing tooling + IF v_table_type = 'SYSTEM VERSIONED' THEN + SET out_exists = 'BASE TABLE'; + ELSE + SET out_exists = v_table_type; + END IF; + END IF; + ELSE + -- Check whether a temporary table exists with the same name. + -- If it does it's possible to SELECT from the table without causing an error. + -- If it does not exist even a PREPARE using the table will fail. + IF v_system_db = FALSE THEN + SET @sys.tmp.table_exists.SQL = CONCAT('SELECT COUNT(*) FROM ', + db_quoted, + '.', + table_quoted); + PREPARE stmt_select FROM @sys.tmp.table_exists.SQL; + IF (NOT v_error) THEN + DEALLOCATE PREPARE stmt_select; + SET out_exists = 'TEMPORARY'; + END IF; + END IF; + END IF; +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/sys_56.sql b/scripts/sys_schema/sys_56.sql new file mode 100644 index 00000000..1de01d25 --- /dev/null +++ b/scripts/sys_schema/sys_56.sql @@ -0,0 +1,179 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +SOURCE ./before_setup.sql + +SOURCE ./views/version.sql + +SOURCE ./tables/sys_config.sql +SOURCE ./tables/sys_config_data.sql + +SOURCE ./triggers/sys_config_insert_set_user.sql +SOURCE ./triggers/sys_config_update_set_user.sql + +SOURCE ./functions/extract_schema_from_file_name.sql +SOURCE ./functions/extract_table_from_file_name.sql +SOURCE ./functions/format_bytes.sql +SOURCE ./functions/format_path.sql +SOURCE ./functions/format_statement.sql +SOURCE ./functions/format_time.sql +SOURCE ./functions/list_add.sql +SOURCE ./functions/list_drop.sql +SOURCE ./functions/ps_is_account_enabled.sql +SOURCE ./functions/ps_is_consumer_enabled.sql +SOURCE ./functions/ps_is_instrument_default_enabled.sql +SOURCE ./functions/ps_is_instrument_default_timed.sql +SOURCE ./functions/ps_is_thread_instrumented.sql +SOURCE ./functions/ps_thread_id.sql +SOURCE ./functions/ps_thread_account.sql +SOURCE ./functions/ps_thread_stack.sql +SOURCE ./functions/quote_identifier.sql +SOURCE ./functions/sys_get_config.sql +SOURCE ./functions/version_major.sql +SOURCE ./functions/version_minor.sql +SOURCE ./functions/version_patch.sql + +SOURCE ./views/i_s/innodb_buffer_stats_by_schema.sql +SOURCE ./views/i_s/x_innodb_buffer_stats_by_schema.sql +SOURCE ./views/i_s/innodb_buffer_stats_by_table.sql +SOURCE ./views/i_s/x_innodb_buffer_stats_by_table.sql +SOURCE ./views/i_s/innodb_lock_waits.sql +SOURCE ./views/i_s/x_innodb_lock_waits.sql +SOURCE ./views/i_s/schema_object_overview.sql +SOURCE ./views/i_s/schema_auto_increment_columns.sql +SOURCE ./views/i_s/x_schema_flattened_keys.sql +SOURCE ./views/i_s/schema_redundant_indexes.sql + +SOURCE ./views/p_s/ps_check_lost_instrumentation.sql +SOURCE ./views/p_s/processlist.sql +SOURCE ./views/p_s/x_processlist.sql + +SOURCE ./views/p_s/sessions.sql +SOURCE ./views/p_s/x_sessions.sql + +SOURCE ./views/p_s/latest_file_io.sql +SOURCE ./views/p_s/x_latest_file_io.sql +SOURCE ./views/p_s/io_by_thread_by_latency.sql +SOURCE ./views/p_s/x_io_by_thread_by_latency.sql +SOURCE ./views/p_s/io_global_by_file_by_bytes.sql +SOURCE ./views/p_s/x_io_global_by_file_by_bytes.sql +SOURCE ./views/p_s/io_global_by_file_by_latency.sql +SOURCE ./views/p_s/x_io_global_by_file_by_latency.sql +SOURCE ./views/p_s/io_global_by_wait_by_bytes.sql +SOURCE ./views/p_s/x_io_global_by_wait_by_bytes.sql +SOURCE ./views/p_s/io_global_by_wait_by_latency.sql +SOURCE ./views/p_s/x_io_global_by_wait_by_latency.sql + +SOURCE ./views/p_s/schema_index_statistics.sql +SOURCE ./views/p_s/x_schema_index_statistics.sql +SOURCE ./views/p_s/x_ps_schema_table_statistics_io.sql +SOURCE ./views/p_s/schema_table_statistics.sql +SOURCE ./views/p_s/x_schema_table_statistics.sql +SOURCE ./views/p_s/schema_table_statistics_with_buffer.sql +SOURCE ./views/p_s/x_schema_table_statistics_with_buffer.sql +SOURCE ./views/p_s/schema_tables_with_full_table_scans.sql +SOURCE ./views/p_s/x_schema_tables_with_full_table_scans.sql +SOURCE ./views/p_s/schema_unused_indexes.sql + +SOURCE ./views/p_s/statement_analysis.sql +SOURCE ./views/p_s/x_statement_analysis.sql +SOURCE ./views/p_s/statements_with_errors_or_warnings.sql +SOURCE ./views/p_s/x_statements_with_errors_or_warnings.sql +SOURCE ./views/p_s/statements_with_full_table_scans.sql +SOURCE ./views/p_s/x_statements_with_full_table_scans.sql +SOURCE ./views/p_s/x_ps_digest_avg_latency_distribution.sql +SOURCE ./views/p_s/x_ps_digest_95th_percentile_by_avg_us.sql +SOURCE ./views/p_s/statements_with_runtimes_in_95th_percentile.sql +SOURCE ./views/p_s/x_statements_with_runtimes_in_95th_percentile.sql +SOURCE ./views/p_s/statements_with_sorting.sql +SOURCE ./views/p_s/x_statements_with_sorting.sql +SOURCE ./views/p_s/statements_with_temp_tables.sql +SOURCE ./views/p_s/x_statements_with_temp_tables.sql + +SOURCE ./views/p_s/user_summary_by_file_io_type.sql +SOURCE ./views/p_s/x_user_summary_by_file_io_type.sql +SOURCE ./views/p_s/user_summary_by_file_io.sql +SOURCE ./views/p_s/x_user_summary_by_file_io.sql +SOURCE ./views/p_s/user_summary_by_statement_type.sql +SOURCE ./views/p_s/x_user_summary_by_statement_type.sql +SOURCE ./views/p_s/user_summary_by_statement_latency.sql +SOURCE ./views/p_s/x_user_summary_by_statement_latency.sql +SOURCE ./views/p_s/user_summary_by_stages.sql +SOURCE ./views/p_s/x_user_summary_by_stages.sql +SOURCE ./views/p_s/user_summary.sql +SOURCE ./views/p_s/x_user_summary.sql + +SOURCE ./views/p_s/host_summary_by_file_io_type.sql +SOURCE ./views/p_s/x_host_summary_by_file_io_type.sql +SOURCE ./views/p_s/host_summary_by_file_io.sql +SOURCE ./views/p_s/x_host_summary_by_file_io.sql +SOURCE ./views/p_s/host_summary_by_statement_type.sql +SOURCE ./views/p_s/x_host_summary_by_statement_type.sql +SOURCE ./views/p_s/host_summary_by_statement_latency.sql +SOURCE ./views/p_s/x_host_summary_by_statement_latency.sql +SOURCE ./views/p_s/host_summary_by_stages.sql +SOURCE ./views/p_s/x_host_summary_by_stages.sql +SOURCE ./views/p_s/host_summary.sql +SOURCE ./views/p_s/x_host_summary.sql + +SOURCE ./views/p_s/wait_classes_global_by_avg_latency.sql +SOURCE ./views/p_s/x_wait_classes_global_by_avg_latency.sql +SOURCE ./views/p_s/wait_classes_global_by_latency.sql +SOURCE ./views/p_s/x_wait_classes_global_by_latency.sql +SOURCE ./views/p_s/waits_by_user_by_latency.sql +SOURCE ./views/p_s/x_waits_by_user_by_latency.sql +SOURCE ./views/p_s/waits_by_host_by_latency.sql +SOURCE ./views/p_s/x_waits_by_host_by_latency.sql +SOURCE ./views/p_s/waits_global_by_latency.sql +SOURCE ./views/p_s/x_waits_global_by_latency.sql + +SOURCE ./views/p_s/metrics_56.sql + +SOURCE ./procedures/create_synonym_db.sql +SOURCE ./procedures/execute_prepared_stmt.sql + +SOURCE ./procedures/diagnostics.sql + +SOURCE ./procedures/ps_statement_avg_latency_histogram.sql +SOURCE ./procedures/ps_trace_statement_digest.sql +SOURCE ./procedures/ps_trace_thread.sql + +SOURCE ./procedures/ps_setup_disable_background_threads.sql +SOURCE ./procedures/ps_setup_disable_consumer.sql +SOURCE ./procedures/ps_setup_disable_instrument.sql +SOURCE ./procedures/ps_setup_disable_thread.sql + +SOURCE ./procedures/ps_setup_enable_background_threads.sql +SOURCE ./procedures/ps_setup_enable_consumer.sql +SOURCE ./procedures/ps_setup_enable_instrument.sql +SOURCE ./procedures/ps_setup_enable_thread.sql + +SOURCE ./procedures/ps_setup_reload_saved.sql +SOURCE ./procedures/ps_setup_reset_to_default_57_before.sql +SOURCE ./procedures/ps_setup_reset_to_default.sql +SOURCE ./procedures/ps_setup_reset_to_default_57_after.sql +SOURCE ./procedures/ps_setup_save.sql +SOURCE ./procedures/ps_setup_show_disabled.sql +SOURCE ./procedures/ps_setup_show_disabled_consumers.sql +SOURCE ./procedures/ps_setup_show_disabled_instruments.sql +SOURCE ./procedures/ps_setup_show_enabled.sql +SOURCE ./procedures/ps_setup_show_enabled_consumers.sql +SOURCE ./procedures/ps_setup_show_enabled_instruments.sql +SOURCE ./procedures/ps_truncate_all_tables.sql + +SOURCE ./procedures/statement_performance_analyzer.sql +SOURCE ./procedures/table_exists.sql + +SOURCE ./after_setup.sql diff --git a/scripts/sys_schema/sys_57.sql b/scripts/sys_schema/sys_57.sql new file mode 100644 index 00000000..277cc624 --- /dev/null +++ b/scripts/sys_schema/sys_57.sql @@ -0,0 +1,195 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +SOURCE ./before_setup.sql + +SOURCE ./views/version.sql + +SOURCE ./tables/sys_config.sql +SOURCE ./tables/sys_config_data_57.sql + +SOURCE ./triggers/sys_config_insert_set_user.sql +SOURCE ./triggers/sys_config_update_set_user.sql + +SOURCE ./functions/extract_schema_from_file_name.sql +SOURCE ./functions/extract_table_from_file_name.sql +SOURCE ./functions/format_bytes.sql +SOURCE ./functions/format_path_57.sql +SOURCE ./functions/format_statement.sql +SOURCE ./functions/format_time.sql +SOURCE ./functions/list_add.sql +SOURCE ./functions/list_drop.sql +SOURCE ./functions/ps_is_account_enabled_57.sql +SOURCE ./functions/ps_is_consumer_enabled.sql +SOURCE ./functions/ps_is_instrument_default_enabled.sql +SOURCE ./functions/ps_is_instrument_default_timed.sql +SOURCE ./functions/ps_is_thread_instrumented.sql +SOURCE ./functions/ps_thread_id.sql +SOURCE ./functions/ps_thread_account.sql +SOURCE ./functions/ps_thread_stack.sql +SOURCE ./functions/ps_thread_trx_info.sql +SOURCE ./functions/quote_identifier.sql +SOURCE ./functions/sys_get_config.sql +SOURCE ./functions/version_major.sql +SOURCE ./functions/version_minor.sql +SOURCE ./functions/version_patch.sql + +SOURCE ./views/i_s/innodb_buffer_stats_by_schema.sql +SOURCE ./views/i_s/x_innodb_buffer_stats_by_schema.sql +SOURCE ./views/i_s/innodb_buffer_stats_by_table.sql +SOURCE ./views/i_s/x_innodb_buffer_stats_by_table.sql +SOURCE ./views/i_s/innodb_lock_waits.sql +SOURCE ./views/i_s/x_innodb_lock_waits.sql +SOURCE ./views/i_s/schema_object_overview.sql +SOURCE ./views/i_s/schema_auto_increment_columns.sql +SOURCE ./views/i_s/x_schema_flattened_keys.sql +SOURCE ./views/i_s/schema_redundant_indexes.sql + +SOURCE ./views/p_s/ps_check_lost_instrumentation_57.sql + +SOURCE ./views/p_s/latest_file_io.sql +SOURCE ./views/p_s/x_latest_file_io.sql +SOURCE ./views/p_s/io_by_thread_by_latency.sql +SOURCE ./views/p_s/x_io_by_thread_by_latency.sql +SOURCE ./views/p_s/io_global_by_file_by_bytes.sql +SOURCE ./views/p_s/x_io_global_by_file_by_bytes.sql +SOURCE ./views/p_s/io_global_by_file_by_latency.sql +SOURCE ./views/p_s/x_io_global_by_file_by_latency.sql +SOURCE ./views/p_s/io_global_by_wait_by_bytes.sql +SOURCE ./views/p_s/x_io_global_by_wait_by_bytes.sql +SOURCE ./views/p_s/io_global_by_wait_by_latency.sql +SOURCE ./views/p_s/x_io_global_by_wait_by_latency.sql + +SOURCE ./views/p_s/memory_by_user_by_current_bytes.sql +SOURCE ./views/p_s/x_memory_by_user_by_current_bytes.sql +SOURCE ./views/p_s/memory_by_host_by_current_bytes.sql +SOURCE ./views/p_s/x_memory_by_host_by_current_bytes.sql +SOURCE ./views/p_s/memory_by_thread_by_current_bytes.sql +SOURCE ./views/p_s/x_memory_by_thread_by_current_bytes.sql +SOURCE ./views/p_s/memory_global_by_current_bytes.sql +SOURCE ./views/p_s/x_memory_global_by_current_bytes.sql +SOURCE ./views/p_s/memory_global_total.sql +SOURCE ./views/p_s/x_memory_global_total.sql + +SOURCE ./views/p_s/schema_index_statistics.sql +SOURCE ./views/p_s/x_schema_index_statistics.sql +SOURCE ./views/p_s/x_ps_schema_table_statistics_io.sql +SOURCE ./views/p_s/schema_table_statistics.sql +SOURCE ./views/p_s/x_schema_table_statistics.sql +SOURCE ./views/p_s/schema_table_statistics_with_buffer.sql +SOURCE ./views/p_s/x_schema_table_statistics_with_buffer.sql +SOURCE ./views/p_s/schema_tables_with_full_table_scans.sql +SOURCE ./views/p_s/x_schema_tables_with_full_table_scans.sql +SOURCE ./views/p_s/schema_unused_indexes.sql +SOURCE ./views/p_s/schema_table_lock_waits.sql +SOURCE ./views/p_s/x_schema_table_lock_waits.sql + +SOURCE ./views/p_s/statement_analysis.sql +SOURCE ./views/p_s/x_statement_analysis.sql +SOURCE ./views/p_s/statements_with_errors_or_warnings.sql +SOURCE ./views/p_s/x_statements_with_errors_or_warnings.sql +SOURCE ./views/p_s/statements_with_full_table_scans.sql +SOURCE ./views/p_s/x_statements_with_full_table_scans.sql +SOURCE ./views/p_s/x_ps_digest_avg_latency_distribution.sql +SOURCE ./views/p_s/x_ps_digest_95th_percentile_by_avg_us.sql +SOURCE ./views/p_s/statements_with_runtimes_in_95th_percentile.sql +SOURCE ./views/p_s/x_statements_with_runtimes_in_95th_percentile.sql +SOURCE ./views/p_s/statements_with_sorting.sql +SOURCE ./views/p_s/x_statements_with_sorting.sql +SOURCE ./views/p_s/statements_with_temp_tables.sql +SOURCE ./views/p_s/x_statements_with_temp_tables.sql + +SOURCE ./views/p_s/user_summary_by_file_io_type.sql +SOURCE ./views/p_s/x_user_summary_by_file_io_type.sql +SOURCE ./views/p_s/user_summary_by_file_io.sql +SOURCE ./views/p_s/x_user_summary_by_file_io.sql +SOURCE ./views/p_s/user_summary_by_statement_type.sql +SOURCE ./views/p_s/x_user_summary_by_statement_type.sql +SOURCE ./views/p_s/user_summary_by_statement_latency.sql +SOURCE ./views/p_s/x_user_summary_by_statement_latency.sql +SOURCE ./views/p_s/user_summary_by_stages.sql +SOURCE ./views/p_s/x_user_summary_by_stages.sql +SOURCE ./views/p_s/user_summary_57.sql +SOURCE ./views/p_s/x_user_summary_57.sql + +SOURCE ./views/p_s/host_summary_by_file_io_type.sql +SOURCE ./views/p_s/x_host_summary_by_file_io_type.sql +SOURCE ./views/p_s/host_summary_by_file_io.sql +SOURCE ./views/p_s/x_host_summary_by_file_io.sql +SOURCE ./views/p_s/host_summary_by_statement_type.sql +SOURCE ./views/p_s/x_host_summary_by_statement_type.sql +SOURCE ./views/p_s/host_summary_by_statement_latency.sql +SOURCE ./views/p_s/x_host_summary_by_statement_latency.sql +SOURCE ./views/p_s/host_summary_by_stages.sql +SOURCE ./views/p_s/x_host_summary_by_stages.sql +SOURCE ./views/p_s/host_summary_57.sql +SOURCE ./views/p_s/x_host_summary_57.sql + +SOURCE ./views/p_s/wait_classes_global_by_avg_latency.sql +SOURCE ./views/p_s/x_wait_classes_global_by_avg_latency.sql +SOURCE ./views/p_s/wait_classes_global_by_latency.sql +SOURCE ./views/p_s/x_wait_classes_global_by_latency.sql +SOURCE ./views/p_s/waits_by_user_by_latency.sql +SOURCE ./views/p_s/x_waits_by_user_by_latency.sql +SOURCE ./views/p_s/waits_by_host_by_latency.sql +SOURCE ./views/p_s/x_waits_by_host_by_latency.sql +SOURCE ./views/p_s/waits_global_by_latency.sql +SOURCE ./views/p_s/x_waits_global_by_latency.sql + +SOURCE ./views/p_s/metrics.sql + +SOURCE ./views/p_s/processlist_57.sql +SOURCE ./views/p_s/x_processlist_57.sql + +SOURCE ./views/p_s/sessions.sql +SOURCE ./views/p_s/x_sessions.sql +SOURCE ./views/p_s/session_ssl_status.sql + +SOURCE ./procedures/create_synonym_db.sql +SOURCE ./procedures/execute_prepared_stmt.sql + +SOURCE ./procedures/diagnostics.sql + +SOURCE ./procedures/ps_statement_avg_latency_histogram.sql +SOURCE ./procedures/ps_trace_statement_digest.sql +SOURCE ./procedures/ps_trace_thread_57.sql + +SOURCE ./procedures/ps_setup_disable_background_threads.sql +SOURCE ./procedures/ps_setup_disable_consumer.sql +SOURCE ./procedures/ps_setup_disable_instrument.sql +SOURCE ./procedures/ps_setup_disable_thread.sql + +SOURCE ./procedures/ps_setup_enable_background_threads.sql +SOURCE ./procedures/ps_setup_enable_consumer.sql +SOURCE ./procedures/ps_setup_enable_instrument.sql +SOURCE ./procedures/ps_setup_enable_thread.sql + +SOURCE ./procedures/ps_setup_reload_saved.sql +SOURCE ./procedures/ps_setup_reset_to_default_57_before.sql +SOURCE ./procedures/ps_setup_reset_to_default_57.sql +SOURCE ./procedures/ps_setup_reset_to_default_57_after.sql +SOURCE ./procedures/ps_setup_save.sql +SOURCE ./procedures/ps_setup_show_disabled.sql +SOURCE ./procedures/ps_setup_show_disabled_consumers.sql +SOURCE ./procedures/ps_setup_show_disabled_instruments.sql +SOURCE ./procedures/ps_setup_show_enabled.sql +SOURCE ./procedures/ps_setup_show_enabled_consumers.sql +SOURCE ./procedures/ps_setup_show_enabled_instruments.sql +SOURCE ./procedures/ps_truncate_all_tables.sql + +SOURCE ./procedures/statement_performance_analyzer.sql +SOURCE ./procedures/table_exists.sql + +SOURCE ./after_setup.sql diff --git a/scripts/sys_schema/tables/sys_config.sql b/scripts/sys_schema/tables/sys_config.sql new file mode 100644 index 00000000..37d0a183 --- /dev/null +++ b/scripts/sys_schema/tables/sys_config.sql @@ -0,0 +1,29 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- Table: sys_config +-- +-- Stores configuration options for sys objects +-- + +CREATE TABLE IF NOT EXISTS sys_config ( + variable VARCHAR(128) PRIMARY KEY, + value VARCHAR(128), + set_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + set_by VARCHAR(128) +) ENGINE = Aria; + + diff --git a/scripts/sys_schema/tables/sys_config_data.sql b/scripts/sys_schema/tables/sys_config_data.sql new file mode 100644 index 00000000..fb322fc7 --- /dev/null +++ b/scripts/sys_schema/tables/sys_config_data.sql @@ -0,0 +1,23 @@ +-- Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- NOTE: This needs to be replicated within the sys_config_clean.inc file + +INSERT IGNORE INTO sys.sys_config (variable, value) VALUES + ('statement_truncate_len', 64), + ('statement_performance_analyzer.limit', 100), + ('statement_performance_analyzer.view', NULL), + ('diagnostics.allow_i_s_tables', 'OFF'), + ('diagnostics.include_raw', 'OFF'); diff --git a/scripts/sys_schema/tables/sys_config_data_57.sql b/scripts/sys_schema/tables/sys_config_data_57.sql new file mode 100644 index 00000000..4abbb0b1 --- /dev/null +++ b/scripts/sys_schema/tables/sys_config_data_57.sql @@ -0,0 +1,26 @@ +-- Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- NOTE: This needs to be replicated within the sys_config_clean.inc file + +INSERT IGNORE INTO sys.sys_config (variable, value) VALUES + ('statement_truncate_len', 64), + ('statement_performance_analyzer.limit', 100), + ('statement_performance_analyzer.view', NULL), + ('diagnostics.allow_i_s_tables', 'OFF'), + ('diagnostics.include_raw', 'OFF'), + ('ps_thread_trx_info.max_length', 65535); + +FLUSH TABLES sys.sys_config; diff --git a/scripts/sys_schema/templates/function.sql b/scripts/sys_schema/templates/function.sql new file mode 100644 index 00000000..dac7899d --- /dev/null +++ b/scripts/sys_schema/templates/function.sql @@ -0,0 +1,56 @@ +-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP FUNCTION IF EXISTS <function name>; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' FUNCTION <function name> ( + /* Variables */ + ) + RETURNS <data type> + COMMENT ' + Description + ----------- + + ... + + Parameters + ----------- + + ... + + Returns + ----------- + + <data type> + + Example + ----------- + + ... + + ' + SQL SECURITY INVOKER + { DETERMINISTIC | NOT DETERMINISTIC } + { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } +BEGIN + + /* BODY */ + RETURN <something>; + +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/templates/procedure.sql b/scripts/sys_schema/templates/procedure.sql new file mode 100644 index 00000000..a6b0860a --- /dev/null +++ b/scripts/sys_schema/templates/procedure.sql @@ -0,0 +1,56 @@ +-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +DROP PROCEDURE IF EXISTS <procedure_name>; + +DELIMITER $$ + +CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE <procedure_name> ( + /* Variables */ + ) + COMMENT ' + Description + ----------- + + ... + + Parameters + ----------- + + ... + + + Configuration Options + ---------------------- + + ... + + + Example + -------- + + ... + + ' + SQL SECURITY INVOKER + { DETERMINISTIC | NOT DETERMINISTIC } + { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } +BEGIN + + /* BODY */ + +END$$ + +DELIMITER ; diff --git a/scripts/sys_schema/triggers/sys_config_insert_set_user.sql b/scripts/sys_schema/triggers/sys_config_insert_set_user.sql new file mode 100644 index 00000000..3d608ace --- /dev/null +++ b/scripts/sys_schema/triggers/sys_config_insert_set_user.sql @@ -0,0 +1,24 @@ +-- Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- Trigger: sys_config_insert_set_user +-- +-- Sets the user that inserts configuration +-- +-- + +DROP TRIGGER IF EXISTS sys_config_insert_set_user; + diff --git a/scripts/sys_schema/triggers/sys_config_update_set_user.sql b/scripts/sys_schema/triggers/sys_config_update_set_user.sql new file mode 100644 index 00000000..8b956da7 --- /dev/null +++ b/scripts/sys_schema/triggers/sys_config_update_set_user.sql @@ -0,0 +1,24 @@ +-- Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- Trigger: sys_config_update_set_user +-- +-- Sets the user that updates configuration +-- +-- + + +DROP TRIGGER IF EXISTS sys_config_update_set_user; diff --git a/scripts/sys_schema/views/i_s/innodb_buffer_stats_by_schema.sql b/scripts/sys_schema/views/i_s/innodb_buffer_stats_by_schema.sql new file mode 100644 index 00000000..46f7cdd0 --- /dev/null +++ b/scripts/sys_schema/views/i_s/innodb_buffer_stats_by_schema.sql @@ -0,0 +1,65 @@ +-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: innodb_buffer_stats_by_schema +-- +-- Summarizes the output of the INFORMATION_SCHEMA.INNODB_BUFFER_PAGE +-- table, aggregating by schema +-- +-- +-- mysql> select * from innodb_buffer_stats_by_schema; +-- +--------------------------+------------+------------+-------+--------------+-----------+-------------+ +-- | object_schema | allocated | data | pages | pages_hashed | pages_old | rows_cached | +-- +--------------------------+------------+------------+-------+--------------+-----------+-------------+ +-- | mem30_trunk__instruments | 1.69 MiB | 510.03 KiB | 108 | 108 | 108 | 3885 | +-- | InnoDB System | 688.00 KiB | 351.62 KiB | 43 | 43 | 43 | 862 | +-- | mem30_trunk__events | 80.00 KiB | 21.61 KiB | 5 | 5 | 5 | 229 | +-- +--------------------------+------------+------------+-------+--------------+-----------+-------------+ +-- + +DELIMITER $$ + +BEGIN NOT ATOMIC + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + END; +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW innodb_buffer_stats_by_schema ( + object_schema, + allocated, + data, + pages, + pages_hashed, + pages_old, + rows_cached +) AS +SELECT IF(LOCATE('.', ibp.table_name) = 0, 'InnoDB System', REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', 1), '`', '')) AS object_schema, + sys.format_bytes(SUM(IF(ibp.compressed_size = 0, 16384, compressed_size))) AS allocated, + sys.format_bytes(SUM(ibp.data_size)) AS data, + COUNT(ibp.page_number) AS pages, + COUNT(IF(ibp.is_hashed = 'YES', 1, NULL)) AS pages_hashed, + COUNT(IF(ibp.is_old = 'YES', 1, NULL)) AS pages_old, + ROUND(SUM(ibp.number_records)/COUNT(DISTINCT ibp.index_name)) AS rows_cached + FROM information_schema.innodb_buffer_page ibp + WHERE table_name IS NOT NULL + GROUP BY object_schema + ORDER BY SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) DESC; +END$$ +DELIMITER ; + diff --git a/scripts/sys_schema/views/i_s/innodb_buffer_stats_by_table.sql b/scripts/sys_schema/views/i_s/innodb_buffer_stats_by_table.sql new file mode 100644 index 00000000..be104fb5 --- /dev/null +++ b/scripts/sys_schema/views/i_s/innodb_buffer_stats_by_table.sql @@ -0,0 +1,67 @@ +-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: innodb_buffer_stats_by_table +-- +-- Summarizes the output of the INFORMATION_SCHEMA.INNODB_BUFFER_PAGE +-- table, aggregating by schema and table name +-- +-- mysql> select * from innodb_buffer_stats_by_table; +-- +--------------------------+------------------------------------+------------+-----------+-------+--------------+-----------+-------------+ +-- | object_schema | object_name | allocated | data | pages | pages_hashed | pages_old | rows_cached | +-- +--------------------------+------------------------------------+------------+-----------+-------+--------------+-----------+-------------+ +-- | InnoDB System | SYS_COLUMNS | 128.00 KiB | 98.97 KiB | 8 | 8 | 8 | 1532 | +-- | InnoDB System | SYS_FOREIGN | 128.00 KiB | 55.48 KiB | 8 | 8 | 8 | 172 | +-- | InnoDB System | SYS_TABLES | 128.00 KiB | 56.18 KiB | 8 | 8 | 8 | 365 | +-- | InnoDB System | SYS_INDEXES | 112.00 KiB | 76.16 KiB | 7 | 7 | 7 | 1046 | +-- | mem30_trunk__instruments | agentlatencytime | 96.00 KiB | 28.83 KiB | 6 | 6 | 6 | 252 | +-- | mem30_trunk__instruments | binlogspaceusagedata | 96.00 KiB | 22.54 KiB | 6 | 6 | 6 | 196 | +-- | mem30_trunk__instruments | connectionsdata | 96.00 KiB | 36.68 KiB | 6 | 6 | 6 | 276 | +-- ... +-- +--------------------------+------------------------------------+------------+-----------+-------+--------------+-----------+-------------+ +-- + +DELIMITER $$ +BEGIN NOT ATOMIC +DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END; +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW innodb_buffer_stats_by_table ( + object_schema, + object_name, + allocated, + data, + pages, + pages_hashed, + pages_old, + rows_cached +) AS +SELECT IF(LOCATE('.', ibp.table_name) = 0, 'InnoDB System', REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', 1), '`', '')) AS object_schema, + REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', -1), '`', '') AS object_name, + sys.format_bytes(SUM(IF(ibp.compressed_size = 0, 16384, compressed_size))) AS allocated, + sys.format_bytes(SUM(ibp.data_size)) AS data, + COUNT(ibp.page_number) AS pages, + COUNT(IF(ibp.is_hashed = 'YES', 1, NULL)) AS pages_hashed, + COUNT(IF(ibp.is_old = 'YES', 1, NULL)) AS pages_old, + ROUND(SUM(ibp.number_records)/COUNT(DISTINCT ibp.index_name)) AS rows_cached + FROM information_schema.innodb_buffer_page ibp + WHERE table_name IS NOT NULL + GROUP BY object_schema, object_name + ORDER BY SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) DESC; +END$$ +DELIMITER ;
\ No newline at end of file diff --git a/scripts/sys_schema/views/i_s/innodb_lock_waits.sql b/scripts/sys_schema/views/i_s/innodb_lock_waits.sql new file mode 100644 index 00000000..493eacfc --- /dev/null +++ b/scripts/sys_schema/views/i_s/innodb_lock_waits.sql @@ -0,0 +1,124 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: innodb_lock_waits +-- +-- Give a snapshot of which InnoDB locks transactions are waiting for. +-- The lock waits are ordered by the age of the lock descending. +-- +-- Versions: 5.1+ (5.1 requires InnoDB Plugin with I_S tables) +-- +-- mysql> SELECT * FROM x$innodb_lock_waits\G +-- *************************** 1. row *************************** +-- wait_started: 2014-11-11 13:39:20 +-- wait_age: 00:00:07 +-- wait_age_secs: 7 +-- locked_table: `db1`.`t1` +-- locked_index: PRIMARY +-- locked_type: RECORD +-- waiting_trx_id: 867158 +-- waiting_trx_started: 2014-11-11 13:39:15 +-- waiting_trx_age: 00:00:12 +-- waiting_trx_rows_locked: 0 +-- waiting_trx_rows_modified: 0 +-- waiting_pid: 3 +-- waiting_query: UPDATE t1 SET val = val + 1 WHERE id = 2 +-- waiting_lock_id: 867158:2363:3:3 +-- waiting_lock_mode: X +-- blocking_trx_id: 867157 +-- blocking_pid: 4 +-- blocking_query: UPDATE t1 SET val = val + 1 + SLEEP(10) WHERE id = 2 +-- blocking_lock_id: 867157:2363:3:3 +-- blocking_lock_mode: X +-- blocking_trx_started: 2014-11-11 13:39:11 +-- blocking_trx_age: 00:00:16 +-- blocking_trx_rows_locked: 1 +-- blocking_trx_rows_modified: 1 +-- sql_kill_blocking_query: KILL QUERY 4 +-- sql_kill_blocking_connection: KILL 4 +-- 1 row in set (0.01 sec) +-- +DELIMITER $$ +BEGIN NOT ATOMIC + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + END; +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW innodb_lock_waits ( + wait_started, + wait_age, + wait_age_secs, + locked_table, + locked_index, + locked_type, + waiting_trx_id, + waiting_trx_started, + waiting_trx_age, + waiting_trx_rows_locked, + waiting_trx_rows_modified, + waiting_pid, + waiting_query, + waiting_lock_id, + waiting_lock_mode, + blocking_trx_id, + blocking_pid, + blocking_query, + blocking_lock_id, + blocking_lock_mode, + blocking_trx_started, + blocking_trx_age, + blocking_trx_rows_locked, + blocking_trx_rows_modified, + sql_kill_blocking_query, + sql_kill_blocking_connection +) AS +SELECT r.trx_wait_started AS wait_started, + TIMEDIFF(NOW(), r.trx_wait_started) AS wait_age, + TIMESTAMPDIFF(SECOND, r.trx_wait_started, NOW()) AS wait_age_secs, + rl.lock_table AS locked_table, + rl.lock_index AS locked_index, + rl.lock_type AS locked_type, + r.trx_id AS waiting_trx_id, + r.trx_started as waiting_trx_started, + TIMEDIFF(NOW(), r.trx_started) AS waiting_trx_age, + r.trx_rows_locked AS waiting_trx_rows_locked, + r.trx_rows_modified AS waiting_trx_rows_modified, + r.trx_mysql_thread_id AS waiting_pid, + sys.format_statement(r.trx_query) AS waiting_query, + rl.lock_id AS waiting_lock_id, + rl.lock_mode AS waiting_lock_mode, + b.trx_id AS blocking_trx_id, + b.trx_mysql_thread_id AS blocking_pid, + sys.format_statement(b.trx_query) AS blocking_query, + bl.lock_id AS blocking_lock_id, + bl.lock_mode AS blocking_lock_mode, + b.trx_started AS blocking_trx_started, + TIMEDIFF(NOW(), b.trx_started) AS blocking_trx_age, + b.trx_rows_locked AS blocking_trx_rows_locked, + b.trx_rows_modified AS blocking_trx_rows_modified, + CONCAT('KILL QUERY ', b.trx_mysql_thread_id) AS sql_kill_blocking_query, + CONCAT('KILL ', b.trx_mysql_thread_id) AS sql_kill_blocking_connection + FROM information_schema.innodb_lock_waits w + INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id + INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id + INNER JOIN information_schema.innodb_locks bl ON bl.lock_id = w.blocking_lock_id + INNER JOIN information_schema.innodb_locks rl ON rl.lock_id = w.requested_lock_id + ORDER BY r.trx_wait_started; + END$$ +DELIMITER ; diff --git a/scripts/sys_schema/views/i_s/schema_auto_increment_columns.sql b/scripts/sys_schema/views/i_s/schema_auto_increment_columns.sql new file mode 100644 index 00000000..98c95695 --- /dev/null +++ b/scripts/sys_schema/views/i_s/schema_auto_increment_columns.sql @@ -0,0 +1,66 @@ + +-- +-- View: schema_auto_increment_columns +-- +-- Present current auto_increment usage/capacity in all tables. +-- +-- mysql> select * from schema_auto_increment_columns limit 5; +-- +-------------------+-------------------+-------------+-----------+-------------+-----------+-------------+---------------------+----------------+----------------------+ +-- | table_schema | table_name | column_name | data_type | column_type | is_signed | is_unsigned | max_value | auto_increment | auto_increment_ratio | +-- +-------------------+-------------------+-------------+-----------+-------------+-----------+-------------+---------------------+----------------+----------------------+ +-- | test | t1 | i | tinyint | tinyint(4) | 1 | 0 | 127 | 34 | 0.2677 | +-- | mem__advisor_text | template_meta | hib_id | int | int(11) | 1 | 0 | 2147483647 | 516 | 0.0000 | +-- | mem__advisors | advisor_schedules | schedule_id | int | int(11) | 1 | 0 | 2147483647 | 249 | 0.0000 | +-- | mem__advisors | app_identity_path | hib_id | int | int(11) | 1 | 0 | 2147483647 | 251 | 0.0000 | +-- | mem__bean_config | plists | id | bigint | bigint(20) | 1 | 0 | 9223372036854775807 | 1 | 0.0000 | +-- +-------------------+-------------------+-------------+-----------+-------------+-----------+-------------+---------------------+----------------+----------------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW schema_auto_increment_columns ( + table_schema, + table_name, + column_name, + data_type, + column_type, + is_signed, + is_unsigned, + max_value, + auto_increment, + auto_increment_ratio +) AS +SELECT TABLE_SCHEMA, + TABLE_NAME, + COLUMN_NAME, + DATA_TYPE, + COLUMN_TYPE, + (LOCATE('unsigned', COLUMN_TYPE) = 0) AS is_signed, + (LOCATE('unsigned', COLUMN_TYPE) > 0) AS is_unsigned, + ( + CASE DATA_TYPE + WHEN 'tinyint' THEN 255 + WHEN 'smallint' THEN 65535 + WHEN 'mediumint' THEN 16777215 + WHEN 'int' THEN 4294967295 + WHEN 'bigint' THEN 18446744073709551615 + END >> IF(LOCATE('unsigned', COLUMN_TYPE) > 0, 0, 1) + ) AS max_value, + AUTO_INCREMENT, + AUTO_INCREMENT / ( + CASE DATA_TYPE + WHEN 'tinyint' THEN 255 + WHEN 'smallint' THEN 65535 + WHEN 'mediumint' THEN 16777215 + WHEN 'int' THEN 4294967295 + WHEN 'bigint' THEN 18446744073709551615 + END >> IF(LOCATE('unsigned', COLUMN_TYPE) > 0, 0, 1) + ) AS auto_increment_ratio + FROM INFORMATION_SCHEMA.COLUMNS + INNER JOIN INFORMATION_SCHEMA.TABLES USING (TABLE_SCHEMA, TABLE_NAME) + WHERE TABLE_SCHEMA NOT IN ('mysql', 'sys', 'INFORMATION_SCHEMA', 'performance_schema') + AND TABLE_TYPE='BASE TABLE' + AND EXTRA='auto_increment' + ORDER BY auto_increment_ratio DESC, max_value; diff --git a/scripts/sys_schema/views/i_s/schema_object_overview.sql b/scripts/sys_schema/views/i_s/schema_object_overview.sql new file mode 100644 index 00000000..9da11254 --- /dev/null +++ b/scripts/sys_schema/views/i_s/schema_object_overview.sql @@ -0,0 +1,58 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: schema_object_overview +-- +-- Shows an overview of the types of objects within each schema +-- +-- Note: On instances with a large number of objects, this could take +-- some time to execute, and is not recommended. +-- +-- mysql> select * from schema_object_overview; +-- +---------------------------------+---------------+-------+ +-- | db | object_type | count | +-- +---------------------------------+---------------+-------+ +-- | information_schema | SYSTEM VIEW | 59 | +-- | mem30_test__instruments | BASE TABLE | 1 | +-- | mem30_test__instruments | INDEX (BTREE) | 2 | +-- | mem30_test__test | BASE TABLE | 9 | +-- | mem30_test__test | INDEX (BTREE) | 19 | +-- ... +-- | sys | FUNCTION | 8 | +-- | sys | PROCEDURE | 16 | +-- | sys | VIEW | 59 | +-- +---------------------------------+---------------+-------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW schema_object_overview ( + db, + object_type, + count +) AS +SELECT ROUTINE_SCHEMA AS db, ROUTINE_TYPE AS object_type, COUNT(*) AS count FROM information_schema.routines GROUP BY ROUTINE_SCHEMA, ROUTINE_TYPE + UNION +SELECT TABLE_SCHEMA, TABLE_TYPE, COUNT(*) FROM information_schema.tables GROUP BY TABLE_SCHEMA, TABLE_TYPE + UNION +SELECT TABLE_SCHEMA, CONCAT('INDEX (', INDEX_TYPE, ')'), COUNT(*) FROM information_schema.statistics GROUP BY TABLE_SCHEMA, INDEX_TYPE + UNION +SELECT TRIGGER_SCHEMA, 'TRIGGER', COUNT(*) FROM information_schema.triggers GROUP BY TRIGGER_SCHEMA + UNION +SELECT EVENT_SCHEMA, 'EVENT', COUNT(*) FROM information_schema.events GROUP BY EVENT_SCHEMA +ORDER BY DB, OBJECT_TYPE; diff --git a/scripts/sys_schema/views/i_s/schema_redundant_indexes.sql b/scripts/sys_schema/views/i_s/schema_redundant_indexes.sql new file mode 100644 index 00000000..8ad8bb82 --- /dev/null +++ b/scripts/sys_schema/views/i_s/schema_redundant_indexes.sql @@ -0,0 +1,92 @@ +-- +-- View: schema_redundant_keys +-- +-- Shows indexes which are made redundant (or duplicate) by other (dominant) keys. +-- +-- mysql> select * from sys.schema_redundant_indexes\G +-- *************************** 1. row *************************** +-- table_schema: test +-- table_name: rkey +-- redundant_index_name: j +-- redundant_index_columns: j +-- redundant_index_non_unique: 1 +-- dominant_index_name: j_2 +-- dominant_index_columns: j,k +-- dominant_index_non_unique: 1 +-- subpart_exists: 0 +-- sql_drop_index: ALTER TABLE `test`.`rkey` DROP INDEX `j` +-- 1 row in set (0.20 sec) +-- +-- mysql> SHOW CREATE TABLE test.rkey\G +-- *************************** 1. row *************************** +-- Table: rkey +-- Create Table: CREATE TABLE `rkey` ( +-- `i` int(11) NOT NULL, +-- `j` int(11) DEFAULT NULL, +-- `k` int(11) DEFAULT NULL, +-- PRIMARY KEY (`i`), +-- KEY `j` (`j`), +-- KEY `j_2` (`j`,`k`) +-- ) ENGINE=InnoDB DEFAULT CHARSET=latin1 +-- 1 row in set (0.06 sec) +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW schema_redundant_indexes ( + table_schema, + table_name, + redundant_index_name, + redundant_index_columns, + redundant_index_non_unique, + dominant_index_name, + dominant_index_columns, + dominant_index_non_unique, + subpart_exists, + sql_drop_index +) AS + SELECT + redundant_keys.table_schema, + redundant_keys.table_name, + redundant_keys.index_name AS redundant_index_name, + redundant_keys.index_columns AS redundant_index_columns, + redundant_keys.non_unique AS redundant_index_non_unique, + dominant_keys.index_name AS dominant_index_name, + dominant_keys.index_columns AS dominant_index_columns, + dominant_keys.non_unique AS dominant_index_non_unique, + IF(redundant_keys.subpart_exists OR dominant_keys.subpart_exists, 1 ,0) AS subpart_exists, + CONCAT( + 'ALTER TABLE `', redundant_keys.table_schema, '`.`', redundant_keys.table_name, '` DROP INDEX `', redundant_keys.index_name, '`' + ) AS sql_drop_index + FROM + x$schema_flattened_keys AS redundant_keys + INNER JOIN x$schema_flattened_keys AS dominant_keys + USING (TABLE_SCHEMA, TABLE_NAME) + WHERE + redundant_keys.index_name != dominant_keys.index_name + AND ( + ( + /* Identical columns */ + (redundant_keys.index_columns = dominant_keys.index_columns) + AND ( + (redundant_keys.non_unique > dominant_keys.non_unique) + OR (redundant_keys.non_unique = dominant_keys.non_unique + AND IF(redundant_keys.index_name='PRIMARY', '', redundant_keys.index_name) > IF(dominant_keys.index_name='PRIMARY', '', dominant_keys.index_name) + ) + ) + ) + OR + ( + /* Non-unique prefix columns */ + LOCATE(CONCAT(redundant_keys.index_columns, ','), dominant_keys.index_columns) = 1 + AND redundant_keys.non_unique = 1 + ) + OR + ( + /* Unique prefix columns */ + LOCATE(CONCAT(dominant_keys.index_columns, ','), redundant_keys.index_columns) = 1 + AND dominant_keys.non_unique = 0 + ) + ); diff --git a/scripts/sys_schema/views/i_s/x_innodb_buffer_stats_by_schema.sql b/scripts/sys_schema/views/i_s/x_innodb_buffer_stats_by_schema.sql new file mode 100644 index 00000000..6637f509 --- /dev/null +++ b/scripts/sys_schema/views/i_s/x_innodb_buffer_stats_by_schema.sql @@ -0,0 +1,62 @@ +-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$innodb_buffer_stats_by_schema +-- +-- Summarizes the output of the INFORMATION_SCHEMA.INNODB_BUFFER_PAGE +-- table, aggregating by schema +-- +-- mysql> select * from x$innodb_buffer_stats_by_schema; +-- +--------------------------+-----------+--------+-------+--------------+-----------+-------------+ +-- | object_schema | allocated | data | pages | pages_hashed | pages_old | rows_cached | +-- +--------------------------+-----------+--------+-------+--------------+-----------+-------------+ +-- | mem30_trunk__instruments | 1769472 | 522272 | 108 | 108 | 108 | 3885 | +-- | InnoDB System | 704512 | 360054 | 43 | 43 | 43 | 862 | +-- | mem30_trunk__events | 81920 | 22125 | 5 | 5 | 5 | 229 | +-- +--------------------------+-----------+--------+-------+--------------+-----------+-------------+ +-- + +DELIMITER $$ +BEGIN NOT ATOMIC + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + END; +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$innodb_buffer_stats_by_schema ( + object_schema, + allocated, + data, + pages, + pages_hashed, + pages_old, + rows_cached +) AS +SELECT IF(LOCATE('.', ibp.table_name) = 0, 'InnoDB System', REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', 1), '`', '')) AS object_schema, + SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) AS allocated, + SUM(ibp.data_size) AS data, + COUNT(ibp.page_number) AS pages, + COUNT(IF(ibp.is_hashed, 1, NULL)) AS pages_hashed, + COUNT(IF(ibp.is_old, 1, NULL)) AS pages_old, + ROUND(IFNULL(SUM(ibp.number_records)/NULLIF(COUNT(DISTINCT ibp.index_name), 0), 0)) AS rows_cached + FROM information_schema.innodb_buffer_page ibp + WHERE table_name IS NOT NULL + GROUP BY object_schema + ORDER BY SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) DESC; +END$$ +DELIMITER ; diff --git a/scripts/sys_schema/views/i_s/x_innodb_buffer_stats_by_table.sql b/scripts/sys_schema/views/i_s/x_innodb_buffer_stats_by_table.sql new file mode 100644 index 00000000..39d19b05 --- /dev/null +++ b/scripts/sys_schema/views/i_s/x_innodb_buffer_stats_by_table.sql @@ -0,0 +1,66 @@ +-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$innodb_buffer_stats_by_table +-- +-- Summarizes the output of the INFORMATION_SCHEMA.INNODB_BUFFER_PAGE +-- table, aggregating by schema and table name +-- +-- mysql> select * from x$innodb_buffer_stats_by_table; +-- +--------------------------+------------------------------------+-----------+--------+-------+--------------+-----------+-------------+ +-- | object_schema | object_name | allocated | data | pages | pages_hashed | pages_old | rows_cached | +-- +--------------------------+------------------------------------+-----------+--------+-------+--------------+-----------+-------------+ +-- | InnoDB System | SYS_COLUMNS | 131072 | 101350 | 8 | 8 | 8 | 1532 | +-- | InnoDB System | SYS_FOREIGN | 131072 | 56808 | 8 | 8 | 8 | 172 | +-- | InnoDB System | SYS_TABLES | 131072 | 57529 | 8 | 8 | 8 | 365 | +-- | InnoDB System | SYS_INDEXES | 114688 | 77984 | 7 | 7 | 7 | 1046 | +-- | mem30_trunk__instruments | agentlatencytime | 98304 | 29517 | 6 | 6 | 6 | 252 | +-- | mem30_trunk__instruments | binlogspaceusagedata | 98304 | 23076 | 6 | 6 | 6 | 196 | +-- | mem30_trunk__instruments | connectionsdata | 98304 | 37563 | 6 | 6 | 6 | 276 | +-- ... +-- +--------------------------+------------------------------------+-----------+--------+-------+--------------+-----------+-------------+ +-- +DELIMITER $$ +BEGIN NOT ATOMIC +DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END; +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$innodb_buffer_stats_by_table ( + object_schema, + object_name, + allocated, + data, + pages, + pages_hashed, + pages_old, + rows_cached +) AS +SELECT IF(LOCATE('.', ibp.table_name) = 0, 'InnoDB System', REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', 1), '`', '')) AS object_schema, + REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', -1), '`', '') AS object_name, + SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) AS allocated, + SUM(ibp.data_size) AS data, + COUNT(ibp.page_number) AS pages, + COUNT(IF(ibp.is_hashed, 1, NULL)) AS pages_hashed, + COUNT(IF(ibp.is_old, 1, NULL)) AS pages_old, + ROUND(IFNULL(SUM(ibp.number_records)/NULLIF(COUNT(DISTINCT ibp.index_name), 0), 0)) AS rows_cached + FROM information_schema.innodb_buffer_page ibp + WHERE table_name IS NOT NULL + GROUP BY object_schema, object_name + ORDER BY SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) DESC; +END$$ +DELIMITER ;
\ No newline at end of file diff --git a/scripts/sys_schema/views/i_s/x_innodb_lock_waits.sql b/scripts/sys_schema/views/i_s/x_innodb_lock_waits.sql new file mode 100644 index 00000000..a36bc4d7 --- /dev/null +++ b/scripts/sys_schema/views/i_s/x_innodb_lock_waits.sql @@ -0,0 +1,124 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$innodb_lock_waits +-- +-- Give a snapshot of which InnoDB locks transactions are waiting for. +-- The lock waits are ordered by the age of the lock descending. +-- +-- Versions: 5.1+ (5.1 requires InnoDB Plugin with I_S tables) +-- +-- mysql> SELECT * FROM x$innodb_lock_waits\G +-- *************************** 1. row *************************** +-- wait_started: 2014-11-11 13:39:20 +-- wait_age: 00:00:07 +-- wait_age_secs: 7 +-- locked_table: `db1`.`t1` +-- locked_index: PRIMARY +-- locked_type: RECORD +-- waiting_trx_id: 867158 +-- waiting_trx_started: 2014-11-11 13:39:15 +-- waiting_trx_age: 00:00:12 +-- waiting_trx_rows_locked: 0 +-- waiting_trx_rows_modified: 0 +-- waiting_pid: 3 +-- waiting_query: UPDATE t1 SET val = val + 1 WHERE id = 2 +-- waiting_lock_id: 867158:2363:3:3 +-- waiting_lock_mode: X +-- blocking_trx_id: 867157 +-- blocking_pid: 4 +-- blocking_query: UPDATE t1 SET val = val + 1 + SLEEP(10) WHERE id = 2 +-- blocking_lock_id: 867157:2363:3:3 +-- blocking_lock_mode: X +-- blocking_trx_started: 2014-11-11 13:39:11 +-- blocking_trx_age: 00:00:16 +-- blocking_trx_rows_locked: 1 +-- blocking_trx_rows_modified: 1 +-- sql_kill_blocking_query: KILL QUERY 4 +-- sql_kill_blocking_connection: KILL 4 +-- 1 row in set (0.01 sec) +-- + +DELIMITER $$ +BEGIN NOT ATOMIC +DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END; + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$innodb_lock_waits ( + wait_started, + wait_age, + wait_age_secs, + locked_table, + locked_index, + locked_type, + waiting_trx_id, + waiting_trx_started, + waiting_trx_age, + waiting_trx_rows_locked, + waiting_trx_rows_modified, + waiting_pid, + waiting_query, + waiting_lock_id, + waiting_lock_mode, + blocking_trx_id, + blocking_pid, + blocking_query, + blocking_lock_id, + blocking_lock_mode, + blocking_trx_started, + blocking_trx_age, + blocking_trx_rows_locked, + blocking_trx_rows_modified, + sql_kill_blocking_query, + sql_kill_blocking_connection +) AS +SELECT r.trx_wait_started AS wait_started, + TIMEDIFF(NOW(), r.trx_wait_started) AS wait_age, + TIMESTAMPDIFF(SECOND, r.trx_wait_started, NOW()) AS wait_age_secs, + rl.lock_table AS locked_table, + rl.lock_index AS locked_index, + rl.lock_type AS locked_type, + r.trx_id AS waiting_trx_id, + r.trx_started as waiting_trx_started, + TIMEDIFF(NOW(), r.trx_started) AS waiting_trx_age, + r.trx_rows_locked AS waiting_trx_rows_locked, + r.trx_rows_modified AS waiting_trx_rows_modified, + r.trx_mysql_thread_id AS waiting_pid, + r.trx_query AS waiting_query, + rl.lock_id AS waiting_lock_id, + rl.lock_mode AS waiting_lock_mode, + b.trx_id AS blocking_trx_id, + b.trx_mysql_thread_id AS blocking_pid, + b.trx_query AS blocking_query, + bl.lock_id AS blocking_lock_id, + bl.lock_mode AS blocking_lock_mode, + b.trx_started AS blocking_trx_started, + TIMEDIFF(NOW(), b.trx_started) AS blocking_trx_age, + b.trx_rows_locked AS blocking_trx_rows_locked, + b.trx_rows_modified AS blocking_trx_rows_modified, + CONCAT('KILL QUERY ', b.trx_mysql_thread_id) AS sql_kill_blocking_query, + CONCAT('KILL ', b.trx_mysql_thread_id) AS sql_kill_blocking_connection + FROM information_schema.innodb_lock_waits w + INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id + INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id + INNER JOIN information_schema.innodb_locks bl ON bl.lock_id = w.blocking_lock_id + INNER JOIN information_schema.innodb_locks rl ON rl.lock_id = w.requested_lock_id + ORDER BY r.trx_wait_started; +END$$ +DELIMITER ; diff --git a/scripts/sys_schema/views/i_s/x_schema_flattened_keys.sql b/scripts/sys_schema/views/i_s/x_schema_flattened_keys.sql new file mode 100644 index 00000000..35001158 --- /dev/null +++ b/scripts/sys_schema/views/i_s/x_schema_flattened_keys.sql @@ -0,0 +1,42 @@ +-- +-- View: x$schema_flattened_keys +-- +-- Helper view for the schema_redundant_keys view. +-- +-- mysql> select * from sys.x$schema_flattened_keys; +-- +---------------+---------------------+------------------------------+------------+----------------+-----------------+ +-- | table_schema | table_name | index_name | non_unique | subpart_exists | index_columns | +-- +---------------+---------------------+------------------------------+------------+----------------+-----------------+ +-- | mem__advisors | advisor_initialized | PRIMARY | 0 | 0 | advisorClassId | +-- | mem__advisors | advisor_schedules | advisorClassIdIdx | 1 | 0 | advisorClassId | +-- | mem__advisors | advisor_schedules | PRIMARY | 0 | 0 | schedule_id | +-- | mem__advisors | app_identity_path | FK_7xbq2i81hgo0xlvnb6rr77s21 | 1 | 0 | for_schedule_id | +-- | mem__advisors | app_identity_path | PRIMARY | 0 | 0 | hib_id | +-- ... +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$schema_flattened_keys ( + table_schema, + table_name, + index_name, + non_unique, + subpart_exists, + index_columns +) AS + SELECT + TABLE_SCHEMA, + TABLE_NAME, + INDEX_NAME, + MAX(NON_UNIQUE) AS non_unique, + MAX(IF(SUB_PART IS NULL, 0, 1)) AS subpart_exists, + GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) AS index_columns + FROM INFORMATION_SCHEMA.STATISTICS + WHERE + INDEX_TYPE='BTREE' + AND TABLE_SCHEMA NOT IN ('mysql', 'sys', 'INFORMATION_SCHEMA', 'PERFORMANCE_SCHEMA') + GROUP BY + TABLE_SCHEMA, TABLE_NAME, INDEX_NAME; diff --git a/scripts/sys_schema/views/p_s/host_summary.sql b/scripts/sys_schema/views/p_s/host_summary.sql new file mode 100644 index 00000000..080100a4 --- /dev/null +++ b/scripts/sys_schema/views/p_s/host_summary.sql @@ -0,0 +1,60 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: host_summary +-- +-- Summarizes statement activity, file IO and connections by host. +-- +-- When the host found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from host_summary; +-- +------+------------+-------------------+-----------------------+-------------+----------+-----------------+---------------------+-------------------+--------------+ +-- | host | statements | statement_latency | statement_avg_latency | table_scans | file_ios | file_io_latency | current_connections | total_connections | unique_users | +-- +------+------------+-------------------+-----------------------+-------------+----------+-----------------+---------------------+-------------------+--------------+ +-- | hal1 | 2924 | 00:03:59.53 | 81.92 ms | 82 | 54702 | 55.61 s | 1 | 1 | 1 | +-- +------+------------+-------------------+-----------------------+-------------+----------+-----------------+---------------------+-------------------+--------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW host_summary ( + host, + statements, + statement_latency, + statement_avg_latency, + table_scans, + file_ios, + file_io_latency, + current_connections, + total_connections, + unique_users +) AS +SELECT IF(accounts.host IS NULL, 'background', accounts.host) AS host, + SUM(stmt.total) AS statements, + sys.format_time(SUM(stmt.total_latency)) AS statement_latency, + sys.format_time(IFNULL(SUM(stmt.total_latency) / NULLIF(SUM(stmt.total), 0), 0)) AS statement_avg_latency, + SUM(stmt.full_scans) AS table_scans, + SUM(io.ios) AS file_ios, + sys.format_time(SUM(io.io_latency)) AS file_io_latency, + SUM(accounts.current_connections) AS current_connections, + SUM(accounts.total_connections) AS total_connections, + COUNT(DISTINCT accounts.user) AS unique_users + FROM performance_schema.accounts + LEFT JOIN sys.x$host_summary_by_statement_latency AS stmt ON accounts.host = stmt.host + LEFT JOIN sys.x$host_summary_by_file_io AS io ON accounts.host = io.host + GROUP BY IF(accounts.host IS NULL, 'background', accounts.host); diff --git a/scripts/sys_schema/views/p_s/host_summary_57.sql b/scripts/sys_schema/views/p_s/host_summary_57.sql new file mode 100644 index 00000000..cd0739f4 --- /dev/null +++ b/scripts/sys_schema/views/p_s/host_summary_57.sql @@ -0,0 +1,66 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: host_summary +-- +-- Summarizes statement activity and connections by host +-- +-- When the host found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from host_summary; +-- +------+------------+---------------+-------------+---------------------+-------------------+--------------+----------------+------------------------+ +-- | host | statements | total_latency | avg_latency | current_connections | total_connections | unique_users | current_memory | total_memory_allocated | +-- +------+------------+---------------+-------------+---------------------+-------------------+--------------+----------------+------------------------+ +-- | hal1 | 5663 | 00:01:47.14 | 18.92 ms | 1 | 1 | 1 | 1.41 MiB | 543.55 MiB | +-- | hal2 | 225 | 14.49 s | 64.40 ms | 1 | 1 | 1 | 707.60 KiB | 81.02 MiB | +-- +------+------------+---------------+-------------+---------------------+-------------------+--------------+----------------+------------------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW host_summary ( + host, + statements, + statement_latency, + statement_avg_latency, + table_scans, + file_ios, + file_io_latency, + current_connections, + total_connections, + unique_users, + current_memory, + total_memory_allocated +) AS +SELECT IF(accounts.host IS NULL, 'background', accounts.host) AS host, + SUM(stmt.total) AS statements, + sys.format_time(SUM(stmt.total_latency)) AS statement_latency, + sys.format_time(IFNULL(SUM(stmt.total_latency) / NULLIF(SUM(stmt.total), 0), 0)) AS statement_avg_latency, + SUM(stmt.full_scans) AS table_scans, + SUM(io.ios) AS file_ios, + sys.format_time(SUM(io.io_latency)) AS file_io_latency, + SUM(accounts.current_connections) AS current_connections, + SUM(accounts.total_connections) AS total_connections, + COUNT(DISTINCT user) AS unique_users, + sys.format_bytes(SUM(mem.current_allocated)) AS current_memory, + sys.format_bytes(SUM(mem.total_allocated)) AS total_memory_allocated + FROM performance_schema.accounts + JOIN sys.x$host_summary_by_statement_latency AS stmt ON accounts.host = stmt.host + JOIN sys.x$host_summary_by_file_io AS io ON accounts.host = io.host + JOIN sys.x$memory_by_host_by_current_bytes mem ON accounts.host = mem.host + GROUP BY IF(accounts.host IS NULL, 'background', accounts.host); diff --git a/scripts/sys_schema/views/p_s/host_summary_by_file_io.sql b/scripts/sys_schema/views/p_s/host_summary_by_file_io.sql new file mode 100644 index 00000000..e1fbf2ea --- /dev/null +++ b/scripts/sys_schema/views/p_s/host_summary_by_file_io.sql @@ -0,0 +1,47 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: host_summary_by_file_io +-- +-- Summarizes file IO totals per host. +-- +-- When the host found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from host_summary_by_file_io; +-- +------------+-------+------------+ +-- | host | ios | io_latency | +-- +------------+-------+------------+ +-- | hal1 | 26457 | 21.58 s | +-- | hal2 | 1189 | 394.21 ms | +-- +------------+-------+------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW host_summary_by_file_io ( + host, + ios, + io_latency +) AS +SELECT IF(host IS NULL, 'background', host) AS host, + SUM(count_star) AS ios, + sys.format_time(SUM(sum_timer_wait)) AS io_latency + FROM performance_schema.events_waits_summary_by_host_by_event_name + WHERE event_name LIKE 'wait/io/file/%' + GROUP BY IF(host IS NULL, 'background', host) + ORDER BY SUM(sum_timer_wait) DESC; diff --git a/scripts/sys_schema/views/p_s/host_summary_by_file_io_type.sql b/scripts/sys_schema/views/p_s/host_summary_by_file_io_type.sql new file mode 100644 index 00000000..58567e3f --- /dev/null +++ b/scripts/sys_schema/views/p_s/host_summary_by_file_io_type.sql @@ -0,0 +1,66 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: host_summary_by_file_io_type +-- +-- Summarizes file IO by event type per host. +-- +-- When the host found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from host_summary_by_file_io_type; +-- +------------+--------------------------------------+-------+---------------+-------------+ +-- | host | event_name | total | total_latency | max_latency | +-- +------------+--------------------------------------+-------+---------------+-------------+ +-- | hal1 | wait/io/file/sql/FRM | 871 | 168.15 ms | 18.48 ms | +-- | hal1 | wait/io/file/innodb/innodb_data_file | 173 | 129.56 ms | 34.09 ms | +-- | hal1 | wait/io/file/innodb/innodb_log_file | 20 | 77.53 ms | 60.66 ms | +-- | hal1 | wait/io/file/myisam/dfile | 40 | 6.54 ms | 4.58 ms | +-- | hal1 | wait/io/file/mysys/charset | 3 | 4.79 ms | 4.71 ms | +-- | hal1 | wait/io/file/myisam/kfile | 67 | 4.38 ms | 300.04 us | +-- | hal1 | wait/io/file/sql/ERRMSG | 5 | 2.72 ms | 1.69 ms | +-- | hal1 | wait/io/file/sql/pid | 3 | 266.30 us | 185.47 us | +-- | hal1 | wait/io/file/sql/casetest | 5 | 246.81 us | 150.19 us | +-- | hal1 | wait/io/file/sql/global_ddl_log | 2 | 21.24 us | 18.59 us | +-- | hal2 | wait/io/file/sql/file_parser | 1422 | 4.80 s | 135.14 ms | +-- | hal2 | wait/io/file/sql/FRM | 865 | 85.82 ms | 9.81 ms | +-- | hal2 | wait/io/file/myisam/kfile | 1073 | 37.14 ms | 15.79 ms | +-- | hal2 | wait/io/file/myisam/dfile | 2991 | 25.53 ms | 5.25 ms | +-- | hal2 | wait/io/file/sql/dbopt | 20 | 1.07 ms | 153.07 us | +-- | hal2 | wait/io/file/sql/misc | 4 | 59.71 us | 33.75 us | +-- | hal2 | wait/io/file/archive/data | 1 | 13.91 us | 13.91 us | +-- +------------+--------------------------------------+-------+---------------+-------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW host_summary_by_file_io_type ( + host, + event_name, + total, + total_latency, + max_latency +) AS +SELECT IF(host IS NULL, 'background', host) AS host, + event_name, + count_star AS total, + sys.format_time(sum_timer_wait) AS total_latency, + sys.format_time(max_timer_wait) AS max_latency + FROM performance_schema.events_waits_summary_by_host_by_event_name + WHERE event_name LIKE 'wait/io/file%' + AND count_star > 0 + ORDER BY IF(host IS NULL, 'background', host), sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/host_summary_by_stages.sql b/scripts/sys_schema/views/p_s/host_summary_by_stages.sql new file mode 100644 index 00000000..97e5a7ee --- /dev/null +++ b/scripts/sys_schema/views/p_s/host_summary_by_stages.sql @@ -0,0 +1,64 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: host_summary_by_stages +-- +-- Summarizes stages by host, ordered by host and total latency per stage. +-- +-- When the host found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from host_summary_by_stages; +-- +------+--------------------------------+-------+---------------+-------------+ +-- | host | event_name | total | total_latency | avg_latency | +-- +------+--------------------------------+-------+---------------+-------------+ +-- | hal | stage/sql/Opening tables | 889 | 1.97 ms | 2.22 us | +-- | hal | stage/sql/Creating sort index | 4 | 1.79 ms | 446.30 us | +-- | hal | stage/sql/init | 10 | 312.27 us | 31.23 us | +-- | hal | stage/sql/checking permissions | 10 | 300.62 us | 30.06 us | +-- | hal | stage/sql/freeing items | 5 | 85.89 us | 17.18 us | +-- | hal | stage/sql/statistics | 5 | 79.15 us | 15.83 us | +-- | hal | stage/sql/preparing | 5 | 69.12 us | 13.82 us | +-- | hal | stage/sql/optimizing | 5 | 53.11 us | 10.62 us | +-- | hal | stage/sql/Sending data | 5 | 44.66 us | 8.93 us | +-- | hal | stage/sql/closing tables | 5 | 37.54 us | 7.51 us | +-- | hal | stage/sql/System lock | 5 | 34.28 us | 6.86 us | +-- | hal | stage/sql/query end | 5 | 24.37 us | 4.87 us | +-- | hal | stage/sql/end | 5 | 8.60 us | 1.72 us | +-- | hal | stage/sql/Sorting result | 5 | 8.33 us | 1.67 us | +-- | hal | stage/sql/executing | 5 | 5.37 us | 1.07 us | +-- | hal | stage/sql/cleaning up | 5 | 4.60 us | 919.00 ns | +-- +------+--------------------------------+-------+---------------+-------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW host_summary_by_stages ( + host, + event_name, + total, + total_latency, + avg_latency +) AS +SELECT IF(host IS NULL, 'background', host) AS host, + event_name, + count_star AS total, + sys.format_time(sum_timer_wait) AS total_latency, + sys.format_time(avg_timer_wait) AS avg_latency + FROM performance_schema.events_stages_summary_by_host_by_event_name + WHERE sum_timer_wait != 0 + ORDER BY IF(host IS NULL, 'background', host), sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/host_summary_by_statement_latency.sql b/scripts/sys_schema/views/p_s/host_summary_by_statement_latency.sql new file mode 100644 index 00000000..9eeb4c30 --- /dev/null +++ b/scripts/sys_schema/views/p_s/host_summary_by_statement_latency.sql @@ -0,0 +1,57 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: host_summary_by_statement_latency +-- +-- Summarizes overall statement statistics by host. +-- +-- When the host found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select-- from host_summary_by_statement_latency; +-- +------+-------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +-- | host | total | total_latency | max_latency | lock_latency | rows_sent | rows_examined | rows_affected | full_scans | +-- +------+-------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +-- | hal | 3381 | 00:02:09.13 | 1.48 s | 1.07 s | 1151 | 93947 | 150 | 91 | +-- +------+-------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW host_summary_by_statement_latency ( + host, + total, + total_latency, + max_latency, + lock_latency, + rows_sent, + rows_examined, + rows_affected, + full_scans +) AS +SELECT IF(host IS NULL, 'background', host) AS host, + SUM(count_star) AS total, + sys.format_time(SUM(sum_timer_wait)) AS total_latency, + sys.format_time(MAX(max_timer_wait)) AS max_latency, + sys.format_time(SUM(sum_lock_time)) AS lock_latency, + SUM(sum_rows_sent) AS rows_sent, + SUM(sum_rows_examined) AS rows_examined, + SUM(sum_rows_affected) AS rows_affected, + SUM(sum_no_index_used) + SUM(sum_no_good_index_used) AS full_scans + FROM performance_schema.events_statements_summary_by_host_by_event_name + GROUP BY IF(host IS NULL, 'background', host) + ORDER BY SUM(sum_timer_wait) DESC; diff --git a/scripts/sys_schema/views/p_s/host_summary_by_statement_type.sql b/scripts/sys_schema/views/p_s/host_summary_by_statement_type.sql new file mode 100644 index 00000000..b529cd8c --- /dev/null +++ b/scripts/sys_schema/views/p_s/host_summary_by_statement_type.sql @@ -0,0 +1,64 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: host_summary_by_statement_type +-- +-- Summarizes the types of statements executed by each host. +-- +-- When the host found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from host_summary_by_statement_type; +-- +------+----------------------+--------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +-- | host | statement | total | total_latency | max_latency | lock_latency | rows_sent | rows_examined | rows_affected | full_scans | +-- +------+----------------------+--------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +-- | hal | create_view | 2063 | 00:05:04.20 | 463.58 ms | 1.42 s | 0 | 0 | 0 | 0 | +-- | hal | select | 174 | 40.87 s | 28.83 s | 858.13 ms | 5212 | 157022 | 0 | 82 | +-- | hal | stmt | 6645 | 15.31 s | 491.78 ms | 0 ps | 0 | 0 | 7951 | 0 | +-- | hal | call_procedure | 17 | 4.78 s | 1.02 s | 37.94 ms | 0 | 0 | 19 | 0 | +-- | hal | create_table | 19 | 3.04 s | 431.71 ms | 0 ps | 0 | 0 | 0 | 0 | +-- ... +-- +------+----------------------+--------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW host_summary_by_statement_type ( + host, + statement, + total, + total_latency, + max_latency, + lock_latency, + rows_sent, + rows_examined, + rows_affected, + full_scans +) AS +SELECT IF(host IS NULL, 'background', host) AS host, + SUBSTRING_INDEX(event_name, '/', -1) AS statement, + count_star AS total, + sys.format_time(sum_timer_wait) AS total_latency, + sys.format_time(max_timer_wait) AS max_latency, + sys.format_time(sum_lock_time) AS lock_latency, + sum_rows_sent AS rows_sent, + sum_rows_examined AS rows_examined, + sum_rows_affected AS rows_affected, + sum_no_index_used + sum_no_good_index_used AS full_scans + FROM performance_schema.events_statements_summary_by_host_by_event_name + WHERE sum_timer_wait != 0 + ORDER BY IF(host IS NULL, 'background', host), sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/io_by_thread_by_latency.sql b/scripts/sys_schema/views/p_s/io_by_thread_by_latency.sql new file mode 100644 index 00000000..c5bf1c69 --- /dev/null +++ b/scripts/sys_schema/views/p_s/io_by_thread_by_latency.sql @@ -0,0 +1,70 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: io_by_thread_by_latency +-- +-- Show the top IO consumers by thread, ordered by total latency +-- +-- mysql> select * from io_by_thread_by_latency; +-- +---------------------+-------+---------------+-------------+-------------+-------------+-----------+----------------+ +-- | user | total | total_latency | min_latency | avg_latency | max_latency | thread_id | processlist_id | +-- +---------------------+-------+---------------+-------------+-------------+-------------+-----------+----------------+ +-- | root@localhost | 11580 | 18.01 s | 429.78 ns | 1.12 ms | 181.07 ms | 25 | 6 | +-- | main | 1358 | 1.31 s | 475.02 ns | 2.27 ms | 350.70 ms | 1 | NULL | +-- | page_cleaner_thread | 654 | 147.44 ms | 588.12 ns | 225.44 us | 46.41 ms | 18 | NULL | +-- | io_write_thread | 131 | 107.75 ms | 8.60 us | 822.55 us | 27.69 ms | 8 | NULL | +-- | io_write_thread | 46 | 47.07 ms | 10.64 us | 1.02 ms | 16.90 ms | 9 | NULL | +-- | io_write_thread | 71 | 46.99 ms | 9.11 us | 661.81 us | 17.04 ms | 11 | NULL | +-- | io_log_thread | 20 | 21.01 ms | 14.25 us | 1.05 ms | 7.08 ms | 3 | NULL | +-- | srv_master_thread | 13 | 17.60 ms | 8.49 us | 1.35 ms | 9.99 ms | 16 | NULL | +-- | srv_purge_thread | 4 | 1.81 ms | 34.31 us | 452.45 us | 1.02 ms | 17 | NULL | +-- | io_write_thread | 19 | 951.39 us | 9.75 us | 50.07 us | 297.47 us | 10 | NULL | +-- | signal_handler | 3 | 218.03 us | 21.64 us | 72.68 us | 154.84 us | 19 | NULL | +-- +---------------------+-------+---------------+-------------+-------------+-------------+-----------+----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW io_by_thread_by_latency ( + user, + total, + total_latency, + min_latency, + avg_latency, + max_latency, + thread_id, + processlist_id +) +AS +SELECT IF(processlist_id IS NULL, + SUBSTRING_INDEX(name, '/', -1), + CONCAT(processlist_user, '@', processlist_host) + ) user, + SUM(count_star) total, + sys.format_time(SUM(sum_timer_wait)) total_latency, + sys.format_time(MIN(min_timer_wait)) min_latency, + sys.format_time(AVG(avg_timer_wait)) avg_latency, + sys.format_time(MAX(max_timer_wait)) max_latency, + thread_id, + processlist_id + FROM performance_schema.events_waits_summary_by_thread_by_event_name + LEFT JOIN performance_schema.threads USING (thread_id) + WHERE event_name LIKE 'wait/io/file/%' + AND sum_timer_wait > 0 + GROUP BY thread_id, processlist_id, user + ORDER BY SUM(sum_timer_wait) DESC; diff --git a/scripts/sys_schema/views/p_s/io_global_by_file_by_bytes.sql b/scripts/sys_schema/views/p_s/io_global_by_file_by_bytes.sql new file mode 100644 index 00000000..cca00495 --- /dev/null +++ b/scripts/sys_schema/views/p_s/io_global_by_file_by_bytes.sql @@ -0,0 +1,58 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: io_global_by_file_by_bytes +-- +-- Shows the top global IO consumers by bytes usage by file. +-- +-- mysql> SELECT * FROM io_global_by_file_by_bytes LIMIT 5; +-- +--------------------------------------------+------------+------------+-----------+-------------+---------------+-----------+------------+-----------+ +-- | file | count_read | total_read | avg_read | count_write | total_written | avg_write | total | write_pct | +-- +--------------------------------------------+------------+------------+-----------+-------------+---------------+-----------+------------+-----------+ +-- | @@datadir/ibdata1 | 147 | 4.27 MiB | 29.71 KiB | 3 | 48.00 KiB | 16.00 KiB | 4.31 MiB | 1.09 | +-- | @@datadir/mysql/proc.MYD | 347 | 85.35 KiB | 252 bytes | 111 | 19.08 KiB | 176 bytes | 104.43 KiB | 18.27 | +-- | @@datadir/ib_logfile0 | 6 | 68.00 KiB | 11.33 KiB | 8 | 4.00 KiB | 512 bytes | 72.00 KiB | 5.56 | +-- | /opt/mysql/5.5.33/share/english/errmsg.sys | 3 | 43.68 KiB | 14.56 KiB | 0 | 0 bytes | 0 bytes | 43.68 KiB | 0.00 | +-- | /opt/mysql/5.5.33/share/charsets/Index.xml | 1 | 17.89 KiB | 17.89 KiB | 0 | 0 bytes | 0 bytes | 17.89 KiB | 0.00 | +-- +--------------------------------------------+------------+------------+-----------+-------------+---------------+-----------+------------+-----------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW io_global_by_file_by_bytes ( + file, + count_read, + total_read, + avg_read, + count_write, + total_written, + avg_write, + total, + write_pct +) AS +SELECT sys.format_path(file_name) AS file, + count_read, + sys.format_bytes(sum_number_of_bytes_read) AS total_read, + sys.format_bytes(IFNULL(sum_number_of_bytes_read / NULLIF(count_read, 0), 0)) AS avg_read, + count_write, + sys.format_bytes(sum_number_of_bytes_write) AS total_written, + sys.format_bytes(IFNULL(sum_number_of_bytes_write / NULLIF(count_write, 0), 0.00)) AS avg_write, + sys.format_bytes(sum_number_of_bytes_read + sum_number_of_bytes_write) AS total, + IFNULL(ROUND(100-((sum_number_of_bytes_read/ NULLIF((sum_number_of_bytes_read+sum_number_of_bytes_write), 0))*100), 2), 0.00) AS write_pct + FROM performance_schema.file_summary_by_instance + ORDER BY sum_number_of_bytes_read + sum_number_of_bytes_write DESC; diff --git a/scripts/sys_schema/views/p_s/io_global_by_file_by_latency.sql b/scripts/sys_schema/views/p_s/io_global_by_file_by_latency.sql new file mode 100644 index 00000000..97b0aae9 --- /dev/null +++ b/scripts/sys_schema/views/p_s/io_global_by_file_by_latency.sql @@ -0,0 +1,58 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: io_global_by_file_by_latency +-- +-- Shows the top global IO consumers by latency by file. +-- +-- mysql> select * from io_global_by_file_by_latency limit 5; +-- +-----------------------------------------------------------+-------+---------------+------------+--------------+-------------+---------------+------------+--------------+ +-- | file | total | total_latency | count_read | read_latency | count_write | write_latency | count_misc | misc_latency | +-- +-----------------------------------------------------------+-------+---------------+------------+--------------+-------------+---------------+------------+--------------+ +-- | @@datadir/sys/wait_classes_global_by_avg_latency_raw.frm~ | 24 | 451.99 ms | 0 | 0 ps | 4 | 108.07 us | 20 | 451.88 ms | +-- | @@datadir/sys/innodb_buffer_stats_by_schema_raw.frm~ | 24 | 379.84 ms | 0 | 0 ps | 4 | 108.88 us | 20 | 379.73 ms | +-- | @@datadir/sys/io_by_thread_by_latency_raw.frm~ | 24 | 379.46 ms | 0 | 0 ps | 4 | 101.37 us | 20 | 379.36 ms | +-- | @@datadir/ibtmp1 | 53 | 373.45 ms | 0 | 0 ps | 48 | 246.08 ms | 5 | 127.37 ms | +-- | @@datadir/sys/statement_analysis_raw.frm~ | 24 | 353.14 ms | 0 | 0 ps | 4 | 94.96 us | 20 | 353.04 ms | +-- +-----------------------------------------------------------+-------+---------------+------------+--------------+-------------+---------------+------------+--------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW io_global_by_file_by_latency ( + file, + total, + total_latency, + count_read, + read_latency, + count_write, + write_latency, + count_misc, + misc_latency +) AS +SELECT sys.format_path(file_name) AS file, + count_star AS total, + sys.format_time(sum_timer_wait) AS total_latency, + count_read, + sys.format_time(sum_timer_read) AS read_latency, + count_write, + sys.format_time(sum_timer_write) AS write_latency, + count_misc, + sys.format_time(sum_timer_misc) AS misc_latency + FROM performance_schema.file_summary_by_instance + ORDER BY sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/io_global_by_wait_by_bytes.sql b/scripts/sys_schema/views/p_s/io_global_by_wait_by_bytes.sql new file mode 100644 index 00000000..edf6b994 --- /dev/null +++ b/scripts/sys_schema/views/p_s/io_global_by_wait_by_bytes.sql @@ -0,0 +1,79 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: io_global_by_wait_by_bytes +-- +-- Shows the top global IO consumer classes by bytes usage. +-- +-- mysql> select * from io_global_by_wait_by_bytes; +-- +--------------------+--------+---------------+-------------+-------------+-------------+------------+------------+-----------+-------------+---------------+-------------+-----------------+ +-- | event_name | total | total_latency | min_latency | avg_latency | max_latency | count_read | total_read | avg_read | count_write | total_written | avg_written | total_requested | +-- +--------------------+--------+---------------+-------------+-------------+-------------+------------+------------+-----------+-------------+---------------+-------------+-----------------+ +-- | myisam/dfile | 163681 | 983.13 ms | 379.08 ns | 6.01 us | 22.06 ms | 68737 | 127.31 MiB | 1.90 KiB | 1012221 | 121.52 MiB | 126 bytes | 248.83 MiB | +-- | myisam/kfile | 1775 | 375.13 ms | 1.02 us | 211.34 us | 35.15 ms | 54066 | 9.97 MiB | 193 bytes | 428257 | 12.40 MiB | 30 bytes | 22.37 MiB | +-- | sql/FRM | 57889 | 8.40 s | 19.44 ns | 145.05 us | 336.71 ms | 8009 | 2.60 MiB | 341 bytes | 14675 | 2.91 MiB | 208 bytes | 5.51 MiB | +-- | sql/global_ddl_log | 164 | 75.96 ms | 5.72 us | 463.19 us | 7.43 ms | 20 | 80.00 KiB | 4.00 KiB | 76 | 304.00 KiB | 4.00 KiB | 384.00 KiB | +-- | sql/file_parser | 419 | 601.37 ms | 1.96 us | 1.44 ms | 37.14 ms | 66 | 42.01 KiB | 652 bytes | 64 | 226.98 KiB | 3.55 KiB | 268.99 KiB | +-- | sql/binlog | 190 | 6.79 s | 1.56 us | 35.76 ms | 4.21 s | 52 | 60.54 KiB | 1.16 KiB | 0 | 0 bytes | 0 bytes | 60.54 KiB | +-- | sql/ERRMSG | 5 | 2.03 s | 8.61 us | 405.40 ms | 2.03 s | 3 | 51.82 KiB | 17.27 KiB | 0 | 0 bytes | 0 bytes | 51.82 KiB | +-- | mysys/charset | 3 | 196.52 us | 17.61 us | 65.51 us | 137.33 us | 1 | 17.83 KiB | 17.83 KiB | 0 | 0 bytes | 0 bytes | 17.83 KiB | +-- | sql/partition | 81 | 18.87 ms | 888.08 ns | 232.92 us | 4.67 ms | 66 | 2.75 KiB | 43 bytes | 8 | 288 bytes | 36 bytes | 3.04 KiB | +-- | sql/dbopt | 329166 | 26.95 s | 2.06 us | 81.89 us | 178.71 ms | 0 | 0 bytes | 0 bytes | 9 | 585 bytes | 65 bytes | 585 bytes | +-- | sql/relaylog | 7 | 1.18 ms | 838.84 ns | 168.30 us | 892.70 us | 0 | 0 bytes | 0 bytes | 1 | 120 bytes | 120 bytes | 120 bytes | +-- | mysys/cnf | 5 | 171.61 us | 303.26 ns | 34.32 us | 115.21 us | 3 | 56 bytes | 19 bytes | 0 | 0 bytes | 0 bytes | 56 bytes | +-- | sql/pid | 3 | 220.55 us | 29.29 us | 73.52 us | 143.11 us | 0 | 0 bytes | 0 bytes | 1 | 5 bytes | 5 bytes | 5 bytes | +-- | sql/casetest | 1 | 121.19 us | 121.19 us | 121.19 us | 121.19 us | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | 0 bytes | +-- | sql/binlog_index | 5 | 593.47 us | 1.07 us | 118.69 us | 535.90 us | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | 0 bytes | +-- | sql/misc | 23 | 2.73 ms | 65.14 us | 118.50 us | 255.31 us | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | 0 bytes | +-- +--------------------+--------+---------------+-------------+-------------+-------------+------------+------------+-----------+-------------+---------------+-------------+-----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW io_global_by_wait_by_bytes ( + event_name, + total, + total_latency, + min_latency, + avg_latency, + max_latency, + count_read, + total_read, + avg_read, + count_write, + total_written, + avg_written, + total_requested +) AS +SELECT SUBSTRING_INDEX(event_name, '/', -2) event_name, + count_star AS total, + sys.format_time(sum_timer_wait) AS total_latency, + sys.format_time(min_timer_wait) AS min_latency, + sys.format_time(avg_timer_wait) AS avg_latency, + sys.format_time(max_timer_wait) AS max_latency, + count_read, + sys.format_bytes(sum_number_of_bytes_read) AS total_read, + sys.format_bytes(IFNULL(sum_number_of_bytes_read / NULLIF(count_read, 0), 0)) AS avg_read, + count_write, + sys.format_bytes(sum_number_of_bytes_write) AS total_written, + sys.format_bytes(IFNULL(sum_number_of_bytes_write / NULLIF(count_write, 0), 0)) AS avg_written, + sys.format_bytes(sum_number_of_bytes_write + sum_number_of_bytes_read) AS total_requested + FROM performance_schema.file_summary_by_event_name + WHERE event_name LIKE 'wait/io/file/%' + AND count_star > 0 + ORDER BY sum_number_of_bytes_write + sum_number_of_bytes_read DESC; diff --git a/scripts/sys_schema/views/p_s/io_global_by_wait_by_latency.sql b/scripts/sys_schema/views/p_s/io_global_by_wait_by_latency.sql new file mode 100644 index 00000000..5783e98c --- /dev/null +++ b/scripts/sys_schema/views/p_s/io_global_by_wait_by_latency.sql @@ -0,0 +1,81 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: io_global_by_wait_by_latency +-- +-- Shows the top global IO consumers by latency. +-- +-- mysql> SELECT * FROM io_global_by_wait_by_latency; +-- +-------------------------+-------+---------------+-------------+-------------+--------------+---------------+--------------+------------+------------+-----------+-------------+---------------+-------------+ +-- | event_name | total | total_latency | avg_latency | max_latency | read_latency | write_latency | misc_latency | count_read | total_read | avg_read | count_write | total_written | avg_written | +-- +-------------------------+-------+---------------+-------------+-------------+--------------+---------------+--------------+------------+------------+-----------+-------------+---------------+-------------+ +-- | sql/file_parser | 5433 | 30.20 s | 5.56 ms | 203.65 ms | 22.08 ms | 24.89 ms | 30.16 s | 24 | 6.18 KiB | 264 bytes | 737 | 2.15 MiB | 2.99 KiB | +-- | innodb/innodb_data_file | 1344 | 1.52 s | 1.13 ms | 350.70 ms | 203.82 ms | 450.96 ms | 868.21 ms | 147 | 2.30 MiB | 16.00 KiB | 1001 | 53.61 MiB | 54.84 KiB | +-- | innodb/innodb_log_file | 828 | 893.48 ms | 1.08 ms | 30.11 ms | 16.32 ms | 705.89 ms | 171.27 ms | 6 | 68.00 KiB | 11.33 KiB | 413 | 2.19 MiB | 5.42 KiB | +-- | myisam/kfile | 7642 | 242.34 ms | 31.71 us | 19.27 ms | 73.60 ms | 23.48 ms | 145.26 ms | 758 | 135.63 KiB | 183 bytes | 4386 | 232.52 KiB | 54 bytes | +-- | myisam/dfile | 12540 | 223.47 ms | 17.82 us | 32.50 ms | 87.76 ms | 16.97 ms | 118.74 ms | 5390 | 4.49 MiB | 873 bytes | 1448 | 2.65 MiB | 1.88 KiB | +-- | csv/metadata | 8 | 28.98 ms | 3.62 ms | 20.15 ms | 399.27 us | 0 ps | 28.58 ms | 2 | 70 bytes | 35 bytes | 0 | 0 bytes | 0 bytes | +-- | mysys/charset | 3 | 24.24 ms | 8.08 ms | 24.15 ms | 24.15 ms | 0 ps | 93.18 us | 1 | 17.31 KiB | 17.31 KiB | 0 | 0 bytes | 0 bytes | +-- | sql/ERRMSG | 5 | 20.43 ms | 4.09 ms | 19.31 ms | 20.32 ms | 0 ps | 103.20 us | 3 | 58.97 KiB | 19.66 KiB | 0 | 0 bytes | 0 bytes | +-- | mysys/cnf | 5 | 11.37 ms | 2.27 ms | 11.28 ms | 11.29 ms | 0 ps | 78.22 us | 3 | 56 bytes | 19 bytes | 0 | 0 bytes | 0 bytes | +-- | sql/dbopt | 57 | 4.04 ms | 70.92 us | 843.70 us | 0 ps | 186.43 us | 3.86 ms | 0 | 0 bytes | 0 bytes | 7 | 431 bytes | 62 bytes | +-- | csv/data | 4 | 411.55 us | 102.89 us | 234.89 us | 0 ps | 0 ps | 411.55 us | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | +-- | sql/misc | 22 | 340.38 us | 15.47 us | 33.77 us | 0 ps | 0 ps | 340.38 us | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | +-- | archive/data | 39 | 277.86 us | 7.12 us | 16.18 us | 0 ps | 0 ps | 277.86 us | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | +-- | sql/pid | 3 | 218.03 us | 72.68 us | 154.84 us | 0 ps | 21.64 us | 196.39 us | 0 | 0 bytes | 0 bytes | 1 | 6 bytes | 6 bytes | +-- | sql/casetest | 5 | 197.15 us | 39.43 us | 126.31 us | 0 ps | 0 ps | 197.15 us | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | +-- | sql/global_ddl_log | 2 | 14.60 us | 7.30 us | 12.12 us | 0 ps | 0 ps | 14.60 us | 0 | 0 bytes | 0 bytes | 0 | 0 bytes | 0 bytes | +-- +-------------------------+-------+---------------+-------------+-------------+--------------+---------------+--------------+------------+------------+-----------+-------------+---------------+-------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW io_global_by_wait_by_latency ( + event_name, + total, + total_latency, + avg_latency, + max_latency, + read_latency, + write_latency, + misc_latency, + count_read, + total_read, + avg_read, + count_write, + total_written, + avg_written +) AS +SELECT SUBSTRING_INDEX(event_name, '/', -2) AS event_name, + count_star AS total, + sys.format_time(sum_timer_wait) AS total_latency, + sys.format_time(avg_timer_wait) AS avg_latency, + sys.format_time(max_timer_wait) AS max_latency, + sys.format_time(sum_timer_read) AS read_latency, + sys.format_time(sum_timer_write) AS write_latency, + sys.format_time(sum_timer_misc) AS misc_latency, + count_read, + sys.format_bytes(sum_number_of_bytes_read) AS total_read, + sys.format_bytes(IFNULL(sum_number_of_bytes_read / NULLIF(count_read, 0), 0)) AS avg_read, + count_write, + sys.format_bytes(sum_number_of_bytes_write) AS total_written, + sys.format_bytes(IFNULL(sum_number_of_bytes_write / NULLIF(count_write, 0), 0)) AS avg_written + FROM performance_schema.file_summary_by_event_name + WHERE event_name LIKE 'wait/io/file/%' + AND count_star > 0 + ORDER BY sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/latest_file_io.sql b/scripts/sys_schema/views/p_s/latest_file_io.sql new file mode 100644 index 00000000..9803cc6c --- /dev/null +++ b/scripts/sys_schema/views/p_s/latest_file_io.sql @@ -0,0 +1,57 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: latest_file_io +-- +-- Shows the latest file IO, by file / thread. +-- +-- mysql> select * from latest_file_io limit 5; +-- +----------------------+----------------------------------------+------------+-----------+-----------+ +-- | thread | file | latency | operation | requested | +-- +----------------------+----------------------------------------+------------+-----------+-----------+ +-- | msandbox@localhost:1 | @@tmpdir/#sqlcf28_1_4e.MYI | 9.26 us | write | 124 bytes | +-- | msandbox@localhost:1 | @@tmpdir/#sqlcf28_1_4e.MYI | 4.00 us | write | 2 bytes | +-- | msandbox@localhost:1 | @@tmpdir/#sqlcf28_1_4e.MYI | 56.34 us | close | NULL | +-- | msandbox@localhost:1 | @@tmpdir/#sqlcf28_1_4e.MYD | 53.93 us | close | NULL | +-- | msandbox@localhost:1 | @@tmpdir/#sqlcf28_1_4e.MYI | 104.05 ms | delete | NULL | +-- +----------------------+----------------------------------------+------------+-----------+-----------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW latest_file_io ( + thread, + file, + latency, + operation, + requested +) AS +SELECT IF(id IS NULL, + CONCAT(SUBSTRING_INDEX(name, '/', -1), ':', thread_id), + CONCAT(user, '@', host, ':', id) + ) thread, + sys.format_path(object_name) file, + sys.format_time(timer_wait) AS latency, + operation, + sys.format_bytes(number_of_bytes) AS requested + FROM performance_schema.events_waits_history_long + JOIN performance_schema.threads USING (thread_id) + LEFT JOIN information_schema.processlist ON processlist_id = id + WHERE object_name IS NOT NULL + AND event_name LIKE 'wait/io/file/%' + ORDER BY timer_start; diff --git a/scripts/sys_schema/views/p_s/memory_by_host_by_current_bytes.sql b/scripts/sys_schema/views/p_s/memory_by_host_by_current_bytes.sql new file mode 100644 index 00000000..ca6ce2da --- /dev/null +++ b/scripts/sys_schema/views/p_s/memory_by_host_by_current_bytes.sql @@ -0,0 +1,52 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: memory_by_host_by_current_bytes +-- +-- Summarizes memory use by host using the 5.7 Performance Schema instrumentation. +-- +-- When the host found is NULL, it is assumed to be a local "background" thread. +-- +-- mysql> select * from memory_by_host_by_current_bytes; +-- +------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- | host | current_count_used | current_allocated | current_avg_alloc | current_max_alloc | total_allocated | +-- +------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- | background | 2773 | 10.84 MiB | 4.00 KiB | 8.00 MiB | 30.69 MiB | +-- | localhost | 1509 | 809.30 KiB | 549 bytes | 176.38 KiB | 83.59 MiB | +-- +------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW memory_by_host_by_current_bytes ( + host, + current_count_used, + current_allocated, + current_avg_alloc, + current_max_alloc, + total_allocated +) AS +SELECT IF(host IS NULL, 'background', host) AS host, + SUM(current_count_used) AS current_count_used, + sys.format_bytes(SUM(current_number_of_bytes_used)) AS current_allocated, + sys.format_bytes(IFNULL(SUM(current_number_of_bytes_used) / NULLIF(SUM(current_count_used), 0), 0)) AS current_avg_alloc, + sys.format_bytes(MAX(current_number_of_bytes_used)) AS current_max_alloc, + sys.format_bytes(SUM(sum_number_of_bytes_alloc)) AS total_allocated + FROM performance_schema.memory_summary_by_host_by_event_name + GROUP BY IF(host IS NULL, 'background', host) + ORDER BY SUM(current_number_of_bytes_used) DESC; diff --git a/scripts/sys_schema/views/p_s/memory_by_thread_by_current_bytes.sql b/scripts/sys_schema/views/p_s/memory_by_thread_by_current_bytes.sql new file mode 100644 index 00000000..6db9d79c --- /dev/null +++ b/scripts/sys_schema/views/p_s/memory_by_thread_by_current_bytes.sql @@ -0,0 +1,62 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: memory_by_thread_by_current_bytes +-- +-- Summarizes memory use by user using the 5.7 Performance Schema instrumentation. +-- +-- User shows either the background or foreground user name appropriately. +-- +-- mysql> select * from sys.memory_by_thread_by_current_bytes limit 5; +-- +-----------+----------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- | thread_id | user | current_count_used | current_allocated | current_avg_alloc | current_max_alloc | total_allocated | +-- +-----------+----------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- | 1 | sql/main | 29333 | 166.02 MiB | 5.80 KiB | 131.13 MiB | 196.00 MiB | +-- | 55 | root@localhost | 175 | 1.04 MiB | 6.09 KiB | 350.86 KiB | 67.37 MiB | +-- | 58 | root@localhost | 236 | 368.13 KiB | 1.56 KiB | 312.05 KiB | 130.34 MiB | +-- | 904 | root@localhost | 32 | 18.00 KiB | 576 bytes | 16.00 KiB | 6.68 MiB | +-- | 970 | root@localhost | 12 | 16.80 KiB | 1.40 KiB | 16.00 KiB | 1.20 MiB | +-- +-----------+----------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW memory_by_thread_by_current_bytes ( + thread_id, + user, + current_count_used, + current_allocated, + current_avg_alloc, + current_max_alloc, + total_allocated +) AS +SELECT thread_id, + IF(t.name = 'thread/sql/one_connection', + CONCAT(t.processlist_user, '@', t.processlist_host), + REPLACE(t.name, 'thread/', '')) user, + SUM(mt.current_count_used) AS current_count_used, + sys.format_bytes(SUM(mt.current_number_of_bytes_used)) AS current_allocated, + sys.format_bytes(IFNULL(SUM(mt.current_number_of_bytes_used) / NULLIF(SUM(current_count_used), 0), 0)) AS current_avg_alloc, + sys.format_bytes(MAX(mt.current_number_of_bytes_used)) AS current_max_alloc, + sys.format_bytes(SUM(mt.sum_number_of_bytes_alloc)) AS total_allocated + FROM performance_schema.memory_summary_by_thread_by_event_name AS mt + JOIN performance_schema.threads AS t USING (thread_id) + GROUP BY thread_id, IF(t.name = 'thread/sql/one_connection', + CONCAT(t.processlist_user, '@', t.processlist_host), + REPLACE(t.name, 'thread/', '')) + ORDER BY SUM(current_number_of_bytes_used) DESC; diff --git a/scripts/sys_schema/views/p_s/memory_by_user_by_current_bytes.sql b/scripts/sys_schema/views/p_s/memory_by_user_by_current_bytes.sql new file mode 100644 index 00000000..efb5267e --- /dev/null +++ b/scripts/sys_schema/views/p_s/memory_by_user_by_current_bytes.sql @@ -0,0 +1,52 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: memory_by_user_by_current_bytes +-- +-- Summarizes memory use by user using the 5.7 Performance Schema instrumentation. +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from memory_by_user_by_current_bytes; +-- +------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- | user | current_count_used | current_allocated | current_avg_alloc | current_max_alloc | total_allocated | +-- +------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- | root | 1401 | 1.09 MiB | 815 bytes | 334.97 KiB | 42.73 MiB | +-- | mark | 201 | 496.08 KiB | 2.47 KiB | 334.97 KiB | 5.50 MiB | +-- +------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW memory_by_user_by_current_bytes ( + user, + current_count_used, + current_allocated, + current_avg_alloc, + current_max_alloc, + total_allocated +) AS +SELECT IF(user IS NULL, 'background', user) AS user, + SUM(current_count_used) AS current_count_used, + sys.format_bytes(SUM(current_number_of_bytes_used)) AS current_allocated, + sys.format_bytes(IFNULL(SUM(current_number_of_bytes_used) / NULLIF(SUM(current_count_used), 0), 0)) AS current_avg_alloc, + sys.format_bytes(MAX(current_number_of_bytes_used)) AS current_max_alloc, + sys.format_bytes(SUM(sum_number_of_bytes_alloc)) AS total_allocated + FROM performance_schema.memory_summary_by_user_by_event_name + GROUP BY IF(user IS NULL, 'background', user) + ORDER BY SUM(current_number_of_bytes_used) DESC; diff --git a/scripts/sys_schema/views/p_s/memory_global_by_current_bytes.sql b/scripts/sys_schema/views/p_s/memory_global_by_current_bytes.sql new file mode 100644 index 00000000..c1e9f27e --- /dev/null +++ b/scripts/sys_schema/views/p_s/memory_global_by_current_bytes.sql @@ -0,0 +1,56 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: memory_global_by_current_bytes +-- +-- Shows the current memory usage within the server globally broken down by allocation type. +-- +-- mysql> select * from memory_global_by_current_bytes; +-- +-------------------------------------------------+---------------+---------------+-------------------+------------+-------------+----------------+ +-- | event_name | current_count | current_alloc | current_avg_alloc | high_count | high_alloc | high_avg_alloc | +-- +-------------------------------------------------+---------------+---------------+-------------------+------------+-------------+----------------+ +-- | memory/performance_schema/internal_buffers | 62 | 293.80 MiB | 4.74 MiB | 62 | 293.80 MiB | 4.74 MiB | +-- | memory/innodb/buf_buf_pool | 1 | 131.06 MiB | 131.06 MiB | 1 | 131.06 MiB | 131.06 MiB | +-- | memory/innodb/log0log | 9 | 8.01 MiB | 911.15 KiB | 9 | 8.01 MiB | 911.15 KiB | +-- | memory/mysys/KEY_CACHE | 3 | 8.00 MiB | 2.67 MiB | 3 | 8.00 MiB | 2.67 MiB | +-- | memory/innodb/hash0hash | 27 | 4.73 MiB | 179.51 KiB | 27 | 6.84 MiB | 259.47 KiB | +-- | memory/innodb/os0event | 24998 | 4.01 MiB | 168 bytes | 24998 | 4.01 MiB | 168 bytes | +-- ... +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW memory_global_by_current_bytes ( + event_name, + current_count, + current_alloc, + current_avg_alloc, + high_count, + high_alloc, + high_avg_alloc +) AS +SELECT event_name, + current_count_used AS current_count, + sys.format_bytes(current_number_of_bytes_used) AS current_alloc, + sys.format_bytes(IFNULL(current_number_of_bytes_used / NULLIF(current_count_used, 0), 0)) AS current_avg_alloc, + high_count_used AS high_count, + sys.format_bytes(high_number_of_bytes_used) AS high_alloc, + sys.format_bytes(IFNULL(high_number_of_bytes_used / NULLIF(high_count_used, 0), 0)) AS high_avg_alloc + FROM performance_schema.memory_summary_global_by_event_name + WHERE current_number_of_bytes_used > 0 + ORDER BY current_number_of_bytes_used DESC; diff --git a/scripts/sys_schema/views/p_s/memory_global_total.sql b/scripts/sys_schema/views/p_s/memory_global_total.sql new file mode 100644 index 00000000..8d014e9d --- /dev/null +++ b/scripts/sys_schema/views/p_s/memory_global_total.sql @@ -0,0 +1,37 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: memory_global_total +-- +-- Shows the total memory usage within the server globally. +-- +-- mysql> select * from memory_global_total; +-- +-----------------+ +-- | total_allocated | +-- +-----------------+ +-- | 123.35 MiB | +-- +-----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW memory_global_total ( + total_allocated +) AS +SELECT sys.format_bytes(SUM(CURRENT_NUMBER_OF_BYTES_USED)) total_allocated + FROM performance_schema.memory_summary_global_by_event_name; diff --git a/scripts/sys_schema/views/p_s/metrics.sql b/scripts/sys_schema/views/p_s/metrics.sql new file mode 100644 index 00000000..0fcc5c5e --- /dev/null +++ b/scripts/sys_schema/views/p_s/metrics.sql @@ -0,0 +1,126 @@ +-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- IMPORTANT +-- If you update this view, also update the "5.7+ and the Performance Schema disabled" +-- query in procedures/diagnostics.sql + +-- View: metrics +-- +-- Creates a union of the following information: +-- +-- * performance_schema.global_status +-- * information_schema.INNODB_METRICS +-- * Performance Schema global memory usage information +-- * Current time +-- +-- This is the same as the metrics_56 view with the exception that the global status is taken from performance_schema.global_status instead of +-- from the Information Schema. Use this view if the MySQL version is 5.7.6 or later and show_compatibility_56 = OFF. +-- See also https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_show_compatibility_56 +-- +-- For view has the following columns: +-- +-- * Variable_name: The name of the variable +-- * Variable_value: The value of the variable +-- * Type: The type of the variable. This will depend on the source, e.g. Global Status, InnoDB Metrics - ..., etc. +-- * Enabled: Whether the variable is enabled or not. Possible values are 'YES', 'NO', 'PARTIAL'. +-- PARTIAL is currently only supported for the memory usage variables and means some but not all of the memory/% instruments +-- are enabled. +-- +-- mysql> SELECT * FROM metrics; +-- +-----------------------------------------------+-------------------------...+--------------------------------------+---------+ +-- | Variable_name | Variable_value ...| Type | Enabled | +-- +-----------------------------------------------+-------------------------...+--------------------------------------+---------+ +-- | aborted_clients | 0 ...| Global Status | YES | +-- | aborted_connects | 0 ...| Global Status | YES | +-- | binlog_cache_disk_use | 0 ...| Global Status | YES | +-- | binlog_cache_use | 0 ...| Global Status | YES | +-- | binlog_stmt_cache_disk_use | 0 ...| Global Status | YES | +-- | binlog_stmt_cache_use | 0 ...| Global Status | YES | +-- | bytes_received | 217081 ...| Global Status | YES | +-- | bytes_sent | 27257 ...| Global Status | YES | +-- ... +-- | innodb_rwlock_x_os_waits | 0 ...| InnoDB Metrics - server | YES | +-- | innodb_rwlock_x_spin_rounds | 2723 ...| InnoDB Metrics - server | YES | +-- | innodb_rwlock_x_spin_waits | 1 ...| InnoDB Metrics - server | YES | +-- | trx_active_transactions | 0 ...| InnoDB Metrics - transaction | NO | +-- ... +-- | trx_rseg_current_size | 0 ...| InnoDB Metrics - transaction | NO | +-- | trx_rseg_history_len | 4 ...| InnoDB Metrics - transaction | YES | +-- | trx_rw_commits | 0 ...| InnoDB Metrics - transaction | NO | +-- | trx_undo_slots_cached | 0 ...| InnoDB Metrics - transaction | NO | +-- | trx_undo_slots_used | 0 ...| InnoDB Metrics - transaction | NO | +-- | memory_current_allocated | 138244216 ...| Performance Schema | PARTIAL | +-- | memory_total_allocated | 138244216 ...| Performance Schema | PARTIAL | +-- | NOW() | 2015-05-31 13:27:50.382 ...| System Time | YES | +-- | UNIX_TIMESTAMP() | 1433042870.382 ...| System Time | YES | +-- +-----------------------------------------------+-------------------------...+--------------------------------------+---------+ +-- 412 rows in set (0.02 sec) +DELIMITER $$ +BEGIN NOT ATOMIC +DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END; + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW metrics ( + Variable_name, + Variable_value, + Type, + Enabled +) AS +( +SELECT LOWER(VARIABLE_NAME) AS Variable_name, VARIABLE_VALUE AS Variable_value, 'Global Status' AS Type, 'YES' AS Enabled + FROM performance_schema.global_status +) UNION ALL ( +SELECT NAME AS Variable_name, COUNT AS Variable_value, + CONCAT('InnoDB Metrics - ', SUBSYSTEM) AS Type, + 'YES' AS Enabled + FROM information_schema.INNODB_METRICS + -- Deduplication - some variables exists both in GLOBAL_STATUS and INNODB_METRICS + -- Keep the one from GLOBAL_STATUS as it is always enabled and it's more likely to be used for existing tools. + WHERE NAME NOT IN ( + 'lock_row_lock_time', 'lock_row_lock_time_avg', 'lock_row_lock_time_max', 'lock_row_lock_waits', + 'buffer_pool_reads', 'buffer_pool_read_requests', 'buffer_pool_write_requests', 'buffer_pool_wait_free', + 'buffer_pool_read_ahead', 'buffer_pool_read_ahead_evicted', 'buffer_pool_pages_total', 'buffer_pool_pages_misc', + 'buffer_pool_pages_data', 'buffer_pool_bytes_data', 'buffer_pool_pages_dirty', 'buffer_pool_bytes_dirty', + 'buffer_pool_pages_free', 'buffer_pages_created', 'buffer_pages_written', 'buffer_pages_read', + 'buffer_data_reads', 'buffer_data_written', 'file_num_open_files', + 'os_log_bytes_written', 'os_log_fsyncs', 'os_log_pending_fsyncs', 'os_log_pending_writes', + 'log_waits', 'log_write_requests', 'log_writes', 'innodb_dblwr_writes', 'innodb_dblwr_pages_written', 'innodb_page_size') +) /*!50702 + -- memory instrumentation available in 5.7.2 and later + UNION ALL ( +SELECT 'memory_current_allocated' AS Variable_name, SUM(CURRENT_NUMBER_OF_BYTES_USED) AS Variable_value, 'Performance Schema' AS Type, + IF((SELECT COUNT(*) FROM performance_schema.setup_instruments WHERE NAME LIKE 'memory/%' AND ENABLED = 'YES') = 0, 'NO', + IF((SELECT COUNT(*) FROM performance_schema.setup_instruments WHERE NAME LIKE 'memory/%' AND ENABLED = 'YES') = (SELECT COUNT(*) FROM performance_schema.setup_instruments WHERE NAME LIKE 'memory/%'), 'YES', + 'PARTIAL')) AS Enabled + FROM performance_schema.memory_summary_global_by_event_name +) UNION ALL ( +SELECT 'memory_total_allocated' AS Variable_name, SUM(SUM_NUMBER_OF_BYTES_ALLOC) AS Variable_value, 'Performance Schema' AS Type, + IF((SELECT COUNT(*) FROM performance_schema.setup_instruments WHERE NAME LIKE 'memory/%' AND ENABLED = 'YES') = 0, 'NO', + IF((SELECT COUNT(*) FROM performance_schema.setup_instruments WHERE NAME LIKE 'memory/%' AND ENABLED = 'YES') = (SELECT COUNT(*) FROM performance_schema.setup_instruments WHERE NAME LIKE 'memory/%'), 'YES', + 'PARTIAL')) AS Enabled + FROM performance_schema.memory_summary_global_by_event_name +) */ + UNION ALL ( +SELECT 'NOW()' AS Variable_name, NOW(3) AS Variable_value, 'System Time' AS Type, 'YES' AS Enabled +) UNION ALL ( +SELECT 'UNIX_TIMESTAMP()' AS Variable_name, ROUND(UNIX_TIMESTAMP(NOW(3)), 3) AS Variable_value, 'System Time' AS Type, 'YES' AS Enabled +) + ORDER BY Type, Variable_name; +END$$ +DELIMITER ;
\ No newline at end of file diff --git a/scripts/sys_schema/views/p_s/metrics_56.sql b/scripts/sys_schema/views/p_s/metrics_56.sql new file mode 100644 index 00000000..79447ae7 --- /dev/null +++ b/scripts/sys_schema/views/p_s/metrics_56.sql @@ -0,0 +1,112 @@ +-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +-- View: metrics +-- +-- Creates a union of the following information: +-- +-- * information_schema.GLOBAL_STATUS +-- * information_schema.INNODB_METRICS +-- * Performance Schema global memory usage information +-- * Current time +-- +-- This is the same as the metrics view with the exception that the global status is taken from information_schema.GLOBAL_STATUS instead of +-- from the Peformance Schema. Use this view if one of the following conditions are fulfilled: +-- +-- * The MySQL version is 5.6 or 5.7.0-5.7.5 +-- * In 5.7.6 and later if show_compatibility_56 is ON. See also https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_show_compatibility_56 +-- +-- In MySQL 5.7.6 and later the view will generate one warning: +-- mysql> SHOW WARNINGS; +-- +---------+------+-----------------------------------------------------------------------------------------------------------------------------------------------+ +-- | Level | Code | Message | +-- +---------+------+-----------------------------------------------------------------------------------------------------------------------------------------------+ +-- | Warning | 1287 | 'INFORMATION_SCHEMA.GLOBAL_STATUS' is deprecated and will be removed in a future release. Please use performance_schema.global_status instead | +-- +---------+------+-----------------------------------------------------------------------------------------------------------------------------------------------+ +-- 1 row in set (0.00 sec) +-- +-- For view has the following columns: +-- +-- * Variable_name: The name of the variable +-- * Variable_value: The value of the variable +-- * Type: The type of the variable. This will depend on the source, e.g. Global Status, InnoDB Metrics - ..., etc. +-- * Enabled: Whether the variable is enabled or not. Possible values are 'YES', 'NO', 'PARTIAL'. +-- PARTIAL is currently only supported for the memory usage variables and means some but not all of the memory/% instruments +-- are enabled. +-- +-- mysql> SELECT * FROM metrics; +-- +-----------------------------------------------+-------------------------...+--------------------------------------+---------+ +-- | Variable_name | Variable_value ...| Type | Enabled | +-- +-----------------------------------------------+-------------------------...+--------------------------------------+---------+ +-- | aborted_clients | 0 ...| Global Status | YES | +-- | aborted_connects | 0 ...| Global Status | YES | +-- | binlog_cache_disk_use | 0 ...| Global Status | YES | +-- | binlog_cache_use | 0 ...| Global Status | YES | +-- | binlog_stmt_cache_disk_use | 0 ...| Global Status | YES | +-- | binlog_stmt_cache_use | 0 ...| Global Status | YES | +-- | bytes_received | 217081 ...| Global Status | YES | +-- | bytes_sent | 27257 ...| Global Status | YES | +-- ... +-- | innodb_rwlock_x_os_waits | 0 ...| InnoDB Metrics - server | YES | +-- | innodb_rwlock_x_spin_rounds | 2723 ...| InnoDB Metrics - server | YES | +-- | innodb_rwlock_x_spin_waits | 1 ...| InnoDB Metrics - server | YES | +-- | trx_active_transactions | 0 ...| InnoDB Metrics - transaction | NO | +-- ... +-- | trx_rseg_current_size | 0 ...| InnoDB Metrics - transaction | NO | +-- | trx_rseg_history_len | 4 ...| InnoDB Metrics - transaction | YES | +-- | trx_rw_commits | 0 ...| InnoDB Metrics - transaction | NO | +-- | trx_undo_slots_cached | 0 ...| InnoDB Metrics - transaction | NO | +-- | trx_undo_slots_used | 0 ...| InnoDB Metrics - transaction | NO | +-- | NOW() | 2015-05-31 13:27:50.382 ...| System Time | YES | +-- | UNIX_TIMESTAMP() | 1433042870.382 ...| System Time | YES | +-- +-----------------------------------------------+-------------------------...+--------------------------------------+---------+ +-- 565 rows in set, 1 warning (0.02 sec) + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW metrics ( + Variable_name, + Variable_value, + Type, + Enabled +) AS +( +SELECT LOWER(VARIABLE_NAME) AS Variable_name, VARIABLE_VALUE AS Variable_value, 'Global Status' AS Type, 'YES' AS Enabled + FROM information_schema.GLOBAL_STATUS +) UNION ALL ( +SELECT NAME AS Variable_name, COUNT AS Variable_value, + CONCAT('InnoDB Metrics - ', SUBSYSTEM) AS Type, + IF(STATUS = 'enabled', 'YES', 'NO') AS Enabled + FROM information_schema.INNODB_METRICS + -- Deduplication - some variables exists both in GLOBAL_STATUS and INNODB_METRICS + -- Keep the one from GLOBAL_STATUS as it is always enabled and it's more likely to be used for existing tools. + WHERE NAME NOT IN ( + 'lock_row_lock_time', 'lock_row_lock_time_avg', 'lock_row_lock_time_max', 'lock_row_lock_waits', + 'buffer_pool_reads', 'buffer_pool_read_requests', 'buffer_pool_write_requests', 'buffer_pool_wait_free', + 'buffer_pool_read_ahead', 'buffer_pool_read_ahead_evicted', 'buffer_pool_pages_total', 'buffer_pool_pages_misc', + 'buffer_pool_pages_data', 'buffer_pool_bytes_data', 'buffer_pool_pages_dirty', 'buffer_pool_bytes_dirty', + 'buffer_pool_pages_free', 'buffer_pages_created', 'buffer_pages_written', 'buffer_pages_read', + 'buffer_data_reads', 'buffer_data_written', 'file_num_open_files', + 'os_log_bytes_written', 'os_log_fsyncs', 'os_log_pending_fsyncs', 'os_log_pending_writes', + 'log_waits', 'log_write_requests', 'log_writes', 'innodb_dblwr_writes', 'innodb_dblwr_pages_written', 'innodb_page_size') +) UNION ALL ( +SELECT 'NOW()' AS Variable_name, NOW(3) AS Variable_value, 'System Time' AS Type, 'YES' AS Enabled +) UNION ALL ( +SELECT 'UNIX_TIMESTAMP()' AS Variable_name, ROUND(UNIX_TIMESTAMP(NOW(3)), 3) AS Variable_value, 'System Time' AS Type, 'YES' AS Enabled +) + ORDER BY Type, Variable_name; diff --git a/scripts/sys_schema/views/p_s/processlist.sql b/scripts/sys_schema/views/p_s/processlist.sql new file mode 100644 index 00000000..33e8969f --- /dev/null +++ b/scripts/sys_schema/views/p_s/processlist.sql @@ -0,0 +1,108 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: processlist +-- +-- A detailed non-blocking processlist view to replace +-- [INFORMATION_SCHEMA. | SHOW FULL] PROCESSLIST +-- +-- mysql> select * from processlist where conn_id is not null\G +-- *************************** 1. row *************************** +-- thd_id: 23 +-- conn_id: 4 +-- user: msandbox@localhost +-- db: test +-- command: Query +-- state: Sending data +-- time: 4 +-- current_statement: select count(*) from t1 +-- statement_latency: 4.56 s +-- lock_latency: 108.00 us +-- rows_examined: 0 +-- rows_sent: 0 +-- rows_affected: 0 +-- tmp_tables: 0 +-- tmp_disk_tables: 0 +-- full_scan: YES +-- last_statement: NULL +-- last_statement_latency: NULL +-- last_wait: wait/io/table/sql/handler +-- last_wait_latency: Still Waiting +-- source: handler.cc:2688 +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW processlist ( + thd_id, + conn_id, + user, + db, + command, + state, + time, + current_statement, + statement_latency, + lock_latency, + rows_examined, + rows_sent, + rows_affected, + tmp_tables, + tmp_disk_tables, + full_scan, + last_statement, + last_statement_latency, + last_wait, + last_wait_latency, + source +) AS +SELECT pps.thread_id AS thd_id, + pps.processlist_id AS conn_id, + IF(pps.name = 'thread/sql/one_connection', + CONCAT(pps.processlist_user, '@', pps.processlist_host), + REPLACE(pps.name, 'thread/', '')) user, + pps.processlist_db AS db, + pps.processlist_command AS command, + pps.processlist_state AS state, + pps.processlist_time AS time, + sys.format_statement(pps.processlist_info) AS current_statement, + IF(esc.end_event_id IS NULL, + sys.format_time(esc.timer_wait), + NULL) AS statement_latency, + sys.format_time(esc.lock_time) AS lock_latency, + esc.rows_examined AS rows_examined, + esc.rows_sent AS rows_sent, + esc.rows_affected AS rows_affected, + esc.created_tmp_tables AS tmp_tables, + esc.created_tmp_disk_tables AS tmp_disk_tables, + IF(esc.no_good_index_used > 0 OR esc.no_index_used > 0, 'YES', 'NO') AS full_scan, + IF(esc.end_event_id IS NOT NULL, + sys.format_statement(esc.sql_text), + NULL) AS last_statement, + IF(esc.end_event_id IS NOT NULL, + sys.format_time(esc.timer_wait), + NULL) AS last_statement_latency, + ewc.event_name AS last_wait, + IF(ewc.end_event_id IS NULL AND ewc.event_name IS NOT NULL, + 'Still Waiting', + sys.format_time(ewc.timer_wait)) last_wait_latency, + ewc.source + FROM performance_schema.threads AS pps + LEFT JOIN performance_schema.events_waits_current AS ewc USING (thread_id) + LEFT JOIN performance_schema.events_statements_current as esc USING (thread_id) + ORDER BY pps.processlist_time DESC, last_wait_latency DESC; diff --git a/scripts/sys_schema/views/p_s/processlist_57.sql b/scripts/sys_schema/views/p_s/processlist_57.sql new file mode 100644 index 00000000..4e4f21ea --- /dev/null +++ b/scripts/sys_schema/views/p_s/processlist_57.sql @@ -0,0 +1,140 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: processlist +-- +-- A detailed non-blocking processlist view to replace +-- [INFORMATION_SCHEMA. | SHOW FULL] PROCESSLIST +-- +-- Performs less locking than the legacy sources, whilst giving extra information. +-- +-- mysql> select * from sys.processlist where conn_id is not null and command != 'daemon' and conn_id != connection_id()\G +-- *************************** 1. row *************************** +-- thd_id: 44524 +-- conn_id: 44502 +-- user: msandbox@localhost +-- db: test +-- command: Query +-- state: alter table (flush) +-- time: 18 +-- current_statement: alter table t1 add column g int +-- statement_latency: 18.45 s +-- progress: 98.84 +-- lock_latency: 265.43 ms +-- rows_examined: 0 +-- rows_sent: 0 +-- rows_affected: 0 +-- tmp_tables: 0 +-- tmp_disk_tables: 0 +-- full_scan: NO +-- last_statement: NULL +-- last_statement_latency: NULL +-- current_memory: 664.06 KiB +-- last_wait: wait/io/file/innodb/innodb_data_file +-- last_wait_latency: 1.07 us +-- source: fil0fil.cc:5146 +-- trx_latency: NULL +-- trx_state: NULL +-- trx_autocommit: NULL +-- pid: 4212 +-- program_name: mysql +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW processlist ( + thd_id, + conn_id, + user, + db, + command, + state, + time, + current_statement, + statement_latency, + progress, + lock_latency, + rows_examined, + rows_sent, + rows_affected, + tmp_tables, + tmp_disk_tables, + full_scan, + last_statement, + last_statement_latency, + current_memory, + last_wait, + last_wait_latency, + source, + trx_latency, + trx_state, + trx_autocommit, + pid, + program_name +) AS +SELECT pps.thread_id AS thd_id, + pps.processlist_id AS conn_id, + IF(pps.name = 'thread/sql/one_connection', + CONCAT(pps.processlist_user, '@', pps.processlist_host), + REPLACE(pps.name, 'thread/', '')) user, + pps.processlist_db AS db, + pps.processlist_command AS command, + pps.processlist_state AS state, + pps.processlist_time AS time, + sys.format_statement(pps.processlist_info) AS current_statement, + IF(esc.end_event_id IS NULL, + sys.format_time(esc.timer_wait), + NULL) AS statement_latency, + IF(esc.end_event_id IS NULL, + ROUND(100 * (estc.work_completed / estc.work_estimated), 2), + NULL) AS progress, + sys.format_time(esc.lock_time) AS lock_latency, + esc.rows_examined AS rows_examined, + esc.rows_sent AS rows_sent, + esc.rows_affected AS rows_affected, + esc.created_tmp_tables AS tmp_tables, + esc.created_tmp_disk_tables AS tmp_disk_tables, + IF(esc.no_good_index_used > 0 OR esc.no_index_used > 0, 'YES', 'NO') AS full_scan, + IF(esc.end_event_id IS NOT NULL, + sys.format_statement(esc.sql_text), + NULL) AS last_statement, + IF(esc.end_event_id IS NOT NULL, + sys.format_time(esc.timer_wait), + NULL) AS last_statement_latency, + sys.format_bytes(mem.current_allocated) AS current_memory, + ewc.event_name AS last_wait, + IF(ewc.end_event_id IS NULL AND ewc.event_name IS NOT NULL, + 'Still Waiting', + sys.format_time(ewc.timer_wait)) last_wait_latency, + ewc.source, + sys.format_time(etc.timer_wait) AS trx_latency, + etc.state AS trx_state, + etc.autocommit AS trx_autocommit, + conattr_pid.attr_value as pid, + conattr_progname.attr_value as program_name + FROM performance_schema.threads AS pps + LEFT JOIN performance_schema.events_waits_current AS ewc USING (thread_id) + LEFT JOIN performance_schema.events_stages_current AS estc USING (thread_id) + LEFT JOIN performance_schema.events_statements_current AS esc USING (thread_id) + LEFT JOIN performance_schema.events_transactions_current AS etc USING (thread_id) + LEFT JOIN sys.x$memory_by_thread_by_current_bytes AS mem USING (thread_id) + LEFT JOIN performance_schema.session_connect_attrs AS conattr_pid + ON conattr_pid.processlist_id=pps.processlist_id and conattr_pid.attr_name='_pid' + LEFT JOIN performance_schema.session_connect_attrs AS conattr_progname + ON conattr_progname.processlist_id=pps.processlist_id and conattr_progname.attr_name='program_name' + ORDER BY pps.processlist_time DESC, last_wait_latency DESC; diff --git a/scripts/sys_schema/views/p_s/ps_check_lost_instrumentation.sql b/scripts/sys_schema/views/p_s/ps_check_lost_instrumentation.sql new file mode 100644 index 00000000..21d8ecb6 --- /dev/null +++ b/scripts/sys_schema/views/p_s/ps_check_lost_instrumentation.sql @@ -0,0 +1,43 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: ps_check_lost_instrumentation +-- +-- Used to check whether Performance Schema is not able to monitor +-- all runtime data - only returns variables that have lost instruments +-- +-- mysql> select * from ps_check_lost_instrumentation; +-- +----------------------------------------+----------------+ +-- | variable_name | variable_value | +-- +----------------------------------------+----------------+ +-- | Performance_schema_file_handles_lost | 101223 | +-- | Performance_schema_file_instances_lost | 1231 | +-- +----------------------------------------+----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW ps_check_lost_instrumentation ( + variable_name, + variable_value +) +AS +SELECT variable_name, variable_value + FROM information_schema.global_status + WHERE variable_name LIKE 'perf%lost' + AND variable_value > 0; diff --git a/scripts/sys_schema/views/p_s/ps_check_lost_instrumentation_57.sql b/scripts/sys_schema/views/p_s/ps_check_lost_instrumentation_57.sql new file mode 100644 index 00000000..25cc829b --- /dev/null +++ b/scripts/sys_schema/views/p_s/ps_check_lost_instrumentation_57.sql @@ -0,0 +1,43 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: ps_check_lost_instrumentation +-- +-- Used to check whether Performance Schema is not able to monitor +-- all runtime data - only returns variables that have lost instruments +-- +-- mysql> select * from ps_check_lost_instrumentation; +-- +----------------------------------------+----------------+ +-- | variable_name | variable_value | +-- +----------------------------------------+----------------+ +-- | Performance_schema_file_handles_lost | 101223 | +-- | Performance_schema_file_instances_lost | 1231 | +-- +----------------------------------------+----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW ps_check_lost_instrumentation ( + variable_name, + variable_value +) +AS +SELECT variable_name, variable_value + FROM performance_schema.global_status + WHERE variable_name LIKE 'perf%lost' + AND variable_value > 0; diff --git a/scripts/sys_schema/views/p_s/schema_index_statistics.sql b/scripts/sys_schema/views/p_s/schema_index_statistics.sql new file mode 100644 index 00000000..84ce7ead --- /dev/null +++ b/scripts/sys_schema/views/p_s/schema_index_statistics.sql @@ -0,0 +1,65 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: schema_index_statistics +-- +-- Statistics around indexes. +-- +-- Ordered by the total wait time descending - top indexes are most contended. +-- +-- mysql> select * from schema_index_statistics limit 5; +-- +------------------+-------------+------------+---------------+----------------+---------------+----------------+--------------+----------------+--------------+----------------+ +-- | table_schema | table_name | index_name | rows_selected | select_latency | rows_inserted | insert_latency | rows_updated | update_latency | rows_deleted | delete_latency | +-- +------------------+-------------+------------+---------------+----------------+---------------+----------------+--------------+----------------+--------------+----------------+ +-- | mem | mysqlserver | PRIMARY | 6208 | 108.27 ms | 0 | 0 ps | 5470 | 1.47 s | 0 | 0 ps | +-- | mem | innodb | PRIMARY | 4666 | 76.27 ms | 0 | 0 ps | 4454 | 571.47 ms | 0 | 0 ps | +-- | mem | connection | PRIMARY | 1064 | 20.98 ms | 0 | 0 ps | 1064 | 457.30 ms | 0 | 0 ps | +-- | mem | environment | PRIMARY | 5566 | 151.17 ms | 0 | 0 ps | 694 | 252.57 ms | 0 | 0 ps | +-- | mem | querycache | PRIMARY | 1698 | 27.99 ms | 0 | 0 ps | 1698 | 371.72 ms | 0 | 0 ps | +-- +------------------+-------------+------------+---------------+----------------+---------------+----------------+--------------+----------------+--------------+----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW schema_index_statistics ( + table_schema, + table_name, + index_name, + rows_selected, + select_latency, + rows_inserted, + insert_latency, + rows_updated, + update_latency, + rows_deleted, + delete_latency +) AS +SELECT OBJECT_SCHEMA AS table_schema, + OBJECT_NAME AS table_name, + INDEX_NAME as index_name, + COUNT_FETCH AS rows_selected, + sys.format_time(SUM_TIMER_FETCH) AS select_latency, + COUNT_INSERT AS rows_inserted, + sys.format_time(SUM_TIMER_INSERT) AS insert_latency, + COUNT_UPDATE AS rows_updated, + sys.format_time(SUM_TIMER_UPDATE) AS update_latency, + COUNT_DELETE AS rows_deleted, + sys.format_time(SUM_TIMER_INSERT) AS delete_latency + FROM performance_schema.table_io_waits_summary_by_index_usage + WHERE index_name IS NOT NULL + ORDER BY sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/schema_table_lock_waits.sql b/scripts/sys_schema/views/p_s/schema_table_lock_waits.sql new file mode 100644 index 00000000..dd293c5b --- /dev/null +++ b/scripts/sys_schema/views/p_s/schema_table_lock_waits.sql @@ -0,0 +1,97 @@ +-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: schema_table_lock_waits +-- +-- Shows sessions that are blocked waiting on table metadata locks, and +-- who is blocking them. +-- +-- mysql> select * from sys.schema_table_lock_waits\G +-- *************************** 1. row *************************** +-- object_schema: test +-- object_name: t +-- waiting_thread_id: 43 +-- waiting_pid: 21 +-- waiting_account: msandbox@localhost +-- waiting_lock_type: SHARED_UPGRADABLE +-- waiting_lock_duration: TRANSACTION +-- waiting_query: alter table test.t add foo int +-- waiting_query_secs: 988 +-- waiting_query_rows_affected: 0 +-- waiting_query_rows_examined: 0 +-- blocking_thread_id: 42 +-- blocking_pid: 20 +-- blocking_account: msandbox@localhost +-- blocking_lock_type: SHARED_NO_READ_WRITE +-- blocking_lock_duration: TRANSACTION +-- sql_kill_blocking_query: KILL QUERY 20 +-- sql_kill_blocking_connection: KILL 20 +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW schema_table_lock_waits ( + object_schema, + object_name, + waiting_thread_id, + waiting_pid, + waiting_account, + waiting_lock_type, + waiting_lock_duration, + waiting_query, + waiting_query_secs, + waiting_query_rows_affected, + waiting_query_rows_examined, + blocking_thread_id, + blocking_pid, + blocking_account, + blocking_lock_type, + blocking_lock_duration, + sql_kill_blocking_query, + sql_kill_blocking_connection +) AS +SELECT g.object_schema AS object_schema, + g.object_name AS object_name, + pt.thread_id AS waiting_thread_id, + pt.processlist_id AS waiting_pid, + sys.ps_thread_account(p.owner_thread_id) AS waiting_account, + p.lock_type AS waiting_lock_type, + p.lock_duration AS waiting_lock_duration, + sys.format_statement(pt.processlist_info) AS waiting_query, + pt.processlist_time AS waiting_query_secs, + ps.rows_affected AS waiting_query_rows_affected, + ps.rows_examined AS waiting_query_rows_examined, + gt.thread_id AS blocking_thread_id, + gt.processlist_id AS blocking_pid, + sys.ps_thread_account(g.owner_thread_id) AS blocking_account, + g.lock_type AS blocking_lock_type, + g.lock_duration AS blocking_lock_duration, + CONCAT('KILL QUERY ', gt.processlist_id) AS sql_kill_blocking_query, + CONCAT('KILL ', gt.processlist_id) AS sql_kill_blocking_connection + FROM performance_schema.metadata_locks g + INNER JOIN performance_schema.metadata_locks p + ON g.object_type = p.object_type + AND g.object_schema = p.object_schema + AND g.object_name = p.object_name + AND g.lock_status = 'GRANTED' + AND p.lock_status = 'PENDING' + INNER JOIN performance_schema.threads gt ON g.owner_thread_id = gt.thread_id + INNER JOIN performance_schema.threads pt ON p.owner_thread_id = pt.thread_id + LEFT JOIN performance_schema.events_statements_current gs ON g.owner_thread_id = gs.thread_id + LEFT JOIN performance_schema.events_statements_current ps ON p.owner_thread_id = ps.thread_id + WHERE g.object_type = 'TABLE'; diff --git a/scripts/sys_schema/views/p_s/schema_table_statistics.sql b/scripts/sys_schema/views/p_s/schema_table_statistics.sql new file mode 100644 index 00000000..198d2e0e --- /dev/null +++ b/scripts/sys_schema/views/p_s/schema_table_statistics.sql @@ -0,0 +1,94 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: schema_table_statistics +-- +-- Statistics around tables. +-- +-- Ordered by the total wait time descending - top tables are most contended. +-- +-- mysql> SELECT * FROM schema_table_statistics\G +-- *************************** 1. row *************************** +-- table_schema: sys +-- table_name: sys_config +-- total_latency: 0 ps +-- rows_fetched: 0 +-- fetch_latency: 0 ps +-- rows_inserted: 0 +-- insert_latency: 0 ps +-- rows_updated: 0 +-- update_latency: 0 ps +-- rows_deleted: 0 +-- delete_latency: 0 ps +-- io_read_requests: 8 +-- io_read: 2.28 KiB +-- io_read_latency: 727.32 us +-- io_write_requests: 0 +-- io_write: 0 bytes +-- io_write_latency: 0 ps +-- io_misc_requests: 10 +-- io_misc_latency: 126.88 us +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW schema_table_statistics ( + table_schema, + table_name, + total_latency, + rows_fetched, + fetch_latency, + rows_inserted, + insert_latency, + rows_updated, + update_latency, + rows_deleted, + delete_latency, + io_read_requests, + io_read, + io_read_latency, + io_write_requests, + io_write, + io_write_latency, + io_misc_requests, + io_misc_latency +) AS +SELECT pst.object_schema AS table_schema, + pst.object_name AS table_name, + sys.format_time(pst.sum_timer_wait) AS total_latency, + pst.count_fetch AS rows_fetched, + sys.format_time(pst.sum_timer_fetch) AS fetch_latency, + pst.count_insert AS rows_inserted, + sys.format_time(pst.sum_timer_insert) AS insert_latency, + pst.count_update AS rows_updated, + sys.format_time(pst.sum_timer_update) AS update_latency, + pst.count_delete AS rows_deleted, + sys.format_time(pst.sum_timer_delete) AS delete_latency, + fsbi.count_read AS io_read_requests, + sys.format_bytes(fsbi.sum_number_of_bytes_read) AS io_read, + sys.format_time(fsbi.sum_timer_read) AS io_read_latency, + fsbi.count_write AS io_write_requests, + sys.format_bytes(fsbi.sum_number_of_bytes_write) AS io_write, + sys.format_time(fsbi.sum_timer_write) AS io_write_latency, + fsbi.count_misc AS io_misc_requests, + sys.format_time(fsbi.sum_timer_misc) AS io_misc_latency + FROM performance_schema.table_io_waits_summary_by_table AS pst + LEFT JOIN x$ps_schema_table_statistics_io AS fsbi + ON pst.object_schema = fsbi.table_schema + AND pst.object_name = fsbi.table_name + ORDER BY pst.sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/schema_table_statistics_with_buffer.sql b/scripts/sys_schema/views/p_s/schema_table_statistics_with_buffer.sql new file mode 100644 index 00000000..acdaefb3 --- /dev/null +++ b/scripts/sys_schema/views/p_s/schema_table_statistics_with_buffer.sql @@ -0,0 +1,122 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: schema_table_statistics_with_buffer +-- +-- Statistics around tables. +-- +-- Ordered by the total wait time descending - top tables are most contended. +-- +-- More statistics such as caching stats for the InnoDB buffer pool with InnoDB tables +-- +-- mysql> select * from schema_table_statistics_with_buffer limit 1\G +-- *************************** 1. row *************************** +-- table_schema: mem +-- table_name: mysqlserver +-- rows_fetched: 27087 +-- fetch_latency: 442.72 ms +-- rows_inserted: 2 +-- insert_latency: 185.04 us +-- rows_updated: 5096 +-- update_latency: 1.39 s +-- rows_deleted: 0 +-- delete_latency: 0 ps +-- io_read_requests: 2565 +-- io_read_bytes: 1121627 +-- io_read_latency: 10.07 ms +-- io_write_requests: 1691 +-- io_write_bytes: 128383 +-- io_write_latency: 14.17 ms +-- io_misc_requests: 2698 +-- io_misc_latency: 433.66 ms +-- innodb_buffer_pages: 19 +-- innodb_buffer_pages_hashed: 19 +-- innodb_buffer_pages_old: 19 +-- innodb_buffer_bytes_allocated: 311296 +-- innodb_buffer_bytes_data: 1924 +-- innodb_buffer_rows_cached: 2 +-- + +DELIMITER $$ +BEGIN NOT ATOMIC +DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END; +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW schema_table_statistics_with_buffer ( + table_schema, + table_name, + rows_fetched, + fetch_latency, + rows_inserted, + insert_latency, + rows_updated, + update_latency, + rows_deleted, + delete_latency, + io_read_requests, + io_read, + io_read_latency, + io_write_requests, + io_write, + io_write_latency, + io_misc_requests, + io_misc_latency, + innodb_buffer_allocated, + innodb_buffer_data, + innodb_buffer_free, + innodb_buffer_pages, + innodb_buffer_pages_hashed, + innodb_buffer_pages_old, + innodb_buffer_rows_cached +) AS +SELECT pst.object_schema AS table_schema, + pst.object_name AS table_name, + pst.count_fetch AS rows_fetched, + sys.format_time(pst.sum_timer_fetch) AS fetch_latency, + pst.count_insert AS rows_inserted, + sys.format_time(pst.sum_timer_insert) AS insert_latency, + pst.count_update AS rows_updated, + sys.format_time(pst.sum_timer_update) AS update_latency, + pst.count_delete AS rows_deleted, + sys.format_time(pst.sum_timer_delete) AS delete_latency, + fsbi.count_read AS io_read_requests, + sys.format_bytes(fsbi.sum_number_of_bytes_read) AS io_read, + sys.format_time(fsbi.sum_timer_read) AS io_read_latency, + fsbi.count_write AS io_write_requests, + sys.format_bytes(fsbi.sum_number_of_bytes_write) AS io_write, + sys.format_time(fsbi.sum_timer_write) AS io_write_latency, + fsbi.count_misc AS io_misc_requests, + sys.format_time(fsbi.sum_timer_misc) AS io_misc_latency, + sys.format_bytes(ibp.allocated) AS innodb_buffer_allocated, + sys.format_bytes(ibp.data) AS innodb_buffer_data, + sys.format_bytes(ibp.allocated - ibp.data) AS innodb_buffer_free, + ibp.pages AS innodb_buffer_pages, + ibp.pages_hashed AS innodb_buffer_pages_hashed, + ibp.pages_old AS innodb_buffer_pages_old, + ibp.rows_cached AS innodb_buffer_rows_cached + FROM performance_schema.table_io_waits_summary_by_table AS pst + LEFT JOIN x$ps_schema_table_statistics_io AS fsbi + ON pst.object_schema = fsbi.table_schema + AND pst.object_name = fsbi.table_name + LEFT JOIN sys.x$innodb_buffer_stats_by_table AS ibp + ON pst.object_schema = ibp.object_schema + AND pst.object_name = ibp.object_name + ORDER BY pst.sum_timer_wait DESC; + +END$$ +DELIMITER ; diff --git a/scripts/sys_schema/views/p_s/schema_tables_with_full_table_scans.sql b/scripts/sys_schema/views/p_s/schema_tables_with_full_table_scans.sql new file mode 100644 index 00000000..6199d244 --- /dev/null +++ b/scripts/sys_schema/views/p_s/schema_tables_with_full_table_scans.sql @@ -0,0 +1,51 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: schema_tables_with_full_table_scans +-- +-- Find tables that are being accessed by full table scans +-- ordering by the number of rows scanned descending. +-- +-- mysql> select * from schema_tables_with_full_table_scans limit 5; +-- +--------------------+--------------------------------+-------------------+-----------+ +-- | object_schema | object_name | rows_full_scanned | latency | +-- +--------------------+--------------------------------+-------------------+-----------+ +-- | mem30__instruments | fsstatistics | 10207042 | 13.10 s | +-- | mem30__instruments | preparedstatementapidata | 436428 | 973.27 ms | +-- | mem30__instruments | mysqlprocessactivity | 411702 | 282.07 ms | +-- | mem30__instruments | querycachequeriesincachedata | 374011 | 767.15 ms | +-- | mem30__instruments | rowaccessesdata | 322321 | 1.55 s | +-- +--------------------+--------------------------------+-------------------+-----------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW schema_tables_with_full_table_scans ( + object_schema, + object_name, + rows_full_scanned, + latency +) AS +SELECT object_schema, + object_name, + count_read AS rows_full_scanned, + sys.format_time(sum_timer_wait) AS latency + FROM performance_schema.table_io_waits_summary_by_index_usage + WHERE index_name IS NULL + AND count_read > 0 + ORDER BY count_read DESC; diff --git a/scripts/sys_schema/views/p_s/schema_unused_indexes.sql b/scripts/sys_schema/views/p_s/schema_unused_indexes.sql new file mode 100644 index 00000000..168f88bb --- /dev/null +++ b/scripts/sys_schema/views/p_s/schema_unused_indexes.sql @@ -0,0 +1,56 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: schema_unused_indexes +-- +-- Finds indexes that have had no events against them (and hence, no usage). +-- +-- To trust whether the data from this view is representative of your workload, +-- you should ensure that the server has been up for a representative amount of +-- time before using it. +-- +-- PRIMARY (key) indexes are ignored. +-- +-- mysql> select * from schema_unused_indexes limit 5; +-- +--------------------+---------------------+--------------------+ +-- | object_schema | object_name | index_name | +-- +--------------------+---------------------+--------------------+ +-- | mem30__bean_config | plists | path | +-- | mem30__config | group_selections | name | +-- | mem30__config | notification_groups | name | +-- | mem30__config | user_form_defaults | FKC1AEF1F9E7EE2CFB | +-- | mem30__enterprise | whats_new_entries | entryId | +-- +--------------------+---------------------+--------------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW schema_unused_indexes ( + object_schema, + object_name, + index_name +) AS +SELECT object_schema, + object_name, + index_name + FROM performance_schema.table_io_waits_summary_by_index_usage + WHERE index_name IS NOT NULL + AND count_star = 0 + AND object_schema != 'mysql' + AND index_name != 'PRIMARY' + ORDER BY object_schema, object_name; diff --git a/scripts/sys_schema/views/p_s/session_ssl_status.sql b/scripts/sys_schema/views/p_s/session_ssl_status.sql new file mode 100644 index 00000000..cb8ce855 --- /dev/null +++ b/scripts/sys_schema/views/p_s/session_ssl_status.sql @@ -0,0 +1,36 @@ +-- +-- View: session_ssl_status +-- +-- Shows SSL version, cipher and the count of re-used SSL sessions per connection +-- +-- mysql> select * from session_ssl_status; +-- +-----------+-------------+--------------------+---------------------+ +-- | thread_id | ssl_version | ssl_cipher | ssl_sessions_reused | +-- +-----------+-------------+--------------------+---------------------+ +-- | 26 | TLSv1 | DHE-RSA-AES256-SHA | 0 | +-- | 27 | TLSv1 | DHE-RSA-AES256-SHA | 0 | +-- | 28 | TLSv1 | DHE-RSA-AES256-SHA | 0 | +-- +-----------+-------------+--------------------+---------------------+ +-- 3 rows in set (0.00 sec) +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW session_ssl_status ( + thread_id, + ssl_version, + ssl_cipher, + ssl_sessions_reused +) AS +SELECT sslver.thread_id, + sslver.variable_value ssl_version, + sslcip.variable_value ssl_cipher, + sslreuse.variable_value ssl_sessions_reused + FROM performance_schema.status_by_thread sslver + LEFT JOIN performance_schema.status_by_thread sslcip + ON (sslcip.thread_id=sslver.thread_id and sslcip.variable_name='Ssl_cipher') + LEFT JOIN performance_schema.status_by_thread sslreuse + ON (sslreuse.thread_id=sslver.thread_id and sslreuse.variable_name='Ssl_sessions_reused') + WHERE sslver.variable_name='Ssl_version'; diff --git a/scripts/sys_schema/views/p_s/sessions.sql b/scripts/sys_schema/views/p_s/sessions.sql new file mode 100644 index 00000000..94471aab --- /dev/null +++ b/scripts/sys_schema/views/p_s/sessions.sql @@ -0,0 +1,64 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: session +-- +-- Filter sys.processlist to only show user sessions and not background threads. +-- This is a non-blocking closer replacement to +-- [INFORMATION_SCHEMA. | SHOW FULL] PROCESSLIST +-- +-- Performs less locking than the legacy sources, whilst giving extra information. +-- +-- mysql> select * from sys.session\G +-- *************************** 1. row *************************** +-- thd_id: 24 +-- conn_id: 2 +-- user: root@localhost +-- db: sys +-- command: Query +-- state: Sending data +-- time: 0 +-- current_statement: select * from sys.session +-- statement_latency: 137.22 ms +-- progress: NULL +-- lock_latency: 33.75 ms +-- rows_examined: 0 +-- rows_sent: 0 +-- rows_affected: 0 +-- tmp_tables: 4 +-- tmp_disk_tables: 1 +-- full_scan: YES +-- last_statement: NULL +-- last_statement_latency: NULL +-- current_memory: 3.26 MiB +-- last_wait: wait/synch/mutex/innodb/file_format_max_mutex +-- last_wait_latency: 64.09 ns +-- source: trx0sys.cc:778 +-- trx_latency: 7.88 s +-- trx_state: ACTIVE +-- trx_autocommit: NO +-- pid: 4212 +-- program_name: mysql +-- + +CREATE OR REPLACE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW session + AS +SELECT * FROM sys.processlist +WHERE conn_id IS NOT NULL AND command != 'Daemon'; + diff --git a/scripts/sys_schema/views/p_s/statement_analysis.sql b/scripts/sys_schema/views/p_s/statement_analysis.sql new file mode 100644 index 00000000..0d9c9cef --- /dev/null +++ b/scripts/sys_schema/views/p_s/statement_analysis.sql @@ -0,0 +1,103 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: statement_analysis +-- +-- Lists a normalized statement view with aggregated statistics, +-- mimics the MySQL Enterprise Monitor Query Analysis view, +-- ordered by the total execution time per normalized statement +-- +-- mysql> select- * from statement_analysis limit 1\G +-- *************************** 1. row--************************** +-- query: SELECT * FROM `schema_object_o ... MA` , `information_schema` ... +-- db: sys +-- full_scan: * +-- exec_count: 2 +-- err_count: 0 +-- warn_count: 0 +-- total_latency: 16.75 s +-- max_latency: 16.57 s +-- avg_latency: 8.38 s +-- lock_latency: 16.69 s +-- rows_sent: 84 +-- rows_sent_avg: 42 +-- rows_examined: 20012 +-- rows_affected: 0 +-- rows_affected_avg: 0 +-- rows_examined_avg: 10006 +-- tmp_tables: 378 +-- tmp_disk_tables: 66 +-- rows_sorted: 168 +-- sort_merge_passes: 0 +-- digest: 54f9bd520f0bbf15db0c2ed93386bec9 +-- first_seen: 2014-03-07 13:13:41 +-- last_seen: 2014-03-07 13:13:48 +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW statement_analysis ( + query, + db, + full_scan, + exec_count, + err_count, + warn_count, + total_latency, + max_latency, + avg_latency, + lock_latency, + rows_sent, + rows_sent_avg, + rows_examined, + rows_examined_avg, + rows_affected, + rows_affected_avg, + tmp_tables, + tmp_disk_tables, + rows_sorted, + sort_merge_passes, + digest, + first_seen, + last_seen +) AS +SELECT sys.format_statement(DIGEST_TEXT) AS query, + SCHEMA_NAME AS db, + IF(SUM_NO_GOOD_INDEX_USED > 0 OR SUM_NO_INDEX_USED > 0, '*', '') AS full_scan, + COUNT_STAR AS exec_count, + SUM_ERRORS AS err_count, + SUM_WARNINGS AS warn_count, + sys.format_time(SUM_TIMER_WAIT) AS total_latency, + sys.format_time(MAX_TIMER_WAIT) AS max_latency, + sys.format_time(AVG_TIMER_WAIT) AS avg_latency, + sys.format_time(SUM_LOCK_TIME) AS lock_latency, + SUM_ROWS_SENT AS rows_sent, + ROUND(IFNULL(SUM_ROWS_SENT / NULLIF(COUNT_STAR, 0), 0)) AS rows_sent_avg, + SUM_ROWS_EXAMINED AS rows_examined, + ROUND(IFNULL(SUM_ROWS_EXAMINED / NULLIF(COUNT_STAR, 0), 0)) AS rows_examined_avg, + SUM_ROWS_AFFECTED AS rows_affected, + ROUND(IFNULL(SUM_ROWS_AFFECTED / NULLIF(COUNT_STAR, 0), 0)) AS rows_affected_avg, + SUM_CREATED_TMP_TABLES AS tmp_tables, + SUM_CREATED_TMP_DISK_TABLES AS tmp_disk_tables, + SUM_SORT_ROWS AS rows_sorted, + SUM_SORT_MERGE_PASSES AS sort_merge_passes, + DIGEST AS digest, + FIRST_SEEN AS first_seen, + LAST_SEEN as last_seen + FROM performance_schema.events_statements_summary_by_digest +ORDER BY SUM_TIMER_WAIT DESC; diff --git a/scripts/sys_schema/views/p_s/statements_with_errors_or_warnings.sql b/scripts/sys_schema/views/p_s/statements_with_errors_or_warnings.sql new file mode 100644 index 00000000..e5e5e67c --- /dev/null +++ b/scripts/sys_schema/views/p_s/statements_with_errors_or_warnings.sql @@ -0,0 +1,64 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: statements_with_errors_or_warnings +-- +-- Lists all normalized statements that have raised errors or warnings. +-- +-- mysql> select * from statements_with_errors_or_warnings LIMIT 1\G +-- *************************** 1. row *************************** +-- query: CREATE OR REPLACE ALGORITHM = ... _delete` AS `rows_deleted` ... +-- db: sys +-- exec_count: 2 +-- errors: 1 +-- error_pct: 50.0000 +-- warnings: 0 +-- warning_pct: 0.0000 +-- first_seen: 2014-03-07 12:56:54 +-- last_seen: 2014-03-07 13:01:01 +-- digest: 943a788859e623d5f7798ba0ae0fd8a9 +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW statements_with_errors_or_warnings ( + query, + db, + exec_count, + errors, + error_pct, + warnings, + warning_pct, + first_seen, + last_seen, + digest +) AS +SELECT sys.format_statement(DIGEST_TEXT) AS query, + SCHEMA_NAME as db, + COUNT_STAR AS exec_count, + SUM_ERRORS AS errors, + IFNULL(SUM_ERRORS / NULLIF(COUNT_STAR, 0), 0) * 100 as error_pct, + SUM_WARNINGS AS warnings, + IFNULL(SUM_WARNINGS / NULLIF(COUNT_STAR, 0), 0) * 100 as warning_pct, + FIRST_SEEN as first_seen, + LAST_SEEN as last_seen, + DIGEST AS digest + FROM performance_schema.events_statements_summary_by_digest + WHERE SUM_ERRORS > 0 + OR SUM_WARNINGS > 0 +ORDER BY SUM_ERRORS DESC, SUM_WARNINGS DESC; diff --git a/scripts/sys_schema/views/p_s/statements_with_full_table_scans.sql b/scripts/sys_schema/views/p_s/statements_with_full_table_scans.sql new file mode 100644 index 00000000..84217364 --- /dev/null +++ b/scripts/sys_schema/views/p_s/statements_with_full_table_scans.sql @@ -0,0 +1,82 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: statements_with_full_table_scans +-- +-- Lists all normalized statements that use have done a full table scan +-- ordered by number the percentage of times a full scan was done, +-- then by the statement latency. +-- +-- This view ignores SHOW statements, as these always cause a full table scan, +-- and there is nothing that can be done about this. +-- +-- mysql> select * from statements_with_full_table_scans limit 1\G +-- *************************** 1. row *************************** +-- query: SELECT * FROM `schema_tables_w ... ex_usage` . `COUNT_READ` DESC +-- db: sys +-- exec_count: 1 +-- total_latency: 88.20 ms +-- no_index_used_count: 1 +-- no_good_index_used_count: 0 +-- no_index_used_pct: 100 +-- rows_sent: 0 +-- rows_examined: 1501 +-- rows_sent_avg: 0 +-- rows_examined_avg: 1501 +-- first_seen: 2014-03-07 13:58:20 +-- last_seen: 2014-03-07 13:58:20 +-- digest: 64baecd5c1e1e1651a6b92e55442a288 +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW statements_with_full_table_scans ( + query, + db, + exec_count, + total_latency, + no_index_used_count, + no_good_index_used_count, + no_index_used_pct, + rows_sent, + rows_examined, + rows_sent_avg, + rows_examined_avg, + first_seen, + last_seen, + digest +) AS +SELECT sys.format_statement(DIGEST_TEXT) AS query, + SCHEMA_NAME as db, + COUNT_STAR AS exec_count, + sys.format_time(SUM_TIMER_WAIT) AS total_latency, + SUM_NO_INDEX_USED AS no_index_used_count, + SUM_NO_GOOD_INDEX_USED AS no_good_index_used_count, + ROUND(IFNULL(SUM_NO_INDEX_USED / NULLIF(COUNT_STAR, 0), 0) * 100) AS no_index_used_pct, + SUM_ROWS_SENT AS rows_sent, + SUM_ROWS_EXAMINED AS rows_examined, + ROUND(SUM_ROWS_SENT/COUNT_STAR) AS rows_sent_avg, + ROUND(SUM_ROWS_EXAMINED/COUNT_STAR) AS rows_examined_avg, + FIRST_SEEN as first_seen, + LAST_SEEN as last_seen, + DIGEST AS digest + FROM performance_schema.events_statements_summary_by_digest + WHERE (SUM_NO_INDEX_USED > 0 + OR SUM_NO_GOOD_INDEX_USED > 0) + AND DIGEST_TEXT NOT LIKE 'SHOW%' + ORDER BY no_index_used_pct DESC, total_latency DESC; diff --git a/scripts/sys_schema/views/p_s/statements_with_runtimes_in_95th_percentile.sql b/scripts/sys_schema/views/p_s/statements_with_runtimes_in_95th_percentile.sql new file mode 100644 index 00000000..6e2489ed --- /dev/null +++ b/scripts/sys_schema/views/p_s/statements_with_runtimes_in_95th_percentile.sql @@ -0,0 +1,74 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: statements_with_runtimes_in_95th_percentile +-- +-- List all statements whose average runtime, in microseconds, is in the top 95th percentile. +-- +-- mysql> select * from statements_with_runtimes_in_95th_percentile limit 5; +-- +-------------------------------------------------------------------+------+-----------+------------+-----------+------------+---------------+-------------+-------------+-----------+---------------+---------------+-------------------+---------------------+---------------------+----------------------------------+ +-- | query | db | full_scan | exec_count | err_count | warn_count | total_latency | max_latency | avg_latency | rows_sent | rows_sent_avg | rows_examined | rows_examined_avg | FIRST_SEEN | LAST_SEEN | digest | +-- +-------------------------------------------------------------------+------+-----------+------------+-----------+------------+---------------+-------------+-------------+-----------+---------------+---------------+-------------------+---------------------+---------------------+----------------------------------+ +-- | SELECT `e` . `round_robin_bin` ... `timestamp` = `maxes` . `ts` | mem | * | 14 | 0 | 0 | 43.96 s | 6.69 s | 3.14 s | 11 | 1 | 253170 | 18084 | 2013-12-04 20:05:01 | 2013-12-04 20:06:34 | 29ba002bf039bb6439357a10134407de | +-- | SELECT `e` . `round_robin_bin` ... `timestamp` = `maxes` . `ts` | mem | * | 8 | 0 | 0 | 17.89 s | 4.12 s | 2.24 s | 7 | 1 | 169534 | 21192 | 2013-12-04 20:04:54 | 2013-12-04 20:05:05 | 0b1c1f91e7e9e0ff91aa49d15f540793 | +-- | SELECT `e` . `round_robin_bin` ... `timestamp` = `maxes` . `ts` | mem | * | 1 | 0 | 0 | 2.22 s | 2.22 s | 2.22 s | 1 | 1 | 40322 | 40322 | 2013-12-04 20:05:39 | 2013-12-04 20:05:39 | 07b27145c8f8a3779737df5032374833 | +-- | SELECT `e` . `round_robin_bin` ... `timestamp` = `maxes` . `ts` | mem | * | 1 | 0 | 0 | 1.97 s | 1.97 s | 1.97 s | 1 | 1 | 40322 | 40322 | 2013-12-04 20:05:39 | 2013-12-04 20:05:39 | a07488137ea5c1bccf3e291c50bfd21f | +-- | SELECT `e` . `round_robin_bin` ... `timestamp` = `maxes` . `ts` | mem | * | 2 | 0 | 0 | 3.91 s | 3.91 s | 1.96 s | 1 | 1 | 13126 | 6563 | 2013-12-04 20:05:04 | 2013-12-04 20:06:34 | b8bddc6566366dafc7e474f67096a93b | +-- +-------------------------------------------------------------------+------+-----------+------------+-----------+------------+---------------+-------------+-------------+-----------+---------------+---------------+-------------------+---------------------+---------------------+----------------------------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW statements_with_runtimes_in_95th_percentile ( + query, + db, + full_scan, + exec_count, + err_count, + warn_count, + total_latency, + max_latency, + avg_latency, + rows_sent, + rows_sent_avg, + rows_examined, + rows_examined_avg, + first_seen, + last_seen, + digest +) AS +SELECT sys.format_statement(DIGEST_TEXT) AS query, + SCHEMA_NAME as db, + IF(SUM_NO_GOOD_INDEX_USED > 0 OR SUM_NO_INDEX_USED > 0, '*', '') AS full_scan, + COUNT_STAR AS exec_count, + SUM_ERRORS AS err_count, + SUM_WARNINGS AS warn_count, + sys.format_time(SUM_TIMER_WAIT) AS total_latency, + sys.format_time(MAX_TIMER_WAIT) AS max_latency, + sys.format_time(AVG_TIMER_WAIT) AS avg_latency, + SUM_ROWS_SENT AS rows_sent, + ROUND(IFNULL(SUM_ROWS_SENT / NULLIF(COUNT_STAR, 0), 0)) AS rows_sent_avg, + SUM_ROWS_EXAMINED AS rows_examined, + ROUND(IFNULL(SUM_ROWS_EXAMINED / NULLIF(COUNT_STAR, 0), 0)) AS rows_examined_avg, + FIRST_SEEN AS first_seen, + LAST_SEEN AS last_seen, + DIGEST AS digest + FROM performance_schema.events_statements_summary_by_digest stmts + JOIN sys.x$ps_digest_95th_percentile_by_avg_us AS top_percentile + ON ROUND(stmts.avg_timer_wait/1000000) >= top_percentile.avg_us + ORDER BY AVG_TIMER_WAIT DESC; diff --git a/scripts/sys_schema/views/p_s/statements_with_sorting.sql b/scripts/sys_schema/views/p_s/statements_with_sorting.sql new file mode 100644 index 00000000..0216a12e --- /dev/null +++ b/scripts/sys_schema/views/p_s/statements_with_sorting.sql @@ -0,0 +1,73 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: statements_with_sorting +-- +-- Lists all normalized statements that have done sorts, +-- ordered by total_latency descending. +-- +-- mysql> select * from statements_with_sorting limit 1\G +-- *************************** 1. row *************************** +-- query: SELECT * FROM `schema_object_o ... MA` , `information_schema` ... +-- db: sys +-- exec_count: 2 +-- total_latency: 16.75 s +-- sort_merge_passes: 0 +-- avg_sort_merges: 0 +-- sorts_using_scans: 12 +-- sort_using_range: 0 +-- rows_sorted: 168 +-- avg_rows_sorted: 84 +-- first_seen: 2014-03-07 13:13:41 +-- last_seen: 2014-03-07 13:13:48 +-- digest: 54f9bd520f0bbf15db0c2ed93386bec9 +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW statements_with_sorting ( + query, + db, + exec_count, + total_latency, + sort_merge_passes, + avg_sort_merges, + sorts_using_scans, + sort_using_range, + rows_sorted, + avg_rows_sorted, + first_seen, + last_seen, + digest +) AS +SELECT sys.format_statement(DIGEST_TEXT) AS query, + SCHEMA_NAME db, + COUNT_STAR AS exec_count, + sys.format_time(SUM_TIMER_WAIT) AS total_latency, + SUM_SORT_MERGE_PASSES AS sort_merge_passes, + ROUND(IFNULL(SUM_SORT_MERGE_PASSES / NULLIF(COUNT_STAR, 0), 0)) AS avg_sort_merges, + SUM_SORT_SCAN AS sorts_using_scans, + SUM_SORT_RANGE AS sort_using_range, + SUM_SORT_ROWS AS rows_sorted, + ROUND(IFNULL(SUM_SORT_ROWS / NULLIF(COUNT_STAR, 0), 0)) AS avg_rows_sorted, + FIRST_SEEN as first_seen, + LAST_SEEN as last_seen, + DIGEST AS digest + FROM performance_schema.events_statements_summary_by_digest + WHERE SUM_SORT_ROWS > 0 + ORDER BY SUM_TIMER_WAIT DESC; diff --git a/scripts/sys_schema/views/p_s/statements_with_temp_tables.sql b/scripts/sys_schema/views/p_s/statements_with_temp_tables.sql new file mode 100644 index 00000000..3f9dfbc6 --- /dev/null +++ b/scripts/sys_schema/views/p_s/statements_with_temp_tables.sql @@ -0,0 +1,68 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: statements_with_temp_tables +-- +-- Lists all normalized statements that use temporary tables +-- ordered by number of on disk temporary tables descending first, +-- then by the number of memory tables. +-- +-- mysql> select * from statements_with_temp_tables limit 1\G +-- *************************** 1. row *************************** +-- query: SELECT * FROM `schema_object_o ... MA` , `information_schema` ... +-- db: sys +-- exec_count: 2 +-- total_latency: 16.75 s +-- memory_tmp_tables: 378 +-- disk_tmp_tables: 66 +-- avg_tmp_tables_per_query: 189 +-- tmp_tables_to_disk_pct: 17 +-- first_seen: 2014-03-07 13:13:41 +-- last_seen: 2014-03-07 13:13:48 +-- digest: 54f9bd520f0bbf15db0c2ed93386bec9 +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW statements_with_temp_tables ( + query, + db, + exec_count, + total_latency, + memory_tmp_tables, + disk_tmp_tables, + avg_tmp_tables_per_query, + tmp_tables_to_disk_pct, + first_seen, + last_seen, + digest +) AS +SELECT sys.format_statement(DIGEST_TEXT) AS query, + SCHEMA_NAME as db, + COUNT_STAR AS exec_count, + sys.format_time(SUM_TIMER_WAIT) as total_latency, + SUM_CREATED_TMP_TABLES AS memory_tmp_tables, + SUM_CREATED_TMP_DISK_TABLES AS disk_tmp_tables, + ROUND(IFNULL(SUM_CREATED_TMP_TABLES / NULLIF(COUNT_STAR, 0), 0)) AS avg_tmp_tables_per_query, + ROUND(IFNULL(SUM_CREATED_TMP_DISK_TABLES / NULLIF(SUM_CREATED_TMP_TABLES, 0), 0) * 100) AS tmp_tables_to_disk_pct, + FIRST_SEEN as first_seen, + LAST_SEEN as last_seen, + DIGEST AS digest + FROM performance_schema.events_statements_summary_by_digest + WHERE SUM_CREATED_TMP_TABLES > 0 +ORDER BY SUM_CREATED_TMP_DISK_TABLES DESC, SUM_CREATED_TMP_TABLES DESC; diff --git a/scripts/sys_schema/views/p_s/user_summary.sql b/scripts/sys_schema/views/p_s/user_summary.sql new file mode 100644 index 00000000..85f08878 --- /dev/null +++ b/scripts/sys_schema/views/p_s/user_summary.sql @@ -0,0 +1,60 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: user_summary +-- +-- Summarizes statement activity, file IO and connections by user. +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from user_summary; +-- +------+------------+-------------------+-----------------------+-------------+----------+-----------------+---------------------+-------------------+--------------+ +-- | user | statements | statement_latency | statement_avg_latency | table_scans | file_ios | file_io_latency | current_connections | total_connections | unique_hosts | +-- +------+------------+-------------------+-----------------------+-------------+----------+-----------------+---------------------+-------------------+--------------+ +-- | root | 2924 | 00:03:59.53 | 81.92 ms | 82 | 54702 | 55.61 s | 1 | 1 | 1 | +-- +------+------------+-------------------+-----------------------+-------------+----------+-----------------+---------------------+-------------------+--------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW user_summary ( + user, + statements, + statement_latency, + statement_avg_latency, + table_scans, + file_ios, + file_io_latency, + current_connections, + total_connections, + unique_hosts +) AS +SELECT IF(accounts.user IS NULL, 'background', accounts.user) AS user, + SUM(stmt.total) AS statements, + sys.format_time(SUM(stmt.total_latency)) AS statement_latency, + sys.format_time(IFNULL(SUM(stmt.total_latency) / NULLIF(SUM(stmt.total), 0), 0)) AS statement_avg_latency, + SUM(stmt.full_scans) AS table_scans, + SUM(io.ios) AS file_ios, + sys.format_time(SUM(io.io_latency)) AS file_io_latency, + SUM(accounts.current_connections) AS current_connections, + SUM(accounts.total_connections) AS total_connections, + COUNT(DISTINCT host) AS unique_hosts + FROM performance_schema.accounts + LEFT JOIN sys.x$user_summary_by_statement_latency AS stmt ON IF(accounts.user IS NULL, 'background', accounts.user) = stmt.user + LEFT JOIN sys.x$user_summary_by_file_io AS io ON IF(accounts.user IS NULL, 'background', accounts.user) = io.user + GROUP BY IF(accounts.user IS NULL, 'background', accounts.user); diff --git a/scripts/sys_schema/views/p_s/user_summary_57.sql b/scripts/sys_schema/views/p_s/user_summary_57.sql new file mode 100644 index 00000000..a3147a17 --- /dev/null +++ b/scripts/sys_schema/views/p_s/user_summary_57.sql @@ -0,0 +1,67 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: user_summary +-- +-- Summarizes statement activity and connections by user +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from user_summary; +-- +------+------------+---------------+-------------+---------------------+-------------------+--------------+----------------+------------------------+ +-- | user | statements | total_latency | avg_latency | current_connections | total_connections | unique_hosts | current_memory | total_memory_allocated | +-- +------+------------+---------------+-------------+---------------------+-------------------+--------------+----------------+------------------------+ +-- | root | 5663 | 00:01:47.14 | 18.92 ms | 1 | 1 | 1 | 1.41 MiB | 543.55 MiB | +-- | mark | 225 | 14.49 s | 64.40 ms | 1 | 1 | 1 | 707.60 KiB | 81.02 MiB | +-- +------+------------+---------------+-------------+---------------------+-------------------+--------------+----------------+------------------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW user_summary ( + user, + statements, + statement_latency, + statement_avg_latency, + table_scans, + file_ios, + file_io_latency, + current_connections, + total_connections, + unique_hosts, + current_memory, + total_memory_allocated +) AS +SELECT IF(accounts.user IS NULL, 'background', accounts.user) AS user, + SUM(stmt.total) AS statements, + sys.format_time(SUM(stmt.total_latency)) AS statement_latency, + sys.format_time(IFNULL(SUM(stmt.total_latency) / NULLIF(SUM(stmt.total), 0), 0)) AS statement_avg_latency, + SUM(stmt.full_scans) AS table_scans, + SUM(io.ios) AS file_ios, + sys.format_time(SUM(io.io_latency)) AS file_io_latency, + SUM(accounts.current_connections) AS current_connections, + SUM(accounts.total_connections) AS total_connections, + COUNT(DISTINCT host) AS unique_hosts, + sys.format_bytes(SUM(mem.current_allocated)) AS current_memory, + sys.format_bytes(SUM(mem.total_allocated)) AS total_memory_allocated + FROM performance_schema.accounts + LEFT JOIN sys.x$user_summary_by_statement_latency AS stmt ON IF(accounts.user IS NULL, 'background', accounts.user) = stmt.user + LEFT JOIN sys.x$user_summary_by_file_io AS io ON IF(accounts.user IS NULL, 'background', accounts.user) = io.user + LEFT JOIN sys.x$memory_by_user_by_current_bytes mem ON IF(accounts.user IS NULL, 'background', accounts.user) = mem.user + GROUP BY IF(accounts.user IS NULL, 'background', accounts.user) + ORDER BY SUM(stmt.total_latency) DESC; diff --git a/scripts/sys_schema/views/p_s/user_summary_by_file_io.sql b/scripts/sys_schema/views/p_s/user_summary_by_file_io.sql new file mode 100644 index 00000000..85862d50 --- /dev/null +++ b/scripts/sys_schema/views/p_s/user_summary_by_file_io.sql @@ -0,0 +1,47 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: user_summary_by_file_io +-- +-- Summarizes file IO totals per user. +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from user_summary_by_file_io; +-- +------------+-------+------------+ +-- | user | ios | io_latency | +-- +------------+-------+------------+ +-- | root | 26457 | 21.58 s | +-- | background | 1189 | 394.21 ms | +-- +------------+-------+------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW user_summary_by_file_io ( + user, + ios, + io_latency +) AS +SELECT IF(user IS NULL, 'background', user) AS user, + SUM(count_star) AS ios, + sys.format_time(SUM(sum_timer_wait)) AS io_latency + FROM performance_schema.events_waits_summary_by_user_by_event_name + WHERE event_name LIKE 'wait/io/file/%' + GROUP BY IF(user IS NULL, 'background', user) + ORDER BY SUM(sum_timer_wait) DESC; diff --git a/scripts/sys_schema/views/p_s/user_summary_by_file_io_type.sql b/scripts/sys_schema/views/p_s/user_summary_by_file_io_type.sql new file mode 100644 index 00000000..37b4b14b --- /dev/null +++ b/scripts/sys_schema/views/p_s/user_summary_by_file_io_type.sql @@ -0,0 +1,66 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: user_summary_by_file_io_type +-- +-- Summarizes file IO by event type per user. +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from user_summary_by_file_io_type; +-- +------------+--------------------------------------+-------+-----------+-------------+ +-- | user | event_name | total | latency | max_latency | +-- +------------+--------------------------------------+-------+-----------+-------------+ +-- | background | wait/io/file/sql/FRM | 871 | 168.15 ms | 18.48 ms | +-- | background | wait/io/file/innodb/innodb_data_file | 173 | 129.56 ms | 34.09 ms | +-- | background | wait/io/file/innodb/innodb_log_file | 20 | 77.53 ms | 60.66 ms | +-- | background | wait/io/file/myisam/dfile | 40 | 6.54 ms | 4.58 ms | +-- | background | wait/io/file/mysys/charset | 3 | 4.79 ms | 4.71 ms | +-- | background | wait/io/file/myisam/kfile | 67 | 4.38 ms | 300.04 us | +-- | background | wait/io/file/sql/ERRMSG | 5 | 2.72 ms | 1.69 ms | +-- | background | wait/io/file/sql/pid | 3 | 266.30 us | 185.47 us | +-- | background | wait/io/file/sql/casetest | 5 | 246.81 us | 150.19 us | +-- | background | wait/io/file/sql/global_ddl_log | 2 | 21.24 us | 18.59 us | +-- | root | wait/io/file/sql/file_parser | 1422 | 4.80 s | 135.14 ms | +-- | root | wait/io/file/sql/FRM | 865 | 85.82 ms | 9.81 ms | +-- | root | wait/io/file/myisam/kfile | 1073 | 37.14 ms | 15.79 ms | +-- | root | wait/io/file/myisam/dfile | 2991 | 25.53 ms | 5.25 ms | +-- | root | wait/io/file/sql/dbopt | 20 | 1.07 ms | 153.07 us | +-- | root | wait/io/file/sql/misc | 4 | 59.71 us | 33.75 us | +-- | root | wait/io/file/archive/data | 1 | 13.91 us | 13.91 us | +-- +------------+--------------------------------------+-------+-----------+-------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW user_summary_by_file_io_type ( + user, + event_name, + total, + latency, + max_latency +) AS +SELECT IF(user IS NULL, 'background', user) AS user, + event_name, + count_star AS total, + sys.format_time(sum_timer_wait) AS latency, + sys.format_time(max_timer_wait) AS max_latency + FROM performance_schema.events_waits_summary_by_user_by_event_name + WHERE event_name LIKE 'wait/io/file%' + AND count_star > 0 + ORDER BY user, sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/user_summary_by_stages.sql b/scripts/sys_schema/views/p_s/user_summary_by_stages.sql new file mode 100644 index 00000000..ab34a3ee --- /dev/null +++ b/scripts/sys_schema/views/p_s/user_summary_by_stages.sql @@ -0,0 +1,64 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: user_summary_by_stages +-- +-- Summarizes stages by user, ordered by user and total latency per stage. +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from user_summary_by_stages; +-- +------+--------------------------------+-------+---------------+-------------+ +-- | user | event_name | total | total_latency | avg_latency | +-- +------+--------------------------------+-------+---------------+-------------+ +-- | root | stage/sql/Opening tables | 889 | 1.97 ms | 2.22 us | +-- | root | stage/sql/Creating sort index | 4 | 1.79 ms | 446.30 us | +-- | root | stage/sql/init | 10 | 312.27 us | 31.23 us | +-- | root | stage/sql/checking permissions | 10 | 300.62 us | 30.06 us | +-- | root | stage/sql/freeing items | 5 | 85.89 us | 17.18 us | +-- | root | stage/sql/statistics | 5 | 79.15 us | 15.83 us | +-- | root | stage/sql/preparing | 5 | 69.12 us | 13.82 us | +-- | root | stage/sql/optimizing | 5 | 53.11 us | 10.62 us | +-- | root | stage/sql/Sending data | 5 | 44.66 us | 8.93 us | +-- | root | stage/sql/closing tables | 5 | 37.54 us | 7.51 us | +-- | root | stage/sql/System lock | 5 | 34.28 us | 6.86 us | +-- | root | stage/sql/query end | 5 | 24.37 us | 4.87 us | +-- | root | stage/sql/end | 5 | 8.60 us | 1.72 us | +-- | root | stage/sql/Sorting result | 5 | 8.33 us | 1.67 us | +-- | root | stage/sql/executing | 5 | 5.37 us | 1.07 us | +-- | root | stage/sql/cleaning up | 5 | 4.60 us | 919.00 ns | +-- +------+--------------------------------+-------+---------------+-------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW user_summary_by_stages ( + user, + event_name, + total, + total_latency, + avg_latency +) AS +SELECT IF(user IS NULL, 'background', user) AS user, + event_name, + count_star AS total, + sys.format_time(sum_timer_wait) AS total_latency, + sys.format_time(avg_timer_wait) AS avg_latency + FROM performance_schema.events_stages_summary_by_user_by_event_name + WHERE sum_timer_wait != 0 + ORDER BY user, sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/user_summary_by_statement_latency.sql b/scripts/sys_schema/views/p_s/user_summary_by_statement_latency.sql new file mode 100644 index 00000000..2c6e0b50 --- /dev/null +++ b/scripts/sys_schema/views/p_s/user_summary_by_statement_latency.sql @@ -0,0 +1,57 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: user_summary_by_statement_latency +-- +-- Summarizes overall statement statistics by user. +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from user_summary_by_statement_latency; +-- +------+-------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +-- | user | total | total_latency | max_latency | lock_latency | rows_sent | rows_examined | rows_affected | full_scans | +-- +------+-------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +-- | root | 3381 | 00:02:09.13 | 1.48 s | 1.07 s | 1151 | 93947 | 150 | 91 | +-- +------+-------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW user_summary_by_statement_latency ( + user, + total, + total_latency, + max_latency, + lock_latency, + rows_sent, + rows_examined, + rows_affected, + full_scans +) AS +SELECT IF(user IS NULL, 'background', user) AS user, + SUM(count_star) AS total, + sys.format_time(SUM(sum_timer_wait)) AS total_latency, + sys.format_time(SUM(max_timer_wait)) AS max_latency, + sys.format_time(SUM(sum_lock_time)) AS lock_latency, + SUM(sum_rows_sent) AS rows_sent, + SUM(sum_rows_examined) AS rows_examined, + SUM(sum_rows_affected) AS rows_affected, + SUM(sum_no_index_used) + SUM(sum_no_good_index_used) AS full_scans + FROM performance_schema.events_statements_summary_by_user_by_event_name + GROUP BY IF(user IS NULL, 'background', user) + ORDER BY SUM(sum_timer_wait) DESC; diff --git a/scripts/sys_schema/views/p_s/user_summary_by_statement_type.sql b/scripts/sys_schema/views/p_s/user_summary_by_statement_type.sql new file mode 100644 index 00000000..f9ddc2bb --- /dev/null +++ b/scripts/sys_schema/views/p_s/user_summary_by_statement_type.sql @@ -0,0 +1,64 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: user_summary_by_statement_type +-- +-- Summarizes the types of statements executed by each user. +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from user_summary_by_statement_type; +-- +------+----------------------+--------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +-- | user | statement | total | total_latency | max_latency | lock_latency | rows_sent | rows_examined | rows_affected | full_scans | +-- +------+----------------------+--------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +-- | root | create_view | 2063 | 00:05:04.20 | 463.58 ms | 1.42 s | 0 | 0 | 0 | 0 | +-- | root | select | 174 | 40.87 s | 28.83 s | 858.13 ms | 5212 | 157022 | 0 | 82 | +-- | root | stmt | 6645 | 15.31 s | 491.78 ms | 0 ps | 0 | 0 | 7951 | 0 | +-- | root | call_procedure | 17 | 4.78 s | 1.02 s | 37.94 ms | 0 | 0 | 19 | 0 | +-- | root | create_table | 19 | 3.04 s | 431.71 ms | 0 ps | 0 | 0 | 0 | 0 | +-- ... +-- +------+----------------------+--------+---------------+-------------+--------------+-----------+---------------+---------------+------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW user_summary_by_statement_type ( + user, + statement, + total, + total_latency, + max_latency, + lock_latency, + rows_sent, + rows_examined, + rows_affected, + full_scans +) AS +SELECT IF(user IS NULL, 'background', user) AS user, + SUBSTRING_INDEX(event_name, '/', -1) AS statement, + count_star AS total, + sys.format_time(sum_timer_wait) AS total_latency, + sys.format_time(max_timer_wait) AS max_latency, + sys.format_time(sum_lock_time) AS lock_latency, + sum_rows_sent AS rows_sent, + sum_rows_examined AS rows_examined, + sum_rows_affected AS rows_affected, + sum_no_index_used + sum_no_good_index_used AS full_scans + FROM performance_schema.events_statements_summary_by_user_by_event_name + WHERE sum_timer_wait != 0 + ORDER BY user, sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/wait_classes_global_by_avg_latency.sql b/scripts/sys_schema/views/p_s/wait_classes_global_by_avg_latency.sql new file mode 100644 index 00000000..faee5823 --- /dev/null +++ b/scripts/sys_schema/views/p_s/wait_classes_global_by_avg_latency.sql @@ -0,0 +1,56 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: wait_classes_global_by_avg_latency +-- +-- Lists the top wait classes by average latency, ignoring idle (this may be very large). +-- +-- mysql> select * from wait_classes_global_by_avg_latency where event_class != 'idle'; +-- +-------------------+--------+---------------+-------------+-------------+-------------+ +-- | event_class | total | total_latency | min_latency | avg_latency | max_latency | +-- +-------------------+--------+---------------+-------------+-------------+-------------+ +-- | wait/io/file | 543123 | 44.60 s | 19.44 ns | 82.11 us | 4.21 s | +-- | wait/io/table | 22002 | 766.60 ms | 148.72 ns | 34.84 us | 44.97 ms | +-- | wait/io/socket | 79613 | 967.17 ms | 0 ps | 12.15 us | 27.10 ms | +-- | wait/lock/table | 35409 | 18.68 ms | 65.45 ns | 527.51 ns | 969.88 us | +-- | wait/synch/rwlock | 37935 | 4.61 ms | 21.38 ns | 121.61 ns | 34.65 us | +-- | wait/synch/mutex | 390622 | 18.60 ms | 19.44 ns | 47.61 ns | 10.32 us | +-- +-------------------+--------+---------------+-------------+-------------+-------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW wait_classes_global_by_avg_latency ( + event_class, + total, + total_latency, + min_latency, + avg_latency, + max_latency +) AS +SELECT SUBSTRING_INDEX(event_name,'/', 3) AS event_class, + SUM(COUNT_STAR) AS total, + sys.format_time(CAST(SUM(sum_timer_wait) AS UNSIGNED)) AS total_latency, + sys.format_time(MIN(min_timer_wait)) AS min_latency, + sys.format_time(IFNULL(SUM(sum_timer_wait) / NULLIF(SUM(COUNT_STAR), 0), 0)) AS avg_latency, + sys.format_time(CAST(MAX(max_timer_wait) AS UNSIGNED)) AS max_latency + FROM performance_schema.events_waits_summary_global_by_event_name + WHERE sum_timer_wait > 0 + AND event_name != 'idle' + GROUP BY event_class + ORDER BY IFNULL(SUM(sum_timer_wait) / NULLIF(SUM(COUNT_STAR), 0), 0) DESC; diff --git a/scripts/sys_schema/views/p_s/wait_classes_global_by_latency.sql b/scripts/sys_schema/views/p_s/wait_classes_global_by_latency.sql new file mode 100644 index 00000000..5675c3f5 --- /dev/null +++ b/scripts/sys_schema/views/p_s/wait_classes_global_by_latency.sql @@ -0,0 +1,56 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: wait_classes_global_by_latency +-- +-- Lists the top wait classes by total latency, ignoring idle (this may be very large). +-- +-- mysql> select * from wait_classes_global_by_latency; +-- +-------------------+--------+---------------+-------------+-------------+-------------+ +-- | event_class | total | total_latency | min_latency | avg_latency | max_latency | +-- +-------------------+--------+---------------+-------------+-------------+-------------+ +-- | wait/io/file | 550470 | 46.01 s | 19.44 ns | 83.58 us | 4.21 s | +-- | wait/io/socket | 228833 | 2.71 s | 0 ps | 11.86 us | 29.93 ms | +-- | wait/io/table | 64063 | 1.89 s | 99.79 ns | 29.43 us | 68.07 ms | +-- | wait/lock/table | 76029 | 47.19 ms | 65.45 ns | 620.74 ns | 969.88 us | +-- | wait/synch/mutex | 635925 | 34.93 ms | 19.44 ns | 54.93 ns | 107.70 us | +-- | wait/synch/rwlock | 61287 | 7.62 ms | 21.38 ns | 124.37 ns | 34.65 us | +-- +-------------------+--------+---------------+-------------+-------------+-------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW wait_classes_global_by_latency ( + event_class, + total, + total_latency, + min_latency, + avg_latency, + max_latency +) AS +SELECT SUBSTRING_INDEX(event_name,'/', 3) AS event_class, + SUM(COUNT_STAR) AS total, + sys.format_time(SUM(sum_timer_wait)) AS total_latency, + sys.format_time(MIN(min_timer_wait)) min_latency, + sys.format_time(IFNULL(SUM(sum_timer_wait) / NULLIF(SUM(COUNT_STAR), 0), 0)) AS avg_latency, + sys.format_time(MAX(max_timer_wait)) AS max_latency + FROM performance_schema.events_waits_summary_global_by_event_name + WHERE sum_timer_wait > 0 + AND event_name != 'idle' + GROUP BY SUBSTRING_INDEX(event_name,'/', 3) + ORDER BY SUM(sum_timer_wait) DESC; diff --git a/scripts/sys_schema/views/p_s/waits_by_host_by_latency.sql b/scripts/sys_schema/views/p_s/waits_by_host_by_latency.sql new file mode 100644 index 00000000..5587fee2 --- /dev/null +++ b/scripts/sys_schema/views/p_s/waits_by_host_by_latency.sql @@ -0,0 +1,54 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: waits_by_host_by_latency +-- +-- Lists the top wait events per host by their total latency, ignoring idle (this may be very large). +-- +-- mysql> select * from sys.waits_by_host_by_latency where host != 'background' limit 5; +-- +-----------+------------------------------+-------+---------------+-------------+-------------+ +-- | host | event | total | total_latency | avg_latency | max_latency | +-- +-----------+------------------------------+-------+---------------+-------------+-------------+ +-- | localhost | wait/io/file/sql/file_parser | 1386 | 14.50 s | 10.46 ms | 357.36 ms | +-- | localhost | wait/io/file/sql/FRM | 162 | 356.08 ms | 2.20 ms | 75.33 ms | +-- | localhost | wait/io/file/myisam/kfile | 410 | 322.29 ms | 786.08 us | 65.98 ms | +-- | localhost | wait/io/file/myisam/dfile | 1327 | 307.44 ms | 231.68 us | 37.16 ms | +-- | localhost | wait/io/file/sql/dbopt | 89 | 180.34 ms | 2.03 ms | 63.41 ms | +-- +-----------+------------------------------+-------+---------------+-------------+-------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW waits_by_host_by_latency ( + host, + event, + total, + total_latency, + avg_latency, + max_latency +) AS +SELECT IF(host IS NULL, 'background', host) AS host, + event_name AS event, + count_star AS total, + sys.format_time(sum_timer_wait) AS total_latency, + sys.format_time(avg_timer_wait) AS avg_latency, + sys.format_time(max_timer_wait) AS max_latency + FROM performance_schema.events_waits_summary_by_host_by_event_name + WHERE event_name != 'idle' + AND sum_timer_wait > 0 + ORDER BY host, sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/waits_by_user_by_latency.sql b/scripts/sys_schema/views/p_s/waits_by_user_by_latency.sql new file mode 100644 index 00000000..5a6a618e --- /dev/null +++ b/scripts/sys_schema/views/p_s/waits_by_user_by_latency.sql @@ -0,0 +1,65 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: waits_by_user_by_latency +-- +-- Lists the top wait events per user by their total latency, ignoring idle (this may be very large). +-- +-- mysql> select * from waits_by_user_by_latency; +-- +------+-----------------------------------------------------+--------+---------------+-------------+-------------+ +-- | user | event | total | total_latency | avg_latency | max_latency | +-- +------+-----------------------------------------------------+--------+---------------+-------------+-------------+ +-- | root | wait/io/file/sql/file_parser | 13743 | 00:01:00.46 | 4.40 ms | 231.88 ms | +-- | root | wait/io/file/innodb/innodb_data_file | 4699 | 3.02 s | 643.38 us | 46.93 ms | +-- | root | wait/io/file/sql/FRM | 11462 | 2.60 s | 226.83 us | 61.72 ms | +-- | root | wait/io/file/myisam/dfile | 26776 | 746.70 ms | 27.89 us | 308.79 ms | +-- | root | wait/io/file/myisam/kfile | 7126 | 462.66 ms | 64.93 us | 88.76 ms | +-- | root | wait/io/file/sql/dbopt | 179 | 137.58 ms | 768.59 us | 15.46 ms | +-- | root | wait/io/file/csv/metadata | 8 | 86.60 ms | 10.82 ms | 50.32 ms | +-- | root | wait/synch/mutex/mysys/IO_CACHE::append_buffer_lock | 798080 | 66.46 ms | 82.94 ns | 161.03 us | +-- | root | wait/io/file/sql/binlog | 19 | 49.11 ms | 2.58 ms | 9.40 ms | +-- | root | wait/io/file/sql/misc | 26 | 22.38 ms | 860.80 us | 15.30 ms | +-- | root | wait/io/file/csv/data | 4 | 297.46 us | 74.37 us | 111.93 us | +-- | root | wait/synch/rwlock/sql/MDL_lock::rwlock | 944 | 287.86 us | 304.62 ns | 874.64 ns | +-- | root | wait/io/file/archive/data | 4 | 82.71 us | 20.68 us | 40.74 us | +-- | root | wait/synch/mutex/myisam/MYISAM_SHARE::intern_lock | 60 | 12.21 us | 203.20 ns | 512.72 ns | +-- | root | wait/synch/mutex/innodb/trx_mutex | 81 | 5.93 us | 73.14 ns | 252.59 ns | +-- +------+-----------------------------------------------------+--------+---------------+-------------+-------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW waits_by_user_by_latency ( + user, + event, + total, + total_latency, + avg_latency, + max_latency +) AS +SELECT IF(user IS NULL, 'background', user) AS user, + event_name AS event, + count_star AS total, + sys.format_time(sum_timer_wait) AS total_latency, + sys.format_time(avg_timer_wait) AS avg_latency, + sys.format_time(max_timer_wait) AS max_latency + FROM performance_schema.events_waits_summary_by_user_by_event_name + WHERE event_name != 'idle' + AND user IS NOT NULL + AND sum_timer_wait > 0 + ORDER BY user, sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/waits_global_by_latency.sql b/scripts/sys_schema/views/p_s/waits_global_by_latency.sql new file mode 100644 index 00000000..a41be3b1 --- /dev/null +++ b/scripts/sys_schema/views/p_s/waits_global_by_latency.sql @@ -0,0 +1,52 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: waits_global_by_latency +-- +-- Lists the top wait events by their total latency, ignoring idle (this may be very large). +-- +-- mysql> select * from waits_global_by_latency limit 5; +-- +--------------------------------------+------------+---------------+-------------+-------------+ +-- | event | total | total_latency | avg_latency | max_latency | +-- +--------------------------------------+------------+---------------+-------------+-------------+ +-- | wait/io/file/myisam/dfile | 3623719744 | 00:47:49.09 | 791.70 ns | 312.96 ms | +-- | wait/io/table/sql/handler | 69114944 | 00:44:30.74 | 38.64 us | 879.49 ms | +-- | wait/io/file/innodb/innodb_log_file | 28100261 | 00:37:42.12 | 80.50 us | 476.00 ms | +-- | wait/io/socket/sql/client_connection | 200704863 | 00:18:37.81 | 5.57 us | 1.27 s | +-- | wait/io/file/innodb/innodb_data_file | 2829403 | 00:08:12.89 | 174.20 us | 455.22 ms | +-- +--------------------------------------+------------+---------------+-------------+-------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW waits_global_by_latency ( + events, + total, + total_latency, + avg_latency, + max_latency +) AS +SELECT event_name AS event, + count_star AS total, + sys.format_time(sum_timer_wait) AS total_latency, + sys.format_time(avg_timer_wait) AS avg_latency, + sys.format_time(max_timer_wait) AS max_latency + FROM performance_schema.events_waits_summary_global_by_event_name + WHERE event_name != 'idle' + AND sum_timer_wait > 0 + ORDER BY sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/x_host_summary.sql b/scripts/sys_schema/views/p_s/x_host_summary.sql new file mode 100644 index 00000000..87d415b0 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_host_summary.sql @@ -0,0 +1,60 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$host_summary +-- +-- Summarizes statement activity, file IO and connections by host. +-- +-- When the host found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from x$host_summary; +-- +------+------------+-------------------+-----------------------+-------------+----------+-----------------+---------------------+-------------------+--------------+ +-- | host | statements | statement_latency | statement_avg_latency | table_scans | file_ios | file_io_latency | current_connections | total_connections | unique_users | +-- +------+------------+-------------------+-----------------------+-------------+----------+-----------------+---------------------+-------------------+--------------+ +-- | hal | 2925 | 239577283481000 | 81906763583.2479 | 83 | 54709 | 55605611965150 | 1 | 1 | 1 | +-- +------+------------+-------------------+-----------------------+-------------+----------+-----------------+---------------------+-------------------+--------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$host_summary ( + host, + statements, + statement_latency, + statement_avg_latency, + table_scans, + file_ios, + file_io_latency, + current_connections, + total_connections, + unique_users +) AS +SELECT IF(accounts.host IS NULL, 'background', accounts.host) AS host, + SUM(stmt.total) AS statements, + SUM(stmt.total_latency) AS statement_latency, + SUM(stmt.total_latency) / SUM(stmt.total) AS statement_avg_latency, + SUM(stmt.full_scans) AS table_scans, + SUM(io.ios) AS file_ios, + SUM(io.io_latency) AS file_io_latency, + SUM(accounts.current_connections) AS current_connections, + SUM(accounts.total_connections) AS total_connections, + COUNT(DISTINCT accounts.user) AS unique_users + FROM performance_schema.accounts + LEFT JOIN sys.x$host_summary_by_statement_latency AS stmt ON accounts.host = stmt.host + LEFT JOIN sys.x$host_summary_by_file_io AS io ON accounts.host = io.host + GROUP BY IF(accounts.host IS NULL, 'background', accounts.host); diff --git a/scripts/sys_schema/views/p_s/x_host_summary_57.sql b/scripts/sys_schema/views/p_s/x_host_summary_57.sql new file mode 100644 index 00000000..5a741ade --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_host_summary_57.sql @@ -0,0 +1,66 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$host_summary +-- +-- Summarizes statement activity and connections by host +-- +-- When the host found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from x$host_summary; +-- +------+------------+-----------------+------------------+---------------------+-------------------+--------------+----------------+------------------------+ +-- | host | statements | total_latency | avg_latency | current_connections | total_connections | unique_users | current_memory | total_memory_allocated | +-- +------+------------+-----------------+------------------+---------------------+-------------------+--------------+----------------+------------------------+ +-- | hal1 | 5685 | 107175100271000 | 18852260381.8821 | 1 | 1 | 1 | 1459022 | 572855680 | +-- | hal2 | 225 | 14489223428000 | 64396548568.8889 | 1 | 1 | 1 | 724578 | 84958286 | +-- +------+------------+-----------------+------------------+---------------------+-------------------+--------------+----------------+------------------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$host_summary ( + host, + statements, + statement_latency, + statement_avg_latency, + table_scans, + file_ios, + file_io_latency, + current_connections, + total_connections, + unique_users, + current_memory, + total_memory_allocated +) AS +SELECT IF(accounts.host IS NULL, 'background', accounts.host) AS host, + SUM(stmt.total) AS statements, + SUM(stmt.total_latency) AS statement_latency, + SUM(stmt.total_latency) / SUM(stmt.total) AS statement_avg_latency, + SUM(stmt.full_scans) AS table_scans, + SUM(io.ios) AS file_ios, + SUM(io.io_latency) AS file_io_latency, + SUM(accounts.current_connections) AS current_connections, + SUM(accounts.total_connections) AS total_connections, + COUNT(DISTINCT accounts.user) AS unique_users, + SUM(mem.current_allocated) AS current_memory, + SUM(mem.total_allocated) AS total_memory_allocated + FROM performance_schema.accounts + JOIN sys.x$host_summary_by_statement_latency AS stmt ON accounts.host = stmt.host + JOIN sys.x$host_summary_by_file_io AS io ON accounts.host = io.host + JOIN sys.x$memory_by_host_by_current_bytes mem ON accounts.host = mem.host + GROUP BY IF(accounts.host IS NULL, 'background', accounts.host); diff --git a/scripts/sys_schema/views/p_s/x_host_summary_by_file_io.sql b/scripts/sys_schema/views/p_s/x_host_summary_by_file_io.sql new file mode 100644 index 00000000..6e1d727a --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_host_summary_by_file_io.sql @@ -0,0 +1,47 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$host_summary_by_file_io +-- +-- Summarizes file IO totals per host. +-- +-- When the host found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from x$host_summary_by_file_io; +-- +------------+-------+----------------+ +-- | host | ios | io_latency | +-- +------------+-------+----------------+ +-- | hal1 | 26457 | 21579585586390 | +-- | hal2 | 1189 | 394212617370 | +-- +------------+-------+----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$host_summary_by_file_io ( + host, + ios, + io_latency +) AS +SELECT IF(host IS NULL, 'background', host) AS host, + SUM(count_star) AS ios, + SUM(sum_timer_wait) AS io_latency + FROM performance_schema.events_waits_summary_by_host_by_event_name + WHERE event_name LIKE 'wait/io/file/%' + GROUP BY IF(host IS NULL, 'background', host) + ORDER BY SUM(sum_timer_wait) DESC; diff --git a/scripts/sys_schema/views/p_s/x_host_summary_by_file_io_type.sql b/scripts/sys_schema/views/p_s/x_host_summary_by_file_io_type.sql new file mode 100644 index 00000000..e272732d --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_host_summary_by_file_io_type.sql @@ -0,0 +1,66 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$host_summary_by_file_io_type +-- +-- Summarizes file IO by event type per host. +-- +-- When the host found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from x$host_summary_by_file_io_type; +-- +------------+--------------------------------------+-------+---------------+--------------+ +-- | host | event_name | total | total_latency | max_latency | +-- +------------+--------------------------------------+-------+---------------+--------------+ +-- | hal1 | wait/io/file/sql/FRM | 871 | 168148450470 | 18482624810 | +-- | hal1 | wait/io/file/innodb/innodb_data_file | 173 | 129564287450 | 34087423890 | +-- | hal1 | wait/io/file/innodb/innodb_log_file | 20 | 77525706960 | 60657475320 | +-- | hal1 | wait/io/file/myisam/dfile | 40 | 6544493800 | 4580546230 | +-- | hal1 | wait/io/file/mysys/charset | 3 | 4793558770 | 4713476430 | +-- | hal1 | wait/io/file/myisam/kfile | 67 | 4384332810 | 300035450 | +-- | hal1 | wait/io/file/sql/ERRMSG | 5 | 2717434850 | 1687316280 | +-- | hal1 | wait/io/file/sql/pid | 3 | 266301490 | 185468920 | +-- | hal1 | wait/io/file/sql/casetest | 5 | 246814360 | 150193030 | +-- | hal1 | wait/io/file/sql/global_ddl_log | 2 | 21236410 | 18593640 | +-- | hal2 | wait/io/file/sql/file_parser | 1422 | 4801104756760 | 135138518970 | +-- | hal2 | wait/io/file/sql/FRM | 865 | 85818594810 | 9812303410 | +-- | hal2 | wait/io/file/myisam/kfile | 1073 | 37143664870 | 15793838190 | +-- | hal2 | wait/io/file/myisam/dfile | 2991 | 25528215700 | 5252232050 | +-- | hal2 | wait/io/file/sql/dbopt | 20 | 1067339780 | 153073310 | +-- | hal2 | wait/io/file/sql/misc | 4 | 59713030 | 33752810 | +-- | hal2 | wait/io/file/archive/data | 1 | 13907530 | 13907530 | +-- +------------+--------------------------------------+-------+---------------+--------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$host_summary_by_file_io_type ( + host, + event_name, + total, + total_latency, + max_latency +) AS +SELECT IF(host IS NULL, 'background', host) AS host, + event_name, + count_star AS total, + sum_timer_wait AS total_latency, + max_timer_wait AS max_latency + FROM performance_schema.events_waits_summary_by_host_by_event_name + WHERE event_name LIKE 'wait/io/file%' + AND count_star > 0 + ORDER BY IF(host IS NULL, 'background', host), sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/x_host_summary_by_stages.sql b/scripts/sys_schema/views/p_s/x_host_summary_by_stages.sql new file mode 100644 index 00000000..801d338e --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_host_summary_by_stages.sql @@ -0,0 +1,64 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$host_summary_by_stages +-- +-- Summarizes stages by host, ordered by host and total latency per stage. +-- +-- When the host found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from x$host_summary_by_stages; +-- +------+--------------------------------+-------+---------------+-------------+ +-- | host | event_name | total | total_latency | avg_latency | +-- +------+--------------------------------+-------+---------------+-------------+ +-- | hal | stage/sql/Opening tables | 1114 | 71919037000 | 64559000 | +-- | hal | stage/sql/Creating sort index | 5 | 2245762000 | 449152000 | +-- | hal | stage/sql/init | 13 | 428798000 | 32984000 | +-- | hal | stage/sql/checking permissions | 13 | 363231000 | 27940000 | +-- | hal | stage/sql/freeing items | 7 | 137728000 | 19675000 | +-- | hal | stage/sql/statistics | 6 | 93955000 | 15659000 | +-- | hal | stage/sql/preparing | 6 | 82571000 | 13761000 | +-- | hal | stage/sql/optimizing | 6 | 63338000 | 10556000 | +-- | hal | stage/sql/Sending data | 6 | 53400000 | 8900000 | +-- | hal | stage/sql/closing tables | 7 | 46922000 | 6703000 | +-- | hal | stage/sql/System lock | 6 | 40175000 | 6695000 | +-- | hal | stage/sql/query end | 7 | 31723000 | 4531000 | +-- | hal | stage/sql/Sorting result | 6 | 9855000 | 1642000 | +-- | hal | stage/sql/end | 6 | 9556000 | 1592000 | +-- | hal | stage/sql/cleaning up | 7 | 7312000 | 1044000 | +-- | hal | stage/sql/executing | 6 | 6487000 | 1081000 | +-- +------+--------------------------------+-------+---------------+-------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$host_summary_by_stages ( + host, + event_name, + total, + total_latency, + avg_latency +) AS +SELECT IF(host IS NULL, 'background', host) AS host, + event_name, + count_star AS total, + sum_timer_wait AS total_latency, + avg_timer_wait AS avg_latency + FROM performance_schema.events_stages_summary_by_host_by_event_name + WHERE sum_timer_wait != 0 + ORDER BY IF(host IS NULL, 'background', host), sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/x_host_summary_by_statement_latency.sql b/scripts/sys_schema/views/p_s/x_host_summary_by_statement_latency.sql new file mode 100644 index 00000000..30a6e390 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_host_summary_by_statement_latency.sql @@ -0,0 +1,57 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$host_summary_by_statement_latency +-- +-- Summarizes overall statement statistics by host. +-- +-- When the host found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from x$host_summary_by_statement_latency; +-- +------+-------+-----------------+---------------+---------------+-----------+---------------+---------------+------------+ +-- | host | total | total_latency | max_latency | lock_latency | rows_sent | rows_examined | rows_affected | full_scans | +-- +------+-------+-----------------+---------------+---------------+-----------+---------------+---------------+------------+ +-- | hal | 3382 | 129134039432000 | 1483246743000 | 1069831000000 | 1152 | 94286 | 150 | 92 | +-- +------+-------+-----------------+---------------+---------------+-----------+---------------+---------------+------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$host_summary_by_statement_latency ( + host, + total, + total_latency, + max_latency, + lock_latency, + rows_sent, + rows_examined, + rows_affected, + full_scans +) AS +SELECT IF(host IS NULL, 'background', host) AS host, + SUM(count_star) AS total, + SUM(sum_timer_wait) AS total_latency, + MAX(max_timer_wait) AS max_latency, + SUM(sum_lock_time) AS lock_latency, + SUM(sum_rows_sent) AS rows_sent, + SUM(sum_rows_examined) AS rows_examined, + SUM(sum_rows_affected) AS rows_affected, + SUM(sum_no_index_used) + SUM(sum_no_good_index_used) AS full_scans + FROM performance_schema.events_statements_summary_by_host_by_event_name + GROUP BY IF(host IS NULL, 'background', host) + ORDER BY SUM(sum_timer_wait) DESC; diff --git a/scripts/sys_schema/views/p_s/x_host_summary_by_statement_type.sql b/scripts/sys_schema/views/p_s/x_host_summary_by_statement_type.sql new file mode 100644 index 00000000..72b75b9c --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_host_summary_by_statement_type.sql @@ -0,0 +1,64 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$host_summary_by_statement_type +-- +-- Summarizes the types of statements executed by each host. +-- +-- When the host found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from x$host_summary_by_statement_type; +-- +------+----------------------+--------+-----------------+----------------+----------------+-----------+---------------+---------------+------------+ +-- | host | statement | total | total_latency | max_latency | lock_latency | rows_sent | rows_examined | rows_affected | full_scans | +-- +------+----------------------+--------+-----------------+----------------+----------------+-----------+---------------+---------------+------------+ +-- | hal | create_view | 2110 | 312717366332000 | 463578029000 | 1432355000000 | 0 | 0 | 0 | 0 | +-- | hal | select | 177 | 41115690428000 | 28827579292000 | 858709000000 | 5254 | 157437 | 0 | 83 | +-- | hal | stmt | 6645 | 15305389969000 | 491780297000 | 0 | 0 | 0 | 7951 | 0 | +-- | hal | call_procedure | 17 | 4783806053000 | 1016083397000 | 37936000000 | 0 | 0 | 19 | 0 | +-- | hal | create_table | 19 | 3035120946000 | 431706815000 | 0 | 0 | 0 | 0 | 0 | +-- ... +-- +------+----------------------+--------+-----------------+----------------+----------------+-----------+---------------+---------------+------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$host_summary_by_statement_type ( + host, + statement, + total, + total_latency, + max_latency, + lock_latency, + rows_sent, + rows_examined, + rows_affected, + full_scans +) AS +SELECT IF(host IS NULL, 'background', host) AS host, + SUBSTRING_INDEX(event_name, '/', -1) AS statement, + count_star AS total, + sum_timer_wait AS total_latency, + max_timer_wait AS max_latency, + sum_lock_time AS lock_latency, + sum_rows_sent AS rows_sent, + sum_rows_examined AS rows_examined, + sum_rows_affected AS rows_affected, + sum_no_index_used + sum_no_good_index_used AS full_scans + FROM performance_schema.events_statements_summary_by_host_by_event_name + WHERE sum_timer_wait != 0 + ORDER BY IF(host IS NULL, 'background', host), sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/x_io_by_thread_by_latency.sql b/scripts/sys_schema/views/p_s/x_io_by_thread_by_latency.sql new file mode 100644 index 00000000..5e02f528 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_io_by_thread_by_latency.sql @@ -0,0 +1,70 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$io_by_thread_by_latency +-- +-- Show the top IO consumers by thread, ordered by total latency +-- +-- mysql> select * from x$io_by_thread_by_latency; +-- +---------------------+-------+----------------+-------------+-----------------+--------------+-----------+----------------+ +-- | user | total | total_latency | min_latency | avg_latency | max_latency | thread_id | processlist_id | +-- +---------------------+-------+----------------+-------------+-----------------+--------------+-----------+----------------+ +-- | root@localhost | 11587 | 18007539905680 | 429780 | 1120831681.6667 | 181065665560 | 25 | 6 | +-- | main | 1358 | 1309001741320 | 475020 | 2269581997.8000 | 350700491310 | 1 | NULL | +-- | page_cleaner_thread | 654 | 147435455960 | 588120 | 225436198.0000 | 46412043990 | 18 | NULL | +-- | io_write_thread | 131 | 107754483070 | 8603140 | 822553303.0000 | 27691592500 | 8 | NULL | +-- | io_write_thread | 46 | 47074926860 | 10642710 | 1023367631.0000 | 16899745070 | 9 | NULL | +-- | io_write_thread | 71 | 46988801210 | 9108320 | 661814075.0000 | 17042760020 | 11 | NULL | +-- | io_log_thread | 20 | 21007710490 | 14250600 | 1050385336.0000 | 7081255090 | 3 | NULL | +-- | srv_master_thread | 13 | 17601511720 | 8486270 | 1353962324.0000 | 9990100380 | 16 | NULL | +-- | srv_purge_thread | 4 | 1809792270 | 34307000 | 452447879.0000 | 1018887740 | 17 | NULL | +-- | io_write_thread | 19 | 951385890 | 9745450 | 50072763.0000 | 297468080 | 10 | NULL | +-- | signal_handler | 3 | 218026640 | 21639800 | 72675421.0000 | 154841440 | 19 | NULL | +-- +---------------------+-------+----------------+-------------+-----------------+--------------+-----------+----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$io_by_thread_by_latency ( + user, + total, + total_latency, + min_latency, + avg_latency, + max_latency, + thread_id, + processlist_id +) +AS +SELECT IF(processlist_id IS NULL, + SUBSTRING_INDEX(name, '/', -1), + CONCAT(processlist_user, '@', processlist_host) + ) user, + SUM(count_star) total, + SUM(sum_timer_wait) total_latency, + MIN(min_timer_wait) min_latency, + AVG(avg_timer_wait) avg_latency, + MAX(max_timer_wait) max_latency, + thread_id, + processlist_id + FROM performance_schema.events_waits_summary_by_thread_by_event_name + LEFT JOIN performance_schema.threads USING (thread_id) + WHERE event_name LIKE 'wait/io/file/%' + AND sum_timer_wait > 0 + GROUP BY thread_id, processlist_id, user + ORDER BY SUM(sum_timer_wait) DESC; diff --git a/scripts/sys_schema/views/p_s/x_io_global_by_file_by_bytes.sql b/scripts/sys_schema/views/p_s/x_io_global_by_file_by_bytes.sql new file mode 100644 index 00000000..d508deb1 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_io_global_by_file_by_bytes.sql @@ -0,0 +1,58 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$io_global_by_file_by_bytes +-- +-- Shows the top global IO consumers by bytes usage by file. +-- +-- mysql> SELECT * FROM x$io_global_by_file_by_bytes LIMIT 5; +-- +------------------------------------------------------+------------+------------+------------+-------------+---------------+------------+---------+-----------+ +-- | file | count_read | total_read | avg_read | count_write | total_written | avg_write | total | write_pct | +-- +------------------------------------------------------+------------+------------+------------+-------------+---------------+------------+---------+-----------+ +-- | /Users/mark/sandboxes/msb_5_5_33/data/ibdata1 | 147 | 4472832 | 30427.4286 | 3 | 49152 | 16384.0000 | 4521984 | 1.09 | +-- | /Users/mark/sandboxes/msb_5_5_33/data/mysql/proc.MYD | 347 | 87397 | 251.8646 | 111 | 19536 | 176.0000 | 106933 | 18.27 | +-- | /Users/mark/sandboxes/msb_5_5_33/data/ib_logfile0 | 6 | 69632 | 11605.3333 | 8 | 4096 | 512.0000 | 73728 | 5.56 | +-- | /opt/mysql/5.5.33/share/english/errmsg.sys | 3 | 44724 | 14908.0000 | 0 | 0 | 0.0000 | 44724 | 0.00 | +-- | /opt/mysql/5.5.33/share/charsets/Index.xml | 1 | 18317 | 18317.0000 | 0 | 0 | 0.0000 | 18317 | 0.00 | +-- +------------------------------------------------------+------------+------------+------------+-------------+---------------+------------+---------+-----------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$io_global_by_file_by_bytes ( + file, + count_read, + total_read, + avg_read, + count_write, + total_written, + avg_write, + total, + write_pct +) AS +SELECT file_name AS file, + count_read, + sum_number_of_bytes_read AS total_read, + IFNULL(sum_number_of_bytes_read / NULLIF(count_read, 0), 0) AS avg_read, + count_write, + sum_number_of_bytes_write AS total_written, + IFNULL(sum_number_of_bytes_write / NULLIF(count_write, 0), 0.00) AS avg_write, + sum_number_of_bytes_read + sum_number_of_bytes_write AS total, + IFNULL(ROUND(100-((sum_number_of_bytes_read/ NULLIF((sum_number_of_bytes_read+sum_number_of_bytes_write), 0))*100), 2), 0.00) AS write_pct + FROM performance_schema.file_summary_by_instance + ORDER BY sum_number_of_bytes_read + sum_number_of_bytes_write DESC; diff --git a/scripts/sys_schema/views/p_s/x_io_global_by_file_by_latency.sql b/scripts/sys_schema/views/p_s/x_io_global_by_file_by_latency.sql new file mode 100644 index 00000000..b1229ff4 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_io_global_by_file_by_latency.sql @@ -0,0 +1,58 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$io_global_by_file_by_latency +-- +-- Shows the top global IO consumers by latency by file. +-- +-- mysql> select * from x$io_global_by_file_by_latency limit 5; +-- +--------------------------------------------------------------------------------------+-------+---------------+------------+--------------+-------------+---------------+------------+--------------+ +-- | file | total | total_latency | count_read | read_latency | count_write | write_latency | count_misc | misc_latency | +-- +--------------------------------------------------------------------------------------+-------+---------------+------------+--------------+-------------+---------------+------------+--------------+ +-- | /Users/mark/sandboxes/msb_5_7_2/data/sys/wait_classes_global_by_avg_latency_raw.frm~ | 30 | 513959738110 | 0 | 0 | 5 | 132130960 | 25 | 513827607150 | +-- | /Users/mark/sandboxes/msb_5_7_2/data/sys/innodb_buffer_stats_by_schema_raw.frm~ | 30 | 490149888410 | 0 | 0 | 5 | 483887040 | 25 | 489666001370 | +-- | /Users/mark/sandboxes/msb_5_7_2/data/sys/io_by_thread_by_latency_raw.frm~ | 30 | 427724241620 | 0 | 0 | 5 | 131399580 | 25 | 427592842040 | +-- | /Users/mark/sandboxes/msb_5_7_2/data/sys/innodb_buffer_stats_by_schema.frm~ | 30 | 406392559950 | 0 | 0 | 5 | 104082160 | 25 | 406288477790 | +-- | /Users/mark/sandboxes/msb_5_7_2/data/sys/statement_analysis_raw.frm~ | 30 | 395527510430 | 0 | 0 | 5 | 118724840 | 25 | 395408785590 | +-- +--------------------------------------------------------------------------------------+-------+---------------+------------+--------------+-------------+---------------+------------+--------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$io_global_by_file_by_latency ( + file, + total, + total_latency, + count_read, + read_latency, + count_write, + write_latency, + count_misc, + misc_latency +) AS +SELECT file_name AS file, + count_star AS total, + sum_timer_wait AS total_latency, + count_read, + sum_timer_read AS read_latency, + count_write, + sum_timer_write AS write_latency, + count_misc, + sum_timer_misc AS misc_latency + FROM performance_schema.file_summary_by_instance + ORDER BY sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/x_io_global_by_wait_by_bytes.sql b/scripts/sys_schema/views/p_s/x_io_global_by_wait_by_bytes.sql new file mode 100644 index 00000000..1ec6e9ce --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_io_global_by_wait_by_bytes.sql @@ -0,0 +1,74 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$io_global_by_wait_by_bytes +-- +-- Shows the top global IO consumer classes by bytes usage. +-- +-- mysql> select * from x$io_global_by_wait_by_bytes; +-- +-------------------------+-------+---------------+-------------+-------------+--------------+------------+------------+------------+-------------+---------------+-------------+-----------------+ +-- | event_name | total | total_latency | min_latency | avg_latency | max_latency | count_read | total_read | avg_read | count_write | total_written | avg_written | total_requested | +-- +-------------------------+-------+---------------+-------------+-------------+--------------+------------+------------+------------+-------------+---------------+-------------+-----------------+ +-- | innodb/innodb_data_file | 151 | 334405721910 | 8399560 | 2214607429 | 107444600380 | 147 | 4472832 | 30427.4286 | 0 | 0 | 0.0000 | 4472832 | +-- | sql/FRM | 555 | 147752034170 | 674830 | 266219881 | 57705900850 | 270 | 112174 | 415.4593 | 0 | 0 | 0.0000 | 112174 | +-- | innodb/innodb_log_file | 22 | 56776429970 | 2476890 | 2580746816 | 18883021430 | 6 | 69632 | 11605.3333 | 5 | 2560 | 512.0000 | 72192 | +-- | sql/ERRMSG | 5 | 11862056180 | 14883960 | 2372411236 | 11109473700 | 3 | 44724 | 14908.0000 | 0 | 0 | 0.0000 | 44724 | +-- | mysys/charset | 3 | 7256869230 | 19796270 | 2418956410 | 7198498320 | 1 | 18317 | 18317.0000 | 0 | 0 | 0.0000 | 18317 | +-- | myisam/kfile | 135 | 10194698280 | 784160 | 75516283 | 2593514950 | 40 | 9216 | 230.4000 | 33 | 1017 | 30.8182 | 10233 | +-- | myisam/dfile | 68 | 10527909730 | 772850 | 154822201 | 7600014630 | 9 | 6667 | 740.7778 | 0 | 0 | 0.0000 | 6667 | +-- | sql/pid | 3 | 216507330 | 41296580 | 72169110 | 100617530 | 0 | 0 | 0.0000 | 1 | 6 | 6.0000 | 6 | +-- | sql/casetest | 5 | 185261570 | 4105530 | 37052314 | 113488310 | 0 | 0 | 0.0000 | 0 | 0 | 0.0000 | 0 | +-- | sql/global_ddl_log | 2 | 21538010 | 3121560 | 10769005 | 18416450 | 0 | 0 | 0.0000 | 0 | 0 | 0.0000 | 0 | +-- | sql/dbopt | 10 | 1004267680 | 1164930 | 100426768 | 939894930 | 0 | 0 | 0.0000 | 0 | 0 | 0.0000 | 0 | +-- +-------------------------+-------+---------------+-------------+-------------+--------------+------------+------------+------------+-------------+---------------+-------------+-----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$io_global_by_wait_by_bytes ( + event_name, + total, + total_latency, + min_latency, + avg_latency, + max_latency, + count_read, + total_read, + avg_read, + count_write, + total_written, + avg_written, + total_requested +) AS +SELECT SUBSTRING_INDEX(event_name, '/', -2) AS event_name, + count_star AS total, + sum_timer_wait AS total_latency, + min_timer_wait AS min_latency, + avg_timer_wait AS avg_latency, + max_timer_wait AS max_latency, + count_read, + sum_number_of_bytes_read AS total_read, + IFNULL(sum_number_of_bytes_read / NULLIF(count_read, 0), 0) AS avg_read, + count_write, + sum_number_of_bytes_write AS total_written, + IFNULL(sum_number_of_bytes_write / NULLIF(count_write, 0), 0) AS avg_written, + sum_number_of_bytes_write + sum_number_of_bytes_read AS total_requested + FROM performance_schema.file_summary_by_event_name + WHERE event_name LIKE 'wait/io/file/%' + AND count_star > 0 + ORDER BY sum_number_of_bytes_write + sum_number_of_bytes_read DESC; diff --git a/scripts/sys_schema/views/p_s/x_io_global_by_wait_by_latency.sql b/scripts/sys_schema/views/p_s/x_io_global_by_wait_by_latency.sql new file mode 100644 index 00000000..23fb1f81 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_io_global_by_wait_by_latency.sql @@ -0,0 +1,82 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$io_global_by_wait_by_latency +-- +-- Shows the top global IO consumers by latency. +-- +-- mysql> select * from x$io_global_by_wait_by_latency; +-- +-------------------------+-------+----------------+-------------+--------------+--------------+---------------+----------------+------------+------------+------------+-------------+---------------+-------------+ +-- | event_name | total | total_latency | avg_latency | max_latency | read_latency | write_latency | misc_latency | count_read | total_read | avg_read | count_write | total_written | avg_written | +-- +-------------------------+-------+----------------+-------------+--------------+--------------+---------------+----------------+------------+------------+------------+-------------+---------------+-------------+ +-- | sql/file_parser | 5945 | 33615441247050 | 5654405471 | 203652881640 | 22093704230 | 27389668280 | 33565957874540 | 26 | 7008 | 269.5385 | 808 | 2479209 | 3068.3280 | +-- | sql/FRM | 6332 | 1755386796800 | 277224688 | 145624702340 | 519139578620 | 1677016640 | 1234570201540 | 2040 | 865905 | 424.4632 | 439 | 103445 | 235.6378 | +-- | innodb/innodb_data_file | 1344 | 1522989889460 | 1133176798 | 350700491310 | 203817502460 | 450959403830 | 868212983170 | 147 | 2408448 | 16384.0000 | 1001 | 56213504 | 56157.3467 | +-- | innodb/innodb_log_file | 828 | 893475794640 | 1079076921 | 30108124800 | 16315236730 | 705886928240 | 171273629670 | 6 | 69632 | 11605.3333 | 413 | 2294272 | 5555.1380 | +-- | myisam/kfile | 7826 | 246001992860 | 31433883 | 19265276810 | 74419162870 | 23923730090 | 147659099900 | 770 | 141058 | 183.1922 | 4516 | 249602 | 55.2706 | +-- | myisam/dfile | 13431 | 228191713620 | 16989882 | 32500163410 | 89162969350 | 17341973610 | 121686770660 | 5819 | 4873176 | 837.4594 | 1577 | 2853444 | 1809.4128 | +-- | csv/metadata | 8 | 28975194560 | 3621899320 | 20148109020 | 399265620 | 0 | 28575928940 | 2 | 70 | 35.0000 | 0 | 0 | 0.0000 | +-- | mysys/charset | 3 | 24244722970 | 8081574072 | 24151547420 | 24151547420 | 0 | 93175550 | 1 | 17722 | 17722.0000 | 0 | 0 | 0.0000 | +-- | sql/ERRMSG | 5 | 20427386850 | 4085477370 | 19312386730 | 20324183100 | 0 | 103203750 | 3 | 60390 | 20130.0000 | 0 | 0 | 0.0000 | +-- | mysys/cnf | 5 | 11366169230 | 2273233846 | 11283602460 | 11287953040 | 0 | 78216190 | 3 | 56 | 18.6667 | 0 | 0 | 0.0000 | +-- | sql/dbopt | 57 | 4042348570 | 70918224 | 843703380 | 0 | 186430270 | 3855918300 | 0 | 0 | 0.0000 | 7 | 431 | 61.5714 | +-- | csv/data | 4 | 411548280 | 102887070 | 234886080 | 0 | 0 | 411548280 | 0 | 0 | 0.0000 | 0 | 0 | 0.0000 | +-- | sql/misc | 24 | 369128240 | 15380092 | 33771660 | 0 | 0 | 369128240 | 0 | 0 | 0.0000 | 0 | 0 | 0.0000 | +-- | archive/data | 39 | 277856540 | 7124169 | 16180840 | 0 | 0 | 277856540 | 0 | 0 | 0.0000 | 0 | 0 | 0.0000 | +-- | sql/pid | 3 | 218026640 | 72675421 | 154841440 | 0 | 21639800 | 196386840 | 0 | 0 | 0.0000 | 1 | 6 | 6.0000 | +-- | sql/casetest | 5 | 197152150 | 39430430 | 126310080 | 0 | 0 | 197152150 | 0 | 0 | 0.0000 | 0 | 0 | 0.0000 | +-- | sql/global_ddl_log | 2 | 14604980 | 7302490 | 12120550 | 0 | 0 | 14604980 | 0 | 0 | 0.0000 | 0 | 0 | 0.0000 | +-- +-------------------------+-------+----------------+-------------+--------------+--------------+---------------+----------------+------------+------------+------------+-------------+---------------+-------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$io_global_by_wait_by_latency ( + event_name, + total, + total_latency, + avg_latency, + max_latency, + read_latency, + write_latency, + misc_latency, + count_read, + total_read, + avg_read, + count_write, + total_written, + avg_written +) AS +SELECT SUBSTRING_INDEX(event_name, '/', -2) AS event_name, + count_star AS total, + sum_timer_wait AS total_latency, + avg_timer_wait AS avg_latency, + max_timer_wait AS max_latency, + sum_timer_read AS read_latency, + sum_timer_write AS write_latency, + sum_timer_misc AS misc_latency, + count_read, + sum_number_of_bytes_read AS total_read, + IFNULL(sum_number_of_bytes_read / NULLIF(count_read, 0), 0) AS avg_read, + count_write, + sum_number_of_bytes_write AS total_written, + IFNULL(sum_number_of_bytes_write / NULLIF(count_write, 0), 0) AS avg_written + FROM performance_schema.file_summary_by_event_name + WHERE event_name LIKE 'wait/io/file/%' + AND count_star > 0 + ORDER BY sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/x_latest_file_io.sql b/scripts/sys_schema/views/p_s/x_latest_file_io.sql new file mode 100644 index 00000000..7cef7b89 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_latest_file_io.sql @@ -0,0 +1,57 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$latest_file_io +-- +-- Shows the latest file IO, by file / thread. +-- +-- mysql> SELECT * FROM x$latest_file_io LIMIT 5; +-- +------------------+------------------------------------------------------------------------------------+-------------+-----------+-----------+ +-- | thread | file | latency | operation | requested | +-- +------------------+------------------------------------------------------------------------------------+-------------+-----------+-----------+ +-- | root@localhost:6 | /Users/mark/sandboxes/msb_5_7_2/data/ps_helper/user_summary_by_statement_type.frm~ | 26152490 | write | 4210 | +-- | root@localhost:6 | /Users/mark/sandboxes/msb_5_7_2/data/ps_helper/user_summary_by_statement_type.frm~ | 30062722690 | sync | NULL | +-- | root@localhost:6 | /Users/mark/sandboxes/msb_5_7_2/data/ps_helper/user_summary_by_statement_type.frm~ | 34144890 | close | NULL | +-- | root@localhost:6 | /Users/mark/sandboxes/msb_5_7_2/data/ps_helper/check_lost_instrumentation.frm | 113001980 | open | NULL | +-- | root@localhost:6 | /Users/mark/sandboxes/msb_5_7_2/data/ps_helper/check_lost_instrumentation.frm | 9553180 | read | 10 | +-- +------------------+------------------------------------------------------------------------------------+-------------+-----------+-----------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$latest_file_io ( + thread, + file, + latency, + operation, + requested +) AS +SELECT IF(id IS NULL, + CONCAT(SUBSTRING_INDEX(name, '/', -1), ':', thread_id), + CONCAT(user, '@', host, ':', id) + ) thread, + object_name file, + timer_wait AS latency, + operation, + number_of_bytes AS requested + FROM performance_schema.events_waits_history_long + JOIN performance_schema.threads USING (thread_id) + LEFT JOIN information_schema.processlist ON processlist_id = id + WHERE object_name IS NOT NULL + AND event_name LIKE 'wait/io/file/%' + ORDER BY timer_start; diff --git a/scripts/sys_schema/views/p_s/x_memory_by_host_by_current_bytes.sql b/scripts/sys_schema/views/p_s/x_memory_by_host_by_current_bytes.sql new file mode 100644 index 00000000..1fc38197 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_memory_by_host_by_current_bytes.sql @@ -0,0 +1,52 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$memory_by_host_by_current_bytes +-- +-- Summarizes memory use by host +-- +-- When the host found is NULL, it is assumed to be a local "background" thread. +-- +-- mysql> select * from x$memory_by_host_by_current_bytes; +-- +------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- | host | current_count_used | current_allocated | current_avg_alloc | current_max_alloc | total_allocated | +-- +------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- | background | 2773 | 11362444 | 4097.5276 | 8390792 | 32184183 | +-- | localhost | 1508 | 813040 | 539.1512 | 180616 | 88168182 | +-- +------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$memory_by_host_by_current_bytes ( + host, + current_count_used, + current_allocated, + current_avg_alloc, + current_max_alloc, + total_allocated +) AS +SELECT IF(host IS NULL, 'background', host) AS host, + SUM(current_count_used) AS current_count_used, + SUM(current_number_of_bytes_used) AS current_allocated, + IFNULL(SUM(current_number_of_bytes_used) / NULLIF(SUM(current_count_used), 0), 0) AS current_avg_alloc, + MAX(current_number_of_bytes_used) AS current_max_alloc, + SUM(sum_number_of_bytes_alloc) AS total_allocated + FROM performance_schema.memory_summary_by_host_by_event_name + GROUP BY IF(host IS NULL, 'background', host) + ORDER BY SUM(current_number_of_bytes_used) DESC; diff --git a/scripts/sys_schema/views/p_s/x_memory_by_thread_by_current_bytes.sql b/scripts/sys_schema/views/p_s/x_memory_by_thread_by_current_bytes.sql new file mode 100644 index 00000000..3f4098bd --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_memory_by_thread_by_current_bytes.sql @@ -0,0 +1,62 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$memory_by_thread_by_current_bytes +-- +-- Summarizes memory use by user +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from sys.x$memory_by_thread_by_current_bytes limit 5; +-- +-----------+----------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- | thread_id | user | current_count_used | current_allocated | current_avg_alloc | current_max_alloc | total_allocated | +-- +-----------+----------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- | 1 | sql/main | 29333 | 174089450 | 5934.9351 | 137494528 | 205523135 | +-- | 55 | root@localhost | 173 | 1074664 | 6211.9306 | 359280 | 72248413 | +-- | 58 | root@localhost | 240 | 377099 | 1571.2458 | 319536 | 169483870 | +-- | 1152 | root@localhost | 30 | 56949 | 1898.3000 | 16391 | 1010024 | +-- | 1154 | root@localhost | 34 | 56369 | 1657.9118 | 16391 | 1958771 | +-- +-----------+----------------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$memory_by_thread_by_current_bytes ( + thread_id, + user, + current_count_used, + current_allocated, + current_avg_alloc, + current_max_alloc, + total_allocated +) AS +SELECT t.thread_id, + IF(t.name = 'thread/sql/one_connection', + CONCAT(t.processlist_user, '@', t.processlist_host), + REPLACE(t.name, 'thread/', '')) user, + SUM(mt.current_count_used) AS current_count_used, + SUM(mt.current_number_of_bytes_used) AS current_allocated, + IFNULL(SUM(mt.current_number_of_bytes_used) / NULLIF(SUM(current_count_used), 0), 0) AS current_avg_alloc, + MAX(mt.current_number_of_bytes_used) AS current_max_alloc, + SUM(mt.sum_number_of_bytes_alloc) AS total_allocated + FROM performance_schema.memory_summary_by_thread_by_event_name AS mt + JOIN performance_schema.threads AS t USING (thread_id) + GROUP BY thread_id, IF(t.name = 'thread/sql/one_connection', + CONCAT(t.processlist_user, '@', t.processlist_host), + REPLACE(t.name, 'thread/', '')) + ORDER BY SUM(mt.current_number_of_bytes_used) DESC; diff --git a/scripts/sys_schema/views/p_s/x_memory_by_user_by_current_bytes.sql b/scripts/sys_schema/views/p_s/x_memory_by_user_by_current_bytes.sql new file mode 100644 index 00000000..794fc568 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_memory_by_user_by_current_bytes.sql @@ -0,0 +1,52 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$memory_by_user_by_current_bytes +-- +-- Summarizes memory use by user +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from x$memory_by_user_by_current_bytes; +-- +------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- | user | current_count_used | current_allocated | current_avg_alloc | current_max_alloc | total_allocated | +-- +------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- | root | 1399 | 1124553 | 803.8263 | 343008 | 45426133 | +-- | mark | 201 | 507990 | 2527.3134 | 343008 | 5769804 | +-- +------+--------------------+-------------------+-------------------+-------------------+-----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$memory_by_user_by_current_bytes ( + user, + current_count_used, + current_allocated, + current_avg_alloc, + current_max_alloc, + total_allocated +) AS +SELECT IF(user IS NULL, 'background', user) AS user, + SUM(current_count_used) AS current_count_used, + SUM(current_number_of_bytes_used) AS current_allocated, + IFNULL(SUM(current_number_of_bytes_used) / NULLIF(SUM(current_count_used), 0), 0) AS current_avg_alloc, + MAX(current_number_of_bytes_used) AS current_max_alloc, + SUM(sum_number_of_bytes_alloc) AS total_allocated + FROM performance_schema.memory_summary_by_user_by_event_name + GROUP BY IF(user IS NULL, 'background', user) + ORDER BY SUM(current_number_of_bytes_used) DESC; diff --git a/scripts/sys_schema/views/p_s/x_memory_global_by_current_bytes.sql b/scripts/sys_schema/views/p_s/x_memory_global_by_current_bytes.sql new file mode 100644 index 00000000..986c4452 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_memory_global_by_current_bytes.sql @@ -0,0 +1,56 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$memory_global_by_current_bytes +-- +-- Shows the current memory usage within the server globally broken down by allocation type. +-- +-- mysql> select * from x$memory_global_by_current_bytes; +-- +-------------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+ +-- | event_name | current_count | current_alloc | current_avg_alloc | high_count | high_alloc | high_avg_alloc | +-- +-------------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+ +-- | memory/performance_schema/internal_buffers | 62 | 308073712 | 4968930.8387 | 62 | 308073712 | 4968930.8387 | +-- | memory/innodb/buf_buf_pool | 1 | 137428992 | 137428992.0000 | 1 | 137428992 | 137428992.0000 | +-- | memory/innodb/log0log | 9 | 8397152 | 933016.8889 | 9 | 8397152 | 933016.8889 | +-- | memory/mysys/KEY_CACHE | 3 | 8390792 | 2796930.6667 | 3 | 8390792 | 2796930.6667 | +-- | memory/innodb/hash0hash | 27 | 4962992 | 183814.5185 | 27 | 7173904 | 265700.1481 | +-- | memory/innodb/os0event | 24998 | 4199664 | 168.0000 | 24998 | 4199664 | 168.0000 | +-- ... +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$memory_global_by_current_bytes ( + event_name, + current_count, + current_alloc, + current_avg_alloc, + high_count, + high_alloc, + high_avg_alloc +) AS +SELECT event_name, + current_count_used AS current_count, + current_number_of_bytes_used AS current_alloc, + IFNULL(current_number_of_bytes_used / NULLIF(current_count_used, 0), 0) AS current_avg_alloc, + high_count_used AS high_count, + high_number_of_bytes_used AS high_alloc, + IFNULL(high_number_of_bytes_used / NULLIF(high_count_used, 0), 0) AS high_avg_alloc + FROM performance_schema.memory_summary_global_by_event_name + WHERE current_number_of_bytes_used > 0 + ORDER BY current_number_of_bytes_used DESC; diff --git a/scripts/sys_schema/views/p_s/x_memory_global_total.sql b/scripts/sys_schema/views/p_s/x_memory_global_total.sql new file mode 100644 index 00000000..9fe7e7b1 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_memory_global_total.sql @@ -0,0 +1,37 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$memory_global_total +-- +-- Shows the total memory usage within the server globally +-- +-- mysql> select * from x$memory_global_total; +-- +-----------------+ +-- | total_allocated | +-- +-----------------+ +-- | 1420023 | +-- +-----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$memory_global_total ( + total_allocated +) AS +SELECT SUM(CURRENT_NUMBER_OF_BYTES_USED) total_allocated + FROM performance_schema.memory_summary_global_by_event_name; diff --git a/scripts/sys_schema/views/p_s/x_processlist.sql b/scripts/sys_schema/views/p_s/x_processlist.sql new file mode 100644 index 00000000..8f39918d --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_processlist.sql @@ -0,0 +1,108 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$processlist +-- +-- A detailed non-blocking processlist view to replace +-- [INFORMATION_SCHEMA. | SHOW FULL] PROCESSLIST +-- +-- mysql> select * from x$processlist where conn_id is not null\G +-- *************************** 1. row *************************** +-- thd_id: 23 +-- conn_id: 4 +-- user: msandbox@localhost +-- db: test +-- command: Query +-- state: altering table +-- time: 19 +-- current_statement: alter table t1 add column j int +-- statement_latency: 19466744276374 +-- lock_latency: 539307000000 +-- rows_examined: 0 +-- rows_sent: 0 +-- rows_affected: 0 +-- tmp_tables: 0 +-- tmp_disk_tables: 0 +-- full_scan: NO +-- last_statement: NULL +-- last_statement_latency: NULL +-- last_wait: wait/io/file/innodb/innodb_temp_file +-- last_wait_latency: 63400681890 +-- source: row0merge.cc:780 +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$processlist ( + thd_id, + conn_id, + user, + db, + command, + state, + time, + current_statement, + statement_latency, + lock_latency, + rows_examined, + rows_sent, + rows_affected, + tmp_tables, + tmp_disk_tables, + full_scan, + last_statement, + last_statement_latency, + last_wait, + last_wait_latency, + source +) AS +SELECT pps.thread_id AS thd_id, + pps.processlist_id AS conn_id, + IF(pps.name = 'thread/sql/one_connection', + CONCAT(pps.processlist_user, '@', pps.processlist_host), + REPLACE(pps.name, 'thread/', '')) user, + pps.processlist_db AS db, + pps.processlist_command AS command, + pps.processlist_state AS state, + pps.processlist_time AS time, + pps.processlist_info AS current_statement, + IF(esc.end_event_id IS NULL, + esc.timer_wait, + NULL) AS statement_latency, + esc.lock_time AS lock_latency, + esc.rows_examined AS rows_examined, + esc.rows_sent AS rows_sent, + esc.rows_affected AS rows_affected, + esc.created_tmp_tables AS tmp_tables, + esc.created_tmp_disk_tables AS tmp_disk_tables, + IF(esc.no_good_index_used > 0 OR esc.no_index_used > 0, 'YES', 'NO') AS full_scan, + IF(esc.end_event_id IS NOT NULL, + esc.sql_text, + NULL) AS last_statement, + IF(esc.end_event_id IS NOT NULL, + esc.timer_wait, + NULL) AS last_statement_latency, + ewc.event_name AS last_wait, + IF(ewc.end_event_id IS NULL AND ewc.event_name IS NOT NULL, + 'Still Waiting', + ewc.timer_wait) last_wait_latency, + ewc.source + FROM performance_schema.threads AS pps + LEFT JOIN performance_schema.events_waits_current AS ewc USING (thread_id) + LEFT JOIN performance_schema.events_statements_current as esc USING (thread_id) + ORDER BY pps.processlist_time DESC, last_wait_latency DESC; diff --git a/scripts/sys_schema/views/p_s/x_processlist_57.sql b/scripts/sys_schema/views/p_s/x_processlist_57.sql new file mode 100644 index 00000000..cfea37a0 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_processlist_57.sql @@ -0,0 +1,141 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$processlist +-- +-- A detailed non-blocking processlist view to replace +-- [INFORMATION_SCHEMA. | SHOW FULL] PROCESSLIST +-- +-- Performs less locking than the legacy sources, whilst giving extra information. +-- +-- mysql> select * from sys.x$processlist where conn_id is not null and command != 'daemon' and conn_id != connection_id()\G +-- ... +-- *************************** 2. row *************************** +-- thd_id: 720 +-- conn_id: 698 +-- user: msandbox@localhost +-- db: test +-- command: Query +-- state: alter table (read PK and internal sort) +-- time: 2 +-- current_statement: alter table t1 add column l int +-- statement_latency: 2349834276374 +-- progress: 60.00 +-- lock_latency: 339707000000 +-- rows_examined: 0 +-- rows_sent: 0 +-- rows_affected: 0 +-- tmp_tables: 0 +-- tmp_disk_tables: 0 +-- full_scan: NO +-- last_statement: NULL +-- last_statement_latency: NULL +-- current_memory: 10186821 +-- last_wait: wait/io/file/innodb/innodb_data_file +-- last_wait_latency: Still Waiting +-- source: fil0fil.cc:5351 +-- trx_latency: NULL +-- trx_state: NULL +-- trx_autocommit: NULL +-- pid: 5559 +-- program_name: mysql +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$processlist ( + thd_id, + conn_id, + user, + db, + command, + state, + time, + current_statement, + statement_latency, + progress, + lock_latency, + rows_examined, + rows_sent, + rows_affected, + tmp_tables, + tmp_disk_tables, + full_scan, + last_statement, + last_statement_latency, + current_memory, + last_wait, + last_wait_latency, + source, + trx_latency, + trx_state, + trx_autocommit, + pid, + program_name +) AS +SELECT pps.thread_id AS thd_id, + pps.processlist_id AS conn_id, + IF(pps.name = 'thread/sql/one_connection', + CONCAT(pps.processlist_user, '@', pps.processlist_host), + REPLACE(pps.name, 'thread/', '')) user, + pps.processlist_db AS db, + pps.processlist_command AS command, + pps.processlist_state AS state, + pps.processlist_time AS time, + pps.processlist_info AS current_statement, + IF(esc.end_event_id IS NULL, + esc.timer_wait, + NULL) AS statement_latency, + IF(esc.end_event_id IS NULL, + ROUND(100 * (estc.work_completed / estc.work_estimated), 2), + NULL) AS progress, + esc.lock_time AS lock_latency, + esc.rows_examined AS rows_examined, + esc.rows_sent AS rows_sent, + esc.rows_affected AS rows_affected, + esc.created_tmp_tables AS tmp_tables, + esc.created_tmp_disk_tables AS tmp_disk_tables, + IF(esc.no_good_index_used > 0 OR esc.no_index_used > 0, 'YES', 'NO') AS full_scan, + IF(esc.end_event_id IS NOT NULL, + esc.sql_text, + NULL) AS last_statement, + IF(esc.end_event_id IS NOT NULL, + esc.timer_wait, + NULL) AS last_statement_latency, + mem.current_allocated AS current_memory, + ewc.event_name AS last_wait, + IF(ewc.end_event_id IS NULL AND ewc.event_name IS NOT NULL, + 'Still Waiting', + ewc.timer_wait) last_wait_latency, + ewc.source, + etc.timer_wait AS trx_latency, + etc.state AS trx_state, + etc.autocommit AS trx_autocommit, + conattr_pid.attr_value as pid, + conattr_progname.attr_value as program_name + FROM performance_schema.threads AS pps + LEFT JOIN performance_schema.events_waits_current AS ewc USING (thread_id) + LEFT JOIN performance_schema.events_stages_current AS estc USING (thread_id) + LEFT JOIN performance_schema.events_statements_current AS esc USING (thread_id) + LEFT JOIN performance_schema.events_transactions_current AS etc USING (thread_id) + LEFT JOIN sys.x$memory_by_thread_by_current_bytes AS mem USING (thread_id) + LEFT JOIN performance_schema.session_connect_attrs AS conattr_pid + ON conattr_pid.processlist_id=pps.processlist_id and conattr_pid.attr_name='_pid' + LEFT JOIN performance_schema.session_connect_attrs AS conattr_progname + ON conattr_progname.processlist_id=pps.processlist_id and conattr_progname.attr_name='program_name' + ORDER BY pps.processlist_time DESC, last_wait_latency DESC; diff --git a/scripts/sys_schema/views/p_s/x_ps_digest_95th_percentile_by_avg_us.sql b/scripts/sys_schema/views/p_s/x_ps_digest_95th_percentile_by_avg_us.sql new file mode 100644 index 00000000..de747b87 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_ps_digest_95th_percentile_by_avg_us.sql @@ -0,0 +1,46 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$ps_digest_95th_percentile_by_avg_us +-- +-- Helper view for statements_with_runtimes_in_95th_percentile. +-- Lists the 95th percentile runtime, for all statements +-- +-- mysql> select * from x$ps_digest_95th_percentile_by_avg_us; +-- +--------+------------+ +-- | avg_us | percentile | +-- +--------+------------+ +-- | 964 | 0.9525 | +-- +--------+------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$ps_digest_95th_percentile_by_avg_us ( + avg_us, + percentile +) AS +SELECT s2.avg_us avg_us, + IFNULL(SUM(s1.cnt)/NULLIF((SELECT COUNT(*) FROM performance_schema.events_statements_summary_by_digest), 0), 0) percentile + FROM sys.x$ps_digest_avg_latency_distribution AS s1 + JOIN sys.x$ps_digest_avg_latency_distribution AS s2 + ON s1.avg_us <= s2.avg_us + GROUP BY s2.avg_us +HAVING IFNULL(SUM(s1.cnt)/NULLIF((SELECT COUNT(*) FROM performance_schema.events_statements_summary_by_digest), 0), 0) > 0.95 + ORDER BY percentile + LIMIT 1; diff --git a/scripts/sys_schema/views/p_s/x_ps_digest_avg_latency_distribution.sql b/scripts/sys_schema/views/p_s/x_ps_digest_avg_latency_distribution.sql new file mode 100644 index 00000000..7a0b468f --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_ps_digest_avg_latency_distribution.sql @@ -0,0 +1,33 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$ps_digest_avg_latency_distribution +-- +-- Helper view for x$ps_digest_95th_percentile_by_avg_us +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$ps_digest_avg_latency_distribution ( + cnt, + avg_us +) AS +SELECT COUNT(*) cnt, + ROUND(avg_timer_wait/1000000) AS avg_us + FROM performance_schema.events_statements_summary_by_digest + GROUP BY avg_us; diff --git a/scripts/sys_schema/views/p_s/x_ps_schema_table_statistics_io.sql b/scripts/sys_schema/views/p_s/x_ps_schema_table_statistics_io.sql new file mode 100644 index 00000000..c2c36cae --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_ps_schema_table_statistics_io.sql @@ -0,0 +1,64 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$ps_schema_table_statistics_io +-- +-- Helper view for schema_table_statistics +-- Having this view with ALGORITHM = TEMPTABLE means MySQL can use the optimizations for +-- materialized views to improve the overall performance. +-- +-- mysql> SELECT * FROM x$ps_schema_table_statistics_io LIMIT 1\G +-- *************************** 1. row *************************** +-- table_schema: charsets +-- table_name: Index +-- count_read: 1 +-- sum_number_of_bytes_read: 18710 +-- sum_timer_read: 20229409070 +-- count_write: 0 +-- sum_number_of_bytes_write: 0 +-- sum_timer_write: 0 +-- count_misc: 2 +-- sum_timer_misc: 80768480 +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$ps_schema_table_statistics_io ( + table_schema, + table_name, + count_read, + sum_number_of_bytes_read, + sum_timer_read, + count_write, + sum_number_of_bytes_write, + sum_timer_write, + count_misc, + sum_timer_misc +) AS +SELECT extract_schema_from_file_name(file_name) AS table_schema, + extract_table_from_file_name(file_name) AS table_name, + SUM(count_read) AS count_read, + SUM(sum_number_of_bytes_read) AS sum_number_of_bytes_read, + SUM(sum_timer_read) AS sum_timer_read, + SUM(count_write) AS count_write, + SUM(sum_number_of_bytes_write) AS sum_number_of_bytes_write, + SUM(sum_timer_write) AS sum_timer_write, + SUM(count_misc) AS count_misc, + SUM(sum_timer_misc) AS sum_timer_misc + FROM performance_schema.file_summary_by_instance + GROUP BY table_schema, table_name; diff --git a/scripts/sys_schema/views/p_s/x_schema_index_statistics.sql b/scripts/sys_schema/views/p_s/x_schema_index_statistics.sql new file mode 100644 index 00000000..1ef5821f --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_schema_index_statistics.sql @@ -0,0 +1,65 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$schema_index_statistics +-- +-- Statistics around indexes. +-- +-- Ordered by the total wait time descending - top indexes are most contended. +-- +-- mysql> SELECT * FROM x$schema_index_statistics LIMIT 5; +-- +---------------+----------------------+-------------------+---------------+----------------+---------------+----------------+--------------+----------------+--------------+----------------+ +-- | table_schema | table_name | index_name | rows_selected | select_latency | rows_inserted | insert_latency | rows_updated | update_latency | rows_deleted | delete_latency | +-- +---------------+----------------------+-------------------+---------------+----------------+---------------+----------------+--------------+----------------+--------------+----------------+ +-- | common_schema | _global_sql_tokens | PRIMARY | 1886 | 1129676730 | 0 | 0 | 0 | 0 | 1878 | 0 | +-- | common_schema | _script_statements | PRIMARY | 4606 | 4212160680 | 0 | 0 | 0 | 0 | 0 | 0 | +-- | common_schema | _global_qs_variables | declaration_depth | 256 | 1650193090 | 0 | 0 | 32 | 1372148050 | 0 | 0 | +-- | common_schema | _global_qs_variables | PRIMARY | 0 | 0 | 0 | 0 | 0 | 0 | 16 | 0 | +-- | common_schema | metadata | PRIMARY | 5 | 76730810 | 0 | 0 | 4 | 114310170 | 0 | 0 | +-- +---------------+----------------------+-------------------+---------------+----------------+---------------+----------------+--------------+----------------+--------------+----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$schema_index_statistics ( + table_schema, + table_name, + index_name, + rows_selected, + select_latency, + rows_inserted, + insert_latency, + rows_updated, + update_latency, + rows_deleted, + delete_latency +) AS +SELECT OBJECT_SCHEMA AS table_schema, + OBJECT_NAME AS table_name, + INDEX_NAME as index_name, + COUNT_FETCH AS rows_selected, + SUM_TIMER_FETCH AS select_latency, + COUNT_INSERT AS rows_inserted, + SUM_TIMER_INSERT AS insert_latency, + COUNT_UPDATE AS rows_updated, + SUM_TIMER_UPDATE AS update_latency, + COUNT_DELETE AS rows_deleted, + SUM_TIMER_INSERT AS delete_latency + FROM performance_schema.table_io_waits_summary_by_index_usage + WHERE index_name IS NOT NULL + ORDER BY sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/x_schema_table_lock_waits.sql b/scripts/sys_schema/views/p_s/x_schema_table_lock_waits.sql new file mode 100644 index 00000000..0cbf84cf --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_schema_table_lock_waits.sql @@ -0,0 +1,97 @@ +-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: schema_table_lock_waits +-- +-- Shows sessions that are blocked waiting on table metadata locks, and +-- who is blocking them. +-- +-- mysql> select * from sys.x$schema_table_lock_waits\G +-- *************************** 1. row *************************** +-- object_schema: test +-- object_name: t +-- waiting_thread_id: 43 +-- waiting_pid: 21 +-- waiting_account: msandbox@localhost +-- waiting_lock_type: SHARED_UPGRADABLE +-- waiting_lock_duration: TRANSACTION +-- waiting_query: alter table test.t add foo int +-- waiting_query_secs: 990 +-- waiting_query_rows_affected: 0 +-- waiting_query_rows_examined: 0 +-- blocking_thread_id: 42 +-- blocking_pid: 20 +-- blocking_account: msandbox@localhost +-- blocking_lock_type: SHARED_NO_READ_WRITE +-- blocking_lock_duration: TRANSACTION +-- sql_kill_blocking_query: KILL QUERY 20 +-- sql_kill_blocking_connection: KILL 20 +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$schema_table_lock_waits ( + object_schema, + object_name, + waiting_thread_id, + waiting_pid, + waiting_account, + waiting_lock_type, + waiting_lock_duration, + waiting_query, + waiting_query_secs, + waiting_query_rows_affected, + waiting_query_rows_examined, + blocking_thread_id, + blocking_pid, + blocking_account, + blocking_lock_type, + blocking_lock_duration, + sql_kill_blocking_query, + sql_kill_blocking_connection +) AS +SELECT g.object_schema AS object_schema, + g.object_name AS object_name, + pt.thread_id AS waiting_thread_id, + pt.processlist_id AS waiting_pid, + sys.ps_thread_account(p.owner_thread_id) AS waiting_account, + p.lock_type AS waiting_lock_type, + p.lock_duration AS waiting_lock_duration, + pt.processlist_info AS waiting_query, + pt.processlist_time AS waiting_query_secs, + ps.rows_affected AS waiting_query_rows_affected, + ps.rows_examined AS waiting_query_rows_examined, + gt.thread_id AS blocking_thread_id, + gt.processlist_id AS blocking_pid, + sys.ps_thread_account(g.owner_thread_id) AS blocking_account, + g.lock_type AS blocking_lock_type, + g.lock_duration AS blocking_lock_duration, + CONCAT('KILL QUERY ', gt.processlist_id) AS sql_kill_blocking_query, + CONCAT('KILL ', gt.processlist_id) AS sql_kill_blocking_connection + FROM performance_schema.metadata_locks g + INNER JOIN performance_schema.metadata_locks p + ON g.object_type = p.object_type + AND g.object_schema = p.object_schema + AND g.object_name = p.object_name + AND g.lock_status = 'GRANTED' + AND p.lock_status = 'PENDING' + INNER JOIN performance_schema.threads gt ON g.owner_thread_id = gt.thread_id + INNER JOIN performance_schema.threads pt ON p.owner_thread_id = pt.thread_id + LEFT JOIN performance_schema.events_statements_current gs ON g.owner_thread_id = gs.thread_id + LEFT JOIN performance_schema.events_statements_current ps ON p.owner_thread_id = ps.thread_id + WHERE g.object_type = 'TABLE'; diff --git a/scripts/sys_schema/views/p_s/x_schema_table_statistics.sql b/scripts/sys_schema/views/p_s/x_schema_table_statistics.sql new file mode 100644 index 00000000..b131200c --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_schema_table_statistics.sql @@ -0,0 +1,94 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$schema_table_statistics +-- +-- Statistics around tables. +-- +-- Ordered by the total wait time descending - top tables are most contended. +-- +-- mysql> select * from x$schema_table_statistics\G +-- *************************** 1. row *************************** +-- table_schema: sys +-- table_name: sys_config +-- total_latency: 0 +-- rows_fetched: 0 +-- fetch_latency: 0 +-- rows_inserted: 0 +-- insert_latency: 0 +-- rows_updated: 0 +-- update_latency: 0 +-- rows_deleted: 0 +-- delete_latency: 0 +-- io_read_requests: 8 +-- io_read: 2336 +-- io_read_latency: 727319710 +-- io_write_requests: 0 +-- io_write: 0 +-- io_write_latency: 0 +-- io_misc_requests: 10 +-- io_misc_latency: 126879350 +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$schema_table_statistics ( + table_schema, + table_name, + total_latency, + rows_fetched, + fetch_latency, + rows_inserted, + insert_latency, + rows_updated, + update_latency, + rows_deleted, + delete_latency, + io_read_requests, + io_read, + io_read_latency, + io_write_requests, + io_write, + io_write_latency, + io_misc_requests, + io_misc_latency +) AS +SELECT pst.object_schema AS table_schema, + pst.object_name AS table_name, + pst.sum_timer_wait AS total_latency, + pst.count_fetch AS rows_fetched, + pst.sum_timer_fetch AS fetch_latency, + pst.count_insert AS rows_inserted, + pst.sum_timer_insert AS insert_latency, + pst.count_update AS rows_updated, + pst.sum_timer_update AS update_latency, + pst.count_delete AS rows_deleted, + pst.sum_timer_delete AS delete_latency, + fsbi.count_read AS io_read_requests, + fsbi.sum_number_of_bytes_read AS io_read, + fsbi.sum_timer_read AS io_read_latency, + fsbi.count_write AS io_write_requests, + fsbi.sum_number_of_bytes_write AS io_write, + fsbi.sum_timer_write AS io_write_latency, + fsbi.count_misc AS io_misc_requests, + fsbi.sum_timer_misc AS io_misc_latency + FROM performance_schema.table_io_waits_summary_by_table AS pst + LEFT JOIN x$ps_schema_table_statistics_io AS fsbi + ON pst.object_schema = fsbi.table_schema + AND pst.object_name = fsbi.table_name + ORDER BY pst.sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/x_schema_table_statistics_with_buffer.sql b/scripts/sys_schema/views/p_s/x_schema_table_statistics_with_buffer.sql new file mode 100644 index 00000000..a573c288 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_schema_table_statistics_with_buffer.sql @@ -0,0 +1,122 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$schema_table_statistics_with_buffer +-- +-- Statistics around tables. +-- +-- Ordered by the total wait time descending - top tables are most contended. +-- +-- More statistics such as caching stats for the InnoDB buffer pool with InnoDB tables +-- +-- mysql> SELECT * FROM x$schema_table_statistics_with_buffer LIMIT 1\G +-- *************************** 1. row *************************** +-- table_schema: common_schema +-- table_name: help_content +-- rows_fetched: 0 +-- fetch_latency: 0 +-- rows_inserted: 169 +-- insert_latency: 409815527680 +-- rows_updated: 0 +-- update_latency: 0 +-- rows_deleted: 0 +-- delete_latency: 0 +-- io_read_requests: 14 +-- io_read: 1180 +-- io_read_latency: 52406770 +-- io_write_requests: 131 +-- io_write: 11719246 +-- io_write_latency: 133726902790 +-- io_misc_requests: 61 +-- io_misc_latency: 209081089750 +-- innodb_buffer_allocated: 688128 +-- innodb_buffer_data: 423667 +-- innodb_buffer_pages: 42 +-- innodb_buffer_pages_hashed: 42 +-- innodb_buffer_pages_old: 42 +-- innodb_buffer_rows_cached: 210 +-- + +DELIMITER $$ +BEGIN NOT ATOMIC +DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END; + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$schema_table_statistics_with_buffer ( + table_schema, + table_name, + rows_fetched, + fetch_latency, + rows_inserted, + insert_latency, + rows_updated, + update_latency, + rows_deleted, + delete_latency, + io_read_requests, + io_read, + io_read_latency, + io_write_requests, + io_write, + io_write_latency, + io_misc_requests, + io_misc_latency, + innodb_buffer_allocated, + innodb_buffer_data, + innodb_buffer_free, + innodb_buffer_pages, + innodb_buffer_pages_hashed, + innodb_buffer_pages_old, + innodb_buffer_rows_cached +) AS +SELECT pst.object_schema AS table_schema, + pst.object_name AS table_name, + pst.count_fetch AS rows_fetched, + pst.sum_timer_fetch AS fetch_latency, + pst.count_insert AS rows_inserted, + pst.sum_timer_insert AS insert_latency, + pst.count_update AS rows_updated, + pst.sum_timer_update AS update_latency, + pst.count_delete AS rows_deleted, + pst.sum_timer_delete AS delete_latency, + fsbi.count_read AS io_read_requests, + fsbi.sum_number_of_bytes_read AS io_read, + fsbi.sum_timer_read AS io_read_latency, + fsbi.count_write AS io_write_requests, + fsbi.sum_number_of_bytes_write AS io_write, + fsbi.sum_timer_write AS io_write_latency, + fsbi.count_misc AS io_misc_requests, + fsbi.sum_timer_misc AS io_misc_latency, + ibp.allocated AS innodb_buffer_allocated, + ibp.data AS innodb_buffer_data, + (ibp.allocated - ibp.data) AS innodb_buffer_free, + ibp.pages AS innodb_buffer_pages, + ibp.pages_hashed AS innodb_buffer_pages_hashed, + ibp.pages_old AS innodb_buffer_pages_old, + ibp.rows_cached AS innodb_buffer_rows_cached + FROM performance_schema.table_io_waits_summary_by_table AS pst + LEFT JOIN x$ps_schema_table_statistics_io AS fsbi + ON pst.object_schema = fsbi.table_schema + AND pst.object_name = fsbi.table_name + LEFT JOIN sys.x$innodb_buffer_stats_by_table AS ibp + ON pst.object_schema = ibp.object_schema + AND pst.object_name = ibp.object_name + ORDER BY pst.sum_timer_wait DESC; +END$$ +DELIMITER ; diff --git a/scripts/sys_schema/views/p_s/x_schema_tables_with_full_table_scans.sql b/scripts/sys_schema/views/p_s/x_schema_tables_with_full_table_scans.sql new file mode 100644 index 00000000..d5868bf1 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_schema_tables_with_full_table_scans.sql @@ -0,0 +1,51 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$schema_tables_with_full_table_scans +-- +-- Find tables that are being accessed by full table scans +-- ordering by the number of rows scanned descending. +-- +-- mysql> select * from x$schema_tables_with_full_table_scans limit 5; +-- +--------------------+------------------------------+-------------------+----------------+ +-- | object_schema | object_name | rows_full_scanned | latency | +-- +--------------------+------------------------------+-------------------+----------------+ +-- | mem30__instruments | fsstatistics | 10207042 | 13098927688488 | +-- | mem30__instruments | preparedstatementapidata | 436428 | 973274338980 | +-- | mem30__instruments | mysqlprocessactivity | 411702 | 282072434940 | +-- | mem30__instruments | querycachequeriesincachedata | 374011 | 767152380564 | +-- | mem30__instruments | rowaccessesdata | 322321 | 1547594778456 | +-- +--------------------+------------------------------+-------------------+----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$schema_tables_with_full_table_scans ( + object_schema, + object_name, + rows_full_scanned, + latency +) AS +SELECT object_schema, + object_name, + count_read AS rows_full_scanned, + sum_timer_wait AS latency + FROM performance_schema.table_io_waits_summary_by_index_usage + WHERE index_name IS NULL + AND count_read > 0 + ORDER BY count_read DESC; diff --git a/scripts/sys_schema/views/p_s/x_sessions.sql b/scripts/sys_schema/views/p_s/x_sessions.sql new file mode 100644 index 00000000..e320777f --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_sessions.sql @@ -0,0 +1,63 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$session +-- +-- Filter sys.processlist to only show user sessions and not background threads. +-- This is a non-blocking closer replacement to +-- [INFORMATION_SCHEMA. | SHOW FULL] PROCESSLIST +-- +-- Performs less locking than the legacy sources, whilst giving extra information. +-- +-- mysql> select * from sys.x$session\G +-- *************************** 1. row *************************** +-- thd_id: 24 +-- conn_id: 2 +-- user: root@localhost +-- db: sys +-- command: Query +-- state: Sending data +-- time: 0 +-- current_statement: select * from sys.x$session +-- statement_latency: 16285980000 +-- progress: NULL +-- lock_latency: 15450000000 +-- rows_examined: 0 +-- rows_sent: 0 +-- rows_affected: 0 +-- tmp_tables: 4 +-- tmp_disk_tables: 1 +-- full_scan: YES +-- last_statement: NULL +-- last_statement_latency: NULL +-- current_memory: 3383772 +-- last_wait: wait/synch/mutex/innodb/trx_mutex +-- last_wait_latency: 56550 +-- source: trx0trx.h:1520 +-- trx_latency: 17893350207000 +-- trx_state: ACTIVE +-- trx_autocommit: NO +-- pid: 5559 +-- program_name: mysql +-- + +CREATE OR REPLACE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$session + AS +SELECT * FROM sys.x$processlist +WHERE conn_id IS NOT NULL AND command != 'Daemon'; diff --git a/scripts/sys_schema/views/p_s/x_statement_analysis.sql b/scripts/sys_schema/views/p_s/x_statement_analysis.sql new file mode 100644 index 00000000..754c073c --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_statement_analysis.sql @@ -0,0 +1,103 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$statement_analysis +-- +-- Lists a normalized statement view with aggregated statistics, +-- mimics the MySQL Enterprise Monitor Query Analysis view, +-- ordered by the total execution time per normalized statement +-- +-- mysql> select * from x$statement_analysis limit 1\G +-- *************************** 1. row *************************** +-- query: SELECT * FROM `schema_object_overview` SELECT `information_schema` . `routines` -- truncated +-- db: sys +-- full_scan: * +-- exec_count: 2 +-- err_count: 0 +-- warn_count: 0 +-- total_latency: 16751388791000 +-- max_latency: 16566171163000 +-- avg_latency: 8375694395000 +-- lock_latency: 16686483000000 +-- rows_sent: 84 +-- rows_sent_avg: 42 +-- rows_examined: 20012 +-- rows_examined_avg: 10006 +-- rows_affected: 0 +-- rows_affected_avg: 0 +-- tmp_tables: 378 +-- tmp_disk_tables: 66 +-- rows_sorted: 168 +-- sort_merge_passes: 0 +-- digest: 54f9bd520f0bbf15db0c2ed93386bec9 +-- first_seen: 2014-03-07 13:13:41 +-- last_seen: 2014-03-07 13:13:48 +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$statement_analysis ( + query, + db, + full_scan, + exec_count, + err_count, + warn_count, + total_latency, + max_latency, + avg_latency, + lock_latency, + rows_sent, + rows_sent_avg, + rows_examined, + rows_examined_avg, + rows_affected, + rows_affected_avg, + tmp_tables, + tmp_disk_tables, + rows_sorted, + sort_merge_passes, + digest, + first_seen, + last_seen +) AS +SELECT DIGEST_TEXT AS query, + SCHEMA_NAME AS db, + IF(SUM_NO_GOOD_INDEX_USED > 0 OR SUM_NO_INDEX_USED > 0, '*', '') AS full_scan, + COUNT_STAR AS exec_count, + SUM_ERRORS AS err_count, + SUM_WARNINGS AS warn_count, + SUM_TIMER_WAIT AS total_latency, + MAX_TIMER_WAIT AS max_latency, + AVG_TIMER_WAIT AS avg_latency, + SUM_LOCK_TIME AS lock_latency, + SUM_ROWS_SENT AS rows_sent, + ROUND(IFNULL(SUM_ROWS_SENT / NULLIF(COUNT_STAR, 0), 0)) AS rows_sent_avg, + SUM_ROWS_EXAMINED AS rows_examined, + ROUND(IFNULL(SUM_ROWS_EXAMINED / NULLIF(COUNT_STAR, 0), 0)) AS rows_examined_avg, + SUM_ROWS_AFFECTED AS rows_affected, + ROUND(IFNULL(SUM_ROWS_AFFECTED / NULLIF(COUNT_STAR, 0), 0)) AS rows_affected_avg, + SUM_CREATED_TMP_TABLES AS tmp_tables, + SUM_CREATED_TMP_DISK_TABLES AS tmp_disk_tables, + SUM_SORT_ROWS AS rows_sorted, + SUM_SORT_MERGE_PASSES AS sort_merge_passes, + DIGEST AS digest, + FIRST_SEEN AS first_seen, + LAST_SEEN as last_seen + FROM performance_schema.events_statements_summary_by_digest +ORDER BY SUM_TIMER_WAIT DESC; diff --git a/scripts/sys_schema/views/p_s/x_statements_with_errors_or_warnings.sql b/scripts/sys_schema/views/p_s/x_statements_with_errors_or_warnings.sql new file mode 100644 index 00000000..aa87cf6e --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_statements_with_errors_or_warnings.sql @@ -0,0 +1,64 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$statements_with_errors_or_warnings +-- +-- Lists all normalized statements that have raised errors or warnings. +-- +-- mysql> select * from x$statements_with_errors_or_warnings LIMIT 1\G +-- *************************** 1. row *************************** +-- query: CREATE OR REPLACE ALGORITHM = TEMPTABLE DEFINER = ? @ ? SQL SECURITY INVOKER VIEW ... truncated +-- db: sys +-- exec_count: 2 +-- errors: 1 +-- error_pct: 50.0000 +-- warnings: 0 +-- warning_pct: 0.0000 +-- first_seen: 2014-03-07 12:56:54 +-- last_seen: 2014-03-07 13:01:01 +-- digest: 943a788859e623d5f7798ba0ae0fd8a9 +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$statements_with_errors_or_warnings ( + query, + db, + exec_count, + errors, + error_pct, + warnings, + warning_pct, + first_seen, + last_seen, + digest +) AS +SELECT DIGEST_TEXT AS query, + SCHEMA_NAME as db, + COUNT_STAR AS exec_count, + SUM_ERRORS AS errors, + IFNULL(SUM_ERRORS / NULLIF(COUNT_STAR, 0), 0) * 100 as error_pct, + SUM_WARNINGS AS warnings, + IFNULL(SUM_WARNINGS / NULLIF(COUNT_STAR, 0), 0) * 100 as warning_pct, + FIRST_SEEN as first_seen, + LAST_SEEN as last_seen, + DIGEST AS digest + FROM performance_schema.events_statements_summary_by_digest + WHERE SUM_ERRORS > 0 + OR SUM_WARNINGS > 0 +ORDER BY SUM_ERRORS DESC, SUM_WARNINGS DESC; diff --git a/scripts/sys_schema/views/p_s/x_statements_with_full_table_scans.sql b/scripts/sys_schema/views/p_s/x_statements_with_full_table_scans.sql new file mode 100644 index 00000000..cd4d653f --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_statements_with_full_table_scans.sql @@ -0,0 +1,82 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$statements_with_full_table_scans +-- +-- Lists all normalized statements that use have done a full table scan +-- ordered by number the percentage of times a full scan was done, +-- then by the statement latency. +-- +-- This view ignores SHOW statements, as these always cause a full table scan, +-- and there is nothing that can be done about this. +-- +-- mysql> select * from x$statements_with_full_table_scans limit 1\G +-- *************************** 1. row *************************** +-- query: SELECT * FROM `schema_object_overview` SELECT `information_schema` . `routines` . `ROUTINE_SCHEMA` // truncated +-- db: sys +-- exec_count: 2 +-- total_latency: 16751388791000 +-- no_index_used_count: 2 +-- no_good_index_used_count: 0 +-- no_index_used_pct: 100 +-- rows_sent: 84 +-- rows_examined: 20012 +-- rows_sent_avg: 42 +-- rows_examined_avg: 10006 +-- first_seen: 2014-03-07 13:13:41 +-- last_seen: 2014-03-07 13:13:48 +-- digest: 54f9bd520f0bbf15db0c2ed93386bec9 +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$statements_with_full_table_scans ( + query, + db, + exec_count, + total_latency, + no_index_used_count, + no_good_index_used_count, + no_index_used_pct, + rows_sent, + rows_examined, + rows_sent_avg, + rows_examined_avg, + first_seen, + last_seen, + digest +) AS +SELECT DIGEST_TEXT AS query, + SCHEMA_NAME as db, + COUNT_STAR AS exec_count, + SUM_TIMER_WAIT AS total_latency, + SUM_NO_INDEX_USED AS no_index_used_count, + SUM_NO_GOOD_INDEX_USED AS no_good_index_used_count, + ROUND(IFNULL(SUM_NO_INDEX_USED / NULLIF(COUNT_STAR, 0), 0) * 100) AS no_index_used_pct, + SUM_ROWS_SENT AS rows_sent, + SUM_ROWS_EXAMINED AS rows_examined, + ROUND(SUM_ROWS_SENT/COUNT_STAR) AS rows_sent_avg, + ROUND(SUM_ROWS_EXAMINED/COUNT_STAR) AS rows_examined_avg, + FIRST_SEEN as first_seen, + LAST_SEEN as last_seen, + DIGEST AS digest + FROM performance_schema.events_statements_summary_by_digest + WHERE (SUM_NO_INDEX_USED > 0 + OR SUM_NO_GOOD_INDEX_USED > 0) + AND DIGEST_TEXT NOT LIKE 'SHOW%' + ORDER BY no_index_used_pct DESC, total_latency DESC; diff --git a/scripts/sys_schema/views/p_s/x_statements_with_runtimes_in_95th_percentile.sql b/scripts/sys_schema/views/p_s/x_statements_with_runtimes_in_95th_percentile.sql new file mode 100644 index 00000000..6281d375 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_statements_with_runtimes_in_95th_percentile.sql @@ -0,0 +1,82 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$statements_with_runtimes_in_95th_percentile +-- +-- List all statements whose average runtime, in microseconds, is in the top 95th percentile. +-- +-- mysql> SELECT * FROM x$statements_with_runtimes_in_95th_percentile LIMIT 1\G +-- *************************** 1. row *************************** +-- query: SELECT `e` . `round_robin_bin` AS `round1_1706_0_` , `e` . `id` AS `id1706_0_` , `e` . `timestamp` AS `timestamp1706_0_` , ... truncated +-- db: mem +-- full_scan: * +-- exec_count: 14 +-- err_count: 0 +-- warn_count: 0 +-- total_latency: 43961670267000 +-- max_latency: 6686877140000 +-- avg_latency: 3140119304000 +-- rows_sent: 11 +-- rows_sent_avg: 1 +-- rows_examined: 253170 +-- rows_examined_avg: 18084 +-- first_seen: 2013-12-04 20:05:01 +-- last_seen: 2013-12-04 20:06:34 +-- digest: 29ba002bf039bb6439357a10134407de +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$statements_with_runtimes_in_95th_percentile ( + query, + db, + full_scan, + exec_count, + err_count, + warn_count, + total_latency, + max_latency, + avg_latency, + rows_sent, + rows_sent_avg, + rows_examined, + rows_examined_avg, + first_seen, + last_seen, + digest +) AS +SELECT DIGEST_TEXT AS query, + SCHEMA_NAME AS db, + IF(SUM_NO_GOOD_INDEX_USED > 0 OR SUM_NO_INDEX_USED > 0, '*', '') AS full_scan, + COUNT_STAR AS exec_count, + SUM_ERRORS AS err_count, + SUM_WARNINGS AS warn_count, + SUM_TIMER_WAIT AS total_latency, + MAX_TIMER_WAIT AS max_latency, + AVG_TIMER_WAIT AS avg_latency, + SUM_ROWS_SENT AS rows_sent, + ROUND(IFNULL(SUM_ROWS_SENT / NULLIF(COUNT_STAR, 0), 0)) AS rows_sent_avg, + SUM_ROWS_EXAMINED AS rows_examined, + ROUND(IFNULL(SUM_ROWS_EXAMINED / NULLIF(COUNT_STAR, 0), 0)) AS rows_examined_avg, + FIRST_SEEN as first_seen, + LAST_SEEN as last_seen, + DIGEST AS digest + FROM performance_schema.events_statements_summary_by_digest stmts + JOIN sys.x$ps_digest_95th_percentile_by_avg_us AS top_percentile + ON ROUND(stmts.avg_timer_wait/1000000) >= top_percentile.avg_us + ORDER BY AVG_TIMER_WAIT DESC; diff --git a/scripts/sys_schema/views/p_s/x_statements_with_sorting.sql b/scripts/sys_schema/views/p_s/x_statements_with_sorting.sql new file mode 100644 index 00000000..a168d19d --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_statements_with_sorting.sql @@ -0,0 +1,73 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$statements_with_sorting +-- +-- Lists all normalized statements that have done sorts, +-- ordered by total_latency descending. +-- +-- mysql> select * from x$statements_with_sorting\G +-- *************************** 1. row *************************** +-- query: SELECT * FROM `schema_object_overview` SELECT `information_schema` . `routines` . `ROUTINE_SCHEMA` AS ... truncated +-- db: sys +-- exec_count: 2 +-- total_latency: 16751388791000 +-- sort_merge_passes: 0 +-- avg_sort_merges: 0 +-- sorts_using_scans: 12 +-- sort_using_range: 0 +-- rows_sorted: 168 +-- avg_rows_sorted: 84 +-- first_seen: 2014-03-07 13:13:41 +-- last_seen: 2014-03-07 13:13:48 +-- digest: 54f9bd520f0bbf15db0c2ed93386bec9 +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$statements_with_sorting ( + query, + db, + exec_count, + total_latency, + sort_merge_passes, + avg_sort_merges, + sorts_using_scans, + sort_using_range, + rows_sorted, + avg_rows_sorted, + first_seen, + last_seen, + digest +) AS +SELECT DIGEST_TEXT AS query, + SCHEMA_NAME db, + COUNT_STAR AS exec_count, + SUM_TIMER_WAIT AS total_latency, + SUM_SORT_MERGE_PASSES AS sort_merge_passes, + ROUND(IFNULL(SUM_SORT_MERGE_PASSES / NULLIF(COUNT_STAR, 0), 0)) AS avg_sort_merges, + SUM_SORT_SCAN AS sorts_using_scans, + SUM_SORT_RANGE AS sort_using_range, + SUM_SORT_ROWS AS rows_sorted, + ROUND(IFNULL(SUM_SORT_ROWS / NULLIF(COUNT_STAR, 0), 0)) AS avg_rows_sorted, + FIRST_SEEN as first_seen, + LAST_SEEN as last_seen, + DIGEST AS digest + FROM performance_schema.events_statements_summary_by_digest + WHERE SUM_SORT_ROWS > 0 + ORDER BY SUM_TIMER_WAIT DESC; diff --git a/scripts/sys_schema/views/p_s/x_statements_with_temp_tables.sql b/scripts/sys_schema/views/p_s/x_statements_with_temp_tables.sql new file mode 100644 index 00000000..d8f5fa2e --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_statements_with_temp_tables.sql @@ -0,0 +1,68 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$statements_with_temp_tables +-- +-- Lists all normalized statements that use temporary tables +-- ordered by number of on disk temporary tables descending first, +-- then by the number of memory tables. +-- +-- mysql> select * from x$statements_with_temp_tables limit 1\G +-- *************************** 1. row *************************** +-- query: SELECT * FROM `schema_object_overview` SELECT `information_schema` . `routines` . `ROUTINE_SCHEMA` AS `db` , ... truncated +-- db: sys +-- exec_count: 2 +-- total_latency: 16751388791000 +-- memory_tmp_tables: 378 +-- disk_tmp_tables: 66 +-- avg_tmp_tables_per_query: 189 +-- tmp_tables_to_disk_pct: 17 +-- first_seen: 2014-03-07 13:13:41 +-- last_seen: 2014-03-07 13:13:48 +-- digest: 54f9bd520f0bbf15db0c2ed93386bec9 +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$statements_with_temp_tables ( + query, + db, + exec_count, + total_latency, + memory_tmp_tables, + disk_tmp_tables, + avg_tmp_tables_per_query, + tmp_tables_to_disk_pct, + first_seen, + last_seen, + digest +) AS +SELECT DIGEST_TEXT AS query, + SCHEMA_NAME as db, + COUNT_STAR AS exec_count, + SUM_TIMER_WAIT as total_latency, + SUM_CREATED_TMP_TABLES AS memory_tmp_tables, + SUM_CREATED_TMP_DISK_TABLES AS disk_tmp_tables, + ROUND(IFNULL(SUM_CREATED_TMP_TABLES / NULLIF(COUNT_STAR, 0), 0)) AS avg_tmp_tables_per_query, + ROUND(IFNULL(SUM_CREATED_TMP_DISK_TABLES / NULLIF(SUM_CREATED_TMP_TABLES, 0), 0) * 100) AS tmp_tables_to_disk_pct, + FIRST_SEEN as first_seen, + LAST_SEEN as last_seen, + DIGEST AS digest + FROM performance_schema.events_statements_summary_by_digest + WHERE SUM_CREATED_TMP_TABLES > 0 +ORDER BY SUM_CREATED_TMP_DISK_TABLES DESC, SUM_CREATED_TMP_TABLES DESC; diff --git a/scripts/sys_schema/views/p_s/x_user_summary.sql b/scripts/sys_schema/views/p_s/x_user_summary.sql new file mode 100644 index 00000000..8c9f4b3b --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_user_summary.sql @@ -0,0 +1,60 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$user_summary +-- +-- Summarizes statement activity, file IO and connections by user. +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from x$user_summary; +-- +------+------------+-------------------+-----------------------+-------------+----------+-----------------+---------------------+-------------------+--------------+ +-- | user | statements | statement_latency | statement_avg_latency | table_scans | file_ios | file_io_latency | current_connections | total_connections | unique_hosts | +-- +------+------------+-------------------+-----------------------+-------------+----------+-----------------+---------------------+-------------------+--------------+ +-- | root | 2925 | 239577283481000 | 81906763583.2479 | 83 | 54709 | 55605611965150 | 1 | 1 | 1 | +-- +------+------------+-------------------+-----------------------+-------------+----------+-----------------+---------------------+-------------------+--------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$user_summary ( + user, + statements, + statement_latency, + statement_avg_latency, + table_scans, + file_ios, + file_io_latency, + current_connections, + total_connections, + unique_hosts +) AS +SELECT IF(accounts.user IS NULL, 'background', accounts.user) AS user, + SUM(stmt.total) AS statements, + SUM(stmt.total_latency) AS statement_latency, + IFNULL(SUM(stmt.total_latency) / NULLIF(SUM(stmt.total), 0), 0) AS statement_avg_latency, + SUM(stmt.full_scans) AS table_scans, + SUM(io.ios) AS file_ios, + SUM(io.io_latency) AS file_io_latency, + SUM(accounts.current_connections) AS current_connections, + SUM(accounts.total_connections) AS total_connections, + COUNT(DISTINCT host) AS unique_hosts + FROM performance_schema.accounts + LEFT JOIN sys.x$user_summary_by_statement_latency AS stmt ON IF(accounts.user IS NULL, 'background', accounts.user) = stmt.user + LEFT JOIN sys.x$user_summary_by_file_io AS io ON IF(accounts.user IS NULL, 'background', accounts.user) = io.user + GROUP BY IF(accounts.user IS NULL, 'background', accounts.user); diff --git a/scripts/sys_schema/views/p_s/x_user_summary_57.sql b/scripts/sys_schema/views/p_s/x_user_summary_57.sql new file mode 100644 index 00000000..9bcaa781 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_user_summary_57.sql @@ -0,0 +1,67 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$user_summary +-- +-- Summarizes statement activity and connections by user +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from x$user_summary; +-- +------+------------+-----------------+------------------+---------------------+-------------------+--------------+----------------+------------------------+ +-- | user | statements | total_latency | avg_latency | current_connections | total_connections | unique_hosts | current_memory | total_memory_allocated | +-- +------+------------+-----------------+------------------+---------------------+-------------------+--------------+----------------+------------------------+ +-- | root | 5685 | 107175100271000 | 18852260381.8821 | 1 | 1 | 1 | 1459022 | 572855680 | +-- | mark | 225 | 14489223428000 | 64396548568.8889 | 1 | 1 | 1 | 724578 | 84958286 | +-- +------+------------+-----------------+------------------+---------------------+-------------------+--------------+----------------+------------------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$user_summary ( + user, + statements, + statement_latency, + statement_avg_latency, + table_scans, + file_ios, + file_io_latency, + current_connections, + total_connections, + unique_hosts, + current_memory, + total_memory_allocated +) AS +SELECT IF(accounts.user IS NULL, 'background', accounts.user) AS user, + SUM(stmt.total) AS statements, + SUM(stmt.total_latency) AS statement_latency, + IFNULL(SUM(stmt.total_latency) / NULLIF(SUM(stmt.total), 0), 0) AS statement_avg_latency, + SUM(stmt.full_scans) AS table_scans, + SUM(io.ios) AS file_ios, + SUM(io.io_latency) AS file_io_latency, + SUM(accounts.current_connections) AS current_connections, + SUM(accounts.total_connections) AS total_connections, + COUNT(DISTINCT host) AS unique_hosts, + SUM(mem.current_allocated) AS current_memory, + SUM(mem.total_allocated) AS total_memory_allocated + FROM performance_schema.accounts + LEFT JOIN sys.x$user_summary_by_statement_latency AS stmt ON IF(accounts.user IS NULL, 'background', accounts.user) = stmt.user + LEFT JOIN sys.x$user_summary_by_file_io AS io ON IF(accounts.user IS NULL, 'background', accounts.user) = io.user + LEFT JOIN sys.x$memory_by_user_by_current_bytes mem ON IF(accounts.user IS NULL, 'background', accounts.user) = mem.user + GROUP BY IF(accounts.user IS NULL, 'background', accounts.user) + ORDER BY SUM(stmt.total_latency) DESC; diff --git a/scripts/sys_schema/views/p_s/x_user_summary_by_file_io.sql b/scripts/sys_schema/views/p_s/x_user_summary_by_file_io.sql new file mode 100644 index 00000000..0fe1f55f --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_user_summary_by_file_io.sql @@ -0,0 +1,47 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$user_summary_by_file_io +-- +-- Summarizes file IO totals per user. +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from x$user_summary_by_file_io; +-- +------------+-------+----------------+ +-- | user | ios | io_latency | +-- +------------+-------+----------------+ +-- | root | 26457 | 21579585586390 | +-- | background | 1189 | 394212617370 | +-- +------------+-------+----------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$user_summary_by_file_io ( + user, + ios, + io_latency +) AS +SELECT IF(user IS NULL, 'background', user) AS user, + SUM(count_star) AS ios, + SUM(sum_timer_wait) AS io_latency + FROM performance_schema.events_waits_summary_by_user_by_event_name + WHERE event_name LIKE 'wait/io/file/%' + GROUP BY IF(user IS NULL, 'background', user) + ORDER BY SUM(sum_timer_wait) DESC; diff --git a/scripts/sys_schema/views/p_s/x_user_summary_by_file_io_type.sql b/scripts/sys_schema/views/p_s/x_user_summary_by_file_io_type.sql new file mode 100644 index 00000000..6705ae97 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_user_summary_by_file_io_type.sql @@ -0,0 +1,66 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$user_summary_by_file_io_type +-- +-- Summarizes file IO by event type per user. +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from x$user_summary_by_file_io_type; +-- +------------+--------------------------------------+-------+---------------+--------------+ +-- | user | event_name | total | latency | max_latency | +-- +------------+--------------------------------------+-------+---------------+--------------+ +-- | background | wait/io/file/sql/FRM | 871 | 168148450470 | 18482624810 | +-- | background | wait/io/file/innodb/innodb_data_file | 173 | 129564287450 | 34087423890 | +-- | background | wait/io/file/innodb/innodb_log_file | 20 | 77525706960 | 60657475320 | +-- | background | wait/io/file/myisam/dfile | 40 | 6544493800 | 4580546230 | +-- | background | wait/io/file/mysys/charset | 3 | 4793558770 | 4713476430 | +-- | background | wait/io/file/myisam/kfile | 67 | 4384332810 | 300035450 | +-- | background | wait/io/file/sql/ERRMSG | 5 | 2717434850 | 1687316280 | +-- | background | wait/io/file/sql/pid | 3 | 266301490 | 185468920 | +-- | background | wait/io/file/sql/casetest | 5 | 246814360 | 150193030 | +-- | background | wait/io/file/sql/global_ddl_log | 2 | 21236410 | 18593640 | +-- | root | wait/io/file/sql/file_parser | 1422 | 4801104756760 | 135138518970 | +-- | root | wait/io/file/sql/FRM | 865 | 85818594810 | 9812303410 | +-- | root | wait/io/file/myisam/kfile | 1073 | 37143664870 | 15793838190 | +-- | root | wait/io/file/myisam/dfile | 2991 | 25528215700 | 5252232050 | +-- | root | wait/io/file/sql/dbopt | 20 | 1067339780 | 153073310 | +-- | root | wait/io/file/sql/misc | 4 | 59713030 | 33752810 | +-- | root | wait/io/file/archive/data | 1 | 13907530 | 13907530 | +-- +------------+--------------------------------------+-------+---------------+--------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$user_summary_by_file_io_type ( + user, + event_name, + total, + latency, + max_latency +) AS +SELECT IF(user IS NULL, 'background', user) AS user, + event_name, + count_star AS total, + sum_timer_wait AS latency, + max_timer_wait AS max_latency + FROM performance_schema.events_waits_summary_by_user_by_event_name + WHERE event_name LIKE 'wait/io/file%' + AND count_star > 0 + ORDER BY user, sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/x_user_summary_by_stages.sql b/scripts/sys_schema/views/p_s/x_user_summary_by_stages.sql new file mode 100644 index 00000000..1e94d6db --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_user_summary_by_stages.sql @@ -0,0 +1,64 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$user_summary_by_stages +-- +-- Summarizes stages by user, ordered by user and total latency per stage. +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from x$user_summary_by_stages; +-- +------+--------------------------------+-------+---------------+-------------+ +-- | user | event_name | total | total_latency | avg_latency | +-- +------+--------------------------------+-------+---------------+-------------+ +-- | root | stage/sql/Opening tables | 1114 | 71919037000 | 64559000 | +-- | root | stage/sql/Creating sort index | 5 | 2245762000 | 449152000 | +-- | root | stage/sql/init | 13 | 428798000 | 32984000 | +-- | root | stage/sql/checking permissions | 13 | 363231000 | 27940000 | +-- | root | stage/sql/freeing items | 7 | 137728000 | 19675000 | +-- | root | stage/sql/statistics | 6 | 93955000 | 15659000 | +-- | root | stage/sql/preparing | 6 | 82571000 | 13761000 | +-- | root | stage/sql/optimizing | 6 | 63338000 | 10556000 | +-- | root | stage/sql/Sending data | 6 | 53400000 | 8900000 | +-- | root | stage/sql/closing tables | 7 | 46922000 | 6703000 | +-- | root | stage/sql/System lock | 6 | 40175000 | 6695000 | +-- | root | stage/sql/query end | 7 | 31723000 | 4531000 | +-- | root | stage/sql/Sorting result | 6 | 9855000 | 1642000 | +-- | root | stage/sql/end | 6 | 9556000 | 1592000 | +-- | root | stage/sql/cleaning up | 7 | 7312000 | 1044000 | +-- | root | stage/sql/executing | 6 | 6487000 | 1081000 | +-- +------+--------------------------------+-------+---------------+-------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$user_summary_by_stages ( + user, + event_name, + total, + total_latency, + avg_latency +) AS +SELECT IF(user IS NULL, 'background', user) AS user, + event_name, + count_star AS total, + sum_timer_wait AS total_latency, + avg_timer_wait AS avg_latency + FROM performance_schema.events_stages_summary_by_user_by_event_name + WHERE sum_timer_wait != 0 + ORDER BY user, sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/x_user_summary_by_statement_latency.sql b/scripts/sys_schema/views/p_s/x_user_summary_by_statement_latency.sql new file mode 100644 index 00000000..5bc520b7 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_user_summary_by_statement_latency.sql @@ -0,0 +1,57 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$user_summary_by_statement_latency +-- +-- Summarizes overall statement statistics by user. +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from x$user_summary_by_statement_latency; +-- +------+-------+-----------------+---------------+---------------+-----------+---------------+---------------+------------+ +-- | user | total | total_latency | max_latency | lock_latency | rows_sent | rows_examined | rows_affected | full_scans | +-- +------+-------+-----------------+---------------+---------------+-----------+---------------+---------------+------------+ +-- | root | 3382 | 129134039432000 | 1483246743000 | 1069831000000 | 1152 | 94286 | 150 | 92 | +-- +------+-------+-----------------+---------------+---------------+-----------+---------------+---------------+------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$user_summary_by_statement_latency ( + user, + total, + total_latency, + max_latency, + lock_latency, + rows_sent, + rows_examined, + rows_affected, + full_scans +) AS +SELECT IF(user IS NULL, 'background', user) AS user, + SUM(count_star) AS total, + SUM(sum_timer_wait) AS total_latency, + SUM(max_timer_wait) AS max_latency, + SUM(sum_lock_time) AS lock_latency, + SUM(sum_rows_sent) AS rows_sent, + SUM(sum_rows_examined) AS rows_examined, + SUM(sum_rows_affected) AS rows_affected, + SUM(sum_no_index_used) + SUM(sum_no_good_index_used) AS full_scans + FROM performance_schema.events_statements_summary_by_user_by_event_name + GROUP BY IF(user IS NULL, 'background', user) + ORDER BY SUM(sum_timer_wait) DESC; diff --git a/scripts/sys_schema/views/p_s/x_user_summary_by_statement_type.sql b/scripts/sys_schema/views/p_s/x_user_summary_by_statement_type.sql new file mode 100644 index 00000000..e2c2c5e7 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_user_summary_by_statement_type.sql @@ -0,0 +1,64 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$user_summary_by_statement_type +-- +-- Summarizes the types of statements executed by each user. +-- +-- When the user found is NULL, it is assumed to be a "background" thread. +-- +-- mysql> select * from x$user_summary_by_statement_type; +-- +------+----------------------+--------+-----------------+----------------+----------------+-----------+---------------+---------------+------------+ +-- | user | statement | total | total_latency | max_latency | lock_latency | rows_sent | rows_examined | rows_affected | full_scans | +-- +------+----------------------+--------+-----------------+----------------+----------------+-----------+---------------+---------------+------------+ +-- | root | create_view | 2110 | 312717366332000 | 463578029000 | 1432355000000 | 0 | 0 | 0 | 0 | +-- | root | select | 177 | 41115690428000 | 28827579292000 | 858709000000 | 5254 | 157437 | 0 | 83 | +-- | root | stmt | 6645 | 15305389969000 | 491780297000 | 0 | 0 | 0 | 7951 | 0 | +-- | root | call_procedure | 17 | 4783806053000 | 1016083397000 | 37936000000 | 0 | 0 | 19 | 0 | +-- | root | create_table | 19 | 3035120946000 | 431706815000 | 0 | 0 | 0 | 0 | 0 | +-- ... +-- +------+----------------------+--------+-----------------+----------------+----------------+-----------+---------------+---------------+------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$user_summary_by_statement_type ( + user, + statement, + total, + total_latency, + max_latency, + lock_latency, + rows_sent, + rows_examined, + rows_affected, + full_scans +) AS +SELECT IF(user IS NULL, 'background', user) AS user, + SUBSTRING_INDEX(event_name, '/', -1) AS statement, + count_star AS total, + sum_timer_wait AS total_latency, + max_timer_wait AS max_latency, + sum_lock_time AS lock_latency, + sum_rows_sent AS rows_sent, + sum_rows_examined AS rows_examined, + sum_rows_affected AS rows_affected, + sum_no_index_used + sum_no_good_index_used AS full_scans + FROM performance_schema.events_statements_summary_by_user_by_event_name + WHERE sum_timer_wait != 0 + ORDER BY user, sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/x_wait_classes_global_by_avg_latency.sql b/scripts/sys_schema/views/p_s/x_wait_classes_global_by_avg_latency.sql new file mode 100644 index 00000000..48dabe51 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_wait_classes_global_by_avg_latency.sql @@ -0,0 +1,57 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$wait_classes_global_by_avg_latency +-- +-- Lists the top wait classes by average latency, ignoring idle (this may be very large). +-- +-- mysql> select * from x$wait_classes_global_by_avg_latency; +-- +-------------------+---------+-------------------+-------------+--------------------+------------------+ +-- | event_class | total | total_latency | min_latency | avg_latency | max_latency | +-- +-------------------+---------+-------------------+-------------+--------------------+------------------+ +-- | idle | 4331 | 16044682716000000 | 2000000 | 3704613880397.1369 | 1593550454000000 | +-- | wait/io/file | 23037 | 20856702551880 | 0 | 905356711.0249 | 350700491310 | +-- | wait/io/table | 224924 | 719670285750 | 116870 | 3199615.3623 | 208579012460 | +-- | wait/lock/table | 6972 | 3674766030 | 109330 | 527074.8752 | 8855730 | +-- | wait/synch/rwlock | 11916 | 1273279800 | 37700 | 106854.6324 | 6838780 | +-- | wait/synch/mutex | 1031881 | 80464286240 | 56550 | 77978.2613 | 2590408470 | +-- +-------------------+---------+-------------------+-------------+--------------------+------------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$wait_classes_global_by_avg_latency ( + event_class, + total, + total_latency, + min_latency, + avg_latency, + max_latency +) AS +SELECT SUBSTRING_INDEX(event_name,'/', 3) AS event_class, + SUM(COUNT_STAR) AS total, + SUM(sum_timer_wait) AS total_latency, + MIN(min_timer_wait) AS min_latency, + IFNULL(SUM(sum_timer_wait) / NULLIF(SUM(COUNT_STAR), 0), 0) AS avg_latency, + MAX(max_timer_wait) AS max_latency + FROM performance_schema.events_waits_summary_global_by_event_name + WHERE sum_timer_wait > 0 + AND event_name != 'idle' + GROUP BY event_class + ORDER BY IFNULL(SUM(sum_timer_wait) / NULLIF(SUM(COUNT_STAR), 0), 0) DESC; + diff --git a/scripts/sys_schema/views/p_s/x_wait_classes_global_by_latency.sql b/scripts/sys_schema/views/p_s/x_wait_classes_global_by_latency.sql new file mode 100644 index 00000000..c9ac5069 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_wait_classes_global_by_latency.sql @@ -0,0 +1,56 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$wait_classes_global_by_latency +-- +-- Lists the top wait classes by total latency, ignoring idle (this may be very large). +-- +-- mysql> SELECT * FROM x$wait_classes_global_by_latency; +-- +-------------------+---------+----------------+-------------+----------------+--------------+ +-- | event_class | total | total_latency | min_latency | avg_latency | max_latency | +-- +-------------------+---------+----------------+-------------+----------------+--------------+ +-- | wait/io/file | 29468 | 27100905420290 | 0 | 919672370.7170 | 350700491310 | +-- | wait/io/table | 224924 | 719670285750 | 116870 | 3199615.3623 | 208579012460 | +-- | wait/synch/mutex | 1532036 | 118515948070 | 56550 | 77358.4616 | 2590408470 | +-- | wait/io/socket | 1193 | 10677541030 | 0 | 8950160.1257 | 287760330 | +-- | wait/lock/table | 6972 | 3674766030 | 109330 | 527074.8752 | 8855730 | +-- | wait/synch/rwlock | 13646 | 1579833580 | 37700 | 115772.6499 | 28293850 | +-- +-------------------+---------+----------------+-------------+----------------+--------------+ +-- + +CREATE OR REPLACE + ALGORITHM = TEMPTABLE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$wait_classes_global_by_latency ( + event_class, + total, + total_latency, + min_latency, + avg_latency, + max_latency +) AS +SELECT SUBSTRING_INDEX(event_name,'/', 3) AS event_class, + SUM(COUNT_STAR) AS total, + SUM(sum_timer_wait) AS total_latency, + MIN(min_timer_wait) AS min_latency, + IFNULL(SUM(sum_timer_wait) / NULLIF(SUM(COUNT_STAR), 0), 0) AS avg_latency, + MAX(max_timer_wait) AS max_latency + FROM performance_schema.events_waits_summary_global_by_event_name + WHERE sum_timer_wait > 0 + AND event_name != 'idle' + GROUP BY SUBSTRING_INDEX(event_name,'/', 3) + ORDER BY SUM(sum_timer_wait) DESC; diff --git a/scripts/sys_schema/views/p_s/x_waits_by_host_by_latency.sql b/scripts/sys_schema/views/p_s/x_waits_by_host_by_latency.sql new file mode 100644 index 00000000..c6f55f90 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_waits_by_host_by_latency.sql @@ -0,0 +1,54 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: waits_by_host_by_latency +-- +-- Lists the top wait events per host by their total latency, ignoring idle (this may be very large). +-- +-- mysql> select * from sys.x$waits_by_host_by_latency where host != 'background' limit 5; +-- +-----------+------------------------------+-------+----------------+-------------+--------------+ +-- | host | event | total | total_latency | avg_latency | max_latency | +-- +-----------+------------------------------+-------+----------------+-------------+--------------+ +-- | localhost | wait/io/file/sql/file_parser | 1388 | 14502657551590 | 10448600240 | 357364034170 | +-- | localhost | wait/io/file/sql/FRM | 167 | 361060236420 | 2162037319 | 75331088170 | +-- | localhost | wait/io/file/myisam/kfile | 410 | 322294755250 | 786084585 | 65978227120 | +-- | localhost | wait/io/file/myisam/dfile | 1327 | 307435262550 | 231676679 | 37162925800 | +-- | localhost | wait/io/file/sql/dbopt | 89 | 180341976360 | 2026314303 | 63405386850 | +-- +-----------+------------------------------+-------+----------------+-------------+--------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$waits_by_host_by_latency ( + host, + event, + total, + total_latency, + avg_latency, + max_latency +) AS +SELECT IF(host IS NULL, 'background', host) AS host, + event_name AS event, + count_star AS total, + sum_timer_wait AS total_latency, + avg_timer_wait AS avg_latency, + max_timer_wait AS max_latency + FROM performance_schema.events_waits_summary_by_host_by_event_name + WHERE event_name != 'idle' + AND sum_timer_wait > 0 + ORDER BY host, sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/x_waits_by_user_by_latency.sql b/scripts/sys_schema/views/p_s/x_waits_by_user_by_latency.sql new file mode 100644 index 00000000..42f42859 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_waits_by_user_by_latency.sql @@ -0,0 +1,65 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$waits_by_user_by_latency +-- +-- Lists the top wait events per user by their total latency, ignoring idle (this may be very large). +-- +-- mysql> select * from x$waits_by_user_by_latency; +-- +------+-----------------------------------------------------+--------+----------------+-------------+--------------+ +-- | user | event | total | total_latency | avg_latency | max_latency | +-- +------+-----------------------------------------------------+--------+----------------+-------------+--------------+ +-- | root | wait/io/file/sql/file_parser | 13745 | 60462025415480 | 4398837508 | 231881092170 | +-- | root | wait/io/file/innodb/innodb_data_file | 4699 | 3023248450820 | 643381037 | 46928334180 | +-- | root | wait/io/file/sql/FRM | 11467 | 2600067790580 | 226743257 | 61718277920 | +-- | root | wait/io/file/myisam/dfile | 26776 | 746701506200 | 27886690 | 308785046960 | +-- | root | wait/io/file/myisam/kfile | 7126 | 462661061590 | 64925432 | 88756408780 | +-- | root | wait/io/file/sql/dbopt | 179 | 137577467690 | 768589146 | 15457199810 | +-- | root | wait/io/file/csv/metadata | 8 | 86599791590 | 10824973666 | 50322529270 | +-- | root | wait/synch/mutex/mysys/IO_CACHE::append_buffer_lock | 798080 | 66461175430 | 82940 | 161028010 | +-- | root | wait/io/file/sql/binlog | 19 | 49110632610 | 2584770058 | 9400449760 | +-- | root | wait/io/file/sql/misc | 26 | 22380676630 | 860795052 | 15298475270 | +-- | root | wait/io/file/csv/data | 4 | 297460540 | 74365135 | 111931300 | +-- | root | wait/synch/rwlock/sql/MDL_lock::rwlock | 944 | 287862120 | 304616 | 874640 | +-- | root | wait/io/file/archive/data | 4 | 82713800 | 20678450 | 40738620 | +-- | root | wait/synch/mutex/myisam/MYISAM_SHARE::intern_lock | 60 | 12211030 | 203203 | 512720 | +-- | root | wait/synch/mutex/innodb/trx_mutex | 81 | 5926440 | 73138 | 252590 | +-- +------+-----------------------------------------------------+--------+----------------+-------------+--------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$waits_by_user_by_latency ( + user, + event, + total, + total_latency, + avg_latency, + max_latency +) AS +SELECT IF(user IS NULL, 'background', user) AS user, + event_name AS event, + count_star AS total, + sum_timer_wait AS total_latency, + avg_timer_wait AS avg_latency, + max_timer_wait AS max_latency + FROM performance_schema.events_waits_summary_by_user_by_event_name + WHERE event_name != 'idle' + AND user IS NOT NULL + AND sum_timer_wait > 0 + ORDER BY user, sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/p_s/x_waits_global_by_latency.sql b/scripts/sys_schema/views/p_s/x_waits_global_by_latency.sql new file mode 100644 index 00000000..9b3ff819 --- /dev/null +++ b/scripts/sys_schema/views/p_s/x_waits_global_by_latency.sql @@ -0,0 +1,52 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: x$waits_global_by_latency +-- +-- Lists the top wait events by their total latency, ignoring idle (this may be very large). +-- +-- mysql> select * from x$waits_global_by_latency limit 5; +-- +--------------------------------------+-------+---------------+-------------+--------------+ +-- | event | total | total_latency | avg_latency | max_latency | +-- +--------------------------------------+-------+---------------+-------------+--------------+ +-- | wait/io/file/sql/file_parser | 679 | 3536136351540 | 5207858773 | 129860439800 | +-- | wait/io/file/innodb/innodb_data_file | 195 | 848170566100 | 4349592637 | 350700491310 | +-- | wait/io/file/sql/FRM | 1355 | 400428476500 | 295518990 | 44823120940 | +-- | wait/io/file/innodb/innodb_log_file | 20 | 54298899070 | 2714944765 | 30108124800 | +-- | wait/io/file/mysys/charset | 3 | 24244722970 | 8081574072 | 24151547420 | +-- +--------------------------------------+-------+---------------+-------------+--------------+ +-- + +CREATE OR REPLACE + ALGORITHM = MERGE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW x$waits_global_by_latency ( + events, + total, + total_latency, + avg_latency, + max_latency +) AS +SELECT event_name AS event, + count_star AS total, + sum_timer_wait AS total_latency, + avg_timer_wait AS avg_latency, + max_timer_wait AS max_latency + FROM performance_schema.events_waits_summary_global_by_event_name + WHERE event_name != 'idle' + AND sum_timer_wait > 0 + ORDER BY sum_timer_wait DESC; diff --git a/scripts/sys_schema/views/version.sql b/scripts/sys_schema/views/version.sql new file mode 100644 index 00000000..a25b5315 --- /dev/null +++ b/scripts/sys_schema/views/version.sql @@ -0,0 +1,37 @@ +-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; version 2 of the License. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +-- +-- View: version +-- +-- Shows the sys schema and mysql versions +-- +-- mysql> select * from sys.version; +-- +-------------+---------------+ +-- | sys_version | mysql_version | +-- +-------------+---------------+ +-- | 1.5.0 | 5.7.8-rc | +-- +-------------+---------------+ +-- + +CREATE OR REPLACE + DEFINER = 'mariadb.sys'@'localhost' + SQL SECURITY INVOKER +VIEW version ( + sys_version, + mysql_version +) AS +SELECT '1.5.1' AS sys_version, + version() AS mysql_version;
\ No newline at end of file diff --git a/scripts/wsrep_sst_backup.sh b/scripts/wsrep_sst_backup.sh new file mode 100644 index 00000000..6f8c6581 --- /dev/null +++ b/scripts/wsrep_sst_backup.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash + +set -ue + +# Copyright (C) 2017-2021 MariaDB +# Copyright (C) 2010-2014 Codership Oy +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1335 USA. + +# This is a reference script for rsync-based state snapshot transfer + +RSYNC_REAL_PID=0 # rsync process id +STUNNEL_REAL_PID=0 # stunnel process id + +OS="$(uname)" +[ "$OS" = 'Darwin' ] && export -n LD_LIBRARY_PATH + +# Setting the path for lsof on CentOS +export PATH="/usr/sbin:/sbin:$PATH" + +. $(dirname "$0")/wsrep_sst_common + +MAGIC_FILE="$WSREP_SST_OPT_DATA/backup_sst_complete" +rm -rf "$MAGIC_FILE" + +WSREP_LOG_DIR=${WSREP_LOG_DIR:-""} +# if WSREP_LOG_DIR env. variable is not set, try to get it from my.cnf +if [ -z "$WSREP_LOG_DIR" ]; then + WSREP_LOG_DIR=$(parse_cnf mysqld innodb-log-group-home-dir '') +fi + +if [ -n "$WSREP_LOG_DIR" ]; then + # handle both relative and absolute paths + WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; mkdir -p "$WSREP_LOG_DIR"; cd $WSREP_LOG_DIR; pwd -P) +else + # default to datadir + WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; pwd -P) +fi + +if [ "$WSREP_SST_OPT_ROLE" = 'donor' ] +then + + [ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" + + RC=0 + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ]; then + + FLUSHED="$WSREP_SST_OPT_DATA/tables_flushed" + ERROR="$WSREP_SST_OPT_DATA/sst_error" + + [ -f "$FLUSHED" ] && rm -f "$FLUSHED" + [ -f "$ERROR" ] && rm -f "$ERROR" + + echo "flush tables" + + # Wait for : + # (a) Tables to be flushed, AND + # (b) Cluster state ID & wsrep_gtid_domain_id to be written to the file, OR + # (c) ERROR file, in case flush tables operation failed. + + while [ ! -r "$FLUSHED" ] || \ + ! grep -q -F ':' -- "$FLUSHED" + do + # Check whether ERROR file exists. + if [ -f "$ERROR" ]; then + # Flush tables operation failed. + rm -f "$ERROR" + exit 255 + fi + sleep 0.2 + done + + STATE=$(cat "$FLUSHED") + rm -f "$FLUSHED" + + + else # BYPASS + + wsrep_log_info "Bypassing state dump." + fi + + echo 'continue' # now server can resume updating data + + echo "$STATE" > "$MAGIC_FILE" + + echo "done $STATE" + +else # joiner + + wsrep_log_error "Unsupported role: '$WSREP_SST_OPT_ROLE'" + exit 22 # EINVAL + +fi + +wsrep_log_info "$WSREP_METHOD $WSREP_TRANSFER_TYPE completed on $WSREP_SST_OPT_ROLE" +exit 0 diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh new file mode 100644 index 00000000..bf96f79e --- /dev/null +++ b/scripts/wsrep_sst_common.sh @@ -0,0 +1,1586 @@ +# Copyright (C) 2017-2022 MariaDB +# Copyright (C) 2012-2015 Codership Oy +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1335 USA. + +# This is a common command line parser to be sourced by other SST scripts + +trap 'exit 32' HUP PIPE +trap 'exit 3' INT QUIT TERM + +# Setting the path for some utilities on CentOS +export PATH="$PATH:/usr/sbin:/usr/bin:/sbin:/bin" + +trim_string() +{ + if [ -n "$BASH_VERSION" ]; then + local pattern="[![:space:]${2:-}]" + local x="${1#*$pattern}" + local z=${#1} + x=${#x} + if [ $x -ne $z ]; then + local y="${1%$pattern*}" + y=${#y} + x=$(( z-x-1 )) + y=$(( y-x+1 )) + printf '%s' "${1:$x:$y}" + else + printf '' + fi + else + local pattern="[[:space:]${2:-}]" + echo "$1" | sed -E "s/^$pattern+|$pattern+\$//g" + fi +} + +trim_dir() +{ + if [ -n "$BASH_VERSION" ]; then + local pattern="![:space:]${2:-}" + local x="${1#*[$pattern]}" + local z=${#1} + x=${#x} + if [ $x -ne $z ]; then + local y="${1%[$pattern/]*}" + y=${#y} + x=$(( z-x-1 )) + y=$(( y-x+1 )) + x="${1:$x:$y}" + [ -z "$x" ] && x='.' + printf '%s' "$x" + else + printf '' + fi + else + local pattern="[:space:]${2:-}" + local x=$(echo "$1" | sed -E "s/^[$pattern]+|[$pattern/]+\$//g") + if [ -n "$x" ]; then + echo "$x" + elif "${1#*/}" != "$1"; then + echo '.' + else + echo '' + fi + fi +} + +trim_right() +{ + if [ -n "$BASH_VERSION" ]; then + local pattern="[![:space:]${2:-}]" + local z=${#1} + local y="${1%$pattern*}" + y=${#y} + if [ $y -ne $z ]; then + y=$(( y+1 )) + printf '%s' "${1:0:$y}" + else + printf '' + fi + else + local pattern="[[:space:]${2:-}]" + echo "$1" | sed -E "s/$pattern+\$//g" + fi +} + +to_minuses() +{ + local x="$1" + local t="${1#*_}" + local r="" + while [ "$t" != "$x" ]; do + r="$r${x%%_*}-" + x="$t" + t="${t#*_}" + done + if [ -n "$BASH_VERSION" ]; then + printf '%s' "$r$x" + else + echo "$r$x" + fi +} + +WSREP_SST_OPT_BYPASS=0 +WSREP_SST_OPT_PROGRESS=0 +WSREP_SST_OPT_BINLOG="" +WSREP_SST_OPT_BINLOG_INDEX="" +WSREP_SST_OPT_LOG_BASENAME="" +WSREP_SST_OPT_DATA="" +WSREP_SST_OPT_AUTH="${WSREP_SST_OPT_AUTH:-}" +WSREP_SST_OPT_USER="${WSREP_SST_OPT_USER:-}" +WSREP_SST_OPT_PSWD="${WSREP_SST_OPT_PSWD:-}" +WSREP_SST_OPT_REMOTE_AUTH="${WSREP_SST_OPT_REMOTE_AUTH:-}" +WSREP_SST_OPT_DEFAULT="" +WSREP_SST_OPT_DEFAULTS="" +WSREP_SST_OPT_EXTRA_DEFAULT="" +WSREP_SST_OPT_EXTRA_DEFAULTS="" +WSREP_SST_OPT_SUFFIX_DEFAULT="" +WSREP_SST_OPT_SUFFIX_VALUE="" +WSREP_SST_OPT_MYSQLD="" +WSREP_SST_OPT_PORT="" +WSREP_SST_OPT_ADDR="" +WSREP_SST_OPT_ADDR_PORT="" +WSREP_SST_OPT_HOST="" +WSREP_SST_OPT_HOST_UNESCAPED="" +ARIA_LOG_DIR="" +INNODB_DATA_HOME_DIR=$(trim_dir "${INNODB_DATA_HOME_DIR:-}") +INNODB_LOG_GROUP_HOME=$(trim_dir "${INNODB_LOG_GROUP_HOME:-}") +INNODB_UNDO_DIR=$(trim_dir "${INNODB_UNDO_DIR:-}") +INNODB_BUFFER_POOL="" +INNODB_FORCE_RECOVERY="" +INNOEXTRA="" + +while [ $# -gt 0 ]; do +case "$1" in + '--address') + WSREP_SST_OPT_ADDR=$(trim_string "$2") + # + # Break address string into host:port/path parts + # + case "$WSREP_SST_OPT_ADDR" in + \[*) + # IPv6 + # Remove the starting and ending square brackets, if present: + addr="${WSREP_SST_OPT_ADDR#\[}" + addr=$(trim_right "${addr%%\]*}") + # Some utilities and subsequent code require an address + # without square brackets: + readonly WSREP_SST_OPT_HOST_UNESCAPED="$addr" + # Square brackets are needed in most cases: + readonly WSREP_SST_OPT_HOST="[$addr]" + # Mark this address as IPv6: + readonly WSREP_SST_OPT_HOST_IPv6=1 + # Let's remove the leading part that contains the host address: + remain="${WSREP_SST_OPT_ADDR#*\]}" + ;; + *) + addr=$(trim_right "${WSREP_SST_OPT_ADDR%%[:/]*}") + readonly WSREP_SST_OPT_HOST="$addr" + readonly WSREP_SST_OPT_HOST_UNESCAPED="$addr" + readonly WSREP_SST_OPT_HOST_IPv6=0 + # Let's remove the leading part that contains the host address: + remain="${WSREP_SST_OPT_ADDR#*[:/]}" + ;; + esac + # If there is nothing but the address, then the remainder is empty: + [ "$remain" = "$WSREP_SST_OPT_ADDR" ] && remain="" + # Let's remove the ":" character that separates the port number + # from the hostname: + remain="${remain#:}" + # Extract the port number from the address - all characters + # up to "/" (if present): + WSREP_SST_OPT_ADDR_PORT="${remain%%/*}" + # If the "/" character is present, then the path is not empty: + if [ "$WSREP_SST_OPT_ADDR_PORT" != "$remain" ]; then + # This operation removes everything up to the "/" character, + # effectively removing the port number from the string: + readonly WSREP_SST_OPT_PATH="${remain#*/}" + else + readonly WSREP_SST_OPT_PATH="" + fi + WSREP_SST_OPT_ADDR_PORT=$(trim_right "$WSREP_SST_OPT_ADDR_PORT") + # Remove the module name part from the string, which ends with "/": + remain="${WSREP_SST_OPT_PATH#*/}" + # This operation removes the tail after the very first occurrence + # of the "/" character, inclusively: + readonly WSREP_SST_OPT_MODULE=$(trim_right "${WSREP_SST_OPT_PATH%%/*}") + # If there is one more "/" in the string, then everything before + # it will be the LSN, otherwise the LSN is empty: + if [ "$remain" != "$WSREP_SST_OPT_PATH" ]; then + # Extract the part that matches the LSN by removing all + # characters starting from the very first "/": + readonly WSREP_SST_OPT_LSN=$(trim_right "${remain%%/*}") + # Exctract everything after the first occurrence of + # the "/" character in the string: + source="$remain" + remain="${remain#*/}" + # If the remainder does not match the original string, + # then there is something else (the version number in + # our case): + if [ "$remain" != "$source" ]; then + # Let's extract the version number by removing the tail + # after the very first occurence of the "/" character + # (inclusively): + readonly WSREP_SST_OPT_SST_VER=$(trim_right "${remain%%/*}") + else + readonly WSREP_SST_OPT_SST_VER="" + fi + else + readonly WSREP_SST_OPT_LSN="" + readonly WSREP_SST_OPT_SST_VER="" + fi + shift + ;; + '--bypass') + readonly WSREP_SST_OPT_BYPASS=1 + ;; + '--progress') + readonly WSREP_SST_OPT_PROGRESS=$(( $2 )) + shift + ;; + '--datadir') + # Let's remove the trailing slash: + readonly WSREP_SST_OPT_DATA=$(trim_dir "$2") + shift + ;; + '--aria-log-dir-path') + # Let's remove the trailing slash: + readonly ARIA_LOG_DIR=$(trim_dir "$2") + shift + ;; + '--innodb-data-home-dir') + # Let's remove the trailing slash: + readonly INNODB_DATA_HOME_DIR=$(trim_dir "$2") + shift + ;; + '--innodb-log-group-home-dir') + # Let's remove the trailing slash: + readonly INNODB_LOG_GROUP_HOME=$(trim_dir "$2") + shift + ;; + '--innodb-undo-directory') + # Let's remove the trailing slash: + readonly INNODB_UNDO_DIR=$(trim_dir "$2") + shift + ;; + '--innodb-buffer-pool-filename') + readonly INNODB_BUFFER_POOL=$(trim_string "$2") + shift + ;; + '--defaults-file') + file=$(trim_string "$2") + readonly WSREP_SST_OPT_DEFAULT="$1=$file" + readonly WSREP_SST_OPT_DEFAULTS="$1='$file'" + shift + ;; + '--defaults-extra-file') + file=$(trim_string "$2") + readonly WSREP_SST_OPT_EXTRA_DEFAULT="$1=$file" + readonly WSREP_SST_OPT_EXTRA_DEFAULTS="$1='$file'" + shift + ;; + '--defaults-group-suffix') + suffix=$(trim_string "$2") + readonly WSREP_SST_OPT_SUFFIX_DEFAULT="$1=$suffix" + readonly WSREP_SST_OPT_SUFFIX_VALUE="$suffix" + shift + ;; + '--host') + addr=$(trim_string "$2") + case "$addr" in + \[*) + # IPv6 + # Remove the starting and ending square brackets, if present: + addr="${addr#\[}" + addr=$(trim_right "${addr%%\]*}") + # Some utilities and subsequent code require an address + # without square brackets: + readonly WSREP_SST_OPT_HOST_UNESCAPED="$addr" + # Square brackets are needed in most cases: + readonly WSREP_SST_OPT_HOST="[$addr]" + # Mark this address as IPv6: + readonly WSREP_SST_OPT_HOST_IPv6=1 + ;; + *) + readonly WSREP_SST_OPT_HOST="$addr" + readonly WSREP_SST_OPT_HOST_UNESCAPED="$addr" + readonly WSREP_SST_OPT_HOST_IPv6=0 + ;; + esac + WSREP_SST_OPT_ADDR="$addr" + shift + ;; + '--local-port') + readonly WSREP_SST_OPT_LPORT=$(( $2 )) + shift + ;; + '--parent') + readonly WSREP_SST_OPT_PARENT=$(( $2 )) + shift + ;; + '--password') + WSREP_SST_OPT_PSWD="$2" + shift + ;; + '--port') + readonly WSREP_SST_OPT_PORT=$(( $2 )) + shift + ;; + '--role') + readonly WSREP_SST_OPT_ROLE=$(trim_string "$2") + shift + ;; + '--socket') + readonly WSREP_SST_OPT_SOCKET=$(trim_string "$2") + shift + ;; + '--user') + WSREP_SST_OPT_USER="$2" + shift + ;; + '--gtid') + readonly WSREP_SST_OPT_GTID=$(trim_string "$2") + shift + ;; + '--binlog'|'--log-bin') + readonly WSREP_SST_OPT_BINLOG=$(trim_string "$2") + shift + ;; + '--binlog-index'|'--log-bin-index') + WSREP_SST_OPT_BINLOG_INDEX=$(trim_string "$2") + shift + ;; + '--log-basename') + readonly WSREP_SST_OPT_LOG_BASENAME=$(trim_string "$2") + shift + ;; + '--gtid-domain-id') + readonly WSREP_SST_OPT_GTID_DOMAIN_ID=$(trim_string "$2") + shift + ;; + '--mysqld-args') + original_cmd="" + shift + cmd_tail=0 + while [ $# -gt 0 ]; do + lname="${1#--}" + # "--" is interpreted as the end of the list of options: + if [ -z "$lname" ]; then + shift + if [ $# -gt 0 ]; then + # copy "--" to the output string: + original_cmd="$original_cmd --" + # All other arguments must be copied unchanged: + while [ $# -gt 0 ]; do + original_cmd="$original_cmd '$1'" + shift + done + fi + break + fi + # Make sure the argument does not start with "--", otherwise it + # is a long option, which is processed after this "if": + if [ "$lname" = "$1" ]; then + # Check if the argument is the short option or the short + # options list, starting with "-": + options="${1#-}" + if [ "$options" != "$1" -a -n "$options" ]; then + slist="" + while [ -n "$options" ]; do + # Let's separate the first character as the current + # option name: + if [ -n "$BASH_VERSION" ]; then + option="${options:0:1}" + else + # If it's not bash, then we need to use slow + # external utilities: + option=$(echo "$options" | cut -c1) + fi + # And the subsequent characters consider option value: + value="" + if [ ${#options} -gt 0 ]; then + value="${options#?}" + fi + # Check for options without argument: + if [ "$option" != '?' -a \ + "$option" != 'a' -a \ + "$option" != 's' -a \ + "$option" != 'v' ] + then + # If the option value is absent, then check + # the following argument: + if [ -z "$value" -a $# -gt 1 ]; then + # if the next argument does not start with + # the "-" character, then next argument is + # the current option value: + if [ "${2#-}" = "$2" ]; then + shift + value="$1" + elif [ "$2" = '--' ]; then + shift + if [ $# -gt 1 ]; then + cmd_tail=1 + shift + value="$1" + fi + fi + fi + if [ "$option" = 'h' ]; then + if [ -z "$WSREP_SST_OPT_DATA" ]; then + MYSQLD_OPT_DATADIR=$(trim_dir "$value") + fi + elif [ "$option" != 'u' -a \ + "$option" != 'P' ] + then + if [ $cmd_tail -ne 0 ]; then + option="$option --" + fi + if [ -z "$value" ]; then + slist="$slist$option" + elif [ -z "$slist" ]; then + slist="$option '$value'" + else + slist="$slist -$option '$value'" + fi + break + fi + if [ $cmd_tail -ne 0 ]; then + if [ -n "$slist" ]; then + slist="$slist --" + else + slist='-' + fi + fi + break + else + slist="$slist$option" + fi + options="$value" + done + if [ -n "$slist" ]; then + original_cmd="$original_cmd -$slist" + fi + elif [ -z "$options" ]; then + # We found an minus sign without any characters after it: + original_cmd="$original_cmd -" + else + # We found a value that does not start with a minus - + # it is a positional argument or the value of previous + # option. Copy it to output string (as is): + original_cmd="$original_cmd '$1'" + fi + shift + if [ $cmd_tail -ne 0 ]; then + # All other arguments must be copied unchanged: + while [ $# -gt 0 ]; do + original_cmd="$original_cmd '$1'" + shift + done + break + fi + continue + fi + # Now we are sure that we are working with an option + # that has a "long" name, so remove all characters after + # the first equal sign: + option="${1%%=*}" + # If the option name contains underscores, then replace + # them to minuses: + if [ "${option#*_}" != "$option" ]; then + option=$(to_minuses "$option") + fi + # The "--loose-" prefix should not affect the recognition + # of the option name: + if [ "${option#--loose-}" != "$option" ]; then + option="--${option#--loose-}" + fi + # Some options just need to be removed from the list: + if [ "$option" != '--defaults-file' -a \ + "$option" != '--defaults-extra-file' -a \ + "$option" != '--defaults-group-suffix' -a \ + "$option" != '--user' -a \ + "$option" != '--port' -a \ + "$option" != '--socket' ]; then + value="${1#*=}" + if [ "$value" = "$1" ]; then + value="" + fi + # Let's fill in the variables containing important paths + # that might not have been passed through explicit parameters + # (+ removing the trailing slash in these paths). Many of these + # options are processed internally within scripts or passed + # explicitly to other programs, so we need to remove them + # from mysqld's argument list: + skip_mysqld_arg=0 + case "$option" in + '--aria-log-dir-path') + if [ -z "$ARIA_LOG_DIR" ]; then + MYSQLD_OPT_ARIA_LOG_DIR=$(trim_dir "$value") + fi + skip_mysqld_arg=1 + ;; + '--innodb-data-home-dir') + if [ -z "$INNODB_DATA_HOME_DIR" ]; then + MYSQLD_OPT_INNODB_DATA_HOME_DIR=$(trim_dir "$value") + fi + skip_mysqld_arg=1 + ;; + '--innodb-log-group-home-dir') + if [ -z "$INNODB_LOG_GROUP_HOME" ]; then + MYSQLD_OPT_INNODB_LOG_GROUP_HOME=$(trim_dir "$value") + fi + skip_mysqld_arg=1 + ;; + '--innodb-undo-directory') + if [ -z "$INNODB_UNDO_DIR" ]; then + MYSQLD_OPT_INNODB_UNDO_DIR=$(trim_dir "$value") + fi + skip_mysqld_arg=1 + ;; + '--innodb-buffer-pool-filename') + if [ -z "$INNODB_BUFFER_POOL" ]; then + MYSQLD_OPT_INNODB_BUFFER_POOL=$(trim_string "$value") + fi + skip_mysqld_arg=1 + ;; + '--innodb-force-recovery') + if [ -n "$value" -a "$value" != "0" ]; then + INNODB_FORCE_RECOVERY=$(trim_string "$value") + fi + skip_mysqld_arg=1 + ;; + '--log-bin') + if [ -z "$WSREP_SST_OPT_BINLOG" ]; then + MYSQLD_OPT_LOG_BIN=$(trim_string "$value") + fi + skip_mysqld_arg=1 + ;; + '--log-bin-index') + if [ -z "$WSREP_SST_OPT_BINLOG_INDEX" ]; then + MYSQLD_OPT_LOG_BIN_INDEX=$(trim_string "$value") + fi + skip_mysqld_arg=1 + ;; + '--log-basename') + if [ -z "$WSREP_SST_OPT_LOG_BASENAME" ]; then + MYSQLD_OPT_LOG_BASENAME=$(trim_string "$value") + fi + skip_mysqld_arg=1 + ;; + '--datadir') + if [ -z "$WSREP_SST_OPT_DATA" ]; then + MYSQLD_OPT_DATADIR=$(trim_dir "$value") + fi + skip_mysqld_arg=1 + ;; + esac + if [ $skip_mysqld_arg -eq 0 ]; then + original_cmd="$original_cmd '$1'" + fi + fi + shift + done + WSREP_SST_OPT_MYSQLD="${original_cmd# *}" + break + ;; + *) # Must be command usage + # exit 1 + ;; +esac +shift +done + +WSREP_TRANSFER_TYPE='SST' +[ $WSREP_SST_OPT_BYPASS -ne 0 ] && readonly WSREP_TRANSFER_TYPE='IST' +# Let's take the name of the current script as a base, +# removing the directory, extension and "wsrep_sst_" prefix: +WSREP_METHOD="${0##*/}" +WSREP_METHOD="${WSREP_METHOD%.*}" +readonly WSREP_METHOD="${WSREP_METHOD#wsrep_sst_}" +if [ -n "${WSREP_SST_OPT_ROLE+x}" ]; then + if [ "$WSREP_SST_OPT_ROLE" != 'donor' -a \ + "$WSREP_SST_OPT_ROLE" != 'joiner' ] + then + wsrep_log_error "Unrecognized role: '$WSREP_SST_OPT_ROLE'" + exit 22 # EINVAL + fi +else + readonly WSREP_SST_OPT_ROLE='donor' +fi + +readonly WSREP_SST_OPT_PROGRESS + +# The same argument can be present on the command line several +# times, in this case we must take its last value: +if [ -n "${MYSQLD_OPT_ARIA_LOG_DIR:-}" -a \ + -z "$ARIA_LOG_DIR" ]; then + readonly ARIA_LOG_DIR="$MYSQLD_OPT_ARIA_LOG_DIR" +fi +if [ -n "${MYSQLD_OPT_INNODB_DATA_HOME_DIR:-}" -a \ + -z "$INNODB_DATA_HOME_DIR" ]; then + readonly INNODB_DATA_HOME_DIR="$MYSQLD_OPT_INNODB_DATA_HOME_DIR" +fi +if [ -n "${MYSQLD_OPT_INNODB_LOG_GROUP_HOME:-}" -a \ + -z "$INNODB_LOG_GROUP_HOME" ]; then + readonly INNODB_LOG_GROUP_HOME="$MYSQLD_OPT_INNODB_LOG_GROUP_HOME" +fi +if [ -n "${MYSQLD_OPT_INNODB_UNDO_DIR:-}" -a \ + -z "$INNODB_UNDO_DIR" ]; then + readonly INNODB_UNDO_DIR="$MYSQLD_OPT_INNODB_UNDO_DIR" +fi +if [ -n "${MYSQLD_OPT_INNODB_BUFFER_POOL:-}" -a \ + -z "$INNODB_BUFFER_POOL" ]; then + readonly INNODB_BUFFER_POOL="$MYSQLD_OPT_INNODB_BUFFER_POOL" +fi +if [ -n "${MYSQLD_OPT_LOG_BIN:-}" -a \ + -z "$WSREP_SST_OPT_BINLOG" ]; then + readonly WSREP_SST_OPT_BINLOG="$MYSQLD_OPT_LOG_BIN" +fi +if [ -n "${MYSQLD_OPT_LOG_BIN_INDEX:-}" -a \ + -z "$WSREP_SST_OPT_BINLOG_INDEX" ]; then + WSREP_SST_OPT_BINLOG_INDEX="$MYSQLD_OPT_LOG_BIN_INDEX" +fi +if [ -n "${MYSQLD_OPT_DATADIR:-}" -a \ + -z "$WSREP_SST_OPT_DATA" ]; then + readonly WSREP_SST_OPT_DATA="$MYSQLD_OPT_DATADIR" +fi +if [ -n "${MYSQLD_OPT_LOG_BASENAME:-}" -a \ + -z "$WSREP_SST_OPT_LOG_BASENAME" ]; then + readonly WSREP_SST_OPT_LOG_BASENAME="$MYSQLD_OPT_LOG_BASENAME" +fi + +# If the --log-bin option is present without a value, then +# set WSREP_SST_OPT_BINLOG value using other arguments: +if [ -z "$WSREP_SST_OPT_BINLOG" -a -n "${MYSQLD_OPT_LOG_BIN+x}" ]; then + if [ -n "$WSREP_SST_OPT_LOG_BASENAME" ]; then + # If the WSREP_SST_OPT_BINLOG variable is not set, but + # --log-basename is present among the arguments to mysqld, + # then set WSREP_SST_OPT_BINLOG equal to the base name + # with the "-bin" suffix: + readonly WSREP_SST_OPT_BINLOG="$WSREP_SST_OPT_LOG_BASENAME-bin" + else + # Take the default name: + readonly WSREP_SST_OPT_BINLOG='mysql-bin' + fi +fi + +# Reconstructing the command line arguments that control the innodb +# and binlog options: +if [ -n "$WSREP_SST_OPT_LOG_BASENAME" ]; then + if [ -n "$WSREP_SST_OPT_MYSQLD" ]; then + WSREP_SST_OPT_MYSQLD="--log-basename='$WSREP_SST_OPT_LOG_BASENAME' $WSREP_SST_OPT_MYSQLD" + else + WSREP_SST_OPT_MYSQLD="--log-basename='$WSREP_SST_OPT_LOG_BASENAME'" + fi +fi +if [ -n "$ARIA_LOG_DIR" ]; then + INNOEXTRA="$INNOEXTRA --aria-log-dir-path='$ARIA_LOG_DIR'" +fi +if [ -n "$INNODB_DATA_HOME_DIR" ]; then + INNOEXTRA="$INNOEXTRA --innodb-data-home-dir='$INNODB_DATA_HOME_DIR'" +fi +if [ -n "$INNODB_LOG_GROUP_HOME" ]; then + INNOEXTRA="$INNOEXTRA --innodb-log-group-home-dir='$INNODB_LOG_GROUP_HOME'" +fi +if [ -n "$INNODB_UNDO_DIR" ]; then + INNOEXTRA="$INNOEXTRA --innodb-undo-directory='$INNODB_UNDO_DIR'" +fi +if [ -n "$INNODB_BUFFER_POOL" ]; then + INNOEXTRA="$INNOEXTRA --innodb-buffer-pool-filename='$INNODB_BUFFER_POOL'" +fi +if [ -n "$WSREP_SST_OPT_BINLOG" ]; then + INNOEXTRA="$INNOEXTRA --log-bin='$WSREP_SST_OPT_BINLOG'" + if [ -n "$WSREP_SST_OPT_BINLOG_INDEX" ]; then + if [ -n "$WSREP_SST_OPT_MYSQLD" ]; then + WSREP_SST_OPT_MYSQLD="--log-bin-index='$WSREP_SST_OPT_BINLOG_INDEX' $WSREP_SST_OPT_MYSQLD" + else + WSREP_SST_OPT_MYSQLD="--log-bin-index='$WSREP_SST_OPT_BINLOG_INDEX'" + fi + fi +fi + +readonly INNODB_FORCE_RECOVERY +readonly WSREP_SST_OPT_MYSQLD + +get_binlog() +{ + # if no command line argument and WSREP_SST_OPT_BINLOG is not set, + # try to get it from my.cnf: + if [ -z "$WSREP_SST_OPT_BINLOG" ]; then + WSREP_SST_OPT_BINLOG=$(parse_cnf '--mysqld' 'log-bin') + fi + # if no command line argument and WSREP_SST_OPT_BINLOG_INDEX is not set, + # try to get it from my.cnf: + if [ -z "$WSREP_SST_OPT_BINLOG_INDEX" ]; then + WSREP_SST_OPT_BINLOG_INDEX=$(parse_cnf '--mysqld' 'log-bin-index') + fi + # if no command line argument and WSREP_SST_OPT_LOG_BASENAME is not set, + # then try to get it from my.cnf: + if [ -z "$WSREP_SST_OPT_LOG_BASENAME" ]; then + WSREP_SST_OPT_LOG_BASENAME=$(parse_cnf '--mysqld' 'log-basename') + fi + if [ -z "$WSREP_SST_OPT_BINLOG" ]; then + # If the log-bin option is specified without a parameter, + # then we need to build the name of the index file according + # to the rules described in the server documentation: + if [ $(in_config '--mysqld' 'log-bin') -ne 0 ]; then + if [ -n "$WSREP_SST_OPT_LOG_BASENAME" ]; then + # If the WSREP_SST_OPT_BINLOG variable is not set, but + # --log-basename is present among the arguments of mysqld, + # then set WSREP_SST_OPT_BINLOG equal to the base name + # with the "-bin" suffix: + readonly WSREP_SST_OPT_BINLOG="$WSREP_SST_OPT_LOG_BASENAME-bin" + else + # Take the default name: + readonly WSREP_SST_OPT_BINLOG='mysql-bin' + fi + fi + fi + if [ -n "$WSREP_SST_OPT_BINLOG" ]; then + # If the name of the index file is not specified, then we will build + # it according to the specifications for the server: + if [ -z "$WSREP_SST_OPT_BINLOG_INDEX" ]; then + if [ -n "$WSREP_SST_OPT_LOG_BASENAME" ]; then + # If the WSREP_SST_OPT_BINLOG_INDEX variable is not set, but + # --log-basename is present among the arguments of mysqld, + # then set WSREP_SST_OPT_BINLOG_INDEX equal to the base name + # with the "-bin" suffix: + readonly WSREP_SST_OPT_BINLOG_INDEX="$WSREP_SST_OPT_LOG_BASENAME-bin.index" + else + # Use the default name (note that base of this name + # is already defined above): + readonly WSREP_SST_OPT_BINLOG_INDEX="$WSREP_SST_OPT_BINLOG.index" + fi + else + # Remove all directories from the index file path: + local filename="${WSREP_SST_OPT_BINLOG_INDEX##*/}" + # Check if the index file name contains the extension: + if [ "${filename%.*}" = "$filename" ]; then + # Let's add the default extension (".index"): + readonly WSREP_SST_OPT_BINLOG_INDEX="$WSREP_SST_OPT_BINLOG_INDEX.index" + else + readonly WSREP_SST_OPT_BINLOG_INDEX + fi + fi + fi +} + +# Check the presence of the port value and, if necessary, transfer +# the port number from the address to the WSREP_SST_OPT_PORT variable +# or vice versa, and also, if necessary, substitute the missing port +# value into the address value: +if [ -n "$WSREP_SST_OPT_ADDR_PORT" ]; then + if [ -n "$WSREP_SST_OPT_PORT" ]; then + if [ "$WSREP_SST_OPT_PORT" != "$WSREP_SST_OPT_ADDR_PORT" ]; then + echo "WSREP_SST: [ERROR] port in --port=$WSREP_SST_OPT_PORT" \ + "differs from port in --address=$WSREP_SST_OPT_ADDR" >&2 + exit 2 + fi + else + # If the address contains a port number, assign it to + # the corresponding variable: + readonly WSREP_SST_OPT_PORT="$WSREP_SST_OPT_ADDR_PORT" + fi +else + # If the port is missing, take the default port: + if [ -z "$WSREP_SST_OPT_PORT" ]; then + readonly WSREP_SST_OPT_PORT=4444 + fi + WSREP_SST_OPT_ADDR_PORT="$WSREP_SST_OPT_PORT" +fi + +# Let's construct a new value for the address with the port: +sst_path="${WSREP_SST_OPT_PATH:+/}$WSREP_SST_OPT_PATH" +WSREP_SST_OPT_ADDR="$WSREP_SST_OPT_HOST:$WSREP_SST_OPT_PORT$sst_path" + +readonly WSREP_SST_OPT_ADDR +readonly WSREP_SST_OPT_ADDR_PORT + +commandex() +{ + if [ -n "$BASH_VERSION" ]; then + command -v "$1" || : + elif [ -x "$1" ]; then + echo "$1" + else + which "$1" || : + fi +} + +# try to use my_print_defaults, mysql and mysqldump that come +# with the sources (for MTR suite): +script_binary=$(dirname "$0") +SCRIPTS_DIR=$(cd "$script_binary"; pwd) +EXTRA_DIR="$SCRIPTS_DIR/../extra" +CLIENT_DIR="$SCRIPTS_DIR/../client" + +if [ -x "$CLIENT_DIR/mariadb" ]; then + MYSQL_CLIENT="$CLIENT_DIR/mariadb" +else + MYSQL_CLIENT=$(commandex 'mariadb') +fi + +if [ -x "$CLIENT_DIR/mariadb-dump" ]; then + MYSQLDUMP="$CLIENT_DIR/mariadb-dump" +else + MYSQLDUMP=$(commandex 'mariadb-dump') +fi + +wsrep_log() +{ + # echo everything to stderr so that it gets into common error log + # deliberately made to look different from the rest of the log + local readonly tst=$(date "+%Y%m%d %H:%M:%S.%N" | cut -b -21) + echo "WSREP_SST: $* ($tst)" >&2 +} + +wsrep_log_error() +{ + wsrep_log "[ERROR] $*" +} + +wsrep_log_warning() +{ + wsrep_log "[WARNING] $*" +} + +wsrep_log_info() +{ + wsrep_log "[INFO] $*" +} + +if [ -x "$SCRIPTS_DIR/my_print_defaults" ]; then + MY_PRINT_DEFAULTS="$SCRIPTS_DIR/my_print_defaults" +elif [ -x "$EXTRA_DIR/my_print_defaults" ]; then + MY_PRINT_DEFAULTS="$EXTRA_DIR/my_print_defaults" +else + MY_PRINT_DEFAULTS=$(commandex 'my_print_defaults') + if [ -z "$MY_PRINT_DEFAULTS" ]; then + wsrep_log_error "my_print_defaults not found in path" + exit 2 + fi +fi + +readonly MY_PRINT_DEFAULTS + +wsrep_defaults="$WSREP_SST_OPT_DEFAULTS" +wsrep_defaults="$wsrep_defaults${WSREP_SST_OPT_EXTRA_DEFAULTS:+ }$WSREP_SST_OPT_EXTRA_DEFAULTS" +wsrep_defaults="$wsrep_defaults${WSREP_SST_OPT_SUFFIX_DEFAULT:+ }$WSREP_SST_OPT_SUFFIX_DEFAULT" + +readonly WSREP_SST_OPT_CONF="${wsrep_defaults:+ }$wsrep_defaults" + +wsrep_defaults="$WSREP_SST_OPT_DEFAULT" +wsrep_defaults="$wsrep_defaults${WSREP_SST_OPT_EXTRA_DEFAULT:+ }$WSREP_SST_OPT_EXTRA_DEFAULT" +wsrep_defaults="$wsrep_defaults${WSREP_SST_OPT_SUFFIX_DEFAULT:+ }$WSREP_SST_OPT_SUFFIX_DEFAULT" + +readonly WSREP_SST_OPT_CONF_UNQUOTED="${wsrep_defaults:+ }$wsrep_defaults" + +# +# User can specify mariabackup specific settings that will be used during sst +# process like encryption, etc. Parse such configuration option. +# +# 1st parameter: group (config file section like sst) or +# my_print_defaults argument (like --mysqld) +# 2nd parameter: var : name of the variable in the section, e.g. server-id +# 3rd parameter: default value for the parameter +# +parse_cnf() +{ + local groups="$1" + local var="$2" + local reval="" + + # normalize the variable names specified in the .cnf file + # (user can use '_' or '-', for example, log-bin or log_bin), + # then search for the last instance of the desired variable + # and finally get the value of that variable (if the variable + # was specified several times - we use only its last instance): + + local pattern='BEGIN {OFS=FS="="} {sub(/^--loose/,"-",$0); gsub(/_/,"-",$1); if ($1=="--'"$var"'") lastval=substr($0,length($1)+2)} END {print lastval}' + + while [ -n "$groups" ]; do + # Remove the largest suffix starting with the '|' character: + local group="${groups%%\|*}" + # Remove the remainder (the group name) from the rest + # of the groups list (as if it were a prefix): + if [ "$group" != "$groups" ]; then + groups="${groups#*\|}" + else + groups="" + fi + # If the group name is the same as the "mysqld" without "--" prefix, + # then try to use it together with the group suffix: + if [ "$group" = 'mysqld' -a -n "$WSREP_SST_OPT_SUFFIX_VALUE" ]; then + reval=$("$MY_PRINT_DEFAULTS" \ + ${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \ + ${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \ + ${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \ + "mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk "$pattern") + if [ -n "$reval" ]; then + break + fi + fi + # Let's try to use the group name as it is: + reval=$("$MY_PRINT_DEFAULTS" \ + ${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \ + ${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \ + ${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \ + "$group" | awk "$pattern") + if [ -n "$reval" ]; then + break + fi + done + + # Use default if we haven't found a value: + [ -z "$reval" ] && reval="${3:-}" + + # Truncate spaces: + [ -n "$reval" ] && reval=$(trim_string "$reval") + + if [ -n "$BASH_VERSION" ]; then + printf '%s' "$reval" + else + echo "$reval" + fi +} + +# +# This function simply checks for the presence of the parameter +# in the config file, but does not return its value. It returns "1" +# (true) even if the parameter is present in the configuration file +# without a value: +# +in_config() +{ + local groups="$1" + local var="$2" + local found=0 + + # normalize the variable names specified in the .cnf file + # (user can use '_' or '-', for example, log-bin or log_bin), + # then search for the last instance(s) of the desired variable: + + local pattern='BEGIN {OFS=FS="="; found=0} {sub(/^--loose/,"-",$0); gsub(/_/,"-",$1); if ($1=="--'"$var"'") found=1} END {print found}' + + while [ -n "$groups" ]; do + # Remove the largest suffix starting with the '|' character: + local group="${groups%%\|*}" + # Remove the remainder (the group name) from the rest + # of the groups list (as if it were a prefix): + if [ "$group" != "$groups" ]; then + groups="${groups#*\|}" + else + groups="" + fi + # If the group name is the same as the "mysqld" without "--" prefix, + # then try to use it together with the group suffix: + if [ "$group" = 'mysqld' -a -n "$WSREP_SST_OPT_SUFFIX_VALUE" ]; then + found=$("$MY_PRINT_DEFAULTS" \ + ${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \ + ${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \ + ${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \ + "mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk "$pattern") + if [ $found -ne 0 ]; then + break + fi + fi + # Let's try to use the group name as it is: + found=$($MY_PRINT_DEFAULTS \ + ${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \ + ${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \ + ${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \ + "$group" | awk "$pattern") + if [ $found -ne 0 ]; then + break + fi + done + if [ -n "$BASH_VERSION" ]; then + printf '%s' $found + else + echo $found + fi +} + +wsrep_auth_not_set() +{ + [ -z "$WSREP_SST_OPT_AUTH" ] +} + +# Get rid of incorrect values resulting from substitution +# in programs external to the script: +if [ "$WSREP_SST_OPT_USER" = '(null)' ]; then + WSREP_SST_OPT_USER="" +fi +if [ "$WSREP_SST_OPT_PSWD" = '(null)' ]; then + WSREP_SST_OPT_PSWD="" +fi +if [ "$WSREP_SST_OPT_AUTH" = '(null)' ]; then + WSREP_SST_OPT_AUTH="" +fi + +# Let's read the value of the authentication string from the +# configuration file so that it does not go to the command line +# and does not appear in the ps output: +if wsrep_auth_not_set; then + WSREP_SST_OPT_AUTH=$(parse_cnf 'sst' 'wsrep-sst-auth') +fi + +# Splitting WSREP_SST_OPT_AUTH as "user:password" pair: +if ! wsrep_auth_not_set; then + # Extract username as shortest prefix up to first ':' character: + WSREP_SST_OPT_AUTH_USER="${WSREP_SST_OPT_AUTH%%:*}" + if [ -z "$WSREP_SST_OPT_USER" ]; then + # if the username is not in the command line arguments, + # set the username and password using WSREP_SST_OPT_AUTH + # from the environment: + WSREP_SST_OPT_USER="$WSREP_SST_OPT_AUTH_USER" + WSREP_SST_OPT_PSWD="${WSREP_SST_OPT_AUTH#*:}" + elif [ "$WSREP_SST_OPT_USER" = "$WSREP_SST_OPT_AUTH_USER" ]; then + # If the username in the command line arguments and in + # the environment variable are the same, set the password + # if it was not specified in the command line: + if [ -z "$WSREP_SST_OPT_PSWD" ]; then + WSREP_SST_OPT_PSWD="${WSREP_SST_OPT_AUTH#*:}" + fi + else + # The username is passed through the command line and does + # not match the username in the environment variable - ignore + # the environment and rebuild the authentication parameters: + WSREP_SST_OPT_AUTH="$WSREP_SST_OPT_USER:$WSREP_SST_OPT_PSWD" + fi +fi + +readonly WSREP_SST_OPT_USER +readonly WSREP_SST_OPT_PSWD +readonly WSREP_SST_OPT_AUTH + +if [ -n "$WSREP_SST_OPT_REMOTE_AUTH" ]; then + # Split auth string at the last ':' + readonly WSREP_SST_OPT_REMOTE_USER="${WSREP_SST_OPT_REMOTE_AUTH%%:*}" + readonly WSREP_SST_OPT_REMOTE_PSWD="${WSREP_SST_OPT_REMOTE_AUTH#*:}" +else + readonly WSREP_SST_OPT_REMOTE_USER= + readonly WSREP_SST_OPT_REMOTE_PSWD= +fi + +readonly WSREP_SST_OPT_REMOTE_AUTH + +if [ -n "$WSREP_SST_OPT_DATA" ]; then + SST_PROGRESS_FILE="$WSREP_SST_OPT_DATA/sst_in_progress" +else + SST_PROGRESS_FILE="" +fi + +wsrep_cleanup_progress_file() +{ + if [ -n "$SST_PROGRESS_FILE" -a -f "$SST_PROGRESS_FILE" ]; then + rm -f "$SST_PROGRESS_FILE" 2>/dev/null || : + fi +} + +wsrep_check_program() +{ + local prog="$1" + local cmd=$(commandex "$prog") + if [ -z "$cmd" ]; then + echo "'$prog' not found in PATH" + return 2 # no such file or directory + fi +} + +wsrep_check_programs() +{ + local ret=0 + while [ $# -gt 0 ]; do + wsrep_check_program "$1" || ret=$? + shift + done + return $ret +} + +wsrep_check_datadir() +{ + if [ -z "$WSREP_SST_OPT_DATA" ]; then + wsrep_log_error \ + "The '--datadir' parameter must be passed to the SST script" + exit 2 + fi +} + +get_openssl() +{ + # If the OPENSSL_BINARY variable is already defined, just return: + if [ -n "${OPENSSL_BINARY+x}" ]; then + return + fi + # Let's look for openssl: + OPENSSL_BINARY=$(commandex 'openssl') + if [ -z "$OPENSSL_BINARY" ]; then + OPENSSL_BINARY='/usr/bin/openssl' + if [ ! -x "$OPENSSL_BINARY" ]; then + OPENSSL_BINARY="" + fi + fi + readonly OPENSSL_BINARY +} + +# +# Generate a string equivalent to 16 random bytes +# +wsrep_gen_secret() +{ + get_openssl + if [ -n "$OPENSSL_BINARY" ]; then + "$OPENSSL_BINARY" rand -hex 16 + elif [ -n "$BASH_VERSION" ]; then + printf '%04x%04x%04x%04x%04x%04x%04x%04x' \ + $RANDOM $RANDOM $RANDOM $RANDOM \ + $RANDOM $RANDOM $RANDOM $RANDOM + elif [ -n "$(commandex cksum)" -a \ + -n "$(commandex printf)" ] + then + printf '%08x%08x%08x%08x' \ + $(head -8 /dev/urandom | cksum | cut -d ' ' -f1) \ + $(head -8 /dev/urandom | cksum | cut -d ' ' -f1) \ + $(head -8 /dev/urandom | cksum | cut -d ' ' -f1) \ + $(head -8 /dev/urandom | cksum | cut -d ' ' -f1) + else + wsrep_log_error "Unable to generate 16-byte secret" + exit 22 + fi +} + +# +# Checking if the address passed to us is local. +# If the second parameter is nonzero, then this function +# does not check for matches with local domain names: +# +is_local_ip() +{ + # Rapid recognition of the most common cases: + [ "$1" = '127.0.0.1' -o \ + "$1" = '127.0.0.2' -o \ + "$1" = 'localhost' -o \ + "$1" = '::1' ] && return 0 + # If the address starts with "127." this is probably a local + # address, but we need to clarify what follows this prefix: + if [ "${1#127.}" != "$1" ]; then + # All 127.0.0.0/8 addresses are local: + if echo "$1" | grep -q -E '^127\.[0-9]+\.[0-9]+\.[0-9]+$'; then + return 0 + fi + fi + # If the second parameter is nonzero, then we will skip + # the domain name check: + if [ "${2:-0}" -eq 0 ]; then + # We consider all the names of a given host to be local addresses: + [ "$1" = "$(hostname -s)" -o \ + "$1" = "$(hostname -f)" -o \ + "$1" = "$(hostname -d)" ] && return 0 + fi + # If the address contains anything other than digits + # and separators, it is not a local address: + [ "${1#*[!0-9.]}" != "$1" ] && \ + [ "${1#*[!0-9A-Fa-f:\[\]]}" != "$1" ] && return 1 + # Now let's check if the given address is assigned to + # one of the network cards: + local ip_util=$(commandex 'ip') + if [ -n "$ip_util" ]; then + # ip address show ouput format is " inet[6] <address>/<mask>": + "$ip_util" address show \ + | grep -o -E '^[[:space:]]*inet.?[[:space:]]+[^[:space:]]+/' \ + | grep -qw -F -- "$1/" && return 0 + else + local ifconfig_util=$(commandex 'ifconfig') + if [ -n "$ifconfig_util" ]; then + # ifconfig output format is " inet[6] <address> ...": + "$ifconfig_util" \ + | grep -o -E '^[[:space:]]*inet.?[[:space:]]+[^[:space:]]+' \ + | grep -qw -F -- "$1" && return 0 + fi + fi + return 1 +} + +check_sockets_utils() +{ + lsof_available=0 + sockstat_available=0 + ss_available=0 + + [ -n "$(commandex lsof)" ] && lsof_available=1 + [ -n "$(commandex sockstat)" ] && sockstat_available=1 + [ -n "$(commandex ss)" ] && ss_available=1 + + if [ $lsof_available -eq 0 -a \ + $sockstat_available -eq 0 -a \ + $ss_available -eq 0 ] + then + wsrep_log_error "Neither lsof, nor sockstat or ss tool was found in" \ + "the PATH. Make sure you have it installed." + exit 2 # ENOENT + fi +} + +# +# Check if the port is in the "listen" state. +# The first parameter is the PID of the process that should +# listen on the port - if it is not known, you can specify +# an empty string or zero. +# The second parameter is the port number. +# The third parameter is a list of the names of utilities +# (via "|") that can listen on this port during the state +# transfer. +# +check_port() +{ + local pid="${1:-0}" + local port="$2" + local utils="$3" + + [ $pid -le 0 ] && pid='[0-9]+' + + local rc=1 + + if [ $lsof_available -ne 0 ]; then + lsof -Pnl -i ":$port" 2>/dev/null | \ + grep -q -E "^($utils)[^[:space:]]*[[:space:]]+$pid[[:space:]].*\\(LISTEN\\)" && rc=0 + elif [ $sockstat_available -ne 0 ]; then + local opts='-p' + if [ "$OS" = 'FreeBSD' ]; then + # sockstat on FreeBSD requires the "-s" option + # to display the connection state: + opts='-sp' + fi + sockstat "$opts" "$port" 2>/dev/null | \ + grep -q -E "[[:space:]]+($utils)[^[:space:]]*[[:space:]]+$pid[[:space:]].*[[:space:]]LISTEN" && rc=0 + elif [ $ss_available -ne 0 ]; then + ss -nlpH "( sport = :$port )" 2>/dev/null | \ + grep -q -E "users:\\(.*\\(\"($utils)[^[:space:]]*\"[^)]*,pid=$pid(,[^)]*)?\\)" && rc=0 + else + wsrep_log_error "Unknown sockets utility" + exit 2 # ENOENT + fi + + return $rc +} + +# +# If the ssl_dhparams variable is already set, uses that as a source +# of dh parameters for OpenSSL. Otherwise, looks for dhparams.pem in +# the datadir, and creates it there if it can't find the file. +# +check_for_dhparams() +{ + ssl_dhparams="$DATA/dhparams.pem" + get_openssl + if [ -n "$OPENSSL_BINARY" ]; then + wsrep_log_info \ + "Could not find dhparams file, creating $ssl_dhparams" + local bug=0 + local errmsg + errmsg=$("$OPENSSL_BINARY" \ + dhparam -out "$ssl_dhparams" -dsaparam 2048 2>&1) || bug=1 + if [ $bug -ne 0 ]; then + wsrep_log_info "run: \"$OPENSSL_BINARY\" dhparam"\ + "-out \"$ssl_dhparams\" -dsaparam 2048" + wsrep_log_info "output: $errmsg" + wsrep_log_error "******** ERROR *****************************************" + wsrep_log_error "* Could not create the dhparams.pem file with OpenSSL. *" + wsrep_log_error "********************************************************" + ssl_dhparams="" + fi + else + # Rollback: if openssl is not installed, then use + # the default parameters: + ssl_dhparams="" + fi +} + +# +# Verifies that the CA file verifies the certificate. +# Doing this here lets us generate better error messages. +# +# 1st param: path to the CA file. +# 2nd param: path to the certificate. +# +verify_ca_matches_cert() +{ + local cert="$1" + local ca="$2" + local cap="$3" + + local readable=1; [ ! -r "$cert" ] && readable=0 + [ -n "$ca" -a ! -r "$ca" ] && readable=0 + [ -n "$cap" -a ! -r "$cap" ] && readable=0 + + if [ $readable -eq 0 ]; then + wsrep_log_error \ + "Both PEM file and CA file (or path) must be readable" + exit 22 + fi + + # If the openssl utility is not installed, then + # we will not do this certificate check: + get_openssl + if [ -z "$OPENSSL_BINARY" ]; then + wsrep_log_info "openssl utility not found" + return + fi + + local not_match=0 + local errmsg + errmsg=$("$OPENSSL_BINARY" verify -verbose \ + ${ca:+ -CAfile} ${ca:+ "$ca"} \ + ${cap:+ -CApath} ${cap:+ "$cap"} \ + "$cert" 2>&1) || not_match=1 + + if [ $not_match -eq 1 ]; then + wsrep_log_info "run: \"$OPENSSL_BINARY\" verify -verbose${ca:+ -CAfile \"$ca\"}${cap:+ -CApath \"$cap\"} \"$cert\"" + wsrep_log_info "output: $errmsg" + wsrep_log_error "******** FATAL ERROR ********************************************" + wsrep_log_error "* The certifcate and CA (certificate authority) do not match. *" + wsrep_log_error "* It does not appear that the certificate was issued by the CA. *" + wsrep_log_error "* Please check your certificate and CA files. *" + wsrep_log_error "*****************************************************************" + exit 22 + fi +} + +# +# Verifies that the certificate matches the private key. +# Doing this will save us having to wait for a timeout that would +# otherwise occur. +# +# 1st param: path to the certificate. +# 2nd param: path to the private key. +# +verify_cert_matches_key() +{ + local cert="$1" + local key="$2" + + if [ ! -r "$key" -o ! -r "$cert" ]; then + wsrep_log_error "Both the certificate file and the key file" \ + "must be readable" + exit 22 + fi + + # If the openssl utility is not installed, then + # we will not do this certificate check: + get_openssl + if [ -z "$OPENSSL_BINARY" ]; then + wsrep_log_info "openssl utility not found" + return + fi + + # Generate the public key from the cert and the key. + # They should match (otherwise we can't create an SSL connection). + local pk1=$("$OPENSSL_BINARY" x509 -in "$cert" -pubkey -noout 2>/dev/null || :) + local pk2=$("$OPENSSL_BINARY" pkey -in "$key" -pubout 2>/dev/null || :) + if [ "$pk1" != "$pk2" ]; then + wsrep_log_error "******************* FATAL ERROR *****************" + wsrep_log_error "* The certificate and private key do not match. *" + wsrep_log_error "* Please check your certificate and key files. *" + wsrep_log_error "*************************************************" + exit 22 + fi +} + +# +# Compares two version strings. +# The first parameter is the version to be checked; +# The second parameter is the minimum version required; +# Returns 1 (failure) if $1 >= $2, 0 (success) otherwise. +# +check_for_version() +{ + local y1="${1#*.}" + [ "$y1" = "$1" ] && y1="" + local z1="${y1#*.}" + [ "$z1" = "$y1" ] && z1="" + local w1="${z1#*.}" + [ "$w1" = "$z1" ] && w1="" + local x1="${1%%.*}" + y1="${y1%%.*}" + z1="${z1%%.*}" + w1="${w1%%.*}" + [ -z "$y1" ] && y1=0 + [ -z "$z1" ] && z1=0 + [ -z "$w1" ] && w1=0 + local y2="${2#*.}" + [ "$y2" = "$2" ] && y2="" + local z2="${y2#*.}" + [ "$z2" = "$y2" ] && z2="" + local w2="${z2#*.}" + [ "$w2" = "$z2" ] && w2="" + local x2="${2%%.*}" + y2="${y2%%.*}" + z2="${z2%%.*}" + w2="${w2%%.*}" + [ -z "$y2" ] && y2=0 + [ -z "$z2" ] && z2=0 + [ -z "$w2" ] && w2=0 + [ $x1 -lt $x2 ] && return 1 + [ $x1 -gt $x2 ] && return 0 + [ $y1 -lt $y2 ] && return 1 + [ $y1 -gt $y2 ] && return 0 + [ $z1 -lt $z2 ] && return 1 + [ $z1 -gt $z2 ] && return 0 + [ $w1 -lt $w2 ] && return 1 + return 0 +} + +# +# Check whether process is still running. +# The first parameter contains the name of the PID file. +# The second parameter is the flag of the need to delete +# the PID file. +# If the second parameter is not zero and not empty, +# then if the process terminates, the corresponding +# PID file will be deleted. +# This function also sets the CHECK_PID variable to zero +# if the process has already exited, or writes the PID +# of the process there if it is still running. +# +check_pid() +{ + local pid_file="$1" + if [ -r "$pid_file" ]; then + local pid=$(cat "$pid_file" 2>/dev/null || :) + if [ -n "$pid" ]; then + if [ $pid -gt 0 ]; then + if ps -p $pid >/dev/null 2>&1; then + CHECK_PID=$pid + return 0 + fi + fi + fi + local remove=${2:-0} + if [ $remove -ne 0 ]; then + rm -f "$pid_file" || : + fi + fi + local config="${3:-}" + if [ -n "$config" -a -f "$config" ]; then + rm -f "$config" || : + fi + CHECK_PID=0 + return 1 +} + +# +# Checking that the process with the specified PID is still +# running and killing it in this case by sending SIGTERM +# (using the "kill" operation). +# The first parameter contains PID of the process. +# The second and third parameters (both optional) are the names +# of the PID and the configuration files, which should be removed +# after the process ends. +# If the first parameter (PID of the process) is zero, then +# the function immediately deletes the PID and the configuration +# files (if specified), without any additional checks. +# +cleanup_pid() +{ + local pid=$1 + local pid_file="${2:-}" + local config="${3:-}" + + if [ $pid -gt 0 ]; then + if ps -p $pid >/dev/null 2>&1; then + if kill $pid >/dev/null 2>&1; then + sleep 0.5 + local round=0 + local force=0 + while ps -p $pid >/dev/null 2>&1; do + sleep 1 + round=$(( round+1 )) + if [ $round -eq 16 ]; then + if [ $force -eq 0 ]; then + round=8 + force=1 + kill -9 $pid >/dev/null 2>&1 || : + sleep 0.5 + else + return 1 + fi + fi + done + elif ps -p $pid >/dev/null 2>&1; then + wsrep_log_warning "Unable to kill PID=$pid ($pid_file)" + return 1 + fi + fi + fi + + [ -n "$pid_file" -a -f "$pid_file" ] && rm -f "$pid_file" || : + [ -n "$config" -a -f "$config" ] && rm -f "$config" || : + + return 0 +} + +nproc="" + +get_proc() +{ + if [ -z "$nproc" ]; then + set +e + if [ "$OS" = 'Linux' ]; then + nproc=$(grep -cw -E '^processor' /proc/cpuinfo 2>/dev/null) + elif [ "$OS" = 'Darwin' -o "$OS" = 'FreeBSD' ]; then + nproc=$(sysctl -n hw.ncpu) + fi + set -e + if [ -z "$nproc" ] || [ $nproc -eq 0 ]; then + nproc=1 + fi + fi +} + +check_server_ssl_config() +{ + # backward-compatible behavior: + tcert=$(parse_cnf 'sst' 'tca') + tcap=$(parse_cnf 'sst' 'tcapath') + tpem=$(parse_cnf 'sst' 'tcert') + tkey=$(parse_cnf 'sst' 'tkey') + # reading new ssl configuration options: + local tcert2=$(parse_cnf "$encgroups" 'ssl-ca') + local tcap2=$(parse_cnf "$encgroups" 'ssl-capath') + local tpem2=$(parse_cnf "$encgroups" 'ssl-cert') + local tkey2=$(parse_cnf "$encgroups" 'ssl-key') + # if there are no old options, then we take new ones: + if [ -z "$tcert" -a -z "$tcap" -a -z "$tpem" -a -z "$tkey" ]; then + tcert="$tcert2" + tcap="$tcap2" + tpem="$tpem2" + tkey="$tkey2" + # checking for presence of the new-style SSL configuration: + elif [ -n "$tcert2" -o -n "$tcap2" -o -n "$tpem2" -o -n "$tkey2" ]; then + if [ "$tcert" != "$tcert2" -o \ + "$tcap" != "$tcap2" -o \ + "$tpem" != "$tpem2" -o \ + "$tkey" != "$tkey2" ] + then + wsrep_log_info \ + "new ssl configuration options (ssl-ca[path], ssl-cert" \ + "and ssl-key) are ignored by SST due to presence" \ + "of the tca[path], tcert and/or tkey in the [sst] section" + fi + fi + if [ -n "$tcert" ]; then + if [ "${tcert%/}" != "$tcert" -o -d "$tcert" ]; then + tcap="$tcert" + tcert="" + fi + fi +} + +simple_cleanup() +{ + # Since this is invoked just after exit NNN + local estatus=$? + if [ $estatus -ne 0 ]; then + wsrep_log_error "Cleanup after exit with status: $estatus" + fi + if [ -n "${SST_PID:-}" ]; then + [ "$(pwd)" != "$OLD_PWD" ] && cd "$OLD_PWD" + [ -f "$SST_PID" ] && rm -f "$SST_PID" || : + fi + exit $estatus +} + +wsrep_log_info "$WSREP_METHOD $WSREP_TRANSFER_TYPE started on $WSREP_SST_OPT_ROLE" diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh new file mode 100644 index 00000000..93f9270e --- /dev/null +++ b/scripts/wsrep_sst_mariabackup.sh @@ -0,0 +1,1602 @@ +#!/usr/bin/env bash + +set -ue + +# Copyright (C) 2017-2022 MariaDB +# Copyright (C) 2013 Percona Inc +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1335 USA. + +# Documentation: +# https://mariadb.com/kb/en/mariabackup-overview/ +# Make sure to read that before proceeding! + +OS="$(uname)" + +. $(dirname "$0")/wsrep_sst_common +wsrep_check_datadir + +ealgo="" +eformat="" +ekey="" +ekeyfile="" +encrypt=0 +ssyslog="" +ssystag="" +BACKUP_PID="" +tcert="" +tcap="" +tpem="" +tkey="" +tmode="" +sockopt="" +progress="" +ttime=0 +totime=0 +lsn="" +ecmd="" +rlimit="" +# Initially +stagemsg="$WSREP_SST_OPT_ROLE" +cpat="" +speciald=1 +ib_home_dir="" +ib_log_dir="" +ib_undo_dir="" +ar_log_dir="" + +sfmt="" +strmcmd="" +tfmt="" +tcmd="" +payload=0 +pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p'" +pvopts="-f -i 10 -N $WSREP_SST_OPT_ROLE" +STATDIR="" +uextra=0 +disver="" + +tmpopts="" +itmpdir="" +xtmpdir="" + +scomp="" +sdecomp="" + +ssl_dhparams="" + +compress='none' +compress_chunk="" +compress_threads="" + +backup_threads="" + +encrypt_threads="" +encrypt_chunk="" + +readonly SECRET_TAG='secret' +readonly TOTAL_TAG='total' + +# Required for backup locks +# For backup locks it is 1 sent by joiner +sst_ver=1 + +declare -a RC + +BACKUP_BIN=$(commandex 'mariadb-backup') +if [ -z "$BACKUP_BIN" ]; then + wsrep_log_error 'mariadb-backup binary not found in path' + exit 42 +fi + +DATA="$WSREP_SST_OPT_DATA" +INFO_FILE='xtrabackup_galera_info' +IST_FILE='xtrabackup_ist' +MAGIC_FILE="$DATA/$INFO_FILE" + +INNOAPPLYLOG="$DATA/mariabackup.prepare.log" +INNOMOVELOG="$DATA/mariabackup.move.log" +INNOBACKUPLOG="$DATA/mariabackup.backup.log" + +timeit() +{ + local stage="$1" + shift + local cmd="$@" + local x1 x2 took extcode + + if [ $ttime -eq 1 ]; then + x1=$(date +%s) + fi + + wsrep_log_info "Evaluating $cmd" + eval $cmd + extcode=$? + + if [ $ttime -eq 1 ]; then + x2=$(date +%s) + took=$(( x2-x1 )) + wsrep_log_info "NOTE: $stage took $took seconds" + totime=$(( totime+took )) + fi + + return $extcode +} + +get_keys() +{ + # $encrypt -eq 1 is for internal purposes only + if [ $encrypt -ge 2 -o $encrypt -eq -1 ]; then + return + fi + + if [ $encrypt -eq 0 ]; then + if [ -n "$ealgo" -o -n "$ekey" -o -n "$ekeyfile" ]; then + wsrep_log_error "Options for encryption are specified," \ + "but encryption itself is disabled. SST may fail." + fi + return + fi + + if [ "$sfmt" = 'tar' ]; then + wsrep_log_info "NOTE: key-based encryption (encrypt=1)" \ + "cannot be enabled with tar format" + encrypt=-1 + return + fi + + wsrep_log_info "Key based encryption enabled in my.cnf" + + if [ -z "$ealgo" ]; then + wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out" + exit 3 + fi + + if [ -z "$ekey" -a ! -r "$ekeyfile" ]; then + wsrep_log_error "FATAL: Either key must be specified" \ + "or keyfile must be readable" + exit 3 + fi + + if [ "$eformat" = 'openssl' ]; then + get_openssl + if [ -z "$OPENSSL_BINARY" ]; then + wsrep_log_error "If encryption using the openssl is enabled," \ + "then you need to install openssl" + exit 2 + fi + ecmd="'$OPENSSL_BINARY' enc -$ealgo" + if "$OPENSSL_BINARY" enc -help 2>&1 | grep -qw -F -- '-pbkdf2'; then + ecmd="$ecmd -pbkdf2" + elif "$OPENSSL_BINARY" enc -help 2>&1 | grep -qw -F -- '-iter'; then + ecmd="$ecmd -iter 1" + elif "$OPENSSL_BINARY" enc -help 2>&1 | grep -qw -F -- '-md'; then + ecmd="$ecmd -md sha256" + fi + if [ -z "$ekey" ]; then + ecmd="$ecmd -kfile '$ekeyfile'" + else + ecmd="$ecmd -k '$ekey'" + fi + elif [ "$eformat" = 'xbcrypt' ]; then + if [ -z "$(commandex xbcrypt)" ]; then + wsrep_log_error "If encryption using the xbcrypt is enabled," \ + "then you need to install xbcrypt" + exit 2 + fi + wsrep_log_info "NOTE: xbcrypt-based encryption," \ + "supported only from Xtrabackup 2.1.4" + if [ -z "$ekey" ]; then + ecmd="xbcrypt --encrypt-algo='$ealgo' --encrypt-key-file='$ekeyfile'" + else + ecmd="xbcrypt --encrypt-algo='$ealgo' --encrypt-key='$ekey'" + fi + if [ -n "$encrypt_threads" ]; then + ecmd="$ecmd --encrypt-threads=$encrypt_threads" + fi + if [ -n "$encrypt_chunk" ]; then + ecmd="$ecmd --encrypt-chunk-size=$encrypt_chunk" + fi + else + wsrep_log_error "Unknown encryption format='$eformat'" + exit 2 + fi + + [ "$WSREP_SST_OPT_ROLE" = 'joiner' ] && ecmd="$ecmd -d" + + stagemsg="$stagemsg-XB-Encrypted" +} + +get_socat_ver() +{ + [ -n "${SOCAT_VERSION+x}" ] && return + # Determine the socat version + SOCAT_VERSION=$(socat -V 2>&1 | \ + grep -m1 -owE '[0-9]+(\.[0-9]+)+' | \ + head -n1 || :) + if [ -z "$SOCAT_VERSION" ]; then + wsrep_log_error "******** FATAL ERROR ******************" + wsrep_log_error "* Cannot determine the socat version. *" + wsrep_log_error "***************************************" + exit 2 + fi +} + +get_transfer() +{ + if [ "$tfmt" = 'nc' ]; then + wsrep_log_info "Using netcat as streamer" + wsrep_check_programs nc + tcmd='nc' + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + if nc -h 2>&1 | grep -q -F 'ncat'; then + wsrep_log_info "Using Ncat as streamer" + tcmd="$tcmd -l" + elif nc -h 2>&1 | grep -qw -F -- '-d'; then + wsrep_log_info "Using Debian netcat as streamer" + tcmd="$tcmd -dl" + if [ $WSREP_SST_OPT_HOST_IPv6 -eq 1 ]; then + # When host is not explicitly specified (when only the port + # is specified) netcat can only bind to an IPv4 address if + # the "-6" option is not explicitly specified: + tcmd="$tcmd -6" + fi + else + wsrep_log_info "Using traditional netcat as streamer" + tcmd="$tcmd -l -p" + fi + tcmd="$tcmd $SST_PORT" + else + # Check to see if netcat supports the '-N' flag. + # -N Shutdown the network socket after EOF on stdin + # If it supports the '-N' flag, then we need to use the '-N' + # flag, otherwise the transfer will stay open after the file + # transfer and cause the command to timeout. + # Older versions of netcat did not need this flag and will + # return an error if the flag is used. + if nc -h 2>&1 | grep -qw -F -- '-N'; then + tcmd="$tcmd -N" + wsrep_log_info "Using nc -N" + fi + # netcat doesn't understand [] around IPv6 address + if nc -h 2>&1 | grep -q -F 'ncat'; then + wsrep_log_info "Using Ncat as streamer" + elif nc -h 2>&1 | grep -qw -F -- '-d'; then + wsrep_log_info "Using Debian netcat as streamer" + else + wsrep_log_info "Using traditional netcat as streamer" + tcmd="$tcmd -q0" + fi + tcmd="$tcmd $WSREP_SST_OPT_HOST_UNESCAPED $SST_PORT" + fi + else + tfmt='socat' + + wsrep_log_info "Using socat as streamer" + wsrep_check_programs socat + + if [ -n "$sockopt" ]; then + sockopt=$(trim_string "$sockopt" ',') + if [ -n "$sockopt" ]; then + sockopt=",$sockopt" + fi + fi + + # Add an option for ipv6 if needed: + if [ $WSREP_SST_OPT_HOST_IPv6 -eq 1 ]; then + # If sockopt contains 'pf=ip6' somewhere in the middle, + # this will not interfere with socat, but exclude the trivial + # cases when sockopt contains 'pf=ip6' as prefix or suffix: + if [ "$sockopt" = "${sockopt#,pf=ip6,}" -a \ + "$sockopt" = "${sockopt%,pf=ip6}" ] + then + sockopt=",pf=ip6$sockopt" + fi + fi + + if [ $encrypt -lt 2 ]; then + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + tcmd="socat -u TCP-LISTEN:$SST_PORT,reuseaddr$sockopt stdio" + else + tcmd="socat -u stdio TCP:$REMOTEIP:$SST_PORT$sockopt" + fi + return + fi + + if ! socat -V | grep -q -F 'WITH_OPENSSL 1'; then + wsrep_log_error "******** FATAL ERROR ************************************************ " + wsrep_log_error "* Encryption requested, but socat is not OpenSSL enabled (encrypt=$encrypt) *" + wsrep_log_error "********************************************************************* " + exit 2 + fi + + local action='Decrypting' + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + tcmd="socat -u openssl-listen:$SST_PORT,reuseaddr" + else + local addr="$REMOTEIP:$SST_PORT" + tcmd="socat -u stdio openssl-connect:$addr" + action='Encrypting' + get_socat_ver + if ! check_for_version "$SOCAT_VERSION" '1.7.4.1'; then + if check_for_version "$SOCAT_VERSION" '1.7.3.3'; then + # Workaround for a bug known as 'Red Hat issue 1870279' + # (connection reset by peer) in socat versions 1.7.3.3 + # to 1.7.4.0: + tcmd="socat stdio openssl-connect:$addr,linger=10" + wsrep_log_info \ + "Use workaround for socat $SOCAT_VERSION bug" + fi + fi + if check_for_version "$SOCAT_VERSION" '1.7.4'; then + tcmd="$tcmd,no-sni=1" + fi + fi + + if [ "${sockopt#*,dhparam=}" = "$sockopt" ]; then + if [ -z "$ssl_dhparams" ]; then + get_socat_ver + if ! check_for_version "$SOCAT_VERSION" '1.7.3'; then + # socat versions < 1.7.3 will have 512-bit dhparams (too small) + # so create 2048-bit dhparams and send that as a parameter: + check_for_dhparams + fi + fi + if [ -n "$ssl_dhparams" ]; then + tcmd="$tcmd,dhparam='$ssl_dhparams'" + fi + fi + + CN_option=",commonname=''" + + if [ $encrypt -eq 2 ]; then + wsrep_log_info \ + "Using openssl based encryption with socat: with crt and pem" + if [ -z "$tpem" -o -z "$tcert$tcap" ]; then + wsrep_log_error \ + "Both PEM file and CRT file (or path) are required" + exit 22 + fi + verify_ca_matches_cert "$tpem" "$tcert" "$tcap" + tcmd="$tcmd,cert='$tpem'" + if [ -n "$tcert" ]; then + tcmd="$tcmd,cafile='$tcert'" + fi + if [ -n "$tcap" ]; then + tcmd="$tcmd,capath='$tcap'" + fi + stagemsg="$stagemsg-OpenSSL-Encrypted-2" + wsrep_log_info "$action with cert='$tpem', ca='$tcert', capath='$tcap'" + elif [ $encrypt -eq 3 -o $encrypt -eq 4 ]; then + wsrep_log_info \ + "Using openssl based encryption with socat: with key and crt" + if [ -z "$tpem" -o -z "$tkey" ]; then + wsrep_log_error "Both the certificate file (or path) and" \ + "the key file are required" + exit 22 + fi + verify_cert_matches_key "$tpem" "$tkey" + stagemsg="$stagemsg-OpenSSL-Encrypted-3" + if [ -z "$tcert$tcap" ]; then + if [ $encrypt -eq 4 ]; then + wsrep_log_error \ + "Peer certificate file (or path) required if encrypt=4" + exit 22 + fi + # no verification + CN_option="" + tcmd="$tcmd,cert='$tpem',key='$tkey',verify=0" + wsrep_log_info \ + "$action with cert='$tpem', key='$tkey', verify=0" + else + # CA verification + verify_ca_matches_cert "$tpem" "$tcert" "$tcap" + if [ -n "$WSREP_SST_OPT_REMOTE_USER" ]; then + CN_option=",commonname='$WSREP_SST_OPT_REMOTE_USER'" + elif [ "$WSREP_SST_OPT_ROLE" = 'joiner' -o $encrypt -eq 4 ] + then + CN_option=",commonname=''" + elif is_local_ip "$WSREP_SST_OPT_HOST_UNESCAPED"; then + CN_option=',commonname=localhost' + else + CN_option=",commonname='$WSREP_SST_OPT_HOST_UNESCAPED'" + fi + tcmd="$tcmd,cert='$tpem',key='$tkey'" + if [ -n "$tcert" ]; then + tcmd="$tcmd,cafile='$tcert'" + fi + if [ -n "$tcap" ]; then + tcmd="$tcmd,capath='$tcap'" + fi + wsrep_log_info "$action with cert='$tpem', key='$tkey'," \ + "ca='$tcert', capath='$tcap'" + fi + else + wsrep_log_info "Unknown encryption mode: encrypt=$encrypt" + exit 22 + fi + + tcmd="$tcmd$CN_option$sockopt" + + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + tcmd="$tcmd stdio" + fi + fi +} + +get_footprint() +{ + cd "$DATA_DIR" + local payload_data=$(find $findopt . \ + -regex '.*undo[0-9]+$\|.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' \ + -type f -print0 | du --files0-from=- --block-size=1 -c -s | \ + awk 'END { print $1 }') + local payload_undo=0 + if [ -n "$ib_undo_dir" -a "$ib_undo_dir" != '.' -a \ + "$ib_undo_dir" != "$DATA_DIR" -a -d "$ib_undo_dir" ] + then + cd "$ib_undo_dir" + payload_undo=$(find . -regex '.*undo[0-9]+$' -type f -print0 | \ + du --files0-from=- --block-size=1 -c -s | awk 'END { print $1 }') + fi + cd "$OLD_PWD" + + wsrep_log_info \ + "SST footprint estimate: data: $payload_data, undo: $payload_undo" + + payload=$(( payload_data+payload_undo )) + + if [ "$compress" != 'none' ]; then + # QuickLZ has around 50% compression ratio + # When compression/compaction used, the progress is only an approximate. + payload=$(( payload*1/2 )) + fi + + if [ $WSREP_SST_OPT_PROGRESS -eq 1 ]; then + # report to parent the total footprint of the SST + echo "$TOTAL_TAG $payload" + fi + + adjust_progress +} + +adjust_progress() +{ + pcmd="" + rcmd="" + + [ "$progress" = 'none' ] && return + + rlimitopts="" + if [ -n "$rlimit" -a "$WSREP_SST_OPT_ROLE" = 'donor' ]; then + wsrep_log_info "Rate-limiting SST to $rlimit" + rlimitopts=" -L $rlimit" + fi + + if [ -n "$progress" ]; then + + # Backward compatibility: user-configured progress output + pcmd="pv $pvopts$rlimitopts" + + if [ -z "${PV_FORMAT+x}" ]; then + PV_FORMAT=0 + pv --help | grep -qw -F -- '-F' && PV_FORMAT=1 + fi + if [ $PV_FORMAT -eq 1 ]; then + pcmd="$pcmd $pvformat" + fi + + if [ $payload -ne 0 ]; then + pcmd="$pcmd -s $payload" + fi + + if [ "$progress" != '1' ]; then + if [ -e "$progress" ]; then + pcmd="$pcmd 2>>'$progress'" + else + pcmd="$pcmd 2>'$progress'" + fi + fi + + elif [ $WSREP_SST_OPT_PROGRESS -eq 1 ]; then + + # Default progress output parseable by parent + pcmd="pv -f -i 1 -n -b$rlimitopts" + + # read progress data, add tag and post to stdout + # for the parent + rcmd="stdbuf -oL tr '\r' '\n' | xargs -n1 echo complete" + + elif [ -n "$rlimitopts" ]; then + + # Rate-limiting only, when rlimit is non-zero + pcmd="pv -q$rlimitopts" + + fi +} + +encgroups='--mysqld|sst|xtrabackup' + +read_cnf() +{ + sfmt=$(parse_cnf sst streamfmt 'mbstream') + tfmt=$(parse_cnf sst transferfmt 'socat') + + encrypt=$(parse_cnf "$encgroups" 'encrypt' 0) + tmode=$(parse_cnf "$encgroups" 'ssl-mode' 'DISABLED' | \ + tr '[[:lower:]]' '[[:upper:]]') + + case "$tmode" in + 'VERIFY_IDENTITY'|'VERIFY_CA'|'REQUIRED'|'DISABLED') + ;; + *) + wsrep_log_error "Unrecognized ssl-mode option: '$tmode'" + exit 22 # EINVAL + ;; + esac + + if [ $encrypt -eq 0 -o $encrypt -ge 2 ]; then + if [ "$tmode" != 'DISABLED' -o $encrypt -ge 2 ]; then + check_server_ssl_config + fi + if [ "$tmode" != 'DISABLED' ]; then + if [ 0 -eq $encrypt -a -n "$tpem" -a -n "$tkey" ] + then + encrypt=3 # enable cert/key SSL encyption + # avoid CA verification if not set explicitly: + # nodes may happen to have different CA if self-generated, + # zeroing up tcert and tcap does the trick: + if [ "${tmode#VERIFY}" = "$tmode" ]; then + tcert="" + tcap="" + fi + fi + fi + elif [ $encrypt -eq 1 ]; then + ealgo=$(parse_cnf "$encgroups" 'encrypt-algo') + eformat=$(parse_cnf "$encgroups" 'encrypt-format' 'openssl') + ekey=$(parse_cnf "$encgroups" 'encrypt-key') + # The keyfile should be read only when the key + # is not specified or empty: + if [ -z "$ekey" ]; then + ekeyfile=$(parse_cnf "$encgroups" 'encrypt-key-file') + fi + fi + + wsrep_log_info "SSL configuration: CA='$tcert', CAPATH='$tcap'," \ + "CERT='$tpem', KEY='$tkey', MODE='$tmode'," \ + "encrypt='$encrypt'" + + if [ $encrypt -ge 2 ]; then + ssl_dhparams=$(parse_cnf "$encgroups" 'ssl-dhparams') + fi + + sockopt=$(parse_cnf sst sockopt "") + progress=$(parse_cnf sst progress "") + ttime=$(parse_cnf sst time 0) + cpat='.*\.pem$\|.*galera\.cache$\|.*sst_in_progress$\|.*\.sst$\|.*gvwstate\.dat$\|.*grastate\.dat$\|.*\.err$\|.*\.log$\|.*RPM_UPGRADE_MARKER$\|.*RPM_UPGRADE_HISTORY$' + [ "$OS" = 'FreeBSD' ] && cpat=$(echo "$cpat" | sed 's/\\|/|/g') + cpat=$(parse_cnf sst cpat "$cpat") + scomp=$(parse_cnf sst compressor "") + sdecomp=$(parse_cnf sst decompressor "") + + rlimit=$(parse_cnf sst rlimit "") + uextra=$(parse_cnf sst use-extra 0) + speciald=$(parse_cnf sst sst-special-dirs 1) + iopts=$(parse_cnf sst inno-backup-opts "") + iapts=$(parse_cnf sst inno-apply-opts "") + impts=$(parse_cnf sst inno-move-opts "") + stimeout=$(parse_cnf sst sst-initial-timeout 300) + ssyslog=$(parse_cnf sst sst-syslog 0) + ssystag=$(parse_cnf mysqld_safe syslog-tag "${SST_SYSLOG_TAG:-}") + ssystag="$ssystag-" + sstlogarchive=$(parse_cnf sst sst-log-archive 1) + sstlogarchivedir="" + if [ $sstlogarchive -ne 0 ]; then + sstlogarchivedir=$(parse_cnf sst sst-log-archive-dir \ + '/tmp/sst_log_archive') + if [ -n "$sstlogarchivedir" ]; then + sstlogarchivedir=$(trim_dir "$sstlogarchivedir") + fi + fi + + if [ $speciald -eq 0 ]; then + wsrep_log_error \ + "sst-special-dirs equal to 0 is not supported, falling back to 1" + speciald=1 + fi + + if [ $ssyslog -ne -1 ]; then + ssyslog=$(in_config 'mysqld_safe' 'syslog') + fi + + if [ "$WSREP_SST_OPT_ROLE" = 'donor' ]; then + compress=$(parse_cnf "$encgroups" 'compress' 'none') + if [ "$compress" != 'none' ]; then + compress_chunk=$(parse_cnf "$encgroups" 'compress-chunk-size') + compress_threads=$(parse_cnf "$encgroups" 'compress-threads') + fi + fi + + backup_threads=$(parse_cnf "$encgroups" 'backup-threads') + + if [ "$eformat" = 'xbcrypt' ]; then + encrypt_threads=$(parse_cnf "$encgroups" 'encrypt-threads') + encrypt_chunk=$(parse_cnf "$encgroups" 'encrypt-chunk-size') + fi +} + +get_stream() +{ + if [ "$sfmt" = 'mbstream' -o "$sfmt" = 'xbstream' ]; then + sfmt='mbstream' + local STREAM_BIN=$(commandex "$sfmt") + if [ -z "$STREAM_BIN" ]; then + wsrep_log_error "Streaming with $sfmt, but $sfmt not found in path" + exit 42 + fi + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + strmcmd="'$STREAM_BIN' -x" + else + strmcmd="'$STREAM_BIN' -c '$INFO_FILE'" + fi + else + sfmt='tar' + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + strmcmd='tar xfi -' + else + strmcmd="tar cf - '$INFO_FILE'" + fi + fi + wsrep_log_info "Streaming with $sfmt" +} + +cleanup_at_exit() +{ + # Since this is invoked just after exit NNN + local estatus=$? + if [ $estatus -ne 0 ]; then + wsrep_log_error "Cleanup after exit with status: $estatus" + elif [ -z "${coords:-}" -a "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + estatus=32 + wsrep_log_error "Failed to get current position" + fi + + [ "$(pwd)" != "$OLD_PWD" ] && cd "$OLD_PWD" + + if [ $estatus -ne 0 ]; then + wsrep_log_error "Removing $MAGIC_FILE file due to signal" + [ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" || : + fi + + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + wsrep_log_info "Removing the sst_in_progress file" + wsrep_cleanup_progress_file + else + if [ -n "$BACKUP_PID" ]; then + if check_pid "$BACKUP_PID" 1; then + wsrep_log_error \ + "mariadb-backup process is still running. Killing..." + cleanup_pid $CHECK_PID "$BACKUP_PID" + fi + fi + [ -f "$DATA/$IST_FILE" ] && rm -f "$DATA/$IST_FILE" || : + fi + + if [ -n "$progress" -a -p "$progress" ]; then + wsrep_log_info "Cleaning up fifo file: $progress" + rm -f "$progress" || : + fi + + wsrep_log_info "Cleaning up temporary directories" + + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + [ -n "$STATDIR" -a -d "$STATDIR" ] && rm -rf "$STATDIR" || : + else + [ -n "$xtmpdir" -a -d "$xtmpdir" ] && rm -rf "$xtmpdir" || : + [ -n "$itmpdir" -a -d "$itmpdir" ] && rm -rf "$itmpdir" || : + fi + + # Final cleanup + pgid=$(ps -o pgid= $$ 2>/dev/null | grep -o -E '[0-9]+' || :) + + # This means no setsid done in mysqld. + # We don't want to kill mysqld here otherwise. + if [ -n "$pgid" ]; then + if [ $$ -eq $pgid ]; then + # This means a signal was delivered to the process. + # So, more cleanup. + if [ $estatus -ge 128 ]; then + kill -KILL -- -$$ || : + fi + fi + fi + + if [ -n "${SST_PID:-}" ]; then + [ -f "$SST_PID" ] && rm -f "$SST_PID" || : + fi + + exit $estatus +} + +setup_ports() +{ + SST_PORT="$WSREP_SST_OPT_PORT" + if [ "$WSREP_SST_OPT_ROLE" = 'donor' ]; then + REMOTEIP="$WSREP_SST_OPT_HOST" + lsn="$WSREP_SST_OPT_LSN" + sst_ver="$WSREP_SST_OPT_SST_VER" + fi +} + +# +# Waits ~30 seconds for socat or nc to open the port and +# then reports ready, regardless of timeout. +# +wait_for_listen() +{ + for i in {1..150}; do + if check_port "" "$SST_PORT" 'socat|nc'; then + break + fi + sleep 0.2 + done + echo "ready $ADDR:$SST_PORT/$MODULE/$lsn/$sst_ver" +} + +check_extra() +{ + local use_socket=1 + if [ $uextra -eq 1 ]; then + local thread_handling=$(parse_cnf '--mysqld' 'thread-handling') + if [ "$thread_handling" = 'pool-of-threads' ]; then + local eport=$(parse_cnf '--mysqld' 'extra-port') + if [ -n "$eport" ]; then + # mariadb-backup works only locally. + # Hence, setting host to 127.0.0.1 unconditionally: + wsrep_log_info "SST through extra_port $eport" + INNOEXTRA="$INNOEXTRA --host=127.0.0.1 --port=$eport" + use_socket=0 + else + wsrep_log_error "Extra port $eport null, failing" + exit 1 + fi + else + wsrep_log_info "Thread pool not set, ignore the option use_extra" + fi + fi + if [ $use_socket -eq 1 -a -n "$WSREP_SST_OPT_SOCKET" ]; then + INNOEXTRA="$INNOEXTRA --socket='$WSREP_SST_OPT_SOCKET'" + fi +} + +recv_joiner() +{ + local dir="$1" + local msg="$2" + local tmt=$3 + local checkf=$4 + local wait=$5 + + if [ ! -d "$dir" ]; then + # This indicates that IST is in progress + return + fi + + local ltcmd="$tcmd" + if [ $tmt -gt 0 ]; then + if [ -n "$(commandex timeout)" ]; then + local koption=0 + if [ "$OS" = 'FreeBSD' ]; then + if timeout 2>&1 | grep -qw -F -- '-k'; then + koption=1 + fi + else + if timeout --help | grep -qw -F -- '-k'; then + koption=1 + fi + fi + if [ $koption -ne 0 ]; then + ltcmd="timeout -k $(( tmt+10 )) $tmt $tcmd" + else + ltcmd="timeout -s 9 $tmt $tcmd" + fi + fi + fi + + if [ $wait -ne 0 ]; then + wait_for_listen & + fi + + cd "$dir" + set +e + timeit "$msg" "$ltcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + cd "$OLD_PWD" + + if [ ${RC[0]} -eq 124 ]; then + wsrep_log_error "Possible timeout in receiving first data from" \ + "donor in gtid stage: exit codes: ${RC[@]}" + exit 32 + fi + + for ecode in "${RC[@]}"; do + if [ $ecode -ne 0 ]; then + wsrep_log_error "Error while getting data from donor node:" \ + "exit codes: ${RC[@]}" + exit 32 + fi + done + + if [ $checkf -eq 1 ]; then + if [ ! -r "$MAGIC_FILE" ]; then + # this message should cause joiner to abort: + wsrep_log_error "receiving process ended without creating" \ + "magic file ($MAGIC_FILE)" + wsrep_log_info "Contents of datadir:" + wsrep_log_info $(ls -l "$dir/"*) + exit 32 + fi + + if [ -n "$MY_SECRET" ]; then + # Check donor supplied secret: + SECRET=$(grep -m1 -E "^$SECRET_TAG[[:space:]]" "$MAGIC_FILE" || :) + SECRET=$(trim_string "${SECRET#$SECRET_TAG}") + if [ "$SECRET" != "$MY_SECRET" ]; then + wsrep_log_error "Donor does not know my secret!" + wsrep_log_info "Donor: '$SECRET', my: '$MY_SECRET'" + exit 32 + fi + fi + + if [ $WSREP_SST_OPT_PROGRESS -eq 1 ]; then + # check total SST footprint + payload=$(grep -m1 -E "^$TOTAL_TAG[[:space:]]" "$MAGIC_FILE" || :) + if [ -n "$payload" ]; then + payload=$(trim_string "${payload#$TOTAL_TAG}") + if [ $payload -ge 0 ]; then + # report to parent + echo "$TOTAL_TAG $payload" + fi + fi + fi + fi +} + +send_donor() +{ + local dir="$1" + local msg="$2" + + cd "$dir" + set +e + timeit "$msg" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + cd "$OLD_PWD" + + for ecode in "${RC[@]}"; do + if [ $ecode -ne 0 ]; then + wsrep_log_error "Error while sending data to joiner node:" \ + "exit codes: ${RC[@]}" + exit 32 + fi + done +} + +monitor_process() +{ + local sst_stream_pid=$1 + + while :; do + if ! ps -p "$WSREP_SST_OPT_PARENT" >/dev/null 2>&1; then + wsrep_log_error \ + "Parent mysqld process (PID: $WSREP_SST_OPT_PARENT)" \ + "terminated unexpectedly." + kill -- -"$WSREP_SST_OPT_PARENT" + exit 32 + fi + if ! ps -p "$sst_stream_pid" >/dev/null 2>&1; then + break + fi + sleep 0.1 + done +} + +[ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" + +read_cnf +setup_ports + +if [ "$progress" = 'none' ]; then + wsrep_log_info "All progress/rate-limiting disabled by configuration" +elif [ -z "$(commandex pv)" ]; then + wsrep_log_info "Progress reporting tool pv not found in path: $PATH" + wsrep_log_info "Disabling all progress/rate-limiting" + progress='none' +fi + +if "$BACKUP_BIN" --help 2>/dev/null | grep -qw -F -- '--version-check'; then + disver=' --no-version-check' +fi + +OLD_PWD="$(pwd)" + +if [ -n "$DATA" -a "$DATA" != '.' ]; then + [ ! -d "$DATA" ] && mkdir -p "$DATA" + cd "$DATA" +fi +DATA_DIR="$(pwd)" + +cd "$OLD_PWD" + +if [ $ssyslog -eq 1 ]; then + if [ -n "$(commandex logger)" ]; then + wsrep_log_info "Logging all stderr of SST/mariadb-backup to syslog" + + exec 2> >(logger -p daemon.err -t ${ssystag}wsrep-sst-$WSREP_SST_OPT_ROLE) + + wsrep_log_error() + { + logger -p daemon.err -t ${ssystag}wsrep-sst-$WSREP_SST_OPT_ROLE "$@" + } + + wsrep_log_warning() + { + logger -p daemon.warning -t ${ssystag}wsrep-sst-$WSREP_SST_OPT_ROLE "$@" + } + + wsrep_log_info() + { + logger -p daemon.info -t ${ssystag}wsrep-sst-$WSREP_SST_OPT_ROLE "$@" + } + else + wsrep_log_error "logger not in path: $PATH. Ignoring" + fi + INNOAPPLY="2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-apply" + INNOMOVE="2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-move" + INNOBACKUP="2> >(logger -p daemon.err -t ${ssystag}innobackupex-backup)" +else + if [ $sstlogarchive -eq 1 ] + then + ARCHIVETIMESTAMP=$(date '+%Y.%m.%d-%H.%M.%S.%N') + + if [ -n "$sstlogarchivedir" ]; then + if [ ! -d "$sstlogarchivedir" ]; then + if ! mkdir -p "$sstlogarchivedir"; then + sstlogarchivedir="" + wsrep_log_warning \ + "Unable to create '$sstlogarchivedir' directory" + fi + elif [ ! -w "$sstlogarchivedir" ]; then + sstlogarchivedir="" + wsrep_log_warning \ + "The '$sstlogarchivedir' directory is not writtable" + fi + fi + + if [ -e "$INNOAPPLYLOG" ]; then + if [ -n "$sstlogarchivedir" ]; then + newfile=$(basename "$INNOAPPLYLOG") + newfile="$sstlogarchivedir/$newfile.$ARCHIVETIMESTAMP" + else + newfile="$INNOAPPLYLOG.$ARCHIVETIMESTAMP" + fi + wsrep_log_info "Moving '$INNOAPPLYLOG' to '$newfile'" + mv "$INNOAPPLYLOG" "$newfile" && gzip "$newfile" || \ + wsrep_log_warning "Failed to archive log file ('$newfile')" + fi + + if [ -e "$INNOMOVELOG" ]; then + if [ -n "$sstlogarchivedir" ]; then + newfile=$(basename "$INNOMOVELOG") + newfile="$sstlogarchivedir/$newfile.$ARCHIVETIMESTAMP" + else + newfile="$INNOMOVELOG.$ARCHIVETIMESTAMP" + fi + wsrep_log_info "Moving '$INNOMOVELOG' to '$newfile'" + mv "$INNOMOVELOG" "$newfile" && gzip "$newfile" || \ + wsrep_log_warning "Failed to archive log file ('$newfile')" + fi + + if [ -e "$INNOBACKUPLOG" ]; then + if [ -n "$sstlogarchivedir" ]; then + newfile=$(basename "$INNOBACKUPLOG") + newfile="$sstlogarchivedir/$newfile.$ARCHIVETIMESTAMP" + else + newfile="$INNOBACKUPLOG.$ARCHIVETIMESTAMP" + fi + wsrep_log_info "Moving '$INNOBACKUPLOG' to '$newfile'" + mv "$INNOBACKUPLOG" "$newfile" && gzip "$newfile" || \ + wsrep_log_warning "Failed to archive log file ('$newfile')" + fi + fi + INNOAPPLY="> '$INNOAPPLYLOG' 2>&1" + INNOMOVE="> '$INNOMOVELOG' 2>&1" + INNOBACKUP="2> '$INNOBACKUPLOG'" +fi + +setup_commands() +{ + local mysqld_args="" + if [ -n "$WSREP_SST_OPT_MYSQLD" ]; then + mysqld_args=" --mysqld-args $WSREP_SST_OPT_MYSQLD" + fi + local recovery="" + if [ -n "$INNODB_FORCE_RECOVERY" ]; then + recovery=" --innodb-force-recovery=$INNODB_FORCE_RECOVERY" + fi + INNOAPPLY="$BACKUP_BIN --prepare$disver$recovery${iapts:+ }$iapts$INNOEXTRA --target-dir='$DATA' --datadir='$DATA'$mysqld_args $INNOAPPLY" + INNOMOVE="$BACKUP_BIN$WSREP_SST_OPT_CONF --move-back$disver${impts:+ }$impts$INNOEXTRA --galera-info --force-non-empty-directories --target-dir='$DATA' --datadir='${TDATA:-$DATA}' $INNOMOVE" + INNOBACKUP="$BACKUP_BIN$WSREP_SST_OPT_CONF --backup$disver${iopts:+ }$iopts$tmpopts$INNOEXTRA --galera-info --stream=$sfmt --target-dir='$itmpdir' --datadir='$DATA'$mysqld_args $INNOBACKUP" +} + +get_stream +get_transfer + +findopt='-L' +[ "$OS" = 'FreeBSD' ] && findopt="$findopt -E" + +if [ "$WSREP_SST_OPT_ROLE" = 'donor' ]; then + + trap cleanup_at_exit EXIT + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ] + then + if [ -z "$sst_ver" ]; then + wsrep_log_error "Upgrade joiner to 5.6.21 or higher for backup locks support" + wsrep_log_error "The joiner is not supported for this version of donor" + exit 93 + fi + + tmpdir=$(parse_cnf "$encgroups" 'tmpdir') + if [ -z "$tmpdir" ]; then + xtmpdir="$(mktemp -d)" + elif [ "$OS" = 'Linux' ]; then + xtmpdir=$(mktemp '-d' "--tmpdir=$tmpdir") + else + xtmpdir=$(TMPDIR="$tmpdir"; mktemp '-d') + fi + + wsrep_log_info "Using '$xtmpdir' as mariadb-backup temporary directory" + tmpopts=" --tmpdir='$xtmpdir'" + + itmpdir="$(mktemp -d)" + wsrep_log_info "Using '$itmpdir' as mariadb-abackup working directory" + + usrst=0 + if [ -n "$WSREP_SST_OPT_USER" ]; then + INNOEXTRA="$INNOEXTRA --user='$WSREP_SST_OPT_USER'" + usrst=1 + fi + + if [ -n "$WSREP_SST_OPT_PSWD" ]; then + export MYSQL_PWD="$WSREP_SST_OPT_PSWD" + elif [ $usrst -eq 1 ]; then + # Empty password, used for testing, debugging etc. + unset MYSQL_PWD + fi + + check_extra + + if [ -n "$progress" -o $WSREP_SST_OPT_PROGRESS -eq 1 ]; then + wsrep_log_info "Estimating total transfer size" + get_footprint + wsrep_log_info "To transfer: $payload" + else + adjust_progress + fi + + wsrep_log_info "Streaming GTID file before SST" + + # Store donor's wsrep GTID (state ID) and wsrep_gtid_domain_id + # (separated by a space). + echo "$WSREP_SST_OPT_GTID $WSREP_SST_OPT_GTID_DOMAIN_ID" > "$MAGIC_FILE" + + if [ -n "$WSREP_SST_OPT_REMOTE_PSWD" ]; then + # Let joiner know that we know its secret + echo "$SECRET_TAG $WSREP_SST_OPT_REMOTE_PSWD" >> "$MAGIC_FILE" + fi + + if [ $WSREP_SST_OPT_PROGRESS -eq 1 ]; then + # Tell joiner what to expect: + echo "$TOTAL_TAG $payload" >> "$MAGIC_FILE" + fi + + ttcmd="$tcmd" + + if [ -n "$scomp" ]; then + tcmd="$scomp | $tcmd" + fi + + get_keys + if [ $encrypt -eq 1 ]; then + tcmd="$ecmd | $tcmd" + fi + + send_donor "$DATA" "$stagemsg-gtid" + + # Restore the transport commmand to its original state + tcmd="$ttcmd" + + if [ -n "$pcmd" ]; then + if [ -n "$rcmd" ]; then + # redirect pv stderr to rcmd for tagging and output to parent + tcmd="{ $pcmd 2>&3 | $tcmd; } 3>&1 | $rcmd" + else + # use user-configured pv output + tcmd="$pcmd | $tcmd" + fi + fi + + wsrep_log_info "Sleeping before data transfer for SST" + sleep 10 + + wsrep_log_info "Streaming the backup to joiner at $REMOTEIP:$SST_PORT" + + # Add compression to the head of the stream (if specified) + if [ -n "$scomp" ]; then + tcmd="$scomp | $tcmd" + fi + + # Add encryption to the head of the stream (if specified) + if [ $encrypt -eq 1 ]; then + tcmd="$ecmd | $tcmd" + fi + + iopts="--databases-exclude='lost+found'${iopts:+ }$iopts" + + if [ ${FORCE_FTWRL:-0} -eq 1 ]; then + wsrep_log_info "Forcing FTWRL due to environment variable" \ + "FORCE_FTWRL equal to $FORCE_FTWRL" + iopts="--no-backup-locks${iopts:+ }$iopts" + fi + + # if compression is enabled for backup files, then add the + # appropriate options to the mariadb-backup command line: + if [ "$compress" != 'none' ]; then + iopts="--compress${compress:+=$compress}${iopts:+ }$iopts" + if [ -n "$compress_threads" ]; then + iopts="--compress-threads=$compress_threads${iopts:+ }$iopts" + fi + if [ -n "$compress_chunk" ]; then + iopts="--compress-chunk-size=$compress_chunk${iopts:+ }$iopts" + fi + fi + + if [ -n "$backup_threads" ]; then + iopts="--parallel=$backup_threads${iopts:+ }$iopts" + fi + + setup_commands + + set +e + timeit "$stagemsg-SST" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + + if [ ${RC[0]} -ne 0 ]; then + wsrep_log_error "mariadb-backup finished with error: ${RC[0]}." \ + "Check syslog or '$INNOBACKUPLOG' for details" + exit 22 + elif [ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]; then + wsrep_log_error "$tcmd finished with error: ${RC[1]}" + exit 22 + fi + + # mariadb-backup implicitly writes PID to fixed location in $xtmpdir + BACKUP_PID="$xtmpdir/xtrabackup_pid" + + else # BYPASS FOR IST + + wsrep_log_info "Bypassing the SST for IST" + echo "continue" # now server can resume updating data + + # Store donor's wsrep GTID (state ID) and wsrep_gtid_domain_id + # (separated by a space). + echo "$WSREP_SST_OPT_GTID $WSREP_SST_OPT_GTID_DOMAIN_ID" > "$MAGIC_FILE" + echo "1" > "$DATA/$IST_FILE" + + if [ -n "$scomp" ]; then + tcmd="$scomp | $tcmd" + fi + + get_keys + if [ $encrypt -eq 1 ]; then + tcmd="$ecmd | $tcmd" + fi + + strmcmd="$strmcmd '$IST_FILE'" + + send_donor "$DATA" "$stagemsg-IST" + + fi + + echo "done $WSREP_SST_OPT_GTID" + wsrep_log_info "Total time on donor: $totime seconds" + +else # joiner + + [ -e "$SST_PROGRESS_FILE" ] && \ + wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE" + [ -n "$SST_PROGRESS_FILE" ] && touch "$SST_PROGRESS_FILE" + + # if no command line argument and INNODB_DATA_HOME_DIR environment + # variable is not set, try to get it from the my.cnf: + if [ -z "$INNODB_DATA_HOME_DIR" ]; then + INNODB_DATA_HOME_DIR=$(parse_cnf '--mysqld' 'innodb-data-home-dir') + INNODB_DATA_HOME_DIR=$(trim_dir "$INNODB_DATA_HOME_DIR") + fi + + if [ -n "$INNODB_DATA_HOME_DIR" -a "$INNODB_DATA_HOME_DIR" != '.' -a \ + "$INNODB_DATA_HOME_DIR" != "$DATA_DIR" ] + then + # handle both relative and absolute paths: + cd "$DATA" + [ ! -d "$INNODB_DATA_HOME_DIR" ] && mkdir -p "$INNODB_DATA_HOME_DIR" + cd "$INNODB_DATA_HOME_DIR" + ib_home_dir="$(pwd)" + cd "$OLD_PWD" + [ "$ib_home_dir" = "$DATA_DIR" ] && ib_home_dir="" + fi + + # if no command line argument and INNODB_LOG_GROUP_HOME is not set, + # then try to get it from the my.cnf: + if [ -z "$INNODB_LOG_GROUP_HOME" ]; then + INNODB_LOG_GROUP_HOME=$(parse_cnf '--mysqld' 'innodb-log-group-home-dir') + INNODB_LOG_GROUP_HOME=$(trim_dir "$INNODB_LOG_GROUP_HOME") + fi + + if [ -n "$INNODB_LOG_GROUP_HOME" -a "$INNODB_LOG_GROUP_HOME" != '.' -a \ + "$INNODB_LOG_GROUP_HOME" != "$DATA_DIR" ] + then + # handle both relative and absolute paths: + cd "$DATA" + [ ! -d "$INNODB_LOG_GROUP_HOME" ] && mkdir -p "$INNODB_LOG_GROUP_HOME" + cd "$INNODB_LOG_GROUP_HOME" + ib_log_dir="$(pwd)" + cd "$OLD_PWD" + [ "$ib_log_dir" = "$DATA_DIR" ] && ib_log_dir="" + fi + + # if no command line argument and INNODB_UNDO_DIR is not set, + # then try to get it from the my.cnf: + if [ -z "$INNODB_UNDO_DIR" ]; then + INNODB_UNDO_DIR=$(parse_cnf '--mysqld' 'innodb-undo-directory') + INNODB_UNDO_DIR=$(trim_dir "$INNODB_UNDO_DIR") + fi + + if [ -n "$INNODB_UNDO_DIR" -a "$INNODB_UNDO_DIR" != '.' -a \ + "$INNODB_UNDO_DIR" != "$DATA_DIR" ] + then + # handle both relative and absolute paths: + cd "$DATA" + [ ! -d "$INNODB_UNDO_DIR" ] && mkdir -p "$INNODB_UNDO_DIR" + cd "$INNODB_UNDO_DIR" + ib_undo_dir="$(pwd)" + cd "$OLD_PWD" + [ "$ib_undo_dir" = "$DATA_DIR" ] && ib_undo_dir="" + fi + + # if no command line argument then try to get it from the my.cnf: + if [ -z "$ARIA_LOG_DIR" ]; then + ARIA_LOG_DIR=$(parse_cnf '--mysqld' 'aria-log-dir-path') + ARIA_LOG_DIR=$(trim_dir "$ARIA_LOG_DIR") + fi + + if [ -n "$ARIA_LOG_DIR" -a "$ARIA_LOG_DIR" != '.' -a \ + "$ARIA_LOG_DIR" != "$DATA_DIR" ] + then + # handle both relative and absolute paths: + cd "$DATA" + [ ! -d "$ARIA_LOG_DIR" ] && mkdir -p "$ARIA_LOG_DIR" + cd "$ARIA_LOG_DIR" + ar_log_dir="$(pwd)" + cd "$OLD_PWD" + [ "$ar_log_dir" = "$DATA_DIR" ] && ar_log_dir="" + fi + + if [ -n "$backup_threads" ]; then + impts="--parallel=$backup_threads${impts:+ }$impts" + fi + + SST_PID="$WSREP_SST_OPT_DATA/wsrep_sst.pid" + + # give some time for previous SST to complete: + check_round=0 + while check_pid "$SST_PID" 0; do + wsrep_log_info "previous SST is not completed, waiting for it to exit" + check_round=$(( check_round + 1 )) + if [ $check_round -eq 10 ]; then + wsrep_log_error "previous SST script still running." + exit 114 # EALREADY + fi + sleep 1 + done + + trap simple_cleanup EXIT + echo $$ > "$SST_PID" + + stagemsg='Joiner-Recv' + + MODULE="${WSREP_SST_OPT_MODULE:-xtrabackup_sst}" + + [ -f "$DATA/$IST_FILE" ] && rm -f "$DATA/$IST_FILE" + + # May need xtrabackup_checkpoints later on + [ -f "$DATA/xtrabackup_binary" ] && rm -f "$DATA/xtrabackup_binary" + [ -f "$DATA/xtrabackup_galera_info" ] && rm -f "$DATA/xtrabackup_galera_info" + + ADDR="$WSREP_SST_OPT_HOST" + + if [ "${tmode#VERIFY}" != "$tmode" ]; then + # backward-incompatible behavior: + CN="" + if [ -n "$tpem" ]; then + # find out my Common Name + get_openssl + if [ -z "$OPENSSL_BINARY" ]; then + wsrep_log_error \ + 'openssl not found but it is required for authentication' + exit 42 + fi + CN=$("$OPENSSL_BINARY" x509 -noout -subject -in "$tpem" | \ + tr ',' '\n' | grep -F 'CN =' | cut -d '=' -f2 | sed s/^\ // | \ + sed s/\ %//) + fi + MY_SECRET="$(wsrep_gen_secret)" + # Add authentication data to address + ADDR="$CN:$MY_SECRET@$ADDR" + else + MY_SECRET="" # for check down in recv_joiner() + fi + + get_keys + if [ $encrypt -eq 1 ]; then + strmcmd="$ecmd | $strmcmd" + fi + + if [ -n "$sdecomp" ]; then + strmcmd="$sdecomp | $strmcmd" + fi + + check_sockets_utils + + trap cleanup_at_exit EXIT + + STATDIR="$(mktemp -d)" + MAGIC_FILE="$STATDIR/$INFO_FILE" + + recv_joiner "$STATDIR" "$stagemsg-gtid" $stimeout 1 1 + + if ! ps -p "$WSREP_SST_OPT_PARENT" >/dev/null 2>&1; then + wsrep_log_error "Parent mysqld process (PID: $WSREP_SST_OPT_PARENT)" \ + "terminated unexpectedly." + exit 32 + fi + + if [ ! -r "$STATDIR/$IST_FILE" ]; then + + adjust_progress + if [ -n "$pcmd" ]; then + if [ -n "$rcmd" ]; then + # redirect pv stderr to rcmd for tagging and output to parent + strmcmd="{ $pcmd 2>&3 | $strmcmd; } 3>&1 | $rcmd" + else + # use user-configured pv output + strmcmd="$pcmd | $strmcmd" + fi + fi + + if [ -d "$DATA/.sst" ]; then + wsrep_log_info \ + "WARNING: Stale temporary SST directory:" \ + "'$DATA/.sst' from previous state transfer, removing..." + rm -rf "$DATA/.sst" + fi + mkdir -p "$DATA/.sst" + (recv_joiner "$DATA/.sst" "$stagemsg-SST" 0 0 0) & + jpid=$! + wsrep_log_info "Proceeding with SST" + + get_binlog + + if [ -n "$WSREP_SST_OPT_BINLOG" ]; then + binlog_dir=$(dirname "$WSREP_SST_OPT_BINLOG") + binlog_base=$(basename "$WSREP_SST_OPT_BINLOG") + binlog_index="$WSREP_SST_OPT_BINLOG_INDEX" + cd "$DATA" + wsrep_log_info "Cleaning the old binary logs" + # If there is a file with binlogs state, delete it: + [ -f "$binlog_base.state" ] && rm "$binlog_base.state" >&2 + # Clean up the old binlog files and index: + if [ -f "$binlog_index" ]; then + while read bin_file || [ -n "$bin_file" ]; do + rm -f "$bin_file" >&2 || : + done < "$binlog_index" + rm "$binlog_index" >&2 + fi + if [ -n "$binlog_dir" -a "$binlog_dir" != '.' -a \ + -d "$binlog_dir" ] + then + cd "$binlog_dir" + if [ "$(pwd)" != "$DATA_DIR" ]; then + wsrep_log_info \ + "Cleaning the binlog directory '$binlog_dir' as well" + fi + fi + rm -f "$binlog_base".[0-9]* >&2 || : + cd "$OLD_PWD" + fi + + wsrep_log_info \ + "Cleaning the existing datadir and innodb-data/log directories" + + find $findopt ${ib_home_dir:+"$ib_home_dir"} \ + ${ib_undo_dir:+"$ib_undo_dir"} \ + ${ib_log_dir:+"$ib_log_dir"} \ + ${ar_log_dir:+"$ar_log_dir"} \ + "$DATA" -mindepth 1 -prune -regex "$cpat" \ + -o -exec rm -rf {} >&2 \+ + + TDATA="$DATA" + DATA="$DATA/.sst" + + MAGIC_FILE="$DATA/$INFO_FILE" + wsrep_log_info "Waiting for SST streaming to complete!" + monitor_process $jpid + + if [ ! -s "$DATA/xtrabackup_checkpoints" ]; then + wsrep_log_error "xtrabackup_checkpoints missing," \ + "failed mariadb-backup/SST on donor" + exit 2 + fi + + # Compact backups are not supported by mariadb-backup + if grep -qw -F 'compact = 1' "$DATA/xtrabackup_checkpoints"; then + wsrep_log_info "Index compaction detected" + wsrel_log_error "Compact backups are not supported by mariadb-backup" + exit 2 + fi + + qpfiles=$(find $findopt "$DATA" -maxdepth 1 -type f -name '*.qp' -print -quit) + if [ -n "$qpfiles" ]; then + wsrep_log_info "Compressed qpress files found" + + if [ -z "$(commandex qpress)" ]; then + wsrep_log_error "qpress utility not found in the path" + exit 22 + fi + + get_proc + + dcmd="xargs -n 2 qpress -dT$nproc" + + if [ -n "$progress" -a "$progress" != 'none' ] && \ + pv --help | grep -qw -F -- '--line-mode' + then + count=$(find $findopt "$DATA" -maxdepth 1 -type f -name '*.qp' | wc -l) + count=$(( count*2 )) + pvopts='-f -l -N Decompression' + pvformat="-F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'" + payload=$count + adjust_progress + dcmd="$pcmd | $dcmd" + fi + + # Decompress the qpress files + wsrep_log_info "Decompression with $nproc threads" + timeit 'Joiner-Decompression' \ + "find $findopt '$DATA' -type f -name '*.qp' -printf '%p\n%h\n' | \ + $dcmd" + extcode=$? + + if [ $extcode -eq 0 ]; then + wsrep_log_info "Removing qpress files after decompression" + find $findopt "$DATA" -type f -name '*.qp' -delete + if [ $? -ne 0 ]; then + wsrep_log_error \ + "Something went wrong with deletion of qpress files." \ + "Investigate" + fi + else + wsrep_log_error "Decompression failed. Exit code: $extcode" + exit 22 + fi + fi + + wsrep_log_info "Preparing the backup at $DATA" + setup_commands + timeit 'mariadb-backup prepare stage' "$INNOAPPLY" + if [ $? -ne 0 ]; then + wsrep_log_error "mariadb-backup apply finished with errors." \ + "Check syslog or '$INNOAPPLYLOG' for details." + exit 22 + fi + + if [ -n "$WSREP_SST_OPT_BINLOG" ]; then + cd "$DATA" + binlogs="" + if [ -f 'xtrabackup_binlog_info' ]; then + NL=$'\n' + while read bin_string || [ -n "$bin_string" ]; do + bin_file=$(echo "$bin_string" | cut -f1) + if [ -f "$bin_file" ]; then + binlogs="$binlogs${binlogs:+$NL}$bin_file" + fi + done < 'xtrabackup_binlog_info' + else + binlogs=$(ls -d -1 "$binlog_base".[0-9]* 2>/dev/null || :) + fi + cd "$DATA_DIR" + if [ -n "$binlog_dir" -a "$binlog_dir" != '.' -a \ + "$binlog_dir" != "$DATA_DIR" ] + then + [ ! -d "$binlog_dir" ] && mkdir -p "$binlog_dir" + fi + index_dir=$(dirname "$binlog_index"); + if [ -n "$index_dir" -a "$index_dir" != '.' -a \ + "$index_dir" != "$DATA_DIR" ] + then + [ ! -d "$index_dir" ] && mkdir -p "$index_dir" + fi + if [ -n "$binlogs" ]; then + wsrep_log_info "Moving binary logs to $binlog_dir" + echo "$binlogs" | \ + while read bin_file || [ -n "$bin_file" ]; do + mv "$DATA/$bin_file" "$binlog_dir" + echo "$binlog_dir${binlog_dir:+/}$bin_file" >> "$binlog_index" + done + fi + cd "$OLD_PWD" + fi + + MAGIC_FILE="$TDATA/$INFO_FILE" + + wsrep_log_info "Moving the backup to $TDATA" + timeit 'mariadb-backup move stage' "$INNOMOVE" + if [ $? -eq 0 ]; then + wsrep_log_info "Move successful, removing $DATA" + rm -rf "$DATA" + DATA="$TDATA" + else + wsrep_log_error "Move failed, keeping '$DATA' for further diagnosis" + wsrep_log_error "Check syslog or '$INNOMOVELOG' for details" + exit 22 + fi + + else + + wsrep_log_info "'$IST_FILE' received from donor: Running IST" + if [ $WSREP_SST_OPT_BYPASS -eq 0 ]; then + readonly WSREP_SST_OPT_BYPASS=1 + readonly WSREP_TRANSFER_TYPE='IST' + fi + + fi + + if [ ! -r "$MAGIC_FILE" ]; then + wsrep_log_error "SST magic file '$MAGIC_FILE' not found/readable" + exit 2 + fi + + # Remove special tags from the magic file, and from the output: + coords=$(head -n1 "$MAGIC_FILE") + wsrep_log_info "Galera co-ords from recovery: $coords" + echo "$coords" # Output : UUID:seqno wsrep_gtid_domain_id + + wsrep_log_info "Total time on joiner: $totime seconds" +fi + +wsrep_log_info "$WSREP_METHOD $WSREP_TRANSFER_TYPE completed on $WSREP_SST_OPT_ROLE" +exit 0 diff --git a/scripts/wsrep_sst_mysqldump.sh b/scripts/wsrep_sst_mysqldump.sh new file mode 100644 index 00000000..87b54b59 --- /dev/null +++ b/scripts/wsrep_sst_mysqldump.sh @@ -0,0 +1,173 @@ +#!/usr/bin/env bash + +set -ue + +# Copyright (C) 2009-2015 Codership Oy +# Copyright (C) 2017-2022 MariaDB +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1335 USA. + +# This is a reference script for mysqldump-based state snapshot tansfer + +. $(dirname "$0")/wsrep_sst_common + +EINVAL=22 + +if test -z "$WSREP_SST_OPT_HOST"; then wsrep_log_error "HOST cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_PORT"; then wsrep_log_error "PORT cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_LPORT"; then wsrep_log_error "LPORT cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_SOCKET";then wsrep_log_error "SOCKET cannot be nil";exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_GTID"; then wsrep_log_error "GTID cannot be nil"; exit $EINVAL; fi + +if is_local_ip "$WSREP_SST_OPT_HOST_UNESCAPED" && \ + [ "$WSREP_SST_OPT_PORT" = "$WSREP_SST_OPT_LPORT" ] +then + wsrep_log_error \ + "destination address '$WSREP_SST_OPT_HOST:$WSREP_SST_OPT_PORT' matches source address." + exit $EINVAL +fi + +# Check client version +if ! $MYSQL_CLIENT --version | grep -q -E 'Distrib 10\.[1-9]'; then + $MYSQL_CLIENT --version >&2 + wsrep_log_error "this operation requires MySQL client version 10.1 or newer" + exit $EINVAL +fi + +AUTH="" +usrst=0 +if [ -n "$WSREP_SST_OPT_USER" ]; then + AUTH="-u$WSREP_SST_OPT_USER" + usrst=1 +fi + +# Refs https://github.com/codership/mysql-wsrep/issues/141 +# Passing password in MYSQL_PWD environment variable is considered +# "extremely insecure" by MySQL Guidelines for Password Security +# (https://dev.mysql.com/doc/refman/5.6/en/password-security-user.html) +# that is even less secure than passing it on a command line! It is doubtful: +# the whole command line is easily observable by any unprivileged user via ps, +# whereas (at least on Linux) unprivileged user can't see process environment +# that he does not own. So while it may be not secure in the NSA sense of the +# word, it is arguably more secure than passing password on the command line. +if [ -n "$WSREP_SST_OPT_PSWD" ]; then + export MYSQL_PWD="$WSREP_SST_OPT_PSWD" +elif [ $usrst -eq 1 ]; then + # Empty password, used for testing, debugging etc. + unset MYSQL_PWD +fi + +STOP_WSREP='SET wsrep_on=OFF;' + +# mysqldump cannot restore CSV tables, fix this issue +CSV_TABLES_FIX=" +set sql_mode=''; + +USE mysql; + +SET @cond = (SELECT (SUPPORT = 'YES' or SUPPORT = 'DEFAULT') FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE = 'csv'); + +SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS general_log ( event_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL, server_id int(10) unsigned NOT NULL, command_type varchar(64) NOT NULL, argument mediumtext NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8mb3 COMMENT=\"General log\"', 'SET @dummy = 0'); + +PREPARE stmt FROM @stmt; +EXECUTE stmt; +DROP PREPARE stmt; + +SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS slow_log ( start_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, query_time time(6) NOT NULL, lock_time time(6) NOT NULL, rows_sent bigint(20) UNSIGNED NOT NULL, rows_examined bigint(20) UNSIGNED NOT NULL, db varchar(512) NOT NULL, last_insert_id int(11) NOT NULL, insert_id int(11) NOT NULL, server_id int(10) unsigned NOT NULL, sql_text mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8mb3 COMMENT=\"Slow log\"', 'SET @dummy = 0'); + +PREPARE stmt FROM @stmt; +EXECUTE stmt; +DROP PREPARE stmt;" + +SET_START_POSITION="SET GLOBAL wsrep_start_position='$WSREP_SST_OPT_GTID';" + +SET_WSREP_GTID_DOMAIN_ID="" +if [ -n "$WSREP_SST_OPT_GTID_DOMAIN_ID" ]; then + SET_WSREP_GTID_DOMAIN_ID=" + SET @val = (SELECT GLOBAL_VALUE FROM INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE VARIABLE_NAME = 'WSREP_GTID_STRICT_MODE' AND GLOBAL_VALUE > 0); + SET @stmt = IF (@val IS NOT NULL, 'SET GLOBAL WSREP_GTID_DOMAIN_ID=$WSREP_SST_OPT_GTID_DOMAIN_ID', 'SET @dummy = 0'); + PREPARE stmt FROM @stmt; + EXECUTE stmt; + DROP PREPARE stmt;" +fi + +MYSQL="$MYSQL_CLIENT$WSREP_SST_OPT_CONF_UNQUOTED "\ +"$AUTH -h$WSREP_SST_OPT_HOST_UNESCAPED "\ +"-P$WSREP_SST_OPT_PORT --disable-reconnect --connect_timeout=10" + +# Check if binary logging is enabled on the joiner node. +# Note: SELECT cannot be used at this point. +LOG_BIN=$(echo "set statement wsrep_sync_wait=0 for SHOW VARIABLES LIKE 'log_bin'" | $MYSQL | \ +tail -1 | awk -F ' ' '{ print $2 }') + +# Check the joiner node's server version. +SERVER_VERSION=$(echo "set statement wsrep_sync_wait=0 for SHOW VARIABLES LIKE 'version'" | $MYSQL | \ +tail -1 | awk -F ' ' '{ print $2 }') + +# Retrieve the donor's @@global.gtid_binlog_state. +GTID_BINLOG_STATE=$(echo "SHOW GLOBAL VARIABLES LIKE 'gtid_binlog_state'" | $MYSQL | \ +tail -1 | awk -F ' ' '{ print $2 }') + +RESET_MASTER="" +SET_GTID_BINLOG_STATE="" +SQL_LOG_BIN_OFF="" + +# Safety check +if [ ${SERVER_VERSION%%.*} -gt 5 ]; then + # If binary logging is enabled on the joiner node, we need to copy donor's + # gtid_binlog_state to joiner. In order to do that, a RESET MASTER must be + # executed to erase binary logs (if any). Binary logging should also be + # turned off for the session so that gtid state does not get altered while + # the dump gets replayed on joiner. + if [ "$LOG_BIN" = 'ON' ]; then + RESET_MASTER="SET GLOBAL wsrep_on=OFF; RESET MASTER; SET GLOBAL wsrep_on=ON;" + SET_GTID_BINLOG_STATE="SET GLOBAL wsrep_on=OFF; SET @@global.gtid_binlog_state='$GTID_BINLOG_STATE'; SET GLOBAL wsrep_on=ON;" + SQL_LOG_BIN_OFF="SET @@session.sql_log_bin=OFF;" + fi +fi + +# NOTE: we don't use --routines here because we're dumping mysql.proc table +MYSQLDUMP="$MYSQLDUMP$WSREP_SST_OPT_CONF_UNQUOTED $AUTH -S$WSREP_SST_OPT_SOCKET \ +--add-drop-database --add-drop-table --skip-add-locks --create-options \ +--disable-keys --extended-insert --skip-lock-tables --quick --set-charset \ +--skip-comments --flush-privileges --all-databases --events" + +if [ $WSREP_SST_OPT_BYPASS -eq 0 ] +then + # need to disable logging when loading the dump + # reason is that dump contains ALTER TABLE for log tables, and + # this causes an error if logging is enabled + GENERAL_LOG_OPT=$($MYSQL --skip-column-names -e "$STOP_WSREP SELECT @@GENERAL_LOG") + SLOW_LOG_OPT=$($MYSQL --skip-column-names -e "$STOP_WSREP SELECT @@LOG_SLOW_QUERY") + + LOG_OFF="SET GLOBAL GENERAL_LOG=OFF; SET GLOBAL LOG_SLOW_QUERY=OFF;" + + # commands to restore log settings + RESTORE_GENERAL_LOG="SET GLOBAL GENERAL_LOG=$GENERAL_LOG_OPT;" + RESTORE_SLOW_QUERY_LOG="SET GLOBAL LOG_SLOW_QUERY=$SLOW_LOG_OPT;" + + (echo "$STOP_WSREP" && echo "$LOG_OFF" && echo "$RESET_MASTER" && \ + echo "$SET_GTID_BINLOG_STATE" && echo "$SQL_LOG_BIN_OFF" && \ + echo "$STOP_WSREP" && $MYSQLDUMP && echo "$CSV_TABLES_FIX" && \ + echo "$RESTORE_GENERAL_LOG" && echo "$RESTORE_SLOW_QUERY_LOG" && \ + echo "$SET_START_POSITION" && echo "$SET_WSREP_GTID_DOMAIN_ID" \ + || echo "SST failed to complete;") | $MYSQL || exit $? +else + wsrep_log_info "Bypassing state dump." + echo "$SET_START_POSITION" | $MYSQL || exit $? +fi + +wsrep_log_info "$WSREP_METHOD $WSREP_TRANSFER_TYPE completed on $WSREP_SST_OPT_ROLE" +exit 0 diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh new file mode 100644 index 00000000..a8bfc413 --- /dev/null +++ b/scripts/wsrep_sst_rsync.sh @@ -0,0 +1,1011 @@ +#!/usr/bin/env bash + +set -ue + +# Copyright (C) 2017-2022 MariaDB +# Copyright (C) 2010-2022 Codership Oy +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1335 USA. + +# This is a reference script for rsync-based state snapshot transfer + +RSYNC_REAL_PID=0 # rsync process id +STUNNEL_REAL_PID=0 # stunnel process id + +OS="$(uname)" +[ "$OS" = 'Darwin' ] && export -n LD_LIBRARY_PATH + +. $(dirname "$0")/wsrep_sst_common +wsrep_check_datadir + +wsrep_check_programs rsync + +cleanup_joiner() +{ + # Since this is invoked just after exit NNN + local estatus=$? + if [ $estatus -ne 0 ]; then + wsrep_log_error "Cleanup after exit with status: $estatus" + elif [ -z "${coords:-}" ]; then + estatus=32 + wsrep_log_error "Failed to get current position" + fi + + local failure=0 + + [ "$(pwd)" != "$OLD_PWD" ] && cd "$OLD_PWD" + + wsrep_log_info "Joiner cleanup: rsync PID=$RSYNC_REAL_PID," \ + "stunnel PID=$STUNNEL_REAL_PID" + + if [ -n "$STUNNEL" ]; then + if cleanup_pid $STUNNEL_REAL_PID "$STUNNEL_PID" "$STUNNEL_CONF"; then + if [ $RSYNC_REAL_PID -eq 0 ]; then + if [ -r "$RSYNC_PID" ]; then + RSYNC_REAL_PID=$(cat "$RSYNC_PID" 2>/dev/null || :) + if [ -z "$RSYNC_REAL_PID" ]; then + RSYNC_REAL_PID=0 + fi + fi + fi + else + wsrep_log_warning "stunnel cleanup failed." + failure=1 + fi + fi + + if [ $failure -eq 0 ]; then + if cleanup_pid $RSYNC_REAL_PID "$RSYNC_PID" "$RSYNC_CONF"; then + [ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" || : + [ -f "$BINLOG_TAR_FILE" ] && rm -f "$BINLOG_TAR_FILE" || : + else + wsrep_log_warning "rsync cleanup failed." + fi + fi + + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + wsrep_cleanup_progress_file + fi + + [ -f "$SST_PID" ] && rm -f "$SST_PID" || : + + wsrep_log_info "Joiner cleanup done." + + exit $estatus +} + +check_pid_and_port() +{ + local pid_file="$1" + local pid=$2 + local addr="$3" + local port="$4" + + local utils='rsync|stunnel' + + if ! check_port $pid "$port" "$utils"; then + local port_info + local busy=0 + + if [ $lsof_available -ne 0 ]; then + port_info=$(lsof -Pnl -i ":$port" 2>/dev/null | \ + grep -F '(LISTEN)') + echo "$port_info" | \ + grep -q -E "[[:space:]](\\*|\\[?::\\]?):$port[[:space:]]" && busy=1 + else + local filter='([^[:space:]]+[[:space:]]+){4}[^[:space:]]+' + if [ $sockstat_available -ne 0 ]; then + local opts='-p' + if [ "$OS" = 'FreeBSD' ]; then + # sockstat on FreeBSD requires the "-s" option + # to display the connection state: + opts='-sp' + # in addition, sockstat produces an additional column: + filter='([^[:space:]]+[[:space:]]+){5}[^[:space:]]+' + fi + port_info=$(sockstat "$opts" "$port" 2>/dev/null | \ + grep -E '[[:space:]]LISTEN' | grep -o -E "$filter") + else + port_info=$(ss -nlpH "( sport = :$port )" 2>/dev/null | \ + grep -F 'users:(' | grep -o -E "$filter") + fi + echo "$port_info" | \ + grep -q -E "[[:space:]](\\*|\\[?::\\]?):$port\$" && busy=1 + fi + + if [ $busy -eq 0 ]; then + if ! echo "$port_info" | grep -qw -F "[$addr]:$port" && \ + ! echo "$port_info" | grep -qw -F -- "$addr:$port" + then + if ! ps -p $pid >/dev/null 2>&1; then + wsrep_log_error \ + "rsync or stunnel daemon (PID: $pid)" \ + "terminated unexpectedly." + exit 16 # EBUSY + fi + return 1 + fi + fi + + if ! check_port $pid "$port" "$utils"; then + wsrep_log_error "rsync or stunnel daemon port '$port'" \ + "has been taken by another program" + exit 16 # EBUSY + fi + fi + + check_pid "$pid_file" && [ $CHECK_PID -eq $pid ] +} + +STUNNEL_CONF="$WSREP_SST_OPT_DATA/stunnel.conf" +STUNNEL_PID="$WSREP_SST_OPT_DATA/stunnel.pid" + +MAGIC_FILE="$WSREP_SST_OPT_DATA/rsync_sst_complete" + +get_binlog + +if [ -n "$WSREP_SST_OPT_BINLOG" ]; then + binlog_dir=$(dirname "$WSREP_SST_OPT_BINLOG") + binlog_base=$(basename "$WSREP_SST_OPT_BINLOG") +fi + +OLD_PWD="$(pwd)" + +DATA="$WSREP_SST_OPT_DATA" +if [ -n "$DATA" -a "$DATA" != '.' ]; then + [ ! -d "$DATA" ] && mkdir -p "$DATA" + cd "$DATA" +fi +DATA_DIR="$(pwd)" + +cd "$OLD_PWD" + +BINLOG_TAR_FILE="$DATA_DIR/wsrep_sst_binlog.tar" + +ar_log_dir="$DATA_DIR" +ib_log_dir="$DATA_DIR" +ib_home_dir="$DATA_DIR" +ib_undo_dir="$DATA_DIR" + +# if no command line argument and INNODB_LOG_GROUP_HOME is not set, +# then try to get it from the my.cnf: +if [ -z "$INNODB_LOG_GROUP_HOME" ]; then + INNODB_LOG_GROUP_HOME=$(parse_cnf '--mysqld' 'innodb-log-group-home-dir') + INNODB_LOG_GROUP_HOME=$(trim_dir "$INNODB_LOG_GROUP_HOME") +fi + +if [ -n "$INNODB_LOG_GROUP_HOME" -a "$INNODB_LOG_GROUP_HOME" != '.' -a \ + "$INNODB_LOG_GROUP_HOME" != "$DATA_DIR" ] +then + # handle both relative and absolute paths: + cd "$DATA" + [ ! -d "$INNODB_LOG_GROUP_HOME" ] && mkdir -p "$INNODB_LOG_GROUP_HOME" + cd "$INNODB_LOG_GROUP_HOME" + ib_log_dir="$(pwd)" + cd "$OLD_PWD" +fi + +# if no command line argument and INNODB_DATA_HOME_DIR environment +# variable is not set, try to get it from the my.cnf: +if [ -z "$INNODB_DATA_HOME_DIR" ]; then + INNODB_DATA_HOME_DIR=$(parse_cnf '--mysqld' 'innodb-data-home-dir') + INNODB_DATA_HOME_DIR=$(trim_dir "$INNODB_DATA_HOME_DIR") +fi + +if [ -n "$INNODB_DATA_HOME_DIR" -a "$INNODB_DATA_HOME_DIR" != '.' -a \ + "$INNODB_DATA_HOME_DIR" != "$DATA_DIR" ] +then + # handle both relative and absolute paths: + cd "$DATA" + [ ! -d "$INNODB_DATA_HOME_DIR" ] && mkdir -p "$INNODB_DATA_HOME_DIR" + cd "$INNODB_DATA_HOME_DIR" + ib_home_dir="$(pwd)" + cd "$OLD_PWD" +fi + +# if no command line argument and INNODB_UNDO_DIR is not set, +# then try to get it from the my.cnf: +if [ -z "$INNODB_UNDO_DIR" ]; then + INNODB_UNDO_DIR=$(parse_cnf '--mysqld' 'innodb-undo-directory') + INNODB_UNDO_DIR=$(trim_dir "$INNODB_UNDO_DIR") +fi + +if [ -n "$INNODB_UNDO_DIR" -a "$INNODB_UNDO_DIR" != '.' -a \ + "$INNODB_UNDO_DIR" != "$DATA_DIR" ] +then + # handle both relative and absolute paths: + cd "$DATA" + [ ! -d "$INNODB_UNDO_DIR" ] && mkdir -p "$INNODB_UNDO_DIR" + cd "$INNODB_UNDO_DIR" + ib_undo_dir="$(pwd)" + cd "$OLD_PWD" +fi + +# if no command line argument then try to get it from the my.cnf: +if [ -z "$ARIA_LOG_DIR" ]; then + ARIA_LOG_DIR=$(parse_cnf '--mysqld' 'aria-log-dir-path') + ARIA_LOG_DIR=$(trim_dir "$ARIA_LOG_DIR") +fi + +if [ -n "$ARIA_LOG_DIR" -a "$ARIA_LOG_DIR" != '.' -a \ + "$ARIA_LOG_DIR" != "$DATA_DIR" ] +then + # handle both relative and absolute paths: + cd "$DATA" + [ ! -d "$ARIA_LOG_DIR" ] && mkdir -p "$ARIA_LOG_DIR" + cd "$ARIA_LOG_DIR" + ar_log_dir="$(pwd)" + cd "$OLD_PWD" +fi + +encgroups='--mysqld|sst' + +check_server_ssl_config + +SSTKEY="$tkey" +SSTCERT="$tpem" +SSTCA="$tcert" +SSTCAP="$tcap" + +SSLMODE=$(parse_cnf "$encgroups" 'ssl-mode' | tr '[[:lower:]]' '[[:upper:]]') + +if [ -z "$SSLMODE" ]; then + # Implicit verification if CA is set and the SSL mode + # is not specified by user: + if [ -n "$SSTCA$SSTCAP" ]; then + STUNNEL_BIN=$(commandex 'stunnel') + if [ -n "$STUNNEL_BIN" ]; then + SSLMODE='VERIFY_CA' + fi + # Require SSL by default if SSL key and cert are present: + elif [ -n "$SSTKEY" -a -n "$SSTCERT" ]; then + SSLMODE='REQUIRED' + fi +else + case "$SSLMODE" in + 'VERIFY_IDENTITY'|'VERIFY_CA'|'REQUIRED'|'DISABLED') + ;; + *) + wsrep_log_error "Unrecognized ssl-mode option: '$SSLMODE'" + exit 22 # EINVAL + ;; + esac +fi + +if [ -n "$SSTKEY" -a -n "$SSTCERT" ]; then + verify_cert_matches_key "$SSTCERT" "$SSTKEY" +fi + +CAFILE_OPT="" +CAPATH_OPT="" +if [ -n "$SSTCA$SSTCAP" ]; then + if [ -n "$SSTCA" ]; then + CAFILE_OPT="CAfile = $SSTCA" + fi + if [ -n "$SSTCAP" ]; then + CAPATH_OPT="CApath = $SSTCAP" + fi + if [ -n "$SSTCERT" ]; then + verify_ca_matches_cert "$SSTCERT" "$SSTCA" "$SSTCAP" + fi +fi + +VERIFY_OPT="" +CHECK_OPT="" +CHECK_OPT_LOCAL="" +if [ "${SSLMODE#VERIFY}" != "$SSLMODE" ]; then + if [ "$SSLMODE" = 'VERIFY_IDENTITY' ]; then + VERIFY_OPT='verifyPeer = yes' + else + VERIFY_OPT='verifyChain = yes' + fi + if [ -z "$SSTCA$SSTCAP" ]; then + wsrep_log_error "Can't have ssl-mode='$SSLMODE' without CA file or path" + exit 22 # EINVAL + fi + if [ -n "$WSREP_SST_OPT_REMOTE_USER" ]; then + CHECK_OPT="checkHost = $WSREP_SST_OPT_REMOTE_USER" + elif [ "$WSREP_SST_OPT_ROLE" = 'donor' ]; then + # check if the address is an ip-address (v4 or v6): + if echo "$WSREP_SST_OPT_HOST_UNESCAPED" | \ + grep -q -E '^([0-9]+(\.[0-9]+){3}|[0-9a-fA-F]*(\:[0-9a-fA-F]*)+)$' + then + CHECK_OPT="checkIP = $WSREP_SST_OPT_HOST_UNESCAPED" + else + CHECK_OPT="checkHost = $WSREP_SST_OPT_HOST" + fi + if is_local_ip "$WSREP_SST_OPT_HOST_UNESCAPED"; then + CHECK_OPT_LOCAL='checkHost = localhost' + fi + fi +fi + +STUNNEL="" +if [ -n "$SSLMODE" -a "$SSLMODE" != 'DISABLED' ]; then + if [ -z "${STUNNEL_BIN+x}" ]; then + STUNNEL_BIN=$(commandex 'stunnel') + fi + if [ -n "$STUNNEL_BIN" ]; then + wsrep_log_info "Using stunnel for SSL encryption: CA: '$SSTCA'," \ + "CAPATH='$SSTCAP', ssl-mode='$SSLMODE'" + STUNNEL="$STUNNEL_BIN $STUNNEL_CONF" + fi +fi + +readonly SECRET_TAG='secret' +readonly BYPASS_TAG='bypass' + +SST_PID="$WSREP_SST_OPT_DATA/wsrep_sst.pid" + +# give some time for previous SST to complete: +check_round=0 +while check_pid "$SST_PID" 0; do + wsrep_log_info "Previous SST is not completed, waiting for it to exit" + check_round=$(( check_round + 1 )) + if [ $check_round -eq 20 ]; then + wsrep_log_error "previous SST script still running." + exit 114 # EALREADY + fi + sleep 1 +done + +trap simple_cleanup EXIT +echo $$ > "$SST_PID" + +# give some time for stunnel from the previous SST to complete: +check_round=0 +while check_pid "$STUNNEL_PID" 1 "$STUNNEL_CONF"; do + wsrep_log_info "Lingering stunnel daemon found at startup," \ + "waiting for it to exit" + check_round=$(( check_round + 1 )) + if [ $check_round -eq 10 ]; then + wsrep_log_error "stunnel daemon still running." + exit 114 # EALREADY + fi + sleep 1 +done + +MODULE="${WSREP_SST_OPT_MODULE:-rsync_sst}" + +RSYNC_PID="$WSREP_SST_OPT_DATA/$MODULE.pid" +RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf" + +# give some time for rsync from the previous SST to complete: +check_round=0 +while check_pid "$RSYNC_PID" 1 "$RSYNC_CONF"; do + wsrep_log_info "Lingering rsync daemon found at startup," \ + "waiting for it to exit" + check_round=$(( check_round + 1 )) + if [ $check_round -eq 10 ]; then + wsrep_log_error "rsync daemon still running." + exit 114 # EALREADY + fi + sleep 1 +done + +[ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" +[ -f "$BINLOG_TAR_FILE" ] && rm -f "$BINLOG_TAR_FILE" + +RC=0 + +if [ "$WSREP_SST_OPT_ROLE" = 'donor' ]; then + + if [ -n "$STUNNEL" ]; then + cat << EOF > "$STUNNEL_CONF" +key = $SSTKEY +cert = $SSTCERT +${CAFILE_OPT} +${CAPATH_OPT} +foreground = yes +pid = $STUNNEL_PID +debug = warning +client = yes +connect = $WSREP_SST_OPT_HOST_UNESCAPED:$WSREP_SST_OPT_PORT +TIMEOUTclose = 0 +${VERIFY_OPT} +${CHECK_OPT} +${CHECK_OPT_LOCAL} +EOF + fi + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ]; then + + FLUSHED="$WSREP_SST_OPT_DATA/tables_flushed" + ERROR="$WSREP_SST_OPT_DATA/sst_error" + + [ -f "$FLUSHED" ] && rm -f "$FLUSHED" + [ -f "$ERROR" ] && rm -f "$ERROR" + + echo 'flush tables' + + # Wait for : + # (a) Tables to be flushed, AND + # (b) Cluster state ID & wsrep_gtid_domain_id to be written to the file, OR + # (c) ERROR file, in case flush tables operation failed. + + while [ ! -r "$FLUSHED" ] || \ + ! grep -q -F ':' -- "$FLUSHED" + do + # Check whether ERROR file exists. + if [ -f "$ERROR" ]; then + # Flush tables operation failed. + rm "$ERROR" + exit 255 + fi + sleep 0.2 + done + + STATE=$(cat "$FLUSHED") + rm "$FLUSHED" + + sync + + wsrep_log_info "Tables flushed" + + if [ -n "$WSREP_SST_OPT_BINLOG" ]; then + # Change the directory to binlog base (if possible): + cd "$DATA" + # Let's check the existence of the file with the index: + if [ -f "$WSREP_SST_OPT_BINLOG_INDEX" ]; then + # Let's read the binlog index: + max_binlogs=$(parse_cnf "$encgroups" 'sst-max-binlogs' 1) + if [ $max_binlogs -ge 0 ]; then + binlog_files="" + if [ $max_binlogs -gt 0 ]; then + binlog_files=$(tail -n $max_binlogs \ + "$WSREP_SST_OPT_BINLOG_INDEX") + fi + else + binlog_files=$(cat "$WSREP_SST_OPT_BINLOG_INDEX") + fi + if [ -n "$binlog_files" ]; then + # Preparing binlog files for transfer: + wsrep_log_info "Preparing binlog files for transfer:" + tar_type=0 + if tar --help | grep -qw -F -- '--transform'; then + tar_type=1 + elif tar --version | grep -qw -E '^bsdtar'; then + tar_type=2 + fi + if [ $tar_type -eq 2 ]; then + if [ -n "$BASH_VERSION" ]; then + printf '%s' "$binlog_files" >&2 + else + echo "$binlog_files" >&2 + fi + fi + if [ $tar_type -ne 0 ]; then + # Preparing list of the binlog file names: + echo "$binlog_files" | { + binlogs="" + while read bin_file || [ -n "$bin_file" ]; do + [ ! -f "$bin_file" ] && continue + if [ -n "$BASH_VERSION" ]; then + first="${bin_file:0:1}" + else + first=$(echo "$bin_file" | cut -c1) + fi + if [ "$first" = '-' -o "$first" = '@' ]; then + bin_file="./$bin_file" + fi + binlogs="$binlogs${binlogs:+ }'$bin_file'" + done + if [ -n "$binlogs" ]; then + if [ $tar_type -eq 1 ]; then + tar_options="--transform='s/^.*\///g'" + else + # bsdtar handles backslash incorrectly: + tar_options="-s '?^.*/??g'" + fi + eval tar -P $tar_options \ + -cvf "'$BINLOG_TAR_FILE'" $binlogs >&2 + fi + } + else + tar_options='-cvf' + echo "$binlog_files" | \ + while read bin_file || [ -n "$bin_file" ]; do + [ ! -f "$bin_file" ] && continue + bin_dir=$(dirname "$bin_file") + bin_base=$(basename "$bin_file") + if [ -n "$BASH_VERSION" ]; then + first="${bin_base:0:1}" + else + first=$(echo "$bin_base" | cut -c1) + fi + if [ "$first" = '-' -o "$first" = '@' ]; then + bin_base="./$bin_base" + fi + if [ -n "$bin_dir" -a "$bin_dir" != '.' -a \ + "$bin_dir" != "$DATA_DIR" ] + then + tar $tar_options "$BINLOG_TAR_FILE" \ + -C "$bin_dir" "$bin_base" >&2 + else + tar $tar_options "$BINLOG_TAR_FILE" \ + "$bin_base" >&2 + fi + tar_options='-rvf' + done + fi + fi + fi + cd "$OLD_PWD" + fi + + # Use deltaxfer only for WAN: + WHOLE_FILE_OPT="" + if [ "${WSREP_METHOD%_wan}" = "$WSREP_METHOD" ]; then + WHOLE_FILE_OPT='--whole-file' + fi + +# Old filter - include everything except selected +# FILTER=(--exclude '*.err' --exclude '*.pid' --exclude '*.sock' \ +# --exclude '*.conf' --exclude core --exclude 'galera.*' \ +# --exclude grastate.txt --exclude '*.pem' \ +# --exclude '*.[0-9][0-9][0-9][0-9][0-9][0-9]' --exclude '*.index') + +# New filter - exclude everything except dirs (schemas) and innodb files +FILTER="-f '- /lost+found' + -f '- /.zfs' + -f '- /.fseventsd' + -f '- /.Trashes' + -f '- /.pid' + -f '- /.conf' + -f '- /.snapshot/' + -f '+ /wsrep_sst_binlog.tar' + -f '- $ib_home_dir/ib_lru_dump' + -f '- $ib_home_dir/ibdata*' + -f '- $ib_undo_dir/undo*' + -f '- $ib_log_dir/ib_logfile[0-9]*' + -f '- $ar_log_dir/aria_log_control' + -f '- $ar_log_dir/aria_log.*' + -f '+ /*/' + -f '- /*'" + + # first, the normal directories, so that we can detect + # incompatible protocol: + eval rsync ${STUNNEL:+"--rsh='$STUNNEL'"} \ + --owner --group --perms --links --specials \ + --ignore-times --inplace --dirs --delete --quiet \ + $WHOLE_FILE_OPT $FILTER "'$WSREP_SST_OPT_DATA/'" \ + "'rsync://$WSREP_SST_OPT_ADDR'" >&2 || RC=$? + + if [ $RC -ne 0 ]; then + wsrep_log_error "rsync returned code $RC:" + case $RC in + 12) RC=71 # EPROTO + wsrep_log_error \ + "rsync server on the other end has incompatible" \ + "protocol. Make sure you have the same version of" \ + "rsync on all nodes." + ;; + 22) RC=12 # ENOMEM + ;; + *) RC=255 # unknown error + ;; + esac + exit $RC + fi + + wsrep_log_info "Transfer of normal directories done" + + # Transfer InnoDB data files + rsync ${STUNNEL:+--rsh="$STUNNEL"} \ + --owner --group --perms --links --specials \ + --ignore-times --inplace --dirs --delete --quiet \ + $WHOLE_FILE_OPT -f '+ /ibdata*' -f '+ /ib_lru_dump' \ + -f '- **' "$ib_home_dir/" \ + "rsync://$WSREP_SST_OPT_ADDR-data_dir" >&2 || RC=$? + + if [ $RC -ne 0 ]; then + wsrep_log_error "rsync innodb_data_home_dir returned code $RC:" + exit 255 # unknown error + fi + + wsrep_log_info "Transfer of InnoDB data files done" + + # second, we transfer the InnoDB log file + rsync ${STUNNEL:+--rsh="$STUNNEL"} \ + --owner --group --perms --links --specials \ + --ignore-times --inplace --dirs --delete --quiet \ + $WHOLE_FILE_OPT -f '+ /ib_logfile0' \ + -f '- **' "$ib_log_dir/" \ + "rsync://$WSREP_SST_OPT_ADDR-log_dir" >&2 || RC=$? + + if [ $RC -ne 0 ]; then + wsrep_log_error "rsync innodb_log_group_home_dir returned code $RC:" + exit 255 # unknown error + fi + + wsrep_log_info "Transfer of InnoDB log files done" + + # third, we transfer InnoDB undo logs + rsync ${STUNNEL:+--rsh="$STUNNEL"} \ + --owner --group --perms --links --specials \ + --ignore-times --inplace --dirs --delete --quiet \ + $WHOLE_FILE_OPT -f '+ /undo*' \ + -f '- **' "$ib_undo_dir/" \ + "rsync://$WSREP_SST_OPT_ADDR-undo_dir" >&2 || RC=$? + + if [ $RC -ne 0 ]; then + wsrep_log_error "rsync innodb_undo_dir returned code $RC:" + exit 255 # unknown error + fi + + wsrep_log_info "Transfer of InnoDB undo logs done" + + # fourth, we transfer Aria logs + rsync ${STUNNEL:+--rsh="$STUNNEL"} \ + --owner --group --perms --links --specials \ + --ignore-times --inplace --dirs --delete --quiet \ + $WHOLE_FILE_OPT -f '+ /aria_log_control' -f '+ /aria_log.*' \ + -f '- **' "$ar_log_dir/" \ + "rsync://$WSREP_SST_OPT_ADDR-aria_log" >&2 || RC=$? + + if [ $RC -ne 0 ]; then + wsrep_log_error "rsync aria_log_dir_path returned code $RC:" + exit 255 # unknown error + fi + + wsrep_log_info "Transfer of Aria logs done" + + # then, we parallelize the transfer of database directories, + # use '.' so that path concatenation works: + + backup_threads=$(parse_cnf '--mysqld|sst' 'backup-threads') + if [ -z "$backup_threads" ]; then + get_proc + backup_threads=$nproc + fi + + cd "$DATA" + + findopt='-L' + [ "$OS" = 'FreeBSD' ] && findopt="$findopt -E" + + find $findopt . -maxdepth 1 -mindepth 1 -type d -not -name 'lost+found' \ + -not -name '.zfs' -not -name .snapshot -print0 \ + | xargs -I{} -0 -P $backup_threads \ + rsync ${STUNNEL:+--rsh="$STUNNEL"} \ + --owner --group --perms --links --specials --ignore-times \ + --inplace --recursive --delete --quiet $WHOLE_FILE_OPT \ + -f '- $ib_home_dir/ib_lru_dump' \ + -f '- $ib_home_dir/ibdata*' \ + -f '- $ib_undo_dir/undo*' \ + -f '- $ib_log_dir/ib_logfile[0-9]*' \ + -f '- $ar_log_dir/aria_log_control' \ + -f '- $ar_log_dir/aria_log.*' \ + "$WSREP_SST_OPT_DATA/{}/" \ + "rsync://$WSREP_SST_OPT_ADDR/{}" >&2 || RC=$? + + cd "$OLD_PWD" + + if [ $RC -ne 0 ]; then + wsrep_log_error "find/rsync returned code $RC:" + exit 255 # unknown error + fi + + wsrep_log_info "Transfer of data done" + + [ -f "$BINLOG_TAR_FILE" ] && rm "$BINLOG_TAR_FILE" + + else # BYPASS + + wsrep_log_info "Bypassing state dump." + + # Store donor's wsrep GTID (state ID) and wsrep_gtid_domain_id + # (separated by a space). + STATE="$WSREP_SST_OPT_GTID $WSREP_SST_OPT_GTID_DOMAIN_ID" + + fi + + wsrep_log_info "Sending continue to donor" + echo 'continue' # now server can resume updating data + + echo "$STATE" > "$MAGIC_FILE" + + if [ -n "$WSREP_SST_OPT_REMOTE_PSWD" ]; then + # Let joiner know that we know its secret + echo "$SECRET_TAG $WSREP_SST_OPT_REMOTE_PSWD" >> "$MAGIC_FILE" + fi + + if [ $WSREP_SST_OPT_BYPASS -ne 0 ]; then + echo "$BYPASS_TAG" >> "$MAGIC_FILE" + fi + + rsync ${STUNNEL:+--rsh="$STUNNEL"} \ + --archive --quiet --checksum "$MAGIC_FILE" \ + "rsync://$WSREP_SST_OPT_ADDR" >&2 || RC=$? + + rm "$MAGIC_FILE" + + if [ $RC -ne 0 ]; then + wsrep_log_error "rsync $MAGIC_FILE returned code $RC:" + exit 255 # unknown error + fi + + echo "done $STATE" + + if [ -n "$STUNNEL" ]; then + rm "$STUNNEL_CONF" + [ -f "$STUNNEL_PID" ] && rm "$STUNNEL_PID" + fi + +else # joiner + + check_sockets_utils + + ADDR="$WSREP_SST_OPT_HOST" + RSYNC_PORT="$WSREP_SST_OPT_PORT" + RSYNC_ADDR="$WSREP_SST_OPT_HOST" + RSYNC_ADDR_UNESCAPED="$WSREP_SST_OPT_HOST_UNESCAPED" + + trap cleanup_joiner EXIT + + touch "$SST_PROGRESS_FILE" + + if [ -n "${MYSQL_TMP_DIR:-}" ]; then + SILENT="log file = $MYSQL_TMP_DIR/rsyncd.log" + else + SILENT="" + fi + +cat << EOF > "$RSYNC_CONF" +pid file = $RSYNC_PID +use chroot = no +read only = no +timeout = 300 +$SILENT +[$MODULE] + path = $WSREP_SST_OPT_DATA + exclude = .zfs +[$MODULE-log_dir] + path = $ib_log_dir +[$MODULE-data_dir] + path = $ib_home_dir +[$MODULE-undo_dir] + path = $ib_undo_dir +[$MODULE-aria_log] + path = $ar_log_dir +EOF + + # If the IP is local, listen only on it: + if is_local_ip "$RSYNC_ADDR_UNESCAPED"; then + RSYNC_EXTRA_ARGS="--address $RSYNC_ADDR_UNESCAPED" + STUNNEL_ACCEPT="$RSYNC_ADDR_UNESCAPED:$RSYNC_PORT" + else + # Not local, possibly a NAT, listen on all interfaces: + RSYNC_EXTRA_ARGS="" + STUNNEL_ACCEPT="$RSYNC_PORT" + # Overwrite address with all: + RSYNC_ADDR='*' + fi + + if [ -z "$STUNNEL" ]; then + rsync --daemon --no-detach --port "$RSYNC_PORT" \ + --config "$RSYNC_CONF" $RSYNC_EXTRA_ARGS & + RSYNC_REAL_PID=$! + TRANSFER_REAL_PID=$RSYNC_REAL_PID + TRANSFER_PID="$RSYNC_PID" + else + # Let's check if the path to the config file contains a space? + RSYNC_BIN=$(commandex 'rsync') + if [ "${RSYNC_CONF#* }" = "$RSYNC_CONF" ]; then + cat << EOF > "$STUNNEL_CONF" +key = $SSTKEY +cert = $SSTCERT +${CAFILE_OPT} +${CAPATH_OPT} +foreground = yes +pid = $STUNNEL_PID +debug = warning +client = no +${VERIFY_OPT} +${CHECK_OPT} +${CHECK_OPT_LOCAL} +[rsync] +accept = $STUNNEL_ACCEPT +exec = $RSYNC_BIN +execargs = rsync --server --daemon --config=$RSYNC_CONF . +EOF + else + # The path contains a space, so we will run it via + # shell with "eval" command: + export RSYNC_CMD="eval '$RSYNC_BIN' --server --daemon --config='$RSYNC_CONF' ." + cat << EOF > "$STUNNEL_CONF" +key = $SSTKEY +cert = $SSTCERT +${CAFILE_OPT} +${CAPATH_OPT} +foreground = yes +pid = $STUNNEL_PID +debug = warning +client = no +${VERIFY_OPT} +${CHECK_OPT} +${CHECK_OPT_LOCAL} +[rsync] +accept = $STUNNEL_ACCEPT +exec = $SHELL +execargs = $SHELL -c \$RSYNC_CMD +EOF + fi + stunnel "$STUNNEL_CONF" & + STUNNEL_REAL_PID=$! + TRANSFER_REAL_PID=$STUNNEL_REAL_PID + TRANSFER_PID="$STUNNEL_PID" + fi + + if [ "${SSLMODE#VERIFY}" != "$SSLMODE" ]; then + # backward-incompatible behavior: + CN="" + if [ -n "$SSTCERT" ]; then + # find out my Common Name + get_openssl + if [ -z "$OPENSSL_BINARY" ]; then + wsrep_log_error \ + 'openssl not found but it is required for authentication' + exit 42 + fi + CN=$("$OPENSSL_BINARY" x509 -noout -subject -in "$SSTCERT" | \ + tr ',' '\n' | grep -F 'CN =' | cut -d '=' -f2 | sed s/^\ // | \ + sed s/\ %//) + fi + MY_SECRET="$(wsrep_gen_secret)" + # Add authentication data to address + ADDR="$CN:$MY_SECRET@$WSREP_SST_OPT_HOST" + else + MY_SECRET="" # for check down in recv_joiner() + fi + + until check_pid_and_port "$TRANSFER_PID" $TRANSFER_REAL_PID \ + "$RSYNC_ADDR_UNESCAPED" "$RSYNC_PORT" + do + sleep 0.2 + done + + echo "ready $ADDR:$RSYNC_PORT/$MODULE" + + MYSQLD_PID="$WSREP_SST_OPT_PARENT" + + # wait for SST to complete by monitoring magic file + while [ ! -r "$MAGIC_FILE" ] && check_pid "$TRANSFER_PID" && \ + ps -p $MYSQLD_PID >/dev/null 2>&1 + do + sleep 1 + done + + if ! ps -p $MYSQLD_PID >/dev/null 2>&1; then + wsrep_log_error \ + "Parent mysqld process (PID: $MYSQLD_PID) terminated unexpectedly." + kill -- -$MYSQLD_PID + sleep 1 + exit 32 + fi + + if [ ! -r "$MAGIC_FILE" ]; then + # This message should cause joiner to abort: + wsrep_log_info "rsync process ended without creating" \ + "magic file ($MAGIC_FILE)" + exit 32 + fi + + if [ -n "$MY_SECRET" ]; then + # Check donor supplied secret: + SECRET=$(grep -m1 -E "^$SECRET_TAG[[:space:]]" "$MAGIC_FILE" || :) + SECRET=$(trim_string "${SECRET#$SECRET_TAG}") + if [ "$SECRET" != "$MY_SECRET" ]; then + wsrep_log_error "Donor does not know my secret!" + wsrep_log_info "Donor: '$SECRET', my: '$MY_SECRET'" + exit 32 + fi + fi + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ]; then + if grep -m1 -qE "^$BYPASS_TAG([[:space:]]+.*)?\$" "$MAGIC_FILE"; then + readonly WSREP_SST_OPT_BYPASS=1 + readonly WSREP_TRANSFER_TYPE='IST' + fi + fi + + binlog_tar_present=0 + if [ -f "$BINLOG_TAR_FILE" ]; then + binlog_tar_present=1 + if [ $WSREP_SST_OPT_BYPASS -ne 0 ]; then + wsrep_log_warning "tar with binlogs transferred in the IST mode" + fi + fi + + if [ $WSREP_SST_OPT_BYPASS -eq 0 -a -n "$WSREP_SST_OPT_BINLOG" ]; then + # If it is SST (not an IST) or tar with binlogs is present + # among the transferred files, then we need to remove the + # old binlogs: + cd "$DATA" + # Clean up the old binlog files and index: + binlog_index="$WSREP_SST_OPT_BINLOG_INDEX" + if [ -f "$binlog_index" ]; then + while read bin_file || [ -n "$bin_file" ]; do + rm -f "$bin_file" || : + done < "$binlog_index" + rm "$binlog_index" + fi + binlog_cd=0 + # Change the directory to binlog base (if possible): + if [ -n "$binlog_dir" -a "$binlog_dir" != '.' -a \ + "$binlog_dir" != "$DATA_DIR" -a -d "$binlog_dir" ] + then + binlog_cd=1 + cd "$binlog_dir" + fi + # Clean up unindexed binlog files: + rm -f "$binlog_base".[0-9]* || : + [ $binlog_cd -ne 0 ] && cd "$DATA_DIR" + if [ $binlog_tar_present -ne 0 ]; then + # Create a temporary file: + tmpdir=$(parse_cnf '--mysqld|sst' 'tmpdir') + if [ -z "$tmpdir" ]; then + tmpfile="$(mktemp)" + elif [ "$OS" = 'Linux' ]; then + tmpfile=$(mktemp "--tmpdir=$tmpdir") + else + tmpfile=$(TMPDIR="$tmpdir"; mktemp) + fi + index_dir=$(dirname "$binlog_index"); + if [ -n "$index_dir" -a "$index_dir" != '.' -a \ + "$index_dir" != "$DATA_DIR" ] + then + [ ! -d "$index_dir" ] && mkdir -p "$index_dir" + fi + binlog_cd=0 + if [ -n "$binlog_dir" -a "$binlog_dir" != '.' -a \ + "$binlog_dir" != "$DATA_DIR" ] + then + [ ! -d "$binlog_dir" ] && mkdir -p "$binlog_dir" + binlog_cd=1 + cd "$binlog_dir" + fi + # Extracting binlog files: + wsrep_log_info "Extracting binlog files:" + if tar --version | grep -qw -E '^bsdtar'; then + tar -tf "$BINLOG_TAR_FILE" > "$tmpfile" && \ + tar -xvf "$BINLOG_TAR_FILE" > /dev/null || RC=$? + else + tar -xvf "$BINLOG_TAR_FILE" > "$tmpfile" && \ + cat "$tmpfile" >&2 || RC=$? + fi + if [ $RC -ne 0 ]; then + wsrep_log_error "Error unpacking tar file with binlog files" + rm "$tmpfile" + exit 32 + fi + # Rebuild binlog index: + [ $binlog_cd -ne 0 ] && cd "$DATA_DIR" + while read bin_file || [ -n "$bin_file" ]; do + echo "$binlog_dir${binlog_dir:+/}$bin_file" >> "$binlog_index" + done < "$tmpfile" + rm "$tmpfile" + cd "$OLD_PWD" + fi + fi + + # Remove special tags from the magic file, and from the output: + coords=$(head -n1 "$MAGIC_FILE") + wsrep_log_info "Galera co-ords from recovery: $coords" + echo "$coords" # Output : UUID:seqno wsrep_gtid_domain_id +fi + +wsrep_log_info "$WSREP_METHOD $WSREP_TRANSFER_TYPE completed on $WSREP_SST_OPT_ROLE" +exit 0 |