From 671d9b6c611be423246b562878da2a5788cc327d Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Thu, 16 Jul 2020 16:30:54 +0200 Subject: [PATCH 001/323] - Fix MDEV-22571 and MDEV-22572. Allow multiple ZIP table and enable using special column in them. modified: storage/connect/tabzip.cpp modified: storage/connect/tabzip.h - Fix some compiler errors modified: storage/connect/tabcmg.cpp --- storage/connect/connect.cc | 1 - storage/connect/filamdbf.cpp | 195 +++++++++++++++++------ storage/connect/filamdbf.h | 2 +- storage/connect/filamzip.cpp | 282 ++++++++++++++++++++++++++++++++-- storage/connect/filamzip.h | 38 ++++- storage/connect/ha_connect.cc | 19 +-- storage/connect/mongo.cpp | 1 - storage/connect/mongo.h | 1 - storage/connect/plgxml.cpp | 2 +- storage/connect/tabcmg.cpp | 2 + storage/connect/tabdos.cpp | 36 +++-- storage/connect/tabdos.h | 1 + storage/connect/tabfix.h | 18 ++- storage/connect/tabjson.cpp | 1 + storage/connect/tabjson.h | 1 - storage/connect/tabzip.cpp | 13 +- storage/connect/tabzip.h | 2 + 17 files changed, 509 insertions(+), 106 deletions(-) diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc index dfc619cf4af..2a0f2ed037f 100644 --- a/storage/connect/connect.cc +++ b/storage/connect/connect.cc @@ -355,7 +355,6 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2, } // endif mode rcop = false; - } catch (int n) { if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); diff --git a/storage/connect/filamdbf.cpp b/storage/connect/filamdbf.cpp index c8bab2b53a4..542159fd172 100644 --- a/storage/connect/filamdbf.cpp +++ b/storage/connect/filamdbf.cpp @@ -49,6 +49,7 @@ #include "global.h" #include "plgdbsem.h" #include "filamdbf.h" +#include "filamzip.h" #include "tabdos.h" #include "valblk.h" #define NO_FUNC @@ -139,7 +140,7 @@ static int dbfhead(PGLOBAL g, FILE *file, PCSZ fn, DBFHEADER *buf) if (fread(buf, HEADLEN, 1, file) != 1) { strcpy(g->Message, MSG(NO_READ_32)); return RC_NF; - } // endif fread + } // endif fread // Check first byte to be sure of .dbf type if ((buf->Version & 0x03) != DBFTYPE) { @@ -149,7 +150,7 @@ static int dbfhead(PGLOBAL g, FILE *file, PCSZ fn, DBFHEADER *buf) if ((buf->Version & 0x30) == 0x30) { strcpy(g->Message, MSG(FOXPRO_FILE)); dbc = 264; // FoxPro database container - } // endif Version + } // endif Version } else strcpy(g->Message, MSG(DBASE_FILE)); @@ -158,12 +159,12 @@ static int dbfhead(PGLOBAL g, FILE *file, PCSZ fn, DBFHEADER *buf) if (fseek(file, buf->Headlen() - dbc, SEEK_SET) != 0) { sprintf(g->Message, MSG(BAD_HEADER), fn); return RC_FX; - } // endif fseek + } // endif fseek if (fread(&endmark, 2, 1, file) != 1) { strcpy(g->Message, MSG(BAD_HEAD_END)); return RC_FX; - } // endif fread + } // endif fread // Some files have just 1D others have 1D00 following fields if (endmark[0] != EOH && endmark[1] != EOH) { @@ -172,7 +173,7 @@ static int dbfhead(PGLOBAL g, FILE *file, PCSZ fn, DBFHEADER *buf) if (rc == RC_OK) return RC_FX; - } // endif endmark + } // endif endmark // Calculate here the number of fields while we have the dbc info buf->SetFields((buf->Headlen() - dbc - 1) / 32); @@ -180,13 +181,58 @@ static int dbfhead(PGLOBAL g, FILE *file, PCSZ fn, DBFHEADER *buf) return rc; } // end of dbfhead +/****************************************************************************/ +/* dbfields: Analyze a DBF header and set the table fields number. */ +/* Parameters: */ +/* PGLOBAL g -- pointer to the CONNECT Global structure */ +/* DBFHEADER *hdrp -- pointer to _dbfheader structure */ +/* Returns: */ +/* RC_OK, RC_INFO, or RC_FX if error. */ +/****************************************************************************/ +static int dbfields(PGLOBAL g, DBFHEADER* hdrp) +{ + char* endmark; + int dbc = 2, rc = RC_OK; + + *g->Message = '\0'; + + // Check first byte to be sure of .dbf type + if ((hdrp->Version & 0x03) != DBFTYPE) { + strcpy(g->Message, MSG(NOT_A_DBF_FILE)); + rc = RC_INFO; + + if ((hdrp->Version & 0x30) == 0x30) { + strcpy(g->Message, MSG(FOXPRO_FILE)); + dbc = 264; // FoxPro database container + } // endif Version + + } else + strcpy(g->Message, MSG(DBASE_FILE)); + + // Check last byte(s) of header + endmark = (char*)hdrp + hdrp->Headlen() - dbc; + + // Some headers just have 1D others have 1D00 following fields + if (endmark[0] != EOH && endmark[1] != EOH) { + sprintf(g->Message, MSG(NO_0DH_HEAD), dbc); + + if (rc == RC_OK) + return RC_FX; + + } // endif endmark + + // Calculate here the number of fields while we have the dbc info + hdrp->SetFields((hdrp->Headlen() - dbc - 1) / 32); + return rc; +} // end of dbfields + /* -------------------------- Function DBFColumns ------------------------- */ /****************************************************************************/ /* DBFColumns: constructs the result blocks containing the description */ /* of all the columns of a DBF file that will be retrieved by #GetData. */ /****************************************************************************/ -PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, bool info) +PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, PTOS topt, bool info) { int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT}; @@ -196,10 +242,12 @@ PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, bool info) char buf[2], filename[_MAX_PATH]; int ncol = sizeof(buftyp) / sizeof(int); int rc, type, len, field, fields; - bool bad; - DBFHEADER mainhead; - DESCRIPTOR thisfield; - FILE *infile = NULL; + bool bad, mul; + PCSZ target, pwd; + DBFHEADER mainhead, *hp; + DESCRIPTOR thisfield, *tfp; + FILE *infile = NULL; + UNZIPUTL *zutp = NULL; PQRYRES qrp; PCOLRES crp; @@ -217,21 +265,55 @@ PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, bool info) /************************************************************************/ PlugSetPath(filename, fn, dp); - if (!(infile= global_fopen(g, MSGID_CANNOT_OPEN, filename, "rb"))) - return NULL; + if (topt->zipped) { + target = GetStringTableOption(g, topt, "Entry", NULL); + mul = (target && *target) ? strchr(target, '*') || strchr(target, '?') + : false; + mul = GetBooleanTableOption(g, topt, "Mulentries", mul); - /************************************************************************/ - /* Get the first 32 bytes of the header. */ - /************************************************************************/ - if ((rc = dbfhead(g, infile, filename, &mainhead)) == RC_FX) { - fclose(infile); - return NULL; - } // endif dbfhead + if (mul) { + strcpy(g->Message, "Cannot find column definition for multiple entries"); + return NULL; + } // endif Multiple - /************************************************************************/ - /* Allocate the structures used to refer to the result set. */ - /************************************************************************/ - fields = mainhead.Fields(); + pwd = GetStringTableOption(g, topt, "Password", NULL); + zutp = new(g) UNZIPUTL(target, pwd, mul); + + if (!zutp->OpenTable(g, MODE_READ, filename)) + hp = (DBFHEADER*)zutp->memory; + else + return NULL; + + /**********************************************************************/ + /* Set the table fields number. */ + /**********************************************************************/ + if ((rc = dbfields(g, hp)) == RC_FX) { + zutp->close(); + return NULL; + } // endif dbfields + + tfp = (DESCRIPTOR*)hp; + } else { + if (!(infile = global_fopen(g, MSGID_CANNOT_OPEN, filename, "rb"))) + return NULL; + else + hp = &mainhead; + + /**********************************************************************/ + /* Get the first 32 bytes of the header. */ + /**********************************************************************/ + if ((rc = dbfhead(g, infile, filename, hp)) == RC_FX) { + fclose(infile); + return NULL; + } // endif dbfhead + + tfp = &thisfield; + } // endif zipped + + /************************************************************************/ + /* Get the number of the table fields. */ + /************************************************************************/ + fields = hp->Fields(); } else fields = 0; @@ -241,19 +323,21 @@ PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, bool info) if (info || !qrp) { if (infile) fclose(infile); + else if (zutp) + zutp->close(); return qrp; - } // endif info + } // endif info if (trace(1)) { htrc("Structure of %s\n", filename); htrc("headlen=%hd reclen=%hd degree=%d\n", - mainhead.Headlen(), mainhead.Reclen(), fields); - htrc("flags(iem)=%d,%d,%d cp=%d\n", mainhead.Incompleteflag, - mainhead.Encryptflag, mainhead.Mdxflag, mainhead.Language); + hp->Headlen(), hp->Reclen(), fields); + htrc("flags(iem)=%d,%d,%d cp=%d\n", hp->Incompleteflag, + hp->Encryptflag, hp->Mdxflag, hp->Language); htrc("%hd records, last changed %02d/%02d/%d\n", - mainhead.Records(), mainhead.Filedate[1], mainhead.Filedate[2], - mainhead.Filedate[0] + (mainhead.Filedate[0] <= 30) ? 2000 : 1900); + hp->Records(), hp->Filedate[1], hp->Filedate[2], + hp->Filedate[0] + (hp->Filedate[0] <= 30) ? 2000 : 1900); htrc("Field Type Offset Len Dec Set Mdx\n"); } // endif trace @@ -265,21 +349,24 @@ PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, bool info) for (field = 0; field < fields; field++) { bad = FALSE; - if (fread(&thisfield, HEADLEN, 1, infile) != 1) { + if (topt->zipped) { + tfp = (DESCRIPTOR*)((char*)tfp + HEADLEN); + } else if (fread(tfp, HEADLEN, 1, infile) != 1) { sprintf(g->Message, MSG(ERR_READING_REC), field+1, fn); goto err; - } else - len = thisfield.Length; + } // endif fread + + len = tfp->Length; if (trace(1)) htrc("%-11s %c %6ld %3d %2d %3d %3d\n", - thisfield.Name, thisfield.Type, thisfield.Offset, len, - thisfield.Decimals, thisfield.Setfield, thisfield.Mdxfield); + tfp->Name, tfp->Type, tfp->Offset, len, + tfp->Decimals, tfp->Setfield, tfp->Mdxfield); /************************************************************************/ /* Now get the results into blocks. */ /************************************************************************/ - switch (thisfield.Type) { + switch (tfp->Type) { case 'C': // Characters case 'L': // Logical 'T' or 'F' or space type = TYPE_STRING; @@ -294,7 +381,7 @@ PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, bool info) // type = TYPE_INT; // break; case 'N': - type = (thisfield.Decimals) ? TYPE_DOUBLE + type = (tfp->Decimals) ? TYPE_DOUBLE : (len > 10) ? TYPE_BIGINT : TYPE_INT; break; case 'F': // Float @@ -306,8 +393,8 @@ PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, bool info) break; default: if (!info) { - sprintf(g->Message, MSG(BAD_DBF_TYPE), thisfield.Type - , thisfield.Name); + sprintf(g->Message, MSG(BAD_DBF_TYPE), tfp->Type + , tfp->Name); goto err; } // endif info @@ -316,27 +403,31 @@ PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, bool info) } // endswitch Type crp = qrp->Colresp; // Column Name - crp->Kdata->SetValue(thisfield.Name, field); + crp->Kdata->SetValue(tfp->Name, field); crp = crp->Next; // Data Type crp->Kdata->SetValue((int)type, field); crp = crp->Next; // Type Name if (bad) { - buf[0] = thisfield.Type; + buf[0] = tfp->Type; crp->Kdata->SetValue(buf, field); } else crp->Kdata->SetValue(GetTypeName(type), field); crp = crp->Next; // Precision - crp->Kdata->SetValue((int)thisfield.Length, field); + crp->Kdata->SetValue((int)tfp->Length, field); crp = crp->Next; // Length - crp->Kdata->SetValue((int)thisfield.Length, field); + crp->Kdata->SetValue((int)tfp->Length, field); crp = crp->Next; // Scale (precision) - crp->Kdata->SetValue((int)thisfield.Decimals, field); + crp->Kdata->SetValue((int)tfp->Decimals, field); } // endfor field qrp->Nblin = field; - fclose(infile); + + if (infile) + fclose(infile); + else if (zutp) + zutp->close(); #if 0 if (info) { @@ -347,9 +438,9 @@ PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, bool info) sprintf(buf, "Ver=%02x ncol=%hu nlin=%u lrecl=%hu headlen=%hu date=%02d/%02d/%02d", - mainhead.Version, fields, mainhead.Records, mainhead.Reclen, - mainhead.Headlen, mainhead.Filedate[0], mainhead.Filedate[1], - mainhead.Filedate[2]); + hp->Version, fields, hp->Records, hp->Reclen, + hp->Headlen, hp->Filedate[0], hp->Filedate[1], + hp->Filedate[2]); strcat(g->Message, buf); } // endif info @@ -360,9 +451,13 @@ PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, bool info) /**************************************************************************/ return qrp; - err: - fclose(infile); - return NULL; +err: + if (infile) + fclose(infile); + else if (zutp) + zutp->close(); + + return NULL; } // end of DBFColumns /* ---------------------------- Class DBFBASE ----------------------------- */ diff --git a/storage/connect/filamdbf.h b/storage/connect/filamdbf.h index 640fc349b4c..dfe5cb5cfc4 100644 --- a/storage/connect/filamdbf.h +++ b/storage/connect/filamdbf.h @@ -19,7 +19,7 @@ typedef class DBMFAM *PDBMFAM; /****************************************************************************/ /* Functions used externally. */ /****************************************************************************/ -PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, bool info); +PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, PTOS tiop, bool info); /****************************************************************************/ /* This is the base class for dBASE file access methods. */ diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamzip.cpp index e76dc496246..eeb23e1f053 100644 --- a/storage/connect/filamzip.cpp +++ b/storage/connect/filamzip.cpp @@ -1,11 +1,11 @@ /*********** File AM Zip C++ Program Source Code File (.CPP) ***********/ /* PROGRAM NAME: FILAMZIP */ /* ------------- */ -/* Version 1.3 */ +/* Version 1.4 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 2016-2017 */ +/* (C) Copyright to the author Olivier BERTRAND 2016-2020 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -45,6 +45,62 @@ #define WRITEBUFFERSIZE (16384) +/****************************************************************************/ +/* Definitions used for DBF tables. */ +/****************************************************************************/ +#define HEADLEN 32 /* sizeof ( mainhead or thisfield ) */ +//efine MEMOLEN 10 /* length of memo field in .dbf */ +#define DBFTYPE 3 /* value of bits 0 and 1 if .dbf */ +#define EOH 0x0D /* end-of-header marker in .dbf file */ + +/****************************************************************************/ +/* First 32 bytes of a DBF table. */ +/* Note: some reserved fields are used here to store info (Fields) */ +/****************************************************************************/ +typedef struct _dbfheader { + uchar Version; /* Version information flags */ + char Filedate[3]; /* date, YYMMDD, binary. YY=year-1900 */ +private: + /* The following four members are stored in little-endian format on disk */ + char m_RecordsBuf[4]; /* records in the file */ + char m_HeadlenBuf[2]; /* bytes in the header */ + char m_ReclenBuf[2]; /* bytes in a record */ + char m_FieldsBuf[2]; /* Reserved but used to store fields */ +public: + char Incompleteflag; /* 01 if incomplete, else 00 */ + char Encryptflag; /* 01 if encrypted, else 00 */ + char Reserved2[12]; /* for LAN use */ + char Mdxflag; /* 01 if production .mdx, else 00 */ + char Language; /* Codepage */ + char Reserved3[2]; + + uint Records(void) const { return uint4korr(m_RecordsBuf); } + ushort Headlen(void) const { return uint2korr(m_HeadlenBuf); } + ushort Reclen(void) const { return uint2korr(m_ReclenBuf); } + ushort Fields(void) const { return uint2korr(m_FieldsBuf); } + + void SetHeadlen(ushort num) { int2store(m_HeadlenBuf, num); } + void SetReclen(ushort num) { int2store(m_ReclenBuf, num); } + void SetFields(ushort num) { int2store(m_FieldsBuf, num); } +} DBFHEADER; + +/****************************************************************************/ +/* Column field descriptor of a .dbf file. */ +/****************************************************************************/ +typedef struct _descriptor { + char Name[11]; /* field name, in capitals, null filled*/ + char Type; /* field type, C, D, F, L, M or N */ + uint Offset; /* used in memvars, not in files. */ + uchar Length; /* field length */ + uchar Decimals; /* number of decimal places */ + short Reserved4; + char Workarea; /* ??? */ + char Reserved5[2]; + char Setfield; /* ??? */ + char Reserved6[7]; + char Mdxfield; /* 01 if tag field in production .mdx */ +} DESCRIPTOR; + bool ZipLoadFile(PGLOBAL g, PCSZ zfn, PCSZ fn, PCSZ entry, bool append, bool mul); /***********************************************************************/ @@ -214,10 +270,21 @@ bool ZipLoadFile(PGLOBAL g, PCSZ zfn, PCSZ fn, PCSZ entry, bool append, bool mul buf = (char*)PlugSubAlloc(g, NULL, WRITEBUFFERSIZE); - if (mul) - err = ZipFiles(g, zutp, fn, buf); - else - err = ZipFile(g, zutp, fn, entry, buf); + if (!mul) { + PCSZ entp; + + if (!entry) { // entry defaults to the file name + char* p = strrchr((char*)fn, '/'); +#if defined(__WIN__) + if (!p) p = strrchr((char*)fn, '\\'); +#endif // __WIN__ + entp = (p) ? p + 1 : entry; + } else + entp = entry; + + err = ZipFile(g, zutp, fn, entp, buf); + } else + err = ZipFiles(g, zutp, fn, buf); zutp->close(); return err; @@ -232,6 +299,7 @@ ZIPUTIL::ZIPUTIL(PCSZ tgt) { zipfile = NULL; target = tgt; + pwd = NULL; fp = NULL; entryopen = false; } // end of ZIPUTIL standard constructor @@ -241,6 +309,7 @@ ZIPUTIL::ZIPUTIL(ZIPUTIL *zutp) { zipfile = zutp->zipfile; target = zutp->target; + pwd = zutp->pwd; fp = zutp->fp; entryopen = zutp->entryopen; } // end of UNZIPUTL copy constructor @@ -385,11 +454,11 @@ void ZIPUTIL::closeEntry() /***********************************************************************/ /* Constructors. */ /***********************************************************************/ -UNZIPUTL::UNZIPUTL(PCSZ tgt, bool mul) +UNZIPUTL::UNZIPUTL(PCSZ tgt, PCSZ pw, bool mul) { zipfile = NULL; target = tgt; - pwd = NULL; + pwd = pw; fp = NULL; memory = NULL; size = 0; @@ -959,7 +1028,7 @@ int UZXFAM::Cardinality(PGLOBAL g) } // end of Cardinality /***********************************************************************/ -/* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */ +/* OpenTableFile: Open a FIX/UNIX table file from a ZIP file. */ /***********************************************************************/ bool UZXFAM::OpenTableFile(PGLOBAL g) { @@ -1015,6 +1084,197 @@ int UZXFAM::GetNext(PGLOBAL g) return RC_OK; } // end of GetNext +/* -------------------------- class UZDFAM --------------------------- */ + +/***********************************************************************/ +/* Constructors. */ +/***********************************************************************/ +UZDFAM::UZDFAM(PDOSDEF tdp) : DBMFAM(tdp) +{ + zutp = NULL; + tdfp = tdp; + //target = tdp->GetEntry(); + //mul = tdp->GetMul(); + //Lrecl = tdp->GetLrecl(); +} // end of UZXFAM standard constructor + +UZDFAM::UZDFAM(PUZDFAM txfp) : DBMFAM(txfp) +{ + zutp = txfp->zutp; + tdfp = txfp->tdfp; + //target = txfp->target; + //mul = txfp->mul; + //Lrecl = txfp->Lrecl; +} // end of UZXFAM copy constructor + +#if 0 +/****************************************************************************/ +/* dbfhead: Routine to analyze a DBF header. */ +/* Parameters: */ +/* PGLOBAL g -- pointer to the CONNECT Global structure */ +/* DBFHEADER *hdrp -- pointer to _dbfheader structure */ +/* Returns: */ +/* RC_OK, RC_NF, RC_INFO, or RC_FX if error. */ +/* Side effects: */ +/* Set the fields number in the header. */ +/****************************************************************************/ +int UZDFAM::dbfhead(PGLOBAL g, void* buf) +{ + char *endmark; + int dbc = 2, rc = RC_OK; + DBFHEADER* hdrp = (DBFHEADER*)buf; + + *g->Message = '\0'; + + // Check first byte to be sure of .dbf type + if ((hdrp->Version & 0x03) != DBFTYPE) { + strcpy(g->Message, MSG(NOT_A_DBF_FILE)); + rc = RC_INFO; + + if ((hdrp->Version & 0x30) == 0x30) { + strcpy(g->Message, MSG(FOXPRO_FILE)); + dbc = 264; // FoxPro database container + } // endif Version + + } else + strcpy(g->Message, MSG(DBASE_FILE)); + + // Check last byte(s) of header + endmark = (char*)hdrp + hdrp->Headlen() - dbc; + + // Some headers just have 1D others have 1D00 following fields + if (endmark[0] != EOH && endmark[1] != EOH) { + sprintf(g->Message, MSG(NO_0DH_HEAD), dbc); + + if (rc == RC_OK) + return RC_FX; + + } // endif endmark + + // Calculate here the number of fields while we have the dbc info + hdrp->SetFields((hdrp->Headlen() - dbc - 1) / 32); + return rc; +} // end of dbfhead + +/****************************************************************************/ +/* ScanHeader: scan the DBF file header for number of records, record size,*/ +/* and header length. Set Records, check that Reclen is equal to lrecl and */ +/* return the header length or 0 in case of error. */ +/****************************************************************************/ +int UZDFAM::ScanHeader(PGLOBAL g, int* rln) +{ + int rc; + DBFHEADER header; + + /************************************************************************/ + /* Get the first 32 bytes of the header. */ + /************************************************************************/ + rc = dbfhead(g, &header); + + if (rc == RC_FX) + return -1; + + *rln = (int)header.Reclen(); + Records = (int)header.Records(); + return (int)header.Headlen(); +} // end of ScanHeader +#endif // 0 + +/***********************************************************************/ +/* ZIP GetFileLength: returns file size in number of bytes. */ +/***********************************************************************/ +int UZDFAM::GetFileLength(PGLOBAL g) +{ + int len; + + if (!zutp && OpenTableFile(g)) + return 0; + + if (zutp->entryopen) + len = zutp->size; + else + len = 0; + + return len; +} // end of GetFileLength + +/***********************************************************************/ +/* ZIP Cardinality: return the number of rows if possible. */ +/***********************************************************************/ +int UZDFAM::Cardinality(PGLOBAL g) +{ + if (!g) + return 1; + + int card = -1; + int len = GetFileLength(g); + + card = Records; + + // Set number of blocks for later use + Block = (card > 0) ? (card + Nrec - 1) / Nrec : 0; + return card; +} // end of Cardinality + +/***********************************************************************/ +/* OpenTableFile: Open a DBF table file from a ZIP file. */ +/***********************************************************************/ +bool UZDFAM::OpenTableFile(PGLOBAL g) +{ + // May have been already opened in GetFileLength + if (!zutp || !zutp->zipfile) { + char filename[_MAX_PATH]; + MODE mode = Tdbp->GetMode(); + + /*********************************************************************/ + /* Allocate the ZIP utility class. */ + /*********************************************************************/ + if (!zutp) + zutp = new(g)UNZIPUTL(tdfp); + + // We used the file name relative to recorded datapath + PlugSetPath(filename, To_File, Tdbp->GetPath()); + + if (!zutp->OpenTable(g, mode, filename)) { + // The pseudo "buffer" is here the entire real buffer + Memory = zutp->memory; + Top = Memory + zutp->size; + To_Fb = zutp->fp; // Useful when closing + return AllocateBuffer(g); + } else + return true; + + } else + Reset(); + + return false; +} // end of OpenTableFile + +/***********************************************************************/ +/* GetNext: go to next entry. */ +/***********************************************************************/ +int UZDFAM::GetNext(PGLOBAL g) +{ + int rc = zutp->nextEntry(g); + + if (rc != RC_OK) + return rc; + + int len = zutp->size; + +#if 0 + if (len % Lrecl) { + sprintf(g->Message, MSG(NOT_FIXED_LEN), zutp->fn, len, Lrecl); + return RC_FX; + } // endif size +#endif // 0 + + Memory = zutp->memory; + Top = Memory + len; + Rewind(); + return RC_OK; +} // end of GetNext + /* -------------------------- class ZIPFAM --------------------------- */ /***********************************************************************/ @@ -1045,7 +1305,7 @@ bool ZIPFAM::OpenTableFile(PGLOBAL g) strcpy(g->Message, "No insert into existing zip file"); return true; } else if (append && len > 0) { - UNZIPUTL *zutp = new(g) UNZIPUTL(target, false); + UNZIPUTL *zutp = new(g) UNZIPUTL(target, NULL, false); if (!zutp->IsInsertOk(g, filename)) { strcpy(g->Message, "No insert into existing entry"); @@ -1129,7 +1389,7 @@ bool ZPXFAM::OpenTableFile(PGLOBAL g) strcpy(g->Message, "No insert into existing zip file"); return true; } else if (append && len > 0) { - UNZIPUTL *zutp = new(g) UNZIPUTL(target, false); + UNZIPUTL *zutp = new(g) UNZIPUTL(target, NULL, false); if (!zutp->IsInsertOk(g, filename)) { strcpy(g->Message, "No insert into existing entry"); diff --git a/storage/connect/filamzip.h b/storage/connect/filamzip.h index be17d954728..7ff1fb0a543 100644 --- a/storage/connect/filamzip.h +++ b/storage/connect/filamzip.h @@ -1,7 +1,7 @@ /************** filamzip H Declares Source Code File (.H) **************/ -/* Name: filamzip.h Version 1.2 */ +/* Name: filamzip.h Version 1.3 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2016-2017 */ +/* (C) Copyright to the author Olivier BERTRAND 2016-2020 */ /* */ /* This file contains the ZIP file access method classes declares. */ /***********************************************************************/ @@ -11,6 +11,7 @@ #include "block.h" #include "filamap.h" #include "filamfix.h" +#include "filamdbf.h" #include "zip.h" #include "unzip.h" @@ -18,6 +19,7 @@ typedef class UNZFAM *PUNZFAM; typedef class UZXFAM *PUZXFAM; +typedef class UZDFAM* PUZDFAM; typedef class ZIPFAM *PZIPFAM; typedef class ZPXFAM *PZPXFAM; @@ -53,7 +55,7 @@ class DllExport ZIPUTIL : public BLOCK { class DllExport UNZIPUTL : public BLOCK { public: // Constructor - UNZIPUTL(PCSZ tgt, bool mul); + UNZIPUTL(PCSZ tgt, PCSZ pw, bool mul); UNZIPUTL(PDOSDEF tdp); // Implementation @@ -143,6 +145,36 @@ class DllExport UZXFAM : public MPXFAM { PDOSDEF tdfp; }; // end of UZXFAM +/***********************************************************************/ +/* This is the fixed unzip file access method. */ +/***********************************************************************/ +class DllExport UZDFAM : public DBMFAM { + //friend class UNZFAM; +public: + // Constructors + UZDFAM(PDOSDEF tdp); + UZDFAM(PUZDFAM txfp); + + // Implementation + virtual AMT GetAmType(void) { return TYPE_AM_ZIP; } + virtual PTXF Duplicate(PGLOBAL g) { return (PTXF) new(g)UZDFAM(this); } + + // Methods + virtual int GetFileLength(PGLOBAL g); + virtual int Cardinality(PGLOBAL g); + virtual bool OpenTableFile(PGLOBAL g); + virtual int GetNext(PGLOBAL g); + //virtual int ReadBuffer(PGLOBAL g); + +protected: + int dbfhead(PGLOBAL g, void* buf); + int ScanHeader(PGLOBAL g, int* rln); + + // Members + UNZIPUTL* zutp; + PDOSDEF tdfp; +}; // end of UZDFAM + /***********************************************************************/ /* This is the zip file access method. */ /***********************************************************************/ diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index a111082e786..bb56d6cd655 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -4507,12 +4507,12 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn, bool quick) case TAB_DIR: case TAB_ZIP: case TAB_OEM: - if (table && table->pos_in_table_list) // if SELECT - { - //Switch_to_definer_security_ctx backup_ctx(thd, table->pos_in_table_list); + if (table && table->pos_in_table_list) { // if SELECT +#if MYSQL_VERSION_ID > 100200 + Switch_to_definer_security_ctx backup_ctx(thd, table->pos_in_table_list); +#endif // VERSION_ID > 100200 return check_global_access(thd, FILE_ACL); - } - else + } else return check_global_access(thd, FILE_ACL); case TAB_ODBC: case TAB_JDBC: @@ -4528,7 +4528,7 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn, bool quick) case TAB_VIR: // This is temporary until a solution is found return false; - } // endswitch type + } // endswitch type my_printf_error(ER_UNKNOWN_ERROR, "check_privileges failed", MYF(0)); return true; @@ -5882,7 +5882,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, } else switch (ttp) { case TAB_DBF: - qrp= DBFColumns(g, dpath, fn, fnc == FNC_COL); + qrp= DBFColumns(g, dpath, fn, topt, fnc == FNC_COL); break; #if defined(ODBC_SUPPORT) case TAB_ODBC: @@ -6733,11 +6733,6 @@ int ha_connect::create(const char *name, TABLE *table_arg, PCSZ m= GetListOption(g, "Mulentries", options->oplist, "NO"); bool mul= *m == '1' || *m == 'Y' || *m == 'y' || !stricmp(m, "ON"); - if (!entry && !mul) { - my_message(ER_UNKNOWN_ERROR, "Missing entry name", MYF(0)); - DBUG_RETURN(HA_ERR_INTERNAL_ERROR); - } // endif entry - strcat(strcat(strcpy(dbpath, "./"), table->s->db.str), "/"); PlugSetPath(zbuf, options->filename, dbpath); PlugSetPath(buf, fn, dbpath); diff --git a/storage/connect/mongo.cpp b/storage/connect/mongo.cpp index 53e2bf377c4..bd3d3b893c1 100644 --- a/storage/connect/mongo.cpp +++ b/storage/connect/mongo.cpp @@ -380,7 +380,6 @@ MGODEF::MGODEF(void) Uri = NULL; Colist = NULL; Filter = NULL; - Level = 0; Base = 0; Version = 0; Pipe = false; diff --git a/storage/connect/mongo.h b/storage/connect/mongo.h index 97c391a217f..dcefac372c0 100644 --- a/storage/connect/mongo.h +++ b/storage/connect/mongo.h @@ -82,7 +82,6 @@ protected: PSZ Wrapname; /* Java wrapper name */ PCSZ Colist; /* Options list */ PCSZ Filter; /* Filtering query */ - int Level; /* Used for catalog table */ int Base; /* The array index base */ int Version; /* The Java driver version */ bool Pipe; /* True is Colist is a pipeline */ diff --git a/storage/connect/plgxml.cpp b/storage/connect/plgxml.cpp index f3d3a010266..8c5cc261899 100644 --- a/storage/connect/plgxml.cpp +++ b/storage/connect/plgxml.cpp @@ -49,7 +49,7 @@ bool XMLDOCUMENT::InitZip(PGLOBAL g, PCSZ entry) { #if defined(ZIP_SUPPORT) bool mul = (entry) ? strchr(entry, '*') || strchr(entry, '?') : false; - zip = new(g) UNZIPUTL(entry, mul); + zip = new(g) UNZIPUTL(entry, NULL, mul); return zip == NULL; #else // !ZIP_SUPPORT sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); diff --git a/storage/connect/tabcmg.cpp b/storage/connect/tabcmg.cpp index b9b7f6e4b60..f2ff721627c 100644 --- a/storage/connect/tabcmg.cpp +++ b/storage/connect/tabcmg.cpp @@ -26,6 +26,8 @@ #include "tabmul.h" #include "filter.h" +PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt, bool info); + /* -------------------------- Class CMGDISC -------------------------- */ /***********************************************************************/ diff --git a/storage/connect/tabdos.cpp b/storage/connect/tabdos.cpp index 8efe2aad702..b3147bb7357 100644 --- a/storage/connect/tabdos.cpp +++ b/storage/connect/tabdos.cpp @@ -1,11 +1,11 @@ /************* TabDos C++ Program Source Code File (.CPP) **************/ /* PROGRAM NAME: TABDOS */ /* ------------- */ -/* Version 4.9.4 */ +/* Version 4.9.5 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 1998-2019 */ +/* (C) Copyright to the author Olivier BERTRAND 1998-2020 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -359,7 +359,26 @@ PTDB DOSDEF::GetTable(PGLOBAL g, MODE mode) /* Allocate table and file processing class of the proper type. */ /* Column blocks will be allocated only when needed. */ /*********************************************************************/ - if (Zipped) { + if (Recfm == RECFM_DBF) { + if (Catfunc == FNC_NO) { + if (Zipped) { + if (mode == MODE_READ || mode == MODE_ANY || mode == MODE_ALTER) { + txfp = new(g) UZDFAM(this); + } else { + strcpy(g->Message, "Zipped DBF tables are read only"); + return NULL; + } // endif's mode + + } else if (map) + txfp = new(g) DBMFAM(this); + else + txfp = new(g) DBFFAM(this); + + tdbp = new(g) TDBFIX(this, txfp); + } else + tdbp = new(g) TDBDCL(this); // Catfunc should be 'C' + + } else if (Zipped) { #if defined(ZIP_SUPPORT) if (Recfm == RECFM_VAR) { if (mode == MODE_READ || mode == MODE_ANY || mode == MODE_ALTER) { @@ -389,17 +408,6 @@ PTDB DOSDEF::GetTable(PGLOBAL g, MODE mode) sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); return NULL; #endif // !ZIP_SUPPORT - } else if (Recfm == RECFM_DBF) { - if (Catfunc == FNC_NO) { - if (map) - txfp = new(g) DBMFAM(this); - else - txfp = new(g) DBFFAM(this); - - tdbp = new(g) TDBFIX(this, txfp); - } else // Catfunc should be 'C' - tdbp = new(g) TDBDCL(this); - } else if (Recfm != RECFM_VAR && Compressed < 2) { if (Huge) txfp = new(g) BGXFAM(this); diff --git a/storage/connect/tabdos.h b/storage/connect/tabdos.h index 207a1277fce..80dfe63845d 100644 --- a/storage/connect/tabdos.h +++ b/storage/connect/tabdos.h @@ -30,6 +30,7 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */ friend class DBFBASE; friend class UNZIPUTL; friend class JSONCOL; + friend class TDBDCL; public: // Constructor DOSDEF(void); diff --git a/storage/connect/tabfix.h b/storage/connect/tabfix.h index 53c0af1c422..5f859a2bffe 100644 --- a/storage/connect/tabfix.h +++ b/storage/connect/tabfix.h @@ -98,18 +98,20 @@ class DllExport BINCOL : public DOSCOL { /* This is the class declaration for the DBF columns catalog table. */ /***********************************************************************/ class TDBDCL : public TDBCAT { - public: - // Constructor - TDBDCL(PDOSDEF tdp) : TDBCAT(tdp) {Fn = tdp->GetFn();} +public: + // Constructor + TDBDCL(PDOSDEF tdp) : TDBCAT(tdp) + {Fn = tdp->GetFn(); Topt = tdp->GetTopt();} - protected: +protected: // Specific routines - virtual PQRYRES GetResult(PGLOBAL g) - {return DBFColumns(g, ((PTABDEF)To_Def)->GetPath(), Fn, false);} + virtual PQRYRES GetResult(PGLOBAL g) + {return DBFColumns(g, ((PTABDEF)To_Def)->GetPath(), Fn, Topt, false);} - // Members + // Members PCSZ Fn; // The DBF file (path) name - }; // end of class TDBOCL + PTOS Topt; +}; // end of class TDBOCL #endif // __TABFIX__ diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index 7e8d6c8d9f0..3b0d458a7a6 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -739,6 +739,7 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) /***********************************************************************/ TDBJSN::TDBJSN(PJDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp) { + G = NULL; Top = NULL; Row = NULL; Val = NULL; diff --git a/storage/connect/tabjson.h b/storage/connect/tabjson.h index 8721a2a5ab7..8c3f1013919 100644 --- a/storage/connect/tabjson.h +++ b/storage/connect/tabjson.h @@ -104,7 +104,6 @@ public: PCSZ Xcol; /* Name of expandable column */ int Limit; /* Limit of multiple values */ int Pretty; /* Depends on file structure */ - int Level; /* Used for catalog table */ int Base; /* The array index base */ bool Strict; /* Strict syntax checking */ char Sep; /* The Jpath separator */ diff --git a/storage/connect/tabzip.cpp b/storage/connect/tabzip.cpp index c026744dba8..d9c13e2a58a 100644 --- a/storage/connect/tabzip.cpp +++ b/storage/connect/tabzip.cpp @@ -23,6 +23,7 @@ #include "filamzip.h" #include "resource.h" // for IDS_COLUMNS #include "tabdos.h" +#include "tabmul.h" #include "tabzip.h" /* -------------------------- Class ZIPDEF --------------------------- */ @@ -41,7 +42,14 @@ bool ZIPDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) /***********************************************************************/ PTDB ZIPDEF::GetTable(PGLOBAL g, MODE m) { - return new(g) TDBZIP(this); + PTDB tdbp = NULL; + + tdbp = new(g) TDBZIP(this); + + if (Multiple) + tdbp = new(g) TDBMUL(tdbp); + + return tdbp; } // end of GetTable /* ------------------------------------------------------------------- */ @@ -108,7 +116,7 @@ int TDBZIP::Cardinality(PGLOBAL g) Cardinal = (err == UNZ_OK) ? (int)ginfo.number_entry : 0; } else - Cardinal = 0; + Cardinal = 10; // Dummy for multiple tables } // endif Cardinal @@ -187,6 +195,7 @@ int TDBZIP::DeleteDB(PGLOBAL g, int irc) void TDBZIP::CloseDB(PGLOBAL g) { close(); + nexterr = UNZ_OK; // For multiple tables Use = USE_READY; // Just to be clean } // end of CloseDB diff --git a/storage/connect/tabzip.h b/storage/connect/tabzip.h index 32b15281f81..d36e4dc01d0 100644 --- a/storage/connect/tabzip.h +++ b/storage/connect/tabzip.h @@ -48,6 +48,8 @@ public: // Implementation virtual AMT GetAmType(void) {return TYPE_AM_ZIP;} + virtual PCSZ GetFile(PGLOBAL) {return zfn;} + virtual void SetFile(PGLOBAL, PCSZ fn) {zfn = fn;} // Methods virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); From c169838611e13c9f0559b2f49ba8c36aec11a78b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Sun, 17 Jan 2016 17:00:19 +0200 Subject: [PATCH 002/323] [MDEV-7978] Update grammar for new syntax Extend the syntax accepted by the grammar to account for the new create user and alter user syntax. --- sql/mysqld.cc | 1 + sql/sp_head.cc | 1 + sql/sql_acl.cc | 20 ++++++++++++++++ sql/sql_acl.h | 1 + sql/sql_cmd.h | 1 + sql/sql_parse.cc | 10 +++++++- sql/sql_yacc.yy | 59 ++++++++++++++++++++++++++++++++---------------- 7 files changed, 73 insertions(+), 20 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8d00b5af948..7e18251c670 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3676,6 +3676,7 @@ SHOW_VAR com_status_vars[]= { {"alter_server", STMT_STATUS(SQLCOM_ALTER_SERVER)}, {"alter_table", STMT_STATUS(SQLCOM_ALTER_TABLE)}, {"alter_tablespace", STMT_STATUS(SQLCOM_ALTER_TABLESPACE)}, + {"alter_user", STMT_STATUS(SQLCOM_ALTER_USER)}, {"analyze", STMT_STATUS(SQLCOM_ANALYZE)}, {"assign_to_keycache", STMT_STATUS(SQLCOM_ASSIGN_TO_KEYCACHE)}, {"begin", STMT_STATUS(SQLCOM_BEGIN)}, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 0428c0198a1..5749d5df18d 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -309,6 +309,7 @@ sp_get_flags_for_command(LEX *lex) case SQLCOM_CREATE_USER: case SQLCOM_CREATE_ROLE: case SQLCOM_ALTER_TABLE: + case SQLCOM_ALTER_USER: case SQLCOM_GRANT: case SQLCOM_GRANT_ROLE: case SQLCOM_REVOKE: diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index cf0b1d87bd7..9178b1f8cc3 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -9840,6 +9840,26 @@ bool mysql_rename_user(THD *thd, List &list) DBUG_RETURN(result); } +/* + Alter a user's connection and resource settings. + + SYNOPSIS + mysql_alter_user() + thd The current thread. + list The users to alter. + + RETURN + > 0 Error. Error message already sent. + 0 OK. + < 0 Error. Error message not yet sent. +*/ +int mysql_alter_user(THD* thd, List &users_list) +{ + DBUG_ENTER("mysql_alter_user"); + int result= 0; + // TODO implement the alter user logic. + DBUG_RETURN(result); +} /* Revoke all privileges from a list of users. diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 3bd896cab79..ac6a064c7e0 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -253,6 +253,7 @@ void get_mqh(const char *user, const char *host, USER_CONN *uc); bool mysql_create_user(THD *thd, List &list, bool handle_as_role); bool mysql_drop_user(THD *thd, List &list, bool handle_as_role); bool mysql_rename_user(THD *thd, List &list); +int mysql_alter_user(THD *thd, List &list); bool mysql_revoke_all(THD *thd, List &list); void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, const char *db, const char *table); diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h index c237bb9270a..5c697c4cd10 100644 --- a/sql/sql_cmd.h +++ b/sql/sql_cmd.h @@ -93,6 +93,7 @@ enum enum_sql_command { SQLCOM_CREATE_ROLE, SQLCOM_DROP_ROLE, SQLCOM_GRANT_ROLE, SQLCOM_REVOKE_ROLE, SQLCOM_COMPOUND, SQLCOM_SHOW_GENERIC, + SQLCOM_ALTER_USER, /* When a command is added here, be sure it's also added in mysqld.cc diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 14ac657862f..77b6f053e79 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -443,6 +443,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_CREATE_USER]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_RENAME_USER]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_DROP_USER]= CF_CHANGES_DATA; + sql_command_flags[SQLCOM_ALTER_USER]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_CREATE_ROLE]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_GRANT]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_GRANT_ROLE]= CF_CHANGES_DATA; @@ -506,6 +507,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_CHECKSUM]= CF_REPORT_PROGRESS; sql_command_flags[SQLCOM_CREATE_USER]|= CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_ALTER_USER]|= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_DROP_USER]|= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_RENAME_USER]|= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_CREATE_ROLE]|= CF_AUTO_COMMIT_TRANS; @@ -601,6 +603,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_ALTER_EVENT]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_DROP_EVENT]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_CREATE_USER]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_ALTER_USER]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_RENAME_USER]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_DROP_USER]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_CREATE_SERVER]|= CF_DISALLOW_IN_RO_TRANS; @@ -4403,6 +4406,7 @@ mysql_execute_command(THD *thd) my_ok(thd); break; } + case SQLCOM_ALTER_USER: case SQLCOM_RENAME_USER: { if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 1) && @@ -4410,7 +4414,11 @@ mysql_execute_command(THD *thd) break; /* Conditionally writes to binlog */ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) - if (!(res= mysql_rename_user(thd, lex->users_list))) + if (lex->sql_command == SQLCOM_ALTER_USER) + res= mysql_alter_user(thd, lex->users_list); + else + res= mysql_rename_user(thd, lex->users_list); + if (!res) my_ok(thd); break; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 2a46bb2a027..0cb13fe5a2b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2531,7 +2531,8 @@ create: Lex->create_view_suid= TRUE; } view_or_trigger_or_sp_or_event { } - | create_or_replace USER_SYM opt_if_not_exists clear_privileges grant_list + | create_or_replace USER opt_if_not_exists clear_privileges grant_list + require_clause resource_options { if (Lex->set_command_with_check(SQLCOM_CREATE_USER, $1 | $3)) MYSQL_YYABORT; @@ -7106,6 +7107,11 @@ alter: lex->sql_command= SQLCOM_ALTER_SERVER; lex->server_options.reset($3); } OPTIONS_SYM '(' server_options_list ')' { } + | ALTER opt_if_exists USER clear_privileges user_list + require_clause resource_options + { + Lex->sql_command= SQLCOM_ALTER_USER; + } ; ev_alter_on_schedule_completion: @@ -15412,24 +15418,8 @@ require_clause: } ; -grant_options: - /* empty */ {} - | WITH grant_option_list - ; - -opt_grant_option: - /* empty */ {} - | WITH GRANT OPTION { Lex->grant |= GRANT_ACL;} - ; - -grant_option_list: - grant_option_list grant_option {} - | grant_option {} - ; - -grant_option: - GRANT OPTION { Lex->grant |= GRANT_ACL;} - | MAX_QUERIES_PER_HOUR ulong_num +resource_option: + MAX_QUERIES_PER_HOUR ulong_num { LEX *lex=Lex; lex->mqh.questions=$2; @@ -15461,6 +15451,37 @@ grant_option: } ; +resource_option_list: + resource_option_list resource_option {} + | resource_option {} + ; + +resource_options: + /* empty */ {} + | WITH resource_option_list + ; + + +grant_options: + /* empty */ {} + | WITH grant_option_list {} + ; + +opt_grant_option: + /* empty */ {} + | WITH GRANT OPTION { Lex->grant |= GRANT_ACL;} + ; + +grant_option_list: + grant_option_list grant_option {} + | grant_option {} + ; + +grant_option: + GRANT OPTION { Lex->grant |= GRANT_ACL;} + | resource_option {} + ; + begin: BEGIN_SYM { From a701e9e6c390c3cbac69872e95b1aec565341d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Mon, 18 Jan 2016 02:16:59 +0200 Subject: [PATCH 003/323] [MDEV-7978] Implement alter user and tested create user Implemented the alter user syntax. Also tested that create user creates users accordingly. --- mysql-test/r/alter_user.result | 79 +++++++++++++++++++++++++++++++++ mysql-test/r/create_user.result | 72 ++++++++++++++++++++++++++++++ mysql-test/t/alter_user.test | 71 +++++++++++++++++++++++++++++ mysql-test/t/create_user.test | 58 ++++++++++++++++++++++++ sql/sql_acl.cc | 51 ++++++++++++++++++++- sql/sql_yacc.yy | 3 +- 6 files changed, 331 insertions(+), 3 deletions(-) create mode 100644 mysql-test/r/alter_user.result create mode 100644 mysql-test/r/create_user.result create mode 100644 mysql-test/t/alter_user.test create mode 100644 mysql-test/t/create_user.test diff --git a/mysql-test/r/alter_user.result b/mysql-test/r/alter_user.result new file mode 100644 index 00000000000..2acc2493acb --- /dev/null +++ b/mysql-test/r/alter_user.result @@ -0,0 +1,79 @@ +select * from mysql.user where user = 'root' and host = 'localhost'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +localhost root Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y 0 0 0 0 N N 0.000000 +# Test syntax +# +# These 2 selects should have no changes from the first one. +alter user CURRENT_USER; +select * from mysql.user where user = 'root' and host = 'localhost'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +localhost root Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y 0 0 0 0 N N 0.000000 +alter user CURRENT_USER(); +select * from mysql.user where user = 'root' and host = 'localhost'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +localhost root Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y 0 0 0 0 N N 0.000000 +create user foo; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo 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 N N 0.000000 +alter user foo; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo 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 N N 0.000000 +# Test super privilege works correctly with a read only database. +SET @start_read_only = @@global.read_only; +SET GLOBAL read_only=1; +grant create user on *.* to foo; +# Currently no super privileges. +connect a, localhost, foo; +select @@global.read_only; +@@global.read_only +1 +alter user foo; +ERROR HY000: The MariaDB server is running with the --read-only option so it cannot execute this statement +# Grant super privilege to the user. +connection default; +grant super on *.* to foo; +# We now have super privilege. We should be able to run alter user. +connect b, localhost, foo; +alter user foo; +connection default; +SET GLOBAL read_only = @start_read_only; +# Test inexistant user. +alter user boo; +ERROR HY000: Operation ALTER USER failed for 'boo' +#--warning ER_CANNOT_USER +alter if exists user boo; +Warnings: +Error 1133 Can't find any matching row in the user table +Note 1396 Operation ALTER USER failed for 'boo' +# Test SSL related altering. +alter user foo identified by 'something'; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 N N 0.000000 +alter user foo identified by 'something2'; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *9CD58369E930E28C8996A89DB18B63294E6DC10C N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 N N 0.000000 +alter user foo identified by password '*88C89BE093D4ECF72D039F62EBB7477EA1FD4D63'; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 N N 0.000000 +alter user foo identified with 'somecoolplugin'; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 somecoolplugin N N 0.000000 +alter user foo identified with 'somecoolplugin' using 'somecoolpassphrase'; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 somecoolplugin somecoolpassphrase N N 0.000000 +# Test resource limits altering. +alter user foo with MAX_QUERIES_PER_HOUR 10 +MAX_UPDATES_PER_HOUR 20 +MAX_CONNECTIONS_PER_HOUR 30 +MAX_USER_CONNECTIONS 40; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 10 20 30 40 somecoolplugin somecoolpassphrase N N 0.000000 +drop user foo; diff --git a/mysql-test/r/create_user.result b/mysql-test/r/create_user.result new file mode 100644 index 00000000000..1411f2e8792 --- /dev/null +++ b/mysql-test/r/create_user.result @@ -0,0 +1,72 @@ +create user foo; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo 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 N N 0.000000 +drop user foo; +create user foo identified by 'password'; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 N N 0.000000 +drop user foo; +create user foo identified by 'password' require SSL; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 ANY 0 0 0 0 N N 0.000000 +drop user foo; +create user foo identified by 'password' require X509; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 X509 0 0 0 0 N N 0.000000 +drop user foo; +create user foo identified by 'password' require CIPHER 'cipher'; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 SPECIFIED cipher 0 0 0 0 N N 0.000000 +drop user foo; +create user foo identified by 'password' require ISSUER 'issuer'; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 SPECIFIED issuer 0 0 0 0 N N 0.000000 +drop user foo; +create user foo identified by 'password' require SUBJECT 'subject'; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 SPECIFIED subject 0 0 0 0 N N 0.000000 +drop user foo; +create user foo identified by 'password' require CIPHER 'cipher' + SUBJECT 'subject'; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 SPECIFIED cipher subject 0 0 0 0 N N 0.000000 +drop user foo; +create user foo identified by 'password' require CIPHER 'cipher' +AND SUBJECT 'subject' + AND ISSUER 'issuer'; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 SPECIFIED cipher issuer subject 0 0 0 0 N N 0.000000 +drop user foo; +create user foo, foo2 identified by 'password' require CIPHER 'cipher' +AND SUBJECT 'subject' + AND ISSUER 'issuer'; +select * from mysql.user where user like 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo 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 SPECIFIED cipher issuer subject 0 0 0 0 N N 0.000000 +#--warning ER_USER_CREATE_EXISTS +create user if not exists foo, foo2 identified by 'password2' + require CIPHER 'cipher2' AND SUBJECT 'subject2' AND ISSUER 'issuer2'; +Warnings: +Note 1973 Can't create user 'foo'@'%'; it already exists +Note 1973 Can't create user 'foo2'@'%'; it already exists +select * from mysql.user where user like 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo 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 SPECIFIED cipher issuer subject 0 0 0 0 N N 0.000000 +drop user foo, foo2; +create user foo with MAX_QUERIES_PER_HOUR 10 +MAX_UPDATES_PER_HOUR 20 +MAX_CONNECTIONS_PER_HOUR 30 +MAX_USER_CONNECTIONS 40; +select * from mysql.user where user like 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo 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 10 20 30 40 N N 0.000000 +drop user foo; diff --git a/mysql-test/t/alter_user.test b/mysql-test/t/alter_user.test new file mode 100644 index 00000000000..3a3a7d74ba5 --- /dev/null +++ b/mysql-test/t/alter_user.test @@ -0,0 +1,71 @@ +--source include/not_embedded.inc +--enable_connect_log + + +select * from mysql.user where user = 'root' and host = 'localhost'; +--echo # Test syntax +--echo # +--echo # These 2 selects should have no changes from the first one. +alter user CURRENT_USER; +select * from mysql.user where user = 'root' and host = 'localhost'; +alter user CURRENT_USER(); +select * from mysql.user where user = 'root' and host = 'localhost'; + +create user foo; +select * from mysql.user where user = 'foo'; +alter user foo; +select * from mysql.user where user = 'foo'; + +--echo # Test super privilege works correctly with a read only database. +SET @start_read_only = @@global.read_only; +SET GLOBAL read_only=1; +grant create user on *.* to foo; + +--echo # Currently no super privileges. +connect (a, localhost, foo); +select @@global.read_only; + +--error ER_OPTION_PREVENTS_STATEMENT +alter user foo; + +--echo # Grant super privilege to the user. +connection default; +grant super on *.* to foo; + +--echo # We now have super privilege. We should be able to run alter user. +connect (b, localhost, foo); +alter user foo; + +connection default; +SET GLOBAL read_only = @start_read_only; + +--echo # Test inexistant user. +--error ER_CANNOT_USER +alter user boo; +--echo #--warning ER_CANNOT_USER +alter if exists user boo; + +--echo # Test SSL related altering. +alter user foo identified by 'something'; +select * from mysql.user where user = 'foo'; + +alter user foo identified by 'something2'; +select * from mysql.user where user = 'foo'; + +alter user foo identified by password '*88C89BE093D4ECF72D039F62EBB7477EA1FD4D63'; +select * from mysql.user where user = 'foo'; + +alter user foo identified with 'somecoolplugin'; +select * from mysql.user where user = 'foo'; + +alter user foo identified with 'somecoolplugin' using 'somecoolpassphrase'; +select * from mysql.user where user = 'foo'; + +--echo # Test resource limits altering. +alter user foo with MAX_QUERIES_PER_HOUR 10 + MAX_UPDATES_PER_HOUR 20 + MAX_CONNECTIONS_PER_HOUR 30 + MAX_USER_CONNECTIONS 40; +select * from mysql.user where user = 'foo'; +drop user foo; +--disable_connect_log diff --git a/mysql-test/t/create_user.test b/mysql-test/t/create_user.test new file mode 100644 index 00000000000..f04cb3e302a --- /dev/null +++ b/mysql-test/t/create_user.test @@ -0,0 +1,58 @@ +--source include/not_embedded.inc + +create user foo; +select * from mysql.user where user = 'foo'; +drop user foo; + +create user foo identified by 'password'; +select * from mysql.user where user = 'foo'; +drop user foo; + +create user foo identified by 'password' require SSL; +select * from mysql.user where user = 'foo'; +drop user foo; + +create user foo identified by 'password' require X509; +select * from mysql.user where user = 'foo'; +drop user foo; + +create user foo identified by 'password' require CIPHER 'cipher'; +select * from mysql.user where user = 'foo'; +drop user foo; + +create user foo identified by 'password' require ISSUER 'issuer'; +select * from mysql.user where user = 'foo'; +drop user foo; + +create user foo identified by 'password' require SUBJECT 'subject'; +select * from mysql.user where user = 'foo'; +drop user foo; + +create user foo identified by 'password' require CIPHER 'cipher' + SUBJECT 'subject'; +select * from mysql.user where user = 'foo'; +drop user foo; + +create user foo identified by 'password' require CIPHER 'cipher' + AND SUBJECT 'subject' + AND ISSUER 'issuer'; +select * from mysql.user where user = 'foo'; +drop user foo; + +create user foo, foo2 identified by 'password' require CIPHER 'cipher' + AND SUBJECT 'subject' + AND ISSUER 'issuer'; +select * from mysql.user where user like 'foo'; + +--echo #--warning ER_USER_CREATE_EXISTS +create user if not exists foo, foo2 identified by 'password2' + require CIPHER 'cipher2' AND SUBJECT 'subject2' AND ISSUER 'issuer2'; +select * from mysql.user where user like 'foo'; +drop user foo, foo2; + +create user foo with MAX_QUERIES_PER_HOUR 10 + MAX_UPDATES_PER_HOUR 20 + MAX_CONNECTIONS_PER_HOUR 30 + MAX_USER_CONNECTIONS 40; +select * from mysql.user where user like 'foo'; +drop user foo; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 9178b1f8cc3..24f4042d2a5 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -9851,13 +9851,60 @@ bool mysql_rename_user(THD *thd, List &list) RETURN > 0 Error. Error message already sent. 0 OK. - < 0 Error. Error message not yet sent. */ int mysql_alter_user(THD* thd, List &users_list) { DBUG_ENTER("mysql_alter_user"); int result= 0; - // TODO implement the alter user logic. + TABLE_LIST tables[TABLES_MAX]; + String wrong_users; + // The only table we're altering is the user table. + if ((result= open_grant_tables(thd, tables, TL_WRITE, Table_user))) + DBUG_RETURN(result); + + // Lock ACL data structures until we finish altering all users. + mysql_rwlock_wrlock(&LOCK_grant); + mysql_mutex_lock(&acl_cache->lock); + + LEX_USER *tmp_lex_user; + List_iterator users_list_iterator(users_list); + while ((tmp_lex_user= users_list_iterator++)) + { + LEX_USER* lex_user= get_current_user(thd, tmp_lex_user, false); + if (!lex_user || + fix_lex_user(thd, lex_user) || + replace_user_table(thd, tables[USER_TABLE].table, *lex_user,0, + false, false, true)) + { + thd->clear_error(); + append_user(thd, &wrong_users, tmp_lex_user); + result= TRUE; + continue; + } + } + + // Unlock ACL data structures. + mysql_mutex_unlock(&acl_cache->lock); + mysql_rwlock_unlock(&LOCK_grant); + + if (result) + { + // 'if exists' flag leads to warnings instead of errors. + if (thd->lex->create_info.if_exists()) + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_CANNOT_USER, + ER_THD(thd, ER_CANNOT_USER), + "ALTER USER", wrong_users.c_ptr_safe()); + result= FALSE; + } + else + { + my_error(ER_CANNOT_USER, MYF(0), + "ALTER USER", + wrong_users.c_ptr_safe()); + } + } DBUG_RETURN(result); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0cb13fe5a2b..dd9f2fdf0ae 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7107,9 +7107,10 @@ alter: lex->sql_command= SQLCOM_ALTER_SERVER; lex->server_options.reset($3); } OPTIONS_SYM '(' server_options_list ')' { } - | ALTER opt_if_exists USER clear_privileges user_list + | ALTER opt_if_exists USER clear_privileges grant_list require_clause resource_options { + Lex->create_info.set($2); Lex->sql_command= SQLCOM_ALTER_USER; } ; From 6b6f066fdd9f5f64813ded550e7dbda176ee3c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Tue, 19 Jan 2016 13:01:28 +0200 Subject: [PATCH 004/323] [MDEV-7978] Update test cases Adding an extra statement requires test cases update. --- mysql-test/r/mysqld--help.result | 2 +- mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index dce1578adee..398625992ac 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -1360,7 +1360,7 @@ performance-schema-max-rwlock-instances -1 performance-schema-max-socket-classes 10 performance-schema-max-socket-instances -1 performance-schema-max-stage-classes 150 -performance-schema-max-statement-classes 178 +performance-schema-max-statement-classes 179 performance-schema-max-table-handles -1 performance-schema-max-table-instances -1 performance-schema-max-thread-classes 50 diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index 21f1f905de8..5f05be1b65e 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -3021,9 +3021,9 @@ READ_ONLY YES COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME PERFORMANCE_SCHEMA_MAX_STATEMENT_CLASSES SESSION_VALUE NULL -GLOBAL_VALUE 178 +GLOBAL_VALUE 179 GLOBAL_VALUE_ORIGIN COMPILE-TIME -DEFAULT_VALUE 178 +DEFAULT_VALUE 179 VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_COMMENT Maximum number of statement instruments. From f8b8d202bc83d3de46c89ef86333fe602e711265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Tue, 19 Jan 2016 14:30:19 +0200 Subject: [PATCH 005/323] [MDEV-7978] Updated syntax for SHOW CREATE USER --- sql/mysqld.cc | 1 + sql/sp_head.cc | 1 + sql/sql_acl.cc | 4 ++++ sql/sql_acl.h | 1 + sql/sql_cmd.h | 1 + sql/sql_parse.cc | 17 ++++++++++++++++- sql/sql_yacc.yy | 12 ++++++++++++ 7 files changed, 36 insertions(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7e18251c670..b28cea5ac46 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3766,6 +3766,7 @@ SHOW_VAR com_status_vars[]= { {"show_create_proc", STMT_STATUS(SQLCOM_SHOW_CREATE_PROC)}, {"show_create_table", STMT_STATUS(SQLCOM_SHOW_CREATE)}, {"show_create_trigger", STMT_STATUS(SQLCOM_SHOW_CREATE_TRIGGER)}, + {"show_create_user", STMT_STATUS(SQLCOM_SHOW_CREATE_USER)}, {"show_databases", STMT_STATUS(SQLCOM_SHOW_DATABASES)}, {"show_engine_logs", STMT_STATUS(SQLCOM_SHOW_ENGINE_LOGS)}, {"show_engine_mutex", STMT_STATUS(SQLCOM_SHOW_ENGINE_MUTEX)}, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 5749d5df18d..a27f0ef4250 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -241,6 +241,7 @@ sp_get_flags_for_command(LEX *lex) case SQLCOM_SHOW_CREATE_PROC: case SQLCOM_SHOW_CREATE_EVENT: case SQLCOM_SHOW_CREATE_TRIGGER: + case SQLCOM_SHOW_CREATE_USER: case SQLCOM_SHOW_DATABASES: case SQLCOM_SHOW_ERRORS: case SQLCOM_SHOW_EXPLAIN: diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 24f4042d2a5..74ceb611a8f 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7811,6 +7811,10 @@ static int show_grants_callback(ACL_USER_BASE *role, void *data) return 0; } +bool mysql_show_create_user(THD *thd, LEX_USER *lex_user) +{ + return FALSE; +} void mysql_show_grants_get_fields(THD *thd, List *fields, const char *name) diff --git a/sql/sql_acl.h b/sql/sql_acl.h index ac6a064c7e0..b480d488bc3 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -246,6 +246,7 @@ bool get_show_user(THD *thd, LEX_USER *lex_user, const char **username, void mysql_show_grants_get_fields(THD *thd, List *fields, const char *name); bool mysql_show_grants(THD *thd, LEX_USER *user); +bool mysql_show_create_user(THD *thd, LEX_USER *user); int fill_schema_enabled_roles(THD *thd, TABLE_LIST *tables, COND *cond); int fill_schema_applicable_roles(THD *thd, TABLE_LIST *tables, COND *cond); void get_privilege_desc(char *to, uint max_length, ulong access); diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h index 5c697c4cd10..2350b4be56c 100644 --- a/sql/sql_cmd.h +++ b/sql/sql_cmd.h @@ -94,6 +94,7 @@ enum enum_sql_command { SQLCOM_COMPOUND, SQLCOM_SHOW_GENERIC, SQLCOM_ALTER_USER, + SQLCOM_SHOW_CREATE_USER, /* When a command is added here, be sure it's also added in mysqld.cc diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 77b6f053e79..a5837585b7d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -422,6 +422,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_SHOW_EXPLAIN]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_PROCESSLIST]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_GRANTS]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_CREATE_USER]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_DB]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_MASTER_STAT]= CF_STATUS_COMMAND; @@ -4715,6 +4716,7 @@ mysql_execute_command(THD *thd) break; #ifndef NO_EMBEDDED_ACCESS_CHECKS + case SQLCOM_SHOW_CREATE_USER: case SQLCOM_SHOW_GRANTS: { LEX_USER *grant_user= lex->grant_user; @@ -4722,7 +4724,20 @@ mysql_execute_command(THD *thd) goto error; WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); - res = mysql_show_grants(thd, grant_user); + if (grant_user->user.str && !strcmp(sctx->priv_user, grant_user->user.str) && + grant_user->host.str && !strcmp(sctx->priv_host, grant_user->host.str)) + grant_user->user= current_user; + + if (grant_user->user.str == current_user.str || + grant_user->user.str == current_role.str || + grant_user->user.str == current_user_and_current_role.str || + !check_access(thd, SELECT_ACL, "mysql", NULL, NULL, 1, 0)) + { + if (lex->sql_command == SQLCOM_SHOW_GRANTS) + res = mysql_show_grants(thd, grant_user); + else + res = mysql_show_create_user(thd, grant_user); + } break; } #endif diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index dd9f2fdf0ae..d7e4fb34005 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -12493,6 +12493,18 @@ show_param: lex->sql_command= SQLCOM_SHOW_CREATE_TRIGGER; lex->spname= $3; } + | CREATE USER + { + Lex->sql_command= SQLCOM_SHOW_CREATE_USER; + if (!(Lex->grant_user= (LEX_USER*)thd->alloc(sizeof(LEX_USER)))) + MYSQL_YYABORT; + Lex->grant_user->user= current_user_and_current_role; + } + | CREATE USER user + { + Lex->sql_command= SQLCOM_SHOW_CREATE_USER; + Lex->grant_user= $3; + } | PROCEDURE_SYM STATUS_SYM wild_and_where { LEX *lex= Lex; From a470b3570a7ce2534c9021f3b84d7457a3ba08e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Tue, 19 Jan 2016 14:33:00 +0200 Subject: [PATCH 006/323] [MDEV-7978] Update test cases Update test to account for the new SHOW CREATE USER command. --- mysql-test/r/mysqld--help.result | 2 +- mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index 398625992ac..a008affa9f8 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -1360,7 +1360,7 @@ performance-schema-max-rwlock-instances -1 performance-schema-max-socket-classes 10 performance-schema-max-socket-instances -1 performance-schema-max-stage-classes 150 -performance-schema-max-statement-classes 179 +performance-schema-max-statement-classes 180 performance-schema-max-table-handles -1 performance-schema-max-table-instances -1 performance-schema-max-thread-classes 50 diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index 5f05be1b65e..4c358fd456a 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -3021,9 +3021,9 @@ READ_ONLY YES COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME PERFORMANCE_SCHEMA_MAX_STATEMENT_CLASSES SESSION_VALUE NULL -GLOBAL_VALUE 179 +GLOBAL_VALUE 180 GLOBAL_VALUE_ORIGIN COMPILE-TIME -DEFAULT_VALUE 179 +DEFAULT_VALUE 180 VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_COMMENT Maximum number of statement instruments. From f3f45e46b614bddcef0a37f4352c5909ca565d1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Thu, 21 Jan 2016 13:20:40 +0200 Subject: [PATCH 007/323] [MDEV-7978] Added show create user implementation. --- mysql-test/r/show_create_user.result | 39 +++++ mysql-test/t/show_create_user.test | 32 ++++ sql/sql_acl.cc | 253 +++++++++++++++++---------- sql/sql_yacc.yy | 2 +- 4 files changed, 233 insertions(+), 93 deletions(-) create mode 100644 mysql-test/r/show_create_user.result create mode 100644 mysql-test/t/show_create_user.test diff --git a/mysql-test/r/show_create_user.result b/mysql-test/r/show_create_user.result new file mode 100644 index 00000000000..63013eca074 --- /dev/null +++ b/mysql-test/r/show_create_user.result @@ -0,0 +1,39 @@ +create user foo; +show create user foo; +CREATE USER for foo@% +CREATE USER 'foo'@'%' +create user foo@test; +show create user foo@test; +CREATE USER for foo@test +CREATE USER 'foo'@'test' +create user foo2@test identified by 'password'; +show create user foo2@test; +CREATE USER for foo2@test +CREATE USER 'foo2'@'test' IDENTIFIED BY PASSWORD '*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19' +alter user foo2@test identified with 'someplugin' as 'somepassword'; +show create user foo2@test; +CREATE USER for foo2@test +CREATE USER 'foo2'@'test' IDENTIFIED VIA someplugin USING 'somepassword' +create user foo3@test require SSL; +show create user foo3@test; +CREATE USER for foo3@test +CREATE USER 'foo3'@'test' REQUIRE SSL +create user foo4@test require cipher 'text' issuer 'foo_issuer' subject 'foo_subject'; +show create user foo4@test; +CREATE USER for foo4@test +CREATE USER 'foo4'@'test' REQUIRE ISSUER 'foo_issuer' SUBJECT 'foo_subject' CIPHER 'text' +create user foo5@test require SSL +with MAX_QUERIES_PER_HOUR 10 +MAX_UPDATES_PER_HOUR 20 +MAX_CONNECTIONS_PER_HOUR 30 +MAX_USER_CONNECTIONS 40 +MAX_STATEMENT_TIME 0.5; +show create user foo5@test; +CREATE USER for foo5@test +CREATE USER 'foo5'@'test' REQUIRE SSL WITH MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 MAX_CONNECTIONS_PER_HOUR 30 MAX_USER_CONNECTIONS 40 MAX_STATEMENT_TIME 0.500000 +drop user foo5@test; +drop user foo4@test; +drop user foo3@test; +drop user foo2@test; +drop user foo@test; +drop user foo; diff --git a/mysql-test/t/show_create_user.test b/mysql-test/t/show_create_user.test new file mode 100644 index 00000000000..124856ad564 --- /dev/null +++ b/mysql-test/t/show_create_user.test @@ -0,0 +1,32 @@ +create user foo; +show create user foo; + +create user foo@test; +show create user foo@test; + +create user foo2@test identified by 'password'; +show create user foo2@test; + +alter user foo2@test identified with 'someplugin' as 'somepassword'; +show create user foo2@test; + +create user foo3@test require SSL; +show create user foo3@test; + +create user foo4@test require cipher 'text' issuer 'foo_issuer' subject 'foo_subject'; +show create user foo4@test; + +create user foo5@test require SSL + with MAX_QUERIES_PER_HOUR 10 + MAX_UPDATES_PER_HOUR 20 + MAX_CONNECTIONS_PER_HOUR 30 + MAX_USER_CONNECTIONS 40 + MAX_STATEMENT_TIME 0.5; +show create user foo5@test; + +drop user foo5@test; +drop user foo4@test; +drop user foo3@test; +drop user foo2@test; +drop user foo@test; +drop user foo; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 74ceb611a8f..11272f586c9 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7756,6 +7756,94 @@ static void add_user_option(String *grant, double value, const char *name) } } +static void add_user_parameters(String *result, ACL_USER* acl_user, + bool with_grant) +{ + result->append(STRING_WITH_LEN("@'")); + result->append(acl_user->host.hostname, acl_user->hostname_length, + system_charset_info); + result->append('\''); + + if (acl_user->plugin.str == native_password_plugin_name.str || + acl_user->plugin.str == old_password_plugin_name.str) + { + if (acl_user->auth_string.length) + { + DBUG_ASSERT(acl_user->salt_len); + result->append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '")); + result->append(acl_user->auth_string.str, acl_user->auth_string.length); + result->append('\''); + } + } + else + { + result->append(STRING_WITH_LEN(" IDENTIFIED VIA ")); + result->append(acl_user->plugin.str, acl_user->plugin.length); + if (acl_user->auth_string.length) + { + result->append(STRING_WITH_LEN(" USING '")); + result->append(acl_user->auth_string.str, acl_user->auth_string.length); + result->append('\''); + } + } + /* "show grants" SSL related stuff */ + if (acl_user->ssl_type == SSL_TYPE_ANY) + result->append(STRING_WITH_LEN(" REQUIRE SSL")); + else if (acl_user->ssl_type == SSL_TYPE_X509) + result->append(STRING_WITH_LEN(" REQUIRE X509")); + else if (acl_user->ssl_type == SSL_TYPE_SPECIFIED) + { + int ssl_options = 0; + result->append(STRING_WITH_LEN(" REQUIRE ")); + if (acl_user->x509_issuer) + { + ssl_options++; + result->append(STRING_WITH_LEN("ISSUER \'")); + result->append(acl_user->x509_issuer,strlen(acl_user->x509_issuer)); + result->append('\''); + } + if (acl_user->x509_subject) + { + if (ssl_options++) + result->append(' '); + result->append(STRING_WITH_LEN("SUBJECT \'")); + result->append(acl_user->x509_subject,strlen(acl_user->x509_subject), + system_charset_info); + result->append('\''); + } + if (acl_user->ssl_cipher) + { + if (ssl_options++) + result->append(' '); + result->append(STRING_WITH_LEN("CIPHER '")); + result->append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher), + system_charset_info); + result->append('\''); + } + } + if (with_grant || + (acl_user->user_resource.questions || + acl_user->user_resource.updates || + acl_user->user_resource.conn_per_hour || + acl_user->user_resource.user_conn || + acl_user->user_resource.max_statement_time != 0.0)) + { + result->append(STRING_WITH_LEN(" WITH")); + if (with_grant) + result->append(STRING_WITH_LEN(" GRANT OPTION")); + add_user_option(result, acl_user->user_resource.questions, + "MAX_QUERIES_PER_HOUR", false); + add_user_option(result, acl_user->user_resource.updates, + "MAX_UPDATES_PER_HOUR", false); + add_user_option(result, acl_user->user_resource.conn_per_hour, + "MAX_CONNECTIONS_PER_HOUR", false); + add_user_option(result, acl_user->user_resource.user_conn, + "MAX_USER_CONNECTIONS", true); + add_user_option(result, acl_user->user_resource.max_statement_time, + "MAX_STATEMENT_TIME"); + } +} + static const char *command_array[]= { "SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", "DROP", "RELOAD", @@ -7802,6 +7890,78 @@ static bool print_grants_for_role(THD *thd, ACL_ROLE * role) } +bool mysql_show_create_user(THD *thd, LEX_USER *lex_user) +{ + const char *username = safe_str(lex_user->user.str); + const char *hostname = safe_str(lex_user->host.str); + char buff[1024]; //Show create user should not take more than 1024 bytes. + Protocol *protocol= thd->protocol; + bool error= false; + ACL_USER *acl_user; + DBUG_ENTER("mysql_show_create_user"); + + // Check if the command specifies a username or not. + if (lex_user->user.str == current_user.str) + { + username= thd->security_ctx->priv_user; + hostname= thd->security_ctx->priv_host; + } + + String field_name(buff, sizeof(buff), system_charset_info); + List field_list; + strxmov(buff, "CREATE USER for ", username, "@", hostname, NullS); + Item_string *field = new (thd->mem_root) Item_string_ascii(thd, "", 0); + if (!field) + { + my_error(ER_OUTOFMEMORY, MYF(0)); + DBUG_RETURN(true); + } + + field->name= buff; + field->max_length= sizeof(buff); + field_list.push_back(field, thd->mem_root); + if (protocol->send_result_set_metadata(&field_list, + Protocol::SEND_NUM_ROWS | + Protocol::SEND_EOF)) + DBUG_RETURN(true); + + String result(buff, sizeof(buff), system_charset_info); + result.length(0); + mysql_rwlock_rdlock(&LOCK_grant); + mysql_mutex_lock(&acl_cache->lock); + + acl_user= find_user_exact(hostname, username); + + // User not found in the internal data structures. + if (!acl_user) + { + my_error(ER_PASSWORD_NO_MATCH, MYF(0)); + error= true; + goto end; + } + + result.append("CREATE USER '"); + result.append(username); + result.append('\''); + + add_user_parameters(&result, acl_user, false); + + protocol->prepare_for_resend(); + protocol->store(result.ptr(), result.length(), result.charset()); + if (protocol->write()) + { + error= true; + } + my_eof(thd); + +end: + mysql_rwlock_unlock(&LOCK_grant); + mysql_mutex_unlock(&acl_cache->lock); + + DBUG_RETURN(error); +} + + static int show_grants_callback(ACL_USER_BASE *role, void *data) { THD *thd= (THD *)data; @@ -7811,11 +7971,6 @@ static int show_grants_callback(ACL_USER_BASE *role, void *data) return 0; } -bool mysql_show_create_user(THD *thd, LEX_USER *lex_user) -{ - return FALSE; -} - void mysql_show_grants_get_fields(THD *thd, List *fields, const char *name) { @@ -8090,93 +8245,7 @@ static bool show_global_privileges(THD *thd, ACL_USER_BASE *acl_entry, global.append('\''); if (!handle_as_role) - { - ACL_USER *acl_user= (ACL_USER *)acl_entry; - - global.append (STRING_WITH_LEN("@'")); - global.append(acl_user->host.hostname, acl_user->hostname_length, - system_charset_info); - global.append ('\''); - - if (acl_user->plugin.str == native_password_plugin_name.str || - acl_user->plugin.str == old_password_plugin_name.str) - { - if (acl_user->auth_string.length) - { - DBUG_ASSERT(acl_user->salt_len); - global.append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '")); - global.append(acl_user->auth_string.str, acl_user->auth_string.length); - global.append('\''); - } - } - else - { - global.append(STRING_WITH_LEN(" IDENTIFIED VIA ")); - global.append(acl_user->plugin.str, acl_user->plugin.length); - if (acl_user->auth_string.length) - { - global.append(STRING_WITH_LEN(" USING '")); - global.append(acl_user->auth_string.str, acl_user->auth_string.length); - global.append('\''); - } - } - /* "show grants" SSL related stuff */ - if (acl_user->ssl_type == SSL_TYPE_ANY) - global.append(STRING_WITH_LEN(" REQUIRE SSL")); - else if (acl_user->ssl_type == SSL_TYPE_X509) - global.append(STRING_WITH_LEN(" REQUIRE X509")); - else if (acl_user->ssl_type == SSL_TYPE_SPECIFIED) - { - int ssl_options = 0; - global.append(STRING_WITH_LEN(" REQUIRE ")); - if (acl_user->x509_issuer) - { - ssl_options++; - global.append(STRING_WITH_LEN("ISSUER \'")); - global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer)); - global.append('\''); - } - if (acl_user->x509_subject) - { - if (ssl_options++) - global.append(' '); - global.append(STRING_WITH_LEN("SUBJECT \'")); - global.append(acl_user->x509_subject,strlen(acl_user->x509_subject), - system_charset_info); - global.append('\''); - } - if (acl_user->ssl_cipher) - { - if (ssl_options++) - global.append(' '); - global.append(STRING_WITH_LEN("CIPHER '")); - global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher), - system_charset_info); - global.append('\''); - } - } - if ((want_access & GRANT_ACL) || - (acl_user->user_resource.questions || - acl_user->user_resource.updates || - acl_user->user_resource.conn_per_hour || - acl_user->user_resource.user_conn || - acl_user->user_resource.max_statement_time != 0.0)) - { - global.append(STRING_WITH_LEN(" WITH")); - if (want_access & GRANT_ACL) - global.append(STRING_WITH_LEN(" GRANT OPTION")); - add_user_option(&global, acl_user->user_resource.questions, - "MAX_QUERIES_PER_HOUR", false); - add_user_option(&global, acl_user->user_resource.updates, - "MAX_UPDATES_PER_HOUR", false); - add_user_option(&global, acl_user->user_resource.conn_per_hour, - "MAX_CONNECTIONS_PER_HOUR", false); - add_user_option(&global, acl_user->user_resource.user_conn, - "MAX_USER_CONNECTIONS", true); - add_user_option(&global, acl_user->user_resource.max_statement_time, - "MAX_STATEMENT_TIME"); - } - } + add_user_parameters(&global, (ACL_USER *)acl_entry, (want_access & GRANT_ACL)); protocol->prepare_for_resend(); protocol->store(global.ptr(),global.length(),global.charset()); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index d7e4fb34005..14616d33fbe 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -12498,7 +12498,7 @@ show_param: Lex->sql_command= SQLCOM_SHOW_CREATE_USER; if (!(Lex->grant_user= (LEX_USER*)thd->alloc(sizeof(LEX_USER)))) MYSQL_YYABORT; - Lex->grant_user->user= current_user_and_current_role; + Lex->grant_user->user= current_user; } | CREATE USER user { From 85b085972b729f6c049050f851692c9a5b86f3d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Tue, 8 Mar 2016 00:35:03 +0200 Subject: [PATCH 008/323] [MDEV-7978] Post review fixes and cleanups. * Maintain coding style in sql_yacc.yy in regards to optional clauses. * Remove unused variable from sql_acl.cc. * Update test case --- mysql-test/r/alter_user.result | 18 ++++++++++++++++-- mysql-test/t/alter_user.test | 13 ++++++++++++- sql/sql_acl.cc | 1 - sql/sql_yacc.yy | 17 +++++++++-------- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/alter_user.result b/mysql-test/r/alter_user.result index 2acc2493acb..ac668bba8fa 100644 --- a/mysql-test/r/alter_user.result +++ b/mysql-test/r/alter_user.result @@ -47,7 +47,7 @@ alter if exists user boo; Warnings: Error 1133 Can't find any matching row in the user table Note 1396 Operation ALTER USER failed for 'boo' -# Test SSL related altering. +# Test password related altering. alter user foo identified by 'something'; select * from mysql.user where user = 'foo'; Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time @@ -68,6 +68,20 @@ alter user foo identified with 'somecoolplugin' using 'somecoolpassphrase'; select * from mysql.user where user = 'foo'; Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time % foo N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 somecoolplugin somecoolpassphrase N N 0.000000 +# Test ssl related altering. +alter user foo identified by 'something' require SSL; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N ANY 0 0 0 0 N N 0.000000 +alter user foo identified by 'something' require X509; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N X509 0 0 0 0 N N 0.000000 +alter user foo identified by 'something' +require cipher 'text' issuer 'foo_issuer' subject 'foo_subject'; +select * from mysql.user where user = 'foo'; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N SPECIFIED text foo_issuer foo_subject 0 0 0 0 N N 0.000000 # Test resource limits altering. alter user foo with MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 @@ -75,5 +89,5 @@ MAX_CONNECTIONS_PER_HOUR 30 MAX_USER_CONNECTIONS 40; select * from mysql.user where user = 'foo'; Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 10 20 30 40 somecoolplugin somecoolpassphrase N N 0.000000 +% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N SPECIFIED text foo_issuer foo_subject 10 20 30 40 N N 0.000000 drop user foo; diff --git a/mysql-test/t/alter_user.test b/mysql-test/t/alter_user.test index 3a3a7d74ba5..e32d0c29f2e 100644 --- a/mysql-test/t/alter_user.test +++ b/mysql-test/t/alter_user.test @@ -45,7 +45,7 @@ alter user boo; --echo #--warning ER_CANNOT_USER alter if exists user boo; ---echo # Test SSL related altering. +--echo # Test password related altering. alter user foo identified by 'something'; select * from mysql.user where user = 'foo'; @@ -61,6 +61,17 @@ select * from mysql.user where user = 'foo'; alter user foo identified with 'somecoolplugin' using 'somecoolpassphrase'; select * from mysql.user where user = 'foo'; +--echo # Test ssl related altering. +alter user foo identified by 'something' require SSL; +select * from mysql.user where user = 'foo'; + +alter user foo identified by 'something' require X509; +select * from mysql.user where user = 'foo'; + +alter user foo identified by 'something' +require cipher 'text' issuer 'foo_issuer' subject 'foo_subject'; +select * from mysql.user where user = 'foo'; + --echo # Test resource limits altering. alter user foo with MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 11272f586c9..2b6ababa8dd 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7907,7 +7907,6 @@ bool mysql_show_create_user(THD *thd, LEX_USER *lex_user) hostname= thd->security_ctx->priv_host; } - String field_name(buff, sizeof(buff), system_charset_info); List field_list; strxmov(buff, "CREATE USER for ", username, "@", hostname, NullS); Item_string *field = new (thd->mem_root) Item_string_ascii(thd, "", 0); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 14616d33fbe..6799781f5e0 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2532,7 +2532,7 @@ create: } view_or_trigger_or_sp_or_event { } | create_or_replace USER opt_if_not_exists clear_privileges grant_list - require_clause resource_options + opt_require_clause opt_resource_options { if (Lex->set_command_with_check(SQLCOM_CREATE_USER, $1 | $3)) MYSQL_YYABORT; @@ -7107,8 +7107,9 @@ alter: lex->sql_command= SQLCOM_ALTER_SERVER; lex->server_options.reset($3); } OPTIONS_SYM '(' server_options_list ')' { } + /* ALTER USER foo is allowed for MySQL compatibility. */ | ALTER opt_if_exists USER clear_privileges grant_list - require_clause resource_options + opt_require_clause opt_resource_options { Lex->create_info.set($2); Lex->sql_command= SQLCOM_ALTER_USER; @@ -15055,14 +15056,14 @@ grant: grant_command: grant_privileges ON opt_table grant_ident TO_SYM grant_list - require_clause grant_options + opt_require_clause opt_grant_options { LEX *lex= Lex; lex->sql_command= SQLCOM_GRANT; lex->type= 0; } | grant_privileges ON FUNCTION_SYM grant_ident TO_SYM grant_list - require_clause grant_options + opt_require_clause opt_grant_options { LEX *lex= Lex; if (lex->columns.elements) @@ -15074,7 +15075,7 @@ grant_command: lex->type= TYPE_ENUM_FUNCTION; } | grant_privileges ON PROCEDURE_SYM grant_ident TO_SYM grant_list - require_clause grant_options + opt_require_clause opt_grant_options { LEX *lex= Lex; if (lex->columns.elements) @@ -15411,7 +15412,7 @@ column_list_id: } ; -require_clause: +opt_require_clause: /* empty */ | REQUIRE_SYM require_list { @@ -15469,13 +15470,13 @@ resource_option_list: | resource_option {} ; -resource_options: +opt_resource_options: /* empty */ {} | WITH resource_option_list ; -grant_options: +opt_grant_options: /* empty */ {} | WITH grant_option_list {} ; From 0ff897807fc2f4a32e1ba1ae148005930ea604b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Tue, 8 Mar 2016 10:50:04 +0200 Subject: [PATCH 009/323] [MDEV-7978] Make show_create_user testcase not run on embedded build --- mysql-test/t/show_create_user.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/t/show_create_user.test b/mysql-test/t/show_create_user.test index 124856ad564..a10c8aeeda6 100644 --- a/mysql-test/t/show_create_user.test +++ b/mysql-test/t/show_create_user.test @@ -1,3 +1,5 @@ +--source include/not_embedded.inc + create user foo; show create user foo; From 053653a23cac6f3f2e5288979438de27c9d0100a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Tue, 8 Mar 2016 11:05:32 +0200 Subject: [PATCH 010/323] [MDEV-7978] Update test cases for sysvars_server_embedded. --- mysql-test/suite/sys_vars/r/sysvars_server_embedded.result | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index 865b5a8ca2f..6be27560d89 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -2825,9 +2825,9 @@ READ_ONLY YES COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME PERFORMANCE_SCHEMA_MAX_STATEMENT_CLASSES SESSION_VALUE NULL -GLOBAL_VALUE 178 +GLOBAL_VALUE 180 GLOBAL_VALUE_ORIGIN COMPILE-TIME -DEFAULT_VALUE 178 +DEFAULT_VALUE 180 VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_COMMENT Maximum number of statement instruments. From 594c11fffc94500c627bdb78e287f65cffacc312 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Tue, 1 Sep 2020 12:49:09 +0200 Subject: [PATCH 011/323] Ukrainian error text translations added. --- sql/share/errmsg-utf8.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index a4465ae0083..4bb1ae951af 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -1800,9 +1800,10 @@ ER_WRONG_AUTO_KEY 42000 S1009 slo "Môžete mať iba jedno AUTO pole a to musí byť definované ako kľúč" spa "Puede ser solamente un campo automatico y este debe ser definido como una clave" swe "Det får finnas endast ett AUTO_INCREMENT-fält och detta måste vara en nyckel" - ukr "Невірне визначення таблиці; Може бути лише один автоматичний стовбець, що повинен бути визначений як ключ" + ukr "Хибне визначення таблиці; Може бути лише один автоматичний стовбець, що повинен бути визначений як ключ" ER_BINLOG_CANT_DELETE_GTID_DOMAIN eng "Could not delete gtid domain. Reason: %s." + ukr "Не можу видалити домен gtid. Причина: %s." ER_NORMAL_SHUTDOWN cze "%s (%s): normální ukončení" dan "%s (%s): Normal nedlukning" @@ -2203,6 +2204,7 @@ ER_INSERT_INFO ER_UPDATE_TABLE_USED eng "Table '%-.192s' is specified twice, both as a target for '%s' and as a separate source for data" swe "Table '%-.192s' är använd två gånger. Både för '%s' och för att hämta data" + ukr "Таблиця '%-.192s' вказується двічі, як цільова для '%s', так і як окреме джерело даних" ER_NO_SUCH_THREAD cze "Neznámá identifikace threadu: %lu" dan "Ukendt tråd id: %lu" @@ -2824,6 +2826,7 @@ ER_WRONG_OUTER_JOIN 42000 ER_NULL_COLUMN_IN_INDEX 42000 eng "Table handler doesn't support NULL in given index. Please change column '%-.192s' to be NOT NULL or use another handler" swe "Tabell hanteraren kan inte indexera NULL kolumner för den givna index typen. Ändra '%-.192s' till NOT NULL eller använd en annan hanterare" + ukr "Вказівник таблиці не підтримує NULL у зазначенному індексі. Будь ласка, зменіть стовпчик '%-.192s' на NOT NULL або використайте інший вказівник таблиці." ER_CANT_FIND_UDF cze "Nemohu načíst funkci '%-.192s'" dan "Kan ikke læse funktionen '%-.192s'" @@ -4314,6 +4317,7 @@ ER_MASTER_INFO jpn "'master info '%.*s''構造体の初期化ができませんでした。MariaDBエラーログでエラーメッセージを確認してください。" serbian "Nisam mogao da inicijalizujem informacionu strukturu glavnog servera, proverite da li imam privilegije potrebne za pristup file-u 'master.info' '%.*s'" swe "Kunde inte initialisera replikationsstrukturerna för '%.*s'. See MariaDB fel fil för mera information" + ukr "Інформаційна структура з'єднання головного і підлеглого (master.info) для '%.*s' не може бути ініціалізована" ER_SLAVE_THREAD dan "Kunne ikke danne en slave-tråd; check systemressourcerne" nla "Kon slave thread niet aanmaken, controleer systeem resources" @@ -4478,6 +4482,7 @@ ER_UNION_TABLES_IN_DIFFERENT_DIR serbian "Pogrešna definicija tabele; sve 'MERGE' tabele moraju biti u istoj bazi podataka" spa "Incorrecta definición de la tabla; Todas las tablas MERGE deben estar en el mismo banco de datos" swe "Felaktig tabelldefinition; alla tabeller i en MERGE-tabell måste vara i samma databas" + ukr "Хибне визначення таблиці; всі MERGE-таблиці повинні належити до однієї бази ланних." ER_LOCK_DEADLOCK 40001 nla "Deadlock gevonden tijdens lock-aanvraag poging; Probeer herstart van de transactie" eng "Deadlock found when trying to get lock; try restarting transaction" @@ -4491,6 +4496,7 @@ ER_LOCK_DEADLOCK 40001 serbian "Unakrsno zaključavanje pronađeno kada sam pokušao da dobijem pravo na zaključavanje; Probajte da restartujete transakciju" spa "Encontrado deadlock cuando tentando obtener el bloqueo; Tente recomenzar la transición" swe "Fick 'DEADLOCK' vid låsförsök av block/rad. Försök att starta om transaktionen" + ukr "Взаємне блокування знайдено під час спроби отримати блокування; спробуйте перезапустити транзакцію." ER_TABLE_CANT_HANDLE_FT nla "Het gebruikte tabel type (%s) ondersteund geen FULLTEXT indexen" eng "The storage engine %s doesn't support FULLTEXT indexes" @@ -4517,6 +4523,7 @@ ER_CANNOT_ADD_FOREIGN serbian "Ne mogu da dodam proveru spoljnog ključa" spa "No puede adicionar clave extranjera constraint" swe "Kan inte lägga till 'FOREIGN KEY constraint'" + ukr "Не можу додати обмеження зовнішнього ключа" ER_NO_REFERENCED_ROW 23000 nla "Kan onderliggende rij niet toevoegen: foreign key beperking gefaald" eng "Cannot add or update a child row: a foreign key constraint fails" @@ -4531,6 +4538,7 @@ ER_NO_REFERENCED_ROW 23000 rus "Невозможно добавить или обновить дочернюю строку: проверка ограничений внешнего ключа не выполняется" spa "No puede adicionar una línea hijo: falla de clave extranjera constraint" swe "FOREIGN KEY-konflikt: Kan inte skriva barn" + ukr "Не вдається додати або оновити дочірній рядок: невдала перевірка обмеження зовнішнього ключа" ER_ROW_IS_REFERENCED 23000 eng "Cannot delete or update a parent row: a foreign key constraint fails" fre "Impossible de supprimer un enregistrement père : une constrainte externe l'empèche" From 0448558a0dd88c8031b66a9ea0296ee05b6333d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 23 Sep 2020 12:14:05 +0300 Subject: [PATCH 012/323] Fix GCC 10.2.0 -Og -fsanitize=undefined -Wformat-overflow For some reason, adding -fsanitize=undefined (cmake -DWITH_UBSAN=ON) to the compilation flags will cause even more warnings to be emitted. The warning was a bogus one: tests/mysql_client_test.c:8632:22: error: '%d' directive writing between 1 and 11 bytes into a region of size 9 [-Werror=format-overflow=] 8632 | sprintf(field, "c%d int", i); | ^~ tests/mysql_client_test.c:8632:20: note: directive argument in the range [-2147483648, 999] The warning does not take into account that the lower bound of the variable actually is 0. But, we can help the compiler and use an unsigned variable. --- tests/mysql_client_test.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index ec878ae830c..9a90862e93f 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -1,5 +1,5 @@ /* Copyright (c) 2002, 2014, Oracle and/or its affiliates. - Copyright (c) 2008, 2017, MariaDB + Copyright (c) 2008, 2020, 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 @@ -8457,7 +8457,8 @@ static void test_mem_overun() char buffer[10000], field[10]; MYSQL_STMT *stmt; MYSQL_RES *field_res; - int rc, i, length; + int rc, length; + unsigned i; myheader("test_mem_overun"); @@ -8471,7 +8472,7 @@ static void test_mem_overun() strxmov(buffer, "create table t_mem_overun(", NullS); for (i= 0; i < 1000; i++) { - sprintf(field, "c%d int", i); + sprintf(field, "c%u int", i); strxmov(buffer, buffer, field, ", ", NullS); } length= strlen(buffer); From af40a2b43e94cab6b25c9efe4b18c3112b4a9e6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 23 Sep 2020 12:27:56 +0300 Subject: [PATCH 013/323] Fix GCC 10.2.0 -Og -fsanitize=undefined -Wmaybe-uninitialized For some reason, adding -fsanitize=undefined (cmake -DWITH_UBSAN=ON) to the compilation flags will cause even more warnings to be emitted. The warnings do look bogus, but the code can be simplified. --- sql/item_geofunc.cc | 16 +++++++++------- sql/opt_subselect.cc | 13 ++++--------- storage/innobase/btr/btr0sea.cc | 6 +----- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 0db8d7075f6..1c3fafc0582 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2003, 2016, Oracle and/or its affiliates. - Copyright (c) 2011, 2016, MariaDB + Copyright (c) 2011, 2020, 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 @@ -456,16 +456,18 @@ String *Item_func_boundary::val_str(String *str_value) DBUG_ASSERT(fixed == 1); String arg_val; String *swkb= args[0]->val_str(&arg_val); + + if ((null_value= args[0]->null_value)) + DBUG_RETURN(0); + Geometry_buffer buffer; - Geometry *g; uint32 srid= 0; Transporter trn(&res_receiver); - - if ((null_value= - args[0]->null_value || - !(g= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))) + + Geometry *g= Geometry::construct(&buffer, swkb->ptr(), swkb->length()); + if (!g) DBUG_RETURN(0); - + if (g->store_shapes(&trn)) goto mem_error; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 45aa625389d..fec4e8b2828 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2010, 2019, MariaDB + Copyright (c) 2010, 2020, 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 @@ -2634,16 +2634,11 @@ bool find_eq_ref_candidate(TABLE *table, table_map sj_inner_tables) do { uint key= keyuse->key; - KEY *keyinfo; key_part_map bound_parts= 0; - bool is_excluded_key= keyuse->is_for_hash_join(); - if (!is_excluded_key) - { - keyinfo= table->key_info + key; - is_excluded_key= !MY_TEST(keyinfo->flags & HA_NOSAME); - } - if (!is_excluded_key) + if (!keyuse->is_for_hash_join() && + (table->key_info[key].flags & HA_NOSAME)) { + KEY *keyinfo= table->key_info + key; do /* For all equalities on all key parts */ { /* diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc index ea34b4034e4..ee39aacf162 100644 --- a/storage/innobase/btr/btr0sea.cc +++ b/storage/innobase/btr/btr0sea.cc @@ -1731,7 +1731,6 @@ func_exit: void btr_search_update_hash_on_insert(btr_cur_t* cursor) { - hash_table_t* table; buf_block_t* block; dict_index_t* index; const rec_t* rec; @@ -1798,6 +1797,7 @@ btr_search_update_hash_on_insert(btr_cur_t* cursor) } rw_lock_t* const latch = btr_get_search_latch(index); + hash_table_t* const table = btr_get_search_table(index); bool locked = false; if (!page_rec_is_infimum(rec)) { @@ -1814,7 +1814,6 @@ btr_search_update_hash_on_insert(btr_cur_t* cursor) goto function_exit; } - table = btr_get_search_table(index); ha_insert_for_fold(table, ins_fold, block, ins_rec); } @@ -1830,7 +1829,6 @@ btr_search_update_hash_on_insert(btr_cur_t* cursor) if (!btr_search_enabled || !block->index) { goto function_exit; } - table = btr_get_search_table(index); } if (!left_side) { @@ -1851,7 +1849,6 @@ check_next_rec: if (!btr_search_enabled || !block->index) { goto function_exit; } - table = btr_get_search_table(index); } ha_insert_for_fold(table, ins_fold, block, ins_rec); @@ -1868,7 +1865,6 @@ check_next_rec: if (!btr_search_enabled || !block->index) { goto function_exit; } - table = btr_get_search_table(index); } if (!left_side) { From 70960bd33d2699bc96821ec0a0381ca6de86e93e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 23 Sep 2020 12:42:30 +0300 Subject: [PATCH 014/323] UBSAN: Fix a bit shift overflow Shifting a 16-bit type by 16 bits is undefined behaviour. The result is at least 32 bits, so let us cast the shift operand to a wider type before shifting. --- sql-common/client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql-common/client.c b/sql-common/client.c index b66eee2a508..ff36b757957 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1,5 +1,5 @@ /* Copyright (c) 2003, 2016, Oracle and/or its affiliates. - Copyright (c) 2009, 2017, MariaDB + Copyright (c) 2009, 2020, 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 @@ -3295,7 +3295,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, /* New protocol with 16 bytes to describe server characteristics */ mysql->server_language=end[2]; mysql->server_status=uint2korr(end+3); - mysql->server_capabilities|= uint2korr(end+5) << 16; + mysql->server_capabilities|= ((unsigned) uint2korr(end+5)) << 16; pkt_scramble_len= end[7]; if (pkt_scramble_len < 0) { From 7c5519c12d46ead947d341cbdcbb6fbbe4d4fe1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 23 Sep 2020 12:47:49 +0300 Subject: [PATCH 015/323] MDEV-22387: Do not violate __attribute__((nonnull)) Passing a null pointer to a nonnull argument is not only undefined behaviour, but it also grants the compiler the permission to optimize away further checks whether the pointer is null. GCC -O2 at least starting with version 8 may do that, potentially causing SIGSEGV. --- sql/protocol.cc | 8 +++++--- sql/sql_string.cc | 2 +- strings/ctype-mb.c | 6 ++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/sql/protocol.cc b/sql/protocol.cc index aa795b9d12a..de6d1b96f76 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. - Copyright (c) 2008, 2012, Monty Program Ab + Copyright (c) 2008, 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 @@ -58,7 +58,8 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length) packet->realloc(packet_length+9+length)) return 1; uchar *to= net_store_length((uchar*) packet->ptr()+packet_length, length); - memcpy(to,from,length); + if (length) + memcpy(to,from,length); packet->length((uint) (to+length-(uchar*) packet->ptr())); return 0; } @@ -715,7 +716,8 @@ void net_send_progress_packet(THD *thd) uchar *net_store_data(uchar *to, const uchar *from, size_t length) { to=net_store_length_fast(to,length); - memcpy(to,from,length); + if (length) + memcpy(to,from,length); return to+length; } diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 177d2a77d09..b79ca82698b 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -826,7 +826,7 @@ int sortcmp(const String *s,const String *t, CHARSET_INFO *cs) int stringcmp(const String *s,const String *t) { uint32 s_len=s->length(),t_len=t->length(),len=MY_MIN(s_len,t_len); - int cmp= memcmp(s->ptr(), t->ptr(), len); + int cmp= len ? memcmp(s->ptr(), t->ptr(), len) : 0; return (cmp) ? cmp : (int) (s_len - t_len); } diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c index 3bcd29bbb8b..cabc940065b 100644 --- a/strings/ctype-mb.c +++ b/strings/ctype-mb.c @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2014, Oracle and/or its affiliates. - Copyright (c) 2009, 2014, SkySQL Ab. + Copyright (c) 2009, 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 @@ -407,7 +407,9 @@ my_copy_fix_mb(CHARSET_INFO *cs, src, src + src_length, nchars, status); DBUG_ASSERT(well_formed_nchars <= nchars); - memmove(dst, src, (well_formed_length= status->m_source_end_pos - src)); + well_formed_length= status->m_source_end_pos - src; + if (well_formed_length) + memmove(dst, src, well_formed_length); if (!status->m_well_formed_error_pos) return well_formed_length; From 8370a38dc07ba8a84bab0893792b999fcd020931 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 23 Sep 2020 15:42:11 +0200 Subject: [PATCH 016/323] Window , MTR : fix lookup for mysql_install_db.exe Fixes (rare) case when mysql-test is included into "noinstall" ZIP. --- mysql-test/mysql-test-run.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index d6abda9eb36..0eacdd9125d 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2332,7 +2332,8 @@ sub environment_setup { $ENV{'MYSQL_EMBEDDED'}= $exe_mysql_embedded; if(IS_WINDOWS) { - $ENV{'MYSQL_INSTALL_DB_EXE'}= mtr_exe_exists("$bindir/sql$opt_vs_config/mysql_install_db"); + $ENV{'MYSQL_INSTALL_DB_EXE'}= mtr_exe_exists("$bindir/sql$opt_vs_config/mysql_install_db", + "$bindir/bin/mysql_install_db"); } my $client_config_exe= From 4ddaa571faeca88309709bce8064b0b6df80159c Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 24 Sep 2020 08:05:56 +1000 Subject: [PATCH 017/323] MDEV-23697: perl -w -> perl Leave debian/additions/mysqlreport as #!/usr/bin/perl Acknowledge that `env perl` is a hack, a complete fix needs to consider which path perl is at and insert into these scripts. The usefulness of these scripts is questionable. --- debian/additions/mysqlreport | 2 +- scripts/mytop.sh | 2 +- tests/drop_test.pl | 2 +- tests/fork2_test.pl | 2 +- tests/fork_big.pl | 2 +- tests/fork_big2.pl | 2 +- tests/index_corrupt.pl | 2 +- tests/insert_and_repair.pl | 2 +- tests/mail_to_db.pl | 2 +- tests/pmail.pl | 2 +- tests/rename_test.pl | 2 +- tests/test_delayed_insert.pl | 2 +- tests/truncate.pl | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/debian/additions/mysqlreport b/debian/additions/mysqlreport index 1bdcfc544a8..86a57bff19c 100755 --- a/debian/additions/mysqlreport +++ b/debian/additions/mysqlreport @@ -1,4 +1,4 @@ -#!/usr/bin/env perl -w +#!/usr/bin/perl # mysqlreport v4.0 Oct 23 2015 # http://hackmysql.com/mysqlreport diff --git a/scripts/mytop.sh b/scripts/mytop.sh index e985d518c01..e7b9040c3a8 100644 --- a/scripts/mytop.sh +++ b/scripts/mytop.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env perl -w +#!/usr/bin/env perl # # $Id: mytop,v 1.91 2012/01/18 16:49:12 mgrennan Exp $ diff --git a/tests/drop_test.pl b/tests/drop_test.pl index e4ae5a2671f..6ed05abb7ab 100755 --- a/tests/drop_test.pl +++ b/tests/drop_test.pl @@ -1,4 +1,4 @@ -#!/usr/bin/env perl -w +#!/usr/bin/env perl # Copyright (C) 2000 MySQL AB # Use is subject to license terms diff --git a/tests/fork2_test.pl b/tests/fork2_test.pl index a05a9b96679..55e494dcedc 100755 --- a/tests/fork2_test.pl +++ b/tests/fork2_test.pl @@ -1,4 +1,4 @@ -#!/usr/bin/env perl -w +#!/usr/bin/env perl # Copyright (C) 2000, 2001 MySQL AB # Use is subject to license terms diff --git a/tests/fork_big.pl b/tests/fork_big.pl index b5f8770c903..bd048e8fcb0 100755 --- a/tests/fork_big.pl +++ b/tests/fork_big.pl @@ -1,4 +1,4 @@ -#!/usr/bin/env perl -w +#!/usr/bin/env perl use strict; # Copyright (c) 2001, 2006 MySQL AB diff --git a/tests/fork_big2.pl b/tests/fork_big2.pl index 7f055609108..d0c17af8cb1 100644 --- a/tests/fork_big2.pl +++ b/tests/fork_big2.pl @@ -1,4 +1,4 @@ -#!/usr/bin/env perl -w +#!/usr/bin/env perl # Copyright (c) 2002, 2003, 2005, 2006 MySQL AB # Use is subject to license terms diff --git a/tests/index_corrupt.pl b/tests/index_corrupt.pl index 8194982755a..e40bb7afdbb 100755 --- a/tests/index_corrupt.pl +++ b/tests/index_corrupt.pl @@ -1,4 +1,4 @@ -#!/usr/bin/env perl -w +#!/usr/bin/env perl # Copyright (C) 2005 MySQL AB # Use is subject to license terms diff --git a/tests/insert_and_repair.pl b/tests/insert_and_repair.pl index 91333746e79..a8e74e5f30e 100755 --- a/tests/insert_and_repair.pl +++ b/tests/insert_and_repair.pl @@ -1,4 +1,4 @@ -#!/usr/bin/env perl -w +#!/usr/bin/env perl # Copyright (C) 2000, 2001 MySQL AB # Use is subject to license terms diff --git a/tests/mail_to_db.pl b/tests/mail_to_db.pl index 6e5c115f543..bab9e7eb74a 100755 --- a/tests/mail_to_db.pl +++ b/tests/mail_to_db.pl @@ -1,4 +1,4 @@ -#!/usr/bin/env perl -w +#!/usr/bin/env perl # Copyright Abandoned 1998 TCX DataKonsult AB & Monty Program KB & Detron HB # This file is public domain and comes with NO WARRANTY of any kind # diff --git a/tests/pmail.pl b/tests/pmail.pl index 97e5914f794..cf46f5a054d 100755 --- a/tests/pmail.pl +++ b/tests/pmail.pl @@ -1,4 +1,4 @@ -#!/usr/bin/env perl -w +#!/usr/bin/env perl # Copyright (C) 2000, 2005 MySQL AB # Use is subject to license terms diff --git a/tests/rename_test.pl b/tests/rename_test.pl index ec7254a4cf6..aa0befa125d 100755 --- a/tests/rename_test.pl +++ b/tests/rename_test.pl @@ -1,4 +1,4 @@ -#!/usr/bin/env perl -w +#!/usr/bin/env perl # Copyright (C) 2000, 2001 MySQL AB # Use is subject to license terms diff --git a/tests/test_delayed_insert.pl b/tests/test_delayed_insert.pl index 2f8f97b25c6..f0702e6378b 100755 --- a/tests/test_delayed_insert.pl +++ b/tests/test_delayed_insert.pl @@ -1,4 +1,4 @@ -#!/usr/bin/env perl -w +#!/usr/bin/env perl # Copyright (C) 2000, 2001 MySQL AB # Use is subject to license terms diff --git a/tests/truncate.pl b/tests/truncate.pl index e83ebab9291..21d469662d9 100755 --- a/tests/truncate.pl +++ b/tests/truncate.pl @@ -1,4 +1,4 @@ -#!/usr/bin/env perl -w +#!/usr/bin/env perl # Copyright (C) 2002 MySQL AB # Use is subject to license terms From 3d28d1f3aaad17115f2109e133e41c0d04c44f65 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 24 Sep 2020 08:16:30 +1000 Subject: [PATCH 018/323] MDEV-23697: /usr/bin/perl for debian scripts --- debian/additions/innotop/innotop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/additions/innotop/innotop b/debian/additions/innotop/innotop index ee0488580f6..b995f44a007 100644 --- a/debian/additions/innotop/innotop +++ b/debian/additions/innotop/innotop @@ -1,4 +1,4 @@ -#!/usr/bin/env perl +#!/usr/bin/perl # vim: tw=160:nowrap:expandtab:tabstop=3:shiftwidth=3:softtabstop=3 From 1be8ac390d3665d061141fe50a1c9e63b7b4b294 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 24 Sep 2020 13:48:21 +1000 Subject: [PATCH 019/323] Revert "[MDEV-7978] add show create user" Appoligies, had a dirty branch before pushing: This reverts commit 053653a23cac6f3f2e5288979438de27c9d0100a. This reverts commit 0ff897807fc2f4a32e1ba1ae148005930ea604b5. This reverts commit 85b085972b729f6c049050f851692c9a5b86f3d5. This reverts commit f3f45e46b614bddcef0a37f4352c5909ca565d1d. This reverts commit a470b3570a7ce2534c9021f3b84d7457a3ba08e1. This reverts commit f8b8d202bc83d3de46c89ef86333fe602e711265. This reverts commit 6b6f066fdd9f5f64813ded550e7dbda176ee3c82. This reverts commit a701e9e6c390c3cbac69872e95b1aec565341d30. This reverts commit c169838611e13c9f0559b2f49ba8c36aec11a78b. --- mysql-test/r/alter_user.result | 93 ------ mysql-test/r/create_user.result | 72 ---- mysql-test/r/mysqld--help.result | 2 +- mysql-test/r/show_create_user.result | 39 --- .../sys_vars/r/sysvars_server_embedded.result | 4 +- .../r/sysvars_server_notembedded.result | 4 +- mysql-test/t/alter_user.test | 82 ----- mysql-test/t/create_user.test | 58 ---- mysql-test/t/show_create_user.test | 34 -- sql/mysqld.cc | 2 - sql/sp_head.cc | 2 - sql/sql_acl.cc | 315 +++++------------- sql/sql_acl.h | 2 - sql/sql_cmd.h | 2 - sql/sql_parse.cc | 27 +- sql/sql_yacc.yy | 81 ++--- 16 files changed, 118 insertions(+), 701 deletions(-) delete mode 100644 mysql-test/r/alter_user.result delete mode 100644 mysql-test/r/create_user.result delete mode 100644 mysql-test/r/show_create_user.result delete mode 100644 mysql-test/t/alter_user.test delete mode 100644 mysql-test/t/create_user.test delete mode 100644 mysql-test/t/show_create_user.test diff --git a/mysql-test/r/alter_user.result b/mysql-test/r/alter_user.result deleted file mode 100644 index ac668bba8fa..00000000000 --- a/mysql-test/r/alter_user.result +++ /dev/null @@ -1,93 +0,0 @@ -select * from mysql.user where user = 'root' and host = 'localhost'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -localhost root Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y 0 0 0 0 N N 0.000000 -# Test syntax -# -# These 2 selects should have no changes from the first one. -alter user CURRENT_USER; -select * from mysql.user where user = 'root' and host = 'localhost'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -localhost root Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y 0 0 0 0 N N 0.000000 -alter user CURRENT_USER(); -select * from mysql.user where user = 'root' and host = 'localhost'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -localhost root Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y 0 0 0 0 N N 0.000000 -create user foo; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo 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 N N 0.000000 -alter user foo; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo 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 N N 0.000000 -# Test super privilege works correctly with a read only database. -SET @start_read_only = @@global.read_only; -SET GLOBAL read_only=1; -grant create user on *.* to foo; -# Currently no super privileges. -connect a, localhost, foo; -select @@global.read_only; -@@global.read_only -1 -alter user foo; -ERROR HY000: The MariaDB server is running with the --read-only option so it cannot execute this statement -# Grant super privilege to the user. -connection default; -grant super on *.* to foo; -# We now have super privilege. We should be able to run alter user. -connect b, localhost, foo; -alter user foo; -connection default; -SET GLOBAL read_only = @start_read_only; -# Test inexistant user. -alter user boo; -ERROR HY000: Operation ALTER USER failed for 'boo' -#--warning ER_CANNOT_USER -alter if exists user boo; -Warnings: -Error 1133 Can't find any matching row in the user table -Note 1396 Operation ALTER USER failed for 'boo' -# Test password related altering. -alter user foo identified by 'something'; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 N N 0.000000 -alter user foo identified by 'something2'; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *9CD58369E930E28C8996A89DB18B63294E6DC10C N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 N N 0.000000 -alter user foo identified by password '*88C89BE093D4ECF72D039F62EBB7477EA1FD4D63'; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 N N 0.000000 -alter user foo identified with 'somecoolplugin'; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 somecoolplugin N N 0.000000 -alter user foo identified with 'somecoolplugin' using 'somecoolpassphrase'; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 somecoolplugin somecoolpassphrase N N 0.000000 -# Test ssl related altering. -alter user foo identified by 'something' require SSL; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N ANY 0 0 0 0 N N 0.000000 -alter user foo identified by 'something' require X509; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N X509 0 0 0 0 N N 0.000000 -alter user foo identified by 'something' -require cipher 'text' issuer 'foo_issuer' subject 'foo_subject'; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N SPECIFIED text foo_issuer foo_subject 0 0 0 0 N N 0.000000 -# Test resource limits altering. -alter user foo with MAX_QUERIES_PER_HOUR 10 -MAX_UPDATES_PER_HOUR 20 -MAX_CONNECTIONS_PER_HOUR 30 -MAX_USER_CONNECTIONS 40; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N SPECIFIED text foo_issuer foo_subject 10 20 30 40 N N 0.000000 -drop user foo; diff --git a/mysql-test/r/create_user.result b/mysql-test/r/create_user.result deleted file mode 100644 index 1411f2e8792..00000000000 --- a/mysql-test/r/create_user.result +++ /dev/null @@ -1,72 +0,0 @@ -create user foo; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo 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 N N 0.000000 -drop user foo; -create user foo identified by 'password'; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 N N 0.000000 -drop user foo; -create user foo identified by 'password' require SSL; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 ANY 0 0 0 0 N N 0.000000 -drop user foo; -create user foo identified by 'password' require X509; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 X509 0 0 0 0 N N 0.000000 -drop user foo; -create user foo identified by 'password' require CIPHER 'cipher'; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 SPECIFIED cipher 0 0 0 0 N N 0.000000 -drop user foo; -create user foo identified by 'password' require ISSUER 'issuer'; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 SPECIFIED issuer 0 0 0 0 N N 0.000000 -drop user foo; -create user foo identified by 'password' require SUBJECT 'subject'; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 SPECIFIED subject 0 0 0 0 N N 0.000000 -drop user foo; -create user foo identified by 'password' require CIPHER 'cipher' - SUBJECT 'subject'; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 SPECIFIED cipher subject 0 0 0 0 N N 0.000000 -drop user foo; -create user foo identified by 'password' require CIPHER 'cipher' -AND SUBJECT 'subject' - AND ISSUER 'issuer'; -select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 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 SPECIFIED cipher issuer subject 0 0 0 0 N N 0.000000 -drop user foo; -create user foo, foo2 identified by 'password' require CIPHER 'cipher' -AND SUBJECT 'subject' - AND ISSUER 'issuer'; -select * from mysql.user where user like 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo 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 SPECIFIED cipher issuer subject 0 0 0 0 N N 0.000000 -#--warning ER_USER_CREATE_EXISTS -create user if not exists foo, foo2 identified by 'password2' - require CIPHER 'cipher2' AND SUBJECT 'subject2' AND ISSUER 'issuer2'; -Warnings: -Note 1973 Can't create user 'foo'@'%'; it already exists -Note 1973 Can't create user 'foo2'@'%'; it already exists -select * from mysql.user where user like 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo 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 SPECIFIED cipher issuer subject 0 0 0 0 N N 0.000000 -drop user foo, foo2; -create user foo with MAX_QUERIES_PER_HOUR 10 -MAX_UPDATES_PER_HOUR 20 -MAX_CONNECTIONS_PER_HOUR 30 -MAX_USER_CONNECTIONS 40; -select * from mysql.user where user like 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo 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 10 20 30 40 N N 0.000000 -drop user foo; diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index a008affa9f8..dce1578adee 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -1360,7 +1360,7 @@ performance-schema-max-rwlock-instances -1 performance-schema-max-socket-classes 10 performance-schema-max-socket-instances -1 performance-schema-max-stage-classes 150 -performance-schema-max-statement-classes 180 +performance-schema-max-statement-classes 178 performance-schema-max-table-handles -1 performance-schema-max-table-instances -1 performance-schema-max-thread-classes 50 diff --git a/mysql-test/r/show_create_user.result b/mysql-test/r/show_create_user.result deleted file mode 100644 index 63013eca074..00000000000 --- a/mysql-test/r/show_create_user.result +++ /dev/null @@ -1,39 +0,0 @@ -create user foo; -show create user foo; -CREATE USER for foo@% -CREATE USER 'foo'@'%' -create user foo@test; -show create user foo@test; -CREATE USER for foo@test -CREATE USER 'foo'@'test' -create user foo2@test identified by 'password'; -show create user foo2@test; -CREATE USER for foo2@test -CREATE USER 'foo2'@'test' IDENTIFIED BY PASSWORD '*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19' -alter user foo2@test identified with 'someplugin' as 'somepassword'; -show create user foo2@test; -CREATE USER for foo2@test -CREATE USER 'foo2'@'test' IDENTIFIED VIA someplugin USING 'somepassword' -create user foo3@test require SSL; -show create user foo3@test; -CREATE USER for foo3@test -CREATE USER 'foo3'@'test' REQUIRE SSL -create user foo4@test require cipher 'text' issuer 'foo_issuer' subject 'foo_subject'; -show create user foo4@test; -CREATE USER for foo4@test -CREATE USER 'foo4'@'test' REQUIRE ISSUER 'foo_issuer' SUBJECT 'foo_subject' CIPHER 'text' -create user foo5@test require SSL -with MAX_QUERIES_PER_HOUR 10 -MAX_UPDATES_PER_HOUR 20 -MAX_CONNECTIONS_PER_HOUR 30 -MAX_USER_CONNECTIONS 40 -MAX_STATEMENT_TIME 0.5; -show create user foo5@test; -CREATE USER for foo5@test -CREATE USER 'foo5'@'test' REQUIRE SSL WITH MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 MAX_CONNECTIONS_PER_HOUR 30 MAX_USER_CONNECTIONS 40 MAX_STATEMENT_TIME 0.500000 -drop user foo5@test; -drop user foo4@test; -drop user foo3@test; -drop user foo2@test; -drop user foo@test; -drop user foo; diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index 6be27560d89..865b5a8ca2f 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -2825,9 +2825,9 @@ READ_ONLY YES COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME PERFORMANCE_SCHEMA_MAX_STATEMENT_CLASSES SESSION_VALUE NULL -GLOBAL_VALUE 180 +GLOBAL_VALUE 178 GLOBAL_VALUE_ORIGIN COMPILE-TIME -DEFAULT_VALUE 180 +DEFAULT_VALUE 178 VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_COMMENT Maximum number of statement instruments. diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index 4c358fd456a..21f1f905de8 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -3021,9 +3021,9 @@ READ_ONLY YES COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME PERFORMANCE_SCHEMA_MAX_STATEMENT_CLASSES SESSION_VALUE NULL -GLOBAL_VALUE 180 +GLOBAL_VALUE 178 GLOBAL_VALUE_ORIGIN COMPILE-TIME -DEFAULT_VALUE 180 +DEFAULT_VALUE 178 VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_COMMENT Maximum number of statement instruments. diff --git a/mysql-test/t/alter_user.test b/mysql-test/t/alter_user.test deleted file mode 100644 index e32d0c29f2e..00000000000 --- a/mysql-test/t/alter_user.test +++ /dev/null @@ -1,82 +0,0 @@ ---source include/not_embedded.inc ---enable_connect_log - - -select * from mysql.user where user = 'root' and host = 'localhost'; ---echo # Test syntax ---echo # ---echo # These 2 selects should have no changes from the first one. -alter user CURRENT_USER; -select * from mysql.user where user = 'root' and host = 'localhost'; -alter user CURRENT_USER(); -select * from mysql.user where user = 'root' and host = 'localhost'; - -create user foo; -select * from mysql.user where user = 'foo'; -alter user foo; -select * from mysql.user where user = 'foo'; - ---echo # Test super privilege works correctly with a read only database. -SET @start_read_only = @@global.read_only; -SET GLOBAL read_only=1; -grant create user on *.* to foo; - ---echo # Currently no super privileges. -connect (a, localhost, foo); -select @@global.read_only; - ---error ER_OPTION_PREVENTS_STATEMENT -alter user foo; - ---echo # Grant super privilege to the user. -connection default; -grant super on *.* to foo; - ---echo # We now have super privilege. We should be able to run alter user. -connect (b, localhost, foo); -alter user foo; - -connection default; -SET GLOBAL read_only = @start_read_only; - ---echo # Test inexistant user. ---error ER_CANNOT_USER -alter user boo; ---echo #--warning ER_CANNOT_USER -alter if exists user boo; - ---echo # Test password related altering. -alter user foo identified by 'something'; -select * from mysql.user where user = 'foo'; - -alter user foo identified by 'something2'; -select * from mysql.user where user = 'foo'; - -alter user foo identified by password '*88C89BE093D4ECF72D039F62EBB7477EA1FD4D63'; -select * from mysql.user where user = 'foo'; - -alter user foo identified with 'somecoolplugin'; -select * from mysql.user where user = 'foo'; - -alter user foo identified with 'somecoolplugin' using 'somecoolpassphrase'; -select * from mysql.user where user = 'foo'; - ---echo # Test ssl related altering. -alter user foo identified by 'something' require SSL; -select * from mysql.user where user = 'foo'; - -alter user foo identified by 'something' require X509; -select * from mysql.user where user = 'foo'; - -alter user foo identified by 'something' -require cipher 'text' issuer 'foo_issuer' subject 'foo_subject'; -select * from mysql.user where user = 'foo'; - ---echo # Test resource limits altering. -alter user foo with MAX_QUERIES_PER_HOUR 10 - MAX_UPDATES_PER_HOUR 20 - MAX_CONNECTIONS_PER_HOUR 30 - MAX_USER_CONNECTIONS 40; -select * from mysql.user where user = 'foo'; -drop user foo; ---disable_connect_log diff --git a/mysql-test/t/create_user.test b/mysql-test/t/create_user.test deleted file mode 100644 index f04cb3e302a..00000000000 --- a/mysql-test/t/create_user.test +++ /dev/null @@ -1,58 +0,0 @@ ---source include/not_embedded.inc - -create user foo; -select * from mysql.user where user = 'foo'; -drop user foo; - -create user foo identified by 'password'; -select * from mysql.user where user = 'foo'; -drop user foo; - -create user foo identified by 'password' require SSL; -select * from mysql.user where user = 'foo'; -drop user foo; - -create user foo identified by 'password' require X509; -select * from mysql.user where user = 'foo'; -drop user foo; - -create user foo identified by 'password' require CIPHER 'cipher'; -select * from mysql.user where user = 'foo'; -drop user foo; - -create user foo identified by 'password' require ISSUER 'issuer'; -select * from mysql.user where user = 'foo'; -drop user foo; - -create user foo identified by 'password' require SUBJECT 'subject'; -select * from mysql.user where user = 'foo'; -drop user foo; - -create user foo identified by 'password' require CIPHER 'cipher' - SUBJECT 'subject'; -select * from mysql.user where user = 'foo'; -drop user foo; - -create user foo identified by 'password' require CIPHER 'cipher' - AND SUBJECT 'subject' - AND ISSUER 'issuer'; -select * from mysql.user where user = 'foo'; -drop user foo; - -create user foo, foo2 identified by 'password' require CIPHER 'cipher' - AND SUBJECT 'subject' - AND ISSUER 'issuer'; -select * from mysql.user where user like 'foo'; - ---echo #--warning ER_USER_CREATE_EXISTS -create user if not exists foo, foo2 identified by 'password2' - require CIPHER 'cipher2' AND SUBJECT 'subject2' AND ISSUER 'issuer2'; -select * from mysql.user where user like 'foo'; -drop user foo, foo2; - -create user foo with MAX_QUERIES_PER_HOUR 10 - MAX_UPDATES_PER_HOUR 20 - MAX_CONNECTIONS_PER_HOUR 30 - MAX_USER_CONNECTIONS 40; -select * from mysql.user where user like 'foo'; -drop user foo; diff --git a/mysql-test/t/show_create_user.test b/mysql-test/t/show_create_user.test deleted file mode 100644 index a10c8aeeda6..00000000000 --- a/mysql-test/t/show_create_user.test +++ /dev/null @@ -1,34 +0,0 @@ ---source include/not_embedded.inc - -create user foo; -show create user foo; - -create user foo@test; -show create user foo@test; - -create user foo2@test identified by 'password'; -show create user foo2@test; - -alter user foo2@test identified with 'someplugin' as 'somepassword'; -show create user foo2@test; - -create user foo3@test require SSL; -show create user foo3@test; - -create user foo4@test require cipher 'text' issuer 'foo_issuer' subject 'foo_subject'; -show create user foo4@test; - -create user foo5@test require SSL - with MAX_QUERIES_PER_HOUR 10 - MAX_UPDATES_PER_HOUR 20 - MAX_CONNECTIONS_PER_HOUR 30 - MAX_USER_CONNECTIONS 40 - MAX_STATEMENT_TIME 0.5; -show create user foo5@test; - -drop user foo5@test; -drop user foo4@test; -drop user foo3@test; -drop user foo2@test; -drop user foo@test; -drop user foo; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b28cea5ac46..8d00b5af948 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3676,7 +3676,6 @@ SHOW_VAR com_status_vars[]= { {"alter_server", STMT_STATUS(SQLCOM_ALTER_SERVER)}, {"alter_table", STMT_STATUS(SQLCOM_ALTER_TABLE)}, {"alter_tablespace", STMT_STATUS(SQLCOM_ALTER_TABLESPACE)}, - {"alter_user", STMT_STATUS(SQLCOM_ALTER_USER)}, {"analyze", STMT_STATUS(SQLCOM_ANALYZE)}, {"assign_to_keycache", STMT_STATUS(SQLCOM_ASSIGN_TO_KEYCACHE)}, {"begin", STMT_STATUS(SQLCOM_BEGIN)}, @@ -3766,7 +3765,6 @@ SHOW_VAR com_status_vars[]= { {"show_create_proc", STMT_STATUS(SQLCOM_SHOW_CREATE_PROC)}, {"show_create_table", STMT_STATUS(SQLCOM_SHOW_CREATE)}, {"show_create_trigger", STMT_STATUS(SQLCOM_SHOW_CREATE_TRIGGER)}, - {"show_create_user", STMT_STATUS(SQLCOM_SHOW_CREATE_USER)}, {"show_databases", STMT_STATUS(SQLCOM_SHOW_DATABASES)}, {"show_engine_logs", STMT_STATUS(SQLCOM_SHOW_ENGINE_LOGS)}, {"show_engine_mutex", STMT_STATUS(SQLCOM_SHOW_ENGINE_MUTEX)}, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index a27f0ef4250..0428c0198a1 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -241,7 +241,6 @@ sp_get_flags_for_command(LEX *lex) case SQLCOM_SHOW_CREATE_PROC: case SQLCOM_SHOW_CREATE_EVENT: case SQLCOM_SHOW_CREATE_TRIGGER: - case SQLCOM_SHOW_CREATE_USER: case SQLCOM_SHOW_DATABASES: case SQLCOM_SHOW_ERRORS: case SQLCOM_SHOW_EXPLAIN: @@ -310,7 +309,6 @@ sp_get_flags_for_command(LEX *lex) case SQLCOM_CREATE_USER: case SQLCOM_CREATE_ROLE: case SQLCOM_ALTER_TABLE: - case SQLCOM_ALTER_USER: case SQLCOM_GRANT: case SQLCOM_GRANT_ROLE: case SQLCOM_REVOKE: diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 2b6ababa8dd..cf0b1d87bd7 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7756,94 +7756,6 @@ static void add_user_option(String *grant, double value, const char *name) } } -static void add_user_parameters(String *result, ACL_USER* acl_user, - bool with_grant) -{ - result->append(STRING_WITH_LEN("@'")); - result->append(acl_user->host.hostname, acl_user->hostname_length, - system_charset_info); - result->append('\''); - - if (acl_user->plugin.str == native_password_plugin_name.str || - acl_user->plugin.str == old_password_plugin_name.str) - { - if (acl_user->auth_string.length) - { - DBUG_ASSERT(acl_user->salt_len); - result->append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '")); - result->append(acl_user->auth_string.str, acl_user->auth_string.length); - result->append('\''); - } - } - else - { - result->append(STRING_WITH_LEN(" IDENTIFIED VIA ")); - result->append(acl_user->plugin.str, acl_user->plugin.length); - if (acl_user->auth_string.length) - { - result->append(STRING_WITH_LEN(" USING '")); - result->append(acl_user->auth_string.str, acl_user->auth_string.length); - result->append('\''); - } - } - /* "show grants" SSL related stuff */ - if (acl_user->ssl_type == SSL_TYPE_ANY) - result->append(STRING_WITH_LEN(" REQUIRE SSL")); - else if (acl_user->ssl_type == SSL_TYPE_X509) - result->append(STRING_WITH_LEN(" REQUIRE X509")); - else if (acl_user->ssl_type == SSL_TYPE_SPECIFIED) - { - int ssl_options = 0; - result->append(STRING_WITH_LEN(" REQUIRE ")); - if (acl_user->x509_issuer) - { - ssl_options++; - result->append(STRING_WITH_LEN("ISSUER \'")); - result->append(acl_user->x509_issuer,strlen(acl_user->x509_issuer)); - result->append('\''); - } - if (acl_user->x509_subject) - { - if (ssl_options++) - result->append(' '); - result->append(STRING_WITH_LEN("SUBJECT \'")); - result->append(acl_user->x509_subject,strlen(acl_user->x509_subject), - system_charset_info); - result->append('\''); - } - if (acl_user->ssl_cipher) - { - if (ssl_options++) - result->append(' '); - result->append(STRING_WITH_LEN("CIPHER '")); - result->append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher), - system_charset_info); - result->append('\''); - } - } - if (with_grant || - (acl_user->user_resource.questions || - acl_user->user_resource.updates || - acl_user->user_resource.conn_per_hour || - acl_user->user_resource.user_conn || - acl_user->user_resource.max_statement_time != 0.0)) - { - result->append(STRING_WITH_LEN(" WITH")); - if (with_grant) - result->append(STRING_WITH_LEN(" GRANT OPTION")); - add_user_option(result, acl_user->user_resource.questions, - "MAX_QUERIES_PER_HOUR", false); - add_user_option(result, acl_user->user_resource.updates, - "MAX_UPDATES_PER_HOUR", false); - add_user_option(result, acl_user->user_resource.conn_per_hour, - "MAX_CONNECTIONS_PER_HOUR", false); - add_user_option(result, acl_user->user_resource.user_conn, - "MAX_USER_CONNECTIONS", true); - add_user_option(result, acl_user->user_resource.max_statement_time, - "MAX_STATEMENT_TIME"); - } -} - static const char *command_array[]= { "SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", "DROP", "RELOAD", @@ -7890,77 +7802,6 @@ static bool print_grants_for_role(THD *thd, ACL_ROLE * role) } -bool mysql_show_create_user(THD *thd, LEX_USER *lex_user) -{ - const char *username = safe_str(lex_user->user.str); - const char *hostname = safe_str(lex_user->host.str); - char buff[1024]; //Show create user should not take more than 1024 bytes. - Protocol *protocol= thd->protocol; - bool error= false; - ACL_USER *acl_user; - DBUG_ENTER("mysql_show_create_user"); - - // Check if the command specifies a username or not. - if (lex_user->user.str == current_user.str) - { - username= thd->security_ctx->priv_user; - hostname= thd->security_ctx->priv_host; - } - - List field_list; - strxmov(buff, "CREATE USER for ", username, "@", hostname, NullS); - Item_string *field = new (thd->mem_root) Item_string_ascii(thd, "", 0); - if (!field) - { - my_error(ER_OUTOFMEMORY, MYF(0)); - DBUG_RETURN(true); - } - - field->name= buff; - field->max_length= sizeof(buff); - field_list.push_back(field, thd->mem_root); - if (protocol->send_result_set_metadata(&field_list, - Protocol::SEND_NUM_ROWS | - Protocol::SEND_EOF)) - DBUG_RETURN(true); - - String result(buff, sizeof(buff), system_charset_info); - result.length(0); - mysql_rwlock_rdlock(&LOCK_grant); - mysql_mutex_lock(&acl_cache->lock); - - acl_user= find_user_exact(hostname, username); - - // User not found in the internal data structures. - if (!acl_user) - { - my_error(ER_PASSWORD_NO_MATCH, MYF(0)); - error= true; - goto end; - } - - result.append("CREATE USER '"); - result.append(username); - result.append('\''); - - add_user_parameters(&result, acl_user, false); - - protocol->prepare_for_resend(); - protocol->store(result.ptr(), result.length(), result.charset()); - if (protocol->write()) - { - error= true; - } - my_eof(thd); - -end: - mysql_rwlock_unlock(&LOCK_grant); - mysql_mutex_unlock(&acl_cache->lock); - - DBUG_RETURN(error); -} - - static int show_grants_callback(ACL_USER_BASE *role, void *data) { THD *thd= (THD *)data; @@ -7970,6 +7811,7 @@ static int show_grants_callback(ACL_USER_BASE *role, void *data) return 0; } + void mysql_show_grants_get_fields(THD *thd, List *fields, const char *name) { @@ -8244,7 +8086,93 @@ static bool show_global_privileges(THD *thd, ACL_USER_BASE *acl_entry, global.append('\''); if (!handle_as_role) - add_user_parameters(&global, (ACL_USER *)acl_entry, (want_access & GRANT_ACL)); + { + ACL_USER *acl_user= (ACL_USER *)acl_entry; + + global.append (STRING_WITH_LEN("@'")); + global.append(acl_user->host.hostname, acl_user->hostname_length, + system_charset_info); + global.append ('\''); + + if (acl_user->plugin.str == native_password_plugin_name.str || + acl_user->plugin.str == old_password_plugin_name.str) + { + if (acl_user->auth_string.length) + { + DBUG_ASSERT(acl_user->salt_len); + global.append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '")); + global.append(acl_user->auth_string.str, acl_user->auth_string.length); + global.append('\''); + } + } + else + { + global.append(STRING_WITH_LEN(" IDENTIFIED VIA ")); + global.append(acl_user->plugin.str, acl_user->plugin.length); + if (acl_user->auth_string.length) + { + global.append(STRING_WITH_LEN(" USING '")); + global.append(acl_user->auth_string.str, acl_user->auth_string.length); + global.append('\''); + } + } + /* "show grants" SSL related stuff */ + if (acl_user->ssl_type == SSL_TYPE_ANY) + global.append(STRING_WITH_LEN(" REQUIRE SSL")); + else if (acl_user->ssl_type == SSL_TYPE_X509) + global.append(STRING_WITH_LEN(" REQUIRE X509")); + else if (acl_user->ssl_type == SSL_TYPE_SPECIFIED) + { + int ssl_options = 0; + global.append(STRING_WITH_LEN(" REQUIRE ")); + if (acl_user->x509_issuer) + { + ssl_options++; + global.append(STRING_WITH_LEN("ISSUER \'")); + global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer)); + global.append('\''); + } + if (acl_user->x509_subject) + { + if (ssl_options++) + global.append(' '); + global.append(STRING_WITH_LEN("SUBJECT \'")); + global.append(acl_user->x509_subject,strlen(acl_user->x509_subject), + system_charset_info); + global.append('\''); + } + if (acl_user->ssl_cipher) + { + if (ssl_options++) + global.append(' '); + global.append(STRING_WITH_LEN("CIPHER '")); + global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher), + system_charset_info); + global.append('\''); + } + } + if ((want_access & GRANT_ACL) || + (acl_user->user_resource.questions || + acl_user->user_resource.updates || + acl_user->user_resource.conn_per_hour || + acl_user->user_resource.user_conn || + acl_user->user_resource.max_statement_time != 0.0)) + { + global.append(STRING_WITH_LEN(" WITH")); + if (want_access & GRANT_ACL) + global.append(STRING_WITH_LEN(" GRANT OPTION")); + add_user_option(&global, acl_user->user_resource.questions, + "MAX_QUERIES_PER_HOUR", false); + add_user_option(&global, acl_user->user_resource.updates, + "MAX_UPDATES_PER_HOUR", false); + add_user_option(&global, acl_user->user_resource.conn_per_hour, + "MAX_CONNECTIONS_PER_HOUR", false); + add_user_option(&global, acl_user->user_resource.user_conn, + "MAX_USER_CONNECTIONS", true); + add_user_option(&global, acl_user->user_resource.max_statement_time, + "MAX_STATEMENT_TIME"); + } + } protocol->prepare_for_resend(); protocol->store(global.ptr(),global.length(),global.charset()); @@ -9912,73 +9840,6 @@ bool mysql_rename_user(THD *thd, List &list) DBUG_RETURN(result); } -/* - Alter a user's connection and resource settings. - - SYNOPSIS - mysql_alter_user() - thd The current thread. - list The users to alter. - - RETURN - > 0 Error. Error message already sent. - 0 OK. -*/ -int mysql_alter_user(THD* thd, List &users_list) -{ - DBUG_ENTER("mysql_alter_user"); - int result= 0; - TABLE_LIST tables[TABLES_MAX]; - String wrong_users; - // The only table we're altering is the user table. - if ((result= open_grant_tables(thd, tables, TL_WRITE, Table_user))) - DBUG_RETURN(result); - - // Lock ACL data structures until we finish altering all users. - mysql_rwlock_wrlock(&LOCK_grant); - mysql_mutex_lock(&acl_cache->lock); - - LEX_USER *tmp_lex_user; - List_iterator users_list_iterator(users_list); - while ((tmp_lex_user= users_list_iterator++)) - { - LEX_USER* lex_user= get_current_user(thd, tmp_lex_user, false); - if (!lex_user || - fix_lex_user(thd, lex_user) || - replace_user_table(thd, tables[USER_TABLE].table, *lex_user,0, - false, false, true)) - { - thd->clear_error(); - append_user(thd, &wrong_users, tmp_lex_user); - result= TRUE; - continue; - } - } - - // Unlock ACL data structures. - mysql_mutex_unlock(&acl_cache->lock); - mysql_rwlock_unlock(&LOCK_grant); - - if (result) - { - // 'if exists' flag leads to warnings instead of errors. - if (thd->lex->create_info.if_exists()) - { - push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, - ER_CANNOT_USER, - ER_THD(thd, ER_CANNOT_USER), - "ALTER USER", wrong_users.c_ptr_safe()); - result= FALSE; - } - else - { - my_error(ER_CANNOT_USER, MYF(0), - "ALTER USER", - wrong_users.c_ptr_safe()); - } - } - DBUG_RETURN(result); -} /* Revoke all privileges from a list of users. diff --git a/sql/sql_acl.h b/sql/sql_acl.h index b480d488bc3..3bd896cab79 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -246,7 +246,6 @@ bool get_show_user(THD *thd, LEX_USER *lex_user, const char **username, void mysql_show_grants_get_fields(THD *thd, List *fields, const char *name); bool mysql_show_grants(THD *thd, LEX_USER *user); -bool mysql_show_create_user(THD *thd, LEX_USER *user); int fill_schema_enabled_roles(THD *thd, TABLE_LIST *tables, COND *cond); int fill_schema_applicable_roles(THD *thd, TABLE_LIST *tables, COND *cond); void get_privilege_desc(char *to, uint max_length, ulong access); @@ -254,7 +253,6 @@ void get_mqh(const char *user, const char *host, USER_CONN *uc); bool mysql_create_user(THD *thd, List &list, bool handle_as_role); bool mysql_drop_user(THD *thd, List &list, bool handle_as_role); bool mysql_rename_user(THD *thd, List &list); -int mysql_alter_user(THD *thd, List &list); bool mysql_revoke_all(THD *thd, List &list); void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, const char *db, const char *table); diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h index 2350b4be56c..c237bb9270a 100644 --- a/sql/sql_cmd.h +++ b/sql/sql_cmd.h @@ -93,8 +93,6 @@ enum enum_sql_command { SQLCOM_CREATE_ROLE, SQLCOM_DROP_ROLE, SQLCOM_GRANT_ROLE, SQLCOM_REVOKE_ROLE, SQLCOM_COMPOUND, SQLCOM_SHOW_GENERIC, - SQLCOM_ALTER_USER, - SQLCOM_SHOW_CREATE_USER, /* When a command is added here, be sure it's also added in mysqld.cc diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a5837585b7d..14ac657862f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -422,7 +422,6 @@ void init_update_queries(void) sql_command_flags[SQLCOM_SHOW_EXPLAIN]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_PROCESSLIST]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_GRANTS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_CREATE_USER]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_DB]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_MASTER_STAT]= CF_STATUS_COMMAND; @@ -444,7 +443,6 @@ void init_update_queries(void) sql_command_flags[SQLCOM_CREATE_USER]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_RENAME_USER]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_DROP_USER]= CF_CHANGES_DATA; - sql_command_flags[SQLCOM_ALTER_USER]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_CREATE_ROLE]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_GRANT]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_GRANT_ROLE]= CF_CHANGES_DATA; @@ -508,7 +506,6 @@ void init_update_queries(void) sql_command_flags[SQLCOM_CHECKSUM]= CF_REPORT_PROGRESS; sql_command_flags[SQLCOM_CREATE_USER]|= CF_AUTO_COMMIT_TRANS; - sql_command_flags[SQLCOM_ALTER_USER]|= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_DROP_USER]|= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_RENAME_USER]|= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_CREATE_ROLE]|= CF_AUTO_COMMIT_TRANS; @@ -604,7 +601,6 @@ void init_update_queries(void) sql_command_flags[SQLCOM_ALTER_EVENT]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_DROP_EVENT]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_CREATE_USER]|= CF_DISALLOW_IN_RO_TRANS; - sql_command_flags[SQLCOM_ALTER_USER]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_RENAME_USER]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_DROP_USER]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_CREATE_SERVER]|= CF_DISALLOW_IN_RO_TRANS; @@ -4407,7 +4403,6 @@ mysql_execute_command(THD *thd) my_ok(thd); break; } - case SQLCOM_ALTER_USER: case SQLCOM_RENAME_USER: { if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 1) && @@ -4415,11 +4410,7 @@ mysql_execute_command(THD *thd) break; /* Conditionally writes to binlog */ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) - if (lex->sql_command == SQLCOM_ALTER_USER) - res= mysql_alter_user(thd, lex->users_list); - else - res= mysql_rename_user(thd, lex->users_list); - if (!res) + if (!(res= mysql_rename_user(thd, lex->users_list))) my_ok(thd); break; } @@ -4716,7 +4707,6 @@ mysql_execute_command(THD *thd) break; #ifndef NO_EMBEDDED_ACCESS_CHECKS - case SQLCOM_SHOW_CREATE_USER: case SQLCOM_SHOW_GRANTS: { LEX_USER *grant_user= lex->grant_user; @@ -4724,20 +4714,7 @@ mysql_execute_command(THD *thd) goto error; WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); - if (grant_user->user.str && !strcmp(sctx->priv_user, grant_user->user.str) && - grant_user->host.str && !strcmp(sctx->priv_host, grant_user->host.str)) - grant_user->user= current_user; - - if (grant_user->user.str == current_user.str || - grant_user->user.str == current_role.str || - grant_user->user.str == current_user_and_current_role.str || - !check_access(thd, SELECT_ACL, "mysql", NULL, NULL, 1, 0)) - { - if (lex->sql_command == SQLCOM_SHOW_GRANTS) - res = mysql_show_grants(thd, grant_user); - else - res = mysql_show_create_user(thd, grant_user); - } + res = mysql_show_grants(thd, grant_user); break; } #endif diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6799781f5e0..2a46bb2a027 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2531,8 +2531,7 @@ create: Lex->create_view_suid= TRUE; } view_or_trigger_or_sp_or_event { } - | create_or_replace USER opt_if_not_exists clear_privileges grant_list - opt_require_clause opt_resource_options + | create_or_replace USER_SYM opt_if_not_exists clear_privileges grant_list { if (Lex->set_command_with_check(SQLCOM_CREATE_USER, $1 | $3)) MYSQL_YYABORT; @@ -7107,13 +7106,6 @@ alter: lex->sql_command= SQLCOM_ALTER_SERVER; lex->server_options.reset($3); } OPTIONS_SYM '(' server_options_list ')' { } - /* ALTER USER foo is allowed for MySQL compatibility. */ - | ALTER opt_if_exists USER clear_privileges grant_list - opt_require_clause opt_resource_options - { - Lex->create_info.set($2); - Lex->sql_command= SQLCOM_ALTER_USER; - } ; ev_alter_on_schedule_completion: @@ -12494,18 +12486,6 @@ show_param: lex->sql_command= SQLCOM_SHOW_CREATE_TRIGGER; lex->spname= $3; } - | CREATE USER - { - Lex->sql_command= SQLCOM_SHOW_CREATE_USER; - if (!(Lex->grant_user= (LEX_USER*)thd->alloc(sizeof(LEX_USER)))) - MYSQL_YYABORT; - Lex->grant_user->user= current_user; - } - | CREATE USER user - { - Lex->sql_command= SQLCOM_SHOW_CREATE_USER; - Lex->grant_user= $3; - } | PROCEDURE_SYM STATUS_SYM wild_and_where { LEX *lex= Lex; @@ -15056,14 +15036,14 @@ grant: grant_command: grant_privileges ON opt_table grant_ident TO_SYM grant_list - opt_require_clause opt_grant_options + require_clause grant_options { LEX *lex= Lex; lex->sql_command= SQLCOM_GRANT; lex->type= 0; } | grant_privileges ON FUNCTION_SYM grant_ident TO_SYM grant_list - opt_require_clause opt_grant_options + require_clause grant_options { LEX *lex= Lex; if (lex->columns.elements) @@ -15075,7 +15055,7 @@ grant_command: lex->type= TYPE_ENUM_FUNCTION; } | grant_privileges ON PROCEDURE_SYM grant_ident TO_SYM grant_list - opt_require_clause opt_grant_options + require_clause grant_options { LEX *lex= Lex; if (lex->columns.elements) @@ -15412,7 +15392,7 @@ column_list_id: } ; -opt_require_clause: +require_clause: /* empty */ | REQUIRE_SYM require_list { @@ -15432,8 +15412,24 @@ opt_require_clause: } ; -resource_option: - MAX_QUERIES_PER_HOUR ulong_num +grant_options: + /* empty */ {} + | WITH grant_option_list + ; + +opt_grant_option: + /* empty */ {} + | WITH GRANT OPTION { Lex->grant |= GRANT_ACL;} + ; + +grant_option_list: + grant_option_list grant_option {} + | grant_option {} + ; + +grant_option: + GRANT OPTION { Lex->grant |= GRANT_ACL;} + | MAX_QUERIES_PER_HOUR ulong_num { LEX *lex=Lex; lex->mqh.questions=$2; @@ -15465,37 +15461,6 @@ resource_option: } ; -resource_option_list: - resource_option_list resource_option {} - | resource_option {} - ; - -opt_resource_options: - /* empty */ {} - | WITH resource_option_list - ; - - -opt_grant_options: - /* empty */ {} - | WITH grant_option_list {} - ; - -opt_grant_option: - /* empty */ {} - | WITH GRANT OPTION { Lex->grant |= GRANT_ACL;} - ; - -grant_option_list: - grant_option_list grant_option {} - | grant_option {} - ; - -grant_option: - GRANT OPTION { Lex->grant |= GRANT_ACL;} - | resource_option {} - ; - begin: BEGIN_SYM { From a50ce9445844c0bdcf8aab8578cdf1244d969d42 Mon Sep 17 00:00:00 2001 From: mkaruza Date: Wed, 2 Sep 2020 20:38:25 +0200 Subject: [PATCH 020/323] MDEV-23559: Galera LeakSanitizer: detected memory leaks in galera.GAL-419 When process is aborted WSREP deinitialization and memory cleanup is not properly handled. Other reported leaks are in Galera library and should be fixed there. --- sql/mysqld.cc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c9bf6045867..26012f317f9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1900,13 +1900,10 @@ extern "C" void unireg_abort(int exit_code) WSREP_INFO("Some threads may fail to exit."); } - if (WSREP_ON) + if (WSREP_ON && wsrep_inited) { - /* In bootstrap mode we deinitialize wsrep here. */ - if (opt_bootstrap || wsrep_recovery) - { - if (wsrep_inited) wsrep_deinit(true); - } + wsrep_deinit(true); + wsrep_deinit_server(); } #endif // WITH_WSREP From 920824c24e94efefc6b1ce135499e7d7e5290ae9 Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 23 Jul 2020 11:35:40 +0300 Subject: [PATCH 021/323] Backported setting of transcation.on=1 in THD::reset_for_reuse() This is to ensure code in 10.4 and 10.5 is logically identical for this variable --- sql/sql_class.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7327f270c33..8f6356b15c7 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1640,6 +1640,7 @@ void THD::reset_for_reuse() abort_on_warning= 0; free_connection_done= 0; m_command= COM_CONNECT; + transaction.on= 1; #if defined(ENABLED_PROFILING) profiling.reset(); #endif From 3cdbaa04bd573f2f09e2f7ff69c71e8b97ca078b Mon Sep 17 00:00:00 2001 From: Monty Date: Mon, 14 Sep 2020 21:22:32 +0300 Subject: [PATCH 022/323] Fixed BUILD script to make plugin-file_key_management DYNAMIC This ensures that all tests can be run. Before this patch some encryption test failed --- BUILD/SETUP.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 992cfa1286f..44e74441de9 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -211,7 +211,7 @@ fi max_no_embedded_configs="$SSL_LIBRARY --with-plugins=max" max_no_qc_configs="$SSL_LIBRARY --with-plugins=max --without-query-cache" -max_configs="$SSL_LIBRARY --with-plugins=max --with-embedded-server --with-libevent --without-plugin=plugin_file_key_management --with-plugin-rocksdb=dynamic --with-plugin-test_sql_discovery=DYNAMIC" +max_configs="$SSL_LIBRARY --with-plugins=max --with-embedded-server --with-libevent --without-plugin=plugin_file_key_management --with-plugin-rocksdb=dynamic --with-plugin-test_sql_discovery=DYNAMIC --with-plugin-file_key_management=DYNAMIC" all_configs="$SSL_LIBRARY --with-plugins=max --with-embedded-server --with-innodb_plugin --with-libevent" # From 16ea692ed490a1a2c6dc0b855247d5bd02bd2345 Mon Sep 17 00:00:00 2001 From: Monty Date: Mon, 7 Sep 2020 10:38:12 +0300 Subject: [PATCH 023/323] MDEV-23586 Mariabackup: GTID saved for replication in 10.4.14 is wrong MDEV-21953 deadlock between BACKUP STAGE BLOCK_COMMIT and parallel replication Fixed by partly reverting MDEV-21953 to put back MDL_BACKUP_COMMIT locking before log_and_order. The original problem for MDEV-21953 was that while a thread was waiting in for another threads to commit in 'log_and_order', it had the MDL_BACKUP_COMMIT lock. The backup thread was waiting to get the MDL_BACKUP_WAIT_COMMIT lock, which blocks all new MDL_BACKUP_COMMIT locks. This causes a deadlock as the waited-for thread can never get past the MDL_BACKUP_COMMIT lock in ha_commit_trans. The main part of the bug fix is to release the MDL_BACKUP_COMMIT lock while a thread is waiting for other 'previous' threads to commit. This ensures that no transactional thread keeps MDL_BACKUP_COMMIT while waiting, which ensures that there are no deadlocks anymore. --- sql/handler.cc | 101 ++++++++++++++++++++++++----------------------- sql/handler.h | 2 +- sql/log.cc | 55 +++++++++++++++++++++++--- sql/sql_class.cc | 30 ++++++++++++-- sql/sql_class.h | 3 ++ sql/xa.cc | 2 +- 6 files changed, 134 insertions(+), 59 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index 40dea349272..d7562bcd2ae 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -114,7 +114,7 @@ static TYPELIB known_extensions= {0,"known_exts", NULL, NULL}; uint known_extensions_id= 0; static int commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, - bool is_real_trans, bool rw_trans); + bool is_real_trans); static plugin_ref ha_default_plugin(THD *thd) @@ -1490,9 +1490,40 @@ int ha_commit_trans(THD *thd, bool all) /* rw_trans is TRUE when we in a transaction changing data */ bool rw_trans= is_real_trans && (rw_ha_count > (thd->is_current_stmt_binlog_disabled()?0U:1U)); + MDL_request mdl_backup; DBUG_PRINT("info", ("is_real_trans: %d rw_trans: %d rw_ha_count: %d", is_real_trans, rw_trans, rw_ha_count)); + if (rw_trans) + { + /* + Acquire a metadata lock which will ensure that COMMIT is blocked + by an active FLUSH TABLES WITH READ LOCK (and vice versa: + COMMIT in progress blocks FTWRL). + + We allow the owner of FTWRL to COMMIT; we assume that it knows + what it does. + */ + mdl_backup.init(MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, MDL_EXPLICIT); + + if (!WSREP(thd)) + { + if (thd->mdl_context.acquire_lock(&mdl_backup, + thd->variables.lock_wait_timeout)) + { + ha_rollback_trans(thd, all); + DBUG_RETURN(1); + } + thd->backup_commit_lock= &mdl_backup; + } + DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock"); + + /* Use shortcut as we already have the MDL_BACKUP_COMMIT lock */ + ha_maria::implicit_commit(thd, TRUE); + } + else + ha_maria_implicit_commit(thd, TRUE); + if (rw_trans && opt_readonly && !(thd->security_ctx->master_access & SUPER_ACL) && @@ -1532,7 +1563,7 @@ int ha_commit_trans(THD *thd, bool all) // Here, the call will not commit inside InnoDB. It is only working // around closing thd->transaction.stmt open by TR_table::open(). if (all) - commit_one_phase_2(thd, false, &thd->transaction.stmt, false, false); + commit_one_phase_2(thd, false, &thd->transaction.stmt, false); } } #endif @@ -1552,7 +1583,7 @@ int ha_commit_trans(THD *thd, bool all) goto wsrep_err; } #endif /* WITH_WSREP */ - error= ha_commit_one_phase(thd, all, rw_trans); + error= ha_commit_one_phase(thd, all); #ifdef WITH_WSREP if (run_wsrep_hooks) error= error || wsrep_after_commit(thd, all); @@ -1604,7 +1635,7 @@ int ha_commit_trans(THD *thd, bool all) if (!is_real_trans) { - error= commit_one_phase_2(thd, all, trans, is_real_trans, rw_trans); + error= commit_one_phase_2(thd, all, trans, is_real_trans); goto done; } #ifdef WITH_WSREP @@ -1622,7 +1653,7 @@ int ha_commit_trans(THD *thd, bool all) DEBUG_SYNC(thd, "ha_commit_trans_after_log_and_order"); DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE();); - error= commit_one_phase_2(thd, all, trans, is_real_trans, rw_trans) ? 2 : 0; + error= commit_one_phase_2(thd, all, trans, is_real_trans) ? 2 : 0; #ifdef WITH_WSREP if (run_wsrep_hooks && (error || (error = wsrep_after_commit(thd, all)))) { @@ -1685,6 +1716,17 @@ err: thd->rgi_slave->is_parallel_exec); } end: + if (mdl_backup.ticket) + { + /* + We do not always immediately release transactional locks + after ha_commit_trans() (see uses of ha_enable_transaction()), + thus we release the commit blocker lock as soon as it's + not needed. + */ + thd->mdl_context.release_lock(mdl_backup.ticket); + } + thd->backup_commit_lock= 0; #ifdef WITH_WSREP if (wsrep_is_active(thd) && is_real_trans && !error && (rw_ha_count == 0 || all) && @@ -1699,8 +1741,8 @@ end: /** @note - This function does not care about global read lock. A caller should. - However backup locks are handled in commit_one_phase_2. + This function does not care about global read lock or backup locks, + the caller should. @param[in] all Is set in case of explicit commit (COMMIT statement), or implicit commit @@ -1709,7 +1751,7 @@ end: autocommit=1. */ -int ha_commit_one_phase(THD *thd, bool all, bool rw_trans) +int ha_commit_one_phase(THD *thd, bool all) { THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt; /* @@ -1735,50 +1777,21 @@ int ha_commit_one_phase(THD *thd, bool all, bool rw_trans) if ((res= thd->wait_for_prior_commit())) DBUG_RETURN(res); } - res= commit_one_phase_2(thd, all, trans, is_real_trans, rw_trans); + res= commit_one_phase_2(thd, all, trans, is_real_trans); DBUG_RETURN(res); } static int -commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans, - bool rw_trans) +commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans) { int error= 0; uint count= 0; Ha_trx_info *ha_info= trans->ha_list, *ha_info_next; - MDL_request mdl_request; DBUG_ENTER("commit_one_phase_2"); if (is_real_trans) DEBUG_SYNC(thd, "commit_one_phase_2"); - if (rw_trans) - { - /* - Acquire a metadata lock which will ensure that COMMIT is blocked - by an active FLUSH TABLES WITH READ LOCK (and vice versa: - COMMIT in progress blocks FTWRL). - - We allow the owner of FTWRL to COMMIT; we assume that it knows - what it does. - */ - mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, MDL_EXPLICIT); - - if (!WSREP(thd) && - thd->mdl_context.acquire_lock(&mdl_request, - thd->variables.lock_wait_timeout)) - { - my_error(ER_ERROR_DURING_COMMIT, MYF(0), 1); - ha_rollback_trans(thd, all); - DBUG_RETURN(1); - } - DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock"); - } - -#if defined(WITH_ARIA_STORAGE_ENGINE) && MYSQL_VERSION_ID < 100500 - ha_maria::implicit_commit(thd, TRUE); -#endif - if (ha_info) { for (; ha_info; ha_info= ha_info_next) @@ -1807,16 +1820,6 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans, #endif } } - if (mdl_request.ticket) - { - /* - We do not always immediately release transactional locks - after ha_commit_trans() (see uses of ha_enable_transaction()), - thus we release the commit blocker lock as soon as it's - not needed. - */ - thd->mdl_context.release_lock(mdl_request.ticket); - } /* Free resources and perform other cleanup even for 'empty' transactions. */ if (is_real_trans) diff --git a/sql/handler.h b/sql/handler.h index 80d0f1b59d8..3b0cedfcd96 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -5024,7 +5024,7 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache); /* transactions: interface to handlerton functions */ int ha_start_consistent_snapshot(THD *thd); int ha_commit_or_rollback_by_xid(XID *xid, bool commit); -int ha_commit_one_phase(THD *thd, bool all, bool rw_trans); +int ha_commit_one_phase(THD *thd, bool all); int ha_commit_trans(THD *thd, bool all); int ha_rollback_trans(THD *thd, bool all); int ha_prepare(THD *thd); diff --git a/sql/log.cc b/sql/log.cc index eaa49bcb58c..bfa77fbd88e 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -6380,11 +6380,25 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate) if (direct) { + /* We come here only for incident events */ int res; uint64 commit_id= 0; + MDL_request mdl_request; DBUG_PRINT("info", ("direct is set")); + DBUG_ASSERT(!thd->backup_commit_lock); + + mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, MDL_EXPLICIT); + thd->mdl_context.acquire_lock(&mdl_request, + thd->variables.lock_wait_timeout); + thd->backup_commit_lock= &mdl_request; + if ((res= thd->wait_for_prior_commit())) + { + if (mdl_request.ticket) + thd->mdl_context.release_lock(mdl_request.ticket); + thd->backup_commit_lock= 0; DBUG_RETURN(res); + } file= &log_file; my_org_b_tell= my_b_tell(file); mysql_mutex_lock(&LOCK_log); @@ -6399,7 +6413,11 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate) commit_name.length); commit_id= entry->val_int(&null_value); }); - if (write_gtid_event(thd, true, using_trans, commit_id)) + res= write_gtid_event(thd, true, using_trans, commit_id); + if (mdl_request.ticket) + thd->mdl_context.release_lock(mdl_request.ticket); + thd->backup_commit_lock= 0; + if (res) goto err; } else @@ -7461,7 +7479,11 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry) group_commit_entry *entry, *orig_queue, *last; wait_for_commit *cur; wait_for_commit *wfc; + bool backup_lock_released= 0; + int result= 0; + THD *thd= orig_entry->thd; DBUG_ENTER("MYSQL_BIN_LOG::queue_for_group_commit"); + DBUG_ASSERT(thd == current_thd); /* Check if we need to wait for another transaction to commit before us. @@ -7493,6 +7515,21 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry) { PSI_stage_info old_stage; + /* + Release MDL_BACKUP_COMMIT LOCK while waiting for other threads to + commit. + This is needed to avoid deadlock between the other threads (which not + yet have the MDL_BACKUP_COMMIT_LOCK) and any threads using + BACKUP LOCK BLOCK_COMMIT. + */ + if (thd->backup_commit_lock && thd->backup_commit_lock->ticket && + !backup_lock_released) + { + backup_lock_released= 1; + thd->mdl_context.release_lock(thd->backup_commit_lock->ticket); + thd->backup_commit_lock->ticket= 0; + } + /* By setting wfc->opaque_pointer to our own entry, we mark that we are ready to commit, but waiting for another transaction to commit before @@ -7553,7 +7590,8 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry) wfc->wakeup_error= ER_QUERY_INTERRUPTED; my_message(wfc->wakeup_error, ER_THD(orig_entry->thd, wfc->wakeup_error), MYF(0)); - DBUG_RETURN(-1); + result= -1; + goto end; } } orig_entry->thd->EXIT_COND(&old_stage); @@ -7567,12 +7605,13 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry) then there is nothing else to do. */ if (orig_entry->queued_by_other) - DBUG_RETURN(0); + goto end; if (wfc && wfc->wakeup_error) { my_error(ER_PRIOR_COMMIT_FAILED, MYF(0)); - DBUG_RETURN(-1); + result= -1; + goto end; } /* Now enqueue ourselves in the group commit queue. */ @@ -7733,7 +7772,13 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry) DBUG_PRINT("info", ("Queued for group commit as %s", (orig_queue == NULL) ? "leader" : "participant")); - DBUG_RETURN(orig_queue == NULL); + result= orig_queue == NULL; + +end: + if (backup_lock_released) + thd->mdl_context.acquire_lock(thd->backup_commit_lock, + thd->variables.lock_wait_timeout); + DBUG_RETURN(result); } bool diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 8f6356b15c7..4986889b3c8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1271,6 +1271,7 @@ void THD::init() first_successful_insert_id_in_prev_stmt_for_binlog= 0; first_successful_insert_id_in_cur_stmt= 0; current_backup_stage= BACKUP_FINISHED; + backup_commit_lock= 0; #ifdef WITH_WSREP wsrep_last_query_id= 0; wsrep_xid.null(); @@ -1383,7 +1384,7 @@ void THD::init_for_queries() set_time(); /* We don't need to call ha_enable_transaction() as we can't have - any active transactions that has to be commited + any active transactions that has to be committed */ transaction.on= TRUE; @@ -7386,16 +7387,33 @@ wait_for_commit::register_wait_for_prior_commit(wait_for_commit *waitee) } -/* - Wait for commit of another transaction to complete, as already registered +/** + Waits for commit of another transaction to complete, as already registered with register_wait_for_prior_commit(). If the commit already completed, returns immediately. + + If thd->backup_commit_lock is set, release it while waiting for other threads */ + int wait_for_commit::wait_for_prior_commit2(THD *thd) { PSI_stage_info old_stage; wait_for_commit *loc_waitee; + bool backup_lock_released= 0; + + /* + Release MDL_BACKUP_COMMIT LOCK while waiting for other threads to commit + This is needed to avoid deadlock between the other threads (which not + yet have the MDL_BACKUP_COMMIT_LOCK) and any threads using + BACKUP LOCK BLOCK_COMMIT. + */ + if (thd->backup_commit_lock && thd->backup_commit_lock->ticket) + { + backup_lock_released= 1; + thd->mdl_context.release_lock(thd->backup_commit_lock->ticket); + thd->backup_commit_lock->ticket= 0; + } mysql_mutex_lock(&LOCK_wait_commit); DEBUG_SYNC(thd, "wait_for_prior_commit_waiting"); @@ -7445,10 +7463,16 @@ wait_for_commit::wait_for_prior_commit2(THD *thd) use within enter_cond/exit_cond. */ DEBUG_SYNC(thd, "wait_for_prior_commit_killed"); + if (backup_lock_released) + thd->mdl_context.acquire_lock(thd->backup_commit_lock, + thd->variables.lock_wait_timeout); return wakeup_error; end: thd->EXIT_COND(&old_stage); + if (backup_lock_released) + thd->mdl_context.acquire_lock(thd->backup_commit_lock, + thd->variables.lock_wait_timeout); return wakeup_error; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 7cacfe25ce4..0c2d03a516a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2200,7 +2200,10 @@ public: rpl_io_thread_info *rpl_io_info; rpl_sql_thread_info *rpl_sql_info; } system_thread_info; + /* Used for BACKUP LOCK */ MDL_ticket *mdl_backup_ticket, *mdl_backup_lock; + /* Used to register that thread has a MDL_BACKUP_WAIT_COMMIT lock */ + MDL_request *backup_commit_lock; void reset_for_next_command(bool do_clear_errors= 1); /* diff --git a/sql/xa.cc b/sql/xa.cc index 15116ba9366..b08ab973cc5 100644 --- a/sql/xa.cc +++ b/sql/xa.cc @@ -582,7 +582,7 @@ bool trans_xa_commit(THD *thd) { DEBUG_SYNC(thd, "trans_xa_commit_after_acquire_commit_lock"); - res= MY_TEST(ha_commit_one_phase(thd, 1, 1)); + res= MY_TEST(ha_commit_one_phase(thd, 1)); if (res) my_error(ER_XAER_RMERR, MYF(0)); } From 895e9950b2a361a7cf428f60a32e7e3ddc49f833 Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 15 Sep 2020 16:13:37 +0300 Subject: [PATCH 024/323] Fix for timeout in rpl.rpl_parallel_retry MDEV-17109 rpl.rpl_parallel_retry fails in buildbot with timeout I was not able to prove that this fix works, but at least it simplifies the problem as it removes some possible timing issues. --- mysql-test/suite/rpl/r/rpl_parallel_retry.result | 2 +- mysql-test/suite/rpl/t/rpl_parallel_retry.test | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_parallel_retry.result b/mysql-test/suite/rpl/r/rpl_parallel_retry.result index 66428c94086..b43556815d1 100644 --- a/mysql-test/suite/rpl/r/rpl_parallel_retry.result +++ b/mysql-test/suite/rpl/r/rpl_parallel_retry.result @@ -372,7 +372,7 @@ connection server_2; SET @old_dbug= @@GLOBAL.debug_dbug; SET @@GLOBAL.debug_dbug="+d,rpl_parallel_simulate_wait_at_retry"; include/start_slave.inc -# Make sure the 2nd seqno_1001 worker has gotten to waiting +# Make sure both workers are waiting at their sync points # Signal to the 1st to proceed after it has reached termination state SET @@DEBUG_SYNC='now SIGNAL proceed_by_1000'; connection spoiler_21; diff --git a/mysql-test/suite/rpl/t/rpl_parallel_retry.test b/mysql-test/suite/rpl/t/rpl_parallel_retry.test index 96863f9021d..55da54e3c8c 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel_retry.test +++ b/mysql-test/suite/rpl/t/rpl_parallel_retry.test @@ -426,8 +426,8 @@ SET @old_dbug= @@GLOBAL.debug_dbug; SET @@GLOBAL.debug_dbug="+d,rpl_parallel_simulate_wait_at_retry"; --source include/start_slave.inc ---echo # Make sure the 2nd seqno_1001 worker has gotten to waiting ---let $wait_condition= SELECT count(*) FROM information_schema.processlist WHERE state LIKE '%debug sync point: now%'; +--echo # Make sure both workers are waiting at their sync points +--let $wait_condition= SELECT count(*)=2 FROM information_schema.processlist WHERE state LIKE '%debug sync point%'; --source include/wait_condition.inc From 0b73ef0688b320c2ff7fe678b28041f3e7505e97 Mon Sep 17 00:00:00 2001 From: Monty Date: Wed, 16 Sep 2020 18:29:11 +0300 Subject: [PATCH 025/323] MDEV-21470 ASAN heap-use-after-free in my_hash_sort_bin The problem was that the server was calling virtual functions on a record that was not initialized with new data. This happened when fill_record() was aborted in the middle because an error in save_val() or save_in_field() --- mysql-test/main/type_blob.result | 15 +++++++++++++++ mysql-test/main/type_blob.test | 20 ++++++++++++++++++++ sql/sql_base.cc | 19 +++++++++++-------- sql/table.cc | 24 +++++++++++++++++------- 4 files changed, 63 insertions(+), 15 deletions(-) diff --git a/mysql-test/main/type_blob.result b/mysql-test/main/type_blob.result index 967fb37b230..a0a5f82a656 100644 --- a/mysql-test/main/type_blob.result +++ b/mysql-test/main/type_blob.result @@ -1125,5 +1125,20 @@ LENGTH(a) LENGTH(DEFAULT(a)) 256 256 DROP TABLE t1; # +# ASAN heap-use-after-free in my_hash_sort_bin or ER_KEY_NOT_FOUND +# upon INSERT into table with long unique blob +# +SET @save_sql_mode=@@sql_mode; +SET SQL_MODE='STRICT_ALL_TABLES'; +CREATE TABLE t1 (a INT, b BLOB) ENGINE=innodb; +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +CREATE TABLE t2 (c BIT, d BLOB, UNIQUE(d)) ENGINE=innodb; +INSERT INTO t2 SELECT * FROM t1; +ERROR 22001: Data too long for column 'c' at row 2 +select * from t2; +c d +DROP TABLE t1, t2; +SET @@sql_mode=@save_sql_mode; +# # End of 10.4 test # diff --git a/mysql-test/main/type_blob.test b/mysql-test/main/type_blob.test index 7801280a8d2..a9b044b5318 100644 --- a/mysql-test/main/type_blob.test +++ b/mysql-test/main/type_blob.test @@ -1,6 +1,7 @@ # This test can't be run with running server (--extern) as this uses # load_file() on a file in the tree. # +--source include/have_innodb.inc # # Basic cleanup @@ -735,6 +736,25 @@ INSERT INTO t1 VALUES (); SELECT LENGTH(a), LENGTH(DEFAULT(a)) FROM t1; DROP TABLE t1; +--echo # +--echo # ASAN heap-use-after-free in my_hash_sort_bin or ER_KEY_NOT_FOUND +--echo # upon INSERT into table with long unique blob +--echo # + +# Note that this test worked with myisam as it caches blobs differently than +# InnoDB + +SET @save_sql_mode=@@sql_mode; +SET SQL_MODE='STRICT_ALL_TABLES'; + +CREATE TABLE t1 (a INT, b BLOB) ENGINE=innodb; +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +CREATE TABLE t2 (c BIT, d BLOB, UNIQUE(d)) ENGINE=innodb; +--error ER_DATA_TOO_LONG +INSERT INTO t2 SELECT * FROM t1; +select * from t2; +DROP TABLE t1, t2; +SET @@sql_mode=@save_sql_mode; --echo # --echo # End of 10.4 test diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 75427f106a4..9f9bee0ad17 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8813,14 +8813,17 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List &values, goto err; field->set_has_explicit_value(); } - /* Update virtual fields */ - thd->abort_on_warning= FALSE; - if (table->versioned()) - table->vers_update_fields(); - if (table->vfield && - table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE)) - goto err; - thd->abort_on_warning= abort_on_warning_saved; + /* Update virtual fields if there wasn't any errors */ + if (!thd->is_error()) + { + thd->abort_on_warning= FALSE; + if (table->versioned()) + table->vers_update_fields(); + if (table->vfield && + table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE)) + goto err; + thd->abort_on_warning= abort_on_warning_saved; + } DBUG_RETURN(thd->is_error()); err: diff --git a/sql/table.cc b/sql/table.cc index 6fa2ef51f89..5d465cf80b5 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -8268,28 +8268,39 @@ public: @details The function computes the values of the virtual columns of the table and stores them in the table record buffer. + This will be done even if is_error() is set either when function was called + or by calculating the virtual function, as most calls to this + function doesn't check the result. We also want to ensure that as many + fields as possible has the right value so that we can optionally + return the partly-faulty-row from a storage engine with a virtual + field that gives an error on storage for an existing row. + + @todo + Ensure that all caller checks the value of this function and + either properly ignores it (and resets the error) or sends the + error forward to the caller. @retval 0 Success @retval - >0 Error occurred when storing a virtual field value + >0 Error occurred when storing a virtual field value or potentially + is_error() was set when function was called. */ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) { DBUG_ENTER("TABLE::update_virtual_fields"); - DBUG_PRINT("enter", ("update_mode: %d", update_mode)); + DBUG_PRINT("enter", ("update_mode: %d is_error: %d", update_mode, + in_use->is_error())); Field **vfield_ptr, *vf; Query_arena backup_arena; Turn_errors_to_warnings_handler Suppress_errors; - int error; bool handler_pushed= 0, update_all_columns= 1; DBUG_ASSERT(vfield); if (h->keyread_enabled()) DBUG_RETURN(0); - error= 0; in_use->set_n_backup_active_arena(expr_arena, &backup_arena); /* When reading or deleting row, ignore errors from virtual columns */ @@ -8312,7 +8323,7 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) } /* Iterate over virtual fields in the table */ - for (vfield_ptr= vfield; *vfield_ptr; vfield_ptr++) + for (vfield_ptr= vfield; *vfield_ptr ; vfield_ptr++) { vf= (*vfield_ptr); Virtual_column_info *vcol_info= vf->vcol_info; @@ -8363,8 +8374,7 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) int field_error __attribute__((unused)) = 0; /* Compute the actual value of the virtual fields */ DBUG_FIX_WRITE_SET(vf); - if (vcol_info->expr->save_in_field(vf, 0)) - field_error= error= 1; + field_error= vcol_info->expr->save_in_field(vf, 0); DBUG_RESTORE_WRITE_SET(vf); DBUG_PRINT("info", ("field '%s' - updated error: %d", vf->field_name.str, field_error)); From 8819b5eea5640dc99a96c76a428f739236600ad8 Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 17 Sep 2020 16:06:16 +0300 Subject: [PATCH 026/323] MDEV-23318 Assertion `cache_empty(keycache)' failed in prepare_resize_simple_key_cache The reason was that during MyISAM parallel repair two threads used the same changed TABLE object to compute virtual columns Fixed by adding a mutex in compute_vcols() --- mysql-test/main/myisam_repair.result | 51 +++++++++++++++++++++++++ mysql-test/main/myisam_repair.test | 57 ++++++++++++++++++++++++++++ storage/myisam/ha_myisam.cc | 14 +++++-- 3 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 mysql-test/main/myisam_repair.result create mode 100644 mysql-test/main/myisam_repair.test diff --git a/mysql-test/main/myisam_repair.result b/mysql-test/main/myisam_repair.result new file mode 100644 index 00000000000..50a9695c8c7 --- /dev/null +++ b/mysql-test/main/myisam_repair.result @@ -0,0 +1,51 @@ +# +# MDEV-23318 Assertion `cache_empty(keycache)' failed in +# prepare_resize_simple_key_cache +# +SET @buffer_size.save= @@key_buffer_size; +SET GLOBAL key_buffer_size= 134217728; +SET myisam_repair_threads= 6; +CREATE TABLE t1 ( +pk INT AUTO_INCREMENT, +a INTEGER, +b DATE, +c VARCHAR(1), +d BLOB, +PRIMARY KEY (pk), +KEY (a), +KEY (b), +KEY (c, a), +UNIQUE (d) +) ENGINE=MyISAM; +INSERT INTO t1 (a,b,c) SELECT seq, '2020-12-12', 'x' FROM seq_1_to_20; +ALTER TABLE t1 DISABLE KEYS; +SET GLOBAL c.key_buffer_size= 13700864; +Warnings: +Warning 1292 Truncated incorrect key_buffer_size value: '13700864' +INSERT INTO t1 SELECT 1; +ERROR 21S01: Column count doesn't match value count at row 1 +SET GLOBAL c.key_buffer_size= 0; +DROP TABLE t1; +SET GLOBAL key_buffer_size= 134217728; +CREATE TABLE t1 ( +pk INT AUTO_INCREMENT, +a INTEGER, +b DATE, +c VARCHAR(1), +d VARBINARY(40982), +PRIMARY KEY (pk), +KEY (a), +KEY (b), +KEY (c, a), +UNIQUE (d) +) ENGINE=MyISAM; +INSERT INTO t1 (a,b,c) SELECT seq, '2020-12-12', 'x' FROM seq_1_to_20; +ALTER TABLE t1 DISABLE KEYS; +SET GLOBAL c.key_buffer_size= 13700864; +Warnings: +Warning 1292 Truncated incorrect key_buffer_size value: '13700864' +INSERT INTO t1 SELECT 1; +ERROR 21S01: Column count doesn't match value count at row 1 +SET GLOBAL c.key_buffer_size= 0; +DROP TABLE t1; +SET GLOBAL key_buffer_size= @buffer_size.save; diff --git a/mysql-test/main/myisam_repair.test b/mysql-test/main/myisam_repair.test new file mode 100644 index 00000000000..bcb69d59e2c --- /dev/null +++ b/mysql-test/main/myisam_repair.test @@ -0,0 +1,57 @@ +--source include/have_sequence.inc + + +--echo # +--echo # MDEV-23318 Assertion `cache_empty(keycache)' failed in +--echo # prepare_resize_simple_key_cache +--echo # + +SET @buffer_size.save= @@key_buffer_size; +SET GLOBAL key_buffer_size= 134217728; +SET myisam_repair_threads= 6; + +CREATE TABLE t1 ( + pk INT AUTO_INCREMENT, + a INTEGER, + b DATE, + c VARCHAR(1), + d BLOB, + PRIMARY KEY (pk), + KEY (a), + KEY (b), + KEY (c, a), + UNIQUE (d) +) ENGINE=MyISAM; + +INSERT INTO t1 (a,b,c) SELECT seq, '2020-12-12', 'x' FROM seq_1_to_20; + +ALTER TABLE t1 DISABLE KEYS; +SET GLOBAL c.key_buffer_size= 13700864; +--error ER_WRONG_VALUE_COUNT_ON_ROW +INSERT INTO t1 SELECT 1; +SET GLOBAL c.key_buffer_size= 0; +DROP TABLE t1; + +SET GLOBAL key_buffer_size= 134217728; + +CREATE TABLE t1 ( + pk INT AUTO_INCREMENT, + a INTEGER, + b DATE, + c VARCHAR(1), + d VARBINARY(40982), + PRIMARY KEY (pk), + KEY (a), + KEY (b), + KEY (c, a), + UNIQUE (d) +) ENGINE=MyISAM; +INSERT INTO t1 (a,b,c) SELECT seq, '2020-12-12', 'x' FROM seq_1_to_20; +ALTER TABLE t1 DISABLE KEYS; +SET GLOBAL c.key_buffer_size= 13700864; +--error ER_WRONG_VALUE_COUNT_ON_ROW +INSERT INTO t1 SELECT 1; +SET GLOBAL c.key_buffer_size= 0; + +DROP TABLE t1; +SET GLOBAL key_buffer_size= @buffer_size.save; diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 1cc396fe2cd..1b994210ddf 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -688,6 +688,8 @@ my_bool mi_killed_in_mariadb(MI_INFO *info) static int compute_vcols(MI_INFO *info, uchar *record, int keynum) { + /* This mutex is needed for parallel repair */ + mysql_mutex_lock(&info->s->intern_lock); TABLE *table= (TABLE*)(info->external_ref); table->move_fields(table->field, record, table->field[0]->record_ptr()); if (keynum == -1) // update all vcols @@ -695,6 +697,7 @@ static int compute_vcols(MI_INFO *info, uchar *record, int keynum) int error= table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_READ); if (table->update_virtual_fields(table->file, VCOL_UPDATE_INDEXED)) error= 1; + mysql_mutex_unlock(&info->s->intern_lock); return error; } // update only one key @@ -703,9 +706,10 @@ static int compute_vcols(MI_INFO *info, uchar *record, int keynum) for (; kp < end; kp++) { Field *f= table->field[kp->fieldnr - 1]; - if (f->vcol_info) + if (f->vcol_info && !f->vcol_info->stored_in_db) table->update_virtual_field(f); } + mysql_mutex_unlock(&info->s->intern_lock); return 0; } @@ -956,7 +960,7 @@ void ha_myisam::setup_vcols_for_repair(HA_CHECK *param) if (!table->vfield) return; - if (file->s->base.reclength == file->s->vreclength) + if (file->s->base.reclength == file->s->vreclength) { bool indexed_vcols= false; ulong new_vreclength= file->s->vreclength; @@ -964,7 +968,8 @@ void ha_myisam::setup_vcols_for_repair(HA_CHECK *param) { if (!(*vf)->stored_in_db()) { - uint vf_end= (*vf)->offset(table->record[0]) + (*vf)->pack_length_in_rec(); + uint vf_end= ((*vf)->offset(table->record[0]) + + (*vf)->pack_length_in_rec()); set_if_bigger(new_vreclength, vf_end); indexed_vcols|= ((*vf)->flags & PART_KEY_FLAG) != 0; } @@ -982,7 +987,8 @@ void ha_myisam::restore_vcos_after_repair() { if (file->s->base.reclength < file->s->vreclength) { - table->move_fields(table->field, table->record[0], table->field[0]->record_ptr()); + table->move_fields(table->field, table->record[0], + table->field[0]->record_ptr()); table->default_column_bitmaps(); } } From 92b5a8bb65991815e44290de8b9a0a96fa815b7a Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 17 Sep 2020 17:59:59 +0300 Subject: [PATCH 027/323] MDEV-17665 Assertion `!share and other errors on concurrent Aria operations Fixes also: MDEV-22674 Server crash in compare_bin ... restore_table_state_after_repair The bug was that the 'can_enable_index' variable in MyISAM and Aria was not properly set and reset for bulk insert. Because of this, insert...select was trying to recreate indexes while another thread was using it, causing crashes in page cache. --- mysql-test/suite/maria/alter.result | 60 +++++++++++++ mysql-test/suite/maria/alter.test | 84 +++++++++++++++++++ .../suite/maria/maria-no-logging.result | 6 ++ mysql-test/suite/maria/maria-no-logging.test | 2 + sql/sql_table.cc | 8 +- storage/maria/ha_maria.cc | 8 +- storage/myisam/ha_myisam.cc | 9 +- 7 files changed, 173 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/maria/alter.result b/mysql-test/suite/maria/alter.result index 4e6f21b70a7..c79c86e8ba0 100644 --- a/mysql-test/suite/maria/alter.result +++ b/mysql-test/suite/maria/alter.result @@ -104,3 +104,63 @@ DROP TABLE t1; # # End of 10.2 test # +# +# MDEV-17665 Assertion `!share || share->page_type == PAGECACHE_LSN_PAGE', +# `type != PAGECACHE_READ_UNKNOWN_PAGE' and similar ones upon concurrent +# Aria operations +# +CREATE TABLE t1 (pk INT PRIMARY KEY, a INT, KEY(a)) ENGINE=Aria; +ALTER TABLE t1 DISABLE KEYS; +INSERT INTO t1 SELECT seq, seq FROM seq_1_to_100; +connect con1,localhost,root,,test; +connect con2,localhost,root,,test; +INSERT INTO t1 SELECT seq, seq FROM seq_1_to_100; +connection con1; +FLUSH TABLES; +connection default; +INSERT INTO t1 SELECT 1; +ERROR 21S01: Column count doesn't match value count at row 1 +connection con2; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +disconnect con2; +connection con1; +disconnect con1; +connection default; +DROP TABLE t1; +# +# MDEV-22674 Server crash in compare_bin, ASAN heap-buffer-overflow in +# _ma_dpointer, Assertion `!info->s->have_versioning || +# info->s->lock_key_trees' failed in restore_table_state_after_repair +# +CREATE TABLE t1 (id INT, d DATETIME, PRIMARY KEY(d,id),INDEX(d)) ENGINE=Aria; +INSERT INTO t1 SELECT seq, NOW() FROM seq_1_to_500; +CREATE TABLE t2 (a INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1); +connect con1,localhost,root,,test; +ALTER TABLE t1 DISABLE KEYS; +INSERT INTO t1 (id) SELECT b FROM t2; +connection default; +INSERT INTO t1 SELECT a FROM t2; +ERROR 21S01: Column count doesn't match value count at row 1 +connection con1; +ERROR 42S22: Unknown column 'b' in 'field list' +disconnect con1; +connection default; +drop table t1, t2; +# This is also in MDEV-22674 +CREATE TABLE t1 (id INT, d DATETIME, PRIMARY KEY(d,id),INDEX(d)) ENGINE=Aria; +INSERT INTO t1 SELECT seq, NOW() FROM seq_1_to_500; +CREATE TABLE t2 (a INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1); +ALTER TABLE t1 DISABLE KEYS; +INSERT INTO t1 (id) SELECT b FROM t2; +ERROR 42S22: Unknown column 'b' in 'field list' +INSERT INTO t1 SELECT a FROM t2; +ERROR 21S01: Column count doesn't match value count at row 1 +SELECT COUNT(*) FROM t1; +COUNT(*) +500 +DROP TABLE t1,t2; +# +# End of 10.4 test +# diff --git a/mysql-test/suite/maria/alter.test b/mysql-test/suite/maria/alter.test index 31eeac1df87..17a270f2a90 100644 --- a/mysql-test/suite/maria/alter.test +++ b/mysql-test/suite/maria/alter.test @@ -1,6 +1,8 @@ # Testing of potential problems in Aria and alter table -- source include/have_maria.inc +-- source include/have_innodb.inc +-- source include/have_sequence.inc drop table if exists t1; @@ -90,3 +92,85 @@ DROP TABLE t1; --echo # --echo # End of 10.2 test --echo # + +--echo # +--echo # MDEV-17665 Assertion `!share || share->page_type == PAGECACHE_LSN_PAGE', +--echo # `type != PAGECACHE_READ_UNKNOWN_PAGE' and similar ones upon concurrent +--echo # Aria operations +--echo # + +CREATE TABLE t1 (pk INT PRIMARY KEY, a INT, KEY(a)) ENGINE=Aria; +ALTER TABLE t1 DISABLE KEYS; +INSERT INTO t1 SELECT seq, seq FROM seq_1_to_100; + +--connect (con1,localhost,root,,test) +--connect (con2,localhost,root,,test) +--send + INSERT INTO t1 SELECT seq, seq FROM seq_1_to_100; + +--connection con1 +--send + FLUSH TABLES; + +--connection default +--error ER_WRONG_VALUE_COUNT_ON_ROW +INSERT INTO t1 SELECT 1; + +# Cleanup +--connection con2 +--error ER_DUP_ENTRY +--reap +--disconnect con2 +--connection con1 +--reap +--disconnect con1 +--connection default +DROP TABLE t1; + +--echo # +--echo # MDEV-22674 Server crash in compare_bin, ASAN heap-buffer-overflow in +--echo # _ma_dpointer, Assertion `!info->s->have_versioning || +--echo # info->s->lock_key_trees' failed in restore_table_state_after_repair +--echo # + +CREATE TABLE t1 (id INT, d DATETIME, PRIMARY KEY(d,id),INDEX(d)) ENGINE=Aria; +INSERT INTO t1 SELECT seq, NOW() FROM seq_1_to_500; + +CREATE TABLE t2 (a INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1); + +--connect (con1,localhost,root,,test) +ALTER TABLE t1 DISABLE KEYS; +--send + INSERT INTO t1 (id) SELECT b FROM t2; + +--connection default +--error ER_WRONG_VALUE_COUNT_ON_ROW +INSERT INTO t1 SELECT a FROM t2; + +# Cleanup +--connection con1 +--error ER_BAD_FIELD_ERROR +--reap +--disconnect con1 + +--connection default +drop table t1, t2; + +--echo # This is also in MDEV-22674 + +CREATE TABLE t1 (id INT, d DATETIME, PRIMARY KEY(d,id),INDEX(d)) ENGINE=Aria; +INSERT INTO t1 SELECT seq, NOW() FROM seq_1_to_500; +CREATE TABLE t2 (a INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1); +ALTER TABLE t1 DISABLE KEYS; +--error ER_BAD_FIELD_ERROR +INSERT INTO t1 (id) SELECT b FROM t2; +--error ER_WRONG_VALUE_COUNT_ON_ROW +INSERT INTO t1 SELECT a FROM t2; +SELECT COUNT(*) FROM t1; +DROP TABLE t1,t2; + +--echo # +--echo # End of 10.4 test +--echo # diff --git a/mysql-test/suite/maria/maria-no-logging.result b/mysql-test/suite/maria/maria-no-logging.result index fb175d0e326..e79686c4731 100644 --- a/mysql-test/suite/maria/maria-no-logging.result +++ b/mysql-test/suite/maria/maria-no-logging.result @@ -31,6 +31,9 @@ insert into t1 select * from t2; show engine aria logs; Type Name Status Aria Size 24576 aria_log.00000001 unknown +select count(*) from t1; +count(*) +65 connection default; connection admin; * shut down mysqld, removed logs, restarted it @@ -40,6 +43,9 @@ insert into t1 select * from t2; show engine aria logs; Type Name Status Aria Size 16384 aria_log.00000001 unknown +select count(*) from t1; +count(*) +64 drop table t1; connection default; connection admin; diff --git a/mysql-test/suite/maria/maria-no-logging.test b/mysql-test/suite/maria/maria-no-logging.test index fb2f34f7708..5d8029156ed 100644 --- a/mysql-test/suite/maria/maria-no-logging.test +++ b/mysql-test/suite/maria/maria-no-logging.test @@ -48,6 +48,7 @@ insert into t1 values('a'); insert into t1 select * from t2; --replace_regex /; .+aria_log/aria_log/ show engine aria logs; +select count(*) from t1; # optimization because table is empty -- source include/maria_empty_logs.inc @@ -55,6 +56,7 @@ truncate table t1; insert into t1 select * from t2; --replace_regex /; .+aria_log/aria_log/ show engine aria logs; +select count(*) from t1; drop table t1; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3831bd03802..c90387cf1c3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -10614,6 +10614,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, bool make_versioned= !from->versioned() && to->versioned(); bool make_unversioned= from->versioned() && !to->versioned(); bool keep_versioned= from->versioned() && to->versioned(); + bool bulk_insert_started= 0; Field *to_row_start= NULL, *to_row_end= NULL, *from_row_end= NULL; MYSQL_TIME query_start; DBUG_ENTER("copy_data_between_tables"); @@ -10652,6 +10653,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, to->file->extra(HA_EXTRA_PREPARE_FOR_ALTER_TABLE); to->file->ha_start_bulk_insert(from->file->stats.records, ignore ? 0 : HA_CREATE_UNIQUE_INDEX_BY_SORT); + bulk_insert_started= 1; List_iterator it(create); Create_field *def; copy_end=copy; @@ -10914,6 +10916,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, to->file->print_error(my_errno,MYF(0)); error= 1; } + bulk_insert_started= 0; if (!ignore) to->file->extra(HA_EXTRA_END_ALTER_COPY); @@ -10927,7 +10930,10 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, error= 1; err: - /* Free resources */ + if (bulk_insert_started) + (void) to->file->ha_end_bulk_insert(); + +/* Free resources */ if (init_read_record_done) end_read_record(&info); delete [] copy; diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 013c740582b..aa99bc157c9 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -1025,7 +1025,7 @@ int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER | HA_CAN_VIRTUAL_COLUMNS | HA_CAN_EXPORT | HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT | HA_CAN_TABLES_WITHOUT_ROLLBACK), -can_enable_indexes(1), bulk_insert_single_undo(BULK_INSERT_NONE) +can_enable_indexes(0), bulk_insert_single_undo(BULK_INSERT_NONE) {} @@ -2089,6 +2089,7 @@ void ha_maria::start_bulk_insert(ha_rows rows, uint flags) DBUG_ENTER("ha_maria::start_bulk_insert"); THD *thd= table->in_use; MARIA_SHARE *share= file->s; + bool index_disabled= 0; DBUG_PRINT("info", ("start_bulk_insert: rows %lu", (ulong) rows)); /* don't enable row cache if too few rows */ @@ -2152,6 +2153,7 @@ void ha_maria::start_bulk_insert(ha_rows rows, uint flags) { /* Internal table; If we get a duplicate something is very wrong */ file->update|= HA_STATE_CHANGED; + index_disabled= share->base.keys > 0; maria_clear_all_keys_active(file->s->state.key_map); } else @@ -2179,6 +2181,7 @@ void ha_maria::start_bulk_insert(ha_rows rows, uint flags) table->key_info[i].algorithm != HA_KEY_ALG_LONG_HASH) { maria_clear_key_active(share->state.key_map, i); + index_disabled= 1; file->update|= HA_STATE_CHANGED; file->create_unique_index_by_sort= all_keys; } @@ -2208,6 +2211,7 @@ void ha_maria::start_bulk_insert(ha_rows rows, uint flags) rows); } } + can_enable_indexes= index_disabled; DBUG_VOID_RETURN; } @@ -2246,7 +2250,6 @@ int ha_maria::end_bulk_insert() if (bulk_insert_single_undo != BULK_INSERT_NONE) { - DBUG_ASSERT(can_enable_indexes); /* Table was transactional just before start_bulk_insert(). No need to flush pages if we did a repair (which already flushed). @@ -2257,6 +2260,7 @@ int ha_maria::end_bulk_insert() first_error= first_error ? first_error : error; bulk_insert_single_undo= BULK_INSERT_NONE; // Safety } + can_enable_indexes= 0; DBUG_RETURN(first_error); } diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 1b994210ddf..f0df75aa578 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -726,7 +726,7 @@ ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg) HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS | HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT | HA_CAN_REPAIR | HA_CAN_TABLES_WITHOUT_ROLLBACK), - can_enable_indexes(1) + can_enable_indexes(0) {} handler *ha_myisam::clone(const char *name __attribute__((unused)), @@ -1729,6 +1729,7 @@ void ha_myisam::start_bulk_insert(ha_rows rows, uint flags) THD *thd= table->in_use; ulong size= MY_MIN(thd->variables.read_buff_size, (ulong) (table->s->avg_row_length*rows)); + bool index_disabled= 0; DBUG_PRINT("info",("start_bulk_insert: rows %lu size %lu", (ulong) rows, size)); @@ -1752,6 +1753,7 @@ void ha_myisam::start_bulk_insert(ha_rows rows, uint flags) if (file->open_flag & HA_OPEN_INTERNAL_TABLE) { file->update|= HA_STATE_CHANGED; + index_disabled= file->s->base.keys > 0; mi_clear_all_keys_active(file->s->state.key_map); } else @@ -1782,6 +1784,7 @@ void ha_myisam::start_bulk_insert(ha_rows rows, uint flags) table->key_info[i].algorithm != HA_KEY_ALG_LONG_HASH) { mi_clear_key_active(share->state.key_map, i); + index_disabled= 1; file->update|= HA_STATE_CHANGED; file->create_unique_index_by_sort= all_keys; } @@ -1789,12 +1792,15 @@ void ha_myisam::start_bulk_insert(ha_rows rows, uint flags) } } else + { if (!file->bulk_insert && (!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT)) { mi_init_bulk_insert(file, (size_t) thd->variables.bulk_insert_buff_size, rows); } + } + can_enable_indexes= index_disabled; DBUG_VOID_RETURN; } @@ -1846,6 +1852,7 @@ int ha_myisam::end_bulk_insert() file->s->state.changed&= ~(STATE_CRASHED|STATE_CRASHED_ON_REPAIR); } } + can_enable_indexes= 0; } DBUG_PRINT("exit", ("first_error: %d", first_error)); DBUG_RETURN(first_error); From bb2c958132a12a049163564b7a6e6d4da8e2851a Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 17 Sep 2020 18:54:11 +0300 Subject: [PATCH 028/323] MDEV-23296 Assertion `block->type == PAGECACHE_EMPTY_PAGE.. with aria_max_sort_file_size=0 When maria_drop_all_indexes() reset the key files, it didn't flush the page cache. This confused the cache as there where old key blocks marked with LSN in it and repair tried to overwrite these with PLAIN blocks which is not allowed. --- mysql-test/suite/maria/alter.result | 20 ++++++++++++++++++++ mysql-test/suite/maria/alter.test | 18 ++++++++++++++++++ storage/maria/ma_check.c | 3 +++ 3 files changed, 41 insertions(+) diff --git a/mysql-test/suite/maria/alter.result b/mysql-test/suite/maria/alter.result index c79c86e8ba0..e1a57ed654f 100644 --- a/mysql-test/suite/maria/alter.result +++ b/mysql-test/suite/maria/alter.result @@ -162,5 +162,25 @@ COUNT(*) 500 DROP TABLE t1,t2; # +# MDEV-23296 Assertion `block->type == PAGECACHE_EMPTY_PAGE || +# block->type == PAGECACHE_READ_UNKNOWN_PAGE || block->type == type || +# (block->type == PAGECACHE_PLAIN_PAGE && type == PAGECACHE_LSN_PAGE)' +# with aria_max_sort_file_size +# +SET @max_size.save= @@aria_max_sort_file_size; +SET GLOBAL aria_max_sort_file_size= 0; +CREATE TABLE t1 (pk INT PRIMARY KEY, a CHAR(255), KEY(a)) ENGINE=Aria; +ALTER TABLE t1 DISABLE KEYS; +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ALTER TABLE t1 ENABLE KEYS; +INSERT INTO t1 VALUES (3,'nice try'); +SELECT * FROM t1; +pk a +1 foo +2 bar +3 nice try +DROP TABLE t1; +SET GLOBAL aria_max_sort_file_size= @max_size.save; +# # End of 10.4 test # diff --git a/mysql-test/suite/maria/alter.test b/mysql-test/suite/maria/alter.test index 17a270f2a90..f2950f0a6d3 100644 --- a/mysql-test/suite/maria/alter.test +++ b/mysql-test/suite/maria/alter.test @@ -171,6 +171,24 @@ INSERT INTO t1 SELECT a FROM t2; SELECT COUNT(*) FROM t1; DROP TABLE t1,t2; +--echo # +--echo # MDEV-23296 Assertion `block->type == PAGECACHE_EMPTY_PAGE || +--echo # block->type == PAGECACHE_READ_UNKNOWN_PAGE || block->type == type || +--echo # (block->type == PAGECACHE_PLAIN_PAGE && type == PAGECACHE_LSN_PAGE)' +--echo # with aria_max_sort_file_size +--echo # + +SET @max_size.save= @@aria_max_sort_file_size; +SET GLOBAL aria_max_sort_file_size= 0; +CREATE TABLE t1 (pk INT PRIMARY KEY, a CHAR(255), KEY(a)) ENGINE=Aria; +ALTER TABLE t1 DISABLE KEYS; +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ALTER TABLE t1 ENABLE KEYS; +INSERT INTO t1 VALUES (3,'nice try'); +SELECT * FROM t1; +DROP TABLE t1; +SET GLOBAL aria_max_sort_file_size= @max_size.save; + --echo # --echo # End of 10.4 test --echo # diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c index 37c2712b143..9670daa9104 100644 --- a/storage/maria/ma_check.c +++ b/storage/maria/ma_check.c @@ -2550,6 +2550,9 @@ static int maria_drop_all_indexes(HA_CHECK *param, MARIA_HA *info, DBUG_PRINT("repair", ("declared all indexes disabled")); } + /* Flush obsolete index data from key cache */ + _ma_flush_table_files(info, MARIA_FLUSH_INDEX, + FLUSH_IGNORE_CHANGED, FLUSH_IGNORE_CHANGED); /* Clear index root block pointers. */ for (i= 0; i < share->base.keys; i++) state->key_root[i]= HA_OFFSET_ERROR; From 71a7b79bcbfe90c3118e3d4379ad734dc72c9f39 Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 25 Sep 2020 13:38:48 +0300 Subject: [PATCH 029/323] Added asssert to init_of_queries() to make it more safe Part of review of 10.4 code by Sergei. Other things: - Changed return type if is_active() from my_bool to bool as this is only used by C++ code. --- sql/sql_class.cc | 1 + sql/sql_class.h | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 4986889b3c8..e57196ee056 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1386,6 +1386,7 @@ void THD::init_for_queries() We don't need to call ha_enable_transaction() as we can't have any active transactions that has to be committed */ + DBUG_ASSERT(transaction.is_empty()); transaction.on= TRUE; reset_root_defaults(mem_root, variables.query_alloc_block_size, diff --git a/sql/sql_class.h b/sql/sql_class.h index 0c2d03a516a..64cd1ed6ba3 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2630,10 +2630,14 @@ public: free_root(&mem_root,MYF(MY_KEEP_PREALLOC)); DBUG_VOID_RETURN; } - my_bool is_active() + bool is_active() { return (all.ha_list != NULL); } + bool is_empty() + { + return all.is_empty() && stmt.is_empty(); + } st_transactions() { bzero((char*)this, sizeof(*this)); From 6a1376252d7997f6fa1268c08bed5f93b32922f8 Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 25 Sep 2020 15:58:08 +0300 Subject: [PATCH 030/323] Reverted wrong patch for mysql_upgrade The original code was correct. mysql_upgrade calls the mysql client to talk with MariaDB. It doesn't call itself! --- client/mysql_upgrade.c | 2 +- mysql-test/main/mysql_upgrade.result | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 4872d187a72..4f3f1ff86da 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -1173,7 +1173,7 @@ static int check_version_match(void) extract_variable_from_show(&ds_version, version_str)) { print_error("Version check failed. Got the following error when calling " - "the 'mysql_upgrade' command line client", &ds_version); + "the 'mysql' command line client", &ds_version); dynstr_free(&ds_version); return 1; /* Query failed */ } diff --git a/mysql-test/main/mysql_upgrade.result b/mysql-test/main/mysql_upgrade.result index 84628e6d504..7be0be6ccc3 100644 --- a/mysql-test/main/mysql_upgrade.result +++ b/mysql-test/main/mysql_upgrade.result @@ -145,7 +145,7 @@ test Phase 7/7: Running 'FLUSH PRIVILEGES' OK DROP USER mysqltest1@'%'; -Version check failed. Got the following error when calling the 'mysql_upgrade' command line client +Version check failed. Got the following error when calling the 'mysql' command line client ERROR 1045 (28000): Access denied for user 'mysqltest1'@'localhost' (using password: YES) FATAL ERROR: Upgrade failed Run mysql_upgrade with a non existing server socket @@ -412,7 +412,7 @@ OK # Bug #21489398: MYSQL_UPGRADE: FATAL ERROR: UPGRADE FAILED - IMPROVE ERROR # Run mysql_upgrade with unauthorized access -Version check failed. Got the following error when calling the 'mysql_upgrade' command line client +Version check failed. Got the following error when calling the 'mysql' command line client ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES) FATAL ERROR: Upgrade failed # From 50c96870134d54224f93f4a76fc916cd8a0b70c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 25 Sep 2020 17:28:54 +0300 Subject: [PATCH 031/323] MDEV-23807 ut_a(n_pending_flushes) failed in fil_node_t::prepare_to_close_or_detach() Before closing file handles, we really must wait until there are no pending os_file_flush(). This was missed in commit b1ab211dee599eabd9a5b886fafa3adea29ae041 (MDEV-15053) where we changed the following: fil_node_close_to_free(): Wait for n_pending==0. Because we no longer do an extra lookup of the tablespace between fil_io() and the completion of the operation, we must give fil_node_t::complete_io() a chance to decrement the counter. --- storage/innobase/fil/fil0fil.cc | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 21743a0e076..a654451f986 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -561,11 +561,9 @@ fil_try_to_close_file_in_LRU( continue; } - if (node->n_pending_flushes > 0) { - + if (const auto n = node->n_pending_flushes) { ib::info() << "Cannot close file " << node->name - << ", because n_pending_flushes " - << node->n_pending_flushes; + << ", because n_pending_flushes " << n; } if (node->needs_flush) { @@ -915,7 +913,7 @@ pfs_os_file_t fil_node_t::close_to_free(bool detach_handle) fil_system.unflushed_spaces.remove(*space); } - if (n_pending) + if (n_pending || n_pending_flushes) { mutex_exit(&fil_system.mutex); os_thread_sleep(100); @@ -939,7 +937,6 @@ pfs_os_file_t fil_node_t::close_to_free(bool detach_handle) ut_ad(UT_LIST_GET_LEN(fil_system.LRU) > 0); UT_LIST_REMOVE(fil_system.LRU, this); } - ut_a(!n_pending_flushes); ut_a(!being_extended); if (detach_handle) { @@ -982,7 +979,6 @@ std::vector fil_system_t::detach(fil_space_t *space, temp_space= nullptr; ut_a(space->magic_n == FIL_SPACE_MAGIC_N); - ut_a(space->n_pending_flushes == 0); for (fil_node_t* node= UT_LIST_GET_FIRST(space->chain); node; node= UT_LIST_GET_NEXT(chain, node)) @@ -1003,6 +999,7 @@ std::vector fil_system_t::detach(fil_space_t *space, handles.push_back(handle); } + ut_ad(space->n_pending_flushes == 0); return handles; } @@ -1612,7 +1609,8 @@ next: if (!node->is_open()) { goto next; } - if (!node->n_pending) { + if (!node->n_pending + && !node->n_pending_flushes) { node->close(); goto next; } @@ -1620,7 +1618,9 @@ next: ib::error() << "File '" << node->name << "' has " << node->n_pending - << " operations"; + << " operations and " + << node->n_pending_flushes + << " flushes"; } space = UT_LIST_GET_NEXT(space_list, space); @@ -1988,17 +1988,18 @@ fil_check_pending_io( *node = UT_LIST_GET_FIRST(space->chain); - if (space->n_pending_flushes > 0 || (*node)->n_pending > 0) { + const auto f = space->n_pending_flushes; + const auto p = (*node)->n_pending; + if (f || p) { ut_a(!(*node)->being_extended); /* Give a warning every 10 second, starting after 1 second */ if ((count % 500) == 50) { ib::info() << "Trying to delete" " tablespace '" << space->name - << "' but there are " - << space->n_pending_flushes - << " flushes and " << (*node)->n_pending + << "' but there are " << f + << " flushes and " << p << " pending i/o's on it."; } From d34523faee248c71d1e335a75977cc71debe67d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 25 Sep 2020 17:29:33 +0300 Subject: [PATCH 032/323] MDEV-15053 fixup: Remove redundant code fil_node_t::close_to_free(): Remove some duplicated code that was added in commit b1ab211dee599eabd9a5b886fafa3adea29ae041. --- storage/innobase/fil/fil0fil.cc | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index a654451f986..0325dce8422 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -921,17 +921,6 @@ pfs_os_file_t fil_node_t::close_to_free(bool detach_handle) continue; } - if (srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC) - { - ut_ad(!space->is_in_unflushed_spaces); - ut_ad(fil_space_is_flushed(space)); - } - else if (space->is_in_unflushed_spaces && fil_space_is_flushed(space)) - { - space->is_in_unflushed_spaces= false; - fil_system.unflushed_spaces.remove(*space); - } - if (fil_space_belongs_in_lru(space)) { ut_ad(UT_LIST_GET_LEN(fil_system.LRU) > 0); From e8b05ce503dffc2d95d1583b7c89403d320e263c Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 8 Sep 2020 17:24:08 +0530 Subject: [PATCH 033/323] MDEV-23675 Assertion `pos < table->n_def' fails in dict_table_get_nth_col - During insertion of clustered inde, InnoDB does the check for foreign key constraints. It rebuild the tuple based on foreign column names when there is no foreign index. While rebuilding, InnoDB should ignore the dropped columns. --- mysql-test/suite/innodb/r/foreign_key.result | 13 +++++++++++++ mysql-test/suite/innodb/t/foreign_key.test | 14 ++++++++++++++ storage/innobase/row/row0ins.cc | 10 ++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index bd40f98ef65..2facbccc466 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -755,4 +755,17 @@ DROP TABLE t1; CREATE TABLE t1 (a GEOMETRY, INDEX(a(8)), FOREIGN KEY (a) REFERENCES x (xx)) ENGINE=InnoDB; ERROR HY000: Can't create table `test`.`t1` (errno: 150 "Foreign key constraint is incorrectly formed") +# +# MDEV-23675 Assertion `pos < table->n_def' in dict_table_get_nth_col +# +CREATE TABLE t1 (pk int PRIMARY KEY, a INT, b INT, c INT, KEY(c), +FOREIGN KEY fx (b) REFERENCES t1 (c)) +ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,0,10,10); +ALTER TABLE t1 DROP a, ALGORITHM=INSTANT; +SET FOREIGN_KEY_CHECKS= 0; +DROP INDEX fx ON t1; +INSERT INTO t1 VALUES (2,11,11); +DROP TABLE t1; +SET FOREIGN_KEY_CHECKS=DEFAULT; # End of 10.4 tests diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test index 9207fce6525..dab0736f712 100644 --- a/mysql-test/suite/innodb/t/foreign_key.test +++ b/mysql-test/suite/innodb/t/foreign_key.test @@ -741,6 +741,20 @@ DROP TABLE t1; CREATE TABLE t1 (a GEOMETRY, INDEX(a(8)), FOREIGN KEY (a) REFERENCES x (xx)) ENGINE=InnoDB; +--echo # +--echo # MDEV-23675 Assertion `pos < table->n_def' in dict_table_get_nth_col +--echo # +CREATE TABLE t1 (pk int PRIMARY KEY, a INT, b INT, c INT, KEY(c), +FOREIGN KEY fx (b) REFERENCES t1 (c)) +ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,0,10,10); +ALTER TABLE t1 DROP a, ALGORITHM=INSTANT; +SET FOREIGN_KEY_CHECKS= 0; +DROP INDEX fx ON t1; +INSERT INTO t1 VALUES (2,11,11); +DROP TABLE t1; +SET FOREIGN_KEY_CHECKS=DEFAULT; + -- echo # End of 10.4 tests --source include/wait_until_count_sessions.inc diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 9c913b0c9f2..a28489062b0 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -1908,8 +1908,14 @@ bool row_ins_foreign_index_entry(dict_foreign_t *foreign, { for (ulint j= 0; j < index->n_fields; j++) { - const char *col_name= dict_table_get_col_name( - index->table, dict_index_get_nth_col_no(index, j)); + const dict_col_t *col= dict_index_get_nth_col(index, j); + + /* A clustered index may contain instantly dropped columns, + which must be skipped. */ + if (col->is_dropped()) + continue; + + const char *col_name= dict_table_get_col_name(index->table, col->ind); if (0 == innobase_strcasecmp(col_name, foreign->foreign_col_names[i])) { dfield_copy(&ref_entry->fields[i], &entry->fields[j]); From e0f5e7bc9ef306a76c5bf4e067ee5c1a9a7b6187 Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 25 Sep 2020 15:58:08 +0300 Subject: [PATCH 034/323] Reverted wrong patch for mysql_upgrade The original code was correct. mysql_upgrade calls the mysql client to talk with MariaDB. It doesn't call itself! --- client/mysql_upgrade.c | 2 +- mysql-test/r/mysql_upgrade.result | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 9cc12c8d7e7..d18dc97c9b8 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -1108,7 +1108,7 @@ static int check_version_match(void) extract_variable_from_show(&ds_version, version_str)) { print_error("Version check failed. Got the following error when calling " - "the 'mysql_upgrade' command line client", &ds_version); + "the 'mysql' command line client", &ds_version); dynstr_free(&ds_version); return 1; /* Query failed */ } diff --git a/mysql-test/r/mysql_upgrade.result b/mysql-test/r/mysql_upgrade.result index a1464bb4853..69637f4078f 100644 --- a/mysql-test/r/mysql_upgrade.result +++ b/mysql-test/r/mysql_upgrade.result @@ -142,7 +142,7 @@ test Phase 7/7: Running 'FLUSH PRIVILEGES' OK DROP USER mysqltest1@'%'; -Version check failed. Got the following error when calling the 'mysql_upgrade' command line client +Version check failed. Got the following error when calling the 'mysql' command line client ERROR 1045 (28000): Access denied for user 'mysqltest1'@'localhost' (using password: YES) FATAL ERROR: Upgrade failed Run mysql_upgrade with a non existing server socket @@ -405,7 +405,7 @@ OK # Bug #21489398: MYSQL_UPGRADE: FATAL ERROR: UPGRADE FAILED - IMPROVE ERROR # Run mysql_upgrade with unauthorized access -Version check failed. Got the following error when calling the 'mysql_upgrade' command line client +Version check failed. Got the following error when calling the 'mysql' command line client ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES) FATAL ERROR: Upgrade failed # From d111e6ae0cef102cd5698d8ed17ee123f77b9791 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sun, 27 Sep 2020 01:01:41 +0200 Subject: [PATCH 035/323] Fix clang-cl build --- cmake/os/Windows.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake index 189253c5b23..1383a717bdc 100644 --- a/cmake/os/Windows.cmake +++ b/cmake/os/Windows.cmake @@ -104,7 +104,8 @@ MACRO(ENABLE_SANITIZERS) STRING(APPEND CMAKE_C_STANDARD_LIBRARIES " \"${${lib}_fullpath}\" ") STRING(APPEND CMAKE_CXX_STANDARD_LIBRARIES " \"${${lib}_fullpath}\" ") ENDFOREACH() - + STRING(APPEND CMAKE_C_FLAGS ${SANITIZER_COMPILE_FLAGS}) + STRING(APPEND CMAKE_CXX_FLAGS ${SANITIZER_COMPILE_FLAGS}) ENDMACRO() @@ -178,6 +179,9 @@ IF(MSVC) -Wno-deprecated-register -Wno-missing-braces \ -Wno-unused-function -Wno-unused-local-typedef -msse4.2 " ) + IF(CMAKE_SIZEOF_VOID_P MATCHES 8) + STRING(APPEND CLANG_CL_FLAGS "-mpclmul ") + ENDIF() STRING(APPEND CMAKE_C_FLAGS " ${CLANG_CL_FLAGS} ${MSVC_CRT_TYPE}") STRING(APPEND CMAKE_CXX_FLAGS " ${CLANG_CL_FLAGS} ${MSVC_CRT_TYPE}") ENDIF() From 080522dcd7177a0008824802cd58a36ee8048d8f Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Sat, 26 Sep 2020 18:04:17 +0400 Subject: [PATCH 036/323] MDEV-23825 Join select_handler and Pushdown_select + XPand changes --- sql/select_handler.cc | 83 ++++++++++++++++++++++--------------------- sql/select_handler.h | 20 +++++++++-- sql/sql_lex.h | 4 +-- sql/sql_select.cc | 16 ++------- sql/sql_select.h | 23 ------------ 5 files changed, 63 insertions(+), 83 deletions(-) diff --git a/sql/select_handler.cc b/sql/select_handler.cc index 9a2f6398a86..795ed8eb641 100644 --- a/sql/select_handler.cc +++ b/sql/select_handler.cc @@ -21,10 +21,10 @@ /** - The methods of the Pushdown_select class. + The methods of the select_handler class. The objects of this class are used for pushdown of the select queries - into engines. The main method of the class is Pushdown_select::execute() + into engines. The main method of the class is select_handler::execute() that initiates execution of a select query by a foreign engine, receives the rows of the result set, put it in a buffer of a temporary table and send them from the buffer directly into output. @@ -36,51 +36,55 @@ */ -Pushdown_select::Pushdown_select(SELECT_LEX *sel, select_handler *h) - : select(sel), handler(h) +select_handler::select_handler(THD *thd_arg, handlerton *ht_arg) + : thd(thd_arg), ht(ht_arg), table(NULL), + is_analyze(thd_arg->lex->analyze_stmt) +{} + + +select_handler::~select_handler() { - is_analyze= handler->thd->lex->analyze_stmt; + if (table) + free_tmp_table(thd, table); } -Pushdown_select::~Pushdown_select() -{ - if (handler->table) - free_tmp_table(handler->thd, handler->table); - delete handler; - select->select_h= NULL; -} - - -bool Pushdown_select::init() +TABLE *select_handler::create_tmp_table(THD *thd, SELECT_LEX *select) { + DBUG_ENTER("select_handler::create_tmp_table"); List types; TMP_TABLE_PARAM tmp_table_param; - THD *thd= handler->thd; - DBUG_ENTER("Pushdown_select::init"); if (select->master_unit()->join_union_item_types(thd, types, 1)) - DBUG_RETURN(true); + DBUG_RETURN(NULL); tmp_table_param.init(); tmp_table_param.field_count= types.elements; - handler->table= create_tmp_table(thd, &tmp_table_param, types, + TABLE *table= ::create_tmp_table(thd, &tmp_table_param, types, (ORDER *) 0, false, 0, TMP_TABLE_ALL_COLUMNS, 1, &empty_clex_str, true, false); - if (!handler->table) - DBUG_RETURN(true); - if (handler->table->fill_item_list(&result_columns)) - DBUG_RETURN(true); - DBUG_RETURN(false); + DBUG_RETURN(table); } -bool Pushdown_select::send_result_set_metadata() +bool select_handler::prepare() { - DBUG_ENTER("Pushdown_select::send_result_set_metadata"); + DBUG_ENTER("select_handler::prepare"); + /* + Some engines (e.g. XPand) initialize "table" on their own. + So we need to create a temporary table only if "table" is NULL. + */ + if (!table && !(table= create_tmp_table(thd, select))) + DBUG_RETURN(true); + DBUG_RETURN(table->fill_item_list(&result_columns)); +} + + +bool select_handler::send_result_set_metadata() +{ + DBUG_ENTER("select_handler::send_result_set_metadata"); #ifdef WITH_WSREP - THD *thd= handler->thd; if (WSREP(thd) && thd->wsrep_retry_query) { WSREP_DEBUG("skipping select metadata"); @@ -96,7 +100,7 @@ bool Pushdown_select::send_result_set_metadata() } -bool Pushdown_select::send_data() +bool select_handler::send_data() { DBUG_ENTER("Pushdown_select::send_data"); @@ -107,9 +111,9 @@ bool Pushdown_select::send_data() } -bool Pushdown_select::send_eof() +bool select_handler::send_eof() { - DBUG_ENTER("Pushdown_select::send_eof"); + DBUG_ENTER("select_handler::send_eof"); if (select->join->result->send_eof()) DBUG_RETURN(true); @@ -117,30 +121,29 @@ bool Pushdown_select::send_eof() } -int Pushdown_select::execute() +int select_handler::execute() { int err; - THD *thd= handler->thd; - DBUG_ENTER("Pushdown_select::execute"); + DBUG_ENTER("select_handler::execute"); - if ((err= handler->init_scan())) + if ((err= init_scan())) goto error; if (is_analyze) { - handler->end_scan(); + end_scan(); DBUG_RETURN(0); } if (send_result_set_metadata()) DBUG_RETURN(-1); - while (!(err= handler->next_row())) + while (!(err= next_row())) { if (thd->check_killed() || send_data()) { - handler->end_scan(); + end_scan(); DBUG_RETURN(-1); } } @@ -148,7 +151,7 @@ int Pushdown_select::execute() if (err != 0 && err != HA_ERR_END_OF_FILE) goto error; - if ((err= handler->end_scan())) + if ((err= end_scan())) goto error_2; if (send_eof()) @@ -157,9 +160,9 @@ int Pushdown_select::execute() DBUG_RETURN(0); error: - handler->end_scan(); + end_scan(); error_2: - handler->print_error(err, MYF(0)); + print_error(err, MYF(0)); DBUG_RETURN(-1); // Error not sent to client } diff --git a/sql/select_handler.h b/sql/select_handler.h index e2ad13b7cdf..5cc63231641 100644 --- a/sql/select_handler.h +++ b/sql/select_handler.h @@ -41,12 +41,24 @@ class select_handler The table is actually never filled. Only its record buffer is used. */ TABLE *table; + List result_columns; - select_handler(THD *thd_arg, handlerton *ht_arg) - : thd(thd_arg), ht(ht_arg), table(0) {} + bool is_analyze; - virtual ~select_handler() {} + bool send_result_set_metadata(); + bool send_data(); + select_handler(THD *thd_arg, handlerton *ht_arg); + + virtual ~select_handler(); + + int execute(); + + virtual bool prepare(); + + static TABLE *create_tmp_table(THD *thd, SELECT_LEX *sel); + +protected: /* Functions to scan the select result set. All these returns 0 if ok, error code in case of error. @@ -67,6 +79,8 @@ class select_handler /* Report errors */ virtual void print_error(int error, myf errflag); + + bool send_eof(); }; #endif /* SELECT_HANDLER_INCLUDED */ diff --git a/sql/sql_lex.h b/sql/sql_lex.h index a07121b9a58..3e59ad3afc9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1334,10 +1334,8 @@ public: table_value_constr *tvc; bool in_tvc; - /* The interface employed to execute the select query by a foreign engine */ - select_handler *select_h; /* The object used to organize execution of the query by a foreign engine */ - Pushdown_select *pushdown_select; + select_handler *pushdown_select; /** System Versioning */ public: diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f0d42c32dd0..22ff3a6e0e3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1608,7 +1608,7 @@ int JOIN::optimize() if (!(select_options & SELECT_DESCRIBE)) { /* Prepare to execute the query pushed into a foreign engine */ - res= select_lex->pushdown_select->init(); + res= select_lex->pushdown_select->prepare(); } with_two_phase_optimization= false; } @@ -4632,19 +4632,7 @@ mysql_select(THD *thd, TABLE_LIST *tables, List &fields, COND *conds, } /* Look for a table owned by an engine with the select_handler interface */ - select_lex->select_h= select_lex->find_select_handler(thd); - if (select_lex->select_h) - { - /* Create a Pushdown_select object for later execution of the query */ - if (!(select_lex->pushdown_select= - new (thd->mem_root) Pushdown_select(select_lex, - select_lex->select_h))) - { - delete select_lex->select_h; - select_lex->select_h= NULL; - DBUG_RETURN(TRUE); - } - } + select_lex->pushdown_select= select_lex->find_select_handler(thd); if ((err= join->optimize())) { diff --git a/sql/sql_select.h b/sql/sql_select.h index 7c8908302cd..947863bc2d9 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -2517,29 +2517,6 @@ public: class select_handler; -class Pushdown_select: public Sql_alloc -{ -private: - bool is_analyze; - List result_columns; - bool send_result_set_metadata(); - bool send_data(); - bool send_eof(); - -public: - SELECT_LEX *select; - select_handler *handler; - - Pushdown_select(SELECT_LEX *sel, select_handler *h); - - ~Pushdown_select(); - - bool init(); - - int execute(); -}; - - bool test_if_order_compatible(SQL_I_List &a, SQL_I_List &b); int test_if_group_changed(List &list); int create_sort_index(THD *thd, JOIN *join, JOIN_TAB *tab, Filesort *fsort); From 15cd9195353282e54e109962d46e1900c9eff3d4 Mon Sep 17 00:00:00 2001 From: Sujatha Date: Thu, 24 Sep 2020 15:07:42 +0530 Subject: [PATCH 037/323] MDEV-22330: mysqlbinlog stops with an error Don't know how to handle column type: 255 meta: 4 (0004) Analysis: ======== "mysqlbinlog -v" option will reconstruct row events and display them as commented SQL statements. If this option is given twice, the output includes comments to indicate column data types and some metadata. `log_event_print_value` is the function reponsible for printing values and their types. This function doesn't handle GEOMETRY type. Hence the above error gets printed. Fix: === Add support for GEOMETRY datatype. --- .../binlog/r/binlog_mysqlbinlog_row.result | 56 ++++++++++++++++++- .../binlog/t/binlog_mysqlbinlog_row.test | 14 ++++- sql/log_event.cc | 17 ++++-- 3 files changed, 80 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_row.result b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_row.result index 9a3f4751165..0b05c4f449f 100644 --- a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_row.result +++ b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_row.result @@ -339,7 +339,11 @@ a 123.47 999.99 DROP TABLE t1dec102; -flush logs; +CREATE TABLE t1 (a GEOMETRY DEFAULT NULL); +INSERT INTO t1 VALUES (NULL); +INSERT INTO t1 VALUES (POINT(10,10)); +DROP TABLE t1; +FLUSH LOGS; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!40019 SET @@session.max_insert_delayed_threads=0*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; @@ -4623,6 +4627,56 @@ SET TIMESTAMP=1000000000/*!*/; DROP TABLE `t1dec102` /* generated by server */ /*!*/; # at # +#010909 4:46:40 server id 1 end_log_pos # GTID 0-1-321 ddl +/*!100001 SET @@session.gtid_seq_no=321*//*!*/; +# at # +#010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0 +SET TIMESTAMP=1000000000/*!*/; +CREATE TABLE t1 (a GEOMETRY DEFAULT NULL) +/*!*/; +# at # +#010909 4:46:40 server id 1 end_log_pos # GTID 0-1-322 +/*!100001 SET @@session.gtid_seq_no=322*//*!*/; +BEGIN +/*!*/; +# at # +#010909 4:46:40 server id 1 end_log_pos # Table_map: `test`.`t1` mapped to number # +# at # +#010909 4:46:40 server id 1 end_log_pos # Write_rows: table id # flags: STMT_END_F +### INSERT INTO `test`.`t1` +### SET +### @1=NULL /* GEOMETRY meta=4 nullable=1 is_null=1 */ +# at # +#010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0 +SET TIMESTAMP=1000000000/*!*/; +COMMIT +/*!*/; +# at # +#010909 4:46:40 server id 1 end_log_pos # GTID 0-1-323 +/*!100001 SET @@session.gtid_seq_no=323*//*!*/; +BEGIN +/*!*/; +# at # +#010909 4:46:40 server id 1 end_log_pos # Table_map: `test`.`t1` mapped to number # +# at # +#010909 4:46:40 server id 1 end_log_pos # Write_rows: table id # flags: STMT_END_F +### INSERT INTO `test`.`t1` +### SET +### @1='\x00\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00$@\x00\x00\x00\x00\x00\x00$@' /* GEOMETRY meta=4 nullable=1 is_null=0 */ +# at # +#010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0 +SET TIMESTAMP=1000000000/*!*/; +COMMIT +/*!*/; +# at # +#010909 4:46:40 server id 1 end_log_pos # GTID 0-1-324 ddl +/*!100001 SET @@session.gtid_seq_no=324*//*!*/; +# at # +#010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0 +SET TIMESTAMP=1000000000/*!*/; +DROP TABLE `t1` /* generated by server */ +/*!*/; +# at # #010909 4:46:40 server id 1 end_log_pos # Rotate to master-bin.000002 pos: 4 DELIMITER ; # End of log file diff --git a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_row.test b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_row.test index 0c94d968338..93c26cc57a2 100644 --- a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_row.test +++ b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_row.test @@ -450,7 +450,19 @@ INSERT INTO t1dec102 VALUES (999.99); SELECT * FROM t1dec102 ORDER BY a; DROP TABLE t1dec102; -flush logs; + +# +# MDEV-22330: mysqlbinlog stops with an error Don't know how to handle column +# type: 255 meta: 4 (0004) +# Check support for GEOMETRY type with verbose mode. +# +CREATE TABLE t1 (a GEOMETRY DEFAULT NULL); + +INSERT INTO t1 VALUES (NULL); +INSERT INTO t1 VALUES (POINT(10,10)); +DROP TABLE t1; + +FLUSH LOGS; --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/ /exec_time=[0-9]*/exec_time=#/ /end_log_pos [0-9]*/end_log_pos #/ /# at [0-9]*/# at #/ /thread_id=[0-9]*/thread_id=#/ /table id [0-9]*/table id #/ /mapped to number [0-9]*/mapped to number #/ /server v [^ ]*/server v #.##.##/ /(@[0-9]*=[0-9]*[.][0-9]{1,3})[0-9e+-]*[^ ]*(.*(FLOAT|DOUBLE).*[*].)/\1...\2/ diff --git a/sql/log_event.cc b/sql/log_event.cc index 4d7bb1726ed..3d28c249e21 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2575,13 +2575,20 @@ log_event_print_value(IO_CACHE *file, const uchar *ptr, "Not enough metadata to display the value. "); break; + case MYSQL_TYPE_GEOMETRY: + strmake(typestr, "GEOMETRY", typestr_length); + if (!ptr) + goto return_null; + + length= uint4korr(ptr); + my_b_write_quoted(file, ptr + meta, length); + return length + meta; + default: { - char tmp[5]; - my_snprintf(tmp, sizeof(tmp), "%04x", meta); - my_b_printf(file, - "!! Don't know how to handle column type=%d meta=%d (%s)", - type, meta, tmp); + fprintf(stderr, + "\nError: Don't know how to handle column type: %d meta: %d (%04x)\n", + type, meta, meta); } break; } From a6987d9fb921a6638bb1a2397b89ca606fad6f49 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 28 Sep 2020 09:49:46 +0200 Subject: [PATCH 038/323] MDEV-23823 Crash in SELECT NEXT VALUE on locked view Make open_table() fail if sequence should be opened, but it turns out to be locked view. --- mysql-test/suite/sql_sequence/next.result | 9 +++++++++ mysql-test/suite/sql_sequence/next.test | 10 ++++++++++ sql/sql_base.cc | 7 +++++++ 3 files changed, 26 insertions(+) diff --git a/mysql-test/suite/sql_sequence/next.result b/mysql-test/suite/sql_sequence/next.result index b1b1bb69306..fe761baa032 100644 --- a/mysql-test/suite/sql_sequence/next.result +++ b/mysql-test/suite/sql_sequence/next.result @@ -534,3 +534,12 @@ select next value for s; next value for s -999 drop sequence s; +# +# MDEV-23823 NEXT VALUE crash on locked view +# +CREATE VIEW v AS SELECT 1; +LOCK TABLE v READ; +SELECT NEXT VALUE FOR v; +ERROR 42S02: 'test.v' is not a SEQUENCE +UNLOCK TABLES; +DROP VIEW v; diff --git a/mysql-test/suite/sql_sequence/next.test b/mysql-test/suite/sql_sequence/next.test index a1f91bd7823..5eac3b668ba 100644 --- a/mysql-test/suite/sql_sequence/next.test +++ b/mysql-test/suite/sql_sequence/next.test @@ -280,3 +280,13 @@ select next value for s; flush tables; select next value for s; drop sequence s; + +--echo # +--echo # MDEV-23823 NEXT VALUE crash on locked view +--echo # +CREATE VIEW v AS SELECT 1; +LOCK TABLE v READ; +--error ER_NOT_SEQUENCE +SELECT NEXT VALUE FOR v; +UNLOCK TABLES; +DROP VIEW v; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 73ed7a855a2..00e1198df0e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1724,7 +1724,14 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx) } if (is_locked_view(thd, table_list)) + { + if (table_list->sequence) + { + my_error(ER_NOT_SEQUENCE, MYF(0), table_list->db.str, table_list->alias.str); + DBUG_RETURN(true); + } DBUG_RETURN(FALSE); // VIEW + } /* No table in the locked tables list. In case of explicit LOCK TABLES From c078f55f47eba8660f6daed6d0c2000694159a6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 28 Sep 2020 11:05:09 +0300 Subject: [PATCH 039/323] MDEV-23659 : Update Galera disabled.def file This will update galera_3nodes/disabled.def. --- mysql-test/suite/galera_3nodes/disabled.def | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mysql-test/suite/galera_3nodes/disabled.def b/mysql-test/suite/galera_3nodes/disabled.def index 0e2706f2dc3..80cfa7a920f 100644 --- a/mysql-test/suite/galera_3nodes/disabled.def +++ b/mysql-test/suite/galera_3nodes/disabled.def @@ -10,7 +10,13 @@ # ############################################################################## + galera_gtid_2_cluster : MDEV-23775 Galera test failure on galera_3nodes.galera_gtid_2_cluster +galera_ipv6_mariabackup.test : MDEV-21770 galera_3nodes.galera_ipv6_mariabackup fails +galera_ipv6_mariabackup_section.test : MDEV-21770 galera_3nodes.galera_ipv6_mariabackup fails +galera_ipv6_mysqldump.test : MDEV-23576 galera_3nodes.galera_ipv6_mysqldump MTR failed: WSREP_SST: [ERROR] rsync daemon port '16008' has been taken +galera_ipv6_rsync.test : MDEV-23581 galera_3nodes.galera_ipv6_rsync MTR failed: WSREP_SST: [ERROR] rsync daemon port '16008' has been taken +galera_ipv6_rsync_section.test : MDEV-23580 galera_3nodes.galera_ipv6_rsync_section MTR failed: WSREP_SST: [ERROR] rsync daemon port '16008' has been taken galera_ist_gcache_rollover : MDEV-23578 WSREP: exception caused by message: {v=0,t=1,ut=255,o=4,s=0,sr=0,as=1,f=6,src=50524cfe,srcvid=view_id(REG,50524cfe,4),insvid=view_id(UNKNOWN,00000000,0),ru=00000000,r=[-1,-1],fs=75,nl=(} galera_slave_options_do :MDEV-8798 galera_slave_options_ignore : MDEV-8798 From 7edfb72efff18b7de7f22cd6dfd90b553e27c286 Mon Sep 17 00:00:00 2001 From: Daniele Sciascia Date: Fri, 25 Sep 2020 14:08:35 +0200 Subject: [PATCH 040/323] Fix MTR test wsrep.variables Require galera_have_debug_sync.inc and re-record to include new variables exposed by latest galera library. --- mysql-test/suite/wsrep/r/variables.result | 6 ++++++ mysql-test/suite/wsrep/t/variables.test | 1 + 2 files changed, 7 insertions(+) diff --git a/mysql-test/suite/wsrep/r/variables.result b/mysql-test/suite/wsrep/r/variables.result index 1ff221f1459..87a385ec9a6 100644 --- a/mysql-test/suite/wsrep/r/variables.result +++ b/mysql-test/suite/wsrep/r/variables.result @@ -48,6 +48,8 @@ wsrep_flow_control_paused_ns # wsrep_flow_control_paused # wsrep_flow_control_sent # wsrep_flow_control_recv # +wsrep_flow_control_active # +wsrep_flow_control_requested # wsrep_cert_deps_distance # wsrep_apply_oooe # wsrep_apply_oool # @@ -63,6 +65,7 @@ wsrep_cert_interval # wsrep_open_transactions # wsrep_open_connections # wsrep_incoming_addresses # +wsrep_debug_sync_waiters # wsrep_applier_thread_count # wsrep_cluster_capabilities # wsrep_cluster_conf_id # @@ -109,6 +112,8 @@ wsrep_flow_control_paused_ns # wsrep_flow_control_paused # wsrep_flow_control_sent # wsrep_flow_control_recv # +wsrep_flow_control_active # +wsrep_flow_control_requested # wsrep_cert_deps_distance # wsrep_apply_oooe # wsrep_apply_oool # @@ -124,6 +129,7 @@ wsrep_cert_interval # wsrep_open_transactions # wsrep_open_connections # wsrep_incoming_addresses # +wsrep_debug_sync_waiters # wsrep_applier_thread_count # wsrep_cluster_capabilities # wsrep_cluster_conf_id # diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test index 89b1ff99012..93aa31b9c93 100644 --- a/mysql-test/suite/wsrep/t/variables.test +++ b/mysql-test/suite/wsrep/t/variables.test @@ -1,6 +1,7 @@ --source include/have_wsrep.inc --source include/force_restart.inc --source include/have_innodb.inc +--source include/galera_have_debug_sync.inc SET @wsrep_provider_options_saved= @@global.wsrep_provider_options; SET @wsrep_cluster_address_saved= @@global.wsrep_cluster_address; From fdb3c64e429cdc6f2370b7f4eefc0fbaf72eac6d Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 28 Sep 2020 17:04:02 +0530 Subject: [PATCH 041/323] MDEV-22277 LeakSanitizer: detected memory leaks in mem_heap_create_block_func after attempt to create foreign key - During online DDL, prepare phase error handler fails to remove the memory allocated for newly created foreign keys. --- mysql-test/suite/innodb/r/foreign_key.result | 11 +++++++++++ mysql-test/suite/innodb/t/foreign_key.test | 14 ++++++++++++++ storage/innobase/handler/handler0alter.cc | 6 ++++++ storage/xtradb/handler/handler0alter.cc | 6 ++++++ 4 files changed, 37 insertions(+) diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index 378fe74e14b..e9fbc742379 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -233,3 +233,14 @@ Opened_table_definitions 2 Opened_tables 2 drop function foo; drop table t2, t1; +CREATE TABLE t1 (pk INT, a INT, PRIMARY KEY (pk)) ENGINE=InnoDB; +XA START 'xid'; +INSERT INTO t1 VALUES (1,2); +CREATE TABLE x AS SELECT * FROM t1; +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state +SET foreign_key_checks= OFF, innodb_lock_wait_timeout= 1; +ALTER TABLE t1 ADD FOREIGN KEY f (a) REFERENCES t1 (pk), LOCK=EXCLUSIVE; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +XA END 'xid'; +XA ROLLBACK 'xid'; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test index b33fbf60675..3269aeed62b 100644 --- a/mysql-test/suite/innodb/t/foreign_key.test +++ b/mysql-test/suite/innodb/t/foreign_key.test @@ -285,6 +285,20 @@ show status like '%opened_tab%'; drop function foo; drop table t2, t1; +CREATE TABLE t1 (pk INT, a INT, PRIMARY KEY (pk)) ENGINE=InnoDB; +XA START 'xid'; +INSERT INTO t1 VALUES (1,2); +--error ER_XAER_RMFAIL +CREATE TABLE x AS SELECT * FROM t1; +--connect (con1,localhost,root,,test) +SET foreign_key_checks= OFF, innodb_lock_wait_timeout= 1; +--error ER_LOCK_WAIT_TIMEOUT +ALTER TABLE t1 ADD FOREIGN KEY f (a) REFERENCES t1 (pk), LOCK=EXCLUSIVE;# Cleanup +--disconnect con1 +--connection default +XA END 'xid'; +XA ROLLBACK 'xid'; +DROP TABLE t1; # # End of 10.1 tests # diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 682f09992a4..e2c7c4421c6 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -3376,6 +3376,12 @@ err_exit: trx_free_for_mysql(ctx->trx); trx_commit_for_mysql(ctx->prebuilt->trx); + for (uint i = 0; i < ctx->num_to_add_fk; i++) { + if (ctx->add_fk[i]) { + dict_foreign_free(ctx->add_fk[i]); + } + } + delete ctx; ha_alter_info->handler_ctx = NULL; diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc index e1b2dcd2441..4126f6b60e0 100644 --- a/storage/xtradb/handler/handler0alter.cc +++ b/storage/xtradb/handler/handler0alter.cc @@ -3388,6 +3388,12 @@ err_exit: trx_free_for_mysql(ctx->trx); trx_commit_for_mysql(ctx->prebuilt->trx); + for (uint i = 0; i < ctx->num_to_add_fk; i++) { + if (ctx->add_fk[i]) { + dict_foreign_free(ctx->add_fk[i]); + } + } + delete ctx; ha_alter_info->handler_ctx = NULL; From 842616532a76cd078ba1d526ae4b85d3ad4be069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 28 Sep 2020 14:39:24 +0300 Subject: [PATCH 042/323] MDEV-23659 : Update Galera disabled.def file Fix typo. --- mysql-test/suite/galera_3nodes/disabled.def | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/galera_3nodes/disabled.def b/mysql-test/suite/galera_3nodes/disabled.def index 80cfa7a920f..ff7262947a0 100644 --- a/mysql-test/suite/galera_3nodes/disabled.def +++ b/mysql-test/suite/galera_3nodes/disabled.def @@ -10,13 +10,12 @@ # ############################################################################## - galera_gtid_2_cluster : MDEV-23775 Galera test failure on galera_3nodes.galera_gtid_2_cluster -galera_ipv6_mariabackup.test : MDEV-21770 galera_3nodes.galera_ipv6_mariabackup fails -galera_ipv6_mariabackup_section.test : MDEV-21770 galera_3nodes.galera_ipv6_mariabackup fails -galera_ipv6_mysqldump.test : MDEV-23576 galera_3nodes.galera_ipv6_mysqldump MTR failed: WSREP_SST: [ERROR] rsync daemon port '16008' has been taken -galera_ipv6_rsync.test : MDEV-23581 galera_3nodes.galera_ipv6_rsync MTR failed: WSREP_SST: [ERROR] rsync daemon port '16008' has been taken -galera_ipv6_rsync_section.test : MDEV-23580 galera_3nodes.galera_ipv6_rsync_section MTR failed: WSREP_SST: [ERROR] rsync daemon port '16008' has been taken +galera_ipv6_mariabackup : MDEV-21770 galera_3nodes.galera_ipv6_mariabackup fails +galera_ipv6_mariabackup_section : MDEV-21770 galera_3nodes.galera_ipv6_mariabackup fails +galera_ipv6_mysqldump : MDEV-23576 galera_3nodes.galera_ipv6_mysqldump MTR failed: WSREP_SST: [ERROR] rsync daemon port '16008' has been taken +galera_ipv6_rsync : MDEV-23581 galera_3nodes.galera_ipv6_rsync MTR failed: WSREP_SST: [ERROR] rsync daemon port '16008' has been taken +galera_ipv6_rsync_section : MDEV-23580 galera_3nodes.galera_ipv6_rsync_section MTR failed: WSREP_SST: [ERROR] rsync daemon port '16008' has been taken galera_ist_gcache_rollover : MDEV-23578 WSREP: exception caused by message: {v=0,t=1,ut=255,o=4,s=0,sr=0,as=1,f=6,src=50524cfe,srcvid=view_id(REG,50524cfe,4),insvid=view_id(UNKNOWN,00000000,0),ru=00000000,r=[-1,-1],fs=75,nl=(} galera_slave_options_do :MDEV-8798 galera_slave_options_ignore : MDEV-8798 From 79e32e47a11150839ac4ab44ac02d4019c0e0019 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sat, 26 Sep 2020 10:07:28 -0700 Subject: [PATCH 043/323] MDEV-23778 Derived table handler looses data on conversion from HEAP to Aria This bug happened when the HEAP temporary table used for the derived table created for a derived handler of a remote engine of the federated type became full and was converted to an Area table. For this conversion the tmp_table_param parameter must be always taken from the select_unit object created for the result of the derived table. --- .../federatedx_create_handlers.result | 44 ++++++++++++++ .../federated/federatedx_create_handlers.test | 57 +++++++++++++++++++ sql/derived_handler.cc | 4 +- 3 files changed, 102 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/federated/federatedx_create_handlers.result b/mysql-test/suite/federated/federatedx_create_handlers.result index 63e56bff425..b115cc73b87 100644 --- a/mysql-test/suite/federated/federatedx_create_handlers.result +++ b/mysql-test/suite/federated/federatedx_create_handlers.result @@ -376,6 +376,50 @@ DROP TABLE federated.t1, federated.t2, federated.t3, federated.t4; connection slave; DROP TABLE federated.t1, federated.t2; connection default; +# +# MDEV-23778: Derived handler used for big derived tables +# +connection slave; +CREATE TABLE federated.t1 ( +a varchar(100) NOT NULL default '123' +) +DEFAULT CHARSET=latin1; +CREATE TABLE federated.t2 LIKE federated.t1; +BEGIN NOT ATOMIC +DECLARE i INT DEFAULT 0; +START TRANSACTION; +WHILE i < 70000 DO +INSERT INTO federated.t1 VALUES (i); +SET i = i + 1; +END WHILE; +COMMIT; +END +$$ +connection master; +CREATE TABLE federated.t1 ( +a varchar(100) NOT NULL default '123' +) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CREATE TABLE federated.t2 ( +a varchar(100) NOT NULL default '123' +) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t2'; +SELECT COUNT(DISTINCT a) FROM federated.t1; +COUNT(DISTINCT a) +70000 +INSERT INTO federated.t2 +SELECT * FROM (SELECT * FROM federated.t1 LIMIT 100) dt; +SELECT COUNT(DISTINCT a) FROM federated.t2; +COUNT(DISTINCT a) +100 +TRUNCATE TABLE federated.t2; +INSERT INTO federated.t2 +SELECT * FROM (SELECT * FROM federated.t1 LIMIT 70000) dt; +SELECT COUNT(DISTINCT a) FROM federated.t2; +COUNT(DISTINCT a) +70000 set global federated_pushdown=0; connection master; DROP TABLE IF EXISTS federated.t1; diff --git a/mysql-test/suite/federated/federatedx_create_handlers.test b/mysql-test/suite/federated/federatedx_create_handlers.test index d765588b79b..4b5789e1d96 100644 --- a/mysql-test/suite/federated/federatedx_create_handlers.test +++ b/mysql-test/suite/federated/federatedx_create_handlers.test @@ -208,6 +208,63 @@ DROP TABLE federated.t1, federated.t2; connection default; +--echo # +--echo # MDEV-23778: Derived handler used for big derived tables +--echo # + +connection slave; + +CREATE TABLE federated.t1 ( + a varchar(100) NOT NULL default '123' +) +DEFAULT CHARSET=latin1; + +CREATE TABLE federated.t2 LIKE federated.t1; + +DELIMITER $$; +BEGIN NOT ATOMIC + DECLARE i INT DEFAULT 0; + START TRANSACTION; + WHILE i < 70000 DO + INSERT INTO federated.t1 VALUES (i); + SET i = i + 1; + END WHILE; + COMMIT; +END +$$ + +DELIMITER ;$$ + +connection master; + +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval +CREATE TABLE federated.t1 ( + a varchar(100) NOT NULL default '123' +) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + + +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval +CREATE TABLE federated.t2 ( + a varchar(100) NOT NULL default '123' +) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t2'; + +SELECT COUNT(DISTINCT a) FROM federated.t1; + +INSERT INTO federated.t2 + SELECT * FROM (SELECT * FROM federated.t1 LIMIT 100) dt; +SELECT COUNT(DISTINCT a) FROM federated.t2; + +TRUNCATE TABLE federated.t2; +INSERT INTO federated.t2 + SELECT * FROM (SELECT * FROM federated.t1 LIMIT 70000) dt; +SELECT COUNT(DISTINCT a) FROM federated.t2; + set global federated_pushdown=0; source include/federated_cleanup.inc; diff --git a/sql/derived_handler.cc b/sql/derived_handler.cc index 76fd736de2b..f48b95cbf76 100644 --- a/sql/derived_handler.cc +++ b/sql/derived_handler.cc @@ -120,8 +120,6 @@ void derived_handler::set_derived(TABLE_LIST *tbl) table= tbl->table; unit= tbl->derived; select= unit->first_select(); - tmp_table_param= select->next_select() ? - ((select_unit *)(unit->result))->get_tmp_table_param() : - &select->join->tmp_table_param; + tmp_table_param= ((select_unit *)(unit->result))->get_tmp_table_param(); } From 83a520dbbbfb40fdc8bcd34f8a9e9035c458ad08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 29 Sep 2020 09:38:19 +0300 Subject: [PATCH 044/323] Cleanup: Remove unused rw_lock_t::writer_is_wait_ex This was missed in commit 2c252ba96b8f124f81371ec86843a45dc3977d54 (MySQL 5.5.42, MariaDB 5.5.42). --- storage/innobase/include/sync0rw.h | 8 +------- storage/xtradb/include/sync0rw.h | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/storage/innobase/include/sync0rw.h b/storage/innobase/include/sync0rw.h index 54b6d46c58d..fba53a3f575 100644 --- a/storage/innobase/include/sync0rw.h +++ b/storage/innobase/include/sync0rw.h @@ -2,6 +2,7 @@ Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. +Copyright (c) 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -620,13 +621,6 @@ struct rw_lock_t { /* last s-lock file/line is not guaranteed to be correct */ const char* last_s_file_name;/*!< File name where last s-locked */ const char* last_x_file_name;/*!< File name where last x-locked */ - ibool writer_is_wait_ex; - /*!< This is TRUE if the writer field is - RW_LOCK_WAIT_EX; this field is located far - from the memory update hotspot fields which - are at the start of this struct, thus we can - peek this field without causing much memory - bus traffic */ unsigned cline:14; /*!< Line where created */ unsigned last_s_line:14; /*!< Line number where last time s-locked */ unsigned last_x_line:14; /*!< Line number where last time x-locked */ diff --git a/storage/xtradb/include/sync0rw.h b/storage/xtradb/include/sync0rw.h index 2e25a27192e..19b4793fc7b 100644 --- a/storage/xtradb/include/sync0rw.h +++ b/storage/xtradb/include/sync0rw.h @@ -2,6 +2,7 @@ Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. +Copyright (c) 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -763,13 +764,6 @@ struct rw_lock_t { /* last s-lock file/line is not guaranteed to be correct */ const char* last_s_file_name;/*!< File name where last s-locked */ const char* last_x_file_name;/*!< File name where last x-locked */ - ibool writer_is_wait_ex; - /*!< This is TRUE if the writer field is - RW_LOCK_WAIT_EX; this field is located far - from the memory update hotspot fields which - are at the start of this struct, thus we can - peek this field without causing much memory - bus traffic */ unsigned cline:14; /*!< Line where created */ unsigned last_s_line:14; /*!< Line number where last time s-locked */ unsigned last_x_line:14; /*!< Line number where last time x-locked */ From 74bd3683ca8da4084e664f4f417b95fd74a5b319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 29 Sep 2020 11:04:12 +0300 Subject: [PATCH 045/323] MDEV-23839 innodb_fast_shutdown=0 hang on change buffer merge ibuf_merge_or_delete_for_page(): Do not attempt to invoke ibuf_delete_recs() on a page of the change buffer itself. The caller could already be holding ibuf->index->lock, and an attempt to acquire it in S mode would hang the release server or cause an assertion failure in rw_lock_s_lock_func() in a debug server. This problem was reproducible on 1 out of 2 runs of the following: ./mtr --no-reorder \ innodb.innodb-page_compression_default \ innodb.innodb-page_compression_snappy \ innodb.innodb-page_compression_zip \ innodb.innodb_wl6326_big innodb.xa_recovery --- storage/innobase/ibuf/ibuf0ibuf.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index 7e01c864a50..7068dab77a4 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -4472,7 +4472,10 @@ ibuf_merge_or_delete_for_page( fil_space_release(space); if (UNIV_UNLIKELY(srv_shutdown_state) - && !srv_fast_shutdown) { + && !srv_fast_shutdown + && (!block + || btr_page_get_index_id(block->frame) + != DICT_IBUF_ID_MIN + IBUF_SPACE_ID)) { /* Prevent an infinite loop on slow shutdown, in case the bitmap bits are wrongly clear even though buffered From aa2f263e595624bb64ddd31ce081126381f86a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 29 Sep 2020 11:07:34 +0300 Subject: [PATCH 046/323] Cleanup: Remove constant parameters async=false, index_name=NULL --- storage/innobase/btr/btr0defragment.cc | 7 +---- storage/innobase/handler/ha_innodb.cc | 35 +++-------------------- storage/innobase/handler/ha_innodb.h | 3 +- storage/innobase/include/btr0defragment.h | 2 -- 4 files changed, 6 insertions(+), 41 deletions(-) diff --git a/storage/innobase/btr/btr0defragment.cc b/storage/innobase/btr/btr0defragment.cc index dfaa61a1343..645334cbf4d 100644 --- a/storage/innobase/btr/btr0defragment.cc +++ b/storage/innobase/btr/btr0defragment.cc @@ -157,8 +157,6 @@ synchronized defragmentation. */ os_event_t btr_defragment_add_index( dict_index_t* index, /*!< index to be added */ - bool async, /*!< whether this is an async - defragmentation */ dberr_t* err) /*!< out: error code */ { mtr_t mtr; @@ -191,10 +189,7 @@ btr_defragment_add_index( return NULL; } btr_pcur_t* pcur = btr_pcur_create_for_mysql(); - os_event_t event = NULL; - if (!async) { - event = os_event_create(0); - } + os_event_t event = os_event_create(0); btr_pcur_open_at_index_side(true, index, BTR_SEARCH_LEAF, pcur, true, 0, &mtr); btr_pcur_move_to_next(pcur, &mtr); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 2493a11b554..fb12297d698 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -14705,25 +14705,14 @@ ha_innobase::analyze( /*****************************************************************//** Defragment table. @return error number */ -UNIV_INTERN -int -ha_innobase::defragment_table( -/*==========================*/ - const char* name, /*!< in: table name */ - const char* index_name, /*!< in: index name */ - bool async) /*!< in: whether to wait until finish */ +inline int ha_innobase::defragment_table(const char *name) { char norm_name[FN_REFLEN]; dict_table_t* table = NULL; dict_index_t* index = NULL; - ibool one_index = (index_name != 0); int ret = 0; dberr_t err = DB_SUCCESS; - if (!srv_defragment) { - return ER_FEATURE_DISABLED; - } - normalize_table_name(norm_name, name); table = dict_table_open_on_name(norm_name, FALSE, @@ -14751,10 +14740,6 @@ ha_innobase::defragment_table( continue; } - if (one_index && strcasecmp(index_name, index->name) != 0) { - continue; - } - if (btr_defragment_find_index(index)) { // We borrow this error code. When the same index is // already in the defragmentation queue, issue another @@ -14770,7 +14755,7 @@ ha_innobase::defragment_table( break; } - os_event_t event = btr_defragment_add_index(index, async, &err); + os_event_t event = btr_defragment_add_index(index, &err); if (err != DB_SUCCESS) { push_warning_printf( @@ -14786,7 +14771,7 @@ ha_innobase::defragment_table( break; } - if (!async && event) { + if (event) { while(os_event_wait_time(event, 1000000)) { if (thd_killed(current_thd)) { btr_defragment_remove_index(index); @@ -14800,19 +14785,9 @@ ha_innobase::defragment_table( if (ret) { break; } - - if (one_index) { - one_index = FALSE; - break; - } } dict_table_close(table, FALSE, FALSE); - - if (ret == 0 && one_index) { - ret = ER_NO_SUCH_INDEX; - } - return ret; } @@ -14838,9 +14813,7 @@ ha_innobase::optimize( bool try_alter = true; if (!m_prebuilt->table->is_temporary() && srv_defragment) { - int err; - - err = defragment_table(m_prebuilt->table->name.m_name, NULL, false); + int err = defragment_table(m_prebuilt->table->name.m_name); if (err == 0) { try_alter = false; diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 6d5c108c4a3..a02c897f7ae 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -219,8 +219,7 @@ public: int delete_table(const char *name); int rename_table(const char* from, const char* to); - int defragment_table(const char* name, const char* index_name, - bool async); + inline int defragment_table(const char* name); int check(THD* thd, HA_CHECK_OPT* check_opt); char* update_table_comment(const char* comment); diff --git a/storage/innobase/include/btr0defragment.h b/storage/innobase/include/btr0defragment.h index 57f8c2f3811..d622c3c7c39 100644 --- a/storage/innobase/include/btr0defragment.h +++ b/storage/innobase/include/btr0defragment.h @@ -64,8 +64,6 @@ is a synchronized defragmentation. */ os_event_t btr_defragment_add_index( dict_index_t* index, /*!< index to be added */ - bool async, /*!< whether this is an async - defragmentation */ dberr_t* err); /*!< out: error code */ /******************************************************************//** When table is dropped, this function is called to mark a table as removed in From 216ed1793482ab7d17cbd784c28780aeb3d286ef Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 17 Sep 2020 10:36:25 +1000 Subject: [PATCH 047/323] MDEV-22678: Debian Upgrade from MySQL-5.7 CE fails with "Plugin 'auth_socket' is not loaded MySQL.com and Percona packages can be root auth_socket only. MariaDB uses unix_socket. As the root user, as the default Debian maintaince user, needs to be accessible to run mariadb-upgrade for a start, we make it accessible again. --- debian/mariadb-server-10.5.postinst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/debian/mariadb-server-10.5.postinst b/debian/mariadb-server-10.5.postinst index 6decee78766..c29b3532cb2 100644 --- a/debian/mariadb-server-10.5.postinst +++ b/debian/mariadb-server-10.5.postinst @@ -103,6 +103,19 @@ EOF rmdir $mysql_upgradedir 2>/dev/null || true done + # Upgrading from mysql.com needs might have the root user as auth_socket. + # auto.cnf is a sign of a mysql install, that doesn't exist in mariadb. + # We use lsof to protect against concurrent access by mysqld (mariadb has + # its own projection). We make sure we're not doing this on a MySQL-8.0 + # directory. + # This direct update is needed to enable an authentication mechanism to + # perform mariadb-upgrade, (MDEV-22678). To keep the impact minimal, we + # skip innodb and set key-buffer-size to 0 as it isn't reused. + if [ -f "$mysql_datadir"/auto.cnf ] && [ -f "$mysql_datadir"/mysql/user.MYD ] && + [ ! lsof -nt "$mysql_datadir"/mysql/user.MYD > /dev/null ] && [ ! -f "$mysql_datadir"/undo_001 ]; then + echo "UPDATE mysql.user SET plugin='unix_socket' WHERE plugin='auth_socket';" | + /usr/sbin/mariadbd --skip-innodb --key_buffer_size=0 --default-storage-engine=MyISAM --bootstrap 2> /dev/null + fi # Ensure the existence and right permissions for the database and # log files. Use mkdir option 'Z' to create with correct SELinux context. From cd5f4d2a5939aa047734f023b28462c65f3e4569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 Sep 2020 13:26:46 +0300 Subject: [PATCH 048/323] Cleanup: Remove unused fts_cache_t::optimize_lock This has been unused from the very beginning (mysql/mysql-server@d5e512ae7e37cd1f70c44a3f12205d70b13118ab). --- storage/innobase/fts/fts0fts.cc | 3 --- storage/innobase/handler/ha_innodb.cc | 1 - storage/innobase/include/fts0types.h | 2 -- storage/innobase/include/sync0sync.h | 1 - storage/innobase/include/sync0types.h | 1 - storage/innobase/sync/sync0debug.cc | 3 --- storage/innobase/sync/sync0sync.cc | 1 - 7 files changed, 12 deletions(-) diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 8a6901bd15b..d56a1cb8bde 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -286,7 +286,6 @@ fts_cache_destroy(fts_cache_t* cache) { rw_lock_free(&cache->lock); rw_lock_free(&cache->init_lock); - mutex_free(&cache->optimize_lock); mutex_free(&cache->deleted_lock); mutex_free(&cache->doc_id_lock); os_event_destroy(cache->sync->event); @@ -623,8 +622,6 @@ fts_cache_create( mutex_create(LATCH_ID_FTS_DELETE, &cache->deleted_lock); - mutex_create(LATCH_ID_FTS_OPTIMIZE, &cache->optimize_lock); - mutex_create(LATCH_ID_FTS_DOC_ID, &cache->doc_id_lock); /* This is the heap used to create the cache itself. */ diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index fb12297d698..fd44324afe0 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -588,7 +588,6 @@ static PSI_mutex_info all_innodb_mutexes[] = { PSI_KEY(flush_list_mutex), PSI_KEY(fts_bg_threads_mutex), PSI_KEY(fts_delete_mutex), - PSI_KEY(fts_optimize_mutex), PSI_KEY(fts_doc_id_mutex), PSI_KEY(log_flush_order_mutex), PSI_KEY(hash_table_mutex), diff --git a/storage/innobase/include/fts0types.h b/storage/innobase/include/fts0types.h index 44c3ab77695..f5760a16c0e 100644 --- a/storage/innobase/include/fts0types.h +++ b/storage/innobase/include/fts0types.h @@ -131,8 +131,6 @@ struct fts_cache_t { intialization, it has different SYNC level as above cache lock */ - ib_mutex_t optimize_lock; /*!< Lock for OPTIMIZE */ - ib_mutex_t deleted_lock; /*!< Lock covering deleted_doc_ids */ ib_mutex_t doc_id_lock; /*!< Lock covering Doc ID */ diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index e250307fa28..1517a93c196 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -62,7 +62,6 @@ extern mysql_pfs_key_t fil_system_mutex_key; extern mysql_pfs_key_t flush_list_mutex_key; extern mysql_pfs_key_t fts_bg_threads_mutex_key; extern mysql_pfs_key_t fts_delete_mutex_key; -extern mysql_pfs_key_t fts_optimize_mutex_key; extern mysql_pfs_key_t fts_doc_id_mutex_key; extern mysql_pfs_key_t fts_pll_tokenize_mutex_key; extern mysql_pfs_key_t hash_table_mutex_key; diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h index 1820642b004..a52bb4437ea 100644 --- a/storage/innobase/include/sync0types.h +++ b/storage/innobase/include/sync0types.h @@ -307,7 +307,6 @@ enum latch_id_t { LATCH_ID_FLUSH_LIST, LATCH_ID_FTS_BG_THREADS, LATCH_ID_FTS_DELETE, - LATCH_ID_FTS_OPTIMIZE, LATCH_ID_FTS_DOC_ID, LATCH_ID_FTS_PLL_TOKENIZE, LATCH_ID_HASH_TABLE_MUTEX, diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc index 815e3cee618..b732ad355a0 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -1320,9 +1320,6 @@ sync_latch_meta_init() LATCH_ADD_MUTEX(FTS_DELETE, SYNC_FTS_OPTIMIZE, fts_delete_mutex_key); - LATCH_ADD_MUTEX(FTS_OPTIMIZE, SYNC_FTS_OPTIMIZE, - fts_optimize_mutex_key); - LATCH_ADD_MUTEX(FTS_DOC_ID, SYNC_FTS_OPTIMIZE, fts_doc_id_mutex_key); LATCH_ADD_MUTEX(FTS_PLL_TOKENIZE, SYNC_FTS_TOKENIZE, diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc index 22bd9f823ec..a9018f2f5d5 100644 --- a/storage/innobase/sync/sync0sync.cc +++ b/storage/innobase/sync/sync0sync.cc @@ -48,7 +48,6 @@ mysql_pfs_key_t fil_system_mutex_key; mysql_pfs_key_t flush_list_mutex_key; mysql_pfs_key_t fts_bg_threads_mutex_key; mysql_pfs_key_t fts_delete_mutex_key; -mysql_pfs_key_t fts_optimize_mutex_key; mysql_pfs_key_t fts_doc_id_mutex_key; mysql_pfs_key_t fts_pll_tokenize_mutex_key; mysql_pfs_key_t hash_table_mutex_key; From bac16c7e0c2e334436d55abecec4b3a77edf007a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sun, 27 Sep 2020 10:26:06 +0300 Subject: [PATCH 049/323] Cleanup: Remove unnecessary #include --- storage/innobase/buf/buf0lru.cc | 6 ------ storage/innobase/include/ut0mem.h | 5 ++--- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc index 26c5850d290..4ee84b0ac18 100644 --- a/storage/innobase/buf/buf0lru.cc +++ b/storage/innobase/buf/buf0lru.cc @@ -25,20 +25,14 @@ Created 11/5/1995 Heikki Tuuri *******************************************************/ #include "buf0lru.h" -#include "ut0byte.h" -#include "ut0rnd.h" #include "sync0rw.h" -#include "hash0hash.h" -#include "os0event.h" #include "fil0fil.h" #include "btr0btr.h" #include "buf0buddy.h" #include "buf0buf.h" -#include "buf0dblwr.h" #include "buf0flu.h" #include "buf0rea.h" #include "btr0sea.h" -#include "ibuf0ibuf.h" #include "os0file.h" #include "page0zip.h" #include "log0recv.h" diff --git a/storage/innobase/include/ut0mem.h b/storage/innobase/include/ut0mem.h index 414c00dfae8..2fc864d49a2 100644 --- a/storage/innobase/include/ut0mem.h +++ b/storage/innobase/include/ut0mem.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2019, MariaDB Corporation. +Copyright (c) 2019, 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 @@ -27,8 +27,7 @@ Created 5/30/1994 Heikki Tuuri #ifndef ut0mem_h #define ut0mem_h -#include "os0event.h" -#include "ut0mutex.h" +#include "univ.i" /******************************************************************** Concatenate 3 strings.*/ From 363da42190c09d80a79ca8a6b91fc6edca420903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sun, 27 Sep 2020 13:05:00 +0300 Subject: [PATCH 050/323] Cleanup: Remove unnecessary declarations --- storage/innobase/btr/btr0defragment.cc | 15 +++++++++++++++ storage/innobase/include/btr0defragment.h | 17 +---------------- storage/innobase/include/dict0defrag_bg.h | 4 +--- storage/innobase/include/dict0stats_bg.h | 2 -- storage/innobase/include/srv0srv.h | 1 - 5 files changed, 17 insertions(+), 22 deletions(-) diff --git a/storage/innobase/btr/btr0defragment.cc b/storage/innobase/btr/btr0defragment.cc index 34099f2b11f..ab0989299de 100644 --- a/storage/innobase/btr/btr0defragment.cc +++ b/storage/innobase/btr/btr0defragment.cc @@ -50,6 +50,21 @@ possible. From experimentation it seems that reduce the target size by 512 every time will make sure the page is compressible within a couple of iterations. */ #define BTR_DEFRAGMENT_PAGE_REDUCTION_STEP_SIZE 512 +/** Item in the work queue for btr_degrament_thread. */ +struct btr_defragment_item_t +{ + btr_pcur_t* pcur; /* persistent cursor where + btr_defragment_n_pages should start */ + os_event_t event; /* if not null, signal after work + is done */ + bool removed; /* Mark an item as removed */ + ulonglong last_processed; /* timestamp of last time this index + is processed by defragment thread */ + + btr_defragment_item_t(btr_pcur_t* pcur, os_event_t event); + ~btr_defragment_item_t(); +}; + /* Work queue for defragmentation. */ typedef std::list btr_defragment_wq_t; static btr_defragment_wq_t btr_defragment_wq; diff --git a/storage/innobase/include/btr0defragment.h b/storage/innobase/include/btr0defragment.h index ed543477bcc..95a52258d07 100644 --- a/storage/innobase/include/btr0defragment.h +++ b/storage/innobase/include/btr0defragment.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (C) 2013, 2014 Facebook, Inc. All Rights Reserved. -Copyright (C) 2014, 2017, MariaDB Corporation. +Copyright (C) 2014, 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 @@ -30,21 +30,6 @@ extern Atomic_counter btr_defragment_compression_failures; extern Atomic_counter btr_defragment_failures; extern Atomic_counter btr_defragment_count; -/** Item in the work queue for btr_degrament_thread. */ -struct btr_defragment_item_t -{ - btr_pcur_t* pcur; /* persistent cursor where - btr_defragment_n_pages should start */ - os_event_t event; /* if not null, signal after work - is done */ - bool removed; /* Mark an item as removed */ - ulonglong last_processed; /* timestamp of last time this index - is processed by defragment thread */ - - btr_defragment_item_t(btr_pcur_t* pcur, os_event_t event); - ~btr_defragment_item_t(); -}; - /******************************************************************//** Initialize defragmentation. */ void diff --git a/storage/innobase/include/dict0defrag_bg.h b/storage/innobase/include/dict0defrag_bg.h index ae017932b9f..3aea41b0bb8 100644 --- a/storage/innobase/include/dict0defrag_bg.h +++ b/storage/innobase/include/dict0defrag_bg.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2016, 2018, MariaDB Corporation. +Copyright (c) 2016, 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 @@ -27,8 +27,6 @@ Created 25/08/2016 Jan Lindström #ifndef dict0defrag_bg_h #define dict0defrag_bg_h -#include "os0event.h" -#include "os0thread.h" #include "dict0types.h" /** Indices whose defrag stats need to be saved to persistent storage.*/ diff --git a/storage/innobase/include/dict0stats_bg.h b/storage/innobase/include/dict0stats_bg.h index 62746e31021..b210a2ec357 100644 --- a/storage/innobase/include/dict0stats_bg.h +++ b/storage/innobase/include/dict0stats_bg.h @@ -28,10 +28,8 @@ Created Apr 26, 2012 Vasil Dimov #define dict0stats_bg_h #include "dict0types.h" -#include "os0event.h" #include "os0thread.h" - #ifdef HAVE_PSI_INTERFACE extern mysql_pfs_key_t dict_stats_recalc_pool_mutex_key; #endif /* HAVE_PSI_INTERFACE */ diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 57542b32719..5da89937b78 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -42,7 +42,6 @@ Created 10/10/1995 Heikki Tuuri #pragma once #include "log0log.h" -#include "os0event.h" #include "que0types.h" #include "trx0types.h" #include "fil0fil.h" From ef254efc659326b4e62529bcf6fa41352b8973dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sun, 27 Sep 2020 13:24:09 +0300 Subject: [PATCH 051/323] Cleanup: Simplify sync_array_object_signalled() --- storage/innobase/include/sync0arr.h | 9 ++++----- storage/innobase/sync/sync0arr.cc | 11 +---------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/storage/innobase/include/sync0arr.h b/storage/innobase/include/sync0arr.h index e4186b74370..f9f923f9939 100644 --- a/storage/innobase/include/sync0arr.h +++ b/storage/innobase/include/sync0arr.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2018, MariaDB Corporation. +Copyright (c) 2015, 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 @@ -79,10 +79,9 @@ sync_array_free_cell( sync_array_t* arr, /*!< in: wait array */ sync_cell_t*& cell); /*!< in: the reserved cell */ -/**********************************************************************//** -Note that one of the wait objects was signalled. */ -void -sync_array_object_signalled(); +/** count of how many times an object has been signalled */ +extern ulint sg_count; +#define sync_array_object_signalled() ++sg_count /**********************************************************************//** Prints warnings of long semaphore waits to stderr. diff --git a/storage/innobase/sync/sync0arr.cc b/storage/innobase/sync/sync0arr.cc index 1e8ef62b429..4b6f818000c 100644 --- a/storage/innobase/sync/sync0arr.cc +++ b/storage/innobase/sync/sync0arr.cc @@ -169,7 +169,7 @@ mutexes and read-write locks */ sync_array_t** sync_wait_array; /** count of how many times an object has been signalled */ -static ulint sg_count; +ulint sg_count; #define sync_array_exit(a) mutex_exit(&(a)->mutex) #define sync_array_enter(a) mutex_enter(&(a)->mutex) @@ -859,15 +859,6 @@ sync_array_detect_deadlock( } #endif /* UNIV_DEBUG */ -/**********************************************************************//** -Increments the signalled count. */ -void -sync_array_object_signalled() -/*=========================*/ -{ - ++sg_count; -} - /**********************************************************************//** Prints warnings of long semaphore waits to stderr. @return TRUE if fatal semaphore wait threshold was exceeded */ From 8bc4ebed67b8d177f92645e1900903ea9a5ac7d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 Sep 2020 13:48:20 +0300 Subject: [PATCH 052/323] MDEV-21534 fixup: Remove traces of removed log_sys.write_mutex This was missed in commit 30ea63b7d2077883713e63cbf4e661ba0345bf68. --- storage/innobase/handler/ha_innodb.cc | 1 - storage/innobase/include/log0log.h | 2 +- storage/innobase/include/srv0srv.h | 3 +-- storage/innobase/include/sync0sync.h | 1 - storage/innobase/include/sync0types.h | 2 -- storage/innobase/sync/sync0debug.cc | 4 ---- storage/innobase/sync/sync0sync.cc | 1 - 7 files changed, 2 insertions(+), 12 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c891743991d..bfdabd802ca 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -524,7 +524,6 @@ static PSI_mutex_info all_innodb_mutexes[] = { PSI_KEY(ibuf_mutex), PSI_KEY(ibuf_pessimistic_insert_mutex), PSI_KEY(log_sys_mutex), - PSI_KEY(log_sys_write_mutex), PSI_KEY(mutex_list_mutex), PSI_KEY(page_zip_stat_per_index_mutex), PSI_KEY(purge_sys_pq_mutex), diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index 9eae5369d48..c80537f809b 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -547,7 +547,7 @@ public: byte *flush_buf; /** recommended maximum size of buf, after which the buffer is flushed */ size_t max_buf_free; - /** Log file stuff. Protected by mutex or write_mutex. */ + /** Log file stuff. Protected by mutex. */ struct file { /** format of the redo log: e.g., FORMAT_10_5 */ uint32_t format; diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 5da89937b78..5233ddad851 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -74,8 +74,7 @@ struct srv_stats_t /** Amount of data written to the log files in bytes */ lsn_ctr_1_t os_log_written; - /** Number of writes being done to the log files. - Protected by log_sys.write_mutex. */ + /** Number of writes being done to the log files */ ulint_ctr_1_t os_log_pending_writes; /** We increase this counter, when we don't have enough diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index 062d7c8a2dc..ff0671b1fea 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -65,7 +65,6 @@ extern mysql_pfs_key_t ibuf_bitmap_mutex_key; extern mysql_pfs_key_t ibuf_mutex_key; extern mysql_pfs_key_t ibuf_pessimistic_insert_mutex_key; extern mysql_pfs_key_t log_sys_mutex_key; -extern mysql_pfs_key_t log_sys_write_mutex_key; extern mysql_pfs_key_t log_cmdq_mutex_key; extern mysql_pfs_key_t log_flush_order_mutex_key; extern mysql_pfs_key_t mutex_list_mutex_key; diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h index a4584937e70..9c9ab72e32d 100644 --- a/storage/innobase/include/sync0types.h +++ b/storage/innobase/include/sync0types.h @@ -212,7 +212,6 @@ enum latch_level_t { SYNC_RECV, SYNC_LOG_FLUSH_ORDER, SYNC_LOG, - SYNC_LOG_WRITE, SYNC_PAGE_CLEANER, SYNC_PURGE_QUEUE, SYNC_TRX_SYS_HEADER, @@ -297,7 +296,6 @@ enum latch_id_t { LATCH_ID_IBUF, LATCH_ID_IBUF_PESSIMISTIC_INSERT, LATCH_ID_LOG_SYS, - LATCH_ID_LOG_WRITE, LATCH_ID_LOG_FLUSH_ORDER, LATCH_ID_LIST, LATCH_ID_MUTEX_LIST, diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc index 9297819a35b..edab86e9ef1 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -469,7 +469,6 @@ LatchDebug::LatchDebug() LEVEL_MAP_INSERT(SYNC_RECV); LEVEL_MAP_INSERT(SYNC_LOG_FLUSH_ORDER); LEVEL_MAP_INSERT(SYNC_LOG); - LEVEL_MAP_INSERT(SYNC_LOG_WRITE); LEVEL_MAP_INSERT(SYNC_PAGE_CLEANER); LEVEL_MAP_INSERT(SYNC_PURGE_QUEUE); LEVEL_MAP_INSERT(SYNC_TRX_SYS_HEADER); @@ -750,7 +749,6 @@ LatchDebug::check_order( case SYNC_FTS_CACHE_INIT: case SYNC_PAGE_CLEANER: case SYNC_LOG: - case SYNC_LOG_WRITE: case SYNC_LOG_FLUSH_ORDER: case SYNC_DOUBLEWRITE: case SYNC_SEARCH_SYS: @@ -1292,8 +1290,6 @@ sync_latch_meta_init() LATCH_ADD_MUTEX(LOG_SYS, SYNC_LOG, log_sys_mutex_key); - LATCH_ADD_MUTEX(LOG_WRITE, SYNC_LOG_WRITE, log_sys_write_mutex_key); - LATCH_ADD_MUTEX(LOG_FLUSH_ORDER, SYNC_LOG_FLUSH_ORDER, log_flush_order_mutex_key); diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc index 4894b625db8..56469b585e9 100644 --- a/storage/innobase/sync/sync0sync.cc +++ b/storage/innobase/sync/sync0sync.cc @@ -51,7 +51,6 @@ mysql_pfs_key_t ibuf_bitmap_mutex_key; mysql_pfs_key_t ibuf_mutex_key; mysql_pfs_key_t ibuf_pessimistic_insert_mutex_key; mysql_pfs_key_t log_sys_mutex_key; -mysql_pfs_key_t log_sys_write_mutex_key; mysql_pfs_key_t log_cmdq_mutex_key; mysql_pfs_key_t log_flush_order_mutex_key; mysql_pfs_key_t mutex_list_mutex_key; From c7399db64508a55bb3d486c789e7386899d88fbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 28 Sep 2020 12:23:48 +0300 Subject: [PATCH 053/323] MDEV-21174 fixup: Remove buf_dblwr_being_created --- storage/innobase/buf/buf0dblwr.cc | 6 ------ storage/innobase/include/buf0dblwr.h | 2 -- 2 files changed, 8 deletions(-) diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index 4b2822bf865..4a583bf7a9a 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -39,9 +39,6 @@ using st_::span; /** The doublewrite buffer */ buf_dblwr_t* buf_dblwr = NULL; -/** Set to TRUE when the doublewrite buffer is being created */ -ibool buf_dblwr_being_created = FALSE; - #define TRX_SYS_DOUBLEWRITE_BLOCKS 2 /****************************************************************//** @@ -144,7 +141,6 @@ buf_dblwr_create() start_again: mtr.start(); - buf_dblwr_being_created = TRUE; buf_block_t *trx_sys_block = buf_dblwr_trx_sys_get(&mtr); @@ -157,7 +153,6 @@ start_again: buf_dblwr_init(TRX_SYS_DOUBLEWRITE + trx_sys_block->frame); mtr.commit(); - buf_dblwr_being_created = FALSE; return(true); } else { if (UT_LIST_GET_FIRST(fil_system.sys_space->chain)->size @@ -307,7 +302,6 @@ too_small: /* Flush the modified pages to disk and make a checkpoint */ log_make_checkpoint(); - buf_dblwr_being_created = FALSE; /* Remove doublewrite pages from LRU */ buf_pool_invalidate(); diff --git a/storage/innobase/include/buf0dblwr.h b/storage/innobase/include/buf0dblwr.h index fca2c61124e..fed64e0ee72 100644 --- a/storage/innobase/include/buf0dblwr.h +++ b/storage/innobase/include/buf0dblwr.h @@ -34,8 +34,6 @@ Created 2011/12/19 Inaam Rana /** Doublewrite system */ extern buf_dblwr_t* buf_dblwr; -/** Set to TRUE when the doublewrite buffer is being created */ -extern ibool buf_dblwr_being_created; /** Create the doublewrite buffer if the doublewrite buffer header is not present in the TRX_SYS page. From a9550c47e4e32f2df8816477e362315608194443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 Sep 2020 14:28:11 +0300 Subject: [PATCH 054/323] MDEV-16264 fixup: Remove unused code and data LATCH_ID_OS_AIO_READ_MUTEX, LATCH_ID_OS_AIO_WRITE_MUTEX, LATCH_ID_OS_AIO_LOG_MUTEX, LATCH_ID_OS_AIO_IBUF_MUTEX, LATCH_ID_OS_AIO_SYNC_MUTEX: Remove. The tpool is not instrumented. lock_set_timeout_event(): Remove. srv_sys_mutex_key, srv_sys_t::mutex, SYNC_THREADS: Remove. srv_slot_t::suspended: Remove. We only ever assigned this data member true, so it is redundant. ib_wqueue_wait(), ib_wqueue_timedwait(): Remove. os_thread_join(): Remove. os_thread_create(), os_thread_exit(): Remove redundant parameters. These were missed in commit 5e62b6a5e06eb02cbde1e34e95e26f42d87fce02. --- extra/mariabackup/backup_copy.cc | 2 +- extra/mariabackup/backup_mysql.cc | 3 +- extra/mariabackup/xtrabackup.cc | 16 ++---- storage/innobase/buf/buf0flu.cc | 2 +- storage/innobase/fil/fil0crypt.cc | 5 +- storage/innobase/handler/ha_innodb.cc | 1 - storage/innobase/include/lock0lock.h | 5 -- storage/innobase/include/os0thread.h | 32 ++--------- storage/innobase/include/srv0srv.h | 3 - storage/innobase/include/sync0sync.h | 1 - storage/innobase/include/sync0types.h | 6 -- storage/innobase/include/ut0wqueue.h | 19 +------ storage/innobase/lock/lock0wait.cc | 5 +- storage/innobase/log/log0recv.cc | 2 +- storage/innobase/os/os0thread.cc | 48 ++-------------- storage/innobase/srv/srv0srv.cc | 16 ------ storage/innobase/srv/srv0start.cc | 2 +- storage/innobase/sync/sync0debug.cc | 19 ------- storage/innobase/sync/sync0sync.cc | 1 - storage/innobase/ut/ut0wqueue.cc | 82 +-------------------------- 20 files changed, 24 insertions(+), 246 deletions(-) diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index ef2e59ab379..cfc6557e011 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -956,7 +956,7 @@ run_data_threads(datadir_iter_t *it, os_thread_func_t func, uint n) data_threads[i].n_thread = i + 1; data_threads[i].count = &count; data_threads[i].count_mutex = &count_mutex; - os_thread_create(func, data_threads + i, &data_threads[i].id); + data_threads[i].id = os_thread_create(func, data_threads + i); } /* Wait for threads to exit */ diff --git a/extra/mariabackup/backup_mysql.cc b/extra/mariabackup/backup_mysql.cc index 83e877ea9bb..28aed958c73 100644 --- a/extra/mariabackup/backup_mysql.cc +++ b/extra/mariabackup/backup_mysql.cc @@ -75,7 +75,6 @@ bool have_multi_threaded_slave = false; bool have_gtid_slave = false; /* Kill long selects */ -os_thread_id_t kill_query_thread_id; os_event_t kill_query_thread_started; os_event_t kill_query_thread_stopped; os_event_t kill_query_thread_stop; @@ -856,7 +855,7 @@ start_query_killer() kill_query_thread_started = os_event_create(0); kill_query_thread_stopped = os_event_create(0); - os_thread_create(kill_query_thread, NULL, &kill_query_thread_id); + os_thread_create(kill_query_thread); os_event_wait(kill_query_thread_started); } diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index b20909583af..7fd5efe2cd5 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -503,7 +503,7 @@ static os_event_t dbug_start_query_thread( par->expect_errno = expected_errno; par->done_event = os_event_create(0); par->con = xb_mysql_connect(); - os_thread_create(dbug_execute_in_new_connection, par, 0); + os_thread_create(dbug_execute_in_new_connection, par); if (!wait_state) return par->done_event; @@ -4060,9 +4060,6 @@ fail: /* definition from recv_recovery_from_checkpoint_start() */ ulint max_cp_field; - /* start back ground thread to copy newer log */ - os_thread_id_t log_copying_thread_id; - /* get current checkpoint_lsn */ /* Look for the latest checkpoint from any of the log groups */ @@ -4152,14 +4149,11 @@ reread_log_header: log_copying_running = true; /* start io throttle */ if(xtrabackup_throttle) { - os_thread_id_t io_watching_thread_id; - io_ticket = xtrabackup_throttle; wait_throttle = os_event_create(0); io_watching_thread_running = true; - os_thread_create(io_watching_thread, NULL, - &io_watching_thread_id); + os_thread_create(io_watching_thread); } /* Populate fil_system with tablespaces to copy */ @@ -4182,7 +4176,7 @@ fail_before_log_copying_thread_start: DBUG_MARIABACKUP_EVENT("before_innodb_log_copy_thread_started",0); log_copying_stop = os_event_create(0); - os_thread_create(log_copying_thread, NULL, &log_copying_thread_id); + os_thread_create(log_copying_thread); /* FLUSH CHANGED_PAGE_BITMAPS call */ if (!flush_changed_page_bitmaps()) { @@ -4224,8 +4218,8 @@ fail_before_log_copying_thread_start: data_threads[i].num = i+1; data_threads[i].count = &count; data_threads[i].count_mutex = &count_mutex; - os_thread_create(data_copy_thread_func, data_threads + i, - &data_threads[i].id); + data_threads[i].id = os_thread_create(data_copy_thread_func, + data_threads + i); } /* Wait for threads to exit */ diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 8f7e2b04782..de493e62bd5 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -2872,7 +2872,7 @@ void buf_flush_page_cleaner_init() page_cleaner.is_running = true; buf_page_cleaner_is_active = true; - os_thread_create(buf_flush_page_cleaner, NULL, NULL); + os_thread_create(buf_flush_page_cleaner); } /** Synchronously flush dirty blocks. diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 7cd939fcc54..5d5bf9967d2 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -2219,11 +2219,10 @@ fil_crypt_set_thread_cnt( uint add = new_cnt - srv_n_fil_crypt_threads; srv_n_fil_crypt_threads = new_cnt; for (uint i = 0; i < add; i++) { - os_thread_id_t rotation_thread_id; - os_thread_create(fil_crypt_thread, NULL, &rotation_thread_id); ib::info() << "Creating #" << i+1 << " encryption thread id " - << os_thread_pf(rotation_thread_id) + << os_thread_pf( + os_thread_create(fil_crypt_thread)) << " total threads " << new_cnt << "."; } } else if (new_cnt < srv_n_fil_crypt_threads) { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index bfdabd802ca..3eb39a22a92 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -542,7 +542,6 @@ static PSI_mutex_info all_innodb_mutexes[] = { PSI_KEY(buf_dblwr_mutex), PSI_KEY(trx_pool_mutex), PSI_KEY(trx_pool_manager_mutex), - PSI_KEY(srv_sys_mutex), PSI_KEY(lock_mutex), PSI_KEY(lock_wait_mutex), PSI_KEY(trx_mutex), diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index dd25c52101f..3b63b06a9bb 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -670,11 +670,6 @@ lock_trx_lock_list_init( /*====================*/ trx_lock_list_t* lock_list); /*!< List to initialise */ -/*******************************************************************//** -Set the lock system timeout event. */ -void -lock_set_timeout_event(); -/*====================*/ /*********************************************************************//** Checks that a transaction id is sensible, i.e., not in the future. @return true if ok */ diff --git a/storage/innobase/include/os0thread.h b/storage/innobase/include/os0thread.h index 67ee3097274..fe351732bc7 100644 --- a/storage/innobase/include/os0thread.h +++ b/storage/innobase/include/os0thread.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 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 @@ -46,10 +46,6 @@ typedef LPTHREAD_START_ROUTINE os_thread_func_t; /** Macro for specifying a Windows thread start function. */ #define DECLARE_THREAD(func) WINAPI func - -#define os_thread_create(f,a,i) \ - os_thread_create_func(f, a, i) - #else typedef pthread_t os_thread_t; @@ -60,8 +56,6 @@ extern "C" { typedef void* (*os_thread_func_t)(void*); } /** Macro for specifying a POSIX thread start function. */ #define DECLARE_THREAD(func) func -#define os_thread_create(f,a,i) os_thread_create_func(f, a, i) - #endif /* _WIN32 */ /* Define a function pointer type to use in a typecast */ @@ -98,28 +92,10 @@ NOTE: We count the number of threads in os_thread_exit(). A created thread should always use that to exit so thatthe thread count will be decremented. We do not return an error code because if there is one, we crash here. */ -os_thread_t -os_thread_create_func( -/*==================*/ - os_thread_func_t func, /*!< in: pointer to function - from which to start */ - void* arg, /*!< in: argument to start - function */ - os_thread_id_t* thread_id); /*!< out: id of the created - thread, or NULL */ +os_thread_t os_thread_create(os_thread_func_t func, void *arg= nullptr); -/** Waits until the specified thread completes and joins it. -Its return value is ignored. -@param[in,out] thread thread to join */ -void -os_thread_join( - os_thread_id_t thread); - -/** Exits the current thread. -@param[in] detach if true, the thread will be detached right before -exiting. If false, another thread is responsible for joining this thread */ -ATTRIBUTE_NORETURN ATTRIBUTE_COLD -void os_thread_exit(bool detach = true); +/** Detach and terminate the current thread. */ +ATTRIBUTE_NORETURN void os_thread_exit(); /*****************************************************************//** Returns the thread identifier of current thread. diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 5233ddad851..4d3da8185b5 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -893,9 +893,6 @@ struct export_var_t{ struct srv_slot_t{ ibool in_use; /*!< TRUE if this slot is in use */ - ibool suspended; /*!< TRUE if the thread is - waiting for the event of this - slot */ /** time(NULL) when the thread was suspended. FIXME: Use my_interval_timer() or similar, to avoid bogus timeouts in lock_wait_check_and_cancel() or lock_wait_suspend_thread() diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index ff0671b1fea..c7cda1beb88 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -94,7 +94,6 @@ extern mysql_pfs_key_t trx_pool_manager_mutex_key; extern mysql_pfs_key_t lock_mutex_key; extern mysql_pfs_key_t lock_wait_mutex_key; extern mysql_pfs_key_t trx_sys_mutex_key; -extern mysql_pfs_key_t srv_sys_mutex_key; extern mysql_pfs_key_t srv_threads_mutex_key; extern mysql_pfs_key_t event_mutex_key; extern mysql_pfs_key_t event_manager_mutex_key; diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h index 9c9ab72e32d..8abce822eac 100644 --- a/storage/innobase/include/sync0types.h +++ b/storage/innobase/include/sync0types.h @@ -216,7 +216,6 @@ enum latch_level_t { SYNC_PURGE_QUEUE, SYNC_TRX_SYS_HEADER, SYNC_REC_LOCK, - SYNC_THREADS, SYNC_TRX, SYNC_RW_TRX_HASH_ELEMENT, SYNC_READ_VIEW, @@ -328,11 +327,6 @@ enum latch_id_t { LATCH_ID_EVENT_MANAGER, LATCH_ID_EVENT_MUTEX, LATCH_ID_SYNC_ARRAY_MUTEX, - LATCH_ID_OS_AIO_READ_MUTEX, - LATCH_ID_OS_AIO_WRITE_MUTEX, - LATCH_ID_OS_AIO_LOG_MUTEX, - LATCH_ID_OS_AIO_IBUF_MUTEX, - LATCH_ID_OS_AIO_SYNC_MUTEX, LATCH_ID_ROW_DROP_LIST, LATCH_ID_INDEX_ONLINE_LOG, LATCH_ID_WORK_QUEUE, diff --git a/storage/innobase/include/ut0wqueue.h b/storage/innobase/include/ut0wqueue.h index 5a895f4ea3c..c6d0de82b41 100644 --- a/storage/innobase/include/ut0wqueue.h +++ b/storage/innobase/include/ut0wqueue.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2006, 2014, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2017, 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 @@ -79,23 +79,6 @@ ib_wqueue_add(ib_wqueue_t* wq, void* item, mem_heap_t* heap, @return whether the queue is empty */ bool ib_wqueue_is_empty(ib_wqueue_t* wq); -/****************************************************************//** -Wait for a work item to appear in the queue. -@return work item */ -void* -ib_wqueue_wait( -/*===========*/ - ib_wqueue_t* wq); /*!< in: work queue */ - -/******************************************************************** -Wait for a work item to appear in the queue for specified time. */ -void* -ib_wqueue_timedwait( -/*================*/ - /* out: work item or NULL on timeout*/ - ib_wqueue_t* wq, /* in: work queue */ - ulint wait_in_usecs); /* in: wait time in micro seconds */ - /******************************************************************** Return first item on work queue or NULL if queue is empty @return work item or NULL */ diff --git a/storage/innobase/lock/lock0wait.cc b/storage/innobase/lock/lock0wait.cc index 7278e0f353d..b606228b1fe 100644 --- a/storage/innobase/lock/lock0wait.cc +++ b/storage/innobase/lock/lock0wait.cc @@ -53,10 +53,9 @@ lock_wait_table_print(void) fprintf(stderr, "Slot %lu:" - " in use %lu, susp %lu, timeout %lu, time %lu\n", + " in use %lu, timeout %lu, time %lu\n", (ulong) i, (ulong) slot->in_use, - (ulong) slot->suspended, slot->wait_timeout, (ulong) difftime(time(NULL), slot->suspend_time)); } @@ -154,7 +153,6 @@ lock_wait_table_reserve_slot( } os_event_reset(slot->event); - slot->suspended = TRUE; slot->suspend_time = time(NULL); slot->wait_timeout = wait_timeout; @@ -443,7 +441,6 @@ lock_wait_check_and_cancel( { ut_ad(lock_wait_mutex_own()); ut_ad(slot->in_use); - ut_ad(slot->suspended); double wait_time = difftime(time(NULL), slot->suspend_time); trx_t* trx = thr_get_trx(slot->thr); diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 2cb798b61fc..befab264454 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -3577,7 +3577,7 @@ completed: /* Spawn the background thread to flush dirty pages from the buffer pools. */ recv_writer_thread_active = true; - os_thread_create(recv_writer_thread, 0, 0); + os_thread_create(recv_writer_thread); if (rescan) { contiguous_lsn = checkpoint_lsn; diff --git a/storage/innobase/os/os0thread.cc b/storage/innobase/os/os0thread.cc index bb5da7df7c4..9417a49c6a0 100644 --- a/storage/innobase/os/os0thread.cc +++ b/storage/innobase/os/os0thread.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 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 @@ -89,15 +89,7 @@ NOTE: We count the number of threads in os_thread_exit(). A created thread should always use that to exit so thatthe thread count will be decremented. We do not return an error code because if there is one, we crash here. */ -os_thread_t -os_thread_create_func( -/*==================*/ - os_thread_func_t func, /*!< in: pointer to function - from which to start */ - void* arg, /*!< in: argument to start - function */ - os_thread_id_t* thread_id) /*!< out: id of the created - thread, or NULL */ +os_thread_t os_thread_create(os_thread_func_t func, void *arg) { os_thread_id_t new_thread_id; @@ -145,39 +137,11 @@ os_thread_create_func( ut_a(os_thread_count <= srv_max_n_threads); - /* Return the thread_id if the caller requests it. */ - if (thread_id != NULL) { - *thread_id = new_thread_id; - } return((os_thread_t)new_thread_id); } -/** Waits until the specified thread completes and joins it. -Its return value is ignored. -@param[in,out] thread thread to join */ -void -os_thread_join( - os_thread_id_t thread) -{ -#ifdef _WIN32 - /* Do nothing. */ -#else -#ifdef UNIV_DEBUG - const int ret = -#endif /* UNIV_DEBUG */ - pthread_join(thread, NULL); - - /* Waiting on already-quit threads is allowed. */ - ut_ad(ret == 0 || ret == ESRCH); -#endif /* _WIN32 */ -} - -/** Exits the current thread. -@param[in] detach if true, the thread will be detached right before -exiting. If false, another thread is responsible for joining this thread */ -ATTRIBUTE_NORETURN -void -os_thread_exit(bool detach) +/** Detach and terminate the current thread. */ +ATTRIBUTE_NORETURN void os_thread_exit() { #ifdef UNIV_DEBUG_THREAD_CREATION ib::info() << "Thread exits, id " @@ -193,9 +157,7 @@ os_thread_exit(bool detach) #ifdef _WIN32 ExitThread(0); #else - if (detach) { - pthread_detach(pthread_self()); - } + pthread_detach(pthread_self()); pthread_exit(NULL); #endif } diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 14ed15a81c9..a01f39cc5c3 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -459,16 +459,6 @@ UNIV_INTERN uint srv_simulate_comp_failures; /** Buffer pool dump status frequence in percentages */ UNIV_INTERN ulong srv_buf_dump_status_frequency; -/** Acquire the system_mutex. */ -#define srv_sys_mutex_enter() do { \ - mutex_enter(&srv_sys.mutex); \ -} while (0) - -/** Release the system mutex. */ -#define srv_sys_mutex_exit() do { \ - mutex_exit(&srv_sys.mutex); \ -} while (0) - /* IMPLEMENTATION OF THE SERVER MAIN PROGRAM ========================================= @@ -548,8 +538,6 @@ struct srv_sys_t{ UT_LIST_BASE_NODE_T(que_thr_t) tasks; /*!< task queue */ - ib_mutex_t mutex; /*!< variable protecting the - fields below. */ srv_stats_t::ulint_ctr_1_t activity_count; /*!< For tracking server activity */ @@ -727,8 +715,6 @@ static void srv_init() srv_thread_pool_init(); if (!srv_read_only_mode) { - mutex_create(LATCH_ID_SRV_SYS, &srv_sys.mutex); - mutex_create(LATCH_ID_SRV_SYS_TASKS, &srv_sys.tasks_mutex); @@ -778,7 +764,6 @@ srv_free(void) mutex_free(&page_zip_stat_per_index_mutex); if (!srv_read_only_mode) { - mutex_free(&srv_sys.mutex); mutex_free(&srv_sys.tasks_mutex); os_event_destroy(buf_flush_event); } @@ -1513,7 +1498,6 @@ void srv_wake_purge_thread_if_not_active() { ut_ad(!srv_read_only_mode); - ut_ad(!mutex_own(&srv_sys.mutex)); if (purge_sys.enabled() && !purge_sys.paused() && trx_sys.rseg_history_len) { diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 229f4879bf8..3481df9160b 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1893,7 +1893,7 @@ file_checked: /* Rollback incomplete non-DDL transactions */ trx_rollback_is_active = true; - os_thread_create(trx_rollback_all_recovered, 0, 0); + os_thread_create(trx_rollback_all_recovered); } } diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc index edab86e9ef1..0b8bbf16d61 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -473,7 +473,6 @@ LatchDebug::LatchDebug() LEVEL_MAP_INSERT(SYNC_PURGE_QUEUE); LEVEL_MAP_INSERT(SYNC_TRX_SYS_HEADER); LEVEL_MAP_INSERT(SYNC_REC_LOCK); - LEVEL_MAP_INSERT(SYNC_THREADS); LEVEL_MAP_INSERT(SYNC_TRX); LEVEL_MAP_INSERT(SYNC_RW_TRX_HASH_ELEMENT); LEVEL_MAP_INSERT(SYNC_READ_VIEW); @@ -752,7 +751,6 @@ LatchDebug::check_order( case SYNC_LOG_FLUSH_ORDER: case SYNC_DOUBLEWRITE: case SYNC_SEARCH_SYS: - case SYNC_THREADS: case SYNC_LOCK_SYS: case SYNC_LOCK_WAIT_SYS: case SYNC_RW_TRX_HASH_ELEMENT: @@ -1358,8 +1356,6 @@ sync_latch_meta_init() LATCH_ADD_MUTEX(TRX_SYS, SYNC_TRX_SYS, trx_sys_mutex_key); - LATCH_ADD_MUTEX(SRV_SYS, SYNC_THREADS, srv_sys_mutex_key); - LATCH_ADD_MUTEX(SRV_SYS_TASKS, SYNC_ANY_LATCH, srv_threads_mutex_key); LATCH_ADD_MUTEX(PAGE_ZIP_STAT_PER_INDEX, SYNC_ANY_LATCH, @@ -1378,21 +1374,6 @@ sync_latch_meta_init() LATCH_ADD_MUTEX(SYNC_ARRAY_MUTEX, SYNC_NO_ORDER_CHECK, sync_array_mutex_key); - LATCH_ADD_MUTEX(OS_AIO_READ_MUTEX, SYNC_NO_ORDER_CHECK, - PFS_NOT_INSTRUMENTED); - - LATCH_ADD_MUTEX(OS_AIO_WRITE_MUTEX, SYNC_NO_ORDER_CHECK, - PFS_NOT_INSTRUMENTED); - - LATCH_ADD_MUTEX(OS_AIO_LOG_MUTEX, SYNC_NO_ORDER_CHECK, - PFS_NOT_INSTRUMENTED); - - LATCH_ADD_MUTEX(OS_AIO_IBUF_MUTEX, SYNC_NO_ORDER_CHECK, - PFS_NOT_INSTRUMENTED); - - LATCH_ADD_MUTEX(OS_AIO_SYNC_MUTEX, SYNC_NO_ORDER_CHECK, - PFS_NOT_INSTRUMENTED); - LATCH_ADD_MUTEX(ROW_DROP_LIST, SYNC_NO_ORDER_CHECK, row_drop_list_mutex_key); diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc index 56469b585e9..cbec0cc4f6f 100644 --- a/storage/innobase/sync/sync0sync.cc +++ b/storage/innobase/sync/sync0sync.cc @@ -80,7 +80,6 @@ mysql_pfs_key_t trx_pool_manager_mutex_key; mysql_pfs_key_t lock_mutex_key; mysql_pfs_key_t lock_wait_mutex_key; mysql_pfs_key_t trx_sys_mutex_key; -mysql_pfs_key_t srv_sys_mutex_key; mysql_pfs_key_t srv_threads_mutex_key; mysql_pfs_key_t event_mutex_key; mysql_pfs_key_t event_manager_mutex_key; diff --git a/storage/innobase/ut/ut0wqueue.cc b/storage/innobase/ut/ut0wqueue.cc index ae97009430e..b56952f27d5 100644 --- a/storage/innobase/ut/ut0wqueue.cc +++ b/storage/innobase/ut/ut0wqueue.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2006, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2019, MariaDB Corporation. +Copyright (c) 2019, 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 @@ -83,86 +83,6 @@ ib_wqueue_add(ib_wqueue_t* wq, void* item, mem_heap_t* heap, bool wq_locked) } } -/****************************************************************//** -Wait for a work item to appear in the queue. -@return work item */ -void* -ib_wqueue_wait( -/*===========*/ - ib_wqueue_t* wq) /*!< in: work queue */ -{ - ib_list_node_t* node; - - for (;;) { - os_event_wait(wq->event); - - mutex_enter(&wq->mutex); - - node = ib_list_get_first(wq->items); - - if (node) { - ib_list_remove(wq->items, node); - - if (!ib_list_get_first(wq->items)) { - /* We must reset the event when the list - gets emptied. */ - os_event_reset(wq->event); - } - - break; - } - - mutex_exit(&wq->mutex); - } - - mutex_exit(&wq->mutex); - - return(node->data); -} - - -/******************************************************************** -Wait for a work item to appear in the queue for specified time. */ -void* -ib_wqueue_timedwait( -/*================*/ - /* out: work item or NULL on timeout*/ - ib_wqueue_t* wq, /* in: work queue */ - ulint wait_in_usecs) /* in: wait time in micro seconds */ -{ - ib_list_node_t* node = NULL; - - for (;;) { - ulint error; - int64_t sig_count; - - mutex_enter(&wq->mutex); - - node = ib_list_get_first(wq->items); - - if (node) { - ib_list_remove(wq->items, node); - - mutex_exit(&wq->mutex); - break; - } - - sig_count = os_event_reset(wq->event); - - mutex_exit(&wq->mutex); - - error = os_event_wait_time_low(wq->event, - (ulint) wait_in_usecs, - sig_count); - - if (error == OS_SYNC_TIME_EXCEEDED) { - break; - } - } - - return(node ? node->data : NULL); -} - /******************************************************************** Return first item on work queue or NULL if queue is empty @return work item or NULL */ From d6b33ea237c620923a7d4458a5907be0738c821d Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Wed, 30 Sep 2020 18:02:29 +0530 Subject: [PATCH 055/323] MDEV-23856 fts_optimize_wq accessed after shutdown of FTS Optimize thread In fts_optimize_remove_table(), InnoDB tries to access the fts_optimize_wq after shutting down the fts optimize thread. This issue caused by the commit a41d429765c7ddb528b9b438c68b25ff55d3bd55. Fix should check for fts optimize thread shutdown state before checking fts_optimize_wq. --- storage/innobase/fts/fts0opt.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index 39720b07bd1..8ad1cf4ebe1 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -2603,9 +2603,13 @@ fts_optimize_remove_table( os_event_destroy(event); - ut_d(mutex_enter(&fts_optimize_wq->mutex)); - ut_ad(!table->fts->in_queue); - ut_d(mutex_exit(&fts_optimize_wq->mutex)); +#ifdef UNIV_DEBUG + if (!fts_opt_start_shutdown) { + mutex_enter(&fts_optimize_wq->mutex); + ut_ad(!table->fts->in_queue); + mutex_exit(&fts_optimize_wq->mutex); + } +#endif /* UNIV_DEBUG */ } /** Send sync fts cache for the table. From 7a1923c3693332584921e5ca938537fdef4bb29c Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Wed, 30 Sep 2020 17:22:43 +0200 Subject: [PATCH 056/323] MDEV-23697: bin/env perl -i -> bin perl -i --- scripts/convert-debug-for-diff.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/convert-debug-for-diff.sh b/scripts/convert-debug-for-diff.sh index 60b328d946b..478d730d15a 100755 --- a/scripts/convert-debug-for-diff.sh +++ b/scripts/convert-debug-for-diff.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env perl -i +#!/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 #. From 904b811636ef62478db2d78fdd8c01080eaac0f9 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 1 Oct 2020 16:10:11 +1000 Subject: [PATCH 057/323] mtr: innodb_stats_dropped_locked cleanup As discovered in later test, this test doesn't remove the innodb_{index,table}_stats entries generated in the test upon completion. --- mysql-test/suite/innodb/r/innodb_stats_drop_locked.result | 2 ++ mysql-test/suite/innodb/t/innodb_stats_drop_locked.test | 2 ++ 2 files changed, 4 insertions(+) diff --git a/mysql-test/suite/innodb/r/innodb_stats_drop_locked.result b/mysql-test/suite/innodb/r/innodb_stats_drop_locked.result index 13cc45e0ef9..c8329156162 100644 --- a/mysql-test/suite/innodb/r/innodb_stats_drop_locked.result +++ b/mysql-test/suite/innodb/r/innodb_stats_drop_locked.result @@ -43,3 +43,5 @@ innodb_stats_drop_locked innodb_stats_drop_locked innodb_stats_drop_locked innodb_stats_drop_locked +DELETE FROM mysql.innodb_index_stats WHERE database_name='test' AND table_name='innodb_stats_drop_locked'; +DELETE FROM mysql.innodb_table_stats WHERE database_name='test' AND table_name='innodb_stats_drop_locked'; diff --git a/mysql-test/suite/innodb/t/innodb_stats_drop_locked.test b/mysql-test/suite/innodb/t/innodb_stats_drop_locked.test index 26367b8e6ae..07c77299451 100644 --- a/mysql-test/suite/innodb/t/innodb_stats_drop_locked.test +++ b/mysql-test/suite/innodb/t/innodb_stats_drop_locked.test @@ -56,6 +56,8 @@ WHERE table_name='innodb_stats_drop_locked'; SELECT table_name FROM mysql.innodb_index_stats WHERE table_name='innodb_stats_drop_locked'; +DELETE FROM mysql.innodb_index_stats WHERE database_name='test' AND table_name='innodb_stats_drop_locked'; +DELETE FROM mysql.innodb_table_stats WHERE database_name='test' AND table_name='innodb_stats_drop_locked'; --disable_query_log call mtr.add_suppression("Unable to delete statistics for table test.innodb_stats_drop_locked: Lock wait timeout. They can be deleted later using DELETE FROM mysql.innodb_index_stats WHERE database_name"); --enable_query_log From bd64c2e8cc610dc774411c5f0a8ab163fc685934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 1 Oct 2020 13:51:31 +0300 Subject: [PATCH 058/323] Cleanup: Remove unnecessary trx_i_s_cache_t::last_read_mutex We can simply use C++11 std::atomic for avoiding undefined behaviour related to concurrent stores to a shared variable. On most if not all ISAs, std::memory_order_relaxed loads and stores will not really differ from non-atomic loads or stores. --- storage/innobase/handler/ha_innodb.cc | 1 - storage/innobase/include/sync0sync.h | 1 - storage/innobase/include/sync0types.h | 3 --- storage/innobase/sync/sync0debug.cc | 5 ----- storage/innobase/sync/sync0sync.cc | 1 - storage/innobase/trx/trx0i_s.cc | 24 ++++-------------------- 6 files changed, 4 insertions(+), 31 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 05e1b2c59d9..7a30a60f059 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -588,7 +588,6 @@ static PSI_mutex_info all_innodb_mutexes[] = { # endif /* !PFS_SKIP_BUFFER_MUTEX_RWLOCK */ PSI_KEY(buf_pool_mutex), PSI_KEY(buf_pool_zip_mutex), - PSI_KEY(cache_last_read_mutex), PSI_KEY(dict_foreign_err_mutex), PSI_KEY(dict_sys_mutex), PSI_KEY(recalc_pool_mutex), diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index 037f5eda597..569b82f15dc 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -53,7 +53,6 @@ instrumentation due to their large number of instances. */ extern mysql_pfs_key_t buffer_block_mutex_key; extern mysql_pfs_key_t buf_pool_mutex_key; extern mysql_pfs_key_t buf_pool_zip_mutex_key; -extern mysql_pfs_key_t cache_last_read_mutex_key; extern mysql_pfs_key_t dict_foreign_err_mutex_key; extern mysql_pfs_key_t dict_sys_mutex_key; extern mysql_pfs_key_t fil_system_mutex_key; diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h index a6611f4464b..f41401bd751 100644 --- a/storage/innobase/include/sync0types.h +++ b/storage/innobase/include/sync0types.h @@ -258,8 +258,6 @@ enum latch_level_t { SYNC_DICT_OPERATION, - SYNC_TRX_I_S_LAST_READ, - SYNC_TRX_I_S_RWLOCK, SYNC_RECV_WRITER, @@ -284,7 +282,6 @@ enum latch_id_t { LATCH_ID_BUF_BLOCK_MUTEX, LATCH_ID_BUF_POOL, LATCH_ID_BUF_POOL_ZIP, - LATCH_ID_CACHE_LAST_READ, LATCH_ID_DICT_FOREIGN_ERR, LATCH_ID_DICT_SYS, LATCH_ID_FILE_FORMAT_MAX, diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc index 6da7ec93f25..b841b03562c 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -508,7 +508,6 @@ LatchDebug::LatchDebug() LEVEL_MAP_INSERT(SYNC_DICT); LEVEL_MAP_INSERT(SYNC_FTS_CACHE); LEVEL_MAP_INSERT(SYNC_DICT_OPERATION); - LEVEL_MAP_INSERT(SYNC_TRX_I_S_LAST_READ); LEVEL_MAP_INSERT(SYNC_TRX_I_S_RWLOCK); LEVEL_MAP_INSERT(SYNC_RECV_WRITER); LEVEL_MAP_INSERT(SYNC_LEVEL_VARYING); @@ -767,7 +766,6 @@ LatchDebug::check_order( case SYNC_DICT_OPERATION: case SYNC_DICT_HEADER: case SYNC_TRX_I_S_RWLOCK: - case SYNC_TRX_I_S_LAST_READ: case SYNC_IBUF_MUTEX: case SYNC_INDEX_ONLINE_LOG: case SYNC_STATS_AUTO_RECALC: @@ -1285,9 +1283,6 @@ sync_latch_meta_init() LATCH_ADD_MUTEX(BUF_POOL_ZIP, SYNC_BUF_BLOCK, buf_pool_zip_mutex_key); - LATCH_ADD_MUTEX(CACHE_LAST_READ, SYNC_TRX_I_S_LAST_READ, - cache_last_read_mutex_key); - LATCH_ADD_MUTEX(DICT_FOREIGN_ERR, SYNC_NO_ORDER_CHECK, dict_foreign_err_mutex_key); diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc index 01db84380a2..eb3c0a1a756 100644 --- a/storage/innobase/sync/sync0sync.cc +++ b/storage/innobase/sync/sync0sync.cc @@ -38,7 +38,6 @@ Created 9/5/1995 Heikki Tuuri mysql_pfs_key_t buffer_block_mutex_key; mysql_pfs_key_t buf_pool_mutex_key; mysql_pfs_key_t buf_pool_zip_mutex_key; -mysql_pfs_key_t cache_last_read_mutex_key; mysql_pfs_key_t dict_foreign_err_mutex_key; mysql_pfs_key_t dict_sys_mutex_key; mysql_pfs_key_t fil_system_mutex_key; diff --git a/storage/innobase/trx/trx0i_s.cc b/storage/innobase/trx/trx0i_s.cc index 54425ae934b..c7613b618a1 100644 --- a/storage/innobase/trx/trx0i_s.cc +++ b/storage/innobase/trx/trx0i_s.cc @@ -141,12 +141,9 @@ struct i_s_table_cache_t { struct trx_i_s_cache_t { rw_lock_t rw_lock; /*!< read-write lock protecting the rest of this structure */ - ulonglong last_read; /*!< last time the cache was read; + Atomic_relaxed last_read; + /*!< last time the cache was read; measured in nanoseconds */ - ib_mutex_t last_read_mutex;/*!< mutex protecting the - last_read member - it is updated - inside a shared lock of the - rw_lock member */ i_s_table_cache_t innodb_trx; /*!< innodb_trx table */ i_s_table_cache_t innodb_locks; /*!< innodb_locks table */ i_s_table_cache_t innodb_lock_waits;/*!< innodb_lock_waits table */ @@ -1190,8 +1187,7 @@ Checks if the cache can safely be updated. @return whether the cache can be updated */ static bool can_cache_be_updated(trx_i_s_cache_t* cache) { - /* Here we read cache->last_read without acquiring its mutex - because last_read is only updated when a shared rw lock on the + /* cache->last_read is only updated when a shared rw lock on the whole cache is being held (see trx_i_s_cache_end_read()) and we are currently holding an exclusive rw lock on the cache. So it is not possible for last_read to be updated while we are @@ -1329,8 +1325,6 @@ trx_i_s_cache_init( release lock mutex release trx_i_s_cache_t::rw_lock acquire trx_i_s_cache_t::rw_lock, S - acquire trx_i_s_cache_t::last_read_mutex - release trx_i_s_cache_t::last_read_mutex release trx_i_s_cache_t::rw_lock */ rw_lock_create(trx_i_s_cache_lock_key, &cache->rw_lock, @@ -1338,8 +1332,6 @@ trx_i_s_cache_init( cache->last_read = 0; - mutex_create(LATCH_ID_CACHE_LAST_READ, &cache->last_read_mutex); - table_cache_init(&cache->innodb_trx, sizeof(i_s_trx_row_t)); table_cache_init(&cache->innodb_locks, sizeof(i_s_locks_row_t)); table_cache_init(&cache->innodb_lock_waits, @@ -1363,7 +1355,6 @@ trx_i_s_cache_free( trx_i_s_cache_t* cache) /*!< in, own: cache to free */ { rw_lock_free(&cache->rw_lock); - mutex_free(&cache->last_read_mutex); hash_table_free(cache->locks_hash); ha_storage_free(cache->storage); @@ -1389,14 +1380,7 @@ trx_i_s_cache_end_read( /*===================*/ trx_i_s_cache_t* cache) /*!< in: cache */ { - ut_ad(rw_lock_own(&cache->rw_lock, RW_LOCK_S)); - - /* update cache last read time */ - const ulonglong now = my_interval_timer(); - mutex_enter(&cache->last_read_mutex); - cache->last_read = now; - mutex_exit(&cache->last_read_mutex); - + cache->last_read = my_interval_timer(); rw_lock_s_unlock(&cache->rw_lock); } From b15224c71ad4896c44678f44be549113d28df931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 1 Oct 2020 14:35:42 +0300 Subject: [PATCH 059/323] MDEV-16264 fixup: Remove unused declarations Remove stale references to srv_sys.sys_threads and srv_sys.mutex that were removed in commit 5e62b6a5e06eb02cbde1e34e95e26f42d87fce02. --- storage/innobase/include/srv0srv.h | 3 +-- storage/innobase/srv/srv0srv.cc | 13 +------------ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 4d3da8185b5..a6223946779 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -657,8 +657,7 @@ void srv_export_innodb_status(void); /*==========================*/ /*******************************************************************//** -Get current server activity count. We don't hold srv_sys::mutex while -reading this value as it is only used in heuristics. +Get current server activity count. @return activity count. */ ulint srv_get_activity_count(void); diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index a01f39cc5c3..144ea17ec0c 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -573,16 +573,6 @@ and/or load it during startup. */ char srv_buffer_pool_dump_at_shutdown = TRUE; char srv_buffer_pool_load_at_startup = TRUE; -/** Slot index in the srv_sys.sys_threads array for the master thread. */ -#define SRV_MASTER_SLOT 0 - -/** Slot index in the srv_sys.sys_threads array for the purge thread. */ -#define SRV_PURGE_SLOT 1 - -/** Slot index in the srv_sys.sys_threads array from which purge workers start. - */ -#define SRV_WORKER_SLOTS_START 2 - #ifdef HAVE_PSI_STAGE_INTERFACE /** Performance schema stage event for monitoring ALTER TABLE progress everything after flush log_make_checkpoint(). */ @@ -1568,8 +1558,7 @@ void purge_sys_t::resume() } /*******************************************************************//** -Get current server activity count. We don't hold srv_sys::mutex while -reading this value as it is only used in heuristics. +Get current server activity count. @return activity count. */ ulint srv_get_activity_count(void) From 99ab562a92c05896ffb54216602507c56ea4e101 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Thu, 1 Oct 2020 19:18:26 +0200 Subject: [PATCH 060/323] - Make possible to allocate work space larger than 4GB All variables handling sizes that were uint are now size_t. The variable connect_work_size is now ulong (was uint); Also make Json functiosn to allocate a larger memory (M=9 was 7) modified: storage/connect/global.h modified: storage/connect/ha_connect.cc modified: storage/connect/json.cpp modified: storage/connect/jsonudf.cpp modified: storage/connect/plgdbutl.cpp modified: storage/connect/plugutil.cpp modified: storage/connect/user_connect.cc - Fix uninitialised variable (pretty) in Json_File. Make Jbin_file accept the same arguments as Json_File ones. modified: storage/connect/jsonudf.cpp - Change the Level option to Depth (the word currently used) (Level being still accepted) modified: storage/connect/mongo.cpp modified: storage/connect/tabjson.cpp modified: storage/connect/tabxml.cpp - Suppress 2nd argument default value for MYSQLtoPLG function modified: storage/connect/myutil.h - Allow REST tables to be create not specifying a file_name modified: storage/connect/tabrest.cpp --- storage/connect/global.h | 20 +++++++------- storage/connect/ha_connect.cc | 21 +++++++++------ storage/connect/json.cpp | 2 +- storage/connect/jsonudf.cpp | 46 +++++++++++++++++++-------------- storage/connect/mongo.cpp | 2 +- storage/connect/myutil.h | 4 +-- storage/connect/plgdbutl.cpp | 20 +++++++------- storage/connect/plugutil.cpp | 24 ++++++++--------- storage/connect/tabjson.cpp | 4 +-- storage/connect/tabrest.cpp | 29 +++++++++++++++------ storage/connect/tabxml.cpp | 3 ++- storage/connect/user_connect.cc | 17 ++++++------ 12 files changed, 109 insertions(+), 83 deletions(-) diff --git a/storage/connect/global.h b/storage/connect/global.h index fd26c87b800..548d047ccc9 100644 --- a/storage/connect/global.h +++ b/storage/connect/global.h @@ -1,7 +1,7 @@ /***********************************************************************/ /* GLOBAL.H: Declaration file used by all CONNECT implementations. */ /* (C) Copyright MariaDB Corporation Ab */ -/* Author Olivier Bertrand 1993-2018 */ +/* Author Olivier Bertrand 1993-2020 */ /***********************************************************************/ /***********************************************************************/ @@ -112,8 +112,8 @@ extern "C" { /***********************************************************************/ #include "os.h" -typedef uint OFFSET; -typedef char NAME[9]; +typedef size_t OFFSET; +typedef char NAME[9]; typedef struct { ushort Length; @@ -136,7 +136,7 @@ typedef struct _parm *PPARM; /***********************************************************************/ typedef struct { /* Plug Area SubAlloc header */ OFFSET To_Free; /* Offset of next free block */ - uint FreeBlk; /* Size of remaining free memory */ + size_t FreeBlk; /* Size of remaining free memory */ } POOLHEADER, *PPOOLHEADER; /***********************************************************************/ @@ -188,7 +188,7 @@ typedef struct _parm { /***********************************************************************/ typedef struct _global { /* Global structure */ void *Sarea; /* Points to work area */ - uint Sarea_Size; /* Work area size */ + size_t Sarea_Size; /* Work area size */ PACTIVITY Activityp; char Message[MAX_STR]; ulong More; /* Used by jsonudf */ @@ -210,16 +210,16 @@ DllExport char *PlugReadMessage(PGLOBAL, int, char *); DllExport char *PlugGetMessage(PGLOBAL, int); #endif // XMSG || NEWMSG #if defined(__WIN__) -DllExport short GetLineLength(PGLOBAL); // Console line length +DllExport short GetLineLength(PGLOBAL); // Console line length #endif // __WIN__ -DllExport PGLOBAL PlugInit(LPCSTR, uint); // Plug global initialization -DllExport int PlugExit(PGLOBAL); // Plug global termination +DllExport PGLOBAL PlugInit(LPCSTR, size_t); // Plug global initialization +DllExport int PlugExit(PGLOBAL); // Plug global termination DllExport LPSTR PlugRemoveType(LPSTR, LPCSTR); DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR prefix, LPCSTR name, LPCSTR dir); DllExport BOOL PlugIsAbsolutePath(LPCSTR path); -DllExport bool AllocSarea(PGLOBAL, uint); +DllExport bool AllocSarea(PGLOBAL, size_t); DllExport void FreeSarea(PGLOBAL); -DllExport BOOL PlugSubSet(void *, uint); +DllExport BOOL PlugSubSet(void *, size_t); DllExport void *PlugSubAlloc(PGLOBAL, void *, size_t); DllExport char *PlugDup(PGLOBAL g, const char *str); DllExport void *MakePtr(void *, OFFSET); diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 7d53f287f74..e39b5cebaf4 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -170,7 +170,7 @@ #define JSONMAX 10 // JSON Default max grp size extern "C" { - char version[]= "Version 1.07.0001 November 12, 2019"; + char version[]= "Version 1.07.0001 September 30, 2020"; #if defined(__WIN__) char compver[]= "Version 1.07.0001 " __DATE__ " " __TIME__; char slash= '\\'; @@ -254,8 +254,8 @@ TYPCONV GetTypeConv(void); char *GetJsonNull(void); uint GetJsonGrpSize(void); char *GetJavaWrapper(void); -uint GetWorkSize(void); -void SetWorkSize(uint); +ulong GetWorkSize(void); +void SetWorkSize(ulong); extern "C" const char *msglang(void); static char *strz(PGLOBAL g, LEX_STRING &ls); @@ -348,10 +348,10 @@ static MYSQL_THDVAR_ENUM( &usetemp_typelib); // typelib // Size used for g->Sarea_Size -static MYSQL_THDVAR_UINT(work_size, +static MYSQL_THDVAR_ULONG(work_size, PLUGIN_VAR_RQCMDARG, "Size of the CONNECT work area.", - NULL, NULL, SZWORK, SZWMIN, UINT_MAX, 1); + NULL, NULL, SZWORK, SZWMIN, ULONG_MAX, 1); // Size used when converting TEXT columns to VARCHAR static MYSQL_THDVAR_INT(conv_size, @@ -461,8 +461,8 @@ char *GetJsonNull(void) {return connect_hton ? THDVAR(current_thd, json_null) : NULL;} uint GetJsonGrpSize(void) {return connect_hton ? THDVAR(current_thd, json_grp_size) : 10;} -uint GetWorkSize(void) {return THDVAR(current_thd, work_size);} -void SetWorkSize(uint) +ulong GetWorkSize(void) {return THDVAR(current_thd, work_size);} +void SetWorkSize(ulong) { // Changing the session variable value seems to be impossible here // and should be done in a check function @@ -5326,7 +5326,12 @@ static bool add_field(String *sql, const char *field_name, int typ, int len, int dec, char *key, uint tm, const char *rem, char *dft, char *xtra, char *fmt, int flag, bool dbf, char v) { - char var= (len > 255) ? 'V' : v; +#if defined(DEVELOPMENT) + // Some client programs regard CHAR(36) as GUID + char var= (len > 255 || len == 36) ? 'V' : v; +#else + char var = (len > 255) ? 'V' : v; +#endif bool q, error= false; const char *type= PLGtoMYSQLtype(typ, dbf, var); diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index 98a4659cea8..a38e6487025 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -425,7 +425,7 @@ char *ParseString(PGLOBAL g, int& i, STRG& src) int n = 0, len = src.len; // Be sure of memory availability - if (len + 1 - i > (signed)((PPOOLHEADER)g->Sarea)->FreeBlk) { + if ((unsigned)(len + 1 - i) > ((PPOOLHEADER)g->Sarea)->FreeBlk) { strcpy(g->Message, "ParseString: Out of memory"); return NULL; } // endif len diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp index dad86d51040..a1c6a77d1f2 100644 --- a/storage/connect/jsonudf.cpp +++ b/storage/connect/jsonudf.cpp @@ -25,7 +25,7 @@ #else #define PUSH_WARNING(M) htrc(M) #endif -#define M 7 +#define M 9 bool IsNum(PSZ s); char *NextChr(PSZ s, char sep); @@ -4423,13 +4423,15 @@ char *json_file(UDF_INIT *initid, UDF_ARGS *args, char *result, fn = MakePSZ(g, args, 0); if (args->arg_count > 1) { - int len, pretty, pty = 3; + int len, pretty = 3, pty = 3; PJSON jsp; PJVAL jvp = NULL; - pretty = (args->arg_type[1] == INT_RESULT) ? (int)*(longlong*)args->args[1] - : (args->arg_count > 2 && args->arg_type[2] == INT_RESULT) - ? (int)*(longlong*)args->args[2] : 3; + for (unsigned int i = 1; i < args->arg_count; i++) + if (args->arg_type[i] == INT_RESULT && *(longlong*)args->args[i] < 4) { + pretty = (int) * (longlong*)args->args[i]; + break; + } // endif type /*******************************************************************************/ /* Parse the json file and allocate its tree structure. */ @@ -5626,21 +5628,20 @@ my_bool jbin_file_init(UDF_INIT *initid, UDF_ARGS *args, char *message) } else if (args->arg_type[0] != STRING_RESULT || !args->args[0]) { strcpy(message, "First argument must be a constant string (file name)"); return true; - } else if (args->arg_count > 1 && args->arg_type[1] != STRING_RESULT) { - strcpy(message, "Second argument is not a string (path)"); - return true; - } else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) { - strcpy(message, "Third argument is not an integer (pretty)"); - return true; - } else if (args->arg_count > 3) { - if (args->arg_type[3] != INT_RESULT) { - strcpy(message, "Fourth argument is not an integer (memory)"); - return true; - } else - more += (ulong)*(longlong*)args->args[3]; - } // endifs + for (unsigned int i = 1; i < args->arg_count; i++) { + if (!(args->arg_type[i] == INT_RESULT || args->arg_type[i] == STRING_RESULT)) { + sprintf(message, "Argument %d is not an integer or a string (pretty or path)", i); + return true; + } // endif arg_type + + // Take care of eventual memory argument + if (args->arg_type[i] == INT_RESULT && args->args[i]) + more += (ulong) * (longlong*)args->args[i]; + + } // endfor i + initid->maybe_null = 1; CalcLen(args, false, reslen, memlen); fl = GetFileLength(args->args[0]); @@ -5654,7 +5655,7 @@ char *jbin_file(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *res_length, char *is_null, char *error) { char *fn; - int pretty, len = 0, pty = 3; + int pretty = 3, len = 0, pty = 3; PJSON jsp; PJVAL jvp = NULL; PGLOBAL g = (PGLOBAL)initid->ptr; @@ -5666,7 +5667,12 @@ char *jbin_file(UDF_INIT *initid, UDF_ARGS *args, char *result, PlugSubSet(g->Sarea, g->Sarea_Size); g->Xchk = NULL; fn = MakePSZ(g, args, 0); - pretty = (args->arg_count > 2 && args->args[2]) ? (int)*(longlong*)args->args[2] : 3; + + for (unsigned int i = 1; i < args->arg_count; i++) + if (args->arg_type[i] == INT_RESULT && *(longlong*)args->args[i] < 4) { + pretty = (int) * (longlong*)args->args[i]; + break; + } // endif type /*********************************************************************************/ /* Parse the json file and allocate its tree structure. */ diff --git a/storage/connect/mongo.cpp b/storage/connect/mongo.cpp index bd3d3b893c1..e821440a0c3 100644 --- a/storage/connect/mongo.cpp +++ b/storage/connect/mongo.cpp @@ -251,7 +251,7 @@ int MGODISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt) PCSZ level = GetStringTableOption(g, topt, "Level", NULL); PMGODEF tdp; - if (level) { + if (level = GetStringTableOption(g, topt, "Depth", level)) { lvl = atoi(level); lvl = (lvl > 16) ? 16 : lvl; } else diff --git a/storage/connect/myutil.h b/storage/connect/myutil.h index 6991172b39e..fa41fa47d61 100644 --- a/storage/connect/myutil.h +++ b/storage/connect/myutil.h @@ -6,8 +6,8 @@ enum enum_field_types PLGtoMYSQL(int type, bool dbf, char var = 0); const char *PLGtoMYSQLtype(int type, bool dbf, char var = 0); -int MYSQLtoPLG(char *typname, char *var = NULL); -int MYSQLtoPLG(int mytype, char *var = NULL); +int MYSQLtoPLG(char *typname, char *var); +int MYSQLtoPLG(int mytype, char *var); PCSZ MyDateFmt(int mytype); PCSZ MyDateFmt(char *typname); diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp index e296553d8e2..7bc7c5f592b 100644 --- a/storage/connect/plgdbutl.cpp +++ b/storage/connect/plgdbutl.cpp @@ -5,7 +5,7 @@ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 1998-2018 */ +/* (C) Copyright to the author Olivier BERTRAND 1998-2020 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -1242,7 +1242,7 @@ void *PlgDBalloc(PGLOBAL g, void *area, MBLOCK& mp) mp.Sub = mp.Size <= ((mp.Sub) ? maxsub : (maxsub >> 2)); if (trace(2)) - htrc("PlgDBalloc: in %p size=%d used=%d free=%d sub=%d\n", + htrc("PlgDBalloc: in %p size=%zd used=%zd free=%zd sub=%d\n", arp, mp.Size, pph->To_Free, pph->FreeBlk, mp.Sub); if (!mp.Sub) { @@ -1258,7 +1258,7 @@ void *PlgDBalloc(PGLOBAL g, void *area, MBLOCK& mp) mp.Memp = malloc(mp.Size); if (trace(8)) - htrc("PlgDBalloc: %s(%d) at %p\n", v, mp.Size, mp.Memp); + htrc("PlgDBalloc: %s(%zd) at %p\n", v, mp.Size, mp.Memp); if (!mp.Inlist && mp.Memp) { // New allocated block, put it in the memory block chain. @@ -1290,7 +1290,7 @@ void *PlgDBrealloc(PGLOBAL g, void *area, MBLOCK& mp, size_t newsize) #endif if (trace(2)) - htrc("PlgDBrealloc: %p size=%d sub=%d\n", mp.Memp, mp.Size, mp.Sub); + htrc("PlgDBrealloc: %p size=%zd sub=%d\n", mp.Memp, mp.Size, mp.Sub); if (newsize == mp.Size) return mp.Memp; // Nothing to do @@ -1340,7 +1340,7 @@ void *PlgDBrealloc(PGLOBAL g, void *area, MBLOCK& mp, size_t newsize) } // endif's if (trace(8)) - htrc(" newsize=%d newp=%p sub=%d\n", mp.Size, mp.Memp, mp.Sub); + htrc(" newsize=%zd newp=%p sub=%d\n", mp.Size, mp.Memp, mp.Sub); return mp.Memp; } // end of PlgDBrealloc @@ -1392,13 +1392,13 @@ void *PlgDBSubAlloc(PGLOBAL g, void *memp, size_t size) pph = (PPOOLHEADER)memp; if (trace(16)) - htrc("PlgDBSubAlloc: memp=%p size=%d used=%d free=%d\n", + htrc("PlgDBSubAlloc: memp=%p size=%zd used=%zd free=%zd\n", memp, size, pph->To_Free, pph->FreeBlk); - if ((uint)size > pph->FreeBlk) { /* Not enough memory left in pool */ + if (size > pph->FreeBlk) { /* Not enough memory left in pool */ sprintf(g->Message, - "Not enough memory in Work area for request of %d (used=%d free=%d)", - (int) size, pph->To_Free, pph->FreeBlk); + "Not enough memory in Work area for request of %zd (used=%zd free=%zd)", + size, pph->To_Free, pph->FreeBlk); if (trace(1)) htrc("%s\n", g->Message); @@ -1414,7 +1414,7 @@ void *PlgDBSubAlloc(PGLOBAL g, void *memp, size_t size) pph->FreeBlk -= size; // New size of pool free block if (trace(16)) - htrc("Done memp=%p used=%d free=%d\n", + htrc("Done memp=%p used=%zd free=%zd\n", memp, pph->To_Free, pph->FreeBlk); return (memp); diff --git a/storage/connect/plugutil.cpp b/storage/connect/plugutil.cpp index e74937b942a..2517b76cd3e 100644 --- a/storage/connect/plugutil.cpp +++ b/storage/connect/plugutil.cpp @@ -6,7 +6,7 @@ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 1993-2019 */ +/* (C) Copyright to the author Olivier BERTRAND 1993-2020 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -142,7 +142,7 @@ void htrc(char const* fmt, ...) /* Language points on initial language name and eventual path. */ /* Return value is the pointer to the Global structure. */ /***********************************************************************/ -PGLOBAL PlugInit(LPCSTR Language, uint worksize) +PGLOBAL PlugInit(LPCSTR Language, size_t worksize) { PGLOBAL g; @@ -459,7 +459,7 @@ short GetLineLength(PGLOBAL g) /***********************************************************************/ /* Program for memory allocation of work and language areas. */ /***********************************************************************/ -bool AllocSarea(PGLOBAL g, uint size) +bool AllocSarea(PGLOBAL g, size_t size) { /*********************************************************************/ /* This is the allocation routine for the WIN32/UNIX/AIX version. */ @@ -483,7 +483,7 @@ bool AllocSarea(PGLOBAL g, uint size) if (trace(8)) { #endif if (g->Sarea) - htrc("Work area of %u allocated at %p\n", size, g->Sarea); + htrc("Work area of %zd allocated at %p\n", size, g->Sarea); else htrc("SareaAlloc: %s\n", g->Message); @@ -510,7 +510,7 @@ void FreeSarea(PGLOBAL g) #else if (trace(8)) #endif - htrc("Freeing Sarea at %p size = %d\n", g->Sarea, g->Sarea_Size); + htrc("Freeing Sarea at %p size = %zd\n", g->Sarea, g->Sarea_Size); g->Sarea = NULL; g->Sarea_Size = 0; @@ -524,7 +524,7 @@ void FreeSarea(PGLOBAL g) /* Here there should be some verification done such as validity of */ /* the address and size not larger than memory size. */ /***********************************************************************/ -BOOL PlugSubSet(void *memp, uint size) +BOOL PlugSubSet(void *memp, size_t size) { PPOOLHEADER pph = (PPOOLHEADER)memp; @@ -560,15 +560,15 @@ void *PlugSubAlloc(PGLOBAL g, void *memp, size_t size) pph = (PPOOLHEADER)memp; if (trace(16)) - htrc("SubAlloc in %p size=%d used=%d free=%d\n", + htrc("SubAlloc in %p size=%zd used=%zd free=%zd\n", memp, size, pph->To_Free, pph->FreeBlk); - if ((uint)size > pph->FreeBlk) { /* Not enough memory left in pool */ + if (size > pph->FreeBlk) { /* Not enough memory left in pool */ PCSZ pname = "Work"; sprintf(g->Message, - "Not enough memory in %s area for request of %u (used=%d free=%d)", - pname, (uint)size, pph->To_Free, pph->FreeBlk); + "Not enough memory in %s area for request of %zd (used=%zd free=%zd)", + pname, size, pph->To_Free, pph->FreeBlk); if (trace(1)) htrc("PlugSubAlloc: %s\n", g->Message); @@ -581,10 +581,10 @@ void *PlugSubAlloc(PGLOBAL g, void *memp, size_t size) /*********************************************************************/ memp = MakePtr(memp, pph->To_Free); /* Points to suballocated block */ pph->To_Free += (OFFSET)size; /* New offset of pool free block */ - pph->FreeBlk -= (uint)size; /* New size of pool free block */ + pph->FreeBlk -= size; /* New size of pool free block */ if (trace(16)) - htrc("Done memp=%p used=%d free=%d\n", + htrc("Done memp=%p used=%zd free=%zd\n", memp, pph->To_Free, pph->FreeBlk); return (memp); diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index 3b0d458a7a6..08040884449 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -177,8 +177,8 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt) bool mgo = (GetTypeID(topt->type) == TAB_MONGO); PCSZ level = GetStringTableOption(g, topt, "Level", NULL); - if (level) { - lvl = atoi(level); + if (level = GetStringTableOption(g, topt, "Depth", level)) { + lvl = atoi(level); lvl = (lvl > 16) ? 16 : lvl; } else lvl = 0; diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp index 9c6b724973f..b1bdeffc880 100644 --- a/storage/connect/tabrest.cpp +++ b/storage/connect/tabrest.cpp @@ -158,17 +158,32 @@ PQRYRES __stdcall ColREST(PGLOBAL g, PTOS tp, char *tab, char *db, bool info) http = GetStringTableOption(g, tp, "Http", NULL); uri = GetStringTableOption(g, tp, "Uri", NULL); - fn = GetStringTableOption(g, tp, "Filename", "rest.json"); #if defined(MARIADB) ftype = GetStringTableOption(g, tp, "Type", "JSON"); #else // !MARIADB // OEM tables must specify the file type ftype = GetStringTableOption(g, tp, "Ftype", "JSON"); #endif // !MARIADB + fn = GetStringTableOption(g, tp, "Filename", NULL); + + if (!fn) { + int n, m = strlen(ftype) + 1; + + strcat(strcpy(filename, tab), "."); + n = strlen(filename); + + // Fold ftype to lower case + for (int i = 0; i < m; i++) + filename[n + i] = tolower(ftype[i]); + + fn = filename; + tp->filename = PlugDup(g, fn); + } // endif fn // We used the file name relative to recorded datapath - strcat(strcat(strcat(strcpy(filename, "."), slash), db), slash); - strncat(filename, fn, _MAX_PATH - strlen(filename)); + PlugSetPath(filename, fn, db); + //strcat(strcat(strcat(strcpy(filename, "."), slash), db), slash); + //strncat(filename, fn, _MAX_PATH - strlen(filename)); // Retrieve the file from the web and copy it locally if (http && grf(g->Message, trace(515), http, uri, filename)) { @@ -227,12 +242,10 @@ bool RESTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) Http = GetStringCatInfo(g, "Http", NULL); Uri = GetStringCatInfo(g, "Uri", NULL); - Fn = GetStringCatInfo(g, "Filename", "rest.json"); + Fn = GetStringCatInfo(g, "Filename", NULL); // We used the file name relative to recorded datapath - //PlugSetPath(filename, Fn, GetPath()); - strcpy(filename, GetPath()); - strncat(filename, Fn, _MAX_PATH - strlen(filename)); + PlugSetPath(filename, Fn, GetPath()); // Retrieve the file from the web and copy it locally rc = grf(g->Message, xt, Http, Uri, filename); @@ -270,7 +283,7 @@ PTDB RESTDEF::GetTable(PGLOBAL g, MODE m) if (trace(515)) htrc("REST GetTable mode=%d\n", m); - if (m != MODE_READ && m != MODE_READX) { + if (m != MODE_READ && m != MODE_READX && m != MODE_ANY) { strcpy(g->Message, "REST tables are currently read only"); return NULL; } // endif m diff --git a/storage/connect/tabxml.cpp b/storage/connect/tabxml.cpp index 68941c67be8..fa140ea0699 100644 --- a/storage/connect/tabxml.cpp +++ b/storage/connect/tabxml.cpp @@ -150,7 +150,8 @@ PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info) return NULL; } else { lvl = GetIntegerTableOption(g, topt, "Level", 0); - lvl = (lvl < 0) ? 0 : (lvl > 16) ? 16 : lvl; + lvl = GetIntegerTableOption(g, topt, "Depth", lvl); + lvl = (lvl < 0) ? 0 : (lvl > 16) ? 16 : lvl; } // endif fn if (trace(1)) diff --git a/storage/connect/user_connect.cc b/storage/connect/user_connect.cc index c25443ef7ef..c061294c57e 100644 --- a/storage/connect/user_connect.cc +++ b/storage/connect/user_connect.cc @@ -28,7 +28,7 @@ */ /****************************************************************************/ -/* Author: Olivier Bertrand -- bertrandop@gmail.com -- 2004-2015 */ +/* Author: Olivier Bertrand -- bertrandop@gmail.com -- 2004-2020 */ /****************************************************************************/ #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation @@ -58,8 +58,8 @@ PCONNECT user_connect::to_users= NULL; /****************************************************************************/ /* Get the work_size SESSION variable value . */ /****************************************************************************/ -uint GetWorkSize(void); -void SetWorkSize(uint); +ulong GetWorkSize(void); +void SetWorkSize(ulong); /* -------------------------- class user_connect -------------------------- */ @@ -97,14 +97,14 @@ user_connect::~user_connect() bool user_connect::user_init() { // Initialize Plug-like environment - uint worksize= GetWorkSize(); + ulong worksize= GetWorkSize(); PACTIVITY ap= NULL; PDBUSER dup= NULL; // Areasize= 64M because of VEC tables. Should be parameterisable //g= PlugInit(NULL, 67108864); //g= PlugInit(NULL, 134217728); // 128M was because of old embedded tests - g= PlugInit(NULL, worksize); + g= PlugInit(NULL, (size_t)worksize); // Check whether the initialization is complete if (!g || !g->Sarea || PlugSubSet(g->Sarea, g->Sarea_Size) @@ -157,15 +157,16 @@ void user_connect::SetHandler(ha_connect *hc) bool user_connect::CheckCleanup(bool force) { if (thdp->query_id > last_query_id || force) { - uint worksize= GetWorkSize(), size = g->Sarea_Size; + ulong worksize = GetWorkSize(); + size_t size = g->Sarea_Size; PlugCleanup(g, true); - if (size != worksize) { + if (size != (size_t)worksize) { FreeSarea(g); // Check whether the work area could be allocated - if (AllocSarea(g, worksize)) { + if (AllocSarea(g, (size_t)worksize)) { AllocSarea(g, size); SetWorkSize(g->Sarea_Size); // Was too big } // endif sarea From 82301aea4f2e1cdbcee5bb40d3235afc6b9bc468 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Fri, 2 Oct 2020 05:19:41 +0200 Subject: [PATCH 061/323] MDEV-23697: bin/env perl -i -> bin/perl -i - reverting 37c88445e30d doesn't mean adding space where shouldn't been - /bin/perl instead of /bin perl --- scripts/convert-debug-for-diff.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/convert-debug-for-diff.sh b/scripts/convert-debug-for-diff.sh index 478d730d15a..5b3ce05b815 100755 --- a/scripts/convert-debug-for-diff.sh +++ b/scripts/convert-debug-for-diff.sh @@ -1,4 +1,4 @@ -#!/usr/bin perl -i +#!/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 #. From 91d39f630db354a4cadba97a3ee70cf18ad6bd5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 2 Oct 2020 07:10:16 +0300 Subject: [PATCH 062/323] Cleanup: Remove unused mutex keys --- storage/innobase/handler/ha_innodb.cc | 5 ----- storage/innobase/handler/i_s.cc | 27 +-------------------------- storage/innobase/include/sync0sync.h | 7 ------- storage/innobase/include/sync0types.h | 19 ++----------------- storage/innobase/sync/sync0debug.cc | 23 +---------------------- storage/innobase/sync/sync0sync.cc | 4 ---- 6 files changed, 4 insertions(+), 81 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 07fcec61b7e..f2729905bce 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -522,7 +522,6 @@ static PSI_mutex_info all_innodb_mutexes[] = { PSI_KEY(ibuf_mutex), PSI_KEY(ibuf_pessimistic_insert_mutex), PSI_KEY(log_sys_mutex), - PSI_KEY(mutex_list_mutex), PSI_KEY(page_zip_stat_per_index_mutex), PSI_KEY(purge_sys_pq_mutex), PSI_KEY(recv_sys_mutex), @@ -533,7 +532,6 @@ static PSI_mutex_info all_innodb_mutexes[] = { PSI_KEY(rw_lock_debug_mutex), # endif /* UNIV_DEBUG */ PSI_KEY(rw_lock_list_mutex), - PSI_KEY(rw_lock_mutex), PSI_KEY(srv_innodb_monitor_mutex), PSI_KEY(srv_misc_tmpfile_mutex), PSI_KEY(srv_monitor_file_mutex), @@ -544,9 +542,6 @@ static PSI_mutex_info all_innodb_mutexes[] = { PSI_KEY(lock_wait_mutex), PSI_KEY(trx_mutex), PSI_KEY(srv_threads_mutex), -# ifndef PFS_SKIP_EVENT_MUTEX - PSI_KEY(event_mutex), -# endif /* PFS_SKIP_EVENT_MUTEX */ PSI_KEY(rtr_active_mutex), PSI_KEY(rtr_match_mutex), PSI_KEY(rtr_path_mutex), diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index a5713e32d86..9d77b6625b8 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -7177,32 +7177,7 @@ i_s_innodb_mutexes_fill_table( /* deny access to user without PROCESS_ACL privilege */ if (check_global_access(thd, PROCESS_ACL)) { DBUG_RETURN(0); - } - - // mutex_enter(&mutex_list_mutex); - -#ifdef JAN_TODO_FIXME - ib_mutex_t* mutex; - for (mutex = UT_LIST_GET_FIRST(os_mutex_list); mutex != NULL; - mutex = UT_LIST_GET_NEXT(list, mutex)) { - if (mutex->count_os_wait == 0) { - continue; - } - - OK(field_store_string(fields[MUTEXES_NAME], mutex->cmutex_name)); - OK(field_store_string(fields[MUTEXES_CREATE_FILE], - innobase_basename(mutex->cfile_name))); - OK(fields[MUTEXES_CREATE_LINE]->store(lock->cline, true)); - fields[MUTEXES_CREATE_LINE]->set_notnull(); - OK(fields[MUTEXES_OS_WAITS]->store(lock->count_os_wait, true)); - fields[MUTEXES_OS_WAITS]->set_notnull(); - OK(schema_table_store_record(thd, tables->table)); - } - - mutex_exit(&mutex_list_mutex); -#endif /* JAN_TODO_FIXME */ - - { + } else { struct Locking { Locking() { mutex_enter(&rw_lock_list_mutex); } diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index d7cb1853df0..10267f1be18 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -43,9 +43,6 @@ Created 9/5/1995 Heikki Tuuri instrumentation due to their large number of instances. */ # define PFS_SKIP_BUFFER_MUTEX_RWLOCK -/* By default, event->mutex will also be excluded from instrumentation */ -# define PFS_SKIP_EVENT_MUTEX - #endif /* UNIV_PFS_MUTEX || UNIV_PFS_RWLOCK */ #ifdef UNIV_PFS_MUTEX @@ -65,7 +62,6 @@ extern mysql_pfs_key_t ibuf_pessimistic_insert_mutex_key; extern mysql_pfs_key_t log_sys_mutex_key; extern mysql_pfs_key_t log_cmdq_mutex_key; extern mysql_pfs_key_t log_flush_order_mutex_key; -extern mysql_pfs_key_t mutex_list_mutex_key; extern mysql_pfs_key_t recalc_pool_mutex_key; extern mysql_pfs_key_t page_cleaner_mutex_key; extern mysql_pfs_key_t purge_sys_pq_mutex_key; @@ -81,7 +77,6 @@ extern mysql_pfs_key_t page_zip_stat_per_index_mutex_key; extern mysql_pfs_key_t rw_lock_debug_mutex_key; # endif /* UNIV_DEBUG */ extern mysql_pfs_key_t rw_lock_list_mutex_key; -extern mysql_pfs_key_t rw_lock_mutex_key; extern mysql_pfs_key_t srv_innodb_monitor_mutex_key; extern mysql_pfs_key_t srv_misc_tmpfile_mutex_key; extern mysql_pfs_key_t srv_monitor_file_mutex_key; @@ -93,8 +88,6 @@ extern mysql_pfs_key_t lock_mutex_key; extern mysql_pfs_key_t lock_wait_mutex_key; extern mysql_pfs_key_t trx_sys_mutex_key; extern mysql_pfs_key_t srv_threads_mutex_key; -extern mysql_pfs_key_t event_mutex_key; -extern mysql_pfs_key_t event_manager_mutex_key; extern mysql_pfs_key_t sync_array_mutex_key; extern mysql_pfs_key_t thread_mutex_key; extern mysql_pfs_key_t row_drop_list_mutex_key; diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h index 69730f1efd0..910601ed1dd 100644 --- a/storage/innobase/include/sync0types.h +++ b/storage/innobase/include/sync0types.h @@ -186,8 +186,6 @@ enum latch_level_t { RW_LOCK_X, RW_LOCK_NOT_LOCKED, - SYNC_MONITOR_MUTEX, - SYNC_ANY_LATCH, SYNC_DOUBLEWRITE, @@ -274,13 +272,12 @@ enum latch_level_t { }; /** Each latch has an ID. This id is used for creating the latch and to look -up its meta-data. See sync0debug.c. */ +up its meta-data. See sync0debug.cc. */ enum latch_id_t { LATCH_ID_NONE = 0, LATCH_ID_BUF_POOL, LATCH_ID_DICT_FOREIGN_ERR, LATCH_ID_DICT_SYS, - LATCH_ID_FILE_FORMAT_MAX, LATCH_ID_FIL_SYSTEM, LATCH_ID_FLUSH_LIST, LATCH_ID_FTS_BG_THREADS, @@ -292,8 +289,6 @@ enum latch_id_t { LATCH_ID_IBUF_PESSIMISTIC_INSERT, LATCH_ID_LOG_SYS, LATCH_ID_LOG_FLUSH_ORDER, - LATCH_ID_LIST, - LATCH_ID_MUTEX_LIST, LATCH_ID_PAGE_CLEANER, LATCH_ID_PURGE_SYS_PQ, LATCH_ID_RECALC_POOL, @@ -306,7 +301,6 @@ enum latch_id_t { LATCH_ID_RTR_MATCH_MUTEX, LATCH_ID_RTR_PATH_MUTEX, LATCH_ID_RW_LOCK_LIST, - LATCH_ID_RW_LOCK_MUTEX, LATCH_ID_SRV_INNODB_MONITOR, LATCH_ID_SRV_MISC_TMPFILE, LATCH_ID_SRV_MONITOR_FILE, @@ -317,11 +311,8 @@ enum latch_id_t { LATCH_ID_LOCK_SYS, LATCH_ID_LOCK_SYS_WAIT, LATCH_ID_TRX_SYS, - LATCH_ID_SRV_SYS, LATCH_ID_SRV_SYS_TASKS, LATCH_ID_PAGE_ZIP_STAT_PER_INDEX, - LATCH_ID_EVENT_MANAGER, - LATCH_ID_EVENT_MUTEX, LATCH_ID_SYNC_ARRAY_MUTEX, LATCH_ID_ROW_DROP_LIST, LATCH_ID_INDEX_ONLINE_LOG, @@ -330,7 +321,6 @@ enum latch_id_t { LATCH_ID_BUF_BLOCK_LOCK, LATCH_ID_BUF_BLOCK_DEBUG, LATCH_ID_DICT_OPERATION, - LATCH_ID_CHECKPOINT, LATCH_ID_FIL_SPACE, LATCH_ID_FTS_CACHE, LATCH_ID_FTS_CACHE_INIT, @@ -339,10 +329,6 @@ enum latch_id_t { LATCH_ID_IBUF_INDEX_TREE, LATCH_ID_INDEX_TREE, LATCH_ID_DICT_TABLE_STATS, - LATCH_ID_HASH_TABLE_RW_LOCK, - LATCH_ID_BUF_CHUNK_MAP_LATCH, - LATCH_ID_SYNC_DEBUG_MUTEX, - LATCH_ID_SCRUB_STAT_MUTEX, LATCH_ID_DEFRAGMENT_MUTEX, LATCH_ID_BTR_DEFRAGMENT_MUTEX, LATCH_ID_FIL_CRYPT_STAT_MUTEX, @@ -350,8 +336,7 @@ enum latch_id_t { LATCH_ID_FIL_CRYPT_THREADS_MUTEX, LATCH_ID_RW_TRX_HASH_ELEMENT, LATCH_ID_READ_VIEW, - LATCH_ID_TEST_MUTEX, - LATCH_ID_MAX = LATCH_ID_TEST_MUTEX + LATCH_ID_MAX = LATCH_ID_READ_VIEW }; #ifndef UNIV_INNOCHECKSUM diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc index cfcd02f47e3..1787861f399 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -452,7 +452,6 @@ LatchDebug::LatchDebug() LEVEL_MAP_INSERT(RW_LOCK_S); LEVEL_MAP_INSERT(RW_LOCK_X); LEVEL_MAP_INSERT(RW_LOCK_NOT_LOCKED); - LEVEL_MAP_INSERT(SYNC_MONITOR_MUTEX); LEVEL_MAP_INSERT(SYNC_ANY_LATCH); LEVEL_MAP_INSERT(SYNC_DOUBLEWRITE); LEVEL_MAP_INSERT(SYNC_BUF_FLUSH_LIST); @@ -737,7 +736,6 @@ LatchDebug::check_order( /* Fall through */ - case SYNC_MONITOR_MUTEX: case SYNC_RECV: case SYNC_FTS_BG_THREADS: case SYNC_WORK_QUEUE: @@ -1244,7 +1242,7 @@ void sync_latch_meta_init() UNIV_NOTHROW { - latch_meta.resize(LATCH_ID_MAX); + latch_meta.resize(LATCH_ID_MAX + 1); /* The latches should be ordered on latch_id_t. So that we can index directly into the vector to update and fetch meta-data. */ @@ -1283,8 +1281,6 @@ sync_latch_meta_init() LATCH_ADD_MUTEX(LOG_FLUSH_ORDER, SYNC_LOG_FLUSH_ORDER, log_flush_order_mutex_key); - LATCH_ADD_MUTEX(MUTEX_LIST, SYNC_NO_ORDER_CHECK, mutex_list_mutex_key); - LATCH_ADD_MUTEX(PAGE_CLEANER, SYNC_PAGE_CLEANER, page_cleaner_mutex_key); @@ -1321,8 +1317,6 @@ sync_latch_meta_init() LATCH_ADD_MUTEX(RW_LOCK_LIST, SYNC_NO_ORDER_CHECK, rw_lock_list_mutex_key); - LATCH_ADD_MUTEX(RW_LOCK_MUTEX, SYNC_NO_ORDER_CHECK, rw_lock_mutex_key); - LATCH_ADD_MUTEX(SRV_INNODB_MONITOR, SYNC_NO_ORDER_CHECK, srv_innodb_monitor_mutex_key); @@ -1353,16 +1347,6 @@ sync_latch_meta_init() LATCH_ADD_MUTEX(PAGE_ZIP_STAT_PER_INDEX, SYNC_ANY_LATCH, page_zip_stat_per_index_mutex_key); -#ifndef PFS_SKIP_EVENT_MUTEX - LATCH_ADD_MUTEX(EVENT_MANAGER, SYNC_NO_ORDER_CHECK, - event_manager_mutex_key); -#else - LATCH_ADD_MUTEX(EVENT_MANAGER, SYNC_NO_ORDER_CHECK, - PFS_NOT_INSTRUMENTED); -#endif /* !PFS_SKIP_EVENT_MUTEX */ - - LATCH_ADD_MUTEX(EVENT_MUTEX, SYNC_NO_ORDER_CHECK, event_mutex_key); - LATCH_ADD_MUTEX(SYNC_ARRAY_MUTEX, SYNC_NO_ORDER_CHECK, sync_array_mutex_key); @@ -1408,12 +1392,7 @@ sync_latch_meta_init() LATCH_ADD_RWLOCK(DICT_TABLE_STATS, SYNC_INDEX_TREE, dict_table_stats_key); - LATCH_ADD_MUTEX(SYNC_DEBUG_MUTEX, SYNC_NO_ORDER_CHECK, - PFS_NOT_INSTRUMENTED); - /* JAN: TODO: Add PFS instrumentation */ - LATCH_ADD_MUTEX(SCRUB_STAT_MUTEX, SYNC_NO_ORDER_CHECK, - PFS_NOT_INSTRUMENTED); LATCH_ADD_MUTEX(DEFRAGMENT_MUTEX, SYNC_NO_ORDER_CHECK, PFS_NOT_INSTRUMENTED); LATCH_ADD_MUTEX(BTR_DEFRAGMENT_MUTEX, SYNC_NO_ORDER_CHECK, diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc index d0e14b38796..7447537f2be 100644 --- a/storage/innobase/sync/sync0sync.cc +++ b/storage/innobase/sync/sync0sync.cc @@ -51,7 +51,6 @@ mysql_pfs_key_t ibuf_pessimistic_insert_mutex_key; mysql_pfs_key_t log_sys_mutex_key; mysql_pfs_key_t log_cmdq_mutex_key; mysql_pfs_key_t log_flush_order_mutex_key; -mysql_pfs_key_t mutex_list_mutex_key; mysql_pfs_key_t recalc_pool_mutex_key; mysql_pfs_key_t page_cleaner_mutex_key; mysql_pfs_key_t purge_sys_pq_mutex_key; @@ -67,7 +66,6 @@ mysql_pfs_key_t rtr_active_mutex_key; mysql_pfs_key_t rtr_match_mutex_key; mysql_pfs_key_t rtr_path_mutex_key; mysql_pfs_key_t rw_lock_list_mutex_key; -mysql_pfs_key_t rw_lock_mutex_key; mysql_pfs_key_t srv_innodb_monitor_mutex_key; mysql_pfs_key_t srv_misc_tmpfile_mutex_key; mysql_pfs_key_t srv_monitor_file_mutex_key; @@ -79,8 +77,6 @@ mysql_pfs_key_t lock_mutex_key; mysql_pfs_key_t lock_wait_mutex_key; mysql_pfs_key_t trx_sys_mutex_key; mysql_pfs_key_t srv_threads_mutex_key; -mysql_pfs_key_t event_mutex_key; -mysql_pfs_key_t event_manager_mutex_key; mysql_pfs_key_t sync_array_mutex_key; mysql_pfs_key_t thread_mutex_key; mysql_pfs_key_t row_drop_list_mutex_key; From 82bc007ffb0568bb01c1c9521d3d5d116a72fa8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 2 Oct 2020 07:11:53 +0300 Subject: [PATCH 063/323] Cleanup: Remove non-existing parameters --- mysql-test/suite/perfschema/t/show_sanity.test | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/mysql-test/suite/perfschema/t/show_sanity.test b/mysql-test/suite/perfschema/t/show_sanity.test index f6c43c88111..8f73c38eab8 100644 --- a/mysql-test/suite/perfschema/t/show_sanity.test +++ b/mysql-test/suite/perfschema/t/show_sanity.test @@ -387,11 +387,6 @@ insert into test.sanity values ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_ADAPTIVE_HASH_INDEX"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_ADAPTIVE_HASH_INDEX_PARTS"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_ADAPTIVE_MAX_SLEEP_DELAY"), - ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_API_BK_COMMIT_INTERVAL"), - ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_API_DISABLE_ROWLOCK"), - ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_API_ENABLE_BINLOG"), - ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_API_ENABLE_MDL"), - ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_API_TRX_LEVEL"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_AUTOEXTEND_INCREMENT"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_AUTOINC_LOCK_MODE"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_BACKGROUND_DROP_LIST_EMPTY"), @@ -429,9 +424,6 @@ insert into test.sanity values ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_DOUBLEWRITE"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_DOUBLEWRITE_BATCH_SIZE"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FAST_SHUTDOWN"), - ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FILE_FORMAT"), - ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FILE_FORMAT_CHECK"), - ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FILE_FORMAT_MAX"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FILE_PER_TABLE"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FILL_FACTOR"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FIL_MAKE_PAGE_DIRTY_DEBUG"), @@ -442,7 +434,6 @@ insert into test.sanity values ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FLUSH_NEIGHBORS"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FORCE_LOAD_CORRUPTED"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FORCE_RECOVERY"), - ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FORCE_RECOVERY_CRASH"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FT_AUX_TABLE"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FT_CACHE_SIZE"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FT_ENABLE_DIAG_PRINT"), @@ -490,8 +481,6 @@ insert into test.sanity values ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_PRINT_ALL_DEADLOCKS"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_PURGE_BATCH_SIZE"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_PURGE_RSEG_TRUNCATE_FREQUENCY"), - ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_PURGE_RUN_NOW"), - ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_PURGE_STOP_NOW"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_PURGE_THREADS"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_RANDOM_READ_AHEAD"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_READ_AHEAD_THRESHOLD"), From 46890349bfb75854f66e1cb9d500a6452b7cc036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 2 Oct 2020 08:36:50 +0300 Subject: [PATCH 064/323] Cleanup: Remove fts_t::bg_threads_mutex, fts_t::bg_threads The unused fts_t::bg_threads was added in mysql/mysql-server@4b1049625c00dbfcd9d7a11ad12a84695ab747e3. Any usage of fts_t::bg_threads_mutex was removed in mysql/mysql-server@33c2404b397e1077daaf0ef0ff9edba445430f5f. --- storage/innobase/fts/fts0fts.cc | 5 ----- storage/innobase/handler/ha_innodb.cc | 1 - storage/innobase/include/fts0fts.h | 12 ++---------- storage/innobase/include/sync0sync.h | 1 - storage/innobase/include/sync0types.h | 2 -- storage/innobase/sync/sync0debug.cc | 5 ----- storage/innobase/sync/sync0sync.cc | 1 - 7 files changed, 2 insertions(+), 25 deletions(-) diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index d56a1cb8bde..fb06d300803 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -5359,7 +5359,6 @@ fts_t::fts_t( mem_heap_t* heap) : added_synced(0), dict_locked(0), - bg_threads(0), add_wq(NULL), cache(NULL), doc_col(ULINT_UNDEFINED), in_queue(false), @@ -5367,8 +5366,6 @@ fts_t::fts_t( { ut_a(table->fts == NULL); - mutex_create(LATCH_ID_FTS_BG_THREADS, &bg_threads_mutex); - ib_alloc_t* heap_alloc = ib_heap_allocator_create(fts_heap); indexes = ib_vector_create(heap_alloc, sizeof(dict_index_t*), 4); @@ -5379,8 +5376,6 @@ fts_t::fts_t( /** fts_t destructor. */ fts_t::~fts_t() { - mutex_free(&bg_threads_mutex); - ut_ad(add_wq == NULL); if (cache != NULL) { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index fd44324afe0..67f110f41ab 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -586,7 +586,6 @@ static PSI_mutex_info all_innodb_mutexes[] = { PSI_KEY(file_format_max_mutex), PSI_KEY(fil_system_mutex), PSI_KEY(flush_list_mutex), - PSI_KEY(fts_bg_threads_mutex), PSI_KEY(fts_delete_mutex), PSI_KEY(fts_doc_id_mutex), PSI_KEY(log_flush_order_mutex), diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h index 30a2cc56778..84d8ccd26ef 100644 --- a/storage/innobase/include/fts0fts.h +++ b/storage/innobase/include/fts0fts.h @@ -317,19 +317,11 @@ public: /** fts_t destructor. */ ~fts_t(); - /** Mutex protecting bg_threads* and fts_add_wq. */ - ib_mutex_t bg_threads_mutex; - - /** Whether the ADDED table record sync-ed after - crash recovery; protected by bg_threads_mutex */ + /** Whether the ADDED table record sync-ed after crash recovery */ unsigned added_synced:1; - /** Whether the table holds dict_sys->mutex; - protected by bg_threads_mutex */ + /** Whether the table holds dict_sys->mutex */ unsigned dict_locked:1; - /** Number of background threads accessing this table. */ - ulint bg_threads; - /** Work queue for scheduling jobs for the FTS 'Add' thread, or NULL if the thread has not yet been created. Each work item is a fts_trx_doc_ids_t*. */ diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index 1517a93c196..0438d9d0c92 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -60,7 +60,6 @@ extern mysql_pfs_key_t dict_sys_mutex_key; extern mysql_pfs_key_t file_format_max_mutex_key; extern mysql_pfs_key_t fil_system_mutex_key; extern mysql_pfs_key_t flush_list_mutex_key; -extern mysql_pfs_key_t fts_bg_threads_mutex_key; extern mysql_pfs_key_t fts_delete_mutex_key; extern mysql_pfs_key_t fts_doc_id_mutex_key; extern mysql_pfs_key_t fts_pll_tokenize_mutex_key; diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h index a52bb4437ea..348515e0781 100644 --- a/storage/innobase/include/sync0types.h +++ b/storage/innobase/include/sync0types.h @@ -219,7 +219,6 @@ enum latch_level_t { SYNC_FTS_TOKENIZE, SYNC_FTS_OPTIMIZE, - SYNC_FTS_BG_THREADS, SYNC_FTS_CACHE_INIT, SYNC_RECV, SYNC_LOG_FLUSH_ORDER, @@ -305,7 +304,6 @@ enum latch_id_t { LATCH_ID_FILE_FORMAT_MAX, LATCH_ID_FIL_SYSTEM, LATCH_ID_FLUSH_LIST, - LATCH_ID_FTS_BG_THREADS, LATCH_ID_FTS_DELETE, LATCH_ID_FTS_DOC_ID, LATCH_ID_FTS_PLL_TOKENIZE, diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc index b732ad355a0..d78d15ac079 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -464,7 +464,6 @@ LatchDebug::LatchDebug() LEVEL_MAP_INSERT(SYNC_WORK_QUEUE); LEVEL_MAP_INSERT(SYNC_FTS_TOKENIZE); LEVEL_MAP_INSERT(SYNC_FTS_OPTIMIZE); - LEVEL_MAP_INSERT(SYNC_FTS_BG_THREADS); LEVEL_MAP_INSERT(SYNC_FTS_CACHE_INIT); LEVEL_MAP_INSERT(SYNC_RECV); LEVEL_MAP_INSERT(SYNC_LOG_FLUSH_ORDER); @@ -743,7 +742,6 @@ LatchDebug::check_order( case SYNC_MONITOR_MUTEX: case SYNC_RECV: - case SYNC_FTS_BG_THREADS: case SYNC_WORK_QUEUE: case SYNC_FTS_TOKENIZE: case SYNC_FTS_OPTIMIZE: @@ -1315,9 +1313,6 @@ sync_latch_meta_init() LATCH_ADD_MUTEX(FLUSH_LIST, SYNC_BUF_FLUSH_LIST, flush_list_mutex_key); - LATCH_ADD_MUTEX(FTS_BG_THREADS, SYNC_FTS_BG_THREADS, - fts_bg_threads_mutex_key); - LATCH_ADD_MUTEX(FTS_DELETE, SYNC_FTS_OPTIMIZE, fts_delete_mutex_key); LATCH_ADD_MUTEX(FTS_DOC_ID, SYNC_FTS_OPTIMIZE, fts_doc_id_mutex_key); diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc index a9018f2f5d5..2e5558a3294 100644 --- a/storage/innobase/sync/sync0sync.cc +++ b/storage/innobase/sync/sync0sync.cc @@ -46,7 +46,6 @@ mysql_pfs_key_t dict_sys_mutex_key; mysql_pfs_key_t file_format_max_mutex_key; mysql_pfs_key_t fil_system_mutex_key; mysql_pfs_key_t flush_list_mutex_key; -mysql_pfs_key_t fts_bg_threads_mutex_key; mysql_pfs_key_t fts_delete_mutex_key; mysql_pfs_key_t fts_doc_id_mutex_key; mysql_pfs_key_t fts_pll_tokenize_mutex_key; From b8b1aef6b1a30349c989536aa80d06f38742c29e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 2 Oct 2020 08:40:06 +0300 Subject: [PATCH 065/323] Cleanup: Orphan que_thr_mutex declaration The orphan declaration was added in MySQL 5.6.2 mysql/mysql-server@2915417e026ef9fdd8e36df17938409ccc157d86 and MariaDB commit 1d0f70c2f894b27e98773a282871d32802f67964. --- storage/innobase/include/que0que.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h index f6609993601..262be4d30a9 100644 --- a/storage/innobase/include/que0que.h +++ b/storage/innobase/include/que0que.h @@ -35,9 +35,6 @@ Created 5/27/1996 Heikki Tuuri #include "row0types.h" #include "pars0types.h" -/** Mutex protecting the query threads. */ -extern ib_mutex_t que_thr_mutex; - /***********************************************************************//** Creates a query graph fork node. @return own: fork node */ From 0ccdf8b11b7537c93ad5f5d966666cf48d7b6857 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 2 Oct 2020 10:19:00 +0400 Subject: [PATCH 066/323] MDEV-19275 Provide SQL service to plugins. test_sql_service plugin added and employed in test_sql_service.test. --- .../suite/plugins/r/test_sql_service.result | 8 + .../suite/plugins/t/test_sql_service.opt | 2 + .../suite/plugins/t/test_sql_service.test | 18 + plugin/test_sql_service/CMakeLists.txt | 18 + plugin/test_sql_service/COPYING | 339 ++++++++++++++++++ plugin/test_sql_service/test_sql_service.c | 145 ++++++++ sql/log.cc | 2 +- sql/sp_head.cc | 3 + sql/sql_acl.cc | 37 ++ sql/sql_prepare.cc | 61 +++- 10 files changed, 630 insertions(+), 3 deletions(-) create mode 100644 mysql-test/suite/plugins/r/test_sql_service.result create mode 100644 mysql-test/suite/plugins/t/test_sql_service.opt create mode 100644 mysql-test/suite/plugins/t/test_sql_service.test create mode 100644 plugin/test_sql_service/CMakeLists.txt create mode 100644 plugin/test_sql_service/COPYING create mode 100644 plugin/test_sql_service/test_sql_service.c diff --git a/mysql-test/suite/plugins/r/test_sql_service.result b/mysql-test/suite/plugins/r/test_sql_service.result new file mode 100644 index 00000000000..af414d6c6e7 --- /dev/null +++ b/mysql-test/suite/plugins/r/test_sql_service.result @@ -0,0 +1,8 @@ +install plugin test_sql_service soname 'test_sql_service'; +set global test_sql_service_run_test= 1; +show status like 'test_sql_service%'; +Variable_name Value +Test_sql_service_passed 0 +uninstall plugin test_sql_service; +Warnings: +Warning 1620 Plugin is busy and will be uninstalled on shutdown diff --git a/mysql-test/suite/plugins/t/test_sql_service.opt b/mysql-test/suite/plugins/t/test_sql_service.opt new file mode 100644 index 00000000000..089ed94b688 --- /dev/null +++ b/mysql-test/suite/plugins/t/test_sql_service.opt @@ -0,0 +1,2 @@ +--thread_handling='one-thread-per-connection' + diff --git a/mysql-test/suite/plugins/t/test_sql_service.test b/mysql-test/suite/plugins/t/test_sql_service.test new file mode 100644 index 00000000000..3384b523bda --- /dev/null +++ b/mysql-test/suite/plugins/t/test_sql_service.test @@ -0,0 +1,18 @@ + +--source include/not_embedded.inc + +if (!$TEST_SQL_SERVICE_SO) { + skip No TEST_SQL_SERVICE plugin; +} + +# An unfortunate wait for check-testcase.test to complete disconnect. +let count_sessions= 1; +source include/wait_until_count_sessions.inc; + +install plugin test_sql_service soname 'test_sql_service'; + +set global test_sql_service_run_test= 1; +show status like 'test_sql_service%'; + +uninstall plugin test_sql_service; + diff --git a/plugin/test_sql_service/CMakeLists.txt b/plugin/test_sql_service/CMakeLists.txt new file mode 100644 index 00000000000..aa9ecfe685e --- /dev/null +++ b/plugin/test_sql_service/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright (C) 2013 Alexey Botchkov and SkySQL 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 Street, Fifth Floor, Boston, MA 02110-1335 USA + +SET(SOURCES test_sql_service.c) + +MYSQL_ADD_PLUGIN(test_sql_service ${SOURCES} MODULE_ONLY RECOMPILE_FOR_EMBEDDED) diff --git a/plugin/test_sql_service/COPYING b/plugin/test_sql_service/COPYING new file mode 100644 index 00000000000..6e475df5526 --- /dev/null +++ b/plugin/test_sql_service/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-1335 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. + + + Copyright (C) + + 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-1335 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. + + , 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/plugin/test_sql_service/test_sql_service.c b/plugin/test_sql_service/test_sql_service.c new file mode 100644 index 00000000000..062f10fce58 --- /dev/null +++ b/plugin/test_sql_service/test_sql_service.c @@ -0,0 +1,145 @@ +/* Copyright (C) 2019, Alexey Botchkov and 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 */ + + +#define PLUGIN_VERSION 0x100 +#define PLUGIN_STR_VERSION "1.0.0" + +#define _my_thread_var loc_thread_var + +#include +#include +#include +#include +#include +//#include /* for enum enum_server_command */ +#include +#include +//#include + + +LEX_STRING * thd_query_string (MYSQL_THD thd); +unsigned long long thd_query_id(const MYSQL_THD thd); +size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen); +const char *thd_user_name(MYSQL_THD thd); +const char *thd_client_host(MYSQL_THD thd); +const char *thd_client_ip(MYSQL_THD thd); +LEX_CSTRING *thd_current_db(MYSQL_THD thd); +int thd_current_status(MYSQL_THD thd); +enum enum_server_command thd_current_command(MYSQL_THD thd); + +int maria_compare_hostname(const char *wild_host, long wild_ip, long ip_mask, + const char *host, const char *ip); +void maria_update_hostname(const char **wild_host, long *wild_ip, long *ip_mask, + const char *host); + +/* Status variables for SHOW STATUS */ +static long test_passed= 0; +static struct st_mysql_show_var test_sql_status[]= +{ + {"test_sql_service_passed", (char *)&test_passed, SHOW_LONG}, + {0,0,0} +}; + +static my_bool do_test= TRUE; +static void run_test(MYSQL_THD thd, struct st_mysql_sys_var *var, + void *var_ptr, const void *save); +static MYSQL_SYSVAR_BOOL(run_test, do_test, PLUGIN_VAR_OPCMDARG, + "Perform the test now.", NULL, run_test, FALSE); +static struct st_mysql_sys_var* test_sql_vars[]= +{ + MYSQL_SYSVAR(run_test), + NULL +}; + + +extern int execute_sql_command(const char *command, + char *hosts, char *names, char *filters); + + + +static int do_tests() +{ + char plugins[1024]; + char names[1024]; + char dl[2048]; + int result; + + result= execute_sql_command("select 'plugin', name, dl from mysql.plugin", + plugins, names, dl); + + return result; +} + + +void auditing(MYSQL_THD thd, unsigned int event_class, const void *ev) +{ +} + + +static void run_test(MYSQL_THD thd __attribute__((unused)), + struct st_mysql_sys_var *var __attribute__((unused)), + void *var_ptr __attribute__((unused)), + const void *save __attribute__((unused))) +{ + test_passed= do_tests(); +} + + +static int init_done= 0; + +static int test_sql_service_plugin_init(void *p __attribute__((unused))) +{ + init_done= 1; + return 0; +} + + +static int test_sql_service_plugin_deinit(void *p __attribute__((unused))) +{ + if (!init_done) + return 0; + + return 0; +} + + +static struct st_mysql_audit maria_descriptor = +{ + MYSQL_AUDIT_INTERFACE_VERSION, + NULL, + auditing, + { MYSQL_AUDIT_GENERAL_CLASSMASK | + MYSQL_AUDIT_TABLE_CLASSMASK | + MYSQL_AUDIT_CONNECTION_CLASSMASK } +}; +maria_declare_plugin(test_sql_service) +{ + MYSQL_AUDIT_PLUGIN, + &maria_descriptor, + "TEST_SQL_SERVICE", + "Alexey Botchkov (MariaDB Corporation)", + "Test SQL service", + PLUGIN_LICENSE_GPL, + test_sql_service_plugin_init, + test_sql_service_plugin_deinit, + PLUGIN_VERSION, + test_sql_status, + test_sql_vars, + PLUGIN_STR_VERSION, + MariaDB_PLUGIN_MATURITY_STABLE +} +maria_declare_plugin_end; + diff --git a/sql/log.cc b/sql/log.cc index 921d68b9feb..2cd04bdc1b2 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1355,7 +1355,7 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, size_t query_length, my_hrtime_t current_time= { hrtime_from_time(thd->start_time) + thd->start_time_sec_part + query_utime }; - if (!query) + if (!query || thd->get_command() == COM_STMT_PREPARE) { is_command= TRUE; query= command_name[thd->get_command()].str; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 49c8229c277..9e5b5bee0f2 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1211,6 +1211,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) Query_arena execute_arena(&execute_mem_root, STMT_INITIALIZED_FOR_SP), backup_arena; query_id_t old_query_id; + CSET_STRING old_query; TABLE *old_derived_tables; TABLE *old_rec_tables; LEX *old_lex; @@ -1291,6 +1292,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) be able properly do close_thread_tables() in instructions. */ old_query_id= thd->query_id; + old_query= thd->query_string; old_derived_tables= thd->derived_tables; thd->derived_tables= 0; old_rec_tables= thd->rec_tables; @@ -1567,6 +1569,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) old_change_list.move_elements_to(thd); thd->lex= old_lex; thd->set_query_id(old_query_id); + thd->set_query_inner(old_query); DBUG_ASSERT(!thd->derived_tables); thd->derived_tables= old_derived_tables; thd->rec_tables= old_rec_tables; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 161ffc66641..3958cb3fba7 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -14679,3 +14679,40 @@ maria_declare_plugin(mysql_password) MariaDB_PLUGIN_MATURITY_STABLE /* Maturity */ } maria_declare_plugin_end; + + +/* + Exporting functions that allow plugins to do server-style + host/user matching. Used in server_audit2 plugin. +*/ +extern "C" int maria_compare_hostname( + const char *wild_host, long wild_ip, long ip_mask, + const char *host, const char *ip) +{ +#ifndef NO_EMBEDDED_ACCESS_CHECKS + acl_host_and_ip h; + h.hostname= (char *) wild_host; + h.ip= wild_ip; + h.ip_mask= ip_mask; + + return compare_hostname(&h, host, ip); +#else + return 0; +#endif +} + + +extern "C" void maria_update_hostname( + const char **wild_host, long *wild_ip, long *ip_mask, + const char *host) +{ +#ifndef NO_EMBEDDED_ACCESS_CHECKS + acl_host_and_ip h; + update_hostname(&h, host); + *wild_host= h.hostname; + *wild_ip= h.ip; + *ip_mask= h.ip_mask; +#endif +} + + diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index fee65ed4e22..ecb56e70f88 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2618,6 +2618,15 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length) if (stmt->prepare(packet, packet_length)) { + /* + Prepare failed and stmt will be freed. + Now we have to save the query_string in the so the + audit plugin later gets the meaningful notification. + */ + if (alloc_query(thd, stmt->query_string.str(), stmt->query_string.length())) + { + thd->set_query(0, 0); + } /* Statement map deletes statement on erase */ thd->stmt_map.erase(stmt); thd->clear_last_stmt(); @@ -2752,6 +2761,7 @@ bool Lex_prepared_stmt::get_dynamic_sql_string(THD *thd, void mysql_sql_stmt_prepare(THD *thd) { LEX *lex= thd->lex; + CSET_STRING orig_query= thd->query_string; const LEX_CSTRING *name= &lex->prepared_stmt.name(); Prepared_statement *stmt; LEX_CSTRING query; @@ -2822,7 +2832,16 @@ void mysql_sql_stmt_prepare(THD *thd) thd->m_statement_psi, stmt->name.str, stmt->name.length); - if (stmt->prepare(query.str, (uint) query.length)) + bool res= stmt->prepare(query.str, (uint) query.length); + /* + stmt->prepare() sets thd->query_string with the prepared + query, so the audit plugin gets adequate notification with the + mysqld_stmt_* set of functions. + But here we should restore the original query so it's mentioned in + logs properly. + */ + thd->set_query(orig_query); + if (res) { /* Statement map deletes the statement on erase */ thd->stmt_map.erase(stmt); @@ -2841,6 +2860,7 @@ void mysql_sql_stmt_prepare(THD *thd) void mysql_sql_stmt_execute_immediate(THD *thd) { LEX *lex= thd->lex; + CSET_STRING orig_query= thd->query_string; Prepared_statement *stmt; LEX_CSTRING query; DBUG_ENTER("mysql_sql_stmt_execute_immediate"); @@ -2889,6 +2909,14 @@ void mysql_sql_stmt_execute_immediate(THD *thd) thd->free_items(); thd->free_list= free_list_backup; + /* + stmt->execute_immediately() sets thd->query_string with the executed + query, so the audit plugin gets adequate notification with the + mysqld_stmt_* set of functions. + But here we should restore the original query so it's mentioned in + logs properly. + */ + thd->set_query_inner(orig_query); stmt->lex->restore_set_statement_var(); delete stmt; DBUG_VOID_RETURN; @@ -3205,6 +3233,13 @@ static void mysql_stmt_execute_common(THD *thd, if (!(stmt= find_prepared_statement(thd, stmt_id))) { char llbuf[22]; + /* + Did not find the statement with the provided stmt_id. + Set thd->query_string with the stmt_id so the + audit plugin gets the meaningful notification. + */ + if (alloc_query(thd, llbuf, strlen(llbuf))) + thd->set_query(0, 0); my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), static_cast(sizeof(llbuf)), llstr(stmt_id, llbuf), "mysqld_stmt_execute"); DBUG_VOID_RETURN; @@ -3969,6 +4004,19 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) DBUG_RETURN(TRUE); } + /* + We'd like to have thd->query to be set to the actual query + after the function ends. + This value will be sent to audit plugins later. + As the statement is created, the query will be stored + in statement's arena. Normally the statement lives longer than + the end of this query, so we can just set thd->query_string to + be the stmt->query_string. + Though errors can result in statement to be freed. These cases + should be handled appropriately. + */ + stmt_backup.query_string= thd->query_string; + old_stmt_arena= thd->stmt_arena; thd->stmt_arena= this; @@ -4504,6 +4552,15 @@ Prepared_statement::reprepare() */ thd->get_stmt_da()->clear_warning_info(thd->query_id); } + else + { + /* + Prepare failed and the 'copy' will be freed. + Now we have to restore the query_string in the so the + audit plugin later gets the meaningful notification. + */ + thd->set_query(query(), query_length()); + } return error; } @@ -5127,7 +5184,7 @@ public: Protocol_local(THD *thd_arg, ulong prealloc= 0) : Protocol_text(thd_arg, prealloc), - cur_data(0), first_data(0), data_tail(&first_data) + cur_data(0), first_data(0), data_tail(&first_data), alloc(0) {} protected: From 7fba16d53fe3c2fa241434e1ff715e6a3789c79a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 2 Oct 2020 14:04:16 +0300 Subject: [PATCH 067/323] MDEV-16264 fixup: Remove unused fts_optimize_wq->event This was missed not only in commit 5e62b6a5e06eb02cbde1e34e95e26f42d87fce02 but also in commit a9550c47e4e32f2df8816477e362315608194443. --- storage/innobase/include/ut0wqueue.h | 3 --- storage/innobase/ut/ut0wqueue.cc | 10 ---------- 2 files changed, 13 deletions(-) diff --git a/storage/innobase/include/ut0wqueue.h b/storage/innobase/include/ut0wqueue.h index c6d0de82b41..347622989dd 100644 --- a/storage/innobase/include/ut0wqueue.h +++ b/storage/innobase/include/ut0wqueue.h @@ -46,9 +46,6 @@ struct ib_wqueue_t ib_mutex_t mutex; /** Work item list */ ib_list_t* items; - /** event we use to signal additions to list; - os_event_set() and os_event_reset() are protected by the mutex */ - os_event_t event; }; /****************************************************************//** diff --git a/storage/innobase/ut/ut0wqueue.cc b/storage/innobase/ut/ut0wqueue.cc index b56952f27d5..53bb0c8b148 100644 --- a/storage/innobase/ut/ut0wqueue.cc +++ b/storage/innobase/ut/ut0wqueue.cc @@ -44,7 +44,6 @@ ib_wqueue_create(void) mutex_create(LATCH_ID_WORK_QUEUE, &wq->mutex); wq->items = ib_list_create(); - wq->event = os_event_create(0); return(wq); } @@ -58,7 +57,6 @@ ib_wqueue_free( { mutex_free(&wq->mutex); ib_list_free(wq->items); - os_event_destroy(wq->event); ut_free(wq); } @@ -76,7 +74,6 @@ ib_wqueue_add(ib_wqueue_t* wq, void* item, mem_heap_t* heap, bool wq_locked) } ib_list_add_last(wq->items, item, heap); - os_event_set(wq->event); if (!wq_locked) { mutex_exit(&wq->mutex); @@ -100,16 +97,9 @@ ib_wqueue_nowait( if (node) { ib_list_remove(wq->items, node); - } } - /* We must reset the event when the list - gets emptied. */ - if(ib_list_is_empty(wq->items)) { - os_event_reset(wq->event); - } - mutex_exit(&wq->mutex); return (node ? node->data : NULL); From dab56d5e8e9c64d3815594b412521e36ba539f48 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sat, 3 Oct 2020 00:24:53 +0200 Subject: [PATCH 068/323] MDEV-23879 server hangs with threadpool, compression, and client pipelining Amend check for unread client data in threadpool. THD::NET will have unread data, in case client uses compression, and wraps multiple commands into a single compression packet MariaDB C/C sends COM_STMT_RESET+COM_STMT_EXECUTE, and wraps it into a single compressed packet, when compression is on, thus trying to use compression and prepared statements against a threadpool-enabled server will result into a hang, before this patch. --- mysql-test/r/pool_of_threads.result | 5 +++++ mysql-test/t/pool_of_threads.test | 6 ++++++ sql/threadpool_common.cc | 14 +++++++++++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/pool_of_threads.result b/mysql-test/r/pool_of_threads.result index 9c02dfac9cd..5f501eb1b68 100644 --- a/mysql-test/r/pool_of_threads.result +++ b/mysql-test/r/pool_of_threads.result @@ -2188,3 +2188,8 @@ sleep(50) connection extracon; sleep(5.5) 0 +connect comp_con,localhost,root,,,,,COMPRESS; +SELECT 1; +1 +1 +disconnect comp_con; diff --git a/mysql-test/t/pool_of_threads.test b/mysql-test/t/pool_of_threads.test index cb62a27faeb..95b320e6dad 100644 --- a/mysql-test/t/pool_of_threads.test +++ b/mysql-test/t/pool_of_threads.test @@ -92,3 +92,9 @@ connection con2; connection extracon; --reap + +# Check if compression works OK +connect (comp_con,localhost,root,,,,,COMPRESS); +SELECT 1; +disconnect comp_con; + diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc index b0438770aae..fc9a79432f0 100644 --- a/sql/threadpool_common.cc +++ b/sql/threadpool_common.cc @@ -324,6 +324,16 @@ static void handle_wait_timeout(THD *thd) thd->net.error= 2; } +/** Check if some client data is cached in thd->net or thd->net.vio */ +static bool has_unread_data(THD* thd) +{ + NET *net= &thd->net; + if (net->compress && net->remain_in_buf) + return true; + Vio *vio= net->vio; + return vio->has_data(vio); +} + /** Process a single client request or a single batch. @@ -358,7 +368,6 @@ static int threadpool_process_request(THD *thd) */ for(;;) { - Vio *vio; thd->net.reading_or_writing= 0; if (mysql_audit_release_required(thd)) mysql_audit_release(thd); @@ -374,8 +383,7 @@ static int threadpool_process_request(THD *thd) set_thd_idle(thd); - vio= thd->net.vio; - if (!vio->has_data(vio)) + if (!has_unread_data(thd)) { /* More info on this debug sync is in sql_parse.cc*/ DEBUG_SYNC(thd, "before_do_command_net_read"); From 34cf947ef227276810d206d089feadbd593897ee Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Sat, 3 Oct 2020 12:38:19 +0300 Subject: [PATCH 069/323] UBSAN UndefinedBehaviorSanitizer: undefined-behavior ../mysys/hash.c:798:9 --- mysys/hash.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mysys/hash.c b/mysys/hash.c index 1270d14c1f6..d5903df40bd 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -792,14 +792,13 @@ void my_hash_replace(HASH *hash, HASH_SEARCH_STATE *current_record, my_bool my_hash_iterate(HASH *hash, my_hash_walk_action action, void *argument) { uint records, i; - HASH_LINK *data; records= hash->records; - data= dynamic_element(&hash->array,0,HASH_LINK*); for (i= 0 ; i < records ; i++) { - if ((*action)(data[i].data, argument)) + if ((*action)(dynamic_element(&hash->array, i, HASH_LINK *)->data, + argument)) return 1; } return 0; From acb0c9e8fd3916cd37e895ef0a1f52f856ad047b Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Fri, 28 Aug 2020 16:05:38 +0200 Subject: [PATCH 070/323] MDEV-23518 Syntax error in ond SP results in misleading message on SHOW CREATE PROCEDURE Add info to the error message how to get details about error which happened. --- mysql-test/main/errors.result | 35 ++++++++++++++++ mysql-test/main/errors.test | 36 ++++++++++++++++ mysql-test/main/sp-destruct.result | 42 ++++++++++++++++--- mysql-test/main/sp-destruct.test | 6 +++ mysql-test/main/sp.result | 6 ++- mysql-test/main/sp.test | 2 +- .../suite/compat/oracle/r/sp-package.result | 42 +++++++++++++++---- .../suite/compat/oracle/t/sp-package.test | 7 ++++ sql/share/errmsg-utf8.txt | 5 ++- 9 files changed, 164 insertions(+), 17 deletions(-) diff --git a/mysql-test/main/errors.result b/mysql-test/main/errors.result index 78695b07b8e..44193865493 100644 --- a/mysql-test/main/errors.result +++ b/mysql-test/main/errors.result @@ -196,3 +196,38 @@ ERROR 22003: BIGINT value is out of range in '-73 * -2465717823867977728' SELECT UPDATEXML(-73 * -2465717823867977728,@@global.long_query_time,null); ERROR 22003: BIGINT value is out of range in '-73 * -2465717823867977728' # End of 10.3 tests +# +# MDEV-23518: Syntax error in ond SP results in misleading +# message on SHOW CREATE PROCEDURE +# +CREATE PROCEDURE P1 () +BEGIN NOT ATOMIC +IF (SELECT 2) THEN +SELECT 4; +END IF ; +END; +$$ +select name,db,body from mysql.proc where name = "P1"; +name db body +P1 test BEGIN NOT ATOMIC +IF (SELECT 2) THEN +SELECT 4; +END IF ; +END +update mysql.proc set body_utf8="BEGIN NOT ATOMIC +IF (SELECT 2) OR foo = 3 THEN +SELECT 4; +END IF ; +END", body="BEGIN NOT ATOMIC +IF (SELECT 2) OR foo = 3 THEN +SELECT 4; +END IF ; +END"where name = "P1"; +show create procedure P1; +ERROR HY000: Failed to load routine test.P1 (internal code -6). For more details, run SHOW WARNINGS +show warnings; +Level Code Message +Error 1327 Undeclared variable: foo +Error 1457 Failed to load routine test.P1 (internal code -6). For more details, run SHOW WARNINGS +drop procedure P1; +# End of 10.4 tests diff --git a/mysql-test/main/errors.test b/mysql-test/main/errors.test index f3aedc8e491..a4b95d48e5d 100644 --- a/mysql-test/main/errors.test +++ b/mysql-test/main/errors.test @@ -246,3 +246,39 @@ SELECT UPDATEXML(-73 * -2465717823867977728,@@global.auto_increment_increment,nu SELECT UPDATEXML(-73 * -2465717823867977728,@@global.long_query_time,null); -- echo # End of 10.3 tests + +--echo # +--echo # MDEV-23518: Syntax error in ond SP results in misleading +--echo # message on SHOW CREATE PROCEDURE +--echo # + +DELIMITER $$; + +CREATE PROCEDURE P1 () +BEGIN NOT ATOMIC + IF (SELECT 2) THEN + SELECT 4; + END IF ; +END; +$$ + +DELIMITER ;$$ + +select name,db,body from mysql.proc where name = "P1"; +update mysql.proc set body_utf8="BEGIN NOT ATOMIC +IF (SELECT 2) OR foo = 3 THEN +SELECT 4; +END IF ; +END", body="BEGIN NOT ATOMIC +IF (SELECT 2) OR foo = 3 THEN +SELECT 4; +END IF ; +END"where name = "P1"; + +--error ER_SP_PROC_TABLE_CORRUPT +show create procedure P1; +show warnings; + +drop procedure P1; + +-- echo # End of 10.4 tests diff --git a/mysql-test/main/sp-destruct.result b/mysql-test/main/sp-destruct.result index 10cfcafdb3b..b5e01f8beeb 100644 --- a/mysql-test/main/sp-destruct.result +++ b/mysql-test/main/sp-destruct.result @@ -71,19 +71,49 @@ values 'alksj wpsj sa ^#!@ ' ); select bug14233_1(); -ERROR HY000: Failed to load routine test.bug14233_1. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +ERROR HY000: Failed to load routine test.bug14233_1 (internal code -6). For more details, run SHOW WARNINGS +show warnings; +Level Code Message +Warning 1601 Creation context of stored routine `test`.`bug14233_1` is invalid +Error 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'select count(*) from mysql.user' at line 3 +Error 1457 Failed to load routine test.bug14233_1 (internal code -6). For more details, run SHOW WARNINGS create view v1 as select bug14233_1(); -ERROR HY000: Failed to load routine test.bug14233_1. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +ERROR HY000: Failed to load routine test.bug14233_1 (internal code -6). For more details, run SHOW WARNINGS +show warnings; +Level Code Message +Warning 1601 Creation context of stored routine `test`.`bug14233_1` is invalid +Error 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'select count(*) from mysql.user' at line 3 +Error 1457 Failed to load routine test.bug14233_1 (internal code -6). For more details, run SHOW WARNINGS select bug14233_2(); -ERROR HY000: Failed to load routine test.bug14233_2. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +ERROR HY000: Failed to load routine test.bug14233_2 (internal code -6). For more details, run SHOW WARNINGS +show warnings; +Level Code Message +Warning 1601 Creation context of stored routine `test`.`bug14233_2` is invalid +Error 1320 No RETURN found in FUNCTION test.bug14233_2 +Error 1457 Failed to load routine test.bug14233_2 (internal code -6). For more details, run SHOW WARNINGS create view v1 as select bug14233_2(); -ERROR HY000: Failed to load routine test.bug14233_2. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +ERROR HY000: Failed to load routine test.bug14233_2 (internal code -6). For more details, run SHOW WARNINGS +show warnings; +Level Code Message +Warning 1601 Creation context of stored routine `test`.`bug14233_2` is invalid +Error 1320 No RETURN found in FUNCTION test.bug14233_2 +Error 1457 Failed to load routine test.bug14233_2 (internal code -6). For more details, run SHOW WARNINGS call bug14233_3(); -ERROR HY000: Failed to load routine test.bug14233_3. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +ERROR HY000: Failed to load routine test.bug14233_3 (internal code -6). For more details, run SHOW WARNINGS +show warnings; +Level Code Message +Warning 1601 Creation context of stored routine `test`.`bug14233_3` is invalid +Error 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'wpsj sa ^#!@ ' at line 3 +Error 1457 Failed to load routine test.bug14233_3 (internal code -6). For more details, run SHOW WARNINGS drop trigger t1_ai; create trigger t1_ai after insert on t1 for each row call bug14233_3(); insert into t1 values (0); -ERROR HY000: Failed to load routine test.bug14233_3. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +ERROR HY000: Failed to load routine test.bug14233_3 (internal code -6). For more details, run SHOW WARNINGS +show warnings; +Level Code Message +Warning 1601 Creation context of stored routine `test`.`bug14233_3` is invalid +Error 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'wpsj sa ^#!@ ' at line 3 +Error 1457 Failed to load routine test.bug14233_3 (internal code -6). For more details, run SHOW WARNINGS drop trigger t1_ai; drop table t1; drop function bug14233_1; diff --git a/mysql-test/main/sp-destruct.test b/mysql-test/main/sp-destruct.test index 12299fa230b..4bdfed70545 100644 --- a/mysql-test/main/sp-destruct.test +++ b/mysql-test/main/sp-destruct.test @@ -128,20 +128,26 @@ values --error ER_SP_PROC_TABLE_CORRUPT select bug14233_1(); +show warnings; --error ER_SP_PROC_TABLE_CORRUPT create view v1 as select bug14233_1(); +show warnings; --error ER_SP_PROC_TABLE_CORRUPT select bug14233_2(); +show warnings; --error ER_SP_PROC_TABLE_CORRUPT create view v1 as select bug14233_2(); +show warnings; --error ER_SP_PROC_TABLE_CORRUPT call bug14233_3(); +show warnings; drop trigger t1_ai; create trigger t1_ai after insert on t1 for each row call bug14233_3(); --error ER_SP_PROC_TABLE_CORRUPT insert into t1 values (0); +show warnings; # Clean-up drop trigger t1_ai; diff --git a/mysql-test/main/sp.result b/mysql-test/main/sp.result index d40516da88e..6bde488642a 100644 --- a/mysql-test/main/sp.result +++ b/mysql-test/main/sp.result @@ -5306,8 +5306,12 @@ drop database if exists това_е_дълго_име_за_база_данни_ create database това_е_дълго_име_за_база_данни_нали| INSERT INTO mysql.proc VALUES ('това_е_дълго_име_за_база_данни_нали','това_е_процедура_с_доста_дълго_име_нали_и_още_по_дълго','PROCEDURE','това_е_процедура_с_доста_дълго_име_нали_и_още_по_дълго','SQL','CONTAINS_SQL','NO','DEFINER','','','bad_body','root@localhost',now(), now(),'','', 'utf8', 'utf8_general_ci', 'utf8_general_ci', 'n/a', 'NONE')| call това_е_дълго_име_за_база_данни_нали.това_е_процедура_с_доста_дълго_име_нали_и_още_по_дълго()| -ERROR HY000: Failed to load routine това_е_дълго_име_за_база_данни_нали.това_е_процедура_с_доста_дълго_име_нали_и_още_по_дълго. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +ERROR HY000: Failed to load routine това_е_дълго_име_за_база_данни_нали.това_е_процедура_с_доста_дълго_име_нали_и_още_по_дълго (internal code -6). For more details, run SHOW WARNINGS drop database това_е_дълго_име_за_база_данни_нали| +show warnings| +Level Code Message +Error 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 2 +Error 1457 Failed to load routine това_е_дълго_име_за_база_данни_нали.това_е_процедура_с_доста_дълго_име_нали_и_още_по_дълго (internal code -6). For more details, run SHOW WARNINGS CREATE TABLE t3 ( Member_ID varchar(15) NOT NULL, PRIMARY KEY (Member_ID) diff --git a/mysql-test/main/sp.test b/mysql-test/main/sp.test index bddd07bdb6c..c6c00ca8d91 100644 --- a/mysql-test/main/sp.test +++ b/mysql-test/main/sp.test @@ -6315,7 +6315,7 @@ INSERT INTO mysql.proc VALUES ('това_е_дълго_име_за_база_да --error ER_SP_PROC_TABLE_CORRUPT call това_е_дълго_име_за_база_данни_нали.това_е_процедура_с_доста_дълго_име_нали_и_още_по_дълго()| drop database това_е_дълго_име_за_база_данни_нали| - +show warnings| # # BUG#21493: Crash on the second call of a procedure containing diff --git a/mysql-test/suite/compat/oracle/r/sp-package.result b/mysql-test/suite/compat/oracle/r/sp-package.result index 4f0f05b1939..e7ab4eaa4a2 100644 --- a/mysql-test/suite/compat/oracle/r/sp-package.result +++ b/mysql-test/suite/compat/oracle/r/sp-package.result @@ -249,7 +249,11 @@ RETURN f2(); END; END; $$ -ERROR HY000: Failed to load routine test.test2. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +ERROR HY000: Failed to load routine test.test2 (internal code -6). For more details, run SHOW WARNINGS +show warnings; +Level Code Message +Error 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'garbage' at line 1 +Error 1457 Failed to load routine test.test2 (internal code -6). For more details, run SHOW WARNINGS DROP PACKAGE test2; # # Broken CREATE PACKAGE at a package function call time @@ -271,11 +275,23 @@ UPDATE mysql.proc SET `body`='garbage' WHERE db='test' AND name='test2' AND type='PACKAGE'; # sp-cache-invalidate SELECT test2.f1(); -ERROR HY000: Failed to load routine test.test2. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +ERROR HY000: Failed to load routine test.test2 (internal code -6). For more details, run SHOW WARNINGS +show warnings; +Level Code Message +Error 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'garbage' at line 1 +Error 1457 Failed to load routine test.test2 (internal code -6). For more details, run SHOW WARNINGS SELECT test2.f1(); -ERROR HY000: Failed to load routine test.test2. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +ERROR HY000: Failed to load routine test.test2 (internal code -6). For more details, run SHOW WARNINGS +show warnings; +Level Code Message +Error 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'garbage' at line 1 +Error 1457 Failed to load routine test.test2 (internal code -6). For more details, run SHOW WARNINGS SELECT test2.f1(); -ERROR HY000: Failed to load routine test.test2. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +ERROR HY000: Failed to load routine test.test2 (internal code -6). For more details, run SHOW WARNINGS +show warnings; +Level Code Message +Error 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'garbage' at line 1 +Error 1457 Failed to load routine test.test2 (internal code -6). For more details, run SHOW WARNINGS DROP PACKAGE test2; # # Broken CREATE PACKAGE at a package procedure call time @@ -297,11 +313,23 @@ UPDATE mysql.proc SET `body`='garbage' WHERE db='test' AND name='test2' AND type='PACKAGE'; # sp-cache-invalidate CALL test2.p1(); -ERROR HY000: Failed to load routine test.test2. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +ERROR HY000: Failed to load routine test.test2 (internal code -6). For more details, run SHOW WARNINGS +show warnings; +Level Code Message +Error 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'garbage' at line 1 +Error 1457 Failed to load routine test.test2 (internal code -6). For more details, run SHOW WARNINGS CALL test2.p1(); -ERROR HY000: Failed to load routine test.test2. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +ERROR HY000: Failed to load routine test.test2 (internal code -6). For more details, run SHOW WARNINGS +show warnings; +Level Code Message +Error 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'garbage' at line 1 +Error 1457 Failed to load routine test.test2 (internal code -6). For more details, run SHOW WARNINGS CALL test2.p1(); -ERROR HY000: Failed to load routine test.test2. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +ERROR HY000: Failed to load routine test.test2 (internal code -6). For more details, run SHOW WARNINGS +show warnings; +Level Code Message +Error 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'garbage' at line 1 +Error 1457 Failed to load routine test.test2 (internal code -6). For more details, run SHOW WARNINGS DROP PACKAGE test2; # # Bad routine names diff --git a/mysql-test/suite/compat/oracle/t/sp-package.test b/mysql-test/suite/compat/oracle/t/sp-package.test index 5eac3987982..96420c18820 100644 --- a/mysql-test/suite/compat/oracle/t/sp-package.test +++ b/mysql-test/suite/compat/oracle/t/sp-package.test @@ -335,6 +335,7 @@ CREATE PACKAGE BODY test2 AS END; $$ DELIMITER ;$$ +show warnings; DROP PACKAGE test2; @@ -367,10 +368,13 @@ UPDATE mysql.proc SET `body`='garbage' --source sp-cache-invalidate.inc --error ER_SP_PROC_TABLE_CORRUPT SELECT test2.f1(); +show warnings; --error ER_SP_PROC_TABLE_CORRUPT SELECT test2.f1(); +show warnings; --error ER_SP_PROC_TABLE_CORRUPT SELECT test2.f1(); +show warnings; DROP PACKAGE test2; @@ -403,10 +407,13 @@ UPDATE mysql.proc SET `body`='garbage' --source sp-cache-invalidate.inc --error ER_SP_PROC_TABLE_CORRUPT CALL test2.p1(); +show warnings; --error ER_SP_PROC_TABLE_CORRUPT CALL test2.p1(); +show warnings; --error ER_SP_PROC_TABLE_CORRUPT CALL test2.p1(); +show warnings; DROP PACKAGE test2; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 6f366e18b2f..e526363029b 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -5722,8 +5722,9 @@ ER_SP_RECURSION_LIMIT eng "Recursive limit %d (as set by the max_sp_recursion_depth variable) was exceeded for routine %.192s" ger "Rekursionsgrenze %d (durch Variable max_sp_recursion_depth gegeben) wurde für Routine %.192s überschritten" ER_SP_PROC_TABLE_CORRUPT - eng "Failed to load routine %-.192s. The table mysql.proc is missing, corrupt, or contains bad data (internal code %d)" - ger "Routine %-.192s konnte nicht geladen werden. Die Tabelle mysql.proc fehlt, ist beschädigt, oder enthält fehlerhaften Daten (interner Code: %d)" + eng "Failed to load routine %-.192s (internal code %d). For more details, run SHOW WARNINGS" + ger "Fehler beim Laden der Routine %-.192s (interner Code %d). Weitere Informationen finden Sie unter SHOW WARNINGS" + ukr "Невдала спроба завантажити процедуру %-.192s (внутрішний код %d). Для отримання детальної інформації використовуйте SHOW WARNINGS" ER_SP_WRONG_NAME 42000 eng "Incorrect routine name '%-.192s'" ger "Ungültiger Routinenname '%-.192s'" From c6eb127ca88eb998fc3a7be122845d869a8d3ffc Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Sat, 3 Oct 2020 19:06:05 +0200 Subject: [PATCH 071/323] - Fix allocating work space larger than 4GB The variable connect_work_size is now ulong or ulonglong for 64bit machines. modified: storage/connect/ha_connect.cc modified: storage/connect/user_connect.cc --- storage/connect/ha_connect.cc | 31 ++++++++++++++++++++----------- storage/connect/user_connect.cc | 12 ++++++------ 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index e39b5cebaf4..cf2a86185ef 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -170,9 +170,9 @@ #define JSONMAX 10 // JSON Default max grp size extern "C" { - char version[]= "Version 1.07.0001 September 30, 2020"; + char version[]= "Version 1.07.0002 October 03, 2020"; #if defined(__WIN__) - char compver[]= "Version 1.07.0001 " __DATE__ " " __TIME__; + char compver[]= "Version 1.07.0002 " __DATE__ " " __TIME__; char slash= '\\'; #else // !__WIN__ char slash= '/'; @@ -254,8 +254,8 @@ TYPCONV GetTypeConv(void); char *GetJsonNull(void); uint GetJsonGrpSize(void); char *GetJavaWrapper(void); -ulong GetWorkSize(void); -void SetWorkSize(ulong); +size_t GetWorkSize(void); +void SetWorkSize(size_t); extern "C" const char *msglang(void); static char *strz(PGLOBAL g, LEX_STRING &ls); @@ -347,11 +347,19 @@ static MYSQL_THDVAR_ENUM( 1, // def (AUTO) &usetemp_typelib); // typelib +#ifdef _WIN64 +// Size used for g->Sarea_Size +static MYSQL_THDVAR_ULONGLONG(work_size, + PLUGIN_VAR_RQCMDARG, + "Size of the CONNECT work area.", + NULL, NULL, SZWORK, SZWMIN, ULONGLONG_MAX, 1); +#else // Size used for g->Sarea_Size static MYSQL_THDVAR_ULONG(work_size, - PLUGIN_VAR_RQCMDARG, - "Size of the CONNECT work area.", - NULL, NULL, SZWORK, SZWMIN, ULONG_MAX, 1); + PLUGIN_VAR_RQCMDARG, + "Size of the CONNECT work area.", + NULL, NULL, SZWORK, SZWMIN, ULONG_MAX, 1); +#endif // Size used when converting TEXT columns to VARCHAR static MYSQL_THDVAR_INT(conv_size, @@ -461,8 +469,8 @@ char *GetJsonNull(void) {return connect_hton ? THDVAR(current_thd, json_null) : NULL;} uint GetJsonGrpSize(void) {return connect_hton ? THDVAR(current_thd, json_grp_size) : 10;} -ulong GetWorkSize(void) {return THDVAR(current_thd, work_size);} -void SetWorkSize(ulong) +size_t GetWorkSize(void) {return (size_t)THDVAR(current_thd, work_size);} +void SetWorkSize(size_t) { // Changing the session variable value seems to be impossible here // and should be done in a check function @@ -472,7 +480,8 @@ void SetWorkSize(ulong) #if defined(JAVA_SUPPORT) char *GetJavaWrapper(void) -{return connect_hton ? THDVAR(current_thd, java_wrapper) : (char*)"wrappers/JdbcInterface";} +{return connect_hton ? THDVAR(current_thd, java_wrapper) + : (char*)"wrappers/JdbcInterface";} #endif // JAVA_SUPPORT #if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) @@ -7376,7 +7385,7 @@ maria_declare_plugin(connect) 0x0107, /* version number (1.07) */ NULL, /* status variables */ connect_system_variables, /* system variables */ - "1.07.0001", /* string version */ + "1.07.0002", /* string version */ MariaDB_PLUGIN_MATURITY_STABLE /* maturity */ } maria_declare_plugin_end; diff --git a/storage/connect/user_connect.cc b/storage/connect/user_connect.cc index c061294c57e..5dbdb8f56f0 100644 --- a/storage/connect/user_connect.cc +++ b/storage/connect/user_connect.cc @@ -58,8 +58,8 @@ PCONNECT user_connect::to_users= NULL; /****************************************************************************/ /* Get the work_size SESSION variable value . */ /****************************************************************************/ -ulong GetWorkSize(void); -void SetWorkSize(ulong); +size_t GetWorkSize(void); +void SetWorkSize(size_t); /* -------------------------- class user_connect -------------------------- */ @@ -97,7 +97,7 @@ user_connect::~user_connect() bool user_connect::user_init() { // Initialize Plug-like environment - ulong worksize= GetWorkSize(); + size_t worksize= GetWorkSize(); PACTIVITY ap= NULL; PDBUSER dup= NULL; @@ -157,16 +157,16 @@ void user_connect::SetHandler(ha_connect *hc) bool user_connect::CheckCleanup(bool force) { if (thdp->query_id > last_query_id || force) { - ulong worksize = GetWorkSize(); + size_t worksize = GetWorkSize(); size_t size = g->Sarea_Size; PlugCleanup(g, true); - if (size != (size_t)worksize) { + if (size != worksize) { FreeSarea(g); // Check whether the work area could be allocated - if (AllocSarea(g, (size_t)worksize)) { + if (AllocSarea(g, worksize)) { AllocSarea(g, size); SetWorkSize(g->Sarea_Size); // Was too big } // endif sarea From 199bc67144b3b1b8d1532fd3c5913f509b4b96ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 5 Oct 2020 09:12:12 +0300 Subject: [PATCH 072/323] Cleanup: Remove unused SYNC_REC_LOCK SYNC_REC_LOCK was never used in the public history of InnoDB, starting with commit 132e667b0bbbe33137b6baeb59f3f22b7524f066. --- storage/innobase/include/sync0types.h | 1 - storage/innobase/sync/sync0debug.cc | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h index 348515e0781..ca8291f666a 100644 --- a/storage/innobase/include/sync0types.h +++ b/storage/innobase/include/sync0types.h @@ -227,7 +227,6 @@ enum latch_level_t { SYNC_PAGE_CLEANER, SYNC_PURGE_QUEUE, SYNC_TRX_SYS_HEADER, - SYNC_REC_LOCK, SYNC_THREADS, SYNC_TRX, SYNC_TRX_SYS, diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc index d78d15ac079..edcb886fe5c 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -472,7 +472,6 @@ LatchDebug::LatchDebug() LEVEL_MAP_INSERT(SYNC_PAGE_CLEANER); LEVEL_MAP_INSERT(SYNC_PURGE_QUEUE); LEVEL_MAP_INSERT(SYNC_TRX_SYS_HEADER); - LEVEL_MAP_INSERT(SYNC_REC_LOCK); LEVEL_MAP_INSERT(SYNC_THREADS); LEVEL_MAP_INSERT(SYNC_TRX); LEVEL_MAP_INSERT(SYNC_TRX_SYS); @@ -843,15 +842,6 @@ LatchDebug::check_order( } break; - case SYNC_REC_LOCK: - - if (find(latches, SYNC_LOCK_SYS) != 0) { - basic_check(latches, level, SYNC_REC_LOCK - 1); - } else { - basic_check(latches, level, SYNC_REC_LOCK); - } - break; - case SYNC_IBUF_BITMAP: /* Either the thread must own the master mutex to all From 295e2d500b31819422c97ad77beb6226b961c207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 5 Oct 2020 09:34:27 +0300 Subject: [PATCH 073/323] MDEV-16664: Add deprecation warning for innodb_lock_schedule_algorithm=VATS The setting innodb_lock_schedule_algorithm=VATS that was introduced in MDEV-11039 (commit 021212b525e39d332cddd0b9f1656e2fa8044905) causes conflicting exclusive locks to be incorrectly granted to two transactions. Specifically, in lock_rec_insert_by_trx_age() the predicate !lock_rec_has_to_wait_in_queue(in_lock) would hold even though an active transaction is already holding an exclusive lock. This was observed between two DELETE of the same clustered index record. The HASH_DELETE invocation in lock_rec_enqueue_waiting() may be related. Due to lack of progress in diagnosing the problem, we will deprecate the option and issue a warning that using it may corrupt data. The unsafe option was enabled between commit 0c15d1a6ff0d18da946f050cfeac176387a76112 (MariaDB 10.2.3) and the parent of commit 1cc1d0429da14a041a6240c6fce17e0d31cad8e2 (MariaDB 10.2.17, 10.3.9). --- .../suite/innodb/t/innodb_trx_weight.opt | 1 - .../suite/sys_vars/t/wsrep_on_basic.opt | 1 - storage/innobase/handler/ha_innodb.cc | 19 ++++++++++++++----- 3 files changed, 14 insertions(+), 7 deletions(-) delete mode 100644 mysql-test/suite/innodb/t/innodb_trx_weight.opt delete mode 100644 mysql-test/suite/sys_vars/t/wsrep_on_basic.opt diff --git a/mysql-test/suite/innodb/t/innodb_trx_weight.opt b/mysql-test/suite/innodb/t/innodb_trx_weight.opt deleted file mode 100644 index bac39c99a74..00000000000 --- a/mysql-test/suite/innodb/t/innodb_trx_weight.opt +++ /dev/null @@ -1 +0,0 @@ ---loose-innodb-lock-schedule-algorithm=FCFS diff --git a/mysql-test/suite/sys_vars/t/wsrep_on_basic.opt b/mysql-test/suite/sys_vars/t/wsrep_on_basic.opt deleted file mode 100644 index aa1fb6cb155..00000000000 --- a/mysql-test/suite/sys_vars/t/wsrep_on_basic.opt +++ /dev/null @@ -1 +0,0 @@ ---innodb-lock-schedule-algorithm=FCFS diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 67f110f41ab..70404eb03cd 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3750,14 +3750,23 @@ innobase_init( goto error; } + if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS) { + ib::warn() << "The parameter innodb_lock_schedule_algorithm" + " is deprecated, and the setting" + " innodb_lock_schedule_algorithm=vats" + " may cause corruption. The parameter may be removed" + " in future releases."; + #ifdef WITH_WSREP - /* Currently, Galera does not support VATS lock schedule algorithm. */ - if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS - && global_system_variables.wsrep_on) { - ib::info() << "For Galera, using innodb_lock_schedule_algorithm=fcfs"; - innodb_lock_schedule_algorithm = INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS; + /* Currently, Galera does not support VATS lock schedule algorithm. */ + if (global_system_variables.wsrep_on) { + ib::info() << "For Galera, using innodb_lock_schedule_algorithm=fcfs"; + innodb_lock_schedule_algorithm = INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS; + } +#endif /* WITH_WSREP */ } +#ifdef WITH_WSREP /* Print deprecation info if xtrabackup is used for SST method */ if (global_system_variables.wsrep_on && wsrep_sst_method From 0aef658dfab527bf91e805589230f907e57bc6b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 5 Oct 2020 10:34:01 +0300 Subject: [PATCH 074/323] Remove unnecessary and incorrect add_suppression. Changes to be committed: modified: mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result modified: mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test --- mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result | 1 - mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test | 2 -- 2 files changed, 3 deletions(-) diff --git a/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result index 8497e220523..4e4893532fb 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result @@ -1,7 +1,6 @@ # # wsrep_cluster_address # -call mtr.add_suppression("safe_mutex: Found wrong usage of mutex.*"); # save the initial value SET @wsrep_cluster_address_global_saved = @@global.wsrep_cluster_address; # default diff --git a/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test index 136c0745e42..6e0767ce853 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test @@ -4,8 +4,6 @@ --echo # wsrep_cluster_address --echo # -call mtr.add_suppression("safe_mutex: Found wrong usage of mutex.*"); - --echo # save the initial value SET @wsrep_cluster_address_global_saved = @@global.wsrep_cluster_address; From 861cd4ce286e7b41cc38facfc86c358e15161a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 5 Oct 2020 13:05:11 +0300 Subject: [PATCH 075/323] MDEV-22871 fixup: Remove SYNC_BUF_PAGE_HASH This was missed in commit 5155a300fab85e97217c75e3ba3c3ce78082dd8a. --- storage/innobase/include/sync0types.h | 2 -- storage/innobase/sync/sync0debug.cc | 2 -- 2 files changed, 4 deletions(-) diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h index 910601ed1dd..9ea104642a1 100644 --- a/storage/innobase/include/sync0types.h +++ b/storage/innobase/include/sync0types.h @@ -192,8 +192,6 @@ enum latch_level_t { SYNC_BUF_FLUSH_LIST, - SYNC_BUF_PAGE_HASH, - SYNC_BUF_POOL, SYNC_POOL, diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc index 1787861f399..0c653344c12 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -455,7 +455,6 @@ LatchDebug::LatchDebug() LEVEL_MAP_INSERT(SYNC_ANY_LATCH); LEVEL_MAP_INSERT(SYNC_DOUBLEWRITE); LEVEL_MAP_INSERT(SYNC_BUF_FLUSH_LIST); - LEVEL_MAP_INSERT(SYNC_BUF_PAGE_HASH); LEVEL_MAP_INSERT(SYNC_BUF_POOL); LEVEL_MAP_INSERT(SYNC_POOL); LEVEL_MAP_INSERT(SYNC_POOL_MANAGER); @@ -767,7 +766,6 @@ LatchDebug::check_order( case SYNC_POOL: case SYNC_POOL_MANAGER: case SYNC_RECV_WRITER: - case SYNC_BUF_PAGE_HASH: basic_check(latches, level, level); break; From 307258c8eec73522805345178aad906aa86a61af Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Mon, 5 Oct 2020 12:29:51 +0200 Subject: [PATCH 076/323] - Use BIN type when charset='binary' modified: storage/connect/ha_connect.cc - Allow JSON columns to be "binary" By setting their type as VARBINAY(132) and their name begin with Jbin_ modified: storage/connect/json.h modified: storage/connect/jsonudf.cpp modified: storage/connect/tabjson.cpp modified: storage/connect/value.cpp modified: storage/connect/value.h - CHARSET BINARY cannot be used for text columns modified: storage/connect/mysql-test/connect/r/updelx.result modified: storage/connect/mysql-test/connect/t/updelx.test --- storage/connect/ha_connect.cc | 9 ++++--- storage/connect/json.h | 24 ++++++++++++++++++- storage/connect/jsonudf.cpp | 10 ++++---- .../mysql-test/connect/r/updelx.result | 4 ++-- .../connect/mysql-test/connect/t/updelx.test | 4 ++-- storage/connect/tabjson.cpp | 13 +++++++++- storage/connect/value.cpp | 9 +++++++ storage/connect/value.h | 7 +++--- 8 files changed, 64 insertions(+), 16 deletions(-) diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index cf2a86185ef..fd00b4878a9 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -1586,6 +1586,9 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf) chset= (char *)fp->charset()->name; + if (!strcmp(chset, "binary")) + v = 'B'; // Binary string + switch (fp->type()) { case MYSQL_TYPE_BLOB: case MYSQL_TYPE_VARCHAR: @@ -1595,7 +1598,7 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf) default: pcf->Type= MYSQLtoPLG(fp->type(), &v); break; - } // endswitch SQL type + } // endswitch SQL type switch (pcf->Type) { case TYPE_STRING: @@ -1649,7 +1652,7 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf) break; default: break; - } // endswitch type + } // endswitch type if (fp->flags & UNSIGNED_FLAG) pcf->Flags |= U_UNSIGNED; @@ -2222,7 +2225,7 @@ int ha_connect::MakeRecord(char *buf) case TYPE_BIN: p= value->GetCharValue(); charset= &my_charset_bin; - rc= fp->store(p, strlen(p), charset, CHECK_FIELD_WARN); + rc= fp->store(p, value->GetSize(), charset, CHECK_FIELD_WARN); break; case TYPE_DOUBLE: rc= fp->store(value->GetFloatValue()); diff --git a/storage/connect/json.h b/storage/connect/json.h index 1d058ad575f..d949f244e21 100644 --- a/storage/connect/json.h +++ b/storage/connect/json.h @@ -1,10 +1,11 @@ /**************** json H Declares Source Code File (.H) ****************/ /* Name: json.h Version 1.2 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2014 - 2017 */ +/* (C) Copyright to the author Olivier BERTRAND 2014 - 2020 */ /* */ /* This file contains the JSON classes declares. */ /***********************************************************************/ +#include #include "value.h" #if defined(_DEBUG) @@ -44,6 +45,27 @@ typedef struct { int len; } STRG, *PSG; +// BSON size should be equal on Linux and Windows +#define BMX 255 +typedef struct BSON* PBSON; + +/***********************************************************************/ +/* Structure used to return binary json to Json UDF functions. */ +/***********************************************************************/ +struct BSON { + char Msg[BMX + 1]; + char *Filename; + PGLOBAL G; + int Pretty; + ulong Reslen; + my_bool Changed; + PJSON Top; + PJSON Jsp; + PBSON Bsp; +}; // end of struct BSON + +PBSON JbinAlloc(PGLOBAL g, UDF_ARGS* args, ulong len, PJSON jsp); + char *NextChr(PSZ s, char sep); char *GetJsonNull(void); diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp index a1c6a77d1f2..0a862d2917d 100644 --- a/storage/connect/jsonudf.cpp +++ b/storage/connect/jsonudf.cpp @@ -1076,6 +1076,7 @@ my_bool JSNX::AddPath(void) /* --------------------------------- JSON UDF ---------------------------------- */ +#if 0 // Moved to json.h // BSON size should be equal on Linux and Windows #define BMX 255 typedef struct BSON *PBSON; @@ -1094,11 +1095,12 @@ struct BSON { PJSON Jsp; PBSON Bsp; }; // end of struct BSON +#endif // 0 /*********************************************************************************/ /* Allocate and initialize a BSON structure. */ /*********************************************************************************/ -static PBSON JbinAlloc(PGLOBAL g, UDF_ARGS *args, ulong len, PJSON jsp) +PBSON JbinAlloc(PGLOBAL g, UDF_ARGS *args, ulong len, PJSON jsp) { PBSON bsp = (PBSON)PlgDBSubAlloc(g, NULL, sizeof(BSON)); @@ -1111,7 +1113,7 @@ static PBSON JbinAlloc(PGLOBAL g, UDF_ARGS *args, ulong len, PJSON jsp) bsp->Reslen = len; bsp->Changed = false; bsp->Top = bsp->Jsp = jsp; - bsp->Bsp = (IsJson(args, 0) == 3) ? (PBSON)args->args[0] : NULL; + bsp->Bsp = (args && IsJson(args, 0) == 3) ? (PBSON)args->args[0] : NULL; } else PUSH_WARNING(g->Message); @@ -1422,7 +1424,7 @@ static int IsJson(UDF_ARGS *args, uint i, bool b) n = 2; // arg is a json file name } else if (b) { char *sap; - PGLOBAL g = PlugInit(NULL, args->lengths[i] * M + 1024); + PGLOBAL g = PlugInit(NULL, (size_t)args->lengths[i] * M + 1024); JsonSubSet(g); sap = MakePSZ(g, args, i); @@ -5763,7 +5765,7 @@ char *json_serialize(UDF_INIT *initid, UDF_ARGS *args, char *result, // Keep result of constant function g->Xchk = (initid->const_item) ? str : NULL; } else { - *error = 1; + // *error = 1; str = strcpy(result, "Argument is not a Jbin tree"); } // endif diff --git a/storage/connect/mysql-test/connect/r/updelx.result b/storage/connect/mysql-test/connect/r/updelx.result index 2aed1e06928..bb82afcc1a8 100644 --- a/storage/connect/mysql-test/connect/r/updelx.result +++ b/storage/connect/mysql-test/connect/r/updelx.result @@ -978,7 +978,7 @@ DROP TABLE t1; # FIX table CREATE TABLE t1 ( id INT(4) KEY NOT NULL, -msg VARCHAR(16) CHARSET BINARY DISTRIB=CLUSTERED) +msg VARCHAR(16) DISTRIB=CLUSTERED) ENGINE=CONNECT TABLE_TYPE=FIX BLOCK_SIZE=4; Warnings: Warning 1105 No file name. Table will use t1.fix @@ -1345,7 +1345,7 @@ DROP TABLE t1; # BIN table CREATE TABLE t1 ( id INT(4) KEY NOT NULL, -msg VARCHAR(16) CHARSET BINARY DISTRIB=CLUSTERED) +msg VARCHAR(16) DISTRIB=CLUSTERED) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=8; Warnings: Warning 1105 No file name. Table will use t1.bin diff --git a/storage/connect/mysql-test/connect/t/updelx.test b/storage/connect/mysql-test/connect/t/updelx.test index 19d0d790a30..f6291432e48 100644 --- a/storage/connect/mysql-test/connect/t/updelx.test +++ b/storage/connect/mysql-test/connect/t/updelx.test @@ -36,7 +36,7 @@ DROP TABLE t1; --echo # FIX table CREATE TABLE t1 ( id INT(4) KEY NOT NULL, -msg VARCHAR(16) CHARSET BINARY DISTRIB=CLUSTERED) +msg VARCHAR(16) DISTRIB=CLUSTERED) ENGINE=CONNECT TABLE_TYPE=FIX BLOCK_SIZE=4; -- source updelx.inc ALTER TABLE t1 MAPPED=YES; @@ -48,7 +48,7 @@ DROP TABLE t1; --echo # BIN table CREATE TABLE t1 ( id INT(4) KEY NOT NULL, -msg VARCHAR(16) CHARSET BINARY DISTRIB=CLUSTERED) +msg VARCHAR(16) DISTRIB=CLUSTERED) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=8; -- source updelx.inc ALTER TABLE t1 MAPPED=YES; diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index 08040884449..3ab750e67f8 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -1486,7 +1486,18 @@ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp) if (Value->IsTypeNum()) { strcpy(g->Message, "Cannot make Json for a numeric column"); Value->Reset(); - } else + } else if (Value->GetType() == TYPE_BIN) { + if (Value->GetClen() >= sizeof(BSON)) { + ULONG len = Tjp->Lrecl ? Tjp->Lrecl : 500; + PBSON bsp = JbinAlloc(g, NULL, len, jsp); + + strcat(bsp->Msg, " column"); + ((BINVAL*)Value)->SetBinValue(bsp, sizeof(BSON)); + } else { + strcpy(g->Message, "Column size too small"); + Value->SetValue_char(NULL, 0); + } // endif Clen + } else Value->SetValue_psz(Serialize(g, jsp, NULL, 0)); return Value; diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index df75722d0e8..de04f7678f9 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -2250,6 +2250,15 @@ void BINVAL::SetBinValue(void *p) Len = Clen; } // end of SetBinValue +/***********************************************************************/ +/* BINVAL SetBinValue: fill string with len bytes. */ +/***********************************************************************/ +void BINVAL::SetBinValue(void* p, ulong len) +{ + memcpy(Binp, p, len); + Len = len; +} // end of SetBinValue + /***********************************************************************/ /* GetBinValue: fill a buffer with the internal binary value. */ /* This function checks whether the buffer length is enough and */ diff --git a/storage/connect/value.h b/storage/connect/value.h index 4f7d9a440fa..ee7a1c8032f 100644 --- a/storage/connect/value.h +++ b/storage/connect/value.h @@ -115,8 +115,8 @@ class DllExport VALUE : public BLOCK { virtual void SetValue(ulonglong) {assert(false);} virtual void SetValue(double) {assert(false);} virtual void SetValue_pvblk(PVBLK blk, int n) = 0; - virtual void SetBinValue(void *p) = 0; - virtual bool GetBinValue(void *buf, int buflen, bool go) = 0; + virtual void SetBinValue(void* p) = 0; + virtual bool GetBinValue(void *buf, int buflen, bool go) = 0; virtual int ShowValue(char *buf, int len) = 0; virtual char *GetCharString(char *p) = 0; virtual bool IsEqual(PVAL vp, bool chktype) = 0; @@ -385,7 +385,8 @@ class DllExport BINVAL: public VALUE { virtual void SetValue(ulonglong n); virtual void SetValue(double f); virtual void SetBinValue(void *p); - virtual bool GetBinValue(void *buf, int buflen, bool go); + virtual void SetBinValue(void* p, ulong len); + virtual bool GetBinValue(void *buf, int buflen, bool go); virtual int CompareValue(PVAL) {assert(false); return 0;} virtual int ShowValue(char *buf, int len); virtual char *GetCharString(char *p); From d4138e7eedada2e079f76dca797bf7137088753a Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Mon, 5 Oct 2020 15:21:58 +0200 Subject: [PATCH 077/323] Fix compile error in tabjson.cpp (ULONG -> ulong) --- storage/connect/tabjson.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index 3ab750e67f8..5fa2021331b 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -177,7 +177,7 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt) bool mgo = (GetTypeID(topt->type) == TAB_MONGO); PCSZ level = GetStringTableOption(g, topt, "Level", NULL); - if (level = GetStringTableOption(g, topt, "Depth", level)) { + if ((level = GetStringTableOption(g, topt, "Depth", level))) { lvl = atoi(level); lvl = (lvl > 16) ? 16 : lvl; } else @@ -254,12 +254,14 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt) jsp = (tjsp->GetDoc()) ? tjsp->GetDoc()->GetValue(0) : NULL; } else { - if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0))) - if (!mgo) { - sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty); - return 0; - } else - tdp->Lrecl = 8192; // Should be enough + if (!((tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0)))) { + if (!mgo) { + sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty); + return 0; + } else + tdp->Lrecl = 8192; // Should be enough + + } // endif Lrecl tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF); @@ -1329,7 +1331,7 @@ bool JSONCOL::ParseJpath(PGLOBAL g) { char *p, *p1 = NULL, *p2 = NULL, *pbuf = NULL; int i; - bool a, mul = false; + bool a; if (Parsed) return false; // Already done @@ -1487,8 +1489,8 @@ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp) strcpy(g->Message, "Cannot make Json for a numeric column"); Value->Reset(); } else if (Value->GetType() == TYPE_BIN) { - if (Value->GetClen() >= sizeof(BSON)) { - ULONG len = Tjp->Lrecl ? Tjp->Lrecl : 500; + if ((unsigned)Value->GetClen() >= sizeof(BSON)) { + ulong len = Tjp->Lrecl ? Tjp->Lrecl : 500; PBSON bsp = JbinAlloc(g, NULL, len, jsp); strcat(bsp->Msg, " column"); @@ -1570,7 +1572,6 @@ void JSONCOL::ReadColumn(PGLOBAL g) PVAL JSONCOL::GetColumnValue(PGLOBAL g, PJSON row, int i) { int n = Nod - 1; - bool expd = false; PJAR arp; PJVAL val = NULL; @@ -2130,13 +2131,15 @@ int TDBJSON::Cardinality(PGLOBAL g) { if (!g) return (Xcol || Multiple) ? 0 : 1; - else if (Cardinal < 0) - if (!Multiple) { - if (MakeDocument(g) == RC_OK) - Cardinal = Doc->size(); + else if (Cardinal < 0) { + if (!Multiple) { + if (MakeDocument(g) == RC_OK) + Cardinal = Doc->size(); - } else - return 10; + } else + return 10; + + } // endif Cardinal return Cardinal; } // end of Cardinality From 418850b2df4256da5a722288c2657650dc228842 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 4 Oct 2020 21:24:17 +0200 Subject: [PATCH 078/323] MDEV-23884 donor uses invalid SST methods --- sql/wsrep_sst.cc | 51 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index af4e02b9e55..c9a88cc30c8 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -1667,24 +1667,65 @@ static int sst_donate_other (const char* method, return arg.err; } +/* return true if character can be a part of a filename */ +static bool filename_char(int const c) +{ + return isalnum(c) || (c == '-') || (c == '_') || (c == '.'); +} + +/* return true if character can be a part of an address string */ +static bool address_char(int const c) +{ + return filename_char(c) || + (c == ':') || (c == '[') || (c == ']') || (c == '/'); +} + +static bool check_request_str(const char* const str, + bool (*check) (int c)) +{ + for (size_t i(0); str[i] != '\0'; ++i) + { + if (!check(str[i])) + { + WSREP_WARN("Illegal character in state transfer request: %i (%c).", + str[i], str[i]); + return true; + } + } + + return false; +} + wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx, const void* msg, size_t msg_len, const wsrep_gtid_t* current_gtid, const char* state, size_t state_len, bool bypass) { - /* This will be reset when sync callback is called. - * Should we set wsrep_ready to FALSE here too? */ - - wsrep_config_state.set(WSREP_MEMBER_DONOR); - const char* method = (char*)msg; size_t method_len = strlen (method); + + if (check_request_str(method, filename_char)) + { + WSREP_ERROR("Bad SST method name. SST canceled."); + return WSREP_CB_FAILURE; + } + const char* data = method + method_len + 1; + if (check_request_str(data, address_char)) + { + WSREP_ERROR("Bad SST address string. SST canceled."); + return WSREP_CB_FAILURE; + } + char uuid_str[37]; wsrep_uuid_print (¤t_gtid->uuid, uuid_str, sizeof(uuid_str)); + /* This will be reset when sync callback is called. + * Should we set wsrep_ready to FALSE here too? */ + wsrep_config_state.set(WSREP_MEMBER_DONOR); + wsp::env env(NULL); if (env.error()) { From f4c85ef5ed0b2977fd5db61b166fd59764394234 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 5 Oct 2020 17:52:00 +0200 Subject: [PATCH 079/323] bump VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 42407f29a37..453e11b3aae 100644 --- a/VERSION +++ b/VERSION @@ -1,3 +1,3 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=1 -MYSQL_VERSION_PATCH=46 +MYSQL_VERSION_PATCH=47 From 01ffccd6a4ec2af645b81bcfef8a02f031a492e5 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Mon, 5 Oct 2020 20:01:05 +0300 Subject: [PATCH 080/323] UBSAN: UndefinedBehaviorSanitizer: undefined-behavior ../sql/item_cmpfunc.cc:3650:14 --- sql/item_cmpfunc.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 03648a323d5..69c7eb33852 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4153,8 +4153,11 @@ void Item_func_in::fix_after_pullout(st_select_lex *new_parent, Item **ref, eval_not_null_tables(NULL); } -static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y) +static int srtcmp_in(const void *cs_, const void *x_, const void *y_) { + const CHARSET_INFO *cs= static_cast(cs_); + const String *x= static_cast(x_); + const String *y= static_cast(y_); return cs->coll->strnncollsp(cs, (uchar *) x->ptr(),x->length(), (uchar *) y->ptr(),y->length()); From 577c61e8be02acd08c41bd2b057fd831976171ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 6 Oct 2020 07:47:11 +0300 Subject: [PATCH 081/323] MDEV-23888: Potential server hang on replication with InnoDB In MDEV-21452, SAFE_MUTEX flagged an ordering problem that involved trx_t::mutex, LOCK_global_system_variables, and LOCK_commit_ordered when running ./mtr --no-reorder\ binlog.binlog_checksum,mix binlog.binlog_commit_wait,mix Because LOCK_commit_ordered is acquired by replication code before innobase_commit_ordered() is invoked, and because LOCK_commit_ordered should be below LOCK_global_system_variables in the global latching order, it turns out that we must avoid acquiring LOCK_global_system_variables in any low-level code. It also turns out that lock_rec_lock() acquires lock_sys_t::mutex and then carries on to call lock_rec_enqueue_waiting(), which may invoke THDVAR() via thd_lock_wait_timeout(). This call is problematic if THDVAR() had never been invoked in that thread earlier. innobase_trx_init(): Let us invoke THDVAR() at the start of an InnoDB transaction so that future invocations of THDVAR() will avoid LOCK_global_system_variables acquisition on the same THD. Because the first call to intern_sys_var_ptr() will initialize all session variables by not passing the offset to sync_dynamic_session_variables(), this will indeed make any future THDVAR() invocation mutex-free. There are some THDVAR() calls in other code (related to indexed virtual columns, fulltext indexes, and DDL operations). No SAFE_MUTEX warning was known for those, but there does not appear to be any replication test coverage for indexed virtual columns or fulltext indexes. DDL should be covered, and perhaps DDL code paths were already invoking THDVAR() while not holding any InnoDB mutex. Side note: MySQL should avoid this type of deadlocks since mysql/mysql-server@4d275c89954685e2ed1b368812b3b5a29ddf9389. MariaDB never defined alloc_and_copy_thd_dynamic_variables(), because we prefer to avoid overhead during connection creation. An important part of the deadlock could be the current handling of SET GLOBAL binlog_checksum=NONE; and similar assignments. In binlog_checksum_update(), we would hold LOCK_global_system_variables while potentially acquiring LOCK_commit_ordered in MYSQL_BIN_LOG::open(). Even if that code was changed later to release LOCK_global_system_variables during the write to mysql_bin_log, it could be a good idea for performance to avoid invoking the expensive code path of THDVAR() while holding any InnoDB mutexes, such as lock_sys.mutex in lock_rec_enqueue_waiting(). Thanks to Andrei Elkin for debugging the SAFE_MUTEX issue, and to Sergei Golubchik for the suggestion to invoke THDVAR() early. --- storage/innobase/handler/ha_innodb.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 70404eb03cd..c408b1a1d30 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -2717,6 +2717,12 @@ innobase_trx_init( DBUG_ENTER("innobase_trx_init"); DBUG_ASSERT(thd == trx->mysql_thd); + /* Ensure that thd_lock_wait_timeout(), which may be called + while holding lock_sys.mutex, by lock_rec_enqueue_waiting(), + will not end up acquiring LOCK_global_system_variables in + intern_sys_var_ptr(). */ + THDVAR(thd, lock_wait_timeout); + trx->check_foreigns = !thd_test_options( thd, OPTION_NO_FOREIGN_KEY_CHECKS); From 33f19876a2fbc9378af25cebd0651cd9bdc5407b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 6 Oct 2020 12:03:13 +0300 Subject: [PATCH 082/323] MDEV-18593 : galera.galera_gcache_recover_full_gcache: Test failure: galera_gcache_recover_full_gcache.test: assert_grep.inc failed Grep only the fact that we need to fall back to SST. --- .../galera/r/galera_gcache_recover_full_gcache.result | 10 +++++++++- .../galera/t/galera_gcache_recover_full_gcache.test | 10 ++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/galera/r/galera_gcache_recover_full_gcache.result b/mysql-test/suite/galera/r/galera_gcache_recover_full_gcache.result index 588af5668bb..9b8408b1b58 100644 --- a/mysql-test/suite/galera/r/galera_gcache_recover_full_gcache.result +++ b/mysql-test/suite/galera/r/galera_gcache_recover_full_gcache.result @@ -17,10 +17,18 @@ connection node_2; Performing --wsrep-recover ... Using --wsrep-start-position when starting mysqld ... connection node_1; +SELECT COUNT(*) FROM t1; +COUNT(*) +5 +connection node_2; +SET SESSION wsrep_sync_wait = 15; +SELECT COUNT(*) FROM t1; +COUNT(*) +5 include/diff_servers.inc [servers=1 2] connection node_1; DROP TABLE t1; CALL mtr.add_suppression("Skipped GCache ring buffer recovery"); -include/assert_grep.inc [IST first seqno 2 not found from cache, falling back to SST] +include/assert_grep.inc [not found from cache, falling back to SST] connection node_2; CALL mtr.add_suppression("Skipped GCache ring buffer recovery"); diff --git a/mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.test b/mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.test index b7fd9cf3aed..0d8994f7d7b 100644 --- a/mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.test +++ b/mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.test @@ -38,6 +38,12 @@ INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10)); --source include/galera_wait_ready.inc --let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +SELECT COUNT(*) FROM t1; + +--connection node_2 +SET SESSION wsrep_sync_wait = 15; +SELECT COUNT(*) FROM t1; + --let $diff_servers = 1 2 --source include/diff_servers.inc @@ -48,8 +54,8 @@ DROP TABLE t1; CALL mtr.add_suppression("Skipped GCache ring buffer recovery"); # Confirm that IST did not take place ---let $assert_text = IST first seqno 2 not found from cache, falling back to SST ---let $assert_select = IST first seqno 2 not found from cache, falling back to SST +--let $assert_text = not found from cache, falling back to SST +--let $assert_select = not found from cache, falling back to SST --let $assert_count = 1 --let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.1.err --let $assert_only_after = starting as process From 5d2ddef26e3fce9784e4befb9e2e0960ff2434cd Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Tue, 6 Oct 2020 12:50:12 +0200 Subject: [PATCH 083/323] Fix search for json subtable in tabjson.cpp --- storage/connect/tabjson.cpp | 46 ++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index 5fa2021331b..fcf7f4d182c 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -1995,8 +1995,9 @@ int TDBJSON::MakeNewDoc(PGLOBAL g) /***********************************************************************/ int TDBJSON::MakeDocument(PGLOBAL g) { - char *p, *memory, *objpath, *key = NULL; + char *p, *p1, *p2, *memory, *objpath, *key = NULL; int len, i = 0; + my_bool a; MODE mode = Mode; PJSON jsp; PJOB objp = NULL; @@ -2039,22 +2040,39 @@ int TDBJSON::MakeDocument(PGLOBAL g) if ((objpath = PlugDup(g, Objname))) { if (*objpath == '$') objpath++; if (*objpath == '.') objpath++; + p1 = p2 = NULL; /*********************************************************************/ /* Find the table in the tree structure. */ /*********************************************************************/ - for (; jsp && objpath; objpath = p) { - if ((p = strchr(objpath, Sep))) - *p++ = 0; + for (p = objpath; jsp && p; p = (p2 ? p2 : NULL)) { + a = (p1 != NULL); + p1 = strchr(p, '['); + p2 = strchr(p, '.'); - if (*objpath != '[' && !IsNum(objpath)) { - // objpass is a key + if (!p2) + p2 = p1; + else if (p1) { + if (p1 < p2) + p2 = p1; + else if (p1 == p2 + 1) + *p2++ = 0; // Old syntax .[ + else + p1 = NULL; + + } // endif p1 + + if (p2) + *p2++ = 0; + + if (!a && *p && *p != '[' && !IsNum(p)) { + // obj is a key if (jsp->GetType() != TYPE_JOB) { strcpy(g->Message, "Table path does not match the json file"); return RC_FX; } // endif Type - key = objpath; + key = p; objp = jsp->GetObject(); arp = NULL; val = objp->GetValue(key); @@ -2065,15 +2083,15 @@ int TDBJSON::MakeDocument(PGLOBAL g) } // endif val } else { - if (*objpath == '[') { + if (*p == '[') { // Old style - if (objpath[strlen(objpath) - 1] != ']') { - sprintf(g->Message, "Invalid Table path %s", Objname); + if (p[strlen(p) - 1] != ']') { + sprintf(g->Message, "Invalid Table path near %s", p); return RC_FX; } else - objpath++; + p++; - } // endif objpath + } // endif p if (jsp->GetType() != TYPE_JAR) { strcpy(g->Message, "Table path does not match the json file"); @@ -2082,7 +2100,7 @@ int TDBJSON::MakeDocument(PGLOBAL g) arp = jsp->GetArray(); objp = NULL; - i = atoi(objpath) - B; + i = atoi(p) - B; val = arp->GetValue(i); if (!val) { @@ -2093,7 +2111,7 @@ int TDBJSON::MakeDocument(PGLOBAL g) } // endif jsp = val->GetJson(); - } // endfor objpath + } // endfor p } // endif objpath From 350c9eb705477afef876e982201ad55dcc65bc9c Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 6 Oct 2020 13:50:26 +0300 Subject: [PATCH 084/323] MDEV-23894 UBSAN: several call to function show_binlog_vars(THD*, st_mysql_show_var*, char*) through pointer to incorrect function type 'int (*)(THD *, st_mysql_show_var *, void *, system_status_var *, enum_var_type) errors --- sql/log.cc | 3 ++- sql/mysqld.cc | 10 +++++----- sql/wsrep_mysqld.h | 4 ++-- sql/wsrep_var.cc | 4 ++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/sql/log.cc b/sql/log.cc index cb484210c50..c784dc1c308 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -10403,7 +10403,8 @@ binlog_checksum_update(MYSQL_THD thd, struct st_mysql_sys_var *var, } -static int show_binlog_vars(THD *thd, SHOW_VAR *var, char *buff) +static int show_binlog_vars(THD *thd, SHOW_VAR *var, void *, + system_status_var *status_var, enum_var_type) { mysql_bin_log.set_status_variables(thd); var->type= SHOW_ARRAY; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 4516e8ff596..ad0b1d9c000 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8337,8 +8337,8 @@ show_ssl_get_server_not_after(THD *thd, SHOW_VAR *var, char *buff, #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ -static int show_default_keycache(THD *thd, SHOW_VAR *var, char *buff, - enum enum_var_type scope) +static int show_default_keycache(THD *thd, SHOW_VAR *var, void *buff, + system_status_var *, enum_var_type) { struct st_data { KEY_CACHE_STATISTICS stats; @@ -8371,7 +8371,7 @@ static int show_default_keycache(THD *thd, SHOW_VAR *var, char *buff, v->name= 0; - DBUG_ASSERT((char*)(v+1) <= buff + SHOW_VAR_FUNC_BUFF_SIZE); + DBUG_ASSERT((char*)(v+1) <= static_cast(buff) + SHOW_VAR_FUNC_BUFF_SIZE); #undef set_one_keycache_var @@ -8395,8 +8395,8 @@ static int show_memory_used(THD *thd, SHOW_VAR *var, char *buff, #ifndef DBUG_OFF -static int debug_status_func(THD *thd, SHOW_VAR *var, char *buff, - enum enum_var_type scope) +static int debug_status_func(THD *thd, SHOW_VAR *var, void *buff, + system_status_var *, enum_var_type) { #define add_var(X,Y,Z) \ v->name= X; \ diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index e28b90885b4..3d68eda0d6b 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -131,8 +131,8 @@ extern const char* wsrep_provider_name; extern const char* wsrep_provider_version; extern const char* wsrep_provider_vendor; -int wsrep_show_status(THD *thd, SHOW_VAR *var, char *buff, - enum enum_var_type scope); +int wsrep_show_status(THD *thd, SHOW_VAR *var, void *buff, + system_status_var *status_var, enum_var_type scope); int wsrep_init(); void wsrep_deinit(bool free_options); diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index 9777cc6ec62..45f929de9de 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -726,8 +726,8 @@ static int show_var_cmp(const void *var1, const void *var2) return strcasecmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name); } -int wsrep_show_status (THD *thd, SHOW_VAR *var, char *buff, - enum enum_var_type scope) +int wsrep_show_status (THD *thd, SHOW_VAR *var, void *buff, + system_status_var *, enum_var_type scope) { uint i, maxi= SHOW_VAR_FUNC_BUFF_SIZE / sizeof(*var) - 1; SHOW_VAR *v= (SHOW_VAR *)buff; From b3a9fbdbab5d29408a637d9d2422a75876f76756 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 6 Oct 2020 17:07:52 +1100 Subject: [PATCH 085/323] travis: 10.2 only - make faster Remove from debian build: * tokudb * mroonga * spider * ograph * embedded server Add ccache to debian build. Backport 10.3 changes to autobake-deb that make travis faster. Merge instructions: Drop this commit on merge to 10.3 --- debian/autobake-deb.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/autobake-deb.sh b/debian/autobake-deb.sh index 687f2356153..ddef69bb350 100755 --- a/debian/autobake-deb.sh +++ b/debian/autobake-deb.sh @@ -26,6 +26,12 @@ then # Don't include test suite package on Travis-CI to make the build time shorter sed '/Package: mariadb-test-data/,/^$/d' -i debian/control sed '/Package: mariadb-test/,/^$/d' -i debian/control + sed '/Package: mariadb-plugin-tokudb/,/^$/d' -i debian/control + sed '/Package: mariadb-plugin-mroonga/,/^$/d' -i debian/control + sed '/Package: mariadb-plugin-spider/,/^$/d' -i debian/control + sed '/Package: mariadb-plugin-oqgraph/,/^$/d' -i debian/control + export MYSQL_COMPILER_LAUNCHER=ccache + sed 's|-DDEB|-DPLUGIN_TOKUDB=NO -DPLUGIN_MROONGA=NO -DPLUGIN_SPIDER=NO -DPLUGIN_OQGRAPH=NO -DPLUGIN_PERFSCHEMA=NO -WITH_EMBEDDED_SERVER=OFF -DDEB|' -i debian/rules fi From 5933081d8b05893b8987c0c89237b4764a2f22e0 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Fri, 2 Oct 2020 17:30:02 +0200 Subject: [PATCH 086/323] MDEV-18163 Assertion `table_share->tmp_table != NO_TMP_TABLE || m_lock_type != 2' failed in handler::ha_rnd_next(); / Assertion `table_list->table' failed in find_field_in_table_ref / ERROR 1901 (on optimized builds) Add the same check for altering DEFAULT used as for CREATE TABLE. --- mysql-test/r/alter_table.result | 11 +++++++++++ mysql-test/t/alter_table.test | 14 ++++++++++++++ sql/sql_yacc.yy | 2 ++ 3 files changed, 27 insertions(+) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index b4379f49c7e..69322bb9028 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -2506,5 +2506,16 @@ t2 CREATE TABLE `t2` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 DROP TABLE t2, t1; # +# MDEV-18163: Assertion `table_share->tmp_table != NO_TMP_TABLE || +# m_lock_type != 2' failed in handler::ha_rnd_next(); / Assertion +# `table_list->table' failed in find_field_in_table_ref / ERROR 1901 +# (on optimized builds) +# +CREATE TABLE t1 (k1 varchar(10) DEFAULT 5); +CREATE TABLE t2 (i1 int); +ALTER TABLE t1 ALTER COLUMN k1 SET DEFAULT (SELECT 1 FROM t2 limit 1); +ERROR HY000: Function or expression 'select ...' cannot be used in the DEFAULT clause of `k1` +DROP TABLE t1,t2; +# # End of 10.2 tests # diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 0f685c470ad..2f1a40cbacd 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -2030,6 +2030,20 @@ ALTER TABLE t2 DROP CONSTRAINT PRIMARY KEY; SHOW CREATE TABLE t2; DROP TABLE t2, t1; +--echo # +--echo # MDEV-18163: Assertion `table_share->tmp_table != NO_TMP_TABLE || +--echo # m_lock_type != 2' failed in handler::ha_rnd_next(); / Assertion +--echo # `table_list->table' failed in find_field_in_table_ref / ERROR 1901 +--echo # (on optimized builds) +--echo # + + +CREATE TABLE t1 (k1 varchar(10) DEFAULT 5); +CREATE TABLE t2 (i1 int); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +ALTER TABLE t1 ALTER COLUMN k1 SET DEFAULT (SELECT 1 FROM t2 limit 1); +DROP TABLE t1,t2; + --echo # --echo # End of 10.2 tests --echo # diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 386c86cb3e2..138d5e13701 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7692,6 +7692,8 @@ alter_list_item: | ALTER opt_column field_ident SET DEFAULT column_default_expr { LEX *lex=Lex; + if (check_expression($6, $3.str, VCOL_DEFAULT)) + MYSQL_YYABORT; Alter_column *ac= new (thd->mem_root) Alter_column($3.str,$6); if (ac == NULL) MYSQL_YYABORT; From 2b832151ad66556cb07ed232b139411f4b6defe3 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 6 Oct 2020 15:07:06 +0300 Subject: [PATCH 087/323] MDEV-23787 mtr --rr fixes 1. rr record -h randomizes number of processors. Disable THREAD_POOL_SIZE check. 2. check for kernel.perf_event_paranoid for user-friendly error message. --- mysql-test/include/mtr_check.sql | 1 + mysql-test/mysql-test-run.pl | 10 ++++++++++ mysql-test/suite/funcs_1/r/is_routines_embedded.result | 6 +++--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/mysql-test/include/mtr_check.sql b/mysql-test/include/mtr_check.sql index 95f0f5420a4..e0b7fcdd2ad 100644 --- a/mysql-test/include/mtr_check.sql +++ b/mysql-test/include/mtr_check.sql @@ -35,6 +35,7 @@ BEGIN AND variable_name != 'INNODB_BUFFER_POOL_LOAD_AT_STARTUP' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' + AND variable_name != 'THREAD_POOL_SIZE' ORDER BY variable_name; -- Dump all databases, there should be none diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 178d65aca41..30cc833ad99 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1820,6 +1820,16 @@ sub command_line_setup { $opt_shutdown_timeout= 24 * 60; # One day for PID file creation (this is given in seconds not minutes) $opt_start_timeout= 24 * 60 * 60; + if ($opt_rr && open(my $fh, '<', '/proc/sys/kernel/perf_event_paranoid')) + { + my $perf_event_paranoid= <$fh>; + close $fh; + chomp $perf_event_paranoid; + if ($perf_event_paranoid == 0) + { + mtr_error("rr requires kernel.perf_event_paranoid set to 1"); + } + } } # -------------------------------------------------------------------------- diff --git a/mysql-test/suite/funcs_1/r/is_routines_embedded.result b/mysql-test/suite/funcs_1/r/is_routines_embedded.result index 193265433aa..282efe8e977 100644 --- a/mysql-test/suite/funcs_1/r/is_routines_embedded.result +++ b/mysql-test/suite/funcs_1/r/is_routines_embedded.result @@ -197,7 +197,7 @@ sp_6_408002_2 def db_datadict_2 sp_6_408002_2 PROCEDURE NULL NULL NULL NULL NUL SELECT * FROM db_datadict_2.res_6_408002_2; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost latin1 latin1_swedish_ci latin1_swedish_ci add_suppression def mtr add_suppression PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN INSERT INTO test_suppressions (pattern) VALUES (pattern); FLUSH NO_WRITE_TO_BINLOG TABLE test_suppressions; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci -check_testcase def mtr check_testcase PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE variable_name NOT IN ('timestamp', 'innodb_file_format_max') AND variable_name not like "Last_IO_Err*" AND variable_name != 'INNODB_IBUF_MAX_SIZE' AND variable_name != 'INNODB_USE_NATIVE_AIO' AND variable_name != 'INNODB_BUFFER_POOL_LOAD_AT_STARTUP' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' ORDER BY variable_name; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mtr_wsrep_notify', 'wsrep_schema'); SELECT table_name AS tables_in_test FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='test'; SELECT CONCAT(table_schema, '.', table_name) AS tables_in_mysql FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='mysql' ORDER BY tables_in_mysql; SELECT CONCAT(table_schema, '.', table_name) AS columns_in_mysql, column_name, ordinal_position, column_default, is_nullable, data_type, character_maximum_length, character_octet_length, numeric_precision, numeric_scale, character_set_name, collation_name, column_type, column_key, extra, column_comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='mysql' ORDER BY columns_in_mysql; SELECT * FROM INFORMATION_SCHEMA.EVENTS; SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME NOT IN ('gs_insert', 'ts_insert'); SELECT * FROM INFORMATION_SCHEMA.ROUTINES; SHOW STATUS LIKE 'slave_open_temp_tables'; checksum table mysql.columns_priv, mysql.db, mysql.func, mysql.help_category, mysql.help_keyword, mysql.help_relation, mysql.host, mysql.plugin, mysql.proc, mysql.procs_priv, mysql.roles_mapping, mysql.tables_priv, mysql.time_zone, mysql.time_zone_leap_second, mysql.time_zone_name, mysql.time_zone_transition, mysql.time_zone_transition_type, mysql.user; SELECT * FROM INFORMATION_SCHEMA.PLUGINS; select * from information_schema.session_variables where variable_name = 'debug_sync'; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci +check_testcase def mtr check_testcase PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE variable_name NOT IN ('timestamp', 'innodb_file_format_max') AND variable_name not like "Last_IO_Err*" AND variable_name != 'INNODB_IBUF_MAX_SIZE' AND variable_name != 'INNODB_USE_NATIVE_AIO' AND variable_name != 'INNODB_BUFFER_POOL_LOAD_AT_STARTUP' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' AND variable_name != 'THREAD_POOL_SIZE' ORDER BY variable_name; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mtr_wsrep_notify', 'wsrep_schema'); SELECT table_name AS tables_in_test FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='test'; SELECT CONCAT(table_schema, '.', table_name) AS tables_in_mysql FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='mysql' ORDER BY tables_in_mysql; SELECT CONCAT(table_schema, '.', table_name) AS columns_in_mysql, column_name, ordinal_position, column_default, is_nullable, data_type, character_maximum_length, character_octet_length, numeric_precision, numeric_scale, character_set_name, collation_name, column_type, column_key, extra, column_comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='mysql' ORDER BY columns_in_mysql; SELECT * FROM INFORMATION_SCHEMA.EVENTS; SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME NOT IN ('gs_insert', 'ts_insert'); SELECT * FROM INFORMATION_SCHEMA.ROUTINES; SHOW STATUS LIKE 'slave_open_temp_tables'; checksum table mysql.columns_priv, mysql.db, mysql.func, mysql.help_category, mysql.help_keyword, mysql.help_relation, mysql.host, mysql.plugin, mysql.proc, mysql.procs_priv, mysql.roles_mapping, mysql.tables_priv, mysql.time_zone, mysql.time_zone_leap_second, mysql.time_zone_name, mysql.time_zone_transition, mysql.time_zone_transition_type, mysql.user; SELECT * FROM INFORMATION_SCHEMA.PLUGINS; select * from information_schema.session_variables where variable_name = 'debug_sync'; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci check_warnings def mtr check_warnings PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN DECLARE `pos` bigint unsigned; SET SQL_LOG_BIN=0; UPDATE error_log el, global_suppressions gs SET suspicious=0 WHERE el.suspicious=1 AND el.line REGEXP gs.pattern; UPDATE error_log el, test_suppressions ts SET suspicious=0 WHERE el.suspicious=1 AND el.line REGEXP ts.pattern; SELECT COUNT(*) INTO @num_warnings FROM error_log WHERE suspicious=1; IF @num_warnings > 0 THEN SELECT line FROM error_log WHERE suspicious=1; SELECT 2 INTO result; ELSE SELECT 0 INTO RESULT; END IF; TRUNCATE test_suppressions; DROP TABLE error_log; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci AddGeometryColumn def mysql AddGeometryColumn PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL 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 NULL NULL SQL NO CONTAINS SQL NULL INVOKER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost latin1 latin1_swedish_ci latin1_swedish_ci @@ -213,7 +213,7 @@ sp_6_408002_2 def db_datadict_2 sp_6_408002_2 PROCEDURE NULL NULL NULL NULL NUL SELECT * FROM db_datadict_2.res_6_408002_2; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost latin1 latin1_swedish_ci latin1_swedish_ci add_suppression def mtr add_suppression PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN INSERT INTO test_suppressions (pattern) VALUES (pattern); FLUSH NO_WRITE_TO_BINLOG TABLE test_suppressions; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci -check_testcase def mtr check_testcase PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE variable_name NOT IN ('timestamp', 'innodb_file_format_max') AND variable_name not like "Last_IO_Err*" AND variable_name != 'INNODB_IBUF_MAX_SIZE' AND variable_name != 'INNODB_USE_NATIVE_AIO' AND variable_name != 'INNODB_BUFFER_POOL_LOAD_AT_STARTUP' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' ORDER BY variable_name; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mtr_wsrep_notify', 'wsrep_schema'); SELECT table_name AS tables_in_test FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='test'; SELECT CONCAT(table_schema, '.', table_name) AS tables_in_mysql FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='mysql' ORDER BY tables_in_mysql; SELECT CONCAT(table_schema, '.', table_name) AS columns_in_mysql, column_name, ordinal_position, column_default, is_nullable, data_type, character_maximum_length, character_octet_length, numeric_precision, numeric_scale, character_set_name, collation_name, column_type, column_key, extra, column_comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='mysql' ORDER BY columns_in_mysql; SELECT * FROM INFORMATION_SCHEMA.EVENTS; SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME NOT IN ('gs_insert', 'ts_insert'); SELECT * FROM INFORMATION_SCHEMA.ROUTINES; SHOW STATUS LIKE 'slave_open_temp_tables'; checksum table mysql.columns_priv, mysql.db, mysql.func, mysql.help_category, mysql.help_keyword, mysql.help_relation, mysql.host, mysql.plugin, mysql.proc, mysql.procs_priv, mysql.roles_mapping, mysql.tables_priv, mysql.time_zone, mysql.time_zone_leap_second, mysql.time_zone_name, mysql.time_zone_transition, mysql.time_zone_transition_type, mysql.user; SELECT * FROM INFORMATION_SCHEMA.PLUGINS; select * from information_schema.session_variables where variable_name = 'debug_sync'; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci +check_testcase def mtr check_testcase PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE variable_name NOT IN ('timestamp', 'innodb_file_format_max') AND variable_name not like "Last_IO_Err*" AND variable_name != 'INNODB_IBUF_MAX_SIZE' AND variable_name != 'INNODB_USE_NATIVE_AIO' AND variable_name != 'INNODB_BUFFER_POOL_LOAD_AT_STARTUP' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' AND variable_name != 'THREAD_POOL_SIZE' ORDER BY variable_name; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mtr_wsrep_notify', 'wsrep_schema'); SELECT table_name AS tables_in_test FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='test'; SELECT CONCAT(table_schema, '.', table_name) AS tables_in_mysql FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='mysql' ORDER BY tables_in_mysql; SELECT CONCAT(table_schema, '.', table_name) AS columns_in_mysql, column_name, ordinal_position, column_default, is_nullable, data_type, character_maximum_length, character_octet_length, numeric_precision, numeric_scale, character_set_name, collation_name, column_type, column_key, extra, column_comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='mysql' ORDER BY columns_in_mysql; SELECT * FROM INFORMATION_SCHEMA.EVENTS; SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME NOT IN ('gs_insert', 'ts_insert'); SELECT * FROM INFORMATION_SCHEMA.ROUTINES; SHOW STATUS LIKE 'slave_open_temp_tables'; checksum table mysql.columns_priv, mysql.db, mysql.func, mysql.help_category, mysql.help_keyword, mysql.help_relation, mysql.host, mysql.plugin, mysql.proc, mysql.procs_priv, mysql.roles_mapping, mysql.tables_priv, mysql.time_zone, mysql.time_zone_leap_second, mysql.time_zone_name, mysql.time_zone_transition, mysql.time_zone_transition_type, mysql.user; SELECT * FROM INFORMATION_SCHEMA.PLUGINS; select * from information_schema.session_variables where variable_name = 'debug_sync'; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci check_warnings def mtr check_warnings PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN DECLARE `pos` bigint unsigned; SET SQL_LOG_BIN=0; UPDATE error_log el, global_suppressions gs SET suspicious=0 WHERE el.suspicious=1 AND el.line REGEXP gs.pattern; UPDATE error_log el, test_suppressions ts SET suspicious=0 WHERE el.suspicious=1 AND el.line REGEXP ts.pattern; SELECT COUNT(*) INTO @num_warnings FROM error_log WHERE suspicious=1; IF @num_warnings > 0 THEN SELECT line FROM error_log WHERE suspicious=1; SELECT 2 INTO result; ELSE SELECT 0 INTO RESULT; END IF; TRUNCATE test_suppressions; DROP TABLE error_log; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci AddGeometryColumn def mysql AddGeometryColumn PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL 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 NULL NULL SQL NO CONTAINS SQL NULL INVOKER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost latin1 latin1_swedish_ci latin1_swedish_ci @@ -229,7 +229,7 @@ sp_6_408002_2 def db_datadict_2 sp_6_408002_2 PROCEDURE NULL NULL NULL NULL NUL SELECT * FROM db_datadict_2.res_6_408002_2; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost latin1 latin1_swedish_ci latin1_swedish_ci add_suppression def mtr add_suppression PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN INSERT INTO test_suppressions (pattern) VALUES (pattern); FLUSH NO_WRITE_TO_BINLOG TABLE test_suppressions; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci -check_testcase def mtr check_testcase PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE variable_name NOT IN ('timestamp', 'innodb_file_format_max') AND variable_name not like "Last_IO_Err*" AND variable_name != 'INNODB_IBUF_MAX_SIZE' AND variable_name != 'INNODB_USE_NATIVE_AIO' AND variable_name != 'INNODB_BUFFER_POOL_LOAD_AT_STARTUP' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' ORDER BY variable_name; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mtr_wsrep_notify', 'wsrep_schema'); SELECT table_name AS tables_in_test FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='test'; SELECT CONCAT(table_schema, '.', table_name) AS tables_in_mysql FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='mysql' ORDER BY tables_in_mysql; SELECT CONCAT(table_schema, '.', table_name) AS columns_in_mysql, column_name, ordinal_position, column_default, is_nullable, data_type, character_maximum_length, character_octet_length, numeric_precision, numeric_scale, character_set_name, collation_name, column_type, column_key, extra, column_comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='mysql' ORDER BY columns_in_mysql; SELECT * FROM INFORMATION_SCHEMA.EVENTS; SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME NOT IN ('gs_insert', 'ts_insert'); SELECT * FROM INFORMATION_SCHEMA.ROUTINES; SHOW STATUS LIKE 'slave_open_temp_tables'; checksum table mysql.columns_priv, mysql.db, mysql.func, mysql.help_category, mysql.help_keyword, mysql.help_relation, mysql.host, mysql.plugin, mysql.proc, mysql.procs_priv, mysql.roles_mapping, mysql.tables_priv, mysql.time_zone, mysql.time_zone_leap_second, mysql.time_zone_name, mysql.time_zone_transition, mysql.time_zone_transition_type, mysql.user; SELECT * FROM INFORMATION_SCHEMA.PLUGINS; select * from information_schema.session_variables where variable_name = 'debug_sync'; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci +check_testcase def mtr check_testcase PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE variable_name NOT IN ('timestamp', 'innodb_file_format_max') AND variable_name not like "Last_IO_Err*" AND variable_name != 'INNODB_IBUF_MAX_SIZE' AND variable_name != 'INNODB_USE_NATIVE_AIO' AND variable_name != 'INNODB_BUFFER_POOL_LOAD_AT_STARTUP' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' AND variable_name != 'THREAD_POOL_SIZE' ORDER BY variable_name; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mtr_wsrep_notify', 'wsrep_schema'); SELECT table_name AS tables_in_test FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='test'; SELECT CONCAT(table_schema, '.', table_name) AS tables_in_mysql FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='mysql' ORDER BY tables_in_mysql; SELECT CONCAT(table_schema, '.', table_name) AS columns_in_mysql, column_name, ordinal_position, column_default, is_nullable, data_type, character_maximum_length, character_octet_length, numeric_precision, numeric_scale, character_set_name, collation_name, column_type, column_key, extra, column_comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='mysql' ORDER BY columns_in_mysql; SELECT * FROM INFORMATION_SCHEMA.EVENTS; SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME NOT IN ('gs_insert', 'ts_insert'); SELECT * FROM INFORMATION_SCHEMA.ROUTINES; SHOW STATUS LIKE 'slave_open_temp_tables'; checksum table mysql.columns_priv, mysql.db, mysql.func, mysql.help_category, mysql.help_keyword, mysql.help_relation, mysql.host, mysql.plugin, mysql.proc, mysql.procs_priv, mysql.roles_mapping, mysql.tables_priv, mysql.time_zone, mysql.time_zone_leap_second, mysql.time_zone_name, mysql.time_zone_transition, mysql.time_zone_transition_type, mysql.user; SELECT * FROM INFORMATION_SCHEMA.PLUGINS; select * from information_schema.session_variables where variable_name = 'debug_sync'; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci check_warnings def mtr check_warnings PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN DECLARE `pos` bigint unsigned; SET SQL_LOG_BIN=0; UPDATE error_log el, global_suppressions gs SET suspicious=0 WHERE el.suspicious=1 AND el.line REGEXP gs.pattern; UPDATE error_log el, test_suppressions ts SET suspicious=0 WHERE el.suspicious=1 AND el.line REGEXP ts.pattern; SELECT COUNT(*) INTO @num_warnings FROM error_log WHERE suspicious=1; IF @num_warnings > 0 THEN SELECT line FROM error_log WHERE suspicious=1; SELECT 2 INTO result; ELSE SELECT 0 INTO RESULT; END IF; TRUNCATE test_suppressions; DROP TABLE error_log; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci AddGeometryColumn def mysql AddGeometryColumn PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL 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 NULL NULL SQL NO CONTAINS SQL NULL INVOKER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost latin1 latin1_swedish_ci latin1_swedish_ci From 1595189250e71d5902fc0f378b0e6b14c5b26901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 6 Oct 2020 22:35:43 +0300 Subject: [PATCH 088/323] MDEV-23897 SIGSEGV on commit with innodb_lock_schedule_algorithm=VATS This regression for debug builds was introduced by MDEV-23101 (commit 224c950462a22e09f4e2e37d19218c9129bccba6). Due to MDEV-16664, the parameter innodb_lock_schedule_algorithm=VATS is not enabled by default. The purpose of the added assertions was to enforce the invariant that Galera replication cannot be enabled together with VATS due to MDEV-12837. However, upon closer inspection, it is obvious that the variable 'lock' may be assigned to the null pointer if no match is found in the previous->hash list. lock_grant_and_move_on_page(), lock_grant_and_move_on_rec(): Assert !lock->trx->is_wsrep() only after ensuring that lock is not a null pointer. --- mysql-test/suite/innodb/t/update-cascade.combinations | 5 +++++ storage/innobase/lock/lock0lock.cc | 7 +++---- 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 mysql-test/suite/innodb/t/update-cascade.combinations diff --git a/mysql-test/suite/innodb/t/update-cascade.combinations b/mysql-test/suite/innodb/t/update-cascade.combinations new file mode 100644 index 00000000000..8fb4862675b --- /dev/null +++ b/mysql-test/suite/innodb/t/update-cascade.combinations @@ -0,0 +1,5 @@ +[FCFS] +--innodb-lock-schedule-algorithm=FCFS + +[VATS] +--innodb-lock-schedule-algorithm=VATS diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index e48ac6bcc92..913c80027bf 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -2306,12 +2306,12 @@ lock_grant_and_move_on_page(ulint rec_fold, ulint space, ulint page_no) lock = previous->hash; } - ut_ad(!lock->trx->is_wsrep()); ut_ad(previous->hash == lock || previous == lock); /* Grant locks if there are no conflicting locks ahead. Move granted locks to the head of the list. */ while (lock) { /* If the lock is a wait lock on this page, and it does not need to wait. */ + ut_ad(!lock->trx->is_wsrep()); if (lock_get_wait(lock) && lock->un_member.rec_lock.space == space && lock->un_member.rec_lock.page_no == page_no @@ -4211,11 +4211,10 @@ lock_grant_and_move_on_rec( } lock = previous->hash; } - ut_ad(!lock->trx->is_wsrep()); /* Grant locks if there are no conflicting locks ahead. Move granted locks to the head of the list. */ - for (;lock != NULL;) { - + while (lock) { + ut_ad(!lock->trx->is_wsrep()); /* If the lock is a wait lock on this page, and it does not need to wait. */ if (lock->un_member.rec_lock.space == space && lock->un_member.rec_lock.page_no == page_no From 291be494744abe90f4bdf6b5a35c4c26ee8ddda5 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 24 Sep 2020 22:02:00 -0700 Subject: [PATCH 089/323] MDEV-23811: With large number of indexes optimizer chooses an inefficient plan This bug could manifest itself for a query with WHERE condition containing top level OR formula such that each conjunct contained a single-range condition supported by the same index. One of these range conditions must be fully covered by another range condition that is used later in the OR formula. Additionally at least one of these condition should be ANDed with a sargable range condition supported by a different index. There were several attempts to fix related problems for OR conditions after the backport of range optimizer code from MySQL (commit 0e19f3e36f7842583feb6bead2c2600cd620bced). Unfortunately the first of these fixes contained typo remained unnoticed until recently. This typo bug led to rejection of valid range accesses. This patch fixed this typo bug. The fix revealed another two bugs: one in a constructor for SEL_ARG, the other in the function tree_or(). Both are fixed in this patch. --- mysql-test/r/range.result | 74 ++++++++++++++++++- mysql-test/r/range_mrr_icp.result | 74 ++++++++++++++++++- .../r/range_vs_index_merge_innodb.result | 2 +- mysql-test/t/range.test | 42 +++++++++++ sql/opt_range.cc | 20 +++-- 5 files changed, 201 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 26ea2c6d323..7299982e72d 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -1274,7 +1274,7 @@ SELECT * FROM t1 WHERE 5 <= a AND b = 3 OR 3 <= a; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range a a 5 NULL 4 Using where; Using index +1 SIMPLE t1 range a a 5 NULL 3 Using where; Using index SELECT * FROM t1 WHERE 3 <= a AND a <= 5 OR 5 <= a AND b = 3 OR @@ -3054,5 +3054,77 @@ a b set eq_range_index_dive_limit=default; drop table t1; # +# MDEV-23811: Both disjunct of WHERE condition contain range conditions +# for the same index such that the second range condition +# fully covers the first one. Additionally one of the disjuncts +# contains a range condition for the other index. +# +create table t1 ( +pk int primary key auto_increment, a int, b int, +index idx1(a), index idx2(b) +); +insert into t1(a,b) values +(5,50), (1,10), (3,30), (7,70), (8,80), (4,40), (2,20), (6,60); +insert into t1(a,b) select a+10, b+100 from t1; +insert into t1(a,b) select a+20, b+200 from t1; +insert into t1(a,b) select a+30, b+300 from t1; +insert into t1(a,b) select a,b from t1; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +explain select * from t1 where ((a between 3 and 4) and b < 100) or (a between 2 and 5); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx1,idx2 idx1 5 NULL 11 Using index condition; Using where +select * from t1 where ((a between 3 and 4) and b < 100) or (a between 2 and 5); +pk a b +7 2 20 +71 2 20 +3 3 30 +67 3 30 +6 4 40 +70 4 40 +1 5 50 +65 5 50 +explain select * from t1 where (a between 2 and 5) or ((a between 3 and 4) and b < 100); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx1,idx2 idx1 5 NULL 11 Using index condition; Using where +select * from t1 where (a between 2 and 5) or ((a between 3 and 4) and b < 100); +pk a b +7 2 20 +71 2 20 +3 3 30 +67 3 30 +6 4 40 +70 4 40 +1 5 50 +65 5 50 +explain select * from t1 where (a between 3 and 4) or ((a between 2 and 5) and b < 100); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx1,idx2 idx1 5 NULL 11 Using index condition; Using where +select * from t1 where (a between 3 and 4) or ((a between 2 and 5) and b < 100); +pk a b +7 2 20 +71 2 20 +3 3 30 +67 3 30 +6 4 40 +70 4 40 +1 5 50 +65 5 50 +explain select * from t1 where ((a between 2 and 5) and b < 100) or (a between 3 and 4); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx1,idx2 idx1 5 NULL 11 Using index condition; Using where +select * from t1 where ((a between 2 and 5) and b < 100) or (a between 3 and 4); +pk a b +7 2 20 +71 2 20 +3 3 30 +67 3 30 +6 4 40 +70 4 40 +1 5 50 +65 5 50 +drop table t1; +# # End of 10.2 tests # diff --git a/mysql-test/r/range_mrr_icp.result b/mysql-test/r/range_mrr_icp.result index fe4eb99f31f..cdaaa5e8ab7 100644 --- a/mysql-test/r/range_mrr_icp.result +++ b/mysql-test/r/range_mrr_icp.result @@ -1276,7 +1276,7 @@ SELECT * FROM t1 WHERE 5 <= a AND b = 3 OR 3 <= a; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range a a 5 NULL 4 Using where; Using index +1 SIMPLE t1 range a a 5 NULL 3 Using where; Using index SELECT * FROM t1 WHERE 3 <= a AND a <= 5 OR 5 <= a AND b = 3 OR @@ -3066,6 +3066,78 @@ a b set eq_range_index_dive_limit=default; drop table t1; # +# MDEV-23811: Both disjunct of WHERE condition contain range conditions +# for the same index such that the second range condition +# fully covers the first one. Additionally one of the disjuncts +# contains a range condition for the other index. +# +create table t1 ( +pk int primary key auto_increment, a int, b int, +index idx1(a), index idx2(b) +); +insert into t1(a,b) values +(5,50), (1,10), (3,30), (7,70), (8,80), (4,40), (2,20), (6,60); +insert into t1(a,b) select a+10, b+100 from t1; +insert into t1(a,b) select a+20, b+200 from t1; +insert into t1(a,b) select a+30, b+300 from t1; +insert into t1(a,b) select a,b from t1; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +explain select * from t1 where ((a between 3 and 4) and b < 100) or (a between 2 and 5); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx1,idx2 idx1 5 NULL 11 Using index condition; Using where; Rowid-ordered scan +select * from t1 where ((a between 3 and 4) and b < 100) or (a between 2 and 5); +pk a b +1 5 50 +3 3 30 +6 4 40 +7 2 20 +65 5 50 +67 3 30 +70 4 40 +71 2 20 +explain select * from t1 where (a between 2 and 5) or ((a between 3 and 4) and b < 100); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx1,idx2 idx1 5 NULL 11 Using index condition; Using where; Rowid-ordered scan +select * from t1 where (a between 2 and 5) or ((a between 3 and 4) and b < 100); +pk a b +1 5 50 +3 3 30 +6 4 40 +7 2 20 +65 5 50 +67 3 30 +70 4 40 +71 2 20 +explain select * from t1 where (a between 3 and 4) or ((a between 2 and 5) and b < 100); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx1,idx2 idx1 5 NULL 11 Using index condition; Using where; Rowid-ordered scan +select * from t1 where (a between 3 and 4) or ((a between 2 and 5) and b < 100); +pk a b +1 5 50 +3 3 30 +6 4 40 +7 2 20 +65 5 50 +67 3 30 +70 4 40 +71 2 20 +explain select * from t1 where ((a between 2 and 5) and b < 100) or (a between 3 and 4); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx1,idx2 idx1 5 NULL 11 Using index condition; Using where; Rowid-ordered scan +select * from t1 where ((a between 2 and 5) and b < 100) or (a between 3 and 4); +pk a b +1 5 50 +3 3 30 +6 4 40 +7 2 20 +65 5 50 +67 3 30 +70 4 40 +71 2 20 +drop table t1; +# # End of 10.2 tests # set optimizer_switch=@mrr_icp_extra_tmp; diff --git a/mysql-test/r/range_vs_index_merge_innodb.result b/mysql-test/r/range_vs_index_merge_innodb.result index 581f512768c..916c30bb770 100644 --- a/mysql-test/r/range_vs_index_merge_innodb.result +++ b/mysql-test/r/range_vs_index_merge_innodb.result @@ -369,7 +369,7 @@ WHERE ((ID < 200) AND (Name LIKE 'Ha%' OR (Country > 'A' AND Country < 'ARG'))) OR ((ID BETWEEN 100 AND 200) AND (Name LIKE 'Pa%' OR (Population > 103000 AND Population < 104000))); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE City index_merge PRIMARY,Population,Country,Name Name,Population,PRIMARY 39,4,4 NULL 307 Using sort_union(Name,Population,PRIMARY); Using where +1 SIMPLE City range PRIMARY,Population,Country,Name PRIMARY 4 NULL 200 Using where SELECT * FROM City USE INDEX () WHERE ((ID < 10) AND (Name LIKE 'H%' OR (Country > 'A' AND Country < 'ARG'))) OR ((ID BETWEEN 100 AND 110) AND diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 67d876d5f10..0d2fbe24835 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -2095,6 +2095,48 @@ set eq_range_index_dive_limit=default; drop table t1; +--echo # +--echo # MDEV-23811: Both disjunct of WHERE condition contain range conditions +--echo # for the same index such that the second range condition +--echo # fully covers the first one. Additionally one of the disjuncts +--echo # contains a range condition for the other index. +--echo # + +create table t1 ( + pk int primary key auto_increment, a int, b int, + index idx1(a), index idx2(b) +); +insert into t1(a,b) values + (5,50), (1,10), (3,30), (7,70), (8,80), (4,40), (2,20), (6,60); +insert into t1(a,b) select a+10, b+100 from t1; +insert into t1(a,b) select a+20, b+200 from t1; +insert into t1(a,b) select a+30, b+300 from t1; +insert into t1(a,b) select a,b from t1; + +analyze table t1; + +let $q1= +select * from t1 where ((a between 3 and 4) and b < 100) or (a between 2 and 5); +eval explain $q1; +eval $q1; + +let $q2= +select * from t1 where (a between 2 and 5) or ((a between 3 and 4) and b < 100); +eval explain $q2; +eval $q2; + +let $q3= +select * from t1 where (a between 3 and 4) or ((a between 2 and 5) and b < 100); +eval explain $q3; +eval $q3; + +let $q4= +select * from t1 where ((a between 2 and 5) and b < 100) or (a between 3 and 4); +eval explain $q4; +eval $q4; + +drop table t1; + --echo # --echo # End of 10.2 tests --echo # diff --git a/sql/opt_range.cc b/sql/opt_range.cc index e933d2af355..cd58202ef5f 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1852,6 +1852,9 @@ SEL_ARG::SEL_ARG(SEL_ARG &arg) :Sql_alloc() next_key_part=arg.next_key_part; max_part_no= arg.max_part_no; use_count=1; elements=1; + next= 0; + if (next_key_part) + ++next_key_part->use_count; } @@ -8869,9 +8872,15 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) } bool no_imerge_from_ranges= FALSE; + SEL_TREE *rt1= tree1; + SEL_TREE *rt2= tree2; /* Build the range part of the tree for the formula (1) */ if (sel_trees_can_be_ored(param, tree1, tree2, &ored_keys)) { + if (no_merges1) + rt1= new SEL_TREE(tree1, TRUE, param); + if (no_merges2) + rt2= new SEL_TREE(tree2, TRUE, param); bool must_be_ored= sel_trees_must_be_ored(param, tree1, tree2, ored_keys); no_imerge_from_ranges= must_be_ored; @@ -8929,12 +8938,6 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) else if (!no_ranges1 && !no_ranges2 && !no_imerge_from_ranges) { /* Build the imerge part of the tree for the formula (1) */ - SEL_TREE *rt1= tree1; - SEL_TREE *rt2= tree2; - if (no_merges1) - rt1= new SEL_TREE(tree1, TRUE, param); - if (no_merges2) - rt2= new SEL_TREE(tree2, TRUE, param); if (!rt1 || !rt2 || result->merges.push_back(imerge_from_ranges) || imerge_from_ranges->or_sel_tree(param, rt1) || @@ -9597,10 +9600,11 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) if (!tmp->next_key_part) { + SEL_ARG *key2_next= key2->next; if (key2->use_count) { SEL_ARG *key2_cpy= new SEL_ARG(*key2); - if (key2_cpy) + if (!key2_cpy) return 0; key2= key2_cpy; } @@ -9621,7 +9625,7 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) Move on to next range in key2 */ key2->increment_use_count(-1); // Free not used tree - key2=key2->next; + key2=key2_next; continue; } else From fee807f6d80af18bfbb276d79c5588e24a854a14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 7 Oct 2020 08:10:36 +0300 Subject: [PATCH 090/323] MDEV-22148 : Assertion `state_ == s_exec || state_ == s_quitting' failed in optimized builds | SIGABRT in wsrep::client_state::disable_streaming Actual bug seems to be already fixed, just adding a test case. --- .../r/galera_var_trx_fragment_size.result | 95 +++++++++++++++++++ .../t/galera_var_trx_fragment_size.test | 43 +++++++++ 2 files changed, 138 insertions(+) create mode 100644 mysql-test/suite/galera/r/galera_var_trx_fragment_size.result create mode 100644 mysql-test/suite/galera/t/galera_var_trx_fragment_size.test diff --git a/mysql-test/suite/galera/r/galera_var_trx_fragment_size.result b/mysql-test/suite/galera/r/galera_var_trx_fragment_size.result new file mode 100644 index 00000000000..be14c53548b --- /dev/null +++ b/mysql-test/suite/galera/r/galera_var_trx_fragment_size.result @@ -0,0 +1,95 @@ +connection node_2; +connection node_1; +SET SESSION wsrep_trx_fragment_size=DEFAULT; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 0 +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 0 +SET SESSION wsrep_trx_fragment_size=0; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 0 +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 0 +SET GLOBAL wsrep_trx_fragment_size=DEFAULT; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 0 +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 0 +SET GLOBAL wsrep_trx_fragment_size=0; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 0 +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 0 +SET GLOBAL wsrep_trx_fragment_size=-1; +Warnings: +Warning 1292 Truncated incorrect wsrep_trx_fragment_size value: '-1' +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 0 +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 0 +SET SESSION wsrep_trx_fragment_size=-1; +Warnings: +Warning 1292 Truncated incorrect wsrep_trx_fragment_size value: '-1' +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 0 +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 0 +SET GLOBAL wsrep_trx_fragment_size=100; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 0 +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 100 +SET SESSION wsrep_trx_fragment_size=100; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 100 +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 100 +SET GLOBAL wsrep_trx_fragment_size='A'; +ERROR 42000: Incorrect argument type to variable 'wsrep_trx_fragment_size' +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 100 +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 100 +SET SESSION wsrep_trx_fragment_size='A'; +ERROR 42000: Incorrect argument type to variable 'wsrep_trx_fragment_size' +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 100 +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 100 +SET GLOBAL wsrep_trx_fragment_size=NULL; +ERROR 42000: Incorrect argument type to variable 'wsrep_trx_fragment_size' +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 100 +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 100 +SET SESSION wsrep_trx_fragment_size=NULL; +ERROR 42000: Incorrect argument type to variable 'wsrep_trx_fragment_size' +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 100 +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +Variable_name Value +wsrep_trx_fragment_size 100 +SET GLOBAL wsrep_trx_fragment_size=DEFAULT; diff --git a/mysql-test/suite/galera/t/galera_var_trx_fragment_size.test b/mysql-test/suite/galera/t/galera_var_trx_fragment_size.test new file mode 100644 index 00000000000..f19152f37f1 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_var_trx_fragment_size.test @@ -0,0 +1,43 @@ +--source include/galera_cluster.inc + +SET SESSION wsrep_trx_fragment_size=DEFAULT; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +SET SESSION wsrep_trx_fragment_size=0; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +SET GLOBAL wsrep_trx_fragment_size=DEFAULT; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +SET GLOBAL wsrep_trx_fragment_size=0; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +SET GLOBAL wsrep_trx_fragment_size=-1; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +SET SESSION wsrep_trx_fragment_size=-1; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +SET GLOBAL wsrep_trx_fragment_size=100; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +SET SESSION wsrep_trx_fragment_size=100; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +--error ER_WRONG_TYPE_FOR_VAR +SET GLOBAL wsrep_trx_fragment_size='A'; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +--error ER_WRONG_TYPE_FOR_VAR +SET SESSION wsrep_trx_fragment_size='A'; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +--error ER_WRONG_TYPE_FOR_VAR +SET GLOBAL wsrep_trx_fragment_size=NULL; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +--error ER_WRONG_TYPE_FOR_VAR +SET SESSION wsrep_trx_fragment_size=NULL; +SHOW SESSION VARIABLES LIKE 'wsrep_trx_fragment_size'; +SHOW GLOBAL VARIABLES LIKE 'wsrep_trx_fragment_size'; +SET GLOBAL wsrep_trx_fragment_size=DEFAULT; From 65c632cb9cf44aea8132b65cc7a08253ec4282af Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Tue, 29 Sep 2020 19:12:00 +0300 Subject: [PATCH 091/323] MDEV-23832 Crash at startup in Log_event::read_log_event The crash was caused by improper raising of an error or replication checksum verification at time of the server initialization. As there is no THD object associated with the main initializing thread yet the error text should be assigned with calling a respective macro that is aware of that possibility. Fixed accordingly. [At merging to 10.4 the new test result file needs +# restart: --master_verify_checksum=ON --debug_dbug=+d,corrupt_read_log_event_char that mtr run will hint on.] --- .../r/binlog_recover_checksum_error.result | 7 ++++ .../t/binlog_recover_checksum_error.test | 37 +++++++++++++++++++ sql/log_event.cc | 2 +- 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/binlog/r/binlog_recover_checksum_error.result create mode 100644 mysql-test/suite/binlog/t/binlog_recover_checksum_error.test diff --git a/mysql-test/suite/binlog/r/binlog_recover_checksum_error.result b/mysql-test/suite/binlog/r/binlog_recover_checksum_error.result new file mode 100644 index 00000000000..f65f7797d7f --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_recover_checksum_error.result @@ -0,0 +1,7 @@ +set @@global.binlog_checksum = CRC32; +call mtr.add_suppression("Replication event checksum verification failed"); +call mtr.add_suppression("Error in Log_event::read_log_event"); +set @@global.debug_dbug = VALUE; +set @@global.master_verify_checksum = DO_CHECKSUM; +set @@global.binlog_checksum = BINLOG_CHECKSUM; +# EOF the test diff --git a/mysql-test/suite/binlog/t/binlog_recover_checksum_error.test b/mysql-test/suite/binlog/t/binlog_recover_checksum_error.test new file mode 100644 index 00000000000..12c9f3d914f --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_recover_checksum_error.test @@ -0,0 +1,37 @@ +# The test verifies server binlog-based recovery. +# +# MDEV-23832 checksum error at server binlog recovery should not crash + +# The test logic really requires --log-bin. +--source include/have_binlog_format_mixed.inc +--source include/have_debug.inc + +--let $do_checksum = `SELECT @@global.master_verify_checksum` +--let $debug_dbug_saved = `SELECT @@global.debug_dbug` +--let $binlog_checksum = `SELECT @@global.binlog_checksum` +set @@global.binlog_checksum = CRC32; + +call mtr.add_suppression("Replication event checksum verification failed"); +call mtr.add_suppression("Error in Log_event::read_log_event"); + +# Proof of no crash follows. +# There's no need for actual bin-loggable queries to the server +--let $restart_parameters= --master_verify_checksum=ON --debug_dbug="+d,corrupt_read_log_event_char" +--let $shutdown_timeout=0 +--source include/restart_mysqld.inc +--let $restart_parameters= +--let $shutdown_timeout= + +# +# Cleanup + +--replace_regex /= .*/= VALUE/ +--eval set @@global.debug_dbug = "$debug_dbug_saved" + +--replace_result $do_checksum DO_CHECKSUM +--eval set @@global.master_verify_checksum = $do_checksum +--replace_result $binlog_checksum BINLOG_CHECKSUM +--eval set @@global.binlog_checksum = $binlog_checksum +# +--echo # EOF the test +# diff --git a/sql/log_event.cc b/sql/log_event.cc index 3d28c249e21..146d8bd5dbe 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1632,7 +1632,7 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len, else DBUG_RETURN(NULL); #else - *error= ER(ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE); + *error= ER_THD_OR_DEFAULT(current_thd, ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE); sql_print_error("%s", *error); DBUG_RETURN(NULL); #endif From 9e100f4b96561e5e76f88ad612761973262e1870 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 7 Oct 2020 11:14:20 +0200 Subject: [PATCH 092/323] Better German Error message. --- sql/share/errmsg-utf8.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index e526363029b..ef0dfd5eb63 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -5723,7 +5723,7 @@ ER_SP_RECURSION_LIMIT ger "Rekursionsgrenze %d (durch Variable max_sp_recursion_depth gegeben) wurde für Routine %.192s überschritten" ER_SP_PROC_TABLE_CORRUPT eng "Failed to load routine %-.192s (internal code %d). For more details, run SHOW WARNINGS" - ger "Fehler beim Laden der Routine %-.192s (interner Code %d). Weitere Informationen finden Sie unter SHOW WARNINGS" + ger "Routine %-.192s (interner Code %d) konnte nicht geladen werden. Weitere Einzelheiten erhalten Sie, wenn Sie SHOW WARNINGS ausführen" ukr "Невдала спроба завантажити процедуру %-.192s (внутрішний код %d). Для отримання детальної інформації використовуйте SHOW WARNINGS" ER_SP_WRONG_NAME 42000 eng "Incorrect routine name '%-.192s'" From 1a850225d38484ce68901756347e5197adc17a9c Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Wed, 7 Oct 2020 11:22:10 -0400 Subject: [PATCH 093/323] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 453e11b3aae..1c88e2091d0 100644 --- a/VERSION +++ b/VERSION @@ -1,3 +1,3 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=1 -MYSQL_VERSION_PATCH=47 +MYSQL_VERSION_PATCH=48 From 4aec143ad8c11564ba37f67ce19308c45f29b566 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Wed, 7 Oct 2020 11:23:43 -0400 Subject: [PATCH 094/323] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index d010acbf85d..a1f0ad08a61 100644 --- a/VERSION +++ b/VERSION @@ -1,3 +1,3 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=2 -MYSQL_VERSION_PATCH=34 +MYSQL_VERSION_PATCH=35 From 89fc49321ad7da6894bfd9182823df3997245989 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Wed, 7 Oct 2020 11:25:40 -0400 Subject: [PATCH 095/323] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 5f8bdaf364f..7f3afc3090f 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=3 -MYSQL_VERSION_PATCH=25 +MYSQL_VERSION_PATCH=26 SERVER_MATURITY=stable From 232715f506ecae487a0b3a15d84a3e593ae85c70 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Wed, 7 Oct 2020 11:27:00 -0400 Subject: [PATCH 096/323] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index bbdcc6a4ee3..d4740047d0c 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=4 -MYSQL_VERSION_PATCH=15 +MYSQL_VERSION_PATCH=16 SERVER_MATURITY=stable From 0c7f52939c907d8e529ad30be065f99ec3a703b4 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Wed, 7 Oct 2020 11:28:28 -0400 Subject: [PATCH 097/323] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index a380661b267..d09c803df7a 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=6 +MYSQL_VERSION_PATCH=7 SERVER_MATURITY=stable From 00c44fb18ec54682ffd208126e0de6ab172fa50b Mon Sep 17 00:00:00 2001 From: Nisha Gopalakrishnan Date: Thu, 20 Sep 2012 12:34:31 +0530 Subject: [PATCH 098/323] MDEV-4851: BUG#11763447: 'YOU CANNOT 'ALTER' A LOG TABLE IF LOGGING IS ENABLED' EVEN IF I LOG TO FILE. Analysis: ---------- MYSQL_UPGRADE of the master breaks the replication when the query logging is enabled with FILE/NONE 'log-output' option on the slave. mysql_upgrade modifies the 'general_log' and 'slow_log' tables after the logging is disabled as below: SET @old_log_state = @@global.general_log; SET GLOBAL general_log = 'OFF'; ALTER TABLE general_log MODIFY event_time TIMESTAMP NOT NULL, ( .... ); SET GLOBAL general_log = @old_log_state; and SET @old_log_state = @@global.slow_query_log; SET GLOBAL slow_query_log = 'OFF'; ALTER TABLE slow_log MODIFY start_time TIMESTAMP NOT NULL, ( .... ); SET GLOBAL slow_query_log = @old_log_state; In the binary log, only the ALTER statements are logged but not the SET statements which turns ON/OFF the logging. So when the slave replays the binary log,the ALTER of LOG tables throws an error since the logging is enabled. Also the 'log-output' option is not checked to determine whether to allow/disallow the ALTER operation. Fix: ---- The 'log-output' option is included in the check while determining whether the query logging happens using the log tables. Picked from mysql respository at 0daaf8aecd8f84ff1fb400029139222ea1f0d812 --- sql/log.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sql/log.cc b/sql/log.cc index 8049b94bab1..f2fe0d852d1 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2018, Oracle and/or its affiliates. +/* Copyright (c) 2000, 2012, 2018, Oracle and/or its affiliates. Copyright (c) 2009, 2019, MariaDB Corporation This program is free software; you can redistribute it and/or modify @@ -534,9 +534,11 @@ bool LOGGER::is_log_table_enabled(uint log_table_type) { switch (log_table_type) { case QUERY_LOG_SLOW: - return (table_log_handler != NULL) && global_system_variables.sql_log_slow; + return (table_log_handler != NULL) && global_system_variables.sql_log_slow + && (log_output_options & LOG_TABLE); case QUERY_LOG_GENERAL: - return (table_log_handler != NULL) && opt_log ; + return (table_log_handler != NULL) && opt_log + && (log_output_options & LOG_TABLE); default: DBUG_ASSERT(0); return FALSE; /* make compiler happy */ From 874942a0f910731b54eb57aef01c1bef701ab6ba Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Mon, 5 Oct 2020 13:26:28 +1100 Subject: [PATCH 099/323] MDEV-4851: (tests) log tables modifiable on log_output!=TABLE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test we can ALTER log tables directly when not being written to. This removes the contraint in the rpl_mysql_upgrade.test such that we can run mysql_upgrade --write-binlog all the way through to a replica. We test this in the replication scenario where the mysql.{slow,general}_log tables aren't being written to. Reviewers: Vicențiu Ciorbaru, Anel Husakovic --- mysql-test/r/log_tables.result | 8 +++ .../suite/rpl/r/rpl_mysql_upgrade.result | 54 ++++++++++++++++--- mysql-test/suite/rpl/t/rpl_mysql_upgrade.test | 34 +++++++++--- mysql-test/t/log_tables.test | 20 ++++++- 4 files changed, 101 insertions(+), 15 deletions(-) diff --git a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result index ff5055e1ae4..cfecae91733 100644 --- a/mysql-test/r/log_tables.result +++ b/mysql-test/r/log_tables.result @@ -377,6 +377,14 @@ slow_log slow_log_new drop table slow_log_new, general_log_new; use test; +SET GLOBAL LOG_OUTPUT = 'FILE'; +SET GLOBAL slow_query_log = 1; +SET GLOBAL general_log = 1; +ALTER TABLE mysql.slow_log ADD COLUMN comment_text TEXT NOT NULL; +ALTER TABLE mysql.general_log ADD COLUMN comment_text TEXT NOT NULL; +SET GLOBAL LOG_OUTPUT = 'NONE'; +ALTER TABLE mysql.slow_log DROP COLUMN comment_text; +ALTER TABLE mysql.general_log DROP COLUMN comment_text; SET GLOBAL LOG_OUTPUT = 'TABLE'; SET GLOBAL general_log = 0; FLUSH LOGS; diff --git a/mysql-test/suite/rpl/r/rpl_mysql_upgrade.result b/mysql-test/suite/rpl/r/rpl_mysql_upgrade.result index 9e360beba2c..5bc891d90fc 100644 --- a/mysql-test/suite/rpl/r/rpl_mysql_upgrade.result +++ b/mysql-test/suite/rpl/r/rpl_mysql_upgrade.result @@ -2,12 +2,54 @@ include/master-slave.inc [connection master] call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); call mtr.add_suppression("table or database name 'mysqltest-1'"); -DROP DATABASE IF EXISTS `#mysql50#mysqltest-1`; -CREATE DATABASE `#mysql50#mysqltest-1`; +CREATE DATABASE `mysqltest-1`; Master position is not changed -STOP SLAVE SQL_THREAD; -include/wait_for_slave_sql_to_stop.inc -Master position has been changed +SET @old_general_log_state = @@global.general_log; +SET @old_slow_log_state = @@global.slow_query_log; +SET @old_log_output = @@global.log_output; +SET GLOBAL general_log = 'ON'; +SET GLOBAL slow_query_log = 'ON'; +SET GLOBAL log_output = 'FILE'; +ALTER TABLE mysql.slow_log DROP COLUMN thread_id, DROP COLUMN rows_affected; DROP DATABASE `mysqltest-1`; -DROP DATABASE `#mysql50#mysqltest-1`; +SHOW CREATE TABLE mysql.slow_log; +Table Create Table +slow_log CREATE TABLE `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` int(11) NOT NULL, + `rows_examined` int(11) 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 +) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='Slow log' +Master position has been changed +SHOW CREATE TABLE mysql.slow_log; +Table Create Table +slow_log CREATE TABLE `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` int(11) NOT NULL, + `rows_examined` int(11) 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, + `rows_affected` int(11) NOT NULL +) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='Slow log' +SET GLOBAL general_log = 'OFF'; +SET GLOBAL slow_query_log = 'OFF'; +truncate mysql.slow_log; +truncate mysql.general_log; +SET GLOBAL general_log = @old_general_log_state; +SET GLOBAL slow_query_log = @old_slow_log_state; +SET GLOBAL log_output = @old_log_output; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test b/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test index 1931e2eab2a..f44c883ef4e 100644 --- a/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test +++ b/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test @@ -14,8 +14,7 @@ call mtr.add_suppression("table or database name 'mysqltest-1'"); connection master; --disable_warnings -DROP DATABASE IF EXISTS `#mysql50#mysqltest-1`; -CREATE DATABASE `#mysql50#mysqltest-1`; +CREATE DATABASE `mysqltest-1`; --enable_warnings sync_slave_with_master; @@ -34,13 +33,25 @@ if ($before_position == $after_position) echo Master position is not changed; } -#Some log events of the mysql_upgrade's will cause errors on slave. +# Some log events of the mysql_upgrade previously caused errors on slave, +# however with MDEV-4851 this should be ok, so we test it: connection slave; -STOP SLAVE SQL_THREAD; -source include/wait_for_slave_sql_to_stop.inc; +SET @old_general_log_state = @@global.general_log; +SET @old_slow_log_state = @@global.slow_query_log; +SET @old_log_output = @@global.log_output; +SET GLOBAL general_log = 'ON'; +SET GLOBAL slow_query_log = 'ON'; +SET GLOBAL log_output = 'FILE'; connection master; #With '--force' option, mysql_upgrade always executes all sql statements for upgrading. +ALTER TABLE mysql.slow_log DROP COLUMN thread_id, DROP COLUMN rows_affected; +DROP DATABASE `mysqltest-1`; +sync_slave_with_master; + +connection slave; +SHOW CREATE TABLE mysql.slow_log; +connection master; --exec $MYSQL_UPGRADE --skip-verbose --write-binlog --force --user=root > $MYSQLTEST_VARDIR/log/mysql_upgrade.log 2>&1 let $datadir= `select @@datadir`; @@ -55,8 +66,15 @@ if ($before_position != $after_position) echo Master position has been changed; } -DROP DATABASE `mysqltest-1`; +sync_slave_with_master; connection slave; -DROP DATABASE `#mysql50#mysqltest-1`; ---let $rpl_only_running_threads= 1 +SHOW CREATE TABLE mysql.slow_log; +SET GLOBAL general_log = 'OFF'; +SET GLOBAL slow_query_log = 'OFF'; +truncate mysql.slow_log; +truncate mysql.general_log; +SET GLOBAL general_log = @old_general_log_state; +SET GLOBAL slow_query_log = @old_slow_log_state; +SET GLOBAL log_output = @old_log_output; + --source include/rpl_end.inc diff --git a/mysql-test/t/log_tables.test b/mysql-test/t/log_tables.test index f822ec8d758..0196e62f12f 100644 --- a/mysql-test/t/log_tables.test +++ b/mysql-test/t/log_tables.test @@ -58,7 +58,7 @@ select * from general_log where argument like '%general_log%'; # # Check some basic queries interfering with the log tables. -# In our test we'll use a tbale with verbose comments to the short +# In our test we'll use a table with verbose comments to the short # command type names, used in the tables # @@ -470,6 +470,24 @@ show tables like "%log%"; drop table slow_log_new, general_log_new; use test; +# +# Bug#69953 / MDEV-4851 +# Log tables should be modifable on LOG_OUTPUT != TABLE +# +# + +SET GLOBAL LOG_OUTPUT = 'FILE'; +SET GLOBAL slow_query_log = 1; +SET GLOBAL general_log = 1; + +ALTER TABLE mysql.slow_log ADD COLUMN comment_text TEXT NOT NULL; +ALTER TABLE mysql.general_log ADD COLUMN comment_text TEXT NOT NULL; + +SET GLOBAL LOG_OUTPUT = 'NONE'; +ALTER TABLE mysql.slow_log DROP COLUMN comment_text; +ALTER TABLE mysql.general_log DROP COLUMN comment_text; + + # # Bug#27857 (Log tables supplies the wrong value for generating # AUTO_INCREMENT numbers) From d312d64146b1858e3fc6cc2f365cbc795b0b067e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 8 Oct 2020 11:13:47 +0300 Subject: [PATCH 100/323] MDEV-23909 innodb_flush_neighbors=2 is treated like innodb_flush_neighbors=0 In MDEV-15053 (commit b1ab211dee599eabd9a5b886fafa3adea29ae041) we inadvertently removed a check whether innodb_flush_neighbors is 0, and thus started treating only the value 1 in a special way. buf_flush_check_neighbors(): Add the parameter contiguous, which can be set to skip the check for non-contiguous page number ranges. Reviewed by: Thirunarayanan Balathandayuthapani --- storage/innobase/buf/buf0flu.cc | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index de493e62bd5..52edcbd01c0 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -1245,10 +1245,11 @@ static bool buf_flush_check_neighbor(const page_id_t id, /** Check which neighbors of a page can be flushed from the buf_pool. @param space tablespace @param id page identifier of a dirty page +@param contiguous whether to consider contiguous areas of pages @param flush LRU or FLUSH_LIST @return last page number that can be flushed */ static page_id_t buf_flush_check_neighbors(const fil_space_t &space, - page_id_t &id, + page_id_t &id, bool contiguous, IORequest::flush_t flush) { ut_ad(id.page_no() < space.size); @@ -1264,6 +1265,13 @@ static page_id_t buf_flush_check_neighbors(const fil_space_t &space, high.set_page_no(std::min(high.page_no(), static_cast(space.committed_size - 1))); + if (!contiguous) + { + high= std::max(id + 1, high); + id= low; + return high; + } + /* Determine the contiguous dirty area around id. */ const ulint id_fold= id.fold(); @@ -1379,13 +1387,18 @@ buf_flush_try_neighbors( /* Flush the freed ranges while flushing the neighbors */ buf_flush_freed_pages(space); + const auto neighbors= srv_flush_neighbors; + page_id_t id = page_id; - page_id_t high = (srv_flush_neighbors != 1 + page_id_t high = (!neighbors || UT_LIST_GET_LEN(buf_pool.LRU) < BUF_LRU_OLD_MIN_LEN || !space->is_rotational()) ? id + 1 /* Flush the minimum. */ - : buf_flush_check_neighbors(*space, id, flush); + : buf_flush_check_neighbors(*space, id, neighbors == 1, flush); + + ut_ad(page_id >= id); + ut_ad(page_id < high); for (; id < high; ++id) { buf_page_t* bpage; From 6504d3d229b086d20e5e4798b1ae10bbbd70d3c7 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 29 Sep 2020 16:18:43 +0530 Subject: [PATCH 101/323] MDEV-23722 InnoDB: Assertion: result != FTS_INVALID in fts_trx_row_get_new_state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Marking of deletion of row in fts index happens twice in self-referential foreign key relation. So while performing referential checks of foreign key, InnoDB can avoid updating of fts index if the foreign key has self-referential relationship. Reviewed-by: Marko Mäkelä --- mysql-test/suite/innodb/r/foreign_key.result | 35 ++++++++++++++++ mysql-test/suite/innodb/t/foreign_key.test | 35 ++++++++++++++++ .../innodb_fts/r/innodb_fts_misc_1.result | 42 +++++++++++++++++++ .../suite/innodb_fts/t/innodb_fts_misc_1.test | 42 +++++++++++++++++++ storage/innobase/dict/dict0mem.cc | 19 +++++++++ storage/innobase/include/dict0mem.h | 4 ++ storage/innobase/row/row0ins.cc | 41 +++--------------- storage/xtradb/dict/dict0mem.cc | 19 +++++++++ storage/xtradb/include/dict0mem.h | 4 ++ storage/xtradb/row/row0ins.cc | 41 +++--------------- 10 files changed, 212 insertions(+), 70 deletions(-) diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index e9fbc742379..74d7cbb7d9a 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -244,3 +244,38 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction XA END 'xid'; XA ROLLBACK 'xid'; DROP TABLE t1; +CREATE TABLE t1 (pk INT PRIMARY KEY, +f1 VARCHAR(10), f2 VARCHAR(10), +f3 VARCHAR(10), f4 VARCHAR(10), +f5 VARCHAR(10), f6 VARCHAR(10), +f7 VARCHAR(10), f8 VARCHAR(10), +INDEX(f1), INDEX(f2), INDEX(f3), INDEX(f4), +INDEX(f5), INDEX(f6), INDEX(f7), INDEX(f8)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, 'mariadb', 'mariadb', 'mariadb', 'mariadb', +'mariadb', 'mariadb', 'mariadb', 'mariadb'), +(2, 'mariadb', 'mariadb', 'mariadb', 'mariadb', +'mariadb', 'mariadb', 'mariadb', 'mariadb'), +(3, 'innodb', 'innodb', 'innodb', 'innodb', +'innodb', 'innodb', 'innodb', 'innodb'); +ALTER TABLE t1 ADD FOREIGN KEY (f1) REFERENCES t1 (f2) ON DELETE SET NULL; +START TRANSACTION; +DELETE FROM t1 where f1='mariadb'; +SELECT * FROM t1; +pk f1 f2 f3 f4 f5 f6 f7 f8 +2 NULL mariadb mariadb mariadb mariadb mariadb mariadb mariadb +3 innodb innodb innodb innodb innodb innodb innodb innodb +ROLLBACK; +ALTER TABLE t1 ADD FOREIGN KEY (f3) REFERENCES t1 (f4) ON DELETE CASCADE; +START TRANSACTION; +DELETE FROM t1 where f3='mariadb'; +SELECT * FROM t1; +pk f1 f2 f3 f4 f5 f6 f7 f8 +3 innodb innodb innodb innodb innodb innodb innodb innodb +ROLLBACK; +ALTER TABLE t1 ADD FOREIGN KEY (f5) REFERENCES t1 (f6) ON UPDATE SET NULL; +UPDATE t1 SET f6='update'; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_3` FOREIGN KEY (`f5`) REFERENCES `t1` (`f6`) ON UPDATE SET NULL) +ALTER TABLE t1 ADD FOREIGN KEY (f7) REFERENCES t1 (f8) ON UPDATE CASCADE; +UPDATE t1 SET f6='cascade'; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_3` FOREIGN KEY (`f5`) REFERENCES `t1` (`f6`) ON UPDATE SET NULL) +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test index 3269aeed62b..29bf91f2f24 100644 --- a/mysql-test/suite/innodb/t/foreign_key.test +++ b/mysql-test/suite/innodb/t/foreign_key.test @@ -299,6 +299,41 @@ ALTER TABLE t1 ADD FOREIGN KEY f (a) REFERENCES t1 (pk), LOCK=EXCLUSIVE;# Cleanu XA END 'xid'; XA ROLLBACK 'xid'; DROP TABLE t1; + +CREATE TABLE t1 (pk INT PRIMARY KEY, + f1 VARCHAR(10), f2 VARCHAR(10), + f3 VARCHAR(10), f4 VARCHAR(10), + f5 VARCHAR(10), f6 VARCHAR(10), + f7 VARCHAR(10), f8 VARCHAR(10), + INDEX(f1), INDEX(f2), INDEX(f3), INDEX(f4), + INDEX(f5), INDEX(f6), INDEX(f7), INDEX(f8)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, 'mariadb', 'mariadb', 'mariadb', 'mariadb', + 'mariadb', 'mariadb', 'mariadb', 'mariadb'), + (2, 'mariadb', 'mariadb', 'mariadb', 'mariadb', + 'mariadb', 'mariadb', 'mariadb', 'mariadb'), + (3, 'innodb', 'innodb', 'innodb', 'innodb', + 'innodb', 'innodb', 'innodb', 'innodb'); +ALTER TABLE t1 ADD FOREIGN KEY (f1) REFERENCES t1 (f2) ON DELETE SET NULL; +START TRANSACTION; +DELETE FROM t1 where f1='mariadb'; +SELECT * FROM t1; +ROLLBACK; + +ALTER TABLE t1 ADD FOREIGN KEY (f3) REFERENCES t1 (f4) ON DELETE CASCADE; + +START TRANSACTION; +DELETE FROM t1 where f3='mariadb'; +SELECT * FROM t1; +ROLLBACK; + +ALTER TABLE t1 ADD FOREIGN KEY (f5) REFERENCES t1 (f6) ON UPDATE SET NULL; +--error ER_ROW_IS_REFERENCED_2 +UPDATE t1 SET f6='update'; + +ALTER TABLE t1 ADD FOREIGN KEY (f7) REFERENCES t1 (f8) ON UPDATE CASCADE; +--error ER_ROW_IS_REFERENCED_2 +UPDATE t1 SET f6='cascade'; +DROP TABLE t1; # # End of 10.1 tests # diff --git a/mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result b/mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result index 9f5c1f271fc..43f79241626 100644 --- a/mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result +++ b/mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result @@ -913,4 +913,46 @@ DROP TABLE t1; DROP TABLE t2; DROP TABLE t3; DROP TABLE t4; +# +# InnoDB: Failing assertion: result != FTS_INVALID in +# fts_trx_row_get_new_state +# +SET FOREIGN_KEY_CHECKS=1; +CREATE TABLE t1 (pk INT PRIMARY KEY, +f1 VARCHAR(10), f2 VARCHAR(10), +f3 VARCHAR(10), f4 VARCHAR(10), +f5 VARCHAR(10), f6 VARCHAR(10), +f7 VARCHAR(10), f8 VARCHAR(10), +FULLTEXT(f1), FULLTEXT(f2), FULLTEXT(f3), FULLTEXT(f4), +FULLTEXT(f5), FULLTEXT(f6), FULLTEXT(f7), FULLTEXT(f8), +INDEX(f1), INDEX(f2), INDEX(f3), INDEX(f4), +INDEX(f5), INDEX(f6), INDEX(f7), INDEX(f8)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, 'mariadb', 'mariadb', 'mariadb', 'mariadb', +'mariadb', 'mariadb', 'mariadb', 'mariadb'), +(2, 'mariadb', 'mariadb', 'mariadb', 'mariadb', +'mariadb', 'mariadb', 'mariadb', 'mariadb'), +(3, 'innodb', 'innodb', 'innodb', 'innodb', +'innodb', 'innodb', 'innodb', 'innodb'); +ALTER TABLE t1 ADD FOREIGN KEY (f1) REFERENCES t1 (f2) ON DELETE SET NULL; +START TRANSACTION; +DELETE FROM t1 where f1='mariadb'; +SELECT * FROM t1; +pk f1 f2 f3 f4 f5 f6 f7 f8 +2 NULL mariadb mariadb mariadb mariadb mariadb mariadb mariadb +3 innodb innodb innodb innodb innodb innodb innodb innodb +ROLLBACK; +ALTER TABLE t1 ADD FOREIGN KEY (f3) REFERENCES t1 (f4) ON DELETE CASCADE; +START TRANSACTION; +DELETE FROM t1 where f3='mariadb'; +SELECT * FROM t1; +pk f1 f2 f3 f4 f5 f6 f7 f8 +3 innodb innodb innodb innodb innodb innodb innodb innodb +ROLLBACK; +ALTER TABLE t1 ADD FOREIGN KEY (f5) REFERENCES t1 (f6) ON UPDATE SET NULL; +UPDATE t1 SET f6='update'; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_3` FOREIGN KEY (`f5`) REFERENCES `t1` (`f6`) ON UPDATE SET NULL) +ALTER TABLE t1 ADD FOREIGN KEY (f7) REFERENCES t1 (f8) ON UPDATE CASCADE; +UPDATE t1 SET f6='cascade'; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_3` FOREIGN KEY (`f5`) REFERENCES `t1` (`f6`) ON UPDATE SET NULL) +DROP TABLE t1; SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; diff --git a/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test b/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test index 6ef0452f4c6..e8a3035ba25 100644 --- a/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test +++ b/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test @@ -907,4 +907,46 @@ DROP TABLE t2; DROP TABLE t3; DROP TABLE t4; +--echo # +--echo # InnoDB: Failing assertion: result != FTS_INVALID in +--echo # fts_trx_row_get_new_state +--echo # +SET FOREIGN_KEY_CHECKS=1; +CREATE TABLE t1 (pk INT PRIMARY KEY, + f1 VARCHAR(10), f2 VARCHAR(10), + f3 VARCHAR(10), f4 VARCHAR(10), + f5 VARCHAR(10), f6 VARCHAR(10), + f7 VARCHAR(10), f8 VARCHAR(10), + FULLTEXT(f1), FULLTEXT(f2), FULLTEXT(f3), FULLTEXT(f4), + FULLTEXT(f5), FULLTEXT(f6), FULLTEXT(f7), FULLTEXT(f8), + INDEX(f1), INDEX(f2), INDEX(f3), INDEX(f4), + INDEX(f5), INDEX(f6), INDEX(f7), INDEX(f8)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, 'mariadb', 'mariadb', 'mariadb', 'mariadb', + 'mariadb', 'mariadb', 'mariadb', 'mariadb'), + (2, 'mariadb', 'mariadb', 'mariadb', 'mariadb', + 'mariadb', 'mariadb', 'mariadb', 'mariadb'), + (3, 'innodb', 'innodb', 'innodb', 'innodb', + 'innodb', 'innodb', 'innodb', 'innodb'); +ALTER TABLE t1 ADD FOREIGN KEY (f1) REFERENCES t1 (f2) ON DELETE SET NULL; +START TRANSACTION; +DELETE FROM t1 where f1='mariadb'; +SELECT * FROM t1; +ROLLBACK; + +ALTER TABLE t1 ADD FOREIGN KEY (f3) REFERENCES t1 (f4) ON DELETE CASCADE; + +START TRANSACTION; +DELETE FROM t1 where f3='mariadb'; +SELECT * FROM t1; +ROLLBACK; + +ALTER TABLE t1 ADD FOREIGN KEY (f5) REFERENCES t1 (f6) ON UPDATE SET NULL; +--error ER_ROW_IS_REFERENCED_2 +UPDATE t1 SET f6='update'; + +ALTER TABLE t1 ADD FOREIGN KEY (f7) REFERENCES t1 (f8) ON UPDATE CASCADE; +--error ER_ROW_IS_REFERENCED_2 +UPDATE t1 SET f6='cascade'; +DROP TABLE t1; + SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index 6ace0ee9a75..157e695f696 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -852,3 +852,22 @@ operator<< (std::ostream& out, const dict_foreign_set& fk_set) return(out); } +/** Check whether fulltext index gets affected by foreign +key constraint. */ +bool dict_foreign_t::affects_fulltext() const +{ + if (foreign_table == referenced_table || !foreign_table->fts) + return false; + + for (ulint i = 0; i < n_fields; i++) + { + if (dict_table_is_fts_column( + foreign_table->fts->indexes, + dict_index_get_nth_col_no(foreign_index, i)) + != ULINT_UNDEFINED) + return true; + } + + return false; +} + diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 505d4925324..7c59789d313 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -848,6 +848,10 @@ struct dict_foreign_t{ does not generate new indexes implicitly */ dict_index_t* referenced_index;/*!< referenced index */ + + /** Check whether the fulltext index gets affected by + foreign key constraint */ + bool affects_fulltext() const; }; std::ostream& diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index ecbfd03ec93..4d86b0f333c 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -510,7 +510,7 @@ row_ins_cascade_calc_update_vec( n_fields_updated = 0; - *fts_col_affected = FALSE; + *fts_col_affected = foreign->affects_fulltext(); if (table->fts) { doc_id_pos = dict_table_get_nth_col_pos( @@ -631,16 +631,6 @@ row_ins_cascade_calc_update_vec( padded_data, min_size); } - /* Check whether the current column has - FTS index on it */ - if (table->fts - && dict_table_is_fts_column( - table->fts->indexes, - dict_col_get_no(col)) - != ULINT_UNDEFINED) { - *fts_col_affected = TRUE; - } - /* If Doc ID is updated, check whether the Doc ID is valid */ if (table->fts @@ -977,7 +967,6 @@ row_ins_foreign_check_on_constraint( upd_t* update; ulint n_to_update; dberr_t err; - ulint i; trx_t* trx; mem_heap_t* tmp_heap = NULL; doc_id_t doc_id = FTS_NULL_DOC_ID; @@ -1191,7 +1180,7 @@ row_ins_foreign_check_on_constraint( UNIV_MEM_INVALID(update->fields, update->n_fields * sizeof *update->fields); - for (i = 0; i < foreign->n_fields; i++) { + for (ulint i = 0; i < foreign->n_fields; i++) { upd_field_t* ufield = &update->fields[i]; ufield->field_no = dict_table_get_nth_col_pos( @@ -1200,32 +1189,14 @@ row_ins_foreign_check_on_constraint( ufield->orig_len = 0; ufield->exp = NULL; dfield_set_null(&ufield->new_val); - - if (table->fts && dict_table_is_fts_column( - table->fts->indexes, - dict_index_get_nth_col_no(index, i)) - != ULINT_UNDEFINED) { - fts_col_affacted = TRUE; - } } - if (fts_col_affacted) { - fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL); - } - } else if (table->fts && cascade->is_delete) { - /* DICT_FOREIGN_ON_DELETE_CASCADE case */ - for (i = 0; i < foreign->n_fields; i++) { - if (table->fts && dict_table_is_fts_column( - table->fts->indexes, - dict_index_get_nth_col_no(index, i)) - != ULINT_UNDEFINED) { - fts_col_affacted = TRUE; - } - } - - if (fts_col_affacted) { + if (foreign->affects_fulltext()) { fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL); } + } else if (table->fts && cascade->is_delete + && foreign->affects_fulltext()) { + fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL); } if (!node->is_delete diff --git a/storage/xtradb/dict/dict0mem.cc b/storage/xtradb/dict/dict0mem.cc index 89b9bd9aead..82480b13827 100644 --- a/storage/xtradb/dict/dict0mem.cc +++ b/storage/xtradb/dict/dict0mem.cc @@ -853,3 +853,22 @@ operator<< (std::ostream& out, const dict_foreign_set& fk_set) return(out); } +/** Check whether fulltext index gets affected by foreign +key constraint. */ +bool dict_foreign_t::affects_fulltext() const +{ + if (foreign_table == referenced_table || !foreign_table->fts) + return false; + + for (ulint i = 0; i < n_fields; i++) + { + if (dict_table_is_fts_column( + foreign_table->fts->indexes, + dict_index_get_nth_col_no(foreign_index, i)) + != ULINT_UNDEFINED) + return true; + } + + return false; +} + diff --git a/storage/xtradb/include/dict0mem.h b/storage/xtradb/include/dict0mem.h index 1dcc3ebdd0c..f39c89d8e4b 100644 --- a/storage/xtradb/include/dict0mem.h +++ b/storage/xtradb/include/dict0mem.h @@ -864,6 +864,10 @@ struct dict_foreign_t{ does not generate new indexes implicitly */ dict_index_t* referenced_index;/*!< referenced index */ + + /** Check whether the fulltext index gets affected by + foreign key constraint */ + bool affects_fulltext() const; }; std::ostream& diff --git a/storage/xtradb/row/row0ins.cc b/storage/xtradb/row/row0ins.cc index f7371d6b83e..c78f5bc8dc4 100644 --- a/storage/xtradb/row/row0ins.cc +++ b/storage/xtradb/row/row0ins.cc @@ -516,7 +516,7 @@ row_ins_cascade_calc_update_vec( n_fields_updated = 0; - *fts_col_affected = FALSE; + *fts_col_affected = foreign->affects_fulltext(); if (table->fts) { doc_id_pos = dict_table_get_nth_col_pos( @@ -637,16 +637,6 @@ row_ins_cascade_calc_update_vec( padded_data, min_size); } - /* Check whether the current column has - FTS index on it */ - if (table->fts - && dict_table_is_fts_column( - table->fts->indexes, - dict_col_get_no(col)) - != ULINT_UNDEFINED) { - *fts_col_affected = TRUE; - } - /* If Doc ID is updated, check whether the Doc ID is valid */ if (table->fts @@ -983,7 +973,6 @@ row_ins_foreign_check_on_constraint( upd_t* update; ulint n_to_update; dberr_t err; - ulint i; trx_t* trx; mem_heap_t* tmp_heap = NULL; doc_id_t doc_id = FTS_NULL_DOC_ID; @@ -1197,7 +1186,7 @@ row_ins_foreign_check_on_constraint( UNIV_MEM_INVALID(update->fields, update->n_fields * sizeof *update->fields); - for (i = 0; i < foreign->n_fields; i++) { + for (ulint i = 0; i < foreign->n_fields; i++) { upd_field_t* ufield = &update->fields[i]; ufield->field_no = dict_table_get_nth_col_pos( @@ -1206,32 +1195,14 @@ row_ins_foreign_check_on_constraint( ufield->orig_len = 0; ufield->exp = NULL; dfield_set_null(&ufield->new_val); - - if (table->fts && dict_table_is_fts_column( - table->fts->indexes, - dict_index_get_nth_col_no(index, i)) - != ULINT_UNDEFINED) { - fts_col_affacted = TRUE; - } } - if (fts_col_affacted) { - fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL); - } - } else if (table->fts && cascade->is_delete) { - /* DICT_FOREIGN_ON_DELETE_CASCADE case */ - for (i = 0; i < foreign->n_fields; i++) { - if (table->fts && dict_table_is_fts_column( - table->fts->indexes, - dict_index_get_nth_col_no(index, i)) - != ULINT_UNDEFINED) { - fts_col_affacted = TRUE; - } - } - - if (fts_col_affacted) { + if (foreign->affects_fulltext()) { fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL); } + } else if (table->fts && cascade->is_delete + && foreign->affects_fulltext()) { + fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL); } if (!node->is_delete From 8984d7791035090fb51cb499fdb412bd14b74638 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Fri, 2 Oct 2020 10:00:59 +0530 Subject: [PATCH 102/323] MDEV-21329 InnoDB: Failing assertion: lock->lock_word.load(std::memory_order_relaxed) == X_LOCK_DECR upon server shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem is that dropping of fts table and sync of fts table happens concurrently during fts optimize thread shutdown. fts_optimize_remove_table() is executed by a user thread that performs DDL, and that the fts_optimize_wq may be removed if fts_optimize_shutdown() has started executing. fts_optimize_remove_table() doesn't remove the table from the queue and it leads to above scenario. While removing the table from fts_optimize_wq, if the table can't be removed then wait till fts_optimize_thread shuts down. Reviewed-by: Marko Mäkelä --- storage/innobase/fts/fts0opt.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index 8ad1cf4ebe1..3cabb64b851 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -2573,6 +2573,11 @@ fts_optimize_remove_table( if (fts_opt_start_shutdown) { ib::info() << "Try to remove table " << table->name << " after FTS optimize thread exiting."; + /* If the table can't be removed then wait till + fts optimize thread shuts down */ + while (fts_optimize_wq) { + os_thread_sleep(10000); + } return; } From a891fe6aa5ede1bf1f4551cfa75cf856f1dd1c50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 9 Oct 2020 12:47:58 +0300 Subject: [PATCH 103/323] MDEV-23927 Crash in ./mtr --skip-innodb-fast-shutdown innodb.temporary_tables innodb_preshutdown(): On innodb_fast_shutdown=0, only wait for transactions to exit if the transaction system had been initialized. Reviewed by: Vladislav Vaintroub --- mysql-test/suite/innodb/t/temporary_table.test | 2 +- storage/innobase/srv/srv0start.cc | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/innodb/t/temporary_table.test b/mysql-test/suite/innodb/t/temporary_table.test index 8e3ddf95634..389e106a345 100644 --- a/mysql-test/suite/innodb/t/temporary_table.test +++ b/mysql-test/suite/innodb/t/temporary_table.test @@ -131,7 +131,7 @@ AND support IN ('YES', 'DEFAULT', 'ENABLED'); # We cannot use include/restart_mysqld.inc in this particular test, # because SHOW STATUS would fail due to unwritable (nonexistent) tmpdir. --source include/shutdown_mysqld.inc ---exec echo "restart: --tmpdir=/dev/null/nonexistent" > $_expect_file_name +--exec echo "restart: --tmpdir=/dev/null/nonexistent --skip-innodb-fast-shutdown" > $_expect_file_name --enable_reconnect --disable_result_log --disable_query_log diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 3481df9160b..59ed743b087 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -2076,8 +2076,9 @@ void innodb_preshutdown() better prevent any further changes from being buffered. */ innodb_change_buffering= 0; - while (trx_sys.any_active_transactions()) - os_thread_sleep(1000); + if (trx_sys.is_initialised()) + while (trx_sys.any_active_transactions()) + os_thread_sleep(1000); } srv_shutdown_bg_undo_sources(); srv_purge_shutdown(); From 266bf77bc752c46bbd08fd0b33c7e30ee173e4b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 6 Oct 2020 13:40:14 +0300 Subject: [PATCH 104/323] MDEV-19968 : Galera test failure on galera_load_data Add necessary wait_conditions to stabilize test. --- .../suite/galera/r/galera_load_data.result | 25 +++++++++------- .../suite/galera/t/galera_load_data.test | 30 +++++++++++++------ 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/mysql-test/suite/galera/r/galera_load_data.result b/mysql-test/suite/galera/r/galera_load_data.result index 8a7397c7cb5..bbfd14a98f6 100644 --- a/mysql-test/suite/galera/r/galera_load_data.result +++ b/mysql-test/suite/galera/r/galera_load_data.result @@ -1,7 +1,7 @@ connection node_1; create database cardtest02; use cardtest02; -CREATE TABLE `cardtest_tbl` ( +CREATE TABLE cardtest_tbl ( `id` bigint(18) NOT NULL AUTO_INCREMENT, `course` bigint(18) NOT NULL, `name` varchar(200) DEFAULT NULL, @@ -22,24 +22,29 @@ CREATE TABLE `cardtest_tbl` ( `type` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1324 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED; -LOCK TABLES `cardtest_tbl` WRITE; -ALTER TABLE `cardtest_tbl` DISABLE KEYS; +LOCK TABLES cardtest_tbl WRITE; +ALTER TABLE cardtest_tbl DISABLE KEYS; Warnings: Note 1031 Storage engine InnoDB of the table `cardtest02`.`cardtest_tbl` doesn't have this option -INSERT INTO `cardtest_tbl` VALUES (1,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(2,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(3,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(4,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(5,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(6,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(7,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(8,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(9,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(10,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(11,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(12,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(13,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(14,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(15,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(16,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(17,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(18,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(19,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(20,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(21,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(22,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(23,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(24,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(25,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(26,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(27,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(28,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(29,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(30,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(31,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(32,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(33,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(34,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(35,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(36,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(37,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(38,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(39,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(40,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(41,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(42,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(43,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(44,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(45,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(46,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(47,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(48,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(49,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(50,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(51,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(52,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(53,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(54,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(55,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(56,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(57,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(58,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(59,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(60,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(61,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(62,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(63,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(64,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(65,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(66,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(67,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(68,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(69,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(70,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(71,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(72,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(73,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(74,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(75,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(76,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(77,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(78,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(79,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(80,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(81,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(82,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(83,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(84,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(85,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(86,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(87,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(88,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(89,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(90,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(91,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(92,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(93,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(94,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(95,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(96,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(97,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(98,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(99,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(100,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(101,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(102,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(103,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(104,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(105,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(106,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(107,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(108,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(109,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(110,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(111,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(112,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(113,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(114,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(115,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(116,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(117,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(118,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(119,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(120,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(121,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(122,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(123,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(124,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(125,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(126,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(127,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(128,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(129,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(130,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(131,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(132,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(133,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(134,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(135,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(136,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(137,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(138,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(139,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(140,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(141,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(142,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(143,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(144,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(145,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(146,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(147,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(148,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(149,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(150,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(151,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(152,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(153,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(154,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(155,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(156,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(157,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(158,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(159,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(160,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(161,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(162,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(163,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(164,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(165,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(166,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(167,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(168,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(169,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(170,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(171,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(172,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(173,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(174,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(175,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(176,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(177,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(178,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(179,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(180,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(181,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(182,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(183,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(184,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(185,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(186,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(187,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(188,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(189,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(190,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(191,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(192,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(193,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(194,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(195,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(196,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(197,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(198,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(199,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(200,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(201,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(202,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(203,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(204,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(205,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(206,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(207,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(208,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(209,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(210,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(211,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(212,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(213,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(214,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(215,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(216,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(217,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(218,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(219,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(220,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(221,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(222,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(223,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(224,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(225,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(226,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(227,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(228,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(229,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(230,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(231,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(232,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(233,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(234,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(235,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(236,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(237,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(238,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(239,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(240,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(241,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(242,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(243,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(244,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(245,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(246,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(247,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(248,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(249,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(250,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(251,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(252,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(253,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(254,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(255,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(256,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(257,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(258,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(259,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(260,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(261,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(262,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(263,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(264,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(265,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(266,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(267,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(268,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(269,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(270,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(271,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(272,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(273,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(274,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(275,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(276,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(277,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(278,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(279,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(280,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(281,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(282,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(283,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(284,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(285,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(286,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(287,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(288,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(289,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(290,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(291,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(292,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(293,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(294,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(295,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(296,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(297,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(298,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(299,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(300,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(301,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL); -ALTER TABLE `cardtest_tbl` ENABLE KEYS; +INSERT INTO cardtest_tbl VALUES (1,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(2,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(3,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(4,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(5,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(6,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(7,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(8,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(9,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(10,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(11,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(12,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(13,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(14,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(15,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(16,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(17,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(18,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(19,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(20,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(21,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(22,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(23,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(24,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(25,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(26,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(27,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(28,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(29,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(30,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(31,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(32,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(33,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(34,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(35,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(36,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(37,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(38,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(39,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(40,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(41,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(42,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(43,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(44,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(45,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(46,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(47,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(48,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(49,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(50,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(51,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(52,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(53,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(54,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(55,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(56,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(57,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(58,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(59,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(60,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(61,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(62,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(63,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(64,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(65,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(66,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(67,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(68,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(69,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(70,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(71,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(72,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(73,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(74,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(75,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(76,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(77,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(78,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(79,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(80,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(81,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(82,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(83,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(84,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(85,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(86,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(87,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(88,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(89,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(90,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(91,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(92,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(93,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(94,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(95,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(96,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(97,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(98,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(99,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(100,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(101,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(102,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(103,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(104,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(105,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(106,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(107,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(108,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(109,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(110,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(111,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(112,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(113,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(114,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(115,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(116,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(117,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(118,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(119,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(120,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(121,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(122,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(123,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(124,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(125,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(126,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(127,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(128,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(129,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(130,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(131,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(132,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(133,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(134,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(135,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(136,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(137,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(138,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(139,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(140,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(141,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(142,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(143,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(144,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(145,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(146,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(147,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(148,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(149,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(150,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(151,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(152,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(153,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(154,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(155,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(156,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(157,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(158,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(159,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(160,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(161,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(162,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(163,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(164,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(165,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(166,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(167,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(168,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(169,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(170,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(171,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(172,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(173,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(174,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(175,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(176,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(177,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(178,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(179,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(180,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(181,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(182,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(183,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(184,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(185,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(186,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(187,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(188,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(189,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(190,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(191,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(192,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(193,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(194,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(195,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(196,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(197,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(198,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(199,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(200,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(201,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(202,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(203,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(204,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(205,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(206,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(207,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(208,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(209,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(210,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(211,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(212,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(213,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(214,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(215,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(216,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(217,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(218,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(219,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(220,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(221,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(222,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(223,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(224,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(225,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(226,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(227,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(228,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(229,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(230,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(231,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(232,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(233,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(234,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(235,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(236,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(237,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(238,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(239,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(240,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(241,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(242,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(243,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(244,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(245,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(246,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(247,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(248,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(249,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(250,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(251,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(252,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(253,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(254,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(255,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(256,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(257,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(258,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(259,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(260,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(261,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(262,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(263,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(264,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(265,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(266,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(267,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(268,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(269,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(270,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(271,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(272,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(273,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(274,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(275,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(276,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(277,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(278,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(279,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(280,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(281,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(282,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(283,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(284,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(285,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(286,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(287,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(288,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(289,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(290,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(291,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(292,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(293,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(294,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(295,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(296,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(297,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(298,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(299,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(300,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(301,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL); +ALTER TABLE cardtest_tbl ENABLE KEYS; Warnings: Note 1031 Storage engine InnoDB of the table `cardtest02`.`cardtest_tbl` doesn't have this option UNLOCK TABLES; use cardtest02; -select count(*) from cardtest_tbl; -count(*) +ANALYZE TABLE cardtest_tbl; +Table Op Msg_type Msg_text +cardtest02.cardtest_tbl analyze status OK +SELECT COUNT(*) AS EXPECT_301 FROM cardtest_tbl; +EXPECT_301 301 connection node_2; -set session wsrep_sync_wait=15; use cardtest02; -select count(*) from cardtest_tbl; -count(*) +ANALYZE TABLE cardtest_tbl; +Table Op Msg_type Msg_text +cardtest02.cardtest_tbl analyze status OK +SELECT COUNT(*) AS EXPECT_301 FROM cardtest_tbl; +EXPECT_301 301 connection node_1; use test; diff --git a/mysql-test/suite/galera/t/galera_load_data.test b/mysql-test/suite/galera/t/galera_load_data.test index d4e09582a55..183095492fa 100644 --- a/mysql-test/suite/galera/t/galera_load_data.test +++ b/mysql-test/suite/galera/t/galera_load_data.test @@ -5,7 +5,7 @@ create database cardtest02; use cardtest02; -CREATE TABLE `cardtest_tbl` ( +CREATE TABLE cardtest_tbl ( `id` bigint(18) NOT NULL AUTO_INCREMENT, `course` bigint(18) NOT NULL, `name` varchar(200) DEFAULT NULL, @@ -27,21 +27,26 @@ CREATE TABLE `cardtest_tbl` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1324 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED; -LOCK TABLES `cardtest_tbl` WRITE; -ALTER TABLE `cardtest_tbl` DISABLE KEYS; +LOCK TABLES cardtest_tbl WRITE; +ALTER TABLE cardtest_tbl DISABLE KEYS; -INSERT INTO `cardtest_tbl` VALUES (1,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(2,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(3,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(4,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(5,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(6,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(7,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(8,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(9,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(10,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(11,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(12,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(13,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(14,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(15,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(16,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(17,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(18,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(19,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(20,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(21,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(22,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(23,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(24,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(25,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(26,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(27,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(28,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(29,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(30,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(31,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(32,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(33,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(34,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(35,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(36,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(37,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(38,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(39,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(40,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(41,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(42,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(43,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(44,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(45,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(46,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(47,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(48,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(49,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(50,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(51,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(52,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(53,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(54,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(55,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(56,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(57,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(58,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(59,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(60,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(61,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(62,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(63,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(64,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(65,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(66,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(67,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(68,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(69,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(70,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(71,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(72,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(73,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(74,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(75,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(76,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(77,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(78,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(79,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(80,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(81,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(82,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(83,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(84,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(85,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(86,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(87,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(88,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(89,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(90,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(91,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(92,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(93,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(94,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(95,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(96,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(97,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(98,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(99,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(100,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(101,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(102,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(103,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(104,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(105,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(106,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(107,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(108,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(109,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(110,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(111,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(112,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(113,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(114,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(115,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(116,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(117,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(118,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(119,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(120,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(121,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(122,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(123,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(124,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(125,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(126,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(127,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(128,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(129,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(130,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(131,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(132,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(133,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(134,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(135,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(136,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(137,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(138,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(139,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(140,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(141,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(142,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(143,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(144,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(145,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(146,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(147,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(148,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(149,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(150,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(151,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(152,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(153,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(154,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(155,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(156,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(157,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(158,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(159,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(160,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(161,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(162,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(163,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(164,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(165,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(166,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(167,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(168,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(169,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(170,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(171,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(172,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(173,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(174,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(175,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(176,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(177,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(178,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(179,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(180,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(181,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(182,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(183,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(184,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(185,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(186,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(187,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(188,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(189,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(190,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(191,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(192,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(193,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(194,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(195,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(196,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(197,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(198,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(199,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(200,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(201,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(202,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(203,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(204,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(205,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(206,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(207,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(208,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(209,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(210,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(211,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(212,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(213,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(214,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(215,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(216,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(217,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(218,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(219,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(220,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(221,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(222,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(223,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(224,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(225,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(226,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(227,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(228,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(229,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(230,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(231,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(232,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(233,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(234,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(235,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(236,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(237,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(238,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(239,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(240,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(241,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(242,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(243,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(244,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(245,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(246,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(247,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(248,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(249,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(250,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(251,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(252,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(253,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(254,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(255,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(256,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(257,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(258,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(259,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(260,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(261,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(262,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(263,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(264,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(265,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(266,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(267,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(268,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(269,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(270,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(271,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(272,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(273,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(274,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(275,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(276,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(277,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(278,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(279,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(280,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(281,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(282,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(283,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(284,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(285,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(286,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(287,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(288,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(289,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(290,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(291,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(292,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(293,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(294,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(295,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(296,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(297,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(298,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(299,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(300,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(301,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL); +INSERT INTO cardtest_tbl VALUES (1,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(2,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(3,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(4,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(5,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(6,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(7,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(8,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(9,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(10,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(11,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(12,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(13,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(14,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(15,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(16,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(17,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(18,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(19,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(20,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(21,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(22,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(23,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(24,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(25,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(26,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(27,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(28,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(29,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(30,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(31,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(32,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(33,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(34,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(35,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(36,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(37,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(38,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(39,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(40,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(41,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(42,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(43,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(44,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(45,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(46,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(47,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(48,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(49,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(50,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(51,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(52,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(53,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(54,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(55,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(56,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(57,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(58,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(59,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(60,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(61,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(62,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(63,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(64,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(65,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(66,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(67,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(68,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(69,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(70,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(71,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(72,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(73,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(74,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(75,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(76,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(77,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(78,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(79,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(80,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(81,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(82,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(83,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(84,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(85,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(86,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(87,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(88,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(89,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(90,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(91,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(92,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(93,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(94,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(95,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(96,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(97,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(98,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(99,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(100,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(101,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(102,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(103,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(104,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(105,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(106,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(107,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(108,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(109,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(110,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(111,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(112,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(113,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(114,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(115,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(116,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(117,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(118,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(119,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(120,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(121,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(122,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(123,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(124,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(125,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(126,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(127,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(128,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(129,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(130,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(131,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(132,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(133,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(134,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(135,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(136,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(137,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(138,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(139,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(140,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(141,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(142,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(143,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(144,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(145,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(146,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(147,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(148,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(149,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(150,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(151,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(152,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(153,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(154,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(155,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(156,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(157,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(158,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(159,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(160,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(161,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(162,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(163,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(164,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(165,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(166,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(167,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(168,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(169,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(170,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(171,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(172,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(173,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(174,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(175,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(176,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(177,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(178,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(179,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(180,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(181,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(182,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(183,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(184,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(185,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(186,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(187,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(188,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(189,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(190,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(191,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(192,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(193,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(194,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(195,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(196,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(197,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(198,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(199,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(200,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(201,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(202,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(203,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(204,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(205,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(206,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(207,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(208,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(209,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(210,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(211,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(212,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(213,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(214,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(215,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(216,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(217,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(218,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(219,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(220,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(221,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(222,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(223,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(224,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(225,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(226,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(227,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(228,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(229,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(230,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(231,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(232,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(233,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(234,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(235,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(236,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(237,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(238,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(239,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(240,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(241,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(242,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(243,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(244,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(245,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(246,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(247,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(248,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(249,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(250,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(251,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(252,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(253,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(254,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(255,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(256,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(257,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(258,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(259,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(260,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(261,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(262,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(263,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(264,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(265,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(266,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(267,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(268,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(269,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(270,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(271,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(272,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(273,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(274,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(275,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(276,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(277,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(278,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(279,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(280,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(281,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(282,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(283,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(284,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(285,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(286,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(287,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(288,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(289,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(290,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(291,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(292,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(293,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(294,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(295,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(296,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(297,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(298,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(299,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(300,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL),(301,1,'','',1,1466430455,1471454450,NULL,10.00000,1,NULL,'','',NULL,NULL,1,NULL,NULL); -ALTER TABLE `cardtest_tbl` ENABLE KEYS; +ALTER TABLE cardtest_tbl ENABLE KEYS; UNLOCK TABLES; use cardtest02; --let $wait_timeout=600 +--let $wait_condition = SELECT COUNT(*) = 301 from cardtest_tbl; +--source include/wait_condition.inc + +ANALYZE TABLE cardtest_tbl; + --let $wait_condition = SELECT table_rows = 301 from information_schema.tables WHERE TABLE_NAME = 'cardtest_tbl'; --source include/wait_condition.inc -select count(*) from cardtest_tbl; +SELECT COUNT(*) AS EXPECT_301 FROM cardtest_tbl; let $cardinality1 = `SELECT cardinality from information_schema.statistics WHERE TABLE_NAME = 'cardtest_tbl'`; let $table_rows1 = `SELECT table_rows from information_schema.tables WHERE TABLE_NAME = 'cardtest_tbl'`; @@ -49,14 +54,21 @@ let $avg_row_length1 = `SELECT avg_row_length from information_schema.tables WHE let $data_length1 = `SELECT data_length from information_schema.tables WHERE TABLE_NAME = 'cardtest_tbl'`; --connection node_2 -set session wsrep_sync_wait=15; use cardtest02; --let $wait_timeout=600 ---let $wait_condition = SELECT table_rows = 301 from information_schema.tables WHERE TABLE_NAME = 'cardtest_tbl'; +--let $wait_condition = SELECT COUNT(*) = 301 from cardtest_tbl; --source include/wait_condition.inc -select count(*) from cardtest_tbl; +ANALYZE TABLE cardtest_tbl; + +--source include/wait_condition.inc +--let $wait_condition = SELECT table_rows = 301 from information_schema.tables WHERE TABLE_NAME = 'cardtest_tbl'; +--source include/wait_condition.inc +--let $wait_condition = SELECT cardinality = 301 from information_schema.statistics WHERE TABLE_NAME = 'cardtest_tbl'; +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_301 FROM cardtest_tbl; if (`SELECT cardinality <> $cardinality1 from information_schema.statistics WHERE TABLE_NAME = 'cardtest_tbl'`) { From fc3b5c7db3a6b2f17d55088f6194c8d7ffb54bc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 6 Oct 2020 14:46:47 +0300 Subject: [PATCH 105/323] MDEV-17585 : wsrep.variables failed in buildbot with deadlock on CREATE USER Stabilize test by using correct galera library and restore original galera cluster at end. --- .../include/galera_have_debug_sync.inc | 2 +- mysql-test/suite/wsrep/r/variables.result | 34 ++++++++----------- mysql-test/suite/wsrep/t/variables.cnf | 7 ++++ mysql-test/suite/wsrep/t/variables.test | 29 +++++++++------- 4 files changed, 40 insertions(+), 32 deletions(-) rename mysql-test/{suite/galera => }/include/galera_have_debug_sync.inc (73%) create mode 100644 mysql-test/suite/wsrep/t/variables.cnf diff --git a/mysql-test/suite/galera/include/galera_have_debug_sync.inc b/mysql-test/include/galera_have_debug_sync.inc similarity index 73% rename from mysql-test/suite/galera/include/galera_have_debug_sync.inc rename to mysql-test/include/galera_have_debug_sync.inc index 7c0156052d8..21e7b3c88c3 100644 --- a/mysql-test/suite/galera/include/galera_have_debug_sync.inc +++ b/mysql-test/include/galera_have_debug_sync.inc @@ -3,7 +3,7 @@ --let $galera_have_debug_sync = `SELECT 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_debug_sync_waiters'` --if (!$galera_have_debug_sync) { - --skip "Test requires Galera debug library with debug_sync functionality" + --skip Test requires Galera debug library with debug_sync functionality } --enable_query_log diff --git a/mysql-test/suite/wsrep/r/variables.result b/mysql-test/suite/wsrep/r/variables.result index 3abc861f3d0..c9c0c5af9c5 100644 --- a/mysql-test/suite/wsrep/r/variables.result +++ b/mysql-test/suite/wsrep/r/variables.result @@ -1,3 +1,4 @@ +call mtr.add_suppression("WSREP: Initial position was provided by configuration or SST, avoiding override"); SET @wsrep_provider_options_saved= @@global.wsrep_provider_options; SET @wsrep_cluster_address_saved= @@global.wsrep_cluster_address; @@ -38,6 +39,7 @@ wsrep_commit_oooe # wsrep_commit_oool # wsrep_commit_window # wsrep_connected # +wsrep_debug_sync_waiters # wsrep_flow_control_paused # wsrep_flow_control_paused_ns # wsrep_flow_control_recv # @@ -85,9 +87,6 @@ wsrep_local_state_comment # SHOW STATUS LIKE 'x'; Variable_name Value SET GLOBAL wsrep_provider=none; -# -# MDEV#6079: xtrabackup SST failing with maria-10.0-galera -# SHOW STATUS LIKE 'wsrep_local_state_uuid'; Variable_name Value @@ -141,14 +140,15 @@ wsrep_thread_count 0 # applier/rollbacker threads. SET GLOBAL wsrep_cluster_address= 'gcomm://'; # Wait for applier thread to get created 1. -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; -VARIABLE_VALUE +# Wait for applier thread to get created 2. +SELECT VARIABLE_VALUE AS EXPECT_1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; +EXPECT_1 1 -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; -VARIABLE_VALUE +SELECT VARIABLE_VALUE AS EXPECT_1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; +EXPECT_1 1 -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; -VARIABLE_VALUE +SELECT VARIABLE_VALUE AS EXPECT_2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; +EXPECT_2 2 SELECT @@global.wsrep_provider; @@global.wsrep_provider @@ -169,14 +169,14 @@ wsrep_thread_count 2 SET @wsrep_slave_threads_saved= @@global.wsrep_slave_threads; SET GLOBAL wsrep_slave_threads= 10; # Wait for 9 applier threads to get created. -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; -VARIABLE_VALUE +SELECT VARIABLE_VALUE AS EXPECT_10 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; +EXPECT_10 10 -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; -VARIABLE_VALUE +SELECT VARIABLE_VALUE AS EXPECT_1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; +EXPECT_1 1 -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; -VARIABLE_VALUE +SELECT VARIABLE_VALUE AS EXPECT_11 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; +EXPECT_11 11 SHOW STATUS LIKE 'threads_connected'; Variable_name Value @@ -208,8 +208,4 @@ SELECT @@global.wsrep_sst_auth; @@global.wsrep_sst_auth NULL SET @@global.wsrep_sst_auth= @wsrep_sst_auth_saved; -SET GLOBAL wsrep_slave_threads= @wsrep_slave_threads_saved; -SET GLOBAL wsrep_provider= none; -SET GLOBAL wsrep_cluster_address= @wsrep_cluster_address_saved; -SET GLOBAL wsrep_provider_options= @wsrep_provider_options_saved; # End of test. diff --git a/mysql-test/suite/wsrep/t/variables.cnf b/mysql-test/suite/wsrep/t/variables.cnf new file mode 100644 index 00000000000..b1c96d2614d --- /dev/null +++ b/mysql-test/suite/wsrep/t/variables.cnf @@ -0,0 +1,7 @@ +!include ../my.cnf + +[mysqld.1] +wsrep-on=ON +wsrep-cluster-address=gcomm:// +wsrep-provider=@ENV.WSREP_PROVIDER +binlog-format=ROW diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test index 5336fae17b6..2556d8ede4f 100644 --- a/mysql-test/suite/wsrep/t/variables.test +++ b/mysql-test/suite/wsrep/t/variables.test @@ -1,5 +1,9 @@ --source include/have_wsrep.inc --source include/force_restart.inc +--source include/have_innodb.inc +--source include/galera_have_debug_sync.inc + +call mtr.add_suppression("WSREP: Initial position was provided by configuration or SST, avoiding override"); SET @wsrep_provider_options_saved= @@global.wsrep_provider_options; SET @wsrep_cluster_address_saved= @@global.wsrep_cluster_address; @@ -50,15 +54,11 @@ SHOW STATUS LIKE 'x'; # Reset it back. SET GLOBAL wsrep_provider=none; ---echo # ---echo # MDEV#6079: xtrabackup SST failing with maria-10.0-galera ---echo # - --disable_query_log eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; --enable_query_log -# The following 2 variables are used in innobackupex during xtrabackup-based +# The following 2 variables are used by mariabackup # SST. --echo --replace_column 2 # @@ -109,12 +109,13 @@ SET GLOBAL wsrep_cluster_address= 'gcomm://'; --let $wait_timeout=600 --let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; --source include/wait_condition.inc +--echo # Wait for applier thread to get created 2. --let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; --source include/wait_condition.inc -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; +SELECT VARIABLE_VALUE AS EXPECT_1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; +SELECT VARIABLE_VALUE AS EXPECT_1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; +SELECT VARIABLE_VALUE AS EXPECT_2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; --replace_regex /.*libgalera_smm.*/libgalera_smm.so/ SELECT @@global.wsrep_provider; @@ -131,9 +132,9 @@ SET GLOBAL wsrep_slave_threads= 10; --let $wait_condition = SELECT VARIABLE_VALUE = 10 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; --source include/wait_condition.inc -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; +SELECT VARIABLE_VALUE AS EXPECT_10 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; +SELECT VARIABLE_VALUE AS EXPECT_1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; +SELECT VARIABLE_VALUE AS EXPECT_11 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; SHOW STATUS LIKE 'threads_connected'; @@ -165,10 +166,14 @@ SELECT @@global.wsrep_sst_auth; SET @@global.wsrep_sst_auth= @wsrep_sst_auth_saved; # Reset (for mtr internal checks) +--disable_query_log SET GLOBAL wsrep_slave_threads= @wsrep_slave_threads_saved; -SET GLOBAL wsrep_provider= none; +eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; SET GLOBAL wsrep_cluster_address= @wsrep_cluster_address_saved; SET GLOBAL wsrep_provider_options= @wsrep_provider_options_saved; +--enable_query_log + +--source include/galera_wait_ready.inc --echo # End of test. From a3eddd9f11863fd137a39cdfa5a7e3a2026d64e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 8 Oct 2020 13:35:06 +0300 Subject: [PATCH 106/323] MDEV-23659 : Update Galera disabled.def file Changes to be committed: modified: mysql-test/suite/galera/disabled.def modified: mysql-test/suite/wsrep/disabled.def --- mysql-test/suite/galera/disabled.def | 1 - mysql-test/suite/wsrep/disabled.def | 1 - 2 files changed, 2 deletions(-) diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def index b4dd37ea7cb..4d911c60a5e 100644 --- a/mysql-test/suite/galera/disabled.def +++ b/mysql-test/suite/galera/disabled.def @@ -18,7 +18,6 @@ galera.galera_defaults : MDEV-21494 Galera test sporadic failure on galera.galer galera_as_slave_replication_bundle : MDEV-15785 OPTION_GTID_BEGIN is set in Gtid_log_event::do_apply_event() galera_binlog_stmt_autoinc : MDEV-19959 Galera test failure on galera_binlog_stmt_autoinc galera_gcache_recover_manytrx : MDEV-18834 Galera test failure -galera_load_data : MDEV-19968 galera.galera_load_data galera_parallel_simple : MDEV-20318 galera.galera_parallel_simple fails galera_shutdown_nonprim : MDEV-21493 galera.galera_shutdown_nonprim galera_ssl_upgrade : MDEV-19950 Galera test failure on galera_ssl_upgrade diff --git a/mysql-test/suite/wsrep/disabled.def b/mysql-test/suite/wsrep/disabled.def index ab3f9fe3604..11577bfe8b0 100644 --- a/mysql-test/suite/wsrep/disabled.def +++ b/mysql-test/suite/wsrep/disabled.def @@ -10,4 +10,3 @@ # ############################################################################## -variables : MDEV-17585 wsrep.variables From 222e1b806ff93083a62f740f6d247f8081983592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Sat, 10 Oct 2020 11:06:59 +0300 Subject: [PATCH 107/323] Add missing file. --- .../suite/galera/include/galera_have_debug_sync.inc | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 mysql-test/suite/galera/include/galera_have_debug_sync.inc diff --git a/mysql-test/suite/galera/include/galera_have_debug_sync.inc b/mysql-test/suite/galera/include/galera_have_debug_sync.inc new file mode 100644 index 00000000000..21e7b3c88c3 --- /dev/null +++ b/mysql-test/suite/galera/include/galera_have_debug_sync.inc @@ -0,0 +1,9 @@ +--disable_query_log + +--let $galera_have_debug_sync = `SELECT 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_debug_sync_waiters'` + +--if (!$galera_have_debug_sync) { + --skip Test requires Galera debug library with debug_sync functionality +} + +--enable_query_log From 72cb20820b4f48fda0ae5e0ead4783d76dde3ec0 Mon Sep 17 00:00:00 2001 From: unki Date: Fri, 25 Sep 2020 08:41:26 +0200 Subject: [PATCH 108/323] mysqlimport manpage - s/mysqldump/mysqlimport/g Closes PR #1672 - Note there are some legacy format not visible when invoking `man` Reviewed by: Ian Gilfillan, Anel Husakovic --- man/mysqlimport.1 | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/man/mysqlimport.1 b/man/mysqlimport.1 index 61d270d7057..449c59cb648 100644 --- a/man/mysqlimport.1 +++ b/man/mysqlimport.1 @@ -57,13 +57,13 @@ all would be imported into a table named patient\&. .PP .PP -\fBmysqldump\fR +\fBmysqlimport\fR supports the following options, which can be specified on the command line or in the -[mysqldump] +[mysqlimport] and [client] option file groups\&. -\fBmysqldump\fR +\fBmysqlimport\fR also supports the options for processing option files\&. .sp .RS 4 @@ -267,17 +267,17 @@ Empty the table before importing the text file\&. .sp -1 .IP \(bu 2.3 .\} -.\" mysqldump: fields-terminated-by option -.\" fields-terminated-by option: mysqldump +.\" mysqlimport: fields-terminated-by option +.\" fields-terminated-by option: mysqlimport \fB\-\-fields\-terminated\-by=\&.\&.\&.\fR, -.\" mysqldump: fields-enclosed-by option -.\" fields-enclosed-by option: mysqldump +.\" mysqlimport: fields-enclosed-by option +.\" fields-enclosed-by option: mysqlimport \fB\-\-fields\-enclosed\-by=\&.\&.\&.\fR, -.\" mysqldump: fields-optionally-enclosed-by option -.\" fields-optionally-enclosed-by option: mysqldump +.\" mysqlimport: fields-optionally-enclosed-by option +.\" fields-optionally-enclosed-by option: mysqlimport \fB\-\-fields\-optionally\-enclosed\-by=\&.\&.\&.\fR, -.\" mysqldump: fields-escaped-by option -.\" fields-escaped-by option: mysqldump +.\" mysqlimport: fields-escaped-by option +.\" fields-escaped-by option: mysqlimport \fB\-\-fields\-escaped\-by=\&.\&.\&.\fR .sp These options have the same meaning as the corresponding clauses for @@ -379,8 +379,8 @@ lines of the data file\&. .sp -1 .IP \(bu 2.3 .\} -.\" mysqldump: lines-terminated-by option -.\" lines-terminated-by option: mysqldump +.\" mysqlimport: lines-terminated-by option +.\" lines-terminated-by option: mysqlimport \fB\-\-lines\-terminated\-by=\&.\&.\&.\fR .sp This option has the same meaning as the corresponding clause for From 52dad6fd264425ef37c5e7ecf0dd904b3f50b7bf Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 13 Oct 2020 03:23:46 +0300 Subject: [PATCH 109/323] MDEV-21584 Linux aio returned OS error 22 Sometimes blockdev --getss returns 4096. In that case ROW_FORMAT=COMPRESSED tables might violate that 4096 bytes alignment. This patch disables O_DIRECT for COMPRESSED tables. OS_DATA_FILE_NO_O_DIRECT: new possible value for os_file_create() argument fil_node_open_file(): do not O_DIRECT ROW_FORMAT=COMPRESSED tables AIO::is_linux_native_aio_supported(): minimal alignment in a general case is 4096 and not 512. --- storage/innobase/fil/fil0fil.cc | 22 ++++++++++++++++++++-- storage/innobase/include/os0file.h | 3 ++- storage/innobase/os/os0file.cc | 10 ++++++---- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 384937063eb..328cd104e5d 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -605,6 +605,14 @@ static bool fil_node_open_file(fil_node_t* node) const bool first_time_open = node->size == 0; + bool o_direct_possible = !FSP_FLAGS_HAS_PAGE_COMPRESSION(space->flags); + if (const ulint ssize = FSP_FLAGS_GET_ZIP_SSIZE(space->flags)) { + compile_time_assert(((UNIV_ZIP_SIZE_MIN >> 1) << 3) == 4096); + if (ssize < 3) { + o_direct_possible = false; + } + } + if (first_time_open || (space->purpose == FIL_TYPE_TABLESPACE && node == UT_LIST_GET_FIRST(space->chain) @@ -623,7 +631,12 @@ retry: node->is_raw_disk ? OS_FILE_OPEN_RAW | OS_FILE_ON_ERROR_NO_EXIT : OS_FILE_OPEN | OS_FILE_ON_ERROR_NO_EXIT, - OS_FILE_AIO, OS_DATA_FILE, read_only_mode, &success); + OS_FILE_AIO, + o_direct_possible + ? OS_DATA_FILE + : OS_DATA_FILE_NO_O_DIRECT, + read_only_mode, + &success); if (!success) { /* The following call prints an error message */ @@ -654,7 +667,12 @@ retry: node->is_raw_disk ? OS_FILE_OPEN_RAW | OS_FILE_ON_ERROR_NO_EXIT : OS_FILE_OPEN | OS_FILE_ON_ERROR_NO_EXIT, - OS_FILE_AIO, OS_DATA_FILE, read_only_mode, &success); + OS_FILE_AIO, + o_direct_possible + ? OS_DATA_FILE + : OS_DATA_FILE_NO_O_DIRECT, + read_only_mode, + &success); } if (space->purpose != FIL_TYPE_LOG) { diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index e85bf74201a..82d1551de6c 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -2,7 +2,7 @@ Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2009, Percona Inc. -Copyright (c) 2013, 2019, MariaDB Corporation. +Copyright (c) 2013, 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Percona Inc.. Those modifications are @@ -161,6 +161,7 @@ static const ulint OS_FILE_NORMAL = 62; static const ulint OS_DATA_FILE = 100; static const ulint OS_LOG_FILE = 101; static const ulint OS_DATA_TEMP_FILE = 102; +static const ulint OS_DATA_FILE_NO_O_DIRECT = 103; /* @} */ /** Error codes from os_file_get_last_error @{ */ diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 94552383c48..5c6da7ad51c 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -2360,8 +2360,8 @@ AIO::is_linux_native_aio_supported() io_prep_pwrite(p_iocb, fd, ptr, UNIV_PAGE_SIZE, 0); } else { - ut_a(UNIV_PAGE_SIZE >= 512); - io_prep_pread(p_iocb, fd, ptr, 512, 0); + ut_a(srv_page_size >= 4096); + io_prep_pread(p_iocb, fd, ptr, srv_page_size, 0); } ut_a(reinterpret_cast(p_iocb->u.c.buf) % OS_FILE_LOG_BLOCK_SIZE @@ -3007,7 +3007,8 @@ os_file_create_func( ut_a(type == OS_LOG_FILE || type == OS_DATA_FILE - || type == OS_DATA_TEMP_FILE); + || type == OS_DATA_TEMP_FILE + || type == OS_DATA_FILE_NO_O_DIRECT); ut_a(purpose == OS_FILE_AIO || purpose == OS_FILE_NORMAL); @@ -3054,7 +3055,8 @@ os_file_create_func( /* We disable OS caching (O_DIRECT) only on data files */ if (!read_only && *success - && (type != OS_LOG_FILE && type != OS_DATA_TEMP_FILE) + && (type != OS_LOG_FILE && type != OS_DATA_TEMP_FILE + && type != OS_DATA_FILE_NO_O_DIRECT) && (srv_file_flush_method == SRV_O_DIRECT || srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC)) { From 5896a49820363ec7c393de7d9967fa8dc8f18b1a Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Wed, 9 Oct 2019 16:48:50 +1000 Subject: [PATCH 110/323] MDEV-19130 Assertion failed in handler::update_auto_increment add store/restore_auto_increment in period portion insert/update functions --- mysql-test/suite/period/r/delete.result | 20 +++++++++++++++++ mysql-test/suite/period/r/update.result | 11 ++++++++++ mysql-test/suite/period/t/delete.test | 29 ++++++++++++++++++++++++- mysql-test/suite/period/t/update.test | 10 +++++++++ sql/sql_delete.cc | 3 +++ sql/table.cc | 3 +++ 6 files changed, 75 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/period/r/delete.result b/mysql-test/suite/period/r/delete.result index 451017e5340..a58f57761b6 100644 --- a/mysql-test/suite/period/r/delete.result +++ b/mysql-test/suite/period/r/delete.result @@ -368,3 +368,23 @@ drop procedure sp; drop table t,t2,t3,log_tbl; drop view v; drop procedure log; +# MDEV-19130 Assertion +# `next_insert_id >= auto_inc_interval_for_cur_row.minimum()' +# failed in handler::update_auto_increment after error 167 +create or replace table t (f tinyint auto_increment null, +s timestamp, e timestamp, +period for app(s,e), key(f, s)); +insert into t (s,e) values +('2021-08-22 10:28:43', '2023-09-17 00:00:00'), +('2019-05-09 21:45:24', '2020-04-22 14:38:49'); +insert into t (s,e) select s,e from t; +insert into t (s,e) select s,e from t; +insert into t (s,e) select s,e from t; +insert into t (s,e) values ('2015-07-07 00:00:00','2020-03-11 08:48:52'); +insert into t (s,e) select s,e from t; +insert into t (s,e) select s,e from t; +insert into t select * from t; +ERROR 22003: Out of range value for column 'f' at row ROW +delete ignore from t +for portion of app from '2015-07-07 00:00:00' to '2020-03-11 08:48:52'; +drop table t; diff --git a/mysql-test/suite/period/r/update.result b/mysql-test/suite/period/r/update.result index 05d1a2eb6d3..b02c075560e 100644 --- a/mysql-test/suite/period/r/update.result +++ b/mysql-test/suite/period/r/update.result @@ -281,3 +281,14 @@ create table t1 (s date, e date, period for app(s,e), f varchar(8)) engine=aria insert into t1 values ('2024-05-13','2026-03-25','foo'); update t1 for portion of app from '2024-04-02' to '2026-03-15' set f = 'bar'; drop table t1; +# MDEV-19130 Assertion +# `next_insert_id >= auto_inc_interval_for_cur_row.minimum()' +# failed in handler::update_auto_increment after error 167 +create table t1 (id int auto_increment, f int, s datetime, e datetime, period for p(s,e), primary key(id)); +insert into t1 (s,e) values ('1994-01-06','2004-11-30'),('1994-06-21','1997-06-20'); +update ignore t1 set id = 2429681664; +Warnings: +Warning 1264 Out of range value for column 'id' at row 1 +Warning 1264 Out of range value for column 'id' at row 2 +update ignore t1 for portion of p from '1995-07-06' to '2009-01-12' set f = 1; +drop table t1; diff --git a/mysql-test/suite/period/t/delete.test b/mysql-test/suite/period/t/delete.test index 738d77d2c19..2a5f65d80ba 100644 --- a/mysql-test/suite/period/t/delete.test +++ b/mysql-test/suite/period/t/delete.test @@ -194,7 +194,34 @@ call sp; drop table t1; drop procedure sp; - drop table t,t2,t3,log_tbl; drop view v; drop procedure log; + +--echo # MDEV-19130 Assertion +--echo # `next_insert_id >= auto_inc_interval_for_cur_row.minimum()' +--echo # failed in handler::update_auto_increment after error 167 + +create or replace table t (f tinyint auto_increment null, + s timestamp, e timestamp, + period for app(s,e), key(f, s)); +insert into t (s,e) values + ('2021-08-22 10:28:43', '2023-09-17 00:00:00'), + ('2019-05-09 21:45:24', '2020-04-22 14:38:49'); +insert into t (s,e) select s,e from t; +insert into t (s,e) select s,e from t; +insert into t (s,e) select s,e from t; +insert into t (s,e) values ('2015-07-07 00:00:00','2020-03-11 08:48:52'); +insert into t (s,e) select s,e from t; +insert into t (s,e) select s,e from t; + +--replace_regex /row \d+/row ROW/ +--error HA_ERR_AUTOINC_ERANGE +insert into t select * from t; + +--disable_warnings +delete ignore from t + for portion of app from '2015-07-07 00:00:00' to '2020-03-11 08:48:52'; +--enable_warnings + +drop table t; diff --git a/mysql-test/suite/period/t/update.test b/mysql-test/suite/period/t/update.test index 0f54dd80eec..d4a2080ea0a 100644 --- a/mysql-test/suite/period/t/update.test +++ b/mysql-test/suite/period/t/update.test @@ -173,3 +173,13 @@ update t1 for portion of app from '2024-04-02' to '2026-03-15' set f = 'bar'; # cleanup drop table t1; + +--echo # MDEV-19130 Assertion +--echo # `next_insert_id >= auto_inc_interval_for_cur_row.minimum()' +--echo # failed in handler::update_auto_increment after error 167 +create table t1 (id int auto_increment, f int, s datetime, e datetime, period for p(s,e), primary key(id)); +insert into t1 (s,e) values ('1994-01-06','2004-11-30'),('1994-06-21','1997-06-20'); +update ignore t1 set id = 2429681664; +update ignore t1 for portion of p from '1995-07-06' to '2009-01-12' set f = 1; + +drop table t1; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index f4cad88124f..a4ef698590c 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -260,6 +260,7 @@ int update_portion_of_time(THD *thd, TABLE *table, uint dst_fieldno= lcond ? table->s->period.end_fieldno : table->s->period.start_fieldno; + table->file->store_auto_increment(); store_record(table, record[1]); if (likely(!res)) res= src->save_in_field(table->field[dst_fieldno], true); @@ -274,6 +275,8 @@ int update_portion_of_time(THD *thd, TABLE *table, res= table->triggers->process_triggers(thd, TRG_EVENT_INSERT, TRG_ACTION_AFTER, true); restore_record(table, record[1]); + if (res) + table->file->restore_auto_increment(); if (likely(!res) && lcond && rcond) res= table->period_make_insert(period_conds.end.item, diff --git a/sql/table.cc b/sql/table.cc index 5d465cf80b5..38777de34a7 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -8499,6 +8499,7 @@ int TABLE::period_make_insert(Item *src, Field *dst) { THD *thd= in_use; + file->store_auto_increment(); store_record(this, record[1]); int res= src->save_in_field(dst, true); @@ -8517,6 +8518,8 @@ int TABLE::period_make_insert(Item *src, Field *dst) TRG_ACTION_AFTER, true); restore_record(this, record[1]); + if (res) + file->restore_auto_increment(); return res; } From 171da6b38b7e7abc0fbea8a7181ad0b4e9ad3855 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Wed, 30 Sep 2020 10:22:58 +1000 Subject: [PATCH 111/323] MDEV-22761: innodb row_search_idx_cond_check handle CHECK_ABORTED_BY_USER MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit handler_rowid_filter_check can return CHECK_ABORTED_BY_USER. All the functions that call row_search_idx_cond_check handle the CHECK_ABORTED_BY_USER return value. So return it rather than generating an error. This incorrect handling was introduced in MDEV-21794 (8d85715d507d). Reviewer: Marko Mäkelä --- .../main/rowid_filter_innodb_debug.result | 26 +++++++++++ .../main/rowid_filter_innodb_debug.test | 46 +++++++++++++++++++ mysql-test/unstable-tests | 1 + storage/innobase/row/row0sel.cc | 6 ++- 4 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 mysql-test/main/rowid_filter_innodb_debug.result create mode 100644 mysql-test/main/rowid_filter_innodb_debug.test diff --git a/mysql-test/main/rowid_filter_innodb_debug.result b/mysql-test/main/rowid_filter_innodb_debug.result new file mode 100644 index 00000000000..91fa66937b6 --- /dev/null +++ b/mysql-test/main/rowid_filter_innodb_debug.result @@ -0,0 +1,26 @@ +set @save_optimizer_switch= @@optimizer_switch; +set @save_use_stat_tables= @@use_stat_tables; +set @save_optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; +set @@use_stat_tables=preferably; +set optimizer_use_condition_selectivity=2; +set optimizer_switch='rowid_filter=on'; +# +# MDEV-22761 KILL QUERY during rowid_filter, crashes +# +CREATE TABLE t1 (a INT, b INT, INDEX(a), INDEX(b)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (0,0),(1,0),(-1,1), (-2,1), (-2,3), (-3,4), (-2,4); +set debug_sync='row_search_pre_rowid_filter_check SIGNAL killme WAIT_FOR go'; +SELECT * FROM t1 WHERE a > 0 AND b=0; +connect con1, localhost, root,,; +connection con1; +set debug_sync='now WAIT_FOR killme'; +kill query @id; +set debug_sync='now SIGNAL go'; +connection default; +a b +set debug_sync='RESET'; +disconnect con1; +drop table t1; +set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity; +set @@optimizer_switch=@save_optimizer_switch; +set @@use_stat_tables=@save_use_stat_tables; diff --git a/mysql-test/main/rowid_filter_innodb_debug.test b/mysql-test/main/rowid_filter_innodb_debug.test new file mode 100644 index 00000000000..3f8eb5b5c38 --- /dev/null +++ b/mysql-test/main/rowid_filter_innodb_debug.test @@ -0,0 +1,46 @@ +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_innodb.inc +--source include/default_optimizer_switch.inc +--source include/count_sessions.inc + +set @save_optimizer_switch= @@optimizer_switch; +set @save_use_stat_tables= @@use_stat_tables; +set @save_optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; + +set @@use_stat_tables=preferably; + +set optimizer_use_condition_selectivity=2; +set optimizer_switch='rowid_filter=on'; + +--echo # +--echo # MDEV-22761 KILL QUERY during rowid_filter, crashes +--echo # + +CREATE TABLE t1 (a INT, b INT, INDEX(a), INDEX(b)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (0,0),(1,0),(-1,1), (-2,1), (-2,3), (-3,4), (-2,4); + +let $ID= `SELECT @id := CONNECTION_ID()`; + +set debug_sync='row_search_pre_rowid_filter_check SIGNAL killme WAIT_FOR go'; +send SELECT * FROM t1 WHERE a > 0 AND b=0; + +connect (con1, localhost, root,,); +connection con1; +let $ignore= `SELECT @id := $ID`; +set debug_sync='now WAIT_FOR killme'; +kill query @id; +set debug_sync='now SIGNAL go'; + +connection default; +reap; +set debug_sync='RESET'; + +disconnect con1; +drop table t1; + +set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity; +set @@optimizer_switch=@save_optimizer_switch; +set @@use_stat_tables=@save_use_stat_tables; + +--source include/wait_until_count_sessions.inc diff --git a/mysql-test/unstable-tests b/mysql-test/unstable-tests index 093df40d1d0..1ddbc8d5278 100644 --- a/mysql-test/unstable-tests +++ b/mysql-test/unstable-tests @@ -184,6 +184,7 @@ main.rowid_filter : Modified in 10.4.13 main.rowid_filter_innodb : MDEV-20538 - Wrong result; modified in 10.4.13 main.rowid_filter_myisam : Added in 10.4.14 main.rpl_mysql_upgrade_slave_repo_check : Added in 10.4.13 +main.rowid_filter_innodb_debug : MDEV-22761 - Added in 10.4.15 main.select : MDEV-20532 - Floating point differences main.select_jcl6 : MDEV-20532 - Floating point differences main.select_pkeycache : MDEV-20532 - Floating point differences diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 26a6d608ad7..7f1362cb931 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -3900,7 +3900,7 @@ exhausted: /*********************************************************************//** Check a pushed-down index condition. -@return CHECK_NEG, CHECK_POS, or CHECK_OUT_OF_RANGE */ +@return CHECK_ABORTED_BY_USER, CHECK_NEG, CHECK_POS, or CHECK_OUT_OF_RANGE */ static check_result_t row_search_idx_cond_check( @@ -3975,6 +3975,8 @@ row_search_idx_cond_check( ut_ad(len == DATA_ROW_ID_LEN); memcpy(prebuilt->row_id, data, DATA_ROW_ID_LEN); } + DEBUG_SYNC_C("row_search_pre_rowid_filter_check"); + result = handler_rowid_filter_check(prebuilt->pk_filter); switch (result) { case CHECK_NEG: @@ -3986,7 +3988,7 @@ row_search_idx_cond_check( case CHECK_POS: break; default: - ut_error; + return(result); } } /* Convert the remaining fields to MySQL format. From c03885cd9ceb1ede7f49a9e218022b401b3a1e28 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 9 Oct 2020 17:48:22 +0300 Subject: [PATCH 112/323] MDEV-22761: innodb row_search_idx_cond_check handle CHECK_ABORTED_BY_USER Part #2: - row_search_mvcc() should return DB_INTERRUPTED when it got - Move the sync point from innodb internals to handler_rowid_filter_check() where other storage engines can use it too - Add a similar syncpoint for the ICP check. - Add a bigger test and test coverage for Rowid Filter with MyISAM - Add test coverage for killed-during-ICP-check scenario --- mysql-test/include/icp_debug_kill.inc | 50 ++++++++++++++ .../include/rowid_filter_debug_kill.inc | 68 +++++++++++++++++++ mysql-test/main/aria_icp_debug.result | 34 ++++++++++ mysql-test/main/aria_icp_debug.test | 5 ++ mysql-test/main/innodb_icp_debug.result | 34 ++++++++++ mysql-test/main/innodb_icp_debug.test | 6 ++ mysql-test/main/myisam_icp_debug.result | 32 +++++++++ mysql-test/main/myisam_icp_debug.test | 1 + .../main/rowid_filter_innodb_debug.result | 61 ++++++++++++++++- .../main/rowid_filter_innodb_debug.test | 11 ++- .../main/rowid_filter_myisam_debug.result | 54 +++++++++++++++ .../main/rowid_filter_myisam_debug.test | 3 + sql/handler.cc | 2 + storage/innobase/row/row0sel.cc | 6 +- 14 files changed, 359 insertions(+), 8 deletions(-) create mode 100644 mysql-test/include/icp_debug_kill.inc create mode 100644 mysql-test/include/rowid_filter_debug_kill.inc create mode 100644 mysql-test/main/aria_icp_debug.result create mode 100644 mysql-test/main/aria_icp_debug.test create mode 100644 mysql-test/main/innodb_icp_debug.result create mode 100644 mysql-test/main/innodb_icp_debug.test create mode 100644 mysql-test/main/myisam_icp_debug.result create mode 100644 mysql-test/main/myisam_icp_debug.test create mode 100644 mysql-test/main/rowid_filter_myisam_debug.result create mode 100644 mysql-test/main/rowid_filter_myisam_debug.test diff --git a/mysql-test/include/icp_debug_kill.inc b/mysql-test/include/icp_debug_kill.inc new file mode 100644 index 00000000000..d0ecc842869 --- /dev/null +++ b/mysql-test/include/icp_debug_kill.inc @@ -0,0 +1,50 @@ +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/count_sessions.inc + +--disable_warnings +drop table if exists t0,t1,t2; +--enable_warnings + +create table t0(a int primary key); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table t1(a int primary key); +insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C; + +create table t2 ( + kp1 int, + kp2 int, + col char(100), + key(kp1, kp2) +); +insert into t2 select a, a, a from t1; + +select engine from information_schema.tables +where table_schema=database() and table_name='t2'; + +explain +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; + +let $target_id= `select connection_id()`; + +set debug_sync='handler_index_cond_check SIGNAL at_icp_check WAIT_FOR go'; +send +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; + +connect (con1, localhost, root,,); +connection con1; +set debug_sync='now WAIT_FOR at_icp_check'; +evalp kill query $target_id; +set debug_sync='now SIGNAL go'; + +connection default; + +--error ER_QUERY_INTERRUPTED +reap; +set debug_sync='RESET'; + +disconnect con1; +drop table t0,t1,t2; +--source include/wait_until_count_sessions.inc + diff --git a/mysql-test/include/rowid_filter_debug_kill.inc b/mysql-test/include/rowid_filter_debug_kill.inc new file mode 100644 index 00000000000..6a8c5d3f70d --- /dev/null +++ b/mysql-test/include/rowid_filter_debug_kill.inc @@ -0,0 +1,68 @@ +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/count_sessions.inc + +--echo # +--echo # MDEV-22761 KILL QUERY during rowid_filter, crashes +--echo # + +create table t0(a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table t1(a int); +insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C; + +# 100 rows +create table t2(a int); +insert into t2 select A.a + B.a* 10 from t0 A, t0 B; + +# 10K rows +CREATE TABLE t3 ( + key1 int , + key2 int, + filler varchar(255), + KEY (key1), + KEY (key2) +); +select engine from information_schema.tables +where table_schema=database() and table_name='t3'; + +insert into t3 +select + A.a, + A.a, + 'filler-data-filler-data' +from + t0 A, t1 B; + +analyze table t2,t3; + +explain +select * from t2, t3 +where + t3.key1=t2.a and t3.key2 in (2,3); + +let $target_id= `select connection_id()`; + +set debug_sync='handler_rowid_filter_check SIGNAL at_rowid_filter_check WAIT_FOR go'; +send +select * from t2, t3 +where + t3.key1=t2.a and t3.key2 in (2,3); + +connect (con1, localhost, root,,); +connection con1; +set debug_sync='now WAIT_FOR at_rowid_filter_check'; +evalp kill query $target_id; +set debug_sync='now SIGNAL go'; + +connection default; +disconnect con1; + +--error ER_QUERY_INTERRUPTED +reap; +set debug_sync='RESET'; + +drop table t0,t1,t2,t3; +--source include/wait_until_count_sessions.inc + diff --git a/mysql-test/main/aria_icp_debug.result b/mysql-test/main/aria_icp_debug.result new file mode 100644 index 00000000000..fc01ee4fb3b --- /dev/null +++ b/mysql-test/main/aria_icp_debug.result @@ -0,0 +1,34 @@ +set default_storage_engine=aria; +drop table if exists t0,t1,t2; +create table t0(a int primary key); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1(a int primary key); +insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C; +create table t2 ( +kp1 int, +kp2 int, +col char(100), +key(kp1, kp2) +); +insert into t2 select a, a, a from t1; +select engine from information_schema.tables +where table_schema=database() and table_name='t2'; +engine +Aria +explain +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range kp1 kp1 5 NULL 10 Using index condition +set debug_sync='handler_index_cond_check SIGNAL at_icp_check WAIT_FOR go'; +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; +connect con1, localhost, root,,; +connection con1; +set debug_sync='now WAIT_FOR at_icp_check'; +kill query $target_id; +set debug_sync='now SIGNAL go'; +connection default; +ERROR 70100: Query execution was interrupted +set debug_sync='RESET'; +disconnect con1; +drop table t0,t1,t2; +set default_storage_engine=default; diff --git a/mysql-test/main/aria_icp_debug.test b/mysql-test/main/aria_icp_debug.test new file mode 100644 index 00000000000..bbdd59d6012 --- /dev/null +++ b/mysql-test/main/aria_icp_debug.test @@ -0,0 +1,5 @@ + +set default_storage_engine=aria; +--source include/icp_debug_kill.inc +set default_storage_engine=default; + diff --git a/mysql-test/main/innodb_icp_debug.result b/mysql-test/main/innodb_icp_debug.result new file mode 100644 index 00000000000..5a169650c8e --- /dev/null +++ b/mysql-test/main/innodb_icp_debug.result @@ -0,0 +1,34 @@ +set default_storage_engine=innodb; +drop table if exists t0,t1,t2; +create table t0(a int primary key); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1(a int primary key); +insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C; +create table t2 ( +kp1 int, +kp2 int, +col char(100), +key(kp1, kp2) +); +insert into t2 select a, a, a from t1; +select engine from information_schema.tables +where table_schema=database() and table_name='t2'; +engine +InnoDB +explain +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range kp1 kp1 5 NULL 11 Using index condition +set debug_sync='handler_index_cond_check SIGNAL at_icp_check WAIT_FOR go'; +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; +connect con1, localhost, root,,; +connection con1; +set debug_sync='now WAIT_FOR at_icp_check'; +kill query $target_id; +set debug_sync='now SIGNAL go'; +connection default; +ERROR 70100: Query execution was interrupted +set debug_sync='RESET'; +disconnect con1; +drop table t0,t1,t2; +set default_storage_engine=default; diff --git a/mysql-test/main/innodb_icp_debug.test b/mysql-test/main/innodb_icp_debug.test new file mode 100644 index 00000000000..4aa08c61e87 --- /dev/null +++ b/mysql-test/main/innodb_icp_debug.test @@ -0,0 +1,6 @@ +--source include/have_innodb.inc + +set default_storage_engine=innodb; +--source include/icp_debug_kill.inc +set default_storage_engine=default; + diff --git a/mysql-test/main/myisam_icp_debug.result b/mysql-test/main/myisam_icp_debug.result new file mode 100644 index 00000000000..cb45a0e2274 --- /dev/null +++ b/mysql-test/main/myisam_icp_debug.result @@ -0,0 +1,32 @@ +drop table if exists t0,t1,t2; +create table t0(a int primary key); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1(a int primary key); +insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C; +create table t2 ( +kp1 int, +kp2 int, +col char(100), +key(kp1, kp2) +); +insert into t2 select a, a, a from t1; +select engine from information_schema.tables +where table_schema=database() and table_name='t2'; +engine +MyISAM +explain +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range kp1 kp1 5 NULL 11 Using index condition +set debug_sync='handler_index_cond_check SIGNAL at_icp_check WAIT_FOR go'; +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; +connect con1, localhost, root,,; +connection con1; +set debug_sync='now WAIT_FOR at_icp_check'; +kill query $target_id; +set debug_sync='now SIGNAL go'; +connection default; +ERROR 70100: Query execution was interrupted +set debug_sync='RESET'; +disconnect con1; +drop table t0,t1,t2; diff --git a/mysql-test/main/myisam_icp_debug.test b/mysql-test/main/myisam_icp_debug.test new file mode 100644 index 00000000000..d5b1af799fa --- /dev/null +++ b/mysql-test/main/myisam_icp_debug.test @@ -0,0 +1 @@ +--source include/icp_debug_kill.inc diff --git a/mysql-test/main/rowid_filter_innodb_debug.result b/mysql-test/main/rowid_filter_innodb_debug.result index 91fa66937b6..6fd75294bdb 100644 --- a/mysql-test/main/rowid_filter_innodb_debug.result +++ b/mysql-test/main/rowid_filter_innodb_debug.result @@ -1,3 +1,59 @@ +set default_storage_engine=innodb; +# +# MDEV-22761 KILL QUERY during rowid_filter, crashes +# +create table t0(a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1(a int); +insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C; +create table t2(a int); +insert into t2 select A.a + B.a* 10 from t0 A, t0 B; +CREATE TABLE t3 ( +key1 int , +key2 int, +filler varchar(255), +KEY (key1), +KEY (key2) +); +select engine from information_schema.tables +where table_schema=database() and table_name='t3'; +engine +InnoDB +insert into t3 +select +A.a, +A.a, +'filler-data-filler-data' +from +t0 A, t1 B; +analyze table t2,t3; +Table Op Msg_type Msg_text +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status OK +test.t3 analyze status Engine-independent statistics collected +test.t3 analyze status OK +explain +select * from t2, t3 +where +t3.key1=t2.a and t3.key2 in (2,3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 100 Using where +1 SIMPLE t3 ref|filter key1,key2 key1|key2 5|5 test.t2.a 1000 (20%) Using where; Using rowid filter +set debug_sync='handler_rowid_filter_check SIGNAL at_rowid_filter_check WAIT_FOR go'; +select * from t2, t3 +where +t3.key1=t2.a and t3.key2 in (2,3); +connect con1, localhost, root,,; +connection con1; +set debug_sync='now WAIT_FOR at_rowid_filter_check'; +kill query $target_id; +set debug_sync='now SIGNAL go'; +connection default; +disconnect con1; +ERROR 70100: Query execution was interrupted +set debug_sync='RESET'; +drop table t0,t1,t2,t3; +set default_storage_engine=default; set @save_optimizer_switch= @@optimizer_switch; set @save_use_stat_tables= @@use_stat_tables; set @save_optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; @@ -6,10 +62,11 @@ set optimizer_use_condition_selectivity=2; set optimizer_switch='rowid_filter=on'; # # MDEV-22761 KILL QUERY during rowid_filter, crashes +# (The smaller testcase) # CREATE TABLE t1 (a INT, b INT, INDEX(a), INDEX(b)) ENGINE=InnoDB; INSERT INTO t1 VALUES (0,0),(1,0),(-1,1), (-2,1), (-2,3), (-3,4), (-2,4); -set debug_sync='row_search_pre_rowid_filter_check SIGNAL killme WAIT_FOR go'; +set debug_sync='handler_rowid_filter_check SIGNAL killme WAIT_FOR go'; SELECT * FROM t1 WHERE a > 0 AND b=0; connect con1, localhost, root,,; connection con1; @@ -17,7 +74,7 @@ set debug_sync='now WAIT_FOR killme'; kill query @id; set debug_sync='now SIGNAL go'; connection default; -a b +ERROR 70100: Query execution was interrupted set debug_sync='RESET'; disconnect con1; drop table t1; diff --git a/mysql-test/main/rowid_filter_innodb_debug.test b/mysql-test/main/rowid_filter_innodb_debug.test index 3f8eb5b5c38..eb43edd9e9e 100644 --- a/mysql-test/main/rowid_filter_innodb_debug.test +++ b/mysql-test/main/rowid_filter_innodb_debug.test @@ -1,6 +1,9 @@ ---source include/have_debug.inc ---source include/have_debug_sync.inc --source include/have_innodb.inc + +set default_storage_engine=innodb; +--source include/rowid_filter_debug_kill.inc +set default_storage_engine=default; + --source include/default_optimizer_switch.inc --source include/count_sessions.inc @@ -15,6 +18,7 @@ set optimizer_switch='rowid_filter=on'; --echo # --echo # MDEV-22761 KILL QUERY during rowid_filter, crashes +--echo # (The smaller testcase) --echo # CREATE TABLE t1 (a INT, b INT, INDEX(a), INDEX(b)) ENGINE=InnoDB; @@ -22,7 +26,7 @@ INSERT INTO t1 VALUES (0,0),(1,0),(-1,1), (-2,1), (-2,3), (-3,4), (-2,4); let $ID= `SELECT @id := CONNECTION_ID()`; -set debug_sync='row_search_pre_rowid_filter_check SIGNAL killme WAIT_FOR go'; +set debug_sync='handler_rowid_filter_check SIGNAL killme WAIT_FOR go'; send SELECT * FROM t1 WHERE a > 0 AND b=0; connect (con1, localhost, root,,); @@ -33,6 +37,7 @@ kill query @id; set debug_sync='now SIGNAL go'; connection default; +--error ER_QUERY_INTERRUPTED reap; set debug_sync='RESET'; diff --git a/mysql-test/main/rowid_filter_myisam_debug.result b/mysql-test/main/rowid_filter_myisam_debug.result new file mode 100644 index 00000000000..16fcb2a416e --- /dev/null +++ b/mysql-test/main/rowid_filter_myisam_debug.result @@ -0,0 +1,54 @@ +# +# MDEV-22761 KILL QUERY during rowid_filter, crashes +# +create table t0(a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1(a int); +insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C; +create table t2(a int); +insert into t2 select A.a + B.a* 10 from t0 A, t0 B; +CREATE TABLE t3 ( +key1 int , +key2 int, +filler varchar(255), +KEY (key1), +KEY (key2) +); +select engine from information_schema.tables +where table_schema=database() and table_name='t3'; +engine +MyISAM +insert into t3 +select +A.a, +A.a, +'filler-data-filler-data' +from +t0 A, t1 B; +analyze table t2,t3; +Table Op Msg_type Msg_text +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status OK +test.t3 analyze status Engine-independent statistics collected +test.t3 analyze status Table is already up to date +explain +select * from t2, t3 +where +t3.key1=t2.a and t3.key2 in (2,3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 100 Using where +1 SIMPLE t3 ref|filter key1,key2 key1|key2 5|5 test.t2.a 1000 (18%) Using where; Using rowid filter +set debug_sync='handler_rowid_filter_check SIGNAL at_rowid_filter_check WAIT_FOR go'; +select * from t2, t3 +where +t3.key1=t2.a and t3.key2 in (2,3); +connect con1, localhost, root,,; +connection con1; +set debug_sync='now WAIT_FOR at_rowid_filter_check'; +kill query $target_id; +set debug_sync='now SIGNAL go'; +connection default; +disconnect con1; +ERROR 70100: Query execution was interrupted +set debug_sync='RESET'; +drop table t0,t1,t2,t3; diff --git a/mysql-test/main/rowid_filter_myisam_debug.test b/mysql-test/main/rowid_filter_myisam_debug.test new file mode 100644 index 00000000000..ba2f79772a9 --- /dev/null +++ b/mysql-test/main/rowid_filter_myisam_debug.test @@ -0,0 +1,3 @@ + +--source include/rowid_filter_debug_kill.inc + diff --git a/sql/handler.cc b/sql/handler.cc index d7562bcd2ae..6dc17109ffd 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6015,6 +6015,7 @@ extern "C" check_result_t handler_index_cond_check(void* h_arg) THD *thd= h->table->in_use; check_result_t res; + DEBUG_SYNC(thd, "handler_index_cond_check"); enum thd_kill_levels abort_at= h->has_transactions() ? THD_ABORT_SOFTLY : THD_ABORT_ASAP; if (thd_kill_level(thd) > abort_at) @@ -6048,6 +6049,7 @@ check_result_t handler_rowid_filter_check(void *h_arg) if (!h->pushed_idx_cond) { THD *thd= h->table->in_use; + DEBUG_SYNC(thd, "handler_rowid_filter_check"); enum thd_kill_levels abort_at= h->has_transactions() ? THD_ABORT_SOFTLY : THD_ABORT_ASAP; if (thd_kill_level(thd) > abort_at) diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 7f1362cb931..941a4904047 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -3975,8 +3975,6 @@ row_search_idx_cond_check( ut_ad(len == DATA_ROW_ID_LEN); memcpy(prebuilt->row_id, data, DATA_ROW_ID_LEN); } - DEBUG_SYNC_C("row_search_pre_rowid_filter_check"); - result = handler_rowid_filter_check(prebuilt->pk_filter); switch (result) { case CHECK_NEG: @@ -5301,8 +5299,10 @@ locks_ok_del_marked: row_unlock_for_mysql(prebuilt, TRUE); } goto next_rec; - case CHECK_OUT_OF_RANGE: case CHECK_ABORTED_BY_USER: + err = DB_INTERRUPTED; + goto idx_cond_failed; + case CHECK_OUT_OF_RANGE: case CHECK_ERROR: err = DB_RECORD_NOT_FOUND; goto idx_cond_failed; From a6f956488c712bef3b13660584d1b905e0c676cc Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Sat, 10 Oct 2020 08:28:53 +1100 Subject: [PATCH 113/323] MDEV-22761: innodb row_search_idx_cond_check handle CHECK_ABORTED_BY_USER Part #3: Two more cases within row_search_mvcc need to handle the CHECK_ABORTED_BY_USER and process this as a DB_INTERRUPTED. --- storage/innobase/row/row0sel.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 941a4904047..fad388f3dbd 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -4453,9 +4453,12 @@ row_search_mvcc( switch (row_search_idx_cond_check( buf, prebuilt, rec, offsets)) { + case CHECK_ABORTED_BY_USER: + err = DB_INTERRUPTED; + mtr.commit(); + goto func_exit; case CHECK_NEG: case CHECK_OUT_OF_RANGE: - case CHECK_ABORTED_BY_USER: case CHECK_ERROR: goto shortcut_mismatch; case CHECK_POS: @@ -5239,9 +5242,11 @@ no_gap_lock: buf, prebuilt, rec, offsets)) { case CHECK_NEG: goto next_rec; - case CHECK_OUT_OF_RANGE: case CHECK_ABORTED_BY_USER: - case CHECK_ERROR: + err = DB_INTERRUPTED; + goto idx_cond_failed; + case CHECK_OUT_OF_RANGE: + case CHECK_ERROR: err = DB_RECORD_NOT_FOUND; goto idx_cond_failed; case CHECK_POS: From 4a97e25aec94d2e3a9f37ee309bd5ba2d1d15466 Mon Sep 17 00:00:00 2001 From: Alice Sherepa Date: Tue, 29 Sep 2020 15:26:04 +0200 Subject: [PATCH 114/323] minor fixes of rpl_start_stop_slave and rpl_slave_grp_exec tests, expanding rpl_gtid_delete_domain for easier later analysis --- mysql-test/suite/rpl/disabled.def | 1 - mysql-test/suite/rpl/r/rpl_start_stop_slave.result | 2 ++ mysql-test/suite/rpl/t/rpl_gtid_delete_domain.test | 9 +++++++++ mysql-test/suite/rpl/t/rpl_slave_grp_exec.test | 6 ++++-- mysql-test/suite/rpl/t/rpl_start_stop_slave.test | 5 +++-- mysys/my_error.c | 3 +++ 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/rpl/disabled.def b/mysql-test/suite/rpl/disabled.def index 62320ad027c..2bf2a69bd62 100644 --- a/mysql-test/suite/rpl/disabled.def +++ b/mysql-test/suite/rpl/disabled.def @@ -15,4 +15,3 @@ rpl_spec_variables : BUG#11755836 2009-10-27 jasonh rpl_spec_variables fa rpl_partition_archive : MDEV-5077 2013-09-27 svoj Cannot exchange partition with archive table rpl_row_binlog_max_cache_size : MDEV-11092 rpl_row_index_choice : MDEV-11666 -rpl_slave_grp_exec: MDEV-10514 diff --git a/mysql-test/suite/rpl/r/rpl_start_stop_slave.result b/mysql-test/suite/rpl/r/rpl_start_stop_slave.result index c0140962a56..e0272b71192 100644 --- a/mysql-test/suite/rpl/r/rpl_start_stop_slave.result +++ b/mysql-test/suite/rpl/r/rpl_start_stop_slave.result @@ -5,10 +5,12 @@ set @time_before_kill := (select CURRENT_TIMESTAMP); [Time before the query] [Connection ID of the slave I/O thread found] kill ; +include/wait_for_slave_io_to_stop.inc set @time_after_kill := (select CURRENT_TIMESTAMP); [Time after the query] [Killing of the slave IO thread was successful] START SLAVE IO_THREAD; +include/wait_for_slave_io_to_start.inc connection master; create table t1 (a int primary key); connection slave; diff --git a/mysql-test/suite/rpl/t/rpl_gtid_delete_domain.test b/mysql-test/suite/rpl/t/rpl_gtid_delete_domain.test index 622e66c5263..0262998798a 100644 --- a/mysql-test/suite/rpl/t/rpl_gtid_delete_domain.test +++ b/mysql-test/suite/rpl/t/rpl_gtid_delete_domain.test @@ -55,8 +55,17 @@ FLUSH BINARY LOGS; --let $purge_to_binlog= query_get_value(SHOW MASTER STATUS, File, 1) --eval PURGE BINARY LOGS TO '$purge_to_binlog'; # with final removal of the extra domain +###adding to debug info to catch the failure (1076): +--error 0,1076 --eval FLUSH BINARY LOGS DELETE_DOMAIN_ID=($extra_domain_id) + +if ($mysql_errno == 1076) { + --echo ### Failure "Could not delete gtid domain" + --source include/show_rpl_debug_info.inc + } + SELECT @@global.gtid_binlog_pos, @@global.gtid_binlog_state; + --connection slave SELECT @@global.gtid_slave_pos; # start the slave sucessfully diff --git a/mysql-test/suite/rpl/t/rpl_slave_grp_exec.test b/mysql-test/suite/rpl/t/rpl_slave_grp_exec.test index 426c3c831b0..84f4438dd76 100644 --- a/mysql-test/suite/rpl/t/rpl_slave_grp_exec.test +++ b/mysql-test/suite/rpl/t/rpl_slave_grp_exec.test @@ -100,7 +100,9 @@ TRUNCATE t3; ALTER TABLE t1 ADD PRIMARY KEY (a); ALTER TABLE t2 ADD PRIMARY KEY (a); ALTER TABLE t3 ADD PRIMARY KEY (a); ---sync_slave_with_master + +#--sync_slave_with_master +--connection slave RENAME TABLE t3 TO t3_bak; --connection master @@ -145,7 +147,7 @@ ALTER TABLE t1 ENGINE=InnoDB; ALTER TABLE t2 ENGINE=InnoDB; ALTER TABLE t3 ENGINE=InnoDB; ---connection slave +--sync_slave_with_master RENAME TABLE t3 TO t3_bak; --connection master diff --git a/mysql-test/suite/rpl/t/rpl_start_stop_slave.test b/mysql-test/suite/rpl/t/rpl_start_stop_slave.test index a38ac8fc6a1..23b25b1bf85 100644 --- a/mysql-test/suite/rpl/t/rpl_start_stop_slave.test +++ b/mysql-test/suite/rpl/t/rpl_start_stop_slave.test @@ -38,8 +38,8 @@ set @time_before_kill := (select CURRENT_TIMESTAMP); --replace_regex /kill [0-9]*/kill / --eval kill $connection_id -let $wait_condition= SELECT COUNT(*) = 0 FROM information_schema.processlist where id=$connection_id; ---source include/wait_condition.inc +--source include/wait_for_slave_io_to_stop.inc + set @time_after_kill := (select CURRENT_TIMESTAMP); --echo [Time after the query] @@ -52,6 +52,7 @@ if(`select TIMESTAMPDIFF(SECOND,@time_after_kill, @time_before_kill) > 60`) --echo [Killing of the slave IO thread was successful] START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc # Ensure that the slave io thread started properly connection master; diff --git a/mysys/my_error.c b/mysys/my_error.c index 5f1ca0af55b..20836269939 100644 --- a/mysys/my_error.c +++ b/mysys/my_error.c @@ -113,6 +113,9 @@ void my_error(uint nr, myf MyFlags, ...) DBUG_ENTER("my_error"); DBUG_PRINT("my", ("nr: %d MyFlags: %lu errno: %d", nr, MyFlags, errno)); + if (errno == 1213) + DBUG_ASSERT(0); + if (!(format = my_get_err_msg(nr))) (void) my_snprintf(ebuff, sizeof(ebuff), "Unknown error %d", nr); else From e98a5e166c16f24fef2d4f356b0d82559a835ee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 14 Oct 2020 19:01:17 +0300 Subject: [PATCH 115/323] MDEV-23955 main.multi_update_big times out Copying generated data from the sequence engine should be faster than copying from MyISAM to MyISAM. Reviewed by: Sergei Petrunia --- mysql-test/r/multi_update_big.result | 3 +-- mysql-test/r/sum_distinct-big.result | 37 ++++++---------------------- mysql-test/t/multi_update_big.test | 21 +++------------- mysql-test/t/sum_distinct-big.test | 32 ++++++------------------ 4 files changed, 20 insertions(+), 73 deletions(-) diff --git a/mysql-test/r/multi_update_big.result b/mysql-test/r/multi_update_big.result index 3712e638f40..746a158f21f 100644 --- a/mysql-test/r/multi_update_big.result +++ b/mysql-test/r/multi_update_big.result @@ -1,6 +1,5 @@ -DROP TABLE IF EXISTS t1,t2; CREATE TABLE t1 ( a INT NOT NULL, b INT NOT NULL) ; -# The protocolling of many inserts into t1 is suppressed. +INSERT INTO t1 SELECT seq,seq FROM seq_1_to_2097152; ALTER TABLE t1 ADD INDEX i1(a); DELETE FROM t1 WHERE a > 2000000; CREATE TABLE t2 LIKE t1; diff --git a/mysql-test/r/sum_distinct-big.result b/mysql-test/r/sum_distinct-big.result index 13e3e62fed2..08afa1dd1b0 100644 --- a/mysql-test/r/sum_distinct-big.result +++ b/mysql-test/r/sum_distinct-big.result @@ -3,27 +3,7 @@ set @save_max_heap_table_size=@@max_heap_table_size; set storage_engine=MYISAM; CREATE TABLE t1 (id INTEGER); CREATE TABLE t2 (id INTEGER); -INSERT INTO t1 (id) VALUES (1), (1), (1),(1); -INSERT INTO t1 (id) SELECT id FROM t1; -/* 8 */ -INSERT INTO t1 (id) SELECT id FROM t1; -/* 12 */ -INSERT INTO t1 (id) SELECT id FROM t1; -/* 16 */ -INSERT INTO t1 (id) SELECT id FROM t1; -/* 20 */ -INSERT INTO t1 (id) SELECT id FROM t1; -/* 24 */ -INSERT INTO t1 SELECT id+1 FROM t1; -INSERT INTO t1 SELECT id+2 FROM t1; -INSERT INTO t1 SELECT id+4 FROM t1; -INSERT INTO t1 SELECT id+8 FROM t1; -INSERT INTO t1 SELECT id+16 FROM t1; -INSERT INTO t1 SELECT id+32 FROM t1; -INSERT INTO t1 SELECT id+64 FROM t1; -INSERT INTO t1 SELECT id+128 FROM t1; -INSERT INTO t1 SELECT id+256 FROM t1; -INSERT INTO t1 SELECT id+512 FROM t1; +INSERT INTO t1 SELECT b.seq FROM seq_1_to_128,seq_1_to_1024 b; SELECT AVG(DISTINCT id) FROM t1 GROUP BY id % 13; AVG(DISTINCT id) 513.5000 @@ -54,11 +34,9 @@ SUM(DISTINCT id)/COUNT(DISTINCT id) 517.0000 511.5000 512.5000 -INSERT INTO t1 SELECT id+1024 FROM t1; -INSERT INTO t1 SELECT id+2048 FROM t1; -INSERT INTO t1 SELECT id+4096 FROM t1; -INSERT INTO t1 SELECT id+8192 FROM t1; -INSERT INTO t2 SELECT id FROM t1 ORDER BY id*rand(); +INSERT INTO t1 SELECT b.seq FROM seq_1_to_128,seq_1025_to_16384 b; +INSERT INTO t2 SELECT b.seq FROM seq_1_to_128 a,seq_1_to_16384 b +ORDER by (a.seq*0+b.seq)*rand(); SELECT SUM(DISTINCT id) sm FROM t1; sm 134225920 @@ -110,9 +88,10 @@ sm # (bug #56927) # SET max_heap_table_size=default; -INSERT INTO t1 SELECT id+16384 FROM t1; -DELETE FROM t2; -INSERT INTO t2 SELECT id FROM t1 ORDER BY id*rand(); +INSERT INTO t1 SELECT b.seq FROM seq_1_to_128,seq_16385_to_32768 b; +TRUNCATE t2; +INSERT INTO t2 SELECT b.seq FROM seq_1_to_128 a,seq_1_to_32768 b +ORDER BY (a.seq*0+b.seq)*rand(); SELECT SUM(DISTINCT id) sm FROM t2; sm 536887296 diff --git a/mysql-test/t/multi_update_big.test b/mysql-test/t/multi_update_big.test index a0f17fabec4..d6fec704822 100644 --- a/mysql-test/t/multi_update_big.test +++ b/mysql-test/t/multi_update_big.test @@ -1,4 +1,5 @@ --source include/long_test.inc +--source include/have_sequence.inc # # Test of update statement that uses many tables. @@ -40,25 +41,9 @@ if (`SELECT '$BIG_TEST' = '' AND $need_big = 1`) # Bug#1820 Rows not deleted from second table on multi-table delete # ---disable_warnings -DROP TABLE IF EXISTS t1,t2; ---enable_warnings - CREATE TABLE t1 ( a INT NOT NULL, b INT NOT NULL) ; ---echo # The protocolling of many inserts into t1 is suppressed. ---disable_query_log -INSERT INTO t1 VALUES (1,1),(2,2),(3,3),(4,4); -let $1=19; -set @d=4; -begin; -while ($1) -{ - eval INSERT INTO t1 SELECT a+@d,b+@d FROM t1; - eval SET @d=@d*2; - dec $1; -} -commit; ---enable_query_log +INSERT INTO t1 SELECT seq,seq FROM seq_1_to_2097152; + ALTER TABLE t1 ADD INDEX i1(a); DELETE FROM t1 WHERE a > 2000000; CREATE TABLE t2 LIKE t1; diff --git a/mysql-test/t/sum_distinct-big.test b/mysql-test/t/sum_distinct-big.test index bc318bf624d..d87569f8668 100644 --- a/mysql-test/t/sum_distinct-big.test +++ b/mysql-test/t/sum_distinct-big.test @@ -19,32 +19,15 @@ set storage_engine=MYISAM; CREATE TABLE t1 (id INTEGER); CREATE TABLE t2 (id INTEGER); -INSERT INTO t1 (id) VALUES (1), (1), (1),(1); -INSERT INTO t1 (id) SELECT id FROM t1; /* 8 */ -INSERT INTO t1 (id) SELECT id FROM t1; /* 12 */ -INSERT INTO t1 (id) SELECT id FROM t1; /* 16 */ -INSERT INTO t1 (id) SELECT id FROM t1; /* 20 */ -INSERT INTO t1 (id) SELECT id FROM t1; /* 24 */ -INSERT INTO t1 SELECT id+1 FROM t1; -INSERT INTO t1 SELECT id+2 FROM t1; -INSERT INTO t1 SELECT id+4 FROM t1; -INSERT INTO t1 SELECT id+8 FROM t1; -INSERT INTO t1 SELECT id+16 FROM t1; -INSERT INTO t1 SELECT id+32 FROM t1; -INSERT INTO t1 SELECT id+64 FROM t1; -INSERT INTO t1 SELECT id+128 FROM t1; -INSERT INTO t1 SELECT id+256 FROM t1; -INSERT INTO t1 SELECT id+512 FROM t1; +INSERT INTO t1 SELECT b.seq FROM seq_1_to_128,seq_1_to_1024 b; # Just test that AVG(DISTINCT) is there SELECT AVG(DISTINCT id) FROM t1 GROUP BY id % 13; SELECT SUM(DISTINCT id)/COUNT(DISTINCT id) FROM t1 GROUP BY id % 13; -INSERT INTO t1 SELECT id+1024 FROM t1; -INSERT INTO t1 SELECT id+2048 FROM t1; -INSERT INTO t1 SELECT id+4096 FROM t1; -INSERT INTO t1 SELECT id+8192 FROM t1; -INSERT INTO t2 SELECT id FROM t1 ORDER BY id*rand(); +INSERT INTO t1 SELECT b.seq FROM seq_1_to_128,seq_1025_to_16384 b; +INSERT INTO t2 SELECT b.seq FROM seq_1_to_128 a,seq_1_to_16384 b +ORDER by (a.seq*0+b.seq)*rand(); # SELECT '++++++++++++++++++++++++++++++++++++++++++++++++++'; @@ -74,9 +57,10 @@ SELECT SUM(DISTINCT id) sm FROM t1 GROUP BY id % 13; SET max_heap_table_size=default; -INSERT INTO t1 SELECT id+16384 FROM t1; -DELETE FROM t2; -INSERT INTO t2 SELECT id FROM t1 ORDER BY id*rand(); +INSERT INTO t1 SELECT b.seq FROM seq_1_to_128,seq_16385_to_32768 b; +TRUNCATE t2; +INSERT INTO t2 SELECT b.seq FROM seq_1_to_128 a,seq_1_to_32768 b +ORDER BY (a.seq*0+b.seq)*rand(); SELECT SUM(DISTINCT id) sm FROM t2; From 4383c705ab2e87acad0a9c16e4a7b39f4e60e39d Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Wed, 14 Oct 2020 21:30:15 +0300 Subject: [PATCH 116/323] MDEV-23960 UBSAN ../storage/innobase/buf/buf0buddy.cc:350:6: runtime error: index 4096 out of bounds for type 'byte [38]' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed by: Marko Mäkelä --- storage/innobase/buf/buf0buddy.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/buf/buf0buddy.cc b/storage/innobase/buf/buf0buddy.cc index a36fc30db9b..80d82b9e78c 100644 --- a/storage/innobase/buf/buf0buddy.cc +++ b/storage/innobase/buf/buf0buddy.cc @@ -346,7 +346,7 @@ buf_buddy_alloc_zip( if (buf) { buf_buddy_free_t* buddy = reinterpret_cast( - buf->stamp.bytes + reinterpret_cast(buf) + (BUF_BUDDY_LOW << i)); ut_ad(!buf_pool_contains_zip(buf_pool, buddy)); From cea6a6669e3b93b34b92dba96dd339f18b505d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Kek=C3=A4l=C3=A4inen?= Date: Wed, 15 Apr 2020 13:54:49 +0300 Subject: [PATCH 117/323] Travis-CI: Use new Ubuntu 20.04 as base, streamline and document Simplify Travis-CI file and extend inline comments. Upgrade to using Ubuntu 20.04 (Focal) as the baseline distro version now that Travis-CI has made it available. Drop Xenial and all the excess repositories Xenial needed. Now we only Focal and one Bionic build to keep things simple and streamlined. Keep GCC-7/Clang-7 as the older compiler, and start using GCC-10 and Clang-10 as the newer compiler. Assume that if both of them build OK, than the intermediate versions would be OK as well. Print 'apt-cache policy' to make it transparent in build logs what repositories was used for build dependencies. Remove temporary workaround from homebrew install step as Travis-CI has fixed the original issue. Revert ignoring results form build that previously failed on the test main.thread_pool_info as MDEV-20372 is not fixed. Keep arm64 failures ignored due to MDEV-23955. Allow failures for the test main.column_compression 'innodb' due to MDEV-23954. --- .travis.yml | 66 ++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/.travis.yml b/.travis.yml index 46588177faf..7395b48c350 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,12 @@ # vim ft=yaml # travis-ci.org definition -dist: bionic +# NOTE TO MERGERS: Most of the contents in the Travis-CI configuration has been +# tailored for a specific release or MariaDB. As a general rule, do not merge +# changes in this file across MariaDB branches to avoid breaking the CI. Updates +# the the Travis-CI pipeline are most of the time better done manually. + +dist: focal git: depth: 2 @@ -15,27 +20,25 @@ cache: addons: apt: - # NOTE: Travis-CI Ubuntu Xenial builders have GCC 5 and Clang 7 available by default - # NOTE: Travis-CI Ubuntu Ubuntu builders have GCC 7 and Clang 7 available by default sources: &add-sources - - ubuntu-toolchain-r-test # Includes e.g. gcc4-9 for xenial, gcc9 for bionic - # https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test/+packages?field.name_filter=&field.status_filter=published&field.series_filter=xenial - - llvm-toolchain-xenial-7 # NOTE: This repo has no clang-7 for s390x + # Remember to document well what packages each extra repository is used for + - ubuntu-toolchain-r-test + # => gcc-9 and gcc-10 for Ubuntu Bionic + # https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test/+packages?field.name_filter=&field.status_filter=published&field.series_filter=bionic - sourceline: 'ppa:maria-captains/travis-ci-helper-repo' - # https://launchpad.net/~maria-captains/+archive/ubuntu/travis-ci-helper-repo/+packages + # => galera-4 for Ubuntu Bionic + # https://launchpad.net/~maria-captains/+archive/ubuntu/travis-ci-helper-repo/+packages?field.name_filter=&field.status_filter=published&field.series_filter=bionic packages: &common-packages - # make sure these include all compilers and all build dependencies (see list above) + # Remember to update this list if the Debian build dependencies are updated - bison - chrpath - - clang-7 # bionic-updates, llvm-toolchain-xenial-6.0 (amd64 only, not s390x) - - clang-8 # xenial, bionic + - clang-7 # In suites: focal, bionic-updates + - clang-10 # In suites: focal, bionic - cmake - cracklib-runtime - - galera-4 - - g++-5 # xenial, bionic, ubuntu-toolchain-r/test (xenial) - - g++-7 # bionic, ubuntu-toolchain-r/test (xenial) - - g++-8 # bionic, ubuntu-toolchain-r/test (xenial) - - g++-9 # ubuntu-toolchain-r/test (xenial and bionic) + - galera-4 # In suites: focal, bionic (via ppa:maria-captains/travis-ci-helper-repo) + - g++-7 # In suites: focal, bionic + - g++-10 # In suites: focal, bionic (via ppa:ubuntu-toolchain-r/test) - gdb - libaio-dev - libboost-atomic-dev @@ -69,9 +72,6 @@ addons: - zlib1g-dev # libsystemd-daemon-dev # https://github.com/travis-ci/apt-package-whitelist/issues/3882 homebrew: - # Temporary workaround, remove when this is solved: - # https://travis-ci.community/t/macos-build-fails-because-of-homebrew-bundle-unknown-command/7296/20 - update: true # OSX builds are not properly maintained on Travis-CI nor buildbot and # thus this list of dependencies is likely to be inaccurate. packages: @@ -104,9 +104,9 @@ addons: # and 'env'. Ensure there is a good variation of architectures and at least the # main suite is run on all architectures, as the main test suite needs to pass # on all architectures (amd64, arm64, ppc64le, s390x) before a release is made. -# All test suites should also run on the clang build at least on one -# arch/platform. In gcc and clang versions prefer 7, which is very widely used, -# and after that prioritize newer versions (8, 9 etc) above older versions (5, 6). +# +# In gcc and clang use a fairly old version and one very recent and assume that +# if both of them built successfully all the intermediate version work as well. arch: amd64 os: linux compiler: @@ -116,15 +116,14 @@ env: - CC_VERSION=7 TYPE=RelWithDebInfo MYSQL_TEST_SUITES=archive,optimizer_unfixed_bugs,parts,sys_vars,unit,vcol,innodb,innodb_gis,innodb_zip,innodb_fts - CC_VERSION=7 TYPE=RelWithDebInfo MYSQL_TEST_SUITES=binlog,binlog_encryption,encryption,rocksdb,versioning,rpl - CC_VERSION=7 TYPE=RelWithDebInfo MYSQL_TEST_SUITES=csv,federated,funcs_1,funcs_2,gcol,handler,heap,json,maria,perfschema,plugins,multi_source,roles - - CC_VERSION=8 TYPE=RelWithDebInfo MYSQL_TEST_SUITES=main + - CC_VERSION=10 TYPE=RelWithDebInfo MYSQL_TEST_SUITES=main jobs: # Define extra jobs that are run in addition to the main jobs matrix include: - os: linux - dist: xenial compiler: gcc - env: DebPackages=xenial + env: DebPackages=focal addons: &deb-addons apt: sources: *add-sources @@ -144,8 +143,10 @@ jobs: - unixodbc-dev script: &deb-script - ${CC} --version ; ${CXX} --version + - apt-cache policy - env DEB_BUILD_OPTIONS="parallel=4" debian/autobake-deb.sh; - os: linux + dist: bionic arch: s390x compiler: gcc env: DebPackages=bionic @@ -155,12 +156,12 @@ jobs: - os: osx osx_image: xcode12u compiler: clang - env: CC_VERSION=8 TYPE=RelWithDebInfo MYSQL_TEST_SUITES=main + env: CC_VERSION=10 TYPE=RelWithDebInfo MYSQL_TEST_SUITES=main # Some chosen ones with s390x and gcc - os: linux arch: s390x compiler: gcc - env: CC_VERSION=8 TYPE=RelWithDebInfo MYSQL_TEST_SUITES=main + env: CC_VERSION=10 TYPE=RelWithDebInfo MYSQL_TEST_SUITES=main - os: linux arch: s390x compiler: gcc @@ -173,7 +174,7 @@ jobs: - os: linux arch: s390x compiler: clang - env: CC_VERSION=8 TYPE=RelWithDebInfo MYSQL_TEST_SUITES=csv,federated,funcs_1,funcs_2,gcol,handler,heap,json,maria,perfschema,plugins,multi_source,roles + env: CC_VERSION=10 TYPE=RelWithDebInfo MYSQL_TEST_SUITES=csv,federated,funcs_1,funcs_2,gcol,handler,heap,json,maria,perfschema,plugins,multi_source,roles # Extra tests to ensure IBM Power and ARM 64 work - os: linux arch: ppc64le @@ -185,13 +186,12 @@ jobs: env: CC_VERSION=7 TYPE=RelWithDebInfo MYSQL_TEST_SUITES=main allow_failures: - # Permanently fails on main.thread_pool_info test (MDEV-20372) + # Permanently fails on main.column_compression 'innodb' test (MDEV-23954) - os: linux - arch: amd64 - compiler: clang - env: CC_VERSION=8 TYPE=RelWithDebInfo MYSQL_TEST_SUITES=main - # Sporadically fails on main.thread_pool_info test (MDEV-20372) - - arch: ppc64le + arch: s390x + compiler: gcc + env: CC_VERSION=10 TYPE=RelWithDebInfo MYSQL_TEST_SUITES=main + # Sporadically fails on main.multi_update_big test (MDEV-23955) - arch: arm64 # Until OSX becomes a bit more stable - os: osx From 308f8350c7baa189cff74c845875117c2fe9c044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 15 Oct 2020 09:40:19 +0300 Subject: [PATCH 118/323] MDEV-23190 after-merge fix: remove unused code The merge commit 4d4865de6f124ed0a97573bf784102077f7296e7 introduced fil_space_t::max_page_number_of_io() with no callers. --- storage/innobase/include/fil0fil.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 96cf0a45b65..1b89d38bef7 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -415,15 +415,6 @@ public: ulint magic_n;/*!< FIL_SPACE_MAGIC_N */ - /** Clamp a page number for batched I/O, such as read-ahead. - @param offset page number limit - @return offset clamped to the tablespace size */ - ulint max_page_number_for_io(ulint offset) const - { - const ulint limit= committed_size; - return limit > offset ? offset : limit; - } - /** @return whether doublewrite buffering is needed */ bool use_doublewrite() const { From fa70c1462aabd3c3a052f6383fb8cef6120a34f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 15 Oct 2020 09:49:20 +0300 Subject: [PATCH 119/323] MDEV-23399 preparation: Remove buf_pool.zip_clean The debug data structure may have been useful during the development of ROW_FORMAT=COMPRESSED page frames. Let us simplify code by removing it. --- storage/innobase/buf/buf0buf.cc | 119 +++++------------------------ storage/innobase/buf/buf0flu.cc | 6 -- storage/innobase/buf/buf0lru.cc | 44 +---------- storage/innobase/buf/buf0rea.cc | 3 - storage/innobase/include/buf0buf.h | 25 ++---- storage/innobase/include/buf0lru.h | 9 --- 6 files changed, 23 insertions(+), 183 deletions(-) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index ec4b7395ca5..8c5eba321a4 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -212,12 +212,12 @@ but not written to disk yet. The block with the oldest modification which has not yet been written to disk is at the end of the chain. The access to this list is protected by buf_pool.flush_list_mutex. -The chain of unmodified compressed blocks (buf_pool.zip_clean) -contains the control blocks (buf_page_t) of those compressed pages +The control blocks for uncompressed pages are accessible via +buf_block_t objects that are reachable via buf_pool.chunks[]. +The control blocks (buf_page_t) of those ROW_FORMAT=COMPRESSED pages that are not in buf_pool.flush_list and for which no uncompressed -page has been allocated in the buffer pool. The control blocks for -uncompressed pages are accessible via buf_block_t objects that are -reachable via buf_pool.chunks[]. +page has been allocated in buf_pool are only accessible via +buf_pool.LRU. The chains of free memory blocks (buf_pool.zip_free[]) are used by the buddy allocator (buf0buddy.cc) to keep track of currently unused @@ -1554,8 +1554,6 @@ bool buf_pool_t::create() UT_LIST_INIT(flush_list, &buf_page_t::list); UT_LIST_INIT(unzip_LRU, &buf_block_t::unzip_LRU); - ut_d(UT_LIST_INIT(zip_clean, &buf_page_t::list)); - for (size_t i= 0; i < UT_ARR_SIZE(zip_free); ++i) UT_LIST_INIT(zip_free[i], &buf_buddy_free_t::list); ulint s= curr_size; @@ -3364,10 +3362,7 @@ evict_from_pool: /* Set after buf_relocate(). */ block->page.set_buf_fix_count(1); - if (!block->page.oldest_modification()) { - ut_d(UT_LIST_REMOVE(buf_pool.zip_clean, &block->page)); - } else { - /* Relocate buf_pool.flush_list. */ + if (block->page.oldest_modification()) { buf_flush_relocate_on_flush_list(bpage, &block->page); } @@ -3870,10 +3865,6 @@ loop: if (block->page.oldest_modification() > 0) buf_flush_relocate_on_flush_list(&block->page, &free_block->page); -#ifdef UNIV_DEBUG - else - UT_LIST_REMOVE(buf_pool.zip_clean, &block->page); -#endif free_block->page.set_state(BUF_BLOCK_FILE_PAGE); buf_unzip_LRU_add_block(free_block, FALSE); @@ -4474,8 +4465,8 @@ void buf_pool_t::validate() for (j = chunk->size; j--; block++) { switch (block->page.state()) { case BUF_BLOCK_ZIP_PAGE: - /* These should only occur on - zip_clean, zip_free[], or flush_list. */ + /* This kind of block descriptors should + be allocated by malloc() only. */ ut_error; break; @@ -4499,34 +4490,6 @@ void buf_pool_t::validate() } } - /* Check clean compressed-only blocks. */ - - for (buf_page_t* b = UT_LIST_GET_FIRST(zip_clean); b; - b = UT_LIST_GET_NEXT(list, b)) { - ut_ad(b->state() == BUF_BLOCK_ZIP_PAGE); - ut_ad(!b->oldest_modification()); - switch (b->io_fix()) { - case BUF_IO_NONE: - case BUF_IO_PIN: - /* All clean blocks should be I/O-unfixed. */ - break; - case BUF_IO_READ: - /* In buf_LRU_free_page(), we temporarily set - b->io_fix = BUF_IO_READ for a newly allocated - control block in order to prevent - buf_page_get_gen() from decompressing the block. */ - break; - default: - ut_error; - break; - } - - const page_id_t id = b->id(); - ut_ad(page_hash_get_low(id, id.fold()) == b); - n_lru++; - n_zip++; - } - /* Check dirty blocks. */ mutex_enter(&flush_list_mutex); @@ -4565,7 +4528,7 @@ void buf_pool_t::validate() << " zip " << n_zip << ". Aborting..."; } - ut_ad(UT_LIST_GET_LEN(LRU) == n_lru); + ut_ad(UT_LIST_GET_LEN(LRU) >= n_lru); if (curr_size == old_size && UT_LIST_GET_LEN(free) != n_free) { @@ -4692,66 +4655,18 @@ void buf_pool_t::print() /** @return the number of latched pages in the buffer pool */ ulint buf_get_latched_pages_number() { - buf_page_t* b; - ulint i; - ulint fixed_pages_number = 0; + ulint fixed_pages_number= 0; - mutex_enter(&buf_pool.mutex); + mutex_enter(&buf_pool.mutex); - auto chunk = buf_pool.chunks; + for (buf_page_t *b= UT_LIST_GET_FIRST(buf_pool.LRU); b; + b= UT_LIST_GET_NEXT(LRU, b)) + if (b->in_file() && (b->buf_fix_count() || b->io_fix() != BUF_IO_NONE)) + fixed_pages_number++; - for (i = buf_pool.n_chunks; i--; chunk++) { - buf_block_t* block= chunk->blocks; + mutex_exit(&buf_pool.mutex); - for (auto j= chunk->size; j--; block++) { - if (block->page.state() == BUF_BLOCK_FILE_PAGE - && (block->page.buf_fix_count() - || block->page.io_fix() != BUF_IO_NONE)) { - - fixed_pages_number++; - } - } - } - - /* Traverse the lists of clean and dirty compressed-only blocks. */ - - for (b = UT_LIST_GET_FIRST(buf_pool.zip_clean); b; - b = UT_LIST_GET_NEXT(list, b)) { - ut_a(b->state() == BUF_BLOCK_ZIP_PAGE); - ut_a(!b->oldest_modification()); - ut_a(b->io_fix() != BUF_IO_WRITE); - - if (b->buf_fix_count() || b->io_fix() != BUF_IO_NONE) { - fixed_pages_number++; - } - } - - mutex_enter(&buf_pool.flush_list_mutex); - for (b = UT_LIST_GET_FIRST(buf_pool.flush_list); b; - b = UT_LIST_GET_NEXT(list, b)) { - ut_ad(b->oldest_modification()); - - switch (b->state()) { - case BUF_BLOCK_ZIP_PAGE: - if (b->buf_fix_count() || b->io_fix() != BUF_IO_NONE) { - fixed_pages_number++; - } - continue; - case BUF_BLOCK_FILE_PAGE: - /* uncompressed page */ - continue; - case BUF_BLOCK_NOT_USED: - case BUF_BLOCK_MEMORY: - case BUF_BLOCK_REMOVE_HASH: - break; - } - ut_error; - } - - mutex_exit(&buf_pool.flush_list_mutex); - mutex_exit(&buf_pool.mutex); - - return(fixed_pages_number); + return fixed_pages_number; } #endif /* UNIV_DEBUG */ diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 52edcbd01c0..e5e35892ab4 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -440,12 +440,6 @@ void buf_flush_remove(buf_page_t* bpage) because we assert on it in buf_flush_block_cmp(). */ bpage->clear_oldest_modification(); -#ifdef UNIV_DEBUG - if (bpage->state() == BUF_BLOCK_ZIP_PAGE) { - buf_LRU_insert_zip_clean(bpage); - } -#endif /* UNIV_DEBUG */ - buf_pool.stat.flush_list_bytes -= bpage->physical_size(); #ifdef UNIV_DEBUG diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc index 4ee84b0ac18..521be10ba21 100644 --- a/storage/innobase/buf/buf0lru.cc +++ b/storage/innobase/buf/buf0lru.cc @@ -455,40 +455,6 @@ void buf_LRU_flush_or_remove_pages(ulint id, bool flush, ulint first) } } -#ifdef UNIV_DEBUG -/********************************************************************//** -Insert a compressed block into buf_pool.zip_clean in the LRU order. */ -void -buf_LRU_insert_zip_clean( -/*=====================*/ - buf_page_t* bpage) /*!< in: pointer to the block in question */ -{ - ut_ad(mutex_own(&buf_pool.mutex)); - ut_ad(bpage->state() == BUF_BLOCK_ZIP_PAGE); - ut_ad(!bpage->oldest_modification()); - - /* Find the first successor of bpage in the LRU list - that is in the zip_clean list. */ - buf_page_t* b = bpage; - - do { - b = UT_LIST_GET_NEXT(LRU, b); - } while (b && (b->state() != BUF_BLOCK_ZIP_PAGE - || b->oldest_modification())); - - /* Insert bpage before b, i.e., after the predecessor of b. */ - if (b != NULL) { - b = UT_LIST_GET_PREV(list, b); - } - - if (b != NULL) { - UT_LIST_INSERT_AFTER(buf_pool.zip_clean, b, bpage); - } else { - UT_LIST_ADD_FIRST(buf_pool.zip_clean, bpage); - } -} -#endif /* UNIV_DEBUG */ - /** Try to free an uncompressed page of a compressed block from the unzip LRU list. The compressed page is preserved, and it need not be clean. @param[in] scan_all true=scan the whole list; @@ -1272,12 +1238,7 @@ func_exit: buf_LRU_add_block(b, b->old); } - if (!b->oldest_modification()) { -#ifdef UNIV_DEBUG - buf_LRU_insert_zip_clean(b); -#endif /* UNIV_DEBUG */ - } else { - /* Relocate on buf_pool.flush_list. */ + if (b->oldest_modification()) { buf_flush_relocate_on_flush_list(bpage, b); } @@ -1480,9 +1441,6 @@ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id, ut_a(bpage->zip.ssize); ut_ad(!bpage->oldest_modification()); -#ifdef UNIV_DEBUG - UT_LIST_REMOVE(buf_pool.zip_clean, bpage); -#endif /* UNIV_DEBUG */ hash_lock->write_unlock(); buf_pool_mutex_exit_forbid(); diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index ed36873837e..911fce4cc43 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -237,9 +237,6 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id, /* The block must be put to the LRU list, to the old blocks. The zip size is already set into the page zip */ buf_LRU_add_block(bpage, true/* to old blocks */); -#ifdef UNIV_DEBUG - buf_LRU_insert_zip_clean(bpage); -#endif /* UNIV_DEBUG */ } mutex_exit(&buf_pool.mutex); diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 04d74b6e36f..3eb1773a5b6 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -818,15 +818,11 @@ public: state() == BUF_BLOCK_NOT_USED: buf_pool.free or buf_pool.withdraw - state() == BUF_BLOCK_FILE_PAGE || - (state() == BUF_BLOCK_ZIP_PAGE && !oldest_modification()): + in_file() && oldest_modification(): buf_pool.flush_list (protected by buf_pool.flush_list_mutex) - state() == BUF_BLOCK_ZIP_PAGE && !oldest_modification(): buf_pool.zip_clean - - The contents is undefined if - !oldest_modification() && state() == BUF_BLOCK_FILE_PAGE, - or if state() is not any of the above. */ + The contents is undefined if in_file() && !oldest_modification(), + or if state() is BUF_BLOCK_MEMORY or BUF_BLOCK_REMOVE_HASH. */ UT_LIST_NODE_T(buf_page_t) list; private: @@ -2024,22 +2020,11 @@ public: unzip_LRU list */ /* @} */ - /** @name Buddy allocator fields - The buddy allocator is used for allocating compressed page - frames and buf_page_t descriptors of blocks that exist - in the buffer pool only in compressed form. */ - /* @{ */ -#ifdef UNIV_DEBUG - /** unmodified ROW_FORMAT=COMPRESSED pages; - protected by buf_pool.mutex */ - UT_LIST_BASE_NODE_T(buf_page_t) zip_clean; -#endif /* UNIV_DEBUG */ - UT_LIST_BASE_NODE_T(buf_buddy_free_t) zip_free[BUF_BUDDY_SIZES_MAX]; - /*!< buddy free lists */ + /** free ROW_FORMAT=COMPRESSED page frames */ + UT_LIST_BASE_NODE_T(buf_buddy_free_t) zip_free[BUF_BUDDY_SIZES_MAX]; #if BUF_BUDDY_LOW > UNIV_ZIP_SIZE_MIN # error "BUF_BUDDY_LOW > UNIV_ZIP_SIZE_MIN" #endif - /* @} */ /** Sentinels to detect if pages are read into the buffer pool while a delete-buffering operation is pending. Protected by mutex. */ diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h index 937cb427a47..bdf56656692 100644 --- a/storage/innobase/include/buf0lru.h +++ b/storage/innobase/include/buf0lru.h @@ -47,15 +47,6 @@ These are low-level functions @param[in] first first page to be flushed or evicted */ void buf_LRU_flush_or_remove_pages(ulint id, bool flush, ulint first = 0); -#ifdef UNIV_DEBUG -/********************************************************************//** -Insert a compressed block into buf_pool.zip_clean in the LRU order. */ -void -buf_LRU_insert_zip_clean( -/*=====================*/ - buf_page_t* bpage); /*!< in: pointer to the block in question */ -#endif /* UNIV_DEBUG */ - /** Try to free a block. If bpage is a descriptor of a compressed-only ROW_FORMAT=COMPRESSED page, the buf_page_t object will be freed as well. The caller must hold buf_pool.mutex. From b535a7904425d730c4dff185f0f313ed99dfbb50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 15 Oct 2020 10:26:52 +0300 Subject: [PATCH 120/323] MDEV-23399: Remove recv_writer_thread Recovery works just fine without a separate thread whose only task is to tell the page cleaner thread to do its job. recv_sys_t::apply(): Flush the buffer pool at the end of each batch. Reviewed by: Vladislav Vaintroub --- storage/innobase/buf/buf0flu.cc | 33 ----- storage/innobase/handler/ha_innodb.cc | 2 - storage/innobase/include/log0recv.h | 13 -- storage/innobase/include/srv0srv.h | 1 - storage/innobase/include/sync0sync.h | 1 - storage/innobase/include/sync0types.h | 6 - storage/innobase/log/log0log.cc | 8 -- storage/innobase/log/log0recv.cc | 170 ++++---------------------- storage/innobase/srv/srv0start.cc | 19 --- storage/innobase/sync/sync0debug.cc | 4 - storage/innobase/sync/sync0sync.cc | 1 - 11 files changed, 23 insertions(+), 235 deletions(-) diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index e5e35892ab4..d0fbd59f968 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -2535,41 +2535,8 @@ static os_thread_ret_t DECLARE_THREAD(buf_flush_page_cleaner)(void*) " page cleaner thread priority can be changed." " See the man page of setpriority()."; } - /* Signal that setpriority() has been attempted. */ - os_event_set(recv_sys.flush_end); #endif /* UNIV_LINUX */ - do { - /* treat flushing requests during recovery. */ - ulint n_flushed_lru = 0; - ulint n_flushed_list = 0; - - os_event_wait(recv_sys.flush_start); - - if (!recv_writer_thread_active) { - break; - } - - if (recv_sys.flush_lru) { - /* Flush pages from end of LRU if required */ - pc_request(0, LSN_MAX); - while (pc_flush_slot() > 0) {} - pc_wait_finished(&n_flushed_lru, &n_flushed_list); - } else { - /* Flush all pages */ - do { - pc_request(ULINT_MAX, LSN_MAX); - while (pc_flush_slot() > 0) {} - } while (!pc_wait_finished(&n_flushed_lru, - &n_flushed_list)); - } - - os_event_reset(recv_sys.flush_start); - os_event_set(recv_sys.flush_end); - } while (recv_writer_thread_active); - - os_event_wait(buf_flush_event); - ulint ret_sleep = 0; ulint n_evicted = 0; ulint n_flushed_last = 0; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index f2729905bce..ec2764f44a9 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -525,7 +525,6 @@ static PSI_mutex_info all_innodb_mutexes[] = { PSI_KEY(page_zip_stat_per_index_mutex), PSI_KEY(purge_sys_pq_mutex), PSI_KEY(recv_sys_mutex), - PSI_KEY(recv_writer_mutex), PSI_KEY(redo_rseg_mutex), PSI_KEY(noredo_rseg_mutex), # ifdef UNIV_DEBUG @@ -579,7 +578,6 @@ performance schema instrumented if "UNIV_PFS_THREAD" is defined */ static PSI_thread_info all_innodb_threads[] = { PSI_KEY(page_cleaner_thread), - PSI_KEY(recv_writer_thread), PSI_KEY(trx_rollback_clean_thread), PSI_KEY(thread_pool_thread) }; diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h index b8d7e40246c..e7cf100cbde 100644 --- a/storage/innobase/include/log0recv.h +++ b/storage/innobase/include/log0recv.h @@ -33,9 +33,6 @@ Created 9/20/1997 Heikki Tuuri #include -/** Is recv_writer_thread active? */ -extern bool recv_writer_thread_active; - /** @return whether recovery is currently running. */ #define recv_recovery_is_on() UNIV_UNLIKELY(recv_sys.recovery_on) @@ -226,16 +223,6 @@ struct recv_sys_t /** whether recv_recover_page(), invoked from buf_page_read_complete(), should apply log records*/ bool apply_log_recs; - - ib_mutex_t writer_mutex;/*!< mutex coordinating - flushing between recv_writer_thread and - the recovery thread. */ - os_event_t flush_start;/*!< event to activate - page cleaner threads */ - os_event_t flush_end;/*!< event to signal that the page - cleaner has finished the request */ - /** whether to flush from buf_pool.LRU instead of buf_pool.flush_list */ - bool flush_lru; /** whether recv_apply_hashed_log_recs() is running */ bool apply_batch_on; byte* buf; /*!< buffer for parsing log records */ diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index a6223946779..ade0f1c198e 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -519,7 +519,6 @@ extern ulong srv_buf_dump_status_frequency; # ifdef UNIV_PFS_THREAD extern mysql_pfs_key_t page_cleaner_thread_key; -extern mysql_pfs_key_t recv_writer_thread_key; extern mysql_pfs_key_t trx_rollback_clean_thread_key; extern mysql_pfs_key_t thread_pool_thread_key; diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index 10267f1be18..1b8b60e9f81 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -66,7 +66,6 @@ extern mysql_pfs_key_t recalc_pool_mutex_key; extern mysql_pfs_key_t page_cleaner_mutex_key; extern mysql_pfs_key_t purge_sys_pq_mutex_key; extern mysql_pfs_key_t recv_sys_mutex_key; -extern mysql_pfs_key_t recv_writer_mutex_key; extern mysql_pfs_key_t rtr_active_mutex_key; extern mysql_pfs_key_t rtr_match_mutex_key; extern mysql_pfs_key_t rtr_path_mutex_key; diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h index 9ea104642a1..36c1ad4495a 100644 --- a/storage/innobase/include/sync0types.h +++ b/storage/innobase/include/sync0types.h @@ -254,8 +254,6 @@ enum latch_level_t { SYNC_TRX_I_S_RWLOCK, - SYNC_RECV_WRITER, - /** Level is varying. Only used with buffer pool page locks, which do not have a fixed level, but instead have their level set after the page is locked; see e.g. ibuf_bitmap_get_map_page(). */ @@ -291,7 +289,6 @@ enum latch_id_t { LATCH_ID_PURGE_SYS_PQ, LATCH_ID_RECALC_POOL, LATCH_ID_RECV_SYS, - LATCH_ID_RECV_WRITER, LATCH_ID_REDO_RSEG, LATCH_ID_NOREDO_RSEG, LATCH_ID_RW_LOCK_DEBUG, @@ -985,9 +982,6 @@ struct sync_checker : public sync_check_functor_t { if (some_allowed) { switch (level) { - case SYNC_RECV_WRITER: - /* This only happens in - recv_apply_hashed_log_recs. */ case SYNC_DICT: case SYNC_DICT_OPERATION: case SYNC_FTS_CACHE: diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 3e2a64a3902..090acc86843 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -1555,14 +1555,6 @@ loop: ut_ad(log_sys.is_initialised() || !srv_was_started); ut_ad(fil_system.is_initialised() || !srv_was_started); - if (!srv_read_only_mode) { - if (recv_sys.flush_start) { - /* This is in case recv_writer_thread was never - started, or buf_flush_page_cleaner - failed to notice its termination. */ - os_event_set(recv_sys.flush_start); - } - } #define COUNT_INTERVAL 600U #define CHECK_INTERVAL 100000U os_thread_sleep(CHECK_INTERVAL); diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index befab264454..6f3f0ffd68a 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -90,13 +90,6 @@ is bigger than the lsn we are able to scan up to, that is an indication that the recovery failed and the database may be corrupt. */ static lsn_t recv_max_page_lsn; -#ifdef UNIV_PFS_THREAD -mysql_pfs_key_t recv_writer_thread_key; -#endif /* UNIV_PFS_THREAD */ - -/** Is recv_writer_thread active? */ -bool recv_writer_thread_active; - /** Stored physical log record with logical LSN (@see log_t::FORMAT_10_5) */ struct log_phys_t : public log_rec_t { @@ -915,7 +908,6 @@ same_space: void recv_sys_t::close() { ut_ad(this == &recv_sys); - ut_ad(!recv_writer_thread_active); if (is_initialised()) { @@ -924,9 +916,6 @@ void recv_sys_t::close() clear(); ut_d(mutex_exit(&mutex)); - os_event_destroy(flush_start); - os_event_destroy(flush_end); - if (buf) { ut_free_dodump(buf, RECV_PARSING_BUF_SIZE); @@ -934,7 +923,6 @@ void recv_sys_t::close() } last_stored_lsn= 0; - mutex_free(&writer_mutex); mutex_free(&mutex); } @@ -944,80 +932,13 @@ void recv_sys_t::close() close_files(); } -/******************************************************************//** -recv_writer thread tasked with flushing dirty pages from the buffer -pools. -@return a dummy parameter */ -extern "C" -os_thread_ret_t -DECLARE_THREAD(recv_writer_thread)( -/*===============================*/ - void* arg MY_ATTRIBUTE((unused))) - /*!< in: a dummy parameter required by - os_thread_create */ -{ - my_thread_init(); - ut_ad(!srv_read_only_mode); - -#ifdef UNIV_PFS_THREAD - pfs_register_thread(recv_writer_thread_key); -#endif /* UNIV_PFS_THREAD */ - -#ifdef UNIV_DEBUG_THREAD_CREATION - ib::info() << "recv_writer thread running, id " - << os_thread_pf(os_thread_get_curr_id()); -#endif /* UNIV_DEBUG_THREAD_CREATION */ - - while (srv_shutdown_state == SRV_SHUTDOWN_NONE) { - - /* Wait till we get a signal to clean the LRU list. - Bounded by max wait time of 100ms. */ - int64_t sig_count = os_event_reset(buf_flush_event); - os_event_wait_time_low(buf_flush_event, 100000, sig_count); - - mutex_enter(&recv_sys.writer_mutex); - - if (!recv_recovery_is_on()) { - mutex_exit(&recv_sys.writer_mutex); - break; - } - - /* Flush pages from end of LRU if required */ - os_event_reset(recv_sys.flush_end); - recv_sys.flush_lru = true; - os_event_set(recv_sys.flush_start); - os_event_wait(recv_sys.flush_end); - - mutex_exit(&recv_sys.writer_mutex); - } - - recv_writer_thread_active = false; - - my_thread_end(); - /* We count the number of threads in os_thread_exit(). - A created thread should always use that to exit and not - use return() to exit. */ - os_thread_exit(); - - OS_THREAD_DUMMY_RETURN; -} - /** Initialize the redo log recovery subsystem. */ void recv_sys_t::create() { ut_ad(this == &recv_sys); ut_ad(!is_initialised()); - ut_ad(!flush_start); - ut_ad(!flush_end); mutex_create(LATCH_ID_RECV_SYS, &mutex); - mutex_create(LATCH_ID_RECV_WRITER, &writer_mutex); - if (!srv_read_only_mode) { - flush_start = os_event_create(0); - flush_end = os_event_create(0); - } - - flush_lru = true; apply_log_recs = false; apply_batch_on = false; @@ -1066,6 +987,7 @@ void recv_sys_t::debug_free() { ut_ad(this == &recv_sys); ut_ad(is_initialised()); + ut_ad(!recv_recovery_is_on()); mutex_enter(&mutex); pages.clear(); @@ -1073,15 +995,6 @@ void recv_sys_t::debug_free() buf= nullptr; - /* wake page cleaner up to progress */ - if (!srv_read_only_mode) - { - ut_ad(!recv_recovery_is_on()); - ut_ad(!recv_writer_thread_active); - os_event_reset(buf_flush_event); - os_event_set(flush_start); - } - mutex_exit(&mutex); } @@ -2759,35 +2672,28 @@ void recv_sys_t::apply(bool last_batch) } } - if (!last_batch) - { - /* Flush all the file pages to disk and invalidate them in buf_pool */ - mutex_exit(&mutex); - log_mutex_exit(); - - /* Stop the recv_writer thread from issuing any LRU flush batches. */ - mutex_enter(&writer_mutex); - - /* Wait for any currently run batch to end. */ - buf_flush_wait_LRU_batch_end(); - - os_event_reset(flush_end); - flush_lru= false; - os_event_set(flush_start); - os_event_wait(flush_end); - - buf_pool_invalidate(); - - /* Allow batches from recv_writer thread. */ - mutex_exit(&writer_mutex); - - log_mutex_enter(); - mutex_enter(&mutex); - mlog_init.reset(); - } - else + if (last_batch) /* We skipped this in buf_page_create(). */ mlog_init.mark_ibuf_exist(mtr); + else + { + mlog_init.reset(); + log_mutex_exit(); + } + + ut_ad(!log_mutex_own()); + mutex_exit(&mutex); + + buf_flush_wait_LRU_batch_end(); + buf_flush_sync(); + + if (!last_batch) + { + buf_pool_invalidate(); + log_mutex_enter(); + } + + mutex_enter(&mutex); ut_d(after_apply= true); clear(); @@ -3120,7 +3026,6 @@ recv_group_scan_log_recs( recv_sys.recovered_lsn = *contiguous_lsn; recv_sys.scanned_checkpoint_no = 0; ut_ad(recv_max_page_lsn == 0); - ut_ad(last_phase || !recv_writer_thread_active); mutex_exit(&recv_sys.mutex); lsn_t start_lsn; @@ -3574,11 +3479,6 @@ completed: ut_ad(srv_force_recovery <= SRV_FORCE_NO_UNDO_LOG_SCAN); - /* Spawn the background thread to flush dirty pages - from the buffer pools. */ - recv_writer_thread_active = true; - os_thread_create(recv_writer_thread); - if (rescan) { contiguous_lsn = checkpoint_lsn; @@ -3659,35 +3559,11 @@ completed: } /** Complete recovery from a checkpoint. */ -void -recv_recovery_from_checkpoint_finish(void) +void recv_recovery_from_checkpoint_finish() { - /* Make sure that the recv_writer thread is done. This is - required because it grabs various mutexes and we want to - ensure that when we enable sync_order_checks there is no - mutex currently held by any thread. */ - mutex_enter(&recv_sys.writer_mutex); - /* Free the resources of the recovery system */ - recv_sys.recovery_on = false; - /* By acquring the mutex we ensure that the recv_writer thread - won't trigger any more LRU batches. Now wait for currently - in progress batches to finish. */ - buf_flush_wait_LRU_batch_end(); - - mutex_exit(&recv_sys.writer_mutex); - - ulint count = 0; - while (recv_writer_thread_active) { - ++count; - os_thread_sleep(100000); - if (srv_print_verbose_log && count > 600) { - ib::info() << "Waiting for recv_writer to" - " finish flushing of buffer pool"; - count = 0; - } - } + recv_sys.recovery_on= false; recv_sys.debug_free(); diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 59ed743b087..9a0f9d04149 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -903,13 +903,6 @@ srv_shutdown_all_bg_threads() ut_ad(!srv_read_only_mode); /* e. Exit the i/o threads */ - if (recv_sys.flush_start != NULL) { - os_event_set(recv_sys.flush_start); - } - if (recv_sys.flush_end != NULL) { - os_event_set(recv_sys.flush_end); - } - os_event_set(buf_flush_event); } @@ -1208,7 +1201,6 @@ dberr_t srv_start(bool create_new_db) + 1 /* buf_dump_thread */ + 1 /* dict_stats_thread */ + 1 /* fts_optimize_thread */ - + 1 /* recv_writer_thread */ + 1 /* trx_rollback_all_recovered */ + 128 /* added as margin, for use of InnoDB Memcached etc. */ @@ -1336,11 +1328,6 @@ dberr_t srv_start(bool create_new_db) if (!srv_read_only_mode) { buf_flush_page_cleaner_init(); - -#ifdef UNIV_LINUX - /* Wait for the setpriority() call to finish. */ - os_event_wait(recv_sys.flush_end); -#endif /* UNIV_LINUX */ srv_start_state_set(SRV_START_STATE_IO); } @@ -1679,7 +1666,6 @@ file_checked: InnoDB files is needed. */ ut_ad(!srv_force_recovery); ut_ad(recv_no_log_write); - buf_flush_sync(); err = fil_write_flushed_lsn(log_get_lsn()); DBUG_ASSERT(!buf_pool.any_io_pending()); log_sys.log.close_file(); @@ -1976,11 +1962,6 @@ skip_monitors: srv_is_being_started = false; - if (!srv_read_only_mode) { - /* wake main loop of page cleaner up */ - os_event_set(buf_flush_event); - } - if (srv_print_verbose_log) { ib::info() << INNODB_VERSION_STR << " started; log sequence number " diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc index 0c653344c12..78e613b52f0 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -505,7 +505,6 @@ LatchDebug::LatchDebug() LEVEL_MAP_INSERT(SYNC_FTS_CACHE); LEVEL_MAP_INSERT(SYNC_DICT_OPERATION); LEVEL_MAP_INSERT(SYNC_TRX_I_S_RWLOCK); - LEVEL_MAP_INSERT(SYNC_RECV_WRITER); LEVEL_MAP_INSERT(SYNC_LEVEL_VARYING); LEVEL_MAP_INSERT(SYNC_NO_ORDER_CHECK); @@ -765,7 +764,6 @@ LatchDebug::check_order( case SYNC_STATS_AUTO_RECALC: case SYNC_POOL: case SYNC_POOL_MANAGER: - case SYNC_RECV_WRITER: basic_check(latches, level, level); break; @@ -1290,8 +1288,6 @@ sync_latch_meta_init() LATCH_ADD_MUTEX(RECV_SYS, SYNC_RECV, recv_sys_mutex_key); - LATCH_ADD_MUTEX(RECV_WRITER, SYNC_RECV_WRITER, recv_writer_mutex_key); - LATCH_ADD_MUTEX(REDO_RSEG, SYNC_REDO_RSEG, redo_rseg_mutex_key); LATCH_ADD_MUTEX(NOREDO_RSEG, SYNC_NOREDO_RSEG, noredo_rseg_mutex_key); diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc index 7447537f2be..6a40c90579d 100644 --- a/storage/innobase/sync/sync0sync.cc +++ b/storage/innobase/sync/sync0sync.cc @@ -55,7 +55,6 @@ mysql_pfs_key_t recalc_pool_mutex_key; mysql_pfs_key_t page_cleaner_mutex_key; mysql_pfs_key_t purge_sys_pq_mutex_key; mysql_pfs_key_t recv_sys_mutex_key; -mysql_pfs_key_t recv_writer_mutex_key; mysql_pfs_key_t redo_rseg_mutex_key; mysql_pfs_key_t noredo_rseg_mutex_key; mysql_pfs_key_t page_zip_stat_per_index_mutex_key; From 46b1f500983d45e89dc84bb9820023bd51a4cda8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 15 Oct 2020 10:27:25 +0300 Subject: [PATCH 121/323] MDEV-23399: Remove buf_pool.flush_rbt Normally, buf_pool.flush_list must be sorted by buf_page_t::oldest_modification, so that log_checkpoint() can choose MIN(oldest_modification) as the checkpoint LSN. During recovery, buf_pool.flush_rbt used to guarantee the ordering. However, we can allow the buf_pool.flush_list to be in an arbitrary order during recovery, and simply ensure that it is in the correct order by the time a log checkpoint needs to be executed. recv_sys_t::apply(): To keep it simple, we will always flush the buffer pool at the end of each batch. Note that log_checkpoint() will invoke recv_sys_t::apply() in case a checkpoint is initiated during the last batch of recovery, when we already allow writes to data pages and the redo log. Reviewed by: Vladislav Vaintroub --- storage/innobase/buf/buf0buf.cc | 7 - storage/innobase/buf/buf0flu.cc | 207 +---------------------------- storage/innobase/include/buf0buf.h | 17 +-- storage/innobase/include/buf0flu.h | 14 -- storage/innobase/log/log0recv.cc | 8 +- 5 files changed, 8 insertions(+), 245 deletions(-) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 8c5eba321a4..078361092fc 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -1607,12 +1607,6 @@ void buf_pool_t::close() mutex_free(&mutex); mutex_free(&flush_list_mutex); - if (flush_rbt) - { - rbt_free(flush_rbt); - flush_rbt= nullptr; - } - for (buf_page_t *bpage= UT_LIST_GET_LAST(LRU), *prev_bpage= nullptr; bpage; bpage= prev_bpage) { @@ -2113,7 +2107,6 @@ inline void buf_pool_t::resize() ut_ad(curr_size == old_size); ut_ad(n_chunks_new == n_chunks); ut_ad(UT_LIST_GET_LEN(withdraw) == 0); - ut_ad(flush_rbt == NULL); n_chunks_new = (new_instance_size << srv_page_size_shift) / srv_buf_pool_chunk_unit; diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index d0fbd59f968..10ed54be452 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -236,134 +236,6 @@ static void buf_flush_validate_skip() } #endif /* UNIV_DEBUG */ -/******************************************************************//** -Insert a block in the flush_rbt and returns a pointer to its -predecessor or NULL if no predecessor. The ordering is maintained -on the basis of the key. -@return pointer to the predecessor or NULL if no predecessor. */ -static -buf_page_t* -buf_flush_insert_in_flush_rbt( -/*==========================*/ - buf_page_t* bpage) /*!< in: bpage to be inserted. */ -{ - const ib_rbt_node_t* c_node; - const ib_rbt_node_t* p_node; - buf_page_t* prev = NULL; - - ut_ad(srv_shutdown_state != SRV_SHUTDOWN_FLUSH_PHASE); - ut_ad(mutex_own(&buf_pool.flush_list_mutex)); - - /* Insert this buffer into the rbt. */ - c_node = rbt_insert(buf_pool.flush_rbt, &bpage, &bpage); - ut_a(c_node != NULL); - - /* Get the predecessor. */ - p_node = rbt_prev(buf_pool.flush_rbt, c_node); - - if (p_node != NULL) { - buf_page_t** value; - value = rbt_value(buf_page_t*, p_node); - prev = *value; - ut_a(prev != NULL); - } - - return(prev); -} - -/*********************************************************//** -Delete a bpage from the flush_rbt. */ -static -void -buf_flush_delete_from_flush_rbt( -/*============================*/ - buf_page_t* bpage) /*!< in: bpage to be removed. */ -{ - ut_ad(mutex_own(&buf_pool.flush_list_mutex)); - -#ifdef UNIV_DEBUG - ibool ret = -#endif /* UNIV_DEBUG */ - rbt_delete(buf_pool.flush_rbt, &bpage); - - ut_ad(ret); -} - -/*****************************************************************//** -Compare two modified blocks in the buffer pool. The key for comparison -is: -key = -This comparison is used to maintian ordering of blocks in the -buf_pool.flush_rbt. -Note that for the purpose of flush_rbt, we only need to order blocks -on the oldest_modification. The other two fields are used to uniquely -identify the blocks. -@return < 0 if b2 < b1, 0 if b2 == b1, > 0 if b2 > b1 */ -static -int -buf_flush_block_cmp( -/*================*/ - const void* p1, /*!< in: block1 */ - const void* p2) /*!< in: block2 */ -{ - const buf_page_t* b1 = *static_cast(p1); - const buf_page_t* b2 = *static_cast(p2); - - ut_ad(b1 != NULL); - ut_ad(b2 != NULL); - - ut_ad(mutex_own(&buf_pool.flush_list_mutex)); - - const lsn_t m1 = b1->oldest_modification(), - m2 = b2->oldest_modification(); - - ut_ad(m1); - ut_ad(m2); - - if (m2 > m1) { - return(1); - } else if (m2 < m1) { - return(-1); - } - - if (b2->id() > b1->id()) { - return 1; - } - if (b2->id() < b1->id()) { - return -1; - } - return 0; -} - -/********************************************************************//** -Initialize the red-black tree to speed up insertions into the flush_list -during recovery process. Should be called at the start of recovery -process before any page has been read/written. */ -void -buf_flush_init_flush_rbt(void) -/*==========================*/ -{ - mutex_enter(&buf_pool.flush_list_mutex); - ut_ad(buf_pool.flush_rbt == NULL); - /* Create red black tree for speedy insertions in flush list. */ - buf_pool.flush_rbt = rbt_create( - sizeof(buf_page_t*), buf_flush_block_cmp); - mutex_exit(&buf_pool.flush_list_mutex); -} - -/********************************************************************//** -Frees up the red-black tree. */ -void -buf_flush_free_flush_rbt(void) -/*==========================*/ -{ - mutex_enter(&buf_pool.flush_list_mutex); - ut_d(buf_flush_validate_low()); - rbt_free(buf_pool.flush_rbt); - buf_pool.flush_rbt = NULL; - mutex_exit(&buf_pool.flush_list_mutex); -} - /** Insert a modified block into the flush list. @param[in,out] block modified block @param[in] lsn oldest modification */ @@ -380,32 +252,7 @@ void buf_flush_insert_into_flush_list(buf_block_t* block, lsn_t lsn) block->physical_size()); incr_flush_list_size_in_bytes(block); - if (UNIV_LIKELY_NULL(buf_pool.flush_rbt)) { - ut_ad(srv_shutdown_state != SRV_SHUTDOWN_FLUSH_PHASE); - /* The field in_LRU_list is protected by buf_pool.mutex, which - we are not holding. However, while a block is in the flush - list, it is dirty and cannot be discarded, not from the - page_hash or from the LRU list. At most, the uncompressed - page frame of a compressed block may be discarded or created - (copying the block->page to or from a buf_page_t that is - dynamically allocated from buf_buddy_alloc()). Because those - transitions hold buf_pool.flush_list_mutex (via - buf_flush_relocate_on_flush_list()), there is no possibility - of a race condition in the assertions below. */ - ut_ad(block->page.in_LRU_list); - /* buf_buddy_block_register() will take a block in the - BUF_BLOCK_MEMORY state, not a file page. */ - ut_ad(!block->page.in_zip_hash); - - if (buf_page_t* prev_b = - buf_flush_insert_in_flush_rbt(&block->page)) { - UT_LIST_INSERT_AFTER(buf_pool.flush_list, prev_b, &block->page); - goto func_exit; - } - } - UT_LIST_ADD_FIRST(buf_pool.flush_list, &block->page); -func_exit: ut_d(buf_flush_validate_skip()); mutex_exit(&buf_pool.flush_list_mutex); } @@ -430,14 +277,6 @@ void buf_flush_remove(buf_page_t* bpage) the bpage from flush list. */ buf_pool.flush_hp.adjust(bpage); UT_LIST_REMOVE(buf_pool.flush_list, bpage); - - /* If the flush_rbt is active then delete from there as well. */ - if (UNIV_LIKELY_NULL(buf_pool.flush_rbt)) { - buf_flush_delete_from_flush_rbt(bpage); - } - - /* Must be done after we have removed it from the flush_rbt - because we assert on it in buf_flush_block_cmp(). */ bpage->clear_oldest_modification(); buf_pool.stat.flush_list_bytes -= bpage->physical_size(); @@ -467,7 +306,6 @@ buf_flush_relocate_on_flush_list( buf_page_t* dpage) /*!< in/out: destination block */ { buf_page_t* prev; - buf_page_t* prev_b = NULL; ut_ad(mutex_own(&buf_pool.mutex)); mutex_enter(&buf_pool.flush_list_mutex); @@ -481,19 +319,10 @@ buf_flush_relocate_on_flush_list( having the buf_pool mutex. */ ut_ad(dpage->oldest_modification()); - /* If recovery is active we must swap the control blocks in - the flush_rbt as well. */ - if (UNIV_LIKELY_NULL(buf_pool.flush_rbt)) { - buf_flush_delete_from_flush_rbt(bpage); - prev_b = buf_flush_insert_in_flush_rbt(dpage); - } - /* Important that we adjust the hazard pointer before removing the bpage from the flush list. */ buf_pool.flush_hp.adjust(bpage); - /* Must be done after we have removed it from the flush_rbt - because we assert on it in buf_flush_block_cmp(). */ bpage->clear_oldest_modification(); prev = UT_LIST_GET_PREV(list, bpage); @@ -506,9 +335,6 @@ buf_flush_relocate_on_flush_list( UT_LIST_ADD_FIRST(buf_pool.flush_list, dpage); } - /* Just an extra check. Previous in flush_list - should be the same control block as in flush_rbt. */ - ut_a(!buf_pool.flush_rbt || prev_b == prev); ut_d(buf_flush_validate_low()); mutex_exit(&buf_pool.flush_list_mutex); } @@ -2889,7 +2715,6 @@ struct Check { static void buf_flush_validate_low() { buf_page_t* bpage; - const ib_rbt_node_t* rnode = NULL; ut_ad(mutex_own(&buf_pool.flush_list_mutex)); @@ -2897,13 +2722,6 @@ static void buf_flush_validate_low() bpage = UT_LIST_GET_FIRST(buf_pool.flush_list); - /* If we are in recovery mode i.e.: flush_rbt != NULL - then each block in the flush_list must also be present - in the flush_rbt. */ - if (UNIV_LIKELY_NULL(buf_pool.flush_rbt)) { - rnode = rbt_first(buf_pool.flush_rbt); - } - while (bpage != NULL) { const lsn_t om = bpage->oldest_modification(); /* A page in buf_pool.flush_list can be in @@ -2912,29 +2730,14 @@ static void buf_flush_validate_low() original descriptor can have this state and still be in the flush list waiting to acquire the buf_pool.flush_list_mutex to complete the relocation. */ - ut_a(bpage->in_file() - || bpage->state() == BUF_BLOCK_REMOVE_HASH); - ut_a(om > 0); - - if (UNIV_LIKELY_NULL(buf_pool.flush_rbt)) { - buf_page_t** prpage; - - ut_a(rnode != NULL); - prpage = rbt_value(buf_page_t*, rnode); - - ut_a(*prpage != NULL); - ut_a(*prpage == bpage); - rnode = rbt_next(buf_pool.flush_rbt, rnode); - } + ut_ad(bpage->in_file() + || bpage->state() == BUF_BLOCK_REMOVE_HASH); + ut_ad(om > 0); bpage = UT_LIST_GET_NEXT(list, bpage); - - ut_a(!bpage || om >= bpage->oldest_modification()); + ut_ad(!bpage || recv_recovery_is_on() + || om >= bpage->oldest_modification()); } - - /* By this time we must have exhausted the traversal of - flush_rbt (if active) as well. */ - ut_a(rnode == NULL); } /** Validate the flush list. */ diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 3eb1773a5b6..9b58fa76c01 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -39,7 +39,6 @@ Created 11/5/1995 Heikki Tuuri #include "hash0hash.h" #include "ut0byte.h" #include "page0types.h" -#include "ut0rbt.h" #include "log0log.h" #include "srv0srv.h" #include @@ -1910,7 +1909,7 @@ public: FlushListMutex flush_list_mutex;/*!< mutex protecting the flush list access. This mutex - protects flush_list, flush_rbt + protects flush_list and bpage::list pointers when the bpage is on flush_list. It also protects writes to @@ -1934,20 +1933,6 @@ public: of the given type running; os_event_set() and os_event_reset() are protected by buf_pool_t::mutex */ - ib_rbt_t* flush_rbt; /*!< a red-black tree is used - exclusively during recovery to - speed up insertions in the - flush_list. This tree contains - blocks in order of - oldest_modification LSN and is - kept in sync with the - flush_list. - Each member of the tree MUST - also be on the flush_list. - This tree is relevant only in - recovery and is set to NULL - once the recovery is over. - Protected by flush_list_mutex */ unsigned freed_page_clock;/*!< a sequence number used to count the number of buffer blocks removed from the end of diff --git a/storage/innobase/include/buf0flu.h b/storage/innobase/include/buf0flu.h index f7f89f1a9e9..17568d0e2b1 100644 --- a/storage/innobase/include/buf0flu.h +++ b/storage/innobase/include/buf0flu.h @@ -164,20 +164,6 @@ void buf_flush_wait_LRU_batch_end(); void buf_flush_validate(); #endif /* UNIV_DEBUG */ -/********************************************************************//** -Initialize the red-black tree to speed up insertions into the flush_list -during recovery process. Should be called at the start of recovery -process before any page has been read/written. */ -void -buf_flush_init_flush_rbt(void); -/*==========================*/ - -/********************************************************************//** -Frees up the red-black tree. */ -void -buf_flush_free_flush_rbt(void); -/*==========================*/ - /** Write a flushable page from buf_pool to a file. buf_pool.mutex must be held. @param bpage buffer control block diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 6f3f0ffd68a..aff1d011a8d 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -2684,6 +2684,8 @@ void recv_sys_t::apply(bool last_batch) ut_ad(!log_mutex_own()); mutex_exit(&mutex); + /* Instead of flushing, last_batch could sort the buf_pool.flush_list + in ascending order of buf_page_t::oldest_modification. */ buf_flush_wait_LRU_batch_end(); buf_flush_sync(); @@ -3271,10 +3273,6 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) ut_ad(UT_LIST_GET_LEN(buf_pool.unzip_LRU) == 0); ut_d(mutex_exit(&buf_pool.flush_list_mutex)); - /* Initialize red-black tree for fast insertions into the - flush_list during recovery process. */ - buf_flush_init_flush_rbt(); - if (srv_force_recovery >= SRV_FORCE_NO_LOG_REDO) { ib::info() << "innodb_force_recovery=6 skips redo log apply"; @@ -3567,8 +3565,6 @@ void recv_recovery_from_checkpoint_finish() recv_sys.debug_free(); - /* Free up the flush_rbt. */ - buf_flush_free_flush_rbt(); /* Enable innodb_sync_debug checks */ ut_d(sync_check_enable()); } From ff8ffef3e1915d7a9caa07d9461cd8d47c4baf98 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 2 Oct 2020 11:09:01 +1000 Subject: [PATCH 122/323] MDEV-23201: mysql_upgrade order mysql.user for 5.7 cross-upgrade As MariaDB tables are expected in a fixed order, the cross upgrade previously placed roles, default_role and max_statement_time after now unused mysql-5.7 columns. Test: $ cp -a /usr/local/mysql-5.7.31/data/ /tmp/m57data $ sql/mysqld --no-defaults --skip-networking --datadir=/tmp/m57data --socket=/tmp/${PWD##*/}.sock --verbose --lc-messages-dir=$PWD/sql/share 2020-10-02 11:02:05 140135193212864 [Note] sql/mysqld (mysqld 10.2.34-MariaDB) starting as process 1457667 ... 2020-10-02 11:02:05 140135193212864 [Note] InnoDB: Mutexes and rw_locks use GCC atomic built $ client/mysql_upgrade --no-defaults -u root -pbob -S /tmp/build-mariadb-server-10.2.sock MySQL upgrade detected Phase 1/7: Checking and upgrading mysql database Processing databases mysql mysql.columns_priv OK mysql.db OK mysql.engine_cost OK mysql.event OK mysql.func OK mysql.gtid_executed OK mysql.help_category OK mysql.help_keyword OK mysql.help_relation OK mysql.help_topic OK mysql.innodb_index_stats OK mysql.innodb_table_stats OK mysql.ndb_binlog_index OK mysql.plugin OK mysql.proc OK mysql.procs_priv OK mysql.proxies_priv OK mysql.server_cost OK mysql.servers OK mysql.slave_master_info OK mysql.slave_relay_log_info OK mysql.slave_worker_info OK mysql.tables_priv OK mysql.time_zone OK mysql.time_zone_leap_second OK mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK Upgrading from a version before MariaDB-10.1 Phase 2/7: Installing used storage engines Result: | user | CREATE TABLE `user` ( `Host` char(60) COLLATE utf8_bin NOT NULL DEFAULT '', `User` char(80) COLLATE utf8_bin NOT NULL DEFAULT '', `Password` char(41) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL DEFAULT '', `Select_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Insert_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Update_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Delete_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Drop_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Reload_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Shutdown_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Process_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `File_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Grant_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `References_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Index_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Alter_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Show_db_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Super_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_tmp_table_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Lock_tables_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Execute_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Repl_slave_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Repl_client_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_view_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Show_view_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_routine_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Alter_routine_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_user_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Event_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Trigger_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_tablespace_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `ssl_type` enum('','ANY','X509','SPECIFIED') CHARACTER SET utf8 NOT NULL DEFAULT '', `ssl_cipher` blob NOT NULL, `x509_issuer` blob NOT NULL, `x509_subject` blob NOT NULL, `max_questions` int(11) unsigned NOT NULL DEFAULT 0, `max_updates` int(11) unsigned NOT NULL DEFAULT 0, `max_connections` int(11) unsigned NOT NULL DEFAULT 0, `max_user_connections` int(11) NOT NULL DEFAULT 0, `plugin` char(64) CHARACTER SET latin1 NOT NULL DEFAULT '', `authentication_string` text COLLATE utf8_bin NOT NULL, `password_expired` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `is_role` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `default_role` char(80) COLLATE utf8_bin NOT NULL DEFAULT '', `max_statement_time` decimal(12,6) NOT NULL DEFAULT 0.000000, `password_last_changed` timestamp NULL DEFAULT NULL, `password_lifetime` smallint(5) unsigned DEFAULT NULL, `account_locked` enum('N','Y') COLLATE utf8_bin NOT NULL DEFAULT 'N', PRIMARY KEY (`Host`,`User`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges' | MariaDB [(none)]> CREATE ROLE `aRole`; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> SET ROLE `aRole`; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> FLUSH PRIVILEGES; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> SET ROLE `aRole`; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> SELECT `User`, `is_role` FROM `mysql`.`user`; +---------------+---------+ | User | is_role | +---------------+---------+ | root | N | | mysql.session | N | | mysql.sys | N | | dan | N | | aRole | Y | +---------------+---------+ 5 rows in set (0.00 sec) Reviewer: Anel Husakovic --- mysql-test/r/mysql_upgrade.result | 170 ++++++++++++++++++++++++++++ mysql-test/std_data/mysql57user.MYD | Bin 0 -> 340 bytes mysql-test/std_data/mysql57user.MYI | Bin 0 -> 4096 bytes mysql-test/std_data/mysql57user.frm | Bin 0 -> 10816 bytes mysql-test/t/mysql_upgrade.test | 35 ++++++ scripts/mysql_system_tables_fix.sql | 12 +- 6 files changed, 211 insertions(+), 6 deletions(-) create mode 100644 mysql-test/std_data/mysql57user.MYD create mode 100644 mysql-test/std_data/mysql57user.MYI create mode 100644 mysql-test/std_data/mysql57user.frm diff --git a/mysql-test/r/mysql_upgrade.result b/mysql-test/r/mysql_upgrade.result index a6a5da8f8c8..b6fb56a63e0 100644 --- a/mysql-test/r/mysql_upgrade.result +++ b/mysql-test/r/mysql_upgrade.result @@ -561,3 +561,173 @@ t1 CREATE TABLE `t1` ( DROP TABLE test.t1; SET GLOBAL enforce_storage_engine=NULL; End of 10.1 tests +# +# MDEV-23201 'Roles' are created incorrectly on an install that was previously MySQL 5.7 +# +# +FLUSH TABLES mysql.user; +FLUSH PRIVILEGES; +SHOW CREATE TABLE mysql.user; +Table Create Table +user CREATE TABLE `user` ( + `Host` char(60) COLLATE utf8_bin NOT NULL DEFAULT '', + `User` char(32) COLLATE utf8_bin NOT NULL DEFAULT '', + `Select_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Insert_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Update_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Delete_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Create_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Drop_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Reload_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Shutdown_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Process_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `File_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Grant_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `References_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Index_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Alter_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Show_db_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Super_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Create_tmp_table_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Lock_tables_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Execute_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Repl_slave_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Repl_client_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Create_view_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Show_view_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Create_routine_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Alter_routine_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Create_user_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Event_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Trigger_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Create_tablespace_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `ssl_type` enum('','ANY','X509','SPECIFIED') CHARACTER SET utf8 NOT NULL DEFAULT '', + `ssl_cipher` blob NOT NULL, + `x509_issuer` blob NOT NULL, + `x509_subject` blob NOT NULL, + `max_questions` int(11) unsigned NOT NULL DEFAULT 0, + `max_updates` int(11) unsigned NOT NULL DEFAULT 0, + `max_connections` int(11) unsigned NOT NULL DEFAULT 0, + `max_user_connections` int(11) unsigned NOT NULL DEFAULT 0, + `plugin` char(64) COLLATE utf8_bin NOT NULL DEFAULT 'mysql_native_password', + `authentication_string` text COLLATE utf8_bin DEFAULT NULL, + `password_expired` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `password_last_changed` timestamp NULL DEFAULT NULL, + `password_lifetime` smallint(5) unsigned DEFAULT NULL, + `account_locked` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + PRIMARY KEY (`Host`,`User`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges' +Phase 1/7: Checking and upgrading mysql database +Processing databases +mysql +mysql.column_stats OK +mysql.columns_priv OK +mysql.db OK +mysql.event OK +mysql.func OK +mysql.gtid_slave_pos OK +mysql.help_category OK +mysql.help_keyword OK +mysql.help_relation OK +mysql.help_topic OK +mysql.host OK +mysql.index_stats OK +mysql.innodb_index_stats OK +mysql.innodb_table_stats OK +mysql.plugin OK +mysql.proc OK +mysql.procs_priv OK +mysql.proxies_priv OK +mysql.roles_mapping OK +mysql.servers OK +mysql.table_stats OK +mysql.tables_priv OK +mysql.time_zone OK +mysql.time_zone_leap_second OK +mysql.time_zone_name OK +mysql.time_zone_transition OK +mysql.time_zone_transition_type OK +mysql.user OK +Upgrading from a version before MariaDB-10.1 +Phase 2/7: Installing used storage engines +Checking for tables with unknown storage engine +Phase 3/7: Fixing views +Phase 4/7: Running 'mysql_fix_privilege_tables' +Phase 5/7: Fixing table and database names +Phase 6/7: Checking and upgrading tables +Processing databases +information_schema +mtr +mtr.global_suppressions OK +mtr.test_suppressions OK +performance_schema +test +Phase 7/7: Running 'FLUSH PRIVILEGES' +OK +SHOW CREATE TABLE mysql.user; +Table Create Table +user CREATE TABLE `user` ( + `Host` char(60) COLLATE utf8_bin NOT NULL DEFAULT '', + `User` char(80) COLLATE utf8_bin NOT NULL DEFAULT '', + `Password` char(41) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL DEFAULT '', + `Select_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Insert_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Update_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Delete_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Create_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Drop_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Reload_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Shutdown_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Process_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `File_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Grant_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `References_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Index_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Alter_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Show_db_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Super_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Create_tmp_table_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Lock_tables_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Execute_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Repl_slave_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Repl_client_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Create_view_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Show_view_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Create_routine_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Alter_routine_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Create_user_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Event_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Trigger_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Create_tablespace_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `ssl_type` enum('','ANY','X509','SPECIFIED') CHARACTER SET utf8 NOT NULL DEFAULT '', + `ssl_cipher` blob NOT NULL, + `x509_issuer` blob NOT NULL, + `x509_subject` blob NOT NULL, + `max_questions` int(11) unsigned NOT NULL DEFAULT 0, + `max_updates` int(11) unsigned NOT NULL DEFAULT 0, + `max_connections` int(11) unsigned NOT NULL DEFAULT 0, + `max_user_connections` int(11) NOT NULL DEFAULT 0, + `plugin` char(64) CHARACTER SET latin1 NOT NULL DEFAULT '', + `authentication_string` text COLLATE utf8_bin NOT NULL, + `password_expired` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `is_role` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `default_role` char(80) COLLATE utf8_bin NOT NULL DEFAULT '', + `max_statement_time` decimal(12,6) NOT NULL DEFAULT 0.000000, + `password_last_changed` timestamp NULL DEFAULT NULL, + `password_lifetime` smallint(5) unsigned DEFAULT NULL, + `account_locked` enum('N','Y') COLLATE utf8_bin NOT NULL DEFAULT 'N', + PRIMARY KEY (`Host`,`User`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges' +CREATE ROLE `aRole`; +SET ROLE `aRole`; +FLUSH PRIVILEGES; +SET ROLE `aRole`; +SELECT `User`, `is_role` FROM `mysql`.`user`; +User is_role +mysql.session N +root N +mysql.sys N +aRole Y +DROP ROLE `aRole`; +FLUSH PRIVILEGES; +End of 10.2 tests diff --git a/mysql-test/std_data/mysql57user.MYD b/mysql-test/std_data/mysql57user.MYD new file mode 100644 index 0000000000000000000000000000000000000000..0fe0eef8d2a9188405a07572bd6aeadb73ecbe0f GIT binary patch literal 340 zcmZQ(Xkhp+{D(6qKRGccBfq$WH@C95Fh{RAwYWGlKaUX=Frjiq!D{345=%16QsWB} zi;K(ii&8Whv_d>QgFS=&{6ieW9DO`p0vv;b!~KI?LOdKpoE`m~TtkChT|8WaTp8o* y{4X#uGx#w47e{gfOHqD)2@^iRh}~+id5p{qHK=~#g!-wn7}fpgJnV*&>>mKhLszl@ literal 0 HcmV?d00001 diff --git a/mysql-test/std_data/mysql57user.MYI b/mysql-test/std_data/mysql57user.MYI new file mode 100644 index 0000000000000000000000000000000000000000..16e9fa662a3f4d6e4758a1e5608a60bae7dc788c GIT binary patch literal 4096 zcmeHFu}%U(5Ph?I!NbI8VP%Z5f{w({##~rl2&c?nAg4=ei)1lnl-naicx2{F)TBrgcLjwbKK5WB!*Temb+BA>Yz4wBXndgb zKr)*i{yz&N2a`*oQ9~V22h;&|V1EwWqFT7lQ}N>b@Z@#m2Svkoz3;hxdB+&l$d0@) eKVxKX&JCsb*xy5Rk~*Lcr~~SNI-m~xmjk~temm6w literal 0 HcmV?d00001 diff --git a/mysql-test/std_data/mysql57user.frm b/mysql-test/std_data/mysql57user.frm new file mode 100644 index 0000000000000000000000000000000000000000..2ae83ceb606fffe3dedc1eceba113012df4284cf GIT binary patch literal 10816 zcmeI2OLN;)6vvO`D6uX1A-@7m0k=H+2uTSr!v@GSY2ys(WMaxt7O0A>Is!#f^~htF z1;d6JJ_`$mEv)!TY?xlo)x$n+J50hV%v>#Oou7{Gz546=e@54OCRHjWfTjen3gAd< zG8CJ96Dj}-4~GSFFz?o%0NVvvSpn!5f%p~*2nB=!LII(GP(Uak6c7ps1%v`Z0il3U z;8H3e;q!hKWa#i6kk0T^f?q*C`;G5B2DZC5*je9u#4hFN|3`yjeX+fufb_51#qRFm zY4p@JJTrEVY$GtE=-3ZOFZ6hM!Srfzjg4>kH4i(dgW>v420qTd#HUa|C?FIN3J3*+ z0zv_yfKWgvAQbpd3VdFL=J`)tdKlSZ)Hl6Rf9(4ErrQrf=g4vGu^pYimCKY_f@S!* z^b0O~tjVXc3}v{A!`p=(;9C*64Wv$6?%X)8``dI#RgXj z7C;+#$n&ra+QVRE#`wU>k5)k2z~myVf_68wCr4GNZiIf2rD~w<*{*MnvakmA;Xx9Q z{9`Wzb*SxzzGX*I7B`@J5ARbJG(o)|nqEE#9h!Ug6Fam$OwSTppbor|eUe3OP}kkq z4zs8Owc&w(Y>f7^xC`nq35ugV=;dRM4+A4M_lrJ%ys(h^7rym<)CA;j$K?}8T5QiM~;1*M z+Q~<&pBPRQB^b7$mWENX{~gXK=s^9@JTaaob`(3l7eN;^4w7_AML36>JhXhz!}K)c zcPKAhY&v(-7WqZeb`)3$++^%{IKg{n5+C4oI~K0J_?{8Pq2rBls_VrnjA5SyPH2zt z*VUUa*NkGrIxxL49;iTTdcb*N$IhXR>yi!Avit<^ql;4k)8>?IT$@anMgX4STSWZxPVt8E+HN>mhiDfH@t( zy96k_jrRzc=i|6Rzyd$zCIMv*ZV^yvAh=CHwS!=p0JV+aeF8Mz#tH#7KJ--rQVH)6 z&{)Kb4+v;hmX=^G12Vtax>_#7hZ5);9e}?-188XoJ|&=CL$F0ar>?57C&3l&_9dJ_ zT@Ark1oWB+z9C?)i{M)Vl!dK7U|-@ZcKIyqVK3KZ(0}0Lz(!LEZ)15Wre(R;Zo{$+ zKb_$zdKsY7QWUr&LyH3$PpNWE@pZh(DU25u#;Xb=C54fC!bmY;q>`}QdALKeNeyA7 zfUueB!D#7Vle)pCMFY>BsTeqlqFk_Pt-w~Ng@R41L@}P(62YGLdq&M3dz^9lEG9Nz zG&*tgtoLd75_iwXO0B(UX5#B?YU+$SdXbpcxT&49!pqa0%*YvW@oYc0a5m%LX_T9H zx=$Q8JNBFnv&@6pOAVM!3^jM(DWKL%Xzsgg)^r)L2MquJVQl@uBlb1cBR1UKygRrz I*xX?754x4tVE_OC literal 0 HcmV?d00001 diff --git a/mysql-test/t/mysql_upgrade.test b/mysql-test/t/mysql_upgrade.test index a19be30e68f..5dad8702fc5 100644 --- a/mysql-test/t/mysql_upgrade.test +++ b/mysql-test/t/mysql_upgrade.test @@ -219,3 +219,38 @@ DROP TABLE test.t1; SET GLOBAL enforce_storage_engine=NULL; --echo End of 10.1 tests + +--echo # +--echo # MDEV-23201 'Roles' are created incorrectly on an install that was previously MySQL 5.7 +--echo # +--echo # + +--exec $MYSQL_DUMP --result-file $MYSQLTEST_VARDIR/tmp/user.sql mysql user +--remove_file $MYSQLD_DATADIR/mysql/user.frm +--remove_file $MYSQLD_DATADIR/mysql/user.MYI +--remove_file $MYSQLD_DATADIR/mysql/user.MYD + +--copy_file std_data/mysql57user.frm $MYSQLD_DATADIR/mysql/user.frm +--copy_file std_data/mysql57user.MYI $MYSQLD_DATADIR/mysql/user.MYI +--copy_file std_data/mysql57user.MYD $MYSQLD_DATADIR/mysql/user.MYD +FLUSH TABLES mysql.user; +FLUSH PRIVILEGES; +SHOW CREATE TABLE mysql.user; + +--exec $MYSQL_UPGRADE --force 2>&1 +SHOW CREATE TABLE mysql.user; + +CREATE ROLE `aRole`; +SET ROLE `aRole`; + +FLUSH PRIVILEGES; + +SET ROLE `aRole`; +SELECT `User`, `is_role` FROM `mysql`.`user`; + +DROP ROLE `aRole`; +--exec $MYSQL mysql < $MYSQLTEST_VARDIR/tmp/user.sql +FLUSH PRIVILEGES; +--remove_file $MYSQLD_DATADIR/mysql_upgrade_info + +--echo End of 10.2 tests diff --git a/scripts/mysql_system_tables_fix.sql b/scripts/mysql_system_tables_fix.sql index a07a4c53d8b..8e0894c41b3 100644 --- a/scripts/mysql_system_tables_fix.sql +++ b/scripts/mysql_system_tables_fix.sql @@ -644,14 +644,14 @@ ALTER TABLE user MODIFY Create_tablespace_priv enum('N','Y') COLLATE utf8_genera UPDATE user SET Create_tablespace_priv = Super_priv WHERE @hadCreateTablespacePriv = 0; -ALTER TABLE user ADD plugin char(64) CHARACTER SET latin1 DEFAULT '' NOT NULL, - ADD authentication_string TEXT NOT NULL; +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 MODIFY plugin char(64) CHARACTER SET latin1 DEFAULT '' NOT NULL, MODIFY authentication_string TEXT NOT NULL; -ALTER TABLE user ADD password_expired ENUM('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; -ALTER TABLE user ADD is_role enum('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; -ALTER TABLE user ADD default_role char(80) binary DEFAULT '' NOT NULL; -ALTER TABLE user ADD max_statement_time decimal(12,6) DEFAULT 0 NOT NULL; +ALTER TABLE user ADD password_expired ENUM('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER authentication_string; +ALTER TABLE user ADD is_role enum('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER password_expired; +ALTER TABLE user ADD default_role char(80) 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 utf8 COLLATE utf8_bin. -- we want password_expired column to have collation utf8_general_ci. ALTER TABLE user MODIFY password_expired ENUM('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; From 24c5af6758091dd4d9513e385ac76618c64ba0d2 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 14 Oct 2020 15:55:16 +0200 Subject: [PATCH 123/323] Fix the constants names --- sql/sql_class.h | 4 ++-- sql/sql_parse.cc | 17 ++++++++++------- sql/sql_prepare.cc | 4 ++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index 8d8ab779d56..d693cfa2727 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -5782,11 +5782,11 @@ public: /** SP Bulk execution safe */ -#define CF_SP_BULK_SAFE (1U << 20) +#define CF_PS_ARRAY_BINDING_SAFE (1U << 20) /** SP Bulk execution optimized */ -#define CF_SP_BULK_OPTIMIZED (1U << 21) +#define CF_PS_ARRAY_BINDING_OPTIMIZED (1U << 21) /* Bits in server_command_flags */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 543c877b7f1..e34181e2eeb 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -577,19 +577,21 @@ void init_update_queries(void) CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED | - CF_UPDATES_DATA | CF_SP_BULK_SAFE; + CF_UPDATES_DATA | + CF_PS_ARRAY_BINDING_SAFE; sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED | - CF_UPDATES_DATA | CF_SP_BULK_SAFE; + CF_UPDATES_DATA | + CF_PS_ARRAY_BINDING_SAFE; sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED | CF_INSERTS_DATA | - CF_SP_BULK_SAFE | - CF_SP_BULK_OPTIMIZED; + CF_PS_ARRAY_BINDING_SAFE | + CF_PS_ARRAY_BINDING_OPTIMIZED; sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | @@ -599,7 +601,7 @@ void init_update_queries(void) CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED | - CF_SP_BULK_SAFE; + CF_PS_ARRAY_BINDING_SAFE; sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | @@ -608,8 +610,9 @@ void init_update_queries(void) CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED | - CF_INSERTS_DATA | CF_SP_BULK_SAFE | - CF_SP_BULK_OPTIMIZED; + CF_INSERTS_DATA | + CF_PS_ARRAY_BINDING_SAFE | + CF_PS_ARRAY_BINDING_OPTIMIZED; sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index f0c9f818f87..1efb9d713bc 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -4390,7 +4390,7 @@ Prepared_statement::execute_bulk_loop(String *expanded_query, return TRUE; } - if (!(sql_command_flags[lex->sql_command] & CF_SP_BULK_SAFE)) + if (!(sql_command_flags[lex->sql_command] & CF_PS_ARRAY_BINDING_SAFE)) { DBUG_PRINT("error", ("Command is not supported in bulk execution.")); my_error(ER_UNSUPPORTED_PS, MYF(0)); @@ -4432,7 +4432,7 @@ Prepared_statement::execute_bulk_loop(String *expanded_query, Here we set parameters for not optimized commands, optimized commands do it inside thier internal loop. */ - if (!(sql_command_flags[lex->sql_command] & CF_SP_BULK_OPTIMIZED)) + if (!(sql_command_flags[lex->sql_command] & CF_PS_ARRAY_BINDING_OPTIMIZED)) { if (set_bulk_parameters(TRUE)) { From 31201dcbaf0f35a4fccb83855c1e1157f9532b31 Mon Sep 17 00:00:00 2001 From: Julius Goryavsky Date: Tue, 13 Oct 2020 13:33:47 +0200 Subject: [PATCH 124/323] MDEV-21770: `galera_3nodes.galera_ipv6_mariabackup` fails This patch fixes several flaws in the SST scripts that cause failures while running tests that use version 6 IP addresses for cluster nodes. First, if the netcat utility is used for streaming (but not socat), then in accordance with its command line syntax, we need to remove the square brackets around the IPv6 address. However, for socat, the address must contain square brackets, as before. Secondly, if an IPv6 address is used, then from the joiner side for a number of systems (such as Debian) we need to explicitly specify the "-6" option, otherwise a listening socket with an IPv6 address may not be created. This patch also contains code improvements in the wsrep_sst_common. Changed the code that pars the connection address - fixed the shortcomings that sometimes led to incorrect parsing of parameters when using shells other than the latest versions of bash. Also, this patch removes the duplicate code that is intended for parsing the connection address and which was located in the wsrep_sst_mariabackup file, since all the necessary actions have already been done in wsrep_sst_common and there they are done in such a way that any shell is supported, not just bash. The fix does not require separate tests, since all the necessary tests are already present in the galera_3nodes suite. On the contrary, after this fix, tests using IPv6 addresses can be removed from the disabled list (this will be done in a separate commit related to MDEV-23659). --- .../t/galera_ipv6_mariabackup.cnf | 5 ++ scripts/wsrep_sst_common.sh | 46 +++++++++++++- scripts/wsrep_sst_mariabackup.sh | 63 ++++++++++--------- 3 files changed, 83 insertions(+), 31 deletions(-) diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.cnf b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.cnf index 3861b17557d..8432b1c368c 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.cnf +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.cnf @@ -10,6 +10,7 @@ wsrep-cluster-address=gcomm:// wsrep_provider_options='base_host=[::1];base_port=@mysqld.1.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.1.#galera_port;ist.recv_addr=[::1]:@mysqld.1.#ist_port' wsrep_sst_receive_address='[::1]:@mysqld.1.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.1.port' +wsrep_node_name=node_1 bind-address=:: [mysqld.2] @@ -17,6 +18,8 @@ wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port' wsrep_provider_options='base_host=[::1];base_port=@mysqld.2.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.2.#galera_port;ist.recv_addr=[::1]:@mysqld.2.#ist_port' wsrep_sst_receive_address='[::1]:@mysqld.2.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.2.port' +wsrep_node_name=node_2 +wsrep_sst_donor=node_1 bind-address=:: [mysqld.3] @@ -24,6 +27,8 @@ wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port' wsrep_provider_options='base_host=[::1];base_port=@mysqld.3.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.3.#galera_port;ist.recv_addr=[::1]:@mysqld.3.#ist_port' wsrep_sst_receive_address='[::1]:@mysqld.3.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.3.port' +wsrep_node_name=node_3 +wsrep_sst_donor=node_1 bind-address=:: [SST] diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh index ee7817a1550..f5adf0b0fd8 100644 --- a/scripts/wsrep_sst_common.sh +++ b/scripts/wsrep_sst_common.sh @@ -45,28 +45,68 @@ case "$1" in case "${WSREP_SST_OPT_ADDR}" in \[*) # IPv6 + # Remove the starting and ending square brackets, if present: addr_no_bracket=${WSREP_SST_OPT_ADDR#\[} readonly WSREP_SST_OPT_HOST_UNESCAPED=${addr_no_bracket%%\]*} + # Square brackets are needed in most cases: readonly WSREP_SST_OPT_HOST="[${WSREP_SST_OPT_HOST_UNESCAPED}]" + # Some utilities and subsequent code require an address + # without square brackets: readonly WSREP_SST_OPT_HOST_ESCAPED="\\[${WSREP_SST_OPT_HOST_UNESCAPED}\\]" + readonly WSREP_SST_OPT_HOST_IPv6=1 ;; *) readonly WSREP_SST_OPT_HOST=${WSREP_SST_OPT_ADDR%%[:/]*} readonly WSREP_SST_OPT_HOST_UNESCAPED=$WSREP_SST_OPT_HOST readonly WSREP_SST_OPT_HOST_ESCAPED=$WSREP_SST_OPT_HOST + readonly WSREP_SST_OPT_HOST_IPv6=0 ;; esac + # Let's remove the leading part that contains the host address: remain=${WSREP_SST_OPT_ADDR#${WSREP_SST_OPT_HOST_ESCAPED}} + # 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): readonly WSREP_SST_OPT_ADDR_PORT=${remain%%/*} - remain=${remain#*/} - readonly WSREP_SST_OPT_MODULE=${remain%%/*} - readonly WSREP_SST_OPT_PATH=${WSREP_SST_OPT_ADDR#*/} + # If the "/" character is present, then the path is not empty: + if [ "${remain#*/}" != "${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 + # The rest of the string is the same as the path (for now): + remain=${WSREP_SST_OPT_PATH} + # If there is one more "/" in the string, then everything before + # it will be the module name, otherwise the module name is empty: + if [ "${remain%%/*}" != "${remain}" ]; then + # This operation removes the tail after the very first + # occurrence of the "/" character (inclusively): + readonly WSREP_SST_OPT_MODULE=${remain%%/*} + else + readonly WSREP_SST_OPT_MODULE="" + fi + # Remove the module name part from the string, which ends with "/": remain=${WSREP_SST_OPT_PATH#*/} + # If the rest of the string does not match the original, then there + # was something else besides the module name: 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=${remain%%/*} + # Exctract everything after the first occurrence of + # the "/" character in the string: remain=${remain#*/} + # If the remainder does not match the original string, + # then there is something else (the version number in + # our case): if [ "$remain" != "${WSREP_SST_OPT_LSN}" ]; 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=${remain%%/*} else readonly WSREP_SST_OPT_SST_VER="" diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh index ef2a3b66de8..85138c3c0be 100644 --- a/scripts/wsrep_sst_mariabackup.sh +++ b/scripts/wsrep_sst_mariabackup.sh @@ -189,27 +189,48 @@ get_transfer() if nc -h 2>&1 | grep -q ncat;then # Ncat tcmd="nc -l ${TSST_PORT}" - elif nc -h 2>&1 | grep -q -- '-d\>';then + elif nc -h 2>&1 | grep -qw -- '-d\>';then # Debian netcat - tcmd="nc -dl ${TSST_PORT}" + 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="nc -dl -6 ${TSST_PORT}" + else + tcmd="nc -dl ${TSST_PORT}" + fi else # traditional netcat tcmd="nc -l -p ${TSST_PORT}" fi 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. + # + tcmd_extra="" + if nc -h 2>&1 | grep -qw -- -N; then + tcmd_extra+="-N" + wsrep_log_info "Using nc -N" + fi + + # netcat doesn't understand [] around IPv6 address if nc -h 2>&1 | grep -q ncat;then # Ncat - tcmd="nc ${REMOTEIP} ${TSST_PORT}" - elif nc -h 2>&1 | grep -q -- '-d\>';then + wsrep_log_info "Using Ncat as streamer" + tcmd="nc ${tcmd_extra} ${WSREP_SST_OPT_HOST_UNESCAPED} ${TSST_PORT}" + elif nc -h 2>&1 | grep -qw -- '-d\>';then # Debian netcat - if nc -h 2>&1 | grep -q -- '-N\>';then - tcmd="nc -N ${REMOTEIP} ${TSST_PORT}" - else - tcmd="nc ${REMOTEIP} ${TSST_PORT}" - fi + wsrep_log_info "Using Debian netcat as streamer" + tcmd="nc ${tcmd_extra} ${WSREP_SST_OPT_HOST_UNESCAPED} ${TSST_PORT}" else # traditional netcat - tcmd="nc -q0 ${REMOTEIP} ${TSST_PORT}" + wsrep_log_info "Using traditional netcat as streamer" + tcmd="nc -q0 ${tcmd_extra} ${WSREP_SST_OPT_HOST_UNESCAPED} ${TSST_PORT}" fi fi else @@ -527,25 +548,11 @@ kill_xtrabackup() setup_ports() { + SST_PORT=${WSREP_SST_OPT_ADDR_PORT} if [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then - if [ "${WSREP_SST_OPT_ADDR#\[}" != "$WSREP_SST_OPT_ADDR" ]; then - remain=$(echo $WSREP_SST_OPT_ADDR | awk -F '\\][:/]' '{ print $2 }') - REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F '\\]:' '{ print $1 }')"]" - SST_PORT=$(echo $remain | awk -F '[:/]' '{ print $1 }') - lsn=$(echo $remain | awk -F '[:/]' '{ print $3 }') - sst_ver=$(echo $remain | awk -F '[:/]' '{ print $4 }') - else - SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }') - REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }') - lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }') - sst_ver=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $5 }') - fi - else - if [ "${WSREP_SST_OPT_ADDR#\[}" != "$WSREP_SST_OPT_ADDR" ]; then - SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F '\\]:' '{ print $2 }') - else - SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }') - fi + REMOTEIP=${WSREP_SST_OPT_HOST} + lsn=${WSREP_SST_OPT_LSN} + sst_ver=${WSREP_SST_OPT_SST_VER} fi } From ebb39bc59c9e9faa35d7f87e4de71a2467052447 Mon Sep 17 00:00:00 2001 From: Julius Goryavsky Date: Tue, 13 Oct 2020 13:37:33 +0200 Subject: [PATCH 125/323] MDEV-23659: Update Galera disabled.def file This fix removes from the list of disabled tests all tests that were fixed by the patch for MDEV-21770. --- mysql-test/suite/galera_3nodes/disabled.def | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mysql-test/suite/galera_3nodes/disabled.def b/mysql-test/suite/galera_3nodes/disabled.def index ff7262947a0..0e2706f2dc3 100644 --- a/mysql-test/suite/galera_3nodes/disabled.def +++ b/mysql-test/suite/galera_3nodes/disabled.def @@ -11,11 +11,6 @@ ############################################################################## galera_gtid_2_cluster : MDEV-23775 Galera test failure on galera_3nodes.galera_gtid_2_cluster -galera_ipv6_mariabackup : MDEV-21770 galera_3nodes.galera_ipv6_mariabackup fails -galera_ipv6_mariabackup_section : MDEV-21770 galera_3nodes.galera_ipv6_mariabackup fails -galera_ipv6_mysqldump : MDEV-23576 galera_3nodes.galera_ipv6_mysqldump MTR failed: WSREP_SST: [ERROR] rsync daemon port '16008' has been taken -galera_ipv6_rsync : MDEV-23581 galera_3nodes.galera_ipv6_rsync MTR failed: WSREP_SST: [ERROR] rsync daemon port '16008' has been taken -galera_ipv6_rsync_section : MDEV-23580 galera_3nodes.galera_ipv6_rsync_section MTR failed: WSREP_SST: [ERROR] rsync daemon port '16008' has been taken galera_ist_gcache_rollover : MDEV-23578 WSREP: exception caused by message: {v=0,t=1,ut=255,o=4,s=0,sr=0,as=1,f=6,src=50524cfe,srcvid=view_id(REG,50524cfe,4),insvid=view_id(UNKNOWN,00000000,0),ru=00000000,r=[-1,-1],fs=75,nl=(} galera_slave_options_do :MDEV-8798 galera_slave_options_ignore : MDEV-8798 From 7cffb5f6e8a231a041152447be8980ce35d2c9b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 15 Oct 2020 12:10:42 +0300 Subject: [PATCH 126/323] MDEV-23399: Performance regression with write workloads The buffer pool refactoring in MDEV-15053 and MDEV-22871 shifted the performance bottleneck to the page flushing. The configuration parameters will be changed as follows: innodb_lru_flush_size=32 (new: how many pages to flush on LRU eviction) innodb_lru_scan_depth=1536 (old: 1024) innodb_max_dirty_pages_pct=90 (old: 75) innodb_max_dirty_pages_pct_lwm=75 (old: 0) Note: The parameter innodb_lru_scan_depth will only affect LRU eviction of buffer pool pages when a new page is being allocated. The page cleaner thread will no longer evict any pages. It used to guarantee that some pages will remain free in the buffer pool. Now, we perform that eviction 'on demand' in buf_LRU_get_free_block(). The parameter innodb_lru_scan_depth(srv_LRU_scan_depth) is used as follows: * When the buffer pool is being shrunk in buf_pool_t::withdraw_blocks() * As a buf_pool.free limit in buf_LRU_list_batch() for terminating the flushing that is initiated e.g., by buf_LRU_get_free_block() The parameter also used to serve as an initial limit for unzip_LRU eviction (evicting uncompressed page frames while retaining ROW_FORMAT=COMPRESSED pages), but now we will use a hard-coded limit of 100 or unlimited for invoking buf_LRU_scan_and_free_block(). The status variables will be changed as follows: innodb_buffer_pool_pages_flushed: This includes also the count of innodb_buffer_pool_pages_LRU_flushed and should work reliably, updated one by one in buf_flush_page() to give more real-time statistics. The function buf_flush_stats(), which we are removing, was not called in every code path. For both counters, we will use regular variables that are incremented in a critical section of buf_pool.mutex. Note that show_innodb_vars() directly links to the variables, and reads of the counters will *not* be protected by buf_pool.mutex, so you cannot get a consistent snapshot of both variables. The following INFORMATION_SCHEMA.INNODB_METRICS counters will be removed, because the page cleaner no longer deals with writing or evicting least recently used pages, and because the single-page writes have been removed: * buffer_LRU_batch_flush_avg_time_slot * buffer_LRU_batch_flush_avg_time_thread * buffer_LRU_batch_flush_avg_time_est * buffer_LRU_batch_flush_avg_pass * buffer_LRU_single_flush_scanned * buffer_LRU_single_flush_num_scan * buffer_LRU_single_flush_scanned_per_call When moving to a single buffer pool instance in MDEV-15058, we missed some opportunity to simplify the buf_flush_page_cleaner thread. It was unnecessarily using a mutex and some complex data structures, even though we always have a single page cleaner thread. Furthermore, the buf_flush_page_cleaner thread had separate 'recovery' and 'shutdown' modes where it was waiting to be triggered by some other thread, adding unnecessary latency and potential for hangs in relatively rarely executed startup or shutdown code. The page cleaner was also running two kinds of batches in an interleaved fashion: "LRU flush" (writing out some least recently used pages and evicting them on write completion) and the normal batches that aim to increase the MIN(oldest_modification) in the buffer pool, to help the log checkpoint advance. The buf_pool.flush_list flushing was being blocked by buf_block_t::lock for no good reason. Furthermore, if the FIL_PAGE_LSN of a page is ahead of log_sys.get_flushed_lsn(), that is, what has been persistently written to the redo log, we would trigger a log flush and then resume the page flushing. This would unnecessarily limit the performance of the page cleaner thread and trigger the infamous messages "InnoDB: page_cleaner: 1000ms intended loop took 4450ms. The settings might not be optimal" that were suppressed in commit d1ab89037a518fcffbc50c24e4bd94e4ec33aed0 unless log_warnings>2. Our revised algorithm will make log_sys.get_flushed_lsn() advance at the start of buf_flush_lists(), and then execute a 'best effort' to write out all pages. The flush batches will skip pages that were modified since the log was written, or are are currently exclusively locked. The MDEV-13670 message "page_cleaner: 1000ms intended loop took" message will be removed, because by design, the buf_flush_page_cleaner() should not be blocked during a batch for extended periods of time. We will remove the single-page flushing altogether. Related to this, the debug parameter innodb_doublewrite_batch_size will be removed, because all of the doublewrite buffer will be used for flushing batches. If a page needs to be evicted from the buffer pool and all 100 least recently used pages in the buffer pool have unflushed changes, buf_LRU_get_free_block() will execute buf_flush_lists() to write out and evict innodb_lru_flush_size pages. At most one thread will execute buf_flush_lists() in buf_LRU_get_free_block(); other threads will wait for that LRU flushing batch to finish. To improve concurrency, we will replace the InnoDB ib_mutex_t and os_event_t native mutexes and condition variables in this area of code. Most notably, this means that the buffer pool mutex (buf_pool.mutex) is no longer instrumented via any InnoDB interfaces. It will continue to be instrumented via PERFORMANCE_SCHEMA. For now, both buf_pool.flush_list_mutex and buf_pool.mutex will be declared with MY_MUTEX_INIT_FAST (PTHREAD_MUTEX_ADAPTIVE_NP). The critical sections of buf_pool.flush_list_mutex should be shorter than those for buf_pool.mutex, because in the worst case, they cover a linear scan of buf_pool.flush_list, while the worst case of a critical section of buf_pool.mutex covers a linear scan of the potentially much longer buf_pool.LRU list. mysql_mutex_is_owner(), safe_mutex_is_owner(): New predicate, usable with SAFE_MUTEX. Some InnoDB debug assertions need this predicate instead of mysql_mutex_assert_owner() or mysql_mutex_assert_not_owner(). buf_pool_t::n_flush_LRU, buf_pool_t::n_flush_list: Replaces buf_pool_t::init_flush[] and buf_pool_t::n_flush[]. The number of active flush operations. buf_pool_t::mutex, buf_pool_t::flush_list_mutex: Use mysql_mutex_t instead of ib_mutex_t, to have native mutexes with PERFORMANCE_SCHEMA and SAFE_MUTEX instrumentation. buf_pool_t::done_flush_LRU: Condition variable for !n_flush_LRU. buf_pool_t::done_flush_list: Condition variable for !n_flush_list. buf_pool_t::do_flush_list: Condition variable to wake up the buf_flush_page_cleaner when a log checkpoint needs to be written or the server is being shut down. Replaces buf_flush_event. We will keep using timed waits (the page cleaner thread will wake _at least_ once per second), because the calculations for innodb_adaptive_flushing depend on fixed time intervals. buf_dblwr: Allocate statically, and move all code to member functions. Use a native mutex and condition variable. Remove code to deal with single-page flushing. buf_dblwr_check_block(): Make the check debug-only. We were spending a significant amount of execution time in page_simple_validate_new(). flush_counters_t::unzip_LRU_evicted: Remove. IORequest: Make more members const. FIXME: m_fil_node should be removed. buf_flush_sync_lsn: Protect by std::atomic, not page_cleaner.mutex (which we are removing). page_cleaner_slot_t, page_cleaner_t: Remove many redundant members. pc_request_flush_slot(): Replaces pc_request() and pc_flush_slot(). recv_writer_thread: Remove. Recovery works just fine without it, if we simply invoke buf_flush_sync() at the end of each batch in recv_sys_t::apply(). recv_recovery_from_checkpoint_finish(): Remove. We can simply call recv_sys.debug_free() directly. srv_started_redo: Replaces srv_start_state. SRV_SHUTDOWN_FLUSH_PHASE: Remove. logs_empty_and_mark_files_at_shutdown() can communicate with the normal page cleaner loop via the new function flush_buffer_pool(). buf_flush_remove(): Assert that the calling thread is holding buf_pool.flush_list_mutex. This removes unnecessary mutex operations from buf_flush_remove_pages() and buf_flush_dirty_pages(), which replace buf_LRU_flush_or_remove_pages(). buf_flush_lists(): Renamed from buf_flush_batch(), with simplified interface. Return the number of flushed pages. Clarified comments and renamed min_n to max_n. Identify LRU batch by lsn=0. Merge all the functions buf_flush_start(), buf_flush_batch(), buf_flush_end() directly to this function, which was their only caller, and remove 2 unnecessary buf_pool.mutex release/re-acquisition that we used to perform around the buf_flush_batch() call. At the start, if not all log has been durably written, wait for a background task to do it, or start a new task to do it. This allows the log write to run concurrently with our page flushing batch. Any pages that were skipped due to too recent FIL_PAGE_LSN or due to them being latched by a writer should be flushed during the next batch, unless there are further modifications to those pages. It is possible that a page that we must flush due to small oldest_modification also carries a recent FIL_PAGE_LSN or is being constantly modified. In the worst case, all writers would then end up waiting in log_free_check() to allow the flushing and the checkpoint to complete. buf_do_flush_list_batch(): Clarify comments, and rename min_n to max_n. Cache the last looked up tablespace. If neighbor flushing is not applicable, invoke buf_flush_page() directly, avoiding a page lookup in between. buf_flush_space(): Auxiliary function to look up a tablespace for page flushing. buf_flush_page(): Defer the computation of space->full_crc32(). Never call log_write_up_to(), but instead skip persistent pages whose latest modification (FIL_PAGE_LSN) is newer than the redo log. Also skip pages on which we cannot acquire a shared latch without waiting. buf_flush_try_neighbors(): Do not bother checking buf_fix_count because buf_flush_page() will no longer wait for the page latch. Take the tablespace as a parameter, and only execute this function when innodb_flush_neighbors>0. Avoid repeated calls of page_id_t::fold(). buf_flush_relocate_on_flush_list(): Declare as cold, and push down a condition from the callers. buf_flush_check_neighbor(): Take id.fold() as a parameter. buf_flush_sync(): Ensure that the buf_pool.flush_list is empty, because the flushing batch will skip pages whose modifications have not yet been written to the log or were latched for modification. buf_free_from_unzip_LRU_list_batch(): Remove redundant local variables. buf_flush_LRU_list_batch(): Let the caller buf_do_LRU_batch() initialize the counters, and report n->evicted. Cache the last looked up tablespace. If neighbor flushing is not applicable, invoke buf_flush_page() directly, avoiding a page lookup in between. buf_do_LRU_batch(): Return the number of pages flushed. buf_LRU_free_page(): Only release and re-acquire buf_pool.mutex if adaptive hash index entries are pointing to the block. buf_LRU_get_free_block(): Do not wake up the page cleaner, because it will no longer perform any useful work for us, and we do not want it to compete for I/O while buf_flush_lists(innodb_lru_flush_size, 0) writes out and evicts at most innodb_lru_flush_size pages. (The function buf_do_LRU_batch() may complete after writing fewer pages if more than innodb_lru_scan_depth pages end up in buf_pool.free list.) Eliminate some mutex release-acquire cycles, and wait for the LRU flush batch to complete before rescanning. buf_LRU_check_size_of_non_data_objects(): Simplify the code. buf_page_write_complete(): Remove the parameter evict, and always evict pages that were part of an LRU flush. buf_page_create(): Take a pre-allocated page as a parameter. buf_pool_t::free_block(): Free a pre-allocated block. recv_sys_t::recover_low(), recv_sys_t::apply(): Preallocate the block while not holding recv_sys.mutex. During page allocation, we may initiate a page flush, which in turn may initiate a log flush, which would require acquiring log_sys.mutex, which should always be acquired before recv_sys.mutex in order to avoid deadlocks. Therefore, we must not be holding recv_sys.mutex while allocating a buffer pool block. BtrBulk::logFreeCheck(): Skip a redundant condition. row_undo_step(): Do not invoke srv_inc_activity_count() for every row that is being rolled back. It should suffice to invoke the function in trx_flush_log_if_needed() during trx_t::commit_in_memory() when the rollback completes. sync_check_enable(): Remove. We will enable innodb_sync_debug from the very beginning. Reviewed by: Vladislav Vaintroub --- extra/mariabackup/xtrabackup.cc | 6 +- include/my_pthread.h | 10 +- include/mysql/psi/mysql_thread.h | 2 + .../t/innodb_encryption_discard_import.opt | 3 +- .../suite/innodb/r/ibuf_not_empty.result | 20 +- .../r/innodb-change-buffer-recovery.result | 2 +- .../r/innodb_skip_innodb_is_tables.result | 7 - mysql-test/suite/innodb/r/monitor.result | 7 - .../suite/innodb/r/purge_secondary.result | 4 - .../innodb/t/ibuf_not_empty.combinations | 4 + mysql-test/suite/innodb/t/ibuf_not_empty.test | 24 +- .../t/innodb-change-buffer-recovery.test | 2 +- .../suite/innodb/t/purge_secondary.test | 3 - .../suite/perfschema/t/show_sanity.test | 1 - ...innodb_doublewrite_batch_size_basic.result | 24 - .../r/innodb_max_dirty_pages_pct_basic.result | 8 +- .../r/innodb_max_dirty_pages_pct_func.result | 34 +- ...nnodb_max_dirty_pages_pct_lwm_basic.result | 8 +- .../sys_vars/r/sysvars_innodb,32bit.rdiff | 60 +- .../suite/sys_vars/r/sysvars_innodb.result | 30 +- .../innodb_doublewrite_batch_size_basic.test | 24 - .../t/innodb_max_dirty_pages_pct_func.test | 17 +- storage/innobase/btr/btr0bulk.cc | 4 +- storage/innobase/btr/btr0cur.cc | 6 +- storage/innobase/btr/btr0sea.cc | 16 +- storage/innobase/buf/buf0buddy.cc | 20 +- storage/innobase/buf/buf0buf.cc | 272 +-- storage/innobase/buf/buf0dblwr.cc | 1448 +++++-------- storage/innobase/buf/buf0dump.cc | 8 +- storage/innobase/buf/buf0flu.cc | 1891 ++++++----------- storage/innobase/buf/buf0lru.cc | 574 ++--- storage/innobase/buf/buf0rea.cc | 10 +- storage/innobase/fil/fil0crypt.cc | 35 +- storage/innobase/fil/fil0fil.cc | 56 +- storage/innobase/fsp/fsp0file.cc | 9 +- storage/innobase/fsp/fsp0fsp.cc | 28 +- storage/innobase/fsp/fsp0sysspace.cc | 2 +- storage/innobase/handler/ha_innodb.cc | 40 +- storage/innobase/handler/i_s.cc | 12 +- storage/innobase/include/buf0buf.h | 159 +- storage/innobase/include/buf0buf.ic | 14 +- storage/innobase/include/buf0dblwr.h | 187 +- storage/innobase/include/buf0flu.h | 101 +- storage/innobase/include/buf0lru.h | 39 +- storage/innobase/include/buf0types.h | 9 +- storage/innobase/include/fil0fil.h | 14 +- storage/innobase/include/log0recv.h | 12 +- storage/innobase/include/os0file.h | 84 +- storage/innobase/include/srv0mon.h | 8 - storage/innobase/include/srv0srv.h | 6 - storage/innobase/include/srv0start.h | 5 - storage/innobase/include/sync0debug.h | 6 +- storage/innobase/include/sync0sync.h | 1 - storage/innobase/include/sync0types.h | 12 +- storage/innobase/include/trx0sys.h | 5 +- storage/innobase/log/log0log.cc | 116 +- storage/innobase/log/log0recv.cc | 64 +- storage/innobase/os/os0file.cc | 7 +- storage/innobase/row/row0import.cc | 18 +- storage/innobase/row/row0log.cc | 13 +- storage/innobase/row/row0merge.cc | 6 +- storage/innobase/row/row0mysql.cc | 3 +- storage/innobase/row/row0quiesce.cc | 17 +- storage/innobase/row/row0sel.cc | 6 +- storage/innobase/row/row0undo.cc | 8 +- storage/innobase/row/row0upd.cc | 2 +- storage/innobase/srv/srv0mon.cc | 40 +- storage/innobase/srv/srv0srv.cc | 16 - storage/innobase/srv/srv0start.cc | 90 +- storage/innobase/sync/sync0debug.cc | 29 +- storage/innobase/sync/sync0sync.cc | 1 - storage/innobase/trx/trx0purge.cc | 4 +- .../r/innodb_i_s_tables_disabled.result | 7 - 73 files changed, 2014 insertions(+), 3826 deletions(-) delete mode 100644 mysql-test/suite/sys_vars/r/innodb_doublewrite_batch_size_basic.result delete mode 100644 mysql-test/suite/sys_vars/t/innodb_doublewrite_batch_size_basic.test diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 7fd5efe2cd5..3da6239b6f8 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -3426,9 +3426,7 @@ xb_data_files_close() { ut_ad(!os_thread_count); fil_close_all_files(); - if (buf_dblwr) { - buf_dblwr_free(); - } + buf_dblwr.close(); } /*********************************************************************** @@ -4017,7 +4015,6 @@ fail: } srv_thread_pool_init(); sync_check_init(); - ut_d(sync_check_enable()); /* Reset the system variables in the recovery module. */ trx_pool_init(); recv_sys.create(); @@ -5385,7 +5382,6 @@ static bool xtrabackup_prepare_func(char** argv) } sync_check_init(); - ut_d(sync_check_enable()); recv_sys.create(); log_sys.create(); recv_sys.recovery_on = true; diff --git a/include/my_pthread.h b/include/my_pthread.h index 4888bfcc2c8..66876032178 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -427,12 +427,10 @@ void safe_mutex_free_deadlock_data(safe_mutex_t *mp); #define MYF_NO_DEADLOCK_DETECTION 2 #ifdef SAFE_MUTEX -#define safe_mutex_assert_owner(mp) \ - DBUG_ASSERT((mp)->count > 0 && \ - pthread_equal(pthread_self(), (mp)->thread)) -#define safe_mutex_assert_not_owner(mp) \ - DBUG_ASSERT(! (mp)->count || \ - ! pthread_equal(pthread_self(), (mp)->thread)) +#define safe_mutex_is_owner(mp) ((mp)->count > 0 && \ + pthread_equal(pthread_self(), (mp)->thread)) +#define safe_mutex_assert_owner(mp) DBUG_ASSERT(safe_mutex_is_owner(mp)) +#define safe_mutex_assert_not_owner(mp) DBUG_ASSERT(!safe_mutex_is_owner(mp)) #define safe_mutex_setflags(mp, F) do { (mp)->create_flags|= (F); } while (0) #define my_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__) #define my_cond_wait(A,B) safe_cond_wait((A), (B), __FILE__, __LINE__) diff --git a/include/mysql/psi/mysql_thread.h b/include/mysql/psi/mysql_thread.h index 711520dba78..47f89f76685 100644 --- a/include/mysql/psi/mysql_thread.h +++ b/include/mysql/psi/mysql_thread.h @@ -1,4 +1,5 @@ /* Copyright (c) 2008, 2013, Oracle and/or its affiliates. + Copyright (c) 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, version 2.0, @@ -262,6 +263,7 @@ typedef struct st_mysql_cond mysql_cond_t; */ #ifndef DISABLE_MYSQL_THREAD_H +#define mysql_mutex_is_owner(M) safe_mutex_is_owner(&(M)->m_mutex) /** @def mysql_mutex_assert_owner(M) Wrapper, to use safe_mutex_assert_owner with instrumented mutexes. diff --git a/mysql-test/suite/encryption/t/innodb_encryption_discard_import.opt b/mysql-test/suite/encryption/t/innodb_encryption_discard_import.opt index bcff011eb82..9fe990f7260 100644 --- a/mysql-test/suite/encryption/t/innodb_encryption_discard_import.opt +++ b/mysql-test/suite/encryption/t/innodb_encryption_discard_import.opt @@ -3,6 +3,5 @@ --innodb-encryption-rotate-key-age=15 --innodb-encryption-threads=4 --innodb-tablespaces-encryption +--innodb-max-dirty-pages-pct_lwm=0 --innodb-max-dirty-pages-pct=0.001 - - diff --git a/mysql-test/suite/innodb/r/ibuf_not_empty.result b/mysql-test/suite/innodb/r/ibuf_not_empty.result index 3382c74174e..d1b8203b063 100644 --- a/mysql-test/suite/innodb/r/ibuf_not_empty.result +++ b/mysql-test/suite/innodb/r/ibuf_not_empty.result @@ -1,4 +1,3 @@ -SET GLOBAL innodb_purge_rseg_truncate_frequency=1; CREATE TABLE t1( a INT AUTO_INCREMENT PRIMARY KEY, b CHAR(1), @@ -6,26 +5,11 @@ c INT, INDEX(b)) ENGINE=InnoDB STATS_PERSISTENT=0; SET GLOBAL innodb_change_buffering_debug = 1; -BEGIN; -INSERT INTO t1 VALUES(0,'x',1); -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -COMMIT; -InnoDB 0 transactions not purged +INSERT INTO t1 SELECT 0,'x',1 FROM seq_1_to_1024; # restart: --innodb-force-recovery=6 --innodb-change-buffer-dump check table t1; Table Op Msg_type Msg_text -test.t1 check Warning InnoDB: Index 'b' contains #### entries, should be 4096. +test.t1 check Warning InnoDB: Index 'b' contains 990 entries, should be 1024. test.t1 check error Corrupt # restart SET GLOBAL innodb_fast_shutdown=0; diff --git a/mysql-test/suite/innodb/r/innodb-change-buffer-recovery.result b/mysql-test/suite/innodb/r/innodb-change-buffer-recovery.result index d795b516d5e..678c8c67be5 100644 --- a/mysql-test/suite/innodb/r/innodb-change-buffer-recovery.result +++ b/mysql-test/suite/innodb/r/innodb-change-buffer-recovery.result @@ -50,5 +50,5 @@ Table Op Msg_type Msg_text test.t1 check status OK SHOW ENGINE INNODB STATUS; Type Name Status -InnoDB insert 79, delete mark 1 +InnoDB DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/innodb_skip_innodb_is_tables.result b/mysql-test/suite/innodb/r/innodb_skip_innodb_is_tables.result index 9ab72408274..6a597a919e1 100644 --- a/mysql-test/suite/innodb/r/innodb_skip_innodb_is_tables.result +++ b/mysql-test/suite/innodb/r/innodb_skip_innodb_is_tables.result @@ -90,14 +90,10 @@ buffer_flush_neighbor_pages buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL N buffer_flush_n_to_flush_requested buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of pages requested for flushing. buffer_flush_n_to_flush_by_age buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of pages target by LSN Age for flushing. buffer_flush_adaptive_avg_time_slot buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for adaptive flushing recently per slot. -buffer_LRU_batch_flush_avg_time_slot buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for LRU batch flushing recently per slot. buffer_flush_adaptive_avg_time_thread buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for adaptive flushing recently per thread. -buffer_LRU_batch_flush_avg_time_thread buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for LRU batch flushing recently per thread. buffer_flush_adaptive_avg_time_est buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Estimated time (ms) spent for adaptive flushing recently. -buffer_LRU_batch_flush_avg_time_est buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Estimated time (ms) spent for LRU batch flushing recently. buffer_flush_avg_time buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for flushing recently. buffer_flush_adaptive_avg_pass buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of adaptive flushes passed during the recent Avg period. -buffer_LRU_batch_flush_avg_pass buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of LRU batch flushes passed during the recent Avg period. buffer_flush_avg_pass buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of flushes passed during the recent Avg period. buffer_LRU_get_free_loops buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Total loops in LRU get free. buffer_LRU_get_free_waits buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Total sleep waits in LRU get free. @@ -124,9 +120,6 @@ buffer_LRU_batch_flush_pages buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL buffer_LRU_batch_evict_total_pages buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_owner Total pages evicted as part of LRU batches buffer_LRU_batches_evict buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_member Number of LRU batches buffer_LRU_batch_evict_pages buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_member Pages queued as an LRU batch -buffer_LRU_single_flush_scanned buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_owner Total pages scanned as part of single page LRU flush -buffer_LRU_single_flush_num_scan buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_member Number of times single page LRU flush is called -buffer_LRU_single_flush_scanned_per_call buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_member Page scanned per single LRU flush buffer_LRU_single_flush_failure_count Buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of times attempt to flush a single page from LRU failed buffer_LRU_get_free_search Buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of searches performed for a clean page buffer_LRU_search_scanned buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_owner Total pages scanned as part of LRU search diff --git a/mysql-test/suite/innodb/r/monitor.result b/mysql-test/suite/innodb/r/monitor.result index 0c0168fb266..4aeab1a8402 100644 --- a/mysql-test/suite/innodb/r/monitor.result +++ b/mysql-test/suite/innodb/r/monitor.result @@ -56,14 +56,10 @@ buffer_flush_neighbor_pages disabled buffer_flush_n_to_flush_requested disabled buffer_flush_n_to_flush_by_age disabled buffer_flush_adaptive_avg_time_slot disabled -buffer_LRU_batch_flush_avg_time_slot disabled buffer_flush_adaptive_avg_time_thread disabled -buffer_LRU_batch_flush_avg_time_thread disabled buffer_flush_adaptive_avg_time_est disabled -buffer_LRU_batch_flush_avg_time_est disabled buffer_flush_avg_time disabled buffer_flush_adaptive_avg_pass disabled -buffer_LRU_batch_flush_avg_pass disabled buffer_flush_avg_pass disabled buffer_LRU_get_free_loops disabled buffer_LRU_get_free_waits disabled @@ -90,9 +86,6 @@ buffer_LRU_batch_flush_pages disabled buffer_LRU_batch_evict_total_pages disabled buffer_LRU_batches_evict disabled buffer_LRU_batch_evict_pages disabled -buffer_LRU_single_flush_scanned disabled -buffer_LRU_single_flush_num_scan disabled -buffer_LRU_single_flush_scanned_per_call disabled buffer_LRU_single_flush_failure_count disabled buffer_LRU_get_free_search disabled buffer_LRU_search_scanned disabled diff --git a/mysql-test/suite/innodb/r/purge_secondary.result b/mysql-test/suite/innodb/r/purge_secondary.result index 7c2b4151e76..a583e46418d 100644 --- a/mysql-test/suite/innodb/r/purge_secondary.result +++ b/mysql-test/suite/innodb/r/purge_secondary.result @@ -148,10 +148,6 @@ SELECT (variable_value > 0) FROM information_schema.global_status WHERE LOWER(variable_name) LIKE 'INNODB_BUFFER_POOL_PAGES_FLUSHED'; (variable_value > 0) 1 -SELECT NAME, SUBSYSTEM FROM INFORMATION_SCHEMA.INNODB_METRICS -WHERE NAME="buffer_LRU_batch_evict_total_pages" AND COUNT > 0; -NAME SUBSYSTEM -buffer_LRU_batch_evict_total_pages buffer # Note: The OTHER_INDEX_SIZE does not cover any SPATIAL INDEX. # To test that all indexes were emptied, replace DROP TABLE # with the following, and examine the root pages in t1.ibd: diff --git a/mysql-test/suite/innodb/t/ibuf_not_empty.combinations b/mysql-test/suite/innodb/t/ibuf_not_empty.combinations index 729380593f3..c4b45dcca32 100644 --- a/mysql-test/suite/innodb/t/ibuf_not_empty.combinations +++ b/mysql-test/suite/innodb/t/ibuf_not_empty.combinations @@ -1,5 +1,9 @@ [strict_crc32] --innodb-checksum-algorithm=strict_crc32 +--innodb-page-size=4k +--innodb-force-recovery=2 [strict_full_crc32] --innodb-checksum-algorithm=strict_full_crc32 +--innodb-page-size=4k +--innodb-force-recovery=2 diff --git a/mysql-test/suite/innodb/t/ibuf_not_empty.test b/mysql-test/suite/innodb/t/ibuf_not_empty.test index a3f4ad9ac5c..3b254177497 100644 --- a/mysql-test/suite/innodb/t/ibuf_not_empty.test +++ b/mysql-test/suite/innodb/t/ibuf_not_empty.test @@ -3,10 +3,8 @@ --source include/have_debug.inc # Embedded server tests do not support restarting --source include/not_embedded.inc -# The test is not big enough to use change buffering with larger page size. ---source include/have_innodb_max_16k.inc +--source include/have_sequence.inc -SET GLOBAL innodb_purge_rseg_truncate_frequency=1; --disable_query_log call mtr.add_suppression("InnoDB: Failed to find tablespace for table `test`\\.`t1` in the cache\\. Attempting to load the tablespace with space id"); call mtr.add_suppression("InnoDB: Allocated tablespace ID \\d+ for test.t1, old maximum was"); @@ -30,27 +28,10 @@ SET GLOBAL innodb_change_buffering_debug = 1; # Create enough rows for the table, so that the change buffer will be # used for modifying the secondary index page. There must be multiple # index pages, because changes to the root page are never buffered. -BEGIN; -INSERT INTO t1 VALUES(0,'x',1); -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -INSERT INTO t1 SELECT 0,b,c FROM t1; -COMMIT; +INSERT INTO t1 SELECT 0,'x',1 FROM seq_1_to_1024; let MYSQLD_DATADIR=`select @@datadir`; let PAGE_SIZE=`select @@innodb_page_size`; -# Ensure that purge will not access the truncated .ibd file ---source include/wait_all_purged.inc - --source include/shutdown_mysqld.inc # Corrupt the change buffer bitmap, to claim that pages are clean @@ -87,7 +68,6 @@ EOF --let $restart_parameters= --innodb-force-recovery=6 --innodb-change-buffer-dump --source include/start_mysqld.inc ---replace_regex /contains \d+ entries/contains #### entries/ check table t1; --source include/shutdown_mysqld.inc diff --git a/mysql-test/suite/innodb/t/innodb-change-buffer-recovery.test b/mysql-test/suite/innodb/t/innodb-change-buffer-recovery.test index 79d9cc814a0..a12ca43cec1 100644 --- a/mysql-test/suite/innodb/t/innodb-change-buffer-recovery.test +++ b/mysql-test/suite/innodb/t/innodb-change-buffer-recovery.test @@ -76,6 +76,6 @@ SET GLOBAL innodb_fast_shutdown=0; --let $restart_parameters= --source include/restart_mysqld.inc CHECK TABLE t1; -replace_regex /.*operations:.* (insert.*), delete \d.*discarded .*/\1/; +replace_regex /.*operations:.* insert [1-9][0-9]*, delete mark [1-9][0-9]*, delete \d.*discarded .*//; SHOW ENGINE INNODB STATUS; DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/purge_secondary.test b/mysql-test/suite/innodb/t/purge_secondary.test index 34b4ce06f5f..f2c85ce10e7 100644 --- a/mysql-test/suite/innodb/t/purge_secondary.test +++ b/mysql-test/suite/innodb/t/purge_secondary.test @@ -131,9 +131,6 @@ ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; SELECT (variable_value > 0) FROM information_schema.global_status WHERE LOWER(variable_name) LIKE 'INNODB_BUFFER_POOL_PAGES_FLUSHED'; -SELECT NAME, SUBSYSTEM FROM INFORMATION_SCHEMA.INNODB_METRICS -WHERE NAME="buffer_LRU_batch_evict_total_pages" AND COUNT > 0; - --echo # Note: The OTHER_INDEX_SIZE does not cover any SPATIAL INDEX. --echo # To test that all indexes were emptied, replace DROP TABLE --echo # with the following, and examine the root pages in t1.ibd: diff --git a/mysql-test/suite/perfschema/t/show_sanity.test b/mysql-test/suite/perfschema/t/show_sanity.test index 8f73c38eab8..61161ea5df6 100644 --- a/mysql-test/suite/perfschema/t/show_sanity.test +++ b/mysql-test/suite/perfschema/t/show_sanity.test @@ -422,7 +422,6 @@ insert into test.sanity values ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_DISABLE_RESIZE_BUFFER_POOL_DEBUG"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_DISABLE_SORT_FILE_CACHE"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_DOUBLEWRITE"), - ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_DOUBLEWRITE_BATCH_SIZE"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FAST_SHUTDOWN"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FILE_PER_TABLE"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_FILL_FACTOR"), diff --git a/mysql-test/suite/sys_vars/r/innodb_doublewrite_batch_size_basic.result b/mysql-test/suite/sys_vars/r/innodb_doublewrite_batch_size_basic.result deleted file mode 100644 index cec90ea8950..00000000000 --- a/mysql-test/suite/sys_vars/r/innodb_doublewrite_batch_size_basic.result +++ /dev/null @@ -1,24 +0,0 @@ -select @@global.innodb_doublewrite_batch_size between 1 and 127; -@@global.innodb_doublewrite_batch_size between 1 and 127 -1 -select @@global.innodb_doublewrite_batch_size; -@@global.innodb_doublewrite_batch_size -120 -select @@session.innodb_doublewrite_batch_size; -ERROR HY000: Variable 'innodb_doublewrite_batch_size' is a GLOBAL variable -show global variables like 'innodb_doublewrite_batch_size'; -Variable_name Value -innodb_doublewrite_batch_size 120 -show session variables like 'innodb_doublewrite_batch_size'; -Variable_name Value -innodb_doublewrite_batch_size 120 -select * from information_schema.global_variables where variable_name='innodb_doublewrite_batch_size'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_DOUBLEWRITE_BATCH_SIZE 120 -select * from information_schema.session_variables where variable_name='innodb_doublewrite_batch_size'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_DOUBLEWRITE_BATCH_SIZE 120 -set global innodb_doublewrite_batch_size=1; -ERROR HY000: Variable 'innodb_doublewrite_batch_size' is a read only variable -set @@session.innodb_doublewrite_batch_size='some'; -ERROR HY000: Variable 'innodb_doublewrite_batch_size' is a read only variable diff --git a/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_basic.result b/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_basic.result index 20b619972dd..ad0ffe9855a 100644 --- a/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_basic.result @@ -7,7 +7,7 @@ SELECT @global_start_value; SET @global_start_max_dirty_lwm_value = @@global.innodb_max_dirty_pages_pct_lwm; SELECT @global_start_max_dirty_lwm_value; @global_start_max_dirty_lwm_value -0 +75 SET @@global.innodb_max_dirty_pages_pct_lwm = 0; SELECT @@global.innodb_max_dirty_pages_pct_lwm; @@global.innodb_max_dirty_pages_pct_lwm @@ -17,13 +17,13 @@ SET @@global.innodb_max_dirty_pages_pct = 0; SET @@global.innodb_max_dirty_pages_pct = DEFAULT; SELECT @@global.innodb_max_dirty_pages_pct; @@global.innodb_max_dirty_pages_pct -75.000000 +90.000000 '#---------------------FN_DYNVARS_046_02-------------------------#' SET innodb_max_dirty_pages_pct = 1; ERROR HY000: Variable 'innodb_max_dirty_pages_pct' is a GLOBAL variable and should be set with SET GLOBAL SELECT @@innodb_max_dirty_pages_pct; @@innodb_max_dirty_pages_pct -75.000000 +90.000000 SELECT local.innodb_max_dirty_pages_pct; ERROR 42S02: Unknown table 'local' in field list SET global innodb_max_dirty_pages_pct = 0; @@ -171,5 +171,5 @@ SELECT @@global.innodb_max_dirty_pages_pct; SET @@global.innodb_max_dirty_pages_pct_lwm = @global_start_max_dirty_lwm_value; SELECT @@global.innodb_max_dirty_pages_pct_lwm; @@global.innodb_max_dirty_pages_pct_lwm -0.000000 +75.000000 SET @@global.innodb_max_dirty_pages_pct=@save_innodb_max_dirty_pages_pct; diff --git a/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_func.result b/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_func.result index 8b68f182789..43cdf17ee27 100644 --- a/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_func.result +++ b/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_func.result @@ -1,26 +1,28 @@ +SET @innodb_max_dirty_pages_pct_lwm = @@global.innodb_max_dirty_pages_pct_lwm; SET @innodb_max_dirty_pages_pct = @@global.innodb_max_dirty_pages_pct; '#--------------------FN_DYNVARS_044_02-------------------------#' +SET @@global.innodb_max_dirty_pages_pct_lwm = 0; SET @@global.innodb_max_dirty_pages_pct = 80; -'connect (con1,localhost,root,,,,)' +SET @@global.innodb_max_dirty_pages_pct_lwm = 80; connect con1,localhost,root,,,,; -'connection con1' connection con1; SELECT @@global.innodb_max_dirty_pages_pct; @@global.innodb_max_dirty_pages_pct 80.000000 SET @@global.innodb_max_dirty_pages_pct = 70; -'connect (con2,localhost,root,,,,)' +Warnings: +Warning 1210 innodb_max_dirty_pages_pct cannot be set lower than innodb_max_dirty_pages_pct_lwm. +Warning 1210 Lowering innodb_max_dirty_page_pct_lwm to 70.000000 +SELECT @@global.innodb_max_dirty_pages_pct_lwm; +@@global.innodb_max_dirty_pages_pct_lwm +70.000000 connect con2,localhost,root,,,,; -'connection con2' connection con2; SELECT @@global.innodb_max_dirty_pages_pct; @@global.innodb_max_dirty_pages_pct 70.000000 -'connection default' connection default; -'disconnect con2' disconnect con2; -'disconnect con1' disconnect con1; SET @@global.innodb_max_dirty_pages_pct = @innodb_max_dirty_pages_pct; '#--------------------FN_DYNVARS_044_02-------------------------#' @@ -85,6 +87,22 @@ b CHAR(200) ) ENGINE = INNODB; '---Check when innodb_max_dirty_pages_pct is 10---' SET @@global.innodb_max_dirty_pages_pct = 10; +Warnings: +Warning 1210 innodb_max_dirty_pages_pct cannot be set lower than innodb_max_dirty_pages_pct_lwm. +Warning 1210 Lowering innodb_max_dirty_page_pct_lwm to 10.000000 +SELECT @@global.innodb_max_dirty_pages_pct_lwm; +@@global.innodb_max_dirty_pages_pct_lwm +10.000000 +SET GLOBAL innodb_max_dirty_pages_pct_lwm = 15; +Warnings: +Warning 1210 innodb_max_dirty_pages_pct_lwm cannot be set higher than innodb_max_dirty_pages_pct. +Warning 1210 Setting innodb_max_dirty_page_pct_lwm to 10.000000 +SELECT @@global.innodb_max_dirty_pages_pct_lwm; +@@global.innodb_max_dirty_pages_pct_lwm +10.000000 +SELECT @@global.innodb_max_dirty_pages_pct; +@@global.innodb_max_dirty_pages_pct +10.000000 FLUSH STATUS; CALL add_until(10); FLUSH TABLES; @@ -98,4 +116,6 @@ DROP PROCEDURE add_until; DROP PROCEDURE check_pct; DROP FUNCTION dirty_pct; DROP TABLE t1; +SET GLOBAL innodb_max_dirty_pages_pct_lwm = 0; SET @@global.innodb_max_dirty_pages_pct = @innodb_max_dirty_pages_pct; +SET @@global.innodb_max_dirty_pages_pct_lwm = @innodb_max_dirty_pages_pct_lwm; diff --git a/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_lwm_basic.result b/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_lwm_basic.result index 641386d5f23..313bdf28e82 100644 --- a/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_lwm_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_lwm_basic.result @@ -3,7 +3,7 @@ set @@global.innodb_max_dirty_pages_pct=75; SET @pct_lwm_start_value = @@global.innodb_max_dirty_pages_pct_lwm; SELECT @pct_lwm_start_value; @pct_lwm_start_value -0 +75 SET @pct_start_value = @@global.innodb_max_dirty_pages_pct; SELECT @pct_start_value; @pct_start_value @@ -13,13 +13,13 @@ SET @@global.innodb_max_dirty_pages_pct_lwm = 0; SET @@global.innodb_max_dirty_pages_pct_lwm = DEFAULT; SELECT @@global.innodb_max_dirty_pages_pct_lwm; @@global.innodb_max_dirty_pages_pct_lwm -0.000000 +75.000000 '#---------------------FN_DYNVARS_046_02-------------------------#' SET innodb_max_dirty_pages_pct_lwm = 1; ERROR HY000: Variable 'innodb_max_dirty_pages_pct_lwm' is a GLOBAL variable and should be set with SET GLOBAL SELECT @@innodb_max_dirty_pages_pct_lwm; @@innodb_max_dirty_pages_pct_lwm -0.000000 +75.000000 SELECT local.innodb_max_dirty_pages_pct_lwm; ERROR 42S02: Unknown table 'local' in field list SET global innodb_max_dirty_pages_pct_lwm = 0; @@ -130,5 +130,5 @@ SELECT @@global.innodb_max_dirty_pages_pct; SET @@global.innodb_max_dirty_pages_pct_lwm = @pct_lwm_start_value; SELECT @@global.innodb_max_dirty_pages_pct_lwm; @@global.innodb_max_dirty_pages_pct_lwm -0.000000 +75.000000 SET @@global.innodb_max_dirty_pages_pct=@save_innodb_max_dirty_pages_pct; diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff b/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff index 2f39a472b99..0a558e77923 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff @@ -85,16 +85,7 @@ VARIABLE_COMMENT Percentage of empty space on a data page that can be reserved to make the page compressible. NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 75 -@@ -661,7 +661,7 @@ - SESSION_VALUE NULL - DEFAULT_VALUE 120 - VARIABLE_SCOPE GLOBAL --VARIABLE_TYPE BIGINT UNSIGNED -+VARIABLE_TYPE INT UNSIGNED - VARIABLE_COMMENT Number of pages reserved in doublewrite buffer for batch flushing - NUMERIC_MIN_VALUE 1 - NUMERIC_MAX_VALUE 127 -@@ -757,7 +757,7 @@ +@@ -745,7 +745,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 600 VARIABLE_SCOPE GLOBAL @@ -103,7 +94,7 @@ VARIABLE_COMMENT Maximum number of seconds that semaphore times out in InnoDB. NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 4294967295 -@@ -805,7 +805,7 @@ +@@ -793,7 +793,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 0 VARIABLE_SCOPE GLOBAL @@ -112,7 +103,7 @@ VARIABLE_COMMENT Make the first page of the given tablespace dirty. NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 4294967295 -@@ -817,7 +817,7 @@ +@@ -805,7 +805,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 30 VARIABLE_SCOPE GLOBAL @@ -121,7 +112,7 @@ VARIABLE_COMMENT Number of iterations over which the background flushing is averaged. NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 1000 -@@ -841,7 +841,7 @@ +@@ -829,7 +829,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 1 VARIABLE_SCOPE GLOBAL @@ -130,7 +121,7 @@ VARIABLE_COMMENT Controls the durability/speed trade-off for commits. Set to 0 (write and flush redo log to disk only once per second), 1 (flush to disk at each commit), 2 (write to log at commit but flush to disk only once per second) or 3 (flush to disk at prepare and at commit, slower and usually redundant). 1 and 3 guarantees that after a crash, committed transactions will not be lost and will be consistent with the binlog and other transactional engines. 2 can get inconsistent and lose transactions if there is a power failure or kernel crash but not if mysqld crashes. 0 has no guarantees in case of crash. 0 and 2 can be faster than 1 or 3. NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 3 -@@ -865,7 +865,7 @@ +@@ -853,7 +853,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 1 VARIABLE_SCOPE GLOBAL @@ -139,7 +130,7 @@ VARIABLE_COMMENT Set to 0 (don't flush neighbors from buffer pool), 1 (flush contiguous neighbors from buffer pool) or 2 (flush neighbors from buffer pool), when flushing a block NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 2 -@@ -913,7 +913,7 @@ +@@ -901,7 +901,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 0 VARIABLE_SCOPE GLOBAL @@ -148,7 +139,7 @@ VARIABLE_COMMENT Helps to save your data in case the disk image of the database becomes corrupt. Value 5 can return bogus data, and 6 can permanently corrupt data. NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 6 -@@ -937,7 +937,7 @@ +@@ -925,7 +925,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 8000000 VARIABLE_SCOPE GLOBAL @@ -157,7 +148,7 @@ VARIABLE_COMMENT InnoDB Fulltext search cache size in bytes NUMERIC_MIN_VALUE 1600000 NUMERIC_MAX_VALUE 80000000 -@@ -973,7 +973,7 @@ +@@ -961,7 +961,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 84 VARIABLE_SCOPE GLOBAL @@ -166,7 +157,7 @@ VARIABLE_COMMENT InnoDB Fulltext search maximum token size in characters NUMERIC_MIN_VALUE 10 NUMERIC_MAX_VALUE 84 -@@ -985,7 +985,7 @@ +@@ -973,7 +973,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 3 VARIABLE_SCOPE GLOBAL @@ -175,7 +166,7 @@ VARIABLE_COMMENT InnoDB Fulltext search minimum token size in characters NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 16 -@@ -997,7 +997,7 @@ +@@ -985,7 +985,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 2000 VARIABLE_SCOPE GLOBAL @@ -184,7 +175,7 @@ VARIABLE_COMMENT InnoDB Fulltext search number of words to optimize for each optimize table call NUMERIC_MIN_VALUE 1000 NUMERIC_MAX_VALUE 10000 -@@ -1009,10 +1009,10 @@ +@@ -997,10 +997,10 @@ SESSION_VALUE NULL DEFAULT_VALUE 2000000000 VARIABLE_SCOPE GLOBAL @@ -197,7 +188,7 @@ NUMERIC_BLOCK_SIZE 0 ENUM_VALUE_LIST NULL READ_ONLY NO -@@ -1033,7 +1033,7 @@ +@@ -1021,7 +1021,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 2 VARIABLE_SCOPE GLOBAL @@ -206,7 +197,7 @@ VARIABLE_COMMENT InnoDB Fulltext search parallel sort degree, will round up to nearest power of 2 number NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 16 -@@ -1045,7 +1045,7 @@ +@@ -1033,7 +1033,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 640000000 VARIABLE_SCOPE GLOBAL @@ -215,7 +206,7 @@ VARIABLE_COMMENT Total memory allocated for InnoDB Fulltext Search cache NUMERIC_MIN_VALUE 32000000 NUMERIC_MAX_VALUE 1600000000 -@@ -1069,7 +1069,7 @@ +@@ -1057,7 +1057,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 100 VARIABLE_SCOPE GLOBAL @@ -224,7 +215,7 @@ VARIABLE_COMMENT Up to what percentage of dirty pages should be flushed when innodb finds it has spare resources to do so. NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 100 -@@ -1105,22 +1105,22 @@ +@@ -1093,22 +1093,22 @@ SESSION_VALUE NULL DEFAULT_VALUE 200 VARIABLE_SCOPE GLOBAL @@ -252,7 +243,7 @@ NUMERIC_BLOCK_SIZE 0 ENUM_VALUE_LIST NULL READ_ONLY NO -@@ -1165,7 +1165,7 @@ +@@ -1153,7 +1153,7 @@ SESSION_VALUE 50 DEFAULT_VALUE 50 VARIABLE_SCOPE SESSION @@ -261,7 +252,7 @@ VARIABLE_COMMENT Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout. NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 1073741824 -@@ -1177,10 +1177,10 @@ +@@ -1165,10 +1165,10 @@ SESSION_VALUE NULL DEFAULT_VALUE 16777216 VARIABLE_SCOPE GLOBAL @@ -274,7 +265,7 @@ NUMERIC_BLOCK_SIZE 1024 ENUM_VALUE_LIST NULL READ_ONLY YES -@@ -1225,7 +1225,7 @@ +@@ -1213,7 +1213,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 1 VARIABLE_SCOPE GLOBAL @@ -283,7 +274,7 @@ VARIABLE_COMMENT Deprecated parameter with no effect. NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 100 -@@ -1273,7 +1273,7 @@ +@@ -1261,7 +1261,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 8192 VARIABLE_SCOPE GLOBAL @@ -292,6 +283,19 @@ VARIABLE_COMMENT Redo log write ahead unit size to avoid read-on-write, it should match the OS cache block IO size NUMERIC_MIN_VALUE 512 NUMERIC_MAX_VALUE 16384 +@@ -1273,10 +1273,10 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 100 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT How many pages to flush on LRU eviction + NUMERIC_MIN_VALUE 1 +-NUMERIC_MAX_VALUE 18446744073709551615 ++NUMERIC_MAX_VALUE 4294967295 + NUMERIC_BLOCK_SIZE 0 + ENUM_VALUE_LIST NULL + READ_ONLY NO @@ -1285,10 +1285,10 @@ SESSION_VALUE NULL DEFAULT_VALUE 1024 diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result index 5b532addaa8..767d31c033e 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result @@ -657,18 +657,6 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST OFF,ON READ_ONLY YES COMMAND_LINE_ARGUMENT NONE -VARIABLE_NAME INNODB_DOUBLEWRITE_BATCH_SIZE -SESSION_VALUE NULL -DEFAULT_VALUE 120 -VARIABLE_SCOPE GLOBAL -VARIABLE_TYPE BIGINT UNSIGNED -VARIABLE_COMMENT Number of pages reserved in doublewrite buffer for batch flushing -NUMERIC_MIN_VALUE 1 -NUMERIC_MAX_VALUE 127 -NUMERIC_BLOCK_SIZE 0 -ENUM_VALUE_LIST NULL -READ_ONLY YES -COMMAND_LINE_ARGUMENT OPTIONAL VARIABLE_NAME INNODB_ENCRYPTION_ROTATE_KEY_AGE SESSION_VALUE NULL DEFAULT_VALUE 1 @@ -1281,9 +1269,21 @@ NUMERIC_BLOCK_SIZE 512 ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME INNODB_LRU_FLUSH_SIZE +SESSION_VALUE NULL +DEFAULT_VALUE 32 +VARIABLE_SCOPE GLOBAL +VARIABLE_TYPE BIGINT UNSIGNED +VARIABLE_COMMENT How many pages to flush on LRU eviction +NUMERIC_MIN_VALUE 1 +NUMERIC_MAX_VALUE 18446744073709551615 +NUMERIC_BLOCK_SIZE 0 +ENUM_VALUE_LIST NULL +READ_ONLY NO +COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME INNODB_LRU_SCAN_DEPTH SESSION_VALUE NULL -DEFAULT_VALUE 1024 +DEFAULT_VALUE 1536 VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_COMMENT How deep to scan LRU to keep it clean @@ -1307,7 +1307,7 @@ READ_ONLY NO COMMAND_LINE_ARGUMENT OPTIONAL VARIABLE_NAME INNODB_MAX_DIRTY_PAGES_PCT SESSION_VALUE NULL -DEFAULT_VALUE 75.000000 +DEFAULT_VALUE 90.000000 VARIABLE_SCOPE GLOBAL VARIABLE_TYPE DOUBLE VARIABLE_COMMENT Percentage of dirty pages allowed in bufferpool. @@ -1319,7 +1319,7 @@ READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME INNODB_MAX_DIRTY_PAGES_PCT_LWM SESSION_VALUE NULL -DEFAULT_VALUE 0.000000 +DEFAULT_VALUE 75.000000 VARIABLE_SCOPE GLOBAL VARIABLE_TYPE DOUBLE VARIABLE_COMMENT Percentage of dirty pages at which flushing kicks in. diff --git a/mysql-test/suite/sys_vars/t/innodb_doublewrite_batch_size_basic.test b/mysql-test/suite/sys_vars/t/innodb_doublewrite_batch_size_basic.test deleted file mode 100644 index 5e9104b5335..00000000000 --- a/mysql-test/suite/sys_vars/t/innodb_doublewrite_batch_size_basic.test +++ /dev/null @@ -1,24 +0,0 @@ ---source include/have_innodb.inc ---source include/have_debug.inc - -# -# exists as global only -# -select @@global.innodb_doublewrite_batch_size between 1 and 127; -select @@global.innodb_doublewrite_batch_size; ---error ER_INCORRECT_GLOBAL_LOCAL_VAR -select @@session.innodb_doublewrite_batch_size; -show global variables like 'innodb_doublewrite_batch_size'; -show session variables like 'innodb_doublewrite_batch_size'; ---disable_warnings -select * from information_schema.global_variables where variable_name='innodb_doublewrite_batch_size'; -select * from information_schema.session_variables where variable_name='innodb_doublewrite_batch_size'; ---enable_warnings - -# -# show that it's read-only -# ---error ER_INCORRECT_GLOBAL_LOCAL_VAR -set global innodb_doublewrite_batch_size=1; ---error ER_INCORRECT_GLOBAL_LOCAL_VAR -set @@session.innodb_doublewrite_batch_size='some'; diff --git a/mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_func.test b/mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_func.test index c7a9e567e69..0720aca65b9 100644 --- a/mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_func.test +++ b/mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_func.test @@ -25,6 +25,7 @@ --source include/have_innodb.inc # safe initial value +SET @innodb_max_dirty_pages_pct_lwm = @@global.innodb_max_dirty_pages_pct_lwm; SET @innodb_max_dirty_pages_pct = @@global.innodb_max_dirty_pages_pct; --echo '#--------------------FN_DYNVARS_044_02-------------------------#' @@ -32,23 +33,19 @@ SET @innodb_max_dirty_pages_pct = @@global.innodb_max_dirty_pages_pct; # Check if setting innodb_max_dirty_pages_pct is changed in new connection # ############################################################################ +SET @@global.innodb_max_dirty_pages_pct_lwm = 0; SET @@global.innodb_max_dirty_pages_pct = 80; ---echo 'connect (con1,localhost,root,,,,)' +SET @@global.innodb_max_dirty_pages_pct_lwm = 80; connect (con1,localhost,root,,,,); ---echo 'connection con1' connection con1; SELECT @@global.innodb_max_dirty_pages_pct; SET @@global.innodb_max_dirty_pages_pct = 70; ---echo 'connect (con2,localhost,root,,,,)' +SELECT @@global.innodb_max_dirty_pages_pct_lwm; connect (con2,localhost,root,,,,); ---echo 'connection con2' connection con2; SELECT @@global.innodb_max_dirty_pages_pct; ---echo 'connection default' connection default; ---echo 'disconnect con2' disconnect con2; ---echo 'disconnect con1' disconnect con1; # restore initial value SET @@global.innodb_max_dirty_pages_pct = @innodb_max_dirty_pages_pct; @@ -138,6 +135,10 @@ b CHAR(200) #========================================================== SET @@global.innodb_max_dirty_pages_pct = 10; +SELECT @@global.innodb_max_dirty_pages_pct_lwm; +SET GLOBAL innodb_max_dirty_pages_pct_lwm = 15; +SELECT @@global.innodb_max_dirty_pages_pct_lwm; +SELECT @@global.innodb_max_dirty_pages_pct; FLUSH STATUS; @@ -164,7 +165,9 @@ DROP FUNCTION dirty_pct; DROP TABLE t1; # restore initial value +SET GLOBAL innodb_max_dirty_pages_pct_lwm = 0; SET @@global.innodb_max_dirty_pages_pct = @innodb_max_dirty_pages_pct; +SET @@global.innodb_max_dirty_pages_pct_lwm = @innodb_max_dirty_pages_pct_lwm; ################################################################## # End of functionality Testing for innodb_max_dirty_pages_pct # diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc index a44b96add2c..e64f3c8c803 100644 --- a/storage/innobase/btr/btr0bulk.cc +++ b/storage/innobase/btr/btr0bulk.cc @@ -981,7 +981,7 @@ inline void BtrBulk::logFreeCheck() if (log_sys.check_flush_or_checkpoint()) { release(); - log_free_check(); + log_check_margins(); latch(); } @@ -1113,7 +1113,7 @@ BtrBulk::insert( /* Wake up page cleaner to flush dirty pages. */ srv_inc_activity_count(); - os_event_set(buf_flush_event); + mysql_cond_signal(&buf_pool.do_flush_list); logFreeCheck(); } diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index a190c11eb0a..f7c0e080cdd 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -7058,7 +7058,7 @@ static void btr_blob_free(buf_block_t *block, bool all, mtr_t *mtr) const ulint fold= page_id.fold(); - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); if (buf_page_t *bpage= buf_pool.page_hash_get_low(page_id, fold)) if(!buf_LRU_free_page(bpage, all) && all && bpage->zip.data) @@ -7066,7 +7066,7 @@ static void btr_blob_free(buf_block_t *block, bool all, mtr_t *mtr) if the whole ROW_FORMAT=COMPRESSED block cannot be deallocted. */ buf_LRU_free_page(bpage, false); - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); } /** Helper class used while writing blob pages, during insert or update. */ @@ -8253,7 +8253,7 @@ btr_rec_copy_externally_stored_field( field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE))) { /* The externally stored field was not written yet. This record should only be seen by - recv_recovery_rollback_active() or any + trx_rollback_recovered() or any TRX_ISO_READ_UNCOMMITTED transactions. */ return(NULL); } diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc index 9ee2342420b..238551783db 100644 --- a/storage/innobase/btr/btr0sea.cc +++ b/storage/innobase/btr/btr0sea.cc @@ -261,9 +261,9 @@ void btr_search_disable() void btr_search_enable(bool resize) { if (!resize) { - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); bool changed = srv_buf_pool_old_size != srv_buf_pool_size; - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); if (changed) { return; } @@ -2133,7 +2133,7 @@ btr_search_hash_table_validate(ulint hash_table_id) rec_offs_init(offsets_); - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); auto &part = btr_search_sys.parts[hash_table_id]; @@ -2144,7 +2144,7 @@ btr_search_hash_table_validate(ulint hash_table_id) give other queries a chance to run. */ if ((i != 0) && ((i % chunk_size) == 0)) { - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); btr_search_x_unlock_all(); os_thread_yield(); @@ -2156,7 +2156,7 @@ btr_search_hash_table_validate(ulint hash_table_id) goto func_exit; } - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); ulint curr_cell_count = part.table.n_cells; @@ -2252,7 +2252,7 @@ state_ok: /* We release search latches every once in a while to give other queries a chance to run. */ if (i != 0) { - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); btr_search_x_unlock_all(); os_thread_yield(); @@ -2264,7 +2264,7 @@ state_ok: goto func_exit; } - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); ulint curr_cell_count = part.table.n_cells; @@ -2285,7 +2285,7 @@ state_ok: } } - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); func_exit: btr_search_x_unlock_all(); diff --git a/storage/innobase/buf/buf0buddy.cc b/storage/innobase/buf/buf0buddy.cc index 8280377b42a..a83d0840cb5 100644 --- a/storage/innobase/buf/buf0buddy.cc +++ b/storage/innobase/buf/buf0buddy.cc @@ -192,7 +192,7 @@ static bool buf_buddy_check_free(const buf_buddy_free_t* buf, ulint i) { const ulint size = BUF_BUDDY_LOW << i; - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(!ut_align_offset(buf, size)); ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN)); @@ -261,7 +261,7 @@ UNIV_INLINE void buf_buddy_add_to_free(buf_buddy_free_t* buf, ulint i) { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(buf_pool.zip_free[i].start != buf); buf_buddy_stamp_free(buf, i); @@ -276,7 +276,7 @@ UNIV_INLINE void buf_buddy_remove_from_free(buf_buddy_free_t* buf, ulint i) { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(buf_buddy_check_free(buf, i)); UT_LIST_REMOVE(buf_pool.zip_free[i], buf); @@ -290,7 +290,7 @@ static buf_buddy_free_t* buf_buddy_alloc_zip(ulint i) { buf_buddy_free_t* buf; - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_a(i < BUF_BUDDY_SIZES); ut_a(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN)); @@ -350,7 +350,7 @@ buf_buddy_block_free(void* buf) buf_page_t* bpage; buf_block_t* block; - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_a(!ut_align_offset(buf, srv_page_size)); HASH_SEARCH(hash, &buf_pool.zip_hash, fold, buf_page_t*, bpage, @@ -433,7 +433,7 @@ byte *buf_buddy_alloc_low(ulint i, bool *lru) { buf_block_t* block; - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN)); if (i < BUF_BUDDY_SIZES) { @@ -483,7 +483,7 @@ static bool buf_buddy_relocate(void* src, void* dst, ulint i, bool force) ulint space; ulint offset; - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(!ut_align_offset(src, size)); ut_ad(!ut_align_offset(dst, size)); ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN)); @@ -584,7 +584,7 @@ void buf_buddy_free_low(void* buf, ulint i) { buf_buddy_free_t* buddy; - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(i <= BUF_BUDDY_SIZES); ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN)); ut_ad(buf_pool.buddy_stat[i].used > 0); @@ -670,7 +670,7 @@ buf_buddy_realloc(void* buf, ulint size) buf_block_t* block = NULL; ulint i = buf_buddy_get_slot(size); - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(i <= BUF_BUDDY_SIZES); ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN)); @@ -711,7 +711,7 @@ buf_buddy_realloc(void* buf, ulint size) /** Combine all pairs of free buddies. */ void buf_buddy_condense_free() { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(buf_pool.curr_size < buf_pool.old_size); for (ulint i = 0; i < UT_ARR_SIZE(buf_pool.zip_free); ++i) { diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 078361092fc..6bde6939fd6 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -525,7 +525,7 @@ decrypt_failed: @retval 0 if all modified persistent pages have been flushed */ lsn_t buf_pool_t::get_oldest_modification() { - mutex_enter(&flush_list_mutex); + mysql_mutex_lock(&flush_list_mutex); /* FIXME: Keep temporary tablespace pages in a separate flush list. We would only need to write out temporary pages if the @@ -538,7 +538,7 @@ lsn_t buf_pool_t::get_oldest_modification() ut_ad(bpage->oldest_modification()); lsn_t oldest_lsn= bpage ? bpage->oldest_modification() : 0; - mutex_exit(&flush_list_mutex); + mysql_mutex_unlock(&flush_list_mutex); /* The result may become stale as soon as we released the mutex. On log checkpoint, also log_sys.flush_order_mutex will be needed. */ @@ -1063,14 +1063,14 @@ buf_madvise_do_dump() ret+= madvise(recv_sys.buf, recv_sys.len, MADV_DODUMP); } - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); auto chunk = buf_pool.chunks; for (ulint n = buf_pool.n_chunks; n--; chunk++) { ret+= madvise(chunk->mem, chunk->mem_size(), MADV_DODUMP); } - mutex_exit(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); return ret; } #endif @@ -1546,7 +1546,7 @@ bool buf_pool_t::create() while (++chunk < chunks + n_chunks); ut_ad(is_initialised()); - mutex_create(LATCH_ID_BUF_POOL, &mutex); + mysql_mutex_init(buf_pool_mutex_key, &mutex, MY_MUTEX_INIT_FAST); UT_LIST_INIT(LRU, &buf_page_t::LRU); UT_LIST_INIT(withdraw, &buf_page_t::list); @@ -1570,17 +1570,18 @@ bool buf_pool_t::create() zip_hash.create(2 * curr_size); last_printout_time= time(NULL); - mutex_create(LATCH_ID_FLUSH_LIST, &flush_list_mutex); + mysql_mutex_init(flush_list_mutex_key, &flush_list_mutex, + MY_MUTEX_INIT_FAST); - for (int i= 0; i < 3; i++) - no_flush[i]= os_event_create(0); + mysql_cond_init(0, &done_flush_LRU, nullptr); + mysql_cond_init(0, &done_flush_list, nullptr); + mysql_cond_init(0, &do_flush_list, nullptr); try_LRU_scan= true; ut_d(flush_hp.m_mutex= &flush_list_mutex;); ut_d(lru_hp.m_mutex= &mutex); ut_d(lru_scan_itr.m_mutex= &mutex); - ut_d(single_scan_itr.m_mutex= &mutex); io_buf.create((srv_n_read_io_threads + srv_n_write_io_threads) * OS_AIO_N_PENDING_IOS_PER_THREAD); @@ -1604,8 +1605,8 @@ void buf_pool_t::close() if (!is_initialised()) return; - mutex_free(&mutex); - mutex_free(&flush_list_mutex); + mysql_mutex_destroy(&mutex); + mysql_mutex_destroy(&flush_list_mutex); for (buf_page_t *bpage= UT_LIST_GET_LAST(LRU), *prev_bpage= nullptr; bpage; bpage= prev_bpage) @@ -1633,8 +1634,9 @@ void buf_pool_t::close() allocator.deallocate_large_dodump(chunk->mem, &chunk->mem_pfx); } - for (int i= 0; i < 3; ++i) - os_event_destroy(no_flush[i]); + mysql_cond_destroy(&done_flush_LRU); + mysql_cond_destroy(&done_flush_list); + mysql_cond_destroy(&do_flush_list); ut_free(chunks); chunks= nullptr; @@ -1661,7 +1663,7 @@ inline bool buf_pool_t::realloc(buf_block_t *block) buf_block_t* new_block; ut_ad(withdrawing); - ut_ad(mutex_own(&mutex)); + mysql_mutex_assert_owner(&mutex); ut_ad(block->page.state() == BUF_BLOCK_FILE_PAGE); new_block = buf_LRU_get_free_only(); @@ -1732,13 +1734,8 @@ inline bool buf_pool_t::realloc(buf_block_t *block) + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xff, 4); MEM_UNDEFINED(block->frame, srv_page_size); block->page.set_state(BUF_BLOCK_REMOVE_HASH); - - /* Relocate flush_list. */ - if (block->page.oldest_modification()) { - buf_flush_relocate_on_flush_list( - &block->page, &new_block->page); - } - + buf_flush_relocate_on_flush_list(&block->page, + &new_block->page); block->page.set_corrupt_id(); /* set other flags of buf_block_t */ @@ -1804,16 +1801,16 @@ inline bool buf_pool_t::withdraw_blocks() << withdraw_target << " blocks"; /* Minimize zip_free[i] lists */ - mutex_enter(&mutex); + mysql_mutex_lock(&mutex); buf_buddy_condense_free(); - mutex_exit(&mutex); + mysql_mutex_unlock(&mutex); while (UT_LIST_GET_LEN(withdraw) < withdraw_target) { /* try to withdraw from free_list */ ulint count1 = 0; - mutex_enter(&mutex); + mysql_mutex_lock(&mutex); block = reinterpret_cast( UT_LIST_GET_FIRST(free)); while (block != NULL @@ -1828,7 +1825,7 @@ inline bool buf_pool_t::withdraw_blocks() UT_LIST_GET_NEXT( list, &block->page)); - if (buf_pool.will_be_withdrawn(block->page)) { + if (will_be_withdrawn(block->page)) { /* This should be withdrawn */ UT_LIST_REMOVE(free, &block->page); UT_LIST_ADD_LAST(withdraw, &block->page); @@ -1838,40 +1835,29 @@ inline bool buf_pool_t::withdraw_blocks() block = next_block; } - mutex_exit(&mutex); + mysql_mutex_unlock(&mutex); /* reserve free_list length */ if (UT_LIST_GET_LEN(withdraw) < withdraw_target) { - ulint scan_depth; - flush_counters_t n; + ulint n_flushed = buf_flush_lists( + std::max(withdraw_target + - UT_LIST_GET_LEN(withdraw), + srv_LRU_scan_depth), 0); + buf_flush_wait_batch_end_acquiring_mutex(true); - /* cap scan_depth with current LRU size. */ - mutex_enter(&mutex); - scan_depth = UT_LIST_GET_LEN(LRU); - mutex_exit(&mutex); - - scan_depth = ut_min( - ut_max(withdraw_target - - UT_LIST_GET_LEN(withdraw), - static_cast(srv_LRU_scan_depth)), - scan_depth); - - buf_flush_do_batch(true, scan_depth, 0, &n); - buf_flush_wait_batch_end(true); - - if (n.flushed) { + if (n_flushed) { MONITOR_INC_VALUE_CUMULATIVE( MONITOR_LRU_BATCH_FLUSH_TOTAL_PAGE, MONITOR_LRU_BATCH_FLUSH_COUNT, MONITOR_LRU_BATCH_FLUSH_PAGES, - n.flushed); + n_flushed); } } /* relocate blocks/buddies in withdrawn area */ ulint count2 = 0; - mutex_enter(&mutex); + mysql_mutex_lock(&mutex); buf_page_t* bpage; bpage = UT_LIST_GET_FIRST(LRU); while (bpage != NULL) { @@ -1892,7 +1878,7 @@ inline bool buf_pool_t::withdraw_blocks() } if (bpage->state() == BUF_BLOCK_FILE_PAGE - && buf_pool.will_be_withdrawn(*bpage)) { + && will_be_withdrawn(*bpage)) { if (bpage->can_relocate()) { buf_pool_mutex_exit_forbid(); if (!realloc( @@ -1911,7 +1897,7 @@ inline bool buf_pool_t::withdraw_blocks() bpage = next_bpage; } - mutex_exit(&mutex); + mysql_mutex_unlock(&mutex); buf_resize_status( "withdrawing blocks. (" ULINTPF "/" ULINTPF ")", @@ -2031,7 +2017,7 @@ inline void buf_pool_t::page_hash_table::write_unlock_all() inline void buf_pool_t::write_lock_all_page_hash() { - ut_ad(mutex_own(&mutex)); + mysql_mutex_assert_owner(&mutex); page_hash.write_lock_all(); for (page_hash_table *old_page_hash= freed_page_hash; old_page_hash; old_page_hash= static_cast @@ -2103,7 +2089,7 @@ inline void buf_pool_t::resize() srv_buf_pool_old_size, srv_buf_pool_size, srv_buf_pool_chunk_unit); - mutex_enter(&mutex); + mysql_mutex_lock(&mutex); ut_ad(curr_size == old_size); ut_ad(n_chunks_new == n_chunks); ut_ad(UT_LIST_GET_LEN(withdraw) == 0); @@ -2111,7 +2097,7 @@ inline void buf_pool_t::resize() n_chunks_new = (new_instance_size << srv_page_size_shift) / srv_buf_pool_chunk_unit; curr_size = n_chunks_new * chunks->size; - mutex_exit(&mutex); + mysql_mutex_unlock(&mutex); #ifdef BTR_CUR_HASH_ADAPT /* disable AHI if needed */ @@ -2225,7 +2211,7 @@ withdraw_retry: /* Indicate critical path */ resizing.store(true, std::memory_order_relaxed); - mutex_enter(&mutex); + mysql_mutex_lock(&mutex); write_lock_all_page_hash(); chunk_t::map_reg = UT_NEW_NOKEY(chunk_t::map()); @@ -2389,7 +2375,7 @@ calc_buf_pool_size: ib::info() << "hash tables were resized"; } - mutex_exit(&mutex); + mysql_mutex_unlock(&mutex); write_unlock_all_page_hash(); UT_DELETE(chunk_map_old); @@ -2454,10 +2440,10 @@ static void buf_resize_callback(void *) { DBUG_ENTER("buf_resize_callback"); ut_a(srv_shutdown_state == SRV_SHUTDOWN_NONE); - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); const auto size= srv_buf_pool_size; const bool work= srv_buf_pool_old_size != size; - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); if (work) buf_pool.resize(); @@ -2495,7 +2481,7 @@ static void buf_relocate(buf_page_t *bpage, buf_page_t *dpage) { const ulint fold= bpage->id().fold(); ut_ad(bpage->state() == BUF_BLOCK_ZIP_PAGE); - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(buf_pool.hash_lock_get(bpage->id())->is_write_locked()); ut_a(bpage->io_fix() == BUF_IO_NONE); ut_a(!bpage->buf_fix_count()); @@ -2568,7 +2554,7 @@ retry: (*hash_lock)->write_unlock(); /* Allocate a watch[] and then try to insert it into the page_hash. */ - mutex_enter(&mutex); + mysql_mutex_lock(&mutex); /* The maximum number of purge tasks should never exceed the UT_ARR_SIZE(watch) - 1, and there is no way for a purge task to hold a @@ -2592,17 +2578,17 @@ retry: *hash_lock= page_hash.lock_get(fold); (*hash_lock)->write_lock(); - mutex_exit(&mutex); + mysql_mutex_unlock(&mutex); buf_page_t *bpage= page_hash_get_low(id, fold); if (UNIV_LIKELY_NULL(bpage)) { (*hash_lock)->write_unlock(); - mutex_enter(&mutex); + mysql_mutex_lock(&mutex); w->set_state(BUF_BLOCK_NOT_USED); *hash_lock= page_hash.lock_get(fold); (*hash_lock)->write_lock(); - mutex_exit(&mutex); + mysql_mutex_unlock(&mutex); goto retry; } @@ -2615,7 +2601,7 @@ retry: } ut_error; - mutex_exit(&mutex); + mysql_mutex_unlock(&mutex); return nullptr; } @@ -2733,10 +2719,10 @@ err_exit: { discard_attempted= true; hash_lock->read_unlock(); - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); if (buf_page_t *bpage= buf_pool.page_hash_get_low(page_id, fold)) buf_LRU_free_page(bpage, false); - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); goto lookup; } @@ -3261,14 +3247,14 @@ got_block: if (UNIV_UNLIKELY(mode == BUF_EVICT_IF_IN_POOL)) { evict_from_pool: ut_ad(!fix_block->page.oldest_modification()); - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); fix_block->unfix(); if (!buf_LRU_free_page(&fix_block->page, true)) { ut_ad(0); } - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); return(NULL); } @@ -3317,7 +3303,7 @@ evict_from_pool: block = buf_LRU_get_free_block(false); buf_block_init_low(block); - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); hash_lock = buf_pool.page_hash.lock_get(fold); hash_lock->write_lock(); @@ -3336,7 +3322,7 @@ evict_from_pool: hash_lock->write_unlock(); buf_LRU_block_free_non_file_page(block); - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); /* Try again */ goto loop; @@ -3355,9 +3341,7 @@ evict_from_pool: /* Set after buf_relocate(). */ block->page.set_buf_fix_count(1); - if (block->page.oldest_modification()) { - buf_flush_relocate_on_flush_list(bpage, &block->page); - } + buf_flush_relocate_on_flush_list(bpage, &block->page); /* Buffer-fix, I/O-fix, and X-latch the block for the duration of the decompression. @@ -3372,7 +3356,7 @@ evict_from_pool: MEM_UNDEFINED(bpage, sizeof *bpage); - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); hash_lock->write_unlock(); buf_pool.n_pend_unzip++; @@ -3412,7 +3396,7 @@ evict_from_pool: ut_ad(fix_block->page.state() == BUF_BLOCK_FILE_PAGE); #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG - +re_evict: if (mode != BUF_GET_IF_IN_POOL && mode != BUF_GET_IF_IN_POOL_OR_WATCH) { } else if (!ibuf_debug) { @@ -3421,18 +3405,19 @@ evict_from_pool: /* Try to evict the block from the buffer pool, to use the insert buffer (change buffer) as much as possible. */ - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); fix_block->unfix(); /* Blocks cannot be relocated or enter or exit the buf_pool while we are holding the buf_pool.mutex. */ + const bool evicted = buf_LRU_free_page(&fix_block->page, true); + space->release_for_io(); - if (buf_LRU_free_page(&fix_block->page, true)) { - space->release_for_io(); + if (evicted) { hash_lock = buf_pool.page_hash.lock_get(fold); hash_lock->write_lock(); - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); /* We may set the watch, as it would have been set if the page were not in the buffer pool in the first place. */ @@ -3456,20 +3441,16 @@ evict_from_pool: return(NULL); } - bool flushed = fix_block->page.ready_for_flush() - && buf_flush_page(&fix_block->page, - IORequest::SINGLE_PAGE, space, true); - space->release_for_io(); - if (flushed) { - guess = fix_block; - goto loop; + fix_block->fix(); + mysql_mutex_unlock(&buf_pool.mutex); + buf_flush_lists(ULINT_UNDEFINED, LSN_MAX); + buf_flush_wait_batch_end_acquiring_mutex(false); + + if (!fix_block->page.oldest_modification()) { + goto re_evict; } - fix_block->fix(); - /* Failed to evict the page; change it directly */ - - mutex_exit(&buf_pool.mutex); } #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ @@ -3793,23 +3774,22 @@ FILE_PAGE (the other is buf_page_get_gen). @param[in] offset offset of the tablespace @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 @param[in,out] mtr mini-transaction +@param[in,out] free_block pre-allocated buffer block @return pointer to the block, page bufferfixed */ buf_block_t* buf_page_create(fil_space_t *space, uint32_t offset, - ulint zip_size, mtr_t *mtr) + ulint zip_size, mtr_t *mtr, buf_block_t *free_block) { page_id_t page_id(space->id, offset); ut_ad(mtr->is_active()); ut_ad(page_id.space() != 0 || !zip_size); space->free_page(offset, false); -loop: - buf_block_t *free_block= buf_LRU_get_free_block(false); free_block->initialise(page_id, zip_size, 1); const ulint fold= page_id.fold(); - - mutex_enter(&buf_pool.mutex); +loop: + mysql_mutex_lock(&buf_pool.mutex); buf_block_t *block= reinterpret_cast (buf_pool.page_hash_get_low(page_id, fold)); @@ -3820,7 +3800,7 @@ loop: #ifdef BTR_CUR_HASH_ADAPT const dict_index_t *drop_hash_entry= nullptr; #endif - switch (block->page.state()) { + switch (UNIV_EXPECT(block->page.state(), BUF_BLOCK_FILE_PAGE)) { default: ut_ad(0); break; @@ -3831,16 +3811,15 @@ loop: while (block->page.io_fix() != BUF_IO_NONE || num_fix_count != block->page.buf_fix_count()) { - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); os_thread_yield(); - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); } } rw_lock_x_lock(&block->lock); #ifdef BTR_CUR_HASH_ADAPT drop_hash_entry= block->index; #endif - buf_LRU_block_free_non_file_page(free_block); break; case BUF_BLOCK_ZIP_PAGE: page_hash_latch *hash_lock= buf_pool.page_hash.lock_get(fold); @@ -3849,15 +3828,13 @@ loop: { hash_lock->write_unlock(); buf_LRU_block_free_non_file_page(free_block); - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); goto loop; } rw_lock_x_lock(&free_block->lock); buf_relocate(&block->page, &free_block->page); - - if (block->page.oldest_modification() > 0) - buf_flush_relocate_on_flush_list(&block->page, &free_block->page); + buf_flush_relocate_on_flush_list(&block->page, &free_block->page); free_block->page.set_state(BUF_BLOCK_FILE_PAGE); buf_unzip_LRU_add_block(free_block, FALSE); @@ -3868,7 +3845,7 @@ loop: break; } - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); #ifdef BTR_CUR_HASH_ADAPT if (drop_hash_entry) @@ -3926,7 +3903,7 @@ loop: else hash_lock->write_unlock(); - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); mtr->memo_push(block, MTR_MEMO_PAGE_X_FIX); block->page.set_accessed(); @@ -4074,12 +4051,12 @@ static void buf_mark_space_corrupt(buf_page_t* bpage, const fil_space_t& space) /** Release and evict a corrupted page. @param bpage page that was being read */ -void buf_pool_t::corrupted_evict(buf_page_t *bpage) +ATTRIBUTE_COLD void buf_pool_t::corrupted_evict(buf_page_t *bpage) { const page_id_t id(bpage->id()); page_hash_latch *hash_lock= hash_lock_get(id); - mutex_enter(&mutex); + mysql_mutex_lock(&mutex); hash_lock->write_lock(); ut_ad(bpage->io_fix() == BUF_IO_READ); @@ -4094,7 +4071,7 @@ void buf_pool_t::corrupted_evict(buf_page_t *bpage) /* remove from LRU and page_hash */ buf_LRU_free_one_page(bpage, id, hash_lock); - mutex_exit(&mutex); + mysql_mutex_unlock(&mutex); ut_d(auto n=) n_pend_reads--; ut_ad(n > 0); @@ -4104,6 +4081,7 @@ void buf_pool_t::corrupted_evict(buf_page_t *bpage) @param[in] bpage Corrupted page @param[in] node data file Also remove the bpage from LRU list. */ +ATTRIBUTE_COLD static void buf_corrupt_page_release(buf_page_t *bpage, const fil_node_t &node) { ut_ad(bpage->id().space() == node.space->id); @@ -4220,7 +4198,7 @@ dberr_t buf_page_read_complete(buf_page_t *bpage, const fil_node_t &node) { const page_id_t id(bpage->id()); ut_ad(bpage->in_file()); - ut_ad(id.space() || !buf_dblwr_page_inside(id.page_no())); + ut_ad(!buf_dblwr.is_inside(id)); ut_ad(id.space() == node.space->id); ut_ad(bpage->zip_size() == node.space->zip_size()); @@ -4287,7 +4265,7 @@ dberr_t buf_page_read_complete(buf_page_t *bpage, const fil_node_t &node) } err= buf_page_check_corrupt(bpage, node); - if (err != DB_SUCCESS) + if (UNIV_UNLIKELY(err != DB_SUCCESS)) { database_corrupted: /* Not a real corruption if it was triggered by error injection */ @@ -4375,12 +4353,12 @@ release_page: @retval nullptr if all freed */ void buf_pool_t::assert_all_freed() { - mutex_enter(&mutex); + mysql_mutex_lock(&mutex); const chunk_t *chunk= chunks; for (auto i= n_chunks; i--; chunk++) if (const buf_block_t* block= chunk->not_freed()) ib::fatal() << "Page " << block->page.id() << " still fixed or dirty"; - mutex_exit(&mutex); + mysql_mutex_unlock(&mutex); } #endif /* UNIV_DEBUG */ @@ -4395,33 +4373,20 @@ void buf_refresh_io_stats() All pages must be in a replaceable state (not modified or latched). */ void buf_pool_invalidate() { - mutex_enter(&buf_pool.mutex); - ut_ad(!buf_pool.init_flush[IORequest::LRU]); - ut_ad(!buf_pool.init_flush[IORequest::FLUSH_LIST]); - ut_ad(!buf_pool.init_flush[IORequest::SINGLE_PAGE]); - ut_ad(!buf_pool.n_flush[IORequest::SINGLE_PAGE]); + mysql_mutex_lock(&buf_pool.mutex); - if (buf_pool.n_flush[IORequest::LRU]) { - mutex_exit(&buf_pool.mutex); - buf_flush_wait_batch_end(true); - mutex_enter(&buf_pool.mutex); - } - - if (buf_pool.n_flush[IORequest::FLUSH_LIST]) { - mutex_exit(&buf_pool.mutex); - buf_flush_wait_batch_end(false); - mutex_enter(&buf_pool.mutex); - } + buf_flush_wait_batch_end(true); + buf_flush_wait_batch_end(false); /* It is possible that a write batch that has been posted earlier is still not complete. For buffer pool invalidation to proceed we must ensure there is NO write activity happening. */ - ut_d(mutex_exit(&buf_pool.mutex)); + ut_d(mysql_mutex_unlock(&buf_pool.mutex)); ut_d(buf_pool.assert_all_freed()); - ut_d(mutex_enter(&buf_pool.mutex)); + ut_d(mysql_mutex_lock(&buf_pool.mutex)); - while (buf_LRU_scan_and_free_block(true)); + while (buf_LRU_scan_and_free_block()); ut_ad(UT_LIST_GET_LEN(buf_pool.LRU) == 0); ut_ad(UT_LIST_GET_LEN(buf_pool.unzip_LRU) == 0); @@ -4432,7 +4397,7 @@ void buf_pool_invalidate() memset(&buf_pool.stat, 0x00, sizeof(buf_pool.stat)); buf_refresh_io_stats(); - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); } #ifdef UNIV_DEBUG @@ -4444,7 +4409,7 @@ void buf_pool_t::validate() ulint n_free = 0; ulint n_zip = 0; - mutex_enter(&mutex); + mysql_mutex_lock(&mutex); chunk_t* chunk = chunks; @@ -4485,7 +4450,7 @@ void buf_pool_t::validate() /* Check dirty blocks. */ - mutex_enter(&flush_list_mutex); + mysql_mutex_lock(&flush_list_mutex); for (buf_page_t* b = UT_LIST_GET_FIRST(flush_list); b; b = UT_LIST_GET_NEXT(list, b)) { ut_ad(b->oldest_modification()); @@ -4511,7 +4476,7 @@ void buf_pool_t::validate() ut_ad(UT_LIST_GET_LEN(flush_list) == n_flushing); - mutex_exit(&flush_list_mutex); + mysql_mutex_unlock(&flush_list_mutex); if (curr_size == old_size && n_lru + n_free > curr_size + n_zip) { @@ -4531,7 +4496,7 @@ void buf_pool_t::validate() << ", free blocks " << n_free << ". Aborting..."; } - mutex_exit(&mutex); + mysql_mutex_unlock(&mutex); ut_d(buf_LRU_validate()); ut_d(buf_flush_validate()); @@ -4559,8 +4524,8 @@ void buf_pool_t::print() counts = static_cast(ut_malloc_nokey(sizeof(ulint) * size)); - mutex_enter(&mutex); - mutex_enter(&flush_list_mutex); + mysql_mutex_lock(&mutex); + mysql_mutex_lock(&flush_list_mutex); ib::info() << "[buffer pool: size=" << curr_size @@ -4570,16 +4535,15 @@ void buf_pool_t::print() << UT_LIST_GET_LEN(flush_list) << ", n pending decompressions=" << n_pend_unzip << ", n pending reads=" << n_pend_reads - << ", n pending flush LRU=" << n_flush[IORequest::LRU] - << " list=" << n_flush[IORequest::FLUSH_LIST] - << " single page=" << n_flush[IORequest::SINGLE_PAGE] + << ", n pending flush LRU=" << n_flush_LRU + << " list=" << n_flush_list << ", pages made young=" << stat.n_pages_made_young << ", not young=" << stat.n_pages_not_made_young << ", pages read=" << stat.n_pages_read << ", created=" << stat.n_pages_created << ", written=" << stat.n_pages_written << "]"; - mutex_exit(&flush_list_mutex); + mysql_mutex_unlock(&flush_list_mutex); /* Count the number of blocks belonging to each index in the buffer */ @@ -4620,7 +4584,7 @@ void buf_pool_t::print() } } - mutex_exit(&mutex); + mysql_mutex_unlock(&mutex); for (i = 0; i < n_found; i++) { index = dict_index_get_if_in_cache(index_ids[i]); @@ -4650,14 +4614,14 @@ ulint buf_get_latched_pages_number() { ulint fixed_pages_number= 0; - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); for (buf_page_t *b= UT_LIST_GET_FIRST(buf_pool.LRU); b; b= UT_LIST_GET_NEXT(LRU, b)) if (b->in_file() && (b->buf_fix_count() || b->io_fix() != BUF_IO_NONE)) fixed_pages_number++; - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); return fixed_pages_number; } @@ -4670,8 +4634,8 @@ void buf_stats_get_pool_info(buf_pool_info_t *pool_info) time_t current_time; double time_elapsed; - mutex_enter(&buf_pool.mutex); - mutex_enter(&buf_pool.flush_list_mutex); + mysql_mutex_lock(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.flush_list_mutex); pool_info->pool_size = buf_pool.curr_size; @@ -4687,19 +4651,11 @@ void buf_stats_get_pool_info(buf_pool_info_t *pool_info) pool_info->n_pend_reads = buf_pool.n_pend_reads; - pool_info->n_pending_flush_lru = - (buf_pool.n_flush[IORequest::LRU] - + buf_pool.init_flush[IORequest::LRU]); + pool_info->n_pending_flush_lru = buf_pool.n_flush_LRU; - pool_info->n_pending_flush_list = - (buf_pool.n_flush[IORequest::FLUSH_LIST] - + buf_pool.init_flush[IORequest::FLUSH_LIST]); + pool_info->n_pending_flush_list = buf_pool.n_flush_list; - pool_info->n_pending_flush_single_page = - (buf_pool.n_flush[IORequest::SINGLE_PAGE] - + buf_pool.init_flush[IORequest::SINGLE_PAGE]); - - mutex_exit(&buf_pool.flush_list_mutex); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); current_time = time(NULL); time_elapsed = 0.001 + difftime(current_time, @@ -4790,7 +4746,7 @@ void buf_stats_get_pool_info(buf_pool_info_t *pool_info) pool_info->unzip_cur = buf_LRU_stat_cur.unzip; buf_refresh_io_stats(); - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); } /*********************************************************************//** @@ -4813,8 +4769,7 @@ buf_print_io_instance( "Percent of dirty pages(LRU & free pages): %.3f\n" "Max dirty pages percent: %.3f\n" "Pending reads " ULINTPF "\n" - "Pending writes: LRU " ULINTPF ", flush list " ULINTPF - ", single page " ULINTPF "\n", + "Pending writes: LRU " ULINTPF ", flush list " ULINTPF "\n", pool_info->pool_size, pool_info->free_list_len, pool_info->lru_len, @@ -4827,8 +4782,7 @@ buf_print_io_instance( srv_max_buf_pool_modified_pct, pool_info->n_pend_reads, pool_info->n_pending_flush_lru, - pool_info->n_pending_flush_list, - pool_info->n_pending_flush_single_page); + pool_info->n_pending_flush_list); fprintf(file, "Pages made young " ULINTPF ", not young " ULINTPF "\n" diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index 4a583bf7a9a..d9faf2ffe06 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -29,6 +29,7 @@ Created 2011/12/19 #include "buf0checksum.h" #include "srv0start.h" #include "srv0srv.h" +#include "sync0sync.h" #include "page0zip.h" #include "trx0sys.h" #include "fil0crypt.h" @@ -37,38 +38,7 @@ Created 2011/12/19 using st_::span; /** The doublewrite buffer */ -buf_dblwr_t* buf_dblwr = NULL; - -#define TRX_SYS_DOUBLEWRITE_BLOCKS 2 - -/****************************************************************//** -Determines if a page number is located inside the doublewrite buffer. -@return TRUE if the location is inside the two blocks of the -doublewrite buffer */ -ibool -buf_dblwr_page_inside( -/*==================*/ - ulint page_no) /*!< in: page number */ -{ - if (buf_dblwr == NULL) { - - return(FALSE); - } - - if (page_no >= buf_dblwr->block1 - && page_no < buf_dblwr->block1 - + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) { - return(TRUE); - } - - if (page_no >= buf_dblwr->block2 - && page_no < buf_dblwr->block2 - + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) { - return(TRUE); - } - - return(FALSE); -} +buf_dblwr_t buf_dblwr; /** @return the TRX_SYS page */ inline buf_block_t *buf_dblwr_trx_sys_get(mtr_t *mtr) @@ -79,616 +49,447 @@ inline buf_block_t *buf_dblwr_trx_sys_get(mtr_t *mtr) return block; } -/****************************************************************//** -Creates or initialializes the doublewrite buffer at a database start. */ -static void buf_dblwr_init(const byte *doublewrite) +/** Initialize the doublewrite buffer data structure. +@param header doublewrite page header in the TRX_SYS page */ +inline void buf_dblwr_t::init(const byte *header) { - ulint buf_size; + ut_ad(!first_free); + ut_ad(!reserved); + ut_ad(!batch_running); - buf_dblwr = static_cast( - ut_zalloc_nokey(sizeof(buf_dblwr_t))); + mysql_mutex_init(buf_dblwr_mutex_key, &mutex, nullptr); + mysql_cond_init(0, &cond, nullptr); + block1= page_id_t(0, mach_read_from_4(header + TRX_SYS_DOUBLEWRITE_BLOCK1)); + block2= page_id_t(0, mach_read_from_4(header + TRX_SYS_DOUBLEWRITE_BLOCK2)); - /* There are two blocks of same size in the doublewrite - buffer. */ - buf_size = TRX_SYS_DOUBLEWRITE_BLOCKS * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE; - - /* There must be atleast one buffer for single page writes - and one buffer for batch writes. */ - ut_a(srv_doublewrite_batch_size > 0 - && srv_doublewrite_batch_size < buf_size); - - mutex_create(LATCH_ID_BUF_DBLWR, &buf_dblwr->mutex); - - buf_dblwr->b_event = os_event_create("dblwr_batch_event"); - buf_dblwr->s_event = os_event_create("dblwr_single_event"); - buf_dblwr->first_free = 0; - buf_dblwr->s_reserved = 0; - buf_dblwr->b_reserved = 0; - - buf_dblwr->block1 = mach_read_from_4( - doublewrite + TRX_SYS_DOUBLEWRITE_BLOCK1); - buf_dblwr->block2 = mach_read_from_4( - doublewrite + TRX_SYS_DOUBLEWRITE_BLOCK2); - - buf_dblwr->write_buf = static_cast( - aligned_malloc(buf_size << srv_page_size_shift, - srv_page_size)); - - buf_dblwr->buf_block_arr = static_cast( - ut_zalloc_nokey(buf_size * sizeof(buf_dblwr_t::element))); + const uint32_t buf_size= 2 * block_size(); + write_buf= static_cast(aligned_malloc(buf_size << srv_page_size_shift, + srv_page_size)); + buf_block_arr= static_cast + (ut_zalloc_nokey(buf_size * sizeof(element))); } -/** Create the doublewrite buffer if the doublewrite buffer header -is not present in the TRX_SYS page. -@return whether the operation succeeded -@retval true if the doublewrite buffer exists or was created -@retval false if the creation failed (too small first data file) */ -bool -buf_dblwr_create() +/** Create or restore the doublewrite buffer in the TRX_SYS page. +@return whether the operation succeeded */ +bool buf_dblwr_t::create() { - buf_block_t* block2; - buf_block_t* new_block; - byte* fseg_header; - ulint page_no; - ulint prev_page_no; - ulint i; - mtr_t mtr; + if (is_initialised()) + return true; - if (buf_dblwr) { - /* Already inited */ - return(true); - } + mtr_t mtr; + const ulint size= block_size(); start_again: - mtr.start(); + mtr.start(); - buf_block_t *trx_sys_block = buf_dblwr_trx_sys_get(&mtr); + buf_block_t *trx_sys_block= buf_dblwr_trx_sys_get(&mtr); - if (mach_read_from_4(TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_MAGIC - + trx_sys_block->frame) - == TRX_SYS_DOUBLEWRITE_MAGIC_N) { - /* The doublewrite buffer has already been created: - just read in some numbers */ + if (mach_read_from_4(TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_MAGIC + + trx_sys_block->frame) == TRX_SYS_DOUBLEWRITE_MAGIC_N) + { + /* The doublewrite buffer has already been created: just read in + some numbers */ + init(TRX_SYS_DOUBLEWRITE + trx_sys_block->frame); + mtr.commit(); + return true; + } - buf_dblwr_init(TRX_SYS_DOUBLEWRITE + trx_sys_block->frame); - - mtr.commit(); - return(true); - } else { - if (UT_LIST_GET_FIRST(fil_system.sys_space->chain)->size - < 3 * FSP_EXTENT_SIZE) { - goto too_small; - } - } - - block2 = fseg_create(fil_system.sys_space, - TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG, - &mtr, false, trx_sys_block); - - if (block2 == NULL) { + if (UT_LIST_GET_FIRST(fil_system.sys_space->chain)->size < 3 * size) + { too_small: - ib::error() - << "Cannot create doublewrite buffer: " - "the first file in innodb_data_file_path" - " must be at least " - << (3 * (FSP_EXTENT_SIZE - >> (20U - srv_page_size_shift))) - << "M."; - mtr.commit(); - return(false); - } + ib::error() << "Cannot create doublewrite buffer: " + "the first file in innodb_data_file_path must be at least " + << (3 * (size >> (20U - srv_page_size_shift))) << "M."; + mtr.commit(); + return false; + } + else + { + buf_block_t *b= fseg_create(fil_system.sys_space, + TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG, + &mtr, false, trx_sys_block); + if (!b) + goto too_small; + ib::info() << "Doublewrite buffer not found: creating new"; - ib::info() << "Doublewrite buffer not found: creating new"; + /* FIXME: After this point, the doublewrite buffer creation + is not atomic. The doublewrite buffer should not exist in + the InnoDB system tablespace file in the first place. + It could be located in separate optional file(s) in a + user-specified location. */ - /* FIXME: After this point, the doublewrite buffer creation - is not atomic. The doublewrite buffer should not exist in - the InnoDB system tablespace file in the first place. - It could be located in separate optional file(s) in a - user-specified location. */ + /* fseg_create acquires a second latch on the page, + therefore we must declare it: */ + buf_block_dbg_add_level(b, SYNC_NO_ORDER_CHECK); + } - /* fseg_create acquires a second latch on the page, - therefore we must declare it: */ + byte *fseg_header= TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG + + trx_sys_block->frame; + for (ulint prev_page_no= 0, i= 0; i < 2 * size + FSP_EXTENT_SIZE / 2; i++) + { + buf_block_t *new_block= fseg_alloc_free_page(fseg_header, prev_page_no + 1, + FSP_UP, &mtr); + if (!new_block) + { + ib::error() << "Cannot create doublewrite buffer: " + " you must increase your tablespace size." + " Cannot continue operation."; + /* This may essentially corrupt the doublewrite + buffer. However, usually the doublewrite buffer + is created at database initialization, and it + should not matter (just remove all newly created + InnoDB files and restart). */ + mtr.commit(); + return false; + } - buf_block_dbg_add_level(block2, SYNC_NO_ORDER_CHECK); + /* We read the allocated pages to the buffer pool; when they are + written to disk in a flush, the space id and page number fields + are also written to the pages. When we at database startup read + pages from the doublewrite buffer, we know that if the space id + and page number in them are the same as the page position in the + tablespace, then the page has not been written to in + doublewrite. */ - fseg_header = TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG - + trx_sys_block->frame; - prev_page_no = 0; + ut_ad(rw_lock_get_x_lock_count(&new_block->lock) == 1); + const page_id_t id= new_block->page.id(); + /* We only do this in the debug build, to ensure that the check in + buf_flush_init_for_writing() will see a valid page type. The + flushes of new_block are actually unnecessary here. */ + ut_d(mtr.write<2>(*new_block, FIL_PAGE_TYPE + new_block->frame, + FIL_PAGE_TYPE_SYS)); - for (i = 0; i < TRX_SYS_DOUBLEWRITE_BLOCKS * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE - + FSP_EXTENT_SIZE / 2; i++) { - new_block = fseg_alloc_free_page( - fseg_header, prev_page_no + 1, FSP_UP, &mtr); - if (new_block == NULL) { - ib::error() << "Cannot create doublewrite buffer: " - " you must increase your tablespace size." - " Cannot continue operation."; - /* This may essentially corrupt the doublewrite - buffer. However, usually the doublewrite buffer - is created at database initialization, and it - should not matter (just remove all newly created - InnoDB files and restart). */ - mtr.commit(); - return(false); - } + if (i == size / 2) + { + ut_a(id.page_no() == size); + mtr.write<4>(*trx_sys_block, + TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_BLOCK1 + + trx_sys_block->frame, id.page_no()); + mtr.write<4>(*trx_sys_block, + TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_REPEAT + + TRX_SYS_DOUBLEWRITE_BLOCK1 + trx_sys_block->frame, + id.page_no()); + } + else if (i == size / 2 + size) + { + ut_a(id.page_no() == 2 * size); + mtr.write<4>(*trx_sys_block, + TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_BLOCK2 + + trx_sys_block->frame, id.page_no()); + mtr.write<4>(*trx_sys_block, + TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_REPEAT + + TRX_SYS_DOUBLEWRITE_BLOCK2 + trx_sys_block->frame, + id.page_no()); + } + else if (i > size / 2) + ut_a(id.page_no() == prev_page_no + 1); - /* We read the allocated pages to the buffer pool; - when they are written to disk in a flush, the space - id and page number fields are also written to the - pages. When we at database startup read pages - from the doublewrite buffer, we know that if the - space id and page number in them are the same as - the page position in the tablespace, then the page - has not been written to in doublewrite. */ + if (((i + 1) & 15) == 0) { + /* rw_locks can only be recursively x-locked 2048 times. (on 32 + bit platforms, (lint) 0 - (X_LOCK_DECR * 2049) is no longer a + negative number, and thus lock_word becomes like a shared lock). + For 4k page size this loop will lock the fseg header too many + times. Since this code is not done while any other threads are + active, restart the MTR occasionally. */ + mtr.commit(); + mtr.start(); + trx_sys_block= buf_dblwr_trx_sys_get(&mtr); + fseg_header= TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG + + trx_sys_block->frame; + } - ut_ad(rw_lock_get_x_lock_count(&new_block->lock) == 1); - page_no = new_block->page.id().page_no(); - /* We only do this in the debug build, to ensure that - the check in buf_flush_init_for_writing() will see a valid - page type. The flushes of new_block are actually - unnecessary here. */ - ut_d(mtr.write<2>(*new_block, - FIL_PAGE_TYPE + new_block->frame, - FIL_PAGE_TYPE_SYS)); + prev_page_no= id.page_no(); + } - if (i == FSP_EXTENT_SIZE / 2) { - ut_a(page_no == FSP_EXTENT_SIZE); - mtr.write<4>(*trx_sys_block, - TRX_SYS_DOUBLEWRITE - + TRX_SYS_DOUBLEWRITE_BLOCK1 - + trx_sys_block->frame, - page_no); - mtr.write<4>(*trx_sys_block, - TRX_SYS_DOUBLEWRITE - + TRX_SYS_DOUBLEWRITE_REPEAT - + TRX_SYS_DOUBLEWRITE_BLOCK1 - + trx_sys_block->frame, - page_no); + mtr.write<4>(*trx_sys_block, + TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_MAGIC + + trx_sys_block->frame, TRX_SYS_DOUBLEWRITE_MAGIC_N); + mtr.write<4>(*trx_sys_block, + TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_MAGIC + + TRX_SYS_DOUBLEWRITE_REPEAT + trx_sys_block->frame, + TRX_SYS_DOUBLEWRITE_MAGIC_N); - } else if (i == FSP_EXTENT_SIZE / 2 - + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) { - ut_a(page_no == 2 * FSP_EXTENT_SIZE); - mtr.write<4>(*trx_sys_block, - TRX_SYS_DOUBLEWRITE - + TRX_SYS_DOUBLEWRITE_BLOCK2 - + trx_sys_block->frame, - page_no); - mtr.write<4>(*trx_sys_block, - TRX_SYS_DOUBLEWRITE - + TRX_SYS_DOUBLEWRITE_REPEAT - + TRX_SYS_DOUBLEWRITE_BLOCK2 - + trx_sys_block->frame, - page_no); - } else if (i > FSP_EXTENT_SIZE / 2) { - ut_a(page_no == prev_page_no + 1); - } + mtr.write<4>(*trx_sys_block, + TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED + + trx_sys_block->frame, TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N); + mtr.commit(); - if (((i + 1) & 15) == 0) { - /* rw_locks can only be recursively x-locked - 2048 times. (on 32 bit platforms, - (lint) 0 - (X_LOCK_DECR * 2049) - is no longer a negative number, and thus - lock_word becomes like a shared lock). - For 4k page size this loop will - lock the fseg header too many times. Since - this code is not done while any other threads - are active, restart the MTR occasionally. */ - mtr.commit(); - mtr.start(); - trx_sys_block = buf_dblwr_trx_sys_get(&mtr); - fseg_header = TRX_SYS_DOUBLEWRITE - + TRX_SYS_DOUBLEWRITE_FSEG - + trx_sys_block->frame; - } + /* Flush the modified pages to disk and make a checkpoint */ + log_make_checkpoint(); - prev_page_no = page_no; - } + /* Remove doublewrite pages from LRU */ + buf_pool_invalidate(); - mtr.write<4>(*trx_sys_block, - TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_MAGIC - + trx_sys_block->frame, - TRX_SYS_DOUBLEWRITE_MAGIC_N); - mtr.write<4>(*trx_sys_block, - TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_MAGIC - + TRX_SYS_DOUBLEWRITE_REPEAT - + trx_sys_block->frame, - TRX_SYS_DOUBLEWRITE_MAGIC_N); - - mtr.write<4>(*trx_sys_block, - TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED - + trx_sys_block->frame, - TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N); - mtr.commit(); - - /* Flush the modified pages to disk and make a checkpoint */ - log_make_checkpoint(); - - /* Remove doublewrite pages from LRU */ - buf_pool_invalidate(); - - ib::info() << "Doublewrite buffer created"; - - goto start_again; + ib::info() << "Doublewrite buffer created"; + goto start_again; } -/** -At database startup initializes the doublewrite buffer memory structure if -we already have a doublewrite buffer created in the data files. If we are -upgrading to an InnoDB version which supports multiple tablespaces, then this -function performs the necessary update operations. If we are in a crash -recovery, this function loads the pages from double write buffer into memory. -@param[in] file File handle -@param[in] path Path name of file +/** Initialize the doublewrite buffer memory structure on recovery. +If we are upgrading from a version before MySQL 4.1, then this +function performs the necessary update operations to support +innodb_file_per_table. If we are in a crash recovery, this function +loads the pages from double write buffer into memory. +@param file File handle +@param path Path name of file @return DB_SUCCESS or error code */ -dberr_t -buf_dblwr_init_or_load_pages( - pfs_os_file_t file, - const char* path) +dberr_t buf_dblwr_t::init_or_load_pages(pfs_os_file_t file, const char *path) { - byte* buf; - byte* page; - ulint block1; - ulint block2; - ulint space_id; - byte* read_buf; - byte* doublewrite; - ibool reset_space_ids = FALSE; - recv_dblwr_t& recv_dblwr = recv_sys.dblwr; + ut_ad(this == &buf_dblwr); + const uint32_t size= block_size(); - /* We do the file i/o past the buffer pool */ - read_buf = static_cast( - aligned_malloc(2 * srv_page_size, srv_page_size)); + /* We do the file i/o past the buffer pool */ + byte *read_buf= static_cast(aligned_malloc(srv_page_size, + srv_page_size)); + /* Read the TRX_SYS header to check if we are using the doublewrite buffer */ + dberr_t err= os_file_read(IORequestRead, file, read_buf, + TRX_SYS_PAGE_NO << srv_page_size_shift, + srv_page_size); - /* Read the trx sys header to check if we are using the doublewrite - buffer */ - dberr_t err; - - IORequest read_request(IORequest::READ); - - err = os_file_read( - read_request, - file, read_buf, TRX_SYS_PAGE_NO << srv_page_size_shift, - srv_page_size); - - if (err != DB_SUCCESS) { - - ib::error() - << "Failed to read the system tablespace header page"; + if (err != DB_SUCCESS) + { + ib::error() << "Failed to read the system tablespace header page"; func_exit: - aligned_free(read_buf); - return(err); - } + aligned_free(read_buf); + return err; + } - doublewrite = read_buf + TRX_SYS_DOUBLEWRITE; + /* TRX_SYS_PAGE_NO is not encrypted see fil_crypt_rotate_page() */ + if (mach_read_from_4(TRX_SYS_DOUBLEWRITE_MAGIC + TRX_SYS_DOUBLEWRITE + + read_buf) != TRX_SYS_DOUBLEWRITE_MAGIC_N) + { + /* There is no doublewrite buffer initialized in the TRX_SYS page. + This should normally not be possible; the doublewrite buffer should + be initialized when creating the database. */ + err= DB_SUCCESS; + goto func_exit; + } - /* TRX_SYS_PAGE_NO is not encrypted see fil_crypt_rotate_page() */ + init(TRX_SYS_DOUBLEWRITE + read_buf); - if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC) - == TRX_SYS_DOUBLEWRITE_MAGIC_N) { - /* The doublewrite buffer has been created */ + const bool upgrade_to_innodb_file_per_table= + mach_read_from_4(TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED + + TRX_SYS_DOUBLEWRITE + read_buf) != + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N; - buf_dblwr_init(doublewrite); + /* Read the pages from the doublewrite buffer to memory */ + err= os_file_read(IORequestRead, file, write_buf, + block1.page_no() << srv_page_size_shift, + size << srv_page_size_shift); - block1 = buf_dblwr->block1; - block2 = buf_dblwr->block2; + if (err != DB_SUCCESS) + { + ib::error() << "Failed to read the first double write buffer extent"; + goto func_exit; + } - buf = buf_dblwr->write_buf; - } else { - err = DB_SUCCESS; - goto func_exit; - } + err= os_file_read(IORequestRead, file, + write_buf + (size << srv_page_size_shift), + block2.page_no() << srv_page_size_shift, + size << srv_page_size_shift); + if (err != DB_SUCCESS) + { + ib::error() << "Failed to read the second double write buffer extent"; + goto func_exit; + } - if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED) - != TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N) { + byte *page= write_buf; - /* We are upgrading from a version < 4.1.x to a version where - multiple tablespaces are supported. We must reset the space id - field in the pages in the doublewrite buffer because starting - from this version the space id is stored to - FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID. */ + if (UNIV_UNLIKELY(upgrade_to_innodb_file_per_table)) + { + ib::info() << "Resetting space id's in the doublewrite buffer"; - reset_space_ids = TRUE; + for (ulint i= 0; i < size * 2; i++, page += srv_page_size) + { + memset(page + FIL_PAGE_SPACE_ID, 0, 4); + /* For innodb_checksum_algorithm=innodb, we do not need to + calculate new checksums for the pages because the field + .._SPACE_ID does not affect them. Write the page back to where + we read it from. */ + const ulint source_page_no= i < size + ? block1.page_no() + i + : block2.page_no() + i - size; + err= os_file_write(IORequestWrite, path, file, page, + source_page_no << srv_page_size_shift, srv_page_size); + if (err != DB_SUCCESS) + { + ib::error() << "Failed to upgrade the double write buffer"; + goto func_exit; + } + } + os_file_flush(file); + } + else + for (ulint i= 0; i < size * 2; i++, page += srv_page_size) + if (mach_read_from_8(my_assume_aligned<8>(page + FIL_PAGE_LSN))) + /* Each valid page header must contain a nonzero FIL_PAGE_LSN field. */ + recv_sys.dblwr.add(page); - ib::info() << "Resetting space id's in the doublewrite buffer"; - } - - /* Read the pages from the doublewrite buffer to memory */ - err = os_file_read( - read_request, - file, buf, block1 << srv_page_size_shift, - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE << srv_page_size_shift); - - if (err != DB_SUCCESS) { - - ib::error() - << "Failed to read the first double write buffer " - "extent"; - goto func_exit; - } - - err = os_file_read( - read_request, - file, - buf + (TRX_SYS_DOUBLEWRITE_BLOCK_SIZE << srv_page_size_shift), - block2 << srv_page_size_shift, - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE << srv_page_size_shift); - - if (err != DB_SUCCESS) { - - ib::error() - << "Failed to read the second double write buffer " - "extent"; - goto func_exit; - } - - /* Check if any of these pages is half-written in data files, in the - intended position */ - - page = buf; - - for (ulint i = 0; i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * 2; i++) { - - if (reset_space_ids) { - ulint source_page_no; - - space_id = 0; - mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, - space_id); - /* We do not need to calculate new checksums for the - pages because the field .._SPACE_ID does not affect - them. Write the page back to where we read it from. */ - - if (i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) { - source_page_no = block1 + i; - } else { - source_page_no = block2 - + i - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE; - } - - err = os_file_write( - IORequestWrite, path, file, page, - source_page_no << srv_page_size_shift, - srv_page_size); - if (err != DB_SUCCESS) { - - ib::error() - << "Failed to write to the double write" - " buffer"; - goto func_exit; - } - } else if (mach_read_from_8(page + FIL_PAGE_LSN)) { - /* Each valid page header must contain - a nonzero FIL_PAGE_LSN field. */ - recv_dblwr.add(page); - } - - page += srv_page_size; - } - - if (reset_space_ids) { - os_file_flush(file); - } - - err = DB_SUCCESS; - goto func_exit; + err= DB_SUCCESS; + goto func_exit; } /** Process and remove the double write buffer pages for all tablespaces. */ -void -buf_dblwr_process() +void buf_dblwr_t::recover() { - ut_ad(recv_sys.parse_start_lsn); + ut_ad(recv_sys.parse_start_lsn); + if (!is_initialised()) + return; - ulint page_no_dblwr = 0; - byte* read_buf; - recv_dblwr_t& recv_dblwr = recv_sys.dblwr; + ulint page_no_dblwr= 0; + byte *read_buf= static_cast(aligned_malloc(3 * srv_page_size, + srv_page_size)); + byte *const buf= read_buf + srv_page_size; - if (!buf_dblwr) { - return; - } + for (recv_dblwr_t::list::iterator i= recv_sys.dblwr.pages.begin(); + i != recv_sys.dblwr.pages.end(); ++i, ++page_no_dblwr) + { + byte *page= *i; + const ulint page_no= page_get_page_no(page); + if (!page_no) /* recovered via Datafile::restore_from_doublewrite() */ + continue; - read_buf = static_cast( - aligned_malloc(3 * srv_page_size, srv_page_size)); - byte* const buf = read_buf + srv_page_size; + const lsn_t lsn= mach_read_from_8(page + FIL_PAGE_LSN); + if (recv_sys.parse_start_lsn > lsn) + /* Pages written before the checkpoint are not useful for recovery. */ + continue; + const ulint space_id= page_get_space_id(page); + const page_id_t page_id(space_id, page_no); - for (recv_dblwr_t::list::iterator i = recv_dblwr.pages.begin(); - i != recv_dblwr.pages.end(); - ++i, ++page_no_dblwr) { - byte* page = *i; - const ulint page_no = page_get_page_no(page); + if (recv_sys.scanned_lsn < lsn) + { + ib::warn() << "Ignoring a doublewrite copy of page " << page_id + << " with future log sequence number " << lsn; + continue; + } - if (!page_no) { - /* page 0 should have been recovered - already via Datafile::restore_from_doublewrite() */ - continue; - } + fil_space_t* space= fil_space_acquire_for_io(space_id); - const ulint space_id = page_get_space_id(page); - const lsn_t lsn = mach_read_from_8(page + FIL_PAGE_LSN); + if (!space) + /* The tablespace that this page once belonged to does not exist */ + continue; - if (recv_sys.parse_start_lsn > lsn) { - /* Pages written before the checkpoint are - not useful for recovery. */ - continue; - } + fil_space_open_if_needed(space); - const page_id_t page_id(space_id, page_no); - - if (recv_sys.scanned_lsn < lsn) { - ib::warn() << "Ignoring a doublewrite copy of page " - << page_id - << " with future log sequence number " - << lsn; - continue; - } - - fil_space_t* space = fil_space_acquire_for_io(space_id); - - if (!space) { - /* Maybe we have dropped the tablespace - and this page once belonged to it: do nothing */ - continue; - } - - fil_space_open_if_needed(space); - - if (UNIV_UNLIKELY(page_no >= space->size)) { - - /* Do not report the warning for undo - tablespaces, because they can be truncated in place. */ - if (!srv_is_undo_tablespace(space_id)) { - ib::warn() << "A copy of page " << page_no - << " in the doublewrite buffer slot " - << page_no_dblwr - << " is beyond the end of tablespace " - << space->name - << " (" << space->size << " pages)"; - } + if (UNIV_UNLIKELY(page_no >= space->size)) + { + /* Do not report the warning for undo tablespaces, because they + can be truncated in place. */ + if (!srv_is_undo_tablespace(space_id)) + ib::warn() << "A copy of page " << page_no + << " in the doublewrite buffer slot " << page_no_dblwr + << " is beyond the end of tablespace " << space->name + << " (" << space->size << " pages)"; next_page: - space->release_for_io(); - continue; - } + space->release_for_io(); + continue; + } - const ulint physical_size = space->physical_size(); - const ulint zip_size = space->zip_size(); - ut_ad(!buf_is_zeroes(span(page, physical_size))); + const ulint physical_size= space->physical_size(); + const ulint zip_size= space->zip_size(); + ut_ad(!buf_is_zeroes(span(page, physical_size))); - /* We want to ensure that for partial reads the - unread portion of the page is NUL. */ - memset(read_buf, 0x0, physical_size); + /* We want to ensure that for partial reads the unread portion of + the page is NUL. */ + memset(read_buf, 0x0, physical_size); - IORequest request; + /* Read in the actual page from the file */ + fil_io_t fio= fil_io(IORequest(IORequest::READ | IORequest::DBLWR_RECOVER), + true, page_id, zip_size, + 0, physical_size, read_buf, nullptr); - request.dblwr_recover(); + if (UNIV_UNLIKELY(fio.err != DB_SUCCESS)) + ib::warn() << "Double write buffer recovery: " << page_id + << " (tablespace '" << space->name + << "') read failed with error: " << fio.err; - /* Read in the actual page from the file */ - fil_io_t fio = fil_io( - request, true, - page_id, zip_size, - 0, physical_size, read_buf, NULL); + if (fio.node) + fio.node->space->release_for_io(); - if (UNIV_UNLIKELY(fio.err != DB_SUCCESS)) { - ib::warn() - << "Double write buffer recovery: " - << page_id << " read failed with " - << "error: " << fio.err; - } + if (buf_is_zeroes(span(read_buf, physical_size))) + { + /* We will check if the copy in the doublewrite buffer is + valid. If not, we will ignore this page (there should be redo + log records to initialize it). */ + } + else if (recv_sys.dblwr.validate_page(page_id, read_buf, space, buf)) + goto next_page; + else + /* We intentionally skip this message for all-zero pages. */ + ib::info() << "Trying to recover page " << page_id + << " from the doublewrite buffer."; - if (fio.node) { - fio.node->space->release_for_io(); - } + page= recv_sys.dblwr.find_page(page_id, space, buf); - if (buf_is_zeroes(span(read_buf, physical_size))) { - /* We will check if the copy in the - doublewrite buffer is valid. If not, we will - ignore this page (there should be redo log - records to initialize it). */ - } else if (recv_dblwr.validate_page( - page_id, read_buf, space, buf)) { - goto next_page; - } else { - /* We intentionally skip this message for - all-zero pages. */ - ib::info() - << "Trying to recover page " << page_id - << " from the doublewrite buffer."; - } + if (!page) + goto next_page; - page = recv_dblwr.find_page(page_id, space, buf); + /* Write the good page from the doublewrite buffer to the intended + position. */ + fio= fil_io(IORequestWrite, true, page_id, zip_size, 0, physical_size, + page, nullptr); - if (!page) { - goto next_page; - } + if (fio.node) + { + ut_ad(fio.err == DB_SUCCESS); + ib::info() << "Recovered page " << page_id << " to '" << fio.node->name + << "' from the doublewrite buffer."; + fio.node->space->release_for_io(); + goto next_page; + } + } - /* Write the good page from the doublewrite buffer to - the intended position. */ - fio = fil_io(IORequestWrite, true, page_id, zip_size, - 0, physical_size, page, nullptr); - - if (fio.node) { - ut_ad(fio.err == DB_SUCCESS); - ib::info() << "Recovered page " << page_id - << " to '" << fio.node->name - << "' from the doublewrite buffer."; - fio.node->space->release_for_io(); - } - - goto next_page; - } - - recv_dblwr.pages.clear(); - - fil_flush_file_spaces(); - aligned_free(read_buf); + recv_sys.dblwr.pages.clear(); + fil_flush_file_spaces(); + aligned_free(read_buf); } -/****************************************************************//** -Frees doublewrite buffer. */ -void -buf_dblwr_free() +/** Free the doublewrite buffer. */ +void buf_dblwr_t::close() { - /* Free the double write data structures. */ - ut_a(buf_dblwr != NULL); - ut_ad(buf_dblwr->s_reserved == 0); - ut_ad(buf_dblwr->b_reserved == 0); + if (!is_initialised()) + return; - os_event_destroy(buf_dblwr->b_event); - os_event_destroy(buf_dblwr->s_event); - aligned_free(buf_dblwr->write_buf); - ut_free(buf_dblwr->buf_block_arr); - mutex_free(&buf_dblwr->mutex); - ut_free(buf_dblwr); - buf_dblwr = NULL; + /* Free the double write data structures. */ + ut_ad(!reserved); + ut_ad(!first_free); + ut_ad(!batch_running); + + mysql_cond_destroy(&cond); + aligned_free(write_buf); + ut_free(buf_block_arr); + mysql_mutex_destroy(&mutex); + + memset((void*) this, 0, sizeof *this); } /** Update the doublewrite buffer on write completion. */ -void buf_dblwr_update(const buf_page_t &bpage, bool single_page) +void buf_dblwr_t::write_completed() { + ut_ad(this == &buf_dblwr); ut_ad(srv_use_doublewrite_buf); - ut_ad(buf_dblwr); - ut_ad(!fsp_is_system_temporary(bpage.id().space())); + ut_ad(is_initialised()); ut_ad(!srv_read_only_mode); - if (!single_page) + mysql_mutex_lock(&mutex); + + ut_ad(batch_running); + ut_ad(reserved); + ut_ad(reserved <= first_free); + + if (!--reserved) { - mutex_enter(&buf_dblwr->mutex); + mysql_mutex_unlock(&mutex); + /* This will finish the batch. Sync data files to the disk. */ + fil_flush_file_spaces(); + mysql_mutex_lock(&mutex); - ut_ad(buf_dblwr->batch_running); - ut_ad(buf_dblwr->b_reserved > 0); - ut_ad(buf_dblwr->b_reserved <= buf_dblwr->first_free); - - if (!--buf_dblwr->b_reserved) - { - mutex_exit(&buf_dblwr->mutex); - /* This will finish the batch. Sync data files to the disk. */ - fil_flush_file_spaces(); - mutex_enter(&buf_dblwr->mutex); - - /* We can now reuse the doublewrite memory buffer: */ - buf_dblwr->first_free= 0; - buf_dblwr->batch_running= false; - os_event_set(buf_dblwr->b_event); - } - - mutex_exit(&buf_dblwr->mutex); - return; + /* We can now reuse the doublewrite memory buffer: */ + first_free= 0; + batch_running= false; + mysql_cond_broadcast(&cond); } - ulint size= TRX_SYS_DOUBLEWRITE_BLOCKS * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE; - mutex_enter(&buf_dblwr->mutex); - for (ulint i= srv_doublewrite_batch_size; i < size; ++i) - { - if (buf_dblwr->buf_block_arr[i].bpage != &bpage) - continue; - buf_dblwr->s_reserved--; - buf_dblwr->buf_block_arr[i].bpage= nullptr; - os_event_set(buf_dblwr->s_event); - mutex_exit(&buf_dblwr->mutex); - return; - } - - /* The block must exist as a reserved block. */ - ut_error; + mysql_mutex_unlock(&mutex); } #ifdef UNIV_DEBUG @@ -718,390 +519,203 @@ static void buf_dblwr_check_page_lsn(const buf_page_t &b, const byte *page) space->release_for_io(); } } + +/** Check the LSN values on the page with which this block is associated. */ +static void buf_dblwr_check_block(const buf_page_t *bpage) +{ + ut_ad(bpage->state() == BUF_BLOCK_FILE_PAGE); + const page_t *page= reinterpret_cast(bpage)->frame; + + switch (fil_page_get_type(page)) { + case FIL_PAGE_INDEX: + case FIL_PAGE_TYPE_INSTANT: + case FIL_PAGE_RTREE: + if (page_is_comp(page)) + { + if (page_simple_validate_new(page)) + return; + } + else if (page_simple_validate_old(page)) + return; + /* While it is possible that this is not an index page but just + happens to have wrongly set FIL_PAGE_TYPE, such pages should never + be modified to without also adjusting the page type during page + allocation or buf_flush_init_for_writing() or + fil_block_reset_type(). */ + buf_page_print(page); + + ib::fatal() << "Apparent corruption of an index page " << bpage->id() + << " to be written to data file. We intentionally crash" + " the server to prevent corrupt data from ending up in" + " data files."; + } +} #endif /* UNIV_DEBUG */ -/********************************************************************//** -Asserts when a corrupt block is find during writing out data to the -disk. */ -static -void -buf_dblwr_assert_on_corrupt_block( -/*==============================*/ - const buf_block_t* block) /*!< in: block to check */ +bool buf_dblwr_t::flush_buffered_writes(const ulint size) { - buf_page_print(block->frame); + mysql_mutex_assert_owner(&mutex); + ut_ad(size == block_size()); - ib::fatal() << "Apparent corruption of an index page " - << block->page.id() - << " to be written to data file. We intentionally crash" - " the server to prevent corrupt data from ending up in" - " data files."; + for (;;) + { + if (!first_free) + return false; + if (!batch_running) + break; + mysql_cond_wait(&cond, &mutex); + } + + ut_ad(reserved == first_free); + /* Disallow anyone else to post to doublewrite buffer or to + start another batch of flushing. */ + batch_running= true; + const ulint old_first_free= first_free; + + /* Now safe to release the mutex. */ + mysql_mutex_unlock(&mutex); +#ifdef UNIV_DEBUG + for (ulint len2= 0, i= 0; i < old_first_free; len2 += srv_page_size, i++) + { + buf_page_t *bpage= buf_block_arr[i].bpage; + + if (bpage->zip.data) + /* No simple validate for ROW_FORMAT=COMPRESSED pages exists. */ + continue; + + /* Check that the actual page in the buffer pool is not corrupt + and the LSN values are sane. */ + buf_dblwr_check_block(bpage); + ut_d(buf_dblwr_check_page_lsn(*bpage, write_buf + len2)); + } +#endif /* UNIV_DEBUG */ + /* Write out the first block of the doublewrite buffer */ + fil_io_t fio= fil_io(IORequestWrite, true, block1, 0, 0, + std::min(size, old_first_free) << srv_page_size_shift, + write_buf, nullptr); + fio.node->space->release_for_io(); + + if (old_first_free > size) + { + /* Write out the second block of the doublewrite buffer. */ + fio= fil_io(IORequestWrite, true, block2, 0, 0, + (old_first_free - size) << srv_page_size_shift, + write_buf + (size << srv_page_size_shift), nullptr); + fio.node->space->release_for_io(); + } + + /* increment the doublewrite flushed pages counter */ + srv_stats.dblwr_pages_written.add(first_free); + srv_stats.dblwr_writes.inc(); + + /* Now flush the doublewrite buffer data to disk */ + fil_flush(TRX_SYS_SPACE); + + /* We know that the writes have been flushed to disk now + and in recovery we will find them in the doublewrite buffer + blocks. Next do the writes to the intended positions. */ + + /* Up to this point old_first_free == first_free because we have set + the batch_running flag disallowing any other thread to post any + request but we can't safely access first_free in the loop below. + This is so because it is possible that after we are done with the + last iteration and before we terminate the loop, the batch gets + finished in the IO helper thread and another thread posts a new + batch setting first_free to a higher value. If this happens and we + are using first_free in the loop termination condition then we'll + end up dispatching the same block twice from two different + threads. */ + ut_ad(old_first_free == first_free); + for (ulint i= 0; i < old_first_free; i++) + { + auto e= buf_block_arr[i]; + buf_page_t* bpage= e.bpage; + ut_a(bpage->in_file()); + + /* We request frame here to get correct buffer in case of + encryption and/or page compression */ + void *frame= buf_page_get_frame(bpage); + + auto e_size= e.size; + + if (UNIV_LIKELY_NULL(bpage->zip.data)) + { + e_size= bpage->zip_size(); + ut_ad(e_size); + } + else + { + ut_ad(bpage->state() == BUF_BLOCK_FILE_PAGE); + ut_ad(!bpage->zip_size()); + ut_d(buf_dblwr_check_page_lsn(*bpage, static_cast(frame))); + } + + fil_io(IORequest(IORequest::WRITE, bpage, e.lru), false, + bpage->id(), bpage->zip_size(), 0, e_size, frame, bpage); + } + + return true; } -/********************************************************************//** -Check the LSN values on the page with which this block is associated. -Also validate the page if the option is set. */ -static -void -buf_dblwr_check_block( -/*==================*/ - const buf_block_t* block) /*!< in: block to check */ +/** Flush possible buffered writes to persistent storage. +It is very important to call this function after a batch of writes has been +posted, and also when we may have to wait for a page latch! +Otherwise a deadlock of threads can occur. */ +void buf_dblwr_t::flush_buffered_writes() { - ut_ad(block->page.state() == BUF_BLOCK_FILE_PAGE); + if (!is_initialised() || !srv_use_doublewrite_buf) + { + os_aio_wait_until_no_pending_writes(); + fil_flush_file_spaces(); + return; + } - switch (fil_page_get_type(block->frame)) { - case FIL_PAGE_INDEX: - case FIL_PAGE_TYPE_INSTANT: - case FIL_PAGE_RTREE: - if (page_is_comp(block->frame)) { - if (page_simple_validate_new(block->frame)) { - return; - } - } else if (page_simple_validate_old(block->frame)) { - return; - } - /* While it is possible that this is not an index page - but just happens to have wrongly set FIL_PAGE_TYPE, - such pages should never be modified to without also - adjusting the page type during page allocation or - buf_flush_init_for_writing() or fil_block_reset_type(). */ - break; - case FIL_PAGE_TYPE_FSP_HDR: - case FIL_PAGE_IBUF_BITMAP: - case FIL_PAGE_TYPE_UNKNOWN: - /* Do not complain again, we already reset this field. */ - case FIL_PAGE_UNDO_LOG: - case FIL_PAGE_INODE: - case FIL_PAGE_IBUF_FREE_LIST: - case FIL_PAGE_TYPE_SYS: - case FIL_PAGE_TYPE_TRX_SYS: - case FIL_PAGE_TYPE_XDES: - case FIL_PAGE_TYPE_BLOB: - case FIL_PAGE_TYPE_ZBLOB: - case FIL_PAGE_TYPE_ZBLOB2: - /* TODO: validate also non-index pages */ - return; - case FIL_PAGE_TYPE_ALLOCATED: - /* empty pages should never be flushed */ - return; - } + ut_ad(!srv_read_only_mode); + const ulint size= block_size(); - buf_dblwr_assert_on_corrupt_block(block); -} - -/********************************************************************//** -Writes a page that has already been written to the doublewrite buffer -to the datafile. It is the job of the caller to sync the datafile. */ -static void -buf_dblwr_write_block_to_datafile(const buf_dblwr_t::element &e, bool sync) -{ - ut_ad(!sync || e.flush == IORequest::SINGLE_PAGE); - buf_page_t* bpage = e.bpage; - ut_a(bpage->in_file()); - IORequest request(IORequest::WRITE, bpage, e.flush); - - /* We request frame here to get correct buffer in case of - encryption and/or page compression */ - void * frame = buf_page_get_frame(bpage); - - fil_io_t fio; - - if (bpage->zip.data) { - ut_ad(bpage->zip_size()); - - fio = fil_io(request, sync, bpage->id(), bpage->zip_size(), 0, - bpage->zip_size(), frame, bpage); - } else { - ut_ad(bpage->state() == BUF_BLOCK_FILE_PAGE); - ut_ad(!bpage->zip_size()); - - ut_d(buf_dblwr_check_page_lsn(*bpage, static_cast - (frame))); - fio = fil_io(request, - sync, bpage->id(), bpage->zip_size(), 0, - e.size, frame, bpage); - } - - if (sync && fio.node) { - ut_ad(fio.err == DB_SUCCESS); - fio.node->space->release_for_io(); - } -} - -/********************************************************************//** -Flushes possible buffered writes from the doublewrite memory buffer to disk. -It is very important to call this function after a batch of writes has been posted, -and also when we may have to wait for a page latch! Otherwise a deadlock -of threads can occur. */ -void -buf_dblwr_flush_buffered_writes() -{ - byte* write_buf; - ulint first_free; - ulint len; - - if (!srv_use_doublewrite_buf || buf_dblwr == NULL) { - /* Sync the writes to the disk. */ - os_aio_wait_until_no_pending_writes(); - /* Now we flush the data to disk (for example, with fsync) */ - fil_flush_file_spaces(); - return; - } - - ut_ad(!srv_read_only_mode); - -try_again: - mutex_enter(&buf_dblwr->mutex); - - /* Write first to doublewrite buffer blocks. We use synchronous - aio and thus know that file write has been completed when the - control returns. */ - - if (buf_dblwr->first_free == 0) { - - mutex_exit(&buf_dblwr->mutex); - return; - } - - if (buf_dblwr->batch_running) { - /* Another thread is running the batch right now. Wait - for it to finish. */ - int64_t sig_count = os_event_reset(buf_dblwr->b_event); - mutex_exit(&buf_dblwr->mutex); - - os_event_wait_low(buf_dblwr->b_event, sig_count); - goto try_again; - } - - ut_ad(buf_dblwr->first_free == buf_dblwr->b_reserved); - - /* Disallow anyone else to post to doublewrite buffer or to - start another batch of flushing. */ - buf_dblwr->batch_running = true; - first_free = buf_dblwr->first_free; - - /* Now safe to release the mutex. Note that though no other - thread is allowed to post to the doublewrite batch flushing - but any threads working on single page flushes are allowed - to proceed. */ - mutex_exit(&buf_dblwr->mutex); - - write_buf = buf_dblwr->write_buf; - - for (ulint len2 = 0, i = 0; - i < buf_dblwr->first_free; - len2 += srv_page_size, i++) { - - buf_page_t* bpage= buf_dblwr->buf_block_arr[i].bpage; - - if (bpage->state() != BUF_BLOCK_FILE_PAGE || bpage->zip.data) { - /* No simple validate for compressed - pages exists. */ - continue; - } - - /* Check that the actual page in the buffer pool is - not corrupt and the LSN values are sane. */ - buf_dblwr_check_block(reinterpret_cast(bpage)); - ut_d(buf_dblwr_check_page_lsn(*bpage, write_buf + len2)); - } - - /* Write out the first block of the doublewrite buffer */ - len = std::min(TRX_SYS_DOUBLEWRITE_BLOCK_SIZE, - buf_dblwr->first_free) << srv_page_size_shift; - - fil_io_t fio = fil_io(IORequestWrite, true, - page_id_t(TRX_SYS_SPACE, buf_dblwr->block1), 0, - 0, len, write_buf, nullptr); - fio.node->space->release_for_io(); - - if (buf_dblwr->first_free <= TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) { - /* No unwritten pages in the second block. */ - goto flush; - } - - /* Write out the second block of the doublewrite buffer. */ - len = (buf_dblwr->first_free - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) - << srv_page_size_shift; - - write_buf = buf_dblwr->write_buf - + (TRX_SYS_DOUBLEWRITE_BLOCK_SIZE << srv_page_size_shift); - - fio = fil_io(IORequestWrite, true, - page_id_t(TRX_SYS_SPACE, buf_dblwr->block2), 0, - 0, len, write_buf, nullptr); - fio.node->space->release_for_io(); - -flush: - /* increment the doublewrite flushed pages counter */ - srv_stats.dblwr_pages_written.add(buf_dblwr->first_free); - srv_stats.dblwr_writes.inc(); - - /* Now flush the doublewrite buffer data to disk */ - fil_flush(TRX_SYS_SPACE); - - /* We know that the writes have been flushed to disk now - and in recovery we will find them in the doublewrite buffer - blocks. Next do the writes to the intended positions. */ - - /* Up to this point first_free and buf_dblwr->first_free are - same because we have set the buf_dblwr->batch_running flag - disallowing any other thread to post any request but we - can't safely access buf_dblwr->first_free in the loop below. - This is so because it is possible that after we are done with - the last iteration and before we terminate the loop, the batch - gets finished in the IO helper thread and another thread posts - a new batch setting buf_dblwr->first_free to a higher value. - If this happens and we are using buf_dblwr->first_free in the - loop termination condition then we'll end up dispatching - the same block twice from two different threads. */ - ut_ad(first_free == buf_dblwr->first_free); - for (ulint i = 0; i < first_free; i++) { - buf_dblwr_write_block_to_datafile( - buf_dblwr->buf_block_arr[i], false); - } + mysql_mutex_lock(&mutex); + if (!flush_buffered_writes(size)) + mysql_mutex_unlock(&mutex); } /** Schedule a page write. If the doublewrite memory buffer is full, -buf_dblwr_flush_buffered_writes() will be invoked to make space. -@param bpage buffer pool page to be written -@param flush type of flush -@param size payload size in bytes */ -void buf_dblwr_t::add_to_batch(buf_page_t *bpage, IORequest::flush_t flush, - size_t size) +flush_buffered_writes() will be invoked to make space. +@param bpage buffer pool page to be written +@param lru true=buf_pool.LRU; false=buf_pool.flush_list +@param size payload size in bytes */ +void buf_dblwr_t::add_to_batch(buf_page_t *bpage, bool lru, size_t size) { ut_ad(bpage->in_file()); - ut_ad(flush == IORequest::LRU || flush == IORequest::FLUSH_LIST); + const ulint buf_size= 2 * block_size(); -try_again: - mutex_enter(&mutex); + mysql_mutex_lock(&mutex); - ut_a(first_free <= srv_doublewrite_batch_size); - - if (batch_running) + for (;;) { - /* This not nearly as bad as it looks. There is only page_cleaner - thread which does background flushing in batches therefore it is - unlikely to be a contention point. The only exception is when a - user thread is forced to do a flush batch because of a sync - checkpoint. */ - int64_t sig_count= os_event_reset(b_event); - mutex_exit(&mutex); + while (batch_running) + mysql_cond_wait(&cond, &mutex); - os_event_wait_low(b_event, sig_count); - goto try_again; - } + ut_ad(first_free <= buf_size); + if (first_free != buf_size) + break; - if (first_free == srv_doublewrite_batch_size) - { - mutex_exit(&mutex); - buf_dblwr_flush_buffered_writes(); - goto try_again; + if (flush_buffered_writes(buf_size / 2)) + mysql_mutex_lock(&mutex); } byte *p= write_buf + srv_page_size * first_free; /* We request frame here to get correct buffer in case of encryption and/or page compression */ - void * frame = buf_page_get_frame(bpage); + void *frame= buf_page_get_frame(bpage); memcpy_aligned(p, frame, size); ut_ad(!bpage->zip_size() || bpage->zip_size() == size); - buf_block_arr[first_free++] = { bpage, flush, size }; - b_reserved++; + ut_ad(reserved == first_free); + ut_ad(reserved < buf_size); + buf_block_arr[first_free++]= { bpage, lru, size }; + reserved= first_free; - ut_ad(!batch_running); - ut_ad(first_free == b_reserved); - ut_ad(b_reserved <= srv_doublewrite_batch_size); - - const bool need_flush= first_free == srv_doublewrite_batch_size; - mutex_exit(&mutex); - - if (need_flush) - buf_dblwr_flush_buffered_writes(); -} - -/** Write a page to the doublewrite buffer on disk, sync it, then write -the page to the datafile and sync the datafile. This function is used -for single page flushes. If all the buffers allocated for single page -flushes in the doublewrite buffer are in use we wait here for one to -become free. We are guaranteed that a slot will become free because any -thread that is using a slot must also release the slot before leaving -this function. -@param bpage buffer pool page to be written -@param sync whether synchronous operation is requested -@param size payload size in bytes */ -void buf_dblwr_t::write_single_page(buf_page_t *bpage, bool sync, size_t size) -{ - ut_ad(bpage->in_file()); - ut_ad(srv_use_doublewrite_buf); - ut_ad(this == buf_dblwr); - - /* total number of slots available for single page flushes - starts from srv_doublewrite_batch_size to the end of the buffer. */ - ulint slots = TRX_SYS_DOUBLEWRITE_BLOCKS * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE; - ut_a(slots > srv_doublewrite_batch_size); - ulint n_slots= slots - srv_doublewrite_batch_size; - - if (bpage->state() == BUF_BLOCK_FILE_PAGE) - { - /* Check that the actual page in the buffer pool is not corrupt - and the LSN values are sane. */ - buf_dblwr_check_block(reinterpret_cast(bpage)); -#ifdef UNIV_DEBUG - /* Check that the page as written to the doublewrite buffer has - sane LSN values. */ - if (!bpage->zip.data) - buf_dblwr_check_page_lsn(*bpage, reinterpret_cast - (bpage)->frame); -#endif - } - -retry: - mutex_enter(&mutex); - if (s_reserved == n_slots) - { - /* All slots are reserved. */ - int64_t sig_count = os_event_reset(s_event); - mutex_exit(&mutex); - os_event_wait_low(s_event, sig_count); - goto retry; - } - - ulint i; - for (i = srv_doublewrite_batch_size; i < slots; ++i) - if (!buf_block_arr[i].bpage) - goto found; - /* We are guaranteed to find a slot. */ - ut_error; -found: - s_reserved++; - buf_block_arr[i]= { bpage, IORequest::SINGLE_PAGE, size }; - - /* increment the doublewrite flushed pages counter */ - srv_stats.dblwr_pages_written.inc(); - srv_stats.dblwr_writes.inc(); - - mutex_exit(&mutex); - - const ulint offset= i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE - ? block1 + i - : block2 + i - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE; - - /* We request frame here to get correct buffer in case of - encryption and/or page compression */ - void * frame = buf_page_get_frame(bpage); - ut_ad(!bpage->zip_size() || bpage->zip_size() == size); - fil_io_t fio= fil_io(IORequestWrite, true, page_id_t(TRX_SYS_SPACE, offset), - 0, 0, size, frame, nullptr); - fio.node->space->release_for_io(); - - /* Now flush the doublewrite buffer data to disk */ - fil_flush(TRX_SYS_SPACE); - - /* We know that the write has been flushed to disk now - and during recovery we will find it in the doublewrite buffer - blocks. Next do the write to the intended position. */ - buf_dblwr_write_block_to_datafile({bpage, IORequest::SINGLE_PAGE, size}, - sync); + if (first_free != buf_size || !flush_buffered_writes(buf_size / 2)) + mysql_mutex_unlock(&mutex); } diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc index d468000f894..01b523d6e94 100644 --- a/storage/innobase/buf/buf0dump.cc +++ b/storage/innobase/buf/buf0dump.cc @@ -276,13 +276,13 @@ buf_dump( ulint n_pages; ulint j; - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); n_pages = UT_LIST_GET_LEN(buf_pool.LRU); /* skip empty buffer pools */ if (n_pages == 0) { - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); goto done; } @@ -310,7 +310,7 @@ buf_dump( n_pages * sizeof(*dump))); if (dump == NULL) { - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); fclose(f); buf_dump_status(STATUS_ERR, "Cannot allocate " ULINTPF " bytes: %s", @@ -335,7 +335,7 @@ buf_dump( dump[j++] = id; } - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); ut_a(j <= n_pages); n_pages = j; diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 10ed54be452..0f8084886c1 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -34,20 +34,10 @@ Created 11/11/1995 Heikki Tuuri #include "buf0checksum.h" #include "buf0dblwr.h" #include "srv0start.h" -#include "srv0srv.h" #include "page0zip.h" -#include "ut0byte.h" -#include "page0page.h" #include "fil0fil.h" -#include "buf0lru.h" -#include "buf0rea.h" -#include "ibuf0ibuf.h" -#include "log0log.h" #include "log0crypt.h" -#include "os0file.h" -#include "trx0sys.h" #include "srv0mon.h" -#include "ut0stage.h" #include "fil0pagecompress.h" #ifdef UNIV_LINUX /* include defs for CPU time priority settings */ @@ -55,30 +45,25 @@ Created 11/11/1995 Heikki Tuuri #include #include #include -static const int buf_flush_page_cleaner_priority = -20; #endif /* UNIV_LINUX */ #ifdef HAVE_LZO -#include "lzo/lzo1x.h" -#endif - -#ifdef HAVE_SNAPPY -#include "snappy-c.h" +# include "lzo/lzo1x.h" +#elif defined HAVE_SNAPPY +# include "snappy-c.h" #endif /** Sleep time in microseconds for loop waiting for the oldest modification lsn */ -static const ulint buf_flush_wait_flushed_sleep_time = 10000; +static constexpr ulint buf_flush_wait_flushed_sleep_time = 10000; -#include - -/** Number of pages flushed through non flush_list flushes. */ +/** Number of pages flushed via LRU. Protected by buf_pool.mutex. +Also included in buf_flush_page_count. */ ulint buf_lru_flush_page_count; -/** Flag indicating if the page_cleaner is in active state. This flag -is set to TRUE by the page_cleaner thread when it is spawned and is set -back to FALSE at shutdown by the page_cleaner as well. Therefore no -need to protect it by a mutex. It is only ever read by the thread -doing the shutdown */ +/** Number of pages flushed. Protected by buf_pool.mutex. */ +ulint buf_flush_page_count; + +/** Flag indicating if the page_cleaner is in active state. */ bool buf_page_cleaner_is_active; /** Factor for scan length to determine n_pages for intended oldest LSN @@ -89,63 +74,20 @@ static ulint buf_flush_lsn_scan_factor = 3; static lsn_t lsn_avg_rate = 0; /** Target oldest LSN for the requested flush_sync */ -static lsn_t buf_flush_sync_lsn = 0; +static std::atomic buf_flush_sync_lsn; #ifdef UNIV_PFS_THREAD mysql_pfs_key_t page_cleaner_thread_key; #endif /* UNIV_PFS_THREAD */ -/** Event to synchronise with the flushing. */ -os_event_t buf_flush_event; - -static void pc_flush_slot_func(void *); -static tpool::task_group page_cleaner_task_group(1); -static tpool::waitable_task pc_flush_slot_task( - pc_flush_slot_func, 0, &page_cleaner_task_group); - -/** State for page cleaner array slot */ -enum page_cleaner_state_t { - /** Not requested any yet. Moved from FINISHED. */ - PAGE_CLEANER_STATE_NONE = 0, - /** Requested but not started flushing. Moved from NONE. */ - PAGE_CLEANER_STATE_REQUESTED, - /** Flushing is on going. Moved from REQUESTED. */ - PAGE_CLEANER_STATE_FLUSHING, - /** Flushing was finished. Moved from FLUSHING. */ - PAGE_CLEANER_STATE_FINISHED -}; - /** Page cleaner request state for buf_pool */ struct page_cleaner_slot_t { - page_cleaner_state_t state; /*!< state of the request. - protected by page_cleaner_t::mutex - if the worker thread got the slot and - set to PAGE_CLEANER_STATE_FLUSHING, - n_flushed_lru and n_flushed_list can be - updated only by the worker thread */ - /* This value is set during state==PAGE_CLEANER_STATE_NONE */ - ulint n_pages_requested; - /*!< number of requested pages - for the slot */ - /* These values are updated during state==PAGE_CLEANER_STATE_FLUSHING, - and commited with state==PAGE_CLEANER_STATE_FINISHED. - The consistency is protected by the 'state' */ - ulint n_flushed_lru; - /*!< number of flushed pages - by LRU scan flushing */ ulint n_flushed_list; /*!< number of flushed pages by flush_list flushing */ - bool succeeded_list; - /*!< true if flush_list flushing - succeeded. */ - ulint flush_lru_time; - /*!< elapsed time for LRU flushing */ ulint flush_list_time; /*!< elapsed time for flush_list flushing */ - ulint flush_lru_pass; - /*!< count to attempt LRU flushing */ ulint flush_list_pass; /*!< count to attempt flush_list flushing */ @@ -153,37 +95,11 @@ struct page_cleaner_slot_t { /** Page cleaner structure */ struct page_cleaner_t { - /* FIXME: do we need mutex? use atomics? */ - ib_mutex_t mutex; /*!< mutex to protect whole of - page_cleaner_t struct and - page_cleaner_slot_t slots. */ - os_event_t is_finished; /*!< event to signal that all - slots were finished. */ - bool requested; /*!< true if requested pages - to flush */ - lsn_t lsn_limit; /*!< upper limit of LSN to be - flushed */ -#if 1 /* FIXME: use bool for these, or remove some of these */ - ulint n_slots_requested; - /*!< number of slots - in the state - PAGE_CLEANER_STATE_REQUESTED */ - ulint n_slots_flushing; - /*!< number of slots - in the state - PAGE_CLEANER_STATE_FLUSHING */ - ulint n_slots_finished; - /*!< number of slots - in the state - PAGE_CLEANER_STATE_FINISHED */ -#endif ulint flush_time; /*!< elapsed time to flush requests for all slots */ ulint flush_pass; /*!< count to finish to flush requests for all slots */ page_cleaner_slot_t slot; - bool is_running; /*!< false if attempt - to shutdown */ }; static page_cleaner_t page_cleaner; @@ -200,15 +116,6 @@ in thrashing. */ /* @} */ -/** Increases flush_list size in bytes with the page size */ -static inline void incr_flush_list_size_in_bytes(const buf_block_t* block) -{ - /* FIXME: use std::atomic! */ - ut_ad(mutex_own(&buf_pool.flush_list_mutex)); - buf_pool.stat.flush_list_bytes += block->physical_size(); - ut_ad(buf_pool.stat.flush_list_bytes <= buf_pool.curr_pool_size); -} - #ifdef UNIV_DEBUG /** Validate the flush list. */ static void buf_flush_validate_low(); @@ -241,37 +148,29 @@ static void buf_flush_validate_skip() @param[in] lsn oldest modification */ void buf_flush_insert_into_flush_list(buf_block_t* block, lsn_t lsn) { - ut_ad(!mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_not_owner(&buf_pool.mutex); ut_ad(log_flush_order_mutex_own()); ut_ad(lsn); - mutex_enter(&buf_pool.flush_list_mutex); + mysql_mutex_lock(&buf_pool.flush_list_mutex); block->page.set_oldest_modification(lsn); MEM_CHECK_DEFINED(block->page.zip.data - ? block->page.zip.data : block->frame, - block->physical_size()); - incr_flush_list_size_in_bytes(block); + ? block->page.zip.data : block->frame, + block->physical_size()); + buf_pool.stat.flush_list_bytes += block->physical_size(); + ut_ad(buf_pool.stat.flush_list_bytes <= buf_pool.curr_pool_size); UT_LIST_ADD_FIRST(buf_pool.flush_list, &block->page); ut_d(buf_flush_validate_skip()); - mutex_exit(&buf_pool.flush_list_mutex); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); } /** Remove a block from the flush list of modified blocks. -@param[in] bpage block to be removed from the flush list */ -void buf_flush_remove(buf_page_t* bpage) +@param[in,out] bpage block to be removed from the flush list */ +static void buf_flush_remove(buf_page_t *bpage) { -#if 0 // FIXME: Rate-limit the output. Move this to the page cleaner? - if (UNIV_UNLIKELY(srv_shutdown_state == SRV_SHUTDOWN_FLUSH_PHASE)) { - service_manager_extend_timeout( - INNODB_EXTEND_TIMEOUT_INTERVAL, - "Flush and remove page with tablespace id %u" - ", flush list length " ULINTPF, - bpage->space, UT_LIST_GET_LEN(buf_pool.flush_list)); - } -#endif - ut_ad(mutex_own(&buf_pool.mutex)); - mutex_enter(&buf_pool.flush_list_mutex); + mysql_mutex_assert_owner(&buf_pool.mutex); + mysql_mutex_assert_owner(&buf_pool.flush_list_mutex); /* Important that we adjust the hazard pointer before removing the bpage from flush list. */ @@ -284,8 +183,78 @@ void buf_flush_remove(buf_page_t* bpage) #ifdef UNIV_DEBUG buf_flush_validate_skip(); #endif /* UNIV_DEBUG */ +} - mutex_exit(&buf_pool.flush_list_mutex); +/** Remove all dirty pages belonging to a given tablespace when we are +deleting the data file of that tablespace. +The pages still remain a part of LRU and are evicted from +the list as they age towards the tail of the LRU. +@param id tablespace identifier */ +void buf_flush_remove_pages(ulint id) +{ + const page_id_t first(id, 0), end(id + 1, 0); + ut_ad(id); + mysql_mutex_lock(&buf_pool.mutex); + + for (;;) + { + bool deferred= false; + + mysql_mutex_lock(&buf_pool.flush_list_mutex); + + for (buf_page_t *bpage= UT_LIST_GET_LAST(buf_pool.flush_list); bpage; ) + { + ut_ad(bpage->in_file()); + buf_page_t *prev= UT_LIST_GET_PREV(list, bpage); + + const page_id_t bpage_id(bpage->id()); + + if (bpage_id < first || bpage_id >= end); + else if (bpage->io_fix() != BUF_IO_NONE) + deferred= true; + else + buf_flush_remove(bpage); + + bpage= prev; + } + + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + + if (!deferred) + break; + + mysql_mutex_unlock(&buf_pool.mutex); + os_thread_yield(); + mysql_mutex_lock(&buf_pool.mutex); + buf_flush_wait_batch_end(false); + } + + mysql_mutex_unlock(&buf_pool.mutex); +} + +/** Try to flush all the dirty pages that belong to a given tablespace. +@param id tablespace identifier +@return number dirty pages that there were for this tablespace */ +ulint buf_flush_dirty_pages(ulint id) +{ + ut_ad(!sync_check_iterate(dict_sync_check())); + + ulint n= 0; + + mysql_mutex_lock(&buf_pool.flush_list_mutex); + + for (buf_page_t *bpage= UT_LIST_GET_FIRST(buf_pool.flush_list); bpage; + bpage= UT_LIST_GET_NEXT(list, bpage)) + { + ut_ad(bpage->in_file()); + ut_ad(bpage->oldest_modification()); + if (id == bpage->id().space()) + n++; + } + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + if (n) + buf_flush_lists(ULINT_UNDEFINED, LSN_MAX); + return n; } /*******************************************************************//** @@ -299,6 +268,7 @@ use the current list node (bpage) to do the list manipulation because the list pointers could have changed between the time that we copied the contents of bpage to the dpage and the flush list manipulation below. */ +ATTRIBUTE_COLD void buf_flush_relocate_on_flush_list( /*=============================*/ @@ -307,8 +277,13 @@ buf_flush_relocate_on_flush_list( { buf_page_t* prev; - ut_ad(mutex_own(&buf_pool.mutex)); - mutex_enter(&buf_pool.flush_list_mutex); + mysql_mutex_assert_owner(&buf_pool.mutex); + + if (!bpage->oldest_modification()) { + return; + } + + mysql_mutex_lock(&buf_pool.flush_list_mutex); /* FIXME: At this point we have both buf_pool and flush_list mutexes. Theoretically removal of a block from flush list is @@ -330,56 +305,29 @@ buf_flush_relocate_on_flush_list( if (prev) { ut_ad(prev->oldest_modification()); - UT_LIST_INSERT_AFTER( buf_pool.flush_list, prev, dpage); + UT_LIST_INSERT_AFTER(buf_pool.flush_list, prev, dpage); } else { UT_LIST_ADD_FIRST(buf_pool.flush_list, dpage); } ut_d(buf_flush_validate_low()); - mutex_exit(&buf_pool.flush_list_mutex); -} - -/** Update the buf_pool data structures on write completion. -@param[in,out] bpage written page -@param[in] flush_type write request type -@param[in] dblwr whether the doublewrite buffer was used */ -static void buf_flush_write_complete(buf_page_t *bpage, - IORequest::flush_t flush_type, bool dblwr) -{ - ut_ad(mutex_own(&buf_pool.mutex)); - buf_flush_remove(bpage); - - switch (--buf_pool.n_flush[flush_type]) { -#ifdef UNIV_DEBUG - case ULINT_UNDEFINED: - ut_error; - break; -#endif - case 0: - if (!buf_pool.init_flush[flush_type]) - os_event_set(buf_pool.no_flush[flush_type]); - } - - if (dblwr) - buf_dblwr_update(*bpage, flush_type == IORequest::SINGLE_PAGE); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); } /** Complete write of a file page from buf_pool. @param bpage written page @param request write request -@param dblwr whether the doublewrite buffer was used -@param evict whether or not to evict the page from LRU list */ +@param dblwr whether the doublewrite buffer was used */ void buf_page_write_complete(buf_page_t *bpage, const IORequest &request, - bool dblwr, bool evict) + bool dblwr) { ut_ad(request.is_write()); ut_ad(bpage->in_file()); ut_ad(bpage->io_fix() == BUF_IO_WRITE); - ut_ad(bpage->id().space() != TRX_SYS_SPACE || - !buf_dblwr_page_inside(bpage->id().page_no())); + ut_ad(!buf_dblwr.is_inside(bpage->id())); /* We do not need protect io_fix here by mutex to read it because - this and buf_page_write_complete() are the only functions where we can + this and buf_page_read_complete() are the only functions where we can change the value from BUF_IO_READ or BUF_IO_WRITE to some other value, and our code ensures that this is the only thread that handles the i/o for this block. */ @@ -393,9 +341,19 @@ void buf_page_write_complete(buf_page_t *bpage, const IORequest &request, buf_page_monitor(bpage, BUF_IO_WRITE); DBUG_PRINT("ib_buf", ("write page %u:%u", bpage->id().space(), bpage->id().page_no())); - mutex_enter(&buf_pool.mutex); + ut_ad(request.is_LRU() ? buf_pool.n_flush_LRU : buf_pool.n_flush_list); + + mysql_mutex_lock(&buf_pool.mutex); bpage->set_io_fix(BUF_IO_NONE); - buf_flush_write_complete(bpage, request.flush_type(), dblwr); + mysql_mutex_lock(&buf_pool.flush_list_mutex); + buf_flush_remove(bpage); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + + if (dblwr) + { + ut_ad(!fsp_is_system_temporary(bpage->id().space())); + buf_dblwr.write_completed(); + } /* Because this thread which does the unlocking might not be the same that did the locking, we use a pass value != 0 in unlock, which simply @@ -405,10 +363,19 @@ void buf_page_write_complete(buf_page_t *bpage, const IORequest &request, buf_pool.stat.n_pages_written++; - if (evict) + if (request.is_LRU()) + { buf_LRU_free_page(bpage, true); + if (!--buf_pool.n_flush_LRU) + mysql_cond_broadcast(&buf_pool.done_flush_LRU); + } + else + { + if (!--buf_pool.n_flush_list) + mysql_cond_broadcast(&buf_pool.done_flush_list); + } - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); } /** Calculate a ROW_FORMAT=COMPRESSED page checksum and update the page. @@ -803,72 +770,47 @@ static void buf_release_freed_page(buf_page_t *bpage) { ut_ad(bpage->in_file()); const bool uncompressed= bpage->state() == BUF_BLOCK_FILE_PAGE; - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); bpage->set_io_fix(BUF_IO_NONE); bpage->status= buf_page_t::NORMAL; + mysql_mutex_lock(&buf_pool.flush_list_mutex); buf_flush_remove(bpage); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); if (uncompressed) rw_lock_sx_unlock_gen(&reinterpret_cast(bpage)->lock, BUF_IO_WRITE); buf_LRU_free_page(bpage, true); - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); } /** Write a flushable page from buf_pool to a file. buf_pool.mutex must be held. @param bpage buffer control block -@param flush_type type of flush -@param space tablespace (or nullptr if not known) -@param sync whether this is a synchronous request - (only for flush_type=SINGLE_PAGE) +@param lru true=buf_pool.LRU; false=buf_pool.flush_list +@param space tablespace @return whether the page was flushed and buf_pool.mutex was released */ -bool buf_flush_page(buf_page_t *bpage, IORequest::flush_t flush_type, - fil_space_t *space, bool sync) +static bool buf_flush_page(buf_page_t *bpage, bool lru, fil_space_t *space) { ut_ad(bpage->in_file()); ut_ad(bpage->ready_for_flush()); - ut_ad(!sync || flush_type == IORequest::SINGLE_PAGE); - ut_ad(mutex_own(&buf_pool.mutex)); rw_lock_t *rw_lock; - bool no_fix_count= bpage->buf_fix_count() == 0; if (bpage->state() != BUF_BLOCK_FILE_PAGE) rw_lock= nullptr; - else if (!(no_fix_count || flush_type == IORequest::FLUSH_LIST) || - (!no_fix_count && srv_shutdown_state <= SRV_SHUTDOWN_CLEANUP && - fsp_is_system_temporary(bpage->id().space()))) - /* This is a heuristic, to avoid expensive SX attempts. */ - /* For table residing in temporary tablespace sync is done - using IO_FIX and so before scheduling for flush ensure that - page is not fixed. */ - return false; else { rw_lock= &reinterpret_cast(bpage)->lock; - if (flush_type != IORequest::FLUSH_LIST && - !rw_lock_sx_lock_nowait(rw_lock, BUF_IO_WRITE)) + if (!rw_lock_sx_lock_nowait(rw_lock, BUF_IO_WRITE)) return false; } - /* We are committed to flushing by the time we get here */ bpage->set_io_fix(BUF_IO_WRITE); - mutex_exit(&buf_pool.mutex); - - if (flush_type == IORequest::FLUSH_LIST && rw_lock && - !rw_lock_sx_lock_nowait(rw_lock, BUF_IO_WRITE)) - { - if (!fsp_is_system_temporary(bpage->id().space())) - /* Avoid a potential deadlock with the doublewrite buffer, - which might be holding another buf_block_t::lock. */ - buf_dblwr_flush_buffered_writes(); - else - os_aio_wait_until_no_pending_writes(); - - rw_lock_sx_lock_gen(rw_lock, BUF_IO_WRITE); - } + buf_flush_page_count++; + mysql_mutex_unlock(&buf_pool.mutex); + mysql_mutex_assert_not_owner(&buf_pool.flush_list_mutex); /* We are holding rw_lock = buf_block_t::lock in SX mode except if this is a ROW_FORMAT=COMPRESSED page whose uncompressed page frame @@ -877,38 +819,21 @@ bool buf_flush_page(buf_page_t *bpage, IORequest::flush_t flush_type, Apart from possible rw_lock protection, bpage is also protected by io_fix and oldest_modification()!=0. Thus, it cannot be relocated in the buffer pool or removed from flush_list or LRU_list. */ -#if 0 /* rw_lock_own() does not hold because we passed BUF_IO_WRITE above. */ - ut_ad(!rw_lock || rw_lock_own(rw_lock, RW_LOCK_SX)); -#endif - const fil_space_t * const provided_space= space; - if (!space) - { - space= fil_space_acquire_for_io(bpage->id().space()); - if (UNIV_UNLIKELY(!space)) - { - mutex_enter(&buf_pool.mutex); - bpage->status= buf_page_t::NORMAL; - bpage->set_io_fix(BUF_IO_NONE); - if (rw_lock) - rw_lock_sx_unlock_gen(rw_lock, BUF_IO_WRITE); - return false; - } - } ut_ad((space->purpose == FIL_TYPE_TEMPORARY) == (space == fil_system.temp_space)); + ut_ad(space->purpose == FIL_TYPE_TABLESPACE || + space->atomic_write_supported); - const bool full_crc32= space->full_crc32(); - - DBUG_PRINT("ib_buf", ("flush %s %u page %u:%u", - sync ? "sync" : "async", (unsigned) flush_type, + DBUG_PRINT("ib_buf", ("%s %u page %u:%u", + lru ? "LRU" : "flush_list", bpage->id().space(), bpage->id().page_no())); - ut_ad(!mutex_own(&buf_pool.mutex)); - ut_ad(!mutex_own(&buf_pool.flush_list_mutex)); ut_ad(bpage->io_fix() == BUF_IO_WRITE); ut_ad(bpage->oldest_modification()); ut_ad(bpage->state() == (rw_lock ? BUF_BLOCK_FILE_PAGE : BUF_BLOCK_ZIP_PAGE)); + ut_ad(ULINT_UNDEFINED > + (lru ? buf_pool.n_flush_LRU : buf_pool.n_flush_list)); /* Because bpage->status can only be changed while buf_block_t exists, it cannot be modified for ROW_FORMAT=COMPRESSED pages @@ -917,22 +842,29 @@ bool buf_flush_page(buf_page_t *bpage, IORequest::flush_t flush_type, is protected even if !rw_lock. */ const auto status= bpage->status; - if (status != buf_page_t::FREED) + buf_block_t *block= reinterpret_cast(bpage); + page_t *frame= bpage->zip.data; + + if (UNIV_LIKELY(space->purpose == FIL_TYPE_TABLESPACE)) { - switch (buf_pool.n_flush[flush_type]++) { - case 0: - os_event_reset(buf_pool.no_flush[flush_type]); - break; -#ifdef UNIV_DEBUG - case ULINT_UNDEFINED: - ut_error; - break; -#endif + const lsn_t lsn= mach_read_from_8(my_assume_aligned<8> + (FIL_PAGE_LSN + + (frame ? frame : block->frame))); + ut_ad(lsn); + ut_ad(lsn >= bpage->oldest_modification()); + ut_ad(!srv_read_only_mode); + if (UNIV_UNLIKELY(lsn > log_sys.get_flushed_lsn())) + { + if (rw_lock) + rw_lock_sx_unlock_gen(rw_lock, BUF_IO_WRITE); + mysql_mutex_lock(&buf_pool.mutex); + bpage->set_io_fix(BUF_IO_NONE); + return false; } } - page_t *frame= bpage->zip.data; size_t size, orig_size; + ulint type= IORequest::WRITE; if (UNIV_UNLIKELY(!rw_lock)) /* ROW_FORMAT=COMPRESSED */ { @@ -948,43 +880,37 @@ bool buf_flush_page(buf_page_t *bpage, IORequest::flush_t flush_type, } else { - buf_block_t *block= reinterpret_cast(bpage); byte *page= block->frame; orig_size= size= block->physical_size(); - if (status != buf_page_t::FREED) + if (status == buf_page_t::FREED); + else if (space->full_crc32()) + { + /* innodb_checksum_algorithm=full_crc32 is not implemented for + ROW_FORMAT=COMPRESSED pages. */ + ut_ad(!frame); + page= buf_page_encrypt(space, bpage, page, &size); + buf_flush_init_for_writing(block, page, nullptr, true); + } + else { - if (full_crc32) - { - /* innodb_checksum_algorithm=full_crc32 is not implemented for - ROW_FORMAT=COMPRESSED pages. */ - ut_ad(!frame); - page= buf_page_encrypt(space, bpage, page, &size); - } - buf_flush_init_for_writing(block, page, frame ? &bpage->zip : nullptr, - full_crc32); - - if (!full_crc32) - page= buf_page_encrypt(space, bpage, frame ? frame : page, &size); + false); + page= buf_page_encrypt(space, bpage, frame ? frame : page, &size); } +#if defined HAVE_FALLOC_PUNCH_HOLE_AND_KEEP_SIZE || defined _WIN32 + if (size != orig_size && space->punch_hole) + type|= IORequest::PUNCH_HOLE; +#else + DBUG_EXECUTE_IF("ignore_punch_hole", + if (size != orig_size && space->punch_hole) + type|= IORequest::PUNCH_HOLE;); +#endif frame= page; } - if (UNIV_LIKELY(space->purpose == FIL_TYPE_TABLESPACE)) - { - const lsn_t lsn= mach_read_from_8(frame + FIL_PAGE_LSN); - ut_ad(lsn); - ut_ad(lsn >= bpage->oldest_modification()); - ut_ad(!srv_read_only_mode); - log_write_up_to(lsn, true); - } - else - ut_ad(space->atomic_write_supported); - - bool use_doublewrite; - IORequest request(IORequest::WRITE, bpage, flush_type); + IORequest request(type, bpage, lru); ut_ad(status == bpage->status); @@ -992,49 +918,29 @@ bool buf_flush_page(buf_page_t *bpage, IORequest::flush_t flush_type, default: ut_ad(status == buf_page_t::FREED); buf_release_freed_page(bpage); - goto done; + break; case buf_page_t::NORMAL: - use_doublewrite= space->use_doublewrite(); - - if (use_doublewrite) + if (space->use_doublewrite()) { ut_ad(!srv_read_only_mode); - if (flush_type == IORequest::SINGLE_PAGE) - buf_dblwr->write_single_page(bpage, sync, size); + if (lru) + buf_pool.n_flush_LRU++; else - buf_dblwr->add_to_batch(bpage, flush_type, size); + buf_pool.n_flush_list++; + buf_dblwr.add_to_batch(bpage, lru, size); break; } /* fall through */ case buf_page_t::INIT_ON_FLUSH: - use_doublewrite= false; - if (size != orig_size) - request.set_punch_hole(); + if (lru) + buf_pool.n_flush_LRU++; + else + buf_pool.n_flush_list++; /* FIXME: pass space to fil_io() */ - fil_io_t fio= fil_io(request, sync, bpage->id(), bpage->zip_size(), 0, - bpage->physical_size(), frame, bpage); - ut_ad(!fio.node || fio.node->space == space); - if (fio.node && sync) - fio.node->space->release_for_io(); + fil_io(request, false, bpage->id(), bpage->zip_size(), 0, + bpage->physical_size(), frame, bpage); } - if (sync) - { - ut_ad(bpage->io_fix() == BUF_IO_WRITE); - - /* When flushing single page synchronously, we flush the changes - only for the tablespace we are working on. */ - if (space->purpose != FIL_TYPE_TEMPORARY) - fil_flush(space); - - if (size != orig_size && space->punch_hole) - request.set_punch_hole(); - buf_page_write_complete(bpage, request, use_doublewrite, true/*evict*/); - } - -done: - if (!provided_space) - space->release_for_io(); /* Increment the I/O operation count used for selecting LRU policy. */ buf_LRU_stat_inc_io(); return true; @@ -1042,15 +948,15 @@ done: /** Check whether a page can be flushed from the buf_pool. @param id page identifier -@param flush LRU or FLUSH_LIST +@param fold id.fold() +@param lru true=buf_pool.LRU; false=buf_pool.flush_list @return whether the page can be flushed */ -static bool buf_flush_check_neighbor(const page_id_t id, - IORequest::flush_t flush) +static bool buf_flush_check_neighbor(const page_id_t id, ulint fold, bool lru) { - ut_ad(flush == IORequest::LRU || flush == IORequest::FLUSH_LIST); - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); + ut_ad(fold == id.fold()); - buf_page_t *bpage= buf_pool.page_hash_get_low(id, id.fold()); + buf_page_t *bpage= buf_pool.page_hash_get_low(id, fold); if (!bpage || buf_pool.watch_is_sentinel(*bpage)) return false; @@ -1058,22 +964,20 @@ static bool buf_flush_check_neighbor(const page_id_t id, /* We avoid flushing 'non-old' blocks in an LRU flush, because the flushed blocks are soon freed */ - return (flush != IORequest::LRU || bpage->is_old()) && - bpage->ready_for_flush(); + return (!lru || bpage->is_old()) && bpage->ready_for_flush(); } /** Check which neighbors of a page can be flushed from the buf_pool. @param space tablespace @param id page identifier of a dirty page @param contiguous whether to consider contiguous areas of pages -@param flush LRU or FLUSH_LIST +@param lru true=buf_pool.LRU; false=buf_pool.flush_list @return last page number that can be flushed */ static page_id_t buf_flush_check_neighbors(const fil_space_t &space, page_id_t &id, bool contiguous, - IORequest::flush_t flush) + bool lru) { ut_ad(id.page_no() < space.size); - ut_ad(flush == IORequest::LRU || flush == IORequest::FLUSH_LIST); /* When flushed, dirty blocks are searched in neighborhoods of this size, and flushed along with the original page. */ const ulint s= buf_pool.curr_size / 16; @@ -1095,7 +999,7 @@ static page_id_t buf_flush_check_neighbors(const fil_space_t &space, /* Determine the contiguous dirty area around id. */ const ulint id_fold= id.fold(); - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); if (id > low) { @@ -1103,8 +1007,7 @@ static page_id_t buf_flush_check_neighbors(const fil_space_t &space, for (page_id_t i= id - 1;; --i) { fold--; - ut_ad(i.fold() == fold); - if (!buf_flush_check_neighbor(i, flush)) + if (!buf_flush_check_neighbor(i, fold, lru)) { low= i + 1; break; @@ -1120,12 +1023,11 @@ static page_id_t buf_flush_check_neighbors(const fil_space_t &space, while (++i < high) { ++fold; - ut_ad(i.fold() == fold); - if (!buf_flush_check_neighbor(i, flush)) + if (!buf_flush_check_neighbor(i, fold, lru)) break; } - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); return i; } @@ -1183,100 +1085,67 @@ static void buf_flush_freed_pages(fil_space_t *space) /** Flushes to disk all flushable pages within the flush area and also write zeroes or punch the hole for the freed ranges of pages. -@param[in] page_id page id -@param[in] flush LRU or FLUSH_LIST -@param[in] n_flushed number of pages flushed so far in this batch -@param[in] n_to_flush maximum number of pages we are allowed to flush +@param space tablespace +@param page_id page identifier +@param contiguous whether to consider contiguous areas of pages +@param lru true=buf_pool.LRU; false=buf_pool.flush_list +@param n_flushed number of pages flushed so far in this batch +@param n_to_flush maximum number of pages we are allowed to flush @return number of pages flushed */ -static -ulint -buf_flush_try_neighbors( - const page_id_t page_id, - IORequest::flush_t flush, - ulint n_flushed, - ulint n_to_flush) +static ulint buf_flush_try_neighbors(fil_space_t *space, + const page_id_t page_id, + bool contiguous, bool lru, + ulint n_flushed, ulint n_to_flush) { - ulint count = 0; + ut_ad(space->id == page_id.space()); - ut_ad(flush == IORequest::LRU || flush == IORequest::FLUSH_LIST); - fil_space_t* space = fil_space_acquire_for_io(page_id.space()); - if (!space) { - return 0; - } + ulint count= 0; + page_id_t id= page_id; + page_id_t high= buf_flush_check_neighbors(*space, id, contiguous, lru); - /* Flush the freed ranges while flushing the neighbors */ - buf_flush_freed_pages(space); + ut_ad(page_id >= id); + ut_ad(page_id < high); - const auto neighbors= srv_flush_neighbors; + for (ulint id_fold= id.fold(); id < high; ++id, ++id_fold) + { + if (count + n_flushed >= n_to_flush) + { + if (id > page_id) + break; + /* If the page whose neighbors we are flushing has not been + flushed yet, we must flush the page that we selected originally. */ + id= page_id; + id_fold= id.fold(); + } - page_id_t id = page_id; - page_id_t high = (!neighbors - || UT_LIST_GET_LEN(buf_pool.LRU) - < BUF_LRU_OLD_MIN_LEN - || !space->is_rotational()) - ? id + 1 /* Flush the minimum. */ - : buf_flush_check_neighbors(*space, id, neighbors == 1, flush); + mysql_mutex_lock(&buf_pool.mutex); - ut_ad(page_id >= id); - ut_ad(page_id < high); + if (buf_page_t *bpage= buf_pool.page_hash_get_low(id, id_fold)) + { + ut_ad(bpage->in_file()); + /* We avoid flushing 'non-old' blocks in an LRU flush, + because the flushed blocks are soon freed */ + if (!lru || id == page_id || bpage->is_old()) + { + if (bpage->ready_for_flush() && buf_flush_page(bpage, lru, space)) + { + ++count; + continue; + } + } + } - for (; id < high; ++id) { - buf_page_t* bpage; + mysql_mutex_unlock(&buf_pool.mutex); + } - if ((count + n_flushed) >= n_to_flush) { + if (auto n= count - 1) + { + MONITOR_INC_VALUE_CUMULATIVE(MONITOR_FLUSH_NEIGHBOR_TOTAL_PAGE, + MONITOR_FLUSH_NEIGHBOR_COUNT, + MONITOR_FLUSH_NEIGHBOR_PAGES, n); + } - /* We have already flushed enough pages and - should call it a day. There is, however, one - exception. If the page whose neighbors we - are flushing has not been flushed yet then - we'll try to flush the victim that we - selected originally. */ - if (id <= page_id) { - id = page_id; - } else { - break; - } - } - - const ulint fold = id.fold(); - - mutex_enter(&buf_pool.mutex); - - bpage = buf_pool.page_hash_get_low(id, fold); - - if (bpage == NULL) { - mutex_exit(&buf_pool.mutex); - continue; - } - - ut_a(bpage->in_file()); - - /* We avoid flushing 'non-old' blocks in an LRU flush, - because the flushed blocks are soon freed */ - - if (flush != IORequest::LRU - || id == page_id || bpage->is_old()) { - if (bpage->ready_for_flush() - && (id == page_id || bpage->buf_fix_count() == 0) - && buf_flush_page(bpage, flush, space, false)) { - ++count; - continue; - } - } - mutex_exit(&buf_pool.mutex); - } - - space->release_for_io(); - - if (count > 1) { - MONITOR_INC_VALUE_CUMULATIVE( - MONITOR_FLUSH_NEIGHBOR_TOTAL_PAGE, - MONITOR_FLUSH_NEIGHBOR_COUNT, - MONITOR_FLUSH_NEIGHBOR_PAGES, - (count - 1)); - } - - return(count); + return count; } /*******************************************************************//** @@ -1293,17 +1162,16 @@ static ulint buf_free_from_unzip_LRU_list_batch(ulint max) { ulint scanned = 0; ulint count = 0; - ulint free_len = UT_LIST_GET_LEN(buf_pool.free); - ulint lru_len = UT_LIST_GET_LEN(buf_pool.unzip_LRU); - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); buf_block_t* block = UT_LIST_GET_LAST(buf_pool.unzip_LRU); - while (block != NULL + while (block && count < max - && free_len < srv_LRU_scan_depth - && lru_len > UT_LIST_GET_LEN(buf_pool.LRU) / 10) { + && UT_LIST_GET_LEN(buf_pool.free) < srv_LRU_scan_depth + && UT_LIST_GET_LEN(buf_pool.unzip_LRU) + > UT_LIST_GET_LEN(buf_pool.LRU) / 10) { ++scanned; if (buf_LRU_free_page(&block->page, false)) { @@ -1311,14 +1179,12 @@ static ulint buf_free_from_unzip_LRU_list_batch(ulint max) released and reacquired */ ++count; block = UT_LIST_GET_LAST(buf_pool.unzip_LRU); - free_len = UT_LIST_GET_LEN(buf_pool.free); - lru_len = UT_LIST_GET_LEN(buf_pool.unzip_LRU); } else { block = UT_LIST_GET_PREV(unzip_LRU, block); } } - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); if (scanned) { MONITOR_INC_VALUE_CUMULATIVE( @@ -1331,23 +1197,42 @@ static ulint buf_free_from_unzip_LRU_list_batch(ulint max) return(count); } -/** Flush dirty blocks from the end of the LRU list. -The calling thread is not allowed to own any latches on pages! +/** Start writing out pages for a tablespace. +@param id tablespace identifier +@return tablespace +@retval nullptr if the pages for this tablespace should be discarded */ +static fil_space_t *buf_flush_space(const uint32_t id) +{ + fil_space_t *space= fil_space_acquire_for_io(id); + if (space) + buf_flush_freed_pages(space); + return space; +} -@param[in] max desired number of blocks to make available - in the free list (best effort; not guaranteed) -@param[out] n counts of flushed and evicted pages */ +struct flush_counters_t +{ + /** number of dirty pages flushed */ + ulint flushed; + /** number of clean pages evicted */ + ulint evicted; +}; + +/** Flush dirty blocks from the end of the LRU list. +@param max maximum number of blocks to make available in buf_pool.free +@param n counts of flushed and evicted pages */ static void buf_flush_LRU_list_batch(ulint max, flush_counters_t *n) { ulint scanned= 0; ulint free_limit= srv_LRU_scan_depth; - n->flushed = 0; - n->evicted = 0; - n->unzip_LRU_evicted = 0; - ut_ad(mutex_own(&buf_pool.mutex)); + + mysql_mutex_assert_owner(&buf_pool.mutex); if (buf_pool.withdraw_target && buf_pool.curr_size < buf_pool.old_size) free_limit+= buf_pool.withdraw_target - UT_LIST_GET_LEN(buf_pool.withdraw); + const auto neighbors= UT_LIST_GET_LEN(buf_pool.LRU) < BUF_LRU_OLD_MIN_LEN + ? 0 : srv_flush_neighbors; + fil_space_t *space= nullptr; + for (buf_page_t *bpage= UT_LIST_GET_LAST(buf_pool.LRU); bpage && n->flushed + n->evicted < max && UT_LIST_GET_LEN(buf_pool.LRU) > BUF_LRU_MIN_LEN && @@ -1369,10 +1254,28 @@ static void buf_flush_LRU_list_batch(ulint max, flush_counters_t *n) /* Block is ready for flush. Dispatch an IO request. The IO helper thread will put it on free list in IO completion routine. */ const page_id_t page_id(bpage->id()); - mutex_exit(&buf_pool.mutex); - n->flushed+= buf_flush_try_neighbors(page_id, IORequest::LRU, n->flushed, - max); - mutex_enter(&buf_pool.mutex); + const uint32_t space_id= page_id.space(); + if (!space || space->id != space_id) + { + if (space) + space->release_for_io(); + space= buf_flush_space(space_id); + if (!space) + continue; + } + if (neighbors && space->is_rotational()) + { + mysql_mutex_unlock(&buf_pool.mutex); + n->flushed+= buf_flush_try_neighbors(space, page_id, neighbors == 1, + true, n->flushed, max); +reacquire_mutex: + mysql_mutex_lock(&buf_pool.mutex); + } + else if (buf_flush_page(bpage, true, space)) + { + ++n->flushed; + goto reacquire_mutex; + } } else /* Can't evict or dispatch this block. Go to previous. */ @@ -1381,18 +1284,16 @@ static void buf_flush_LRU_list_batch(ulint max, flush_counters_t *n) buf_pool.lru_hp.set(nullptr); + if (space) + space->release_for_io(); + /* We keep track of all flushes happening as part of LRU flush. When estimating the desired rate at which flush_list should be flushed, we factor in this value. */ buf_lru_flush_page_count+= n->flushed; - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); - if (n->evicted) - MONITOR_INC_VALUE_CUMULATIVE(MONITOR_LRU_BATCH_EVICT_TOTAL_PAGE, - MONITOR_LRU_BATCH_EVICT_COUNT, - MONITOR_LRU_BATCH_EVICT_PAGES, - n->evicted); if (scanned) MONITOR_INC_VALUE_CUMULATIVE(MONITOR_LRU_BATCH_SCANNED, MONITOR_LRU_BATCH_SCANNED_NUM_CALL, @@ -1402,44 +1303,49 @@ static void buf_flush_LRU_list_batch(ulint max, flush_counters_t *n) /** Flush and move pages from LRU or unzip_LRU list to the free list. Whether LRU or unzip_LRU is used depends on the state of the system. -@param[in] max desired number of blocks to make available - in the free list (best effort; not guaranteed) -@param[out] n counts of flushed and evicted pages */ -static void buf_do_LRU_batch(ulint max, flush_counters_t* n) +@param max maximum number of blocks to make available in buf_pool.free +@return number of flushed pages */ +static ulint buf_do_LRU_batch(ulint max) { - n->unzip_LRU_evicted = buf_LRU_evict_from_unzip_LRU() - ? buf_free_from_unzip_LRU_list_batch(max) : 0; + const ulint n_unzip_LRU_evicted= buf_LRU_evict_from_unzip_LRU() + ? buf_free_from_unzip_LRU_list_batch(max) + : 0; + flush_counters_t n; + n.flushed= 0; + n.evicted= n_unzip_LRU_evicted; + buf_flush_LRU_list_batch(max, &n); - if (max > n->unzip_LRU_evicted) { - buf_flush_LRU_list_batch(max - n->unzip_LRU_evicted, n); - } else { - n->evicted = 0; - n->flushed = 0; - } + if (const ulint evicted= n.evicted - n_unzip_LRU_evicted) + { + MONITOR_INC_VALUE_CUMULATIVE(MONITOR_LRU_BATCH_EVICT_TOTAL_PAGE, + MONITOR_LRU_BATCH_EVICT_COUNT, + MONITOR_LRU_BATCH_EVICT_PAGES, + evicted); + } - /* Add evicted pages from unzip_LRU to the evicted pages from - the simple LRU. */ - n->evicted += n->unzip_LRU_evicted; + return n.flushed; } /** This utility flushes dirty blocks from the end of the flush_list. The calling thread is not allowed to own any latches on pages! -@param[in] min_n wished minimum mumber of blocks flushed (it is -not guaranteed that the actual number is that big, though) -@param[in] lsn_limit all blocks whose oldest_modification is smaller -than this should be flushed (if their number does not exceed min_n) +@param max_n maximum mumber of blocks to flush +@param lsn once an oldest_modification>=lsn is found, terminate the batch @return number of blocks for which the write request was queued */ -static ulint buf_do_flush_list_batch(ulint min_n, lsn_t lsn_limit) +static ulint buf_do_flush_list_batch(ulint max_n, lsn_t lsn) { ulint count= 0; ulint scanned= 0; - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); + + const auto neighbors= UT_LIST_GET_LEN(buf_pool.LRU) < BUF_LRU_OLD_MIN_LEN + ? 0 : srv_flush_neighbors; + fil_space_t *space= nullptr; /* Start from the end of the list looking for a suitable block to be flushed. */ - mutex_enter(&buf_pool.flush_list_mutex); - ulint len = UT_LIST_GET_LEN(buf_pool.flush_list); + mysql_mutex_lock(&buf_pool.flush_list_mutex); + ulint len= UT_LIST_GET_LEN(buf_pool.flush_list); /* In order not to degenerate this scan to O(n*n) we attempt to preserve pointer of previous block in the flush list. To do so we @@ -1447,17 +1353,17 @@ static ulint buf_do_flush_list_batch(ulint min_n, lsn_t lsn_limit) must check the hazard pointer and if it is removing the same block then it must reset it. */ for (buf_page_t *bpage= UT_LIST_GET_LAST(buf_pool.flush_list); - bpage && len && count < min_n; + bpage && len && count < max_n; bpage= buf_pool.flush_hp.get(), ++scanned, len--) { const lsn_t oldest_modification= bpage->oldest_modification(); - if (oldest_modification >= lsn_limit) + if (oldest_modification >= lsn) break; - ut_a(oldest_modification); + ut_ad(oldest_modification); buf_page_t *prev= UT_LIST_GET_PREV(list, bpage); buf_pool.flush_hp.set(prev); - mutex_exit(&buf_pool.flush_list_mutex); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); ut_ad(bpage->in_file()); const bool flushed= bpage->ready_for_flush(); @@ -1465,18 +1371,39 @@ static ulint buf_do_flush_list_batch(ulint min_n, lsn_t lsn_limit) if (flushed) { const page_id_t page_id(bpage->id()); - mutex_exit(&buf_pool.mutex); - count+= buf_flush_try_neighbors(page_id, IORequest::FLUSH_LIST, - count, min_n); - mutex_enter(&buf_pool.mutex); + const uint32_t space_id= page_id.space(); + if (!space || space->id != space_id) + { + if (space) + space->release_for_io(); + space= buf_flush_space(space_id); + if (!space) + continue; + } + if (neighbors && space->is_rotational()) + { + mysql_mutex_unlock(&buf_pool.mutex); + count+= buf_flush_try_neighbors(space, page_id, neighbors == 1, + false, count, max_n); +reacquire_mutex: + mysql_mutex_lock(&buf_pool.mutex); + } + else if (buf_flush_page(bpage, false, space)) + { + ++count; + goto reacquire_mutex; + } } - mutex_enter(&buf_pool.flush_list_mutex); + mysql_mutex_lock(&buf_pool.flush_list_mutex); ut_ad(flushed || buf_pool.flush_hp.is_hp(prev)); } buf_pool.flush_hp.set(nullptr); - mutex_exit(&buf_pool.flush_list_mutex); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + + if (space) + space->release_for_io(); if (scanned) MONITOR_INC_VALUE_CUMULATIVE(MONITOR_FLUSH_BATCH_SCANNED, @@ -1488,160 +1415,136 @@ static ulint buf_do_flush_list_batch(ulint min_n, lsn_t lsn_limit) MONITOR_FLUSH_BATCH_COUNT, MONITOR_FLUSH_BATCH_PAGES, count); - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); return count; } -/** This utility flushes dirty blocks from the end of the LRU list or -flush_list. -NOTE 1: in the case of an LRU flush the calling thread may own latches to -pages: to avoid deadlocks, this function must be written so that it cannot -end up waiting for these latches! NOTE 2: in the case of a flush list flush, -the calling thread is not allowed to own any latches on pages! -@param[in] lru true=LRU; false=FLUSH_LIST; -if !lru, then the caller must not own any latches on pages -@param[in] min_n wished minimum mumber of blocks flushed (it is -not guaranteed that the actual number is that big, though) -@param[in] lsn_limit in the case of !lru all blocks whose -@param[out] n counts of flushed and evicted pages -oldest_modification is smaller than this should be flushed (if their number -does not exceed min_n), otherwise ignored */ -static -void -buf_flush_batch( - bool lru, - ulint min_n, - lsn_t lsn_limit, - flush_counters_t* n) -{ - ut_ad(lru || !sync_check_iterate(dict_sync_check())); - - mutex_enter(&buf_pool.mutex); - - /* Note: The buffer pool mutex is released and reacquired within - the flush functions. */ - if (lru) { - buf_do_LRU_batch(min_n, n); - } else { - n->flushed = buf_do_flush_list_batch(min_n, lsn_limit); - n->evicted = 0; - } - - mutex_exit(&buf_pool.mutex); - - DBUG_PRINT("ib_buf", - (lru ? "LRU flush completed" : "flush_list completed")); -} - -/******************************************************************//** -Gather the aggregated stats for both flush list and LRU list flushing. -@param page_count_flush number of pages flushed from the end of the flush_list -@param page_count_LRU number of pages flushed from the end of the LRU list -*/ -static -void -buf_flush_stats( -/*============*/ - ulint page_count_flush, - ulint page_count_LRU) -{ - DBUG_PRINT("ib_buf", ("flush completed, from flush_list %u pages, " - "from LRU_list %u pages", - unsigned(page_count_flush), - unsigned(page_count_LRU))); - - srv_stats.buf_pool_flushed.add(page_count_flush + page_count_LRU); -} - -/** Start a buffer flush batch for LRU or flush list -@param[in] lru true=buf_pool.LRU; false=buf_pool.flush_list -@return whether the flush batch was started (was not already running) */ -static bool buf_flush_start(bool lru) -{ - IORequest::flush_t flush_type= lru ? IORequest::LRU : IORequest::FLUSH_LIST; - mutex_enter(&buf_pool.mutex); - - if (buf_pool.n_flush[flush_type] > 0 || buf_pool.init_flush[flush_type]) - { - /* There is already a flush batch of the same type running */ - mutex_exit(&buf_pool.mutex); - return false; - } - - buf_pool.init_flush[flush_type]= true; - os_event_reset(buf_pool.no_flush[flush_type]); - mutex_exit(&buf_pool.mutex); - return true; -} - -/** End a buffer flush batch. -@param[in] lru true=buf_pool.LRU; false=buf_pool.flush_list */ -static void buf_flush_end(bool lru) -{ - IORequest::flush_t flush_type= lru ? IORequest::LRU : IORequest::FLUSH_LIST; - - mutex_enter(&buf_pool.mutex); - - buf_pool.init_flush[flush_type]= false; - buf_pool.try_LRU_scan= true; - - if (!buf_pool.n_flush[flush_type]) - /* The running flush batch has ended */ - os_event_set(buf_pool.no_flush[flush_type]); - - mutex_exit(&buf_pool.mutex); - - if (!srv_read_only_mode) - buf_dblwr_flush_buffered_writes(); -} - /** Wait until a flush batch ends. -@param[in] lru true=buf_pool.LRU; false=buf_pool.flush_list */ +@param lru true=buf_pool.LRU; false=buf_pool.flush_list */ void buf_flush_wait_batch_end(bool lru) { - thd_wait_begin(nullptr, THD_WAIT_DISKIO); - os_event_wait(buf_pool.no_flush[lru - ? IORequest::LRU : IORequest::FLUSH_LIST]); - thd_wait_end(nullptr); + const auto &n_flush= lru ? buf_pool.n_flush_LRU : buf_pool.n_flush_list; + + if (n_flush) + { + auto cond= lru ? &buf_pool.done_flush_LRU : &buf_pool.done_flush_list; + tpool::tpool_wait_begin(); + thd_wait_begin(nullptr, THD_WAIT_DISKIO); + do + mysql_cond_wait(cond, &buf_pool.mutex); + while (n_flush); + tpool::tpool_wait_end(); + thd_wait_end(nullptr); + mysql_cond_broadcast(cond); + } } -/** Do flushing batch of a given type. -NOTE: The calling thread is not allowed to own any latches on pages! -@param[in] lru true=buf_pool.LRU; false=buf_pool.flush_list -@param[in] min_n wished minimum mumber of blocks flushed -(it is not guaranteed that the actual number is that big, though) -@param[in] lsn_limit if !lru, all blocks whose -oldest_modification is smaller than this should be flushed (if their number -does not exceed min_n), otherwise ignored -@param[out] n_processed the number of pages which were processed is -passed back to caller. Ignored if NULL -@retval true if a batch was queued successfully. -@retval false if another batch of same type was already running. */ -bool buf_flush_do_batch(bool lru, ulint min_n, lsn_t lsn_limit, - flush_counters_t *n) +/** Whether a background log flush is pending */ +static std::atomic_flag log_flush_pending; + +/** Advance log_sys.get_flushed_lsn() */ +static void log_flush(void *) { - if (n) - n->flushed= 0; + log_write_up_to(log_sys.get_lsn(), true); + log_flush_pending.clear(); +} - if (!buf_flush_start(lru)) - return false; +static tpool::waitable_task log_flush_task(log_flush, nullptr, nullptr); - buf_flush_batch(lru, min_n, lsn_limit, n); - buf_flush_end(lru); +/** Write out dirty blocks from buf_pool.flush_list. +@param max_n wished maximum mumber of blocks flushed +@param lsn buf_pool.get_oldest_modification(LSN_MAX) target (0=LRU flush) +@return the number of processed pages +@retval 0 if a batch of the same type (lsn==0 or lsn!=0) is already running */ +ulint buf_flush_lists(ulint max_n, lsn_t lsn) +{ + auto &n_flush= lsn ? buf_pool.n_flush_list : buf_pool.n_flush_LRU; - return true; + if (n_flush) + return 0; + + if (log_sys.get_lsn() > log_sys.get_flushed_lsn()) + { + log_flush_task.wait(); + if (log_sys.get_lsn() > log_sys.get_flushed_lsn() && + !log_flush_pending.test_and_set()) + srv_thread_pool->submit_task(&log_flush_task); +#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG + if (UNIV_UNLIKELY(ibuf_debug)) + log_write_up_to(log_sys.get_lsn(), true); +#endif + } + + auto cond= lsn ? &buf_pool.done_flush_list : &buf_pool.done_flush_LRU; + + mysql_mutex_lock(&buf_pool.mutex); + const bool running= n_flush != 0; + /* FIXME: we are performing a dirty read of buf_pool.flush_list.count + while not holding buf_pool.flush_list_mutex */ + if (running || !UT_LIST_GET_LEN(buf_pool.flush_list)) + { + mysql_mutex_unlock(&buf_pool.mutex); + if (running) + return 0; + mysql_cond_broadcast(cond); + return 0; + } + n_flush++; + + ulint n_flushed= lsn + ? buf_do_flush_list_batch(max_n, lsn) + : buf_do_LRU_batch(max_n); + + const auto n_flushing= --n_flush; + + buf_pool.try_LRU_scan= true; + + mysql_mutex_unlock(&buf_pool.mutex); + + if (!n_flushing) + mysql_cond_broadcast(cond); + + buf_dblwr.flush_buffered_writes(); + + DBUG_PRINT("ib_buf", ("%s completed, " ULINTPF " pages", + lsn ? "flush_list" : "LRU flush", n_flushed)); + return n_flushed; +} + +/** Request IO burst and wake up the page_cleaner. +@param lsn desired lower bound of oldest_modification */ +static void buf_flush_request_force(lsn_t lsn) +{ + lsn+= lsn_avg_rate * 3; + + lsn_t o= 0; + + while (!buf_flush_sync_lsn.compare_exchange_weak(o, lsn, + std::memory_order_acquire, + std::memory_order_relaxed)) + if (lsn > o) + break; + + mysql_cond_signal(&buf_pool.do_flush_list); } /** Wait until a flush batch of the given lsn ends @param[in] new_oldest target oldest_modified_lsn to wait for */ void buf_flush_wait_flushed(lsn_t new_oldest) { + ut_ad(new_oldest); + + if (srv_flush_sync) { + /* wake page cleaner for IO burst */ + buf_flush_request_force(new_oldest); + } + for (;;) { /* We don't need to wait for fsync of the flushed blocks, because anyway we need fsync to make chekpoint. So, we don't need to wait for the batch end here. */ - mutex_enter(&buf_pool.flush_list_mutex); + mysql_mutex_lock(&buf_pool.flush_list_mutex); buf_page_t* bpage; /* FIXME: Keep temporary tablespace pages in a separate flush @@ -1656,7 +1559,7 @@ void buf_flush_wait_flushed(lsn_t new_oldest) lsn_t oldest = bpage ? bpage->oldest_modification() : 0; - mutex_exit(&buf_pool.flush_list_mutex); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); if (oldest == 0 || oldest >= new_oldest) { break; @@ -1669,145 +1572,15 @@ void buf_flush_wait_flushed(lsn_t new_oldest) } } -/** This utility flushes dirty blocks from the end of the flush list. -NOTE: The calling thread is not allowed to own any latches on pages! -@param[in] min_n wished minimum mumber of blocks flushed (it is -not guaranteed that the actual number is that big, though) -@param[in] lsn_limit all blocks whose -oldest_modification is smaller than this should be flushed (if their number -does not exceed min_n), otherwise ignored -@param[out] n_processed the number of pages which were processed is -passed back to caller. Ignored if NULL. -@retval true if a batch was queued successfully -@retval false if another batch of same type was already running */ -bool buf_flush_lists(ulint min_n, lsn_t lsn_limit, ulint *n_processed) +/** Wait for pending flushes to complete. */ +void buf_flush_wait_batch_end_acquiring_mutex(bool lru) { - flush_counters_t n; - - bool success = buf_flush_do_batch(false, min_n, lsn_limit, &n); - - if (n.flushed) { - buf_flush_stats(n.flushed, 0); - } - - if (n_processed) { - *n_processed = n.flushed; - } - - return success; -} - -/******************************************************************//** -This function picks up a single page from the tail of the LRU -list, flushes it (if it is dirty), removes it from page_hash and LRU -list and puts it on the free list. It is called from user threads when -they are unable to find a replaceable page at the tail of the LRU -list i.e.: when the background LRU flushing in the page_cleaner thread -is not fast enough to keep pace with the workload. -@return true if success. */ -bool buf_flush_single_page_from_LRU() -{ - ulint scanned = 0; - bool freed = false; - - mutex_enter(&buf_pool.mutex); - - for (buf_page_t* bpage = buf_pool.single_scan_itr.start(); bpage; - ++scanned, bpage = buf_pool.single_scan_itr.get()) { - - ut_ad(mutex_own(&buf_pool.mutex)); - - buf_page_t* prev = UT_LIST_GET_PREV(LRU, bpage); - buf_pool.single_scan_itr.set(prev); - - if (!bpage->ready_for_flush()) { // FIXME: ready_for_replace() - continue; - } - - if (!bpage->buf_fix_count() - && buf_LRU_free_page(bpage, true)) { - /* block is ready for eviction i.e., it is - clean and is not IO-fixed or buffer fixed. */ - freed = true; - break; - } else { - /* Block is ready for flush. Try and dispatch an IO - request. We'll put it on free list in IO completion - routine if it is not buffer fixed. The following call - will release the buf_pool.mutex. - - Note: There is no guarantee that this page has actually - been freed, only that it has been flushed to disk */ - - freed = buf_flush_page(bpage, IORequest::SINGLE_PAGE, - nullptr, true); - - if (freed) { - goto found; - } - } - } - - mutex_exit(&buf_pool.mutex); -found: - if (scanned) { - MONITOR_INC_VALUE_CUMULATIVE( - MONITOR_LRU_SINGLE_FLUSH_SCANNED, - MONITOR_LRU_SINGLE_FLUSH_SCANNED_NUM_CALL, - MONITOR_LRU_SINGLE_FLUSH_SCANNED_PER_CALL, - scanned); - } - - ut_ad(!mutex_own(&buf_pool.mutex)); - return(freed); -} - -/** -Clear up the tail of the LRU list. -Put replaceable pages at the tail of LRU to the free list. -Flush dirty pages at the tail of LRU to the disk. -The depth to which we scan each buffer pool is controlled by dynamic -config parameter innodb_LRU_scan_depth. -@return total pages flushed */ -static ulint buf_flush_LRU_list() -{ - ulint scan_depth, withdraw_depth; - flush_counters_t n; - - memset(&n, 0, sizeof(flush_counters_t)); - - /* srv_LRU_scan_depth can be arbitrarily large value. - We cap it with current LRU size. */ - mutex_enter(&buf_pool.mutex); - scan_depth = UT_LIST_GET_LEN(buf_pool.LRU); - if (buf_pool.curr_size < buf_pool.old_size - && buf_pool.withdraw_target > 0) { - withdraw_depth = buf_pool.withdraw_target - - UT_LIST_GET_LEN(buf_pool.withdraw); - } else { - withdraw_depth = 0; - } - mutex_exit(&buf_pool.mutex); - if (withdraw_depth > srv_LRU_scan_depth) { - scan_depth = ut_min(withdraw_depth, scan_depth); - } else { - scan_depth = ut_min(static_cast(srv_LRU_scan_depth), - scan_depth); - } - /* Currently one of page_cleaners is the only thread - that can trigger an LRU flush at the same time. - So, it is not possible that a batch triggered during - last iteration is still running, */ - buf_flush_do_batch(true, scan_depth, 0, &n); - - return(n.flushed); -} - -/** Wait for any possible LRU flushes to complete. */ -void buf_flush_wait_LRU_batch_end() -{ - if (buf_pool.n_flush[IORequest::LRU] || buf_pool.init_flush[IORequest::LRU]) - buf_flush_wait_batch_end(true); + if (lru ? buf_pool.n_flush_LRU : buf_pool.n_flush_list) + { + mysql_mutex_lock(&buf_pool.mutex); + buf_flush_wait_batch_end(lru); + mysql_mutex_unlock(&buf_pool.mutex); + } } /*********************************************************************//** @@ -1911,7 +1684,6 @@ page_cleaner_flush_pages_recommendation(ulint last_pages_in) static ulint n_iterations = 0; static time_t prev_time; lsn_t oldest_lsn; - lsn_t cur_lsn; lsn_t age; lsn_t lsn_rate; ulint n_pages = 0; @@ -1919,7 +1691,7 @@ page_cleaner_flush_pages_recommendation(ulint last_pages_in) ulint pct_for_lsn = 0; ulint pct_total = 0; - cur_lsn = log_sys.get_lsn(); + const lsn_t cur_lsn = log_sys.get_lsn(); if (prev_lsn == 0) { /* First time around. */ @@ -1958,29 +1730,18 @@ page_cleaner_flush_pages_recommendation(ulint last_pages_in) lsn_avg_rate = (lsn_avg_rate + lsn_rate) / 2; - /* aggregate stats of all slots */ - mutex_enter(&page_cleaner.mutex); - ulint flush_tm = page_cleaner.flush_time; ulint flush_pass = page_cleaner.flush_pass; page_cleaner.flush_time = 0; page_cleaner.flush_pass = 0; - ulint lru_tm = page_cleaner.slot.flush_lru_time; ulint list_tm = page_cleaner.slot.flush_list_time; - ulint lru_pass = page_cleaner.slot.flush_lru_pass; ulint list_pass = page_cleaner.slot.flush_list_pass; - page_cleaner.slot.flush_lru_time = 0; - page_cleaner.slot.flush_lru_pass = 0; page_cleaner.slot.flush_list_time = 0; page_cleaner.slot.flush_list_pass = 0; - mutex_exit(&page_cleaner.mutex); /* minimum values are 1, to avoid dividing by zero. */ - if (lru_tm < 1) { - lru_tm = 1; - } if (list_tm < 1) { list_tm = 1; } @@ -1988,9 +1749,6 @@ page_cleaner_flush_pages_recommendation(ulint last_pages_in) flush_tm = 1; } - if (lru_pass < 1) { - lru_pass = 1; - } if (list_pass < 1) { list_pass = 1; } @@ -2000,23 +1758,14 @@ page_cleaner_flush_pages_recommendation(ulint last_pages_in) MONITOR_SET(MONITOR_FLUSH_ADAPTIVE_AVG_TIME_SLOT, list_tm / list_pass); - MONITOR_SET(MONITOR_LRU_BATCH_FLUSH_AVG_TIME_SLOT, - lru_tm / lru_pass); MONITOR_SET(MONITOR_FLUSH_ADAPTIVE_AVG_TIME_THREAD, list_tm / flush_pass); - MONITOR_SET(MONITOR_LRU_BATCH_FLUSH_AVG_TIME_THREAD, - lru_tm / flush_pass); MONITOR_SET(MONITOR_FLUSH_ADAPTIVE_AVG_TIME_EST, - flush_tm * list_tm / flush_pass - / (list_tm + lru_tm)); - MONITOR_SET(MONITOR_LRU_BATCH_FLUSH_AVG_TIME_EST, - flush_tm * lru_tm / flush_pass - / (list_tm + lru_tm)); + flush_tm / flush_pass); MONITOR_SET(MONITOR_FLUSH_AVG_TIME, flush_tm / flush_pass); MONITOR_SET(MONITOR_FLUSH_ADAPTIVE_AVG_PASS, list_pass); - MONITOR_SET(MONITOR_LRU_BATCH_FLUSH_AVG_PASS, lru_pass); MONITOR_SET(MONITOR_FLUSH_AVG_PASS, flush_pass); prev_lsn = cur_lsn; @@ -2043,7 +1792,7 @@ page_cleaner_flush_pages_recommendation(ulint last_pages_in) + lsn_avg_rate * buf_flush_lsn_scan_factor; ulint pages_for_lsn = 0; - mutex_enter(&buf_pool.flush_list_mutex); + mysql_mutex_lock(&buf_pool.flush_list_mutex); for (buf_page_t* b = UT_LIST_GET_LAST(buf_pool.flush_list); b != NULL; b = UT_LIST_GET_PREV(list, b)) { @@ -2052,13 +1801,7 @@ page_cleaner_flush_pages_recommendation(ulint last_pages_in) } ++pages_for_lsn; } - mutex_exit(&buf_pool.flush_list_mutex); - - mutex_enter(&page_cleaner.mutex); - ut_ad(page_cleaner.slot.state == PAGE_CLEANER_STATE_NONE); - page_cleaner.slot.n_pages_requested - = pages_for_lsn / buf_flush_lsn_scan_factor + 1; - mutex_exit(&page_cleaner.mutex); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); pages_for_lsn /= buf_flush_lsn_scan_factor; if (pages_for_lsn < 1) { @@ -2077,21 +1820,6 @@ page_cleaner_flush_pages_recommendation(ulint last_pages_in) n_pages = srv_max_io_capacity; } - mutex_enter(&page_cleaner.mutex); - ut_ad(page_cleaner.n_slots_requested == 0); - ut_ad(page_cleaner.n_slots_flushing == 0); - ut_ad(page_cleaner.n_slots_finished == 0); - - /* if REDO has enough of free space, - don't care about age distribution of pages */ - if (pct_for_lsn > 30) { - page_cleaner.slot.n_pages_requested *= n_pages - / pages_for_lsn + 1; - } else { - page_cleaner.slot.n_pages_requested = n_pages; - } - mutex_exit(&page_cleaner.mutex); - MONITOR_SET(MONITOR_FLUSH_N_TO_FLUSH_REQUESTED, n_pages); MONITOR_SET(MONITOR_FLUSH_N_TO_FLUSH_BY_AGE, pages_for_lsn); @@ -2104,229 +1832,28 @@ page_cleaner_flush_pages_recommendation(ulint last_pages_in) return(n_pages); } -/*********************************************************************//** -Puts the page_cleaner thread to sleep if it has finished work in less -than a second -@retval 0 wake up by event set, -@retval OS_SYNC_TIME_EXCEEDED if timeout was exceeded -@param next_loop_time time when next loop iteration should start -@param sig_count zero or the value returned by previous call of - os_event_reset() -@param cur_time current time as in ut_time_ms() */ -static -ulint -pc_sleep_if_needed( -/*===============*/ - ulint next_loop_time, - int64_t sig_count, - ulint cur_time) +/** Initiate a flushing batch. +@param max_n maximum mumber of blocks flushed +@param lsn oldest_modification limit +@return ut_time_ms() at the start of the wait */ +static ulint pc_request_flush_slot(ulint max_n, lsn_t lsn) { - /* No sleep if we are cleaning the buffer pool during the shutdown - with everything else finished */ - if (srv_shutdown_state == SRV_SHUTDOWN_FLUSH_PHASE) - return OS_SYNC_TIME_EXCEEDED; + ut_ad(max_n); + ut_ad(lsn); - if (next_loop_time > cur_time) { - /* Get sleep interval in micro seconds. We use - ut_min() to avoid long sleep in case of wrap around. */ - ulint sleep_us; - - sleep_us = ut_min(static_cast(1000000), - (next_loop_time - cur_time) * 1000); - - return(os_event_wait_time_low(buf_flush_event, - sleep_us, sig_count)); - } - - return(OS_SYNC_TIME_EXCEEDED); + const ulint flush_start_tm= ut_time_ms(); + page_cleaner.slot.n_flushed_list= buf_flush_lists(max_n, lsn); + page_cleaner.slot.flush_list_time+= ut_time_ms() - flush_start_tm; + page_cleaner.slot.flush_list_pass++; + return flush_start_tm; } -/** -Requests for all slots to flush. -@param min_n wished minimum mumber of blocks flushed - (it is not guaranteed that the actual number is that big) -@param lsn_limit in the case of buf_pool.flush_list all blocks whose - oldest_modification is smaller than this should be flushed - (if their number does not exceed min_n), otherwise ignored -*/ -static void pc_request(ulint min_n, lsn_t lsn_limit) -{ - mutex_enter(&page_cleaner.mutex); - - ut_ad(page_cleaner.n_slots_requested == 0); - ut_ad(page_cleaner.n_slots_flushing == 0); - ut_ad(page_cleaner.n_slots_finished == 0); - - page_cleaner.requested = (min_n > 0); - page_cleaner.lsn_limit = lsn_limit; - - ut_ad(page_cleaner.slot.state == PAGE_CLEANER_STATE_NONE); - - if (min_n == 0 || min_n == ULINT_MAX) { - page_cleaner.slot.n_pages_requested = min_n; - } - - /* page_cleaner.slot.n_pages_requested was already set by - page_cleaner_flush_pages_recommendation() */ - - page_cleaner.slot.state = PAGE_CLEANER_STATE_REQUESTED; - - page_cleaner.n_slots_requested = 1; - page_cleaner.n_slots_flushing = 0; - page_cleaner.n_slots_finished = 0; - - mutex_exit(&page_cleaner.mutex); -} - -/** -Do flush for one slot. -@return the number of the slots which has not been treated yet. */ -static ulint pc_flush_slot() -{ - ulint lru_tm = 0; - ulint list_tm = 0; - ulint lru_pass = 0; - ulint list_pass = 0; - - mutex_enter(&page_cleaner.mutex); - - if (page_cleaner.n_slots_requested) { - ut_ad(page_cleaner.slot.state == PAGE_CLEANER_STATE_REQUESTED); - page_cleaner.n_slots_requested--; - page_cleaner.n_slots_flushing++; - page_cleaner.slot.state = PAGE_CLEANER_STATE_FLUSHING; - - if (UNIV_UNLIKELY(!page_cleaner.is_running)) { - page_cleaner.slot.n_flushed_lru = 0; - page_cleaner.slot.n_flushed_list = 0; - goto finish_mutex; - } - - mutex_exit(&page_cleaner.mutex); - - lru_tm = ut_time_ms(); - - /* Flush pages from end of LRU if required */ - page_cleaner.slot.n_flushed_lru = buf_flush_LRU_list(); - - lru_tm = ut_time_ms() - lru_tm; - lru_pass++; - - if (UNIV_UNLIKELY(!page_cleaner.is_running)) { - page_cleaner.slot.n_flushed_list = 0; - goto finish; - } - - /* Flush pages from flush_list if required */ - if (page_cleaner.requested) { - flush_counters_t n; - memset(&n, 0, sizeof(flush_counters_t)); - list_tm = ut_time_ms(); - - page_cleaner.slot.succeeded_list = buf_flush_do_batch( - false, - page_cleaner.slot.n_pages_requested, - page_cleaner.lsn_limit, - &n); - - page_cleaner.slot.n_flushed_list = n.flushed; - - list_tm = ut_time_ms() - list_tm; - list_pass++; - } else { - page_cleaner.slot.n_flushed_list = 0; - page_cleaner.slot.succeeded_list = true; - } -finish: - mutex_enter(&page_cleaner.mutex); -finish_mutex: - page_cleaner.n_slots_flushing--; - page_cleaner.n_slots_finished++; - page_cleaner.slot.state = PAGE_CLEANER_STATE_FINISHED; - - page_cleaner.slot.flush_lru_time += lru_tm; - page_cleaner.slot.flush_list_time += list_tm; - page_cleaner.slot.flush_lru_pass += lru_pass; - page_cleaner.slot.flush_list_pass += list_pass; - - if (page_cleaner.n_slots_requested == 0 - && page_cleaner.n_slots_flushing == 0) { - os_event_set(page_cleaner.is_finished); - } - } - - ulint ret = page_cleaner.n_slots_requested; - - mutex_exit(&page_cleaner.mutex); - - return(ret); -} - -/** -Wait until all flush requests are finished. -@param n_flushed_lru number of pages flushed from the end of the LRU list. -@param n_flushed_list number of pages flushed from the end of the - flush_list. -@return true if all flush_list flushing batch were success. */ -static -bool -pc_wait_finished( - ulint* n_flushed_lru, - ulint* n_flushed_list) -{ - bool all_succeeded = true; - - *n_flushed_lru = 0; - *n_flushed_list = 0; - - os_event_wait(page_cleaner.is_finished); - - mutex_enter(&page_cleaner.mutex); - - ut_ad(page_cleaner.n_slots_requested == 0); - ut_ad(page_cleaner.n_slots_flushing == 0); - ut_ad(page_cleaner.n_slots_finished == 1); - - ut_ad(page_cleaner.slot.state == PAGE_CLEANER_STATE_FINISHED); - page_cleaner.slot.state = PAGE_CLEANER_STATE_NONE; - *n_flushed_lru = page_cleaner.slot.n_flushed_lru; - *n_flushed_list = page_cleaner.slot.n_flushed_list; - all_succeeded = page_cleaner.slot.succeeded_list; - page_cleaner.slot.n_pages_requested = 0; - - page_cleaner.n_slots_finished = 0; - - os_event_reset(page_cleaner.is_finished); - - mutex_exit(&page_cleaner.mutex); - - return(all_succeeded); -} - -#ifdef UNIV_LINUX -/** -Set priority for page_cleaner threads. -@param[in] priority priority intended to set -@return true if set as intended */ -static -bool -buf_flush_page_cleaner_set_priority( - int priority) -{ - setpriority(PRIO_PROCESS, (pid_t)syscall(SYS_gettid), - priority); - return(getpriority(PRIO_PROCESS, (pid_t)syscall(SYS_gettid)) - == priority); -} -#endif /* UNIV_LINUX */ - #ifdef UNIV_DEBUG /** Loop used to disable the page cleaner thread. */ static void buf_flush_page_cleaner_disabled_loop() { while (innodb_page_cleaner_disabled_debug - && srv_shutdown_state == SRV_SHUTDOWN_NONE - && page_cleaner.is_running) { + && srv_shutdown_state == SRV_SHUTDOWN_NONE) { os_thread_sleep(100000); } } @@ -2343,6 +1870,7 @@ static os_thread_ret_t DECLARE_THREAD(buf_flush_page_cleaner)(void*) pfs_register_thread(page_cleaner_thread_key); #endif /* UNIV_PFS_THREAD */ ut_ad(!srv_read_only_mode); + ut_ad(buf_page_cleaner_is_active); #ifdef UNIV_DEBUG_THREAD_CREATION ib::info() << "page_cleaner thread running, id " @@ -2350,198 +1878,56 @@ static os_thread_ret_t DECLARE_THREAD(buf_flush_page_cleaner)(void*) #endif /* UNIV_DEBUG_THREAD_CREATION */ #ifdef UNIV_LINUX /* linux might be able to set different setting for each thread. - worth to try to set high priority for page cleaner threads */ - if (buf_flush_page_cleaner_set_priority( - buf_flush_page_cleaner_priority)) { - - ib::info() << "page_cleaner coordinator priority: " - << buf_flush_page_cleaner_priority; - } else { + worth to try to set high priority for the page cleaner thread */ + const pid_t tid= static_cast(syscall(SYS_gettid)); + setpriority(PRIO_PROCESS, tid, -20); + if (getpriority(PRIO_PROCESS, tid) != -20) { ib::info() << "If the mysqld execution user is authorized," " page cleaner thread priority can be changed." " See the man page of setpriority()."; } #endif /* UNIV_LINUX */ - ulint ret_sleep = 0; - ulint n_evicted = 0; - ulint n_flushed_last = 0; - ulint warn_interval = 1; - ulint warn_count = 0; - int64_t sig_count = os_event_reset(buf_flush_event); - ulint next_loop_time = ut_time_ms() + 1000; + ulint curr_time = ut_time_ms(); ulint n_flushed = 0; ulint last_activity = srv_get_activity_count(); ulint last_pages = 0; - while (srv_shutdown_state <= SRV_SHUTDOWN_INITIATED) { - ulint curr_time = ut_time_ms(); + for (ulint next_loop_time = curr_time + 1000; + srv_shutdown_state <= SRV_SHUTDOWN_INITIATED; + curr_time = ut_time_ms()) { + bool sleep_timeout; /* The page_cleaner skips sleep if the server is idle and there are no pending IOs in the buffer pool and there is work to do. */ - if (!n_flushed || !buf_pool.n_pend_reads - || srv_check_activity(&last_activity)) { - - ret_sleep = pc_sleep_if_needed( - next_loop_time, sig_count, curr_time); - } else if (curr_time > next_loop_time) { - ret_sleep = OS_SYNC_TIME_EXCEEDED; + if (next_loop_time <= curr_time) { + sleep_timeout = true; + } else if (!n_flushed || !buf_pool.n_pend_reads + || srv_check_activity(&last_activity)) { + const ulint sleep_ms = std::min(next_loop_time + - curr_time, + 1000); + timespec abstime; + set_timespec_nsec(abstime, 1000000ULL * sleep_ms); + mysql_mutex_lock(&buf_pool.flush_list_mutex); + const auto error = mysql_cond_timedwait( + &buf_pool.do_flush_list, + &buf_pool.flush_list_mutex, + &abstime); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + sleep_timeout = error == ETIMEDOUT || error == ETIME; + if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED) { + break; + } } else { - ret_sleep = 0; + sleep_timeout = false; } - if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED) { - break; - } - - sig_count = os_event_reset(buf_flush_event); - - if (ret_sleep == OS_SYNC_TIME_EXCEEDED) { - if (global_system_variables.log_warnings > 2 - && curr_time > next_loop_time + 3000 - && !(test_flags & TEST_SIGINT)) { - if (warn_count == 0) { - ib::info() << "page_cleaner: 1000ms" - " intended loop took " - << 1000 + curr_time - - next_loop_time - << "ms. The settings might not" - " be optimal. (flushed=" - << n_flushed_last - << " and evicted=" - << n_evicted - << ", during the time.)"; - if (warn_interval > 300) { - warn_interval = 600; - } else { - warn_interval *= 2; - } - - warn_count = warn_interval; - } else { - --warn_count; - } - } else { - /* reset counter */ - warn_interval = 1; - warn_count = 0; - } - - next_loop_time = curr_time + 1000; - n_flushed_last = n_evicted = 0; - } - - if (ret_sleep != OS_SYNC_TIME_EXCEEDED - && srv_flush_sync - && buf_flush_sync_lsn > 0) { - /* woke up for flush_sync */ - mutex_enter(&page_cleaner.mutex); - lsn_t lsn_limit = buf_flush_sync_lsn; - buf_flush_sync_lsn = 0; - mutex_exit(&page_cleaner.mutex); - - /* Request flushing for threads */ - pc_request(ULINT_MAX, lsn_limit); - - ulint tm = ut_time_ms(); - - /* Coordinator also treats requests */ - while (pc_flush_slot() > 0) {} - - /* only coordinator is using these counters, - so no need to protect by lock. */ - page_cleaner.flush_time += ut_time_ms() - tm; - page_cleaner.flush_pass++; - - /* Wait for all slots to be finished */ - ulint n_flushed_lru = 0; - ulint n_flushed_list = 0; - pc_wait_finished(&n_flushed_lru, &n_flushed_list); - - if (n_flushed_list > 0 || n_flushed_lru > 0) { - buf_flush_stats(n_flushed_list, n_flushed_lru); - - MONITOR_INC_VALUE_CUMULATIVE( - MONITOR_FLUSH_SYNC_TOTAL_PAGE, - MONITOR_FLUSH_SYNC_COUNT, - MONITOR_FLUSH_SYNC_PAGES, - n_flushed_lru + n_flushed_list); - } - - n_flushed = n_flushed_lru + n_flushed_list; - - } else if (srv_check_activity(&last_activity)) { - ulint n_to_flush; - lsn_t lsn_limit; - - /* Estimate pages from flush_list to be flushed */ - if (ret_sleep == OS_SYNC_TIME_EXCEEDED) { - last_activity = srv_get_activity_count(); - n_to_flush = - page_cleaner_flush_pages_recommendation( - last_pages); - lsn_limit = LSN_MAX; - } else { - n_to_flush = 0; - lsn_limit = 0; - } - - /* Request flushing for threads */ - pc_request(n_to_flush, lsn_limit); - - ulint tm = ut_time_ms(); - - /* Coordinator also treats requests */ - while (pc_flush_slot() > 0) { - /* No op */ - } - - /* only coordinator is using these counters, - so no need to protect by lock. */ - page_cleaner.flush_time += ut_time_ms() - tm; - page_cleaner.flush_pass++ ; - - /* Wait for all slots to be finished */ - ulint n_flushed_lru = 0; - ulint n_flushed_list = 0; - - pc_wait_finished(&n_flushed_lru, &n_flushed_list); - - if (n_flushed_list > 0 || n_flushed_lru > 0) { - buf_flush_stats(n_flushed_list, n_flushed_lru); - } - - if (ret_sleep == OS_SYNC_TIME_EXCEEDED) { - last_pages = n_flushed_list; - } - - n_evicted += n_flushed_lru; - n_flushed_last += n_flushed_list; - - n_flushed = n_flushed_lru + n_flushed_list; - - if (n_flushed_lru) { - MONITOR_INC_VALUE_CUMULATIVE( - MONITOR_LRU_BATCH_FLUSH_TOTAL_PAGE, - MONITOR_LRU_BATCH_FLUSH_COUNT, - MONITOR_LRU_BATCH_FLUSH_PAGES, - n_flushed_lru); - } - - if (n_flushed_list) { - MONITOR_INC_VALUE_CUMULATIVE( - MONITOR_FLUSH_ADAPTIVE_TOTAL_PAGE, - MONITOR_FLUSH_ADAPTIVE_COUNT, - MONITOR_FLUSH_ADAPTIVE_PAGES, - n_flushed_list); - } - - } else if (ret_sleep == OS_SYNC_TIME_EXCEEDED) { + if (sleep_timeout) { /* no activity, slept enough */ - buf_flush_lists(srv_io_capacity, LSN_MAX, &n_flushed); - - n_flushed_last += n_flushed; + n_flushed = buf_flush_lists(srv_io_capacity, LSN_MAX); + last_pages = n_flushed; if (n_flushed) { MONITOR_INC_VALUE_CUMULATIVE( @@ -2551,99 +1937,56 @@ static os_thread_ret_t DECLARE_THREAD(buf_flush_page_cleaner)(void*) n_flushed); } + } else if (lsn_t lsn_limit = buf_flush_sync_lsn.exchange( + 0, std::memory_order_release)) { + page_cleaner.flush_time += ut_time_ms() + - pc_request_flush_slot(ULINT_MAX, lsn_limit); + page_cleaner.flush_pass++; + n_flushed = page_cleaner.slot.n_flushed_list; - } else { + if (n_flushed) { + MONITOR_INC_VALUE_CUMULATIVE( + MONITOR_FLUSH_SYNC_TOTAL_PAGE, + MONITOR_FLUSH_SYNC_COUNT, + MONITOR_FLUSH_SYNC_PAGES, + n_flushed); + } + } else if (!srv_check_activity(&last_activity)) { /* no activity, but woken up by event */ n_flushed = 0; + } else if (ulint n= page_cleaner_flush_pages_recommendation( + last_pages)) { + /* Estimate pages from flush_list to be flushed */ + ulint tm= pc_request_flush_slot(n, LSN_MAX); + + page_cleaner.flush_time += ut_time_ms() - tm; + page_cleaner.flush_pass++ ; + + n_flushed = page_cleaner.slot.n_flushed_list; + + if (n_flushed) { + MONITOR_INC_VALUE_CUMULATIVE( + MONITOR_FLUSH_ADAPTIVE_TOTAL_PAGE, + MONITOR_FLUSH_ADAPTIVE_COUNT, + MONITOR_FLUSH_ADAPTIVE_PAGES, + n_flushed); + } + } else { + n_flushed = 0; + } + + if (!n_flushed) { + next_loop_time = curr_time + 1000; } ut_d(buf_flush_page_cleaner_disabled_loop()); } - ut_ad(srv_shutdown_state > SRV_SHUTDOWN_INITIATED); - if (srv_fast_shutdown == 2 - || srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { - /* In very fast shutdown or when innodb failed to start, we - simulate a crash of the buffer pool. We are not required to do - any flushing. */ - goto thread_exit; + if (srv_fast_shutdown != 2) { + buf_flush_wait_batch_end_acquiring_mutex(true); + buf_flush_wait_batch_end_acquiring_mutex(false); } - /* In case of normal and slow shutdown the page_cleaner thread - must wait for all other activity in the server to die down. - Note that we can start flushing the buffer pool as soon as the - server enters shutdown phase but we must stay alive long enough - to ensure that any work done by the master or purge threads is - also flushed. - During shutdown we pass through two stages. In the first stage, - when SRV_SHUTDOWN_CLEANUP is set other threads like the master - and the purge threads may be working as well. We start flushing - the buffer pool but can't be sure that no new pages are being - dirtied until we enter SRV_SHUTDOWN_FLUSH_PHASE phase. */ - - do { - pc_request(ULINT_MAX, LSN_MAX); - - while (pc_flush_slot() > 0) {} - - ulint n_flushed_lru = 0; - ulint n_flushed_list = 0; - pc_wait_finished(&n_flushed_lru, &n_flushed_list); - - n_flushed = n_flushed_lru + n_flushed_list; - - /* We sleep only if there are no pages to flush */ - if (n_flushed == 0) { - os_thread_sleep(100000); - } - } while (srv_shutdown_state == SRV_SHUTDOWN_CLEANUP); - - /* At this point all threads including the master and the purge - thread must have been suspended. */ - ut_ad(!srv_any_background_activity()); - ut_ad(srv_shutdown_state == SRV_SHUTDOWN_FLUSH_PHASE); - - /* We can now make a final sweep on flushing the buffer pool - and exit after we have cleaned the whole buffer pool. - It is important that we wait for any running batch that has - been triggered by us to finish. Otherwise we can end up - considering end of that batch as a finish of our final - sweep and we'll come out of the loop leaving behind dirty pages - in the flush_list */ - buf_flush_wait_batch_end(false); - buf_flush_wait_LRU_batch_end(); - - bool success; - - do { - pc_request(ULINT_MAX, LSN_MAX); - - while (pc_flush_slot() > 0) {} - - ulint n_flushed_lru = 0; - ulint n_flushed_list = 0; - success = pc_wait_finished(&n_flushed_lru, &n_flushed_list); - - n_flushed = n_flushed_lru + n_flushed_list; - - buf_flush_wait_batch_end(false); - buf_flush_wait_LRU_batch_end(); - - } while (!success || n_flushed > 0); - - /* Some sanity checks */ - ut_ad(!srv_any_background_activity()); - ut_ad(srv_shutdown_state == SRV_SHUTDOWN_FLUSH_PHASE); - ut_a(UT_LIST_GET_LEN(buf_pool.flush_list) == 0); - - /* We have lived our life. Time to die. */ - -thread_exit: - page_cleaner.is_running = false; - mutex_destroy(&page_cleaner.mutex); - - os_event_destroy(page_cleaner.is_finished); - buf_page_cleaner_is_active = false; my_thread_end(); @@ -2654,52 +1997,34 @@ thread_exit: OS_THREAD_DUMMY_RETURN; } -static void pc_flush_slot_func(void*) -{ - while (pc_flush_slot() > 0) {}; -} - /** Initialize page_cleaner. */ void buf_flush_page_cleaner_init() { - ut_ad(!page_cleaner.is_running); - - mutex_create(LATCH_ID_PAGE_CLEANER, &page_cleaner.mutex); - - page_cleaner.is_finished = os_event_create("pc_is_finished"); - - page_cleaner.is_running = true; - - buf_page_cleaner_is_active = true; - os_thread_create(buf_flush_page_cleaner); + ut_ad(!buf_page_cleaner_is_active); + buf_page_cleaner_is_active= true; + os_thread_create(buf_flush_page_cleaner); } /** Synchronously flush dirty blocks. NOTE: The calling thread is not allowed to hold any buffer page latches! */ void buf_flush_sync() { - bool success; - do { - success = buf_flush_lists(ULINT_MAX, LSN_MAX, NULL); - buf_flush_wait_batch_end(false); - } while (!success); -} + ut_ad(!sync_check_iterate(dict_sync_check())); -/** Request IO burst and wake page_cleaner up. -@param[in] lsn_limit upper limit of LSN to be flushed */ -void buf_flush_request_force(lsn_t lsn_limit) -{ - /* adjust based on lsn_avg_rate not to get old */ - lsn_t lsn_target = lsn_limit + lsn_avg_rate * 3; - - mutex_enter(&page_cleaner.mutex); - if (lsn_target > buf_flush_sync_lsn) { - buf_flush_sync_lsn = lsn_target; - } - mutex_exit(&page_cleaner.mutex); - - os_event_set(buf_flush_event); + for (;;) + { + const ulint n_flushed= buf_flush_lists(ULINT_UNDEFINED, LSN_MAX); + buf_flush_wait_batch_end_acquiring_mutex(false); + if (!n_flushed) + { + mysql_mutex_lock(&buf_pool.flush_list_mutex); + const auto len= UT_LIST_GET_LEN(buf_pool.flush_list); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + if (!len) + return; + } + } } #ifdef UNIV_DEBUG @@ -2716,7 +2041,7 @@ static void buf_flush_validate_low() { buf_page_t* bpage; - ut_ad(mutex_own(&buf_pool.flush_list_mutex)); + mysql_mutex_assert_owner(&buf_pool.flush_list_mutex); ut_list_validate(buf_pool.flush_list, Check()); @@ -2743,8 +2068,8 @@ static void buf_flush_validate_low() /** Validate the flush list. */ void buf_flush_validate() { - mutex_enter(&buf_pool.flush_list_mutex); - buf_flush_validate_low(); - mutex_exit(&buf_pool.flush_list_mutex); + mysql_mutex_lock(&buf_pool.flush_list_mutex); + buf_flush_validate_low(); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); } #endif /* UNIV_DEBUG */ diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc index 521be10ba21..f9ed938b20c 100644 --- a/storage/innobase/buf/buf0lru.cc +++ b/storage/innobase/buf/buf0lru.cc @@ -39,6 +39,9 @@ Created 11/5/1995 Heikki Tuuri #include "srv0srv.h" #include "srv0mon.h" +/** Flush this many pages in buf_LRU_get_free_block() */ +size_t innodb_lru_flush_size; + /** The number of blocks from the LRU_old pointer onward, including the block pointed to, must be buf_pool.LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV of the whole LRU list length, except that the tolerance defined below @@ -46,28 +49,13 @@ is allowed. Note that the tolerance must be small enough such that for even the BUF_LRU_OLD_MIN_LEN long LRU list, the LRU_old pointer is not allowed to point to either end of the LRU list. */ -static const ulint BUF_LRU_OLD_TOLERANCE = 20; +static constexpr ulint BUF_LRU_OLD_TOLERANCE = 20; /** The minimum amount of non-old blocks when the LRU_old list exists (that is, when there are more than BUF_LRU_OLD_MIN_LEN blocks). @see buf_LRU_old_adjust_len */ #define BUF_LRU_NON_OLD_MIN_LEN 5 -#ifdef BTR_CUR_HASH_ADAPT -/** When dropping the search hash index entries before deleting an ibd -file, we build a local array of pages belonging to that tablespace -in the buffer pool. Following is the size of that array. -We also release buf_pool.mutex after scanning this many pages of the -flush_list when dropping a table. This is to ensure that other threads -are not blocked for extended period of time when using very large -buffer pools. */ -static const ulint BUF_LRU_DROP_SEARCH_SIZE = 1024; -#endif /* BTR_CUR_HASH_ADAPT */ - -/** We scan these many blocks when looking for a clean page to evict -during LRU eviction. */ -static const ulint BUF_LRU_SEARCH_SCAN_THRESHOLD = 100; - /** If we switch on the InnoDB monitor because there are too few available frames in the buffer pool, we set this to TRUE */ static bool buf_lru_switched_on_innodb_mon = false; @@ -149,7 +137,7 @@ static void buf_LRU_block_free_hashed_page(buf_block_t *block) static inline void incr_LRU_size_in_bytes(const buf_page_t* bpage) { /* FIXME: use atomics, not mutex */ - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); buf_pool.stat.LRU_bytes += bpage->physical_size(); @@ -160,7 +148,7 @@ static inline void incr_LRU_size_in_bytes(const buf_page_t* bpage) instead of the general LRU list */ bool buf_LRU_evict_from_unzip_LRU() { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); /* If the unzip_LRU list is empty, we can only use the LRU. */ if (UT_LIST_GET_LEN(buf_pool.unzip_LRU) == 0) { @@ -196,280 +184,19 @@ bool buf_LRU_evict_from_unzip_LRU() return(unzip_avg <= io_avg * BUF_LRU_IO_TO_UNZIP_FACTOR); } -#ifdef BTR_CUR_HASH_ADAPT -/** -While flushing (or removing dirty) pages from a tablespace we don't -want to hog the CPU and resources. Release the buffer pool and block -mutex and try to force a context switch. Then reacquire the same mutexes. -The current page is "fixed" before the release of the mutexes and then -"unfixed" again once we have reacquired the mutexes. -@param[in,out] bpage current page */ -static void buf_flush_yield(buf_page_t *bpage) -{ - mutex_exit(&buf_pool.flush_list_mutex); - ut_ad(bpage->oldest_modification()); - ut_ad(bpage->in_file()); - ut_ad(bpage->io_fix() == BUF_IO_NONE); - /** Make the block sticky, so that even after we release buf_pool.mutex: - (1) it cannot be removed from the buf_pool.flush_list - (2) bpage cannot be relocated in buf_pool - (3) bpage->in_LRU_list cannot change - However, bpage->LRU can change. */ - bpage->set_io_fix(BUF_IO_PIN); - mutex_exit(&buf_pool.mutex); - - /* Try and force a context switch. */ - os_thread_yield(); - - mutex_enter(&buf_pool.mutex); - bpage->io_unfix(); - mutex_enter(&buf_pool.flush_list_mutex); - /* Should not have been removed from the flush - list during the yield. However, this check is - not sufficient to catch a remove -> add. */ - ut_ad(bpage->oldest_modification()); -} - -/******************************************************************//** -If we have hogged the resources for too long then release the buffer -pool and flush list mutex and do a thread yield. Set the current page -to "sticky" so that it is not relocated during the yield. -@return true if yielded */ -static MY_ATTRIBUTE((warn_unused_result)) -bool -buf_flush_try_yield( -/*================*/ - buf_page_t* bpage, /*!< in/out: bpage to remove */ - ulint processed) /*!< in: number of pages processed */ -{ - /* Every BUF_LRU_DROP_SEARCH_SIZE iterations in the - loop we release buf_pool.mutex to let other threads - do their job but only if the block is not IO fixed. This - ensures that the block stays in its position in the - flush_list. */ - - if (bpage != NULL - && processed >= BUF_LRU_DROP_SEARCH_SIZE - && bpage->io_fix() == BUF_IO_NONE) { - - /* Release the buf_pool.mutex - to give the other threads a go. */ - - buf_flush_yield(bpage); - return(true); - } - - return(false); -} -#endif /* BTR_CUR_HASH_ADAPT */ - -/** Remove a single page from flush_list. -@param[in,out] bpage buffer page to remove -@param[in] flush whether to flush the page before removing -@return true if page was removed. */ -static bool buf_flush_or_remove_page(buf_page_t *bpage, bool flush) -{ - ut_ad(mutex_own(&buf_pool.mutex)); - ut_ad(mutex_own(&buf_pool.flush_list_mutex)); - - /* bpage->id and bpage->io_fix are protected by - buf_pool.mutex (and bpage->id additionally by hash_lock). - It is safe to check them while holding buf_pool.mutex only. */ - - if (bpage->io_fix() != BUF_IO_NONE) { - - /* We cannot remove this page during this scan - yet; maybe the system is currently reading it - in, or flushing the modifications to the file */ - return(false); - - } - - bool processed = false; - - /* We have to release the flush_list_mutex to obey the - latching order. We are however guaranteed that the page - will stay in the flush_list and won't be relocated because - buf_flush_remove() and buf_flush_relocate_on_flush_list() - need buf_pool.mutex as well. */ - - mutex_exit(&buf_pool.flush_list_mutex); - - ut_ad(bpage->oldest_modification()); - - if (!flush) { - buf_flush_remove(bpage); - processed = true; - } else if (bpage->ready_for_flush()) { - processed = buf_flush_page(bpage, IORequest::SINGLE_PAGE, - nullptr, false); - - if (processed) { - mutex_enter(&buf_pool.mutex); - } - } - - mutex_enter(&buf_pool.flush_list_mutex); - - ut_ad(mutex_own(&buf_pool.mutex)); - - return(processed); -} - -/** Remove all dirty pages belonging to a given tablespace when we are -deleting the data file of that tablespace. -The pages still remain a part of LRU and are evicted from -the list as they age towards the tail of the LRU. -@param[in] id tablespace identifier -@param[in] flush whether to flush the pages before removing -@param[in] first first page to be flushed or evicted -@return whether all matching dirty pages were removed */ -static bool buf_flush_or_remove_pages(ulint id, bool flush, ulint first) -{ - buf_page_t* prev; - buf_page_t* bpage; - ulint processed = 0; - - mutex_enter(&buf_pool.flush_list_mutex); -rescan: - bool all_freed = true; - - for (bpage = UT_LIST_GET_LAST(buf_pool.flush_list); - bpage != NULL; - bpage = prev) { - - ut_a(bpage->in_file()); - - /* Save the previous link because once we free the - page we can't rely on the links. */ - - prev = UT_LIST_GET_PREV(list, bpage); - - const page_id_t bpage_id(bpage->id()); - - if (id != bpage_id.space()) { - /* Skip this block, because it is for a - different tablespace. */ - } else if (bpage_id.page_no() < first) { - /* Skip this block, because it is below the limit. */ - } else if (!buf_flush_or_remove_page(bpage, flush)) { - - /* Remove was unsuccessful, we have to try again - by scanning the entire list from the end. - This also means that we never released the - buf_pool mutex. Therefore we can trust the prev - pointer. - buf_flush_or_remove_page() released the - flush list mutex but not the buf_pool mutex. - Therefore it is possible that a new page was - added to the flush list. For example, in case - where we are at the head of the flush list and - prev == NULL. That is OK because we have the - tablespace quiesced and no new pages for this - space-id should enter flush_list. This is - because the only callers of this function are - DROP TABLE and FLUSH TABLE FOR EXPORT. - We know that we'll have to do at least one more - scan but we don't break out of loop here and - try to do as much work as we can in this - iteration. */ - - all_freed = false; - } else if (flush) { - - /* The processing was successful. And during the - processing we have released the buf_pool mutex - when calling buf_page_flush(). We cannot trust - prev pointer. */ - goto rescan; - } - -#ifdef BTR_CUR_HASH_ADAPT - ++processed; - - /* Yield if we have hogged the CPU and mutexes for too long. */ - if (buf_flush_try_yield(prev, processed)) { - /* Reset the batch size counter if we had to yield. */ - processed = 0; - } -#endif /* BTR_CUR_HASH_ADAPT */ - } - - mutex_exit(&buf_pool.flush_list_mutex); - - return(all_freed); -} - -/** Remove or flush all the dirty pages that belong to a given tablespace. -The pages will remain in the LRU list and will be evicted from the LRU list -as they age and move towards the tail of the LRU list. -@param[in] id tablespace identifier -@param[in] flush whether to flush the pages before removing -@param[in] first first page to be flushed or evicted */ -static void buf_flush_dirty_pages(ulint id, bool flush, ulint first) -{ - mutex_enter(&buf_pool.mutex); - while (!buf_flush_or_remove_pages(id, flush, first)) - { - mutex_exit(&buf_pool.mutex); - ut_d(buf_flush_validate()); - os_thread_sleep(2000); - mutex_enter(&buf_pool.mutex); - } - -#ifdef UNIV_DEBUG - if (!first) - { - mutex_enter(&buf_pool.flush_list_mutex); - - for (buf_page_t *bpage= UT_LIST_GET_FIRST(buf_pool.flush_list); bpage; - bpage= UT_LIST_GET_NEXT(list, bpage)) - { - ut_ad(bpage->in_file()); - ut_ad(bpage->oldest_modification()); - ut_ad(id != bpage->id().space()); - } - - mutex_exit(&buf_pool.flush_list_mutex); - } -#endif - - mutex_exit(&buf_pool.mutex); -} - -/** Empty the flush list for all pages belonging to a tablespace. -@param[in] id tablespace identifier -@param[in] flush whether to write the pages to files -@param[in] first first page to be flushed or evicted */ -void buf_LRU_flush_or_remove_pages(ulint id, bool flush, ulint first) -{ - /* Pages in the system tablespace must never be discarded. */ - ut_ad(id || flush); - - buf_flush_dirty_pages(id, flush, first); - - if (flush) { - /* Ensure that all asynchronous IO is completed. */ - os_aio_wait_until_no_pending_writes(); - fil_flush(id); - } -} - /** Try to free an uncompressed page of a compressed block from the unzip LRU list. The compressed page is preserved, and it need not be clean. -@param[in] scan_all true=scan the whole list; - false=scan srv_LRU_scan_depth / 2 blocks +@param limit maximum number of blocks to scan @return true if freed */ -static bool buf_LRU_free_from_unzip_LRU_list(bool scan_all) +static bool buf_LRU_free_from_unzip_LRU_list(ulint limit) { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); if (!buf_LRU_evict_from_unzip_LRU()) { return(false); } ulint scanned = 0; - const ulint limit = scan_all ? ULINT_UNDEFINED : srv_LRU_scan_depth; bool freed = false; for (buf_block_t* block = UT_LIST_GET_LAST(buf_pool.unzip_LRU); @@ -500,31 +227,24 @@ static bool buf_LRU_free_from_unzip_LRU_list(bool scan_all) } /** Try to free a clean page from the common LRU list. -@param[in] scan_all true=scan the whole LRU list - false=use BUF_LRU_SEARCH_SCAN_THRESHOLD +@param limit maximum number of blocks to scan @return whether a page was freed */ -static bool buf_LRU_free_from_common_LRU_list(bool scan_all) +static bool buf_LRU_free_from_common_LRU_list(ulint limit) { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ulint scanned = 0; bool freed = false; for (buf_page_t* bpage = buf_pool.lru_scan_itr.start(); - bpage && (scan_all || scanned < BUF_LRU_SEARCH_SCAN_THRESHOLD); + bpage && scanned < limit; ++scanned, bpage = buf_pool.lru_scan_itr.get()) { buf_page_t* prev = UT_LIST_GET_PREV(LRU, bpage); buf_pool.lru_scan_itr.set(prev); const auto accessed = bpage->is_accessed(); - freed = bpage->ready_for_replace(); - - if (freed) { - freed = buf_LRU_free_page(bpage, true); - if (!freed) { - continue; - } - + if (!bpage->oldest_modification() + && buf_LRU_free_page(bpage, true)) { if (!accessed) { /* Keep track of pages that are evicted without ever being accessed. This gives us a measure of @@ -532,6 +252,7 @@ static bool buf_LRU_free_from_common_LRU_list(bool scan_all) ++buf_pool.stat.n_ra_pages_evicted; } + freed = true; break; } } @@ -548,15 +269,14 @@ static bool buf_LRU_free_from_common_LRU_list(bool scan_all) } /** Try to free a replaceable block. -@param[in] scan_all true=scan the whole LRU list, - false=use BUF_LRU_SEARCH_SCAN_THRESHOLD +@param limit maximum number of blocks to scan @return true if found and freed */ -bool buf_LRU_scan_and_free_block(bool scan_all) +bool buf_LRU_scan_and_free_block(ulint limit) { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); - return(buf_LRU_free_from_unzip_LRU_list(scan_all) - || buf_LRU_free_from_common_LRU_list(scan_all)); + return buf_LRU_free_from_unzip_LRU_list(limit) || + buf_LRU_free_from_common_LRU_list(limit); } /** @return a buffer block from the buf_pool.free list @@ -565,7 +285,7 @@ buf_block_t* buf_LRU_get_free_only() { buf_block_t* block; - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); block = reinterpret_cast( UT_LIST_GET_FIRST(buf_pool.free)); @@ -611,106 +331,89 @@ function will either assert or issue a warning and switch on the status monitor. */ static void buf_LRU_check_size_of_non_data_objects() { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); - if (!recv_recovery_is_on() - && buf_pool.curr_size == buf_pool.old_size - && UT_LIST_GET_LEN(buf_pool.free) - + UT_LIST_GET_LEN(buf_pool.LRU) < buf_pool.curr_size / 20) { + if (recv_recovery_is_on() || buf_pool.curr_size != buf_pool.old_size) + return; - ib::fatal() << "Over 95 percent of the buffer pool is" - " occupied by lock heaps" + const auto s= UT_LIST_GET_LEN(buf_pool.free) + UT_LIST_GET_LEN(buf_pool.LRU); + + if (s < buf_pool.curr_size / 20) + ib::fatal() << "Over 95 percent of the buffer pool is" + " occupied by lock heaps" #ifdef BTR_CUR_HASH_ADAPT - " or the adaptive hash index!" + " or the adaptive hash index" #endif /* BTR_CUR_HASH_ADAPT */ - " Check that your transactions do not set too many" - " row locks, or review if" - " innodb_buffer_pool_size=" - << (buf_pool.curr_size >> (20U - srv_page_size_shift)) - << "M could be bigger."; - } else if (!recv_recovery_is_on() - && buf_pool.curr_size == buf_pool.old_size - && (UT_LIST_GET_LEN(buf_pool.free) - + UT_LIST_GET_LEN(buf_pool.LRU)) - < buf_pool.curr_size / 3) { + "! Check that your transactions do not set too many" + " row locks, or review if innodb_buffer_pool_size=" + << (buf_pool.curr_size >> (20U - srv_page_size_shift)) + << "M could be bigger."; - if (!buf_lru_switched_on_innodb_mon && srv_monitor_timer) { - - /* Over 67 % of the buffer pool is occupied by lock - heaps or the adaptive hash index. This may be a memory - leak! */ - - ib::warn() << "Over 67 percent of the buffer pool is" - " occupied by lock heaps" + if (s < buf_pool.curr_size / 3) + { + if (!buf_lru_switched_on_innodb_mon && srv_monitor_timer) + { + /* Over 67 % of the buffer pool is occupied by lock heaps or + the adaptive hash index. This may be a memory leak! */ + ib::warn() << "Over 67 percent of the buffer pool is" + " occupied by lock heaps" #ifdef BTR_CUR_HASH_ADAPT - " or the adaptive hash index!" + " or the adaptive hash index" #endif /* BTR_CUR_HASH_ADAPT */ - " Check that your transactions do not" - " set too many row locks." - " innodb_buffer_pool_size=" - << (buf_pool.curr_size >> - (20U - srv_page_size_shift)) << "M." - " Starting the InnoDB Monitor to print" - " diagnostics."; - - buf_lru_switched_on_innodb_mon = true; - srv_print_innodb_monitor = TRUE; - srv_monitor_timer_schedule_now(); - } - - } else if (buf_lru_switched_on_innodb_mon) { - - /* Switch off the InnoDB Monitor; this is a simple way - to stop the monitor if the situation becomes less urgent, - but may also surprise users if the user also switched on the - monitor! */ - - buf_lru_switched_on_innodb_mon = false; - srv_print_innodb_monitor = FALSE; - } + "! Check that your transactions do not set too many row locks." + " innodb_buffer_pool_size=" + << (buf_pool.curr_size >> (20U - srv_page_size_shift)) + << "M. Starting the InnoDB Monitor to print diagnostics."; + buf_lru_switched_on_innodb_mon= true; + srv_print_innodb_monitor= TRUE; + srv_monitor_timer_schedule_now(); + } + } + else if (buf_lru_switched_on_innodb_mon) + { + /* Switch off the InnoDB Monitor; this is a simple way to stop the + monitor if the situation becomes less urgent, but may also + surprise users who did SET GLOBAL innodb_status_output=ON earlier! */ + buf_lru_switched_on_innodb_mon= false; + srv_print_innodb_monitor= FALSE; + } } -/** Get a free block from the buf_pool. The block is taken off the -free list. If free list is empty, blocks are moved from the end of the -LRU list to the free list. +/** Get a block from the buf_pool.free list. +If the list is empty, blocks will be moved from the end of buf_pool.LRU +to buf_pool.free. This function is called from a user thread when it needs a clean block to read in a page. Note that we only ever get a block from the free list. Even when we flush a page or find a page in LRU scan we put it to free list to be used. * iteration 0: - * get a block from free list, success:done + * get a block from the buf_pool.free list, success:done * if buf_pool.try_LRU_scan is set - * scan LRU up to srv_LRU_scan_depth to find a clean block - * the above will put the block on free list + * scan LRU up to 100 pages to free a clean block * success:retry the free list - * flush one dirty page from tail of LRU to disk - * the above will put the block on free list + * flush up to innodb_lru_flush_size LRU blocks to data files + (until UT_LIST_GET_GEN(buf_pool.free) < innodb_lru_scan_depth) + * on buf_page_write_complete() the blocks will put on buf_pool.free list * success: retry the free list -* iteration 1: - * same as iteration 0 except: - * scan whole LRU list - * scan LRU list even if buf_pool.try_LRU_scan is not set -* iteration > 1: - * same as iteration 1 but sleep 10ms +* subsequent iterations: same as iteration 0 except: + * scan whole LRU list + * scan LRU list even if buf_pool.try_LRU_scan is not set @param have_mutex whether buf_pool.mutex is already being held @return the free control block, in state BUF_BLOCK_MEMORY */ buf_block_t* buf_LRU_get_free_block(bool have_mutex) { - buf_block_t* block = NULL; - bool freed = false; ulint n_iterations = 0; ulint flush_failures = 0; MONITOR_INC(MONITOR_LRU_GET_FREE_SEARCH); if (have_mutex) { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); goto got_mutex; } loop: - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); got_mutex: - buf_LRU_check_size_of_non_data_objects(); DBUG_EXECUTE_IF("ib_lru_force_no_free_page", @@ -718,49 +421,38 @@ got_mutex: n_iterations = 21; goto not_found;}); +retry: /* If there is a block in the free list, take it */ - block = buf_LRU_get_free_only(); - - if (block) { + if (buf_block_t* block = buf_LRU_get_free_only()) { if (!have_mutex) { - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); } memset(&block->page.zip, 0, sizeof block->page.zip); - return(block); + return block; } MONITOR_INC( MONITOR_LRU_GET_FREE_LOOPS ); - freed = false; if (n_iterations || buf_pool.try_LRU_scan) { /* If no block was in the free list, search from the end of the LRU list and try to free a block there. If we are doing for the first time we'll scan only tail of the LRU list otherwise we scan the whole LRU list. */ - freed = buf_LRU_scan_and_free_block(n_iterations > 0); - - if (!freed && n_iterations == 0) { - /* Tell other threads that there is no point - in scanning the LRU list. This flag is set to - TRUE again when we flush a batch from this - buffer pool. */ - buf_pool.try_LRU_scan = false; - - /* Also tell the page_cleaner thread that - there is work for it to do. */ - os_event_set(buf_flush_event); + if (buf_LRU_scan_and_free_block(n_iterations + ? ULINT_UNDEFINED : 100)) { + goto retry; } + + /* Tell other threads that there is no point + in scanning the LRU list. */ + buf_pool.try_LRU_scan = false; } #ifndef DBUG_OFF not_found: #endif - - mutex_exit(&buf_pool.mutex); - - if (freed) { - goto loop; - } + mysql_mutex_unlock(&buf_pool.mutex); + buf_flush_wait_batch_end_acquiring_mutex(true); if (n_iterations > 20 && !buf_lru_free_blocks_error_printed && srv_buf_pool_old_size == srv_buf_pool_size) { @@ -782,18 +474,8 @@ not_found: buf_lru_free_blocks_error_printed = true; } - /* If we have scanned the whole LRU and still are unable to - find a free block then we should sleep here to let the - page_cleaner do an LRU batch for us. */ - - if (!srv_read_only_mode) { - os_event_set(buf_flush_event); - } - if (n_iterations > 1) { - MONITOR_INC( MONITOR_LRU_GET_FREE_WAITS ); - os_thread_sleep(10000); } /* No free block was found: try to flush the LRU list. @@ -804,10 +486,10 @@ not_found: TODO: A more elegant way would have been to return the freed up block to the caller here but the code that deals with removing the block from page_hash and LRU_list is fairly - involved (particularly in case of compressed pages). We + involved (particularly in case of ROW_FORMAT=COMPRESSED pages). We can do that in a separate patch sometime in future. */ - if (!buf_flush_single_page_from_LRU()) { + if (!buf_flush_lists(innodb_lru_flush_size, 0)) { MONITOR_INC(MONITOR_LRU_SINGLE_FLUSH_FAILURE_COUNT); ++flush_failures; } @@ -827,7 +509,7 @@ static void buf_LRU_old_adjust_len() ulint new_len; ut_a(buf_pool.LRU_old); - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(buf_pool.LRU_old_ratio >= BUF_LRU_OLD_RATIO_MIN); ut_ad(buf_pool.LRU_old_ratio <= BUF_LRU_OLD_RATIO_MAX); compile_time_assert(BUF_LRU_OLD_RATIO_MIN * BUF_LRU_OLD_MIN_LEN @@ -888,7 +570,7 @@ static void buf_LRU_old_adjust_len() called when the LRU list grows to BUF_LRU_OLD_MIN_LEN length. */ static void buf_LRU_old_init() { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_a(UT_LIST_GET_LEN(buf_pool.LRU) == BUF_LRU_OLD_MIN_LEN); /* We first initialize all blocks in the LRU list as old and then use @@ -917,7 +599,7 @@ static void buf_LRU_old_init() static void buf_unzip_LRU_remove_block_if_needed(buf_page_t* bpage) { ut_ad(bpage->in_file()); - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); if (bpage->belongs_to_unzip_LRU()) { buf_block_t* block = reinterpret_cast(bpage); @@ -1000,7 +682,7 @@ buf_unzip_LRU_add_block( ibool old) /*!< in: TRUE if should be put to the end of the list, else put to the start */ { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_a(block->page.belongs_to_unzip_LRU()); ut_ad(!block->in_unzip_LRU_list); ut_d(block->in_unzip_LRU_list = true); @@ -1024,7 +706,7 @@ buf_LRU_add_block( LRU list is very short, the block is added to the start, regardless of this parameter */ { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(!bpage->in_LRU_list); if (!old || (UT_LIST_GET_LEN(buf_pool.LRU) < BUF_LRU_OLD_MIN_LEN)) { @@ -1084,7 +766,7 @@ void buf_page_make_young(buf_page_t *bpage) { ut_ad(bpage->in_file()); - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); if (UNIV_UNLIKELY(bpage->old)) buf_pool.stat.n_pages_made_young++; @@ -1092,7 +774,7 @@ void buf_page_make_young(buf_page_t *bpage) buf_LRU_remove_block(bpage); buf_LRU_add_block(bpage, false); - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); } /** Try to free a block. If bpage is a descriptor of a compressed-only @@ -1107,7 +789,7 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip) const page_id_t id(bpage->id()); buf_page_t* b = nullptr; - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(bpage->in_file()); ut_ad(bpage->in_LRU_list); @@ -1148,7 +830,7 @@ func_exit: b->set_state(BUF_BLOCK_ZIP_PAGE); } - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(bpage->in_file()); ut_ad(bpage->in_LRU_list); @@ -1238,9 +920,7 @@ func_exit: buf_LRU_add_block(b, b->old); } - if (b->oldest_modification()) { - buf_flush_relocate_on_flush_list(bpage, b); - } + buf_flush_relocate_on_flush_list(bpage, b); bpage->zip.data = nullptr; @@ -1253,25 +933,35 @@ func_exit: hash_lock->write_unlock(); } - mutex_exit(&buf_pool.mutex); - - /* Remove possible adaptive hash index on the page. - The page was declared uninitialized by - buf_LRU_block_remove_hashed(). We need to flag - the contents of the page valid (which it still is) in - order to avoid bogus Valgrind or MSAN warnings.*/ buf_block_t* block = reinterpret_cast(bpage); - MEM_MAKE_DEFINED(block->frame, srv_page_size); - btr_search_drop_page_hash_index(block); - MEM_UNDEFINED(block->frame, srv_page_size); +#ifdef BTR_CUR_HASH_ADAPT + if (block->index) { + mysql_mutex_unlock(&buf_pool.mutex); + /* Remove the adaptive hash index on the page. + The page was declared uninitialized by + buf_LRU_block_remove_hashed(). We need to flag + the contents of the page valid (which it still is) in + order to avoid bogus Valgrind or MSAN warnings.*/ + + MEM_MAKE_DEFINED(block->frame, srv_page_size); + btr_search_drop_page_hash_index(block); + MEM_UNDEFINED(block->frame, srv_page_size); + + if (UNIV_LIKELY_NULL(b)) { + ut_ad(b->zip_size()); + b->io_unfix(); + } + + mysql_mutex_lock(&buf_pool.mutex); + } else +#endif if (UNIV_LIKELY_NULL(b)) { ut_ad(b->zip_size()); b->io_unfix(); } - mutex_enter(&buf_pool.mutex); buf_LRU_block_free_hashed_page(block); return(true); @@ -1332,6 +1022,16 @@ buf_LRU_block_free_non_file_page( MEM_NOACCESS(block->frame, srv_page_size); } +/** Release a memory block to the buffer pool. */ +ATTRIBUTE_COLD void buf_pool_t::free_block(buf_block_t *block) +{ + ut_ad(this == &buf_pool); + mysql_mutex_lock(&mutex); + buf_LRU_block_free_non_file_page(block); + mysql_mutex_unlock(&mutex); +} + + /** Remove bpage from buf_pool.LRU and buf_pool.page_hash. If bpage->state() == BUF_BLOCK_ZIP_PAGE && !bpage->oldest_modification(), @@ -1350,7 +1050,7 @@ this case the block is already returned to the buddy allocator. */ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id, page_hash_latch *hash_lock, bool zip) { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(hash_lock->is_write_locked()); ut_a(bpage->io_fix() == BUF_IO_NONE); @@ -1545,7 +1245,7 @@ uint buf_LRU_old_ratio_update(uint old_pct, bool adjust) } if (adjust) { - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); if (ratio != buf_pool.LRU_old_ratio) { buf_pool.LRU_old_ratio = ratio; @@ -1556,7 +1256,7 @@ uint buf_LRU_old_ratio_update(uint old_pct, bool adjust) } } - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); } else { buf_pool.LRU_old_ratio = ratio; } @@ -1609,7 +1309,7 @@ void buf_LRU_validate() ulint old_len; ulint new_len; - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); if (UT_LIST_GET_LEN(buf_pool.LRU) >= BUF_LRU_OLD_MIN_LEN) { @@ -1687,7 +1387,7 @@ void buf_LRU_validate() ut_a(block->page.belongs_to_unzip_LRU()); } - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); } #endif /* UNIV_DEBUG */ @@ -1695,7 +1395,7 @@ void buf_LRU_validate() /** Dump the LRU list to stderr. */ void buf_LRU_print() { - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); for (buf_page_t* bpage = UT_LIST_GET_FIRST(buf_pool.LRU); bpage != NULL; @@ -1744,6 +1444,6 @@ void buf_LRU_print() } } - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); } #endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG */ diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index 911fce4cc43..d843865d0a9 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -121,7 +121,7 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id, const ulint fold= page_id.fold(); - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); /* We must acquire hash_lock this early to prevent a race condition with buf_pool_t::watch_remove() */ @@ -239,11 +239,11 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id, buf_LRU_add_block(bpage, true/* to old blocks */); } - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); buf_pool.n_pend_reads++; goto func_exit_no_mutex; func_exit: - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); func_exit_no_mutex: if (mode == BUF_READ_IBUF_PAGES_ONLY) ibuf_mtr_commit(&mtr); @@ -286,10 +286,10 @@ buf_read_page_low( *err = DB_SUCCESS; - if (!page_id.space() && buf_dblwr_page_inside(page_id.page_no())) { - + if (buf_dblwr.is_inside(page_id)) { ib::error() << "Trying to read doublewrite buffer page " << page_id; + ut_ad(0); return(0); } diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 5d5bf9967d2..131df87b383 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -1080,20 +1080,8 @@ static bool fil_crypt_start_encrypting_space(fil_space_t* space) mtr.commit(); - /* record lsn of update */ - lsn_t end_lsn = mtr.commit_lsn(); - /* 4 - sync tablespace before publishing crypt data */ - - bool success = false; - ulint sum_pages = 0; - - do { - ulint n_pages = 0; - success = buf_flush_lists(ULINT_MAX, end_lsn, &n_pages); - buf_flush_wait_batch_end(false); - sum_pages += n_pages; - } while (!success); + while (buf_flush_dirty_pages(space->id)); /* 5 - publish crypt data */ mutex_enter(&fil_crypt_threads_mutex); @@ -1156,7 +1144,6 @@ struct rotate_thread_t { case SRV_SHUTDOWN_CLEANUP: case SRV_SHUTDOWN_INITIATED: return true; - case SRV_SHUTDOWN_FLUSH_PHASE: case SRV_SHUTDOWN_LAST_PHASE: break; } @@ -1945,8 +1932,7 @@ fil_crypt_rotate_pages( * real pages, they will be updated anyway when the * real page is updated */ - if (space == TRX_SYS_SPACE && - buf_dblwr_page_inside(state->offset)) { + if (buf_dblwr.is_inside(page_id_t(space, state->offset))) { continue; } @@ -1978,20 +1964,19 @@ fil_crypt_flush_space( lsn_t end_lsn = crypt_data->rotate_state.end_lsn; if (end_lsn > 0 && !space->is_stopping()) { - bool success = false; - ulint n_pages = 0; ulint sum_pages = 0; const ulonglong start = my_interval_timer(); - do { - success = buf_flush_lists(ULINT_MAX, end_lsn, &n_pages); - buf_flush_wait_batch_end(false); - sum_pages += n_pages; - } while (!success && !space->is_stopping()); + ulint n_dirty= buf_flush_dirty_pages(state->space->id); + if (!n_dirty) { + break; + } + sum_pages += n_dirty; + } while (!space->is_stopping()); - const ulonglong end = my_interval_timer(); + if (sum_pages) { + const ulonglong end = my_interval_timer(); - if (sum_pages && end > start) { state->cnt_waited += sum_pages; state->sum_waited_us += (end - start) / 1000; diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 0325dce8422..93047391aa2 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -171,7 +171,6 @@ fil_system_t fil_system; /** At this age or older a space/page will be rotated */ UNIV_INTERN extern uint srv_fil_crypt_rotate_key_age; -UNIV_INTERN extern ib_mutex_t fil_crypt_threads_mutex; /** Determine if the space id is a user tablespace id or not. @param[in] space_id Space ID to check @@ -713,8 +712,8 @@ fil_space_extend_must_retry( const ulint page_size = space->physical_size(); - /* fil_read_first_page() expects srv_page_size bytes. - fil_node_open_file() expects at least 4 * srv_page_size bytes.*/ + /* Datafile::read_first_page() expects srv_page_size bytes. + fil_node_t::read_page0() expects at least 4 * srv_page_size bytes.*/ os_offset_t new_size = std::max( os_offset_t(size - file_start_page_no) * page_size, os_offset_t(FIL_IBD_FILE_INITIAL_SIZE << srv_page_size_shift)); @@ -2097,7 +2096,10 @@ void fil_close_tablespace(ulint id) Thus we can clean the tablespace out of buf_pool completely and permanently. The flag stop_new_ops also prevents fil_flush() from being applied to this tablespace. */ - buf_LRU_flush_or_remove_pages(id, true); + while (buf_flush_dirty_pages(id)); + /* Ensure that all asynchronous IO is completed. */ + os_aio_wait_until_no_pending_writes(); + fil_flush(id); /* If the free is successful, the X lock will be released before the space memory data structure is freed. */ @@ -2186,7 +2188,7 @@ dberr_t fil_delete_tablespace(ulint id, bool if_exists, ::stop_new_ops flag in fil_io(). */ err = DB_SUCCESS; - buf_LRU_flush_or_remove_pages(id, false); + buf_flush_remove_pages(id); /* If it is a delete then also delete any generated files, otherwise when we drop the database the remove directory will fail. */ @@ -3683,15 +3685,6 @@ fil_report_invalid_page_access(const page_id_t id, const char *name, << ". Byte offset " << byte_offset << ", len " << len; } -inline void IORequest::set_fil_node(fil_node_t* node) -{ - if (!node->space->punch_hole) { - clear_punch_hole(); - } - - m_fil_node = node; -} - /** Reads or writes data. This operation could be asynchronous (aio). @param[in,out] type IO context @@ -3726,9 +3719,8 @@ fil_io( bool punch_hole) { os_offset_t offset; - IORequest req_type(type); - ut_ad(req_type.validate()); + ut_ad(type.validate()); ut_ad(len > 0); ut_ad(byte_offset < srv_page_size); @@ -3742,7 +3734,7 @@ fil_io( /* ibuf bitmap pages must be read in the sync AIO mode: */ ut_ad(recv_no_ibuf_operations - || req_type.is_write() + || type.is_write() || !ibuf_bitmap_page(page_id, zip_size) || sync); @@ -3750,7 +3742,7 @@ fil_io( if (sync) { mode = OS_AIO_SYNC; - } else if (req_type.is_read() + } else if (type.is_read() && !recv_no_ibuf_operations && ibuf_page(page_id, zip_size, NULL)) { mode = OS_AIO_IBUF; @@ -3758,11 +3750,11 @@ fil_io( mode = OS_AIO_NORMAL; } - if (req_type.is_read()) { + if (type.is_read()) { srv_stats.data_read.add(len); - } else if (req_type.is_write()) { + } else if (type.is_write()) { ut_ad(!srv_read_only_mode || fsp_is_system_temporary(page_id.space())); @@ -3776,7 +3768,7 @@ fil_io( page_id.space()); if (!space - || (req_type.is_read() + || (type.is_read() && !sync && space->is_stopping() && !space->is_being_truncated)) { @@ -3786,7 +3778,7 @@ fil_io( ib::error() << "Trying to do I/O to a tablespace which" " does not exist. I/O type: " - << (req_type.is_read() ? "read" : "write") + << (type.is_read() ? "read" : "write") << ", page: " << page_id << ", I/O length: " << len << " bytes"; } @@ -3807,7 +3799,7 @@ fil_io( fil_report_invalid_page_access( page_id, space->name, byte_offset, len, - req_type.is_read()); + type.is_read()); } else if (fil_is_user_tablespace_id(space->id) && node->size == 0) { @@ -3838,7 +3830,7 @@ fil_io( << space->name << "' which exists without .ibd data file." " I/O type: " - << (req_type.is_read() + << (type.is_read() ? "read" : "write") << ", page: " << page_id @@ -3853,14 +3845,14 @@ fil_io( /* If we can tolerate the non-existent pages, we should return with DB_ERROR and let caller decide what to do. */ - node->complete_io(req_type.is_write()); + node->complete_io(type.is_write()); mutex_exit(&fil_system.mutex); return {DB_ERROR, nullptr}; } fil_report_invalid_page_access( page_id, space->name, byte_offset, len, - req_type.is_read()); + type.is_read()); } space->acquire_for_io(); @@ -3879,9 +3871,7 @@ fil_io( const char* name = node->name == NULL ? space->name : node->name; - req_type.set_fil_node(node); - - ut_ad(!req_type.is_write() + ut_ad(!type.is_write() || !fil_is_user_tablespace_id(page_id.space()) || offset == page_id.page_no() * zip_size); @@ -3897,6 +3887,8 @@ fil_io( err = DB_SUCCESS; } } else { + IORequest req_type(type); + req_type.set_fil_node(node); /* Queue the aio request */ err = os_aio( req_type, @@ -3909,10 +3901,10 @@ fil_io( /* We an try to recover the page from the double write buffer if the decompression fails or the page is corrupt. */ - ut_a(req_type.is_dblwr_recover() || err == DB_SUCCESS); + ut_a(type.is_dblwr_recover() || err == DB_SUCCESS); if (sync) { mutex_enter(&fil_system.mutex); - node->complete_io(req_type.is_write()); + node->complete_io(type.is_write()); mutex_exit(&fil_system.mutex); ut_ad(fil_validate_skip()); } @@ -3960,7 +3952,7 @@ write_completed: bpage->status= buf_page_t::NORMAL; dblwr= false; } - buf_page_write_complete(bpage, data->type, dblwr, false); + buf_page_write_complete(bpage, data->type, dblwr); goto write_completed; } diff --git a/storage/innobase/fsp/fsp0file.cc b/storage/innobase/fsp/fsp0file.cc index a8f04a754b4..e8fc47f3e41 100644 --- a/storage/innobase/fsp/fsp0file.cc +++ b/storage/innobase/fsp/fsp0file.cc @@ -296,14 +296,13 @@ Datafile::read_first_page(bool read_only_mode) m_first_page = static_cast( aligned_malloc(UNIV_PAGE_SIZE_MAX, srv_page_size)); - IORequest request; + constexpr IORequest request(IORequest::READ | + IORequest::DISABLE_PARTIAL_IO_WARNINGS); dberr_t err = DB_ERROR; size_t page_size = UNIV_PAGE_SIZE_MAX; /* Don't want unnecessary complaints about partial reads. */ - request.disable_partial_io_warnings(); - while (page_size >= UNIV_PAGE_SIZE_MIN) { ulint n_read = 0; @@ -805,10 +804,8 @@ Datafile::restore_from_doublewrite() << physical_size << " bytes into file '" << m_filepath << "'"; - IORequest request(IORequest::WRITE); - return(os_file_write( - request, + IORequestWrite, m_filepath, m_handle, page, 0, physical_size) != DB_SUCCESS); } diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index 6ac57ca395c..fedade4366f 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -553,11 +553,18 @@ void fsp_header_init(fil_space_t* space, ulint size, mtr_t* mtr) const page_id_t page_id(space->id, 0); const ulint zip_size = space->zip_size(); + buf_block_t *free_block = buf_LRU_get_free_block(false); + mtr_x_lock_space(space, mtr); - buf_block_t* block = buf_page_create(space, 0, zip_size, mtr); + buf_block_t* block = buf_page_create(space, 0, zip_size, mtr, + free_block); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); + if (UNIV_UNLIKELY(block != free_block)) { + buf_pool.free_block(free_block); + } + space->size_in_header = size; space->free_len = 0; space->free_limit = 0; @@ -874,11 +881,14 @@ fsp_fill_free_list( pages should be ignored. */ if (i > 0) { + buf_block_t *f= buf_LRU_get_free_block(false); block= buf_page_create( space, static_cast(i), - zip_size, mtr); - + zip_size, mtr, f); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); + if (UNIV_UNLIKELY(block != f)) { + buf_pool.free_block(f); + } fsp_init_file_page(space, block, mtr); mtr->write<2>(*block, FIL_PAGE_TYPE + block->frame, @@ -886,13 +896,16 @@ fsp_fill_free_list( } if (space->purpose != FIL_TYPE_TEMPORARY) { + buf_block_t *f= buf_LRU_get_free_block(false); block = buf_page_create( space, static_cast( i + FSP_IBUF_BITMAP_OFFSET), - zip_size, mtr); + zip_size, mtr, f); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); - + if (UNIV_UNLIKELY(block != f)) { + buf_pool.free_block(f); + } fsp_init_file_page(space, block, mtr); mtr->write<2>(*block, block->frame + FIL_PAGE_TYPE, @@ -1042,8 +1055,11 @@ static buf_block_t* fsp_page_create(fil_space_t *space, page_no_t offset, mtr_t *mtr) { + buf_block_t *free_block= buf_LRU_get_free_block(false); buf_block_t *block= buf_page_create(space, static_cast(offset), - space->zip_size(), mtr); + space->zip_size(), mtr, free_block); + if (UNIV_UNLIKELY(block != free_block)) + buf_pool.free_block(free_block); fsp_init_file_page(space, block, mtr); return block; } diff --git a/storage/innobase/fsp/fsp0sysspace.cc b/storage/innobase/fsp/fsp0sysspace.cc index 5d381fca033..2e4b3678760 100644 --- a/storage/innobase/fsp/fsp0sysspace.cc +++ b/storage/innobase/fsp/fsp0sysspace.cc @@ -559,7 +559,7 @@ SysTablespace::read_lsn_and_check_flags(lsn_t* flushed_lsn) ut_a(it->order() == 0); if (srv_operation == SRV_OPERATION_NORMAL) { - buf_dblwr_init_or_load_pages(it->handle(), it->filepath()); + buf_dblwr.init_or_load_pages(it->handle(), it->filepath()); } /* Check the contents of the first page of the diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ec2764f44a9..f9cc8629a73 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -878,8 +878,7 @@ static SHOW_VAR innodb_status_variables[]= { &export_vars.innodb_buffer_pool_pages_dirty, SHOW_SIZE_T}, {"buffer_pool_bytes_dirty", &export_vars.innodb_buffer_pool_bytes_dirty, SHOW_SIZE_T}, - {"buffer_pool_pages_flushed", - &export_vars.innodb_buffer_pool_pages_flushed, SHOW_SIZE_T}, + {"buffer_pool_pages_flushed", &buf_flush_page_count, SHOW_SIZE_T}, {"buffer_pool_pages_free", &export_vars.innodb_buffer_pool_pages_free, SHOW_SIZE_T}, #ifdef UNIV_DEBUG @@ -17505,6 +17504,7 @@ func_exit: block->frame[FIL_PAGE_SPACE_ID]); } mtr.commit(); + log_write_up_to(mtr.commit_lsn(), true); goto func_exit; } #endif // UNIV_DEBUG @@ -17966,7 +17966,7 @@ static bool innodb_buffer_pool_evict_uncompressed() { bool all_evicted = true; - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); for (buf_block_t* block = UT_LIST_GET_LAST(buf_pool.unzip_LRU); block != NULL; ) { @@ -17986,7 +17986,7 @@ static bool innodb_buffer_pool_evict_uncompressed() } } - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); return(all_evicted); } @@ -19063,13 +19063,13 @@ static MYSQL_SYSVAR_ULONG(page_cleaners, deprecated::innodb_page_cleaners, static MYSQL_SYSVAR_DOUBLE(max_dirty_pages_pct, srv_max_buf_pool_modified_pct, PLUGIN_VAR_RQCMDARG, "Percentage of dirty pages allowed in bufferpool.", - NULL, innodb_max_dirty_pages_pct_update, 75.0, 0, 99.999, 0); + NULL, innodb_max_dirty_pages_pct_update, 90.0, 0, 99.999, 0); static MYSQL_SYSVAR_DOUBLE(max_dirty_pages_pct_lwm, srv_max_dirty_pages_pct_lwm, PLUGIN_VAR_RQCMDARG, "Percentage of dirty pages at which flushing kicks in.", - NULL, innodb_max_dirty_pages_pct_lwm_update, 0, 0, 99.999, 0); + NULL, innodb_max_dirty_pages_pct_lwm_update, 75.0, 0, 99.999, 0); static MYSQL_SYSVAR_DOUBLE(adaptive_flushing_lwm, srv_adaptive_flushing_lwm, @@ -19234,13 +19234,6 @@ static MYSQL_SYSVAR_ULONG(buffer_pool_chunk_size, srv_buf_pool_chunk_unit, NULL, NULL, 128 * 1024 * 1024, 1024 * 1024, LONG_MAX, 1024 * 1024); -#if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG -static MYSQL_SYSVAR_ULONG(doublewrite_batch_size, srv_doublewrite_batch_size, - PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, - "Number of pages reserved in doublewrite buffer for batch flushing", - NULL, NULL, 120, 1, 127, 0); -#endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */ - static MYSQL_SYSVAR_ENUM(lock_schedule_algorithm, innodb_lock_schedule_algorithm, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "The algorithm Innodb uses for deciding which locks to grant next when" @@ -19364,7 +19357,12 @@ static MYSQL_SYSVAR_UINT(defragment_frequency, srv_defragment_frequency, static MYSQL_SYSVAR_ULONG(lru_scan_depth, srv_LRU_scan_depth, PLUGIN_VAR_RQCMDARG, "How deep to scan LRU to keep it clean", - NULL, NULL, 1024, 100, ~0UL, 0); + NULL, NULL, 1536, 100, ~0UL, 0); + +static MYSQL_SYSVAR_SIZE_T(lru_flush_size, innodb_lru_flush_size, + PLUGIN_VAR_RQCMDARG, + "How many pages to flush on LRU eviction", + NULL, NULL, 32, 1, SIZE_T_MAX, 0); static MYSQL_SYSVAR_ULONG(flush_neighbors, srv_flush_neighbors, PLUGIN_VAR_OPCMDARG, @@ -19994,6 +19992,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(defragment_fill_factor_n_recs), MYSQL_SYSVAR(defragment_frequency), MYSQL_SYSVAR(lru_scan_depth), + MYSQL_SYSVAR(lru_flush_size), MYSQL_SYSVAR(flush_neighbors), MYSQL_SYSVAR(checksum_algorithm), MYSQL_SYSVAR(log_checksums), @@ -20115,9 +20114,6 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(buf_flush_list_now), MYSQL_SYSVAR(merge_threshold_set_all_debug), #endif /* UNIV_DEBUG */ -#if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG - MYSQL_SYSVAR(doublewrite_batch_size), -#endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */ MYSQL_SYSVAR(status_output), MYSQL_SYSVAR(status_output_locks), MYSQL_SYSVAR(print_all_deadlocks), @@ -21191,10 +21187,10 @@ innodb_buffer_pool_size_validate( #endif /* UNIV_DEBUG */ - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); if (srv_buf_pool_old_size != srv_buf_pool_size) { - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); my_printf_error(ER_WRONG_ARGUMENTS, "Another buffer pool resize is already in progress.", MYF(0)); return(1); @@ -21205,13 +21201,13 @@ innodb_buffer_pool_size_validate( *static_cast(save) = requested_buf_pool_size; if (srv_buf_pool_size == ulint(intbuf)) { - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); /* nothing to do */ return(0); } if (srv_buf_pool_size == requested_buf_pool_size) { - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_WRONG_ARGUMENTS, "innodb_buffer_pool_size must be at least" @@ -21222,7 +21218,7 @@ innodb_buffer_pool_size_validate( } srv_buf_pool_size = requested_buf_pool_size; - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); if (intbuf != static_cast(requested_buf_pool_size)) { char buf[64]; diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 9d77b6625b8..de4195b5727 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -1635,7 +1635,7 @@ i_s_cmpmem_fill_low( buf_buddy_stat_t buddy_stat_local[BUF_BUDDY_SIZES_MAX + 1]; /* Save buddy stats for buffer pool in local variables. */ - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) { zip_free_len_local[x] = (x < BUF_BUDDY_SIZES) ? @@ -1650,7 +1650,7 @@ i_s_cmpmem_fill_low( } } - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) { buf_buddy_stat_t* buddy_stat = &buddy_stat_local[x]; @@ -4270,7 +4270,7 @@ static int i_s_innodb_buffer_page_fill(THD *thd, TABLE_LIST *tables, Item *) buffer pool info printout, we are not required to preserve the overall consistency, so we can release mutex periodically */ - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); /* GO through each block in the chunk */ for (n_blocks = num_to_process; n_blocks--; block++) { @@ -4281,7 +4281,7 @@ static int i_s_innodb_buffer_page_fill(THD *thd, TABLE_LIST *tables, Item *) num_page++; } - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); /* Fill in information schema table with information just collected from the buffer chunk scan */ @@ -4604,7 +4604,7 @@ static int i_s_innodb_fill_buffer_lru(THD *thd, TABLE_LIST *tables, Item *) /* Aquire the mutex before allocating info_buffer, since UT_LIST_GET_LEN(buf_pool.LRU) could change */ - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); lru_len = UT_LIST_GET_LEN(buf_pool.LRU); @@ -4636,7 +4636,7 @@ static int i_s_innodb_fill_buffer_lru(THD *thd, TABLE_LIST *tables, Item *) ut_ad(lru_pos == UT_LIST_GET_LEN(buf_pool.LRU)); exit: - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); if (info_buffer) { status = i_s_innodb_buf_page_lru_fill( diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 9b58fa76c01..d5b65bb7ed8 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -104,10 +104,6 @@ struct buf_pool_info_t ulint n_pend_reads; /*!< buf_pool.n_pend_reads, pages pending read */ ulint n_pending_flush_lru; /*!< Pages pending flush in LRU */ - ulint n_pending_flush_single_page;/*!< Pages pending to be - flushed as part of single page - flushes issued by various user - threads */ ulint n_pending_flush_list; /*!< Pages pending flush in FLUSH LIST */ ulint n_pages_made_young; /*!< number of pages made young */ @@ -339,10 +335,11 @@ FILE_PAGE (the other is buf_page_get_gen). @param[in] offset offset of the tablespace @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 @param[in,out] mtr mini-transaction +@param[in,out] free_block pre-allocated buffer block @return pointer to the block, page bufferfixed */ buf_block_t* buf_page_create(fil_space_t *space, uint32_t offset, - ulint zip_size, mtr_t *mtr); + ulint zip_size, mtr_t *mtr, buf_block_t *free_block); /********************************************************************//** Releases a compressed-only page acquired with buf_page_get_zip(). */ @@ -1038,7 +1035,7 @@ struct buf_block_t{ is of size srv_page_size, and aligned to an address divisible by srv_page_size */ - BPageLock lock; /*!< read-write lock of the buffer + rw_lock_t lock; /*!< read-write lock of the buffer frame */ #ifdef UNIV_DEBUG /** whether page.list is in buf_pool.withdraw @@ -1214,13 +1211,13 @@ public: virtual ~HazardPointer() {} /** @return current value */ - buf_page_t *get() const { ut_ad(mutex_own(m_mutex)); return m_hp; } + buf_page_t *get() const { mysql_mutex_assert_owner(m_mutex); return m_hp; } /** Set current value @param bpage buffer block to be set as hp */ void set(buf_page_t *bpage) { - ut_ad(mutex_own(m_mutex)); + mysql_mutex_assert_owner(m_mutex); ut_ad(!bpage || bpage->in_file()); m_hp= bpage; } @@ -1229,7 +1226,7 @@ public: @param bpage buffer block to be compared @return true if it is hp */ bool is_hp(const buf_page_t *bpage) const - { ut_ad(mutex_own(m_mutex)); return bpage == m_hp; } + { mysql_mutex_assert_owner(m_mutex); return bpage == m_hp; } /** Adjust the value of hp. This happens when some other thread working on the same list attempts to @@ -1238,7 +1235,7 @@ public: #ifdef UNIV_DEBUG /** mutex that protects access to the m_hp. */ - const ib_mutex_t *m_mutex= nullptr; + const mysql_mutex_t *m_mutex= nullptr; #endif /* UNIV_DEBUG */ protected: @@ -1494,7 +1491,10 @@ public: bool will_be_withdrawn(const byte *ptr) const { ut_ad(curr_size < old_size); - ut_ad(!resizing.load(std::memory_order_relaxed) || mutex_own(&mutex)); +#ifdef SAFE_MUTEX + if (resizing.load(std::memory_order_relaxed)) + mysql_mutex_assert_owner(&mutex); +#endif /* SAFE_MUTEX */ for (const chunk_t *chunk= chunks + n_chunks_new, * const echunk= chunks + n_chunks; @@ -1511,7 +1511,10 @@ public: bool will_be_withdrawn(const buf_page_t &bpage) const { ut_ad(curr_size < old_size); - ut_ad(!resizing.load(std::memory_order_relaxed) || mutex_own(&mutex)); +#ifdef SAFE_MUTEX + if (resizing.load(std::memory_order_relaxed)) + mysql_mutex_assert_owner(&mutex); +#endif /* SAFE_MUTEX */ for (const chunk_t *chunk= chunks + n_chunks_new, * const echunk= chunks + n_chunks; @@ -1524,7 +1527,10 @@ public: /** Release and evict a corrupted page. @param bpage page that was being read */ - void corrupted_evict(buf_page_t *bpage); + ATTRIBUTE_COLD void corrupted_evict(buf_page_t *bpage); + + /** Release a memory block to the buffer pool. */ + ATTRIBUTE_COLD void free_block(buf_block_t *block); #ifdef UNIV_DEBUG /** Find a block that points to a ROW_FORMAT=COMPRESSED page @@ -1533,7 +1539,7 @@ public: @retval nullptr if not found */ const buf_block_t *contains_zip(const void *data) const { - ut_ad(mutex_own(&mutex)); + mysql_mutex_assert_owner(&mutex); for (const chunk_t *chunk= chunks, * const end= chunks + n_chunks; chunk != end; chunk++) if (const buf_block_t *block= chunk->contains_zip(data)) @@ -1556,8 +1562,8 @@ public: inline buf_block_t *block_from_ahi(const byte *ptr) const; #endif /* BTR_CUR_HASH_ADAPT */ - bool is_block_lock(const BPageLock *l) const - { return is_block_field(reinterpret_cast(l)); } + bool is_block_lock(const rw_lock_t *l) const + { return is_block_field(static_cast(l)); } /** @return the smallest oldest_modification lsn for any page @@ -1588,7 +1594,10 @@ public: buf_page_t *page_hash_get_low(const page_id_t id, const ulint fold) { ut_ad(id.fold() == fold); - ut_ad(mutex_own(&mutex) || page_hash.lock_get(fold)->is_locked()); +#ifdef SAFE_MUTEX + DBUG_ASSERT(mysql_mutex_is_owner(&mutex) || + page_hash.lock_get(fold)->is_locked()); +#endif /* SAFE_MUTEX */ buf_page_t *bpage; /* Look for the page in the hash table */ HASH_SEARCH(hash, &page_hash, fold, buf_page_t*, bpage, @@ -1655,7 +1664,10 @@ public: @return whether bpage a sentinel for a buffer pool watch */ bool watch_is_sentinel(const buf_page_t &bpage) { - ut_ad(mutex_own(&mutex) || hash_lock_get(bpage.id())->is_locked()); +#ifdef SAFE_MUTEX + DBUG_ASSERT(mysql_mutex_is_owner(&mutex) || + hash_lock_get(bpage.id())->is_locked()); +#endif /* SAFE_MUTEX */ ut_ad(bpage.in_file()); if (&bpage < &watch[0] || &bpage >= &watch[UT_ARR_SIZE(watch)]) @@ -1712,7 +1724,7 @@ public: HASH_DELETE(buf_page_t, hash, &page_hash, fold, watch); hash_lock->write_unlock(); // Now that the watch is detached from page_hash, release it to watch[]. - mutex_enter(&mutex); + mysql_mutex_lock(&mutex); /* It is possible that watch_remove() already removed the watch. */ if (watch->id_ == id) { @@ -1720,7 +1732,7 @@ public: ut_ad(watch->state() == BUF_BLOCK_ZIP_PAGE); watch->set_state(BUF_BLOCK_NOT_USED); } - mutex_exit(&mutex); + mysql_mutex_unlock(&mutex); } else hash_lock->write_unlock(); @@ -1753,14 +1765,13 @@ public: @return the predecessor in the LRU list */ buf_page_t *LRU_remove(buf_page_t *bpage) { - ut_ad(mutex_own(&mutex)); + mysql_mutex_assert_owner(&mutex); ut_ad(bpage->in_LRU_list); ut_ad(bpage->in_page_hash); ut_ad(!bpage->in_zip_hash); ut_ad(bpage->in_file()); lru_hp.adjust(bpage); lru_scan_itr.adjust(bpage); - single_scan_itr.adjust(bpage); ut_d(bpage->in_LRU_list= false); buf_page_t *prev= UT_LIST_GET_PREV(LRU, bpage); UT_LIST_REMOVE(LRU, bpage); @@ -1770,9 +1781,19 @@ public: /** Number of pages to read ahead */ static constexpr uint32_t READ_AHEAD_PAGES= 64; + /** Buffer pool mutex */ + mysql_mutex_t mutex; + /** Number of pending LRU flush. */ + Atomic_counter n_flush_LRU; + /** broadcast when n_flush_LRU reaches 0; protected by mutex */ + mysql_cond_t done_flush_LRU; + /** Number of pending flush_list flush. */ + Atomic_counter n_flush_list; + /** broadcast when n_flush_list reaches 0; protected by mutex */ + mysql_cond_t done_flush_list; + /** @name General fields */ /* @{ */ - BufPoolMutex mutex; /*!< Buffer pool mutex */ ulint curr_pool_size; /*!< Current pool size in bytes */ ulint LRU_old_ratio; /*!< Reserve this much of the buffer pool for "old" blocks */ @@ -1903,36 +1924,23 @@ public: /* @} */ - /** @name Page flushing algorithm fields */ + /** @name Page flushing algorithm fields */ + /* @{ */ - /* @{ */ + /** mutex protecting flush_list, buf_page_t::set_oldest_modification() + and buf_page_t::list pointers when !oldest_modification() */ + mysql_mutex_t flush_list_mutex; + /** "hazard pointer" for flush_list scans; protected by flush_list_mutex */ + FlushHp flush_hp; + /** modified blocks (a subset of LRU) */ + UT_LIST_BASE_NODE_T(buf_page_t) flush_list; + + /** signalled to wake up the page_cleaner; protected by flush_list_mutex */ + mysql_cond_t do_flush_list; + + // n_flush_LRU + n_flush_list is approximately COUNT(io_fix()==BUF_IO_WRITE) + // in flush_list - FlushListMutex flush_list_mutex;/*!< mutex protecting the - flush list access. This mutex - protects flush_list - and bpage::list pointers when - the bpage is on flush_list. It - also protects writes to - bpage::oldest_modification and - flush_list_hp */ - FlushHp flush_hp;/*!< "hazard pointer" - used during scan of flush_list - while doing flush list batch. - Protected by flush_list_mutex */ - UT_LIST_BASE_NODE_T(buf_page_t) flush_list; - /*!< base node of the modified block - list */ - /** set if a flush of the type is being initialized */ - Atomic_relaxed init_flush[3]; - /** Number of pending writes of a flush type. - The sum of these is approximately the sum of BUF_IO_WRITE blocks. */ - Atomic_counter n_flush[3]; - os_event_t no_flush[3]; - /*!< this is in the set state - when there is no flush batch - of the given type running; - os_event_set() and os_event_reset() - are protected by buf_pool_t::mutex */ unsigned freed_page_clock;/*!< a sequence number used to count the number of buffer blocks removed from the end of @@ -1978,10 +1986,6 @@ public: replacable victim. Protected by buf_pool_t::mutex. */ LRUItr lru_scan_itr; - /** Iterator used to scan the LRU list when searching for - single page flushing victim. Protected by buf_pool_t::mutex. */ - LRUItr single_scan_itr; - UT_LIST_BASE_NODE_T(buf_page_t) LRU; /*!< base node of the LRU list */ @@ -2020,16 +2024,12 @@ public: /** @return whether any I/O is pending */ bool any_io_pending() const { - return n_pend_reads || - n_flush[IORequest::LRU] || n_flush[IORequest::FLUSH_LIST] || - n_flush[IORequest::SINGLE_PAGE]; + return n_pend_reads || n_flush_LRU || n_flush_list; } /** @return total amount of pending I/O */ ulint io_pending() const { - return n_pend_reads + - n_flush[IORequest::LRU] + n_flush[IORequest::FLUSH_LIST] + - n_flush[IORequest::SINGLE_PAGE]; + return n_pend_reads + n_flush_LRU + n_flush_list; } private: /** Temporary memory for page_compressed and encrypted I/O */ @@ -2086,7 +2086,7 @@ extern buf_pool_t buf_pool; inline void page_hash_latch::read_lock() { - ut_ad(!mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_not_owner(&buf_pool.mutex); if (!read_trylock()) read_lock_wait(); } @@ -2099,19 +2099,19 @@ inline void page_hash_latch::write_lock() inline void buf_page_t::add_buf_fix_count(uint32_t count) { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); buf_fix_count_+= count; } inline void buf_page_t::set_buf_fix_count(uint32_t count) { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); buf_fix_count_= count; } inline void buf_page_t::set_state(buf_page_state state) { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); #ifdef UNIV_DEBUG switch (state) { case BUF_BLOCK_REMOVE_HASH: @@ -2140,7 +2140,7 @@ inline void buf_page_t::set_state(buf_page_state state) inline void buf_page_t::set_io_fix(buf_io_fix io_fix) { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); io_fix_= io_fix; } @@ -2166,7 +2166,7 @@ inline void buf_page_t::set_corrupt_id() /** Set oldest_modification when adding to buf_pool.flush_list */ inline void buf_page_t::set_oldest_modification(lsn_t lsn) { - ut_ad(mutex_own(&buf_pool.flush_list_mutex)); + mysql_mutex_assert_owner(&buf_pool.flush_list_mutex); ut_ad(!oldest_modification()); oldest_modification_= lsn; } @@ -2174,7 +2174,7 @@ inline void buf_page_t::set_oldest_modification(lsn_t lsn) /** Clear oldest_modification when removing from buf_pool.flush_list */ inline void buf_page_t::clear_oldest_modification() { - ut_ad(mutex_own(&buf_pool.flush_list_mutex)); + mysql_mutex_assert_owner(&buf_pool.flush_list_mutex); ut_d(const auto state= state_); ut_ad(state == BUF_BLOCK_FILE_PAGE || state == BUF_BLOCK_ZIP_PAGE || state == BUF_BLOCK_REMOVE_HASH); @@ -2185,7 +2185,7 @@ inline void buf_page_t::clear_oldest_modification() /** @return whether the block is modified and ready for flushing */ inline bool buf_page_t::ready_for_flush() const { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(in_LRU_list); ut_a(in_file()); return oldest_modification() && io_fix_ == BUF_IO_NONE; @@ -2195,7 +2195,7 @@ inline bool buf_page_t::ready_for_flush() const The block can be dirty, but it must not be I/O-fixed or bufferfixed. */ inline bool buf_page_t::can_relocate() const { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(in_file()); ut_ad(in_LRU_list); return io_fix_ == BUF_IO_NONE && !buf_fix_count_; @@ -2204,7 +2204,7 @@ inline bool buf_page_t::can_relocate() const /** @return whether the block has been flagged old in buf_pool.LRU */ inline bool buf_page_t::is_old() const { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(in_file()); ut_ad(in_LRU_list); return old; @@ -2213,7 +2213,7 @@ inline bool buf_page_t::is_old() const /** Set whether a block is old in buf_pool.LRU */ inline void buf_page_t::set_old(bool old) { - ut_ad(mutex_own(&buf_pool.mutex)); + mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(in_LRU_list); #ifdef UNIV_LRU_DEBUG @@ -2240,14 +2240,14 @@ inline void buf_page_t::set_old(bool old) #ifdef UNIV_DEBUG /** Forbid the release of the buffer pool mutex. */ -# define buf_pool_mutex_exit_forbid() do { \ - ut_ad(mutex_own(&buf_pool.mutex)); \ - buf_pool.mutex_exit_forbidden++; \ +# define buf_pool_mutex_exit_forbid() do { \ + mysql_mutex_assert_owner(&buf_pool.mutex); \ + buf_pool.mutex_exit_forbidden++; \ } while (0) /** Allow the release of the buffer pool mutex. */ # define buf_pool_mutex_exit_allow() do { \ - ut_ad(mutex_own(&buf_pool.mutex)); \ - ut_ad(buf_pool.mutex_exit_forbidden--); \ + mysql_mutex_assert_owner(&buf_pool.mutex); \ + ut_ad(buf_pool.mutex_exit_forbidden--); \ } while (0) #else /** Forbid the release of the buffer pool mutex. */ @@ -2265,8 +2265,7 @@ MEMORY: is not in free list, LRU list, or flush list, nor page hash table FILE_PAGE: space and offset are defined, is in page hash table if io_fix == BUF_IO_WRITE, - pool: no_flush[flush_type] is in reset state, - pool: n_flush[flush_type] > 0 + buf_pool.n_flush_LRU > 0 || buf_pool.n_flush_list > 0 (1) if buf_fix_count == 0, then is in LRU list, not in free list @@ -2303,7 +2302,7 @@ of the LRU list. @return buf_page_t from where to start scan. */ inline buf_page_t *LRUItr::start() { - ut_ad(mutex_own(m_mutex)); + mysql_mutex_assert_owner(m_mutex); if (!m_hp || m_hp->old) m_hp= UT_LIST_GET_LAST(buf_pool.LRU); diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic index 2384c46af02..3074489527f 100644 --- a/storage/innobase/include/buf0buf.ic +++ b/storage/innobase/include/buf0buf.ic @@ -198,9 +198,9 @@ buf_block_free( /*===========*/ buf_block_t* block) /*!< in, own: block to be freed */ { - mutex_enter(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.mutex); buf_LRU_block_free_non_file_page(block); - mutex_exit(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); } /********************************************************************//** @@ -213,12 +213,20 @@ buf_block_modify_clock_inc( /*=======================*/ buf_block_t* block) /*!< in: block */ { +#ifdef SAFE_MUTEX /* No latch is acquired for the shared temporary tablespace. */ ut_ad(fsp_is_system_temporary(block->page.id().space()) - || (mutex_own(&buf_pool.mutex) + || (mysql_mutex_is_owner(&buf_pool.mutex) && !block->page.buf_fix_count()) || rw_lock_own_flagged(&block->lock, RW_LOCK_FLAG_X | RW_LOCK_FLAG_SX)); +#else /* SAFE_MUTEX */ + /* No latch is acquired for the shared temporary tablespace. */ + ut_ad(fsp_is_system_temporary(block->page.id().space()) + || !block->page.buf_fix_count() + || rw_lock_own_flagged(&block->lock, + RW_LOCK_FLAG_X | RW_LOCK_FLAG_SX)); +#endif /* SAFE_MUTEX */ assert_block_ahi_valid(block); block->modify_clock++; diff --git a/storage/innobase/include/buf0dblwr.h b/storage/innobase/include/buf0dblwr.h index fed64e0ee72..1b9415d38be 100644 --- a/storage/innobase/include/buf0dblwr.h +++ b/storage/innobase/include/buf0dblwr.h @@ -24,101 +24,38 @@ Doublewrite buffer module Created 2011/12/19 Inaam Rana *******************************************************/ -#ifndef buf0dblwr_h -#define buf0dblwr_h +#pragma once -#include "ut0byte.h" -#include "log0log.h" +#include "os0file.h" #include "buf0types.h" -#include "log0recv.h" - -/** Doublewrite system */ -extern buf_dblwr_t* buf_dblwr; - -/** Create the doublewrite buffer if the doublewrite buffer header -is not present in the TRX_SYS page. -@return whether the operation succeeded -@retval true if the doublewrite buffer exists or was created -@retval false if the creation failed (too small first data file) */ -MY_ATTRIBUTE((warn_unused_result)) -bool -buf_dblwr_create(); - -/** -At database startup initializes the doublewrite buffer memory structure if -we already have a doublewrite buffer created in the data files. If we are -upgrading to an InnoDB version which supports multiple tablespaces, then this -function performs the necessary update operations. If we are in a crash -recovery, this function loads the pages from double write buffer into memory. -@param[in] file File handle -@param[in] path Path name of file -@return DB_SUCCESS or error code */ -dberr_t -buf_dblwr_init_or_load_pages( - pfs_os_file_t file, - const char* path); - -/** Process and remove the double write buffer pages for all tablespaces. */ -void -buf_dblwr_process(); - -/****************************************************************//** -frees doublewrite buffer. */ -void -buf_dblwr_free(); - -/** Update the doublewrite buffer on write completion. */ -void buf_dblwr_update(const buf_page_t &bpage, bool single_page); -/****************************************************************//** -Determines if a page number is located inside the doublewrite buffer. -@return TRUE if the location is inside the two blocks of the -doublewrite buffer */ -ibool -buf_dblwr_page_inside( -/*==================*/ - ulint page_no); /*!< in: page number */ - -/********************************************************************//** -Flushes possible buffered writes from the doublewrite memory buffer to disk. -It is very important to call this function after a batch of writes -has been posted, and also when we may have to wait for a page latch! -Otherwise a deadlock of threads can occur. */ -void -buf_dblwr_flush_buffered_writes(); /** Doublewrite control struct */ -struct buf_dblwr_t{ - ib_mutex_t mutex; /*!< mutex protecting the first_free - field and write_buf */ - ulint block1; /*!< the page number of the first - doublewrite block (64 pages) */ - ulint block2; /*!< page number of the second block */ - ulint first_free;/*!< first free position in write_buf - measured in units of srv_page_size */ - ulint b_reserved;/*!< number of slots currently reserved - for batch flush. */ - os_event_t b_event;/*!< event where threads wait for a - batch flush to end; - os_event_set() and os_event_reset() - are protected by buf_dblwr_t::mutex */ - ulint s_reserved;/*!< number of slots currently - reserved for single page flushes. */ - os_event_t s_event;/*!< event where threads wait for a - single page flush slot. Protected by mutex. */ - bool batch_running;/*!< set to TRUE if currently a batch - is being written from the doublewrite - buffer. */ - byte* write_buf;/*!< write buffer used in writing to the - doublewrite buffer, aligned to an - address divisible by srv_page_size - (which is required by Windows aio) */ +class buf_dblwr_t +{ + /** the page number of the first doublewrite block (block_size() pages) */ + page_id_t block1= page_id_t(0, 0); + /** the page number of the second doublewrite block (block_size() pages) */ + page_id_t block2= page_id_t(0, 0); + + /** mutex protecting the data members below */ + mysql_mutex_t mutex; + /** condition variable for !batch_running */ + mysql_cond_t cond; + /** whether a batch is being written from the doublewrite buffer */ + bool batch_running; + /** first free position in write_buf measured in units of srv_page_size */ + ulint first_free; + /** number of slots reserved for the current write batch */ + ulint reserved; + /** the doublewrite buffer, aligned to srv_page_size */ + byte *write_buf; struct element { /** block descriptor */ buf_page_t *bpage; - /** flush type */ - IORequest::flush_t flush; + /** true=buf_pool.flush_list, false=buf_pool.LRU */ + bool lru; /** payload size in bytes */ size_t size; }; @@ -126,23 +63,67 @@ struct buf_dblwr_t{ /** buffer blocks to be written via write_buf */ element *buf_block_arr; + /** Initialize the doublewrite buffer data structure. + @param header doublewrite page header in the TRX_SYS page */ + inline void init(const byte *header); + + /** Flush possible buffered writes to persistent storage. */ + bool flush_buffered_writes(const ulint size); + +public: + /** Create or restore the doublewrite buffer in the TRX_SYS page. + @return whether the operation succeeded */ + bool create(); + /** Free the doublewrite buffer. */ + void close(); + + /** Initialize the doublewrite buffer memory structure on recovery. + If we are upgrading from a version before MySQL 4.1, then this + function performs the necessary update operations to support + innodb_file_per_table. If we are in a crash recovery, this function + loads the pages from double write buffer into memory. + @param file File handle + @param path Path name of file + @return DB_SUCCESS or error code */ + dberr_t init_or_load_pages(pfs_os_file_t file, const char *path); + + /** Process and remove the double write buffer pages for all tablespaces. */ + void recover(); + + /** Update the doublewrite buffer on write completion. */ + void write_completed(); + /** Flush possible buffered writes to persistent storage. + It is very important to call this function after a batch of writes has been + posted, and also when we may have to wait for a page latch! + Otherwise a deadlock of threads can occur. */ + void flush_buffered_writes(); + + /** Size of the doublewrite block in pages */ + uint32_t block_size() const { return FSP_EXTENT_SIZE; } + /** Schedule a page write. If the doublewrite memory buffer is full, - buf_dblwr_flush_buffered_writes() will be invoked to make space. - @param bpage buffer pool page to be written - @param flush type of flush - @param size payload size in bytes */ - void add_to_batch(buf_page_t *bpage, IORequest::flush_t flush, size_t size); - /** Write a page to the doublewrite buffer on disk, sync it, then write - the page to the datafile and sync the datafile. This function is used - for single page flushes. If all the buffers allocated for single page - flushes in the doublewrite buffer are in use we wait here for one to - become free. We are guaranteed that a slot will become free because any - thread that is using a slot must also release the slot before leaving - this function. - @param bpage buffer pool page to be written - @param sync whether synchronous operation is requested - @param size payload size in bytes */ - void write_single_page(buf_page_t *bpage, bool sync, size_t size); + flush_buffered_writes() will be invoked to make space. + @param bpage buffer pool page to be written + @param lru true=buf_pool.LRU; false=buf_pool.flush_list + @param size payload size in bytes */ + void add_to_batch(buf_page_t *bpage, bool lru, size_t size); + + /** Determine whether the doublewrite buffer is initialized */ + bool is_initialised() const + { return UNIV_LIKELY(block1 != page_id_t(0, 0)); } + + /** @return whether a page identifier is part of the doublewrite buffer */ + bool is_inside(const page_id_t id) const + { + if (!is_initialised()) + return false; + ut_ad(block1 < block2); + if (id < block1) + return false; + const uint32_t size= block_size(); + return id < block1 + size || (id >= block2 && id < block2 + size); + } }; -#endif +/** The doublewrite buffer */ +extern buf_dblwr_t buf_dblwr; diff --git a/storage/innobase/include/buf0flu.h b/storage/innobase/include/buf0flu.h index 17568d0e2b1..12ebf6f01e9 100644 --- a/storage/innobase/include/buf0flu.h +++ b/storage/innobase/include/buf0flu.h @@ -31,7 +31,10 @@ Created 11/5/1995 Heikki Tuuri #include "log0log.h" #include "buf0types.h" -/** Number of pages flushed through non flush_list flushes. */ +/** Number of pages flushed. Protected by buf_pool.mutex. */ +extern ulint buf_flush_page_count; +/** Number of pages flushed via LRU. Protected by buf_pool.mutex. +Also included in buf_flush_page_count. */ extern ulint buf_lru_flush_page_count; /** Flag indicating if the page_cleaner is in active state. */ @@ -44,27 +47,24 @@ extern my_bool innodb_page_cleaner_disabled_debug; #endif /* UNIV_DEBUG */ -/** Event to synchronise with the flushing. */ -extern os_event_t buf_flush_event; +/** Remove all dirty pages belonging to a given tablespace when we are +deleting the data file of that tablespace. +The pages still remain a part of LRU and are evicted from +the list as they age towards the tail of the LRU. +@param id tablespace identifier */ +void buf_flush_remove_pages(ulint id); -class ut_stage_alter_t; - -/** Handled page counters for a single flush */ -struct flush_counters_t { - ulint flushed; /*!< number of dirty pages flushed */ - ulint evicted; /*!< number of clean pages evicted */ - ulint unzip_LRU_evicted;/*!< number of uncompressed page images - evicted */ -}; - -/** Remove a block from the flush list of modified blocks. -@param[in] bpage block to be removed from the flush list */ -void buf_flush_remove(buf_page_t* bpage); +/** Try to flush all the dirty pages that belong to a given tablespace. +@param id tablespace identifier +@return number dirty pages that there were for this tablespace */ +ulint buf_flush_dirty_pages(ulint id) + MY_ATTRIBUTE((warn_unused_result)); /*******************************************************************//** Relocates a buffer control block on the flush_list. Note that it is assumed that the contents of bpage has already been copied to dpage. */ +ATTRIBUTE_COLD void buf_flush_relocate_on_flush_list( /*=============================*/ @@ -74,10 +74,9 @@ buf_flush_relocate_on_flush_list( /** Complete write of a file page from buf_pool. @param bpage written page @param request write request -@param dblwr whether the doublewrite buffer was used -@param evict whether or not to evict the page from LRU list */ +@param dblwr whether the doublewrite buffer was used */ void buf_page_write_complete(buf_page_t *bpage, const IORequest &request, - bool dblwr, bool evict); + bool dblwr); /** Assign the full crc32 checksum for non-compressed page. @param[in,out] page page to be updated */ @@ -95,46 +94,15 @@ buf_flush_init_for_writing( void* page_zip_, bool use_full_checksum); -/** Do flushing batch of a given type. -NOTE: The calling thread is not allowed to own any latches on pages! -@param[in] lru true=buf_pool.LRU; false=buf_pool.flush_list -@param[in] min_n wished minimum mumber of blocks flushed -(it is not guaranteed that the actual number is that big, though) -@param[in] lsn_limit in the case BUF_FLUSH_LIST all blocks whose -oldest_modification is smaller than this should be flushed (if their number -does not exceed min_n), otherwise ignored -@param[out] n the number of pages which were processed is -passed back to caller. Ignored if NULL -@retval true if a batch was queued successfully. -@retval false if another batch of same type was already running. */ -bool buf_flush_do_batch(bool lru, ulint min_n, lsn_t lsn_limit, - flush_counters_t *n); - -/** This utility flushes dirty blocks from the end of the flush list. -NOTE: The calling thread is not allowed to own any latches on pages! -@param[in] min_n wished minimum mumber of blocks flushed (it is -not guaranteed that the actual number is that big, though) -@param[in] lsn_limit in the case BUF_FLUSH_LIST all blocks whose -oldest_modification is smaller than this should be flushed (if their number -does not exceed min_n), otherwise ignored -@param[out] n_processed the number of pages which were processed is -passed back to caller. Ignored if NULL. -@retval true if a batch was queued successfully -@retval false if another batch of same type was already running */ -bool buf_flush_lists(ulint min_n, lsn_t lsn_limit, ulint *n_processed); - -/******************************************************************//** -This function picks up a single page from the tail of the LRU -list, flushes it (if it is dirty), removes it from page_hash and LRU -list and puts it on the free list. It is called from user threads when -they are unable to find a replaceable page at the tail of the LRU -list i.e.: when the background LRU flushing in the page_cleaner thread -is not fast enough to keep pace with the workload. -@return true if success. */ -bool buf_flush_single_page_from_LRU(); +/** Write out dirty blocks from buf_pool.flush_list. +@param max_n wished maximum mumber of blocks flushed +@param lsn buf_pool.get_oldest_modification(LSN_MAX) target (0=LRU flush) +@return the number of processed pages +@retval 0 if a batch of the same type (lsn==0 or lsn!=0) is already running */ +ulint buf_flush_lists(ulint max_n, lsn_t lsn); /** Wait until a flush batch ends. -@param[in] lru true=buf_pool.LRU; false=buf_pool.flush_list */ +@param lru true=buf_pool.LRU; false=buf_pool.flush_list */ void buf_flush_wait_batch_end(bool lru); /** Wait until a flush batch of the given lsn ends @param[in] new_oldest target oldest_modified_lsn to wait for */ @@ -156,33 +124,18 @@ buf_flush_note_modification( /** Initialize page_cleaner. */ void buf_flush_page_cleaner_init(); -/** Wait for any possible LRU flushes to complete. */ -void buf_flush_wait_LRU_batch_end(); +/** Wait for pending flushes to complete. */ +void buf_flush_wait_batch_end_acquiring_mutex(bool lru); #ifdef UNIV_DEBUG /** Validate the flush list. */ void buf_flush_validate(); #endif /* UNIV_DEBUG */ -/** Write a flushable page from buf_pool to a file. -buf_pool.mutex must be held. -@param bpage buffer control block -@param flush_type type of flush -@param space tablespace (or nullptr if not known) -@param sync whether this is a synchronous request - (only for flush_type=SINGLE_PAGE) -@return whether the page was flushed and buf_pool.mutex was released */ -bool buf_flush_page(buf_page_t *bpage, IORequest::flush_t flush_type, - fil_space_t *space, bool sync); - /** Synchronously flush dirty blocks. NOTE: The calling thread is not allowed to hold any buffer page latches! */ void buf_flush_sync(); -/** Request IO burst and wake page_cleaner up. -@param[in] lsn_limit upper limit of LSN to be flushed */ -void buf_flush_request_force(lsn_t lsn_limit); - #include "buf0flu.ic" #endif diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h index bdf56656692..540c14a49c9 100644 --- a/storage/innobase/include/buf0lru.h +++ b/storage/innobase/include/buf0lru.h @@ -34,6 +34,9 @@ Created 11/5/1995 Heikki Tuuri struct trx_t; struct fil_space_t; +/** Flush this many pages in buf_LRU_get_free_block() */ +extern size_t innodb_lru_flush_size; + /*####################################################################### These are low-level functions #########################################################################*/ @@ -41,12 +44,6 @@ These are low-level functions /** Minimum LRU list length for which the LRU_old pointer is defined */ #define BUF_LRU_OLD_MIN_LEN 512 /* 8 megabytes of 16k pages */ -/** Empty the flush list for all pages belonging to a tablespace. -@param[in] id tablespace identifier -@param[in] flush whether to write the pages to files -@param[in] first first page to be flushed or evicted */ -void buf_LRU_flush_or_remove_pages(ulint id, bool flush, ulint first = 0); - /** Try to free a block. If bpage is a descriptor of a compressed-only ROW_FORMAT=COMPRESSED page, the buf_page_t object will be freed as well. The caller must hold buf_pool.mutex. @@ -58,38 +55,34 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip) MY_ATTRIBUTE((nonnull)); /** Try to free a replaceable block. -@param[in] scan_all true=scan the whole LRU list, - false=use BUF_LRU_SEARCH_SCAN_THRESHOLD +@param limit maximum number of blocks to scan @return true if found and freed */ -bool buf_LRU_scan_and_free_block(bool scan_all); +bool buf_LRU_scan_and_free_block(ulint limit= ULINT_UNDEFINED); /** @return a buffer block from the buf_pool.free list @retval NULL if the free list is empty */ buf_block_t* buf_LRU_get_free_only(); -/** Get a free block from the buf_pool. The block is taken off the -free list. If free list is empty, blocks are moved from the end of the -LRU list to the free list. +/** Get a block from the buf_pool.free list. +If the list is empty, blocks will be moved from the end of buf_pool.LRU +to buf_pool.free. This function is called from a user thread when it needs a clean block to read in a page. Note that we only ever get a block from the free list. Even when we flush a page or find a page in LRU scan we put it to free list to be used. * iteration 0: - * get a block from free list, success:done + * get a block from the buf_pool.free list, success:done * if buf_pool.try_LRU_scan is set - * scan LRU up to srv_LRU_scan_depth to find a clean block - * the above will put the block on free list + * scan LRU up to 100 pages to free a clean block * success:retry the free list - * flush one dirty page from tail of LRU to disk - * the above will put the block on free list + * flush up to innodb_lru_flush_size LRU blocks to data files + (until UT_LIST_GET_GEN(buf_pool.free) < innodb_lru_scan_depth) + * on buf_page_write_complete() the blocks will put on buf_pool.free list * success: retry the free list -* iteration 1: - * same as iteration 0 except: - * scan whole LRU list - * scan LRU list even if buf_pool.try_LRU_scan is not set -* iteration > 1: - * same as iteration 1 but sleep 10ms +* subsequent iterations: same as iteration 0 except: + * scan whole LRU list + * scan LRU list even if buf_pool.try_LRU_scan is not set @param have_mutex whether buf_pool.mutex is already being held @return the free control block, in state BUF_BLOCK_MEMORY */ diff --git a/storage/innobase/include/buf0types.h b/storage/innobase/include/buf0types.h index 55bd2ac3a5a..b50352a1c0b 100644 --- a/storage/innobase/include/buf0types.h +++ b/storage/innobase/include/buf0types.h @@ -27,8 +27,7 @@ Created 11/17/1995 Heikki Tuuri #ifndef buf0types_h #define buf0types_h -#include "os0event.h" -#include "ut0ut.h" +#include "univ.i" /** Buffer page (uncompressed or compressed) */ class buf_page_t; @@ -38,8 +37,6 @@ struct buf_block_t; struct buf_pool_stat_t; /** Buffer pool buddy statistics struct */ struct buf_buddy_stat_t; -/** Doublewrite memory struct */ -struct buf_dblwr_t; /** A buffer frame. @see page_t */ typedef byte buf_frame_t; @@ -194,10 +191,6 @@ extern const byte field_ref_zero[UNIV_PAGE_SIZE_MAX]; #include "sync0rw.h" #include "rw_lock.h" -typedef ib_mutex_t BufPoolMutex; -typedef ib_mutex_t FlushListMutex; -typedef rw_lock_t BPageLock; - class page_hash_latch : public rw_lock { public: diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 1b89d38bef7..b6ff8b6b6bb 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -33,6 +33,7 @@ Created 10/25/1995 Heikki Tuuri #ifndef UNIV_INNOCHECKSUM +#include "buf0dblwr.h" #include "hash0hash.h" #include "log0recv.h" #include "dict0types.h" @@ -92,7 +93,6 @@ inline bool srv_is_undo_tablespace(ulint space_id) space_id < srv_undo_space_id_start + srv_undo_tablespaces_open; } -extern struct buf_dblwr_t* buf_dblwr; class page_id_t; /** Structure containing encryption specification */ @@ -415,12 +415,12 @@ public: ulint magic_n;/*!< FIL_SPACE_MAGIC_N */ - /** @return whether doublewrite buffering is needed */ - bool use_doublewrite() const - { - return !atomic_write_supported - && srv_use_doublewrite_buf && buf_dblwr; - } + /** @return whether doublewrite buffering is needed */ + bool use_doublewrite() const + { + return !atomic_write_supported && srv_use_doublewrite_buf && + buf_dblwr.is_initialised(); + } /** Append a file to the chain of files of a space. @param[in] name file name of a file that is not open diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h index e7cf100cbde..f822a874565 100644 --- a/storage/innobase/include/log0recv.h +++ b/storage/innobase/include/log0recv.h @@ -50,21 +50,12 @@ ATTRIBUTE_COLD void recv_recover_page(fil_space_t* space, buf_page_t* bpage) MY_ATTRIBUTE((nonnull)); /** Start recovering from a redo log checkpoint. -@see recv_recovery_from_checkpoint_finish @param[in] flush_lsn FIL_PAGE_FILE_FLUSH_LSN of first system tablespace page @return error code or DB_SUCCESS */ dberr_t recv_recovery_from_checkpoint_start( lsn_t flush_lsn); -/** Complete recovery from a checkpoint. */ -void -recv_recovery_from_checkpoint_finish(void); -/********************************************************//** -Initiates the rollback of active transactions. */ -void -recv_recovery_rollback_active(void); -/*===============================*/ /** Whether to store redo log records in recv_sys.pages */ enum store_t { @@ -296,9 +287,10 @@ private: @param page_id page identifier @param p iterator pointing to page_id @param mtr mini-transaction + @param b pre-allocated buffer pool block @return whether the page was successfully initialized */ inline buf_block_t *recover_low(const page_id_t page_id, map::iterator &p, - mtr_t &mtr); + mtr_t &mtr, buf_block_t *b); /** Attempt to initialize a page based on redo log records. @param page_id page identifier @return the recovered block diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index 08ea482333b..4be5e5341ba 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -182,32 +182,14 @@ static const ulint OS_FILE_OPERATION_NOT_SUPPORTED = 125; static const ulint OS_FILE_ERROR_MAX = 200; /* @} */ -/** Types for AIO operations @{ */ - -/** No transformations during read/write, write as is. */ -#define IORequestRead IORequest(IORequest::READ) -#define IORequestWrite IORequest(IORequest::WRITE) - /** The I/O context that is passed down to the low level IO code */ class IORequest { public: - /** Buffer pool flush types */ - enum flush_t - { - /** via buf_pool.LRU */ - LRU= 0, - /** via buf_pool.flush_list */ - FLUSH_LIST, - /** single page of buf_poof.LRU */ - SINGLE_PAGE - }; - - IORequest(ulint type= READ, buf_page_t *bpage= nullptr, - flush_t flush_type= LRU) : - m_bpage(bpage), m_type(static_cast(type)), - m_flush_type(flush_type) {} + constexpr IORequest(ulint type= READ, buf_page_t *bpage= nullptr, + bool lru= false) : + m_bpage(bpage), m_type(static_cast(type)), m_LRU(lru) {} /** Flags passed in the request, they can be ORred together. */ enum { @@ -243,12 +225,6 @@ public: return((m_type & WRITE) == WRITE); } - /** Clear the punch hole flag */ - void clear_punch_hole() - { - m_type &= uint16_t(~PUNCH_HOLE); - } - /** @return true if partial read warning disabled */ bool is_partial_io_warning_disabled() const MY_ATTRIBUTE((warn_unused_result)) @@ -256,12 +232,6 @@ public: return !!(m_type & DISABLE_PARTIAL_IO_WARNINGS); } - /** Disable partial read warnings */ - void disable_partial_io_warnings() - { - m_type |= DISABLE_PARTIAL_IO_WARNINGS; - } - /** @return true if punch hole should be used */ bool punch_hole() const MY_ATTRIBUTE((warn_unused_result)) @@ -276,29 +246,15 @@ public: return(is_read() ^ is_write()); } - /** Set the punch hole flag */ - void set_punch_hole() - { - if (is_punch_hole_supported()) { - m_type |= PUNCH_HOLE; - } - } - /** Set the pointer to file node for IO @param[in] node File node */ - inline void set_fil_node(fil_node_t* node); + void set_fil_node(fil_node_t *node) { m_fil_node= node; } bool operator==(const IORequest& rhs) const { return(m_type == rhs.m_type); } - /** Note that the IO is for double write recovery. */ - void dblwr_recover() - { - m_type |= DBLWR_RECOVER; - } - /** @return true if the request is from the dblwr recovery */ bool is_dblwr_recover() const MY_ATTRIBUTE((warn_unused_result)) @@ -306,24 +262,6 @@ public: return((m_type & DBLWR_RECOVER) == DBLWR_RECOVER); } - /** @return true if punch hole is supported */ - static bool is_punch_hole_supported() - { - - /* In this debugging mode, we act as if punch hole is supported, - and then skip any calls to actually punch a hole here. - In this way, Transparent Page Compression is still being tested. */ - DBUG_EXECUTE_IF("ignore_punch_hole", - return(true); - ); - -#if defined(HAVE_FALLOC_PUNCH_HOLE_AND_KEEP_SIZE) || defined(_WIN32) - return(true); -#else - return(false); -#endif /* HAVE_FALLOC_PUNCH_HOLE_AND_KEEP_SIZE || _WIN32 */ - } - ulint get_trim_length(ulint write_length) const { return (m_bpage ? @@ -340,8 +278,8 @@ public: @return DB_SUCCESS or error code */ dberr_t punch_hole(os_file_t fh, os_offset_t off, ulint len); - /** @return the flush type */ - flush_t flush_type() const { return m_flush_type; } + /** @return type of page flush (for writes) */ + bool is_LRU() const { return m_LRU; } private: /** Page to be written on write operation. */ @@ -350,14 +288,16 @@ private: /** File node */ fil_node_t* m_fil_node= nullptr; - /** Request type bit flags */ - uint16_t m_type= READ; + /** Request type bit flags */ + const uint16_t m_type; /** for writes, type of page flush */ - flush_t m_flush_type= LRU; + const bool m_LRU= false; }; -/* @} */ +constexpr IORequest IORequestRead(IORequest::READ); +constexpr IORequest IORequestWrite(IORequest::WRITE); + /** Sparse file size information. */ struct os_file_size_t { diff --git a/storage/innobase/include/srv0mon.h b/storage/innobase/include/srv0mon.h index 325bb3a2cee..a18ff5d49ad 100644 --- a/storage/innobase/include/srv0mon.h +++ b/storage/innobase/include/srv0mon.h @@ -196,16 +196,11 @@ enum monitor_id_t { MONITOR_FLUSH_N_TO_FLUSH_BY_AGE, MONITOR_FLUSH_ADAPTIVE_AVG_TIME_SLOT, - MONITOR_LRU_BATCH_FLUSH_AVG_TIME_SLOT, - MONITOR_FLUSH_ADAPTIVE_AVG_TIME_THREAD, - MONITOR_LRU_BATCH_FLUSH_AVG_TIME_THREAD, MONITOR_FLUSH_ADAPTIVE_AVG_TIME_EST, - MONITOR_LRU_BATCH_FLUSH_AVG_TIME_EST, MONITOR_FLUSH_AVG_TIME, MONITOR_FLUSH_ADAPTIVE_AVG_PASS, - MONITOR_LRU_BATCH_FLUSH_AVG_PASS, MONITOR_FLUSH_AVG_PASS, MONITOR_LRU_GET_FREE_LOOPS, @@ -234,9 +229,6 @@ enum monitor_id_t { MONITOR_LRU_BATCH_EVICT_TOTAL_PAGE, MONITOR_LRU_BATCH_EVICT_COUNT, MONITOR_LRU_BATCH_EVICT_PAGES, - MONITOR_LRU_SINGLE_FLUSH_SCANNED, - MONITOR_LRU_SINGLE_FLUSH_SCANNED_NUM_CALL, - MONITOR_LRU_SINGLE_FLUSH_SCANNED_PER_CALL, MONITOR_LRU_SINGLE_FLUSH_FAILURE_COUNT, MONITOR_LRU_GET_FREE_SEARCH, MONITOR_LRU_SEARCH_SCANNED, diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index ade0f1c198e..e956e421a6a 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -100,10 +100,6 @@ struct srv_stats_t need to make a flush, in order to be able to read or create a page. */ ulint_ctr_1_t buf_pool_wait_free; - /** Count the number of pages that were written from buffer - pool to the disk */ - ulint_ctr_1_t buf_pool_flushed; - /** Number of buffer pool reads that led to the reading of a disk page */ ulint_ctr_1_t buf_pool_reads; @@ -409,7 +405,6 @@ extern unsigned long long srv_stats_modified_counter; extern my_bool srv_stats_sample_traditional; extern my_bool srv_use_doublewrite_buf; -extern ulong srv_doublewrite_batch_size; extern ulong srv_checksum_algorithm; extern double srv_max_buf_pool_modified_pct; @@ -764,7 +759,6 @@ struct export_var_t{ ulint innodb_buffer_pool_read_requests; /*!< buf_pool.stat.n_page_gets */ ulint innodb_buffer_pool_reads; /*!< srv_buf_pool_reads */ ulint innodb_buffer_pool_wait_free; /*!< srv_buf_pool_wait_free */ - ulint innodb_buffer_pool_pages_flushed; /*!< srv_buf_pool_flushed */ ulint innodb_buffer_pool_write_requests;/*!< srv_buf_pool_write_requests */ ulint innodb_buffer_pool_read_ahead_rnd;/*!< srv_read_ahead_rnd */ ulint innodb_buffer_pool_read_ahead; /*!< srv_read_ahead */ diff --git a/storage/innobase/include/srv0start.h b/storage/innobase/include/srv0start.h index 23dc8347129..324e3f0478d 100644 --- a/storage/innobase/include/srv0start.h +++ b/storage/innobase/include/srv0start.h @@ -112,11 +112,6 @@ enum srv_shutdown_t { SRV_SHUTDOWN_INITIATED, SRV_SHUTDOWN_CLEANUP, /*!< Cleaning up in logs_empty_and_mark_files_at_shutdown() */ - SRV_SHUTDOWN_FLUSH_PHASE,/*!< At this phase the master and the - purge threads must have completed their - work. Once we enter this phase the - page_cleaner can clean up the buffer - pool and exit */ SRV_SHUTDOWN_LAST_PHASE,/*!< Last phase after ensuring that the buffer pool can be freed: flush all file spaces and close all files */ diff --git a/storage/innobase/include/sync0debug.h b/storage/innobase/include/sync0debug.h index 55ea99cd47b..07e985465e0 100644 --- a/storage/innobase/include/sync0debug.h +++ b/storage/innobase/include/sync0debug.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -44,10 +44,6 @@ void sync_check_close(); #ifdef UNIV_DEBUG -/** Enable sync order checking. */ -void -sync_check_enable(); - /** Check if it is OK to acquire the latch. @param[in] latch latch type */ void diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index 1b8b60e9f81..72f2d8ffb74 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -63,7 +63,6 @@ extern mysql_pfs_key_t log_sys_mutex_key; extern mysql_pfs_key_t log_cmdq_mutex_key; extern mysql_pfs_key_t log_flush_order_mutex_key; extern mysql_pfs_key_t recalc_pool_mutex_key; -extern mysql_pfs_key_t page_cleaner_mutex_key; extern mysql_pfs_key_t purge_sys_pq_mutex_key; extern mysql_pfs_key_t recv_sys_mutex_key; extern mysql_pfs_key_t rtr_active_mutex_key; diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h index 36c1ad4495a..a6d0bd8a86c 100644 --- a/storage/innobase/include/sync0types.h +++ b/storage/innobase/include/sync0types.h @@ -188,12 +188,6 @@ enum latch_level_t { SYNC_ANY_LATCH, - SYNC_DOUBLEWRITE, - - SYNC_BUF_FLUSH_LIST, - - SYNC_BUF_POOL, - SYNC_POOL, SYNC_POOL_MANAGER, @@ -208,7 +202,6 @@ enum latch_level_t { SYNC_RECV, SYNC_LOG_FLUSH_ORDER, SYNC_LOG, - SYNC_PAGE_CLEANER, SYNC_PURGE_QUEUE, SYNC_TRX_SYS_HEADER, SYNC_REC_LOCK, @@ -271,11 +264,9 @@ enum latch_level_t { up its meta-data. See sync0debug.cc. */ enum latch_id_t { LATCH_ID_NONE = 0, - LATCH_ID_BUF_POOL, LATCH_ID_DICT_FOREIGN_ERR, LATCH_ID_DICT_SYS, LATCH_ID_FIL_SYSTEM, - LATCH_ID_FLUSH_LIST, LATCH_ID_FTS_BG_THREADS, LATCH_ID_FTS_DELETE, LATCH_ID_FTS_DOC_ID, @@ -285,7 +276,6 @@ enum latch_id_t { LATCH_ID_IBUF_PESSIMISTIC_INSERT, LATCH_ID_LOG_SYS, LATCH_ID_LOG_FLUSH_ORDER, - LATCH_ID_PAGE_CLEANER, LATCH_ID_PURGE_SYS_PQ, LATCH_ID_RECALC_POOL, LATCH_ID_RECV_SYS, @@ -299,7 +289,6 @@ enum latch_id_t { LATCH_ID_SRV_INNODB_MONITOR, LATCH_ID_SRV_MISC_TMPFILE, LATCH_ID_SRV_MONITOR_FILE, - LATCH_ID_BUF_DBLWR, LATCH_ID_TRX_POOL, LATCH_ID_TRX_POOL_MANAGER, LATCH_ID_TRX, @@ -982,6 +971,7 @@ struct sync_checker : public sync_check_functor_t { if (some_allowed) { switch (level) { + case SYNC_FSP: case SYNC_DICT: case SYNC_DICT_OPERATION: case SYNC_FTS_CACHE: diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index acb10428108..0bc8b95dd77 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2017, 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 @@ -340,9 +340,6 @@ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID. */ constexpr uint32_t TRX_SYS_DOUBLEWRITE_MAGIC_N= 536853855; /** Contents of TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED */ constexpr uint32_t TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N= 1783657386; - -/** Size of the doublewrite block in pages */ -#define TRX_SYS_DOUBLEWRITE_BLOCK_SIZE FSP_EXTENT_SIZE /* @} */ trx_t* current_trx(); diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 090acc86843..7563f30e8fb 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -493,7 +493,7 @@ void log_t::create() log record has a non-zero start lsn, a fact which we will use */ set_lsn(LOG_START_LSN + LOG_BLOCK_HDR_SIZE); - set_flushed_lsn(0); + set_flushed_lsn(LOG_START_LSN + LOG_BLOCK_HDR_SIZE); ut_ad(srv_log_buffer_size >= 16 * OS_FILE_LOG_BLOCK_SIZE); ut_ad(srv_log_buffer_size >= 4U << srv_page_size_shift); @@ -936,7 +936,8 @@ loop: and invoke log_mutex_enter(). */ static void log_write_flush_to_disk_low(lsn_t lsn) { - log_sys.log.flush(); + if (!log_sys.log.writes_are_durable()) + log_sys.log.flush(); ut_a(lsn >= log_sys.get_flushed_lsn()); log_sys.set_flushed_lsn(lsn); } @@ -1129,12 +1130,7 @@ void log_write_up_to(lsn_t lsn, bool flush_to_disk, bool rotate_key) /* Flush the highest written lsn.*/ auto flush_lsn = write_lock.value(); flush_lock.set_pending(flush_lsn); - - if (!log_sys.log.writes_are_durable()) - { - log_write_flush_to_disk_low(flush_lsn); - } - + log_write_flush_to_disk_low(flush_lsn); flush_lock.release(flush_lsn); innobase_mysql_log_notify(flush_lsn); @@ -1186,7 +1182,7 @@ this lsn which means that we could not start this flush batch */ static bool log_preflush_pool_modified_pages(lsn_t new_oldest) { - bool success; + bool success; if (recv_recovery_is_on()) { /* If the recovery is running, we must first apply all @@ -1204,29 +1200,22 @@ static bool log_preflush_pool_modified_pages(lsn_t new_oldest) || !buf_page_cleaner_is_active || srv_is_being_started) { - ulint n_pages; + ulint n_pages = buf_flush_lists(ULINT_UNDEFINED, new_oldest); - success = buf_flush_lists(ULINT_MAX, new_oldest, &n_pages); + buf_flush_wait_batch_end_acquiring_mutex(false); - buf_flush_wait_batch_end(false); - - if (!success) { - MONITOR_INC(MONITOR_FLUSH_SYNC_WAITS); - } + MONITOR_INC(MONITOR_FLUSH_SYNC_WAITS); MONITOR_INC_VALUE_CUMULATIVE( MONITOR_FLUSH_SYNC_TOTAL_PAGE, MONITOR_FLUSH_SYNC_COUNT, MONITOR_FLUSH_SYNC_PAGES, n_pages); + + const lsn_t oldest = buf_pool.get_oldest_modification(); + success = !oldest || oldest >= new_oldest; } else { /* better to wait for flushed by page cleaner */ - - if (srv_flush_sync) { - /* wake page cleaner for IO burst */ - buf_flush_request_force(new_oldest); - } - buf_flush_wait_flushed(new_oldest); success = true; @@ -1515,6 +1504,41 @@ void log_check_margins() extern void buf_resize_shutdown(); +/** @return the number of dirty pages in the buffer pool */ +static ulint flush_list_length() +{ + mysql_mutex_lock(&buf_pool.flush_list_mutex); + const ulint len= UT_LIST_GET_LEN(buf_pool.flush_list); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + return len; +} + +static void flush_buffer_pool() +{ + service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, + "Waiting to flush the buffer pool"); + while (buf_pool.n_flush_list || flush_list_length()) + { + buf_flush_lists(ULINT_UNDEFINED, LSN_MAX); + timespec abstime; + + if (buf_pool.n_flush_list) + { + service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, + "Waiting to flush " ULINTPF " pages", + flush_list_length()); + set_timespec(abstime, INNODB_EXTEND_TIMEOUT_INTERVAL / 2); + mysql_mutex_lock(&buf_pool.mutex); + while (buf_pool.n_flush_list) + mysql_cond_timedwait(&buf_pool.done_flush_list, &buf_pool.mutex, + &abstime); + mysql_mutex_unlock(&buf_pool.mutex); + } + } + + ut_ad(!buf_pool.any_io_pending()); +} + /** Make a checkpoint at the latest lsn on shutdown. */ void logs_empty_and_mark_files_at_shutdown() { @@ -1616,30 +1640,26 @@ wait_suspend_loop: goto wait_suspend_loop; } + if (buf_page_cleaner_is_active) { + thread_name = "page cleaner thread"; + mysql_cond_signal(&buf_pool.do_flush_list); + goto wait_suspend_loop; + } + buf_load_dump_end(); - srv_shutdown_state = SRV_SHUTDOWN_FLUSH_PHASE; - - /* At this point only page_cleaner should be active. We wait - here to let it complete the flushing of the buffer pools - before proceeding further. */ - - count = 0; - service_manager_extend_timeout(COUNT_INTERVAL * CHECK_INTERVAL/1000000 * 2, - "Waiting for page cleaner"); - while (buf_page_cleaner_is_active) { - ++count; - os_thread_sleep(CHECK_INTERVAL); - if (srv_print_verbose_log && count > COUNT_INTERVAL) { - service_manager_extend_timeout(COUNT_INTERVAL * CHECK_INTERVAL/1000000 * 2, - "Waiting for page cleaner"); - ib::info() << "Waiting for page_cleaner to " - "finish flushing of buffer pool"; - /* This is a workaround to avoid the InnoDB hang - when OS datetime changed backwards */ - os_event_set(buf_flush_event); + if (!buf_pool.is_initialised()) { + ut_ad(!srv_was_started); + } else if (ulint pending_io = buf_pool.io_pending()) { + if (srv_print_verbose_log && count > 600) { + ib::info() << "Waiting for " << pending_io << " buffer" + " page I/Os to complete"; count = 0; } + + goto loop; + } else { + flush_buffer_pool(); } if (log_sys.is_initialised()) { @@ -1660,18 +1680,6 @@ wait_suspend_loop: } } - if (!buf_pool.is_initialised()) { - ut_ad(!srv_was_started); - } else if (ulint pending_io = buf_pool.io_pending()) { - if (srv_print_verbose_log && count > 600) { - ib::info() << "Waiting for " << pending_io << " buffer" - " page I/Os to complete"; - count = 0; - } - - goto loop; - } - if (srv_fast_shutdown == 2 || !srv_was_started) { if (!srv_read_only_mode && srv_was_started) { ib::info() << "MySQL has requested a very fast" diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index aff1d011a8d..11c57618e53 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -987,9 +987,9 @@ void recv_sys_t::debug_free() { ut_ad(this == &recv_sys); ut_ad(is_initialised()); - ut_ad(!recv_recovery_is_on()); mutex_enter(&mutex); + recovery_on= false; pages.clear(); ut_free_dodump(buf, RECV_PARSING_BUF_SIZE); @@ -2497,9 +2497,11 @@ static void recv_read_in_area(page_id_t page_id) @param page_id page identifier @param p iterator pointing to page_id @param mtr mini-transaction +@param b pre-allocated buffer pool block @return whether the page was successfully initialized */ inline buf_block_t *recv_sys_t::recover_low(const page_id_t page_id, - map::iterator &p, mtr_t &mtr) + map::iterator &p, mtr_t &mtr, + buf_block_t *b) { ut_ad(mutex_own(&mutex)); ut_ad(p->first == page_id); @@ -2515,20 +2517,21 @@ inline buf_block_t *recv_sys_t::recover_low(const page_id_t page_id, { mtr.start(); mtr.set_log_mode(MTR_LOG_NO_REDO); - block= buf_page_create(space, page_id.page_no(), space->zip_size(), &mtr); - p= recv_sys.pages.find(page_id); - if (p == recv_sys.pages.end()) + block= buf_page_create(space, page_id.page_no(), space->zip_size(), &mtr, + b); + if (UNIV_UNLIKELY(block != b)) { /* The page happened to exist in the buffer pool, or it was just being read in. Before buf_page_get_with_no_latch() returned to buf_page_create(), all changes must have been applied to the page already. */ + ut_ad(recv_sys.pages.find(page_id) == recv_sys.pages.end()); mtr.commit(); block= nullptr; } else { - ut_ad(&recs == &p->second); + ut_ad(&recs == &recv_sys.pages.find(page_id)->second); i.created= true; buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK); recv_recover_page(block, mtr, p, space, &i); @@ -2548,6 +2551,7 @@ inline buf_block_t *recv_sys_t::recover_low(const page_id_t page_id, @return whether the page was successfully initialized */ buf_block_t *recv_sys_t::recover_low(const page_id_t page_id) { + buf_block_t *free_block= buf_LRU_get_free_block(false); buf_block_t *block= nullptr; mutex_enter(&mutex); @@ -2556,10 +2560,13 @@ buf_block_t *recv_sys_t::recover_low(const page_id_t page_id) if (p != pages.end() && p->second.state == page_recv_t::RECV_WILL_NOT_READ) { mtr_t mtr; - block= recover_low(page_id, p, mtr); + block= recover_low(page_id, p, mtr, free_block); + ut_ad(!block || block == free_block); } mutex_exit(&mutex); + if (UNIV_UNLIKELY(!block)) + buf_pool.free_block(free_block); return block; } @@ -2614,6 +2621,8 @@ void recv_sys_t::apply(bool last_batch) trim(page_id_t(id + srv_undo_space_id_start, t.pages), t.lsn); } + buf_block_t *free_block= buf_LRU_get_free_block(false); + for (map::iterator p= pages.begin(); p != pages.end(); ) { const page_id_t page_id= p->first; @@ -2626,7 +2635,14 @@ void recv_sys_t::apply(bool last_batch) p++; continue; case page_recv_t::RECV_WILL_NOT_READ: - recover_low(page_id, p, mtr); + if (UNIV_LIKELY(!!recover_low(page_id, p, mtr, free_block))) + { + mutex_exit(&mutex); + free_block= buf_LRU_get_free_block(false); + mutex_enter(&mutex); +next_page: + p= pages.lower_bound(page_id); + } continue; case page_recv_t::RECV_NOT_PROCESSED: mtr.start(); @@ -2652,9 +2668,11 @@ void recv_sys_t::apply(bool last_batch) continue; } - p= pages.lower_bound(page_id); + goto next_page; } + buf_pool.free_block(free_block); + /* Wait until all the pages have been processed */ while (!pages.empty()) { @@ -2686,7 +2704,6 @@ void recv_sys_t::apply(bool last_batch) /* Instead of flushing, last_batch could sort the buf_pool.flush_list in ascending order of buf_page_t::oldest_modification. */ - buf_flush_wait_LRU_batch_end(); buf_flush_sync(); if (!last_batch) @@ -3250,7 +3267,6 @@ recv_init_crash_recovery_spaces(bool rescan, bool& missing_tablespace) } /** Start recovering from a redo log checkpoint. -@see recv_recovery_from_checkpoint_finish @param[in] flush_lsn FIL_PAGE_FILE_FLUSH_LSN of first system tablespace page @return error code or DB_SUCCESS */ @@ -3268,10 +3284,10 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) ut_ad(srv_operation == SRV_OPERATION_NORMAL || srv_operation == SRV_OPERATION_RESTORE || srv_operation == SRV_OPERATION_RESTORE_EXPORT); - ut_d(mutex_enter(&buf_pool.flush_list_mutex)); + ut_d(mysql_mutex_lock(&buf_pool.flush_list_mutex)); ut_ad(UT_LIST_GET_LEN(buf_pool.LRU) == 0); ut_ad(UT_LIST_GET_LEN(buf_pool.unzip_LRU) == 0); - ut_d(mutex_exit(&buf_pool.flush_list_mutex)); + ut_d(mysql_mutex_unlock(&buf_pool.flush_list_mutex)); if (srv_force_recovery >= SRV_FORCE_NO_LOG_REDO) { @@ -3424,6 +3440,11 @@ completed: } log_sys.set_lsn(recv_sys.recovered_lsn); + if (UNIV_LIKELY(log_sys.get_flushed_lsn() < recv_sys.recovered_lsn)) { + /* This may already have been set by create_log_file() + if no logs existed when the server started up. */ + log_sys.set_flushed_lsn(recv_sys.recovered_lsn); + } if (recv_needed_recovery) { bool missing_tablespace = false; @@ -3472,7 +3493,7 @@ completed: recv_sys.parse_start_lsn = checkpoint_lsn; if (srv_operation == SRV_OPERATION_NORMAL) { - buf_dblwr_process(); + buf_dblwr.recover(); } ut_ad(srv_force_recovery <= SRV_FORCE_NO_UNDO_LOG_SCAN); @@ -3556,19 +3577,6 @@ completed: return(DB_SUCCESS); } -/** Complete recovery from a checkpoint. */ -void recv_recovery_from_checkpoint_finish() -{ - /* Free the resources of the recovery system */ - - recv_sys.recovery_on= false; - - recv_sys.debug_free(); - - /* Enable innodb_sync_debug checks */ - ut_d(sync_check_enable()); -} - bool recv_dblwr_t::validate_page(const page_id_t page_id, const byte *page, const fil_space_t *space, @@ -3651,7 +3659,7 @@ byte *recv_dblwr_t::find_page(const page_id_t page_id, if (lsn <= max_lsn || !validate_page(page_id, page, space, tmp_buf)) { - /* Mark processed for subsequent iterations in buf_dblwr_process() */ + /* Mark processed for subsequent iterations in buf_dblwr_t::recover() */ memset(page + FIL_PAGE_LSN, 0, 8); continue; } diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 0a7e0ed5dc8..e0817934e67 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -153,9 +153,6 @@ static ulint os_innodb_umask = 0; #endif /* _WIN32 */ -/** Flag indicating if the page_cleaner is in active state. */ -extern bool buf_page_cleaner_is_active; - #ifdef WITH_INNODB_DISALLOW_WRITES #define WAIT_ALLOW_WRITES() os_event_wait(srv_allow_writes_event) #else @@ -3829,9 +3826,7 @@ IORequest::punch_hole(os_file_t fh, os_offset_t off, ulint len) /* If punch hole is not supported, set space so that it is not used. */ if (err == DB_IO_NO_PUNCH_HOLE) { - if (m_fil_node) { - m_fil_node->space->punch_hole = false; - } + m_fil_node->space->punch_hole = false; err = DB_SUCCESS; } } diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 2ec0a06709e..539c2e83f04 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -3423,11 +3423,10 @@ fil_iterate( ? iter.crypt_io_buffer : io_buffer; byte* const writeptr = readptr; - IORequest read_request(IORequest::READ); - read_request.disable_partial_io_warnings(); - err = os_file_read_no_error_handling( - read_request, iter.file, readptr, offset, n_bytes, 0); + IORequest(IORequest::READ + | IORequest::DISABLE_PARTIAL_IO_WARNINGS), + iter.file, readptr, offset, n_bytes, 0); if (err != DB_SUCCESS) { ib::error() << iter.filepath << ": os_file_read() failed"; @@ -3760,11 +3759,10 @@ fil_tablespace_iterate( /* Read the first page and determine the page and zip size. */ - IORequest request(IORequest::READ); - request.disable_partial_io_warnings(); - - err = os_file_read_no_error_handling(request, file, page, 0, - srv_page_size, 0); + err = os_file_read_no_error_handling( + IORequest(IORequest::READ + | IORequest::DISABLE_PARTIAL_IO_WARNINGS), + file, page, 0, srv_page_size, 0); if (err == DB_SUCCESS) { err = callback.init(file_size, block); @@ -4175,7 +4173,7 @@ row_import_for_mysql( /* Ensure that all pages dirtied during the IMPORT make it to disk. The only dirty pages generated should be from the pessimistic purge of delete marked records that couldn't be purged in Phase I. */ - buf_LRU_flush_or_remove_pages(prebuilt->table->space_id, true); + while (buf_flush_dirty_pages(prebuilt->table->space_id)); ib::info() << "Phase IV - Flush complete"; prebuilt->table->space->set_imported(); diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index 4db1b7cfa7f..02429aac23b 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -410,7 +410,6 @@ row_log_online_op( const os_offset_t byte_offset = (os_offset_t) log->tail.blocks * srv_sort_buf_size; - IORequest request(IORequest::WRITE); byte* buf = log->tail.block; if (byte_offset + srv_sort_buf_size >= srv_online_max_size) { @@ -448,7 +447,7 @@ row_log_online_op( log->tail.blocks++; if (os_file_write( - request, + IORequestWrite, "(modification log)", log->fd, buf, byte_offset, srv_sort_buf_size) @@ -549,7 +548,6 @@ row_log_table_close_func( const os_offset_t byte_offset = (os_offset_t) log->tail.blocks * srv_sort_buf_size; - IORequest request(IORequest::WRITE); byte* buf = log->tail.block; if (byte_offset + srv_sort_buf_size >= srv_online_max_size) { @@ -587,7 +585,7 @@ row_log_table_close_func( log->tail.blocks++; if (os_file_write( - request, + IORequestWrite, "(modification log)", log->fd, buf, byte_offset, srv_sort_buf_size) @@ -2874,11 +2872,10 @@ all_done: goto func_exit; } - IORequest request(IORequest::READ); byte* buf = index->online_log->head.block; if (os_file_read_no_error_handling( - request, index->online_log->fd, + IORequestRead, index->online_log->fd, buf, ofs, srv_sort_buf_size, 0) != DB_SUCCESS) { ib::error() << "Unable to read temporary file" @@ -3767,8 +3764,6 @@ all_done: os_offset_t ofs = static_cast( index->online_log->head.blocks) * srv_sort_buf_size; - IORequest request(IORequest::READ); - ut_ad(has_index_lock); has_index_lock = false; rw_lock_x_unlock(dict_index_get_lock(index)); @@ -3783,7 +3778,7 @@ all_done: byte* buf = index->online_log->head.block; if (os_file_read_no_error_handling( - request, index->online_log->fd, + IORequestRead, index->online_log->fd, buf, ofs, srv_sort_buf_size, 0) != DB_SUCCESS) { ib::error() << "Unable to read temporary file" diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 37814b70188..a57a53aaaea 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -1080,9 +1080,8 @@ row_merge_read( DBUG_LOG("ib_merge_sort", "fd=" << fd << " ofs=" << ofs); DBUG_EXECUTE_IF("row_merge_read_failure", DBUG_RETURN(FALSE);); - IORequest request(IORequest::READ); const bool success = DB_SUCCESS == os_file_read_no_error_handling( - request, fd, buf, ofs, srv_sort_buf_size, 0); + IORequestRead, fd, buf, ofs, srv_sort_buf_size, 0); /* If encryption is enabled decrypt buffer */ if (success && log_tmp_is_encrypted()) { @@ -1144,9 +1143,8 @@ row_merge_write( out_buf = crypt_buf; } - IORequest request(IORequest::WRITE); const bool success = DB_SUCCESS == os_file_write( - request, "(merge)", fd, out_buf, ofs, buf_len); + IORequestWrite, "(merge)", fd, out_buf, ofs, buf_len); #ifdef POSIX_FADV_DONTNEED /* The block will be needed on the next merge pass, diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 00c2c41c1d0..c9ccb35ea05 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -3391,8 +3391,7 @@ row_drop_table_for_mysql( dict_stats_recalc_pool_del(table); dict_stats_defrag_pool_del(table, NULL); if (btr_defragment_active) { - /* During fts_drop_orphaned_tables() in - recv_recovery_rollback_active() the + /* During fts_drop_orphaned_tables() the btr_defragment_mutex has not yet been initialized by btr_defragment_init(). */ btr_defragment_remove_table(table); diff --git a/storage/innobase/row/row0quiesce.cc b/storage/innobase/row/row0quiesce.cc index ff50e4f1510..0cddde4b3ca 100644 --- a/storage/innobase/row/row0quiesce.cc +++ b/storage/innobase/row/row0quiesce.cc @@ -525,17 +525,27 @@ row_quiesce_table_start( } for (ulint count = 0; - ibuf_merge_space(table->space_id) != 0 - && !trx_is_interrupted(trx); + ibuf_merge_space(table->space_id); ++count) { + if (trx_is_interrupted(trx)) { + goto aborted; + } if (!(count % 20)) { ib::info() << "Merging change buffer entries for " << table->name; } } + while (buf_flush_dirty_pages(table->space_id)) { + if (trx_is_interrupted(trx)) { + goto aborted; + } + } + if (!trx_is_interrupted(trx)) { - buf_LRU_flush_or_remove_pages(table->space_id, true); + /* Ensure that all asynchronous IO is completed. */ + os_aio_wait_until_no_pending_writes(); + fil_flush(table->space_id); if (row_quiesce_write_cfg(table, trx->mysql_thd) != DB_SUCCESS) { @@ -546,6 +556,7 @@ row_quiesce_table_start( << " flushed to disk"; } } else { +aborted: ib::warn() << "Quiesce aborted!"; } diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 239544c453e..9af0738faad 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -121,7 +121,7 @@ row_sel_sec_rec_is_for_blob( field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE)) { /* The externally stored field was not written yet. This record should only be seen by - recv_recovery_rollback_active() or any + trx_rollback_recovered() or any TRX_ISO_READ_UNCOMMITTED transactions. */ return(FALSE); } @@ -528,7 +528,7 @@ row_sel_fetch_columns( externally stored field was not written yet. This record should only be seen by - recv_recovery_rollback_active() or any + trx_rollback_recovered() or any TRX_ISO_READ_UNCOMMITTED transactions. The InnoDB SQL parser (the sole caller of this function) @@ -2891,7 +2891,7 @@ row_sel_store_mysql_field( if (UNIV_UNLIKELY(!data)) { /* The externally stored field was not written yet. This record should only be seen by - recv_recovery_rollback_active() or any + trx_rollback_recovered() or any TRX_ISO_READ_UNCOMMITTED transactions. */ if (heap != prebuilt->blob_heap) { diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc index 2fe1135b894..82c999d8b53 100644 --- a/storage/innobase/row/row0undo.cc +++ b/storage/innobase/row/row0undo.cc @@ -466,13 +466,7 @@ row_undo_step( { dberr_t err; undo_node_t* node; - trx_t* trx; - - ut_ad(thr); - - srv_inc_activity_count(); - - trx = thr_get_trx(thr); + trx_t* trx = thr_get_trx(thr); node = static_cast(thr->run_node); diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index fa3fad5fe26..aee20477ac0 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -1539,7 +1539,7 @@ row_upd_changes_ord_field_binary_func( /* The externally stored field was not written yet. This record should only be seen by - recv_recovery_rollback_active(), + trx_rollback_recovered() when the server had crashed before storing the field. */ ut_ad(thr->graph->trx->is_recovered); diff --git a/storage/innobase/srv/srv0mon.cc b/storage/innobase/srv/srv0mon.cc index ef16c453657..81ab97daac9 100644 --- a/storage/innobase/srv/srv0mon.cc +++ b/storage/innobase/srv/srv0mon.cc @@ -386,31 +386,16 @@ static monitor_info_t innodb_counter_info[] = MONITOR_NONE, MONITOR_DEFAULT_START, MONITOR_FLUSH_ADAPTIVE_AVG_TIME_SLOT}, - {"buffer_LRU_batch_flush_avg_time_slot", "buffer", - "Avg time (ms) spent for LRU batch flushing recently per slot.", - MONITOR_NONE, - MONITOR_DEFAULT_START, MONITOR_LRU_BATCH_FLUSH_AVG_TIME_SLOT}, - {"buffer_flush_adaptive_avg_time_thread", "buffer", "Avg time (ms) spent for adaptive flushing recently per thread.", MONITOR_NONE, MONITOR_DEFAULT_START, MONITOR_FLUSH_ADAPTIVE_AVG_TIME_THREAD}, - {"buffer_LRU_batch_flush_avg_time_thread", "buffer", - "Avg time (ms) spent for LRU batch flushing recently per thread.", - MONITOR_NONE, - MONITOR_DEFAULT_START, MONITOR_LRU_BATCH_FLUSH_AVG_TIME_THREAD}, - {"buffer_flush_adaptive_avg_time_est", "buffer", "Estimated time (ms) spent for adaptive flushing recently.", MONITOR_NONE, MONITOR_DEFAULT_START, MONITOR_FLUSH_ADAPTIVE_AVG_TIME_EST}, - {"buffer_LRU_batch_flush_avg_time_est", "buffer", - "Estimated time (ms) spent for LRU batch flushing recently.", - MONITOR_NONE, - MONITOR_DEFAULT_START, MONITOR_LRU_BATCH_FLUSH_AVG_TIME_EST}, - {"buffer_flush_avg_time", "buffer", "Avg time (ms) spent for flushing recently.", MONITOR_NONE, @@ -421,11 +406,6 @@ static monitor_info_t innodb_counter_info[] = MONITOR_NONE, MONITOR_DEFAULT_START, MONITOR_FLUSH_ADAPTIVE_AVG_PASS}, - {"buffer_LRU_batch_flush_avg_pass", "buffer", - "Number of LRU batch flushes passed during the recent Avg period.", - MONITOR_NONE, - MONITOR_DEFAULT_START, MONITOR_LRU_BATCH_FLUSH_AVG_PASS}, - {"buffer_flush_avg_pass", "buffer", "Number of flushes passed during the recent Avg period.", MONITOR_NONE, @@ -562,23 +542,6 @@ static monitor_info_t innodb_counter_info[] = MONITOR_SET_MEMBER, MONITOR_LRU_BATCH_EVICT_TOTAL_PAGE, MONITOR_LRU_BATCH_EVICT_PAGES}, - /* Cumulative counter for single page LRU scans */ - {"buffer_LRU_single_flush_scanned", "buffer", - "Total pages scanned as part of single page LRU flush", - MONITOR_SET_OWNER, - MONITOR_LRU_SINGLE_FLUSH_SCANNED_NUM_CALL, - MONITOR_LRU_SINGLE_FLUSH_SCANNED}, - - {"buffer_LRU_single_flush_num_scan", "buffer", - "Number of times single page LRU flush is called", - MONITOR_SET_MEMBER, MONITOR_LRU_SINGLE_FLUSH_SCANNED, - MONITOR_LRU_SINGLE_FLUSH_SCANNED_NUM_CALL}, - - {"buffer_LRU_single_flush_scanned_per_call", "buffer", - "Page scanned per single LRU flush", - MONITOR_SET_MEMBER, MONITOR_LRU_SINGLE_FLUSH_SCANNED, - MONITOR_LRU_SINGLE_FLUSH_SCANNED_PER_CALL}, - {"buffer_LRU_single_flush_failure_count", "Buffer", "Number of times attempt to flush a single page from LRU failed", MONITOR_NONE, @@ -1468,7 +1431,8 @@ srv_mon_set_module_control( ibool set_current_module = FALSE; ut_a(module_id <= NUM_MONITOR); - ut_a(UT_ARR_SIZE(innodb_counter_info) == NUM_MONITOR); + compile_time_assert(array_elements(innodb_counter_info) + == NUM_MONITOR); /* The module_id must be an ID of MONITOR_MODULE type */ ut_a(innodb_counter_info[module_id].monitor_type & MONITOR_MODULE); diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 144ea17ec0c..3303edf9272 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -342,11 +342,6 @@ my_bool srv_stats_sample_traditional; my_bool srv_use_doublewrite_buf; -/** innodb_doublewrite_batch_size (a debug parameter) specifies the -number of pages to use in LRU and flush_list batch flushing. -The rest of the doublewrite buffer is used for single-page flushing. */ -ulong srv_doublewrite_batch_size = 120; - /** innodb_sync_spin_loops */ ulong srv_n_spin_wait_rounds; /** innodb_spin_wait_delay */ @@ -707,9 +702,6 @@ static void srv_init() if (!srv_read_only_mode) { mutex_create(LATCH_ID_SRV_SYS_TASKS, &srv_sys.tasks_mutex); - - buf_flush_event = os_event_create("buf_flush_event"); - UT_LIST_INIT(srv_sys.tasks, &que_thr_t::queue); } @@ -755,7 +747,6 @@ srv_free(void) if (!srv_read_only_mode) { mutex_free(&srv_sys.tasks_mutex); - os_event_destroy(buf_flush_event); } ut_d(os_event_destroy(srv_master_thread_disabled_event)); @@ -1119,9 +1110,6 @@ srv_export_innodb_status(void) export_vars.innodb_buffer_pool_wait_free = srv_stats.buf_pool_wait_free; - export_vars.innodb_buffer_pool_pages_flushed = - srv_stats.buf_pool_flushed; - export_vars.innodb_buffer_pool_reads = srv_stats.buf_pool_reads; export_vars.innodb_buffer_pool_read_ahead_rnd = @@ -1871,10 +1859,6 @@ srv_master_do_idle_tasks(void) log_checkpoint(); MONITOR_INC_TIME_IN_MICRO_SECS(MONITOR_SRV_CHECKPOINT_MICROSECOND, counter_time); - - /* This is a workaround to avoid the InnoDB hang when OS datetime - changed backwards.*/ - os_event_set(buf_flush_event); } /** diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 9a0f9d04149..dba660ee13f 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -140,30 +140,8 @@ UNIV_INTERN uint srv_sys_space_size_debug; UNIV_INTERN bool srv_log_file_created; #endif /* UNIV_DEBUG */ -/** Bit flags for tracking background thread creation. They are used to -determine which threads need to be stopped if we need to abort during -the initialisation step. */ -enum srv_start_state_t { - /** No thread started */ - SRV_START_STATE_NONE = 0, /*!< No thread started */ - /** lock_wait_timeout timer task started */ - SRV_START_STATE_LOCK_SYS = 1, - /** buf_flush_page_cleaner_coordinator, - buf_flush_page_cleaner_worker started */ - SRV_START_STATE_IO = 2, - /** srv_error_monitor_thread, srv_print_monitor_task started */ - SRV_START_STATE_MONITOR = 4, - /** srv_master_thread started */ - SRV_START_STATE_MASTER = 8, - /** srv_purge_coordinator_thread, srv_worker_thread started */ - SRV_START_STATE_PURGE = 16, - /** fil_crypt_thread, - (all background threads that can generate redo log but not undo log */ - SRV_START_STATE_REDO = 32 -}; - -/** Track server thrd starting phases */ -static ulint srv_start_state; +/** whether some background threads that create redo log have been started */ +static bool srv_started_redo; /** At a shutdown this value climbs from SRV_SHUTDOWN_NONE to SRV_SHUTDOWN_CLEANUP and then to SRV_SHUTDOWN_LAST_PHASE, and so on */ @@ -844,30 +822,6 @@ srv_open_tmp_tablespace(bool create_new_db) return(err); } -/****************************************************************//** -Set state to indicate start of particular group of threads in InnoDB. */ -UNIV_INLINE -void -srv_start_state_set( -/*================*/ - srv_start_state_t state) /*!< in: indicate current state of - thread startup */ -{ - srv_start_state |= ulint(state); -} - -/****************************************************************//** -Check if following group of threads is started. -@return true if started */ -UNIV_INLINE -bool -srv_start_state_is_set( -/*===================*/ - srv_start_state_t state) /*!< in: state to check for */ -{ - return(srv_start_state & ulint(state)); -} - /** Shutdown all background threads created by InnoDB. */ static @@ -899,11 +853,11 @@ srv_shutdown_all_bg_threads() } } - if (srv_start_state_is_set(SRV_START_STATE_IO)) { + if (buf_page_cleaner_is_active) { ut_ad(!srv_read_only_mode); - /* e. Exit the i/o threads */ - os_event_set(buf_flush_event); + /* e. Exit the buf_flush_page_cleaner */ + mysql_cond_signal(&buf_pool.do_flush_list); } if (!os_thread_count) { @@ -1145,8 +1099,7 @@ dberr_t srv_start(bool create_new_db) || srv_force_recovery > SRV_FORCE_NO_IBUF_MERGE || srv_sys_space.created_new_raw(); - /* Reset the start state. */ - srv_start_state = SRV_START_STATE_NONE; + srv_started_redo = false; compile_time_assert(sizeof(ulint) == sizeof(void*)); @@ -1328,7 +1281,7 @@ dberr_t srv_start(bool create_new_db) if (!srv_read_only_mode) { buf_flush_page_cleaner_init(); - srv_start_state_set(SRV_START_STATE_IO); + ut_ad(buf_page_cleaner_is_active); } srv_startup_is_before_trx_rollback_phase = !create_new_db; @@ -1377,11 +1330,10 @@ dberr_t srv_start(bool create_new_db) std::string logfile0; if (create_new_db) { - + flushed_lsn = log_sys.get_lsn(); + log_sys.set_flushed_lsn(flushed_lsn); buf_flush_sync(); - flushed_lsn = log_get_lsn(); - err = create_log_file(flushed_lsn, logfile0); if (err != DB_SUCCESS) { @@ -1652,10 +1604,7 @@ file_checked: } } - /* recv_recovery_from_checkpoint_finish needs trx lists which - are initialized in trx_lists_init_at_db_start(). */ - - recv_recovery_from_checkpoint_finish(); + recv_sys.debug_free(); if (srv_operation == SRV_OPERATION_RESTORE || srv_operation == SRV_OPERATION_RESTORE_EXPORT) { @@ -1757,7 +1706,7 @@ file_checked: /* Create the doublewrite buffer to a new tablespace */ if (!srv_read_only_mode && srv_force_recovery < SRV_FORCE_NO_TRX_UNDO - && !buf_dblwr_create()) { + && !buf_dblwr.create()) { return(srv_init_abort(DB_ERROR)); } @@ -1896,9 +1845,6 @@ file_checked: srv_start_periodic_timer(srv_error_monitor_timer, srv_error_monitor_task, 1000); srv_start_periodic_timer(srv_monitor_timer, srv_monitor_task, 5000); - srv_start_state |= SRV_START_STATE_LOCK_SYS - | SRV_START_STATE_MONITOR; - #ifndef DBUG_OFF skip_monitors: #endif @@ -1957,7 +1903,6 @@ skip_monitors: srv_init_purge_tasks(); purge_sys.coordinator_startup(); srv_wake_purge_thread_if_not_active(); - srv_start_state_set(SRV_START_STATE_PURGE); } srv_is_being_started = false; @@ -2016,7 +1961,7 @@ skip_monitors: /* Initialize online defragmentation. */ btr_defragment_init(); - srv_start_state |= SRV_START_STATE_REDO; + srv_started_redo = true; } return(DB_SUCCESS); @@ -2103,7 +2048,8 @@ void innodb_shutdown() ut_ad(dict_sys.is_initialised() || !srv_was_started); ut_ad(trx_sys.is_initialised() || !srv_was_started); - ut_ad(buf_dblwr || !srv_was_started || srv_read_only_mode + ut_ad(buf_dblwr.is_initialised() || !srv_was_started + || srv_read_only_mode || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO); ut_ad(lock_sys.is_initialised() || !srv_was_started); ut_ad(log_sys.is_initialised() || !srv_was_started); @@ -2111,7 +2057,7 @@ void innodb_shutdown() dict_stats_deinit(); - if (srv_start_state_is_set(SRV_START_STATE_REDO)) { + if (srv_started_redo) { ut_ad(!srv_read_only_mode); /* srv_shutdown_bg_undo_sources() already invoked fts_optimize_shutdown(); dict_stats_shutdown(); */ @@ -2132,9 +2078,7 @@ void innodb_shutdown() log_sys.close(); purge_sys.close(); trx_sys.close(); - if (buf_dblwr) { - buf_dblwr_free(); - } + buf_dblwr.close(); lock_sys.close(); trx_pool_close(); @@ -2161,7 +2105,7 @@ void innodb_shutdown() << "; transaction id " << trx_sys.get_max_trx_id(); } srv_thread_pool_end(); - srv_start_state = SRV_START_STATE_NONE; + srv_started_redo = false; srv_was_started = false; srv_start_has_been_called = false; } diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc index 78e613b52f0..11038c6020d 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -453,9 +453,6 @@ LatchDebug::LatchDebug() LEVEL_MAP_INSERT(RW_LOCK_X); LEVEL_MAP_INSERT(RW_LOCK_NOT_LOCKED); LEVEL_MAP_INSERT(SYNC_ANY_LATCH); - LEVEL_MAP_INSERT(SYNC_DOUBLEWRITE); - LEVEL_MAP_INSERT(SYNC_BUF_FLUSH_LIST); - LEVEL_MAP_INSERT(SYNC_BUF_POOL); LEVEL_MAP_INSERT(SYNC_POOL); LEVEL_MAP_INSERT(SYNC_POOL_MANAGER); LEVEL_MAP_INSERT(SYNC_SEARCH_SYS); @@ -467,7 +464,6 @@ LatchDebug::LatchDebug() LEVEL_MAP_INSERT(SYNC_RECV); LEVEL_MAP_INSERT(SYNC_LOG_FLUSH_ORDER); LEVEL_MAP_INSERT(SYNC_LOG); - LEVEL_MAP_INSERT(SYNC_PAGE_CLEANER); LEVEL_MAP_INSERT(SYNC_PURGE_QUEUE); LEVEL_MAP_INSERT(SYNC_TRX_SYS_HEADER); LEVEL_MAP_INSERT(SYNC_REC_LOCK); @@ -741,10 +737,8 @@ LatchDebug::check_order( case SYNC_FTS_OPTIMIZE: case SYNC_FTS_CACHE: case SYNC_FTS_CACHE_INIT: - case SYNC_PAGE_CLEANER: case SYNC_LOG: case SYNC_LOG_FLUSH_ORDER: - case SYNC_DOUBLEWRITE: case SYNC_SEARCH_SYS: case SYNC_LOCK_SYS: case SYNC_LOCK_WAIT_SYS: @@ -802,15 +796,6 @@ LatchDebug::check_order( } break; - case SYNC_BUF_FLUSH_LIST: - case SYNC_BUF_POOL: - - /* We can have multiple mutexes of this type therefore we - can only check whether the greater than condition holds. */ - - basic_check(latches, level, level - 1); - break; - case SYNC_REC_LOCK: if (find(latches, SYNC_LOCK_SYS) != 0) { @@ -1169,8 +1154,7 @@ sync_check_iterate(const sync_check_functor_t& functor) Note: We don't enforce any synchronisation checks. The caller must ensure that no races can occur */ -void -sync_check_enable() +static void sync_check_enable() { if (!srv_sync_debug) { @@ -1243,8 +1227,6 @@ sync_latch_meta_init() /* The latches should be ordered on latch_id_t. So that we can index directly into the vector to update and fetch meta-data. */ - LATCH_ADD_MUTEX(BUF_POOL, SYNC_BUF_POOL, buf_pool_mutex_key); - LATCH_ADD_MUTEX(DICT_FOREIGN_ERR, SYNC_NO_ORDER_CHECK, dict_foreign_err_mutex_key); @@ -1252,8 +1234,6 @@ sync_latch_meta_init() LATCH_ADD_MUTEX(FIL_SYSTEM, SYNC_ANY_LATCH, fil_system_mutex_key); - LATCH_ADD_MUTEX(FLUSH_LIST, SYNC_BUF_FLUSH_LIST, flush_list_mutex_key); - LATCH_ADD_MUTEX(FTS_BG_THREADS, SYNC_FTS_BG_THREADS, fts_bg_threads_mutex_key); @@ -1277,9 +1257,6 @@ sync_latch_meta_init() LATCH_ADD_MUTEX(LOG_FLUSH_ORDER, SYNC_LOG_FLUSH_ORDER, log_flush_order_mutex_key); - LATCH_ADD_MUTEX(PAGE_CLEANER, SYNC_PAGE_CLEANER, - page_cleaner_mutex_key); - LATCH_ADD_MUTEX(PURGE_SYS_PQ, SYNC_PURGE_QUEUE, purge_sys_pq_mutex_key); @@ -1320,8 +1297,6 @@ sync_latch_meta_init() LATCH_ADD_MUTEX(SRV_MONITOR_FILE, SYNC_NO_ORDER_CHECK, srv_monitor_file_mutex_key); - LATCH_ADD_MUTEX(BUF_DBLWR, SYNC_DOUBLEWRITE, buf_dblwr_mutex_key); - LATCH_ADD_MUTEX(TRX_POOL, SYNC_POOL, trx_pool_mutex_key); LATCH_ADD_MUTEX(TRX_POOL_MANAGER, SYNC_POOL_MANAGER, @@ -1456,6 +1431,8 @@ sync_check_init() ut_d(LatchDebug::init()); sync_array_init(); + + ut_d(sync_check_enable()); } /** Free the InnoDB synchronization data structures. */ diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc index 6a40c90579d..f88a3945773 100644 --- a/storage/innobase/sync/sync0sync.cc +++ b/storage/innobase/sync/sync0sync.cc @@ -52,7 +52,6 @@ mysql_pfs_key_t log_sys_mutex_key; mysql_pfs_key_t log_cmdq_mutex_key; mysql_pfs_key_t log_flush_order_mutex_key; mysql_pfs_key_t recalc_pool_mutex_key; -mysql_pfs_key_t page_cleaner_mutex_key; mysql_pfs_key_t purge_sys_pq_mutex_key; mysql_pfs_key_t recv_sys_mutex_key; mysql_pfs_key_t redo_rseg_mutex_key; diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 393f044d23a..f9f564e1841 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -262,7 +262,7 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) or in trx_rollback_recovered() in slow shutdown. Before any transaction-generating background threads or the - purge have been started, recv_recovery_rollback_active() can + purge have been started, we can start transactions in row_merge_drop_temp_indexes() and fts_drop_orphaned_tables(), and roll back recovered transactions. @@ -680,7 +680,7 @@ not_free: mini-transaction commit and the server was killed, then discarding the to-be-trimmed pages without flushing would break crash recovery. So, we cannot avoid the write. */ - buf_LRU_flush_or_remove_pages(space.id, true); + while (buf_flush_dirty_pages(space.id)); log_free_check(); diff --git a/storage/rocksdb/mysql-test/rocksdb/r/innodb_i_s_tables_disabled.result b/storage/rocksdb/mysql-test/rocksdb/r/innodb_i_s_tables_disabled.result index 2139b1bfe05..d4623c2f054 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/innodb_i_s_tables_disabled.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/innodb_i_s_tables_disabled.result @@ -72,14 +72,10 @@ buffer_flush_neighbor_pages buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL N buffer_flush_n_to_flush_requested buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of pages requested for flushing. buffer_flush_n_to_flush_by_age buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of pages target by LSN Age for flushing. buffer_flush_adaptive_avg_time_slot buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for adaptive flushing recently per slot. -buffer_LRU_batch_flush_avg_time_slot buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for LRU batch flushing recently per slot. buffer_flush_adaptive_avg_time_thread buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for adaptive flushing recently per thread. -buffer_LRU_batch_flush_avg_time_thread buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for LRU batch flushing recently per thread. buffer_flush_adaptive_avg_time_est buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Estimated time (ms) spent for adaptive flushing recently. -buffer_LRU_batch_flush_avg_time_est buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Estimated time (ms) spent for LRU batch flushing recently. buffer_flush_avg_time buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for flushing recently. buffer_flush_adaptive_avg_pass buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of adaptive flushes passed during the recent Avg period. -buffer_LRU_batch_flush_avg_pass buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of LRU batch flushes passed during the recent Avg period. buffer_flush_avg_pass buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of flushes passed during the recent Avg period. buffer_LRU_get_free_loops buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Total loops in LRU get free. buffer_LRU_get_free_waits buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Total sleep waits in LRU get free. @@ -106,9 +102,6 @@ buffer_LRU_batch_flush_pages buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL buffer_LRU_batch_evict_total_pages buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_owner Total pages evicted as part of LRU batches buffer_LRU_batches_evict buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_member Number of LRU batches buffer_LRU_batch_evict_pages buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_member Pages queued as an LRU batch -buffer_LRU_single_flush_scanned buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_owner Total pages scanned as part of single page LRU flush -buffer_LRU_single_flush_num_scan buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_member Number of times single page LRU flush is called -buffer_LRU_single_flush_scanned_per_call buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_member Page scanned per single LRU flush buffer_LRU_single_flush_failure_count Buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of times attempt to flush a single page from LRU failed buffer_LRU_get_free_search Buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of searches performed for a clean page buffer_LRU_search_scanned buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_owner Total pages scanned as part of LRU search From abb678b61894146fcb88eed7f4a5facf434aea7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 15 Oct 2020 13:27:09 +0300 Subject: [PATCH 127/323] MDEV-19514 fixup: Simplify buf_page_read_complete() False positives for buf_page_t::ibuf_exist are acceptable, because it does not hurt to unnecessarily invoke ibuf_merge_or_delete_for_page(). Invoking buf_page_get_gen() in a read completion function is a definite no-no, because it could trigger a page flush or cause the server to run out of buffer pool. With some MDEV-23855 changes present, the test innodb.purge_secondary occasionally failed due to the table having been dropped while ibuf_page_exists() invoked buf_page_get_gen(). Reviewed by: Thirunarayanan Balathandayuthapani --- storage/innobase/buf/buf0buf.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 6bde6939fd6..1f3cbb56234 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -4325,7 +4325,7 @@ release_page: if (bpage->state() == BUF_BLOCK_FILE_PAGE && !recv_no_ibuf_operations && (!id.space() || !is_predefined_tablespace(id.space())) && fil_page_get_type(frame) == FIL_PAGE_INDEX && - page_is_leaf(frame) && ibuf_page_exists(id, bpage->zip_size())) + page_is_leaf(frame)) bpage->ibuf_exist= true; if (UNIV_UNLIKELY(MONITOR_IS_ON(MONITOR_MODULE_BUF_PAGE))) From ecb913c2a5f3f797f28cd0ded2cfe20881c52db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 15 Oct 2020 13:21:52 +0300 Subject: [PATCH 128/323] Cleanup: Compare page_id_t directly --- storage/innobase/btr/btr0btr.cc | 2 +- storage/innobase/ibuf/ibuf0ibuf.cc | 3 +-- storage/innobase/trx/trx0sys.cc | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 8ed25db8cb7..e292815d00e 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -1049,7 +1049,7 @@ btr_create( return(FIL_NULL); } - ut_ad(block->page.id().page_no() == IBUF_TREE_ROOT_PAGE_NO); + ut_ad(block->page.id() == page_id_t(0,IBUF_TREE_ROOT_PAGE_NO)); buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW); diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index ca13e2e33af..84003fb415c 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -934,8 +934,7 @@ ibuf_update_free_bits_for_two_pages_low( @return TRUE if a fixed address ibuf i/o page */ inline bool ibuf_fixed_addr_page(const page_id_t page_id, ulint zip_size) { - return((page_id.space() == IBUF_SPACE_ID - && page_id.page_no() == IBUF_TREE_ROOT_PAGE_NO) + return(page_id == page_id_t(IBUF_SPACE_ID, IBUF_TREE_ROOT_PAGE_NO) || ibuf_bitmap_page(page_id, zip_size)); } diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index a3ada6636fd..9011ca8f2e1 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -163,7 +163,7 @@ trx_sysf_create( mtr); buf_block_dbg_add_level(block, SYNC_TRX_SYS_HEADER); - ut_a(block->page.id().page_no() == TRX_SYS_PAGE_NO); + ut_a(block->page.id() == page_id_t(0, TRX_SYS_PAGE_NO)); mtr->write<2>(*block, FIL_PAGE_TYPE + block->frame, FIL_PAGE_TYPE_TRX_SYS); @@ -195,7 +195,7 @@ trx_sysf_create( slot_no, block, mtr); ut_a(slot_no == TRX_SYS_SYSTEM_RSEG_ID); - ut_a(rblock->page.id().page_no() == FSP_FIRST_RSEG_PAGE_NO); + ut_a(rblock->page.id() == page_id_t(0, FSP_FIRST_RSEG_PAGE_NO)); } /** Create the instance */ From 61161d51d724a7fc7f99af56b7c00dd7e86c023f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 15 Oct 2020 15:04:43 +0300 Subject: [PATCH 129/323] Cleanup: Remove export_vars.innodb_num_open_files --- storage/innobase/handler/ha_innodb.cc | 2 +- storage/innobase/include/srv0srv.h | 1 - storage/innobase/srv/srv0srv.cc | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index f9cc8629a73..dcfd402de0c 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -978,7 +978,7 @@ static SHOW_VAR innodb_status_variables[]= { {"system_rows_read", &export_vars.innodb_system_rows_read, SHOW_SIZE_T}, {"system_rows_updated", &export_vars.innodb_system_rows_updated, SHOW_SIZE_T}, - {"num_open_files", &export_vars.innodb_num_open_files, SHOW_SIZE_T}, + {"num_open_files", &fil_system.n_open, SHOW_SIZE_T}, {"truncated_status_writes", &export_vars.innodb_truncated_status_writes, SHOW_SIZE_T}, {"available_undo_logs", &srv_available_undo_logs, SHOW_ULONG}, diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index e956e421a6a..915cc3ffd4f 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -812,7 +812,6 @@ struct export_var_t{ ulint innodb_system_rows_inserted; /*!< srv_n_system_rows_inserted */ ulint innodb_system_rows_updated; /*!< srv_n_system_rows_updated */ ulint innodb_system_rows_deleted; /*!< srv_n_system_rows_deleted*/ - ulint innodb_num_open_files; /*!< fil_system_t::n_open */ ulint innodb_truncated_status_writes; /*!< srv_truncated_status_writes */ /** Number of undo tablespace truncation operations */ diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 3303edf9272..6337428e450 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -1225,8 +1225,6 @@ srv_export_innodb_status(void) export_vars.innodb_system_rows_deleted = srv_stats.n_system_rows_deleted; - export_vars.innodb_num_open_files = fil_system.n_open; - export_vars.innodb_truncated_status_writes = srv_truncated_status_writes; From 9028cc6b865222cae8c396b4ec3e317c8ee068d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 15 Oct 2020 16:28:19 +0300 Subject: [PATCH 130/323] Cleanup: Make InnoDB page numbers uint32_t InnoDB stores a 32-bit page number in page headers and in some data structures, such as FIL_ADDR (consisting of a 32-bit page number and a 16-bit byte offset within a page). For better compile-time error detection and to reduce the memory footprint in some data structures, let us use a uint32_t for the page number, instead of ulint (size_t) which can be 64 bits. --- extra/mariabackup/xtrabackup.cc | 4 +- .../sys_vars/r/sysvars_innodb,32bit.rdiff | 27 --- .../suite/sys_vars/r/sysvars_innodb.result | 6 +- storage/innobase/btr/btr0btr.cc | 37 ++-- storage/innobase/btr/btr0bulk.cc | 9 +- storage/innobase/btr/btr0cur.cc | 186 +++++++---------- storage/innobase/btr/btr0defragment.cc | 2 +- storage/innobase/buf/buf0buddy.cc | 10 +- storage/innobase/buf/buf0buf.cc | 4 +- storage/innobase/buf/buf0dblwr.cc | 6 +- storage/innobase/buf/buf0dump.cc | 14 +- storage/innobase/buf/buf0rea.cc | 23 +-- storage/innobase/fil/fil0crypt.cc | 16 +- storage/innobase/fil/fil0fil.cc | 33 ++- storage/innobase/fsp/fsp0fsp.cc | 193 ++++++++---------- storage/innobase/fsp/fsp0sysspace.cc | 49 ++--- storage/innobase/gis/gis0sea.cc | 16 +- storage/innobase/handler/ha_innodb.cc | 28 +-- storage/innobase/ibuf/ibuf0ibuf.cc | 151 ++++++-------- storage/innobase/include/btr0btr.h | 8 +- storage/innobase/include/btr0btr.ic | 5 +- storage/innobase/include/btr0bulk.h | 9 +- storage/innobase/include/btr0cur.h | 2 +- storage/innobase/include/buf0rea.h | 11 +- storage/innobase/include/buf0types.h | 6 +- storage/innobase/include/fil0crypt.h | 4 +- storage/innobase/include/fil0fil.h | 45 ++-- storage/innobase/include/fsp0file.h | 6 +- storage/innobase/include/fsp0fsp.h | 20 +- storage/innobase/include/fsp0space.h | 6 +- storage/innobase/include/fsp0sysspace.h | 13 +- storage/innobase/include/gis0rtree.h | 4 +- storage/innobase/include/gis0rtree.ic | 4 +- storage/innobase/include/gis0type.h | 12 +- storage/innobase/include/page0page.h | 4 +- storage/innobase/include/page0page.ic | 4 +- storage/innobase/include/trx0rseg.h | 10 +- storage/innobase/include/trx0rseg.ic | 6 +- storage/innobase/log/log0recv.cc | 6 +- storage/innobase/os/os0file.cc | 8 +- storage/innobase/row/row0import.cc | 8 +- storage/innobase/row/row0merge.cc | 8 +- storage/innobase/row/row0sel.cc | 2 +- storage/innobase/srv/srv0start.cc | 8 +- storage/innobase/trx/trx0rseg.cc | 8 +- storage/innobase/trx/trx0undo.cc | 4 +- 46 files changed, 441 insertions(+), 604 deletions(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 3da6239b6f8..1d98f89894a 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -3099,7 +3099,7 @@ xb_load_single_table_tablespace( ut_a(space != NULL); - space->add(file->filepath(), OS_FILE_CLOSED, ulint(n_pages), + space->add(file->filepath(), OS_FILE_CLOSED, uint32_t(n_pages), false, false); /* by opening the tablespace we forcing node and space objects in the cache to be populated with fields from space header */ @@ -4901,7 +4901,7 @@ xtrabackup_apply_delta( space->chain); bool fail = !strcmp(n->name, dst_path) && !fil_space_extend( - space, (ulint)n_pages); + space, uint32_t(n_pages)); if (fail) goto error; } } diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff b/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff index 0a558e77923..ea9f47d8f3a 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff @@ -9,15 +9,6 @@ VARIABLE_COMMENT Number of InnoDB Adaptive Hash Index Partitions (default 8) NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 512 -@@ -73,7 +73,7 @@ - SESSION_VALUE NULL - DEFAULT_VALUE 64 - VARIABLE_SCOPE GLOBAL --VARIABLE_TYPE BIGINT UNSIGNED -+VARIABLE_TYPE INT UNSIGNED - VARIABLE_COMMENT Data file autoextend increment in megabytes - NUMERIC_MIN_VALUE 1 - NUMERIC_MAX_VALUE 1000 @@ -85,7 +85,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 1 @@ -94,15 +85,6 @@ VARIABLE_COMMENT Maximum number of seconds that semaphore times out in InnoDB. NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 4294967295 -@@ -793,7 +793,7 @@ - SESSION_VALUE NULL - DEFAULT_VALUE 0 - VARIABLE_SCOPE GLOBAL --VARIABLE_TYPE BIGINT UNSIGNED -+VARIABLE_TYPE INT UNSIGNED - VARIABLE_COMMENT Make the first page of the given tablespace dirty. - NUMERIC_MIN_VALUE 0 - NUMERIC_MAX_VALUE 4294967295 @@ -805,7 +805,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 30 @@ -398,15 +380,6 @@ VARIABLE_COMMENT Number of background read I/O threads in InnoDB. NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 64 -@@ -1657,7 +1657,7 @@ - SESSION_VALUE NULL - DEFAULT_VALUE 0 - VARIABLE_SCOPE GLOBAL --VARIABLE_TYPE BIGINT UNSIGNED -+VARIABLE_TYPE INT UNSIGNED - VARIABLE_COMMENT An InnoDB page number. - NUMERIC_MIN_VALUE 0 - NUMERIC_MAX_VALUE 4294967295 @@ -1705,7 +1705,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 1048576 diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result index 767d31c033e..5227c08052e 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result @@ -73,7 +73,7 @@ VARIABLE_NAME INNODB_AUTOEXTEND_INCREMENT SESSION_VALUE NULL DEFAULT_VALUE 64 VARIABLE_SCOPE GLOBAL -VARIABLE_TYPE BIGINT UNSIGNED +VARIABLE_TYPE INT UNSIGNED VARIABLE_COMMENT Data file autoextend increment in megabytes NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 1000 @@ -793,7 +793,7 @@ VARIABLE_NAME INNODB_FIL_MAKE_PAGE_DIRTY_DEBUG SESSION_VALUE NULL DEFAULT_VALUE 0 VARIABLE_SCOPE GLOBAL -VARIABLE_TYPE BIGINT UNSIGNED +VARIABLE_TYPE INT UNSIGNED VARIABLE_COMMENT Make the first page of the given tablespace dirty. NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 4294967295 @@ -1657,7 +1657,7 @@ VARIABLE_NAME INNODB_SAVED_PAGE_NUMBER_DEBUG SESSION_VALUE NULL DEFAULT_VALUE 0 VARIABLE_SCOPE GLOBAL -VARIABLE_TYPE BIGINT UNSIGNED +VARIABLE_TYPE INT UNSIGNED VARIABLE_COMMENT An InnoDB page number. NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 4294967295 diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index e292815d00e..e7e70f76790 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -55,7 +55,7 @@ bool btr_can_merge_with_page( /*====================*/ btr_cur_t* cursor, /*!< in: cursor on the page to merge */ - ulint page_no, /*!< in: a sibling page */ + uint32_t page_no, /*!< in: a sibling page */ buf_block_t** merge_block, /*!< out: the merge block */ mtr_t* mtr); /*!< in: mini-transaction */ @@ -511,7 +511,7 @@ buf_block_t* btr_page_alloc_low( /*===============*/ dict_index_t* index, /*!< in: index */ - ulint hint_page_no, /*!< in: hint of a good page */ + uint32_t hint_page_no, /*!< in: hint of a good page */ byte file_direction, /*!< in: direction where a possible page split is made */ ulint level, /*!< in: level where the page is placed @@ -548,7 +548,7 @@ buf_block_t* btr_page_alloc( /*===========*/ dict_index_t* index, /*!< in: index */ - ulint hint_page_no, /*!< in: hint of a good page */ + uint32_t hint_page_no, /*!< in: hint of a good page */ byte file_direction, /*!< in: direction where a possible page split is made */ ulint level, /*!< in: level where the page is placed @@ -2801,7 +2801,7 @@ func_start: tuple to be inserted should be the first record on the upper half-page */ bool insert_left = false; - ulint hint_page_no = block->page.id().page_no() + 1; + uint32_t hint_page_no = block->page.id().page_no() + 1; byte direction = FSP_UP; if (tuple && n_iterations > 0) { @@ -3386,8 +3386,6 @@ btr_compress( mtr_t* mtr) /*!< in/out: mini-transaction */ { dict_index_t* index; - ulint left_page_no; - ulint right_page_no; buf_block_t* merge_block; page_t* merge_page = NULL; page_zip_des_t* merge_page_zip; @@ -3416,8 +3414,8 @@ btr_compress( MONITOR_INC(MONITOR_INDEX_MERGE_ATTEMPTS); - left_page_no = btr_page_get_prev(page); - right_page_no = btr_page_get_next(page); + const uint32_t left_page_no = btr_page_get_prev(page); + const uint32_t right_page_no = btr_page_get_next(page); #ifdef UNIV_DEBUG if (!page_is_leaf(page) && left_page_no == FIL_NULL) { @@ -3989,8 +3987,6 @@ btr_discard_page( mtr_t* mtr) /*!< in: mtr */ { dict_index_t* index; - ulint left_page_no; - ulint right_page_no; buf_block_t* merge_block; buf_block_t* block; btr_cur_t parent_cursor; @@ -4014,8 +4010,8 @@ btr_discard_page( /* Decide the page which will inherit the locks */ - left_page_no = btr_page_get_prev(block->frame); - right_page_no = btr_page_get_next(block->frame); + const uint32_t left_page_no = btr_page_get_prev(block->frame); + const uint32_t right_page_no = btr_page_get_next(block->frame); ut_d(bool parent_is_different = false); if (left_page_no != FIL_NULL) { @@ -4598,8 +4594,6 @@ btr_validate_level( btr_cur_t node_cur; btr_cur_t right_node_cur; rec_t* rec; - ulint right_page_no; - ulint left_page_no; page_cur_t cursor; dtuple_t* node_ptr_tuple; bool ret = true; @@ -4612,8 +4606,8 @@ btr_validate_level( #endif /* UNIV_ZIP_DEBUG */ ulint savepoint = 0; ulint savepoint2 = 0; - ulint parent_page_no = FIL_NULL; - ulint parent_right_page_no = FIL_NULL; + uint32_t parent_page_no = FIL_NULL; + uint32_t parent_right_page_no = FIL_NULL; bool rightmost_child = false; mtr.start(); @@ -4669,7 +4663,7 @@ btr_validate_level( does not use such scan for any of its DML or query operations */ if (dict_index_is_spatial(index)) { - left_page_no = btr_page_get_prev(page); + uint32_t left_page_no = btr_page_get_prev(page); while (left_page_no != FIL_NULL) { /* To obey latch order of tree blocks, @@ -4738,8 +4732,8 @@ loop: ut_a(btr_page_get_level(page) == level); - right_page_no = btr_page_get_next(page); - left_page_no = btr_page_get_prev(page); + uint32_t right_page_no = btr_page_get_next(page); + uint32_t left_page_no = btr_page_get_prev(page); ut_a(!page_is_empty(page) || (level == 0 @@ -4860,8 +4854,7 @@ loop: rec = btr_cur_get_rec(&node_cur); fprintf(stderr, "\n" - "InnoDB: node ptr child page n:o " - ULINTPF "\n", + "InnoDB: node ptr child page n:o %u\n", btr_node_ptr_get_child_page_no(rec, offsets)); fputs("InnoDB: record on page ", stderr); @@ -5096,7 +5089,7 @@ bool btr_can_merge_with_page( /*====================*/ btr_cur_t* cursor, /*!< in: cursor on the page to merge */ - ulint page_no, /*!< in: a sibling page */ + uint32_t page_no, /*!< in: a sibling page */ buf_block_t** merge_block, /*!< out: the merge block */ mtr_t* mtr) /*!< in: mini-transaction */ { diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc index e64f3c8c803..791d1d84b53 100644 --- a/storage/innobase/btr/btr0bulk.cc +++ b/storage/innobase/btr/btr0bulk.cc @@ -43,7 +43,6 @@ PageBulk::init() { buf_block_t* new_block; page_t* new_page; - ulint new_page_no; ut_ad(m_heap == NULL); m_heap = mem_heap_create(1000); @@ -81,7 +80,7 @@ PageBulk::init() alloc_mtr.commit(); new_page = buf_block_get_frame(new_block); - new_page_no = page_get_page_no(new_page); + m_page_no = new_block->page.id().page_no(); byte* index_id = my_assume_aligned<2> (PAGE_HEADER + PAGE_INDEX_ID + new_page); @@ -108,8 +107,7 @@ PageBulk::init() false, &m_mtr); new_page = buf_block_get_frame(new_block); - new_page_no = page_get_page_no(new_page); - ut_ad(m_page_no == new_page_no); + ut_ad(new_block->page.id().page_no() == m_page_no); ut_ad(page_dir_get_n_heap(new_page) == PAGE_HEAP_NO_USER_LOW); @@ -125,7 +123,6 @@ PageBulk::init() m_block = new_block; m_page = new_page; - m_page_no = new_page_no; m_cur_rec = page_get_infimum_rec(new_page); ut_ad(m_is_comp == !!page_is_comp(new_page)); m_free_space = page_get_free_space_of_empty(m_is_comp); @@ -1163,7 +1160,7 @@ if no error occurs. dberr_t BtrBulk::finish(dberr_t err) { - ulint last_page_no = FIL_NULL; + uint32_t last_page_no = FIL_NULL; ut_ad(!m_index->table->is_temporary()); diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index f7c0e080cdd..8fec8a8a824 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -770,20 +770,16 @@ btr_cur_optimistic_latch_leaves( unsigned line, mtr_t* mtr) { - rw_lock_type_t mode; - ulint left_page_no; - ulint curr_page_no; - switch (*latch_mode) { + default: + ut_error; + return(false); case BTR_SEARCH_LEAF: case BTR_MODIFY_LEAF: return(buf_page_optimistic_get(*latch_mode, block, modify_clock, file, line, mtr)); case BTR_SEARCH_PREV: case BTR_MODIFY_PREV: - mode = *latch_mode == BTR_SEARCH_PREV - ? RW_S_LATCH : RW_X_LATCH; - if (block->page.state() != BUF_BLOCK_FILE_PAGE) { return(false); } @@ -793,13 +789,15 @@ btr_cur_optimistic_latch_leaves( rw_lock_s_lock(&block->lock); if (block->modify_clock != modify_clock) { rw_lock_s_unlock(&block->lock); - - goto unpin_failed; + break; } - curr_page_no = block->page.id().page_no(); - left_page_no = btr_page_get_prev(block->frame); + const uint32_t curr_page_no = block->page.id().page_no(); + const uint32_t left_page_no = btr_page_get_prev(block->frame); rw_lock_s_unlock(&block->lock); + const rw_lock_type_t mode = *latch_mode == BTR_SEARCH_PREV + ? RW_S_LATCH : RW_X_LATCH; + if (left_page_no != FIL_NULL) { dberr_t err = DB_SUCCESS; cursor->left_block = buf_page_get_gen( @@ -818,7 +816,7 @@ btr_cur_optimistic_latch_leaves( /* release the left block */ btr_leaf_page_release( cursor->left_block, mode, mtr); - goto unpin_failed; + break; } } else { cursor->left_block = NULL; @@ -841,15 +839,11 @@ btr_cur_optimistic_latch_leaves( btr_leaf_page_release(cursor->left_block, mode, mtr); } -unpin_failed: - /* unpin the block */ - buf_block_buf_fix_dec(block); - return(false); - - default: - ut_error; - return(false); } + + /* unpin the block */ + buf_block_buf_fix_dec(block); + return false; } /** @@ -1713,7 +1707,7 @@ retry_page_get: if (retrying_for_search_prev && height != 0) { /* also latch left sibling */ - ulint left_page_no; + uint32_t left_page_no; buf_block_t* get_block; ut_ad(rw_latch == RW_NO_LATCH); @@ -7026,7 +7020,7 @@ btr_cur_unmark_extern_fields( Returns the length of a BLOB part stored on the header page. @return part length */ static -ulint +uint32_t btr_blob_get_part_len( /*==================*/ const byte* blob_header) /*!< in: blob header */ @@ -7038,7 +7032,7 @@ btr_blob_get_part_len( Returns the page number where the next BLOB part is stored. @return page number or FIL_NULL if no more pages */ static -ulint +uint32_t btr_blob_get_next_page_no( /*======================*/ const byte* blob_header) /*!< in: blob header */ @@ -7118,12 +7112,13 @@ struct btr_blob_log_check_t { { dict_index_t* index = m_pcur->index(); ulint offs = 0; - ulint page_no = ULINT_UNDEFINED; + uint32_t page_no = FIL_NULL; if (UNIV_UNLIKELY(m_op == BTR_STORE_INSERT_BULK)) { offs = page_offset(*m_rec); page_no = (*m_block)->page.id().page_no(); buf_block_buf_fix_inc(*m_block, __FILE__, __LINE__); + ut_ad(page_no != FIL_NULL); } else { btr_pcur_store_position(m_pcur, m_mtr); } @@ -7140,7 +7135,7 @@ struct btr_blob_log_check_t { m_mtr->set_log_mode(log_mode); index->set_modified(*m_mtr); - if (UNIV_UNLIKELY(m_op == BTR_STORE_INSERT_BULK)) { + if (UNIV_UNLIKELY(page_no != FIL_NULL)) { m_pcur->btr_cur.page_cur.block = btr_block_get( *index, page_no, RW_X_LATCH, false, m_mtr); m_pcur->btr_cur.page_cur.rec @@ -7203,14 +7198,10 @@ btr_store_big_rec_extern_fields( committed and restarted. */ enum blob_op op) /*! in: operation code */ { - ulint rec_page_no; byte* field_ref; ulint extern_len; ulint store_len; - ulint page_no; ulint space_id; - ulint prev_page_no; - ulint hint_page_no; ulint i; mtr_t mtr; mem_heap_t* heap = NULL; @@ -7234,7 +7225,6 @@ btr_store_big_rec_extern_fields( &rec, op); page_zip = buf_block_get_page_zip(rec_block); space_id = rec_block->page.id().space(); - rec_page_no = rec_block->page.id().page_no(); ut_a(fil_page_index_page_check(page_align(rec)) || op == BTR_STORE_INSERT_BULK); @@ -7297,7 +7287,7 @@ btr_store_big_rec_extern_fields( MEM_CHECK_DEFINED(big_rec_vec->fields[i].data, extern_len); ut_a(extern_len > 0); - prev_page_no = FIL_NULL; + uint32_t prev_page_no = FIL_NULL; if (page_zip) { int err = deflateReset(&c_stream); @@ -7323,7 +7313,6 @@ btr_store_big_rec_extern_fields( rec, offsets, field_no); page_zip = buf_block_get_page_zip(rec_block); - rec_page_no = rec_block->page.id().page_no(); } mtr.start(); @@ -7333,10 +7322,9 @@ btr_store_big_rec_extern_fields( buf_page_get(rec_block->page.id(), rec_block->zip_size(), RW_X_LATCH, &mtr); - if (prev_page_no == FIL_NULL) { - hint_page_no = 1 + rec_page_no; - } else { - hint_page_no = prev_page_no + 1; + uint32_t hint_prev = prev_page_no; + if (hint_prev == FIL_NULL) { + hint_prev = rec_block->page.id().page_no(); } if (!fsp_reserve_free_extents(&r_extents, @@ -7347,14 +7335,14 @@ btr_store_big_rec_extern_fields( goto func_exit; } - block = btr_page_alloc(index, hint_page_no, FSP_NO_DIR, - 0, &mtr, &mtr); + block = btr_page_alloc(index, hint_prev + 1, + FSP_NO_DIR, 0, &mtr, &mtr); index->table->space->release_free_extents(r_extents); ut_a(block != NULL); - page_no = block->page.id().page_no(); + const uint32_t page_no = block->page.id().page_no(); if (prev_page_no != FIL_NULL) { buf_block_t* prev_block; @@ -7632,12 +7620,12 @@ btr_free_externally_stored_field( X-latch to the index tree */ { page_t* page; - const ulint space_id = mach_read_from_4( + const uint32_t space_id = mach_read_from_4( field_ref + BTR_EXTERN_SPACE_ID); - const ulint start_page = mach_read_from_4( + const uint32_t start_page = mach_read_from_4( field_ref + BTR_EXTERN_PAGE_NO); - ulint page_no; - ulint next_page_no; + uint32_t page_no; + uint32_t next_page_no; mtr_t mtr; ut_ad(index->is_primary()); @@ -7870,10 +7858,9 @@ btr_copy_blob_prefix( /*=================*/ byte* buf, /*!< out: the externally stored part of the field, or a prefix of it */ - ulint len, /*!< in: length of buf, in bytes */ - ulint space_id,/*!< in: space id of the BLOB pages */ - ulint page_no,/*!< in: page number of the first BLOB page */ - ulint offset) /*!< in: offset on the first BLOB page */ + uint32_t len, /*!< in: length of buf, in bytes */ + page_id_t id, /*!< in: page identifier of the first BLOB page */ + uint32_t offset) /*!< in: offset on the first BLOB page */ { ulint copied_len = 0; @@ -7887,8 +7874,7 @@ btr_copy_blob_prefix( mtr_start(&mtr); - block = buf_page_get(page_id_t(space_id, page_no), - 0, RW_S_LATCH, &mtr); + block = buf_page_get(id, 0, RW_S_LATCH, &mtr); buf_block_dbg_add_level(block, SYNC_EXTERN_STORAGE); page = buf_block_get_frame(block); @@ -7902,11 +7888,11 @@ btr_copy_blob_prefix( blob_header + BTR_BLOB_HDR_SIZE, copy_len); copied_len += copy_len; - page_no = btr_blob_get_next_page_no(blob_header); + id.set_page_no(btr_blob_get_next_page_no(blob_header)); mtr_commit(&mtr); - if (page_no == FIL_NULL || copy_len != part_len) { + if (id.page_no() == FIL_NULL || copy_len != part_len) { MEM_CHECK_DEFINED(buf, copied_len); return(copied_len); } @@ -7927,18 +7913,16 @@ by a lock or a page latch. or a prefix of it @param[in] len length of buf, in bytes @param[in] zip_size ROW_FORMAT=COMPRESSED page size -@param[in] space_id space id of the BLOB pages -@param[in] offset offset on the first BLOB page +@param[in] id page identifier of the BLOB pages @return number of bytes written to buf */ static ulint btr_copy_zblob_prefix( byte* buf, - ulint len, + uint32_t len, ulint zip_size, - ulint space_id, - ulint page_no, - ulint offset) + page_id_t id, + uint32_t offset) { ulint page_type = FIL_PAGE_TYPE_ZBLOB; mem_heap_t* heap; @@ -7957,25 +7941,23 @@ btr_copy_zblob_prefix( ut_ad(zip_size); ut_ad(ut_is_2pow(zip_size)); - ut_ad(space_id); + ut_ad(id.space()); err = inflateInit(&d_stream); ut_a(err == Z_OK); for (;;) { buf_page_t* bpage; - ulint next_page_no; + uint32_t next_page_no; /* There is no latch on bpage directly. Instead, bpage is protected by the B-tree page latch that is being held on the clustered index record, or, in row_merge_copy_blobs(), by an exclusive table lock. */ - bpage = buf_page_get_zip(page_id_t(space_id, page_no), - zip_size); + bpage = buf_page_get_zip(id, zip_size); if (UNIV_UNLIKELY(!bpage)) { - ib::error() << "Cannot load compressed BLOB " - << page_id_t(space_id, page_no); + ib::error() << "Cannot load compressed BLOB " << id; goto func_exit; } @@ -7984,8 +7966,7 @@ btr_copy_zblob_prefix( ib::error() << "Unexpected type " << fil_page_get_type(bpage->zip.data) - << " of compressed BLOB page " - << page_id_t(space_id, page_no); + << " of compressed BLOB page " << id; ut_ad(0); goto end_of_blob; @@ -8020,7 +8001,7 @@ btr_copy_zblob_prefix( default: inflate_error: ib::error() << "inflate() of compressed BLOB page " - << page_id_t(space_id, page_no) + << id << " returned " << err << " (" << d_stream.msg << ")"; @@ -8032,8 +8013,7 @@ inflate_error: if (!d_stream.avail_in) { ib::error() << "Unexpected end of compressed " - << "BLOB page " - << page_id_t(space_id, page_no); + << "BLOB page " << id; } else { err = inflate(&d_stream, Z_FINISH); switch (err) { @@ -8055,7 +8035,7 @@ end_of_blob: /* On other BLOB pages except the first the BLOB header always is at the page header: */ - page_no = next_page_no; + id.set_page_no(next_page_no); offset = FIL_PAGE_NEXT; page_type = FIL_PAGE_TYPE_ZBLOB2; } @@ -8074,31 +8054,24 @@ by a lock or a page latch. field, or a prefix of it @param[in] len length of buf, in bytes @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 -@param[in] space_id space id of the first BLOB page -@param[in] page_no page number of the first BLOB page +@param[in] id page identifier of the first BLOB page @param[in] offset offset on the first BLOB page @return number of bytes written to buf */ static ulint btr_copy_externally_stored_field_prefix_low( byte* buf, - ulint len, + uint32_t len, ulint zip_size, - ulint space_id, - ulint page_no, - ulint offset) + page_id_t id, + uint32_t offset) { - if (len == 0) { - return(0); - } + if (len == 0) + return 0; - if (zip_size) { - return(btr_copy_zblob_prefix(buf, len, zip_size, - space_id, page_no, offset)); - } else { - return(btr_copy_blob_prefix(buf, len, space_id, - page_no, offset)); - } + return zip_size + ? btr_copy_zblob_prefix(buf, len, zip_size, id, offset) + : btr_copy_blob_prefix(buf, len, id, offset); } /** Copies the prefix of an externally stored field of a record. @@ -8120,10 +8093,6 @@ btr_copy_externally_stored_field_prefix( const byte* data, ulint local_len) { - ulint space_id; - ulint page_no; - ulint offset; - ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE); local_len -= BTR_EXTERN_FIELD_REF_SIZE; @@ -8146,17 +8115,18 @@ btr_copy_externally_stored_field_prefix( return(0); } - space_id = mach_read_from_4(data + BTR_EXTERN_SPACE_ID); - - page_no = mach_read_from_4(data + BTR_EXTERN_PAGE_NO); - - offset = mach_read_from_4(data + BTR_EXTERN_OFFSET); + uint32_t space_id = mach_read_from_4(data + BTR_EXTERN_SPACE_ID); + uint32_t page_no = mach_read_from_4(data + BTR_EXTERN_PAGE_NO); + uint32_t offset = mach_read_from_4(data + BTR_EXTERN_OFFSET); + len -= local_len; return(local_len + btr_copy_externally_stored_field_prefix_low(buf + local_len, - len - local_len, + uint32_t(len), zip_size, - space_id, page_no, + page_id_t( + space_id, + page_no), offset)); } @@ -8178,26 +8148,24 @@ btr_copy_externally_stored_field( ulint local_len, mem_heap_t* heap) { - ulint space_id; - ulint page_no; - ulint offset; - ulint extern_len; byte* buf; ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE); local_len -= BTR_EXTERN_FIELD_REF_SIZE; - space_id = mach_read_from_4(data + local_len + BTR_EXTERN_SPACE_ID); - - page_no = mach_read_from_4(data + local_len + BTR_EXTERN_PAGE_NO); - - offset = mach_read_from_4(data + local_len + BTR_EXTERN_OFFSET); + uint32_t space_id = mach_read_from_4(data + local_len + + BTR_EXTERN_SPACE_ID); + uint32_t page_no = mach_read_from_4(data + local_len + + BTR_EXTERN_PAGE_NO); + uint32_t offset = mach_read_from_4(data + local_len + + BTR_EXTERN_OFFSET); /* Currently a BLOB cannot be bigger than 4 GB; we leave the 4 upper bytes in the length field unused */ - extern_len = mach_read_from_4(data + local_len + BTR_EXTERN_LEN + 4); + uint32_t extern_len = mach_read_from_4(data + local_len + + BTR_EXTERN_LEN + 4); buf = (byte*) mem_heap_alloc(heap, local_len + extern_len); @@ -8206,8 +8174,10 @@ btr_copy_externally_stored_field( + btr_copy_externally_stored_field_prefix_low(buf + local_len, extern_len, zip_size, - space_id, - page_no, offset); + page_id_t( + space_id, + page_no), + offset); return(buf); } diff --git a/storage/innobase/btr/btr0defragment.cc b/storage/innobase/btr/btr0defragment.cc index 80d5031d80b..2c4c338ce70 100644 --- a/storage/innobase/btr/btr0defragment.cc +++ b/storage/innobase/btr/btr0defragment.cc @@ -619,7 +619,7 @@ btr_defragment_n_pages( blocks[0] = block; for (uint i = 1; i <= n_pages; i++) { page_t* page = buf_block_get_frame(blocks[i-1]); - ulint page_no = btr_page_get_next(page); + uint32_t page_no = btr_page_get_next(page); total_data_size += page_get_data_size(page); total_n_recs += page_get_n_recs(page); if (page_no == FIL_NULL) { diff --git a/storage/innobase/buf/buf0buddy.cc b/storage/innobase/buf/buf0buddy.cc index a83d0840cb5..b8ed7bb3f36 100644 --- a/storage/innobase/buf/buf0buddy.cc +++ b/storage/innobase/buf/buf0buddy.cc @@ -480,8 +480,6 @@ static bool buf_buddy_relocate(void* src, void* dst, ulint i, bool force) { buf_page_t* bpage; const ulint size = BUF_BUDDY_LOW << i; - ulint space; - ulint offset; mysql_mutex_assert_owner(&buf_pool.mutex); ut_ad(!ut_align_offset(src, size)); @@ -489,10 +487,10 @@ static bool buf_buddy_relocate(void* src, void* dst, ulint i, bool force) ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN)); MEM_CHECK_ADDRESSABLE(dst, size); - space = mach_read_from_4((const byte*) src - + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); - offset = mach_read_from_4((const byte*) src - + FIL_PAGE_OFFSET); + uint32_t space = mach_read_from_4(static_cast(src) + + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + uint32_t offset = mach_read_from_4(static_cast(src) + + FIL_PAGE_OFFSET); /* Suppress Valgrind or MSAN warnings. */ MEM_MAKE_DEFINED(&space, sizeof space); diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 1f3cbb56234..8c296c4f03b 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -719,9 +719,9 @@ static void buf_page_check_lsn(bool check_lsn, const byte* read_buf) phase it makes no sense to spam the log with error messages. */ if (current_lsn < page_lsn) { - const ulint space_id = mach_read_from_4( + const uint32_t space_id = mach_read_from_4( read_buf + FIL_PAGE_SPACE_ID); - const ulint page_no = mach_read_from_4( + const uint32_t page_no = mach_read_from_4( read_buf + FIL_PAGE_OFFSET); ib::error() << "Page " << page_id_t(space_id, page_no) diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index d9faf2ffe06..ad515e4e194 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -125,7 +125,7 @@ too_small: byte *fseg_header= TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG + trx_sys_block->frame; - for (ulint prev_page_no= 0, i= 0; i < 2 * size + FSP_EXTENT_SIZE / 2; i++) + for (uint32_t prev_page_no= 0, i= 0; i < 2 * size + FSP_EXTENT_SIZE / 2; i++) { buf_block_t *new_block= fseg_alloc_free_page(fseg_header, prev_page_no + 1, FSP_UP, &mtr); @@ -335,7 +335,7 @@ void buf_dblwr_t::recover() if (!is_initialised()) return; - ulint page_no_dblwr= 0; + uint32_t page_no_dblwr= 0; byte *read_buf= static_cast(aligned_malloc(3 * srv_page_size, srv_page_size)); byte *const buf= read_buf + srv_page_size; @@ -344,7 +344,7 @@ void buf_dblwr_t::recover() i != recv_sys.dblwr.pages.end(); ++i, ++page_no_dblwr) { byte *page= *i; - const ulint page_no= page_get_page_no(page); + const uint32_t page_no= page_get_page_no(page); if (!page_no) /* recovered via Datafile::restore_from_doublewrite() */ continue; diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc index 01b523d6e94..ee9be7e47d2 100644 --- a/storage/innobase/buf/buf0dump.cc +++ b/storage/innobase/buf/buf0dump.cc @@ -489,8 +489,8 @@ buf_load() page_id_t* dump; ulint dump_n; ulint i; - ulint space_id; - ulint page_no; + uint32_t space_id; + uint32_t page_no; int fscanf_ret; /* Ignore any leftovers from before */ @@ -514,7 +514,7 @@ buf_load() This file is tiny (approx 500KB per 1GB buffer pool), reading it two times is fine. */ dump_n = 0; - while (fscanf(f, ULINTPF "," ULINTPF, &space_id, &page_no) == 2 + while (fscanf(f, "%u,%u", &space_id, &page_no) == 2 && !SHUTTING_DOWN()) { dump_n++; } @@ -565,8 +565,7 @@ buf_load() export_vars.innodb_buffer_pool_load_incomplete = 1; for (i = 0; i < dump_n && !SHUTTING_DOWN(); i++) { - fscanf_ret = fscanf(f, ULINTPF "," ULINTPF, - &space_id, &page_no); + fscanf_ret = fscanf(f, "%u,%u", &space_id, &page_no); if (fscanf_ret != 2) { if (feof(f)) { @@ -588,9 +587,8 @@ buf_load() fclose(f); buf_load_status(STATUS_ERR, "Error parsing '%s': bogus" - " space,page " ULINTPF "," ULINTPF - " at line " ULINTPF "," - " unable to load buffer pool", + " space,page %u,%u at line " ULINTPF + ", unable to load buffer pool", full_filename, space_id, page_no, i); diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index d843865d0a9..f4207ff393e 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -411,8 +411,7 @@ buf_read_ahead_random(const page_id_t page_id, ulint zip_size, bool ibuf) ulint count= 5 + buf_read_ahead_area / 8; const page_id_t low= page_id - (page_id.page_no() % buf_read_ahead_area); page_id_t high= low + buf_read_ahead_area; - high.set_page_no(std::min(high.page_no(), - static_cast(space->committed_size - 1))); + high.set_page_no(std::min(high.page_no(), space->committed_size - 1)); /* Count how many blocks in the area have been recently accessed, that is, reside near the start of the LRU list. */ @@ -723,13 +722,9 @@ for the highest address page to get read in, before this function returns @param[in] space_id tablespace id @param[in] page_nos array of page numbers to read, with the highest page number the last in the array -@param[in] n_stored number of page numbers in the array */ -void -buf_read_recv_pages( - bool sync, - ulint space_id, - const ulint* page_nos, - ulint n_stored) +@param[in] n number of page numbers in the array */ +void buf_read_recv_pages(bool sync, ulint space_id, const uint32_t *page_nos, + ulint n) { fil_space_t* space = fil_space_get(space_id); @@ -742,11 +737,10 @@ buf_read_recv_pages( const ulint zip_size = space->zip_size(); - for (ulint i = 0; i < n_stored; i++) { + for (ulint i = 0; i < n; i++) { /* Ignore if the page already present in freed ranges. */ - if (space->freed_ranges.contains( - static_cast(page_nos[i]))) { + if (space->freed_ranges.contains(page_nos[i])) { continue; } @@ -772,7 +766,7 @@ buf_read_recv_pages( dberr_t err; buf_read_page_low( - &err, sync && i + 1 == n_stored, + &err, sync && i + 1 == n, BUF_READ_ANY_PAGE, cur_page_id, zip_size, true); if (err == DB_DECRYPTION_FAILED || err == DB_PAGE_CORRUPTED) { @@ -781,6 +775,5 @@ buf_read_recv_pages( } } - DBUG_PRINT("ib_buf", ("recovery read-ahead (%u pages)", - unsigned(n_stored))); + DBUG_PRINT("ib_buf", ("recovery read-ahead (%u pages)", n)); } diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 131df87b383..5587355f23a 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -1122,7 +1122,7 @@ struct rotate_thread_t { uint thread_no; bool first; /*!< is position before first space */ fil_space_t* space; /*!< current space or NULL */ - ulint offset; /*!< current offset */ + uint32_t offset; /*!< current page number */ ulint batch; /*!< #pages to rotate */ uint min_key_version_found;/*!< min key version found but not rotated */ lsn_t end_lsn; /*!< max lsn when rotating this space */ @@ -1694,7 +1694,7 @@ fil_crypt_find_page_to_rotate( } } - crypt_data->rotate_state.next_offset += batch; + crypt_data->rotate_state.next_offset += uint32_t(batch); mutex_exit(&crypt_data->mutex); return found; } @@ -1716,7 +1716,7 @@ static buf_block_t* fil_crypt_get_page_throttle_func( rotate_thread_t* state, - ulint offset, + uint32_t offset, mtr_t* mtr, ulint* sleeptime_ms, const char* file, @@ -1792,7 +1792,7 @@ fil_crypt_rotate_page( { fil_space_t*space = state->space; ulint space_id = space->id; - ulint offset = state->offset; + uint32_t offset = state->offset; ulint sleeptime_ms = 0; fil_space_crypt_t *crypt_data = space->crypt_data; @@ -1916,9 +1916,9 @@ fil_crypt_rotate_pages( const key_state_t* key_state, rotate_thread_t* state) { - ulint space = state->space->id; - ulint end = std::min(state->offset + state->batch, - state->space->free_limit); + ulint space_id = state->space->id; + uint32_t end = std::min(state->offset + uint32_t(state->batch), + state->space->free_limit); ut_ad(state->space->referenced()); @@ -1932,7 +1932,7 @@ fil_crypt_rotate_pages( * real pages, they will be updated anyway when the * real page is updated */ - if (buf_dblwr.is_inside(page_id_t(space, state->offset))) { + if (buf_dblwr.is_inside(page_id_t(space_id, state->offset))) { continue; } diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 93047391aa2..7662a4b643c 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -354,8 +354,8 @@ static bool fil_comp_algo_validate(const fil_space_t* space) or ULINT_MAX for unlimited @return file object */ fil_node_t* fil_space_t::add(const char* name, pfs_os_file_t handle, - ulint size, bool is_raw, bool atomic_write, - ulint max_pages) + uint32_t size, bool is_raw, bool atomic_write, + uint32_t max_pages) { fil_node_t* node; @@ -668,7 +668,7 @@ bool fil_space_extend_must_retry( fil_space_t* space, fil_node_t* node, - ulint size, + uint32_t size, bool* success) { ut_ad(mutex_own(&fil_system.mutex)); @@ -707,10 +707,10 @@ fil_space_extend_must_retry( ut_ad(size >= space->size); - ulint last_page_no = space->size; - const ulint file_start_page_no = last_page_no - node->size; + uint32_t last_page_no = space->size; + const uint32_t file_start_page_no = last_page_no - node->size; - const ulint page_size = space->physical_size(); + const unsigned page_size = space->physical_size(); /* Datafile::read_first_page() expects srv_page_size bytes. fil_node_t::read_page0() expects at least 4 * srv_page_size bytes.*/ @@ -732,7 +732,7 @@ fil_space_extend_must_retry( os_offset_t fsize = os_file_get_size(node->handle); ut_a(fsize != os_offset_t(-1)); - last_page_no = ulint(fsize / page_size) + last_page_no = uint32_t(fsize / page_size) + file_start_page_no; } mutex_enter(&fil_system.mutex); @@ -741,11 +741,11 @@ fil_space_extend_must_retry( node->being_extended = false; ut_a(last_page_no - file_start_page_no >= node->size); - ulint file_size = last_page_no - file_start_page_no; + uint32_t file_size = last_page_no - file_start_page_no; space->size += file_size - node->size; node->size = file_size; - const ulint pages_in_MiB = node->size - & ~ulint((1U << (20U - srv_page_size_shift)) - 1); + const uint32_t pages_in_MiB = node->size + & ~uint32_t((1U << (20U - srv_page_size_shift)) - 1); node->complete_io(); @@ -832,7 +832,7 @@ fil_mutex_enter_and_prepare_for_io( } } - ulint size = space->recv_size; + uint32_t size = space->recv_size; if (UNIV_UNLIKELY(size != 0)) { ut_ad(node); bool success; @@ -877,10 +877,7 @@ fil_mutex_enter_and_prepare_for_io( @param[in,out] space tablespace @param[in] size desired size in pages @return whether the tablespace is at least as big as requested */ -bool -fil_space_extend( - fil_space_t* space, - ulint size) +bool fil_space_extend(fil_space_t *space, uint32_t size) { ut_ad(!srv_read_only_mode || space->purpose == FIL_TYPE_TEMPORARY); @@ -1305,7 +1302,7 @@ fil_space_get_space( return(space); } -void fil_space_set_recv_size_and_flags(ulint id, ulint size, uint32_t flags) +void fil_space_set_recv_size_and_flags(ulint id, uint32_t size, uint32_t flags) { ut_ad(id < SRV_SPACE_ID_UPPER_BOUND); mutex_enter(&fil_system.mutex); @@ -2589,7 +2586,7 @@ fil_ibd_create( const char* name, const char* path, ulint flags, - ulint size, + uint32_t size, fil_encryption_t mode, uint32_t key_id, dberr_t* err) @@ -3554,7 +3551,7 @@ void fsp_flags_try_adjust(fil_space_t* space, ulint flags) if (buf_block_t* b = buf_page_get( page_id_t(space->id, 0), space->zip_size(), RW_X_LATCH, &mtr)) { - ulint f = fsp_header_get_flags(b->frame); + uint32_t f = fsp_header_get_flags(b->frame); if (fil_space_t::full_crc32(f)) { goto func_exit; } diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index fedade4366f..beebb85c86b 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -45,7 +45,7 @@ Created 11/29/1995 Heikki Tuuri // JAN: MySQL 5.7 Encryption // #include -typedef ulint page_no_t; +typedef uint32_t page_no_t; /** Return an extent to the free list of a space. @param[in,out] space tablespace @@ -111,7 +111,7 @@ fseg_alloc_free_page_low( fil_space_t* space, fseg_inode_t* seg_inode, buf_block_t* iblock, - ulint hint, + uint32_t hint, byte direction, #ifdef UNIV_DEBUG bool has_done_reservation, @@ -169,28 +169,29 @@ Find a free page. @param descr extent descriptor @param hint page offset to start searching from (towards larger pages) @return free page offset -@retval ULINT_UNDEFINED if no page is free */ -inline ulint xdes_find_free(const xdes_t *descr, ulint hint= 0) +@retval FIL_NULL if no page is free */ +inline uint32_t xdes_find_free(const xdes_t *descr, uint32_t hint= 0) { - ut_ad(hint < FSP_EXTENT_SIZE); - for (ulint i= hint; i < FSP_EXTENT_SIZE; i++) + const uint32_t extent_size= FSP_EXTENT_SIZE; + ut_ad(hint < extent_size); + for (uint32_t i= hint; i < extent_size; i++) if (xdes_is_free(descr, i)) return i; - for (ulint i= 0; i < hint; i++) + for (uint32_t i= 0; i < hint; i++) if (xdes_is_free(descr, i)) return i; - return ULINT_UNDEFINED; + return FIL_NULL; } /** Determine the number of used pages in a descriptor. @param descr file descriptor @return number of pages used */ -inline ulint xdes_get_n_used(const xdes_t *descr) +inline uint32_t xdes_get_n_used(const xdes_t *descr) { - ulint count= 0; + uint32_t count= 0; - for (ulint i= 0; i < FSP_EXTENT_SIZE; ++i) + for (uint32_t i= FSP_EXTENT_SIZE; i--; ) if (!xdes_is_free(descr, i)) count++; @@ -317,16 +318,14 @@ xdes_get_descriptor_with_space_hdr( mtr_t* mtr, bool init_space = false) { - ulint limit; - ulint size; - ulint descr_page_no; ut_ad(mtr->memo_contains(*space)); ut_ad(mtr->memo_contains_flagged(header, MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX)); /* Read free limit and space size */ - limit = mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT - + header->frame); - size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE + header->frame); + uint32_t limit = mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT + + header->frame); + uint32_t size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE + + header->frame); ut_ad(limit == space->free_limit || (space->free_limit == 0 && (init_space @@ -340,9 +339,9 @@ xdes_get_descriptor_with_space_hdr( return(NULL); } - const ulint zip_size = space->zip_size(); + const unsigned zip_size = space->zip_size(); - descr_page_no = xdes_calc_descriptor_page(zip_size, offset); + uint32_t descr_page_no = xdes_calc_descriptor_page(zip_size, offset); buf_block_t* block = header; @@ -455,17 +454,12 @@ xdes_lst_get_descriptor( /********************************************************************//** Returns page offset of the first page in extent described by a descriptor. @return offset of the first page in extent */ -UNIV_INLINE -ulint -xdes_get_offset( -/*============*/ - const xdes_t* descr) /*!< in: extent descriptor */ +static uint32_t xdes_get_offset(const xdes_t *descr) { - ut_ad(descr); - - return(page_get_page_no(page_align(descr)) - + ((page_offset(descr) - XDES_ARR_OFFSET) / XDES_SIZE) - * FSP_EXTENT_SIZE); + ut_ad(descr); + return page_get_page_no(page_align(descr)) + + uint32_t(((page_offset(descr) - XDES_ARR_OFFSET) / XDES_SIZE) * + FSP_EXTENT_SIZE); } /** Initialize a file page whose prior contents should be ignored. @@ -548,7 +542,7 @@ fsp_header_init_fields( @param[in,out] space tablespace @param[in] size current size in blocks @param[in,out] mtr mini-transaction */ -void fsp_header_init(fil_space_t* space, ulint size, mtr_t* mtr) +void fsp_header_init(fil_space_t* space, uint32_t size, mtr_t* mtr) { const page_id_t page_id(space->id, 0); const ulint zip_size = space->zip_size(); @@ -627,7 +621,7 @@ static ATTRIBUTE_COLD __attribute__((warn_unused_result)) bool fsp_try_extend_data_file_with_pages( fil_space_t* space, - ulint page_no, + uint32_t page_no, buf_block_t* header, mtr_t* mtr) { @@ -658,9 +652,9 @@ fsp_try_extend_data_file_with_pages( /** Calculate the number of physical pages in an extent for this file. @param[in] physical_size page_size of the datafile @return number of pages in an extent for this file */ -inline ulint fsp_get_extent_size_in_pages(ulint physical_size) +inline uint32_t fsp_get_extent_size_in_pages(ulint physical_size) { - return (FSP_EXTENT_SIZE << srv_page_size_shift) / physical_size; + return uint32_t((FSP_EXTENT_SIZE << srv_page_size_shift) / physical_size); } @@ -676,12 +670,13 @@ on one extent descriptor page. See xdes_calc_descriptor_page(). @param[in] physical_size page size in data file @param[in] size current number of pages in the datafile @return number of pages to extend the file. */ -static ulint fsp_get_pages_to_extend_ibd(ulint physical_size, ulint size) +static uint32_t fsp_get_pages_to_extend_ibd(unsigned physical_size, + uint32_t size) { - ulint extent_size = fsp_get_extent_size_in_pages(physical_size); + uint32_t extent_size = fsp_get_extent_size_in_pages(physical_size); /* The threshold is set at 32MiB except when the physical page size is small enough that it must be done sooner. */ - ulint threshold = std::min(32 * extent_size, physical_size); + uint32_t threshold = std::min(32 * extent_size, physical_size); if (size >= threshold) { /* Below in fsp_fill_free_list() we assume @@ -704,8 +699,6 @@ static ulint fsp_try_extend_data_file(fil_space_t *space, buf_block_t *header, mtr_t *mtr) { - ulint size; /* current number of pages in the datafile */ - ulint size_increase; /* number of pages to extend this file */ const char* OUT_OF_SPACE_MSG = "ran out of space. Please add another file or use" " 'autoextend' for the last file in setting"; @@ -742,10 +735,12 @@ fsp_try_extend_data_file(fil_space_t *space, buf_block_t *header, mtr_t *mtr) return(0); } - size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE + header->frame); + uint32_t size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE + + header->frame); ut_ad(size == space->size_in_header); + uint32_t size_increase; - const ulint ps = space->physical_size(); + const unsigned ps = space->physical_size(); switch (space->id) { case TRX_SYS_SPACE: @@ -755,7 +750,7 @@ fsp_try_extend_data_file(fil_space_t *space, buf_block_t *header, mtr_t *mtr) size_increase = srv_tmp_space.get_increment(); break; default: - ulint extent_pages = fsp_get_extent_size_in_pages(ps); + uint32_t extent_pages = fsp_get_extent_size_in_pages(ps); if (size < extent_pages) { /* Let us first extend the file to extent_size */ if (!fsp_try_extend_data_file_with_pages( @@ -825,18 +820,13 @@ fsp_fill_free_list( buf_block_t* header, mtr_t* mtr) { - ulint limit; - ulint size; - xdes_t* descr; - ulint count = 0; - ulint i; - ut_d(space->modify_check(*mtr)); /* Check if we can fill free list from above the free list limit */ - size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE + header->frame); - limit = mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT - + header->frame); + uint32_t size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE + + header->frame); + uint32_t limit = mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT + + header->frame); ut_ad(size == space->size_in_header); ut_ad(limit == space->free_limit); @@ -860,17 +850,18 @@ fsp_fill_free_list( } } - i = limit; + uint32_t count = 0; - while ((init_space && i < 1) - || ((i + FSP_EXTENT_SIZE <= size) && (count < FSP_FREE_ADD))) { + for (uint32_t i = limit, extent_size = FSP_EXTENT_SIZE, + physical_size = space->physical_size(); + (init_space && i < 1) + || (i + extent_size <= size && count < FSP_FREE_ADD); + i += extent_size) { + const bool init_xdes = !ut_2pow_remainder(i, physical_size); - const bool init_xdes = 0 - == ut_2pow_remainder(i, ulint(space->physical_size())); - - space->free_limit = i + FSP_EXTENT_SIZE; + space->free_limit = i + extent_size; mtr->write<4>(*header, FSP_HEADER_OFFSET + FSP_FREE_LIMIT - + header->frame, i + FSP_EXTENT_SIZE); + + header->frame, i + extent_size); if (init_xdes) { @@ -914,7 +905,7 @@ fsp_fill_free_list( } buf_block_t* xdes; - descr = xdes_get_descriptor_with_space_hdr( + xdes_t* descr = xdes_get_descriptor_with_space_hdr( header, space, i, &xdes, mtr, init_space); if (xdes != header && !space->full_crc32()) { fil_block_check_type(*xdes, FIL_PAGE_TYPE_XDES, mtr); @@ -946,8 +937,6 @@ fsp_fill_free_list( xdes, xoffset, mtr); count++; } - - i += FSP_EXTENT_SIZE; } space->free_len += count; @@ -964,7 +953,7 @@ static xdes_t* fsp_alloc_free_extent( fil_space_t* space, - ulint hint, + uint32_t hint, buf_block_t** xdes, mtr_t* mtr) { @@ -1076,13 +1065,12 @@ static MY_ATTRIBUTE((warn_unused_result, nonnull)) buf_block_t* fsp_alloc_free_page( fil_space_t* space, - ulint hint, + uint32_t hint, mtr_t* mtr, mtr_t* init_mtr) { fil_addr_t first; xdes_t* descr; - ulint free; const ulint space_id = space->id; ut_d(space->modify_check(*mtr)); @@ -1133,8 +1121,8 @@ fsp_alloc_free_page( /* Now we have in descr an extent with at least one free page. Look for a free page in the extent. */ - free = xdes_find_free(descr, hint % FSP_EXTENT_SIZE); - if (free == ULINT_UNDEFINED) { + uint32_t free = xdes_find_free(descr, hint % FSP_EXTENT_SIZE); + if (free == FIL_NULL) { ut_print_buf(stderr, ((byte*) descr) - 500, 1000); putc('\n', stderr); @@ -1142,10 +1130,10 @@ fsp_alloc_free_page( ut_error; } - page_no_t page_no = xdes_get_offset(descr) + free; + uint32_t page_no = xdes_get_offset(descr) + free; - page_no_t space_size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE - + block->frame); + uint32_t space_size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE + + block->frame); ut_ad(space_size == space->size_in_header || (space_id == TRX_SYS_SPACE && srv_startup_is_before_trx_rollback_phase)); @@ -1545,7 +1533,7 @@ fseg_inode_get( @param n slot index @return page number @retval FIL_NULL if not in use */ -static ulint fseg_get_nth_frag_page_no(const fseg_inode_t *inode, ulint n) +static uint32_t fseg_get_nth_frag_page_no(const fseg_inode_t *inode, ulint n) { ut_ad(inode); ut_ad(n < FSEG_FRAG_ARR_N_SLOTS); @@ -1808,7 +1796,7 @@ fseg_fill_free_list( fseg_inode_t* inode, buf_block_t* iblock, fil_space_t* space, - ulint hint, + uint32_t hint, mtr_t* mtr) { xdes_t* descr; @@ -1945,7 +1933,7 @@ fseg_alloc_free_page_low( fil_space_t* space, fseg_inode_t* seg_inode, buf_block_t* iblock, - ulint hint, + uint32_t hint, byte direction, #ifdef UNIV_DEBUG bool has_done_reservation, @@ -1958,7 +1946,7 @@ fseg_alloc_free_page_low( ulint used; ulint reserved; xdes_t* descr; /*!< extent of the hinted page */ - ulint ret_page; /*!< the allocated page offset, FIL_NULL + uint32_t ret_page; /*!< the allocated page offset, FIL_NULL if could not be allocated */ xdes_t* ret_descr; /*!< the extent of the allocated page */ buf_block_t* xdes; @@ -2060,9 +2048,12 @@ take_hinted_page: segment) ========*/ ret_descr = descr; - ret_page = xdes_get_offset(ret_descr) - + xdes_find_free(ret_descr, hint % FSP_EXTENT_SIZE); - ut_ad(!has_done_reservation || ret_page != FIL_NULL); + ret_page = xdes_find_free(ret_descr, hint % FSP_EXTENT_SIZE); + if (ret_page == FIL_NULL) { + ut_ad(!has_done_reservation); + } else { + ret_page += xdes_get_offset(ret_descr); + } /*-----------------------------------------------------------*/ } else if (reserved - used > 0) { /* 5. We take any unused page from the segment @@ -2079,9 +2070,12 @@ take_hinted_page: } ret_descr = xdes_lst_get_descriptor(space, first, &xdes, mtr); - ret_page = xdes_get_offset(ret_descr) - + xdes_find_free(ret_descr); - ut_ad(!has_done_reservation || ret_page != FIL_NULL); + ret_page = xdes_find_free(ret_descr); + if (ret_page == FIL_NULL) { + ut_ad(!has_done_reservation); + } else { + ret_page += xdes_get_offset(ret_descr); + } /*-----------------------------------------------------------*/ } else if (used < FSEG_FRAG_LIMIT) { /* 6. We allocate an individual page from the space @@ -2180,7 +2174,7 @@ buf_block_t* fseg_alloc_free_page_general( /*=========================*/ fseg_header_t* seg_header,/*!< in/out: segment header */ - ulint hint, /*!< in: hint of which page would be + uint32_t hint, /*!< in: hint of which page would be desirable */ byte direction,/*!< in: if the new page is needed because of an index page split, and records are @@ -2254,10 +2248,9 @@ fsp_reserve_free_pages( buf_block_t* header, ulint size, mtr_t* mtr, - ulint n_pages) + uint32_t n_pages) { xdes_t* descr; - ulint n_used; ut_a(!is_system_tablespace(space->id)); ut_a(size < FSP_EXTENT_SIZE); @@ -2265,7 +2258,7 @@ fsp_reserve_free_pages( buf_block_t* xdes; descr = xdes_get_descriptor_with_space_hdr(header, space, 0, &xdes, mtr); - n_used = xdes_get_n_used(descr); + uint32_t n_used = xdes_get_n_used(descr); ut_a(n_used <= size); @@ -2319,7 +2312,7 @@ fsp_reserve_free_extents( ulint n_ext, fsp_reserve_t alloc_type, mtr_t* mtr, - ulint n_pages) + uint32_t n_pages) { ulint n_free_list_ext; ulint free_limit; @@ -2537,7 +2530,7 @@ void fseg_free_page( fseg_header_t* seg_header, fil_space_t* space, - ulint offset, + uint32_t offset, mtr_t* mtr) { DBUG_ENTER("fseg_free_page"); @@ -2600,7 +2593,7 @@ fseg_free_extent( fseg_inode_t* seg_inode, buf_block_t* iblock, fil_space_t* space, - ulint page, + uint32_t page, mtr_t* mtr) { @@ -2614,7 +2607,7 @@ fseg_free_extent( ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); ut_d(space->modify_check(*mtr)); - const ulint first_page_in_extent = page - (page % FSP_EXTENT_SIZE); + const uint32_t first_page_in_extent = page - (page % FSP_EXTENT_SIZE); const uint16_t xoffset= uint16_t(descr - xdes->frame + XDES_FLST_NODE); const uint16_t ioffset= uint16_t(seg_inode - iblock->frame); @@ -2629,9 +2622,9 @@ fseg_free_extent( flst_remove(iblock, static_cast(FSEG_NOT_FULL + ioffset), xdes, xoffset, mtr); - ulint not_full_n_used = mach_read_from_4( + uint32_t not_full_n_used = mach_read_from_4( FSEG_NOT_FULL_N_USED + seg_inode); - ulint descr_n_used = xdes_get_n_used(descr); + uint32_t descr_n_used = xdes_get_n_used(descr); ut_a(not_full_n_used >= descr_n_used); mtr->write<4>(*iblock, seg_inode + FSEG_NOT_FULL_N_USED, not_full_n_used - descr_n_used); @@ -2663,15 +2656,12 @@ fseg_free_step( mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint n; - ulint page; fseg_inode_t* inode; - ulint space_id; - ulint header_page; DBUG_ENTER("fseg_free_step"); - space_id = page_get_space_id(page_align(header)); - header_page = page_get_page_no(page_align(header)); + const uint32_t space_id = page_get_space_id(page_align(header)); + const uint32_t header_page = page_get_page_no(page_align(header)); fil_space_t* space = mtr_x_lock_space(space_id, mtr); buf_block_t* xdes; @@ -2698,8 +2688,8 @@ fseg_free_step( if (descr != NULL) { /* Free the extent held by the segment */ - page = xdes_get_offset(descr); - fseg_free_extent(inode, iblock, space, page, mtr); + fseg_free_extent(inode, iblock, space, xdes_get_offset(descr), + mtr); DBUG_RETURN(false); } @@ -2741,13 +2731,10 @@ fseg_free_step_not_header( mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint n; - ulint page; xdes_t* descr; fseg_inode_t* inode; - ulint space_id; - ulint page_no; - space_id = page_get_space_id(page_align(header)); + const uint32_t space_id = page_get_space_id(page_align(header)); ut_ad(mtr->is_named_space(space_id)); fil_space_t* space = mtr_x_lock_space(space_id, mtr); @@ -2763,8 +2750,8 @@ fseg_free_step_not_header( if (descr != NULL) { /* Free the extent held by the segment */ - page = xdes_get_offset(descr); - fseg_free_extent(inode, iblock, space, page, mtr); + fseg_free_extent(inode, iblock, space, xdes_get_offset(descr), + mtr); return false; } @@ -2774,7 +2761,7 @@ fseg_free_step_not_header( ut_a(n != ULINT_UNDEFINED); - page_no = fseg_get_nth_frag_page_no(inode, n); + uint32_t page_no = fseg_get_nth_frag_page_no(inode, n); if (page_no == page_get_page_no(page_align(header))) { return true; diff --git a/storage/innobase/fsp/fsp0sysspace.cc b/storage/innobase/fsp/fsp0sysspace.cc index 2e4b3678760..f8342157560 100644 --- a/storage/innobase/fsp/fsp0sysspace.cc +++ b/storage/innobase/fsp/fsp0sysspace.cc @@ -47,7 +47,7 @@ SysTablespace srv_tmp_space; /** If the last data file is auto-extended, we add this many pages to it at a time. We have to make this public because it is a config variable. */ -ulong sys_tablespace_auto_extend_increment; +uint sys_tablespace_auto_extend_increment; /** Convert a numeric string that optionally ends in G or M or K, to a number containing megabytes. @@ -275,7 +275,8 @@ SysTablespace::parse_params( } } - m_files.push_back(Datafile(filepath, flags(), size, order)); + m_files.push_back(Datafile(filepath, flags(), uint32_t(size), + order)); Datafile* datafile = &m_files.back(); datafile->make_filepath(path(), filepath, NO_EXT); @@ -351,7 +352,7 @@ SysTablespace::check_size( also the data file could contain an incomplete extent. So we need to round the size downward to a megabyte.*/ - const ulint rounded_size_pages = static_cast( + const uint32_t rounded_size_pages = static_cast( size >> srv_page_size_shift); /* If last file */ @@ -904,7 +905,6 @@ SysTablespace::open_or_create( if (it != begin) { } else if (is_temp) { - ut_ad(!fil_system.temp_space); ut_ad(space_id() == SRV_TMP_SPACE_ID); space = fil_space_create( name(), SRV_TMP_SPACE_ID, flags(), @@ -919,12 +919,10 @@ SysTablespace::open_or_create( ut_ad(!space->is_compressed()); ut_ad(space->full_crc32()); } else { - ut_ad(!fil_system.sys_space); ut_ad(space_id() == TRX_SYS_SPACE); space = fil_space_create( name(), TRX_SYS_SPACE, it->flags(), FIL_TYPE_TABLESPACE, NULL); - mutex_enter(&fil_system.mutex); fil_system.sys_space = space; mutex_exit(&fil_system.mutex); @@ -935,10 +933,10 @@ SysTablespace::open_or_create( ut_a(fil_validate()); - ulint max_size = (++node_counter == m_files.size() + uint32_t max_size = (++node_counter == m_files.size() ? (m_last_file_size_max == 0 - ? ULINT_MAX - : m_last_file_size_max) + ? UINT32_MAX + : uint32_t(m_last_file_size_max)) : it->m_size); space->add(it->m_filepath, OS_FILE_CLOSED, it->m_size, @@ -965,30 +963,21 @@ SysTablespace::normalize_size() /** @return next increment size */ -ulint -SysTablespace::get_increment() const +uint32_t SysTablespace::get_increment() const { - ulint increment; + if (m_last_file_size_max == 0) + return get_autoextend_increment(); - if (m_last_file_size_max == 0) { - increment = get_autoextend_increment(); - } else { + if (!is_valid_size()) + { + ib::error() << "The last data file in " << name() + << " has a size of " << last_file_size() + << " but the max size allowed is " + << m_last_file_size_max; + } - if (!is_valid_size()) { - ib::error() << "The last data file in " << name() - << " has a size of " << last_file_size() - << " but the max size allowed is " - << m_last_file_size_max; - } - - increment = m_last_file_size_max - last_file_size(); - } - - if (increment > get_autoextend_increment()) { - increment = get_autoextend_increment(); - } - - return(increment); + return std::min(uint32_t(m_last_file_size_max) - last_file_size(), + get_autoextend_increment()); } diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc index 21783a94e9c..0a0d4242c00 100644 --- a/storage/innobase/gis/gis0sea.cc +++ b/storage/innobase/gis/gis0sea.cc @@ -1323,8 +1323,8 @@ rtr_cur_restore_position( page_cur_t* page_cursor; node_visit_t* node = rtr_get_parent_node(btr_cur, level, false); node_seq_t path_ssn = node->seq_no; - const ulint zip_size = index->table->space->zip_size(); - ulint page_no = node->page_no; + const unsigned zip_size = index->table->space->zip_size(); + uint32_t page_no = node->page_no; heap = mem_heap_create(256); @@ -1484,14 +1484,13 @@ rtr_non_leaf_insert_stack_push( dict_index_t* index, /*!< in: index descriptor */ rtr_node_path_t* path, /*!< in/out: search path */ ulint level, /*!< in: index page level */ - ulint child_no,/*!< in: child page no */ + uint32_t child_no,/*!< in: child page no */ const buf_block_t* block, /*!< in: block of the page */ const rec_t* rec, /*!< in: positioned record */ double mbr_inc)/*!< in: MBR needs to be enlarged */ { node_seq_t new_seq; btr_pcur_t* my_cursor; - ulint page_no = block->page.id().page_no(); my_cursor = static_cast( ut_malloc_nokey(sizeof(*my_cursor))); @@ -1503,8 +1502,8 @@ rtr_non_leaf_insert_stack_push( (btr_pcur_get_btr_cur(my_cursor))->index = index; new_seq = rtr_get_current_ssn_id(index); - rtr_non_leaf_stack_push(path, page_no, new_seq, level, child_no, - my_cursor, mbr_inc); + rtr_non_leaf_stack_push(path, block->page.id().page_no(), + new_seq, level, child_no, my_cursor, mbr_inc); } /** Copy a buf_block_t, except "block->lock". @@ -1827,7 +1826,7 @@ rtr_cur_search_with_match( rtr_info->matches for leaf nodes */ if (rtr_info && mode != PAGE_CUR_RTREE_INSERT) { if (!is_leaf) { - ulint page_no; + uint32_t page_no; node_seq_t new_seq; bool is_loc; @@ -1919,12 +1918,11 @@ rtr_cur_search_with_match( then we select the record that result in least increased area */ if (mode == PAGE_CUR_RTREE_INSERT) { - ulint child_no; ut_ad(least_inc < DBL_MAX); offsets = rec_get_offsets( best_rec, index, offsets, false, ULINT_UNDEFINED, &heap); - child_no = + uint32_t child_no = btr_node_ptr_get_child_page_no( best_rec, offsets); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index dcfd402de0c..546957f8800 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -17452,20 +17452,8 @@ innodb_change_buffer_max_size_update(THD*, st_mysql_sys_var*, void*, } #ifdef UNIV_DEBUG -static ulong srv_fil_make_page_dirty_debug = 0; -static ulong srv_saved_page_number_debug = 0; - -/****************************************************************//** -Save an InnoDB page number. */ -static -void -innodb_save_page_no(THD*, st_mysql_sys_var*, void*, const void* save) -{ - srv_saved_page_number_debug = *static_cast(save); - - ib::info() << "Saving InnoDB page number: " - << srv_saved_page_number_debug; -} +static uint srv_fil_make_page_dirty_debug = 0; +static uint srv_saved_page_number_debug; /****************************************************************//** Make the first page of given user tablespace dirty. */ @@ -17474,7 +17462,7 @@ void innodb_make_page_dirty(THD*, st_mysql_sys_var*, void*, const void* save) { mtr_t mtr; - ulong space_id = *static_cast(save); + uint space_id = *static_cast(save); mysql_mutex_unlock(&LOCK_global_system_variables); fil_space_t* space = fil_space_acquire_silent(space_id); @@ -19195,11 +19183,11 @@ static MYSQL_SYSVAR_BOOL(log_optimize_ddl, deprecated::innodb_log_optimize_ddl, PLUGIN_VAR_OPCMDARG, innodb_deprecated_ignored, NULL, innodb_log_optimize_ddl_warn, FALSE); -static MYSQL_SYSVAR_ULONG(autoextend_increment, +static MYSQL_SYSVAR_UINT(autoextend_increment, sys_tablespace_auto_extend_increment, PLUGIN_VAR_RQCMDARG, "Data file autoextend increment in megabytes", - NULL, NULL, 64L, 1L, 1000L, 0); + NULL, NULL, 64, 1, 1000, 0); /** Validate the requested buffer pool size. Also, reserve the necessary memory needed for buffer pool resize. @@ -19808,15 +19796,15 @@ static MYSQL_SYSVAR_UINT(data_file_size_debug, "InnoDB system tablespace size to be set in recovery.", NULL, NULL, 0, 0, 256U << 20, 0); -static MYSQL_SYSVAR_ULONG(fil_make_page_dirty_debug, +static MYSQL_SYSVAR_UINT(fil_make_page_dirty_debug, srv_fil_make_page_dirty_debug, PLUGIN_VAR_OPCMDARG, "Make the first page of the given tablespace dirty.", NULL, innodb_make_page_dirty, 0, 0, UINT_MAX32, 0); -static MYSQL_SYSVAR_ULONG(saved_page_number_debug, +static MYSQL_SYSVAR_UINT(saved_page_number_debug, srv_saved_page_number_debug, PLUGIN_VAR_OPCMDARG, "An InnoDB page number.", - NULL, innodb_save_page_no, 0, 0, UINT_MAX32, 0); + NULL, NULL, 0, 0, UINT_MAX32, 0); static MYSQL_SYSVAR_BOOL(disable_resize_buffer_pool_debug, buf_disable_resize_buffer_pool_debug, PLUGIN_VAR_NOCMDARG, diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index 84003fb415c..494ae2798ee 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -662,10 +662,11 @@ ibuf_bitmap_page_set_bits( @return the bitmap page id where the file page is mapped */ inline page_id_t ibuf_bitmap_page_no_calc(const page_id_t page_id, ulint size) { - if (!size) size = srv_page_size; + if (!size) + size= srv_page_size; - return page_id_t(page_id.space(), FSP_IBUF_BITMAP_OFFSET - + (page_id.page_no() & ~(size - 1))); + return page_id_t(page_id.space(), FSP_IBUF_BITMAP_OFFSET + + uint32_t(page_id.page_no() & ~(size - 1))); } /** Gets the ibuf bitmap page where the bits describing a given file page are @@ -1034,7 +1035,7 @@ ibuf_page_low( Returns the page number field of an ibuf record. @return page number */ static -ulint +uint32_t ibuf_rec_get_page_no_func( /*======================*/ #ifdef UNIV_DEBUG @@ -1072,7 +1073,7 @@ Returns the space id field of an ibuf record. For < 4.1.x format records returns 0. @return space id */ static -ulint +uint32_t ibuf_rec_get_space_func( /*====================*/ #ifdef UNIV_DEBUG @@ -1900,7 +1901,6 @@ ibuf_remove_free_page(void) mtr_t mtr; mtr_t mtr2; page_t* header_page; - ulint page_no; log_free_check(); @@ -1932,8 +1932,8 @@ ibuf_remove_free_page(void) mutex_exit(&ibuf_mutex); - page_no = flst_get_last(PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST - + root->frame).page; + uint32_t page_no = flst_get_last(PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST + + root->frame).page; /* NOTE that we must release the latch on the ibuf tree root because in fseg_free_page we access level 1 pages, and the root @@ -2042,19 +2042,19 @@ ibuf_get_merge_page_nos_func( #ifdef UNIV_DEBUG mtr_t* mtr, /*!< in: mini-transaction holding rec */ #endif /* UNIV_DEBUG */ - ulint* space_ids,/*!< in/out: space id's of the pages */ - ulint* page_nos,/*!< in/out: buffer for at least + uint32_t* space_ids,/*!< in/out: space id's of the pages */ + uint32_t* page_nos,/*!< in/out: buffer for at least IBUF_MAX_N_PAGES_MERGED many page numbers; the page numbers are in an ascending order */ ulint* n_stored)/*!< out: number of page numbers stored to page_nos in this function */ { - ulint prev_page_no; - ulint prev_space_id; - ulint first_page_no; - ulint first_space_id; - ulint rec_page_no; - ulint rec_space_id; + uint32_t prev_page_no; + uint32_t prev_space_id; + uint32_t first_page_no; + uint32_t first_space_id; + uint32_t rec_page_no; + uint32_t rec_space_id; ulint sum_volumes; ulint volume_for_page; ulint rec_volume; @@ -2247,25 +2247,23 @@ ulint ibuf_get_merge_pages( /*=================*/ btr_pcur_t* pcur, /*!< in/out: cursor */ - ulint space, /*!< in: space for which to merge */ + uint32_t space, /*!< in: space for which to merge */ ulint limit, /*!< in: max page numbers to read */ - ulint* pages, /*!< out: pages read */ - ulint* spaces, /*!< out: spaces read */ + uint32_t* pages, /*!< out: pages read */ + uint32_t* spaces, /*!< out: spaces read */ ulint* n_pages,/*!< out: number of pages read */ mtr_t* mtr) /*!< in: mini transaction */ { const rec_t* rec; ulint volume = 0; - ut_a(space != ULINT_UNDEFINED); - *n_pages = 0; while ((rec = ibuf_get_user_rec(pcur, mtr)) != 0 && ibuf_rec_get_space(mtr, rec) == space && *n_pages < limit) { - ulint page_no = ibuf_rec_get_page_no(mtr, rec); + uint32_t page_no = ibuf_rec_get_page_no(mtr, rec); if (*n_pages == 0 || pages[*n_pages - 1] != page_no) { spaces[*n_pages] = space; @@ -2283,19 +2281,18 @@ ibuf_get_merge_pages( /** Delete a change buffer record. -@param[in] space tablespace identifier -@param[in] page_no page number +@param[in] page_id page identifier @param[in,out] pcur persistent cursor positioned on the record @param[in] search_tuple search key for (space,page_no) @param[in,out] mtr mini-transaction @return whether mtr was committed (due to pessimistic operation) */ static MY_ATTRIBUTE((warn_unused_result, nonnull)) -bool ibuf_delete_rec(ulint space, ulint page_no, btr_pcur_t* pcur, +bool ibuf_delete_rec(const page_id_t page_id, btr_pcur_t* pcur, const dtuple_t* search_tuple, mtr_t* mtr); /** Merge the change buffer to some pages. */ -static void ibuf_read_merge_pages(const ulint* space_ids, - const ulint* page_nos, ulint n_stored) +static void ibuf_read_merge_pages(const uint32_t* space_ids, + const uint32_t* page_nos, ulint n_stored) { mem_heap_t* heap = mem_heap_create(512); ulint dops[IBUF_OP_COUNT]; @@ -2359,7 +2356,7 @@ loop: dops[ibuf_rec_get_op_type(&mtr, ibuf_rec)]++; /* Delete the record from ibuf */ - if (ibuf_delete_rec(space_id, page_nos[i], + if (ibuf_delete_rec(page_id_t(space_id, page_nos[i]), &pcur, tuple, &mtr)) { /* Deletion was pessimistic and mtr was committed: we start from the @@ -2398,8 +2395,8 @@ ibuf_merge_pages( mtr_t mtr; btr_pcur_t pcur; ulint sum_sizes; - ulint page_nos[IBUF_MAX_N_PAGES_MERGED]; - ulint space_ids[IBUF_MAX_N_PAGES_MERGED]; + uint32_t page_nos[IBUF_MAX_N_PAGES_MERGED]; + uint32_t space_ids[IBUF_MAX_N_PAGES_MERGED]; *n_pages = 0; @@ -2472,8 +2469,8 @@ ibuf_merge_space( ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf.index)); ulint sum_sizes = 0; - ulint pages[IBUF_MAX_N_PAGES_MERGED]; - ulint spaces[IBUF_MAX_N_PAGES_MERGED]; + uint32_t pages[IBUF_MAX_N_PAGES_MERGED]; + uint32_t spaces[IBUF_MAX_N_PAGES_MERGED]; if (page_is_empty(btr_pcur_get_page(&pcur))) { /* If a B-tree page is empty, it must be the root page @@ -2485,7 +2482,7 @@ ibuf_merge_space( } else { sum_sizes = ibuf_get_merge_pages( - &pcur, space, IBUF_MAX_N_PAGES_MERGED, + &pcur, uint32_t(space), IBUF_MAX_N_PAGES_MERGED, &pages[0], &spaces[0], &n_pages, &mtr); ib::info() << "Size of pages merged " << sum_sizes; @@ -2789,9 +2786,7 @@ ibuf_get_volume_buffered( ulint volume; const rec_t* rec; const page_t* page; - ulint prev_page_no; const page_t* prev_page; - ulint next_page_no; const page_t* next_page; /* bitmap of buffered recs */ ulint hash_bitmap[128 / sizeof(ulint)]; @@ -2816,6 +2811,8 @@ ibuf_get_volume_buffered( rec = page_rec_get_prev_const(rec); } + uint32_t prev_page_no; + for (; !page_rec_is_infimum(rec); rec = page_rec_get_prev_const(rec)) { ut_ad(page_align(rec) == page); @@ -2908,7 +2905,7 @@ count_later: /* Look at the next page */ - next_page_no = btr_page_get_next(page); + uint32_t next_page_no = btr_page_get_next(page); if (next_page_no == FIL_NULL) { @@ -3196,8 +3193,8 @@ ibuf_insert_low( page_t* root; dberr_t err; ibool do_merge; - ulint space_ids[IBUF_MAX_N_PAGES_MERGED]; - ulint page_nos[IBUF_MAX_N_PAGES_MERGED]; + uint32_t space_ids[IBUF_MAX_N_PAGES_MERGED]; + uint32_t page_nos[IBUF_MAX_N_PAGES_MERGED]; ulint n_stored; mtr_t mtr; mtr_t bitmap_mtr; @@ -4011,14 +4008,12 @@ ibuf_delete( /*********************************************************************//** Restores insert buffer tree cursor position -@return TRUE if the position was restored; FALSE if not */ +@return whether the position was restored */ static MY_ATTRIBUTE((nonnull)) -ibool +bool ibuf_restore_pos( /*=============*/ - ulint space, /*!< in: space id */ - ulint page_no,/*!< in: index page number where the record - should belong */ + const page_id_t page_id,/*!< in: page identifier */ const dtuple_t* search_tuple, /*!< in: search tuple for entries of page_no */ ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */ @@ -4029,15 +4024,14 @@ ibuf_restore_pos( ut_ad(mode == BTR_MODIFY_LEAF || BTR_LATCH_MODE_WITHOUT_INTENTION(mode) == BTR_MODIFY_TREE); - if (btr_pcur_restore_position(mode, pcur, mtr)) { - - return(TRUE); + if (UNIV_LIKELY(btr_pcur_restore_position(mode, pcur, mtr))) { + return true; } - if (fil_space_t* s = fil_space_acquire_silent(space)) { + if (fil_space_t* s = fil_space_acquire_silent(page_id.space())) { ib::error() << "ibuf cursor restoration fails!" " ibuf record inserted to page " - << space << ":" << page_no + << page_id << " in file " << s->chain.start->name; s->release(); @@ -4052,19 +4046,18 @@ ibuf_restore_pos( } ibuf_btr_pcur_commit_specify_mtr(pcur, mtr); - return(FALSE); + return false; } /** Delete a change buffer record. -@param[in] space tablespace identifier -@param[in] page_no page number +@param[in] page_id page identifier @param[in,out] pcur persistent cursor positioned on the record @param[in] search_tuple search key for (space,page_no) @param[in,out] mtr mini-transaction @return whether mtr was committed (due to pessimistic operation) */ static MY_ATTRIBUTE((warn_unused_result, nonnull)) -bool ibuf_delete_rec(ulint space, ulint page_no, btr_pcur_t* pcur, +bool ibuf_delete_rec(const page_id_t page_id, btr_pcur_t* pcur, const dtuple_t* search_tuple, mtr_t* mtr) { ibool success; @@ -4073,14 +4066,14 @@ bool ibuf_delete_rec(ulint space, ulint page_no, btr_pcur_t* pcur, ut_ad(ibuf_inside(mtr)); ut_ad(page_rec_is_user_rec(btr_pcur_get_rec(pcur))); - ut_ad(ibuf_rec_get_page_no(mtr, btr_pcur_get_rec(pcur)) == page_no); - ut_ad(ibuf_rec_get_space(mtr, btr_pcur_get_rec(pcur)) == space); + ut_ad(ibuf_rec_get_page_no(mtr, btr_pcur_get_rec(pcur)) + == page_id.page_no()); + ut_ad(ibuf_rec_get_space(mtr, btr_pcur_get_rec(pcur)) + == page_id.space()); success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), 0, mtr); - const page_id_t page_id(space, page_no); - if (success) { if (page_is_empty(btr_pcur_get_page(pcur))) { /* If a B-tree page is empty, it must be the root page @@ -4101,10 +4094,6 @@ bool ibuf_delete_rec(ulint space, ulint page_no, btr_pcur_t* pcur, return(FALSE); } - ut_ad(page_rec_is_user_rec(btr_pcur_get_rec(pcur))); - ut_ad(ibuf_rec_get_page_no(mtr, btr_pcur_get_rec(pcur)) == page_no); - ut_ad(ibuf_rec_get_space(mtr, btr_pcur_get_rec(pcur)) == space); - /* We have to resort to a pessimistic delete from ibuf. Delete-mark the record so that it will not be applied again, in case the server crashes before the pessimistic delete is @@ -4118,7 +4107,7 @@ bool ibuf_delete_rec(ulint space, ulint page_no, btr_pcur_t* pcur, ibuf_mtr_start(mtr); mutex_enter(&ibuf_mutex); - if (!ibuf_restore_pos(space, page_no, search_tuple, + if (!ibuf_restore_pos(page_id, search_tuple, BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE, pcur, mtr)) { @@ -4440,9 +4429,7 @@ loop: buf_block_dbg_add_level( block, SYNC_IBUF_TREE_NODE); - if (!ibuf_restore_pos(page_id.space(), - page_id.page_no(), - search_tuple, + if (!ibuf_restore_pos(page_id, search_tuple, BTR_MODIFY_LEAF, &pcur, &mtr)) { @@ -4465,8 +4452,7 @@ loop: } /* Delete the record from ibuf */ - if (ibuf_delete_rec(page_id.space(), page_id.page_no(), - &pcur, search_tuple, &mtr)) { + if (ibuf_delete_rec(page_id, &pcur, search_tuple, &mtr)) { /* Deletion was pessimistic and mtr was committed: we start from the beginning again */ @@ -4518,7 +4504,6 @@ void ibuf_delete_for_discarded_space(ulint space) btr_pcur_t pcur; dtuple_t* search_tuple; const rec_t* ibuf_rec; - ulint page_no; mtr_t mtr; /* Counts for discarded operations. */ @@ -4557,13 +4542,13 @@ loop: goto leave_loop; } - page_no = ibuf_rec_get_page_no(&mtr, ibuf_rec); + uint32_t page_no = ibuf_rec_get_page_no(&mtr, ibuf_rec); dops[ibuf_rec_get_op_type(&mtr, ibuf_rec)]++; /* Delete the record from ibuf */ - if (ibuf_delete_rec(space, page_no, &pcur, search_tuple, - &mtr)) { + if (ibuf_delete_rec(page_id_t(space, page_no), + &pcur, search_tuple, &mtr)) { /* Deletion was pessimistic and mtr was committed: we start from the beginning again */ @@ -4641,19 +4626,18 @@ ibuf_print( @return DB_SUCCESS or error code */ dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) { - ulint page_no; ut_ad(trx->mysql_thd); ut_ad(space->purpose == FIL_TYPE_IMPORT); - const ulint zip_size = space->zip_size(); - const ulint physical_size = space->physical_size(); + const unsigned zip_size = space->zip_size(); + const unsigned physical_size = space->physical_size(); /* fil_space_t::size and fil_space_t::free_limit would still be 0 at this point. So, we will have to read page 0. */ ut_ad(!space->free_limit); ut_ad(!space->size); - mtr_t mtr; - ulint size; + mtr_t mtr; + uint32_t size; mtr.start(); if (buf_block_t* sp = buf_page_get(page_id_t(space->id, 0), zip_size, @@ -4668,10 +4652,6 @@ dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) } mtr.commit(); - if (size == 0) { - return(DB_TABLE_NOT_FOUND); - } - mutex_enter(&ibuf_mutex); /* The two bitmap pages (allocation bitmap and ibuf bitmap) repeat @@ -4680,7 +4660,7 @@ dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) below page_no is measured in number of pages since the beginning of the space, as usual. */ - for (page_no = 0; page_no < size; page_no += physical_size) { + for (uint32_t page_no = 0; page_no < size; page_no += physical_size) { if (trx_is_interrupted(trx)) { mutex_exit(&ibuf_mutex); return(DB_INTERRUPTED); @@ -4706,7 +4686,7 @@ dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) ibuf bitmap page. The subsequent page should be all-zero pages. */ #ifdef UNIV_DEBUG - for (ulint curr_page = page_no + 1; + for (uint32_t curr_page = page_no + 1; curr_page < physical_size; curr_page++) { buf_block_t* block = buf_page_get( @@ -4723,9 +4703,9 @@ dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) continue; } - for (ulint i = FSP_IBUF_BITMAP_OFFSET + 1; i < physical_size; + for (uint32_t i = FSP_IBUF_BITMAP_OFFSET + 1; i < physical_size; i++) { - const ulint offset = page_no + i; + const uint32_t offset = page_no + i; const page_id_t cur_page_id(space->id, offset); if (ibuf_bitmap_page_get_bits( @@ -4739,7 +4719,7 @@ dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) ib_errf(trx->mysql_thd, IB_LOG_LEVEL_ERROR, ER_INNODB_INDEX_CORRUPT, - "File %s page " ULINTPF + "File %s page %u" " is wrongly flagged to belong to the" " insert buffer", space->chain.start->name, offset); @@ -4754,8 +4734,7 @@ dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) IB_LOG_LEVEL_WARN, ER_INNODB_INDEX_CORRUPT, "Buffered changes" - " for file %s page " ULINTPF - " are lost", + " for file %s page %u are lost", space->chain.start->name, offset); /* Tolerate this error, so that diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index b02c65f3a31..317c63c97d8 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -227,8 +227,8 @@ btr_height_get( @param[in] line line where called @param[in,out] mtr mini-transaction @return block */ -inline buf_block_t* btr_block_get_func(const dict_index_t& index, ulint page, - ulint mode, bool merge, +inline buf_block_t* btr_block_get_func(const dict_index_t& index, + uint32_t page, ulint mode, bool merge, const char* file, unsigned line, mtr_t* mtr) { @@ -323,7 +323,7 @@ the child page number. In other words offsets must have been retrieved with rec_get_offsets(n_fields=ULINT_UNDEFINED). @return child node address */ UNIV_INLINE -ulint +uint32_t btr_node_ptr_get_child_page_no( /*===========================*/ const rec_t* rec, /*!< in: node pointer record */ @@ -607,7 +607,7 @@ buf_block_t* btr_page_alloc( /*===========*/ dict_index_t* index, /*!< in: index tree */ - ulint hint_page_no, /*!< in: hint of a good page */ + uint32_t hint_page_no, /*!< in: hint of a good page */ byte file_direction, /*!< in: direction where a possible page split is made */ ulint level, /*!< in: level where the page is placed diff --git a/storage/innobase/include/btr0btr.ic b/storage/innobase/include/btr0btr.ic index 5d2faa1e298..89826e8f214 100644 --- a/storage/innobase/include/btr0btr.ic +++ b/storage/innobase/include/btr0btr.ic @@ -90,7 +90,7 @@ the child page number. In other words offsets must have been retrieved with rec_get_offsets(n_fields=ULINT_UNDEFINED). @return child node address */ UNIV_INLINE -ulint +uint32_t btr_node_ptr_get_child_page_no( /*===========================*/ const rec_t* rec, /*!< in: node pointer record */ @@ -98,7 +98,6 @@ btr_node_ptr_get_child_page_no( { const byte* field; ulint len; - ulint page_no; ut_ad(!rec_offs_comp(offsets) || rec_get_node_ptr_flag(rec)); @@ -108,7 +107,7 @@ btr_node_ptr_get_child_page_no( ut_ad(len == 4); - page_no = mach_read_from_4(field); + uint32_t page_no = mach_read_from_4(field); ut_ad(page_no > 1); return(page_no); diff --git a/storage/innobase/include/btr0bulk.h b/storage/innobase/include/btr0bulk.h index dc28d15b391..375b7b34fe4 100644 --- a/storage/innobase/include/btr0bulk.h +++ b/storage/innobase/include/btr0bulk.h @@ -57,7 +57,7 @@ public: PageBulk( dict_index_t* index, trx_id_t trx_id, - ulint page_no, + uint32_t page_no, ulint level) : m_heap(NULL), @@ -179,10 +179,7 @@ public: inline bool isSpaceAvailable(ulint rec_size); /** Get page no */ - ulint getPageNo() - { - return(m_page_no); - } + uint32_t getPageNo() const { return m_page_no; } /** Get page level */ ulint getLevel() @@ -241,7 +238,7 @@ private: rec_t* m_cur_rec; /** The page no */ - ulint m_page_no; + uint32_t m_page_no; /** The page level in B-tree */ ulint m_level; diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index 03ebf6f448f..838b49dad47 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -799,7 +799,7 @@ struct btr_path_t { ulint n_recs; /** Number of the page containing the record. */ - ulint page_no; + uint32_t page_no; /** Level of the page. If later we fetch the page under page_no and it is no different level then we know that the tree has been diff --git a/storage/innobase/include/buf0rea.h b/storage/innobase/include/buf0rea.h index f4d1560862a..e111bbd7a02 100644 --- a/storage/innobase/include/buf0rea.h +++ b/storage/innobase/include/buf0rea.h @@ -106,14 +106,9 @@ for the highest address page to get read in, before this function returns @param[in] space_id tablespace id @param[in] page_nos array of page numbers to read, with the highest page number the last in the array -@param[in] n_stored number of page numbers in the array */ - -void -buf_read_recv_pages( - bool sync, - ulint space_id, - const ulint* page_nos, - ulint n_stored); +@param[in] n number of page numbers in the array */ +void buf_read_recv_pages(bool sync, ulint space_id, const uint32_t *page_nos, + ulint n); /** @name Modes used in read-ahead @{ */ /** read only pages belonging to the insert buffer tree */ diff --git a/storage/innobase/include/buf0types.h b/storage/innobase/include/buf0types.h index b50352a1c0b..ba1e2e5eaa6 100644 --- a/storage/innobase/include/buf0types.h +++ b/storage/innobase/include/buf0types.h @@ -122,10 +122,9 @@ public: /** Constructor from (space, page_no). @param[in] space tablespace id @param[in] page_no page number */ - page_id_t(ulint space, ulint page_no) : m_id(uint64_t{space} << 32 | page_no) + page_id_t(ulint space, uint32_t page_no) : m_id(uint64_t{space} << 32 | page_no) { ut_ad(space <= 0xFFFFFFFFU); - ut_ad(page_no <= 0xFFFFFFFFU); } page_id_t(uint64_t id) : m_id(id) {} @@ -167,9 +166,8 @@ public: /** Reset the page number only. @param[in] page_no page number */ - void set_page_no(ulint page_no) + void set_page_no(uint32_t page_no) { - ut_ad(page_no <= 0xFFFFFFFFU); m_id= (m_id & ~uint64_t{0} << 32) | page_no; } diff --git a/storage/innobase/include/fil0crypt.h b/storage/innobase/include/fil0crypt.h index 62714b88679..49567a49a78 100644 --- a/storage/innobase/include/fil0crypt.h +++ b/storage/innobase/include/fil0crypt.h @@ -85,8 +85,8 @@ struct fil_space_rotate_state_t { time_t start_time; /*!< time when rotation started */ ulint active_threads; /*!< active threads in space */ - ulint next_offset; /*!< next "free" offset */ - ulint max_offset; /*!< max offset needing to be rotated */ + uint32_t next_offset; /*!< next "free" offset */ + uint32_t max_offset; /*!< max offset needing to be rotated */ uint min_key_version_found; /*!< min key version found but not rotated */ lsn_t end_lsn; /*!< max lsn created when rotating this diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index b6ff8b6b6bb..0fa0c0b598b 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -335,21 +335,21 @@ struct fil_space_t fil_type_t purpose;/*!< purpose */ UT_LIST_BASE_NODE_T(fil_node_t) chain; /*!< base node for the file chain */ - ulint size; /*!< tablespace file size in pages; + uint32_t size; /*!< tablespace file size in pages; 0 if not known yet */ - ulint size_in_header; + uint32_t size_in_header; /* FSP_SIZE in the tablespace header; 0 if not known yet */ - ulint free_len; + uint32_t free_len; /*!< length of the FSP_FREE list */ - ulint free_limit; + uint32_t free_limit; /*!< contents of FSP_FREE_LIMIT */ - ulint recv_size; + uint32_t recv_size; /*!< recovered tablespace size in pages; 0 if no size change was read from the redo log, or if the size change was implemented */ /** the committed size of the tablespace in pages */ - Atomic_relaxed committed_size; + Atomic_relaxed committed_size; ulint n_reserved_extents; /*!< number of reserved free extents for ongoing operations like B-tree page split */ @@ -370,7 +370,7 @@ private: /** Flag in n_pending_ops that indicates that the tablespace is being deleted, and no further operations should be performed */ - static const size_t STOP_NEW_OPS= ~(~size_t(0) >> 1); + static constexpr uint32_t STOP_NEW_OPS= ~(~uint32_t(0) >> 1); public: /** Number of pending block read or write operations (when a write is imminent or a read has recently completed). @@ -429,11 +429,11 @@ public: @param[in] is_raw whether this is a raw device @param[in] atomic_write true if atomic write could be enabled @param[in] max_pages maximum number of pages in file, - or ULINT_MAX for unlimited + or UINT32_MAX for unlimited @return file object */ fil_node_t* add(const char* name, pfs_os_file_t handle, - ulint size, bool is_raw, bool atomic_write, - ulint max_pages = ULINT_MAX); + uint32_t size, bool is_raw, bool atomic_write, + uint32_t max_pages = UINT32_MAX); #ifdef UNIV_DEBUG /** Assert that the mini-transaction is compatible with updating an allocation bitmap page. @@ -886,18 +886,18 @@ struct fil_node_t { /** size of the file in database pages (0 if not known yet); the possible last incomplete megabyte may be ignored if space->id == 0 */ - ulint size; + uint32_t size; /** initial size of the file in database pages; FIL_IBD_FILE_INITIAL_SIZE by default */ - ulint init_size; + uint32_t init_size; /** maximum size of the file in database pages (0 if unlimited) */ - ulint max_size; + uint32_t max_size; /** count of pending i/o's; is_open must be true if nonzero */ ulint n_pending; /** count of pending flushes; is_open must be true if nonzero */ ulint n_pending_flushes; /** whether the file is currently being extended */ - bool being_extended; + Atomic_relaxed being_extended; /** whether this file had writes after lasy fsync() */ bool needs_flush; /** link to other files in this tablespace */ @@ -962,8 +962,8 @@ inline void fil_space_t::set_imported() inline bool fil_space_t::is_rotational() const { - for (const fil_node_t* node = UT_LIST_GET_FIRST(chain); - node != NULL; node = UT_LIST_GET_NEXT(chain, node)) { + for (const fil_node_t* node = UT_LIST_GET_FIRST(chain); node; + node = UT_LIST_GET_NEXT(chain, node)) { if (!node->on_ssd) { return true; } @@ -1379,7 +1379,7 @@ Error messages are issued to the server log. @param[in] id tablespace identifier @param[in] flags tablespace flags @param[in] purpose tablespace purpose -@param[in,out] crypt_data encryption information +@param[in,out] crypt_data encryption information @param[in] mode encryption mode @return pointer to created tablespace, to be filled in with fil_space_t::add() @retval NULL on failure (such as when the same tablespace exists) */ @@ -1418,8 +1418,8 @@ fil_space_free( @param id tablespace ID @param size recovered size in pages @param flags tablespace flags */ -UNIV_INTERN -void fil_space_set_recv_size_and_flags(ulint id, ulint size, uint32_t flags); +void fil_space_set_recv_size_and_flags(ulint id, uint32_t size, + uint32_t flags); /*******************************************************************//** Returns the size of the space in pages. The tablespace must be cached in the @@ -1576,7 +1576,7 @@ fil_ibd_create( const char* name, const char* path, ulint flags, - ulint size, + uint32_t size, fil_encryption_t mode, uint32_t key_id, dberr_t* err) @@ -1688,10 +1688,7 @@ fil_space_for_table_exists_in_mem( @param[in,out] space tablespace @param[in] size desired size in pages @return whether the tablespace is at least as big as requested */ -bool -fil_space_extend( - fil_space_t* space, - ulint size); +bool fil_space_extend(fil_space_t *space, uint32_t size); struct fil_io_t { diff --git a/storage/innobase/include/fsp0file.h b/storage/innobase/include/fsp0file.h index 759970bb46d..7a0687d4960 100644 --- a/storage/innobase/include/fsp0file.h +++ b/storage/innobase/include/fsp0file.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2018, MariaDB Corporation. +Copyright (c) 2018, 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 @@ -68,7 +68,7 @@ public: /* No op */ } - Datafile(const char* name, ulint flags, ulint size, ulint order) + Datafile(const char* name, ulint flags, uint32_t size, ulint order) : m_name(mem_strdup(name)), m_filepath(), @@ -431,7 +431,7 @@ private: /** size in megabytes or pages; converted from megabytes to pages in SysTablespace::normalize_size() */ - ulint m_size; + uint32_t m_size; /** ordinal position of this datafile in the tablespace */ ulint m_order; diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index 31c66cb57ea..308b0916284 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/include/fsp0fsp.h @@ -316,11 +316,9 @@ inline uint32_t fsp_header_get_field(const page_t* page, ulint field) /** Read the flags from the tablespace header page. @param[in] page first page of a tablespace @return the contents of FSP_SPACE_FLAGS */ -inline -ulint -fsp_header_get_flags(const page_t* page) +inline uint32_t fsp_header_get_flags(const page_t *page) { - return(fsp_header_get_field(page, FSP_SPACE_FLAGS)); + return fsp_header_get_field(page, FSP_SPACE_FLAGS); } /** Get the byte offset of encryption information in page 0. @@ -359,7 +357,7 @@ fsp_header_init_fields( @param[in,out] space tablespace @param[in] size current size in blocks @param[in,out] mtr mini-transaction */ -void fsp_header_init(fil_space_t* space, ulint size, mtr_t* mtr) +void fsp_header_init(fil_space_t* space, uint32_t size, mtr_t* mtr) MY_ATTRIBUTE((nonnull)); /** Create a new segment. @@ -411,7 +409,7 @@ buf_block_t* fseg_alloc_free_page_general( /*=========================*/ fseg_header_t* seg_header,/*!< in/out: segment header */ - ulint hint, /*!< in: hint of which page would be + uint32_t hint, /*!< in: hint of which page would be desirable */ byte direction,/*!< in: if the new page is needed because of an index page split, and records are @@ -473,7 +471,7 @@ fsp_reserve_free_extents( ulint n_ext, fsp_reserve_t alloc_type, mtr_t* mtr, - ulint n_pages = 2); + uint32_t n_pages = 2); /** Free a page in a file segment. @param[in,out] seg_header file segment header @@ -484,7 +482,7 @@ void fseg_free_page( fseg_header_t* seg_header, fil_space_t* space, - ulint offset, + uint32_t offset, mtr_t* mtr); /** Determine whether a page is free. @param[in,out] space tablespace @@ -736,7 +734,7 @@ inline ulint xdes_calc_descriptor_index(ulint zip_size, ulint offset) @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 @param[in] offset page offset @return descriptor page offset */ -inline ulint xdes_calc_descriptor_page(ulint zip_size, ulint offset) +inline uint32_t xdes_calc_descriptor_page(ulint zip_size, uint32_t offset) { compile_time_assert(UNIV_PAGE_SIZE_MAX > XDES_ARR_OFFSET + (UNIV_PAGE_SIZE_MAX / FSP_EXTENT_SIZE_MAX) @@ -754,8 +752,8 @@ inline ulint xdes_calc_descriptor_page(ulint zip_size, ulint offset) ut_ad(!zip_size || zip_size > XDES_ARR_OFFSET + (zip_size / FSP_EXTENT_SIZE) * XDES_SIZE); - return ut_2pow_round(offset, - zip_size ? zip_size : srv_page_size); + return ut_2pow_round(offset, + uint32_t(zip_size ? zip_size : srv_page_size)); } #endif /* UNIV_INNOCHECKSUM */ diff --git a/storage/innobase/include/fsp0space.h b/storage/innobase/include/fsp0space.h index 632c65e14cc..c00c8d689bf 100644 --- a/storage/innobase/include/fsp0space.h +++ b/storage/innobase/include/fsp0space.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 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 @@ -163,9 +163,9 @@ public: void shutdown(); /** @return the sum of the file sizes of each Datafile */ - ulint get_sum_of_sizes() const + uint32_t get_sum_of_sizes() const { - ulint sum = 0; + uint32_t sum = 0; for (const_iterator it = begin(); it != end(); ++it) { sum += it->m_size; diff --git a/storage/innobase/include/fsp0sysspace.h b/storage/innobase/include/fsp0sysspace.h index bcb8dd5e5e9..2e0a395f71c 100644 --- a/storage/innobase/include/fsp0sysspace.h +++ b/storage/innobase/include/fsp0sysspace.h @@ -30,7 +30,7 @@ Created 2013-7-26 by Kevin Lewis /** If the last data file is auto-extended, we add this many pages to it at a time. We have to make this public because it is a config variable. */ -extern ulong sys_tablespace_auto_extend_increment; +extern uint sys_tablespace_auto_extend_increment; /** Data structure that contains the information about shared tablespaces. Currently this can be the system tablespace or a temporary table tablespace */ @@ -120,7 +120,7 @@ public: /** Set the last file size. @param[in] size the size to set */ - void set_last_file_size(ulint size) + void set_last_file_size(uint32_t size) { ut_ad(!m_files.empty()); m_files.back().m_size = size; @@ -128,7 +128,7 @@ public: /** Get the size of the last data file in the tablespace @return the size of the last data file in the array */ - ulint last_file_size() const + uint32_t last_file_size() const { ut_ad(!m_files.empty()); return(m_files.back().m_size); @@ -136,7 +136,7 @@ public: /** @return the autoextend increment in pages. */ - ulint get_autoextend_increment() const + uint32_t get_autoextend_increment() const { return sys_tablespace_auto_extend_increment << (20 - srv_page_size_shift); @@ -144,7 +144,7 @@ public: /** @return next increment size */ - ulint get_increment() const; + uint32_t get_increment() const; /** Open or create the data files @param[in] is_temp whether this is a temporary tablespace @@ -240,8 +240,7 @@ private: /** if true, then we auto-extend the last data file */ bool m_auto_extend_last_file; - /** if != 0, this tells the max size auto-extending may increase the - last data file size */ + /** maximum size of the last data file (0=unlimited) */ ulint m_last_file_size_max; /** If the following is true we do not allow diff --git a/storage/innobase/include/gis0rtree.h b/storage/innobase/include/gis0rtree.h index f064df01679..f7a2d6cd4cd 100644 --- a/storage/innobase/include/gis0rtree.h +++ b/storage/innobase/include/gis0rtree.h @@ -169,10 +169,10 @@ void rtr_non_leaf_stack_push( /*====================*/ rtr_node_path_t* path, /*!< in/out: search path */ - ulint pageno, /*!< in: pageno to insert */ + uint32_t pageno, /*!< in: pageno to insert */ node_seq_t seq_no, /*!< in: Node sequence num */ ulint level, /*!< in: index level */ - ulint child_no, /*!< in: child page no */ + uint32_t child_no, /*!< in: child page no */ btr_pcur_t* cursor, /*!< in: position cursor */ double mbr_inc); /*!< in: MBR needs to be enlarged */ diff --git a/storage/innobase/include/gis0rtree.ic b/storage/innobase/include/gis0rtree.ic index 2076b24b9b1..82747bdc95a 100644 --- a/storage/innobase/include/gis0rtree.ic +++ b/storage/innobase/include/gis0rtree.ic @@ -96,10 +96,10 @@ void rtr_non_leaf_stack_push( /*====================*/ rtr_node_path_t* path, /*!< in/out: search path */ - ulint pageno, /*!< in: pageno to insert */ + uint32_t pageno, /*!< in: pageno to insert */ node_seq_t seq_no, /*!< in: Node sequence num */ ulint level, /*!< in: index page level */ - ulint child_no, /*!< in: child page no */ + uint32_t child_no, /*!< in: child page no */ btr_pcur_t* cursor, /*!< in: position cursor */ double mbr_inc) /*!< in: MBR needs to be enlarged */ diff --git a/storage/innobase/include/gis0type.h b/storage/innobase/include/gis0type.h index a1e0a878cb2..55944bfcce3 100644 --- a/storage/innobase/include/gis0type.h +++ b/storage/innobase/include/gis0type.h @@ -37,15 +37,15 @@ Created 2013/03/27 Jimmy Yang #include #include -/* Node Sequence Number. Only updated when page splits */ -typedef ib_uint32_t node_seq_t; +/** Node Sequence Number. Only updated when page splits */ +typedef uint32_t node_seq_t; /* RTree internal non-leaf Nodes to be searched, from root to leaf */ -typedef struct node_visit { - ulint page_no; /*!< the page number */ +struct node_visit_t { + uint32_t page_no; /*!< the page number */ node_seq_t seq_no; /*!< the SSN (split sequence number */ ulint level; /*!< the page's index level */ - ulint child_no; /*!< child page num if for parent + uint32_t child_no; /*!< child page num if for parent recording */ btr_pcur_t* cursor; /*!< cursor structure if we positioned FIXME: there is no need to use whole @@ -53,7 +53,7 @@ typedef struct node_visit { members */ double mbr_inc; /*!< whether this node needs to be enlarged for insertion */ -} node_visit_t; +}; typedef std::vector > rtr_node_path_t; diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index 2aae5ed6989..a73b9e48755 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -568,7 +568,7 @@ page_get_middle_rec( Gets the page number. @return page number */ UNIV_INLINE -ulint +uint32_t page_get_page_no( /*=============*/ const page_t* page); /*!< in: page */ @@ -577,7 +577,7 @@ page_get_page_no( Gets the tablespace identifier. @return space id */ UNIV_INLINE -ulint +uint32_t page_get_space_id( /*==============*/ const page_t* page); /*!< in: page */ diff --git a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic index ad6fac32b69..2de2ad38080 100644 --- a/storage/innobase/include/page0page.ic +++ b/storage/innobase/include/page0page.ic @@ -300,7 +300,7 @@ page_get_middle_rec( Gets the page number. @return page number */ UNIV_INLINE -ulint +uint32_t page_get_page_no( /*=============*/ const page_t* page) /*!< in: page */ @@ -314,7 +314,7 @@ page_get_page_no( Gets the tablespace identifier. @return space id */ UNIV_INLINE -ulint +uint32_t page_get_space_id( /*==============*/ const page_t* page) /*!< in: page */ diff --git a/storage/innobase/include/trx0rseg.h b/storage/innobase/include/trx0rseg.h index 937e05dfba6..a3ccc90b630 100644 --- a/storage/innobase/include/trx0rseg.h +++ b/storage/innobase/include/trx0rseg.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2017, 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 @@ -37,7 +37,7 @@ Created 3/26/1996 Heikki Tuuri @return rollback segment header, page x-latched */ UNIV_INLINE buf_block_t* -trx_rsegf_get(fil_space_t* space, ulint page_no, mtr_t* mtr); +trx_rsegf_get(fil_space_t* space, uint32_t page_no, mtr_t* mtr); /** Gets a newly created rollback segment header. @param[in] space space where placed @@ -48,7 +48,7 @@ UNIV_INLINE buf_block_t* trx_rsegf_get_new( ulint space, - ulint page_no, + uint32_t page_no, mtr_t* mtr); /** Create a rollback segment header. @@ -106,10 +106,10 @@ struct trx_rseg_t { fil_space_t* space; /** page number of the rollback segment header */ - ulint page_no; + uint32_t page_no; /** current size in pages */ - ulint curr_size; + uint32_t curr_size; /*--------------------------------------------------------*/ /* Fields for undo logs */ diff --git a/storage/innobase/include/trx0rseg.ic b/storage/innobase/include/trx0rseg.ic index e0e8c175a5d..b293d9f1ae1 100644 --- a/storage/innobase/include/trx0rseg.ic +++ b/storage/innobase/include/trx0rseg.ic @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2017, 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 @@ -34,7 +34,7 @@ Created 3/26/1996 Heikki Tuuri @return rollback segment header, page x-latched */ UNIV_INLINE buf_block_t* -trx_rsegf_get(fil_space_t* space, ulint page_no, mtr_t* mtr) +trx_rsegf_get(fil_space_t* space, uint32_t page_no, mtr_t* mtr) { ut_ad(space == fil_system.sys_space || space == fil_system.temp_space || srv_is_undo_tablespace(space->id) @@ -56,7 +56,7 @@ UNIV_INLINE buf_block_t* trx_rsegf_get_new( ulint space, - ulint page_no, + uint32_t page_no, mtr_t* mtr) { buf_block_t* block; diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 11c57618e53..e241c849c4e 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -535,7 +535,7 @@ struct file_name_t { fil_status status; /** FSP_SIZE of tablespace */ - ulint size = 0; + uint32_t size = 0; /** Freed pages of tablespace */ range_set freed_ranges; @@ -2467,12 +2467,12 @@ page number. @param[in] page_id page id */ static void recv_read_in_area(page_id_t page_id) { - ulint page_nos[RECV_READ_AHEAD_AREA]; + uint32_t page_nos[RECV_READ_AHEAD_AREA]; compile_time_assert(ut_is_2pow(RECV_READ_AHEAD_AREA)); page_id.set_page_no(ut_2pow_round(page_id.page_no(), RECV_READ_AHEAD_AREA)); const ulint up_limit = page_id.page_no() + RECV_READ_AHEAD_AREA; - ulint* p = page_nos; + uint32_t* p = page_nos; for (recv_sys_t::map::iterator i= recv_sys.pages.lower_bound(page_id); i != recv_sys.pages.end() diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index e0817934e67..7e24ff7ab5e 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -4501,9 +4501,9 @@ corrupted: ? ULINT_UNDEFINED : mach_read_from_4(FIL_PAGE_SPACE_ID + page); ulint flags = fsp_header_get_flags(page); - const ulint size = fsp_header_get_field(page, FSP_SIZE); - const ulint free_limit = fsp_header_get_field(page, FSP_FREE_LIMIT); - const ulint free_len = flst_get_len(FSP_HEADER_OFFSET + FSP_FREE + const uint32_t size = fsp_header_get_field(page, FSP_SIZE); + const uint32_t free_limit = fsp_header_get_field(page, FSP_FREE_LIMIT); + const uint32_t free_len = flst_get_len(FSP_HEADER_OFFSET + FSP_FREE + page); if (!fil_space_t::is_valid_flags(flags, space->id)) { ulint cflags = fsp_flags_convert_from_101(flags); @@ -4565,7 +4565,7 @@ invalid: space->flags = (space->flags & FSP_FLAGS_MEM_MASK) | flags; space->punch_hole = space->is_compressed(); - this->size = ulint(size_bytes / psize); + this->size = uint32_t(size_bytes / psize); space->committed_size = space->size += this->size; } else if (space->id != TRX_SYS_SPACE || space->size_in_header) { /* If this is not the first-time open, do nothing. diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 539c2e83f04..03706d9ae99 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -528,7 +528,7 @@ protected: /** Check if the page is marked as free in the extent descriptor. @param page_no page number to check in the extent descriptor. @return true if the page is marked as free */ - bool is_free(ulint page_no) const UNIV_NOTHROW + bool is_free(uint32_t page_no) const UNIV_NOTHROW { ut_a(xdes_calc_descriptor_page(get_zip_size(), page_no) == m_xdes_page_no); @@ -3437,7 +3437,7 @@ fil_iterate( os_offset_t page_off = offset; ulint n_pages_read = n_bytes / size; /* This block is not attached to buf_pool */ - block->page.id_.set_page_no(ulint(page_off / size)); + block->page.id_.set_page_no(uint32_t(page_off / size)); for (ulint i = 0; i < n_pages_read; ++block->page.id_, @@ -3859,7 +3859,6 @@ row_import_for_mysql( trx_t* trx; ib_uint64_t autoinc = 0; char* filepath = NULL; - ulint space_flags MY_ATTRIBUTE((unused)); /* The caller assured that this is not read_only_mode and that no temorary tablespace is being imported. */ @@ -3978,9 +3977,6 @@ row_import_for_mysql( err = cfg.set_root_by_heuristic(); } } - - space_flags = fetchIndexRootPages.get_space_flags(); - } else { rw_lock_s_unlock(&dict_sys.latch); } diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index a57a53aaaea..558bf6d5a07 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -1999,18 +1999,14 @@ end_of_index: goto write_buffers; } } else { - ulint next_page_no; - buf_block_t* block; - - next_page_no = btr_page_get_next( + uint32_t next_page_no = btr_page_get_next( page_cur_get_page(cur)); if (next_page_no == FIL_NULL) { goto end_of_index; } - block = page_cur_get_block(cur); - block = btr_block_get( + buf_block_t* block = btr_block_get( *clust_index, next_page_no, RW_S_LATCH, false, &mtr); diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 9af0738faad..401a655517f 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -1109,7 +1109,7 @@ re_scan: /* MDEV-14059 FIXME: why re-latch the block? pcur is already positioned on it! */ - ulint page_no = page_get_page_no( + uint32_t page_no = page_get_page_no( btr_pcur_get_page(pcur)); cur_block = buf_page_get_gen( diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index dba660ee13f..5f800d390bf 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -562,7 +562,7 @@ err_exit: if (create) { - space->size= file->size= ulint(size >> srv_page_size_shift); + space->size= file->size= uint32_t(size >> srv_page_size_shift); space->size_in_header= SRV_UNDO_TABLESPACE_SIZE_IN_PAGES; space->committed_size= SRV_UNDO_TABLESPACE_SIZE_IN_PAGES; } @@ -1423,7 +1423,8 @@ file_checked: ut_ad(fil_system.sys_space->id == 0); compile_time_assert(TRX_SYS_SPACE == 0); compile_time_assert(IBUF_SPACE_ID == 0); - fsp_header_init(fil_system.sys_space, sum_of_new_sizes, &mtr); + fsp_header_init(fil_system.sys_space, + uint32_t(sum_of_new_sizes), &mtr); ulint ibuf_root = btr_create( DICT_CLUSTERED | DICT_IBUF, fil_system.sys_space, @@ -1545,7 +1546,8 @@ file_checked: mtr.write<4>(*block, FSP_HEADER_OFFSET + FSP_SIZE + block->frame, size); - fil_system.sys_space->size_in_header = size; + fil_system.sys_space->size_in_header + = uint32_t(size); mtr.commit(); /* Immediately write the log record about increased tablespace size to disk, so that it diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc index fb58687beab..2aee1636084 100644 --- a/storage/innobase/trx/trx0rseg.cc +++ b/storage/innobase/trx/trx0rseg.cc @@ -391,7 +391,7 @@ trx_rseg_mem_free(trx_rseg_t* rseg) @param[in] page_no page number of the segment header */ static trx_rseg_t* -trx_rseg_mem_create(ulint id, fil_space_t* space, ulint page_no) +trx_rseg_mem_create(ulint id, fil_space_t* space, uint32_t page_no) { trx_rseg_t* rseg = static_cast( ut_zalloc_nokey(sizeof *rseg)); @@ -418,12 +418,12 @@ trx_rseg_mem_create(ulint id, fil_space_t* space, ulint page_no) @param[in,out] max_trx_id maximum observed transaction identifier @param[in] rseg_header rollback segment header @return the combined size of undo log segments in pages */ -static ulint trx_undo_lists_init(trx_rseg_t *rseg, trx_id_t &max_trx_id, - const buf_block_t *rseg_header) +static uint32_t trx_undo_lists_init(trx_rseg_t *rseg, trx_id_t &max_trx_id, + const buf_block_t *rseg_header) { ut_ad(srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN); - ulint size= 0; + uint32_t size= 0; for (ulint i= 0; i < TRX_RSEG_N_SLOTS; i++) { diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index ae3224a29a6..e6ec441bdeb 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -237,8 +237,8 @@ trx_undo_get_next_rec_from_next_page(buf_block_t *&block, uint32_t page_no, mach_read_from_2(block->frame + offset + TRX_UNDO_NEXT_LOG)) return NULL; - ulint next= flst_get_next_addr(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + - block->frame).page; + uint32_t next= flst_get_next_addr(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + + block->frame).page; if (next == FIL_NULL) return NULL; From 3e807d255e0e667eec9791dd505a5be4bbfc6a25 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 9 Oct 2020 17:48:22 +0300 Subject: [PATCH 131/323] MDEV-23938: innodb row_search_idx_cond_check handle ICP_ABORTED_BY_USER - row_search_mvcc() should return DB_INTERRUPTED when it got killed. - Add a syncpoint for the ICP check. - Add test coverage for killed-during-ICP-check scenario Backport of MDEV-22761 fixes for ICP from 10.4 commits: * a6f956488c712bef3b13660584d1b905e0c676cc * c03885cd9ceb1ede7f49a9e218022b401b3a1e28 XtraDB was fixed in deb3b9a17498 Reviewer: Daniel Black --- mysql-test/include/icp_debug_kill.inc | 50 +++++++++++++++++++++++++++ mysql-test/t/aria_icp_debug.result | 34 ++++++++++++++++++ mysql-test/t/aria_icp_debug.test | 5 +++ mysql-test/t/innodb_icp_debug.result | 34 ++++++++++++++++++ mysql-test/t/innodb_icp_debug.test | 6 ++++ mysql-test/t/myisam_icp_debug.result | 32 +++++++++++++++++ mysql-test/t/myisam_icp_debug.test | 1 + sql/handler.cc | 1 + storage/innobase/row/row0sel.cc | 19 ++++++---- 9 files changed, 176 insertions(+), 6 deletions(-) create mode 100644 mysql-test/include/icp_debug_kill.inc create mode 100644 mysql-test/t/aria_icp_debug.result create mode 100644 mysql-test/t/aria_icp_debug.test create mode 100644 mysql-test/t/innodb_icp_debug.result create mode 100644 mysql-test/t/innodb_icp_debug.test create mode 100644 mysql-test/t/myisam_icp_debug.result create mode 100644 mysql-test/t/myisam_icp_debug.test diff --git a/mysql-test/include/icp_debug_kill.inc b/mysql-test/include/icp_debug_kill.inc new file mode 100644 index 00000000000..d0ecc842869 --- /dev/null +++ b/mysql-test/include/icp_debug_kill.inc @@ -0,0 +1,50 @@ +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/count_sessions.inc + +--disable_warnings +drop table if exists t0,t1,t2; +--enable_warnings + +create table t0(a int primary key); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table t1(a int primary key); +insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C; + +create table t2 ( + kp1 int, + kp2 int, + col char(100), + key(kp1, kp2) +); +insert into t2 select a, a, a from t1; + +select engine from information_schema.tables +where table_schema=database() and table_name='t2'; + +explain +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; + +let $target_id= `select connection_id()`; + +set debug_sync='handler_index_cond_check SIGNAL at_icp_check WAIT_FOR go'; +send +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; + +connect (con1, localhost, root,,); +connection con1; +set debug_sync='now WAIT_FOR at_icp_check'; +evalp kill query $target_id; +set debug_sync='now SIGNAL go'; + +connection default; + +--error ER_QUERY_INTERRUPTED +reap; +set debug_sync='RESET'; + +disconnect con1; +drop table t0,t1,t2; +--source include/wait_until_count_sessions.inc + diff --git a/mysql-test/t/aria_icp_debug.result b/mysql-test/t/aria_icp_debug.result new file mode 100644 index 00000000000..fc01ee4fb3b --- /dev/null +++ b/mysql-test/t/aria_icp_debug.result @@ -0,0 +1,34 @@ +set default_storage_engine=aria; +drop table if exists t0,t1,t2; +create table t0(a int primary key); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1(a int primary key); +insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C; +create table t2 ( +kp1 int, +kp2 int, +col char(100), +key(kp1, kp2) +); +insert into t2 select a, a, a from t1; +select engine from information_schema.tables +where table_schema=database() and table_name='t2'; +engine +Aria +explain +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range kp1 kp1 5 NULL 10 Using index condition +set debug_sync='handler_index_cond_check SIGNAL at_icp_check WAIT_FOR go'; +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; +connect con1, localhost, root,,; +connection con1; +set debug_sync='now WAIT_FOR at_icp_check'; +kill query $target_id; +set debug_sync='now SIGNAL go'; +connection default; +ERROR 70100: Query execution was interrupted +set debug_sync='RESET'; +disconnect con1; +drop table t0,t1,t2; +set default_storage_engine=default; diff --git a/mysql-test/t/aria_icp_debug.test b/mysql-test/t/aria_icp_debug.test new file mode 100644 index 00000000000..bbdd59d6012 --- /dev/null +++ b/mysql-test/t/aria_icp_debug.test @@ -0,0 +1,5 @@ + +set default_storage_engine=aria; +--source include/icp_debug_kill.inc +set default_storage_engine=default; + diff --git a/mysql-test/t/innodb_icp_debug.result b/mysql-test/t/innodb_icp_debug.result new file mode 100644 index 00000000000..5a169650c8e --- /dev/null +++ b/mysql-test/t/innodb_icp_debug.result @@ -0,0 +1,34 @@ +set default_storage_engine=innodb; +drop table if exists t0,t1,t2; +create table t0(a int primary key); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1(a int primary key); +insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C; +create table t2 ( +kp1 int, +kp2 int, +col char(100), +key(kp1, kp2) +); +insert into t2 select a, a, a from t1; +select engine from information_schema.tables +where table_schema=database() and table_name='t2'; +engine +InnoDB +explain +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range kp1 kp1 5 NULL 11 Using index condition +set debug_sync='handler_index_cond_check SIGNAL at_icp_check WAIT_FOR go'; +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; +connect con1, localhost, root,,; +connection con1; +set debug_sync='now WAIT_FOR at_icp_check'; +kill query $target_id; +set debug_sync='now SIGNAL go'; +connection default; +ERROR 70100: Query execution was interrupted +set debug_sync='RESET'; +disconnect con1; +drop table t0,t1,t2; +set default_storage_engine=default; diff --git a/mysql-test/t/innodb_icp_debug.test b/mysql-test/t/innodb_icp_debug.test new file mode 100644 index 00000000000..4aa08c61e87 --- /dev/null +++ b/mysql-test/t/innodb_icp_debug.test @@ -0,0 +1,6 @@ +--source include/have_innodb.inc + +set default_storage_engine=innodb; +--source include/icp_debug_kill.inc +set default_storage_engine=default; + diff --git a/mysql-test/t/myisam_icp_debug.result b/mysql-test/t/myisam_icp_debug.result new file mode 100644 index 00000000000..cb45a0e2274 --- /dev/null +++ b/mysql-test/t/myisam_icp_debug.result @@ -0,0 +1,32 @@ +drop table if exists t0,t1,t2; +create table t0(a int primary key); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1(a int primary key); +insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C; +create table t2 ( +kp1 int, +kp2 int, +col char(100), +key(kp1, kp2) +); +insert into t2 select a, a, a from t1; +select engine from information_schema.tables +where table_schema=database() and table_name='t2'; +engine +MyISAM +explain +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range kp1 kp1 5 NULL 11 Using index condition +set debug_sync='handler_index_cond_check SIGNAL at_icp_check WAIT_FOR go'; +select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; +connect con1, localhost, root,,; +connection con1; +set debug_sync='now WAIT_FOR at_icp_check'; +kill query $target_id; +set debug_sync='now SIGNAL go'; +connection default; +ERROR 70100: Query execution was interrupted +set debug_sync='RESET'; +disconnect con1; +drop table t0,t1,t2; diff --git a/mysql-test/t/myisam_icp_debug.test b/mysql-test/t/myisam_icp_debug.test new file mode 100644 index 00000000000..d5b1af799fa --- /dev/null +++ b/mysql-test/t/myisam_icp_debug.test @@ -0,0 +1 @@ +--source include/icp_debug_kill.inc diff --git a/sql/handler.cc b/sql/handler.cc index 76a187f4312..09ce175e967 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -5519,6 +5519,7 @@ extern "C" enum icp_result handler_index_cond_check(void* h_arg) THD *thd= h->table->in_use; enum icp_result res; + DEBUG_SYNC(thd, "handler_index_cond_check"); enum thd_kill_levels abort_at= h->has_transactions() ? THD_ABORT_SOFTLY : THD_ABORT_ASAP; if (thd_kill_level(thd) > abort_at) diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index f45702157c8..a6654a603db 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -3588,7 +3588,7 @@ row_sel_try_search_shortcut_for_mysql( /*********************************************************************//** Check a pushed-down index condition. -@return ICP_NO_MATCH, ICP_MATCH, or ICP_OUT_OF_RANGE */ +@return ICP_ABORTED_BY_USER, ICP_NO_MATCH, ICP_MATCH, or ICP_OUT_OF_RANGE */ static enum icp_result row_search_idx_cond_check( @@ -4110,10 +4110,13 @@ row_search_for_mysql( switch (row_search_idx_cond_check( buf, prebuilt, rec, offsets)) { + case ICP_ABORTED_BY_USER: + mtr_commit(&mtr); + err = DB_INTERRUPTED; + goto release_search_latch_if_needed; + case ICP_ERROR: case ICP_NO_MATCH: case ICP_OUT_OF_RANGE: - case ICP_ABORTED_BY_USER: - case ICP_ERROR: goto shortcut_mismatch; case ICP_MATCH: goto shortcut_match; @@ -4849,8 +4852,10 @@ no_gap_lock: buf, prebuilt, rec, offsets)) { case ICP_NO_MATCH: goto next_rec; - case ICP_OUT_OF_RANGE: case ICP_ABORTED_BY_USER: + err = DB_INTERRUPTED; + goto idx_cond_failed; + case ICP_OUT_OF_RANGE: case ICP_ERROR: err = DB_RECORD_NOT_FOUND; goto idx_cond_failed; @@ -4904,9 +4909,11 @@ locks_ok_del_marked: row_unlock_for_mysql(prebuilt, TRUE); } goto next_rec; + case ICP_ABORTED_BY_USER: + err = DB_INTERRUPTED; + goto idx_cond_failed; case ICP_OUT_OF_RANGE: - case ICP_ABORTED_BY_USER: - case ICP_ERROR: + case ICP_ERROR: err = DB_RECORD_NOT_FOUND; goto idx_cond_failed; case ICP_MATCH: From a0113683d7a848be9d0403393c7b5c478cd813a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 16 Oct 2020 07:51:37 +0300 Subject: [PATCH 132/323] Fixup 9028cc6b865222cae8c396b4ec3e317c8ee068d1 We forgot to change innodb_autoextend_increment from ULONG to UINT (always 32-bit) in Mariabackup. --- extra/mariabackup/xtrabackup.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 1d98f89894a..cc7aea4e399 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -1255,7 +1255,7 @@ struct my_option xb_server_options[] = "Data file autoextend increment in megabytes", (G_PTR*) &sys_tablespace_auto_extend_increment, (G_PTR*) &sys_tablespace_auto_extend_increment, - 0, GET_ULONG, REQUIRED_ARG, 8L, 1L, 1000L, 0, 1L, 0}, + 0, GET_UINT, REQUIRED_ARG, 8, 1, 1000, 0, 1, 0}, {"innodb_data_file_path", OPT_INNODB_DATA_FILE_PATH, "Path to individual files and their sizes.", &innobase_data_file_path, &innobase_data_file_path, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, From bdbec5a2e9455dd8765900d220b5fcb12396e05a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 16 Oct 2020 17:28:23 +0300 Subject: [PATCH 133/323] MDEV-23973 Change buffer corruption when reallocating an recently freed page After commit abb678b61894146fcb88eed7f4a5facf434aea7c (a follow-up fix to MDEV-19514 to prevent potential hangs) and MDEV-23399, the probability for hitting a dormant bug that is related to MDEV-19514 was increased. buf_page_create(): Call ibuf_merge_or_delete_for_page() also when reusing a previously freed page. Reviewed by: Thirunarayanan Balathandayuthapani --- storage/innobase/buf/buf0buf.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 8c296c4f03b..031deaa0a23 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -3854,6 +3854,13 @@ loop: mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX); + if (block->page.ibuf_exist) + { + if (!recv_recovery_is_on()) + ibuf_merge_or_delete_for_page(nullptr, page_id, zip_size, true); + block->page.ibuf_exist= false; + } + return block; } From 311b7f94e6115b50e947767af3172a73508958eb Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 16 Oct 2020 15:36:12 +0300 Subject: [PATCH 134/323] MDEV-23248 Server crashes in mi_extra / ha_partition::loop_extra_alter upon REORGANIZE This also fixes some issues with MDEV-23730 s3.replication_partition 'innodb,mix' segv The problem was that mysql_change_partitions() closes all handler files in case of error, which was not properly reflected in fast_alter_partition_table(). This caused handle_alter_part_error() to try to close already closed tables, which caused the crash. Fixed fast_alter_partion_table() to reflect when tables are opened. I also fixed that ha_partition::change_partitions() resets m_new_file in case of errors. Either of the above changes fixes the issue, but both are needed to ensure that the code works as expected. --- mysql-test/suite/parts/r/reorganize.result | 13 +++++++++++++ mysql-test/suite/parts/t/reorganize.test | 20 ++++++++++++++++++++ sql/ha_partition.cc | 4 ++++ sql/sql_partition.cc | 2 +- 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/parts/r/reorganize.result create mode 100644 mysql-test/suite/parts/t/reorganize.test diff --git a/mysql-test/suite/parts/r/reorganize.result b/mysql-test/suite/parts/r/reorganize.result new file mode 100644 index 00000000000..5e6fe176edc --- /dev/null +++ b/mysql-test/suite/parts/r/reorganize.result @@ -0,0 +1,13 @@ +# +# MDEV-23248 Server crashes in mi_extra / +# ha_partition::loop_extra_alter upon REORGANIZE +# +CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM PARTITION BY RANGE (a) SUBPARTITION BY HASH (a) SUBPARTITIONS 70 (PARTITION p1 VALUES LESS THAN (100), PARTITION p2 VALUES LESS THAN MAXVALUE); +INSERT INTO t1 SELECT 4, 6 FROM seq_1_to_131072; +UPDATE t1 SET a = 7; +set @org_debug=@@debug_dbug; +set @@debug_dbug="+d,debug_abort_copy_partitions"; +ALTER TABLE t1 REORGANIZE PARTITION p1,p2 INTO (PARTITION p1 VALUES LESS THAN (5), PARTITION p2 VALUES LESS THAN MAXVALUE); +ERROR 42000: Table 't1' uses an extension that doesn't exist in this MariaDB version +set @@debug_dbug=@org_debug; +DROP TABLE t1; diff --git a/mysql-test/suite/parts/t/reorganize.test b/mysql-test/suite/parts/t/reorganize.test new file mode 100644 index 00000000000..66641254468 --- /dev/null +++ b/mysql-test/suite/parts/t/reorganize.test @@ -0,0 +1,20 @@ +--source include/have_sequence.inc +--source include/have_partition.inc +--source include/have_debug.inc + +--echo # +--echo # MDEV-23248 Server crashes in mi_extra / +--echo # ha_partition::loop_extra_alter upon REORGANIZE +--echo # + +CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM PARTITION BY RANGE (a) SUBPARTITION BY HASH (a) SUBPARTITIONS 70 (PARTITION p1 VALUES LESS THAN (100), PARTITION p2 VALUES LESS THAN MAXVALUE); +INSERT INTO t1 SELECT 4, 6 FROM seq_1_to_131072; +UPDATE t1 SET a = 7; + +set @org_debug=@@debug_dbug; +set @@debug_dbug="+d,debug_abort_copy_partitions"; +--error ER_UNSUPPORTED_EXTENSION +ALTER TABLE t1 REORGANIZE PARTITION p1,p2 INTO (PARTITION p1 VALUES LESS THAN (5), PARTITION p2 VALUES LESS THAN MAXVALUE); +set @@debug_dbug=@org_debug; + +DROP TABLE t1; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index d4cab001a9a..c742524a236 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2025,6 +2025,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, DBUG_ASSERT(part_elem->part_state == PART_TO_BE_REORGED); part_elem->part_state= PART_TO_BE_DROPPED; } + DBUG_ASSERT(m_new_file == 0); m_new_file= new_file_array; if (unlikely((error= copy_partitions(copied, deleted)))) { @@ -2033,6 +2034,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, They will later be deleted through the ddl-log. */ cleanup_new_partition(part_count); + m_new_file= 0; } DBUG_RETURN(error); } @@ -2124,6 +2126,8 @@ int ha_partition::copy_partitions(ulonglong * const copied, file->ha_rnd_end(); reorg_part++; } + DBUG_EXECUTE_IF("debug_abort_copy_partitions", + DBUG_RETURN(HA_ERR_UNSUPPORTED); ); DBUG_RETURN(FALSE); error: m_reorged_file[reorg_part]->ha_rnd_end(); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 4e9c78480b5..972684df378 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -7487,11 +7487,11 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECT_CRASH("crash_change_partition_2") || ERROR_INJECT_ERROR("fail_change_partition_2") || - (close_table_on_failure= TRUE, FALSE) || write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_3") || ERROR_INJECT_ERROR("fail_change_partition_3") || mysql_change_partitions(lpt) || + (close_table_on_failure= TRUE, FALSE) || ERROR_INJECT_CRASH("crash_change_partition_4") || ERROR_INJECT_ERROR("fail_change_partition_4") || wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) || From 6dc037a9d1af3ab56db7bf1dc69f6c46278a9224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 16 Oct 2020 22:02:54 +0300 Subject: [PATCH 135/323] MDEV-23399 fixup: Remove double-free of a buffer page In commit 7cffb5f6e8a231a041152447be8980ce35d2c9b8 we changed the interface of buf_page_create() so that the free_block is allocated by the caller. Both calls to buf_LRU_block_free_non_file_page() should have been removed. This caused an assertion failure 'block->page.state() == BUF_BLOCK_MEMORY' in buf_LRU_block_free_non_file_page(). The bug only affected ROW_FORMAT=COMPRESSED pages. --- storage/innobase/buf/buf0buf.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 031deaa0a23..9408ce7bf62 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -3827,7 +3827,6 @@ loop: if (block->page.io_fix() != BUF_IO_NONE) { hash_lock->write_unlock(); - buf_LRU_block_free_non_file_page(free_block); mysql_mutex_unlock(&buf_pool.mutex); goto loop; } From db02c458c9db93e754b8ae259d8c276fa3bb44f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sat, 17 Oct 2020 13:13:01 +0300 Subject: [PATCH 136/323] Clean up some encryption tests Instead of pointlessly waiting for a page flush to occur, take the matter into our own hands and request an explicit flush. Also, test with the minimum necessary amount of data (0 or 1 rows) so that both page encryption and decryption will be exercised. --- .../innodb-page_encryption_compression.result | 18 ++++ ...nodb-page_encryption_log_encryption.result | 84 ++++++++++--------- .../t/innodb-page_encryption_compression.test | 15 +++- ...innodb-page_encryption_log_encryption.test | 68 ++++++--------- 4 files changed, 101 insertions(+), 84 deletions(-) diff --git a/mysql-test/suite/encryption/r/innodb-page_encryption_compression.result b/mysql-test/suite/encryption/r/innodb-page_encryption_compression.result index 808345ab4ca..e8e88a1e41f 100644 --- a/mysql-test/suite/encryption/r/innodb-page_encryption_compression.result +++ b/mysql-test/suite/encryption/r/innodb-page_encryption_compression.result @@ -41,6 +41,14 @@ call innodb_insert_proc(2000); insert into innodb_compact select * from innodb_normal; insert into innodb_dynamic select * from innodb_normal; commit; +FLUSH TABLES innodb_compact FOR EXPORT; +UNLOCK TABLES; +FLUSH TABLES innodb_dynamic FOR EXPORT; +UNLOCK TABLES; +select variable_value > 0 from information_schema.global_status +where variable_name = 'INNODB_NUM_PAGES_PAGE_COMPRESSED'; +variable_value > 0 +1 set global innodb_compression_algorithm = 1; alter table innodb_normal engine=innodb page_compressed=DEFAULT; show create table innodb_normal; @@ -63,6 +71,16 @@ innodb_dynamic CREATE TABLE `innodb_dynamic` ( `c1` bigint(20) NOT NULL, `b` char(200) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC +FLUSH TABLES innodb_normal FOR EXPORT; +UNLOCK TABLES; +FLUSH TABLES innodb_compact FOR EXPORT; +UNLOCK TABLES; +FLUSH TABLES innodb_dynamic FOR EXPORT; +UNLOCK TABLES; +select variable_value > 0 from information_schema.global_status +where variable_name = 'INNODB_NUM_PAGES_PAGE_DECOMPRESSED'; +variable_value > 0 +1 drop procedure innodb_insert_proc; drop table innodb_normal; drop table innodb_compact; diff --git a/mysql-test/suite/encryption/r/innodb-page_encryption_log_encryption.result b/mysql-test/suite/encryption/r/innodb-page_encryption_log_encryption.result index 189be75b83f..a550b6b01b3 100644 --- a/mysql-test/suite/encryption/r/innodb-page_encryption_log_encryption.result +++ b/mysql-test/suite/encryption/r/innodb-page_encryption_log_encryption.result @@ -37,40 +37,43 @@ innodb_redundant CREATE TABLE `innodb_redundant` ( `c1` bigint(20) NOT NULL, `b` char(200) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=REDUNDANT `encrypted`=yes `encryption_key_id`=4 -create procedure innodb_insert_proc (repeat_count int) -begin -declare current_num int; -set current_num = 0; -while current_num < repeat_count do -insert into innodb_normal values(current_num, substring(MD5(RAND()), -64)); -set current_num = current_num + 1; -end while; -end// -commit; -begin; -call innodb_insert_proc(2000); -insert into innodb_compact select * from innodb_normal; -insert into innodb_compressed select * from innodb_normal; -insert into innodb_dynamic select * from innodb_normal; -insert into innodb_redundant select * from innodb_normal; -commit; -SELECT variable_value > 0 FROM information_schema.global_status WHERE variable_name = 'innodb_num_pages_encrypted'; -variable_value > 0 -1 -SELECT variable_value >= 0 FROM information_schema.global_status WHERE variable_name = 'innodb_num_pages_decrypted'; -variable_value >= 0 -1 -update innodb_normal set c1 = c1 +1; -update innodb_compact set c1 = c1 + 1; -update innodb_compressed set c1 = c1 + 1; -update innodb_dynamic set c1 = c1 + 1; -update innodb_redundant set c1 = c1 + 1; -SELECT variable_value > 0 FROM information_schema.global_status WHERE variable_name = 'innodb_num_pages_encrypted'; -variable_value > 0 -1 -SELECT variable_value > 0 FROM information_schema.global_status WHERE variable_name = 'innodb_num_pages_decrypted'; +FLUSH TABLES innodb_normal FOR EXPORT; +UNLOCK TABLES; +FLUSH TABLES innodb_compact FOR EXPORT; +UNLOCK TABLES; +FLUSH TABLES innodb_compressed FOR EXPORT; +UNLOCK TABLES; +FLUSH TABLES innodb_dynamic FOR EXPORT; +UNLOCK TABLES; +FLUSH TABLES innodb_redundant FOR EXPORT; +UNLOCK TABLES; +select variable_value > 0 from information_schema.global_status +where variable_name = 'INNODB_NUM_PAGES_ENCRYPTED'; variable_value > 0 1 +BEGIN; +INSERT INTO innodb_normal SET c1 = 1; +INSERT INTO innodb_compact SET c1 = 1; +INSERT INTO innodb_compressed SET c1 = 1; +INSERT INTO innodb_dynamic SET c1 = 1; +INSERT INTO innodb_redundant SET c1 = 1; +COMMIT; +FLUSH TABLES innodb_normal FOR EXPORT; +UNLOCK TABLES; +FLUSH TABLES innodb_compact FOR EXPORT; +UNLOCK TABLES; +FLUSH TABLES innodb_compressed FOR EXPORT; +UNLOCK TABLES; +FLUSH TABLES innodb_dynamic FOR EXPORT; +UNLOCK TABLES; +FLUSH TABLES innodb_redundant FOR EXPORT; +UNLOCK TABLES; +select variable_name from information_schema.global_status +where variable_value > 0 and variable_name +IN ('INNODB_NUM_PAGES_ENCRYPTED','INNODB_NUM_PAGES_DECRYPTED'); +variable_name +INNODB_NUM_PAGES_ENCRYPTED +INNODB_NUM_PAGES_DECRYPTED SET GLOBAL innodb_encrypt_tables=OFF; alter table innodb_compact engine=innodb encrypted=DEFAULT encryption_key_id=DEFAULT; show create table innodb_compact; @@ -100,13 +103,16 @@ innodb_redundant CREATE TABLE `innodb_redundant` ( `c1` bigint(20) NOT NULL, `b` char(200) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=REDUNDANT -SELECT variable_value >= 0 FROM information_schema.global_status WHERE variable_name = 'innodb_num_pages_encrypted'; -variable_value >= 0 -1 -SELECT variable_value >= 0 FROM information_schema.global_status WHERE variable_name = 'innodb_num_pages_decrypted'; -variable_value >= 0 -1 -drop procedure innodb_insert_proc; +FLUSH TABLES innodb_normal FOR EXPORT; +UNLOCK TABLES; +FLUSH TABLES innodb_compact FOR EXPORT; +UNLOCK TABLES; +FLUSH TABLES innodb_compressed FOR EXPORT; +UNLOCK TABLES; +FLUSH TABLES innodb_dynamic FOR EXPORT; +UNLOCK TABLES; +FLUSH TABLES innodb_redundant FOR EXPORT; +UNLOCK TABLES; drop table innodb_normal; drop table innodb_compact; drop table innodb_compressed; diff --git a/mysql-test/suite/encryption/t/innodb-page_encryption_compression.test b/mysql-test/suite/encryption/t/innodb-page_encryption_compression.test index d902fa38508..5fe6f686576 100644 --- a/mysql-test/suite/encryption/t/innodb-page_encryption_compression.test +++ b/mysql-test/suite/encryption/t/innodb-page_encryption_compression.test @@ -37,8 +37,10 @@ insert into innodb_compact select * from innodb_normal; insert into innodb_dynamic select * from innodb_normal; commit; -let $wait_condition= select variable_value > 0 from information_schema.global_status where variable_name = 'INNODB_NUM_PAGES_PAGE_COMPRESSED'; ---source include/wait_condition.inc +FLUSH TABLES innodb_compact FOR EXPORT; UNLOCK TABLES; +FLUSH TABLES innodb_dynamic FOR EXPORT; UNLOCK TABLES; +select variable_value > 0 from information_schema.global_status +where variable_name = 'INNODB_NUM_PAGES_PAGE_COMPRESSED'; --let $restart_parameters=--innodb-encrypt-tables=OFF --source include/restart_mysqld.inc @@ -52,8 +54,13 @@ alter table innodb_compact engine=innodb encrypted=DEFAULT encryption_key_id=DEF show create table innodb_compact; alter table innodb_dynamic engine=innodb encrypted=DEFAULT encryption_key_id=DEFAULT page_compressed=DEFAULT; show create table innodb_dynamic; -let $wait_condition= select variable_value > 0 from information_schema.global_status where variable_name = 'INNODB_NUM_PAGES_PAGE_DECOMPRESSED'; ---source include/wait_condition.inc + +FLUSH TABLES innodb_normal FOR EXPORT; UNLOCK TABLES; +FLUSH TABLES innodb_compact FOR EXPORT; UNLOCK TABLES; +FLUSH TABLES innodb_dynamic FOR EXPORT; UNLOCK TABLES; + +select variable_value > 0 from information_schema.global_status +where variable_name = 'INNODB_NUM_PAGES_PAGE_DECOMPRESSED'; drop procedure innodb_insert_proc; drop table innodb_normal; diff --git a/mysql-test/suite/encryption/t/innodb-page_encryption_log_encryption.test b/mysql-test/suite/encryption/t/innodb-page_encryption_log_encryption.test index 5b472094653..a736c7292ad 100644 --- a/mysql-test/suite/encryption/t/innodb-page_encryption_log_encryption.test +++ b/mysql-test/suite/encryption/t/innodb-page_encryption_log_encryption.test @@ -18,47 +18,34 @@ show create table innodb_compressed; show create table innodb_dynamic; show create table innodb_redundant; -delimiter //; -create procedure innodb_insert_proc (repeat_count int) -begin - declare current_num int; - set current_num = 0; - while current_num < repeat_count do - insert into innodb_normal values(current_num, substring(MD5(RAND()), -64)); - set current_num = current_num + 1; - end while; -end// -delimiter ;// -commit; +FLUSH TABLES innodb_normal FOR EXPORT; UNLOCK TABLES; +FLUSH TABLES innodb_compact FOR EXPORT; UNLOCK TABLES; +FLUSH TABLES innodb_compressed FOR EXPORT; UNLOCK TABLES; +FLUSH TABLES innodb_dynamic FOR EXPORT; UNLOCK TABLES; +FLUSH TABLES innodb_redundant FOR EXPORT; UNLOCK TABLES; -begin; -call innodb_insert_proc(2000); -insert into innodb_compact select * from innodb_normal; -insert into innodb_compressed select * from innodb_normal; -insert into innodb_dynamic select * from innodb_normal; -insert into innodb_redundant select * from innodb_normal; -commit; - -let $wait_condition= select variable_value > 0 from information_schema.global_status where variable_name = 'INNODB_NUM_PAGES_ENCRYPTED'; ---source include/wait_condition.inc - -# Note there that these variables are updated only when real I/O is done, thus they are not reliable -SELECT variable_value > 0 FROM information_schema.global_status WHERE variable_name = 'innodb_num_pages_encrypted'; -SELECT variable_value >= 0 FROM information_schema.global_status WHERE variable_name = 'innodb_num_pages_decrypted'; +select variable_value > 0 from information_schema.global_status +where variable_name = 'INNODB_NUM_PAGES_ENCRYPTED'; --source include/restart_mysqld.inc -update innodb_normal set c1 = c1 +1; -update innodb_compact set c1 = c1 + 1; -update innodb_compressed set c1 = c1 + 1; -update innodb_dynamic set c1 = c1 + 1; -update innodb_redundant set c1 = c1 + 1; +BEGIN; +INSERT INTO innodb_normal SET c1 = 1; +INSERT INTO innodb_compact SET c1 = 1; +INSERT INTO innodb_compressed SET c1 = 1; +INSERT INTO innodb_dynamic SET c1 = 1; +INSERT INTO innodb_redundant SET c1 = 1; +COMMIT; -let $wait_condition= select variable_value > 0 from information_schema.global_status where variable_name = 'INNODB_NUM_PAGES_ENCRYPTED'; ---source include/wait_condition.inc +FLUSH TABLES innodb_normal FOR EXPORT; UNLOCK TABLES; +FLUSH TABLES innodb_compact FOR EXPORT; UNLOCK TABLES; +FLUSH TABLES innodb_compressed FOR EXPORT; UNLOCK TABLES; +FLUSH TABLES innodb_dynamic FOR EXPORT; UNLOCK TABLES; +FLUSH TABLES innodb_redundant FOR EXPORT; UNLOCK TABLES; -SELECT variable_value > 0 FROM information_schema.global_status WHERE variable_name = 'innodb_num_pages_encrypted'; -SELECT variable_value > 0 FROM information_schema.global_status WHERE variable_name = 'innodb_num_pages_decrypted'; +select variable_name from information_schema.global_status +where variable_value > 0 and variable_name +IN ('INNODB_NUM_PAGES_ENCRYPTED','INNODB_NUM_PAGES_DECRYPTED'); SET GLOBAL innodb_encrypt_tables=OFF; alter table innodb_compact engine=innodb encrypted=DEFAULT encryption_key_id=DEFAULT; @@ -70,13 +57,12 @@ show create table innodb_dynamic; alter table innodb_redundant engine=innodb encrypted=DEFAULT encryption_key_id=DEFAULT; show create table innodb_redundant; -let $wait_condition= select variable_value > 0 from information_schema.global_status where variable_name = 'INNODB_NUM_PAGES_DECRYPTED'; ---source include/wait_condition.inc +FLUSH TABLES innodb_normal FOR EXPORT; UNLOCK TABLES; +FLUSH TABLES innodb_compact FOR EXPORT; UNLOCK TABLES; +FLUSH TABLES innodb_compressed FOR EXPORT; UNLOCK TABLES; +FLUSH TABLES innodb_dynamic FOR EXPORT; UNLOCK TABLES; +FLUSH TABLES innodb_redundant FOR EXPORT; UNLOCK TABLES; -SELECT variable_value >= 0 FROM information_schema.global_status WHERE variable_name = 'innodb_num_pages_encrypted'; -SELECT variable_value >= 0 FROM information_schema.global_status WHERE variable_name = 'innodb_num_pages_decrypted'; - -drop procedure innodb_insert_proc; drop table innodb_normal; drop table innodb_compact; drop table innodb_compressed; From 95bb3cb886cb64be3ee5ace660bb78618dd4c1d0 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Tue, 6 Oct 2020 17:43:13 +0200 Subject: [PATCH 137/323] MDEV-16676 Using malloc-lib=jemalloc in MariaDB 10.2 causes non-critical error about missing mysql_config on startup - This commit is based on patch 84fe9720a4d2483ff67b6a and suggestion of Jean Weisbuch to use `ldconfig -p` - Format of ldconfig output: "libjemalloc.so.1 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libjemalloc.so.1" ``` $ ./scripts/mysqld_safe 201013 13:36:50 mysqld_safe Adding '/usr/lib/x86_64-linux-gnu/libjemalloc.so.1' to LD_PRELOAD for mysqld 201013 13:36:50 mysqld_safe Logging to '/home/anel/builds/data-10.5/mysqld_safe_anel.err'. 201013 13:36:50 mysqld_safe Starting mysqld daemon with databases from /home/anel/builds/data-10.5 ``` Reviewed by: Daniel Black, Faustin Lammler --- scripts/mysqld_safe.sh | 56 +++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 07fa304a4cf..0110653be90 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -456,25 +456,10 @@ mysqld_ld_preload_text() { echo "$text" } - -mysql_config= -get_mysql_config() { - if [ -z "$mysql_config" ]; then - mysql_config=`echo "$0" | sed 's,/[^/][^/]*$,/mysql_config,'` - if [ ! -x "$mysql_config" ]; then - log_error "Can not run mysql_config $@ from '$mysql_config'" - exit 1 - fi - fi - - "$mysql_config" "$@" -} - - # set_malloc_lib LIB # - If LIB is empty, do nothing and return -# - If LIB starts with 'tcmalloc' or 'jemalloc', look for the shared library in -# /usr/lib, /usr/lib64 and then pkglibdir. +# - 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 # @@ -482,28 +467,28 @@ get_mysql_config() { # running mysqld. See ld.so for details. set_malloc_lib() { malloc_lib="$1" - if expr "$malloc_lib" : "\(tcmalloc\|jemalloc\)" > /dev/null ; then - pkglibdir=`get_mysql_config --variable=pkglibdir` - where='' - # This list is kept intentionally simple. Simply set --malloc-lib - # to a full path if another location is desired. - for libdir in /usr/lib /usr/lib64 "$pkglibdir" "$pkglibdir/mysql"; do - tmp=`echo "$libdir/lib$malloc_lib.so".[0-9]` - where="$where $libdir" - # log_notice "DEBUG: Checking for malloc lib '$tmp'" - [ -r "$tmp" ] || continue - malloc_lib="$tmp" - where='' - break - done - - if [ -n "$where" ]; then - log_error "no shared library for lib$malloc_lib.so.[0-9] found in$where" + if ! my_which ldconfig > /dev/null 2>&1 + then + log_error "ldconfig command not found, required for ldconfig -p" exit 1 fi - 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 @@ -520,7 +505,6 @@ set_malloc_lib() { exit 1 ;; esac - add_mysqld_ld_preload "$malloc_lib" } From dc3a693b7039cb4b1d46d797ca86364ac3173be7 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Sun, 18 Oct 2020 17:20:44 +0200 Subject: [PATCH 138/323] - Inline MakePtr and MakeOff with OFFSET as size_t Also add a new member Saved_Size in the Global structure. modified: storage/connect/global.h modified: storage/connect/plugutil.cpp modified: storage/connect/user_connect.cc modified: storage/connect/jsonudf.cpp - Add session variables json_all_path and default_depth modified: storage/connect/ha_connect.cc modified: storage/connect/mongo.cpp modified: storage/connect/tabjson.cpp modified: storage/connect/tabxml.cpp - ADD column options JPATH and XPATH Work as FIELD_FORMAT but are more readable modified: storage/connect/ha_connect.cc modified: storage/connect/ha_connect.h modified: storage/connect/mysql-test/connect/r/json_java_2.result modified: storage/connect/mysql-test/connect/r/json_java_3.result modified: storage/connect/mysql-test/connect/r/json_mongo_c.result - Handle negative numbes in the option list modified: storage/connect/ha_connect.cc - Fix Json parse that could crash the server. Was because it could use THROW out of the TRY block. Also handle all error by THROW. It is now done by a new class JSON. modified: storage/connect/json.cpp modified: storage/connect/json.h - Add a new UDF function jfile_translate. It translate a Json file to pretty = 0. Fast because it does not a real parse of the file. modified: storage/connect/jsonudf.cpp modified: storage/connect/jsonudf.h - Add a now options JSIZE and STRINGIFY to Json tables. STRINGIFY makes Objects or Arrays to be returned by their json representation instead of by their concatenated values. JSIZE allows to specify the LRECL (was 256) defaults to 1024. Also fix a bug about locating the sub-table by its path. modified: storage/connect/tabjson.cpp modified: storage/connect/tabjson.h --- storage/connect/global.h | 40 +- storage/connect/ha_connect.cc | 186 ++++--- storage/connect/ha_connect.h | 4 +- storage/connect/json.cpp | 164 +++--- storage/connect/json.h | 33 +- storage/connect/jsonudf.cpp | 500 +++++++++++++++++- storage/connect/jsonudf.h | 39 ++ storage/connect/mongo.cpp | 10 +- .../mysql-test/connect/r/json_java_2.result | 36 +- .../mysql-test/connect/r/json_java_3.result | 36 +- .../mysql-test/connect/r/json_mongo_c.result | 36 +- storage/connect/plugutil.cpp | 43 +- storage/connect/tabjson.cpp | 51 +- storage/connect/tabjson.h | 4 +- storage/connect/tabxml.cpp | 6 +- storage/connect/user_connect.cc | 9 +- 16 files changed, 836 insertions(+), 361 deletions(-) diff --git a/storage/connect/global.h b/storage/connect/global.h index 548d047ccc9..d17620861fa 100644 --- a/storage/connect/global.h +++ b/storage/connect/global.h @@ -89,14 +89,10 @@ extern "C" { #define PAT_LOG "log" #if defined(UNIX) || defined(LINUX) || defined(UNIV_LINUX) - /*********************************************************************/ - /* printf does not accept null pointer for %s target. */ - /*********************************************************************/ + // printf does not accept null pointer for %s target #define SVP(S) ((S) ? S : "") #else - /*********************************************************************/ - /* printf accepts null pointer for %s target. */ - /*********************************************************************/ + // printf accepts null pointer for %s target #define SVP(S) S #endif @@ -112,9 +108,6 @@ extern "C" { /***********************************************************************/ #include "os.h" -typedef size_t OFFSET; -typedef char NAME[9]; - typedef struct { ushort Length; char String[2]; @@ -127,6 +120,7 @@ typedef struct _global *PGLOBAL; typedef struct _globplg *PGS; typedef struct _activity *PACTIVITY; typedef struct _parm *PPARM; +typedef char NAME[9]; /***********************************************************************/ /* Segment Sub-Allocation block structure declares. */ @@ -135,7 +129,7 @@ typedef struct _parm *PPARM; /* restore them if needed. This scheme implies that no SubFree be used */ /***********************************************************************/ typedef struct { /* Plug Area SubAlloc header */ - OFFSET To_Free; /* Offset of next free block */ + size_t To_Free; /* Offset of next free block */ size_t FreeBlk; /* Size of remaining free memory */ } POOLHEADER, *PPOOLHEADER; @@ -190,9 +184,10 @@ typedef struct _global { /* Global structure */ void *Sarea; /* Points to work area */ size_t Sarea_Size; /* Work area size */ PACTIVITY Activityp; - char Message[MAX_STR]; + char Message[MAX_STR]; /* Message (result, error, trace) */ ulong More; /* Used by jsonudf */ - int Createas; /* To pass multi to ext tables */ + size_t Saved_Size; /* Saved work area to_free */ + bool Createas; /* To pass multi to ext tables */ void *Xchk; /* indexes in create/alter */ short Alchecked; /* Checked for ALTER */ short Mrr; /* True when doing mrr */ @@ -222,7 +217,6 @@ DllExport void FreeSarea(PGLOBAL); DllExport BOOL PlugSubSet(void *, size_t); DllExport void *PlugSubAlloc(PGLOBAL, void *, size_t); DllExport char *PlugDup(PGLOBAL g, const char *str); -DllExport void *MakePtr(void *, OFFSET); DllExport void htrc(char const *fmt, ...); DllExport void xtrc(uint, char const* fmt, ...); DllExport uint GetTraceValue(void); @@ -232,8 +226,24 @@ DllExport uint GetTraceValue(void); #endif /***********************************************************************/ -/* Non exported routine declarations. */ +/* Inline routine definitions. */ /***********************************************************************/ -//void *PlugSubAlloc(PGLOBAL, void *, size_t); // Does throw +/***********************************************************************/ +/* This routine makes a pointer from an offset to a memory pointer. */ +/***********************************************************************/ +inline void* MakePtr(void* memp, size_t offset) { + // return ((offset == 0) ? NULL : &((char*)memp)[offset]); + return (!offset) ? NULL : (char *)memp + offset; +} /* end of MakePtr */ + +/***********************************************************************/ +/* This routine makes an offset from a pointer new format. */ +/***********************************************************************/ +inline size_t MakeOff(void* memp, void* ptr) { +#if defined(_DEBUG) + assert(ptr > memp); +#endif // _DEBUG + return ((!ptr) ? 0 : (size_t)((char*)ptr - (size_t)memp)); +} /* end of MakeOff */ /*-------------------------- End of Global.H --------------------------*/ diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index fd00b4878a9..a3dfc50562d 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -170,7 +170,7 @@ #define JSONMAX 10 // JSON Default max grp size extern "C" { - char version[]= "Version 1.07.0002 October 03, 2020"; + char version[]= "Version 1.07.0002 October 18, 2020"; #if defined(__WIN__) char compver[]= "Version 1.07.0002 " __DATE__ " " __TIME__; char slash= '\\'; @@ -251,6 +251,7 @@ bool ExactInfo(void); USETEMP UseTemp(void); int GetConvSize(void); TYPCONV GetTypeConv(void); +bool JsonAllPath(void); char *GetJsonNull(void); uint GetJsonGrpSize(void); char *GetJavaWrapper(void); @@ -394,6 +395,11 @@ static MYSQL_THDVAR_ENUM( 1, // def (yes) &xconv_typelib); // typelib +// Adding JPATH to all Json table columns +static MYSQL_THDVAR_BOOL(json_all_path, PLUGIN_VAR_RQCMDARG, + "Adding JPATH to all Json table columns", + NULL, NULL, 0); // NO by default + // Null representation for JSON values static MYSQL_THDVAR_STR(json_null, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC, @@ -401,6 +407,12 @@ static MYSQL_THDVAR_STR(json_null, // check_json_null, update_json_null, NULL, NULL, ""); +// Default Json, XML or Mongo depth +static MYSQL_THDVAR_INT(default_depth, + PLUGIN_VAR_RQCMDARG, + "Default depth used by Json, XML and Mongo discovery", + NULL, NULL, 0, -1, 16, 1); + // Estimate max number of rows for JSON aggregate functions static MYSQL_THDVAR_UINT(json_grp_size, PLUGIN_VAR_RQCMDARG, // opt @@ -462,11 +474,13 @@ uint GetTraceValue(void) {return (uint)(connect_hton ? THDVAR(current_thd, xtrace) : 0);} bool ExactInfo(void) {return THDVAR(current_thd, exact_info);} static bool CondPushEnabled(void) {return THDVAR(current_thd, cond_push);} +bool JsonAllPath(void) {return THDVAR(current_thd, json_all_path);} USETEMP UseTemp(void) {return (USETEMP)THDVAR(current_thd, use_tempfile);} int GetConvSize(void) {return THDVAR(current_thd, conv_size);} TYPCONV GetTypeConv(void) {return (TYPCONV)THDVAR(current_thd, type_conv);} char *GetJsonNull(void) {return connect_hton ? THDVAR(current_thd, json_null) : NULL;} +int GetDefaultDepth(void) {return THDVAR(current_thd, default_depth);} uint GetJsonGrpSize(void) {return connect_hton ? THDVAR(current_thd, json_grp_size) : 10;} size_t GetWorkSize(void) {return (size_t)THDVAR(current_thd, work_size);} @@ -630,8 +644,10 @@ ha_create_table_option connect_field_option_list[]= HA_FOPTION_NUMBER("FIELD_LENGTH", fldlen, 0, 0, INT_MAX32, 1), HA_FOPTION_STRING("DATE_FORMAT", dateformat), HA_FOPTION_STRING("FIELD_FORMAT", fieldformat), - HA_FOPTION_STRING("SPECIAL", special), - HA_FOPTION_ENUM("DISTRIB", opt, "scattered,clustered,sorted", 0), + HA_FOPTION_STRING("JPATH", jsonpath), + HA_FOPTION_STRING("XPATH", xmlpath), + HA_FOPTION_STRING("SPECIAL", special), + HA_FOPTION_ENUM("DISTRIB", opt, "scattered,clustered,sorted", 0), HA_FOPTION_END }; @@ -1322,9 +1338,10 @@ int GetIntegerTableOption(PGLOBAL g, PTOS options, PCSZ opname, int idef) if ((ulonglong) opval == (ulonglong)NO_IVAL) { PCSZ pv; - if ((pv= GetListOption(g, opname, options->oplist))) - opval= CharToNumber((char*)pv, strlen(pv), ULONGLONG_MAX, true); - else + if ((pv = GetListOption(g, opname, options->oplist))) { + // opval = CharToNumber((char*)pv, strlen(pv), ULONGLONG_MAX, false); + return atoi(pv); + } else return idef; } // endif opval @@ -1576,8 +1593,9 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf) pcf->Offset= (int)fop->offset; pcf->Freq= (int)fop->freq; pcf->Datefmt= (char*)fop->dateformat; - pcf->Fieldfmt= (char*)fop->fieldformat; - } else { + pcf->Fieldfmt = fop->fieldformat ? (char*)fop->fieldformat + : fop->jsonpath ? (char*)fop->jsonpath : (char*)fop->xmlpath; + } else { pcf->Offset= -1; pcf->Freq= 0; pcf->Datefmt= NULL; @@ -4984,7 +5002,7 @@ int ha_connect::check_stmt(PGLOBAL g, MODE newmode, bool cras) } // endif CheckCleanup if (cras) - g->Createas= 1; // To tell external tables of a multi-table command + g->Createas= true; // To tell external tables of a multi-table command if (trace(1)) htrc("Calling CntCheckDB db=%s cras=%d\n", GetDBName(NULL), cras); @@ -5334,96 +5352,100 @@ static char *encode(PGLOBAL g, const char *cnm) @return Return 0 if ok */ -static bool add_field(String *sql, const char *field_name, int typ, int len, - int dec, char *key, uint tm, const char *rem, char *dft, - char *xtra, char *fmt, int flag, bool dbf, char v) -{ +static bool add_field(String* sql, TABTYPE ttp, const char* field_name, int typ, + int len, int dec, char* key, uint tm, const char* rem, + char* dft, char* xtra, char* fmt, int flag, bool dbf, char v) { #if defined(DEVELOPMENT) // Some client programs regard CHAR(36) as GUID - char var= (len > 255 || len == 36) ? 'V' : v; + char var = (len > 255 || len == 36) ? 'V' : v; #else char var = (len > 255) ? 'V' : v; #endif - bool q, error= false; - const char *type= PLGtoMYSQLtype(typ, dbf, var); + bool q, error = false; + const char* type = PLGtoMYSQLtype(typ, dbf, var); - error|= sql->append('`'); - error|= sql->append(field_name); - error|= sql->append("` "); - error|= sql->append(type); + error |= sql->append('`'); + error |= sql->append(field_name); + error |= sql->append("` "); + error |= sql->append(type); - if (typ == TYPE_STRING || - (len && typ != TYPE_DATE && (typ != TYPE_DOUBLE || dec >= 0))) { - error|= sql->append('('); - error|= sql->append_ulonglong(len); + if (typ == TYPE_STRING || + (len && typ != TYPE_DATE && (typ != TYPE_DOUBLE || dec >= 0))) { + error |= sql->append('('); + error |= sql->append_ulonglong(len); if (typ == TYPE_DOUBLE) { - error|= sql->append(','); - // dec must be < len and < 31 - error|= sql->append_ulonglong(MY_MIN(dec, (MY_MIN(len, 31) - 1))); - } else if (dec > 0 && !strcmp(type, "DECIMAL")) { - error|= sql->append(','); - // dec must be < len - error|= sql->append_ulonglong(MY_MIN(dec, len - 1)); - } // endif dec + error |= sql->append(','); + // dec must be < len and < 31 + error |= sql->append_ulonglong(MY_MIN(dec, (MY_MIN(len, 31) - 1))); + } else if (dec > 0 && !strcmp(type, "DECIMAL")) { + error |= sql->append(','); + // dec must be < len + error |= sql->append_ulonglong(MY_MIN(dec, len - 1)); + } // endif dec - error|= sql->append(')'); - } // endif len + error |= sql->append(')'); + } // endif len - if (v == 'U') - error|= sql->append(" UNSIGNED"); - else if (v == 'Z') - error|= sql->append(" ZEROFILL"); + if (v == 'U') + error |= sql->append(" UNSIGNED"); + else if (v == 'Z') + error |= sql->append(" ZEROFILL"); - if (key && *key) { - error|= sql->append(" "); - error|= sql->append(key); - } // endif key + if (key && *key) { + error |= sql->append(" "); + error |= sql->append(key); + } // endif key - if (tm) - error|= sql->append(STRING_WITH_LEN(" NOT NULL"), system_charset_info); + if (tm) + error |= sql->append(STRING_WITH_LEN(" NOT NULL"), system_charset_info); - if (dft && *dft) { - error|= sql->append(" DEFAULT "); + if (dft && *dft) { + error |= sql->append(" DEFAULT "); - if (typ == TYPE_DATE) - q= (strspn(dft, "0123456789 -:/") == strlen(dft)); - else - q= !IsTypeNum(typ); + if (typ == TYPE_DATE) + q = (strspn(dft, "0123456789 -:/") == strlen(dft)); + else + q = !IsTypeNum(typ); - if (q) { - error|= sql->append("'"); - error|= sql->append_for_single_quote(dft, strlen(dft)); - error|= sql->append("'"); - } else - error|= sql->append(dft); + if (q) { + error |= sql->append("'"); + error |= sql->append_for_single_quote(dft, strlen(dft)); + error |= sql->append("'"); + } else + error |= sql->append(dft); - } // endif dft + } // endif dft - if (xtra && *xtra) { - error|= sql->append(" "); - error|= sql->append(xtra); - } // endif rem + if (xtra && *xtra) { + error |= sql->append(" "); + error |= sql->append(xtra); + } // endif rem - if (rem && *rem) { - error|= sql->append(" COMMENT '"); - error|= sql->append_for_single_quote(rem, strlen(rem)); - error|= sql->append("'"); - } // endif rem + if (rem && *rem) { + error |= sql->append(" COMMENT '"); + error |= sql->append_for_single_quote(rem, strlen(rem)); + error |= sql->append("'"); + } // endif rem - if (fmt && *fmt) { - error|= sql->append(" FIELD_FORMAT='"); - error|= sql->append_for_single_quote(fmt, strlen(fmt)); - error|= sql->append("'"); - } // endif flag + if (fmt && *fmt) { + switch (ttp) { + case TAB_JSON: error |= sql->append(" JPATH='"); break; + case TAB_XML: error |= sql->append(" XPATH='"); break; + default: error |= sql->append(" FIELD_FORMAT='"); + } // endswitch ttp - if (flag) { - error|= sql->append(" FLAG="); - error|= sql->append_ulonglong(flag); - } // endif flag + error |= sql->append_for_single_quote(fmt, strlen(fmt)); + error |= sql->append("'"); + } // endif flag - error|= sql->append(','); - return error; + if (flag) { + error |= sql->append(" FLAG="); + error |= sql->append_ulonglong(flag); + } // endif flag + + error |= sql->append(','); + return error; } // end of add_field /** @@ -6045,7 +6067,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, len= 256; // STRBLK's have 0 length // Now add the field - if (add_field(&sql, cnm, typ, len, dec, NULL, tm, + if (add_field(&sql, ttp, cnm, typ, len, dec, NULL, tm, NULL, NULL, NULL, NULL, flg, dbf, v)) rc= HA_ERR_OUT_OF_MEM; } // endfor crp @@ -6239,7 +6261,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, prec= 0; // Now add the field - if (add_field(&sql, cnm, typ, prec, dec, key, tm, rem, dft, xtra, + if (add_field(&sql, ttp, cnm, typ, prec, dec, key, tm, rem, dft, xtra, fmt, flg, dbf, v)) rc= HA_ERR_OUT_OF_MEM; } // endfor i @@ -6992,7 +7014,7 @@ bool ha_connect::NoFieldOptionChange(TABLE *tab) fop1->fldlen == fop2->fldlen && CheckString(fop1->dateformat, fop2->dateformat) && CheckString(fop1->fieldformat, fop2->fieldformat) && - CheckString(fop1->special, fop2->special)); + CheckString(fop1->special, fop2->special)); } // endfor fld return rc; @@ -7362,7 +7384,9 @@ static struct st_mysql_sys_var* connect_system_variables[]= { MYSQL_SYSVAR(errmsg_dir_path), #endif // XMSG MYSQL_SYSVAR(json_null), - MYSQL_SYSVAR(json_grp_size), + MYSQL_SYSVAR(json_all_path), + MYSQL_SYSVAR(default_depth), + MYSQL_SYSVAR(json_grp_size), #if defined(JAVA_SUPPORT) MYSQL_SYSVAR(jvm_path), MYSQL_SYSVAR(class_path), diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h index 9a12ef94431..21e81b141a8 100644 --- a/storage/connect/ha_connect.h +++ b/storage/connect/ha_connect.h @@ -104,7 +104,9 @@ struct ha_field_option_struct uint opt; const char *dateformat; const char *fieldformat; - char *special; + const char* jsonpath; + const char* xmlpath; + char *special; }; /* diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index a38e6487025..ea3ea18da0b 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -93,9 +93,8 @@ char *NextChr(PSZ s, char sep) PJSON ParseJson(PGLOBAL g, char *s, int len, int *ptyp, bool *comma) { int i, pretty = (ptyp) ? *ptyp : 3; - bool b = false, pty[3] = {true, true, true}; - PJSON jsp = NULL; - STRG src; + bool b = false, pty[3] = {true,true,true}; + PJSON jsp = NULL, jp = NULL; if (trace(1)) htrc("ParseJson: s=%.10s len=%d\n", s, len); @@ -106,27 +105,29 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int *ptyp, bool *comma) } else if (comma) *comma = false; - src.str = s; - src.len = len; - // Trying to guess the pretty format if (s[0] == '[' && (s[1] == '\n' || (s[1] == '\r' && s[2] == '\n'))) pty[0] = false; try { - for (i = 0; i < len; i++) + jp = new(g) JSON(); + jp->s = s; + jp->len = len; + jp->pty = pty; + + for (i = 0; i < jp->len; i++) switch (s[i]) { case '[': if (jsp) - goto tryit; - else if (!(jsp = ParseArray(g, ++i, src, pty))) - throw 1; + jsp = jp->ParseAsArray(g, i, pretty, ptyp); + else + jsp = jp->ParseArray(g, ++i); break; case '{': if (jsp) - goto tryit; - else if (!(jsp = ParseObject(g, ++i, src, pty))) + jsp = jp->ParseAsArray(g, i, pretty, ptyp); + else if (!(jsp = jp->ParseObject(g, ++i))) throw 2; break; @@ -157,8 +158,8 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int *ptyp, bool *comma) default: if (jsp) - goto tryit; - else if (!(jsp = ParseValue(g, i, src, pty))) + jsp = jp->ParseAsArray(g, i, pretty, ptyp); + else if (!(jsp = jp->ParseValue(g, i))) throw 4; break; @@ -187,10 +188,17 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int *ptyp, bool *comma) } // end catch return jsp; +} // end of ParseJson -tryit: +/***********************************************************************/ +/* Parse several items as being in an array. */ +/***********************************************************************/ +PJAR JSON::ParseAsArray(PGLOBAL g, int& i, int pretty, int *ptyp) +{ if (pty[0] && (!pretty || pretty > 2)) { - if ((jsp = ParseArray(g, (i = 0), src, pty)) && ptyp && pretty == 3) + PJAR jsp; + + if ((jsp = ParseArray(g, (i = 0))) && ptyp && pretty == 3) *ptyp = (pty[0]) ? 0 : 3; return jsp; @@ -198,26 +206,23 @@ tryit: strcpy(g->Message, "More than one item in file"); return NULL; -} // end of ParseJson +} // end of ParseAsArray /***********************************************************************/ /* Parse a JSON Array. */ /***********************************************************************/ -PJAR ParseArray(PGLOBAL g, int& i, STRG& src, bool *pty) +PJAR JSON::ParseArray(PGLOBAL g, int& i) { - char *s = src.str; - int len = src.len; - int level = 0; - bool b = (!i); - PJAR jarp = new(g) JARRAY; - PJVAL jvp = NULL; + int level = 0; + bool b = (!i); + PJAR jarp = new(g) JARRAY; for (; i < len; i++) switch (s[i]) { case ',': if (level < 2) { sprintf(g->Message, "Unexpected ',' near %.*s",ARGS); - return NULL; + throw 1; } else level = 1; @@ -225,8 +230,8 @@ PJAR ParseArray(PGLOBAL g, int& i, STRG& src, bool *pty) case ']': if (level == 1) { sprintf(g->Message, "Unexpected ',]' near %.*s", ARGS); - return NULL; - } // endif level + throw 1; + } // endif level jarp->InitArray(g); return jarp; @@ -240,11 +245,9 @@ PJAR ParseArray(PGLOBAL g, int& i, STRG& src, bool *pty) default: if (level == 2) { sprintf(g->Message, "Unexpected value near %.*s", ARGS); - return NULL; - } else if ((jvp = ParseValue(g, i, src, pty))) - jarp->AddValue(g, jvp); - else - return NULL; + throw 1; + } else + jarp->AddValue(g, ParseValue(g, i)); level = (b) ? 1 : 2; break; @@ -256,18 +259,15 @@ PJAR ParseArray(PGLOBAL g, int& i, STRG& src, bool *pty) return jarp; } // endif b - strcpy(g->Message, "Unexpected EOF in array"); - return NULL; + throw ("Unexpected EOF in array"); } // end of ParseArray /***********************************************************************/ /* Parse a JSON Object. */ /***********************************************************************/ -PJOB ParseObject(PGLOBAL g, int& i, STRG& src, bool *pty) +PJOB JSON::ParseObject(PGLOBAL g, int& i) { PSZ key; - char *s = src.str; - int len = src.len; int level = 0; PJOB jobp = new(g) JOBJECT; PJPR jpp = NULL; @@ -276,42 +276,37 @@ PJOB ParseObject(PGLOBAL g, int& i, STRG& src, bool *pty) switch (s[i]) { case '"': if (level < 2) { - if ((key = ParseString(g, ++i, src))) { - jpp = jobp->AddPair(g, key); - level = 1; - } else - return NULL; - + key = ParseString(g, ++i); + jpp = jobp->AddPair(g, key); + level = 1; } else { sprintf(g->Message, "misplaced string near %.*s", ARGS); - return NULL; + throw 2; } // endif level break; case ':': if (level == 1) { - if (!(jpp->Val = ParseValue(g, ++i, src, pty))) - return NULL; - + jpp->Val = ParseValue(g, ++i); level = 2; } else { sprintf(g->Message, "Unexpected ':' near %.*s", ARGS); - return NULL; + throw 2; } // endif level break; case ',': if (level < 2) { sprintf(g->Message, "Unexpected ',' near %.*s", ARGS); - return NULL; + throw 2; } else - level = 1; + level = 0; break; case '}': - if (level == 1) { + if (level < 2) { sprintf(g->Message, "Unexpected '}' near %.*s", ARGS); - return NULL; + throw 2; } // endif level return jobp; @@ -324,20 +319,19 @@ PJOB ParseObject(PGLOBAL g, int& i, STRG& src, bool *pty) default: sprintf(g->Message, "Unexpected character '%c' near %.*s", s[i], ARGS); - return NULL; + throw 2; }; // endswitch s[i] strcpy(g->Message, "Unexpected EOF in Object"); - return NULL; + throw 2; } // end of ParseObject /***********************************************************************/ /* Parse a JSON Value. */ /***********************************************************************/ -PJVAL ParseValue(PGLOBAL g, int& i, STRG& src, bool *pty) +PJVAL JSON::ParseValue(PGLOBAL g, int& i) { - char *strval, *s = src.str; - int n, len = src.len; + int n; PJVAL jvp = new(g) JVALUE; for (; i < len; i++) @@ -355,21 +349,13 @@ PJVAL ParseValue(PGLOBAL g, int& i, STRG& src, bool *pty) suite: switch (s[i]) { case '[': - if (!(jvp->Jsp = ParseArray(g, ++i, src, pty))) - return NULL; - + jvp->Jsp = ParseArray(g, ++i); break; case '{': - if (!(jvp->Jsp = ParseObject(g, ++i, src, pty))) - return NULL; - + jvp->Jsp = ParseObject(g, ++i); break; case '"': - if ((strval = ParseString(g, ++i, src))) - jvp->Value = AllocateValue(g, strval, TYPE_STRING); - else - return NULL; - + jvp->Value = AllocateValue(g, ParseString(g, ++i), TYPE_STRING); break; case 't': if (!strncmp(s + i, "true", 4)) { @@ -398,11 +384,9 @@ PJVAL ParseValue(PGLOBAL g, int& i, STRG& src, bool *pty) break; case '-': default: - if (s[i] == '-' || isdigit(s[i])) { - if (!(jvp->Value = ParseNumeric(g, i, src))) - goto err; - - } else + if (s[i] == '-' || isdigit(s[i])) + jvp->Value = ParseNumeric(g, i); + else goto err; }; // endswitch s[i] @@ -410,25 +394,21 @@ PJVAL ParseValue(PGLOBAL g, int& i, STRG& src, bool *pty) return jvp; err: - sprintf(g->Message, "Unexpected character '%c' near %.*s", - s[i], ARGS); - return NULL; + sprintf(g->Message, "Unexpected character '%c' near %.*s", s[i], ARGS); + throw 3; } // end of ParseValue /***********************************************************************/ /* Unescape and parse a JSON string. */ /***********************************************************************/ -char *ParseString(PGLOBAL g, int& i, STRG& src) +char *JSON::ParseString(PGLOBAL g, int& i) { - char *s = src.str; uchar *p; - int n = 0, len = src.len; + int n = 0; // Be sure of memory availability - if ((unsigned)(len + 1 - i) > ((PPOOLHEADER)g->Sarea)->FreeBlk) { - strcpy(g->Message, "ParseString: Out of memory"); - return NULL; - } // endif len + if (((size_t)len + 1 - i) > ((PPOOLHEADER)g->Sarea)->FreeBlk) + throw("ParseString: Out of memory"); // The size to allocate is not known yet p = (uchar*)PlugSubAlloc(g, NULL, 0); @@ -502,17 +482,16 @@ char *ParseString(PGLOBAL g, int& i, STRG& src) }; // endswitch s[i] err: - strcpy(g->Message, "Unexpected EOF in String"); - return NULL; + throw("Unexpected EOF in String"); } // end of ParseString /***********************************************************************/ /* Parse a JSON numeric value. */ /***********************************************************************/ -PVAL ParseNumeric(PGLOBAL g, int& i, STRG& src) +PVAL JSON::ParseNumeric(PGLOBAL g, int& i) { - char *s = src.str, buf[50]; - int n = 0, len = src.len; + char buf[50]; + int n = 0; short nd = 0; bool has_dot = false; bool has_e = false; @@ -575,14 +554,11 @@ PVAL ParseNumeric(PGLOBAL g, int& i, STRG& src) i--; // Unstack following character return valp; - } else { - strcpy(g->Message, "No digit found"); - return NULL; - } // endif found_digit + } else + throw("No digit found"); err: - strcpy(g->Message, "Unexpected EOF in number"); - return NULL; + throw("Unexpected EOF in number"); } // end of ParseNumeric /***********************************************************************/ diff --git a/storage/connect/json.h b/storage/connect/json.h index d949f244e21..bc94b372133 100644 --- a/storage/connect/json.h +++ b/storage/connect/json.h @@ -69,12 +69,7 @@ PBSON JbinAlloc(PGLOBAL g, UDF_ARGS* args, ulong len, PJSON jsp); char *NextChr(PSZ s, char sep); char *GetJsonNull(void); -PJSON ParseJson(PGLOBAL g, char *s, int n, int *prty = NULL, bool *b = NULL); -PJAR ParseArray(PGLOBAL g, int& i, STRG& src, bool *pty); -PJOB ParseObject(PGLOBAL g, int& i, STRG& src, bool *pty); -PJVAL ParseValue(PGLOBAL g, int& i, STRG& src, bool *pty); -char *ParseString(PGLOBAL g, int& i, STRG& src); -PVAL ParseNumeric(PGLOBAL g, int& i, STRG& src); +PJSON ParseJson(PGLOBAL g, char* s, int n, int* prty = NULL, bool* b = NULL); PSZ Serialize(PGLOBAL g, PJSON jsp, char *fn, int pretty); bool SerializeArray(JOUT *js, PJAR jarp, bool b); bool SerializeObject(JOUT *js, PJOB jobp); @@ -152,7 +147,7 @@ class JOUTPRT : public JOUTFILE { class JPAIR : public BLOCK { friend class JOBJECT; friend class JSNX; - friend PJOB ParseObject(PGLOBAL, int&, STRG&, bool*); + friend class JSON; friend bool SerializeObject(JOUT *, PJOB); public: JPAIR(PCSZ key) : BLOCK() {Key = key; Val = NULL; Next = NULL;} @@ -171,8 +166,9 @@ class JPAIR : public BLOCK { /* Class JSON. The base class for all other json classes. */ /***********************************************************************/ class JSON : public BLOCK { + friend PJSON ParseJson(PGLOBAL, char*, int, int*, bool*); public: - JSON(void) {Size = 0;} + JSON(void) : s(NULL), len(0), pty(NULL) {Size = 0;} int size(void) {return Size;} virtual int GetSize(bool b) {return Size;} @@ -209,14 +205,27 @@ class JSON : public BLOCK { virtual bool IsNull(void) {X return true;} protected: - int Size; + PJAR ParseArray(PGLOBAL g, int& i); + PJOB ParseObject(PGLOBAL g, int& i); + PJVAL ParseValue(PGLOBAL g, int& i); + char *ParseString(PGLOBAL g, int& i); + PVAL ParseNumeric(PGLOBAL g, int& i); + PJAR ParseAsArray(PGLOBAL g, int& i, int pretty, int *ptyp); + + // Members + int Size; + + // Only used when parsing + private: + char *s; + int len; + bool *pty; }; // end of class JSON /***********************************************************************/ /* Class JOBJECT: contains a list of value pairs. */ /***********************************************************************/ class JOBJECT : public JSON { - friend PJOB ParseObject(PGLOBAL, int&, STRG&, bool*); friend bool SerializeObject(JOUT *, PJOB); friend class JSNX; public: @@ -282,8 +291,8 @@ class JVALUE : public JSON { friend class JARRAY; friend class JSNX; friend class JSONCOL; - friend PJVAL ParseValue(PGLOBAL, int&, STRG&, bool*); - friend bool SerializeValue(JOUT *, PJVAL); + friend class JSON; + friend bool SerializeValue(JOUT*, PJVAL); public: JVALUE(void) : JSON() {Clear();} JVALUE(PJSON jsp); diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp index 0a862d2917d..06164f4ed78 100644 --- a/storage/connect/jsonudf.cpp +++ b/storage/connect/jsonudf.cpp @@ -1076,27 +1076,6 @@ my_bool JSNX::AddPath(void) /* --------------------------------- JSON UDF ---------------------------------- */ -#if 0 // Moved to json.h -// BSON size should be equal on Linux and Windows -#define BMX 255 -typedef struct BSON *PBSON; - -/*********************************************************************************/ -/* Structure used to return binary json. */ -/*********************************************************************************/ -struct BSON { - char Msg[BMX + 1]; - char *Filename; - PGLOBAL G; - int Pretty; - ulong Reslen; - my_bool Changed; - PJSON Top; - PJSON Jsp; - PBSON Bsp; -}; // end of struct BSON -#endif // 0 - /*********************************************************************************/ /* Allocate and initialize a BSON structure. */ /*********************************************************************************/ @@ -1146,7 +1125,7 @@ static my_bool JsonSubSet(PGLOBAL g) { PPOOLHEADER pph = (PPOOLHEADER)g->Sarea; - pph->To_Free = (OFFSET)((g->Createas) ? g->Createas : sizeof(POOLHEADER)); + pph->To_Free = (g->Saved_Size) ? g->Saved_Size : (size_t)sizeof(POOLHEADER); pph->FreeBlk = g->Sarea_Size - pph->To_Free; return FALSE; } /* end of JsonSubSet */ @@ -1156,7 +1135,7 @@ static my_bool JsonSubSet(PGLOBAL g) /*********************************************************************************/ inline void JsonMemSave(PGLOBAL g) { - g->Createas = (int)((PPOOLHEADER)g->Sarea)->To_Free; + g->Saved_Size = ((PPOOLHEADER)g->Sarea)->To_Free; } /* end of JsonMemSave */ /*********************************************************************************/ @@ -1627,7 +1606,7 @@ static my_bool CheckMemory(PGLOBAL g, UDF_INIT *initid, UDF_ARGS *args, uint n, return true; } // endif SareaAlloc - g->Createas = 0; + g->Saved_Size = 0; g->Xchk = NULL; initid->max_length = rl; } // endif Size @@ -4501,6 +4480,7 @@ my_bool jfile_make_init(UDF_INIT *initid, UDF_ARGS *args, char *message) } // endif CalcLen(args, false, reslen, memlen); + memlen = memlen + 5000; // To take care of not pretty files return JsonInit(initid, args, message, true, reslen, memlen); } // end of jfile_make_init @@ -5781,6 +5761,478 @@ void json_serialize_deinit(UDF_INIT* initid) JsonFreeMem((PGLOBAL)initid->ptr); } // end of json_serialize_deinit +/*********************************************************************************/ +/* Convert a prettiest Json file to Pretty=0. */ +/*********************************************************************************/ +my_bool jfile_convert_init(UDF_INIT* initid, UDF_ARGS* args, char* message) { + unsigned long reslen, memlen; + + if (args->arg_count != 3) { + strcpy(message, "This function must have 3 arguments"); + return true; + } else if (args->arg_type[2] != INT_RESULT) { + strcpy(message, "Third Argument must be an integer (LRECL)"); + return true; + } else for (int i = 0; i < 2; i++) + if (args->arg_type[i] != STRING_RESULT) { + sprintf(message, "Arguments %d must be a string (file name)", i+1); + return true; + } // endif args + + CalcLen(args, false, reslen, memlen); + return JsonInit(initid, args, message, false, reslen, memlen); +} // end of jfile_convert_init + +char *jfile_convert(UDF_INIT* initid, UDF_ARGS* args, char* result, + unsigned long *res_length, char *, char *error) { + char *str, *fn, *ofn; + int lrecl = (int)*(longlong*)args->args[2]; + PGLOBAL g = (PGLOBAL)initid->ptr; + + PlugSubSet(g->Sarea, g->Sarea_Size); + fn = MakePSZ(g, args, 0); + ofn = MakePSZ(g, args, 1); + + if (!g->Xchk) { + JUP* jup = new(g) JUP(g); + + str = jup->UnprettyJsonFile(g, fn, ofn, lrecl); + g->Xchk = str; + } else + str = (char*)g->Xchk; + + if (!str) { + if (g->Message) + str = PlugDup(g, g->Message); + else + str = PlugDup(g, "Unexpected error"); + + } // endif str + + *res_length = strlen(str); + return str; +} // end of jfile_convert + +void jfile_convert_deinit(UDF_INIT* initid) { + JsonFreeMem((PGLOBAL)initid->ptr); +} // end of jfile_convert_deinit + +/* --------------------------------- Class JUP --------------------------------- */ + +#define ARGS MY_MIN(24,len-i),s+MY_MAX(i-3,0) + +/*********************************************************************************/ +/* JUP public constructor. */ +/*********************************************************************************/ +JUP::JUP(PGLOBAL g) { + fs = NULL; + s = buff = NULL; + i = k = len = recl = 0; +} // end of JUP constructor + +/*********************************************************************************/ +/* Copy a json file to another with pretty = 0. */ +/*********************************************************************************/ +char* JUP::UnprettyJsonFile(PGLOBAL g, char *fn, char *outfn, int lrecl) { + char *ret = NULL; + HANDLE hFile; + MEMMAP mm; + + /*******************************************************************************/ + /* Create the mapping file object. */ + /*******************************************************************************/ + hFile = CreateFileMap(g, fn, &mm, MODE_READ, false); + + if (hFile == INVALID_HANDLE_VALUE) { + DWORD rc = GetLastError(); + + if (!(*g->Message)) + sprintf(g->Message, MSG(OPEN_MODE_ERROR), "map", (int)rc, fn); + + return NULL; + } // endif hFile + + /*******************************************************************************/ + /* Get the file size (assuming file is smaller than 4 GB) */ + /*******************************************************************************/ + if (!mm.lenL) { // Empty or deleted file + CloseFileHandle(hFile); + return NULL; + } else + len = (int)mm.lenL; + + if (!mm.memory) { + CloseFileHandle(hFile); + sprintf(g->Message, MSG(MAP_VIEW_ERROR), fn, GetLastError()); + return NULL; + } else + s = (char*)mm.memory; + + CloseFileHandle(hFile); // Not used anymore + + /*********************************************************************************/ + /* Parse the json file and allocate its tree structure. */ + /*********************************************************************************/ + if (!(fs = fopen(outfn, "wb"))) { + sprintf(g->Message, MSG(OPEN_MODE_ERROR), + "w", (int)errno, outfn); + strcat(strcat(g->Message, ": "), strerror(errno)); + CloseMemMap(mm.memory, (size_t)mm.lenL); + return NULL; + } // endif fs + + g->Message[0] = 0; + + if (!unPretty(g, lrecl)) + ret = outfn; + + CloseMemMap(mm.memory, (size_t)mm.lenL); + fclose(fs); + return ret; +} // end of UnprettyJsonFile + +/***********************************************************************/ +/* Translate a json file to pretty = 0. */ +/***********************************************************************/ +bool JUP::unPretty(PGLOBAL g, int lrecl) { + bool go, next, rc = false; + + if (trace(1)) + htrc("UnPretty: s=%.10s len=%zd lrecl=%d\n", s, len, lrecl); + + if (!s || !len) { + strcpy(g->Message, "Void JSON file"); + return true; + } else if (*s != '[') { + // strcpy(g->Message, "JSON file is not an array"); + s = strchr(s, '['); + // return true; + } // endif s + + i = 1; + go = next = true; + + try { + // Allocate the record + buff = (char*)PlugSubAlloc(g, NULL, (size_t)lrecl + 3); + recl = lrecl; + + do { + for (k = 0; go && i < len; i++) + switch (s[i]) { + case '{': + buff[k++] = s[i++]; + CopyObject(g); + break; + case '[': + throw "JSON file is not an array of objects"; + break; + case ' ': + case '\t': + case '\n': + case '\r': + break; + case ',': + go = false; + break; + case ']': + go = next = false; + break; + default: + sprintf(g->Message, "Unexpected '%c' near %.*s", s[i], ARGS); + throw 4; + break; + }; // endswitch s[i] + + // Write the record +#ifdef __win_ + buff[k++] = '\r'; +#endif + buff[k++] = '\n'; + buff[k] = 0; + + if ((fputs(buff, fs)) == EOF) { + sprintf(g->Message, MSG(FPUTS_ERROR), strerror(errno)); + throw 5; + } // endif EOF + + go = true; + } while (next); + + } catch (int n) { + if (trace(1)) + htrc("Exception %d: %s\n", n, g->Message); + rc = true; + } catch (const char* msg) { + strcpy(g->Message, msg); + rc = true; + } // end catch + + return rc; +} // end of unPretty + +/***********************************************************************/ +/* Copy a JSON Object. */ +/***********************************************************************/ +void JUP::CopyObject(PGLOBAL g) { + int level = 0; + + for (; i < len; i++) + switch (s[i]) { + case '"': + AddBuff(s[i++]); + + if (level < 2) { + CopyString(g); + level = 1; + } else { + sprintf(g->Message, "misplaced string near %.*s", ARGS); + throw 3; + } // endif level + + break; + case ':': + AddBuff(s[i++]); + + if (level == 1) { + CopyValue(g); + level = 2; + } else { + sprintf(g->Message, "Unexpected ':' near %.*s", ARGS); + throw 3; + } // endif level + + break; + case ',': + AddBuff(s[i]); + + if (level < 2) { + sprintf(g->Message, "Unexpected ',' near %.*s", ARGS); + throw 3; + } else + level = 0; + + break; + case '}': + AddBuff(s[i]); + + if (level == 1) { + sprintf(g->Message, "Unexpected '}' near %.*s", ARGS); + throw 3; + } // endif level + + return; + case '\n': + case '\r': + case ' ': + case '\t': + break; + default: + sprintf(g->Message, "Unexpected character '%c' near %.*s", s[i], ARGS); + throw 3; + }; // endswitch s[i] + + throw "Unexpected EOF in Object"; +} // end of CopyObject + +/***********************************************************************/ +/* Copy a JSON Array. */ +/***********************************************************************/ +void JUP::CopyArray(PGLOBAL g) { + int level = 0; + + for (; i < len; i++) + switch (s[i]) { + case ',': + if (level < 2) { + sprintf(g->Message, "Unexpected ',' near %.*s", ARGS); + throw 2; + } else + level = 1; + + AddBuff(s[i]); + break; + case ']': + if (level == 1) { + sprintf(g->Message, "Unexpected ',]' near %.*s", ARGS); + throw 2; + } // endif level + + AddBuff(s[i]); + return; + case '\n': + case '\r': + case ' ': + case '\t': + break; + default: + if (level == 2) { + sprintf(g->Message, "Unexpected value near %.*s", ARGS); + throw 2; + } // endif level + + CopyValue(g); + level = 2; + break; + }; // endswitch s[i] + + throw "Unexpected EOF in array"; +} // end of CopyArray + +/***********************************************************************/ +/* Copy a JSON Value. */ +/***********************************************************************/ +void JUP::CopyValue(PGLOBAL g) { + for (; i < len; i++) + switch (s[i]) { + case '\n': + case '\r': + case ' ': + case '\t': + break; + default: + goto suite; + } // endswitch + +suite: + switch (s[i]) { + case '[': + AddBuff(s[i++]); + CopyArray(g); + break; + case '{': + AddBuff(s[i++]); + CopyObject(g); + break; + case '"': + AddBuff(s[i++]); + CopyString(g); + break; + case 't': + if (!strncmp(s + i, "true", 4)) { + AddBuff(s[i++]); + AddBuff(s[i++]); + AddBuff(s[i++]); + AddBuff(s[i]); + } else + goto err; + + break; + case 'f': + if (!strncmp(s + i, "false", 5)) { + AddBuff(s[i++]); + AddBuff(s[i++]); + AddBuff(s[i++]); + AddBuff(s[i++]); + AddBuff(s[i]); + } else + goto err; + + break; + case 'n': + if (!strncmp(s + i, "null", 4)) { + AddBuff(s[i++]); + AddBuff(s[i++]); + AddBuff(s[i++]); + AddBuff(s[i]); + } else + goto err; + + break; + default: + if (s[i] == '-' || isdigit(s[i])) + CopyNumeric(g); + else + goto err; + + }; // endswitch s[i] + + return; + +err: + sprintf(g->Message, "Unexpected character '%c' near %.*s", s[i], ARGS); + throw 1; +} // end of CopyValue + +/***********************************************************************/ +/* Unescape and parse a JSON string. */ +/***********************************************************************/ +void JUP::CopyString(PGLOBAL g) { + for (; i < len; i++) { + AddBuff(s[i]); + + switch (s[i]) { + case '"': + return; + case '\\': + AddBuff(s[++i]); + break; + default: + break; + }; // endswitch s[i] + + } // endfor i + + throw "Unexpected EOF in String"; +} // end of CopyString + +/***********************************************************************/ +/* Copy a JSON numeric value. */ +/***********************************************************************/ +void JUP::CopyNumeric(PGLOBAL g) { + bool has_dot = false; + bool has_e = false; + bool found_digit = false; + + for (; i < len; i++) { + switch (s[i]) { + case '.': + if (!found_digit || has_dot || has_e) + goto err; + + has_dot = true; + break; + case 'e': + case 'E': + if (!found_digit || has_e) + goto err; + + has_e = true; + found_digit = false; + break; + case '+': + if (!has_e) + goto err; + + // fall through + case '-': + if (found_digit) + goto err; + + break; + default: + if (isdigit(s[i])) { + found_digit = true; + } else + goto fin; + + }; // endswitch s[i] + + AddBuff(s[i]); + } // endfor i + +fin: + if (!found_digit) + throw "No digit found"; + else + i--; + + return; + +err: + throw "Unexpected EOF in number"; +} // end of CopyNumeric + /*********************************************************************************/ /* Utility function returning an environment variable value. */ /*********************************************************************************/ diff --git a/storage/connect/jsonudf.h b/storage/connect/jsonudf.h index ee56869a111..897b0fe9919 100644 --- a/storage/connect/jsonudf.h +++ b/storage/connect/jsonudf.h @@ -235,6 +235,10 @@ extern "C" { DllExport char *json_serialize(UDF_EXEC_ARGS); DllExport void json_serialize_deinit(UDF_INIT*); + DllExport my_bool jfile_convert_init(UDF_INIT*, UDF_ARGS*, char*); + DllExport char* jfile_convert(UDF_EXEC_ARGS); + DllExport void jfile_convert_deinit(UDF_INIT*); + DllExport my_bool envar_init(UDF_INIT*, UDF_ARGS*, char*); DllExport char *envar(UDF_EXEC_ARGS); @@ -324,3 +328,38 @@ protected: my_bool Wr; // Write mode my_bool Jb; // Must return json item }; // end of class JSNX + +/*********************************************************************************/ +/* Class JUP: used by jfile_convert to make a json file pretty = 0. */ +/*********************************************************************************/ +class JUP : public BLOCK { +public: + // Constructor + JUP(PGLOBAL g); + + // Implementation + void AddBuff(char c) { + if (k < recl) + buff[k++] = c; + else + throw "Record size is too small"; + } // end of AddBuff + + // Methods + char *UnprettyJsonFile(PGLOBAL g, char* fn, char* outfn, int lrecl); + bool unPretty(PGLOBAL g, int lrecl); + void CopyObject(PGLOBAL g); + void CopyArray(PGLOBAL g); + void CopyValue(PGLOBAL g); + void CopyString(PGLOBAL g); + void CopyNumeric(PGLOBAL g); + + // Members + FILE* fs; + char* s; + char* buff; + int len; + int recl; + int i, k; +}; // end of class JUP + diff --git a/storage/connect/mongo.cpp b/storage/connect/mongo.cpp index e821440a0c3..5f10a89ee67 100644 --- a/storage/connect/mongo.cpp +++ b/storage/connect/mongo.cpp @@ -35,6 +35,7 @@ bool MakeSelector(PGLOBAL g, PFIL fp, PSTRG s); bool IsNum(PSZ s); +int GetDefaultDepth(void); /***********************************************************************/ /* Make selector json representation for Mongo tables. */ @@ -248,15 +249,10 @@ MGODISC::MGODISC(PGLOBAL g, int *lg) { /***********************************************************************/ int MGODISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt) { - PCSZ level = GetStringTableOption(g, topt, "Level", NULL); PMGODEF tdp; - if (level = GetStringTableOption(g, topt, "Depth", level)) { - lvl = atoi(level); - lvl = (lvl > 16) ? 16 : lvl; - } else - lvl = 0; - + lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth()); + lvl = GetIntegerTableOption(g, topt, "Depth", lvl); all = GetBooleanTableOption(g, topt, "Fullarray", false); /*********************************************************************/ diff --git a/storage/connect/mysql-test/connect/r/json_java_2.result b/storage/connect/mysql-test/connect/r/json_java_2.result index 4bbac236200..47fc4abbd28 100644 --- a/storage/connect/mysql-test/connect/r/json_java_2.result +++ b/storage/connect/mysql-test/connect/r/json_java_2.result @@ -20,12 +20,12 @@ SELECT * from t1; Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Nullable Jpath _id 1 CHAR 24 24 0 0 _id address_building 1 CHAR 10 10 0 0 address.building -address_coord 1 CHAR 256 256 0 1 address.coord +address_coord 1 CHAR 1024 1024 0 1 address.coord address_street 1 CHAR 38 38 0 0 address.street address_zipcode 1 CHAR 5 5 0 0 address.zipcode borough 1 CHAR 13 13 0 0 cuisine 1 CHAR 64 64 0 0 -grades_date 1 CHAR 256 256 0 1 grades.0.date +grades_date 1 CHAR 1024 1024 0 1 grades.0.date grades_grade 1 CHAR 14 14 0 1 grades.0.grade grades_score 5 BIGINT 2 2 0 1 grades.0.score name 1 CHAR 98 98 0 0 @@ -64,16 +64,16 @@ OPTION_LIST='Level=1,Driver=Java,Version=2' CONNECTION='mongodb://localhost:2701 SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `_id` char(24) NOT NULL `FIELD_FORMAT`='_id', - `address_building` char(10) NOT NULL `FIELD_FORMAT`='address.building', - `address_coord` varchar(256) DEFAULT NULL `FIELD_FORMAT`='address.coord', - `address_street` char(38) NOT NULL `FIELD_FORMAT`='address.street', - `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode', + `_id` char(24) NOT NULL `JPATH`='_id', + `address_building` char(10) NOT NULL `JPATH`='address.building', + `address_coord` varchar(1024) DEFAULT NULL `JPATH`='address.coord', + `address_street` char(38) NOT NULL `JPATH`='address.street', + `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode', `borough` char(13) NOT NULL, `cuisine` char(64) NOT NULL, - `grades_date` varchar(256) DEFAULT NULL `FIELD_FORMAT`='grades.0.date', - `grades_grade` char(14) DEFAULT NULL `FIELD_FORMAT`='grades.0.grade', - `grades_score` bigint(2) DEFAULT NULL `FIELD_FORMAT`='grades.0.score', + `grades_date` varchar(1024) DEFAULT NULL `JPATH`='grades.0.date', + `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade', + `grades_score` bigint(2) DEFAULT NULL `JPATH`='grades.0.score', `name` char(98) NOT NULL, `restaurant_id` char(8) NOT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `OPTION_LIST`='Level=1,Driver=Java,Version=2' `DATA_CHARSET`='utf8' `LRECL`=4096 @@ -251,15 +251,15 @@ OPTION_LIST='Driver=Java,level=2,version=2'; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `_id` char(24) NOT NULL `FIELD_FORMAT`='_id', - `address_building` char(10) NOT NULL `FIELD_FORMAT`='address.building', - `address_coord` double(18,16) DEFAULT NULL `FIELD_FORMAT`='address.coord.0', - `address_street` char(38) NOT NULL `FIELD_FORMAT`='address.street', - `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode', + `_id` char(24) NOT NULL `JPATH`='_id', + `address_building` char(10) NOT NULL `JPATH`='address.building', + `address_coord` double(18,16) DEFAULT NULL `JPATH`='address.coord.0', + `address_street` char(38) NOT NULL `JPATH`='address.street', + `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode', `borough` char(13) NOT NULL, - `grades_date` char(24) DEFAULT NULL `FIELD_FORMAT`='grades.0.date', - `grades_grade` char(14) DEFAULT NULL `FIELD_FORMAT`='grades.0.grade', - `grades_score` bigint(2) DEFAULT NULL `FIELD_FORMAT`='grades.0.score', + `grades_date` char(24) DEFAULT NULL `JPATH`='grades.0.date', + `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade', + `grades_score` bigint(2) DEFAULT NULL `JPATH`='grades.0.score', `name` char(98) NOT NULL, `restaurant_id` char(8) NOT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `COLIST`='{"cuisine":0}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=Java,level=2,version=2' `LRECL`=4096 diff --git a/storage/connect/mysql-test/connect/r/json_java_3.result b/storage/connect/mysql-test/connect/r/json_java_3.result index eb8bfc022d6..720c82cd7f9 100644 --- a/storage/connect/mysql-test/connect/r/json_java_3.result +++ b/storage/connect/mysql-test/connect/r/json_java_3.result @@ -20,12 +20,12 @@ SELECT * from t1; Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Nullable Jpath _id 1 CHAR 24 24 0 0 _id address_building 1 CHAR 10 10 0 0 address.building -address_coord 1 CHAR 256 256 0 1 address.coord +address_coord 1 CHAR 1024 1024 0 1 address.coord address_street 1 CHAR 38 38 0 0 address.street address_zipcode 1 CHAR 5 5 0 0 address.zipcode borough 1 CHAR 13 13 0 0 cuisine 1 CHAR 64 64 0 0 -grades_date 1 CHAR 256 256 0 1 grades.0.date +grades_date 1 CHAR 1024 1024 0 1 grades.0.date grades_grade 1 CHAR 14 14 0 1 grades.0.grade grades_score 5 BIGINT 2 2 0 1 grades.0.score name 1 CHAR 98 98 0 0 @@ -64,16 +64,16 @@ OPTION_LIST='Level=1,Driver=Java,Version=3' CONNECTION='mongodb://localhost:2701 SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `_id` char(24) NOT NULL `FIELD_FORMAT`='_id', - `address_building` char(10) NOT NULL `FIELD_FORMAT`='address.building', - `address_coord` varchar(256) DEFAULT NULL `FIELD_FORMAT`='address.coord', - `address_street` char(38) NOT NULL `FIELD_FORMAT`='address.street', - `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode', + `_id` char(24) NOT NULL `JPATH`='_id', + `address_building` char(10) NOT NULL `JPATH`='address.building', + `address_coord` varchar(1024) DEFAULT NULL `JPATH`='address.coord', + `address_street` char(38) NOT NULL `JPATH`='address.street', + `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode', `borough` char(13) NOT NULL, `cuisine` char(64) NOT NULL, - `grades_date` varchar(256) DEFAULT NULL `FIELD_FORMAT`='grades.0.date', - `grades_grade` char(14) DEFAULT NULL `FIELD_FORMAT`='grades.0.grade', - `grades_score` bigint(2) DEFAULT NULL `FIELD_FORMAT`='grades.0.score', + `grades_date` varchar(1024) DEFAULT NULL `JPATH`='grades.0.date', + `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade', + `grades_score` bigint(2) DEFAULT NULL `JPATH`='grades.0.score', `name` char(98) NOT NULL, `restaurant_id` char(8) NOT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `OPTION_LIST`='Level=1,Driver=Java,Version=3' `DATA_CHARSET`='utf8' `LRECL`=4096 @@ -251,15 +251,15 @@ OPTION_LIST='Driver=Java,level=2,version=3'; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `_id` char(24) NOT NULL `FIELD_FORMAT`='_id', - `address_building` char(10) NOT NULL `FIELD_FORMAT`='address.building', - `address_coord` double(18,16) DEFAULT NULL `FIELD_FORMAT`='address.coord.0', - `address_street` char(38) NOT NULL `FIELD_FORMAT`='address.street', - `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode', + `_id` char(24) NOT NULL `JPATH`='_id', + `address_building` char(10) NOT NULL `JPATH`='address.building', + `address_coord` double(18,16) DEFAULT NULL `JPATH`='address.coord.0', + `address_street` char(38) NOT NULL `JPATH`='address.street', + `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode', `borough` char(13) NOT NULL, - `grades_date` bigint(13) DEFAULT NULL `FIELD_FORMAT`='grades.0.date', - `grades_grade` char(14) DEFAULT NULL `FIELD_FORMAT`='grades.0.grade', - `grades_score` bigint(2) DEFAULT NULL `FIELD_FORMAT`='grades.0.score', + `grades_date` bigint(13) DEFAULT NULL `JPATH`='grades.0.date', + `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade', + `grades_score` bigint(2) DEFAULT NULL `JPATH`='grades.0.score', `name` char(98) NOT NULL, `restaurant_id` char(8) NOT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `COLIST`='{"cuisine":0}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=Java,level=2,version=3' `LRECL`=4096 diff --git a/storage/connect/mysql-test/connect/r/json_mongo_c.result b/storage/connect/mysql-test/connect/r/json_mongo_c.result index 550e94f286e..f9bfc01763e 100644 --- a/storage/connect/mysql-test/connect/r/json_mongo_c.result +++ b/storage/connect/mysql-test/connect/r/json_mongo_c.result @@ -20,12 +20,12 @@ SELECT * from t1; Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Nullable Jpath _id 1 CHAR 24 24 0 0 _id address_building 1 CHAR 10 10 0 0 address.building -address_coord 1 CHAR 256 256 0 1 address.coord +address_coord 1 CHAR 1024 1024 0 1 address.coord address_street 1 CHAR 38 38 0 0 address.street address_zipcode 1 CHAR 5 5 0 0 address.zipcode borough 1 CHAR 13 13 0 0 cuisine 1 CHAR 64 64 0 0 -grades_date 1 CHAR 256 256 0 1 grades.0.date +grades_date 1 CHAR 1024 1024 0 1 grades.0.date grades_grade 1 CHAR 14 14 0 1 grades.0.grade grades_score 5 BIGINT 2 2 0 1 grades.0.score name 1 CHAR 98 98 0 0 @@ -64,16 +64,16 @@ OPTION_LIST='Level=1,Driver=C,Version=0' CONNECTION='mongodb://localhost:27017' SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `_id` char(24) NOT NULL `FIELD_FORMAT`='_id', - `address_building` char(10) NOT NULL `FIELD_FORMAT`='address.building', - `address_coord` varchar(256) DEFAULT NULL `FIELD_FORMAT`='address.coord', - `address_street` char(38) NOT NULL `FIELD_FORMAT`='address.street', - `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode', + `_id` char(24) NOT NULL `JPATH`='_id', + `address_building` char(10) NOT NULL `JPATH`='address.building', + `address_coord` varchar(1024) DEFAULT NULL `JPATH`='address.coord', + `address_street` char(38) NOT NULL `JPATH`='address.street', + `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode', `borough` char(13) NOT NULL, `cuisine` char(64) NOT NULL, - `grades_date` varchar(256) DEFAULT NULL `FIELD_FORMAT`='grades.0.date', - `grades_grade` char(14) DEFAULT NULL `FIELD_FORMAT`='grades.0.grade', - `grades_score` bigint(2) DEFAULT NULL `FIELD_FORMAT`='grades.0.score', + `grades_date` varchar(1024) DEFAULT NULL `JPATH`='grades.0.date', + `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade', + `grades_score` bigint(2) DEFAULT NULL `JPATH`='grades.0.score', `name` char(98) NOT NULL, `restaurant_id` char(8) NOT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `OPTION_LIST`='Level=1,Driver=C,Version=0' `DATA_CHARSET`='utf8' `LRECL`=1024 @@ -251,15 +251,15 @@ OPTION_LIST='Driver=C,level=2,version=0'; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `_id` char(24) NOT NULL `FIELD_FORMAT`='_id', - `address_building` char(10) NOT NULL `FIELD_FORMAT`='address.building', - `address_coord` double(23,20) DEFAULT NULL `FIELD_FORMAT`='address.coord.0', - `address_street` char(38) NOT NULL `FIELD_FORMAT`='address.street', - `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode', + `_id` char(24) NOT NULL `JPATH`='_id', + `address_building` char(10) NOT NULL `JPATH`='address.building', + `address_coord` double(23,20) DEFAULT NULL `JPATH`='address.coord.0', + `address_street` char(38) NOT NULL `JPATH`='address.street', + `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode', `borough` char(13) NOT NULL, - `grades_date` bigint(13) DEFAULT NULL `FIELD_FORMAT`='grades.0.date', - `grades_grade` char(14) DEFAULT NULL `FIELD_FORMAT`='grades.0.grade', - `grades_score` bigint(2) DEFAULT NULL `FIELD_FORMAT`='grades.0.score', + `grades_date` bigint(13) DEFAULT NULL `JPATH`='grades.0.date', + `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade', + `grades_score` bigint(2) DEFAULT NULL `JPATH`='grades.0.score', `name` char(98) NOT NULL, `restaurant_id` char(8) NOT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `COLIST`='{"projection":{"cuisine":0}}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=C,level=2,version=0' `LRECL`=1024 diff --git a/storage/connect/plugutil.cpp b/storage/connect/plugutil.cpp index 2517b76cd3e..0ab594f5533 100644 --- a/storage/connect/plugutil.cpp +++ b/storage/connect/plugutil.cpp @@ -158,13 +158,14 @@ PGLOBAL PlugInit(LPCSTR Language, size_t worksize) } // end try/catch g->Sarea = NULL; - g->Createas = 0; + g->Createas = false; g->Alchecked = 0; g->Mrr = 0; g->Activityp = NULL; g->Xchk = NULL; g->N = 0; g->More = 0; + g->Saved_Size = 0; strcpy(g->Message, ""); /*******************************************************************/ @@ -528,7 +529,7 @@ BOOL PlugSubSet(void *memp, size_t size) { PPOOLHEADER pph = (PPOOLHEADER)memp; - pph->To_Free = (OFFSET)sizeof(POOLHEADER); + pph->To_Free = (size_t)sizeof(POOLHEADER); pph->FreeBlk = size - pph->To_Free; return FALSE; } /* end of PlugSubSet */ @@ -580,7 +581,7 @@ void *PlugSubAlloc(PGLOBAL g, void *memp, size_t size) /* Do the suballocation the simplest way. */ /*********************************************************************/ memp = MakePtr(memp, pph->To_Free); /* Points to suballocated block */ - pph->To_Free += (OFFSET)size; /* New offset of pool free block */ + pph->To_Free += size; /* New offset of pool free block */ pph->FreeBlk -= size; /* New size of pool free block */ if (trace(16)) @@ -605,40 +606,4 @@ char *PlugDup(PGLOBAL g, const char *str) } // end of PlugDup -#if 0 -/***********************************************************************/ -/* This routine suballocate a copy of the passed string. */ -/***********************************************************************/ -char *PlugDup(PGLOBAL g, const char *str) - { - char *buf; - size_t len; - - if (str && (len = strlen(str))) { - buf = (char*)PlugSubAlloc(g, NULL, len + 1); - strcpy(buf, str); - } else - buf = NULL; - - return(buf); - } /* end of PlugDup */ -#endif // 0 - -/***********************************************************************/ -/* This routine makes a pointer from an offset to a memory pointer. */ -/***********************************************************************/ -void *MakePtr(void *memp, OFFSET offset) - { - return ((offset == 0) ? NULL : &((char *)memp)[offset]); - } /* end of MakePtr */ - -/***********************************************************************/ -/* This routine makes an offset from a pointer new format. */ -/***********************************************************************/ -#if 0 -OFFSET MakeOff(void *memp, void *ptr) - { - return ((!ptr) ? 0 : (OFFSET)((char *)ptr - (char *)memp)); - } /* end of MakeOff */ -#endif /*--------------------- End of PLUGUTIL program -----------------------*/ diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index fcf7f4d182c..cdf9e40f97c 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -52,19 +52,10 @@ /* External functions. */ /***********************************************************************/ USETEMP UseTemp(void); +bool JsonAllPath(void); +int GetDefaultDepth(void); char *GetJsonNull(void); -//typedef struct _jncol { -// struct _jncol *Next; -// char *Name; -// char *Fmt; -// int Type; -// int Len; -// int Scale; -// bool Cbn; -// bool Found; -//} JCOL, *PJCL; - /***********************************************************************/ /* JSONColumns: construct the result blocks containing the description */ /* of all the columns of a table contained inside a JSON file. */ @@ -167,23 +158,20 @@ JSONDISC::JSONDISC(PGLOBAL g, uint *lg) jsp = NULL; row = NULL; sep = NULL; - i = n = bf = ncol = lvl = 0; - all = false; + i = n = bf = ncol = lvl = sz = 0; + all = strfy = false; } // end of JSONDISC constructor int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt) { char filename[_MAX_PATH]; bool mgo = (GetTypeID(topt->type) == TAB_MONGO); - PCSZ level = GetStringTableOption(g, topt, "Level", NULL); - if ((level = GetStringTableOption(g, topt, "Depth", level))) { - lvl = atoi(level); - lvl = (lvl > 16) ? 16 : lvl; - } else - lvl = 0; - - sep = GetStringTableOption(g, topt, "Separator", "."); + lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth()); + lvl = GetIntegerTableOption(g, topt, "Depth", lvl); + sep = GetStringTableOption(g, topt, "Separator", "."); + sz = GetIntegerTableOption(g, topt, "Jsize", 1024); + strfy = GetBooleanTableOption(g, topt, "Stringify", false); /*********************************************************************/ /* Open the input file. */ @@ -306,7 +294,7 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt) // Allocate the parse work memory PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL)); memset(G, 0, sizeof(GLOBAL)); - G->Sarea_Size = tdp->Lrecl * 10; + G->Sarea_Size = (size_t)tdp->Lrecl * 10; G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size); PlugSubSet(G->Sarea, G->Sarea_Size); G->jump_level = 0; @@ -403,7 +391,10 @@ bool JSONDISC::Find(PGLOBAL g, PJVAL jvp, PCSZ key, int j) PJAR jar; if ((valp = jvp ? jvp->GetValue() : NULL)) { - jcol.Type = valp->GetType(); + if (JsonAllPath() && !fmt[bf]) + strcat(fmt, colname); + + jcol.Type = valp->GetType(); jcol.Len = valp->GetValLen(); jcol.Scale = valp->GetValPrec(); jcol.Cbn = valp->IsNull(); @@ -482,8 +473,16 @@ bool JSONDISC::Find(PGLOBAL g, PJVAL jvp, PCSZ key, int j) } // endswitch Type } else if (lvl >= 0) { - jcol.Type = TYPE_STRING; - jcol.Len = 256; + if (strfy) { + if (!fmt[bf]) + strcat(fmt, colname); + + strcat(fmt, ".*"); + } else if (JsonAllPath() && !fmt[bf]) + strcat(fmt, colname); + + jcol.Type = TYPE_STRING; + jcol.Len = sz; jcol.Scale = 0; jcol.Cbn = true; } else @@ -2040,7 +2039,7 @@ int TDBJSON::MakeDocument(PGLOBAL g) if ((objpath = PlugDup(g, Objname))) { if (*objpath == '$') objpath++; if (*objpath == '.') objpath++; - p1 = p2 = NULL; + p1 = (*objpath == '[') ? objpath++ : NULL; /*********************************************************************/ /* Find the table in the tree structure. */ diff --git a/storage/connect/tabjson.h b/storage/connect/tabjson.h index 8c3f1013919..88aa5e2ee8b 100644 --- a/storage/connect/tabjson.h +++ b/storage/connect/tabjson.h @@ -68,8 +68,8 @@ public: PCSZ sep; char colname[65], fmt[129], buf[16]; uint *length; - int i, n, bf, ncol, lvl; - bool all; + int i, n, bf, ncol, lvl, sz; + bool all, strfy; }; // end of JSONDISC /***********************************************************************/ diff --git a/storage/connect/tabxml.cpp b/storage/connect/tabxml.cpp index fa140ea0699..6c9e9597cec 100644 --- a/storage/connect/tabxml.cpp +++ b/storage/connect/tabxml.cpp @@ -3,7 +3,7 @@ /* ------------- */ /* Version 3.0 */ /* */ -/* Author Olivier BERTRAND 2007 - 2017 */ +/* Author Olivier BERTRAND 2007 - 2020 */ /* */ /* This program are the XML tables classes using MS-DOM or libxml2. */ /***********************************************************************/ @@ -62,6 +62,8 @@ extern "C" char version[]; #define TYPE_UNKNOWN 12 /* Must be greater than other types */ #define XLEN(M) sizeof(M) - strlen(M) - 1 /* To avoid overflow*/ +int GetDefaultDepth(void); + /***********************************************************************/ /* Class and structure used by XMLColumns. */ /***********************************************************************/ @@ -149,7 +151,7 @@ PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info) strcpy(g->Message, MSG(MISSING_FNAME)); return NULL; } else { - lvl = GetIntegerTableOption(g, topt, "Level", 0); + lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth()); lvl = GetIntegerTableOption(g, topt, "Depth", lvl); lvl = (lvl < 0) ? 0 : (lvl > 16) ? 16 : lvl; } // endif fn diff --git a/storage/connect/user_connect.cc b/storage/connect/user_connect.cc index 5dbdb8f56f0..09d6db1ad27 100644 --- a/storage/connect/user_connect.cc +++ b/storage/connect/user_connect.cc @@ -158,16 +158,16 @@ bool user_connect::CheckCleanup(bool force) { if (thdp->query_id > last_query_id || force) { size_t worksize = GetWorkSize(); - size_t size = g->Sarea_Size; PlugCleanup(g, true); - if (size != worksize) { + if (worksize != g->Sarea_Size) { FreeSarea(g); + g->Saved_Size = g->Sarea_Size; // Check whether the work area could be allocated if (AllocSarea(g, worksize)) { - AllocSarea(g, size); + AllocSarea(g, g->Saved_Size); SetWorkSize(g->Sarea_Size); // Was too big } // endif sarea @@ -175,10 +175,11 @@ bool user_connect::CheckCleanup(bool force) PlugSubSet(g->Sarea, g->Sarea_Size); g->Xchk = NULL; - g->Createas = 0; + g->Createas = false; g->Alchecked = 0; g->Mrr = 0; g->More = 0; + g->Saved_Size = 0; last_query_id= thdp->query_id; if (trace(65) && !force) From 5ca14dafbee8a1877ac30e955616e9ecea77fbfc Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 19 Oct 2020 16:51:52 +0400 Subject: [PATCH 139/323] MDEV-19275 Provide SQL service to plugins. Debian scripts fixed. --- debian/mariadb-test.install | 3 +++ debian/rules | 1 + 2 files changed, 4 insertions(+) diff --git a/debian/mariadb-test.install b/debian/mariadb-test.install index 767ec1ce587..6aba73b3c1c 100644 --- a/debian/mariadb-test.install +++ b/debian/mariadb-test.install @@ -3,11 +3,14 @@ usr/bin/mariadb-client-test-embedded usr/bin/mariadb-test usr/bin/mariadb-test-embedded usr/lib/*/libmariadb3/plugin/auth_test_plugin.so +usr/lib/*/libmariadb3/plugin/test_sql_service.so usr/lib/*/libmariadb3/plugin/qa_auth_client.so usr/lib/*/libmariadb3/plugin/qa_auth_interface.so +usr/lib/*/libmariadb3/plugin/auth_test_plugin.so usr/lib/mysql/plugin/adt_null.so usr/lib/mysql/plugin/auth_0x0100.so usr/lib/mysql/plugin/auth_test_plugin.so +usr/lib/mysql/plugin/test_sql_service.so usr/lib/mysql/plugin/daemon_example.ini usr/lib/mysql/plugin/debug_key_management.so usr/lib/mysql/plugin/dialog_examples.so diff --git a/debian/rules b/debian/rules index b157145cd0d..9b9540be012 100755 --- a/debian/rules +++ b/debian/rules @@ -167,6 +167,7 @@ endif # load from the libmariadb path as well ln -s ../../../mysql/plugin/auth_test_plugin.so $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadb3/plugin/auth_test_plugin.so ln -s ../../../mysql/plugin/qa_auth_interface.so $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadb3/plugin/qa_auth_interface.so + ln -s ../../../mysql/plugin/test_sql_service.so $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadb3/plugin/test_sql_service.so # Move test plugins that are only needed by the client to the libmariadb path mv -v $(TMP)/usr/lib/mysql/plugin/qa_auth_client.so $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadb3/plugin/ From bba22543b1556a5e3bc7ecd59d9d794dc4e5a1ed Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 29 Jul 2020 21:54:24 +0200 Subject: [PATCH 140/323] MDEV-23327 Can't uninstall UDF if the implementation library file doesn't exist Made cleanup of DROP (udf) FUNCTION procedure and also check of mysql.func (not only loaded udf). --- mysql-test/r/udf.result | 14 ++++ mysql-test/t/udf.test | 22 ++++++ sql/sql_parse.cc | 25 +++---- sql/sql_udf.cc | 151 +++++++++++++++++++++++++++++----------- sql/sql_udf.h | 8 ++- 5 files changed, 164 insertions(+), 56 deletions(-) diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result index 56bc2e26b2a..49768f6c514 100644 --- a/mysql-test/r/udf.result +++ b/mysql-test/r/udf.result @@ -479,3 +479,17 @@ myfunc_int(max(a) over (order by b) , b) drop view v1; drop function myfunc_int; drop table t1; +# +# MDEV-23327: Can't uninstall UDF if the implementation library +# file doesn't exist +# +insert into mysql.func values ("unexisting_udf", 0, "soname", "function"); +select * from mysql.func WHERE name='unexisting_udf'; +name ret dl type +unexisting_udf 0 soname function +DROP FUNCTION unexisting_udf; +select * from mysql.plugin WHERE name='unexisting_udf'; +name dl +DROP FUNCTION unexisting_udf; +ERROR 42000: FUNCTION test.unexisting_udf does not exist +# End of 10.2 tests diff --git a/mysql-test/t/udf.test b/mysql-test/t/udf.test index 7cdff2b6000..07c7f599db7 100644 --- a/mysql-test/t/udf.test +++ b/mysql-test/t/udf.test @@ -541,3 +541,25 @@ select * from v1; drop view v1; drop function myfunc_int; drop table t1; + +--echo # +--echo # MDEV-23327: Can't uninstall UDF if the implementation library +--echo # file doesn't exist +--echo # + +# emulate brocken so/ddl udf +insert into mysql.func values ("unexisting_udf", 0, "soname", "function"); + +# check that we have the function "installed" +select * from mysql.func WHERE name='unexisting_udf'; + +# make attempt to drop the function +DROP FUNCTION unexisting_udf; + +# check that we have the plugin uninstalled +select * from mysql.plugin WHERE name='unexisting_udf'; + +--error ER_SP_DOES_NOT_EXIST +DROP FUNCTION unexisting_udf; + +--echo # End of 10.2 tests diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e34181e2eeb..5dddbf0360d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5623,23 +5623,20 @@ mysql_execute_command(THD *thd) ! lex->spname->m_explicit_name) { /* DROP FUNCTION */ - udf_func *udf = find_udf(lex->spname->m_name.str, - lex->spname->m_name.length); - if (udf) + enum drop_udf_result rc= mysql_drop_function(thd, + &lex->spname->m_name); + if (rc == UDF_DEL_RESULT_DELETED) { - if (check_access(thd, DELETE_ACL, "mysql", NULL, NULL, 1, 0)) - goto error; - - if (!(res = mysql_drop_function(thd, &lex->spname->m_name))) - { - my_ok(thd); - break; - } - my_error(ER_SP_DROP_FAILED, MYF(0), - "FUNCTION (UDF)", lex->spname->m_name.str); - goto error; + my_ok(thd); + break; } + if (rc == UDF_DEL_RESULT_ERROR) + goto error; + + DBUG_ASSERT(rc == UDF_DEL_RESULT_ABSENT); + + // If there was no current database, so it can not be SP if (lex->spname->m_db.str == NULL) { if (lex->if_exists()) diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 9099345a64c..b4e863709d5 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -58,6 +58,8 @@ static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl, Item_udftype typ); static void del_udf(udf_func *udf); static void *find_udf_dl(const char *dl); +static bool find_udf_everywhere(THD* thd, const char *name, uint len, + TABLE *table); static char *init_syms(udf_func *tmp, char *nm) { @@ -417,6 +419,45 @@ static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl, return tmp; } +/** + Find record with the udf in the udf func table + + @param exact_name_str udf name + @param exact_name_len udf name length + @param table table of mysql.func + + @retval TRUE found + @retral FALSE not found +*/ + +static bool find_udf_in_table(const char *exact_name_str, uint exact_name_len, + TABLE *table) +{ + table->use_all_columns(); + table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin); + return (!table->file->ha_index_read_idx_map(table->record[0], 0, + (uchar*) table->field[0]->ptr, + HA_WHOLE_KEY, + HA_READ_KEY_EXACT)); +} + +static bool remove_udf_in_table(const char *exact_name_str, + uint exact_name_len, + TABLE *table) +{ + if (find_udf_in_table(exact_name_str, exact_name_len, table)) + { + int error; + if ((error= table->file->ha_delete_row(table->record[0]))) + { + table->file->print_error(error, MYF(0)); + return TRUE; + } + } + return FALSE; +} + + /* Drop user defined function. @@ -447,18 +488,21 @@ static int mysql_drop_function_internal(THD *thd, udf_func *udf, TABLE *table) if (!table) DBUG_RETURN(1); - table->use_all_columns(); - table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin); - if (!table->file->ha_index_read_idx_map(table->record[0], 0, - (uchar*) table->field[0]->ptr, - HA_WHOLE_KEY, - HA_READ_KEY_EXACT)) - { - int error; - if ((error= table->file->ha_delete_row(table->record[0]))) - table->file->print_error(error, MYF(0)); - } - DBUG_RETURN(0); + bool ret= remove_udf_in_table(exact_name_str, exact_name_len, table); + DBUG_RETURN(ret); +} + + +static TABLE *open_udf_func_table(THD *thd) +{ + TABLE_LIST tables; + TABLE *table; + + tables.init_one_table(STRING_WITH_LEN("mysql"), STRING_WITH_LEN("func"), + "func", TL_WRITE); + table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT); + + return table; } @@ -505,9 +549,7 @@ int mysql_create_function(THD *thd,udf_func *udf) if (check_ident_length(&udf->name)) DBUG_RETURN(1); - tables.init_one_table(STRING_WITH_LEN("mysql"), STRING_WITH_LEN("func"), - "func", TL_WRITE); - table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT); + table= open_udf_func_table(thd); mysql_rwlock_wrlock(&THR_LOCK_udf); DEBUG_SYNC(current_thd, "mysql_create_function_after_lock"); @@ -606,43 +648,59 @@ err: } -int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) +enum drop_udf_result mysql_drop_function(THD *thd, const LEX_STRING *udf_name) { TABLE *table; - TABLE_LIST tables; udf_func *udf; DBUG_ENTER("mysql_drop_function"); - if (!initialized) + if (!(table= open_udf_func_table(thd))) + DBUG_RETURN(UDF_DEL_RESULT_ERROR); + + // Fast pre-check + if (!mysql_rwlock_tryrdlock(&THR_LOCK_udf)) { - if (opt_noacl) - my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str); - else - my_message(ER_OUT_OF_RESOURCES, ER_THD(thd, ER_OUT_OF_RESOURCES), - MYF(0)); - DBUG_RETURN(1); + bool found=find_udf_everywhere(thd, udf_name->str, udf_name->length, table); + mysql_rwlock_unlock(&THR_LOCK_udf); + if (!found) + { + close_mysql_tables(thd); + DBUG_RETURN(UDF_DEL_RESULT_ABSENT); + } } - tables.init_one_table(STRING_WITH_LEN("mysql"), STRING_WITH_LEN("func"), - "func", TL_WRITE); - table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT); + if (!initialized) + { + close_mysql_tables(thd); + if (opt_noacl) + DBUG_RETURN(UDF_DEL_RESULT_ABSENT); // SP should be checked + + my_message(ER_OUT_OF_RESOURCES, ER_THD(thd, ER_OUT_OF_RESOURCES), MYF(0)); + DBUG_RETURN(UDF_DEL_RESULT_ERROR); + } mysql_rwlock_wrlock(&THR_LOCK_udf); + + // re-check under protection + if (!find_udf_everywhere(thd, udf_name->str, udf_name->length, table)) + { + close_mysql_tables(thd); + mysql_rwlock_unlock(&THR_LOCK_udf); + DBUG_RETURN(UDF_DEL_RESULT_ABSENT); + } + + if (check_access(thd, DELETE_ACL, "mysql", NULL, NULL, 1, 0)) + goto err; + + DEBUG_SYNC(current_thd, "mysql_drop_function_after_lock"); + if (!(udf= (udf_func*) my_hash_search(&udf_hash, (uchar*) udf_name->str, (uint) udf_name->length)) ) { - if (thd->lex->check_exists) - { - push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, - ER_FUNCTION_NOT_DEFINED, - ER_THD(thd, ER_FUNCTION_NOT_DEFINED), - udf_name->str); - goto done; - } - - my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str); - goto err; + if (remove_udf_in_table(udf_name->str, (uint) udf_name->length, table)) + goto err; + goto done; } if (mysql_drop_function_internal(thd, udf, table)) @@ -656,13 +714,24 @@ done: while binlogging, to avoid binlog inconsistency. */ if (write_bin_log(thd, TRUE, thd->query(), thd->query_length())) - DBUG_RETURN(1); + DBUG_RETURN(UDF_DEL_RESULT_ERROR); - DBUG_RETURN(0); + close_mysql_tables(thd); + DBUG_RETURN(UDF_DEL_RESULT_DELETED); err: + close_mysql_tables(thd); mysql_rwlock_unlock(&THR_LOCK_udf); - DBUG_RETURN(1); + DBUG_RETURN(UDF_DEL_RESULT_ERROR); +} + +static bool find_udf_everywhere(THD* thd, const char *name, uint len, + TABLE *table) +{ + if (initialized && my_hash_search(&udf_hash, (uchar*) name, len)) + return true; + + return find_udf_in_table(name, len, table); } #endif /* HAVE_DLOPEN */ diff --git a/sql/sql_udf.h b/sql/sql_udf.h index a683b8a7554..bfa03dcce33 100644 --- a/sql/sql_udf.h +++ b/sql/sql_udf.h @@ -140,7 +140,13 @@ void udf_init(void),udf_free(void); udf_func *find_udf(const char *name, uint len=0,bool mark_used=0); void free_udf(udf_func *udf); int mysql_create_function(THD *thd,udf_func *udf); -int mysql_drop_function(THD *thd,const LEX_STRING *name); +enum drop_udf_result +{ + UDF_DEL_RESULT_ABSENT, + UDF_DEL_RESULT_DELETED, + UDF_DEL_RESULT_ERROR +}; +enum drop_udf_result mysql_drop_function(THD *thd,const LEX_STRING *name); #else static inline void udf_init(void) { } static inline void udf_free(void) { } From 923ecbdfeff5b7b349bb13e862aaf74de2eeedd7 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 19 Oct 2020 19:36:00 +0530 Subject: [PATCH 141/323] MDEV-23387 dict_load_foreign() fails to load the table during alter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: ======= InnoDB allows virtual index to be referenced index in foreign key relations. While dropping the virtual column, Inplace alter does allow the table to be closed and open it using table name to update dict_table_t::v_cols. While loading the table, it doesn't allow any error to be ignored. InnoDB can't find the referenced virtual index and fails to load the table during Inplace alter. Solution: ========= During inplace alter, ignore the foreign key error while loading the table. Reviewed-by: Marko Mäkelä --- .../suite/gcol/r/innodb_virtual_fk.result | 21 +++++++++++++++++++ .../suite/gcol/t/innodb_virtual_fk.test | 12 +++++++++++ storage/innobase/handler/handler0alter.cc | 2 +- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/gcol/r/innodb_virtual_fk.result b/mysql-test/suite/gcol/r/innodb_virtual_fk.result index a3cdacb67a2..50685e04a69 100644 --- a/mysql-test/suite/gcol/r/innodb_virtual_fk.result +++ b/mysql-test/suite/gcol/r/innodb_virtual_fk.result @@ -769,3 +769,24 @@ ID ParentID Value Flag INSERT INTO parent (ID) VALUES (100); UPDATE child SET ParentID=100 WHERE ID=123123; DROP TABLE child, parent; +# +# MDEV-23387 dict_load_foreign() fails to load the table during alter +# +SET FOREIGN_KEY_CHECKS=0; +CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL, +f3 INT AS (f1) VIRTUAL, +INDEX(f1), INDEX(f2))ENGINE=InnoDB; +ALTER TABLE t1 ADD CONSTRAINT r FOREIGN KEY(f2) REFERENCES t1(f1), LOCK=NONE; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) NOT NULL, + `f2` int(11) NOT NULL, + `f3` int(11) GENERATED ALWAYS AS (`f1`) VIRTUAL, + KEY `f1` (`f1`), + KEY `f2` (`f2`), + CONSTRAINT `r` FOREIGN KEY (`f2`) REFERENCES `t1` (`f1`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +ALTER TABLE t1 DROP INDEX f1; +ALTER TABLE t1 DROP f3; +DROP TABLE t1; diff --git a/mysql-test/suite/gcol/t/innodb_virtual_fk.test b/mysql-test/suite/gcol/t/innodb_virtual_fk.test index 226bacabaef..23d3ee97290 100644 --- a/mysql-test/suite/gcol/t/innodb_virtual_fk.test +++ b/mysql-test/suite/gcol/t/innodb_virtual_fk.test @@ -637,3 +637,15 @@ UPDATE child SET ParentID=100 WHERE ID=123123; # Cleanup DROP TABLE child, parent; +--echo # +--echo # MDEV-23387 dict_load_foreign() fails to load the table during alter +--echo # +SET FOREIGN_KEY_CHECKS=0; +CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL, + f3 INT AS (f1) VIRTUAL, + INDEX(f1), INDEX(f2))ENGINE=InnoDB; +ALTER TABLE t1 ADD CONSTRAINT r FOREIGN KEY(f2) REFERENCES t1(f1), LOCK=NONE; +SHOW CREATE TABLE t1; +ALTER TABLE t1 DROP INDEX f1; +ALTER TABLE t1 DROP f3; +DROP TABLE t1; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 1fd793b42f3..44942bf164b 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -8717,7 +8717,7 @@ foreign_fail: dict_table_close(m_prebuilt->table, true, false); dict_table_remove_from_cache(m_prebuilt->table); m_prebuilt->table = dict_table_open_on_name( - tb_name, TRUE, TRUE, DICT_ERR_IGNORE_NONE); + tb_name, TRUE, TRUE, DICT_ERR_IGNORE_FK_NOKEY); /* Drop outdated table stats. */ char errstr[1024]; From f4f00e7c408a1e6603f5dac7f6fae83df50cad96 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 19 Oct 2020 19:37:03 +0530 Subject: [PATCH 142/323] MDEV-23966 btr_search_sys->hash_tables accessed without taking proper ahi latch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This issue is caused by the commit af40a2b43e94cab6b25c9efe4b18c3112b4a9e6c. In btr_search_update_hash_on_insert(), btr_search_sys->hash_tables is being accessed without taking proper ahi latch. During buffer pool resizing, btr_get_search_table() is being accessed and it leads to segmentation fault. Reviewed-by: Marko Mäkelä --- storage/innobase/btr/btr0sea.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc index ee39aacf162..79e6326ac1c 100644 --- a/storage/innobase/btr/btr0sea.cc +++ b/storage/innobase/btr/btr0sea.cc @@ -1797,7 +1797,8 @@ btr_search_update_hash_on_insert(btr_cur_t* cursor) } rw_lock_t* const latch = btr_get_search_latch(index); - hash_table_t* const table = btr_get_search_table(index); + /* We must not look up "table" before acquiring the latch. */ + hash_table_t* table = NULL; bool locked = false; if (!page_rec_is_infimum(rec)) { @@ -1814,6 +1815,7 @@ btr_search_update_hash_on_insert(btr_cur_t* cursor) goto function_exit; } + table = btr_get_search_table(index); ha_insert_for_fold(table, ins_fold, block, ins_rec); } @@ -1829,6 +1831,8 @@ btr_search_update_hash_on_insert(btr_cur_t* cursor) if (!btr_search_enabled || !block->index) { goto function_exit; } + + table = btr_get_search_table(index); } if (!left_side) { @@ -1849,6 +1853,8 @@ check_next_rec: if (!btr_search_enabled || !block->index) { goto function_exit; } + + table = btr_get_search_table(index); } ha_insert_for_fold(table, ins_fold, block, ins_rec); @@ -1865,6 +1871,8 @@ check_next_rec: if (!btr_search_enabled || !block->index) { goto function_exit; } + + table = btr_get_search_table(index); } if (!left_side) { From 1066312a12023d2558eecde84739c4bbb60eb509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 19 Oct 2020 20:36:05 +0300 Subject: [PATCH 143/323] MDEV-23982: Mariabackup hangs on backup MDEV-13318 introduced a condition to Mariabackup that can cause it to hang if the server goes idle after writing a log block that has no payload after the 12-byte header. Normal recovery in log0recv.cc would allow blocks with exactly 12 bytes of length, and only reject blocks where the length field is shorter than that. --- extra/mariabackup/xtrabackup.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 33a64356366..162efebbd9f 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -2723,7 +2723,7 @@ static lsn_t xtrabackup_copy_log(lsn_t start_lsn, lsn_t end_lsn, bool last) scanned_lsn += data_len; } else if (data_len >= OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE - || data_len <= LOG_BLOCK_HDR_SIZE) { + || data_len < LOG_BLOCK_HDR_SIZE) { /* We got a garbage block (abrupt end of the log). */ msg(0,"garbage block: " LSN_PF ",%zu",scanned_lsn, data_len); break; From d36cd5f01ec322c4cdf2feda288c3932260c5c57 Mon Sep 17 00:00:00 2001 From: Rucha Deodhar Date: Mon, 27 Jul 2020 02:51:33 +0530 Subject: [PATCH 144/323] MDEV-17729: Assertion `! is_set() || m_can_overwrite_status' failed in Diagnostics_area::set_error_status Analysis: When strict mode is enabled, all warnings are converted to errors including those which do not occur because of bad data. Fix: Query should not be aborted when we have warning because limit to examine rows was reached because it doesn't happen due to bad data. So thd->abort_on_warning should be false. --- mysql-test/r/limit_rows_examined.result | 15 +++++++++++++++ mysql-test/t/limit_rows_examined.test | 17 +++++++++++++++++ sql/sql_select.cc | 3 +++ 3 files changed, 35 insertions(+) diff --git a/mysql-test/r/limit_rows_examined.result b/mysql-test/r/limit_rows_examined.result index 0b3bc196a31..a3ab6122c59 100644 --- a/mysql-test/r/limit_rows_examined.result +++ b/mysql-test/r/limit_rows_examined.result @@ -853,3 +853,18 @@ Warnings: Warning 1931 Query execution was interrupted. The query examined at least 22 rows, which exceeds LIMIT ROWS EXAMINED (21). The query result may be incomplete. drop view v; drop table t1, t2; +# +# 10.1 Test +# +# MDEV-17729: Assertion `! is_set() || m_can_overwrite_status' +# failed in Diagnostics_area::set_error_status +# +set @old_mode= @@sql_mode; +CREATE TABLE t1(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,k INT, c CHAR(20)); +INSERT INTO t1 (k,c) VALUES(0,'0'), (0,'0'),(0,'0'),(0,'0'),(0,'0'),(0,'0'),(0,'0'); +SET @@sql_mode='STRICT_TRANS_TABLES'; +INSERT INTO t1 (c) SELECT k FROM t1 LIMIT ROWS EXAMINED 2; +Warnings: +Warning 1931 Query execution was interrupted. The query examined at least 4 rows, which exceeds LIMIT ROWS EXAMINED (2). The query result may be incomplete. +SET @@sql_mode=@old_mode; +DROP TABLE t1; diff --git a/mysql-test/t/limit_rows_examined.test b/mysql-test/t/limit_rows_examined.test index 45ee483c7aa..346a0478891 100644 --- a/mysql-test/t/limit_rows_examined.test +++ b/mysql-test/t/limit_rows_examined.test @@ -576,3 +576,20 @@ EXECUTE ps; drop view v; drop table t1, t2; + +--echo # +--echo # 10.1 Test +--echo # +--echo # MDEV-17729: Assertion `! is_set() || m_can_overwrite_status' +--echo # failed in Diagnostics_area::set_error_status +--echo # +set @old_mode= @@sql_mode; + +CREATE TABLE t1(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,k INT, c CHAR(20)); +INSERT INTO t1 (k,c) VALUES(0,'0'), (0,'0'),(0,'0'),(0,'0'),(0,'0'),(0,'0'),(0,'0'); + +SET @@sql_mode='STRICT_TRANS_TABLES'; +INSERT INTO t1 (c) SELECT k FROM t1 LIMIT ROWS EXAMINED 2; + +SET @@sql_mode=@old_mode; +DROP TABLE t1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e2e87bb1a86..138f98212aa 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -399,11 +399,14 @@ bool handle_select(THD *thd, LEX *lex, select_result *result, If LIMIT ROWS EXAMINED interrupted query execution, issue a warning, continue with normal processing and produce an incomplete query result. */ + bool saved_abort_on_warning= thd->abort_on_warning; + thd->abort_on_warning= false; push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT, ER_THD(thd, ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT), thd->accessed_rows_and_keys, thd->lex->limit_rows_examined->val_uint()); + thd->abort_on_warning= saved_abort_on_warning; thd->reset_killed(); } /* Disable LIMIT ROWS EXAMINED after query execution. */ From 9fca6645f42a6322215de51d97c9237f4a28a2d1 Mon Sep 17 00:00:00 2001 From: Rucha Deodhar Date: Thu, 17 Sep 2020 18:55:59 +0530 Subject: [PATCH 145/323] MDEV-5628: Assertion `! is_set()' or `!is_set() || (m_status == DA_OK_BULK && is_bulk_op())' fails on UPDATE on a partitioned table with subquery (MySQL:71630) Analysis and fix: Error is not checked. So correct error state is not returned. Fix: Check for error and return the error state. --- mysql-test/r/partition.result | 11 +++++++++++ mysql-test/t/partition.test | 16 ++++++++++++++++ sql/sql_update.cc | 2 ++ 3 files changed, 29 insertions(+) diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 57fa374d4f1..662929c5b48 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -2796,5 +2796,16 @@ id 16 drop table t1; # +# MDEV-5628: Assertion `! is_set()' or `!is_set() || +# (m_status == DA_OK_BULK && is_bulk_op())' fails on UPDATE on a +# partitioned table with subquery (MySQL:71630) +# +CREATE TABLE t1 (a INT) PARTITION BY HASH(a) PARTITIONS 2; +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (1),(2); +UPDATE t1 SET a = 7 WHERE a = ( SELECT b FROM t2 ) ORDER BY a LIMIT 6; +ERROR 21000: Subquery returns more than 1 row +DROP TABLE t1,t2; +# # End of 10.1 tests # diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index 23f3fa0b4d8..b82485dfc5c 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -2998,6 +2998,22 @@ insert t1 values (6, 'ab'), (4, 'ab'), (5, 'ab'), (16, 'ab'), (14, 'ab'), (15, ' select id from t1 where data = 'ab' order by id; drop table t1; +--echo # +--echo # MDEV-5628: Assertion `! is_set()' or `!is_set() || +--echo # (m_status == DA_OK_BULK && is_bulk_op())' fails on UPDATE on a +--echo # partitioned table with subquery (MySQL:71630) +--echo # + +CREATE TABLE t1 (a INT) PARTITION BY HASH(a) PARTITIONS 2; + +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (1),(2); + +--error ER_SUBQUERY_NO_1_ROW +UPDATE t1 SET a = 7 WHERE a = ( SELECT b FROM t2 ) ORDER BY a LIMIT 6; + +DROP TABLE t1,t2; + --echo # --echo # End of 10.1 tests --echo # diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 9b2d24c3ba3..f44aaa2ea99 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -413,6 +413,8 @@ int mysql_update(THD *thd, query_plan.set_no_partitions(); if (thd->lex->describe || thd->lex->analyze_stmt) goto produce_explain_and_leave; + if (thd->is_error()) + DBUG_RETURN(1); my_ok(thd); // No matching records DBUG_RETURN(0); From 00bf48827f45e0b0d164d474ced6fb30d923c5fd Mon Sep 17 00:00:00 2001 From: Rucha Deodhar Date: Thu, 8 Oct 2020 23:05:35 +0530 Subject: [PATCH 146/323] MDEV-23445: LIMIT ROWS EXAMINED throws error in Debug build only Analysis: When we reach the maximum limit to examine rows killed_state is set as ABORT. But this isn't an actual error and we still return TRUE. This eventually sets error as UNKNOWN ERROR. Fix: Check if need to stop execution by checking the killed state. If we have to abort it, return false because this isn't an actual error. --- mysql-test/main/information_schema.test | 7 ------- sql/sql_show.cc | 5 +++++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/mysql-test/main/information_schema.test b/mysql-test/main/information_schema.test index 22baad77a69..d090921c97c 100644 --- a/mysql-test/main/information_schema.test +++ b/mysql-test/main/information_schema.test @@ -1932,14 +1932,7 @@ SELECT SCHEMA_NAME from information_schema.schemata where schema_name=REPEAT('a' --echo # Diagnostics_area::sql_errno upon query from I_S with LIMIT ROWS EXAMINED --echo # -if ($have_debug) { ---error ER_UNKNOWN_ERROR SELECT * FROM INFORMATION_SCHEMA.`COLUMNS` LIMIT ROWS EXAMINED 10; -SHOW WARNINGS; -} -if (!$have_debug) { -SELECT * FROM INFORMATION_SCHEMA.`COLUMNS` LIMIT ROWS EXAMINED 10; -} --echo # --echo # End of 10.2 Test diff --git a/sql/sql_show.cc b/sql/sql_show.cc index b9c914f9545..0fe8b707472 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5273,6 +5273,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) free_root(&tmp_mem_root, MY_MARK_BLOCKS_FREE); } } + if (thd->killed == ABORT_QUERY) + { + error= 0; + goto err; + } } } } From 7b7ea33124345dfba5cbdfb8a5ece7031c6c7d33 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Thu, 15 Oct 2020 13:26:18 +0530 Subject: [PATCH 147/323] MDEV-23072 Diskspace not reused for Blob in data file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - This issue is caused by commit a4948dafcd7eee65f16d848bdc6562fc49ef8916. Purge doesn't free the externally stored page associated with the last record of the root page. In that case, purge thread does empty the root page and leads to more orphaned blob page in the tablespace. Purge thread should free the blob even for the last record of the root page. Reviewed-by: Marko Mäkelä --- storage/innobase/btr/btr0cur.cc | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index a68bc6550d7..a682148a482 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -5469,7 +5469,6 @@ btr_cur_optimistic_delete_func( mem_heap_t* heap = NULL; rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs* offsets = offsets_; - ibool no_compress_needed; rec_offs_init(offsets_); ut_ad(flags == 0 || flags == BTR_CREATE_FLAG); @@ -5490,6 +5489,20 @@ btr_cur_optimistic_delete_func( rec = btr_cur_get_rec(cursor); + offsets = rec_get_offsets(rec, cursor->index, offsets, true, + ULINT_UNDEFINED, &heap); + + const ibool no_compress_needed = !rec_offs_any_extern(offsets) + && btr_cur_can_delete_without_compress( + cursor, rec_offs_size(offsets), mtr); + + if (!no_compress_needed) { + /* prefetch siblings of the leaf for the pessimistic + operation. */ + btr_cur_prefetch_siblings(block); + goto func_exit; + } + if (UNIV_UNLIKELY(block->page.id.page_no() == cursor->index->page && page_get_n_recs(block->frame) == 1 + (cursor->index->is_instant() @@ -5528,18 +5541,10 @@ btr_cur_optimistic_delete_func( index->remove_instant(); } - return true; + goto func_exit; } - offsets = rec_get_offsets(rec, cursor->index, offsets, true, - ULINT_UNDEFINED, &heap); - - no_compress_needed = !rec_offs_any_extern(offsets) - && btr_cur_can_delete_without_compress( - cursor, rec_offs_size(offsets), mtr); - - if (no_compress_needed) { - + { page_t* page = buf_block_get_frame(block); page_zip_des_t* page_zip= buf_block_get_page_zip(block); @@ -5599,10 +5604,6 @@ btr_cur_optimistic_delete_func( ibuf_update_free_bits_low(block, max_ins, mtr); } } - } else { - /* prefetch siblings of the leaf for the pessimistic - operation. */ - btr_cur_prefetch_siblings(block); } func_exit: From a3c379ea61a5ba09b6d0db639ea28e700e66a591 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 20 Oct 2020 10:49:54 +0300 Subject: [PATCH 148/323] MDEV-23799 CREATE .. SELECT wrong result on join versioned table For join to work correctly versioning condition must be added to table on_expr. Without that JOIN_CACHE gets expression (1) trigcond(xtitle.row_end = TIMESTAMP'2038-01-19 06:14:07.999999') and trigcond(xtitle.elementId = x.`id` and xtitle.pkey = 'title') instead of (2) trigcond(xtitle.elementId = x.`id` and xtitle.pkey = 'title') for join_null_complements(). It is NULL-row of xtitle for complementing the join and the above comparisons of course FALSE, but trigcond (Item_func_trig_cond) makes them TRUE via its trig_var property which is bound to some boolean properties of JOIN_TAB. Expression (2) evaluated to TRUE because its trig_var is bound to first_inner_tab->not_null_compl. The expression (1) does not evaluate correctly because row_end comparison's trig_var is bound to first_inner->found earlier. As a result JOIN_CACHE::check_match() skipped the row for join_null_complements(). When we add versioning condition to table's on_expr the optimizer in make_join_select() distributes conditions differently. tmp_cond inherits on_expr value and in Good case it is full expression xgender.elementId = x.`id` and xgender.pkey = 'gender' and xgender.row_end = TIMESTAMP'2038-01-19 06:14:07.999999' while in Bad case it is only xgender.elementId = x.`id` and xgender.pkey = 'gender'. Later in Good row_end condition is optimized out and we get one trigcond in form of (2). --- mysql-test/suite/versioning/r/select.result | 21 +++++++++++++++++++++ mysql-test/suite/versioning/t/select.test | 21 +++++++++++++++++++++ sql/sql_select.cc | 1 + 3 files changed, 43 insertions(+) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 23c6e2d74af..00e257a576f 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -609,6 +609,27 @@ ERROR 22007: Incorrect date value: 'foo' for column `test`.`t2`.`b` at row 1 drop prepare stmt; drop procedure pr; drop table t1, t2; +# +# MDEV-23799 CREATE .. SELECT wrong result on join versioned table +# +create or replace table x (id Int) with system versioning; +create or replace table x_p (elementId Int, pkey varchar(20), pvalue varchar(20)) with system versioning; +insert into x values (1), (2), (3); +insert into x_p values (1, 'gender', 'male'); +insert into x_p values (2, 'gender', 'female'); +insert into x_p values (3, 'gender', 'male'); +create table tmp1 +select xgender.pvalue as gender, xtitle.pvalue as title +from x +left join x_p as xgender on x.id = xgender.elementId and xgender.pkey = 'gender' + left join x_p as xtitle on x.id = xtitle.elementId and xtitle.pkey = 'title'; +select * from tmp1; +gender title +male NULL +female NULL +male NULL +drop table tmp1; +drop tables x, x_p; call verify_trt_dummy(34); No A B C D 1 1 1 1 1 diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index c70f2714fff..f1217c382cf 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -421,6 +421,27 @@ drop prepare stmt; drop procedure pr; drop table t1, t2; +--echo # +--echo # MDEV-23799 CREATE .. SELECT wrong result on join versioned table +--echo # +create or replace table x (id Int) with system versioning; +create or replace table x_p (elementId Int, pkey varchar(20), pvalue varchar(20)) with system versioning; + +insert into x values (1), (2), (3); +insert into x_p values (1, 'gender', 'male'); +insert into x_p values (2, 'gender', 'female'); +insert into x_p values (3, 'gender', 'male'); + +create table tmp1 +select xgender.pvalue as gender, xtitle.pvalue as title +from x + left join x_p as xgender on x.id = xgender.elementId and xgender.pkey = 'gender' + left join x_p as xtitle on x.id = xtitle.elementId and xtitle.pkey = 'title'; + +select * from tmp1; + +drop table tmp1; +drop tables x, x_p; call verify_trt_dummy(34); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 10ba86b41db..3bbfc71e4e4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -784,6 +784,7 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) case SQLCOM_SELECT: use_sysvar= true; /* fall through */ + case SQLCOM_CREATE_TABLE: case SQLCOM_INSERT_SELECT: case SQLCOM_REPLACE_SELECT: case SQLCOM_DELETE_MULTI: From ddea8f6a39bfd32d8c5d8e38b8fa60c14156025c Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 20 Oct 2020 10:49:54 +0300 Subject: [PATCH 149/323] MDEV-23779 Error upon querying the view, that selecting from versioned table with partitions PARTITION clause in SELECT means query is non-versioned (see WITH_PARTITION_STORAGE_ENGINE in vers_setup_conds()). vers_setup_conds() expands such query to SYSTEM_TIME_ALL which is then added to VIEW specification. When VIEW is queried both clauses PARTITION and FOR SYSTEM_TIME ALL lead to ER_VERS_QUERY_IN_PARTITION (same place WITH_PARTITION_STORAGE_ENGINE). Fix removes FOR SYSTEM_TIME ALL from VIEW by accessing original SYSTEM_TIME clause: the one specified in parser. As a side-effect EXPLAIN SELECT displays SYSTEM_TIME specified in SELECT which is user-friendly. --- mysql-test/suite/versioning/r/cte.result | 8 ++++---- mysql-test/suite/versioning/r/derived.result | 4 ++-- mysql-test/suite/versioning/r/select.result | 10 +++++----- mysql-test/suite/versioning/r/trx_id.result | 6 +++--- mysql-test/suite/versioning/r/view.result | 11 +++++++++++ mysql-test/suite/versioning/t/view.test | 13 +++++++++++++ sql/sql_select.cc | 2 +- 7 files changed, 39 insertions(+), 15 deletions(-) diff --git a/mysql-test/suite/versioning/r/cte.result b/mysql-test/suite/versioning/r/cte.result index e35ab3e84d6..65cc90da2a7 100644 --- a/mysql-test/suite/versioning/r/cte.result +++ b/mysql-test/suite/versioning/r/cte.result @@ -38,7 +38,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 UNION e ALL NULL NULL NULL NULL 4 100.00 Using where NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Warnings: -Note 1003 with ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME ALL `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME ALL `e` where `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors` +Note 1003 with ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors` select row_start into @ts_2 from emp where name="john"; explain extended /* All report to 'Bill' */ with recursive @@ -62,7 +62,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 RECURSIVE UNION ref key0 key0 5 test.e.mgr 2 100.00 NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Warnings: -Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME ALL `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME ALL `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors` +Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors` /* All report to 'Bill' */ with recursive ancestors @@ -103,7 +103,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 RECURSIVE UNION ref key0 key0 5 test.e.mgr 2 100.00 NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Warnings: -Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME ALL `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME ALL `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors` +Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors` with recursive ancestors as @@ -145,7 +145,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 RECURSIVE UNION ref key0 key0 5 test.e.mgr 2 100.00 NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Warnings: -Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME ALL `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME ALL `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `test`.`emp`.`name` AS `name` from `test`.`emp` FOR SYSTEM_TIME ALL semi join (`ancestors`) where `test`.`emp`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999' +Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `test`.`emp`.`name` AS `name` from `test`.`emp` semi join (`ancestors`) where `test`.`emp`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999' with recursive ancestors as diff --git a/mysql-test/suite/versioning/r/derived.result b/mysql-test/suite/versioning/r/derived.result index 5b8eee4ab4a..700c92a8d5c 100644 --- a/mysql-test/suite/versioning/r/derived.result +++ b/mysql-test/suite/versioning/r/derived.result @@ -211,12 +211,12 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join) Query A: -Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL join `test`.`t2` FOR SYSTEM_TIME ALL where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > (current_timestamp(6)) and `test`.`t2`.`row_start` <= (current_timestamp(6)) and `test`.`t1`.`row_end` > (current_timestamp(6)) and `test`.`t1`.`row_start` <= (current_timestamp(6)) +Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > (current_timestamp(6)) and `test`.`t2`.`row_start` <= (current_timestamp(6)) and `test`.`t1`.`row_end` > (current_timestamp(6)) and `test`.`t1`.`row_start` <= (current_timestamp(6)) id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join) Query B: -Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL join `test`.`t2` FOR SYSTEM_TIME ALL where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > (current_timestamp(6)) and `test`.`t2`.`row_start` <= (current_timestamp(6)) and `test`.`t1`.`row_end` > (current_timestamp(6)) and `test`.`t1`.`row_start` <= (current_timestamp(6)) +Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > (current_timestamp(6)) and `test`.`t2`.`row_start` <= (current_timestamp(6)) and `test`.`t1`.`row_end` > (current_timestamp(6)) and `test`.`t1`.`row_start` <= (current_timestamp(6)) Fine result: queries A and B are equal. ## LEFT JOIN: t1, t2 versioned select * from ( diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 00e257a576f..6e0b5784402 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -153,21 +153,21 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join) Warnings: -Note 1003 select `test`.`t1`.`x` AS `IJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL join `test`.`t2` FOR SYSTEM_TIME ALL where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0` and `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0` +Note 1003 select `test`.`t1`.`x` AS `IJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0` and `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0` explain extended select * from (select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x) for system_time as of timestamp @t0 as t; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join) Warnings: -Note 1003 select `test`.`t1`.`x` AS `LJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL left join `test`.`t2` FOR SYSTEM_TIME ALL on(`test`.`t2`.`x` = `test`.`t1`.`x` and `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0`) where `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0` +Note 1003 select `test`.`t1`.`x` AS `LJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` left join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` on(`test`.`t2`.`x` = `test`.`t1`.`x` and `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0`) where `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0` explain extended select * from (select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x) for system_time as of timestamp @t0 as t; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join) Warnings: -Note 1003 select `test`.`t1`.`x` AS `RJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t2` FOR SYSTEM_TIME ALL left join `test`.`t1` FOR SYSTEM_TIME ALL on(`test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0`) where `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0` +Note 1003 select `test`.`t1`.`x` AS `RJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` left join `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` on(`test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0`) where `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0` select * from (select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x) for system_time as of timestamp @t0 as t; IJ2_x1 y1 x2 y2 @@ -293,7 +293,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a` from `test`.`t1` FOR SYSTEM_TIME ALL left join (`test`.`t1` FOR SYSTEM_TIME ALL `t2` left join `test`.`t1` FOR SYSTEM_TIME ALL `t3` on(`test`.`t3`.`a` = `test`.`t2`.`a` and `test`.`t3`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999')) on(`test`.`t2`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999' and `test`.`t1`.`a` > 1) where `test`.`t1`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999' +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a` from `test`.`t1` left join (`test`.`t1` `t2` left join `test`.`t1` `t3` on(`test`.`t3`.`a` = `test`.`t2`.`a` and `test`.`t3`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999')) on(`test`.`t2`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999' and `test`.`t1`.`a` > 1) where `test`.`t1`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999' select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; a a 2 1 @@ -525,7 +525,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE t4 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (incremental, BNL join) Warnings: -Note 1003 select `test`.`t1`.`f1` AS `f1` from `test`.`t1` FOR SYSTEM_TIME ALL join `test`.`t2` left join (`test`.`t3` left join `test`.`t4` FOR SYSTEM_TIME ALL on(`test`.`t4`.`f4` = `test`.`t2`.`f2` and `test`.`t4`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999')) on(`test`.`t3`.`f3` = `test`.`t2`.`f2`) where `test`.`t1`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999' +Note 1003 select `test`.`t1`.`f1` AS `f1` from `test`.`t1` join `test`.`t2` left join (`test`.`t3` left join `test`.`t4` on(`test`.`t4`.`f4` = `test`.`t2`.`f2` and `test`.`t4`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999')) on(`test`.`t3`.`f3` = `test`.`t2`.`f2`) where `test`.`t1`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999' drop view v1; drop table t1, t2, t3, t4; # diff --git a/mysql-test/suite/versioning/r/trx_id.result b/mysql-test/suite/versioning/r/trx_id.result index a140052439c..5dd9e7aa188 100644 --- a/mysql-test/suite/versioning/r/trx_id.result +++ b/mysql-test/suite/versioning/r/trx_id.result @@ -197,17 +197,17 @@ EXPLAIN EXTENDED SELECT x FROM t1 FOR SYSTEM_TIME AS OF TRANSACTION @ts; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`x` AS `x` from `test`.`t1` FOR SYSTEM_TIME ALL where trt_trx_sees(`test`.`t1`.`sys_trx_end`,@`ts`) and trt_trx_sees_eq(@`ts`,`test`.`t1`.`sys_trx_start`) +Note 1003 select `test`.`t1`.`x` AS `x` from `test`.`t1` FOR SYSTEM_TIME AS OF TRANSACTION @`ts` where trt_trx_sees(`test`.`t1`.`sys_trx_end`,@`ts`) and trt_trx_sees_eq(@`ts`,`test`.`t1`.`sys_trx_start`) EXPLAIN EXTENDED SELECT x FROM t1 FOR SYSTEM_TIME AS OF TIMESTAMP @ts; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`x` AS `x` from `test`.`t1` FOR SYSTEM_TIME ALL where trt_trx_sees(`test`.`t1`.`sys_trx_end`,(trt_trx_id(@`ts`))) and trt_trx_sees_eq((trt_trx_id(@`ts`)),`test`.`t1`.`sys_trx_start`) +Note 1003 select `test`.`t1`.`x` AS `x` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts` where trt_trx_sees(`test`.`t1`.`sys_trx_end`,(trt_trx_id(@`ts`))) and trt_trx_sees_eq((trt_trx_id(@`ts`)),`test`.`t1`.`sys_trx_start`) EXPLAIN EXTENDED SELECT x FROM t1 FOR SYSTEM_TIME AS OF @ts; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`x` AS `x` from `test`.`t1` FOR SYSTEM_TIME ALL where trt_trx_sees(`test`.`t1`.`sys_trx_end`,(trt_trx_id(@`ts`))) and trt_trx_sees_eq((trt_trx_id(@`ts`)),`test`.`t1`.`sys_trx_start`) +Note 1003 select `test`.`t1`.`x` AS `x` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts` where trt_trx_sees(`test`.`t1`.`sys_trx_end`,(trt_trx_id(@`ts`))) and trt_trx_sees_eq((trt_trx_id(@`ts`)),`test`.`t1`.`sys_trx_start`) DROP TABLE t1; # # Testing AS OF with expressions of various kinds and data types diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index e9e74899790..0528edc4bb3 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -279,3 +279,14 @@ b check_row(row_start, row_end) drop view v2; drop view v1; drop table t1, t2; +# +# MDEV-23779 Error upon querying the view, that selecting from versioned table with partitions +# +create table t1 (i int) with system versioning +partition by system_time (partition p0 history, partition pn current); +create view v1 as select * from t1 partition (pn); +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1` PARTITION (`pn`) latin1 latin1_swedish_ci +drop view v1; +drop table t1; diff --git a/mysql-test/suite/versioning/t/view.test b/mysql-test/suite/versioning/t/view.test index 37676a7fb50..9bb915f7b77 100644 --- a/mysql-test/suite/versioning/t/view.test +++ b/mysql-test/suite/versioning/t/view.test @@ -1,5 +1,6 @@ --source suite/versioning/engines.inc --source suite/versioning/common.inc +--source include/have_partition.inc create or replace table t1 (x int) with system versioning; insert into t1 values (1); @@ -213,4 +214,16 @@ drop view v2; drop view v1; drop table t1, t2; +--echo # +--echo # MDEV-23779 Error upon querying the view, that selecting from versioned table with partitions +--echo # +create table t1 (i int) with system versioning +partition by system_time (partition p0 history, partition pn current); +create view v1 as select * from t1 partition (pn); +show create view v1; + +# cleanup +drop view v1; +drop table t1; + --source suite/versioning/common_finish.inc diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3bbfc71e4e4..aaa4b4d6b8b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -695,7 +695,7 @@ bool vers_select_conds_t::init_from_sysvar(THD *thd) void vers_select_conds_t::print(String *str, enum_query_type query_type) const { - switch (type) { + switch (orig_type) { case SYSTEM_TIME_UNSPECIFIED: break; case SYSTEM_TIME_AS_OF: From 9b46d8e5c4108b0c55f8df3aa9abd8dd344d7688 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 20 Oct 2020 10:49:54 +0300 Subject: [PATCH 150/323] MDEV-23968 CREATE TEMPORARY TABLE .. LIKE (system versioned table) returns error if unique index is defined in the table - Remove row_start/row_end from keys in fix_create_like(); - Disable manual adding of implicit row_start/row_end to indexes on CREATE TABLE. INVISIBLE_SYSTEM fields are unoperable by user; - Fix memory leak on allocation of Key_part_spec. --- mysql-test/suite/versioning/r/create.result | 56 +++++++++++++++++++++ mysql-test/suite/versioning/t/create.test | 33 ++++++++++++ sql/handler.cc | 19 +++++++ sql/sql_class.h | 5 +- sql/sql_table.cc | 16 +++--- 5 files changed, 120 insertions(+), 9 deletions(-) diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index 5189e55bc30..65fbfaefcbd 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -524,3 +524,59 @@ with system versioning select 1 as x; ERROR HY000: Table `t1` must have at least one versioned column drop tables t0, t1, t2, t3; +# +# MDEV-23968 CREATE TEMPORARY TABLE .. LIKE (system versioned table) returns error if unique index is defined in the table +# +create table t1 (id int primary key, index(row_start)) with system versioning; +ERROR 42000: Key column 'row_start' doesn't exist in table +create table t1 (id int primary key, index(row_end)) with system versioning; +ERROR 42000: Key column 'row_end' doesn't exist in table +create table t1 (id int, primary key(id, row_end, row_end)) with system versioning; +ERROR 42000: Key column 'row_end' doesn't exist in table +create table t1 (id int primary key) with system versioning; +create temporary table t2 like t1; +Warnings: +Warning 1105 System versioning is stripped from temporary `test.t2` +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +show create table t2; +Table Create Table +t2 CREATE TEMPORARY TABLE `t2` ( + `id` int(11) NOT NULL +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 +drop temporary table t2; +create or replace table t1 ( +a int, +row_start timestamp(6) as row start, +row_end timestamp(6) as row end, +period for system_time (row_start, row_end), +index(row_start), +index(row_end), +primary key(row_end, a, row_start), +index(row_end, row_start, a)) with system versioning; +create temporary table t2 like t1; +Warnings: +Warning 1105 System versioning is stripped from temporary `test.t2` +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `row_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `row_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PRIMARY KEY (`row_end`,`a`,`row_start`), + KEY `row_start` (`row_start`), + KEY `row_end` (`row_end`), + KEY `row_end_2` (`row_end`,`row_start`,`a`), + PERIOD FOR SYSTEM_TIME (`row_start`, `row_end`) +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +show create table t2; +Table Create Table +t2 CREATE TEMPORARY TABLE `t2` ( + `a` int(11) NOT NULL +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 +drop temporary table t2; +drop table t1; diff --git a/mysql-test/suite/versioning/t/create.test b/mysql-test/suite/versioning/t/create.test index fc4120ef2aa..8d3131cff74 100644 --- a/mysql-test/suite/versioning/t/create.test +++ b/mysql-test/suite/versioning/t/create.test @@ -406,3 +406,36 @@ with system versioning select 1 as x; drop tables t0, t1, t2, t3; + +--echo # +--echo # MDEV-23968 CREATE TEMPORARY TABLE .. LIKE (system versioned table) returns error if unique index is defined in the table +--echo # +--error ER_KEY_COLUMN_DOES_NOT_EXITS +create table t1 (id int primary key, index(row_start)) with system versioning; +--error ER_KEY_COLUMN_DOES_NOT_EXITS +create table t1 (id int primary key, index(row_end)) with system versioning; +--error ER_KEY_COLUMN_DOES_NOT_EXITS +create table t1 (id int, primary key(id, row_end, row_end)) with system versioning; +create table t1 (id int primary key) with system versioning; +create temporary table t2 like t1; +--replace_result $default_engine DEFAULT_ENGINE +show create table t1; +--replace_result $default_engine DEFAULT_ENGINE +show create table t2; +drop temporary table t2; +create or replace table t1 ( + a int, + row_start timestamp(6) as row start, + row_end timestamp(6) as row end, + period for system_time (row_start, row_end), + index(row_start), + index(row_end), + primary key(row_end, a, row_start), + index(row_end, row_start, a)) with system versioning; +create temporary table t2 like t1; +--replace_result $default_engine DEFAULT_ENGINE +show create table t1; +--replace_result $default_engine DEFAULT_ENGINE +show create table t2; +drop temporary table t2; +drop table t1; diff --git a/sql/handler.cc b/sql/handler.cc index dcc130c340e..664289eaa27 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -7390,6 +7390,8 @@ Vers_parse_info::fix_create_like(Alter_info &alter_info, HA_CREATE_INFO &create_ TABLE_LIST &src_table, TABLE_LIST &table) { List_iterator it(alter_info.create_list); + List_iterator key_it(alter_info.key_list); + List_iterator kp_it; Create_field *f, *f_start=NULL, *f_end= NULL; DBUG_ASSERT(alter_info.create_list.elements > 2); @@ -7404,6 +7406,23 @@ Vers_parse_info::fix_create_like(Alter_info &alter_info, HA_CREATE_INFO &create_ it.remove(); remove--; } + key_it.rewind(); + while (Key *key= key_it++) + { + kp_it.init(key->columns); + while (Key_part_spec *kp= kp_it++) + { + if (0 == lex_string_cmp(system_charset_info, &kp->field_name, + &f->field_name)) + { + kp_it.remove(); + } + } + if (0 == key->columns.elements) + { + key_it.remove(); + } + } } DBUG_ASSERT(remove == 0); push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, diff --git a/sql/sql_class.h b/sql/sql_class.h index 5ced820a34d..0645452c594 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -254,8 +254,9 @@ class Key_part_spec :public Sql_alloc { public: LEX_CSTRING field_name; uint length; - Key_part_spec(const LEX_CSTRING *name, uint len) - : field_name(*name), length(len) + bool generated; + Key_part_spec(const LEX_CSTRING *name, uint len, bool gen= false) + : field_name(*name), length(len), generated(gen) {} bool operator==(const Key_part_spec& other) const; /** diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7c448dea4b1..4578cb89d28 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3328,7 +3328,7 @@ mysql_add_invisible_index(THD *thd, List *key_list, Key *key= NULL; key= new (thd->mem_root) Key(type, &null_clex_str, HA_KEY_ALG_UNDEF, false, DDL_options(DDL_options::OPT_NONE)); - key->columns.push_back(new(thd->mem_root) Key_part_spec(field_name, 0), + key->columns.push_back(new(thd->mem_root) Key_part_spec(field_name, 0, true), thd->mem_root); key_list->push_back(key, thd->mem_root); return key; @@ -3843,7 +3843,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, /* Either field is not present or field visibility is > INVISIBLE_USER */ - if (!sql_field) + if (!sql_field || (sql_field->invisible > INVISIBLE_USER && + !column->generated)) { my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str); DBUG_RETURN(TRUE); @@ -4509,9 +4510,10 @@ static bool vers_prepare_keys(THD *thd, HA_CREATE_INFO *create_info, if (key_part) continue; // Key already contains Sys_start or Sys_end - Key_part_spec *key_part_sys_end_col= - new (thd->mem_root) Key_part_spec(&create_info->vers_info.as_row.end, 0); - key->columns.push_back(key_part_sys_end_col); + Key_part_spec *row_end= + new (thd->mem_root) Key_part_spec(&create_info->vers_info.as_row.end, 0, + true); + key->columns.push_back(row_end); } return false; @@ -8408,8 +8410,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, key_part_length= 0; // Use whole field } key_part_length /= kfield->charset()->mbmaxlen; - key_parts.push_back(new Key_part_spec(&cfield->field_name, - key_part_length), + key_parts.push_back(new (thd->mem_root) Key_part_spec(&cfield->field_name, + key_part_length, true), thd->mem_root); } if (table->s->tmp_table == NO_TMP_TABLE) From d1667fb837f9e5300dc9cc10f2cce72533188b83 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 20 Oct 2020 11:16:40 +0300 Subject: [PATCH 151/323] MDEV-23852 alter table rename column to uppercase doesn't work Case-sensitive compare to detect column name case change in inplace alter rename. --- mysql-test/main/alter_table.result | 23 ++++++++++++++ mysql-test/main/alter_table.test | 12 ++++++++ mysql-test/suite/innodb/r/innodb-alter.result | 30 +++++++++---------- sql/sql_table.cc | 5 ++-- 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/mysql-test/main/alter_table.result b/mysql-test/main/alter_table.result index 197e52b35ca..d717820d621 100644 --- a/mysql-test/main/alter_table.result +++ b/mysql-test/main/alter_table.result @@ -3322,5 +3322,28 @@ Note 1176 Key 'x' doesn't exist in table 't1' unlock tables; drop table t1; # +# MDEV-23852 alter table rename column to uppercase doesn't work +# +create table t1 (abc int); +alter table t1 rename column abc to Abc, algorithm=copy; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `Abc` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t1 rename column abc to ABc, algorithm=inplace; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `ABc` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t1 rename column abc to ABC; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `ABC` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +# # End of 10.5 tests # diff --git a/mysql-test/main/alter_table.test b/mysql-test/main/alter_table.test index 6fe61a3222a..f5d3fdea907 100644 --- a/mysql-test/main/alter_table.test +++ b/mysql-test/main/alter_table.test @@ -2529,6 +2529,18 @@ alter table t1 rename key if exists x to xx; unlock tables; drop table t1; +--echo # +--echo # MDEV-23852 alter table rename column to uppercase doesn't work +--echo # +create table t1 (abc int); +alter table t1 rename column abc to Abc, algorithm=copy; +show create table t1; +alter table t1 rename column abc to ABc, algorithm=inplace; +show create table t1; +alter table t1 rename column abc to ABC; +show create table t1; +drop table t1; + --echo # --echo # End of 10.5 tests --echo # diff --git a/mysql-test/suite/innodb/r/innodb-alter.result b/mysql-test/suite/innodb/r/innodb-alter.result index 4bd1a09dd73..59abdb01d82 100644 --- a/mysql-test/suite/innodb/r/innodb-alter.result +++ b/mysql-test/suite/innodb/r/innodb-alter.result @@ -738,7 +738,7 @@ Table Create Table t2 CREATE TABLE `t2` ( `C2` int(11) DEFAULT NULL, KEY `c2` (`C2`), - CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`c2`) REFERENCES `t1` (`c1`) + CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`C2`) REFERENCES `t1` (`C1`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ALTER TABLE t1 CHANGE COLUMN C1 c5 INT; ALTER TABLE t2 CHANGE COLUMN C2 c6 INT; @@ -785,7 +785,7 @@ SELECT C.NAME FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS C INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES T ON C.TABLE_ID=T.TABLE_ID WHERE T.NAME='test/t1'; NAME -a +A b DROP TABLE t1; # different FOREIGN KEY cases @@ -842,27 +842,27 @@ t2 CREATE TABLE `t2` ( KEY `bb` (`BB`), KEY `CC` (`CC`), KEY `DD` (`DD`), - CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`aa`) REFERENCES `t1` (`a`), - CONSTRAINT `t2_ibfk_2` FOREIGN KEY (`bb`) REFERENCES `t1` (`b`), - CONSTRAINT `t2_ibfk_3` FOREIGN KEY (`cc`) REFERENCES `t1` (`c`), - CONSTRAINT `t2_ibfk_4` FOREIGN KEY (`dd`) REFERENCES `t1` (`d`) + CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`AA`) REFERENCES `t1` (`A`), + CONSTRAINT `t2_ibfk_2` FOREIGN KEY (`BB`) REFERENCES `t1` (`B`), + CONSTRAINT `t2_ibfk_3` FOREIGN KEY (`CC`) REFERENCES `t1` (`C`), + CONSTRAINT `t2_ibfk_4` FOREIGN KEY (`DD`) REFERENCES `t1` (`D`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 DELETE FROM t1 WHERE a=1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`aa`) REFERENCES `t1` (`a`)) +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`AA`) REFERENCES `t1` (`A`)) DELETE FROM t1 WHERE A=1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`aa`) REFERENCES `t1` (`a`)) +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`AA`) REFERENCES `t1` (`A`)) DELETE FROM t1 WHERE b=1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`aa`) REFERENCES `t1` (`a`)) +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`AA`) REFERENCES `t1` (`A`)) DELETE FROM t1 WHERE B=1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`aa`) REFERENCES `t1` (`a`)) +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`AA`) REFERENCES `t1` (`A`)) DELETE FROM t1 WHERE c=1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`aa`) REFERENCES `t1` (`a`)) +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`AA`) REFERENCES `t1` (`A`)) DELETE FROM t1 WHERE C=1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`aa`) REFERENCES `t1` (`a`)) +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`AA`) REFERENCES `t1` (`A`)) DELETE FROM t1 WHERE d=1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`aa`) REFERENCES `t1` (`a`)) +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`AA`) REFERENCES `t1` (`A`)) DELETE FROM t1 WHERE D=1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`aa`) REFERENCES `t1` (`a`)) +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`AA`) REFERENCES `t1` (`A`)) DROP TABLE t2, t1; # virtual columns case too CREATE TABLE t1 (a INT, b INT GENERATED ALWAYS AS (a) VIRTUAL) ENGINE = InnoDB; @@ -877,7 +877,7 @@ SELECT C.NAME FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS C INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES T ON C.TABLE_ID=T.TABLE_ID WHERE T.NAME='test/t1'; NAME -a +A b DROP TABLE t1; # and an MDEV-18041 regression related to indexes prefixes diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 345edf4d75c..31f165ef98a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7171,9 +7171,8 @@ static bool fill_alter_inplace_info(THD *thd, TABLE *table, bool varchar, ha_alter_info->handler_flags|= ALTER_STORED_COLUMN_TYPE; } - /* Check if field was renamed */ - if (lex_string_cmp(system_charset_info, &field->field_name, - &new_field->field_name)) + /* Check if field was renamed (case-sensitive for detecting case change) */ + if (cmp(&field->field_name, &new_field->field_name)) { field->flags|= FIELD_IS_RENAMED; ha_alter_info->handler_flags|= ALTER_COLUMN_NAME; From e3fc9c1db04bdc5566bcdafcc3d5159199089c00 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 20 Oct 2020 11:55:52 +0400 Subject: [PATCH 152/323] MDEV-19275 Provide SQL service to plugins. Duplicating lines removed from the debian script. --- debian/mariadb-test.install | 2 -- 1 file changed, 2 deletions(-) diff --git a/debian/mariadb-test.install b/debian/mariadb-test.install index 6aba73b3c1c..56947ac78ef 100644 --- a/debian/mariadb-test.install +++ b/debian/mariadb-test.install @@ -3,10 +3,8 @@ usr/bin/mariadb-client-test-embedded usr/bin/mariadb-test usr/bin/mariadb-test-embedded usr/lib/*/libmariadb3/plugin/auth_test_plugin.so -usr/lib/*/libmariadb3/plugin/test_sql_service.so usr/lib/*/libmariadb3/plugin/qa_auth_client.so usr/lib/*/libmariadb3/plugin/qa_auth_interface.so -usr/lib/*/libmariadb3/plugin/auth_test_plugin.so usr/lib/mysql/plugin/adt_null.so usr/lib/mysql/plugin/auth_0x0100.so usr/lib/mysql/plugin/auth_test_plugin.so From 7eda55619654b76add275695e0a6039e60876e81 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 20 Oct 2020 10:57:57 +0300 Subject: [PATCH 153/323] MDEV-23672 Assertion `v.v_indexes.empty()' failed in dict_table_t::instant_column dict_v_idx_t node was shared between two dict_v_col_t objects because of wrong object copy. Replace memory plain copy with copy constructor. Tha patch also removes n_v_indexes property and improves "page full" judgements for trx_undo_log_v_idx(). --- .../suite/innodb/r/instant_alter_bugs.result | 25 ++++++++++++++++++ .../suite/innodb/t/instant_alter_bugs.test | 19 ++++++++++++++ storage/innobase/dict/dict0dict.cc | 1 - storage/innobase/dict/dict0mem.cc | 1 - storage/innobase/handler/handler0alter.cc | 10 +++---- storage/innobase/include/dict0mem.h | 9 +------ storage/innobase/trx/trx0rec.cc | 26 +++++++++++++++---- 7 files changed, 70 insertions(+), 21 deletions(-) diff --git a/mysql-test/suite/innodb/r/instant_alter_bugs.result b/mysql-test/suite/innodb/r/instant_alter_bugs.result index 3da8fccd3c5..45172be8593 100644 --- a/mysql-test/suite/innodb/r/instant_alter_bugs.result +++ b/mysql-test/suite/innodb/r/instant_alter_bugs.result @@ -413,4 +413,29 @@ DROP TABLE t; CREATE TABLE t (pk SERIAL, b TEXT CHARACTER SET utf8) ENGINE=InnoDB; ALTER TABLE t MODIFY b TEXT CHARACTER SET utf8mb4 FIRST; DROP TABLE t; +# +# MDEV-23672 Assertion `v.v_indexes.empty()' failed in dict_table_t::instant_column +# +create table t1 ( +col_int integer, +col_text text not null, +col_int_g integer generated always as (col_int) unique, +col_text_g text generated always as (substr(col_text,1,499)) ) +engine innodb row_format = redundant; +insert into t1 values (0, 'a', default, default); +insert into t1 values (null, 'b', default, default); +alter table t1 modify column col_text text null, algorithm = instant; +insert into t1 values (1, null, default, default); +insert into t1 values (null, null, default, default); +update t1 set col_text= 'd'; +select * from t1; +col_int col_text col_int_g col_text_g +0 d 0 d +NULL d NULL d +1 d 1 d +NULL d NULL d +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency; diff --git a/mysql-test/suite/innodb/t/instant_alter_bugs.test b/mysql-test/suite/innodb/t/instant_alter_bugs.test index 9522a960928..12beabf1be2 100644 --- a/mysql-test/suite/innodb/t/instant_alter_bugs.test +++ b/mysql-test/suite/innodb/t/instant_alter_bugs.test @@ -436,4 +436,23 @@ CREATE TABLE t (pk SERIAL, b TEXT CHARACTER SET utf8) ENGINE=InnoDB; ALTER TABLE t MODIFY b TEXT CHARACTER SET utf8mb4 FIRST; DROP TABLE t; +--echo # +--echo # MDEV-23672 Assertion `v.v_indexes.empty()' failed in dict_table_t::instant_column +--echo # +create table t1 ( + col_int integer, + col_text text not null, + col_int_g integer generated always as (col_int) unique, + col_text_g text generated always as (substr(col_text,1,499)) ) +engine innodb row_format = redundant; +insert into t1 values (0, 'a', default, default); +insert into t1 values (null, 'b', default, default); +alter table t1 modify column col_text text null, algorithm = instant; +insert into t1 values (1, null, default, default); +insert into t1 values (null, null, default, default); +update t1 set col_text= 'd'; +select * from t1; +check table t1; +drop table t1; + SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency; diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 411abdcd494..d33e1dd3c3a 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -2146,7 +2146,6 @@ dict_index_add_col( if (col->is_virtual()) { dict_v_col_t* v_col = reinterpret_cast(col); /* Register the index with the virtual column index list */ - v_col->n_v_indexes++; v_col->v_indexes.push_front(dict_v_idx_t(index, index->n_def)); col_name = dict_table_get_v_col_name_mysql( table, dict_col_get_no(col)); diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index b72451e0f34..d179806324f 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -425,7 +425,6 @@ dict_mem_table_add_v_col( /* Initialize the index list for virtual columns */ ut_ad(v_col->v_indexes.empty()); - v_col->n_v_indexes = 0; return(v_col); } diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 1a355dbbeb1..b714dd63da6 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -589,8 +589,10 @@ inline bool dict_table_t::instant_column(const dict_table_t& table, mem_heap_dup(heap, table.v_col_names, ulint(end - table.v_col_names))); v_cols = static_cast( - mem_heap_dup(heap, table.v_cols, - table.n_v_cols * sizeof *v_cols)); + mem_heap_alloc(heap, table.n_v_cols * sizeof(*v_cols))); + for (ulint i = table.n_v_cols; i--; ) { + new (&v_cols[i]) dict_v_col_t(table.v_cols[i]); + } } else { ut_ad(table.n_v_cols == 0); v_col_names = NULL; @@ -603,8 +605,6 @@ inline bool dict_table_t::instant_column(const dict_table_t& table, for (unsigned i = 0; i < n_v_def; i++) { dict_v_col_t& v = v_cols[i]; - DBUG_ASSERT(v.v_indexes.empty()); - v.n_v_indexes = 0; v.base_col = static_cast( mem_heap_dup(heap, v.base_col, v.num_base * sizeof *v.base_col)); @@ -714,7 +714,6 @@ dup_dropped: (f.col); v_col->v_indexes.push_front( dict_v_idx_t(index, i)); - v_col->n_v_indexes++; } } } @@ -5031,7 +5030,6 @@ prepare_inplace_add_virtual( ctx->add_vcol[j].v_pos = ctx->old_table->n_v_cols - ctx->num_to_drop_vcol + j; - ctx->add_vcol[j].n_v_indexes = 0; /* MDEV-17468: Do this on ctx->instant_table later */ innodb_base_col_setup(ctx->old_table, field, &ctx->add_vcol[j]); j++; diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index e20812b862b..017b01e79ad 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -766,9 +766,6 @@ struct dict_v_col_t{ /** column pos in table */ unsigned v_pos:10; - /** number of indexes */ - unsigned n_v_indexes:12; - /** Virtual index list, and column position in the index */ std::forward_list > v_indexes; @@ -777,21 +774,17 @@ struct dict_v_col_t{ @param index index to be detached from */ void detach(const dict_index_t &index) { - if (!n_v_indexes) return; + if (v_indexes.empty()) return; auto i= v_indexes.before_begin(); - ut_d(unsigned n= 0); do { auto prev = i++; if (i == v_indexes.end()) { - ut_ad(n == n_v_indexes); return; } - ut_ad(++n <= n_v_indexes); if (i->index == &index) { v_indexes.erase_after(prev); - n_v_indexes--; return; } } diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index b164daf0ecc..310d071d368 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -230,20 +230,35 @@ trx_undo_log_v_idx( { ut_ad(pos < table->n_v_def); dict_v_col_t* vcol = dict_table_get_nth_v_col(table, pos); - ulint n_idx = vcol->n_v_indexes; byte* old_ptr; - ut_ad(n_idx > 0); + ut_ad(!vcol->v_indexes.empty()); /* Size to reserve, max 5 bytes for each index id and position, plus 5 bytes for num of indexes, 2 bytes for write total length. 1 byte for undo log record format version marker */ - ulint size = n_idx * (5 + 5) + 5 + 2 + (first_v_col ? 1 : 0); + ulint size = 5 + 2 + (first_v_col ? 1 : 0); + const ulint avail = trx_undo_left(undo_block, ptr); - if (trx_undo_left(undo_block, ptr) < size) { + if (avail < size) { return(NULL); } + size = 0; + ulint n_idx = 0; + for (const auto& v_index : vcol->v_indexes) { + n_idx++; + /* FIXME: index->id is 64 bits! */ + size += mach_get_compressed_size(uint32_t(v_index.index->id)); + size += mach_get_compressed_size(v_index.nth_field); + } + size += 2 + mach_get_compressed_size(n_idx); + + if (avail < size) { + return(NULL); + } + + if (first_v_col) { /* write the version marker */ mach_write_to_1(ptr, VIRTUAL_COL_UNDO_FORMAT_1); @@ -259,7 +274,8 @@ trx_undo_log_v_idx( for (const auto& v_index : vcol->v_indexes) { ptr += mach_write_compressed( - ptr, static_cast(v_index.index->id)); + /* FIXME: index->id is 64 bits! */ + ptr, uint32_t(v_index.index->id)); ptr += mach_write_compressed(ptr, v_index.nth_field); } From 692a44b30928e9bfb8f7a1aaf450fc29fa97c4b8 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Tue, 20 Oct 2020 12:01:37 +0200 Subject: [PATCH 154/323] MDEV-23327: followup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix an error with locked taböes --- sql/sql_udf.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index b4e863709d5..2af12d94228 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -654,6 +654,12 @@ enum drop_udf_result mysql_drop_function(THD *thd, const LEX_STRING *udf_name) udf_func *udf; DBUG_ENTER("mysql_drop_function"); + if (thd->locked_tables_mode) + { + my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); + DBUG_RETURN(UDF_DEL_RESULT_ERROR); + } + if (!(table= open_udf_func_table(thd))) DBUG_RETURN(UDF_DEL_RESULT_ERROR); From 888010d9dd5409c48caf01fb0f465c98caa232c7 Mon Sep 17 00:00:00 2001 From: Julius Goryavsky Date: Tue, 24 Mar 2020 14:55:07 +0100 Subject: [PATCH 155/323] MDEV-21951: mariabackup SST fail if data-directory have lost+found directory To fix this, it is necessary to add an option to exclude the database with the name "lost+found" from processing (the database name will be checked by the check_if_skip_database_by_path() or by the check_if_skip_database() function, and as a result "lost+found" will be skipped). In addition, it is necessary to slightly modify the verification logic in the check_if_skip_database() function. Also added a new test galera_sst_mariabackup_lost_found.test --- extra/mariabackup/xtrabackup.cc | 2 +- .../galera_sst_mariabackup_lost_found.result | 37 ++++++++++ .../t/galera_sst_mariabackup_lost_found.cnf | 15 ++++ .../t/galera_sst_mariabackup_lost_found.test | 71 +++++++++++++++++++ scripts/wsrep_sst_mariabackup.sh | 4 +- 5 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 mysql-test/suite/galera/r/galera_sst_mariabackup_lost_found.result create mode 100644 mysql-test/suite/galera/t/galera_sst_mariabackup_lost_found.cnf create mode 100644 mysql-test/suite/galera/t/galera_sst_mariabackup_lost_found.test diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 162efebbd9f..7cb9d5ac3fe 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -2371,7 +2371,7 @@ check_if_skip_database( if (databases_exclude_hash && find_filter_in_hashtable(name, databases_exclude_hash, &database) && - !database->has_tables) { + (!database->has_tables || !databases_include_hash)) { /* Database is found and there are no tables specified, skip entire db. */ return DATABASE_SKIP; diff --git a/mysql-test/suite/galera/r/galera_sst_mariabackup_lost_found.result b/mysql-test/suite/galera/r/galera_sst_mariabackup_lost_found.result new file mode 100644 index 00000000000..b2a2005748f --- /dev/null +++ b/mysql-test/suite/galera/r/galera_sst_mariabackup_lost_found.result @@ -0,0 +1,37 @@ +connection node_1; +connection node_2; +connection node_2; +Shutting down server ... +connection node_1; +CREATE DATABASE `lost+found`; +USE `lost+found`; +CREATE TABLE t1(id INT); +INSERT INTO t1 VALUES (1), (2); +SELECT * FROM `lost+found`.t1; +id +1 +2 +CREATE DATABASE `#mysql50#not_lost+found`; +USE `#mysql50#not_lost+found`; +CREATE TABLE t1(id INT); +INSERT INTO t1 VALUES (1), (2); +SELECT * FROM `#mysql50#not_lost+found`.t1; +id +1 +2 +Cleaning var directory ... +connection node_2; +Starting server ... +SELECT * FROM `lost+found`.t1; +id +1 +2 +SELECT * FROM `#mysql50#not_lost+found`.t1; +id +1 +2 +connection node_1; +DROP DATABASE `lost+found`; +DROP DATABASE `#mysql50#not_lost+found`; +disconnect node_2; +disconnect node_1; diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup_lost_found.cnf b/mysql-test/suite/galera/t/galera_sst_mariabackup_lost_found.cnf new file mode 100644 index 00000000000..a09efd2e011 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sst_mariabackup_lost_found.cnf @@ -0,0 +1,15 @@ +!include ../galera_2nodes.cnf + +[mysqld] +wsrep_sst_method=mariabackup +wsrep_sst_auth="root:" + +[mysqld.1] +wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore_sb=true' + +[mysqld.2] +wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true' + +[sst] +transferfmt=@ENV.MTR_GALERA_TFMT +streamfmt=xbstream diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup_lost_found.test b/mysql-test/suite/galera/t/galera_sst_mariabackup_lost_found.test new file mode 100644 index 00000000000..d1c30656139 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sst_mariabackup_lost_found.test @@ -0,0 +1,71 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_mariabackup.inc + +# Save original auto_increment_offset values. +--let $node_1=node_1 +--let $node_2=node_2 +--source include/auto_increment_offset_save.inc + +--connection node_2 + +#--connection node_2 +#--source suite/galera/include/galera_unload_provider.inc + +--echo Shutting down server ... +--source include/shutdown_mysqld.inc + +--connection node_1 +--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' +--source include/wait_condition.inc + +CREATE DATABASE `lost+found`; +USE `lost+found`; +CREATE TABLE t1(id INT); +INSERT INTO t1 VALUES (1), (2); +SELECT * FROM `lost+found`.t1; + +CREATE DATABASE `#mysql50#not_lost+found`; +USE `#mysql50#not_lost+found`; +CREATE TABLE t1(id INT); +INSERT INTO t1 VALUES (1), (2); +SELECT * FROM `#mysql50#not_lost+found`.t1; + +# +# Force SST +# +--echo Cleaning var directory ... +--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat +--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/mtr +--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/performance_schema +--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/test +--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/mysql +--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data + +--connection node_2 + +--echo Starting server ... +let $restart_noprint=2; +--source include/start_mysqld.inc + +--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--source include/wait_condition.inc + +--let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready'; +--source include/wait_condition.inc + +SELECT * FROM `lost+found`.t1; +SELECT * FROM `#mysql50#not_lost+found`.t1; + +--connection node_1 + +DROP DATABASE `lost+found`; +DROP DATABASE `#mysql50#not_lost+found`; + +# rmdir $MYSQLD_DATADIR/lost+found; +# rmdir $MYSQLD_DATADIR/not_lost+found; + +# Restore original auto_increment_offset values. +--source include/auto_increment_offset_restore.inc + +--source include/galera_end.inc diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh index 85138c3c0be..231cf6e3702 100644 --- a/scripts/wsrep_sst_mariabackup.sh +++ b/scripts/wsrep_sst_mariabackup.sh @@ -712,9 +712,11 @@ if ${INNOBACKUPEX_BIN} /tmp --help 2>/dev/null | grep -q -- '--version-check'; t disver="--no-version-check" fi +iopts+=" --databases-exclude=\"lost+found\"" + 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+=" --no-backup-locks" fi INNOEXTRA=$WSREP_SST_OPT_MYSQLD From edfeb1291945e43bf800017365d49240d2a4a20e Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Tue, 20 Oct 2020 13:08:16 +0000 Subject: [PATCH 156/323] MCS engine ref update --- debian/mariadb-plugin-columnstore.install | 1 + storage/columnstore/columnstore | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/mariadb-plugin-columnstore.install b/debian/mariadb-plugin-columnstore.install index 3b4c9619dc6..f519fa2a37e 100644 --- a/debian/mariadb-plugin-columnstore.install +++ b/debian/mariadb-plugin-columnstore.install @@ -55,6 +55,7 @@ usr/bin/mariadb-columnstore-start.sh usr/bin/mariadb-columnstore-stop.sh usr/bin/mariadb-command-line.sh usr/bin/master-rep-columnstore.sh +usr/bin/mcs-savebrm.py usr/bin/mcs-loadbrm.py usr/bin/mcs-stop-controllernode.sh usr/bin/mcsGetConfig diff --git a/storage/columnstore/columnstore b/storage/columnstore/columnstore index b6b02ed516f..0f21cbe5173 160000 --- a/storage/columnstore/columnstore +++ b/storage/columnstore/columnstore @@ -1 +1 @@ -Subproject commit b6b02ed516f92055127d416370799d91a82754ea +Subproject commit 0f21cbe517363de2e43a497084a21455a6373d66 From 88d22f0e65192ca1b1e69b46661ce57ce19dbaa4 Mon Sep 17 00:00:00 2001 From: Kentoku SHIBA Date: Thu, 16 Apr 2020 00:44:20 +0900 Subject: [PATCH 157/323] MDEV-20100 MariaDB 13.3.9 Crash "[ERROR] mysqld got signal 11 ;" Some functions on ha_partition call functions on all partitions, but handler->reset() is only called that pruned by m_partitions_to_reset. So Spider didn't clear pointer on unpruned partitions, if the unpruned partitions are used by next query, Spider reference the pointer that is already freed. --- sql/ha_partition.cc | 85 ++++++++----- .../bugfix/include/mdev_20100_deinit.inc | 11 ++ .../spider/bugfix/include/mdev_20100_init.inc | 46 +++++++ .../spider/bugfix/r/mdev_20100.result | 119 ++++++++++++++++++ .../mysql-test/spider/bugfix/t/mdev_20100.cnf | 3 + .../spider/bugfix/t/mdev_20100.test | 85 +++++++++++++ 6 files changed, 320 insertions(+), 29 deletions(-) create mode 100644 storage/spider/mysql-test/spider/bugfix/include/mdev_20100_deinit.inc create mode 100644 storage/spider/mysql-test/spider/bugfix/include/mdev_20100_init.inc create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_20100.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_20100.cnf create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_20100.test diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index c742524a236..b11890aaffb 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -11019,7 +11019,7 @@ TABLE_LIST *ha_partition::get_next_global_for_child() const COND *ha_partition::cond_push(const COND *cond) { - handler **file= m_file; + uint i; COND *res_cond= NULL; DBUG_ENTER("ha_partition::cond_push"); @@ -11029,26 +11029,35 @@ const COND *ha_partition::cond_push(const COND *cond) We want to do this in a separate loop to not come into a situation where we have only done cond_push() to some of the tables */ - do + for (i= bitmap_get_first_set(&m_partitions_to_reset); + i < m_tot_parts; + i= bitmap_get_next_set(&m_partitions_to_reset, i)) { - if (((*file)->set_top_table_and_fields(top_table, - top_table_field, - top_table_fields))) - DBUG_RETURN(cond); // Abort cond push, no error - } while (*(++file)); - file= m_file; + if (bitmap_is_set(&m_opened_partitions, i)) + { + if ((m_file[i]->set_top_table_and_fields(top_table, + top_table_field, + top_table_fields))) + DBUG_RETURN(cond); // Abort cond push, no error + } + } } - do + for (i= bitmap_get_first_set(&m_partitions_to_reset); + i < m_tot_parts; + i= bitmap_get_next_set(&m_partitions_to_reset, i)) { - if ((*file)->pushed_cond != cond) + if (bitmap_is_set(&m_opened_partitions, i)) { - if ((*file)->cond_push(cond)) - res_cond= (COND *) cond; - else - (*file)->pushed_cond= cond; + if (m_file[i]->pushed_cond != cond) + { + if (m_file[i]->cond_push(cond)) + res_cond= (COND *) cond; + else + m_file[i]->pushed_cond= cond; + } } - } while (*(++file)); + } DBUG_RETURN(res_cond); } @@ -11060,13 +11069,18 @@ const COND *ha_partition::cond_push(const COND *cond) void ha_partition::cond_pop() { - handler **file= m_file; + uint i; DBUG_ENTER("ha_partition::cond_pop"); - do + for (i= bitmap_get_first_set(&m_partitions_to_reset); + i < m_tot_parts; + i= bitmap_get_next_set(&m_partitions_to_reset, i)) { - (*file)->cond_pop(); - } while (*(++file)); + if (bitmap_is_set(&m_opened_partitions, i)) + { + m_file[i]->cond_pop(); + } + } DBUG_VOID_RETURN; } @@ -11642,23 +11656,29 @@ int ha_partition::pre_direct_delete_rows() int ha_partition::info_push(uint info_type, void *info) { - int error= 0; - handler **file= m_file; + int error= 0, tmp; + uint i; DBUG_ENTER("ha_partition::info_push"); - do + for (i= bitmap_get_first_set(&m_partitions_to_reset); + i < m_tot_parts; + i= bitmap_get_next_set(&m_partitions_to_reset, i)) { - int tmp; - if ((tmp= (*file)->info_push(info_type, info))) - error= tmp; - } while (*(++file)); + if (bitmap_is_set(&m_opened_partitions, i)) + { + if ((tmp= m_file[i]->info_push(info_type, info))) + { + error= tmp; + } + } + } DBUG_RETURN(error); } void ha_partition::clear_top_table_fields() { - handler **file; + uint i; DBUG_ENTER("ha_partition::clear_top_table_fields"); if (set_top_table_fields) @@ -11667,8 +11687,15 @@ void ha_partition::clear_top_table_fields() top_table= NULL; top_table_field= NULL; top_table_fields= 0; - for (file= m_file; *file; file++) - (*file)->clear_top_table_fields(); + for (i= bitmap_get_first_set(&m_partitions_to_reset); + i < m_tot_parts; + i= bitmap_get_next_set(&m_partitions_to_reset, i)) + { + if (bitmap_is_set(&m_opened_partitions, i)) + { + m_file[i]->clear_top_table_fields(); + } + } } DBUG_VOID_RETURN; } diff --git a/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_deinit.inc b/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_deinit.inc new file mode 100644 index 00000000000..1880a1c7bba --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_deinit.inc @@ -0,0 +1,11 @@ +--let $MASTER_1_COMMENT_P_2_1= $MASTER_1_COMMENT_P_2_1_BACKUP +--let $CHILD2_1_DROP_TABLES= $CHILD2_1_DROP_TABLES_BACKUP +--let $CHILD2_1_CREATE_TABLES= $CHILD2_1_CREATE_TABLES_BACKUP +--let $CHILD2_1_SELECT_TABLES= $CHILD2_1_SELECT_TABLES_BACKUP +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_deinit.inc +--enable_result_log +--enable_query_log +--enable_warnings diff --git a/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_init.inc b/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_init.inc new file mode 100644 index 00000000000..ed6e27962d2 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_init.inc @@ -0,0 +1,46 @@ +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_init.inc +--enable_result_log +--enable_query_log +--enable_warnings +--let $MASTER_1_COMMENT_P_2_1_BACKUP= $MASTER_1_COMMENT_P_2_1 +let $MASTER_1_COMMENT_P_2_1= + PARTITION BY RANGE(a) ( + PARTITION pt1 VALUES LESS THAN (5) COMMENT='srv "s_2_1", table "ta_r2"', + PARTITION pt2 VALUES LESS THAN (10) COMMENT='srv "s_2_1", table "ta_r3"', + PARTITION pt3 VALUES LESS THAN MAXVALUE COMMENT='srv "s_2_1", table "ta_r4"' + ); +--let $CHILD2_1_DROP_TABLES_BACKUP= $CHILD2_1_DROP_TABLES +let $CHILD2_1_DROP_TABLES= + DROP TABLE IF EXISTS ta_r2 $STR_SEMICOLON + DROP TABLE IF EXISTS ta_r3 $STR_SEMICOLON + DROP TABLE IF EXISTS ta_r4; +--let $CHILD2_1_CREATE_TABLES_BACKUP= $CHILD2_1_CREATE_TABLES +let $CHILD2_1_CREATE_TABLES= + CREATE TABLE ta_r2 ( + a INT, + b CHAR(1), + c DATETIME, + PRIMARY KEY(a) + ) $CHILD2_1_ENGINE $CHILD2_1_CHARSET $STR_SEMICOLON + CREATE TABLE ta_r3 ( + a INT, + b CHAR(1), + c DATETIME, + PRIMARY KEY(a) + ) $CHILD2_1_ENGINE $CHILD2_1_CHARSET $STR_SEMICOLON + CREATE TABLE ta_r4 ( + a INT, + b CHAR(1), + c DATETIME, + PRIMARY KEY(a) + ) $CHILD2_1_ENGINE $CHILD2_1_CHARSET; +--let $CHILD2_1_SELECT_TABLES_BACKUP= $CHILD2_1_SELECT_TABLES +let $CHILD2_1_SELECT_TABLES= + SELECT a, b, c FROM ta_r2 ORDER BY a $STR_SEMICOLON + SELECT a, b, c FROM ta_r3 ORDER BY a $STR_SEMICOLON + SELECT a, b, c FROM ta_r4 ORDER BY a; +let $CHILD2_1_SELECT_ARGUMENT1= + SELECT argument FROM mysql.general_log WHERE argument LIKE '%select %'; diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_20100.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_20100.result new file mode 100644 index 00000000000..fc4fb02d72f --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_20100.result @@ -0,0 +1,119 @@ +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 + +this test is for MDEV-20100 + +drop and create databases +connection master_1; +CREATE DATABASE auto_test_local; +USE auto_test_local; +connection child2_1; +SET @old_log_output = @@global.log_output; +SET GLOBAL log_output = 'TABLE,FILE'; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; + +create table and insert +connection child2_1; +CHILD2_1_CREATE_TABLES +TRUNCATE TABLE mysql.general_log; +connection master_1; +CREATE TABLE tbl_a ( +a INT, +b CHAR(1), +c DATETIME, +PRIMARY KEY(a) +) ENGINE=Spider PARTITION BY RANGE(a) ( +PARTITION pt1 VALUES LESS THAN (5) COMMENT='srv "s_2_1", table "ta_r2"', +PARTITION pt2 VALUES LESS THAN (10) COMMENT='srv "s_2_1", table "ta_r3"', +PARTITION pt3 VALUES LESS THAN MAXVALUE COMMENT='srv "s_2_1", table "ta_r4"' + ) +INSERT INTO tbl_a (a, b, c) VALUES +(1, 'a', '2008-08-01 10:21:39'), +(2, 'b', '2000-01-01 00:00:00'), +(3, 'e', '2007-06-04 20:03:11'), +(4, 'd', '2003-11-30 05:01:03'), +(5, 'c', '2001-12-31 23:59:59'); + +test 1 +connection child2_1; +TRUNCATE TABLE mysql.general_log; +connection master_1; +SELECT a, b, c FROM tbl_a PARTITION (pt2) WHERE b = 'c'; +a b c +5 c 2001-12-31 23:59:59 +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt2); +a b c +1 a 2008-08-01 10:21:39 +2 b 2000-01-01 00:00:00 +3 e 2007-06-04 20:03:11 +4 d 2003-11-30 05:01:03 +5 c 2001-12-31 23:59:59 +SELECT a, b, c FROM tbl_a PARTITION (pt3) WHERE b = 'c'; +a b c +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt2); +a b c +1 a 2008-08-01 10:21:39 +2 b 2000-01-01 00:00:00 +3 e 2007-06-04 20:03:11 +4 d 2003-11-30 05:01:03 +5 c 2001-12-31 23:59:59 +SELECT a, b, c FROM tbl_a PARTITION (pt1) WHERE b = 'c'; +a b c +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt3); +a b c +1 a 2008-08-01 10:21:39 +2 b 2000-01-01 00:00:00 +3 e 2007-06-04 20:03:11 +4 d 2003-11-30 05:01:03 +SELECT a, b, c FROM tbl_a PARTITION (pt1) WHERE b = 'c'; +a b c +SELECT a, b, c FROM tbl_a PARTITION (pt2,pt3); +a b c +5 c 2001-12-31 23:59:59 +connection child2_1; +SELECT argument FROM mysql.general_log WHERE argument LIKE '%select %'; +argument +select `a`,`b`,`c` from `auto_test_remote`.`ta_r3` where (`b` = 'c') +select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` +select `a`,`b`,`c` from `auto_test_remote`.`ta_r3` +select `a`,`b`,`c` from `auto_test_remote`.`ta_r4` where (`b` = 'c') +select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` +select `a`,`b`,`c` from `auto_test_remote`.`ta_r3` +select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` where (`b` = 'c') +select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` +select `a`,`b`,`c` from `auto_test_remote`.`ta_r4` +select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` where (`b` = 'c') +select `a`,`b`,`c` from `auto_test_remote`.`ta_r3` +select `a`,`b`,`c` from `auto_test_remote`.`ta_r4` +SELECT argument FROM mysql.general_log WHERE argument LIKE '%select %' +SELECT a, b, c FROM ta_r2 ORDER BY a ; +SELECT a, b, c FROM ta_r3 ORDER BY a ; +SELECT a, b, c FROM ta_r4 ORDER BY a; +a b c +1 a 2008-08-01 10:21:39 +2 b 2000-01-01 00:00:00 +3 e 2007-06-04 20:03:11 +4 d 2003-11-30 05:01:03 +a b c +5 c 2001-12-31 23:59:59 +a b c + +deinit +connection master_1; +DROP DATABASE IF EXISTS auto_test_local; +connection child2_1; +DROP DATABASE IF EXISTS auto_test_remote; +SET GLOBAL log_output = @old_log_output; +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 + +end of test diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.cnf b/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.cnf new file mode 100644 index 00000000000..05dfd8a0bce --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.cnf @@ -0,0 +1,3 @@ +!include include/default_mysqld.cnf +!include ../my_1_1.cnf +!include ../my_2_1.cnf diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.test new file mode 100644 index 00000000000..b72facd11a6 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.test @@ -0,0 +1,85 @@ +--source ../include/mdev_20100_init.inc +--echo +--echo this test is for MDEV-20100 +--echo +--echo drop and create databases + +--connection master_1 +--disable_warnings +CREATE DATABASE auto_test_local; +USE auto_test_local; + +--connection child2_1 +SET @old_log_output = @@global.log_output; +SET GLOBAL log_output = 'TABLE,FILE'; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; +--enable_warnings + +--echo +--echo create table and insert + +--connection child2_1 +--disable_query_log +echo CHILD2_1_CREATE_TABLES; +eval $CHILD2_1_CREATE_TABLES; +--enable_query_log +TRUNCATE TABLE mysql.general_log; + +--connection master_1 +--disable_query_log +echo CREATE TABLE tbl_a ( + a INT, + b CHAR(1), + c DATETIME, + PRIMARY KEY(a) +) $MASTER_1_ENGINE $MASTER_1_COMMENT_P_2_1; +eval CREATE TABLE tbl_a ( + a INT, + b CHAR(1), + c DATETIME, + PRIMARY KEY(a) +) $MASTER_1_ENGINE $MASTER_1_COMMENT_P_2_1; +--enable_query_log +INSERT INTO tbl_a (a, b, c) VALUES + (1, 'a', '2008-08-01 10:21:39'), + (2, 'b', '2000-01-01 00:00:00'), + (3, 'e', '2007-06-04 20:03:11'), + (4, 'd', '2003-11-30 05:01:03'), + (5, 'c', '2001-12-31 23:59:59'); + +--echo +--echo test 1 + +--connection child2_1 +TRUNCATE TABLE mysql.general_log; + +--connection master_1 +SELECT a, b, c FROM tbl_a PARTITION (pt2) WHERE b = 'c'; +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt2); +SELECT a, b, c FROM tbl_a PARTITION (pt3) WHERE b = 'c'; +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt2); +SELECT a, b, c FROM tbl_a PARTITION (pt1) WHERE b = 'c'; +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt3); +SELECT a, b, c FROM tbl_a PARTITION (pt1) WHERE b = 'c'; +SELECT a, b, c FROM tbl_a PARTITION (pt2,pt3); + +--connection child2_1 +eval $CHILD2_1_SELECT_ARGUMENT1; +eval $CHILD2_1_SELECT_TABLES; + +--echo +--echo deinit +--disable_warnings + +--connection master_1 +DROP DATABASE IF EXISTS auto_test_local; + +--connection child2_1 +DROP DATABASE IF EXISTS auto_test_remote; +SET GLOBAL log_output = @old_log_output; + +--enable_warnings +--source ../include/mdev_20100_deinit.inc +--echo +--echo end of test From 0627c4ae21adaae414dec28bc26f225f3deed431 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Sat, 17 Oct 2020 14:18:54 +0200 Subject: [PATCH 158/323] Updated mtr help - Updated combination example to use `innodb_plugin` ``` $ ./mysql-test/mtr rpl.rpl_invoked_features # no rpl.rpl_invoked_features,mix,xtradb_plugin worker[1] Using MTR_BUILD_THREAD 300, with reserved ports 16000..16019 rpl.rpl_invoked_features 'innodb_plugin,mix' [ pass ] 904 rpl.rpl_invoked_features 'mix,xtradb' [ pass ] 1707 rpl.rpl_invoked_features 'innodb_plugin,row' [ pass ] 927 rpl.rpl_invoked_features 'row,xtradb' [ pass ] 828 rpl.rpl_invoked_features 'innodb_plugin,stmt' [ pass ] 855 rpl.rpl_invoked_features 'stmt,xtradb' [ pass ] 952 -------------------------------------------------------------------------- ``` - `gdb` option can take optional gdb arguments (good documentation in KB) --- mysql-test/mysql-test-run.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 52920530132..e76712cc079 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -6088,7 +6088,7 @@ Examples: alias main.alias 'main' is the name of the suite for the 't' directory. -rpl.rpl_invoked_features,mix,xtradb_plugin +rpl.rpl_invoked_features,mix,innodb_plugin suite/rpl/t/rpl.rpl_invoked_features Options to control what engine/variation to run: @@ -6216,7 +6216,7 @@ Options for debugging the product debug-server Use debug version of server, but without turning on tracing debugger=NAME Start mysqld in the selected debugger - gdb Start the mysqld(s) in gdb + gdb[=gdb_arguments] Start the mysqld(s) in gdb manual-debug Let user manually start mysqld in debugger, before running test(s) manual-gdb Let user manually start mysqld in gdb, before running From d1af93a5e84c416833b5f77719db36a976ebde50 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Sat, 17 Oct 2020 14:33:04 +0200 Subject: [PATCH 159/323] Update mtr help - Based on patch: d6a983351c5a454bd0cb113852f - Update combination example for 10.2 (commit 2a3fe45dd2df added change for 10.3+) ``` ============================================================================== TEST RESULT TIME (ms) or COMMENT -------------------------------------------------------------------------- worker[1] Using MTR_BUILD_THREAD 300, with reserved ports 16000..16019 rpl.rpl_invoked_features 'innodb,mix' [ pass ] 1677 rpl.rpl_invoked_features 'innodb,row' [ pass ] 3516 rpl.rpl_invoked_features 'innodb,stmt' [ pass ] 1609 -------------------------------------------------------------------------- ``` - `gdb` option will be added during the merge --- mysql-test/mysql-test-run.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 30cc833ad99..ef3fd6294f4 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -6418,7 +6418,7 @@ Examples: alias main.alias 'main' is the name of the suite for the 't' directory. -rpl.rpl_invoked_features,mix,xtradb_plugin +rpl.rpl_invoked_features,mix,innodb suite/rpl/t/rpl.rpl_invoked_features Options to control what engine/variation to run: From 832a6acb72027ee1cf2fbf9be224a8cd65cfd6fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 20 Oct 2020 18:31:56 +0300 Subject: [PATCH 160/323] MDEV-23996 Race conditions in SHOW ENGINE INNODB MUTEX The function innodb_show_mutex_status() is the only ultimate caller of LatchCounter::iterate() via MutexMonitor::iterate(). Because the call is not protected by LatchCounter::m_mutex, any mutex_create() or mutex_free() that is invoked concurrently during the execution, bad things such as a crash could happen. The most likely way for this to happen is buffer pool resizing, which could cause buf_block_t::mutex (which existed before MDEV-15053) to be created or freed. We could also register InnoDB mutexes in TrxFactory::init() if trx_pools needs to grow. The view INFORMATION_SCHEMA.INNODB_MUTEXES is not affected, because it only displays information about rw-locks, not mutexes. This commit intentionally touches also MutexMonitor::iterate() and the only code that interfaces with LatchCounter::iterate() to make it clearer for future readers that the scattered code that is obfuscated by templates belongs together. This is based on mysql/mysql-server@273a93396f49c7e0a8b07b260128d9a990c2b154 --- storage/innobase/handler/ha_innodb.cc | 12 +++--------- storage/innobase/include/sync0types.h | 8 +++++--- storage/innobase/include/ut0mutex.h | 16 +++++----------- 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c408b1a1d30..637c66612ce 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -16332,8 +16332,7 @@ struct ShowStatus { /** Collect the latch metrics. Ignore entries where the spins and waits are zero. @param[in] count The latch metrics */ - void operator()(Count* count) - UNIV_NOTHROW + void operator()(Count* count) const UNIV_NOTHROW { if (count->m_spins > 0 || count->m_waits > 0) { @@ -16361,13 +16360,8 @@ struct ShowStatus { bool operator()(latch_meta_t& latch_meta) UNIV_NOTHROW { - latch_meta_t::CounterType* counter; - - counter = latch_meta.get_counter(); - - GetCount get_count(latch_meta.get_name(), &m_values); - - counter->iterate(get_count); + latch_meta.get_counter()->iterate( + GetCount(latch_meta.get_name(), &m_values)); return(true); } diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h index ca8291f666a..563176f4abe 100644 --- a/storage/innobase/include/sync0types.h +++ b/storage/innobase/include/sync0types.h @@ -659,10 +659,10 @@ public: } /** Iterate over the counters */ - template - void iterate(Callback& callback) const - UNIV_NOTHROW + template void iterate(const C& callback) UNIV_NOTHROW { + m_mutex.enter(); + Counters::const_iterator end = m_counters.end(); for (Counters::const_iterator it = m_counters.begin(); @@ -671,6 +671,8 @@ public: callback(*it); } + + m_mutex.exit(); } /** Disable the monitoring */ diff --git a/storage/innobase/include/ut0mutex.h b/storage/innobase/include/ut0mutex.h index 1f99ee17a24..5375be0ed71 100644 --- a/storage/innobase/include/ut0mutex.h +++ b/storage/innobase/include/ut0mutex.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2012, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 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 @@ -142,16 +142,10 @@ public: /* Some of the slots will be null in non-debug mode */ - if (*it == NULL) { - continue; - } - - latch_meta_t* latch_meta = *it; - - bool ret = callback(*latch_meta); - - if (!ret) { - return(ret); + if (latch_meta_t* l= *it) { + if (!callback(*l)) { + return false; + } } } From 0049d5b515d066c88d8f452868da07d9f08e01bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 20 Oct 2020 19:11:15 +0300 Subject: [PATCH 161/323] Revert MDEV-23484 Rollback unnecessarily acquires dict_operation_lock In row_undo_ins_remove_clust_rec() and similar places, an assertion !node->trx->dict_operation_lock_mode could fail, because an online ALTER is not allowed to run at the same time while DDL operations on the table are being rolled back. This race condition would be fixed by always acquiring an InnoDB table lock in ha_innobase::prepare_inplace_alter_table() or prepare_inplace_alter_table_dict(), or by ensuring that recovered transactions are protected by MDL that would block concurrent DDL until the rollback has been completed. This reverts commit 1509363970e9cb574005e3af560299c055dda983 and commit 22c4a7512f8dc3f2d2586a856b362ad97ab2bf7d. --- storage/innobase/handler/handler0alter.cc | 4 +- storage/innobase/row/row0uins.cc | 7 +-- storage/innobase/row/row0umod.cc | 57 ++++++++++++++++++++--- storage/innobase/row/row0undo.cc | 20 ++++---- 4 files changed, 64 insertions(+), 24 deletions(-) diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 44942bf164b..b766cac5dd5 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -8273,11 +8273,11 @@ ha_innobase::commit_inplace_alter_table( /* Exclusively lock the table, to ensure that no other transaction is holding locks on the table while we - change the table definition. The meta-data lock (MDL) + change the table definition. The MySQL meta-data lock should normally guarantee that no conflicting locks exist. However, FOREIGN KEY constraints checks and any transactions collected during crash recovery could be - holding InnoDB locks only, not MDL. */ + holding InnoDB locks only, not MySQL locks. */ dberr_t error = row_merge_lock_table( m_prebuilt->trx, ctx->old_table, LOCK_X); diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc index 7e5aac1ba9f..54fa244fca6 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -81,7 +81,6 @@ row_undo_ins_remove_clust_rec( mtr.set_log_mode(MTR_LOG_NO_REDO); } else { mtr.set_named_space(index->space); - ut_ad(lock_table_has_locks(index->table)); } /* This is similar to row_undo_mod_clust(). The DDL thread may @@ -92,7 +91,8 @@ row_undo_ins_remove_clust_rec( online = dict_index_is_online_ddl(index); if (online) { - ut_ad(!node->trx->dict_operation_lock_mode); + ut_ad(node->trx->dict_operation_lock_mode + != RW_X_LATCH); ut_ad(node->table->id != DICT_INDEXES_ID); mtr_s_lock(dict_index_get_lock(index), &mtr); } @@ -491,9 +491,6 @@ row_undo_ins( return(DB_SUCCESS); } - ut_ad(node->table->is_temporary() - || lock_table_has_locks(node->table)); - /* Iterate over all the indexes and undo the insert.*/ node->index = dict_table_get_first_index(node->table); diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index 0de0760834e..80d90f40379 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -264,7 +264,10 @@ row_undo_mod_clust( bool online; ut_ad(thr_get_trx(thr) == node->trx); + ut_ad(node->trx->dict_operation_lock_mode); ut_ad(node->trx->in_rollback); + ut_ad(rw_lock_own_flagged(&dict_operation_lock, + RW_LOCK_FLAG_X | RW_LOCK_FLAG_S)); log_free_check(); pcur = &node->pcur; @@ -275,12 +278,11 @@ row_undo_mod_clust( mtr.set_log_mode(MTR_LOG_NO_REDO); } else { mtr.set_named_space(index->space); - ut_ad(lock_table_has_locks(index->table)); } online = dict_index_is_online_ddl(index); if (online) { - ut_ad(!node->trx->dict_operation_lock_mode); + ut_ad(node->trx->dict_operation_lock_mode != RW_X_LATCH); mtr_s_lock(dict_index_get_lock(index), &mtr); } @@ -319,7 +321,17 @@ row_undo_mod_clust( ut_ad(err == DB_SUCCESS || err == DB_OUT_OF_FILE_SPACE); } - if (err == DB_SUCCESS && online && dict_index_is_online_ddl(index)) { + /* Online rebuild cannot be initiated while we are holding + dict_operation_lock and index->lock. (It can be aborted.) */ + ut_ad(online || !dict_index_is_online_ddl(index)); + + if (err == DB_SUCCESS && online) { + + ut_ad(rw_lock_own_flagged( + &index->lock, + RW_LOCK_FLAG_S | RW_LOCK_FLAG_X + | RW_LOCK_FLAG_SX)); + switch (node->rec_type) { case TRX_UNDO_DEL_MARK_REC: row_log_table_insert( @@ -794,6 +806,37 @@ func_exit_no_pcur: return(err); } +/***********************************************************//** +Flags a secondary index corrupted. */ +static MY_ATTRIBUTE((nonnull)) +void +row_undo_mod_sec_flag_corrupted( +/*============================*/ + trx_t* trx, /*!< in/out: transaction */ + dict_index_t* index) /*!< in: secondary index */ +{ + ut_ad(!dict_index_is_clust(index)); + + switch (trx->dict_operation_lock_mode) { + case RW_S_LATCH: + /* Because row_undo() is holding an S-latch + on the data dictionary during normal rollback, + we can only mark the index corrupted in the + data dictionary cache. TODO: fix this somehow.*/ + mutex_enter(&dict_sys->mutex); + dict_set_corrupted_index_cache_only(index); + mutex_exit(&dict_sys->mutex); + break; + default: + ut_ad(0); + /* fall through */ + case RW_X_LATCH: + /* This should be the rollback of a data dictionary + transaction. */ + dict_set_corrupted(index, trx, "rollback"); + } +} + /***********************************************************//** Undoes a modify in secondary indexes when undo record type is UPD_DEL. @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ @@ -907,7 +950,8 @@ row_undo_mod_del_mark_sec( } if (err == DB_DUPLICATE_KEY) { - index->type |= DICT_CORRUPT; + row_undo_mod_sec_flag_corrupted( + thr_get_trx(thr), index); err = DB_SUCCESS; /* Do not return any error to the caller. The duplicate will be reported by ALTER TABLE or @@ -1053,7 +1097,8 @@ row_undo_mod_upd_exist_sec( } if (err == DB_DUPLICATE_KEY) { - index->type |= DICT_CORRUPT; + row_undo_mod_sec_flag_corrupted( + thr_get_trx(thr), index); err = DB_SUCCESS; } else if (err != DB_SUCCESS) { break; @@ -1205,8 +1250,6 @@ row_undo_mod( return(DB_SUCCESS); } - ut_ad(node->table->is_temporary() - || lock_table_has_locks(node->table)); node->index = dict_table_get_first_index(node->table); ut_ad(dict_index_is_clust(node->index)); /* Skip the clustered index (the first index) */ diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc index 185a71e670b..b65b173fedb 100644 --- a/storage/innobase/row/row0undo.cc +++ b/storage/innobase/row/row0undo.cc @@ -279,16 +279,15 @@ row_undo( ? UNDO_NODE_INSERT : UNDO_NODE_MODIFY; } - /* Prevent prepare_inplace_alter_table_dict() from adding - dict_table_t::indexes while we are processing the record. - Recovered transactions are not protected by MDL, and the - secondary index creation is not protected by table locks - for online operation. (A table lock would only be acquired - when committing the ALTER TABLE operation.) */ - const bool locked_data_dict = UNIV_UNLIKELY(trx->is_recovered) - && !trx->dict_operation_lock_mode; + /* Prevent DROP TABLE etc. while we are rolling back this row. + If we are doing a TABLE CREATE or some other dictionary operation, + then we already have dict_operation_lock locked in x-mode. Do not + try to lock again, because that would cause a hang. */ + + const bool locked_data_dict = (trx->dict_operation_lock_mode == 0); + + if (locked_data_dict) { - if (UNIV_UNLIKELY(locked_data_dict)) { row_mysql_freeze_data_dictionary(trx); } @@ -304,7 +303,8 @@ row_undo( err = row_undo_mod(node, thr); } - if (UNIV_UNLIKELY(locked_data_dict)) { + if (locked_data_dict) { + row_mysql_unfreeze_data_dictionary(trx); } From f9c432c5a9c9e0942962677154041bddbdc8fbdb Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 10 Sep 2020 16:28:12 +0300 Subject: [PATCH 162/323] Disable from valgrind big innodb tests that doesn't run well in valgrind --- .../suite/encryption/t/innodb_encryption-page-compression.test | 2 ++ mysql-test/suite/innodb/t/alter_large_dml.test | 2 ++ mysql-test/suite/innodb/t/innodb_bug30113362.test | 2 ++ mysql-test/suite/innodb/t/undo_truncate_recover.test | 1 + 4 files changed, 7 insertions(+) diff --git a/mysql-test/suite/encryption/t/innodb_encryption-page-compression.test b/mysql-test/suite/encryption/t/innodb_encryption-page-compression.test index ad1a9ea8671..57c8721282f 100644 --- a/mysql-test/suite/encryption/t/innodb_encryption-page-compression.test +++ b/mysql-test/suite/encryption/t/innodb_encryption-page-compression.test @@ -1,6 +1,8 @@ -- source include/have_innodb.inc -- source include/have_example_key_management_plugin.inc -- source include/not_embedded.inc +# This test is too slow for valgrind and causes innnodb semaphores to time out +-- source include/not_valgrind.inc let $innodb_encrypt_tables_orig = `SELECT @@innodb_encrypt_tables`; let $innodb_encryption_threads_orig = `SELECT @@innodb_encryption_threads`; diff --git a/mysql-test/suite/innodb/t/alter_large_dml.test b/mysql-test/suite/innodb/t/alter_large_dml.test index 5ab3f394115..e44adf2c3ba 100644 --- a/mysql-test/suite/innodb/t/alter_large_dml.test +++ b/mysql-test/suite/innodb/t/alter_large_dml.test @@ -1,4 +1,6 @@ --source include/big_test.inc +# debug sync points times out when using valgrind +--source include/not_valgrind.inc --source include/have_innodb.inc --source include/have_debug.inc --source include/have_debug_sync.inc diff --git a/mysql-test/suite/innodb/t/innodb_bug30113362.test b/mysql-test/suite/innodb/t/innodb_bug30113362.test index de5d07ffb29..789f1a493cb 100644 --- a/mysql-test/suite/innodb/t/innodb_bug30113362.test +++ b/mysql-test/suite/innodb/t/innodb_bug30113362.test @@ -6,6 +6,8 @@ --source include/have_debug.inc --source include/have_debug_sync.inc --source include/have_innodb_16k.inc +# debug sync points times out when using valgrind +--source include/not_valgrind.inc --disable_query_log SET @old_innodb_limit_optimistic_insert_debug = @@innodb_limit_optimistic_insert_debug; diff --git a/mysql-test/suite/innodb/t/undo_truncate_recover.test b/mysql-test/suite/innodb/t/undo_truncate_recover.test index e6a873085e0..e499ff3dfbe 100644 --- a/mysql-test/suite/innodb/t/undo_truncate_recover.test +++ b/mysql-test/suite/innodb/t/undo_truncate_recover.test @@ -3,6 +3,7 @@ # --source include/big_test.inc +--source include/not_valgrind.inc # With larger innodb_page_size, the undo log tablespaces do not grow enough. --source include/innodb_page_size_small.inc --source include/have_innodb.inc From 5902d5e0eb6bda11ff9a9792d5308e209f0b9140 Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 13 Sep 2020 14:20:10 +0300 Subject: [PATCH 163/323] Added wait-for-pos-timeout=NUM argument to mtr Other things: - Updated help text for --gdb --- mysql-test/mysql-test-run.pl | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 7deff1f68f5..95ebbaf50c7 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -321,6 +321,7 @@ my $opt_start_timeout = $ENV{MTR_START_TIMEOUT} || 180; # seconds sub suite_timeout { return $opt_suite_timeout * 60; }; my $opt_wait_all; +my $opt_wait_for_pos_timeout; my $opt_user_args; my $opt_repeat= 1; my $opt_retry= 1; @@ -1229,6 +1230,7 @@ sub command_line_setup { 'verbose+' => \$opt_verbose, 'verbose-restart' => \&report_option, 'sleep=i' => \$opt_sleep, + 'wait-for-pos-timeout=i' => \$opt_wait_for_pos_timeout, 'start-dirty' => \$opt_start_dirty, 'start-and-exit' => \$opt_start_exit, 'start' => \$opt_start, @@ -5824,11 +5826,15 @@ sub start_mysqltest ($) { mtr_add_arg($args, "--sleep=%d", $opt_sleep); } - if ( $opt_valgrind ) + if ( $opt_valgrind || $opt_wait_for_pos_timeout) { - # We are running server under valgrind, which causes some replication - # test to be much slower, notable rpl_mdev6020. Increase timeout. - mtr_add_arg($args, "--wait-for-pos-timeout=1500"); + if (! $opt_wait_for_pos_timeout) + { + # We are running server under valgrind, which causes some replication + # test to be much slower, notable rpl_mdev6020. Increase timeout. + $opt_wait_for_pos_timeout= 1500; + } + mtr_add_arg($args, "--wait-for-pos-timeout=$opt_wait_for_pos_timeout"); } if ( $opt_ssl ) @@ -6456,7 +6462,7 @@ Options for debugging the product debug-server Use debug version of server, but without turning on tracing debugger=NAME Start mysqld in the selected debugger - gdb Start the mysqld(s) in gdb + gdb[=gdb-arguments] Start the mysqld(s) in gdb. manual-debug Let user manually start mysqld in debugger, before running test(s) manual-gdb Let user manually start mysqld in gdb, before running @@ -6563,6 +6569,7 @@ Misc options the file (for buildbot) sleep=SECONDS Passed to mysqltest, will be used as fixed sleep time + wait-for-pos-timeout=NUM Passed to mysqltest debug-sync-timeout=NUM Set default timeout for WAIT_FOR debug sync actions. Disable facility with NUM=0. gcov Collect coverage information after the test. From 71d263a19891e0382d4eec4f3169a4968b032ead Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 13 Sep 2020 15:45:41 +0300 Subject: [PATCH 164/323] MDEV-23691 S3 storage engine: delayed slave can drop the table This commit fixed the problems with S3 after the "DROP TABLE FORCE" changes. It also fixes all failing replication S3 tests. A slave is delayed if it is trying to execute replicated queries on a table that is already converted to S3 by the master later in the binlog. Fixes for replication events on S3 tables for delayed slaves: - INSERT and INSERT ... SELECT and CREATE TABLE are ignored but written to the binary log. UPDATE & DELETE will be fixed in a future commit. Other things: - On slaves with --s3-slave-ignore-updates set, allow S3 tables to be opened in read-write mode. This was done to be able to ignore-but-replicate queries like insert. Without this change any open of an S3 table failed with 'Table is read only' which is too early to be able to replicate the original query. - Errors are now printed if handler::extra() call fails in wait_while_tables_are_used(). - Error message for row changes are changed from HA_ERR_WRONG_COMMAND to HA_ERR_TABLE_READONLY. - Disable some maria_extra() calls for S3 tables. This could cause S3 tables to fail in some cases. - Added missing thr_lock_delete() to ma_open() in case of failure. - Removed from mysql_prepare_insert() the not needed argument 'table'. --- mysql-test/suite/s3/alter.result | 8 ++ mysql-test/suite/s3/alter.test | 4 + mysql-test/suite/s3/partition.result | 2 +- mysql-test/suite/s3/replication.inc | 10 +- mysql-test/suite/s3/replication_delayed.cnf | 3 + .../suite/s3/replication_delayed.result | 124 ++++++++++++++++++ mysql-test/suite/s3/replication_delayed.test | 115 ++++++++++++++++ mysql-test/suite/s3/replication_mixed.result | 27 +++- mysql-test/suite/s3/replication_stmt.result | 27 +++- sql/handler.cc | 9 +- sql/log.cc | 6 + sql/sql_base.cc | 13 +- sql/sql_class.cc | 32 +++++ sql/sql_class.h | 1 + sql/sql_insert.cc | 92 +++++++------ sql/sql_insert.h | 10 +- sql/sql_parse.cc | 8 ++ sql/sql_parse.h | 2 +- sql/sql_prepare.cc | 5 +- sql/sql_table.cc | 69 +++++++++- storage/maria/ha_s3.cc | 22 +++- storage/maria/ha_s3.h | 12 +- storage/maria/ma_extra.c | 15 ++- storage/maria/ma_open.c | 5 + 24 files changed, 539 insertions(+), 82 deletions(-) create mode 100644 mysql-test/suite/s3/replication_delayed.cnf create mode 100644 mysql-test/suite/s3/replication_delayed.result create mode 100644 mysql-test/suite/s3/replication_delayed.test diff --git a/mysql-test/suite/s3/alter.result b/mysql-test/suite/s3/alter.result index 0764d661468..da9ddb11ea7 100644 --- a/mysql-test/suite/s3/alter.result +++ b/mysql-test/suite/s3/alter.result @@ -25,6 +25,14 @@ t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL ) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 COMMENT='hello' +alter table t1 engine=s3; +alter table t1 engine=innodb; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 COMMENT='hello' select count(*), sum(a), sum(b) from t1; count(*) sum(a) sum(b) 1000 500500 510500 diff --git a/mysql-test/suite/s3/alter.test b/mysql-test/suite/s3/alter.test index 791d7750cb1..4504804c91a 100644 --- a/mysql-test/suite/s3/alter.test +++ b/mysql-test/suite/s3/alter.test @@ -1,5 +1,6 @@ --source include/have_s3.inc --source include/have_sequence.inc +--source include/have_innodb.inc # # Create unique database for running the tests @@ -21,6 +22,9 @@ alter table t1 comment="hello"; show create table t1; alter table t1 engine=aria; show create table t1; +alter table t1 engine=s3; +alter table t1 engine=innodb; +show create table t1; select count(*), sum(a), sum(b) from t1; drop table t1; diff --git a/mysql-test/suite/s3/partition.result b/mysql-test/suite/s3/partition.result index 7020ce88483..ee837611d50 100644 --- a/mysql-test/suite/s3/partition.result +++ b/mysql-test/suite/s3/partition.result @@ -63,7 +63,7 @@ count(*) ALTER TABLE t2 CHECK PARTITION p3; Table Op Msg_type Msg_text s3.t2 check error Subpartition p3sp0 returned error -s3.t2 check error Unknown - internal error 131 during operation +s3.t2 check error Unknown - internal error 165 during operation SELECT count(*) FROM t2; count(*) 6 diff --git a/mysql-test/suite/s3/replication.inc b/mysql-test/suite/s3/replication.inc index 26dd9a5da25..d790c70f221 100644 --- a/mysql-test/suite/s3/replication.inc +++ b/mysql-test/suite/s3/replication.inc @@ -20,6 +20,8 @@ connection master; create table t1 (a int, b int) engine=aria; insert into t1 select seq,seq+10 from seq_1_to_10; +sync_slave_with_master; +connection master; alter table t1 engine=s3; show create table t1; @@ -116,12 +118,18 @@ connection slave; stop slave; connection master; rename table t1 to t2; -create table t1 (a int, b int) engine=aria; +# Check the different create options with the table +create table t1 (a int) engine=aria; +drop table t1; +create table if not exists t1 (a int, b int) engine=aria; +drop table t1; +create or replace table t1 (a int, b int, c int) engine=aria; alter table t1 engine=s3; connection slave; start slave; connection master; sync_slave_with_master; +show create table t1; select * from t1 limit 2; select * from t2 limit 2; connection master; diff --git a/mysql-test/suite/s3/replication_delayed.cnf b/mysql-test/suite/s3/replication_delayed.cnf new file mode 100644 index 00000000000..9313546f637 --- /dev/null +++ b/mysql-test/suite/s3/replication_delayed.cnf @@ -0,0 +1,3 @@ +!include ../rpl/my.cnf +!include ./my.cnf +!include ./slave.cnf diff --git a/mysql-test/suite/s3/replication_delayed.result b/mysql-test/suite/s3/replication_delayed.result new file mode 100644 index 00000000000..cad8b905d0b --- /dev/null +++ b/mysql-test/suite/s3/replication_delayed.result @@ -0,0 +1,124 @@ +include/master-slave.inc +[connection master] +set binlog_format=mixed; +RESET MASTER; +connection slave; +set binlog_format=mixed; +RESET MASTER; +connection master; +connection slave; +use database; +connection master; +# +# MDEV-23691 S3 storage engine: delayed slave can drop the table +# +connection slave; +stop slave; +connection master; +create /*or replace*/ table t100 ( +pk varchar(100) +) engine = 'innodb'; +insert into t100 values ('old data'); +alter table t100 engine=s3; +drop table t100; +create /*or replace*/ table t100 ( +pk varchar(100) +) engine= innodb; +insert into t100 select 'new data' from seq_1_to_10; +alter table t100 engine=s3; +select count(*), 'before slave start' from t100; +count(*) before slave start +10 before slave start +connection slave; +start slave; +connection master; +connection slave; +connection master; +flush tables; +select count(*), 'after slave start' from t100; +count(*) after slave start +10 after slave start +show create table t100; +Table Create Table +t100 CREATE TABLE `t100` ( + `pk` varchar(100) DEFAULT NULL +) ENGINE=S3 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 +connection slave; +select count(*) from t100; +count(*) +10 +connection master; +drop table t100; +# +# Test delayed slave with inserts +# +connection slave; +stop slave; +connection master; +create table t1 (a int) engine=innodb; +insert into t1 values (1),(2),(3); +insert into t1 select * from seq_4_to_6; +alter table t1 engine=s3; +connection slave; +start slave; +connection master; +connection slave; +select * from t1; +a +1 +2 +3 +4 +5 +6 +connection master; +drop table t1; +# +# Check slave binary log +# +connection slave; +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # create database database +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; create /*or replace*/ table t100 ( +pk varchar(100) +) engine = 'innodb' +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `database`; insert into t100 values ('old data') +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; alter table t100 engine=s3 +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; DROP TABLE IF EXISTS `t100` /* generated by server */ +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; create /*or replace*/ table t100 ( +pk varchar(100) +) engine= innodb +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `database`; insert into t100 select 'new data' from seq_1_to_10 +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; alter table t100 engine=s3 +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; flush tables +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; DROP TABLE IF EXISTS `t100` /* generated by server */ +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; create table t1 (a int) engine=innodb +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `database`; insert into t1 values (1),(2),(3) +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `database`; insert into t1 select * from seq_4_to_6 +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; alter table t1 engine=s3 +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; DROP TABLE IF EXISTS `t1` /* generated by server */ +connection master; +# +# clean up +# +include/rpl_end.inc diff --git a/mysql-test/suite/s3/replication_delayed.test b/mysql-test/suite/s3/replication_delayed.test new file mode 100644 index 00000000000..0ae93b850c4 --- /dev/null +++ b/mysql-test/suite/s3/replication_delayed.test @@ -0,0 +1,115 @@ +--source include/have_s3.inc +--source include/have_innodb.inc +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc +--source include/have_sequence.inc + +# First clear the binlog +set binlog_format=mixed; +RESET MASTER; +connection slave; +set binlog_format=mixed; +RESET MASTER; +connection master; + +# +# Create unique database for running the tests +# +--source create_database.inc +sync_slave_with_master; +--replace_result $database database +--eval use $database +connection master; + +--echo # +--echo # MDEV-23691 S3 storage engine: delayed slave can drop the table +--echo # + +connection slave; +stop slave; +connection master; + +# +# Create version 1 of the table +# + +create /*or replace*/ table t100 ( + pk varchar(100) +) engine = 'innodb'; + +insert into t100 values ('old data'); +alter table t100 engine=s3; + +# +# Create version 2 of the table +# +drop table t100; +create /*or replace*/ table t100 ( + pk varchar(100) +) engine= innodb; +insert into t100 select 'new data' from seq_1_to_10; +alter table t100 engine=s3; + +select count(*), 'before slave start' from t100; + +# +# Now, start the slave +# +connection slave; +start slave; +connection master; +sync_slave_with_master; +#select count(*) from t100; +connection master; + +flush tables; +select count(*), 'after slave start' from t100; +show create table t100; + +connection slave; + +select count(*) from t100; + +connection master; + +drop table t100; + +--echo # +--echo # Test delayed slave with inserts +--echo # + + +# Stop slave + +connection slave; +stop slave; +connection master; + +# Create tables with data while slave is stopped +create table t1 (a int) engine=innodb; +insert into t1 values (1),(2),(3); +insert into t1 select * from seq_4_to_6; +alter table t1 engine=s3; + +connection slave; +start slave; +connection master; +sync_slave_with_master; +select * from t1; +connection master; +drop table t1; + +--echo # +--echo # Check slave binary log +--echo # + +sync_slave_with_master; +--let $binlog_database=$database +--source include/show_binlog_events.inc +connection master; + +--echo # +--echo # clean up +--echo # +--source drop_database.inc +--source include/rpl_end.inc diff --git a/mysql-test/suite/s3/replication_mixed.result b/mysql-test/suite/s3/replication_mixed.result index 47cf907b187..077ae2bf1f9 100644 --- a/mysql-test/suite/s3/replication_mixed.result +++ b/mysql-test/suite/s3/replication_mixed.result @@ -13,6 +13,8 @@ connection master; # create table t1 (a int, b int) engine=aria; insert into t1 select seq,seq+10 from seq_1_to_10; +connection slave; +connection master; alter table t1 engine=s3; show create table t1; Table Create Table @@ -134,14 +136,25 @@ connection slave; stop slave; connection master; rename table t1 to t2; -create table t1 (a int, b int) engine=aria; +create table t1 (a int) engine=aria; +drop table t1; +create table if not exists t1 (a int, b int) engine=aria; +drop table t1; +create or replace table t1 (a int, b int, c int) engine=aria; alter table t1 engine=s3; connection slave; start slave; connection master; connection slave; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL +) ENGINE=S3 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 select * from t1 limit 2; -a b +a b c select * from t2 limit 2; a b f 1 11 NULL @@ -238,7 +251,15 @@ slave-bin.000001 # Query # # use `database`; set @@sql_if_exists=1; alter table slave-bin.000001 # Gtid # # GTID #-#-# slave-bin.000001 # Query # # use `database`; set @@sql_if_exists=1; rename table t1 to t2 slave-bin.000001 # Gtid # # GTID #-#-# -slave-bin.000001 # Query # # use `database`; create table t1 (a int, b int) engine=aria +slave-bin.000001 # Query # # use `database`; create table t1 (a int) engine=aria +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; DROP TABLE IF EXISTS `t1` /* generated by server */ +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; create table if not exists t1 (a int, b int) engine=aria +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; DROP TABLE IF EXISTS `t1` /* generated by server */ +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; create or replace table t1 (a int, b int, c int) engine=aria slave-bin.000001 # Gtid # # GTID #-#-# slave-bin.000001 # Query # # use `database`; alter table t1 engine=s3 slave-bin.000001 # Gtid # # GTID #-#-# diff --git a/mysql-test/suite/s3/replication_stmt.result b/mysql-test/suite/s3/replication_stmt.result index 56fd07445a4..8284c053cac 100644 --- a/mysql-test/suite/s3/replication_stmt.result +++ b/mysql-test/suite/s3/replication_stmt.result @@ -13,6 +13,8 @@ connection master; # create table t1 (a int, b int) engine=aria; insert into t1 select seq,seq+10 from seq_1_to_10; +connection slave; +connection master; alter table t1 engine=s3; show create table t1; Table Create Table @@ -134,14 +136,25 @@ connection slave; stop slave; connection master; rename table t1 to t2; -create table t1 (a int, b int) engine=aria; +create table t1 (a int) engine=aria; +drop table t1; +create table if not exists t1 (a int, b int) engine=aria; +drop table t1; +create or replace table t1 (a int, b int, c int) engine=aria; alter table t1 engine=s3; connection slave; start slave; connection master; connection slave; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL +) ENGINE=S3 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 select * from t1 limit 2; -a b +a b c select * from t2 limit 2; a b f 1 11 NULL @@ -238,7 +251,15 @@ slave-bin.000001 # Query # # use `database`; set @@sql_if_exists=1; alter table slave-bin.000001 # Gtid # # GTID #-#-# slave-bin.000001 # Query # # use `database`; set @@sql_if_exists=1; rename table t1 to t2 slave-bin.000001 # Gtid # # GTID #-#-# -slave-bin.000001 # Query # # use `database`; create table t1 (a int, b int) engine=aria +slave-bin.000001 # Query # # use `database`; create table t1 (a int) engine=aria +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; DROP TABLE IF EXISTS `t1` /* generated by server */ +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; create table if not exists t1 (a int, b int) engine=aria +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; DROP TABLE IF EXISTS `t1` /* generated by server */ +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `database`; create or replace table t1 (a int, b int, c int) engine=aria slave-bin.000001 # Gtid # # GTID #-#-# slave-bin.000001 # Query # # use `database`; alter table t1 engine=s3 slave-bin.000001 # Gtid # # GTID #-#-# diff --git a/sql/handler.cc b/sql/handler.cc index e9972a42b64..302467b4479 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2764,6 +2764,9 @@ int ha_delete_table(THD *thd, handlerton *hton, const char *path, if (hton == NULL || hton == view_pseudo_hton) DBUG_RETURN(0); + if (ha_check_if_updates_are_ignored(thd, hton, "DROP")) + DBUG_RETURN(0); + error= hton->drop_table(hton, path); if (error > 0) { @@ -2801,7 +2804,8 @@ int ha_delete_table(THD *thd, handlerton *hton, const char *path, error= -1; } } - + if (error) + DBUG_PRINT("exit", ("error: %d", error)); DBUG_RETURN(error); } @@ -5008,7 +5012,8 @@ static my_bool delete_table_force(THD *thd, plugin_ref plugin, void *arg) handlerton *hton = plugin_hton(plugin); st_force_drop_table_params *param = (st_force_drop_table_params *)arg; - if (param->discovering == (hton->discover_table != NULL)) + if (param->discovering == (hton->discover_table != NULL) && + !(thd->slave_thread && (hton->flags & HTON_IGNORE_UPDATES))) { int error; error= ha_delete_table(thd, hton, param->path, param->db, param->alias, 0); diff --git a/sql/log.cc b/sql/log.cc index 2cd04bdc1b2..60e2bf9d4ab 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2151,6 +2151,12 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) DBUG_RETURN(0); } + /* + This is true if we are doing an alter table that is replicated as + CREATE TABLE ... SELECT + */ + if (thd->variables.option_bits & OPTION_BIN_COMMIT_OFF) + DBUG_RETURN(0); DBUG_PRINT("debug", ("all: %d, in_transaction: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e6d0ab13e75..20f1fb356a3 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1316,7 +1316,12 @@ bool wait_while_table_is_used(THD *thd, TABLE *table, table->s->tdc->flush(thd, true); /* extra() call must come only after all instances above are closed */ if (function != HA_EXTRA_NOT_USED) - DBUG_RETURN(table->file->extra(function)); + { + int error= table->file->extra(function); + if (error) + table->file->print_error(error, MYF(0)); + DBUG_RETURN(error); + } DBUG_RETURN(FALSE); } @@ -3907,7 +3912,8 @@ static bool upgrade_lock_if_not_exists(THD *thd, { DEBUG_SYNC(thd,"create_table_before_check_if_exists"); if (!create_info.or_replace() && - ha_table_exists(thd, &create_table->db, &create_table->table_name)) + ha_table_exists(thd, &create_table->db, &create_table->table_name, + &create_table->db_type)) { if (create_info.if_not_exists()) { @@ -3955,7 +3961,8 @@ static bool upgrade_lock_if_not_exists(THD *thd, Note that for CREATE TABLE IF EXISTS we only generate a warning but still return TRUE (to abort the calling open_table() function). On must check THD->is_error() if one wants to distinguish between warning - and error. + and error. If table existed, tables_start->db_type is set to the handlerton + for the found table. */ bool diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d27d0c678e4..e522fd1b1af 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -7477,6 +7477,38 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, DBUG_RETURN(0); } + +/** + Binlog current query as a statement, ignoring the binlog filter setting. + + The filter is in decide_logging_format() to mark queries to not be stored + in the binary log, for example by a shared distributed engine like S3. + This function resets the filter to ensure the the query is logged if + the binlog is active. + + Note that 'direct' is set to false, which means that the query will + not be directly written to the binary log but instead to the cache. + + @retval false ok + @retval true error +*/ + + +bool THD::binlog_current_query_unfiltered() +{ + if (!mysql_bin_log.is_open()) + return 0; + + reset_binlog_local_stmt_filter(); + clear_binlog_local_stmt_filter(); + return binlog_query(THD::STMT_QUERY_TYPE, query(), query_length(), + /* is_trans */ FALSE, + /* direct */ FALSE, + /* suppress_use */ FALSE, + /* Error */ 0) > 0; +} + + void THD::wait_for_wakeup_ready() { diff --git a/sql/sql_class.h b/sql/sql_class.h index 994fb9dd6ad..e20366e578b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3491,6 +3491,7 @@ public: char const *query, ulong query_len, bool is_trans, bool direct, bool suppress_use, int errcode); + bool binlog_current_query_unfiltered(); #endif inline void diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 4ad4c478937..5e0346c3977 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -724,6 +724,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list, Item *unused_conds= 0; DBUG_ENTER("mysql_insert"); + bzero((char*) &info,sizeof(info)); create_explain_query(thd->lex, thd->mem_root); /* Upgrade lock type if the requested lock is incompatible with @@ -764,16 +765,28 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(TRUE); value_count= values->elements; - if (mysql_prepare_insert(thd, table_list, table, fields, values, - update_fields, update_values, duplic, - &unused_conds, FALSE)) + if ((res= mysql_prepare_insert(thd, table_list, fields, values, + update_fields, update_values, duplic, + &unused_conds, FALSE))) + { + retval= thd->is_error(); + if (res < 0) + { + /* + Insert should be ignored but we have to log the query in statement + format in the binary log + */ + if (thd->binlog_current_query_unfiltered()) + retval= 1; + } goto abort; + } + /* mysql_prepare_insert sets table_list->table if it was not set */ + table= table_list->table; /* Prepares LEX::returing_list if it is not empty */ if (returning) result->prepare(returning->item_list, NULL); - /* mysql_prepare_insert sets table_list->table if it was not set */ - table= table_list->table; context= &thd->lex->first_select_lex()->context; /* @@ -828,7 +841,6 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list, /* Fill in the given fields and dump it to the table file */ - bzero((char*) &info,sizeof(info)); info.ignore= ignore; info.handle_duplicates=duplic; info.update_fields= &update_fields; @@ -1534,9 +1546,6 @@ static void prepare_for_positional_update(TABLE *table, TABLE_LIST *tables) mysql_prepare_insert() thd Thread handler table_list Global/local table list - table Table to insert into - (can be NULL if table should - be taken from table_list->table) where Where clause (for insert ... select) select_insert TRUE if INSERT ... SELECT statement @@ -1551,15 +1560,16 @@ static void prepare_for_positional_update(TABLE *table, TABLE_LIST *tables) before releasing the table object. RETURN VALUE - FALSE OK - TRUE error + 0 OK + >0 error + <0 insert should be ignored */ -bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, - TABLE *table, List &fields, List_item *values, - List &update_fields, List &update_values, - enum_duplicates duplic, COND **where, - bool select_insert) +int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, + List &fields, List_item *values, + List &update_fields, List &update_values, + enum_duplicates duplic, COND **where, + bool select_insert) { SELECT_LEX *select_lex= thd->lex->first_select_lex(); Name_resolution_context *context= &select_lex->context; @@ -1567,29 +1577,34 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, bool insert_into_view= (table_list->view != 0); bool res= 0; table_map map= 0; + TABLE *table; DBUG_ENTER("mysql_prepare_insert"); - DBUG_PRINT("enter", ("table_list: %p table: %p view: %d", - table_list, table, - (int)insert_into_view)); + DBUG_PRINT("enter", ("table_list: %p view: %d", + table_list, (int) insert_into_view)); /* INSERT should have a SELECT or VALUES clause */ DBUG_ASSERT (!select_insert || !values); if (mysql_handle_derived(thd->lex, DT_INIT)) - DBUG_RETURN(TRUE); + DBUG_RETURN(1); if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT)) - DBUG_RETURN(TRUE); + DBUG_RETURN(1); if (thd->lex->handle_list_of_derived(table_list, DT_PREPARE)) - DBUG_RETURN(TRUE); + DBUG_RETURN(1); if (duplic == DUP_UPDATE) { /* it should be allocated before Item::fix_fields() */ if (table_list->set_insert_values(thd->mem_root)) - DBUG_RETURN(TRUE); + DBUG_RETURN(1); } + table= table_list->table; + + if (table->file->check_if_updates_are_ignored("INSERT")) + DBUG_RETURN(-1); + if (mysql_prepare_insert_check_table(thd, table_list, fields, select_insert)) - DBUG_RETURN(TRUE); + DBUG_RETURN(1); /* Prepare the fields in the statement. */ if (values) @@ -1632,9 +1647,6 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, if (res) DBUG_RETURN(res); - if (!table) - table= table_list->table; - if (check_duplic_insert_without_overlaps(thd, table, duplic) != 0) DBUG_RETURN(true); @@ -1642,7 +1654,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, { // Additional memory may be required to create historical items. if (table_list->set_insert_values(thd->mem_root)) - DBUG_RETURN(TRUE); + DBUG_RETURN(1); } if (!select_insert) @@ -1653,7 +1665,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, CHECK_DUP_ALLOW_DIFFERENT_ALIAS))) { update_non_unique_table_error(table_list, "INSERT", duplicate); - DBUG_RETURN(TRUE); + DBUG_RETURN(1); } select_lex->fix_prepare_information(thd, &fake_conds, &fake_conds); } @@ -1663,7 +1675,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, */ if (duplic == DUP_UPDATE || duplic == DUP_REPLACE) prepare_for_positional_update(table, table_list); - DBUG_RETURN(FALSE); + DBUG_RETURN(0); } @@ -3703,12 +3715,14 @@ bool Delayed_insert::handle_inserts(void) thd thread handler RETURN - FALSE OK - TRUE Error + 0 OK + > 0 Error + < 0 Ok, ignore insert */ -bool mysql_insert_select_prepare(THD *thd, select_result *sel_res) +int mysql_insert_select_prepare(THD *thd, select_result *sel_res) { + int res; LEX *lex= thd->lex; SELECT_LEX *select_lex= lex->first_select_lex(); DBUG_ENTER("mysql_insert_select_prepare"); @@ -3718,11 +3732,11 @@ bool mysql_insert_select_prepare(THD *thd, select_result *sel_res) clause if table is VIEW */ - if (mysql_prepare_insert(thd, lex->query_tables, - lex->query_tables->table, lex->field_list, 0, - lex->update_list, lex->value_list, lex->duplicates, - &select_lex->where, TRUE)) - DBUG_RETURN(TRUE); + if ((res= mysql_prepare_insert(thd, lex->query_tables, lex->field_list, 0, + lex->update_list, lex->value_list, + lex->duplicates, + &select_lex->where, TRUE))) + DBUG_RETURN(res); /* If sel_res is not empty, it means we have items in returing_list. @@ -3763,7 +3777,7 @@ bool mysql_insert_select_prepare(THD *thd, select_result *sel_res) while ((table= ti++) && insert_tables--) ti.remove(); - DBUG_RETURN(FALSE); + DBUG_RETURN(0); } diff --git a/sql/sql_insert.h b/sql/sql_insert.h index 14041976973..80666a81c50 100644 --- a/sql/sql_insert.h +++ b/sql/sql_insert.h @@ -23,11 +23,11 @@ typedef List List_item; typedef struct st_copy_info COPY_INFO; -bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, - List &fields, List_item *values, - List &update_fields, - List &update_values, enum_duplicates duplic, - COND **where, bool select_insert); +int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, + List &fields, List_item *values, + List &update_fields, + List &update_values, enum_duplicates duplic, + COND **where, bool select_insert); bool mysql_insert(THD *thd,TABLE_LIST *table,List &fields, List &values, List &update_fields, List &update_values, enum_duplicates flag, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4ef2a4c5d46..c8fad45acac 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4717,6 +4717,14 @@ mysql_execute_command(THD *thd) } delete sel_result; } + else if (res < 0) + { + /* + Insert should be ignored but we have to log the query in statement + format in the binary log + */ + res= thd->binlog_current_query_unfiltered(); + } delete result; if (save_protocol) { diff --git a/sql/sql_parse.h b/sql/sql_parse.h index 6b0ee75b57b..0e5cc7f4bad 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -41,7 +41,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables); bool multi_delete_precheck(THD *thd, TABLE_LIST *tables); int mysql_multi_update_prepare(THD *thd); int mysql_multi_delete_prepare(THD *thd); -bool mysql_insert_select_prepare(THD *thd,select_result *sel_res); +int mysql_insert_select_prepare(THD *thd,select_result *sel_res); bool update_precheck(THD *thd, TABLE_LIST *tables); bool delete_precheck(THD *thd, TABLE_LIST *tables); bool insert_precheck(THD *thd, TABLE_LIST *tables); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index ecb56e70f88..8b801ae7cd9 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1243,9 +1243,8 @@ static bool mysql_test_insert(Prepared_statement *stmt, table_list->table->insert_values=(uchar *)1; } - if (mysql_prepare_insert(thd, table_list, table_list->table, - fields, values, update_fields, update_values, - duplic, &unused_conds, FALSE)) + if (mysql_prepare_insert(thd, table_list, fields, values, update_fields, + update_values, duplic, &unused_conds, FALSE)) goto error; value_count= values->elements; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 31f165ef98a..a1c58b53bb0 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5079,6 +5079,7 @@ int create_table_impl(THD *thd, const LEX_CSTRING &orig_db, int error= 1; bool frm_only= create_table_mode == C_ALTER_TABLE_FRM_ONLY; bool internal_tmp_table= create_table_mode == C_ALTER_TABLE || frm_only; + handlerton *exists_hton; DBUG_ENTER("mysql_create_table_no_lock"); DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d path: %s", db.str, table_name.str, internal_tmp_table, path)); @@ -5167,8 +5168,16 @@ int create_table_impl(THD *thd, const LEX_CSTRING &orig_db, goto err; } - if (!internal_tmp_table && ha_table_exists(thd, &db, &table_name)) + if (!internal_tmp_table && ha_table_exists(thd, &db, &table_name, + &exists_hton)) { + if (ha_check_if_updates_are_ignored(thd, exists_hton, "CREATE")) + { + /* Don't create table. CREATE will still be logged in binary log */ + error= 0; + goto err; + } + if (options.or_replace()) { (void) delete_statistics_for_table(thd, &db, &table_name); @@ -5206,7 +5215,20 @@ int create_table_impl(THD *thd, const LEX_CSTRING &orig_db, goto err; } else if (options.if_not_exists()) + { + /* + We never come here as part of normal create table as table existance + is checked in open_and_lock_tables(). We may come here as part of + ALTER TABLE when converting a table for a distributed engine to a + a local one. + */ + + /* Log CREATE IF NOT EXISTS on slave for distributed engines */ + if (thd->slave_thread && (exists_hton && exists_hton->flags & + HTON_IGNORE_UPDATES)) + thd->log_current_statement= 1; goto warn; + } else { my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name.str); @@ -5437,12 +5459,21 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, thd->lex->create_info.options|= create_info->options; /* Open or obtain an exclusive metadata lock on table being created */ + create_table->db_type= 0; result= open_and_lock_tables(thd, *create_info, create_table, FALSE, 0); thd->lex->create_info.options= save_thd_create_info_options; if (result) { + if (thd->slave_thread && + !thd->is_error() && create_table->db_type && + (create_table->db_type->flags & HTON_IGNORE_UPDATES)) + { + /* Table existed in distributed engine. Log query to binary log */ + result= 0; + goto err; + } /* is_error() may be 0 if table existed and we generated a warning */ DBUG_RETURN(thd->is_error()); } @@ -9777,7 +9808,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, mysql_prepare_create_table(). */ bool varchar= create_info->varchar, table_creation_was_logged= 0; - bool binlog_done= 0, log_if_exists= 0; + bool binlog_as_create_select= 0, log_if_exists= 0; uint tables_opened; handlerton *new_db_type, *old_db_type; ha_rows copied=0, deleted=0; @@ -10699,7 +10730,6 @@ do_continue:; thd->variables.option_bits|= OPTION_BIN_COMMIT_OFF; res= (binlog_drop_table(thd, table) || binlog_create_table(thd, new_table, 1)); - thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF; new_table->s->tmp_table= org_tmp_table; if (res) goto err_new_table_cleanup; @@ -10707,7 +10737,7 @@ do_continue:; ha_write_row() will log inserted rows in copy_data_between_tables(). No additional logging of query is needed */ - binlog_done= 1; + binlog_as_create_select= 1; DBUG_ASSERT(new_table->file->row_logging); new_table->mark_columns_needed_for_insert(); thd->binlog_write_table_map(new_table, 1); @@ -10763,10 +10793,21 @@ do_continue:; if (thd->rename_temporary_table(new_table, &alter_ctx.new_db, &alter_ctx.new_name)) goto err_new_table_cleanup; + + if (binlog_as_create_select) + { + /* + The original table is now deleted. Copy the + DROP + CREATE + data statement to the binary log + */ + thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF; + (binlog_hton->commit)(binlog_hton, thd, 1); + } + /* We don't replicate alter table statement on temporary tables */ if (!thd->is_current_stmt_binlog_format_row() && table_creation_was_logged && - !binlog_done && + !binlog_as_create_select && write_bin_log_with_if_exists(thd, true, false, log_if_exists)) DBUG_RETURN(true); my_free(const_cast(frm.str)); @@ -10926,6 +10967,15 @@ do_continue:; NO_FRM_RENAME | (engine_changed ? 0 : FN_IS_TMP)); } + if (binlog_as_create_select) + { + /* + The original table is now deleted. Copy the + DROP + CREATE + data statement to the binary log + */ + thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF; + binlog_hton->commit(binlog_hton, thd, 1); + } if (error) { @@ -10938,6 +10988,7 @@ do_continue:; } end_inplace: + thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF; if (thd->locked_tables_list.reopen_tables(thd, false)) goto err_with_mdl_after_alter; @@ -10949,7 +11000,7 @@ end_inplace: DBUG_ASSERT(!(mysql_bin_log.is_open() && thd->is_current_stmt_binlog_format_row() && (create_info->tmp_table()))); - if (!binlog_done) + if (!binlog_as_create_select) { if (write_bin_log_with_if_exists(thd, true, false, log_if_exists)) DBUG_RETURN(true); @@ -10967,6 +11018,8 @@ end_inplace: } end_temporary: + thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF; + my_snprintf(alter_ctx.tmp_buff, sizeof(alter_ctx.tmp_buff), ER_THD(thd, ER_INSERT_INFO), (ulong) (copied + deleted), (ulong) deleted, @@ -10977,6 +11030,8 @@ end_temporary: err_new_table_cleanup: DBUG_PRINT("error", ("err_new_table_cleanup")); + thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF; + my_free(const_cast(frm.str)); /* No default value was provided for a DATE/DATETIME field, the @@ -11014,7 +11069,7 @@ err_with_mdl_after_alter: We can't reset error as we will return 'true' below and the server expects that error is set */ - if (!binlog_done) + if (!binlog_as_create_select) write_bin_log_with_if_exists(thd, FALSE, FALSE, log_if_exists); err_with_mdl: diff --git a/storage/maria/ha_s3.cc b/storage/maria/ha_s3.cc index 190d99035a5..d5b4b5bfd31 100644 --- a/storage/maria/ha_s3.cc +++ b/storage/maria/ha_s3.cc @@ -269,7 +269,7 @@ int ha_s3::write_row(const uchar *buf) DBUG_ENTER("ha_s3::write_row"); if (in_alter_table) DBUG_RETURN(ha_maria::write_row(buf)); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); + DBUG_RETURN(HA_ERR_TABLE_READONLY); } /* Return true if S3 can be used */ @@ -576,7 +576,25 @@ int ha_s3::open(const char *name, int mode, uint open_flags) if (!s3_usable()) DBUG_RETURN(HA_ERR_UNSUPPORTED); - if (mode != O_RDONLY && !(open_flags & HA_OPEN_FOR_CREATE)) + /* + On slaves with s3_slave_ignore_updates set we allow tables to be + opened in write mode to be able to ignore queries that modify + the table trough handler::check_if_updates_are_ignored(). + + This is needed for the slave to be able to handle + CREATE TABLE t1... + INSERT INTO TABLE t1 .... + ALTER TABLE t1 ENGINE=S3 + If this is not done, the insert will fail on the slave if the + master has already executed the ALTER TABLE. + + We also have to allow open for create, as part of + ALTER TABLE ... ENGINE=S3. + + Otherwise we only allow the table to be open in read mode + */ + if (mode != O_RDONLY && !(open_flags & HA_OPEN_FOR_CREATE) && + !s3_slave_ignore_updates) DBUG_RETURN(EACCES); open_args= 0; diff --git a/storage/maria/ha_s3.h b/storage/maria/ha_s3.h index 0dd36609a9e..8fc607e6717 100644 --- a/storage/maria/ha_s3.h +++ b/storage/maria/ha_s3.h @@ -37,32 +37,32 @@ public: int update_row(const uchar * old_data, const uchar * new_data) { DBUG_ENTER("update_row"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); + DBUG_RETURN(HA_ERR_TABLE_READONLY); } int delete_row(const uchar * buf) { DBUG_ENTER("delete_row"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); + DBUG_RETURN(HA_ERR_TABLE_READONLY); } int check(THD * thd, HA_CHECK_OPT * check_opt) { DBUG_ENTER("delete_row"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); + DBUG_RETURN(HA_ERR_TABLE_READONLY); } int analyze(THD * thd, HA_CHECK_OPT * check_opt) { DBUG_ENTER("analyze"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); + DBUG_RETURN(HA_ERR_TABLE_READONLY); } int repair(THD * thd, HA_CHECK_OPT * check_opt) { DBUG_ENTER("repair"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); + DBUG_RETURN(HA_ERR_TABLE_READONLY); } int preload_keys(THD * thd, HA_CHECK_OPT * check_opt) { DBUG_ENTER("preload_keys"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); + DBUG_RETURN(HA_ERR_TABLE_READONLY); } int external_lock(THD * thd, int lock_type); /* diff --git a/storage/maria/ma_extra.c b/storage/maria/ma_extra.c index b464cf4f94e..042a96efabf 100644 --- a/storage/maria/ma_extra.c +++ b/storage/maria/ma_extra.c @@ -229,6 +229,9 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function, info->lock_wait= MY_SHORT_WAIT; break; case HA_EXTRA_NO_KEYS: + if (share->s3_path) /* Not supported with S3 */ + break; + /* we're going to modify pieces of the state, stall Checkpoint */ mysql_mutex_lock(&share->intern_lock); if (info->lock_type == F_UNLCK) @@ -369,16 +372,16 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function, if (end_io_cache(&info->rec_cache)) error= 1; } - if (share->kfile.file >= 0) + if (share->kfile.file >= 0 && share->s3_path == 0) { if (do_flush) { /* Save the state so that others can find it from disk. */ - if ((share->changed && - _ma_state_info_write(share, + if (share->changed && + (_ma_state_info_write(share, MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET | - MA_STATE_INFO_WRITE_FULL_INFO)) || - mysql_file_sync(share->kfile.file, MYF(0))) + MA_STATE_INFO_WRITE_FULL_INFO) || + mysql_file_sync(share->kfile.file, MYF(0)))) error= my_errno; } else @@ -390,7 +393,7 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function, } } if (share->data_file_type == BLOCK_RECORD && - share->bitmap.file.file >= 0) + share->bitmap.file.file >= 0 && share->s3_path == 0) { DBUG_ASSERT(share->bitmap.non_flushable == 0 && share->bitmap.changed == 0); diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c index e7d6f97d57c..f32fd6dd19d 100644 --- a/storage/maria/ma_open.c +++ b/storage/maria/ma_open.c @@ -369,6 +369,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags, #ifdef WITH_S3_STORAGE_ENGINE else { + open_mode= mode; errpos= 1; if (s3f.set_database_and_table_from_path(s3, name_buff)) { @@ -1050,6 +1051,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags, share->state_history->next= 0; } } + errpos= 7; thr_lock_init(&share->lock); mysql_mutex_init(key_SHARE_intern_lock, &share->intern_lock, MY_MUTEX_INIT_FAST); @@ -1193,6 +1195,9 @@ err: _ma_report_error(save_errno, &tmp_name); } switch (errpos) { + case 7: + thr_lock_delete(&share->lock); + /* fall through */ case 6: /* Avoid mutex test in _ma_bitmap_end() */ share->internal_table= 1; From 2c8c15483d15d7a8e5b266ffcfbe7cf3503949f9 Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 16 Oct 2020 19:36:24 +0300 Subject: [PATCH 165/323] MDEV-23730 s3.replication_partition 'innodb,mix' segv This failure was caused because of several bugs: - Someone had removed s3-slave-ignore-updates=1 from slave.cnf, which caused the slave to remove files that the master was working on. - Bug in ha_partition::change_partitions() that didn't reset m_new_file in case of errors. This caused crashes in ha_maria::extra() as the maria handler was called on files that was already closed. - In ma_pagecache there was a bug that when one got a read error one a big block (s3 block), it left the flag PCBLOCK_BIG_READ on for the page which cased an assert when the page where flushed. - Flush all cached tables in case of ignored ALTER TABLE Note that when merging code from 10.3, that fixes the partition bug, use the code from this patch instead. Changes to ma_pagecache.cc written or reviewed by Sanja --- mysql-test/suite/parts/r/reorganize.result | 13 +++++++ mysql-test/suite/parts/t/reorganize.test | 20 +++++++++++ mysql-test/suite/s3/disabled.def | 3 -- .../suite/s3/replication_partition.result | 18 ++++++---- .../suite/s3/replication_partition.test | 22 +++++------- mysql-test/suite/s3/slave.cnf | 5 +++ sql/ha_partition.cc | 4 +++ sql/sql_table.cc | 35 +++++++++++++------ storage/maria/ma_pagecache.c | 11 +++--- 9 files changed, 94 insertions(+), 37 deletions(-) create mode 100644 mysql-test/suite/parts/r/reorganize.result create mode 100644 mysql-test/suite/parts/t/reorganize.test diff --git a/mysql-test/suite/parts/r/reorganize.result b/mysql-test/suite/parts/r/reorganize.result new file mode 100644 index 00000000000..5e6fe176edc --- /dev/null +++ b/mysql-test/suite/parts/r/reorganize.result @@ -0,0 +1,13 @@ +# +# MDEV-23248 Server crashes in mi_extra / +# ha_partition::loop_extra_alter upon REORGANIZE +# +CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM PARTITION BY RANGE (a) SUBPARTITION BY HASH (a) SUBPARTITIONS 70 (PARTITION p1 VALUES LESS THAN (100), PARTITION p2 VALUES LESS THAN MAXVALUE); +INSERT INTO t1 SELECT 4, 6 FROM seq_1_to_131072; +UPDATE t1 SET a = 7; +set @org_debug=@@debug_dbug; +set @@debug_dbug="+d,debug_abort_copy_partitions"; +ALTER TABLE t1 REORGANIZE PARTITION p1,p2 INTO (PARTITION p1 VALUES LESS THAN (5), PARTITION p2 VALUES LESS THAN MAXVALUE); +ERROR 42000: Table 't1' uses an extension that doesn't exist in this MariaDB version +set @@debug_dbug=@org_debug; +DROP TABLE t1; diff --git a/mysql-test/suite/parts/t/reorganize.test b/mysql-test/suite/parts/t/reorganize.test new file mode 100644 index 00000000000..66641254468 --- /dev/null +++ b/mysql-test/suite/parts/t/reorganize.test @@ -0,0 +1,20 @@ +--source include/have_sequence.inc +--source include/have_partition.inc +--source include/have_debug.inc + +--echo # +--echo # MDEV-23248 Server crashes in mi_extra / +--echo # ha_partition::loop_extra_alter upon REORGANIZE +--echo # + +CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM PARTITION BY RANGE (a) SUBPARTITION BY HASH (a) SUBPARTITIONS 70 (PARTITION p1 VALUES LESS THAN (100), PARTITION p2 VALUES LESS THAN MAXVALUE); +INSERT INTO t1 SELECT 4, 6 FROM seq_1_to_131072; +UPDATE t1 SET a = 7; + +set @org_debug=@@debug_dbug; +set @@debug_dbug="+d,debug_abort_copy_partitions"; +--error ER_UNSUPPORTED_EXTENSION +ALTER TABLE t1 REORGANIZE PARTITION p1,p2 INTO (PARTITION p1 VALUES LESS THAN (5), PARTITION p2 VALUES LESS THAN MAXVALUE); +set @@debug_dbug=@org_debug; + +DROP TABLE t1; diff --git a/mysql-test/suite/s3/disabled.def b/mysql-test/suite/s3/disabled.def index 8eae300e21e..e69de29bb2d 100644 --- a/mysql-test/suite/s3/disabled.def +++ b/mysql-test/suite/s3/disabled.def @@ -1,3 +0,0 @@ -replication_partition : MDEV-23730: Server crashes in ha_maria::extra -replication_mixed : MDEV-23770: Replication failure -replication_stmt : MDEV-23770: Replication failure diff --git a/mysql-test/suite/s3/replication_partition.result b/mysql-test/suite/s3/replication_partition.result index 40fb2aec698..2b9297ea9a0 100644 --- a/mysql-test/suite/s3/replication_partition.result +++ b/mysql-test/suite/s3/replication_partition.result @@ -89,10 +89,18 @@ select sum(c1)+0 from t1; sum(c1)+0 600 stop slave; -flush tables; -select sum(c1)+0 from t1; -sum(c1)+0 -600 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL, + `c2` int(11) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=S3 DEFAULT CHARSET=latin1 + PARTITION BY RANGE (`c1`) +(PARTITION `p1` VALUES LESS THAN (200) ENGINE = S3, + PARTITION `p2` VALUES LESS THAN (300) ENGINE = S3, + PARTITION `p3` VALUES LESS THAN (400) ENGINE = S3, + PARTITION `p4` VALUES LESS THAN (500) ENGINE = S3) connection master; drop table t1; connection slave; @@ -204,8 +212,6 @@ slave-bin.000001 # Query # # use `database`; alter table t1 engine=S3 slave-bin.000001 # Gtid # # GTID #-#-# slave-bin.000001 # Query # # use `database`; set @@sql_if_exists=1; ALTER TABLE t1 ADD PARTITION (PARTITION p4 VALUES LESS THAN (500)) slave-bin.000001 # Gtid # # GTID #-#-# -slave-bin.000001 # Query # # use `database`; flush tables -slave-bin.000001 # Gtid # # GTID #-#-# slave-bin.000001 # Query # # use `database`; DROP TABLE IF EXISTS `t1` /* generated by server */ slave-bin.000001 # Gtid # # GTID #-#-# slave-bin.000001 # Query # # use `database`; CREATE TABLE t2 ( diff --git a/mysql-test/suite/s3/replication_partition.test b/mysql-test/suite/s3/replication_partition.test index 0430d14d7a7..8a8699920bf 100644 --- a/mysql-test/suite/s3/replication_partition.test +++ b/mysql-test/suite/s3/replication_partition.test @@ -7,6 +7,12 @@ --source create_database.inc sync_slave_with_master; + +if (`select @@s3_slave_ignore_updates <> 1`) +{ + die "Slave is not configured with s3-slave-ignore-updates=1"; +} + let $MYSQLD_DATADIR= `select @@datadir`; --replace_result $database database --eval use $database @@ -65,20 +71,8 @@ sync_slave_with_master; select sum(c1)+0 from t1; stop slave; -# .frm amd .par files should not exists on the salve as it has just seen the -# ALTER TABLE which cased the removal of the .frm and .par files. The table -# from the above "select sum()" came from table cache and was used as it's -# id matches the one in S3 ---error 1 ---file_exists $MYSQLD_DATADIR/$database/t1.frm ---error 1 ---file_exists $MYSQLD_DATADIR/$database/t1.par -# Flushing the table cache will force the .frm and .par files to be -# re-generated -flush tables; -select sum(c1)+0 from t1; ---file_exists $MYSQLD_DATADIR/$database/t1.frm ---file_exists $MYSQLD_DATADIR/$database/t1.par +# Ensure the slave is using the new table +show create table t1; connection master; drop table t1; diff --git a/mysql-test/suite/s3/slave.cnf b/mysql-test/suite/s3/slave.cnf index b9b1da73a92..ade80c9ef8e 100644 --- a/mysql-test/suite/s3/slave.cnf +++ b/mysql-test/suite/s3/slave.cnf @@ -2,6 +2,11 @@ plugin-maturity = alpha plugin-load-add=@ENV.HA_S3_SO s3=ON +s3-slave-ignore-updates=1 + +# You can change the following when running the tests against +# your own S3 setup + #s3-host-name=s3.amazonaws.com #s3-protocol-version=Amazon #s3-bucket=MariaDB diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 921b461f15e..a3c0029adbb 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2069,6 +2069,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, DBUG_ASSERT(part_elem->part_state == PART_TO_BE_REORGED); part_elem->part_state= PART_TO_BE_DROPPED; } + DBUG_ASSERT(m_new_file == 0); m_new_file= new_file_array; if (unlikely((error= copy_partitions(copied, deleted)))) { @@ -2077,6 +2078,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, They will later be deleted through the ddl-log. */ cleanup_new_partition(part_count); + m_new_file= 0; } DBUG_RETURN(error); } @@ -2166,6 +2168,8 @@ int ha_partition::copy_partitions(ulonglong * const copied, file->ha_rnd_end(); reorg_part++; } + DBUG_EXECUTE_IF("debug_abort_copy_partitions", + DBUG_RETURN(HA_ERR_UNSUPPORTED); ); DBUG_RETURN(FALSE); error: m_reorged_file[reorg_part]->ha_rnd_end(); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a1c58b53bb0..8db2ec3d761 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9739,6 +9739,22 @@ static int create_table_for_inplace_alter(THD *thd, } +/* + log query if slave thread and send my_ok() + + Help function for mysql_alter_table() +*/ + +static bool log_and_ok(THD *thd) +{ + if (thd->slave_thread && + write_bin_log(thd, true, thd->query(), thd->query_length())) + return(true); + my_ok(thd); + return(0); +} + + /** Alter table @@ -9873,10 +9889,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, table_list->mdl_request.type= MDL_EXCLUSIVE; /* This will only drop the .frm file and local tables, not shared ones */ error= mysql_rm_table(thd, table_list, 1, 0, 0, 1); - if (write_bin_log(thd, true, thd->query(), thd->query_length()) || error) - DBUG_RETURN(true); - my_ok(thd); - DBUG_RETURN(0); + DBUG_RETURN(log_and_ok(thd)); } /* @@ -9908,16 +9921,14 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, the statement as this slave may not have the table shared */ thd->clear_error(); - if (thd->slave_thread && - write_bin_log(thd, true, thd->query(), thd->query_length())) - DBUG_RETURN(true); - my_ok(thd); - DBUG_RETURN(0); + DBUG_RETURN(log_and_ok(thd)); } } DBUG_RETURN(true); } + table= table_list->table; + #ifdef WITH_WSREP if (WSREP(thd) && (thd->lex->sql_command == SQLCOM_ALTER_TABLE || @@ -9929,7 +9940,6 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, DEBUG_SYNC(thd, "alter_table_after_open_tables"); - table= table_list->table; if (table->versioned()) { if (handlerton *hton1= create_info->db_type) @@ -9968,12 +9978,17 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, Alter_table_ctx alter_ctx(thd, table_list, tables_opened, new_db, new_name); mdl_ticket= table->mdl_ticket; + /* + We have to do a check also after table is opened as there could be no + ENGINE= on the command line or the table could a partitioned S3 table. + */ if (table->file->check_if_updates_are_ignored("ALTER")) { /* Table is a shared table. Remove the .frm file. Discovery will create a new one if needed. */ + table->s->tdc->flushed= 1; // Force close of all instances if (thd->mdl_context.upgrade_shared_lock(mdl_ticket, MDL_EXCLUSIVE, thd->variables.lock_wait_timeout)) diff --git a/storage/maria/ma_pagecache.c b/storage/maria/ma_pagecache.c index 0a55018db0f..bf646115bd9 100644 --- a/storage/maria/ma_pagecache.c +++ b/storage/maria/ma_pagecache.c @@ -2810,7 +2810,7 @@ static void read_big_block(PAGECACHE *pagecache, if (block_to_read->status & PCBLOCK_ERROR) { /* We get first block with an error so all operation failed */ - goto error; + DBUG_VOID_RETURN; } if (block_to_read->status & PCBLOCK_BIG_READ) { @@ -2842,7 +2842,11 @@ static void read_big_block(PAGECACHE *pagecache, // page should be read by other thread DBUG_ASSERT(block->status & PCBLOCK_READ || block->status & PCBLOCK_ERROR); - DBUG_ASSERT(block->status & PCBLOCK_BIG_READ); + /* + It is possible that other thread already removed the flag (in + case of two threads waiting) but it will not make harm to try to + remove it even in that case. + */ block->status&= ~PCBLOCK_BIG_READ; // all is read => lets finish nice DBUG_ASSERT(block_to_read != block); @@ -2960,9 +2964,8 @@ static void read_big_block(PAGECACHE *pagecache, } pagecache->big_block_free(&data); - block_to_read->status&= ~PCBLOCK_BIG_READ; - end: + block_to_read->status&= ~PCBLOCK_BIG_READ; if (block_to_read != block) { remove_reader(block_to_read); From dd757ee02f24f2999ddc8722587cca98b144c72c Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 10 Sep 2020 16:55:24 +0300 Subject: [PATCH 166/323] Update S3 engine to maturity Gamma --- mysql-test/suite/s3/my.cnf | 2 +- mysql-test/suite/s3/slave.cnf | 2 +- storage/maria/ha_s3.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/s3/my.cnf b/mysql-test/suite/s3/my.cnf index a979bf31817..e5f7d4e59f1 100644 --- a/mysql-test/suite/s3/my.cnf +++ b/mysql-test/suite/s3/my.cnf @@ -2,7 +2,7 @@ !include include/default_client.cnf [mysqld.1] -plugin-maturity = alpha +plugin-maturity = gamma plugin-load-add=@ENV.HA_S3_SO s3=ON #s3-host-name=s3.amazonaws.com diff --git a/mysql-test/suite/s3/slave.cnf b/mysql-test/suite/s3/slave.cnf index ade80c9ef8e..8e1349db2cc 100644 --- a/mysql-test/suite/s3/slave.cnf +++ b/mysql-test/suite/s3/slave.cnf @@ -1,5 +1,5 @@ [mysqld.2] -plugin-maturity = alpha +plugin-maturity = gamma plugin-load-add=@ENV.HA_S3_SO s3=ON s3-slave-ignore-updates=1 diff --git a/storage/maria/ha_s3.cc b/storage/maria/ha_s3.cc index d5b4b5bfd31..e9396329c50 100644 --- a/storage/maria/ha_s3.cc +++ b/storage/maria/ha_s3.cc @@ -1110,6 +1110,6 @@ maria_declare_plugin(s3) status_variables, /* status variables */ system_variables, /* system variables */ "1.0", /* string version */ - MariaDB_PLUGIN_MATURITY_ALPHA /* maturity */ + MariaDB_PLUGIN_MATURITY_GAMMA /* maturity */ } maria_declare_plugin_end; From 3c4b8440eb9c25daa7f2d5bd3ee3be80f1117fe3 Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 13 Sep 2020 15:51:26 +0300 Subject: [PATCH 167/323] Trivial fixups, no code changes - Indentation changes - Fixed wrong name for used in DBUG_ENTER - Added some code comments --- sql/log_event.h | 6 ++++-- sql/sql_class.cc | 10 +++++----- sql/sql_insert.cc | 17 ++++++++++------- sql/sql_table.cc | 16 ++++++++++++---- sql/sql_trigger.cc | 2 +- 5 files changed, 32 insertions(+), 19 deletions(-) diff --git a/sql/log_event.h b/sql/log_event.h index 222e611ecae..4e193232f4b 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -2227,8 +2227,10 @@ public: virtual bool is_commit() { return false; } virtual bool is_rollback() { return false; } #ifdef MYSQL_SERVER - Query_compressed_log_event(THD* thd_arg, const char* query_arg, ulong query_length, - bool using_trans, bool direct, bool suppress_use, int error); + Query_compressed_log_event(THD* thd_arg, const char* query_arg, + ulong query_length, + bool using_trans, bool direct, bool suppress_use, + int error); virtual bool write(); #endif }; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index e522fd1b1af..b94630274d5 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -6562,8 +6562,8 @@ exit:; /** Check if we should log a table DDL to the binlog - @@return true yes - @@return false no + @retval true yes + @retval false no */ bool THD::binlog_table_should_be_logged(const LEX_CSTRING *db) @@ -7452,14 +7452,14 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, */ if (binlog_should_compress(query_len)) { - Query_compressed_log_event qinfo(this, query_arg, query_len, is_trans, direct, - suppress_use, errcode); + Query_compressed_log_event qinfo(this, query_arg, query_len, is_trans, + direct, suppress_use, errcode); error= mysql_bin_log.write(&qinfo); } else { Query_log_event qinfo(this, query_arg, query_len, is_trans, direct, - suppress_use, errcode); + suppress_use, errcode); error= mysql_bin_log.write(&qinfo); } /* diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 5e0346c3977..7833059438e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1211,7 +1211,7 @@ values_loop_end: such case the flag is ignored for constructing binlog event. */ DBUG_ASSERT(thd->killed != KILL_BAD_DATA || error > 0); - if (was_insert_delayed && table_list->lock_type == TL_WRITE) + if (was_insert_delayed && table_list->lock_type == TL_WRITE) { /* Binlog INSERT DELAYED as INSERT without DELAYED. */ String log_query; @@ -3823,15 +3823,18 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) */ lex->current_select= lex->first_select_lex(); - res= setup_returning_fields(thd, table_list) || - setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0, 0) || - check_insert_fields(thd, table_list, *fields, values, - !insert_into_view, 1, &map); + res= (setup_returning_fields(thd, table_list) || + setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0, + 0) || + check_insert_fields(thd, table_list, *fields, values, + !insert_into_view, 1, &map)); if (!res && fields->elements) { - Abort_on_warning_instant_set aws(thd, !info.ignore && thd->is_strict_mode()); - res= check_that_all_fields_are_given_values(thd, table_list->table, table_list); + Abort_on_warning_instant_set aws(thd, + !info.ignore && thd->is_strict_mode()); + res= check_that_all_fields_are_given_values(thd, table_list->table, + table_list); } if (info.handle_duplicates == DUP_UPDATE && !res) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8db2ec3d761..16f4330637d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2828,6 +2828,12 @@ bool log_drop_table(THD *thd, const LEX_CSTRING *db_name, append_identifier(thd, &query, table_name); query.append(STRING_WITH_LEN("/* Generated to handle " "failed CREATE OR REPLACE */")); + + /* + In case of temporary tables we don't have to log the database name + in the binary log. We log this for non temporary tables, as the slave + may use a filter to ignore queries for a specific database. + */ error= thd->binlog_query(THD::STMT_QUERY_TYPE, query.ptr(), query.length(), FALSE, FALSE, temporary_table, 0) > 0; @@ -5205,7 +5211,8 @@ int create_table_impl(THD *thd, const LEX_CSTRING &orig_db, thd->variables.option_bits|= OPTION_KEEP_LOG; thd->log_current_statement= 1; create_info->table_was_deleted= 1; - DBUG_EXECUTE_IF("send_kill_after_delete", thd->set_killed(KILL_QUERY); ); + DBUG_EXECUTE_IF("send_kill_after_delete", + thd->set_killed(KILL_QUERY); ); /* Restart statement transactions for the case of CREATE ... SELECT. @@ -5745,7 +5752,8 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db, DBUG_ENTER("mysql_rename_table"); DBUG_ASSERT(base); DBUG_PRINT("enter", ("old: '%s'.'%s' new: '%s'.'%s'", - old_db->str, old_name->str, new_db->str, new_name->str)); + old_db->str, old_name->str, new_db->str, + new_name->str)); // Temporarily disable foreign key checks if (flags & NO_FK_CHECKS) @@ -5755,8 +5763,8 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db, build_table_filename(from, sizeof(from) - 1, old_db->str, old_name->str, "", flags & FN_FROM_IS_TMP); - length= build_table_filename(to, sizeof(to) - 1, new_db->str, new_name->str, "", - flags & FN_TO_IS_TMP); + length= build_table_filename(to, sizeof(to) - 1, new_db->str, + new_name->str, "", flags & FN_TO_IS_TMP); // Check if we hit FN_REFLEN bytes along with file extension. if (length+reg_ext_length > FN_REFLEN) { diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 677e6cfa510..9417ec667ff 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1826,7 +1826,7 @@ bool Table_triggers_list::drop_all_triggers(THD *thd, const LEX_CSTRING *db, TABLE table; char path[FN_REFLEN]; bool result= 0; - DBUG_ENTER("Triggers::drop_all_triggers"); + DBUG_ENTER("Table_triggers_list::drop_all_triggers"); table.reset(); init_sql_alloc(key_memory_Table_trigger_dispatcher, From 2912f1f8660d05ef5a70806af0fb7f060c4ec481 Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 16 Oct 2020 15:45:30 +0300 Subject: [PATCH 168/323] Fixed typo in mtr_cases.pm --- mysql-test/lib/mtr_cases.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 97fbdcae838..b61333535dc 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -745,7 +745,7 @@ sub collect_one_test_case { if ( $enable_disabled ) { # User has selected to run all disabled tests - mtr_report(" - $tinfo->{name} wil be run although it's been disabled\n", + mtr_report(" - $tinfo->{name} will be run although it's been disabled\n", " due to '$disable'"); } else From 21c15cc20b3f17d10863ade48488e6fa7fff801a Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 16 Oct 2020 15:45:50 +0300 Subject: [PATCH 169/323] Fixed compiler warning in connect/filemazip.cpp --- storage/connect/filamzip.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamzip.cpp index eb14e846120..6cd4bae6999 100644 --- a/storage/connect/filamzip.cpp +++ b/storage/connect/filamzip.cpp @@ -1207,7 +1207,6 @@ int UZDFAM::Cardinality(PGLOBAL g) return 1; int card = -1; - int len = GetFileLength(g); card = Records; From 8c074df6ace3edf9f74dbbb602b3353978ecc0fb Mon Sep 17 00:00:00 2001 From: Monty Date: Mon, 19 Oct 2020 22:04:45 +0300 Subject: [PATCH 170/323] MDEV-23648 s3.partition_move 'innodb' test failure - object deleted before copy attempted Updated submodule libmarias3 which fixes the problem Enabled disable S3 tests. --- mysql-test/suite/s3/partition.test | 5 ----- mysql-test/suite/s3/partition_move.test | 5 ----- storage/maria/CMakeLists.txt | 3 ++- storage/maria/libmarias3 | 2 +- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/mysql-test/suite/s3/partition.test b/mysql-test/suite/s3/partition.test index b60eb1bf2dd..03bbc2f0da9 100644 --- a/mysql-test/suite/s3/partition.test +++ b/mysql-test/suite/s3/partition.test @@ -1,8 +1,3 @@ -if (`SELECT @@s3_host_name <> "s3.amazonaws.com"`) -{ - skip The test is disabled for emulator environment due to MDEV-23648; -} - --source include/have_partition.inc --source include/have_s3.inc --source create_database.inc diff --git a/mysql-test/suite/s3/partition_move.test b/mysql-test/suite/s3/partition_move.test index 1a5c45ca0b1..35edbd75b5a 100644 --- a/mysql-test/suite/s3/partition_move.test +++ b/mysql-test/suite/s3/partition_move.test @@ -1,8 +1,3 @@ -if (`SELECT @@s3_host_name <> "s3.amazonaws.com"`) -{ - skip The test is disabled for emulator environment due to MDEV-23648; -} - --source include/have_partition.inc --source include/have_innodb.inc --source include/have_s3.inc diff --git a/storage/maria/CMakeLists.txt b/storage/maria/CMakeLists.txt index c21694a070c..f15ba313694 100644 --- a/storage/maria/CMakeLists.txt +++ b/storage/maria/CMakeLists.txt @@ -109,7 +109,8 @@ INCLUDE (CheckIncludeFiles) SET(S3_SOURCES s3_func.c libmarias3/src/debug.c libmarias3/src/error.c libmarias3/src/marias3.c libmarias3/src/request.c libmarias3/src/response.c libmarias3/src/sha256.c - libmarias3/src/sha256-internal.c libmarias3/src/xml.c) + libmarias3/src/sha256-internal.c libmarias3/src/xml.c + libmarias3/src/assume_role.c) IF(NOT PLUGIN_S3 STREQUAL NO) FIND_PACKAGE(CURL) diff --git a/storage/maria/libmarias3 b/storage/maria/libmarias3 index 7aa450e3a02..0d48bf334fd 160000 --- a/storage/maria/libmarias3 +++ b/storage/maria/libmarias3 @@ -1 +1 @@ -Subproject commit 7aa450e3a02a20ef62616666a2b582f4d07fb5b3 +Subproject commit 0d48bf334fde7d4e0dac22bda560e86037d35d77 From c7552969d0d33e2d8a678ea30de9453253ca2ec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 21 Oct 2020 10:04:44 +0300 Subject: [PATCH 171/323] MDEV-23999 Potential stack overflow in InnoDB fulltext search fts_query_t::nested_sub_exp: Keep track of nested fts_ast_visit_sub_exp() calls. fts_ast_visit_sub_exp(): Return DB_OUT_OF_MEMORY if the maximum recursion depth is exceeded. This is motivated by a change in MySQL 5.6.50: mysql/mysql-server@e2a46b4834a0030e5380d45789772cb6beab6e92 Bug #29929684 USING MANY NESTED ARGUMENTS WITH BOOLEAN FTS CAN LEAD TO TERMINATE SERVER --- mysql-test/suite/innodb_fts/r/basic.result | 21 +++++++++++++++++++++ mysql-test/suite/innodb_fts/t/basic.test | 20 ++++++++++++++++++++ storage/innobase/fts/fts0que.cc | 19 ++++++++++++++++--- storage/innobase/include/fts0ast.h | 15 +-------------- storage/xtradb/fts/fts0que.cc | 19 ++++++++++++++++--- storage/xtradb/include/fts0ast.h | 15 +-------------- 6 files changed, 75 insertions(+), 34 deletions(-) diff --git a/mysql-test/suite/innodb_fts/r/basic.result b/mysql-test/suite/innodb_fts/r/basic.result index ae23b93dc84..749787b8e1c 100644 --- a/mysql-test/suite/innodb_fts/r/basic.result +++ b/mysql-test/suite/innodb_fts/r/basic.result @@ -125,6 +125,27 @@ id title body 3 Optimizing MySQL In this tutorial we will show ... 4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... 5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((((Security)))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +ERROR HY000: Table handler out of memory +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('((((((((((((((((((((((((((((((((Security))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((vs))))))))))))))))))))))))))))))),(((to)))' + IN BOOLEAN MODE); +id title body +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('((((((((((((((((((((((((((((((((Security)))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +ERROR 42000: syntax error, unexpected $end +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((((Security))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +ERROR 42000: syntax error, unexpected $end SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('+ MySQL + (>Well < stands)' IN BOOLEAN MODE); id title body diff --git a/mysql-test/suite/innodb_fts/t/basic.test b/mysql-test/suite/innodb_fts/t/basic.test index 58f36be08a5..3c6d64a6fce 100644 --- a/mysql-test/suite/innodb_fts/t/basic.test +++ b/mysql-test/suite/innodb_fts/t/basic.test @@ -99,6 +99,26 @@ SELECT * FROM articles WHERE MATCH (title,body) SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('+ MySQL - (Well stands)' IN BOOLEAN MODE); +--error 128 +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((((Security)))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('((((((((((((((((((((((((((((((((Security))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((vs))))))))))))))))))))))))))))))),(((to)))' + IN BOOLEAN MODE); + +--error ER_PARSE_ERROR +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('((((((((((((((((((((((((((((((((Security)))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +--error ER_PARSE_ERROR +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((((Security))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); + # Test sub-expression boolean search. Find rows contain # "MySQL" and "Well" or "MySQL" and "stands". But rank the # doc with "Well" higher, and doc with "stands" lower. diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc index ce6151e63b8..f1a5b4ccbe4 100644 --- a/storage/innobase/fts/fts0que.cc +++ b/storage/innobase/fts/fts0que.cc @@ -1,7 +1,7 @@ /***************************************************************************** -Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2007, 2020, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2017, 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 @@ -146,6 +146,8 @@ struct fts_query_t { fts_word_freq_t */ bool multi_exist; /*!< multiple FTS_EXIST oper */ + byte visiting_sub_exp; /*!< count of nested + fts_ast_visit_sub_exp() */ }; /** For phrase matching, first we collect the documents and the positions @@ -2836,6 +2838,8 @@ fts_query_get_token( return(new_ptr); } +static dberr_t fts_ast_visit_sub_exp(fts_ast_node_t*, fts_ast_callback, void*); + /*****************************************************************//** Visit every node of the AST. */ static @@ -2925,7 +2929,7 @@ Process (nested) sub-expression, create a new result set to store the sub-expression result by processing nodes under current sub-expression list. Merge the sub-expression result with that of parent expression list. @return DB_SUCCESS if all well */ -UNIV_INTERN +static dberr_t fts_ast_visit_sub_exp( /*==================*/ @@ -2945,6 +2949,14 @@ fts_ast_visit_sub_exp( ut_a(node->type == FTS_AST_SUBEXP_LIST); + /* To avoid stack overflow, we limit the mutual recursion + depth between fts_ast_visit(), fts_query_visitor() and + fts_ast_visit_sub_exp(). */ + if (query->visiting_sub_exp++ > 31) { + query->error = DB_OUT_OF_MEMORY; + DBUG_RETURN(query->error); + } + cur_oper = query->oper; /* Save current result set */ @@ -2967,6 +2979,7 @@ fts_ast_visit_sub_exp( /* Reinstate parent node state */ query->multi_exist = multi_exist; query->oper = cur_oper; + query->visiting_sub_exp--; /* Merge the sub-expression result with the parent result set. */ subexpr_doc_ids = query->doc_ids; diff --git a/storage/innobase/include/fts0ast.h b/storage/innobase/include/fts0ast.h index b7d467e0082..b7870cbc7bc 100644 --- a/storage/innobase/include/fts0ast.h +++ b/storage/innobase/include/fts0ast.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2018, MariaDB Corporation. +Copyright (c) 2016, 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 @@ -204,19 +204,6 @@ fts_ast_visit( operator, currently we only ignore FTS_IGNORE operator */ MY_ATTRIBUTE((nonnull, warn_unused_result)); -/*****************************************************************//** -Process (nested) sub-expression, create a new result set to store the -sub-expression result by processing nodes under current sub-expression -list. Merge the sub-expression result with that of parent expression list. -@return DB_SUCCESS if all went well */ -UNIV_INTERN -dberr_t -fts_ast_visit_sub_exp( -/*==================*/ - fts_ast_node_t* node, /*!< in: instance to traverse*/ - fts_ast_callback visitor, /*!< in: callback */ - void* arg) /*!< in: callback arg */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); /******************************************************************** Create a lex instance.*/ UNIV_INTERN diff --git a/storage/xtradb/fts/fts0que.cc b/storage/xtradb/fts/fts0que.cc index 8fce8efac2b..0c51e702907 100644 --- a/storage/xtradb/fts/fts0que.cc +++ b/storage/xtradb/fts/fts0que.cc @@ -1,7 +1,7 @@ /***************************************************************************** -Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2007, 2020, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2017, 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 @@ -146,6 +146,8 @@ struct fts_query_t { fts_word_freq_t */ bool multi_exist; /*!< multiple FTS_EXIST oper */ + byte visiting_sub_exp; /*!< count of nested + fts_ast_visit_sub_exp() */ }; /** For phrase matching, first we collect the documents and the positions @@ -2856,6 +2858,8 @@ fts_query_get_token( return(new_ptr); } +static dberr_t fts_ast_visit_sub_exp(fts_ast_node_t*, fts_ast_callback, void*); + /*****************************************************************//** Visit every node of the AST. */ static @@ -2945,7 +2949,7 @@ Process (nested) sub-expression, create a new result set to store the sub-expression result by processing nodes under current sub-expression list. Merge the sub-expression result with that of parent expression list. @return DB_SUCCESS if all well */ -UNIV_INTERN +static dberr_t fts_ast_visit_sub_exp( /*==================*/ @@ -2965,6 +2969,14 @@ fts_ast_visit_sub_exp( ut_a(node->type == FTS_AST_SUBEXP_LIST); + /* To avoid stack overflow, we limit the mutual recursion + depth between fts_ast_visit(), fts_query_visitor() and + fts_ast_visit_sub_exp(). */ + if (query->visiting_sub_exp++ > 31) { + query->error = DB_OUT_OF_MEMORY; + DBUG_RETURN(query->error); + } + cur_oper = query->oper; /* Save current result set */ @@ -2987,6 +2999,7 @@ fts_ast_visit_sub_exp( /* Reinstate parent node state */ query->multi_exist = multi_exist; query->oper = cur_oper; + query->visiting_sub_exp--; /* Merge the sub-expression result with the parent result set. */ subexpr_doc_ids = query->doc_ids; diff --git a/storage/xtradb/include/fts0ast.h b/storage/xtradb/include/fts0ast.h index b7d467e0082..b7870cbc7bc 100644 --- a/storage/xtradb/include/fts0ast.h +++ b/storage/xtradb/include/fts0ast.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2018, MariaDB Corporation. +Copyright (c) 2016, 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 @@ -204,19 +204,6 @@ fts_ast_visit( operator, currently we only ignore FTS_IGNORE operator */ MY_ATTRIBUTE((nonnull, warn_unused_result)); -/*****************************************************************//** -Process (nested) sub-expression, create a new result set to store the -sub-expression result by processing nodes under current sub-expression -list. Merge the sub-expression result with that of parent expression list. -@return DB_SUCCESS if all went well */ -UNIV_INTERN -dberr_t -fts_ast_visit_sub_exp( -/*==================*/ - fts_ast_node_t* node, /*!< in: instance to traverse*/ - fts_ast_callback visitor, /*!< in: callback */ - void* arg) /*!< in: callback arg */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); /******************************************************************** Create a lex instance.*/ UNIV_INTERN From 05cd5acba6f248f21940795066c736c32ec0c607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 21 Oct 2020 10:53:55 +0300 Subject: [PATCH 172/323] MDEV-23986: fil_page_type_validate() fails on crash recovery In MDEV-12353, we changed the redo log format so that whenever any data field is changed, the unchanged prefix of the bytes will by default be omitted from the redo log record. However, in order for the MDEV-23199 logic to work, changes of FSP_SPACE_FLAGS must always be written in full (mtr_t::FORCED), so that crash recovery can parse them. We must know the flags in advance, because we might be applying log to other pages than page 0 first. recv_scan_log_recs(): Correct a misleading message about starting crash recovery. Display both the checkpoint LSN and the start of the records that end in the FILE_CHECKPOINT marker. Reviewed by: Thirunarayanan Balathandayuthapani --- storage/innobase/fil/fil0fil.cc | 5 +++-- storage/innobase/fsp/fsp0fsp.cc | 9 +++++---- storage/innobase/handler/handler0alter.cc | 16 +++++++++------- storage/innobase/log/log0recv.cc | 4 ++-- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 7662a4b643c..56476edbfa0 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -3567,8 +3567,9 @@ void fsp_flags_try_adjust(fil_space_t* space, ulint flags) << " to " << ib::hex(flags); } mtr.set_named_space(space); - mtr.write<4>(*b, FSP_HEADER_OFFSET + FSP_SPACE_FLAGS - + b->frame, flags); + mtr.write<4,mtr_t::FORCED>(*b, + FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + + b->frame, flags); } func_exit: mtr.commit(); diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index beebb85c86b..7af8ee56893 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -582,10 +582,11 @@ void fsp_header_init(fil_space_t* space, uint32_t size, mtr_t* mtr) + block->frame, size); ut_ad(0 == mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT + block->frame)); - mtr->write<4,mtr_t::MAYBE_NOP>(*block, - FSP_HEADER_OFFSET + FSP_SPACE_FLAGS - + block->frame, - space->flags & ~FSP_FLAGS_MEM_MASK); + if (auto f = space->flags & ~FSP_FLAGS_MEM_MASK) { + mtr->write<4,mtr_t::FORCED>(*block, + FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + + block->frame, f); + } ut_ad(0 == mach_read_from_4(FSP_HEADER_OFFSET + FSP_FRAG_N_USED + block->frame)); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index d1adb2b6645..d5486567e44 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -10316,13 +10316,15 @@ commit_cache_norebuild( page_id_t(space->id, 0), space->zip_size(), RW_X_LATCH, &mtr)) { - mtr.set_named_space(space); - mtr.write<4,mtr_t::MAYBE_NOP>( - *b, - FSP_HEADER_OFFSET - + FSP_SPACE_FLAGS + b->frame, - space->flags - & ~FSP_FLAGS_MEM_MASK); + byte* f = FSP_HEADER_OFFSET + + FSP_SPACE_FLAGS + b->frame; + const auto sf = space->flags + & ~FSP_FLAGS_MEM_MASK; + if (mach_read_from_4(f) != sf) { + mtr.set_named_space(space); + mtr.write<4,mtr_t::FORCED>( + *b, f, sf); + } } mtr.commit(); } diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index e241c849c4e..e3ac675cd56 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -2929,8 +2929,8 @@ static bool recv_scan_log_recs( } ib::info() << "Starting crash recovery from" - " checkpoint LSN=" - << recv_sys.scanned_lsn; + " checkpoint LSN=" << checkpoint_lsn + << "," << recv_sys.scanned_lsn; } /* We were able to find more log data: add it to the From 1668465f68126d4d995a4fb6976be9302943aaf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 21 Oct 2020 10:56:26 +0300 Subject: [PATCH 173/323] MDEV-23998 Race between buf_page_optimistic_get() and buf_page_t::init() MDEV-22871 tried to optimize the buf_page_t initialization in buf_page_init_for_read() by initializing everything while the block is in freed state, and only afterwards attaching the block to buf_pool.page_hash. In an rr replay trace, we have multiple threads executing in buf_page_optimistic_get() on the same buf_block_t while the block is being freed and reallocated several times in buf_page_init_for_read(). Because also the buf_page_t::id() is changing, the buf_pool.page_hash is being protected by a different rw-lock than the one that buf_page_optimistic_get() are successfully read-locking. buf_page_optimistic_get(): Validate also buf_page_t::id() after acquiring the buf_pool.page_hash latch. Reviewed by: Thirunarayanan Balathandayuthapani --- storage/innobase/buf/buf0buf.cc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 9408ce7bf62..0f25232ebba 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -3630,10 +3630,13 @@ buf_page_optimistic_get( return FALSE; } - page_hash_latch *hash_lock = buf_pool.hash_lock_get(block->page.id()); + const page_id_t id(block->page.id()); + + page_hash_latch *hash_lock = buf_pool.hash_lock_get(id); hash_lock->read_lock(); - if (UNIV_UNLIKELY(block->page.state() != BUF_BLOCK_FILE_PAGE + if (UNIV_UNLIKELY(id != block->page.id() + || block->page.state() != BUF_BLOCK_FILE_PAGE || block->page.io_fix() != BUF_IO_NONE)) { hash_lock->read_unlock(); return(FALSE); @@ -3646,8 +3649,7 @@ buf_page_optimistic_get( buf_page_make_young_if_needed(&block->page); - ut_ad(!ibuf_inside(mtr) - || ibuf_page(block->page.id(), block->zip_size(), NULL)); + ut_ad(!ibuf_inside(mtr) || ibuf_page(id, block->zip_size(), NULL)); mtr_memo_type_t fix_type; @@ -3660,6 +3662,8 @@ buf_page_optimistic_get( &block->lock, file, line); } + ut_ad(id == block->page.id()); + if (!success) { buf_block_buf_fix_dec(block); return(FALSE); From b4c225ac354686242b5336da84b7a758640936bd Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Wed, 7 Oct 2020 16:06:20 +1100 Subject: [PATCH 174/323] MDEV-23887: check_linker_flags correct for old cmake compatibility It was only from CMake-3.14.0 that CMAKE_REQUIRED_LINK_OPTIONS was used in CHECK_CXX_SOURCE_COMPILES. Without this, it could be the case (as was on OSX) that a flag was never checked in CHECK_CXX_SOURCE_COMPILES, the CHECK successfully passed, but failed at link time. As such we use CMAKE_REQUIRED_LIBRARIES to include the flags to check as its compatible enough with the cmake versions for non-Windows compilers/linkers. Tested on x86_64 with: * 3.11.4 * 3.17.4 Corrects: 7473e1841c630d86f1873a2a7afacb53955b3f6f In the future: * cmake >=3.14.0 can use CMAKE_REQUIRED_LINK_OPTIONS * cmake >=3.18.0 can use CHECK_LINKER_FLAG (with policy CMP0057 NEW) (e.g: commit c7ac2deff9a2c965887dcc67cbf2a3a7c3e0123d) CMAKE_REQUIRED_LIBRARIES suggested by serg@mariadb.com Reviewed-by: anel@mariadb.org --- cmake/check_linker_flag.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/check_linker_flag.cmake b/cmake/check_linker_flag.cmake index ff4b91e89f6..1ea1772d79e 100644 --- a/cmake/check_linker_flag.cmake +++ b/cmake/check_linker_flag.cmake @@ -6,11 +6,11 @@ FUNCTION(MY_CHECK_AND_SET_LINKER_FLAG flag_to_set) RETURN() ENDIF() STRING(REGEX REPLACE "[-,= +]" "_" result "HAVE_LINK_FLAG_${flag_to_set}") - SET(SAVE_CMAKE_REQUIRED_LINK_OPTIONS "${CMAKE_REQUIRED_LINK_OPTIONS}") + SET(SAVE_CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}") STRING(REGEX REPLACE "^-Wno-" "-W" flag_to_check ${flag_to_set}) - SET(CMAKE_REQUIRED_LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS} ${flag_to_check}) + SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${flag_to_check}) CHECK_CXX_SOURCE_COMPILES("int main(void) { return 0; }" ${result}) - SET(CMAKE_REQUIRED_LINK_OPTIONS "${SAVE_CMAKE_REQUIRED_LINK_OPTIONS}") + SET(CMAKE_REQUIRED_LIBRARIES "${SAVE_CMAKE_REQUIRED_LIBRARIES}") IF (${result}) FOREACH(linktype SHARED MODULE EXE) IF(ARGN) From a1b6691f93e50ad4a8a53dbf89ba578d6a64b2cb Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Wed, 21 Oct 2020 17:43:23 +0700 Subject: [PATCH 175/323] MDEV-23925: Fixed warnings generated during compilation of mysys_ssl/openssl.c on MacOS Compiler warnings like one listed below are generated during server build on MacOS: In file included from server-10.2-MDEV-23564/mysys_ssl/openssl.c:33: In file included from /usr/local/include/openssl/evp.h:16: In file included from /usr/local/include/openssl/bio.h:20: /usr/local/include/openssl/crypto.h:206:10: warning: 'CRYPTO_cleanup_all_ex_data' macro redefined [-Wmacro-redefined] ^ /mariadb/server-10.2-MDEV-23564/include/ssl_compat.h:46:9: note: previous definition is here ^ In case MariaDB serer is build with -DCMAKE_BUILD_TYPE=Debug it results in build error. The reason of compiler warnings is that header file included before the openssl system header files. File ssl_compat.h contains some macros with the same names as SSL API functions declared in the openssl system header files. It resulted in duplicate symbols that produces compiler warnings. To fix the issue the header file ssl_compat.h should be included after a line where openssl system header is included. --- mysys_ssl/openssl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysys_ssl/openssl.c b/mysys_ssl/openssl.c index f3dc8f4277c..a11db113b14 100644 --- a/mysys_ssl/openssl.c +++ b/mysys_ssl/openssl.c @@ -15,7 +15,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include -#include /* The check is only done for OpenSSL 1.1.x. @@ -25,13 +24,14 @@ */ #ifndef HAVE_OPENSSL11 +#include int check_openssl_compatibility() { return 0; } #else #include - +#include static uint testing, alloc_size, alloc_count; static void *coc_malloc(size_t size, const char *f __attribute__((unused)), From fdf87973cb5246c2edbd11945e65aedb06889bcc Mon Sep 17 00:00:00 2001 From: Daniele Sciascia Date: Thu, 15 Oct 2020 09:24:01 +0200 Subject: [PATCH 176/323] MDEV-23081 Stray XA transactions at startup, with wsrep_on=OFF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change xarecover_handlerton so that transaction with WSREP prefixed xids are rolled back when Galera is disabled. Reviewd-by: Jan Lindström --- mysql-test/suite/wsrep/r/MDEV-23081.result | 24 ++++++++ mysql-test/suite/wsrep/t/MDEV-23081.cnf | 9 +++ .../suite/wsrep/t/MDEV-23081.combinations | 4 ++ mysql-test/suite/wsrep/t/MDEV-23081.test | 57 +++++++++++++++++++ sql/handler.cc | 2 +- 5 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/wsrep/r/MDEV-23081.result create mode 100644 mysql-test/suite/wsrep/t/MDEV-23081.cnf create mode 100644 mysql-test/suite/wsrep/t/MDEV-23081.combinations create mode 100644 mysql-test/suite/wsrep/t/MDEV-23081.test diff --git a/mysql-test/suite/wsrep/r/MDEV-23081.result b/mysql-test/suite/wsrep/r/MDEV-23081.result new file mode 100644 index 00000000000..5d0ad90b030 --- /dev/null +++ b/mysql-test/suite/wsrep/r/MDEV-23081.result @@ -0,0 +1,24 @@ +CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB; +connect con1, localhost, root; +SET DEBUG_SYNC = "wsrep_after_certification SIGNAL after_certification_reached WAIT_FOR continue_after_certification"; +SET DEBUG_SYNC = "wsrep_before_commit_order_enter SIGNAL before_commit_order_reached_1 WAIT_FOR continue_before_commit_order_1"; +INSERT INTO t1 VALUES (9); +connect con_ctrl, localhost, root; +SET DEBUG_SYNC = "now WAIT_FOR after_certification_reached"; +connect con2, localhost, root; +SET DEBUG_SYNC = "wsrep_before_commit_order_enter SIGNAL before_commit_order_reached_2 WAIT_FOR continue_before_commit_order_2"; +INSERT INTO t1 VALUES (10); +connection con_ctrl; +SET DEBUG_SYNC = "now WAIT_FOR before_commit_order_reached_2"; +SET DEBUG_SYNC = "now SIGNAL continue_after_certification"; +SET DEBUG_SYNC = "now WAIT_FOR before_commit_order_reached_1"; +connection default; +# Kill the server +XA RECOVER; +formatID gtrid_length bqual_length data +disconnect con1; +disconnect con2; +disconnect con_ctrl; +connection default; +DROP TABLE t1; +CALL mtr.add_suppression("You need to use --log-bin to make --binlog-format work"); diff --git a/mysql-test/suite/wsrep/t/MDEV-23081.cnf b/mysql-test/suite/wsrep/t/MDEV-23081.cnf new file mode 100644 index 00000000000..489c4385dbd --- /dev/null +++ b/mysql-test/suite/wsrep/t/MDEV-23081.cnf @@ -0,0 +1,9 @@ +!include ../my.cnf + +[mysqld.1] +wsrep-on=ON +binlog-format=ROW +innodb-flush-log-at-trx-commit=1 +wsrep-cluster-address=gcomm:// +wsrep-provider=@ENV.WSREP_PROVIDER +innodb-autoinc-lock-mode=2 diff --git a/mysql-test/suite/wsrep/t/MDEV-23081.combinations b/mysql-test/suite/wsrep/t/MDEV-23081.combinations new file mode 100644 index 00000000000..1ce3b45aa1a --- /dev/null +++ b/mysql-test/suite/wsrep/t/MDEV-23081.combinations @@ -0,0 +1,4 @@ +[binlogon] +log-bin + +[binlogoff] diff --git a/mysql-test/suite/wsrep/t/MDEV-23081.test b/mysql-test/suite/wsrep/t/MDEV-23081.test new file mode 100644 index 00000000000..04305b22b24 --- /dev/null +++ b/mysql-test/suite/wsrep/t/MDEV-23081.test @@ -0,0 +1,57 @@ +# +# MDEV-23081: Stray XA transactions at startup +# if node restarts with wsrep_on=OFF +# +--source include/have_wsrep.inc +--source include/have_innodb.inc +--source include/have_wsrep_provider.inc +--source include/have_debug_sync.inc + +CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB; + +# +# Execute two inserts on block those after becoming +# prepared, and before they are committed +# +--connect con1, localhost, root +SET DEBUG_SYNC = "wsrep_after_certification SIGNAL after_certification_reached WAIT_FOR continue_after_certification"; +SET DEBUG_SYNC = "wsrep_before_commit_order_enter SIGNAL before_commit_order_reached_1 WAIT_FOR continue_before_commit_order_1"; +--send INSERT INTO t1 VALUES (9) + +--connect con_ctrl, localhost, root +SET DEBUG_SYNC = "now WAIT_FOR after_certification_reached"; + +--connect con2, localhost, root +SET DEBUG_SYNC = "wsrep_before_commit_order_enter SIGNAL before_commit_order_reached_2 WAIT_FOR continue_before_commit_order_2"; +--send INSERT INTO t1 VALUES (10) + +--connection con_ctrl +SET DEBUG_SYNC = "now WAIT_FOR before_commit_order_reached_2"; +SET DEBUG_SYNC = "now SIGNAL continue_after_certification"; +SET DEBUG_SYNC = "now WAIT_FOR before_commit_order_reached_1"; + +# +# Kill the server +# +--connection default +--source include/kill_mysqld.inc + +# +# and restart it with wsrep-on=OFF +# +let $restart_noprint=2; +--let $restart_parameters=--wsrep-on=OFF +--source include/start_mysqld.inc + +# +# Expect no prepared XA transactions to be reported +# +XA RECOVER; + +--disconnect con1 +--disconnect con2 +--disconnect con_ctrl +--connection default + +DROP TABLE t1; +CALL mtr.add_suppression("You need to use --log-bin to make --binlog-format work"); diff --git a/sql/handler.cc b/sql/handler.cc index 6dc17109ffd..845d288b780 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2167,7 +2167,7 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin, for (int i=0; i < got; i ++) { - my_xid x= IF_WSREP(WSREP_ON && wsrep_is_wsrep_xid(&info->list[i]) ? + my_xid x= IF_WSREP(wsrep_is_wsrep_xid(&info->list[i]) ? wsrep_xid_seqno(&info->list[i]) : info->list[i].get_my_xid(), info->list[i].get_my_xid()); From ac8d20579512e05001f9bf8193187e47c870d35a Mon Sep 17 00:00:00 2001 From: Kentoku SHIBA Date: Thu, 16 Apr 2020 00:44:20 +0900 Subject: [PATCH 177/323] MDEV-20100 MariaDB 13.3.9 Crash "[ERROR] mysqld got signal 11 ;" Some functions on ha_partition call functions on all partitions, but handler->reset() is only called that pruned by m_partitions_to_reset. So Spider didn't clear pointer on unpruned partitions, if the unpruned partitions are used by next query, Spider reference the pointer that is already freed. --- sql/ha_partition.cc | 85 ++++++++----- .../bugfix/include/mdev_20100_deinit.inc | 11 ++ .../spider/bugfix/include/mdev_20100_init.inc | 46 +++++++ .../spider/bugfix/r/mdev_20100.result | 119 ++++++++++++++++++ .../mysql-test/spider/bugfix/t/mdev_20100.cnf | 3 + .../spider/bugfix/t/mdev_20100.test | 85 +++++++++++++ 6 files changed, 320 insertions(+), 29 deletions(-) create mode 100644 storage/spider/mysql-test/spider/bugfix/include/mdev_20100_deinit.inc create mode 100644 storage/spider/mysql-test/spider/bugfix/include/mdev_20100_init.inc create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_20100.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_20100.cnf create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_20100.test diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index f745acda75f..5a48af51d3d 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -11148,7 +11148,7 @@ TABLE_LIST *ha_partition::get_next_global_for_child() const COND *ha_partition::cond_push(const COND *cond) { - handler **file= m_file; + uint i; COND *res_cond= NULL; DBUG_ENTER("ha_partition::cond_push"); @@ -11158,26 +11158,35 @@ const COND *ha_partition::cond_push(const COND *cond) We want to do this in a separate loop to not come into a situation where we have only done cond_push() to some of the tables */ - do + for (i= bitmap_get_first_set(&m_partitions_to_reset); + i < m_tot_parts; + i= bitmap_get_next_set(&m_partitions_to_reset, i)) { - if (((*file)->set_top_table_and_fields(top_table, - top_table_field, - top_table_fields))) - DBUG_RETURN(cond); // Abort cond push, no error - } while (*(++file)); - file= m_file; + if (bitmap_is_set(&m_opened_partitions, i)) + { + if ((m_file[i]->set_top_table_and_fields(top_table, + top_table_field, + top_table_fields))) + DBUG_RETURN(cond); // Abort cond push, no error + } + } } - do + for (i= bitmap_get_first_set(&m_partitions_to_reset); + i < m_tot_parts; + i= bitmap_get_next_set(&m_partitions_to_reset, i)) { - if ((*file)->pushed_cond != cond) + if (bitmap_is_set(&m_opened_partitions, i)) { - if ((*file)->cond_push(cond)) - res_cond= (COND *) cond; - else - (*file)->pushed_cond= cond; + if (m_file[i]->pushed_cond != cond) + { + if (m_file[i]->cond_push(cond)) + res_cond= (COND *) cond; + else + m_file[i]->pushed_cond= cond; + } } - } while (*(++file)); + } DBUG_RETURN(res_cond); } @@ -11189,13 +11198,18 @@ const COND *ha_partition::cond_push(const COND *cond) void ha_partition::cond_pop() { - handler **file= m_file; + uint i; DBUG_ENTER("ha_partition::cond_pop"); - do + for (i= bitmap_get_first_set(&m_partitions_to_reset); + i < m_tot_parts; + i= bitmap_get_next_set(&m_partitions_to_reset, i)) { - (*file)->cond_pop(); - } while (*(++file)); + if (bitmap_is_set(&m_opened_partitions, i)) + { + m_file[i]->cond_pop(); + } + } DBUG_VOID_RETURN; } @@ -11779,23 +11793,29 @@ int ha_partition::pre_direct_delete_rows() int ha_partition::info_push(uint info_type, void *info) { - int error= 0; - handler **file= m_file; + int error= 0, tmp; + uint i; DBUG_ENTER("ha_partition::info_push"); - do + for (i= bitmap_get_first_set(&m_partitions_to_reset); + i < m_tot_parts; + i= bitmap_get_next_set(&m_partitions_to_reset, i)) { - int tmp; - if ((tmp= (*file)->info_push(info_type, info))) - error= tmp; - } while (*(++file)); + if (bitmap_is_set(&m_opened_partitions, i)) + { + if ((tmp= m_file[i]->info_push(info_type, info))) + { + error= tmp; + } + } + } DBUG_RETURN(error); } void ha_partition::clear_top_table_fields() { - handler **file; + uint i; DBUG_ENTER("ha_partition::clear_top_table_fields"); if (set_top_table_fields) @@ -11804,8 +11824,15 @@ void ha_partition::clear_top_table_fields() top_table= NULL; top_table_field= NULL; top_table_fields= 0; - for (file= m_file; *file; file++) - (*file)->clear_top_table_fields(); + for (i= bitmap_get_first_set(&m_partitions_to_reset); + i < m_tot_parts; + i= bitmap_get_next_set(&m_partitions_to_reset, i)) + { + if (bitmap_is_set(&m_opened_partitions, i)) + { + m_file[i]->clear_top_table_fields(); + } + } } DBUG_VOID_RETURN; } diff --git a/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_deinit.inc b/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_deinit.inc new file mode 100644 index 00000000000..1880a1c7bba --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_deinit.inc @@ -0,0 +1,11 @@ +--let $MASTER_1_COMMENT_P_2_1= $MASTER_1_COMMENT_P_2_1_BACKUP +--let $CHILD2_1_DROP_TABLES= $CHILD2_1_DROP_TABLES_BACKUP +--let $CHILD2_1_CREATE_TABLES= $CHILD2_1_CREATE_TABLES_BACKUP +--let $CHILD2_1_SELECT_TABLES= $CHILD2_1_SELECT_TABLES_BACKUP +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_deinit.inc +--enable_result_log +--enable_query_log +--enable_warnings diff --git a/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_init.inc b/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_init.inc new file mode 100644 index 00000000000..ed6e27962d2 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_init.inc @@ -0,0 +1,46 @@ +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_init.inc +--enable_result_log +--enable_query_log +--enable_warnings +--let $MASTER_1_COMMENT_P_2_1_BACKUP= $MASTER_1_COMMENT_P_2_1 +let $MASTER_1_COMMENT_P_2_1= + PARTITION BY RANGE(a) ( + PARTITION pt1 VALUES LESS THAN (5) COMMENT='srv "s_2_1", table "ta_r2"', + PARTITION pt2 VALUES LESS THAN (10) COMMENT='srv "s_2_1", table "ta_r3"', + PARTITION pt3 VALUES LESS THAN MAXVALUE COMMENT='srv "s_2_1", table "ta_r4"' + ); +--let $CHILD2_1_DROP_TABLES_BACKUP= $CHILD2_1_DROP_TABLES +let $CHILD2_1_DROP_TABLES= + DROP TABLE IF EXISTS ta_r2 $STR_SEMICOLON + DROP TABLE IF EXISTS ta_r3 $STR_SEMICOLON + DROP TABLE IF EXISTS ta_r4; +--let $CHILD2_1_CREATE_TABLES_BACKUP= $CHILD2_1_CREATE_TABLES +let $CHILD2_1_CREATE_TABLES= + CREATE TABLE ta_r2 ( + a INT, + b CHAR(1), + c DATETIME, + PRIMARY KEY(a) + ) $CHILD2_1_ENGINE $CHILD2_1_CHARSET $STR_SEMICOLON + CREATE TABLE ta_r3 ( + a INT, + b CHAR(1), + c DATETIME, + PRIMARY KEY(a) + ) $CHILD2_1_ENGINE $CHILD2_1_CHARSET $STR_SEMICOLON + CREATE TABLE ta_r4 ( + a INT, + b CHAR(1), + c DATETIME, + PRIMARY KEY(a) + ) $CHILD2_1_ENGINE $CHILD2_1_CHARSET; +--let $CHILD2_1_SELECT_TABLES_BACKUP= $CHILD2_1_SELECT_TABLES +let $CHILD2_1_SELECT_TABLES= + SELECT a, b, c FROM ta_r2 ORDER BY a $STR_SEMICOLON + SELECT a, b, c FROM ta_r3 ORDER BY a $STR_SEMICOLON + SELECT a, b, c FROM ta_r4 ORDER BY a; +let $CHILD2_1_SELECT_ARGUMENT1= + SELECT argument FROM mysql.general_log WHERE argument LIKE '%select %'; diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_20100.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_20100.result new file mode 100644 index 00000000000..9d2297b4daf --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_20100.result @@ -0,0 +1,119 @@ +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 + +this test is for MDEV-20100 + +drop and create databases +connection master_1; +CREATE DATABASE auto_test_local; +USE auto_test_local; +connection child2_1; +SET @old_log_output = @@global.log_output; +SET GLOBAL log_output = 'TABLE,FILE'; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; + +create table and insert +connection child2_1; +CHILD2_1_CREATE_TABLES +TRUNCATE TABLE mysql.general_log; +connection master_1; +CREATE TABLE tbl_a ( +a INT, +b CHAR(1), +c DATETIME, +PRIMARY KEY(a) +) ENGINE=Spider PARTITION BY RANGE(a) ( +PARTITION pt1 VALUES LESS THAN (5) COMMENT='srv "s_2_1", table "ta_r2"', +PARTITION pt2 VALUES LESS THAN (10) COMMENT='srv "s_2_1", table "ta_r3"', +PARTITION pt3 VALUES LESS THAN MAXVALUE COMMENT='srv "s_2_1", table "ta_r4"' + ) +INSERT INTO tbl_a (a, b, c) VALUES +(1, 'a', '2008-08-01 10:21:39'), +(2, 'b', '2000-01-01 00:00:00'), +(3, 'e', '2007-06-04 20:03:11'), +(4, 'd', '2003-11-30 05:01:03'), +(5, 'c', '2001-12-31 23:59:59'); + +test 1 +connection child2_1; +TRUNCATE TABLE mysql.general_log; +connection master_1; +SELECT a, b, c FROM tbl_a PARTITION (pt2) WHERE b = 'c'; +a b c +5 c 2001-12-31 23:59:59 +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt2); +a b c +1 a 2008-08-01 10:21:39 +2 b 2000-01-01 00:00:00 +3 e 2007-06-04 20:03:11 +4 d 2003-11-30 05:01:03 +5 c 2001-12-31 23:59:59 +SELECT a, b, c FROM tbl_a PARTITION (pt3) WHERE b = 'c'; +a b c +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt2); +a b c +1 a 2008-08-01 10:21:39 +2 b 2000-01-01 00:00:00 +3 e 2007-06-04 20:03:11 +4 d 2003-11-30 05:01:03 +5 c 2001-12-31 23:59:59 +SELECT a, b, c FROM tbl_a PARTITION (pt1) WHERE b = 'c'; +a b c +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt3); +a b c +1 a 2008-08-01 10:21:39 +2 b 2000-01-01 00:00:00 +3 e 2007-06-04 20:03:11 +4 d 2003-11-30 05:01:03 +SELECT a, b, c FROM tbl_a PARTITION (pt1) WHERE b = 'c'; +a b c +SELECT a, b, c FROM tbl_a PARTITION (pt2,pt3); +a b c +5 c 2001-12-31 23:59:59 +connection child2_1; +SELECT argument FROM mysql.general_log WHERE argument LIKE '%select %'; +argument +select t0.`a` `a`,t0.`b` `b`,t0.`c` `c` from `auto_test_remote`.`ta_r3` t0 where (t0.`b` = 'c') +select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` +select `a`,`b`,`c` from `auto_test_remote`.`ta_r3` +select t0.`a` `a`,t0.`b` `b`,t0.`c` `c` from `auto_test_remote`.`ta_r4` t0 where (t0.`b` = 'c') +select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` +select `a`,`b`,`c` from `auto_test_remote`.`ta_r3` +select t0.`a` `a`,t0.`b` `b`,t0.`c` `c` from `auto_test_remote`.`ta_r2` t0 where (t0.`b` = 'c') +select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` +select `a`,`b`,`c` from `auto_test_remote`.`ta_r4` +select t0.`a` `a`,t0.`b` `b`,t0.`c` `c` from `auto_test_remote`.`ta_r2` t0 where (t0.`b` = 'c') +select `a`,`b`,`c` from `auto_test_remote`.`ta_r3` +select `a`,`b`,`c` from `auto_test_remote`.`ta_r4` +SELECT argument FROM mysql.general_log WHERE argument LIKE '%select %' +SELECT a, b, c FROM ta_r2 ORDER BY a ; +SELECT a, b, c FROM ta_r3 ORDER BY a ; +SELECT a, b, c FROM ta_r4 ORDER BY a; +a b c +1 a 2008-08-01 10:21:39 +2 b 2000-01-01 00:00:00 +3 e 2007-06-04 20:03:11 +4 d 2003-11-30 05:01:03 +a b c +5 c 2001-12-31 23:59:59 +a b c + +deinit +connection master_1; +DROP DATABASE IF EXISTS auto_test_local; +connection child2_1; +DROP DATABASE IF EXISTS auto_test_remote; +SET GLOBAL log_output = @old_log_output; +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 + +end of test diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.cnf b/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.cnf new file mode 100644 index 00000000000..05dfd8a0bce --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.cnf @@ -0,0 +1,3 @@ +!include include/default_mysqld.cnf +!include ../my_1_1.cnf +!include ../my_2_1.cnf diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.test new file mode 100644 index 00000000000..b72facd11a6 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.test @@ -0,0 +1,85 @@ +--source ../include/mdev_20100_init.inc +--echo +--echo this test is for MDEV-20100 +--echo +--echo drop and create databases + +--connection master_1 +--disable_warnings +CREATE DATABASE auto_test_local; +USE auto_test_local; + +--connection child2_1 +SET @old_log_output = @@global.log_output; +SET GLOBAL log_output = 'TABLE,FILE'; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; +--enable_warnings + +--echo +--echo create table and insert + +--connection child2_1 +--disable_query_log +echo CHILD2_1_CREATE_TABLES; +eval $CHILD2_1_CREATE_TABLES; +--enable_query_log +TRUNCATE TABLE mysql.general_log; + +--connection master_1 +--disable_query_log +echo CREATE TABLE tbl_a ( + a INT, + b CHAR(1), + c DATETIME, + PRIMARY KEY(a) +) $MASTER_1_ENGINE $MASTER_1_COMMENT_P_2_1; +eval CREATE TABLE tbl_a ( + a INT, + b CHAR(1), + c DATETIME, + PRIMARY KEY(a) +) $MASTER_1_ENGINE $MASTER_1_COMMENT_P_2_1; +--enable_query_log +INSERT INTO tbl_a (a, b, c) VALUES + (1, 'a', '2008-08-01 10:21:39'), + (2, 'b', '2000-01-01 00:00:00'), + (3, 'e', '2007-06-04 20:03:11'), + (4, 'd', '2003-11-30 05:01:03'), + (5, 'c', '2001-12-31 23:59:59'); + +--echo +--echo test 1 + +--connection child2_1 +TRUNCATE TABLE mysql.general_log; + +--connection master_1 +SELECT a, b, c FROM tbl_a PARTITION (pt2) WHERE b = 'c'; +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt2); +SELECT a, b, c FROM tbl_a PARTITION (pt3) WHERE b = 'c'; +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt2); +SELECT a, b, c FROM tbl_a PARTITION (pt1) WHERE b = 'c'; +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt3); +SELECT a, b, c FROM tbl_a PARTITION (pt1) WHERE b = 'c'; +SELECT a, b, c FROM tbl_a PARTITION (pt2,pt3); + +--connection child2_1 +eval $CHILD2_1_SELECT_ARGUMENT1; +eval $CHILD2_1_SELECT_TABLES; + +--echo +--echo deinit +--disable_warnings + +--connection master_1 +DROP DATABASE IF EXISTS auto_test_local; + +--connection child2_1 +DROP DATABASE IF EXISTS auto_test_remote; +SET GLOBAL log_output = @old_log_output; + +--enable_warnings +--source ../include/mdev_20100_deinit.inc +--echo +--echo end of test From b30ad01d407c0d7f517a5c46deedefb02212d098 Mon Sep 17 00:00:00 2001 From: Kentoku SHIBA Date: Thu, 16 Apr 2020 00:44:20 +0900 Subject: [PATCH 178/323] MDEV-20100 MariaDB 13.3.9 Crash "[ERROR] mysqld got signal 11 ;" Some functions on ha_partition call functions on all partitions, but handler->reset() is only called that pruned by m_partitions_to_reset. So Spider didn't clear pointer on unpruned partitions, if the unpruned partitions are used by next query, Spider reference the pointer that is already freed. --- sql/ha_partition.cc | 54 +++++--- .../bugfix/include/mdev_20100_deinit.inc | 11 ++ .../spider/bugfix/include/mdev_20100_init.inc | 46 +++++++ .../spider/bugfix/r/mdev_20100.result | 119 ++++++++++++++++++ .../mysql-test/spider/bugfix/t/mdev_20100.cnf | 3 + .../spider/bugfix/t/mdev_20100.test | 85 +++++++++++++ 6 files changed, 299 insertions(+), 19 deletions(-) create mode 100644 storage/spider/mysql-test/spider/bugfix/include/mdev_20100_deinit.inc create mode 100644 storage/spider/mysql-test/spider/bugfix/include/mdev_20100_init.inc create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_20100.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_20100.cnf create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_20100.test diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index a3c0029adbb..7f00a194698 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -11232,20 +11232,25 @@ TABLE_LIST *ha_partition::get_next_global_for_child() const COND *ha_partition::cond_push(const COND *cond) { - handler **file= m_file; + uint i; COND *res_cond= NULL; DBUG_ENTER("ha_partition::cond_push"); - do + for (i= bitmap_get_first_set(&m_partitions_to_reset); + i < m_tot_parts; + i= bitmap_get_next_set(&m_partitions_to_reset, i)) { - if ((*file)->pushed_cond != cond) + if (bitmap_is_set(&m_opened_partitions, i)) { - if ((*file)->cond_push(cond)) - res_cond= (COND *) cond; - else - (*file)->pushed_cond= cond; + if (m_file[i]->pushed_cond != cond) + { + if (m_file[i]->cond_push(cond)) + res_cond= (COND *) cond; + else + m_file[i]->pushed_cond= cond; + } } - } while (*(++file)); + } DBUG_RETURN(res_cond); } @@ -11257,13 +11262,18 @@ const COND *ha_partition::cond_push(const COND *cond) void ha_partition::cond_pop() { - handler **file= m_file; + uint i; DBUG_ENTER("ha_partition::cond_pop"); - do + for (i= bitmap_get_first_set(&m_partitions_to_reset); + i < m_tot_parts; + i= bitmap_get_next_set(&m_partitions_to_reset, i)) { - (*file)->cond_pop(); - } while (*(++file)); + if (bitmap_is_set(&m_opened_partitions, i)) + { + m_file[i]->cond_pop(); + } + } DBUG_VOID_RETURN; } @@ -11853,16 +11863,22 @@ int ha_partition::pre_direct_delete_rows() int ha_partition::info_push(uint info_type, void *info) { - int error= 0; - handler **file= m_file; + int error= 0, tmp; + uint i; DBUG_ENTER("ha_partition::info_push"); - do + for (i= bitmap_get_first_set(&m_partitions_to_reset); + i < m_tot_parts; + i= bitmap_get_next_set(&m_partitions_to_reset, i)) { - int tmp; - if ((tmp= (*file)->info_push(info_type, info))) - error= tmp; - } while (*(++file)); + if (bitmap_is_set(&m_opened_partitions, i)) + { + if ((tmp= m_file[i]->info_push(info_type, info))) + { + error= tmp; + } + } + } DBUG_RETURN(error); } diff --git a/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_deinit.inc b/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_deinit.inc new file mode 100644 index 00000000000..1880a1c7bba --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_deinit.inc @@ -0,0 +1,11 @@ +--let $MASTER_1_COMMENT_P_2_1= $MASTER_1_COMMENT_P_2_1_BACKUP +--let $CHILD2_1_DROP_TABLES= $CHILD2_1_DROP_TABLES_BACKUP +--let $CHILD2_1_CREATE_TABLES= $CHILD2_1_CREATE_TABLES_BACKUP +--let $CHILD2_1_SELECT_TABLES= $CHILD2_1_SELECT_TABLES_BACKUP +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_deinit.inc +--enable_result_log +--enable_query_log +--enable_warnings diff --git a/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_init.inc b/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_init.inc new file mode 100644 index 00000000000..ed6e27962d2 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/mdev_20100_init.inc @@ -0,0 +1,46 @@ +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_init.inc +--enable_result_log +--enable_query_log +--enable_warnings +--let $MASTER_1_COMMENT_P_2_1_BACKUP= $MASTER_1_COMMENT_P_2_1 +let $MASTER_1_COMMENT_P_2_1= + PARTITION BY RANGE(a) ( + PARTITION pt1 VALUES LESS THAN (5) COMMENT='srv "s_2_1", table "ta_r2"', + PARTITION pt2 VALUES LESS THAN (10) COMMENT='srv "s_2_1", table "ta_r3"', + PARTITION pt3 VALUES LESS THAN MAXVALUE COMMENT='srv "s_2_1", table "ta_r4"' + ); +--let $CHILD2_1_DROP_TABLES_BACKUP= $CHILD2_1_DROP_TABLES +let $CHILD2_1_DROP_TABLES= + DROP TABLE IF EXISTS ta_r2 $STR_SEMICOLON + DROP TABLE IF EXISTS ta_r3 $STR_SEMICOLON + DROP TABLE IF EXISTS ta_r4; +--let $CHILD2_1_CREATE_TABLES_BACKUP= $CHILD2_1_CREATE_TABLES +let $CHILD2_1_CREATE_TABLES= + CREATE TABLE ta_r2 ( + a INT, + b CHAR(1), + c DATETIME, + PRIMARY KEY(a) + ) $CHILD2_1_ENGINE $CHILD2_1_CHARSET $STR_SEMICOLON + CREATE TABLE ta_r3 ( + a INT, + b CHAR(1), + c DATETIME, + PRIMARY KEY(a) + ) $CHILD2_1_ENGINE $CHILD2_1_CHARSET $STR_SEMICOLON + CREATE TABLE ta_r4 ( + a INT, + b CHAR(1), + c DATETIME, + PRIMARY KEY(a) + ) $CHILD2_1_ENGINE $CHILD2_1_CHARSET; +--let $CHILD2_1_SELECT_TABLES_BACKUP= $CHILD2_1_SELECT_TABLES +let $CHILD2_1_SELECT_TABLES= + SELECT a, b, c FROM ta_r2 ORDER BY a $STR_SEMICOLON + SELECT a, b, c FROM ta_r3 ORDER BY a $STR_SEMICOLON + SELECT a, b, c FROM ta_r4 ORDER BY a; +let $CHILD2_1_SELECT_ARGUMENT1= + SELECT argument FROM mysql.general_log WHERE argument LIKE '%select %'; diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_20100.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_20100.result new file mode 100644 index 00000000000..9d2297b4daf --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_20100.result @@ -0,0 +1,119 @@ +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 + +this test is for MDEV-20100 + +drop and create databases +connection master_1; +CREATE DATABASE auto_test_local; +USE auto_test_local; +connection child2_1; +SET @old_log_output = @@global.log_output; +SET GLOBAL log_output = 'TABLE,FILE'; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; + +create table and insert +connection child2_1; +CHILD2_1_CREATE_TABLES +TRUNCATE TABLE mysql.general_log; +connection master_1; +CREATE TABLE tbl_a ( +a INT, +b CHAR(1), +c DATETIME, +PRIMARY KEY(a) +) ENGINE=Spider PARTITION BY RANGE(a) ( +PARTITION pt1 VALUES LESS THAN (5) COMMENT='srv "s_2_1", table "ta_r2"', +PARTITION pt2 VALUES LESS THAN (10) COMMENT='srv "s_2_1", table "ta_r3"', +PARTITION pt3 VALUES LESS THAN MAXVALUE COMMENT='srv "s_2_1", table "ta_r4"' + ) +INSERT INTO tbl_a (a, b, c) VALUES +(1, 'a', '2008-08-01 10:21:39'), +(2, 'b', '2000-01-01 00:00:00'), +(3, 'e', '2007-06-04 20:03:11'), +(4, 'd', '2003-11-30 05:01:03'), +(5, 'c', '2001-12-31 23:59:59'); + +test 1 +connection child2_1; +TRUNCATE TABLE mysql.general_log; +connection master_1; +SELECT a, b, c FROM tbl_a PARTITION (pt2) WHERE b = 'c'; +a b c +5 c 2001-12-31 23:59:59 +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt2); +a b c +1 a 2008-08-01 10:21:39 +2 b 2000-01-01 00:00:00 +3 e 2007-06-04 20:03:11 +4 d 2003-11-30 05:01:03 +5 c 2001-12-31 23:59:59 +SELECT a, b, c FROM tbl_a PARTITION (pt3) WHERE b = 'c'; +a b c +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt2); +a b c +1 a 2008-08-01 10:21:39 +2 b 2000-01-01 00:00:00 +3 e 2007-06-04 20:03:11 +4 d 2003-11-30 05:01:03 +5 c 2001-12-31 23:59:59 +SELECT a, b, c FROM tbl_a PARTITION (pt1) WHERE b = 'c'; +a b c +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt3); +a b c +1 a 2008-08-01 10:21:39 +2 b 2000-01-01 00:00:00 +3 e 2007-06-04 20:03:11 +4 d 2003-11-30 05:01:03 +SELECT a, b, c FROM tbl_a PARTITION (pt1) WHERE b = 'c'; +a b c +SELECT a, b, c FROM tbl_a PARTITION (pt2,pt3); +a b c +5 c 2001-12-31 23:59:59 +connection child2_1; +SELECT argument FROM mysql.general_log WHERE argument LIKE '%select %'; +argument +select t0.`a` `a`,t0.`b` `b`,t0.`c` `c` from `auto_test_remote`.`ta_r3` t0 where (t0.`b` = 'c') +select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` +select `a`,`b`,`c` from `auto_test_remote`.`ta_r3` +select t0.`a` `a`,t0.`b` `b`,t0.`c` `c` from `auto_test_remote`.`ta_r4` t0 where (t0.`b` = 'c') +select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` +select `a`,`b`,`c` from `auto_test_remote`.`ta_r3` +select t0.`a` `a`,t0.`b` `b`,t0.`c` `c` from `auto_test_remote`.`ta_r2` t0 where (t0.`b` = 'c') +select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` +select `a`,`b`,`c` from `auto_test_remote`.`ta_r4` +select t0.`a` `a`,t0.`b` `b`,t0.`c` `c` from `auto_test_remote`.`ta_r2` t0 where (t0.`b` = 'c') +select `a`,`b`,`c` from `auto_test_remote`.`ta_r3` +select `a`,`b`,`c` from `auto_test_remote`.`ta_r4` +SELECT argument FROM mysql.general_log WHERE argument LIKE '%select %' +SELECT a, b, c FROM ta_r2 ORDER BY a ; +SELECT a, b, c FROM ta_r3 ORDER BY a ; +SELECT a, b, c FROM ta_r4 ORDER BY a; +a b c +1 a 2008-08-01 10:21:39 +2 b 2000-01-01 00:00:00 +3 e 2007-06-04 20:03:11 +4 d 2003-11-30 05:01:03 +a b c +5 c 2001-12-31 23:59:59 +a b c + +deinit +connection master_1; +DROP DATABASE IF EXISTS auto_test_local; +connection child2_1; +DROP DATABASE IF EXISTS auto_test_remote; +SET GLOBAL log_output = @old_log_output; +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 + +end of test diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.cnf b/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.cnf new file mode 100644 index 00000000000..05dfd8a0bce --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.cnf @@ -0,0 +1,3 @@ +!include include/default_mysqld.cnf +!include ../my_1_1.cnf +!include ../my_2_1.cnf diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.test new file mode 100644 index 00000000000..b72facd11a6 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_20100.test @@ -0,0 +1,85 @@ +--source ../include/mdev_20100_init.inc +--echo +--echo this test is for MDEV-20100 +--echo +--echo drop and create databases + +--connection master_1 +--disable_warnings +CREATE DATABASE auto_test_local; +USE auto_test_local; + +--connection child2_1 +SET @old_log_output = @@global.log_output; +SET GLOBAL log_output = 'TABLE,FILE'; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; +--enable_warnings + +--echo +--echo create table and insert + +--connection child2_1 +--disable_query_log +echo CHILD2_1_CREATE_TABLES; +eval $CHILD2_1_CREATE_TABLES; +--enable_query_log +TRUNCATE TABLE mysql.general_log; + +--connection master_1 +--disable_query_log +echo CREATE TABLE tbl_a ( + a INT, + b CHAR(1), + c DATETIME, + PRIMARY KEY(a) +) $MASTER_1_ENGINE $MASTER_1_COMMENT_P_2_1; +eval CREATE TABLE tbl_a ( + a INT, + b CHAR(1), + c DATETIME, + PRIMARY KEY(a) +) $MASTER_1_ENGINE $MASTER_1_COMMENT_P_2_1; +--enable_query_log +INSERT INTO tbl_a (a, b, c) VALUES + (1, 'a', '2008-08-01 10:21:39'), + (2, 'b', '2000-01-01 00:00:00'), + (3, 'e', '2007-06-04 20:03:11'), + (4, 'd', '2003-11-30 05:01:03'), + (5, 'c', '2001-12-31 23:59:59'); + +--echo +--echo test 1 + +--connection child2_1 +TRUNCATE TABLE mysql.general_log; + +--connection master_1 +SELECT a, b, c FROM tbl_a PARTITION (pt2) WHERE b = 'c'; +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt2); +SELECT a, b, c FROM tbl_a PARTITION (pt3) WHERE b = 'c'; +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt2); +SELECT a, b, c FROM tbl_a PARTITION (pt1) WHERE b = 'c'; +SELECT a, b, c FROM tbl_a PARTITION (pt1,pt3); +SELECT a, b, c FROM tbl_a PARTITION (pt1) WHERE b = 'c'; +SELECT a, b, c FROM tbl_a PARTITION (pt2,pt3); + +--connection child2_1 +eval $CHILD2_1_SELECT_ARGUMENT1; +eval $CHILD2_1_SELECT_TABLES; + +--echo +--echo deinit +--disable_warnings + +--connection master_1 +DROP DATABASE IF EXISTS auto_test_local; + +--connection child2_1 +DROP DATABASE IF EXISTS auto_test_remote; +SET GLOBAL log_output = @old_log_output; + +--enable_warnings +--source ../include/mdev_20100_deinit.inc +--echo +--echo end of test From 709ba7dcae871e365697f67677c908b55ad4a964 Mon Sep 17 00:00:00 2001 From: Rinat Ibragimov Date: Wed, 21 Oct 2020 23:34:36 +0300 Subject: [PATCH 179/323] MDEV-20945: BACKUP UNLOCK + FTWRL assertion failure MDEV-20945: BACKUP UNLOCK + FTWRL assertion failure | SIGSEGV in I_P_List from MDL_context::release_lock on INSERT w/ BACKUP LOCK (on optimized builds) | Assertion `ticket->m_duration == MDL_EXPLICIT' failed BACKUP LOCK behavior is modified so it won't be used wrong: - BACKUP LOCK should commit any active transactions. - BACKUP LOCK should not be allowed in stored procedures. - When BACKUP LOCK is active, don't allow any DDL's for that connection. - FTWRL is forbidden on the same connection while BACKUP LOCK is active. Reviewed-by: monty@mariadb.com --- mysql-test/main/backup_locks.result | 102 +++++++++++++++++++++ mysql-test/main/backup_locks.test | 119 +++++++++++++++++++++++++ mysql-test/main/implicit_commit.result | 10 +++ mysql-test/main/implicit_commit.test | 10 +++ sql/backup.cc | 6 ++ sql/sql_class.cc | 2 +- sql/sql_class.h | 9 +- sql/sql_parse.cc | 9 +- sql/sql_reload.cc | 10 ++- sql/sql_yacc.yy | 4 + 10 files changed, 277 insertions(+), 4 deletions(-) diff --git a/mysql-test/main/backup_locks.result b/mysql-test/main/backup_locks.result index a3a66937cf9..f1c02677b7a 100644 --- a/mysql-test/main/backup_locks.result +++ b/mysql-test/main/backup_locks.result @@ -39,6 +39,108 @@ MDL_INTENTION_EXCLUSIVE Schema metadata lock test select * from t1; ERROR 40001: Deadlock found when trying to get lock; try restarting transaction backup unlock; +# +# BACKUP LOCK and BACKUP UNLOCK are not allowed in procedures. +# +CREATE PROCEDURE p_BACKUP_LOCK() +BEGIN +BACKUP LOCK; +END| +ERROR 0A000: BACKUP LOCK is not allowed in stored procedures +CREATE PROCEDURE p_BACKUP_UNLOCK() +BEGIN +BACKUP UNLOCK; +END| +ERROR 0A000: BACKUP UNLOCK is not allowed in stored procedures +# +# BACKUP STAGE doesn't work when a BACKUP LOCK is active. +# +CREATE TABLE t1 (a INT); +BACKUP LOCK t1; +BACKUP STAGE START; +ERROR HY000: Can't execute the query because you have a conflicting read lock +BACKUP UNLOCK; +DROP TABLE t1; +# +# FLUSH TABLES WITH READ LOCK is not allowed when BACKUP LOCK is active. +# +CREATE TABLE t1 (a INT); +BACKUP LOCK t1; +FLUSH TABLES t1 WITH READ LOCK; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +BACKUP UNLOCK; +BACKUP LOCK t1; +FLUSH TABLES WITH READ LOCK; +BACKUP UNLOCK; +UNLOCK TABLES; +DROP TABLE t1; +# +# MDEV-20945 BACKUP UNLOCK assertion failures. +# +# Scenario 1. +CREATE TABLE t1 (a INT); +BACKUP LOCK t1; +FLUSH TABLE t1 WITH READ LOCK; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +UNLOCK TABLES; +BACKUP UNLOCK; +DROP TABLE t1; +# Scenario 2. +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b INT); +LOCK TABLES t2 AS a2 WRITE; +BACKUP LOCK t1; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +UNLOCK TABLES; +INSERT INTO t1 VALUES(0); +# restart +DROP TABLE t1; +DROP TABLE t2; +# Scenario 3. +CREATE TEMPORARY TABLE t3 (c INT); +BACKUP LOCK t1; +SET @@SESSION.profiling=ON; +CREATE TABLE t1 (c INT); +ERROR HY000: Can't execute the query because you have a conflicting read lock +LOCK TABLES t3 AS a1 READ, t1 AS a3 READ, t3 AS a5 READ LOCAL; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +UNLOCK TABLE; +# restart +# Scenario 4. +CREATE TABLE t (c INT); +BACKUP LOCK not_existing.t; +LOCK TABLES t WRITE; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +UNLOCK TABLES; +# restart +DROP TABLE t; +# Scenario 5. +BACKUP LOCK t1; +CREATE TABLE t2 (c1 TIME, c2 TIME, c3 DATE, KEY(c1, c2)); +ERROR HY000: Can't execute the query because you have a conflicting read lock +LOCK TABLE t2 READ; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +# restart +# Scenario 6. +BACKUP LOCK t; +CREATE VIEW v AS SELECT 1; +ERROR HY000: Can't execute the query because you have a conflicting read lock +LOCK TABLES v READ; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +START TRANSACTION READ ONLY; +BACKUP LOCK t; +# restart +# Scenario 7. +SET SQL_MODE=''; +SET STATEMENT max_statement_time=180 FOR BACKUP LOCK test.u; +CREATE TABLE t (a INT) ENGINE=Aria; +ERROR HY000: Can't execute the query because you have a conflicting read lock +CREATE TEMPORARY TABLE IF NOT EXISTS s (c INT) ENGINE=Aria; +LOCK TABLES s AS a READ LOCAL,t AS b WRITE; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +SET STATEMENT max_statement_time=180 FOR BACKUP LOCK test.u; +# restart +# connection con1; connection default; disconnect con1; diff --git a/mysql-test/main/backup_locks.test b/mysql-test/main/backup_locks.test index 21b67100506..ed7d3875d1d 100644 --- a/mysql-test/main/backup_locks.test +++ b/mysql-test/main/backup_locks.test @@ -43,6 +43,125 @@ SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.me --error ER_LOCK_DEADLOCK select * from t1; backup unlock; + +--echo # +--echo # BACKUP LOCK and BACKUP UNLOCK are not allowed in procedures. +--echo # +delimiter |; +--error ER_SP_BADSTATEMENT +CREATE PROCEDURE p_BACKUP_LOCK() +BEGIN + BACKUP LOCK; +END| +--error ER_SP_BADSTATEMENT +CREATE PROCEDURE p_BACKUP_UNLOCK() +BEGIN + BACKUP UNLOCK; +END| +delimiter ;| + +--echo # +--echo # BACKUP STAGE doesn't work when a BACKUP LOCK is active. +--echo # +CREATE TABLE t1 (a INT); +BACKUP LOCK t1; +--error ER_CANT_UPDATE_WITH_READLOCK +BACKUP STAGE START; +BACKUP UNLOCK; +DROP TABLE t1; + +--echo # +--echo # FLUSH TABLES WITH READ LOCK is not allowed when BACKUP LOCK is active. +--echo # +CREATE TABLE t1 (a INT); +BACKUP LOCK t1; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +FLUSH TABLES t1 WITH READ LOCK; +BACKUP UNLOCK; + +BACKUP LOCK t1; +FLUSH TABLES WITH READ LOCK; +BACKUP UNLOCK; +UNLOCK TABLES; +DROP TABLE t1; + +--echo # +--echo # MDEV-20945 BACKUP UNLOCK assertion failures. +--echo # + +--echo # Scenario 1. +CREATE TABLE t1 (a INT); +BACKUP LOCK t1; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +FLUSH TABLE t1 WITH READ LOCK; +UNLOCK TABLES; +BACKUP UNLOCK; # Shouldn't trigger an assertion. +DROP TABLE t1; + +--echo # Scenario 2. +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b INT); +LOCK TABLES t2 AS a2 WRITE; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +BACKUP LOCK t1; +UNLOCK TABLES; +INSERT INTO t1 VALUES(0); +--source include/restart_mysqld.inc +DROP TABLE t1; +DROP TABLE t2; + +--echo # Scenario 3. +CREATE TEMPORARY TABLE t3 (c INT); +BACKUP LOCK t1; # Table `t1` doesn't exist. +SET @@SESSION.profiling=ON; +--error ER_CANT_UPDATE_WITH_READLOCK +CREATE TABLE t1 (c INT); +--error ER_LOCK_OR_ACTIVE_TRANSACTION +LOCK TABLES t3 AS a1 READ, t1 AS a3 READ, t3 AS a5 READ LOCAL; +UNLOCK TABLE; +--source include/restart_mysqld.inc + +--echo # Scenario 4. +CREATE TABLE t (c INT); +BACKUP LOCK not_existing.t; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +LOCK TABLES t WRITE; +UNLOCK TABLES; +--source include/restart_mysqld.inc +DROP TABLE t; + +--echo # Scenario 5. +BACKUP LOCK t1; +--error ER_CANT_UPDATE_WITH_READLOCK +CREATE TABLE t2 (c1 TIME, c2 TIME, c3 DATE, KEY(c1, c2)); +--error ER_LOCK_OR_ACTIVE_TRANSACTION +LOCK TABLE t2 READ; +--source include/restart_mysqld.inc + +--echo # Scenario 6. +BACKUP LOCK t; +--error ER_CANT_UPDATE_WITH_READLOCK +CREATE VIEW v AS SELECT 1; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +LOCK TABLES v READ; +START TRANSACTION READ ONLY; +BACKUP LOCK t; +--source include/restart_mysqld.inc + +--echo # Scenario 7. +SET SQL_MODE=''; +SET STATEMENT max_statement_time=180 FOR BACKUP LOCK test.u; +--error ER_CANT_UPDATE_WITH_READLOCK +CREATE TABLE t (a INT) ENGINE=Aria; +CREATE TEMPORARY TABLE IF NOT EXISTS s (c INT) ENGINE=Aria; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +LOCK TABLES s AS a READ LOCAL,t AS b WRITE; +--let $q= `SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE` +SET STATEMENT max_statement_time=180 FOR BACKUP LOCK test.u; +--source include/restart_mysqld.inc + +--echo # + connection con1; --reap connection default; diff --git a/mysql-test/main/implicit_commit.result b/mysql-test/main/implicit_commit.result index b0cd0b75e8d..911aec085d8 100644 --- a/mysql-test/main/implicit_commit.result +++ b/mysql-test/main/implicit_commit.result @@ -1035,6 +1035,16 @@ YES # SQLCOM_BACKUP # # +# SQLCOM_BACKUP_LOCK +# +INSERT INTO db1.trans VALUES (1); +BACKUP LOCK t1; +ROLLBACK; +BACKUP UNLOCK; +CALL db1.test_if_commit(); +IMPLICIT COMMIT +YES +# # SQLCOM_SHOW_ARCHIVE # # diff --git a/mysql-test/main/implicit_commit.test b/mysql-test/main/implicit_commit.test index bcc43865395..09f2e2e921e 100644 --- a/mysql-test/main/implicit_commit.test +++ b/mysql-test/main/implicit_commit.test @@ -1114,6 +1114,16 @@ source include/implicit_commit_helper.inc; # backup database db1 to 'backup_db1.ba'; #source include/implicit_commit_helper.inc; +--echo # +--echo # SQLCOM_BACKUP_LOCK +--echo # + +INSERT INTO db1.trans VALUES (1); +BACKUP LOCK t1; +ROLLBACK; +BACKUP UNLOCK; +CALL db1.test_if_commit(); + --echo # --echo # SQLCOM_SHOW_ARCHIVE --echo # diff --git a/sql/backup.cc b/sql/backup.cc index 813485ea29a..cff14415d96 100644 --- a/sql/backup.cc +++ b/sql/backup.cc @@ -377,7 +377,13 @@ bool backup_reset_alter_copy_lock(THD *thd) bool backup_lock(THD *thd, TABLE_LIST *table) { + /* We should leave the previous table unlocked in case of errors */ backup_unlock(thd); + if (thd->locked_tables_mode) + { + my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); + return 1; + } table->mdl_request.duration= MDL_EXPLICIT; if (thd->mdl_context.acquire_lock(&table->mdl_request, thd->variables.lock_wait_timeout)) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index e57196ee056..ab9a0118bde 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2569,7 +2569,7 @@ void THD::give_protection_error() my_error(ER_BACKUP_LOCK_IS_ACTIVE, MYF(0)); else { - DBUG_ASSERT(global_read_lock.is_acquired()); + DBUG_ASSERT(global_read_lock.is_acquired() || mdl_backup_lock); my_error(ER_CANT_UPDATE_WITH_READLOCK, MYF(0)); } } diff --git a/sql/sql_class.h b/sql/sql_class.h index 64cd1ed6ba3..6f07cc0037f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3630,10 +3630,17 @@ public: return server_status & SERVER_STATUS_IN_TRANS; } void give_protection_error(); + /* + Give an error if any of the following is true for this connection + - BACKUP STAGE is active + - FLUSH TABLE WITH READ LOCK is active + - BACKUP LOCK table_name is active + */ inline bool has_read_only_protection() { if (current_backup_stage == BACKUP_FINISHED && - !global_read_lock.is_acquired()) + !global_read_lock.is_acquired() && + !mdl_backup_lock) return FALSE; give_protection_error(); return TRUE; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 909cb245b2e..61a3fe4740f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -780,7 +780,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_ALTER_SERVER]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_DROP_SERVER]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_BACKUP]= CF_AUTO_COMMIT_TRANS; - sql_command_flags[SQLCOM_BACKUP_LOCK]= 0; + sql_command_flags[SQLCOM_BACKUP_LOCK]= CF_AUTO_COMMIT_TRANS; /* The following statements can deal with temporary tables, @@ -5002,6 +5002,13 @@ mysql_execute_command(THD *thd) goto error; } + /* Should not lock tables while BACKUP LOCK is active */ + if (thd->mdl_backup_lock) + { + my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); + goto error; + } + /* Here we have to pre-open temporary tables for LOCK TABLES. diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index ef432e556e4..5b4600ece9a 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -217,6 +217,7 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options, thd->handler_tables_hash.records || thd->ull_hash.records || thd->global_read_lock.is_acquired() || + thd->mdl_backup_lock || thd->current_backup_stage != BACKUP_FINISHED ); @@ -530,7 +531,14 @@ bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables) if (thd->current_backup_stage != BACKUP_FINISHED) { my_error(ER_BACKUP_LOCK_IS_ACTIVE, MYF(0)); - return true; + goto error; + } + + /* Should not flush tables while BACKUP LOCK is active */ + if (thd->mdl_backup_lock) + { + my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); + goto error; } if (thd->lex->type & REFRESH_READ_LOCK) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 83323e3f7e3..8c58d703e41 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -14868,6 +14868,8 @@ backup_statements: } | LOCK_SYM { + if (unlikely(Lex->sphead)) + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "BACKUP LOCK")); if (Lex->main_select_push()) MYSQL_YYABORT; } @@ -14881,6 +14883,8 @@ backup_statements: } | UNLOCK_SYM { + if (unlikely(Lex->sphead)) + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "BACKUP UNLOCK")); /* Table list is empty for unlock */ Lex->sql_command= SQLCOM_BACKUP_LOCK; } From 43ec9370b328fc9bf82e318bf992953a71925cd3 Mon Sep 17 00:00:00 2001 From: Sujatha Date: Thu, 22 Oct 2020 07:16:29 +0530 Subject: [PATCH 180/323] MDEV-10149: sys_vars.rpl_init_slave_func fails sporadically in buildbot problem: ======== mysqltest: In included file "./include/assert.inc": included from mysql-test/suite/sys_vars/t/rpl_init_slave_func.test at line 69: Assertion text: '@@global.max_connections = @start_max_connections' Assertion result: '0' mysqltest: In included file "./include/assert.inc": included from mysql-test/suite/sys_vars/t/rpl_init_slave_func.test at line 86: Assertion text: '@@global.max_connections = @start_max_connections + 1' Assertion result: '0' Analysis: ========= A slave SQL thread sets its Running state to Yes very early in its initialisation, before the majority of initialisation actions, including executing the init_slave command, are done. Thus the testcase has a race condition where the initial replication setup might finish executing later than the testcase SET GLOBAL init_slave, making the testcase see its effect where it checks for its absence. Fix: === Include 'sync_slave_sql_with_master.inc' at the beginning of the test to ensure that slave applier has completed the execution of 'init_slave' command and proceeded to event application. Replace the apparently needless RESET MASTER / RESET SLAVE etc. Patch is based on: https://github.com/percona/percona-server/pull/1464/commits/b91e2e6f90611aa299c302929fb8b068e8ac0dee Author: laurynas-biveinis --- .../sys_vars/r/rpl_init_slave_func.result | 15 +++------ .../suite/sys_vars/t/rpl_init_slave_func.test | 33 ++++++++++--------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/mysql-test/suite/sys_vars/r/rpl_init_slave_func.result b/mysql-test/suite/sys_vars/r/rpl_init_slave_func.result index 691f6f10e02..d63a540fe15 100644 --- a/mysql-test/suite/sys_vars/r/rpl_init_slave_func.result +++ b/mysql-test/suite/sys_vars/r/rpl_init_slave_func.result @@ -1,6 +1,6 @@ include/master-slave.inc [connection master] -connection slave +include/sync_slave_sql_with_master.inc SET @start_max_connections= @@global.max_connections; SET @start_init_slave= @@global.init_slave; SET NAMES utf8; @@ -19,18 +19,11 @@ SELECT @@global.init_slave = 'SET @@global.max_connections = @@global.max_connec 1 Expect 1 include/assert.inc [@@global.max_connections = @start_max_connections] -STOP SLAVE; -RESET MASTER; -RESET SLAVE; -START SLAVE; -include/wait_for_slave_to_start.inc +include/restart_slave.inc +include/sync_slave_sql_with_master.inc include/assert.inc [@@global.max_connections = @start_max_connections + 1] SET @@global.init_slave = "SET @a=5"; -STOP SLAVE; -RESET MASTER; -RESET SLAVE; -START SLAVE; -include/wait_for_slave_to_start.inc +include/restart_slave.inc SHOW VARIABLES LIKE 'init_slave'; Variable_name Value init_slave SET @a=5 diff --git a/mysql-test/suite/sys_vars/t/rpl_init_slave_func.test b/mysql-test/suite/sys_vars/t/rpl_init_slave_func.test index 1d57bfeddc5..0e5ff7a3f39 100644 --- a/mysql-test/suite/sys_vars/t/rpl_init_slave_func.test +++ b/mysql-test/suite/sys_vars/t/rpl_init_slave_func.test @@ -29,8 +29,13 @@ ############################################################################### source include/master-slave.inc; ---echo connection slave -connection slave; + +# Since a part of slave SQL thread initialisation happens after Slave_SQL_Running +# has been set to Yes, there is a race condition between initialisation above and +# init_slave setting given below. Synchronise slave applier with master to ensure +# init_slave is complete and applier had processed few events like FD. +--source include/sync_slave_sql_with_master.inc + --disable_query_log call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); --enable_query_log @@ -67,14 +72,15 @@ let $wait_condition= SELECT @@global.max_connections = @start_max_connections; --let $assert_text= @@global.max_connections = @start_max_connections --let $assert_cond= @@global.max_connections = @start_max_connections --source include/assert.inc -# -# reset of the server -STOP SLAVE; ---wait_for_slave_to_stop -RESET MASTER; -RESET SLAVE; -START SLAVE; -source include/wait_for_slave_to_start.inc; + +--source include/restart_slave_sql.inc + +# Upon slave start, sync the applier with master, to ensure slave has +# completed init_slave command execution and processed FD event from the +# master. +--connection master +--source include/sync_slave_sql_with_master.inc + # # wait for the slave threads have set the global variable. let $wait_timeout= 90; @@ -88,12 +94,7 @@ let $wait_condition= SELECT @@global.max_connections = @start_max_connections + # Setting a variable(which is local to a session) and must not be visible SET @@global.init_slave = "SET @a=5"; # -STOP SLAVE; ---wait_for_slave_to_stop -RESET MASTER; -RESET SLAVE; -START SLAVE; -source include/wait_for_slave_to_start.inc; +--source include/restart_slave_sql.inc # SHOW VARIABLES LIKE 'init_slave'; # expect NULL From 77c00799e501def2868399ec3f39ee1bee3f2384 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Thu, 22 Oct 2020 10:14:17 +0700 Subject: [PATCH 181/323] MDEV-23935: Fix warnings generated during compilation of plugin/auth_pam/testing/pam_mariadb_mtr.c on MacOS During build server 10.4 on MacOS warnings like the following one are generated on compiling the file plugin/auth_pam/testing/pam_mariadb_mtr.c server-10.4/plugin/auth_pam/testing/pam_mariadb_mtr.c:25:22: error: initializing 'char *' with an expression of type 'const char [23]' discards qualifiers [-Werror,-Wincompatible-pointer-types-discards-qualifiers] { PAM_TEXT_INFO, "Challenge input first." } The reason of the warnings is that the data member pam_message::msg is declared as 'char *' on MacOS but initializer of the data member is 'const char *'. To eliminate warnings the compiler option -Wno-incompatible-pointer-types-discards-qualifiers has been added to the compiler flags used for compiling the file pam_mariadb_mtr.c. --- plugin/auth_pam/testing/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugin/auth_pam/testing/CMakeLists.txt b/plugin/auth_pam/testing/CMakeLists.txt index 889cb524402..c8d2e3cbb97 100644 --- a/plugin/auth_pam/testing/CMakeLists.txt +++ b/plugin/auth_pam/testing/CMakeLists.txt @@ -4,6 +4,12 @@ ADD_LIBRARY(pam_mariadb_mtr MODULE pam_mariadb_mtr.c) SET_TARGET_PROPERTIES (pam_mariadb_mtr PROPERTIES PREFIX "") TARGET_LINK_LIBRARIES(pam_mariadb_mtr pam) +IF(APPLE) + SET_SOURCE_FILES_PROPERTIES( + pam_mariadb_mtr.c + PROPERTY COMPILE_FLAGS "-Wno-incompatible-pointer-types-discards-qualifiers") +ENDIF() + SET(dest DESTINATION "${INSTALL_MYSQLTESTDIR}/suite/plugins/pam" COMPONENT Test) INSTALL(TARGETS pam_mariadb_mtr ${dest}) INSTALL(FILES mariadb_mtr.conf RENAME mariadb_mtr ${dest}) From 1619ae899099c4934f3b5919b2398c95a7cacc94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 22 Oct 2020 13:19:18 +0300 Subject: [PATCH 182/323] MDEV-23672: Partly revert an incorrect fix In commit 7eda55619654b76add275695e0a6039e60876e81 we removed a valid debug assertion. AddressSanitizer would trip when writing undo log for an INSERT operation that follows the problematic ALTER TABLE because the v_indexes would refer to an index object that was freed during the execution of ALTER TABLE. The operation to remove NOT NULL attribute from a column should lead into any affected indexes to be dropped and re-created. But, the SQL layer set the ha_alter_info->handler_flags to HA_INPLACE_ADD_UNIQUE_INDEX_NO_WRITE|ALTER_COLUMN_NULLABLE (that is, InnoDB was asked to add an index and change the column, but not to drop the index that depended on the column). Let us restore the debug assertion that catches this problem outside AddressSanitizer, and 'defuse' the offending ALTER TABLE statement in the test until something has been fixed in the SQL layer. --- mysql-test/suite/innodb/r/instant_alter_bugs.result | 6 ++---- mysql-test/suite/innodb/t/instant_alter_bugs.test | 10 ++++++---- storage/innobase/handler/handler0alter.cc | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/innodb/r/instant_alter_bugs.result b/mysql-test/suite/innodb/r/instant_alter_bugs.result index 45172be8593..473ee1926da 100644 --- a/mysql-test/suite/innodb/r/instant_alter_bugs.result +++ b/mysql-test/suite/innodb/r/instant_alter_bugs.result @@ -422,11 +422,9 @@ col_text text not null, col_int_g integer generated always as (col_int) unique, col_text_g text generated always as (substr(col_text,1,499)) ) engine innodb row_format = redundant; -insert into t1 values (0, 'a', default, default); -insert into t1 values (null, 'b', default, default); +insert into t1 (col_int,col_text) values (0, 'a'), (null, 'b'); alter table t1 modify column col_text text null, algorithm = instant; -insert into t1 values (1, null, default, default); -insert into t1 values (null, null, default, default); +insert into t1 (col_int,col_text) values (1, null), (null, null); update t1 set col_text= 'd'; select * from t1; col_int col_text col_int_g col_text_g diff --git a/mysql-test/suite/innodb/t/instant_alter_bugs.test b/mysql-test/suite/innodb/t/instant_alter_bugs.test index 12beabf1be2..eb2198e2a96 100644 --- a/mysql-test/suite/innodb/t/instant_alter_bugs.test +++ b/mysql-test/suite/innodb/t/instant_alter_bugs.test @@ -445,11 +445,13 @@ create table t1 ( col_int_g integer generated always as (col_int) unique, col_text_g text generated always as (substr(col_text,1,499)) ) engine innodb row_format = redundant; -insert into t1 values (0, 'a', default, default); -insert into t1 values (null, 'b', default, default); +insert into t1 (col_int,col_text) values (0, 'a'), (null, 'b'); +# FIXME: remove the following to trigger the bug +--disable_query_log +alter table t1 modify column col_text text null, force; +--enable_query_log alter table t1 modify column col_text text null, algorithm = instant; -insert into t1 values (1, null, default, default); -insert into t1 values (null, null, default, default); +insert into t1 (col_int,col_text) values (1, null), (null, null); update t1 set col_text= 'd'; select * from t1; check table t1; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index b714dd63da6..b0108d32e58 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -605,6 +605,7 @@ inline bool dict_table_t::instant_column(const dict_table_t& table, for (unsigned i = 0; i < n_v_def; i++) { dict_v_col_t& v = v_cols[i]; + DBUG_ASSERT(v.v_indexes.empty()); v.base_col = static_cast( mem_heap_dup(heap, v.base_col, v.num_base * sizeof *v.base_col)); From 45e10d46d89aa52dbd96df35191514cf224ba2e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 22 Oct 2020 13:50:06 +0300 Subject: [PATCH 183/323] After-merge fix to wsrep.variables We must make the test depend on a debug version of Galera. --- mysql-test/suite/wsrep/t/variables.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test index c6d7a0dacbb..f2c3a0a3b78 100644 --- a/mysql-test/suite/wsrep/t/variables.test +++ b/mysql-test/suite/wsrep/t/variables.test @@ -1,6 +1,7 @@ --source include/have_wsrep.inc --source include/force_restart.inc --source include/have_innodb.inc +--source include/galera_have_debug_sync.inc call mtr.add_suppression("WSREP: Initial position was provided by configuration or SST, avoiding override"); From 9868253b32877554a2707634dc6a6fd79c491053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 22 Oct 2020 13:52:45 +0300 Subject: [PATCH 184/323] MDEV-23576: Disable galera_3nodes.galera_ipv6_mysqldump --- mysql-test/suite/galera_3nodes/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/galera_3nodes/disabled.def b/mysql-test/suite/galera_3nodes/disabled.def index 0e2706f2dc3..5e3804b9844 100644 --- a/mysql-test/suite/galera_3nodes/disabled.def +++ b/mysql-test/suite/galera_3nodes/disabled.def @@ -14,3 +14,4 @@ galera_gtid_2_cluster : MDEV-23775 Galera test failure on galera_3nodes.galera_g galera_ist_gcache_rollover : MDEV-23578 WSREP: exception caused by message: {v=0,t=1,ut=255,o=4,s=0,sr=0,as=1,f=6,src=50524cfe,srcvid=view_id(REG,50524cfe,4),insvid=view_id(UNKNOWN,00000000,0),ru=00000000,r=[-1,-1],fs=75,nl=(} galera_slave_options_do :MDEV-8798 galera_slave_options_ignore : MDEV-8798 +galera_ipv6_mysqldump : MDEV-23576 From cca75c95bc3c5d0d4a2efb920d3942da3e658654 Mon Sep 17 00:00:00 2001 From: Stepan Patryshev Date: Thu, 22 Oct 2020 14:40:11 +0300 Subject: [PATCH 185/323] MDEV-23659 Update Galera disabled.def file --- mysql-test/suite/galera_3nodes/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/galera_3nodes/disabled.def b/mysql-test/suite/galera_3nodes/disabled.def index ff7262947a0..2da6786061c 100644 --- a/mysql-test/suite/galera_3nodes/disabled.def +++ b/mysql-test/suite/galera_3nodes/disabled.def @@ -10,6 +10,7 @@ # ############################################################################## +GCF-354 : MDEV-24010 galera_3nodes.GCF-354 MTR fails : WSREP has not yet prepared node for application use galera_gtid_2_cluster : MDEV-23775 Galera test failure on galera_3nodes.galera_gtid_2_cluster galera_ipv6_mariabackup : MDEV-21770 galera_3nodes.galera_ipv6_mariabackup fails galera_ipv6_mariabackup_section : MDEV-21770 galera_3nodes.galera_ipv6_mariabackup fails From 21ea14db8cc8c5d88ff804650de7caf984d08a98 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 22 Oct 2020 15:51:14 +0400 Subject: [PATCH 186/323] MDEV-20593 SIGSEGV in report_json_error_ex (on optimized builds). When first argument to the JSON_MERGE_PATCH was NULL and second - the invalid JSON line, the error code was garbage. So it should be set to 0 initially. --- mysql-test/r/func_json.result | 5 +++++ mysql-test/t/func_json.test | 1 + sql/item_jsonfunc.cc | 2 ++ 3 files changed, 8 insertions(+) diff --git a/mysql-test/r/func_json.result b/mysql-test/r/func_json.result index caf46eb5145..8f014c89733 100644 --- a/mysql-test/r/func_json.result +++ b/mysql-test/r/func_json.result @@ -898,6 +898,11 @@ NULL SELECT JSON_MERGE_PATCH(NULL, '[1,2,3]'); JSON_MERGE_PATCH(NULL, '[1,2,3]') [1, 2, 3] +SELECT JSON_MERGE_PATCH(NULL, 'a'); +JSON_MERGE_PATCH(NULL, 'a') +NULL +Warnings: +Warning 4038 Syntax error in JSON text in argument 2 to function 'json_merge_patch' at position 1 SELECT JSON_MERGE_PATCH('{"a":"b"}', NULL, '[1,2,3]', '{"c":null,"d":"e"}'); JSON_MERGE_PATCH('{"a":"b"}', NULL, '[1,2,3]', '{"c":null,"d":"e"}') {"d": "e"} diff --git a/mysql-test/t/func_json.test b/mysql-test/t/func_json.test index c9adbd945b1..805e9954b81 100644 --- a/mysql-test/t/func_json.test +++ b/mysql-test/t/func_json.test @@ -531,6 +531,7 @@ DROP TABLE merge_t; SELECT JSON_MERGE_PATCH('{"a":"b"}', NULL, '{"c":"d"}'); SELECT JSON_MERGE_PATCH(NULL, '[1,2,3]'); +SELECT JSON_MERGE_PATCH(NULL, 'a'); SELECT JSON_MERGE_PATCH('{"a":"b"}', NULL, '[1,2,3]', '{"c":null,"d":"e"}'); --error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index b3c8366907a..7db1ae1ffaf 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -2429,6 +2429,8 @@ String *Item_func_json_merge_patch::val_str(String *str) uint n_arg; bool empty_result, merge_to_null; + /* To report errors properly if some JSON is invalid. */ + je1.s.error= je2.s.error= 0; merge_to_null= args[0]->null_value; for (n_arg=1; n_arg < arg_count; n_arg++) From 897ea21e57034e45bf3bc5997ba1b560eabc8221 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 26 Aug 2020 13:08:33 +0200 Subject: [PATCH 187/323] MDEV-23358 main.upgrade_MDEV-19650 fails with result difference When including a generated file, always use <...>. We need the compiler to find it in the BINDIR, not in the SRCDIR. But when including as "..." SRCDIR is always searched first. The bug can only happen in out-of-source builds, if there was an in-source build before. --- client/mysql_upgrade.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index d18dc97c9b8..8da7a4b01f2 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -18,7 +18,7 @@ #include "client_priv.h" #include -#include "../scripts/mysql_fix_privilege_tables_sql.c" +#include <../scripts/mysql_fix_privilege_tables_sql.c> #include /* ORACLE_WELCOME_COPYRIGHT_NOTICE */ From 0d581562d8bce2181ec16aaa6f019ce8dc8851b4 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 22 Oct 2020 17:09:18 +0300 Subject: [PATCH 188/323] Fix memory leak on Alter_drop allocation Fixes 7f613ebdb686 (MDEV-7284 INDEX: CREATE OR REPLACE). --- sql/sql_table.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ec4ec0d26e9..67a505d78bc 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6719,7 +6719,7 @@ remove_key: DBUG_ASSERT(key->or_replace()); Alter_drop::drop_type type= (key->type == Key::FOREIGN_KEY) ? Alter_drop::FOREIGN_KEY : Alter_drop::KEY; - Alter_drop *ad= new Alter_drop(type, key->name.str, FALSE); + Alter_drop *ad= new (thd->mem_root) Alter_drop(type, key->name.str, FALSE); if (ad != NULL) { // Adding the index into the drop list for replacing From 54c521ca338322ea08a6aba583be3b99649fb666 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 22 Oct 2020 16:49:57 +0300 Subject: [PATCH 189/323] MDEV-23672: incorrect v_indexes access fix v_indexes was wrongly copied from the source table. --- mysql-test/suite/innodb/t/instant_alter_bugs.test | 4 ---- storage/innobase/handler/handler0alter.cc | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/mysql-test/suite/innodb/t/instant_alter_bugs.test b/mysql-test/suite/innodb/t/instant_alter_bugs.test index eb2198e2a96..cdfe6472c06 100644 --- a/mysql-test/suite/innodb/t/instant_alter_bugs.test +++ b/mysql-test/suite/innodb/t/instant_alter_bugs.test @@ -446,10 +446,6 @@ create table t1 ( col_text_g text generated always as (substr(col_text,1,499)) ) engine innodb row_format = redundant; insert into t1 (col_int,col_text) values (0, 'a'), (null, 'b'); -# FIXME: remove the following to trigger the bug ---disable_query_log -alter table t1 modify column col_text text null, force; ---enable_query_log alter table t1 modify column col_text text null, algorithm = instant; insert into t1 (col_int,col_text) values (1, null), (null, null); update t1 set col_text= 'd'; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 21918fbbe41..fef2d9650c0 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -592,6 +592,7 @@ inline bool dict_table_t::instant_column(const dict_table_t& table, mem_heap_alloc(heap, table.n_v_cols * sizeof(*v_cols))); for (ulint i = table.n_v_cols; i--; ) { new (&v_cols[i]) dict_v_col_t(table.v_cols[i]); + v_cols[i].v_indexes.clear(); } } else { ut_ad(table.n_v_cols == 0); From cc1646dae821a136c8368ee84954aac9937abdd4 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 22 Oct 2020 14:00:17 +0400 Subject: [PATCH 190/323] MDEV-19443 server_audit plugin doesn't log proxy users. PROXY_USER event added. --- .../suite/plugins/r/server_audit.result | 55 ++++++++++++++++ mysql-test/suite/plugins/t/server_audit.test | 21 ++++++- plugin/server_audit/server_audit.c | 62 ++++++++++++++++++- 3 files changed, 136 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/plugins/r/server_audit.result b/mysql-test/suite/plugins/r/server_audit.result index 89f1c69a746..7c287b369b1 100644 --- a/mysql-test/suite/plugins/r/server_audit.result +++ b/mysql-test/suite/plugins/r/server_audit.result @@ -227,6 +227,21 @@ set global server_audit_logging= on; disconnect cn1; drop user user1@localhost; set global server_audit_events=''; +CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest'; +CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd'; +connect(localhost,plug,plug_dest,test,MYSQL_PORT,MYSQL_SOCK); +connect plug_con,localhost,plug,plug_dest; +ERROR 28000: Access denied for user 'plug'@'localhost' (using password: YES) +GRANT PROXY ON plug_dest TO plug; +connect plug_con,localhost,plug,plug_dest; +connection plug_con; +select USER(),CURRENT_USER(); +USER() CURRENT_USER() +plug@localhost plug_dest@% +connection default; +disconnect plug_con; +DROP USER plug; +DROP USER plug_dest; set global server_audit_query_log_limit= 15; select (1), (2), (3), (4); 1 2 3 4 @@ -404,6 +419,46 @@ TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,procs_priv, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,roles_mapping, TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_events=\'\'',0 +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,columns_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,procs_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,roles_mapping, +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'CREATE USER plug IDENTIFIED WITH \'test_plugin_server\' AS \'plug_dest\'',0 +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,columns_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,procs_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,roles_mapping, +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'CREATE USER plug_dest IDENTIFIED BY *****',0 +TIME,HOSTNAME,plug,localhost,ID,0,FAILED_CONNECT,,,ID +TIME,HOSTNAME,plug,localhost,ID,0,DISCONNECT,,,0 +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv, +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'GRANT PROXY ON plug_dest TO plug',0 +TIME,HOSTNAME,plug,localhost,ID,0,PROXY_CONNECT,test,`plug_dest`@`%`,0 +TIME,HOSTNAME,plug,localhost,ID,0,CONNECT,test,,0 +TIME,HOSTNAME,plug,localhost,ID,0,DISCONNECT,test,,0 +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,columns_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,procs_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,roles_mapping, +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'DROP USER plug',0 +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,columns_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,procs_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,roles_mapping, +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'DROP USER plug_dest',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global serv',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'select (1), (2)',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'select \'A\', ',0 diff --git a/mysql-test/suite/plugins/t/server_audit.test b/mysql-test/suite/plugins/t/server_audit.test index 7f1653ee444..397dd554962 100644 --- a/mysql-test/suite/plugins/t/server_audit.test +++ b/mysql-test/suite/plugins/t/server_audit.test @@ -1,4 +1,4 @@ - +--source include/have_plugin_auth.inc --source include/not_embedded.inc if (!$SERVER_AUDIT_SO) { @@ -174,6 +174,25 @@ drop user user1@localhost; set global server_audit_events=''; +CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest'; +CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd'; +--sleep 2 +--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK +--error ER_ACCESS_DENIED_ERROR : this should fail : no grant +connect(plug_con,localhost,plug,plug_dest); +--sleep 2 +GRANT PROXY ON plug_dest TO plug; +--sleep 2 +connect(plug_con,localhost,plug,plug_dest); +connection plug_con; +select USER(),CURRENT_USER(); +connection default; +disconnect plug_con; +--sleep 2 +--sleep 2 +DROP USER plug; +DROP USER plug_dest; + set global server_audit_query_log_limit= 15; select (1), (2), (3), (4); select 'A', 'B', 'C', 'D'; diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index 1061c207a75..a029b426ea1 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -15,7 +15,7 @@ #define PLUGIN_VERSION 0x104 -#define PLUGIN_STR_VERSION "1.4.7" +#define PLUGIN_STR_VERSION "1.4.9" #define _my_thread_var loc_thread_var @@ -328,6 +328,10 @@ struct connection_info char query_buffer[1024]; time_t query_time; int log_always; + char proxy[64]; + int proxy_length; + char proxy_host[64]; + int proxy_host_length; }; #define DEFAULT_FILENAME_LEN 16 @@ -1128,9 +1132,13 @@ static void setup_connection_simple(struct connection_info *ci) ci->ip_length= 0; ci->query_length= 0; ci->header= 0; + ci->proxy_length= 0; } +#define MAX_HOSTNAME 61 +#define USERNAME_LENGTH 384 + static void setup_connection_connect(struct connection_info *cn, const struct mysql_event_connection *event) { @@ -1147,6 +1155,29 @@ static void setup_connection_connect(struct connection_info *cn, get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip), event->ip, event->ip_length); cn->header= 0; + if (event->proxy_user && event->proxy_user[0]) + { + const char *priv_host= event->proxy_user + + sizeof(char[MAX_HOSTNAME+USERNAME_LENGTH+5]); + size_t priv_host_length; + + if (mysql_57_started) + { + priv_host+= sizeof(size_t); + priv_host_length= *(size_t *) (priv_host + MAX_HOSTNAME); + } + else + priv_host_length= strlen(priv_host); + + + get_str_n(cn->proxy, &cn->proxy_length, sizeof(cn->proxy), + event->priv_user, event->priv_user_length); + get_str_n(cn->proxy_host, &cn->proxy_host_length, + sizeof(cn->proxy_host), + priv_host, priv_host_length); + } + else + cn->proxy_length= 0; } @@ -1346,6 +1377,31 @@ static size_t log_header(char *message, size_t message_len, } +static int log_proxy(const struct connection_info *cn, + const struct mysql_event_connection *event) + +{ + time_t ctime; + size_t csize; + char message[1024]; + + (void) time(&ctime); + csize= log_header(message, sizeof(message)-1, &ctime, + servhost, servhost_len, + cn->user, cn->user_length, + cn->host, cn->host_length, + cn->ip, cn->ip_length, + event->thread_id, 0, "PROXY_CONNECT"); + csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize, + ",%.*s,`%.*s`@`%.*s`,%d", cn->db_length, cn->db, + cn->proxy_length, cn->proxy, + cn->proxy_host_length, cn->proxy_host, + event->status); + message[csize]= '\n'; + return write_log(message, csize + 1, 1); +} + + static int log_connection(const struct connection_info *cn, const struct mysql_event_connection *event, const char *type) @@ -2007,9 +2063,13 @@ static void update_connection_info(struct connection_info *cn, { case MYSQL_AUDIT_CONNECTION_CONNECT: setup_connection_connect(cn, event); + if (event->status == 0 && event->proxy_user && event->proxy_user[0]) + log_proxy(cn, event); break; case MYSQL_AUDIT_CONNECTION_CHANGE_USER: *after_action= AA_CHANGE_USER; + if (event->proxy_user && event->proxy_user[0]) + log_proxy(cn, event); break; default:; } From bff82f51ba01d31b4307a94b22a438e3ea1c471c Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Wed, 21 Oct 2020 19:12:54 +0000 Subject: [PATCH 191/323] Fixed compilation issues with debug build and install test issues for Ubuntu Xenial --- storage/columnstore/columnstore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/columnstore/columnstore b/storage/columnstore/columnstore index 0f21cbe5173..86dcaa57d1c 160000 --- a/storage/columnstore/columnstore +++ b/storage/columnstore/columnstore @@ -1 +1 @@ -Subproject commit 0f21cbe517363de2e43a497084a21455a6373d66 +Subproject commit 86dcaa57d1c0284dc8ea1edfaeff9e748afb3963 From 81870e499ff14afacc7e9cabde65a626165f209f Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Mon, 31 Aug 2020 16:36:32 +0200 Subject: [PATCH 192/323] MDEV-21786 mysqldump will forget sequence definition details on --no-data dump - Original patch was contributed by Jani Tolonen https://github.com/an3l/server/commits/bb-10.3-anel-MDEV-21786-dump-sequence which distinguishes data structure (linked list) of sequences from tables. - Added standard sql output to prevent future changes of sequences and disabled locks for sequences. - Added test case for `MDEV-20070: mysqldump won't work correct on sequences` where table column depends on sequence value. - Restore sequence last value in the following way: - Find `next_not_cached_value` and use it to `setval()` - We just need for logical restore, so don't execute `setval()` - `setval()` should be showed also in case of `--no-data` option. Reviewed-by: daniel@mariadb.org --- client/mysqldump.c | 77 +++++++++++- mysql-test/main/mysqldump.result | 118 ++++++++++++++++++ mysql-test/main/mysqldump.test | 83 ++++++++++++ .../suite/sql_sequence/mysqldump.result | 32 +---- 4 files changed, 279 insertions(+), 31 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 13193c5188c..921905d1853 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -39,7 +39,7 @@ ** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov */ -#define DUMP_VERSION "10.17" +#define DUMP_VERSION "10.18" #include #include @@ -83,6 +83,7 @@ #define IGNORE_NONE 0x00 /* no ignore */ #define IGNORE_DATA 0x01 /* don't dump data for this table */ #define IGNORE_INSERT_DELAYED 0x02 /* table doesn't support INSERT DELAYED */ +#define IGNORE_SEQUENCE_TABLE 0x04 /* catch the SEQUENCE*/ /* Chars needed to store LONGLONG, excluding trailing '\0'. */ #define LONGLONG_LEN 20 @@ -2738,7 +2739,68 @@ static inline my_bool general_log_or_slow_log_tables(const char *db, !my_strcasecmp(charset_info, table, "slow_log") || !my_strcasecmp(charset_info, table, "transaction_registry")); } +/* + get_sequence_structure-- retrievs sequence structure, prints out corresponding + CREATE statement + ARGS + seq - sequence name + db - db name +*/ +static void get_sequence_structure(const char *seq, const char *db) +{ + + char table_buff[NAME_LEN*2+3]; + char *result_seq; + FILE *sql_file= md_result_file; + MYSQL_RES *result; + MYSQL_ROW row; + + DBUG_ENTER("get_sequence_structure"); + DBUG_PRINT("enter", ("db: %s sequence: %s", db, seq)); + + verbose_msg("-- Retrieving sequence structure for %s...\n", seq); + + result_seq= quote_name(seq, table_buff, 1); + // Sequences as tables share same flags + if (!opt_no_create_info) + { + char buff[20+FN_REFLEN]; + my_snprintf(buff, sizeof(buff), "SHOW CREATE SEQUENCE %s", result_seq); + if (mysql_query_with_error_report(mysql, &result, buff)) + { + DBUG_VOID_RETURN; + } + + print_comment(sql_file, 0, + "\n--\n-- Sequence structure for %s\n--\n\n", + fix_for_comment(result_seq)); + if (opt_drop) + { + fprintf(sql_file, "DROP SEQUENCE IF EXISTS %s;\n", result_seq); + check_io(sql_file); + } + + row= mysql_fetch_row(result); + fprintf(sql_file, "%s;\n", row[1]); + mysql_free_result(result); + + // Restore next not cached value from sequence + my_snprintf(buff, sizeof(buff), "SELECT next_not_cached_value FROM %s", result_seq); + if (mysql_query_with_error_report(mysql, &result, buff)) + { + DBUG_VOID_RETURN; + } + row= mysql_fetch_row(result); + if (row[0]) + { + fprintf(sql_file, "SELECT SETVAL(%s, %s, 0);\n", result_seq, row[0]); + } + // Sequences will not use inserts, so no need for REPLACE and LOCKS + mysql_free_result(result); + } + DBUG_VOID_RETURN; +} /* get_table_structure -- retrievs database structure, prints out corresponding CREATE statement and fills out insert_pat if the table is the type we will @@ -3720,6 +3782,14 @@ static void dump_table(char *table, char *db, const uchar *hash_key, size_t len) MYSQL_ROW row; DBUG_ENTER("dump_table"); + /* + Check does table has a sequence structure and if has apply different sql queries + */ + if (check_if_ignore_table(table, table_type) & IGNORE_SEQUENCE_TABLE) + { + get_sequence_structure(table, db); + DBUG_VOID_RETURN; + } /* Make sure you get the create table info before the following check for --no-data flag below. Otherwise, the create table info won't be printed. @@ -5688,7 +5758,7 @@ char check_if_ignore_table(const char *table_name, char *table_type) /* Check memory for quote_for_like() */ DBUG_ASSERT(2*sizeof(table_name) < sizeof(show_name_buff)); my_snprintf(buff, sizeof(buff), - "SELECT engine FROM INFORMATION_SCHEMA.TABLES " + "SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES " "WHERE table_schema = DATABASE() AND table_name = %s", quote_for_equal(table_name, show_name_buff)); if (mysql_query_with_error_report(mysql, &res, buff)) @@ -5728,7 +5798,8 @@ char check_if_ignore_table(const char *table_name, char *table_type) strcmp(table_type,"MEMORY")) result= IGNORE_INSERT_DELAYED; } - + if (!strcmp(row[1],"SEQUENCE")) + result|= IGNORE_SEQUENCE_TABLE; /* If these two types, we do want to skip dumping the table */ diff --git a/mysql-test/main/mysqldump.result b/mysql-test/main/mysqldump.result index 5f3f0d89593..622ef745859 100644 --- a/mysql-test/main/mysqldump.result +++ b/mysql-test/main/mysqldump.result @@ -5904,4 +5904,122 @@ invisible int(11) YES NULL a b c & $!@#$%^&*( ) int(11) YES 4 INVISIBLE ds=~!@ \# $% ^ & * ( ) _ - = + int(11) YES 5 INVISIBLE drop database d; +# +# MDEV-21786: +# mysqldump will forget sequence definition details on --no-data dump +# +create database d; +CREATE SEQUENCE d.s1 START WITH 100 INCREMENT BY 10 MINVALUE=100 MAXVALUE=1100 CYCLE; +CREATE SEQUENCE d.s2 START WITH 200 INCREMENT BY 20 MINVALUE=200 MAXVALUE=1200 CYCLE; +CREATE SEQUENCE d.s3 START WITH 300 INCREMENT BY 30 MINVALUE=300 MAXVALUE=1300 CYCLE; +CREATE SEQUENCE d.s4 START WITH 400 INCREMENT BY 40 MINVALUE=400 MAXVALUE=1400 CYCLE; +SELECT NEXTVAL(d.s1),NEXTVAL(d.s2),NEXTVAL(d.s3), NEXTVAL(d.s4); +NEXTVAL(d.s1) NEXTVAL(d.s2) NEXTVAL(d.s3) NEXTVAL(d.s4) +100 200 300 400 +# Show create before dump +show create sequence d.s1; +Table Create Table +s1 CREATE SEQUENCE `s1` start with 100 minvalue 100 maxvalue 1100 increment by 10 cache 1000 cycle ENGINE=MyISAM +show create sequence d.s2; +Table Create Table +s2 CREATE SEQUENCE `s2` start with 200 minvalue 200 maxvalue 1200 increment by 20 cache 1000 cycle ENGINE=MyISAM +show create sequence d.s3; +Table Create Table +s3 CREATE SEQUENCE `s3` start with 300 minvalue 300 maxvalue 1300 increment by 30 cache 1000 cycle ENGINE=MyISAM +show create sequence d.s4; +Table Create Table +s4 CREATE SEQUENCE `s4` start with 400 minvalue 400 maxvalue 1400 increment by 40 cache 1000 cycle ENGINE=MyISAM +# Dump sequence without `--no-data` +# Restore from mysqldump +SETVAL(`s1`, 1101, 0) +1101 +SETVAL(`s2`, 1201, 0) +1201 +SETVAL(`s3`, 1301, 0) +1301 +SETVAL(`s4`, 1401, 0) +1401 +# Show create after restore +show create sequence d.s1; +Table Create Table +s1 CREATE SEQUENCE `s1` start with 100 minvalue 100 maxvalue 1100 increment by 10 cache 1000 cycle ENGINE=MyISAM +show create sequence d.s2; +Table Create Table +s2 CREATE SEQUENCE `s2` start with 200 minvalue 200 maxvalue 1200 increment by 20 cache 1000 cycle ENGINE=MyISAM +show create sequence d.s3; +Table Create Table +s3 CREATE SEQUENCE `s3` start with 300 minvalue 300 maxvalue 1300 increment by 30 cache 1000 cycle ENGINE=MyISAM +show create sequence d.s4; +Table Create Table +s4 CREATE SEQUENCE `s4` start with 400 minvalue 400 maxvalue 1400 increment by 40 cache 1000 cycle ENGINE=MyISAM +SELECT NEXTVAL(d.s1),NEXTVAL(d.s2),NEXTVAL(d.s3), NEXTVAL(d.s4); +NEXTVAL(d.s1) NEXTVAL(d.s2) NEXTVAL(d.s3) NEXTVAL(d.s4) +100 200 300 400 +# Dump sequence with `--no-data` +# Restore from mysqldump +SETVAL(`s1`, 1101, 0) +1101 +SETVAL(`s2`, 1201, 0) +1201 +SETVAL(`s3`, 1301, 0) +1301 +SETVAL(`s4`, 1401, 0) +1401 +# Show create after restore `--no-data` +show create sequence d.s1; +Table Create Table +s1 CREATE SEQUENCE `s1` start with 100 minvalue 100 maxvalue 1100 increment by 10 cache 1000 cycle ENGINE=MyISAM +show create sequence d.s2; +Table Create Table +s2 CREATE SEQUENCE `s2` start with 200 minvalue 200 maxvalue 1200 increment by 20 cache 1000 cycle ENGINE=MyISAM +show create sequence d.s3; +Table Create Table +s3 CREATE SEQUENCE `s3` start with 300 minvalue 300 maxvalue 1300 increment by 30 cache 1000 cycle ENGINE=MyISAM +show create sequence d.s4; +Table Create Table +s4 CREATE SEQUENCE `s4` start with 400 minvalue 400 maxvalue 1400 increment by 40 cache 1000 cycle ENGINE=MyISAM +SELECT NEXTVAL(d.s1),NEXTVAL(d.s2),NEXTVAL(d.s3), NEXTVAL(d.s4); +NEXTVAL(d.s1) NEXTVAL(d.s2) NEXTVAL(d.s3) NEXTVAL(d.s4) +100 200 300 400 +# Restore to different database than original +create database d2; +SETVAL(`s1`, 1101, 0) +1101 +SETVAL(`s2`, 1201, 0) +1201 +SETVAL(`s3`, 1301, 0) +1301 +SETVAL(`s4`, 1401, 0) +1401 +show create sequence d2.s1; +Table Create Table +s1 CREATE SEQUENCE `s1` start with 100 minvalue 100 maxvalue 1100 increment by 10 cache 1000 cycle ENGINE=MyISAM +drop sequence d.s1, d.s2, d.s3, d.s4; +drop database d; +drop database d2; +# +# MDEV-20070 +# mysqldump won't work correct on sequences +# +DROP DATABASE IF EXISTS test1; +Warnings: +Note 1008 Can't drop database 'test1'; database doesn't exist +DROP DATABASE IF EXISTS test2; +Warnings: +Note 1008 Can't drop database 'test2'; database doesn't exist +CREATE DATABASE test1; +CREATE DATABASE test2; +USE test1; +CREATE SEQUENCE seq_t_i INCREMENT 5 START WITH 1; +CREATE TABLE t( +i integer DEFAULT nextval(seq_t_i), +j integer +); +INSERT INTO t VALUES (1,1),(2,2),(3,3),(4,4); +# Dump database 1 +# Restore from database 1 to database 2 +SETVAL(`seq_t_i`, 1, 0) +1 +DROP DATABASE IF EXISTS test1; +DROP DATABASE IF EXISTS test2; # End of 10.3 tests diff --git a/mysql-test/main/mysqldump.test b/mysql-test/main/mysqldump.test index 10dc9bf6d96..662ff077d91 100644 --- a/mysql-test/main/mysqldump.test +++ b/mysql-test/main/mysqldump.test @@ -2793,4 +2793,87 @@ select * from t3; desc t3; drop database d; +--echo # +--echo # MDEV-21786: +--echo # mysqldump will forget sequence definition details on --no-data dump +--echo # +create database d; + +CREATE SEQUENCE d.s1 START WITH 100 INCREMENT BY 10 MINVALUE=100 MAXVALUE=1100 CYCLE; +CREATE SEQUENCE d.s2 START WITH 200 INCREMENT BY 20 MINVALUE=200 MAXVALUE=1200 CYCLE; +CREATE SEQUENCE d.s3 START WITH 300 INCREMENT BY 30 MINVALUE=300 MAXVALUE=1300 CYCLE; +CREATE SEQUENCE d.s4 START WITH 400 INCREMENT BY 40 MINVALUE=400 MAXVALUE=1400 CYCLE; +SELECT NEXTVAL(d.s1),NEXTVAL(d.s2),NEXTVAL(d.s3), NEXTVAL(d.s4); + +--echo # Show create before dump +show create sequence d.s1; +show create sequence d.s2; +show create sequence d.s3; +show create sequence d.s4; + +--echo # Dump sequence without `--no-data` +--exec $MYSQL_DUMP --databases d > $MYSQLTEST_VARDIR/tmp/dump1.sql +--echo # Restore from mysqldump +--exec $MYSQL -Dd < $MYSQLTEST_VARDIR/tmp/dump1.sql +--remove_file $MYSQLTEST_VARDIR/tmp/dump1.sql + +--echo # Show create after restore +show create sequence d.s1; +show create sequence d.s2; +show create sequence d.s3; +show create sequence d.s4; +SELECT NEXTVAL(d.s1),NEXTVAL(d.s2),NEXTVAL(d.s3), NEXTVAL(d.s4); + +--echo # Dump sequence with `--no-data` +--exec $MYSQL_DUMP --databases d --no-data > $MYSQLTEST_VARDIR/tmp/dump-no-data.sql +--echo # Restore from mysqldump +--exec $MYSQL -Dd < $MYSQLTEST_VARDIR/tmp/dump-no-data.sql +--remove_file $MYSQLTEST_VARDIR/tmp/dump-no-data.sql + +--echo # Show create after restore `--no-data` +show create sequence d.s1; +show create sequence d.s2; +show create sequence d.s3; +show create sequence d.s4; +SELECT NEXTVAL(d.s1),NEXTVAL(d.s2),NEXTVAL(d.s3), NEXTVAL(d.s4); + +--echo # Restore to different database than original +--exec $MYSQL_DUMP d > $MYSQLTEST_VARDIR/tmp/dumpd.sql +create database d2; +--exec $MYSQL d2 < $MYSQLTEST_VARDIR/tmp/dumpd.sql +--remove_file $MYSQLTEST_VARDIR/tmp/dumpd.sql +show create sequence d2.s1; + +drop sequence d.s1, d.s2, d.s3, d.s4; +drop database d; +drop database d2; + +--echo # +--echo # MDEV-20070 +--echo # mysqldump won't work correct on sequences +--echo # + +DROP DATABASE IF EXISTS test1; +DROP DATABASE IF EXISTS test2; +CREATE DATABASE test1; +CREATE DATABASE test2; +USE test1; +CREATE SEQUENCE seq_t_i INCREMENT 5 START WITH 1; +CREATE TABLE t( +i integer DEFAULT nextval(seq_t_i), +j integer +); +INSERT INTO t VALUES (1,1),(2,2),(3,3),(4,4); + +--echo # Dump database 1 +--exec $MYSQL_DUMP test1 > $MYSQLTEST_VARDIR/tmp/dumptest1.sql +--echo # Restore from database 1 to database 2 + +--error 1 +--exec $MYSQL test2 < $MYSQLTEST_VARDIR/tmp/dumptest1.sql + +--remove_file $MYSQLTEST_VARDIR/tmp/dumptest1.sql +DROP DATABASE IF EXISTS test1; +DROP DATABASE IF EXISTS test2; + --echo # End of 10.3 tests diff --git a/mysql-test/suite/sql_sequence/mysqldump.result b/mysql-test/suite/sql_sequence/mysqldump.result index 5a3711ebda3..e6aedb57ea6 100644 --- a/mysql-test/suite/sql_sequence/mysqldump.result +++ b/mysql-test/suite/sql_sequence/mysqldump.result @@ -2,20 +2,8 @@ CREATE SEQUENCE a1 engine=aria; CREATE TABLE t1(a INT, KEY (a)) KEY_BLOCK_SIZE=1024; insert into t1 values (1),(2); CREATE SEQUENCE x1 engine=innodb; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `a1` ( - `next_not_cached_value` bigint(21) NOT NULL, - `minimum_value` bigint(21) NOT NULL, - `maximum_value` bigint(21) NOT NULL, - `start_value` bigint(21) NOT NULL COMMENT 'start value when sequences is created or value if RESTART is used', - `increment` bigint(21) NOT NULL COMMENT 'increment value', - `cache_size` bigint(21) unsigned NOT NULL, - `cycle_option` tinyint(1) unsigned NOT NULL COMMENT '0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed', - `cycle_count` bigint(21) NOT NULL COMMENT 'How many cycles have been done' -) ENGINE=Aria SEQUENCE=1; -/*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO `a1` VALUES (1,1,9223372036854775806,1,1,1000,0,0); +CREATE SEQUENCE `a1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=Aria; +SELECT SETVAL(`a1`, 1, 0); /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `t1` ( @@ -24,20 +12,8 @@ CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=1024; /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO `t1` VALUES (1),(2); -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `x1` ( - `next_not_cached_value` bigint(21) NOT NULL, - `minimum_value` bigint(21) NOT NULL, - `maximum_value` bigint(21) NOT NULL, - `start_value` bigint(21) NOT NULL COMMENT 'start value when sequences is created or value if RESTART is used', - `increment` bigint(21) NOT NULL COMMENT 'increment value', - `cache_size` bigint(21) unsigned NOT NULL, - `cycle_option` tinyint(1) unsigned NOT NULL COMMENT '0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed', - `cycle_count` bigint(21) NOT NULL COMMENT 'How many cycles have been done' -) ENGINE=InnoDB SEQUENCE=1; -/*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO `x1` VALUES (1,1,9223372036854775806,1,1,1000,0,0); +CREATE SEQUENCE `x1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=InnoDB; +SELECT SETVAL(`x1`, 1, 0); DROP TABLE a1,t1,x1; set default_storage_engine=InnoDB; create sequence t1; From 985ede92034696d544d484a29b45828d56a031a5 Mon Sep 17 00:00:00 2001 From: Vlad Lesin Date: Tue, 20 Oct 2020 13:05:58 +0300 Subject: [PATCH 193/323] MDEV-20755 InnoDB: Database page corruption on disk or a failed file read of tablespace upon prepare of mariabackup incremental backup The problem: When incremental backup is taken, delta files are created for innodb tables which are marked as new tables during innodb ddl tracking. When such tablespace is tried to be opened during prepare in xb_delta_open_matching_space(), it is "created", i.e. xb_space_create_file() is invoked, instead of opening, even if a tablespace with the same name exists in the base backup directory. xb_space_create_file() writes page 0 header the tablespace. This header does not contain crypt data, as mariabackup does not have any information about crypt data in delta file metadata for tablespaces. After delta file is applied, recovery process is started. As the sequence of recovery for different pages is not defined, there can be the situation when crypt data redo log event is executed after some other page is read for recovery. When some page is read for recovery, it's decrypted using crypt data stored in tablespace header in page 0, if there is no crypt data, the page is not decryped and does not pass corruption test. This causes error for incremental backup --prepare for encrypted tablespaces. The error is not stable because crypt data redo log event updates crypt data on page 0, and recovery for different pages can be executed in undefined order. The fix: When delta file is created, the corresponding write filter copies only the pages which LSN is greater then some incremental LSN. When new file is created during incremental backup, the LSN of all it's pages must be greater then incremental LSN, so there is no need to create delta for such table, we can just copy it completely. The fix is to copy the whole file which was tracked during incremental backup with innodb ddl tracker, and copy it to base directory during --prepare instead of delta applying. There is also DBUG_EXECUTE_IF() in innodb code to avoid writing redo log record for crypt data updating on page 0 to make the test case stable. Note: The issue is not reproducible in 10.5 as optimized DDL's are deprecated in 10.5. But the fix is still useful because it allows to decrease data copy size during backup, as delta file contains some extra info. The test case should be removed for 10.5 as it will always pass. --- extra/mariabackup/xtrabackup.cc | 153 ++++++++++++------ .../mariabackup/ddl_incremental_encrypted.opt | 7 + .../ddl_incremental_encrypted.result | 26 +++ .../ddl_incremental_encrypted.test | 66 ++++++++ storage/innobase/fil/fil0crypt.cc | 2 + 5 files changed, 203 insertions(+), 51 deletions(-) create mode 100644 mysql-test/suite/mariabackup/ddl_incremental_encrypted.opt create mode 100644 mysql-test/suite/mariabackup/ddl_incremental_encrypted.result create mode 100644 mysql-test/suite/mariabackup/ddl_incremental_encrypted.test diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 7cb9d5ac3fe..668a355f0fa 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -2537,17 +2537,24 @@ xb_get_copy_action(const char *dflt) return(action); } -/* TODO: We may tune the behavior (e.g. by fil_aio)*/ -static -my_bool -xtrabackup_copy_datafile(fil_node_t* node, uint thread_n, const char *dest_name=0, ulonglong max_size=ULLONG_MAX) +/** Copy innodb data file to the specified destination. + +@param[in] node file node of a tablespace +@param[in] thread_n thread id, used in the text of diagnostic messages +@param[in] dest_name destination file name +@param[in] write_filter write filter to copy data, can be pass-through filter +for full backup, pages filter for incremental backup, etc. + +@return FALSE on success and TRUE on error */ +static my_bool xtrabackup_copy_datafile(fil_node_t *node, uint thread_n, + const char *dest_name, + const xb_write_filt_t &write_filter) { char dst_name[FN_REFLEN]; ds_file_t *dstfile = NULL; xb_fil_cur_t cursor; xb_fil_cur_result_t res; - xb_write_filt_t *write_filter = NULL; xb_write_filt_ctxt_t write_filt_ctxt; const char *action; xb_read_filt_t *read_filter; @@ -2587,7 +2594,7 @@ xtrabackup_copy_datafile(fil_node_t* node, uint thread_n, const char *dest_name= read_filter = &rf_bitmap; } - res = xb_fil_cur_open(&cursor, read_filter, node, thread_n,max_size); + res = xb_fil_cur_open(&cursor, read_filter, node, thread_n, ULLONG_MAX); if (res == XB_FIL_CUR_SKIP) { goto skip; } else if (res == XB_FIL_CUR_ERROR) { @@ -2598,18 +2605,11 @@ xtrabackup_copy_datafile(fil_node_t* node, uint thread_n, const char *dest_name= sizeof dst_name - 1); dst_name[sizeof dst_name - 1] = '\0'; - /* Setup the page write filter */ - if (xtrabackup_incremental) { - write_filter = &wf_incremental; - } else { - write_filter = &wf_write_through; - } - memset(&write_filt_ctxt, 0, sizeof(xb_write_filt_ctxt_t)); - ut_a(write_filter->process != NULL); + ut_a(write_filter.process != NULL); - if (write_filter->init != NULL && - !write_filter->init(&write_filt_ctxt, dst_name, &cursor)) { + if (write_filter.init != NULL && + !write_filter.init(&write_filt_ctxt, dst_name, &cursor)) { msg (thread_n, "mariabackup: error: failed to initialize page write filter."); goto error; } @@ -2630,7 +2630,7 @@ xtrabackup_copy_datafile(fil_node_t* node, uint thread_n, const char *dest_name= /* The main copy loop */ while ((res = xb_fil_cur_read(&cursor)) == XB_FIL_CUR_SUCCESS) { - if (!write_filter->process(&write_filt_ctxt, dstfile)) { + if (!write_filter.process(&write_filt_ctxt, dstfile)) { goto error; } } @@ -2639,8 +2639,8 @@ xtrabackup_copy_datafile(fil_node_t* node, uint thread_n, const char *dest_name= goto error; } - if (write_filter->finalize - && !write_filter->finalize(&write_filt_ctxt, dstfile)) { + if (write_filter.finalize + && !write_filter.finalize(&write_filt_ctxt, dstfile)) { goto error; } @@ -2654,8 +2654,8 @@ xtrabackup_copy_datafile(fil_node_t* node, uint thread_n, const char *dest_name= if (ds_close(dstfile)) { rc = TRUE; } - if (write_filter && write_filter->deinit) { - write_filter->deinit(&write_filt_ctxt); + if (write_filter.deinit) { + write_filter.deinit(&write_filt_ctxt); } return(rc); @@ -2664,8 +2664,8 @@ error: if (dstfile != NULL) { ds_close(dstfile); } - if (write_filter && write_filter->deinit) { - write_filter->deinit(&write_filt_ctxt);; + if (write_filter.deinit) { + write_filter.deinit(&write_filt_ctxt);; } msg(thread_n, "mariabackup: xtrabackup_copy_datafile() failed."); return(TRUE); /*ERROR*/ @@ -2675,8 +2675,8 @@ skip: if (dstfile != NULL) { ds_close(dstfile); } - if (write_filter && write_filter->deinit) { - write_filter->deinit(&write_filt_ctxt); + if (write_filter.deinit) { + write_filter.deinit(&write_filt_ctxt); } msg(thread_n,"Warning: We assume the table was dropped during xtrabackup execution and ignore the tablespace %s", node_name); return(FALSE); @@ -2974,9 +2974,9 @@ data_copy_thread_func( while ((node = datafiles_iter_next(ctxt->it)) != NULL) { DBUG_MARIABACKUP_EVENT("before_copy", node->space->name); /* copy the datafile */ - if(xtrabackup_copy_datafile(node, num)) { + if (xtrabackup_copy_datafile(node, num, NULL, + xtrabackup_incremental ? wf_incremental : wf_write_through)) die("failed to copy datafile."); - } DBUG_MARIABACKUP_EVENT("after_copy", node->space->name); @@ -4620,7 +4620,7 @@ void backup_fix_ddl(void) continue; std::string dest_name(node->space->name); dest_name.append(".new"); - xtrabackup_copy_datafile(node, 0, dest_name.c_str()/*, do_full_copy ? ULONGLONG_MAX:UNIV_PAGE_SIZE */); + xtrabackup_copy_datafile(node, 0, dest_name.c_str(), wf_write_through); } datafiles_iter_free(it); @@ -5176,22 +5176,66 @@ static void rename_force(const char *from, const char *to) { rename_file(from,to); } -/* During prepare phase, rename ".new" files , that were created in backup_fix_ddl(), - to ".ibd".*/ -static ibool prepare_handle_new_files( - const char* data_home_dir, /*!(arg); std::string src_path = std::string(data_home_dir) + '/' + std::string(db_name) + '/' + file_name; - std::string dest_path = src_path; + /* Copy "*.new" files from incremental to base dir for incremental backup */ + std::string dest_path= + dest_dir ? std::string(dest_dir) + '/' + std::string(db_name) + + '/' + file_name : src_path; size_t index = dest_path.find(".new"); DBUG_ASSERT(index != std::string::npos); - dest_path.replace(index, 4, ".ibd"); + dest_path.replace(index, strlen(".ibd"), ".ibd"); rename_force(src_path.c_str(),dest_path.c_str()); + + if (dest_dir) { + /* remove delta and meta files to avoid delta applying for new file */ + index = src_path.find(".new"); + DBUG_ASSERT(index != std::string::npos); + src_path.replace(index, std::string::npos, ".ibd.delta"); + if (access(src_path.c_str(), R_OK) == 0) { + msg("Removing %s", src_path.c_str()); + if (my_delete(src_path.c_str(), MYF(MY_WME))) + die("Can't remove %s, errno %d", src_path.c_str(), errno); + } + src_path.replace(index, std::string::npos, ".ibd.meta"); + if (access(src_path.c_str(), R_OK) == 0) { + msg("Removing %s", src_path.c_str()); + if (my_delete(src_path.c_str(), MYF(MY_WME))) + die("Can't remove %s, errno %d", src_path.c_str(), errno); + } + + /* add table name to the container to avoid it's deletion at the end of + prepare */ + std::string table_name = std::string(db_name) + '/' + + std::string(file_name, file_name + strlen(file_name) - strlen(".new")); + xb_filter_entry_t *table = static_cast + (malloc(sizeof(xb_filter_entry_t) + table_name.size() + 1)); + table->name = ((char*)table) + sizeof(xb_filter_entry_t); + strcpy(table->name, table_name.c_str()); + HASH_INSERT(xb_filter_entry_t, name_hash, inc_dir_tables_hash, + ut_fold_string(table->name), table); + } + return TRUE; } @@ -5228,17 +5272,18 @@ rm_if_not_found( return(TRUE); } -/************************************************************************ -Function enumerates files in datadir (provided by path) which are matched +/** Function enumerates files in datadir (provided by path) which are matched by provided suffix. For each entry callback is called. + +@param[in] path datadir path +@param[in] suffix suffix to match against +@param[in] func callback +@param[in] func_arg arguments for the above callback + @return FALSE if callback for some entry returned FALSE */ -static -ibool -xb_process_datadir( - const char* path, /*! Date: Fri, 18 Sep 2020 15:34:24 +0200 Subject: [PATCH 194/323] MDEV-21954 mysqld got signal 11 Fatal signal 6 while backtracing on parallel show global status protect global toku_global_status_rows with a mutex --- storage/tokudb/hatoku_hton.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/storage/tokudb/hatoku_hton.cc b/storage/tokudb/hatoku_hton.cc index 81355ea20ff..6002a3efd88 100644 --- a/storage/tokudb/hatoku_hton.cc +++ b/storage/tokudb/hatoku_hton.cc @@ -26,6 +26,7 @@ Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. #include "hatoku_hton.h" #include "PerconaFT/src/ydb.h" +#include #define TOKU_METADB_NAME "tokudb_meta" @@ -239,6 +240,7 @@ tokudb::thread::rwlock_t tokudb_hton_initialized_lock; static SHOW_VAR *toku_global_status_variables = NULL; static uint64_t toku_global_status_max_rows; static TOKU_ENGINE_STATUS_ROW_S* toku_global_status_rows = NULL; +static std::mutex toku_global_status_rows_mutex; static void handle_ydb_error(int error) { switch (error) { @@ -1902,6 +1904,7 @@ static int show_tokudb_vars(TOKUDB_UNUSED(THD* thd), const int panic_string_len = 1024; char panic_string[panic_string_len] = {'\0'}; fs_redzone_state redzone_state; + const std::lock_guard lock(toku_global_status_rows_mutex); uint64_t num_rows; error = db_env->get_engine_status( From 94b493571a8ba8f30c97a5c30fc641171ca48e8a Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 23 Oct 2020 12:20:17 +0400 Subject: [PATCH 195/323] MDEV-20744 SET GLOBAL `replicate_do_db` = DEFAULT causes crash. DEFAULT for the replicate_do_db is the "" as our documentation states. --- mysql-test/suite/sys_vars/r/replicate_do_db_basic.result | 4 ++++ mysql-test/suite/sys_vars/t/replicate_do_db_basic.test | 3 +++ sql/sys_vars.ic | 6 +++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/sys_vars/r/replicate_do_db_basic.result b/mysql-test/suite/sys_vars/r/replicate_do_db_basic.result index a05b85a9bfd..54adf835962 100644 --- a/mysql-test/suite/sys_vars/r/replicate_do_db_basic.result +++ b/mysql-test/suite/sys_vars/r/replicate_do_db_basic.result @@ -37,5 +37,9 @@ SET @@GLOBAL.replicate_do_db=null; SELECT @@GLOBAL.replicate_do_db; @@GLOBAL.replicate_do_db +SET @@GLOBAL.replicate_do_db=DEFAULT; +SELECT @@GLOBAL.replicate_do_db; +@@GLOBAL.replicate_do_db + # Cleanup. SET @@GLOBAL.replicate_do_db = @save_replicate_do_db; diff --git a/mysql-test/suite/sys_vars/t/replicate_do_db_basic.test b/mysql-test/suite/sys_vars/t/replicate_do_db_basic.test index 59d0176add2..b7004d1938b 100644 --- a/mysql-test/suite/sys_vars/t/replicate_do_db_basic.test +++ b/mysql-test/suite/sys_vars/t/replicate_do_db_basic.test @@ -38,5 +38,8 @@ SELECT @@GLOBAL.replicate_do_db; SET @@GLOBAL.replicate_do_db=null; SELECT @@GLOBAL.replicate_do_db; +SET @@GLOBAL.replicate_do_db=DEFAULT; +SELECT @@GLOBAL.replicate_do_db; + --echo # Cleanup. SET @@GLOBAL.replicate_do_db = @save_replicate_do_db; diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index ae4568866b7..737f9bb545c 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -614,7 +614,11 @@ public: { DBUG_ASSERT(FALSE); } void global_save_default(THD *thd, set_var *var) - { DBUG_ASSERT(FALSE); } + { + char *ptr= (char*)(intptr)option.def_value; + var->save_result.string_value.str= ptr; + var->save_result.string_value.length= ptr ? strlen(ptr) : 0; + } bool session_update(THD *thd, set_var *var) { From 5a9484b78438775f431601a1fc2b302e01e35882 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 22 Oct 2020 14:00:17 +0400 Subject: [PATCH 196/323] MDEV-19443 server_audit plugin doesn't log proxy users. PROXY_USER event added. Conflicts: plugin/server_audit/server_audit.c --- .../suite/plugins/r/server_audit.result | 55 ++++++++++++++++ mysql-test/suite/plugins/t/server_audit.test | 21 ++++++- plugin/server_audit/server_audit.c | 62 ++++++++++++++++++- 3 files changed, 136 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/plugins/r/server_audit.result b/mysql-test/suite/plugins/r/server_audit.result index 89f1c69a746..7c287b369b1 100644 --- a/mysql-test/suite/plugins/r/server_audit.result +++ b/mysql-test/suite/plugins/r/server_audit.result @@ -227,6 +227,21 @@ set global server_audit_logging= on; disconnect cn1; drop user user1@localhost; set global server_audit_events=''; +CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest'; +CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd'; +connect(localhost,plug,plug_dest,test,MYSQL_PORT,MYSQL_SOCK); +connect plug_con,localhost,plug,plug_dest; +ERROR 28000: Access denied for user 'plug'@'localhost' (using password: YES) +GRANT PROXY ON plug_dest TO plug; +connect plug_con,localhost,plug,plug_dest; +connection plug_con; +select USER(),CURRENT_USER(); +USER() CURRENT_USER() +plug@localhost plug_dest@% +connection default; +disconnect plug_con; +DROP USER plug; +DROP USER plug_dest; set global server_audit_query_log_limit= 15; select (1), (2), (3), (4); 1 2 3 4 @@ -404,6 +419,46 @@ TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,procs_priv, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,roles_mapping, TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_events=\'\'',0 +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,columns_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,procs_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,roles_mapping, +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'CREATE USER plug IDENTIFIED WITH \'test_plugin_server\' AS \'plug_dest\'',0 +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,columns_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,procs_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,roles_mapping, +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'CREATE USER plug_dest IDENTIFIED BY *****',0 +TIME,HOSTNAME,plug,localhost,ID,0,FAILED_CONNECT,,,ID +TIME,HOSTNAME,plug,localhost,ID,0,DISCONNECT,,,0 +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv, +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'GRANT PROXY ON plug_dest TO plug',0 +TIME,HOSTNAME,plug,localhost,ID,0,PROXY_CONNECT,test,`plug_dest`@`%`,0 +TIME,HOSTNAME,plug,localhost,ID,0,CONNECT,test,,0 +TIME,HOSTNAME,plug,localhost,ID,0,DISCONNECT,test,,0 +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,columns_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,procs_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,roles_mapping, +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'DROP USER plug',0 +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,columns_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,procs_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv, +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,roles_mapping, +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'DROP USER plug_dest',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global serv',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'select (1), (2)',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'select \'A\', ',0 diff --git a/mysql-test/suite/plugins/t/server_audit.test b/mysql-test/suite/plugins/t/server_audit.test index 7f1653ee444..397dd554962 100644 --- a/mysql-test/suite/plugins/t/server_audit.test +++ b/mysql-test/suite/plugins/t/server_audit.test @@ -1,4 +1,4 @@ - +--source include/have_plugin_auth.inc --source include/not_embedded.inc if (!$SERVER_AUDIT_SO) { @@ -174,6 +174,25 @@ drop user user1@localhost; set global server_audit_events=''; +CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest'; +CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd'; +--sleep 2 +--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK +--error ER_ACCESS_DENIED_ERROR : this should fail : no grant +connect(plug_con,localhost,plug,plug_dest); +--sleep 2 +GRANT PROXY ON plug_dest TO plug; +--sleep 2 +connect(plug_con,localhost,plug,plug_dest); +connection plug_con; +select USER(),CURRENT_USER(); +connection default; +disconnect plug_con; +--sleep 2 +--sleep 2 +DROP USER plug; +DROP USER plug_dest; + set global server_audit_query_log_limit= 15; select (1), (2), (3), (4); select 'A', 'B', 'C', 'D'; diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index 4e45b36ec3e..6badbbfedf7 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -15,7 +15,7 @@ #define PLUGIN_VERSION 0x104 -#define PLUGIN_STR_VERSION "1.4.8" +#define PLUGIN_STR_VERSION "1.4.10" #define _my_thread_var loc_thread_var @@ -326,6 +326,10 @@ struct connection_info char query_buffer[1024]; time_t query_time; int log_always; + char proxy[64]; + int proxy_length; + char proxy_host[64]; + int proxy_host_length; }; #define DEFAULT_FILENAME_LEN 16 @@ -1130,9 +1134,13 @@ static void setup_connection_simple(struct connection_info *ci) ci->ip_length= 0; ci->query_length= 0; ci->header= 0; + ci->proxy_length= 0; } +#define MAX_HOSTNAME 61 +#define USERNAME_LENGTH 384 + static void setup_connection_connect(struct connection_info *cn, const struct mysql_event_connection *event) { @@ -1149,6 +1157,29 @@ static void setup_connection_connect(struct connection_info *cn, get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip), event->ip, event->ip_length); cn->header= 0; + if (event->proxy_user && event->proxy_user[0]) + { + const char *priv_host= event->proxy_user + + sizeof(char[MAX_HOSTNAME+USERNAME_LENGTH+5]); + size_t priv_host_length; + + if (mysql_57_started) + { + priv_host+= sizeof(size_t); + priv_host_length= *(size_t *) (priv_host + MAX_HOSTNAME); + } + else + priv_host_length= strlen(priv_host); + + + get_str_n(cn->proxy, &cn->proxy_length, sizeof(cn->proxy), + event->priv_user, event->priv_user_length); + get_str_n(cn->proxy_host, &cn->proxy_host_length, + sizeof(cn->proxy_host), + priv_host, priv_host_length); + } + else + cn->proxy_length= 0; } @@ -1348,6 +1379,31 @@ static size_t log_header(char *message, size_t message_len, } +static int log_proxy(const struct connection_info *cn, + const struct mysql_event_connection *event) + +{ + time_t ctime; + size_t csize; + char message[1024]; + + (void) time(&ctime); + csize= log_header(message, sizeof(message)-1, &ctime, + servhost, servhost_len, + cn->user, cn->user_length, + cn->host, cn->host_length, + cn->ip, cn->ip_length, + event->thread_id, 0, "PROXY_CONNECT"); + csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize, + ",%.*s,`%.*s`@`%.*s`,%d", cn->db_length, cn->db, + cn->proxy_length, cn->proxy, + cn->proxy_host_length, cn->proxy_host, + event->status); + message[csize]= '\n'; + return write_log(message, csize + 1, 1); +} + + static int log_connection(const struct connection_info *cn, const struct mysql_event_connection *event, const char *type) @@ -2009,9 +2065,13 @@ static void update_connection_info(struct connection_info *cn, { case MYSQL_AUDIT_CONNECTION_CONNECT: setup_connection_connect(cn, event); + if (event->status == 0 && event->proxy_user && event->proxy_user[0]) + log_proxy(cn, event); break; case MYSQL_AUDIT_CONNECTION_CHANGE_USER: *after_action= AA_CHANGE_USER; + if (event->proxy_user && event->proxy_user[0]) + log_proxy(cn, event); break; default:; } From 6dc14453c5b72920575116ec3c836c1647f05873 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Fri, 23 Oct 2020 17:18:39 +0700 Subject: [PATCH 197/323] MDEV-23926: Fix warnings generated during compilation of plugin/auth_pam/mapper/pam_user_map.c on MacOS Compiler warnings like one listed below are generated during server build on MacOS: [88%] Building C object plugin/auth_pam/CMakeFiles/pam_user_map.dir/mapper/pam_user_map.c.o mariadb/server-10.2/plugin/auth_pam/mapper/pam_user_map.c:87:41: error: passing 'gid_t *' (aka 'unsigned int *') to parameter of type 'int *' converts between pointers to integer types with different sign [-Werror,-Wpointer-sign] if (getgrouplist(user, user_group_id, loc_groups, &ng) < 0) ^~~~~~~~~~ /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/usr/include/unistd.h:650:43: note: passing argument to parameter here int getgrouplist(const char *, int, int *, int *); ^ In case MariaDB server is build with -DCMAKE_BUILD_TYPE=Debug it results in build error. The reason of compiler warnings is that declaration of the Posix C API function getgrouplist() on MacOS differs from declaration of getgrouplist() proposed by Posix. To suppress this compiler warning cmake configure was adapted to detect what kind of getgrouplist() function is declared on the build platform and set the macros HAVE_POSIX_GETGROUPLIST in case the building platform supports Posix compatible interface for the getgrouplist() function. Depending on whether this macros is set the compatible type of arguments is used to pass parameter values to the function. --- plugin/auth_pam/CMakeLists.txt | 26 +++++++++++++++++++++++ plugin/auth_pam/mapper/pam_user_map.c | 30 +++++++++++++++++---------- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/plugin/auth_pam/CMakeLists.txt b/plugin/auth_pam/CMakeLists.txt index ac598e4ffa6..fce9b8cf8a6 100644 --- a/plugin/auth_pam/CMakeLists.txt +++ b/plugin/auth_pam/CMakeLists.txt @@ -5,6 +5,30 @@ CHECK_INCLUDE_FILES (security/pam_ext.h HAVE_PAM_EXT_H) CHECK_INCLUDE_FILES (security/pam_appl.h HAVE_PAM_APPL_H) CHECK_FUNCTION_EXISTS (strndup HAVE_STRNDUP) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) + +# Check whether getgrouplist uses git_t for second and third arguments. +SET(CMAKE_REQUIRED_FLAGS -Werror) +CHECK_C_SOURCE_COMPILES( +" +#ifdef HAVE_GRP_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +int main() { + char *arg_1; + gid_t arg_2, arg_3; + int arg_4; + (void)getgrouplist(arg_1,arg_2,&arg_3,arg_4); + return 0; +} +" +HAVE_POSIX_GETGROUPLIST +) +SET(CMAKE_REQUIRED_FLAGS) + SET(CMAKE_REQUIRED_LIBRARIES pam) CHECK_FUNCTION_EXISTS(pam_syslog HAVE_PAM_SYSLOG) SET(CMAKE_REQUIRED_LIBRARIES) @@ -36,3 +60,5 @@ IF(HAVE_PAM_APPL_H) ENDIF() ENDIF(HAVE_PAM_APPL_H) +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/config_auth_pam.h) diff --git a/plugin/auth_pam/mapper/pam_user_map.c b/plugin/auth_pam/mapper/pam_user_map.c index 9d7ed53f8b1..fa8d9ae08c1 100644 --- a/plugin/auth_pam/mapper/pam_user_map.c +++ b/plugin/auth_pam/mapper/pam_user_map.c @@ -31,6 +31,7 @@ These comments are written to the syslog as 'authpriv.debug' and usually end up in /var/log/secure file. */ +#include #include #include #include @@ -70,10 +71,16 @@ pam_syslog (const pam_handle_t *pamh, int priority, #define GROUP_BUFFER_SIZE 100 static const char debug_keyword[]= "debug"; -static int populate_user_groups(const char *user, gid_t **groups) +#ifdef HAVE_POSIX_GETGROUPLIST +typedef gid_t my_gid_t; +#else +typedef int my_gid_t; +#endif + +static int populate_user_groups(const char *user, my_gid_t **groups) { - gid_t user_group_id; - gid_t *loc_groups= *groups; + my_gid_t user_group_id; + my_gid_t *loc_groups= *groups; int ng; { @@ -88,22 +95,23 @@ static int populate_user_groups(const char *user, gid_t **groups) { /* The rare case when the user is present in more than */ /* GROUP_BUFFER_SIZE groups. */ - loc_groups= (gid_t *) malloc(ng * sizeof (gid_t)); + loc_groups= (my_gid_t *) malloc(ng * sizeof (my_gid_t)); + if (!loc_groups) return 0; (void) getgrouplist(user, user_group_id, loc_groups, &ng); - *groups= loc_groups; + *groups= (my_gid_t*)loc_groups; } return ng; } -static int user_in_group(const gid_t *user_groups, int ng,const char *group) +static int user_in_group(const my_gid_t *user_groups, int ng,const char *group) { - gid_t group_id; - const gid_t *groups_end = user_groups + ng; + my_gid_t group_id; + const my_gid_t *groups_end = user_groups + ng; { struct group *g= getgrnam(group); @@ -122,7 +130,7 @@ static int user_in_group(const gid_t *user_groups, int ng,const char *group) } -static void print_groups(pam_handle_t *pamh, const gid_t *user_groups, int ng) +static void print_groups(pam_handle_t *pamh, const my_gid_t *user_groups, int ng) { char buf[256]; char *c_buf= buf, *buf_end= buf+sizeof(buf)-2; @@ -158,8 +166,8 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, const char *username; char buf[256]; FILE *f; - gid_t group_buffer[GROUP_BUFFER_SIZE]; - gid_t *groups= group_buffer; + my_gid_t group_buffer[GROUP_BUFFER_SIZE]; + my_gid_t *groups= group_buffer; int n_groups= -1; for (; argc > 0; argc--) From 5e7cde41e028eee19d7844c320415057afabaaac Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Fri, 23 Oct 2020 17:21:10 +0700 Subject: [PATCH 198/323] MDEV-23926: Follow-up patch to cleanup plugin/auth_pam/CMakeLists.txt code This patch moves definitions of macros variables HAVE_PAM_SYSLOG, HAVE_PAM_EXT_H, HAVE_PAM_APPL_H, HAVE_STRNDUP from command line (in the form -Dmacros) to the auto-generated header file config_auth_pam.h --- plugin/auth_pam/CMakeLists.txt | 12 ------------ plugin/auth_pam/auth_pam.c | 1 + 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/plugin/auth_pam/CMakeLists.txt b/plugin/auth_pam/CMakeLists.txt index fce9b8cf8a6..d3b3c256527 100644 --- a/plugin/auth_pam/CMakeLists.txt +++ b/plugin/auth_pam/CMakeLists.txt @@ -33,19 +33,7 @@ SET(CMAKE_REQUIRED_LIBRARIES pam) CHECK_FUNCTION_EXISTS(pam_syslog HAVE_PAM_SYSLOG) SET(CMAKE_REQUIRED_LIBRARIES) -IF(HAVE_PAM_SYSLOG) - ADD_DEFINITIONS(-DHAVE_PAM_SYSLOG) -ENDIF() - -IF(HAVE_PAM_EXT_H) - ADD_DEFINITIONS(-DHAVE_PAM_EXT_H) -ENDIF() - IF(HAVE_PAM_APPL_H) - ADD_DEFINITIONS(-DHAVE_PAM_APPL_H) - IF(HAVE_STRNDUP) - ADD_DEFINITIONS(-DHAVE_STRNDUP) - ENDIF(HAVE_STRNDUP) FIND_LIBRARY(PAM_LIBRARY pam) # for srpm build-depends detection MYSQL_ADD_PLUGIN(auth_pam auth_pam.c LINK_LIBRARIES pam MODULE_ONLY) diff --git a/plugin/auth_pam/auth_pam.c b/plugin/auth_pam/auth_pam.c index fae73aea690..c80ec51b48d 100644 --- a/plugin/auth_pam/auth_pam.c +++ b/plugin/auth_pam/auth_pam.c @@ -16,6 +16,7 @@ #define _GNU_SOURCE 1 /* for strndup */ +#include #include #include #include From 1a70c2c73a7c461cc2492db7f13c9d575330a2f4 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Fri, 23 Oct 2020 18:10:16 +0700 Subject: [PATCH 199/323] MDEV-23926: Follow-up patch to add missed file plugin/auth_pam/config.h.cmake --- plugin/auth_pam/config.h.cmake | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 plugin/auth_pam/config.h.cmake diff --git a/plugin/auth_pam/config.h.cmake b/plugin/auth_pam/config.h.cmake new file mode 100644 index 00000000000..2a60e99d52c --- /dev/null +++ b/plugin/auth_pam/config.h.cmake @@ -0,0 +1,5 @@ +#cmakedefine HAVE_POSIX_GETGROUPLIST 1 +#cmakedefine HAVE_PAM_SYSLOG 1 +#cmakedefine HAVE_PAM_EXT_H 1 +#cmakedefine HAVE_PAM_APPL_H 1 +#cmakedefine HAVE_STRNDUP 1 From 641f81baf45212569ec8a98072d62fd29e3fc8f0 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 1 Aug 2020 13:19:59 +0200 Subject: [PATCH 200/323] cleanup: use my_multi_malloc(), etc --- sql/sql_parse.cc | 2 +- sql/sql_select.cc | 18 ++++++------------ sql/sql_show.cc | 29 ++++++++++++----------------- storage/heap/ha_heap.cc | 25 ++++++++++--------------- 4 files changed, 29 insertions(+), 45 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8408771692d..88e6d01304f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7728,7 +7728,6 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, bool is_com_multi, bool is_next_command) { - int error __attribute__((unused)); DBUG_ENTER("mysql_parse"); DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on();); @@ -7808,6 +7807,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, (char *) thd->security_ctx->host_or_ip, 0); + int error __attribute__((unused)); error= mysql_execute_command(thd); MYSQL_QUERY_EXEC_DONE(error); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 738e1912994..461c7b18363 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -17490,8 +17490,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List &fields, No need to change table name to lower case as we are only creating MyISAM, Aria or HEAP tables here */ - fn_format(path, path, mysql_tmpdir, "", - MY_REPLACE_EXT|MY_UNPACK_FILENAME); + fn_format(path, path, mysql_tmpdir, "", MY_REPLACE_EXT|MY_UNPACK_FILENAME); if (group) { @@ -18673,14 +18672,10 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, } } - if (unlikely((error= maria_create(share->path.str, - file_type, - share->keys, &keydef, - (uint) (*recinfo-start_recinfo), - start_recinfo, - share->uniques, &uniquedef, - &create_info, - create_flags)))) + if (unlikely((error= maria_create(share->path.str, file_type, share->keys, + &keydef, (uint) (*recinfo-start_recinfo), + start_recinfo, share->uniques, &uniquedef, + &create_info, create_flags)))) { table->file->print_error(error,MYF(0)); /* purecov: inspected */ table->db_stat=0; @@ -18881,8 +18876,7 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table, if (is_duplicate) *is_duplicate= FALSE; - if (table->s->db_type() != heap_hton || - error != HA_ERR_RECORD_FILE_FULL) + if (table->s->db_type() != heap_hton || error != HA_ERR_RECORD_FILE_FULL) { /* We don't want this error to be converted to a warning, e.g. in case of diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0fe8b707472..2a569204908 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -8165,7 +8165,7 @@ mark_all_fields_used_in_query(THD *thd, 0schema_table= 1; SELECT_LEX *select_lex= thd->lex->current_select; bool keep_row_order= is_show_command(thd); - if (!(table= create_tmp_table(thd, tmp_table_param, - field_list, (ORDER*) 0, 0, 0, - (select_lex->options | thd->variables.option_bits | - TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR, - &table_list->alias, false, keep_row_order))) + if (!(table= create_tmp_table(thd, tmp_table_param, field_list, (ORDER*) 0, 0, + 0, (select_lex->options | thd->variables.option_bits | + TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR, + &table_list->alias, false, keep_row_order))) DBUG_RETURN(0); my_bitmap_map* bitmaps= (my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count)); @@ -8794,10 +8793,10 @@ bool optimize_schema_tables_reads(JOIN *join) cond= tab->cache_select->cond; } if (optimize_for_get_all_tables(thd, table_list, cond)) - DBUG_RETURN(TRUE); // Handle OOM + DBUG_RETURN(1); // Handle OOM } } - DBUG_RETURN(FALSE); + DBUG_RETURN(0); } @@ -8862,13 +8861,10 @@ bool get_schema_tables_result(JOIN *join, continue; /* - If schema table is already processed and - the statement is not a subselect then - we don't need to fill this table again. - If schema table is already processed and - schema_table_state != executed_place then - table is already processed and - we should skip second data processing. + If schema table is already processed and the statement is not a + subselect then we don't need to fill this table again. If schema table + is already processed and schema_table_state != executed_place then + table is already processed and we should skip second data processing. */ if (table_list->schema_table_state && (!is_subselect || table_list->schema_table_state != executed_place)) @@ -8930,8 +8926,7 @@ bool get_schema_tables_result(JOIN *join, It also means that an audit plugin cannot process the error correctly either. See also thd->clear_error() */ - thd->get_stmt_da()->push_warning(thd, - thd->get_stmt_da()->sql_errno(), + thd->get_stmt_da()->push_warning(thd, thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->get_sqlstate(), Sql_condition::WARN_LEVEL_ERROR, thd->get_stmt_da()->message()); diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc index 2ffe2da06b2..396887df1b1 100644 --- a/storage/heap/ha_heap.cc +++ b/storage/heap/ha_heap.cc @@ -26,12 +26,8 @@ #include "ha_heap.h" #include "sql_base.h" // enum_tdc_remove_table_type -static handler *heap_create_handler(handlerton *hton, - TABLE_SHARE *table, - MEM_ROOT *mem_root); -static int -heap_prepare_hp_create_info(TABLE *table_arg, bool internal_table, - HP_CREATE_INFO *hp_create_info); +static handler *heap_create_handler(handlerton *, TABLE_SHARE *, MEM_ROOT *); +static int heap_prepare_hp_create_info(TABLE *, bool, HP_CREATE_INFO *); int heap_panic(handlerton *hton, ha_panic_function flag) @@ -603,16 +599,15 @@ ha_rows ha_heap::records_in_range(uint inx, key_range *min_key, } -static int -heap_prepare_hp_create_info(TABLE *table_arg, bool internal_table, - HP_CREATE_INFO *hp_create_info) +static int heap_prepare_hp_create_info(TABLE *table_arg, bool internal_table, + HP_CREATE_INFO *hp_create_info) { - uint key, parts, mem_per_row= 0, keys= table_arg->s->keys; + TABLE_SHARE *share= table_arg->s; + uint key, parts, mem_per_row= 0, keys= share->keys; uint auto_key= 0, auto_key_type= 0; ha_rows max_rows; HP_KEYDEF *keydef; HA_KEYSEG *seg; - TABLE_SHARE *share= table_arg->s; bool found_real_auto_increment= 0; bzero(hp_create_info, sizeof(*hp_create_info)); @@ -620,11 +615,11 @@ heap_prepare_hp_create_info(TABLE *table_arg, bool internal_table, for (key= parts= 0; key < keys; key++) parts+= table_arg->key_info[key].user_defined_key_parts; - if (!(keydef= (HP_KEYDEF*) my_malloc(keys * sizeof(HP_KEYDEF) + - parts * sizeof(HA_KEYSEG), - MYF(MY_WME | MY_THREAD_SPECIFIC)))) + if (!my_multi_malloc(MYF(MY_WME | MY_THREAD_SPECIFIC), + &keydef, keys * sizeof(HP_KEYDEF), + &seg, parts * sizeof(HA_KEYSEG), + NULL)) return my_errno; - seg= reinterpret_cast(keydef + keys); for (key= 0; key < keys; key++) { KEY *pos= table_arg->key_info+key; From 6cefe7d31ef43cadb905d71be743462825c7b4ff Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 2 Aug 2020 10:30:46 +0200 Subject: [PATCH 201/323] cleanup: use predefined CMAKE_DL_LIBS instead of, say, MY_SEARCH_LIBS(dlopen dl LIBDL) --- cmake/jemalloc.cmake | 2 +- cmake/ssl.cmake | 2 +- configure.cmake | 3 +-- libmysqld/CMakeLists.txt | 2 +- mysql-test/lib/My/SafeProcess/CMakeLists.txt | 2 +- mysys/CMakeLists.txt | 2 +- sql/CMakeLists.txt | 2 +- storage/mroonga/vendor/groonga/CMakeLists.txt | 1 - storage/mroonga/vendor/groonga/lib/CMakeLists.txt | 2 +- storage/rocksdb/build_rocksdb.cmake | 2 +- wsrep/CMakeLists.txt | 2 +- 11 files changed, 10 insertions(+), 12 deletions(-) diff --git a/cmake/jemalloc.cmake b/cmake/jemalloc.cmake index 5ad636d0e6c..b94a880cf05 100644 --- a/cmake/jemalloc.cmake +++ b/cmake/jemalloc.cmake @@ -17,7 +17,7 @@ MACRO (CHECK_JEMALLOC) IF(WITH_JEMALLOC STREQUAL "static") SET(libname jemalloc_pic) - SET(CMAKE_REQUIRED_LIBRARIES pthread dl m) + SET(CMAKE_REQUIRED_LIBRARIES pthread ${CMAKE_DL_LIBS} m) SET(what bundled) ELSE() SET(libname jemalloc c) diff --git a/cmake/ssl.cmake b/cmake/ssl.cmake index cc4f0d2daa0..c9562aa4910 100644 --- a/cmake/ssl.cmake +++ b/cmake/ssl.cmake @@ -135,7 +135,7 @@ MACRO (MYSQL_CHECK_SSL) SET(SSL_LIBRARIES ${SSL_LIBRARIES} ${LIBSOCKET}) ENDIF() IF(CMAKE_SYSTEM_NAME MATCHES "Linux") - SET(SSL_LIBRARIES ${SSL_LIBRARIES} ${LIBDL}) + SET(SSL_LIBRARIES ${SSL_LIBRARIES} ${CMAKE_DL_LIBS}) ENDIF() MESSAGE_ONCE(OPENSSL_INCLUDE_DIR "OPENSSL_INCLUDE_DIR = ${OPENSSL_INCLUDE_DIR}") diff --git a/configure.cmake b/configure.cmake index 75a02d2edc3..f32e4cbb9ad 100644 --- a/configure.cmake +++ b/configure.cmake @@ -130,7 +130,6 @@ IF(UNIX) MY_SEARCH_LIBS(bind "bind;socket" LIBBIND) MY_SEARCH_LIBS(crypt crypt LIBCRYPT) MY_SEARCH_LIBS(setsockopt socket LIBSOCKET) - MY_SEARCH_LIBS(dlopen dl LIBDL) MY_SEARCH_LIBS(sched_yield rt LIBRT) IF(NOT LIBRT) MY_SEARCH_LIBS(clock_gettime rt LIBRT) @@ -138,7 +137,7 @@ IF(UNIX) FIND_PACKAGE(Threads) SET(CMAKE_REQUIRED_LIBRARIES - ${LIBM} ${LIBNSL} ${LIBBIND} ${LIBCRYPT} ${LIBSOCKET} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT} ${LIBRT} ${LIBEXECINFO}) + ${LIBM} ${LIBNSL} ${LIBBIND} ${LIBCRYPT} ${LIBSOCKET} ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT} ${LIBRT} ${LIBEXECINFO}) # Need explicit pthread for gcc -fsanitize=address IF(CMAKE_USE_PTHREADS_INIT AND CMAKE_C_FLAGS MATCHES "-fsanitize=") SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} pthread) diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 445613eb579..9880653b2a5 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -148,7 +148,7 @@ ENDIF() SET(LIBS dbug strings mysys mysys_ssl pcre vio ${ZLIB_LIBRARY} ${SSL_LIBRARIES} - ${LIBWRAP} ${LIBCRYPT} ${LIBDL} + ${LIBWRAP} ${LIBCRYPT} ${CMAKE_DL_LIBS} ${MYSQLD_STATIC_PLUGIN_LIBS} sql_embedded ) diff --git a/mysql-test/lib/My/SafeProcess/CMakeLists.txt b/mysql-test/lib/My/SafeProcess/CMakeLists.txt index 4c3b62fa67e..33ff99da89b 100644 --- a/mysql-test/lib/My/SafeProcess/CMakeLists.txt +++ b/mysql-test/lib/My/SafeProcess/CMakeLists.txt @@ -24,7 +24,7 @@ ENDIF() IF(WITH_WSREP) ADD_EXECUTABLE(wsrep_check_version wsrep_check_version.c) - TARGET_LINK_LIBRARIES(wsrep_check_version ${LIBDL}) + TARGET_LINK_LIBRARIES(wsrep_check_version ${CMAKE_DL_LIBS}) ENDIF() IF(NOT INSTALL_MYSQLTESTDIR) diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 0a61c856506..3505f417762 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -75,7 +75,7 @@ ENDIF() ADD_CONVENIENCE_LIBRARY(mysys ${MYSYS_SOURCES}) TARGET_LINK_LIBRARIES(mysys dbug strings ${ZLIB_LIBRARY} - ${LIBNSL} ${LIBM} ${LIBRT} ${LIBDL} ${LIBSOCKET} ${LIBEXECINFO} ${CRC32_LIBRARY}) + ${LIBNSL} ${LIBM} ${LIBRT} ${CMAKE_DL_LIBS} ${LIBSOCKET} ${LIBEXECINFO} ${CRC32_LIBRARY}) DTRACE_INSTRUMENT(mysys) IF(HAVE_BFD_H) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 8ed75f86067..5f5d7daf1a5 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -167,7 +167,7 @@ ADD_LIBRARY(sql STATIC ${SQL_SOURCE}) DTRACE_INSTRUMENT(sql) TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS} mysys mysys_ssl dbug strings vio pcre - ${LIBWRAP} ${LIBCRYPT} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT} + ${LIBWRAP} ${LIBCRYPT} ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT} ${WSREP_LIB} ${SSL_LIBRARIES} ${LIBSYSTEMD}) diff --git a/storage/mroonga/vendor/groonga/CMakeLists.txt b/storage/mroonga/vendor/groonga/CMakeLists.txt index 564e859d146..d271d4c4eb9 100644 --- a/storage/mroonga/vendor/groonga/CMakeLists.txt +++ b/storage/mroonga/vendor/groonga/CMakeLists.txt @@ -240,7 +240,6 @@ include(build/ac_macros/check_functions.m4) ac_check_symbols(fpclassify math.h) ac_check_lib(m fpclassify) -ac_check_lib(dl dlopen) ac_check_lib(execinfo backtrace) if(HAVE_LIBEXECINFO) set(HAVE_BACKTRACE TRUE) diff --git a/storage/mroonga/vendor/groonga/lib/CMakeLists.txt b/storage/mroonga/vendor/groonga/lib/CMakeLists.txt index 21628b26ce2..8c71563f722 100644 --- a/storage/mroonga/vendor/groonga/lib/CMakeLists.txt +++ b/storage/mroonga/vendor/groonga/lib/CMakeLists.txt @@ -97,7 +97,7 @@ set(GRN_ALL_LIBRARIES ${LZ4_LIBS} ${LIBZSTD_LIBS} ${MESSAGE_PACK_LIBS} - ${DL_LIBS} + ${CMAKE_DL_LIBS} ${M_LIBS} ${WS2_32_LIBS} ${MRUBY_LIBS} diff --git a/storage/rocksdb/build_rocksdb.cmake b/storage/rocksdb/build_rocksdb.cmake index 8a981b8ec89..1099b51f850 100644 --- a/storage/rocksdb/build_rocksdb.cmake +++ b/storage/rocksdb/build_rocksdb.cmake @@ -160,7 +160,7 @@ find_package(Threads REQUIRED) if(WIN32) set(SYSTEM_LIBS ${SYSTEM_LIBS} Shlwapi.lib Rpcrt4.lib) else() - set(SYSTEM_LIBS ${CMAKE_THREAD_LIBS_INIT} ${LIBRT} ${LIBDL}) + set(SYSTEM_LIBS ${CMAKE_THREAD_LIBS_INIT} ${LIBRT} ${CMAKE_DL_LIBS}) endif() set(ROCKSDB_LIBS rocksdblib}) diff --git a/wsrep/CMakeLists.txt b/wsrep/CMakeLists.txt index 061cb9f4a32..b8abcaf9613 100644 --- a/wsrep/CMakeLists.txt +++ b/wsrep/CMakeLists.txt @@ -23,4 +23,4 @@ ADD_CONVENIENCE_LIBRARY(wsrep ${WSREP_SOURCES}) DTRACE_INSTRUMENT(wsrep) #ADD_EXECUTABLE(listener wsrep_listener.c ${WSREP_SOURCES}) -#TARGET_LINK_LIBRARIES(listener ${LIBDL}) +#TARGET_LINK_LIBRARIES(listener ${CMAKE_DL_LIBS}) From e64084d5a3a72462fa6263d1d0a86e72c0ba0d47 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 1 Aug 2020 13:12:50 +0200 Subject: [PATCH 202/323] MDEV-21201 No records produced in information_schema query, depending on projection Reimplement MDEV-14275 Improving memory utilization for information schema Postpone temp table instantiation until after setup_fields(). Replace all unused (not marked in read_set) columns in an I_S table with CHAR(0). This can drastically reduce the footprint of a MEMORY table (a TABLE_CATALOG alone is 1538 bytes per row). This does not change the engine. If the table was decided to be Aria (because of, say, blobs) then after optimization it'll stay Aria even if all blobs were removed. Note 1: when transforming table structure, share->blob_fields is preserved, otherwise Aria might switch from DYNAMIC to STATIC row format and expect a special field for a deleted mark, which create_tmp_tabe didn't provide. Note 2: optimizer was doing handler::info() (to know the number of rows) before the temp table is populated. That didn't make much sense. Now it's done before the table is even instantiated. Preserve the old behavior and report 0 rows. This reverts e2664ee8362 and a8458a2345e --- sql/set_var.cc | 3 - sql/sql_lex.cc | 16 ++-- sql/sql_parse.cc | 2 - sql/sql_select.cc | 20 ++--- sql/sql_show.cc | 180 +++++++++++++++++--------------------- sql/table.h | 1 - storage/heap/ha_heap.cc | 2 +- storage/maria/ha_maria.cc | 3 + 8 files changed, 99 insertions(+), 128 deletions(-) diff --git a/sql/set_var.cc b/sql/set_var.cc index eb2b9234db3..58b6b392449 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1068,7 +1068,6 @@ static void store_var(Field *field, sys_var *var, enum_var_type scope, int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond) { char name_buffer[NAME_CHAR_LEN]; - enum_check_fields save_count_cuted_fields= thd->count_cuted_fields; bool res= 1; CHARSET_INFO *scs= system_charset_info; StringBuffer strbuf(scs); @@ -1078,7 +1077,6 @@ int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond) DBUG_ASSERT(tables->table->in_use == thd); cond= make_cond_for_info_schema(thd, cond, tables); - thd->count_cuted_fields= CHECK_FIELD_WARN; mysql_prlock_rdlock(&LOCK_system_variables_hash); for (uint i= 0; i < system_variable_hash.records; i++) @@ -1243,7 +1241,6 @@ int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond) res= 0; end: mysql_prlock_unlock(&LOCK_system_variables_hash); - thd->count_cuted_fields= save_count_cuted_fields; return res; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 4f64dbfbbf9..b5483c671de 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3312,21 +3312,21 @@ bool LEX::can_not_use_merged() } } -/* - Detect that we need only table structure of derived table/view +/** + Detect that we need only table structure of derived table/view. - SYNOPSIS - only_view_structure() + Also used by I_S tables (@see create_schema_table) to detect that + they need a full table structure and cannot optimize unused columns away - RETURN - TRUE yes, we need only structure - FALSE no, we need data + @retval TRUE yes, we need only structure + @retval FALSE no, we need data */ bool LEX::only_view_structure() { switch (sql_command) { case SQLCOM_SHOW_CREATE: + case SQLCOM_CHECKSUM: case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_FIELDS: case SQLCOM_REVOKE_ALL: @@ -3334,6 +3334,8 @@ bool LEX::only_view_structure() case SQLCOM_GRANT: case SQLCOM_CREATE_VIEW: return TRUE; + case SQLCOM_CREATE_TABLE: + return create_info.like(); default: return FALSE; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 88e6d01304f..1b382ce0136 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -8905,8 +8905,6 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List *using_fields, SELECT_LEX *lex) { b->natural_join= a; - a->part_of_natural_join= TRUE; - b->part_of_natural_join= TRUE; lex->prev_join_using= using_fields; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 461c7b18363..37755387dda 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2468,6 +2468,10 @@ int JOIN::optimize_stage2() (select_options & (SELECT_DESCRIBE | SELECT_NO_JOIN_CACHE)) | (select_lex->ftfunc_list->elements ? SELECT_NO_JOIN_CACHE : 0); + if (select_lex->options & OPTION_SCHEMA_TABLE && + optimize_schema_tables_reads(this)) + DBUG_RETURN(1); + if (make_join_readinfo(this, select_opts_for_readinfo, no_jbuf_after)) DBUG_RETURN(1); @@ -2644,10 +2648,6 @@ int JOIN::optimize_stage2() having_is_correlated= MY_TEST(having->used_tables() & OUTER_REF_TABLE_BIT); tmp_having= having; - if ((select_lex->options & OPTION_SCHEMA_TABLE) && - optimize_schema_tables_reads(this)) - DBUG_RETURN(TRUE); - if (unlikely(thd->is_error())) DBUG_RETURN(TRUE); @@ -17138,15 +17138,11 @@ Field *Item::create_field_for_schema(THD *thd, TABLE *table) { Field *field; if (max_length > MAX_FIELD_VARCHARLENGTH) - field= new (thd->mem_root) Field_blob(max_length, maybe_null, &name, - collation.collation); - else if (max_length > 0) - field= new (thd->mem_root) Field_varstring(max_length, maybe_null, &name, - table->s, - collation.collation); - else - field= new Field_null((uchar*) 0, 0, Field::NONE, &name, + field= new Field_blob(max_length, maybe_null, &name, collation.collation); + else + field= new Field_varstring(max_length, maybe_null, &name, + table->s, collation.collation); if (field) field->init(table); return field; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 2a569204908..6bd8c9b5c27 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3700,8 +3700,6 @@ static bool show_status_array(THD *thd, const char *wild, CHARSET_INFO *charset= system_charset_info; DBUG_ENTER("show_status_array"); - thd->count_cuted_fields= CHECK_FIELD_WARN; - prefix_end=strnmov(name_buffer, prefix, sizeof(name_buffer)-1); if (*prefix) *prefix_end++= '_'; @@ -3801,6 +3799,8 @@ static bool show_status_array(THD *thd, const char *wild, pos= get_one_variable(thd, var, scope, show_type, status_var, &charset, buff, &length); + if (table->field[1]->field_length) + thd->count_cuted_fields= CHECK_FIELD_WARN; table->field[1]->store(pos, (uint32) length, charset); thd->count_cuted_fields= CHECK_FIELD_IGNORE; table->field[1]->set_notnull(); @@ -8108,51 +8108,6 @@ ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx) return &schema_tables[schema_table_idx]; } -static void -mark_all_fields_used_in_query(THD *thd, - ST_FIELD_INFO *schema_fields, - MY_BITMAP *bitmap, - Item *all_items) -{ - Item *item; - DBUG_ENTER("mark_all_fields_used_in_query"); - - /* If not SELECT command, return all columns */ - if (thd->lex->sql_command != SQLCOM_SELECT && - thd->lex->sql_command != SQLCOM_SET_OPTION) - { - bitmap_set_all(bitmap); - DBUG_VOID_RETURN; - } - - for (item= all_items ; item ; item= item->next) - { - if (item->type() == Item::FIELD_ITEM) - { - ST_FIELD_INFO *fields= schema_fields; - uint count; - Item_field *item_field= (Item_field*) item; - - /* item_field can be '*' as this function is called before fix_fields */ - if (item_field->field_name.str == star_clex_str.str) - { - bitmap_set_all(bitmap); - break; - } - for (count=0; fields->field_name; fields++, count++) - { - if (!my_strcasecmp(system_charset_info, fields->field_name, - item_field->field_name.str)) - { - bitmap_set_bit(bitmap, count); - break; - } - } - } - } - DBUG_VOID_RETURN; -} - /** Create information_schema table using schema_table data. @@ -8176,37 +8131,19 @@ mark_all_fields_used_in_query(THD *thd, TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) { - uint field_count; - Item *item, *all_items; + uint field_count= 0; + Item *item; TABLE *table; List field_list; ST_SCHEMA_TABLE *schema_table= table_list->schema_table; ST_FIELD_INFO *fields_info= schema_table->fields_info; - ST_FIELD_INFO *fields; CHARSET_INFO *cs= system_charset_info; MEM_ROOT *mem_root= thd->mem_root; - MY_BITMAP bitmap; - my_bitmap_map *buf; + bool need_all_fieds= table_list->schema_table_reformed || // SHOW command + thd->lex->only_view_structure(); // need table structure DBUG_ENTER("create_schema_table"); - for (field_count= 0, fields= fields_info; fields->field_name; fields++) - field_count++; - if (!(buf= (my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count)))) - DBUG_RETURN(NULL); - my_bitmap_init(&bitmap, buf, field_count, 0); - - if (!thd->stmt_arena->is_conventional() && - thd->mem_root != thd->stmt_arena->mem_root) - all_items= thd->stmt_arena->free_list; - else - all_items= thd->free_list; - - if (table_list->part_of_natural_join) - bitmap_set_all(&bitmap); - else - mark_all_fields_used_in_query(thd, fields_info, &bitmap, all_items); - - for (field_count=0; fields_info->field_name; fields_info++) + for (; fields_info->field_name; fields_info++) { size_t field_name_length= strlen(fields_info->field_name); switch (fields_info->field_type) { @@ -8283,44 +8220,19 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: - if (bitmap_is_set(&bitmap, field_count)) - { - if (!(item= new (mem_root) - Item_blob(thd, fields_info->field_name, - fields_info->field_length))) - { - DBUG_RETURN(0); - } - } - else - { - if (!(item= new (mem_root) - Item_empty_string(thd, "", 0, cs))) - { - DBUG_RETURN(0); - } - item->set_name(thd, fields_info->field_name, - field_name_length, cs); - } + if (!(item= new (mem_root) Item_blob(thd, fields_info->field_name, + fields_info->field_length))) + DBUG_RETURN(0); break; default: - { - bool show_field; /* Don't let unimplemented types pass through. Could be a grave error. */ DBUG_ASSERT(fields_info->field_type == MYSQL_TYPE_STRING); - - show_field= bitmap_is_set(&bitmap, field_count); - if (!(item= new (mem_root) - Item_empty_string(thd, "", - show_field ? fields_info->field_length : 0, cs))) - { + if (!(item= new (mem_root) Item_empty_string(thd, "", + fields_info->field_length, cs))) DBUG_RETURN(0); - } - item->set_name(thd, fields_info->field_name, - field_name_length, cs); + item->set_name(thd, fields_info->field_name, field_name_length, cs); break; } - } field_list.push_back(item, thd->mem_root); item->maybe_null= (fields_info->field_flags & MY_I_S_MAYBE_NULL); field_count++; @@ -8335,7 +8247,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) if (!(table= create_tmp_table(thd, tmp_table_param, field_list, (ORDER*) 0, 0, 0, (select_lex->options | thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR, - &table_list->alias, false, keep_row_order))) + &table_list->alias, !need_all_fieds, keep_row_order))) DBUG_RETURN(0); my_bitmap_map* bitmaps= (my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count)); @@ -8751,6 +8663,67 @@ end: } +static int optimize_schema_tables_memory_usage(TABLE_LIST *table_list) +{ + TABLE *table= table_list->table; + THD *thd=table->in_use; + if (!table->is_created()) + { + TMP_TABLE_PARAM *p= table_list->schema_table_param; + TMP_ENGINE_COLUMNDEF *from_recinfo, *to_recinfo; + DBUG_ASSERT(table->s->keys == 0); + DBUG_ASSERT(table->s->uniques == 0); + + // XXX HACK HACK HACK: in a stored function, RETURN (SELECT ...) + // enables warnings (in THD::sp_eval_expr) for the whole val_xxx/store pair, + // while the intention is to warn only for store(). Until this is + // fixed let's avoid data truncation warnings in I_S->fill_table() + if (thd->count_cuted_fields == CHECK_FIELD_IGNORE) + { + + uchar *cur= table->field[0]->ptr; + /* first recinfo could be a NULL bitmap, not an actual Field */ + from_recinfo= to_recinfo= p->start_recinfo + (cur != table->record[0]); + for (uint i=0; i < table->s->fields; i++, from_recinfo++) + { + Field *field= table->field[i]; + DBUG_ASSERT(field->vcol_info == 0); + DBUG_ASSERT(from_recinfo->length= field->pack_length_in_rec()); + if (bitmap_is_set(table->read_set, i)) + { + field->move_field(cur); + *to_recinfo++= *from_recinfo; + cur+= from_recinfo->length; + } + else + { + field= new (thd->mem_root) Field_string(cur, 0, field->null_ptr, + field->null_bit, Field::NONE, + &field->field_name, field->dtcollation()); + field->init(table); + field->field_index= i; + DBUG_ASSERT(field->pack_length_in_rec() == 0); + table->field[i]= field; + } + } + if ((table->s->reclength= (ulong)(cur - table->record[0])) == 0) + { + /* all fields were optimized away. Force a non-0-length row */ + table->s->reclength= to_recinfo->length= 1; + to_recinfo++; + } + p->recinfo= to_recinfo; + } // XXX end of HACK HACK HACK + + // TODO switch from Aria to Memory if all blobs were optimized away? + if (instantiate_tmp_table(table, p->keyinfo, p->start_recinfo, &p->recinfo, + table_list->select_lex->options | thd->variables.option_bits)) + return 1; + } + return 0; +} + + /* This is the optimizer part of get_schema_tables_result(). */ @@ -8771,6 +8744,9 @@ bool optimize_schema_tables_reads(JOIN *join) TABLE_LIST *table_list= tab->table->pos_in_table_list; if (table_list->schema_table && thd->fill_information_schema_tables()) { + if (optimize_schema_tables_memory_usage(table_list)) + DBUG_RETURN(1); + /* A value of 0 indicates a dummy implementation */ if (table_list->schema_table->fill_table == 0) continue; diff --git a/sql/table.h b/sql/table.h index a42feba68c4..c7e7a39b46f 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2190,7 +2190,6 @@ struct TABLE_LIST parsing 'this' is a NATURAL/USING join iff (natural_join != NULL). */ TABLE_LIST *natural_join; - bool part_of_natural_join; /* True if 'this' represents a nested join that is a NATURAL JOIN. For one of the operands of 'this', the member 'natural_join' points diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc index 396887df1b1..a40f4b8a464 100644 --- a/storage/heap/ha_heap.cc +++ b/storage/heap/ha_heap.cc @@ -364,7 +364,7 @@ int ha_heap::info(uint flag) HEAPINFO hp_info; if (!table) - return 1; + return 0; (void) heap_info(file,&hp_info,flag); diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index c0163473f3a..23d2becbb04 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -2440,6 +2440,9 @@ int ha_maria::info(uint flag) MARIA_INFO maria_info; char name_buff[FN_REFLEN]; + if (!table) + return 0; + (void) maria_status(file, &maria_info, flag); if (flag & HA_STATUS_VARIABLE) { From 79f6f0c4fcd5a79fe776a6c089e14c65a04a81bf Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Fri, 23 Oct 2020 18:42:26 +0700 Subject: [PATCH 203/323] MDEV-23564: CMAKE failing due to deprecated Apple GSS method Some GSS-API functions like gss_import_name(), gss_release_buffer() used in plugin/auth_gssapi and libmariadb/plugins/auth are marked as deprecated in MacOS starting from version 10.14+. It results in extra warnings output on server building. To eliminate extra warnings the flag '-Wno-deprecated-declarations' has been added to compiler invocation string for those source files that invoke deprecated GSS-API functions. --- libmariadb | 2 +- plugin/auth_gssapi/CMakeLists.txt | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index a746c3af449..cfc36a46d1c 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit a746c3af449a8754e78ad7971e59e79af7957cdb +Subproject commit cfc36a46d1cab755e46532bcc6cddab62652c0a0 diff --git a/plugin/auth_gssapi/CMakeLists.txt b/plugin/auth_gssapi/CMakeLists.txt index bca4f5af3a1..4d3718dd471 100644 --- a/plugin/auth_gssapi/CMakeLists.txt +++ b/plugin/auth_gssapi/CMakeLists.txt @@ -18,6 +18,11 @@ ELSE() SET(GSSAPI_SERVER gssapi_server.cc) SET(GSSAPI_ERRMSG gssapi_errmsg.cc) + IF(APPLE) + SET_SOURCE_FILES_PROPERTIES( + ${GSSAPI_CLIENT} ${GSSAPI_SERVER} ${GSSAPI_ERRMSG} + PROPERTY COMPILE_FLAGS "-Wno-deprecated-declarations") + ENDIF() SET(CMAKE_REQUIRED_INCLUDES ${GSSAPI_INCS}) SET(CMAKE_REQUIRED_LIBRARIES ${GSSAPI_LIBS}) INCLUDE(CheckCXXSymbolExists) From 58da04b26122b61c960cbd5130bd638b32e66f01 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Fri, 23 Oct 2020 19:15:22 +0700 Subject: [PATCH 204/323] MDEV-23926: Follow-up patch This patch fixes incorrect argument type passed to the last parameter of getgrouplist() in cmake macros CHECK_C_SOURCE_COMPILES() --- plugin/auth_pam/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/auth_pam/CMakeLists.txt b/plugin/auth_pam/CMakeLists.txt index d3b3c256527..e06859ae9b7 100644 --- a/plugin/auth_pam/CMakeLists.txt +++ b/plugin/auth_pam/CMakeLists.txt @@ -21,7 +21,7 @@ int main() { char *arg_1; gid_t arg_2, arg_3; int arg_4; - (void)getgrouplist(arg_1,arg_2,&arg_3,arg_4); + (void)getgrouplist(arg_1,arg_2,&arg_3,&arg_4); return 0; } " From 4654501e00947422710b949832d1b9ff8a7a40a5 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Fri, 23 Oct 2020 20:01:50 +0700 Subject: [PATCH 205/323] MDEV-23926: Follow-up patch This patch removes unnecessary #ifdefs in cmake macros CHECK_C_SOURCE_COMPILES. --- plugin/auth_pam/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugin/auth_pam/CMakeLists.txt b/plugin/auth_pam/CMakeLists.txt index e06859ae9b7..dbb4701fbc4 100644 --- a/plugin/auth_pam/CMakeLists.txt +++ b/plugin/auth_pam/CMakeLists.txt @@ -11,12 +11,8 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) SET(CMAKE_REQUIRED_FLAGS -Werror) CHECK_C_SOURCE_COMPILES( " -#ifdef HAVE_GRP_H #include -#endif -#ifdef HAVE_UNISTD_H #include -#endif int main() { char *arg_1; gid_t arg_2, arg_3; From e864e6b181f4e85fbd76cb5a0f36d0735a47d7ef Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 23 Oct 2020 15:44:07 +0200 Subject: [PATCH 206/323] compilation failure with new C/C define symbols as C/C does to avoid "macro redefined" warnings --- include/mysql_version.h.in | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/mysql_version.h.in b/include/mysql_version.h.in index f22e00dabb9..16876dbfedd 100644 --- a/include/mysql_version.h.in +++ b/include/mysql_version.h.in @@ -17,12 +17,15 @@ #define MYSQL_SERVER_SUFFIX_DEF "@MYSQL_SERVER_SUFFIX@" #define FRM_VER @DOT_FRM_VERSION@ #define MYSQL_VERSION_ID @MYSQL_VERSION_ID@ -#define MYSQL_PORT @MYSQL_TCP_PORT@ +#define MARIADB_PORT @MYSQL_TCP_PORT@ #define MYSQL_PORT_DEFAULT @MYSQL_TCP_PORT_DEFAULT@ -#define MYSQL_UNIX_ADDR "@MYSQL_UNIX_ADDR@" +#define MARIADB_UNIX_ADDR "@MYSQL_UNIX_ADDR@" #define MYSQL_CONFIG_NAME "my" #define MYSQL_COMPILATION_COMMENT "@COMPILATION_COMMENT@" +#define MYSQL_PORT MARIADB_PORT +#define MYSQL_UNIX_ADDR MARIADB_UNIX_ADDR + #ifdef WITH_WSREP #define WSREP_PATCH_VERSION "@WSREP_PATCH_VERSION@" #endif From 1cabfe2c2b7debfe0a75b30dedf5e5d2bba672e7 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 23 Oct 2020 15:45:04 +0200 Subject: [PATCH 207/323] .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d91bac43dee..8477515105b 100644 --- a/.gitignore +++ b/.gitignore @@ -100,6 +100,7 @@ pcre/pcre_chartables.c pcre/pcregrep pcre/pcretest pcre/test*grep +plugin/auth_pam/config_auth_pam.h plugin/aws_key_management/aws-sdk-cpp plugin/aws_key_management/aws_sdk_cpp plugin/aws_key_management/aws_sdk_cpp-prefix From 15f03c204159325c343bd8c793f71edad0be3347 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 31 Aug 2020 09:54:46 +0200 Subject: [PATCH 208/323] MDEV-23492 performance_schema_digests_size changing from default to 5000 when enabling performance_schema max allowed value limit should be larger than any auto-sized value --- mysql-test/suite/sys_vars/r/sysvars_server_embedded.result | 2 +- mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result | 2 +- sql/sys_vars.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index 8221a64472b..87795f802e2 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -2137,7 +2137,7 @@ VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BIGINT VARIABLE_COMMENT Size of the statement digest. Use 0 to disable, -1 for automated sizing. NUMERIC_MIN_VALUE -1 -NUMERIC_MAX_VALUE 200 +NUMERIC_MAX_VALUE 1048576 NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL READ_ONLY YES diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index f9c92b91d86..aaaf1afb8b7 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -2277,7 +2277,7 @@ VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BIGINT VARIABLE_COMMENT Size of the statement digest. Use 0 to disable, -1 for automated sizing. NUMERIC_MIN_VALUE -1 -NUMERIC_MAX_VALUE 200 +NUMERIC_MAX_VALUE 1048576 NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL READ_ONLY YES diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index af261299496..2a582a098fb 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -323,7 +323,7 @@ static Sys_var_long Sys_pfs_digest_size( "Size of the statement digest." " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_digest_sizing), - CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 200), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024 * 1024), DEFAULT(-1), BLOCK_SIZE(1)); From 2cd5df8c83d018d1aa58c8426b8406c3c6528d7e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 1 Oct 2020 16:35:55 +0200 Subject: [PATCH 209/323] MDEV-23656 view: removal of parentheses results in wrong result Item_ref should have the precedence of the item it's referencing --- mysql-test/r/precedence_bugs.result | 13 +++++++++++++ mysql-test/t/precedence_bugs.test | 10 ++++++++++ sql/item.h | 6 +++++- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 mysql-test/r/precedence_bugs.result create mode 100644 mysql-test/t/precedence_bugs.test diff --git a/mysql-test/r/precedence_bugs.result b/mysql-test/r/precedence_bugs.result new file mode 100644 index 00000000000..a9b1cd81503 --- /dev/null +++ b/mysql-test/r/precedence_bugs.result @@ -0,0 +1,13 @@ +# +# MDEV-23656 view: removal of parentheses results in wrong result +# +create table t1 (a int, b decimal(10,2)); +insert into t1 values (1, 10.2); +create view v1 as select avg(b) / (2 + a) from t1; +show create view v1; +View v1 +Create View CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select avg(`t1`.`b`) / (2 + `t1`.`a`) AS `avg(b) / (2 + a)` from `t1` +character_set_client latin1 +collation_connection latin1_swedish_ci +drop view v1; +drop table t1; diff --git a/mysql-test/t/precedence_bugs.test b/mysql-test/t/precedence_bugs.test new file mode 100644 index 00000000000..6e00fee41a5 --- /dev/null +++ b/mysql-test/t/precedence_bugs.test @@ -0,0 +1,10 @@ + +--echo # +--echo # MDEV-23656 view: removal of parentheses results in wrong result +--echo # +create table t1 (a int, b decimal(10,2)); +insert into t1 values (1, 10.2); +create view v1 as select avg(b) / (2 + a) from t1; +query_vertical show create view v1; +drop view v1; +drop table t1; diff --git a/sql/item.h b/sql/item.h index 4a761bfd70a..6c48d570203 100644 --- a/sql/item.h +++ b/sql/item.h @@ -4541,7 +4541,11 @@ public: { (*ref)->restore_to_before_no_rows_in_result(); } - virtual void print(String *str, enum_query_type query_type); + void print(String *str, enum_query_type query_type); + enum precedence precedence() const + { + return ref ? (*ref)->precedence() : DEFAULT_PRECEDENCE; + } void cleanup(); Item_field *field_for_view_update() { return (*ref)->field_for_view_update(); } From 71a5857291d6d1d54bc5929efc5156c6f3035007 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 5 Oct 2020 13:11:12 +0200 Subject: [PATCH 210/323] cleanup: move precedence tests into precedence_bugs.test --- mysql-test/r/func_math.result | 5 ---- mysql-test/r/func_test.result | 10 -------- mysql-test/r/precedence_bugs.result | 37 +++++++++++++++++++++++++++++ mysql-test/r/view.result | 11 --------- mysql-test/t/func_math.test | 5 ---- mysql-test/t/func_test.test | 9 ------- mysql-test/t/precedence_bugs.test | 24 +++++++++++++++++++ mysql-test/t/view.test | 11 --------- 8 files changed, 61 insertions(+), 51 deletions(-) diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index 436542b7225..1a01a4ed150 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -1766,8 +1766,3 @@ select 0=0, 0=-0, 0.0= -0.0, 0.0 = -(0.0), 0.0E1=-0.0E1, 0.0E1=-(0.0E1); select CRC32(NULL), CRC32(''), CRC32('MySQL'), CRC32('mysql'), CRC32('01234567'), CRC32('012345678'); CRC32(NULL) CRC32('') CRC32('MySQL') CRC32('mysql') CRC32('01234567') CRC32('012345678') NULL 0 3259397556 2501908538 763378421 939184570 -explain extended select (3-2)+1, (3/2)*1, 3-(2+1), 3/(2*1); -id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used -Warnings: -Note 1003 select 3 - 2 + 1 AS `(3-2)+1`,3 / 2 * 1 AS `(3/2)*1`,3 - (2 + 1) AS `3-(2+1)`,3 / (2 * 1) AS `3/(2*1)` diff --git a/mysql-test/r/func_test.result b/mysql-test/r/func_test.result index 8f175a6805b..94cf6d3e6fa 100644 --- a/mysql-test/r/func_test.result +++ b/mysql-test/r/func_test.result @@ -273,16 +273,6 @@ NULL select mod(NULL, 2.0) as 'NULL'; NULL NULL -create table t1 (a int, b int); -insert into t1 values (1,2), (2,3), (3,4), (4,5); -select * from t1 where a not between 1 and 2; -a b -3 4 -4 5 -select * from t1 where a not between 1 and 2 and b not between 3 and 4; -a b -4 5 -drop table t1; SELECT GREATEST(1,NULL) FROM DUAL; GREATEST(1,NULL) NULL diff --git a/mysql-test/r/precedence_bugs.result b/mysql-test/r/precedence_bugs.result index a9b1cd81503..3da61b6b58a 100644 --- a/mysql-test/r/precedence_bugs.result +++ b/mysql-test/r/precedence_bugs.result @@ -1,4 +1,41 @@ # +# Bug#6726: NOT BETWEEN parse failure +# +create table t1 (a int, b int); +insert into t1 values (1,2), (2,3), (3,4), (4,5); +select * from t1 where a not between 1 and 2; +a b +3 4 +4 5 +select * from t1 where a not between 1 and 2 and b not between 3 and 4; +a b +4 5 +drop table t1; +# +# MDEV-13673 Bad result in view +# +explain extended select (3-2)+1, (3/2)*1, 3-(2+1), 3/(2*1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select 3 - 2 + 1 AS `(3-2)+1`,3 / 2 * 1 AS `(3/2)*1`,3 - (2 + 1) AS `3-(2+1)`,3 / (2 * 1) AS `3/(2*1)` +# +# MDEV-11784 View is created with invalid definition which causes ERROR 1241 (21000): Operand should contain 1 column(s) +# +create table t1 (i int, j int); +insert t1 values (1,1),(2,2); +create view v1 as select (2, 3) not in (select i, j from t1); +select * from v1; +(2, 3) not in (select i, j from t1) +1 +show create view v1; +View v1 +Create View CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select !((2,3) in (select `t1`.`i`,`t1`.`j` from `t1`)) AS `(2, 3) not in (select i, j from t1)` +character_set_client latin1 +collation_connection latin1_swedish_ci +drop view v1; +drop table t1; +# # MDEV-23656 view: removal of parentheses results in wrong result # create table t1 (a int, b decimal(10,2)); diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index a422819ad0f..994d5949460 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -6649,17 +6649,6 @@ INSERT INTO v (f1, f3) VALUES (1,1), (2,2); ERROR HY000: Can not modify more than one base table through a join view 'test.v' drop view v; drop tables t1,t2,t3; -create table t1 (i int, j int); -insert t1 values (1,1),(2,2); -create view v1 as select (2, 3) not in (select i, j from t1); -select * from v1; -(2, 3) not in (select i, j from t1) -1 -show create view v1; -View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select !((2,3) in (select `t1`.`i`,`t1`.`j` from `t1`)) AS `(2, 3) not in (select i, j from t1)` latin1 latin1_swedish_ci -drop view v1; -drop table t1; # # MDEV-10704: Assertion `field->field->table == table_arg' # failed in fill_record(THD*, TABLE*, List&, List&, diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index 077cfdc5b6d..8dfec3063f4 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -792,8 +792,3 @@ select 0=0, 0=-0, 0.0= -0.0, 0.0 = -(0.0), 0.0E1=-0.0E1, 0.0E1=-(0.0E1); --echo # select CRC32(NULL), CRC32(''), CRC32('MySQL'), CRC32('mysql'), CRC32('01234567'), CRC32('012345678'); - -# -# MDEV-13673 Bad result in view -# -explain extended select (3-2)+1, (3/2)*1, 3-(2+1), 3/(2*1); diff --git a/mysql-test/t/func_test.test b/mysql-test/t/func_test.test index d1c0702da80..9bdbe5bc4e4 100644 --- a/mysql-test/t/func_test.test +++ b/mysql-test/t/func_test.test @@ -141,15 +141,6 @@ select mod(NULL, 2) as 'NULL'; select mod(NULL, 2.0) as 'NULL'; -# -# Bug#6726: NOT BETWEEN parse failure -# -create table t1 (a int, b int); -insert into t1 values (1,2), (2,3), (3,4), (4,5); -select * from t1 where a not between 1 and 2; -select * from t1 where a not between 1 and 2 and b not between 3 and 4; -drop table t1; - # # Test for bug #12791: one of the arguments of LEAST/GREATEST is NULL # diff --git a/mysql-test/t/precedence_bugs.test b/mysql-test/t/precedence_bugs.test index 6e00fee41a5..46a803504f2 100644 --- a/mysql-test/t/precedence_bugs.test +++ b/mysql-test/t/precedence_bugs.test @@ -1,3 +1,27 @@ +--echo # +--echo # Bug#6726: NOT BETWEEN parse failure +--echo # +create table t1 (a int, b int); +insert into t1 values (1,2), (2,3), (3,4), (4,5); +select * from t1 where a not between 1 and 2; +select * from t1 where a not between 1 and 2 and b not between 3 and 4; +drop table t1; + +--echo # +--echo # MDEV-13673 Bad result in view +--echo # +explain extended select (3-2)+1, (3/2)*1, 3-(2+1), 3/(2*1); + +--echo # +--echo # MDEV-11784 View is created with invalid definition which causes ERROR 1241 (21000): Operand should contain 1 column(s) +--echo # +create table t1 (i int, j int); +insert t1 values (1,1),(2,2); +create view v1 as select (2, 3) not in (select i, j from t1); +select * from v1; +query_vertical show create view v1; +drop view v1; +drop table t1; --echo # --echo # MDEV-23656 view: removal of parentheses results in wrong result diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index d4e5fdd7a46..cd5cc6efade 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -6362,17 +6362,6 @@ INSERT INTO v (f1, f3) VALUES (1,1), (2,2); drop view v; drop tables t1,t2,t3; -# -# MDEV-11784 View is created with invalid definition which causes ERROR 1241 (21000): Operand should contain 1 column(s) -# -create table t1 (i int, j int); -insert t1 values (1,1),(2,2); -create view v1 as select (2, 3) not in (select i, j from t1); -select * from v1; -show create view v1; -drop view v1; -drop table t1; - --echo # --echo # MDEV-10704: Assertion `field->field->table == table_arg' --echo # failed in fill_record(THD*, TABLE*, List&, List&, From 9ad4e0d6d8952b861848da95778e35cf3abc1b93 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 14 Oct 2020 14:00:09 +0200 Subject: [PATCH 211/323] A fairly exhastive test for operator precedence some results are incorrect --- mysql-test/r/precedence.result | 8104 ++++++++++++++++++++++++++++++++ mysql-test/t/precedence.test | 4789 +++++++++++++++++++ 2 files changed, 12893 insertions(+) create mode 100644 mysql-test/r/precedence.result create mode 100644 mysql-test/t/precedence.test diff --git a/mysql-test/r/precedence.result b/mysql-test/r/precedence.result new file mode 100644 index 00000000000..be07af1c550 --- /dev/null +++ b/mysql-test/r/precedence.result @@ -0,0 +1,8104 @@ +create or replace view v1 as select NOT NULL IS TRUE, NOT (NULL IS TRUE), (NOT NULL) IS TRUE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(NULL is true) AS `NOT NULL IS TRUE`,!(NULL is true) AS `NOT (NULL IS TRUE)`,!NULL is true AS `(NOT NULL) IS TRUE` +select NOT NULL IS TRUE, NOT (NULL IS TRUE), (NOT NULL) IS TRUE union select * from v1; +NOT NULL IS TRUE NOT (NULL IS TRUE) (NOT NULL) IS TRUE +1 1 0 +create or replace view v1 as select ! NULL IS TRUE, ! (NULL IS TRUE), (! NULL) IS TRUE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !NULL is true AS `! NULL IS TRUE`,!(NULL is true) AS `! (NULL IS TRUE)`,!NULL is true AS `(! NULL) IS TRUE` +select ! NULL IS TRUE, ! (NULL IS TRUE), (! NULL) IS TRUE union select * from v1; +! NULL IS TRUE ! (NULL IS TRUE) (! NULL) IS TRUE +0 1 0 +create or replace view v1 as select charset(NOT 2 COLLATE latin1_bin), charset(NOT (2 COLLATE latin1_bin)), charset((NOT 2) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(!2 collate latin1_bin) AS `charset(NOT 2 COLLATE latin1_bin)`,charset(!2 collate latin1_bin) AS `charset(NOT (2 COLLATE latin1_bin))`,charset((!2) collate latin1_bin) AS `charset((NOT 2) COLLATE latin1_bin)` +select charset(NOT 2 COLLATE latin1_bin), charset(NOT (2 COLLATE latin1_bin)), charset((NOT 2) COLLATE latin1_bin) union select * from v1; +charset(NOT 2 COLLATE latin1_bin) charset(NOT (2 COLLATE latin1_bin)) charset((NOT 2) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select NOT 2 IN (0,2), NOT (2 IN (0,2)), (NOT 2) IN (0,2); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 not in (0,2) AS `NOT 2 IN (0,2)`,2 not in (0,2) AS `NOT (2 IN (0,2))`,!2 in (0,2) AS `(NOT 2) IN (0,2)` +select NOT 2 IN (0,2), NOT (2 IN (0,2)), (NOT 2) IN (0,2) union select * from v1; +NOT 2 IN (0,2) NOT (2 IN (0,2)) (NOT 2) IN (0,2) +0 0 1 +create or replace view v1 as select NOT 2 OR 3, NOT (2 OR 3), (NOT 2) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 or 3 AS `NOT 2 OR 3`,!2 and !3 AS `NOT (2 OR 3)`,!2 or 3 AS `(NOT 2) OR 3` +select NOT 2 OR 3, NOT (2 OR 3), (NOT 2) OR 3 union select * from v1; +NOT 2 OR 3 NOT (2 OR 3) (NOT 2) OR 3 +1 0 1 +create or replace view v1 as select NOT 2 || 3, NOT (2 || 3), (NOT 2) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 or 3 AS `NOT 2 || 3`,!2 and !3 AS `NOT (2 || 3)`,!2 or 3 AS `(NOT 2) || 3` +select NOT 2 || 3, NOT (2 || 3), (NOT 2) || 3 union select * from v1; +NOT 2 || 3 NOT (2 || 3) (NOT 2) || 3 +1 0 1 +create or replace view v1 as select NOT 2 AND 0, NOT (2 AND 0), (NOT 2) AND 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 and 0 AS `NOT 2 AND 0`,!2 or !0 AS `NOT (2 AND 0)`,!2 and 0 AS `(NOT 2) AND 0` +select NOT 2 AND 0, NOT (2 AND 0), (NOT 2) AND 0 union select * from v1; +NOT 2 AND 0 NOT (2 AND 0) (NOT 2) AND 0 +0 1 0 +create or replace view v1 as select NOT 2 && 0, NOT (2 && 0), (NOT 2) && 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 and 0 AS `NOT 2 && 0`,!2 or !0 AS `NOT (2 && 0)`,!2 and 0 AS `(NOT 2) && 0` +select NOT 2 && 0, NOT (2 && 0), (NOT 2) && 0 union select * from v1; +NOT 2 && 0 NOT (2 && 0) (NOT 2) && 0 +0 1 0 +create or replace view v1 as select NOT 2 = 3, NOT (2 = 3), (NOT 2) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 AS `NOT 2 = 3`,2 <> 3 AS `NOT (2 = 3)`,!2 = 3 AS `(NOT 2) = 3` +select NOT 2 = 3, NOT (2 = 3), (NOT 2) = 3 union select * from v1; +NOT 2 = 3 NOT (2 = 3) (NOT 2) = 3 +1 1 0 +create or replace view v1 as select NOT 2 <=> 3, NOT (2 <=> 3), (NOT 2) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(2 <=> 3) AS `NOT 2 <=> 3`,!(2 <=> 3) AS `NOT (2 <=> 3)`,!2 <=> 3 AS `(NOT 2) <=> 3` +select NOT 2 <=> 3, NOT (2 <=> 3), (NOT 2) <=> 3 union select * from v1; +NOT 2 <=> 3 NOT (2 <=> 3) (NOT 2) <=> 3 +1 1 0 +create or replace view v1 as select NOT 2 >= 3, NOT (2 >= 3), (NOT 2) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 AS `NOT 2 >= 3`,2 < 3 AS `NOT (2 >= 3)`,!2 >= 3 AS `(NOT 2) >= 3` +select NOT 2 >= 3, NOT (2 >= 3), (NOT 2) >= 3 union select * from v1; +NOT 2 >= 3 NOT (2 >= 3) (NOT 2) >= 3 +1 1 0 +create or replace view v1 as select NOT 2 <= 3, NOT (2 <= 3), (NOT 2) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 AS `NOT 2 <= 3`,2 > 3 AS `NOT (2 <= 3)`,!2 <= 3 AS `(NOT 2) <= 3` +select NOT 2 <= 3, NOT (2 <= 3), (NOT 2) <= 3 union select * from v1; +NOT 2 <= 3 NOT (2 <= 3) (NOT 2) <= 3 +0 0 1 +create or replace view v1 as select NOT 2 < 3, NOT (2 < 3), (NOT 2) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 AS `NOT 2 < 3`,2 >= 3 AS `NOT (2 < 3)`,!2 < 3 AS `(NOT 2) < 3` +select NOT 2 < 3, NOT (2 < 3), (NOT 2) < 3 union select * from v1; +NOT 2 < 3 NOT (2 < 3) (NOT 2) < 3 +0 0 1 +create or replace view v1 as select NOT 2 <> 3, NOT (2 <> 3), (NOT 2) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 3 AS `NOT 2 <> 3`,2 = 3 AS `NOT (2 <> 3)`,!2 <> 3 AS `(NOT 2) <> 3` +select NOT 2 <> 3, NOT (2 <> 3), (NOT 2) <> 3 union select * from v1; +NOT 2 <> 3 NOT (2 <> 3) (NOT 2) <> 3 +0 0 1 +create or replace view v1 as select NOT 2 > 3, NOT (2 > 3), (NOT 2) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 AS `NOT 2 > 3`,2 <= 3 AS `NOT (2 > 3)`,!2 > 3 AS `(NOT 2) > 3` +select NOT 2 > 3, NOT (2 > 3), (NOT 2) > 3 union select * from v1; +NOT 2 > 3 NOT (2 > 3) (NOT 2) > 3 +1 1 0 +create or replace view v1 as select NOT 2 != 3, NOT (2 != 3), (NOT 2) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 3 AS `NOT 2 != 3`,2 = 3 AS `NOT (2 != 3)`,!2 <> 3 AS `(NOT 2) != 3` +select NOT 2 != 3, NOT (2 != 3), (NOT 2) != 3 union select * from v1; +NOT 2 != 3 NOT (2 != 3) (NOT 2) != 3 +0 0 1 +create or replace view v1 as select NOT 2 LIKE 3, NOT (2 LIKE 3), (NOT 2) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 not like 3 AS `NOT 2 LIKE 3`,2 not like 3 AS `NOT (2 LIKE 3)`,!2 like 3 AS `(NOT 2) LIKE 3` +select NOT 2 LIKE 3, NOT (2 LIKE 3), (NOT 2) LIKE 3 union select * from v1; +NOT 2 LIKE 3 NOT (2 LIKE 3) (NOT 2) LIKE 3 +1 1 0 +create or replace view v1 as select NOT 2 REGEXP 3, NOT (2 REGEXP 3), (NOT 2) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(2 regexp 3) AS `NOT 2 REGEXP 3`,!(2 regexp 3) AS `NOT (2 REGEXP 3)`,!2 regexp 3 AS `(NOT 2) REGEXP 3` +select NOT 2 REGEXP 3, NOT (2 REGEXP 3), (NOT 2) REGEXP 3 union select * from v1; +NOT 2 REGEXP 3 NOT (2 REGEXP 3) (NOT 2) REGEXP 3 +1 1 0 +create or replace view v1 as select NOT 2 | 3, NOT (2 | 3), (NOT 2) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(2 | 3) AS `NOT 2 | 3`,!(2 | 3) AS `NOT (2 | 3)`,!2 | 3 AS `(NOT 2) | 3` +select NOT 2 | 3, NOT (2 | 3), (NOT 2) | 3 union select * from v1; +NOT 2 | 3 NOT (2 | 3) (NOT 2) | 3 +0 0 3 +create or replace view v1 as select NOT 0 & 2, NOT (0 & 2), (NOT 0) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(0 & 2) AS `NOT 0 & 2`,!(0 & 2) AS `NOT (0 & 2)`,!0 & 2 AS `(NOT 0) & 2` +select NOT 0 & 2, NOT (0 & 2), (NOT 0) & 2 union select * from v1; +NOT 0 & 2 NOT (0 & 2) (NOT 0) & 2 +1 1 0 +create or replace view v1 as select NOT 0 << 3, NOT (0 << 3), (NOT 0) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(0 << 3) AS `NOT 0 << 3`,!(0 << 3) AS `NOT (0 << 3)`,!0 << 3 AS `(NOT 0) << 3` +select NOT 0 << 3, NOT (0 << 3), (NOT 0) << 3 union select * from v1; +NOT 0 << 3 NOT (0 << 3) (NOT 0) << 3 +1 1 8 +create or replace view v1 as select NOT 2 >> 3, NOT (2 >> 3), (NOT 2) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(2 >> 3) AS `NOT 2 >> 3`,!(2 >> 3) AS `NOT (2 >> 3)`,!2 >> 3 AS `(NOT 2) >> 3` +select NOT 2 >> 3, NOT (2 >> 3), (NOT 2) >> 3 union select * from v1; +NOT 2 >> 3 NOT (2 >> 3) (NOT 2) >> 3 +1 1 0 +create or replace view v1 as select NOT '2000-01-01' +INTERVAL 1 DAY, NOT ('2000-01-01' +INTERVAL 1 DAY), (NOT '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !('2000-01-01' + interval 1 day) AS `NOT '2000-01-01' +INTERVAL 1 DAY`,!('2000-01-01' + interval 1 day) AS `NOT ('2000-01-01' +INTERVAL 1 DAY)`,!'2000-01-01' + interval 1 day AS `(NOT '2000-01-01') +INTERVAL 1 DAY` +select NOT '2000-01-01' +INTERVAL 1 DAY, NOT ('2000-01-01' +INTERVAL 1 DAY), (NOT '2000-01-01') +INTERVAL 1 DAY union select * from v1; +NOT '2000-01-01' +INTERVAL 1 DAY NOT ('2000-01-01' +INTERVAL 1 DAY) (NOT '2000-01-01') +INTERVAL 1 DAY +0 0 NULL +create or replace view v1 as select NOT 2 + 3, NOT (2 + 3), (NOT 2) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(2 + 3) AS `NOT 2 + 3`,!(2 + 3) AS `NOT (2 + 3)`,!2 + 3 AS `(NOT 2) + 3` +select NOT 2 + 3, NOT (2 + 3), (NOT 2) + 3 union select * from v1; +NOT 2 + 3 NOT (2 + 3) (NOT 2) + 3 +0 0 3 +create or replace view v1 as select NOT 2 - 3, NOT (2 - 3), (NOT 2) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(2 - 3) AS `NOT 2 - 3`,!(2 - 3) AS `NOT (2 - 3)`,!2 - 3 AS `(NOT 2) - 3` +select NOT 2 - 3, NOT (2 - 3), (NOT 2) - 3 union select * from v1; +NOT 2 - 3 NOT (2 - 3) (NOT 2) - 3 +0 0 -3 +create or replace view v1 as select NOT 0 * 3, NOT (0 * 3), (NOT 0) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(0 * 3) AS `NOT 0 * 3`,!(0 * 3) AS `NOT (0 * 3)`,!0 * 3 AS `(NOT 0) * 3` +select NOT 0 * 3, NOT (0 * 3), (NOT 0) * 3 union select * from v1; +NOT 0 * 3 NOT (0 * 3) (NOT 0) * 3 +1 1 3 +create or replace view v1 as select NOT 0 / 3, NOT (0 / 3), (NOT 0) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(0 / 3) AS `NOT 0 / 3`,!(0 / 3) AS `NOT (0 / 3)`,!0 / 3 AS `(NOT 0) / 3` +select NOT 0 / 3, NOT (0 / 3), (NOT 0) / 3 union select * from v1; +NOT 0 / 3 NOT (0 / 3) (NOT 0) / 3 +1 1 0.3333 +create or replace view v1 as select NOT 2 DIV 3, NOT (2 DIV 3), (NOT 2) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(2 DIV 3) AS `NOT 2 DIV 3`,!(2 DIV 3) AS `NOT (2 DIV 3)`,!2 DIV 3 AS `(NOT 2) DIV 3` +select NOT 2 DIV 3, NOT (2 DIV 3), (NOT 2) DIV 3 union select * from v1; +NOT 2 DIV 3 NOT (2 DIV 3) (NOT 2) DIV 3 +1 1 0 +create or replace view v1 as select NOT 6 MOD 3, NOT (6 MOD 3), (NOT 6) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(6 % 3) AS `NOT 6 MOD 3`,!(6 % 3) AS `NOT (6 MOD 3)`,!6 % 3 AS `(NOT 6) MOD 3` +select NOT 6 MOD 3, NOT (6 MOD 3), (NOT 6) MOD 3 union select * from v1; +NOT 6 MOD 3 NOT (6 MOD 3) (NOT 6) MOD 3 +1 1 0 +create or replace view v1 as select NOT 6 % 3, NOT (6 % 3), (NOT 6) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(6 % 3) AS `NOT 6 % 3`,!(6 % 3) AS `NOT (6 % 3)`,!6 % 3 AS `(NOT 6) % 3` +select NOT 6 % 3, NOT (6 % 3), (NOT 6) % 3 union select * from v1; +NOT 6 % 3 NOT (6 % 3) (NOT 6) % 3 +1 1 0 +create or replace view v1 as select NOT 2 ^ 3, NOT (2 ^ 3), (NOT 2) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(2 ^ 3) AS `NOT 2 ^ 3`,!(2 ^ 3) AS `NOT (2 ^ 3)`,!2 ^ 3 AS `(NOT 2) ^ 3` +select NOT 2 ^ 3, NOT (2 ^ 3), (NOT 2) ^ 3 union select * from v1; +NOT 2 ^ 3 NOT (2 ^ 3) (NOT 2) ^ 3 +0 0 3 +create or replace view v1 as select NOT 2 BETWEEN 3 AND 4, NOT (2 BETWEEN 3 AND 4), (NOT 2) BETWEEN 3 AND 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 not between 3 and 4 AS `NOT 2 BETWEEN 3 AND 4`,2 not between 3 and 4 AS `NOT (2 BETWEEN 3 AND 4)`,!2 between 3 and 4 AS `(NOT 2) BETWEEN 3 AND 4` +select NOT 2 BETWEEN 3 AND 4, NOT (2 BETWEEN 3 AND 4), (NOT 2) BETWEEN 3 AND 4 union select * from v1; +NOT 2 BETWEEN 3 AND 4 NOT (2 BETWEEN 3 AND 4) (NOT 2) BETWEEN 3 AND 4 +1 1 0 +create or replace view v1 as select - 2 IS TRUE, - (2 IS TRUE), (- 2) IS TRUE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 is true AS `- 2 IS TRUE`,-(2 is true) AS `- (2 IS TRUE)`,-2 is true AS `(- 2) IS TRUE` +select - 2 IS TRUE, - (2 IS TRUE), (- 2) IS TRUE union select * from v1; +- 2 IS TRUE - (2 IS TRUE) (- 2) IS TRUE +1 -1 1 +create or replace view v1 as select charset(- "2" COLLATE latin1_bin), charset(- ("2" COLLATE latin1_bin)), charset((- "2") COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(-'2' collate latin1_bin) AS `charset(- "2" COLLATE latin1_bin)`,charset(-'2' collate latin1_bin) AS `charset(- ("2" COLLATE latin1_bin))`,charset((-'2') collate latin1_bin) AS `charset((- "2") COLLATE latin1_bin)` +select charset(- "2" COLLATE latin1_bin), charset(- ("2" COLLATE latin1_bin)), charset((- "2") COLLATE latin1_bin) union select * from v1; +charset(- "2" COLLATE latin1_bin) charset(- ("2" COLLATE latin1_bin)) charset((- "2") COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select - 2 IN (2,1), - (2 IN (2,1)), (- 2) IN (2,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 in (2,1) AS `- 2 IN (2,1)`,-(2 in (2,1)) AS `- (2 IN (2,1))`,-2 in (2,1) AS `(- 2) IN (2,1)` +select - 2 IN (2,1), - (2 IN (2,1)), (- 2) IN (2,1) union select * from v1; +- 2 IN (2,1) - (2 IN (2,1)) (- 2) IN (2,1) +0 -1 0 +create or replace view v1 as select - 2 OR 3, - (2 OR 3), (- 2) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 or 3 AS `- 2 OR 3`,-(2 or 3) AS `- (2 OR 3)`,-2 or 3 AS `(- 2) OR 3` +select - 2 OR 3, - (2 OR 3), (- 2) OR 3 union select * from v1; +- 2 OR 3 - (2 OR 3) (- 2) OR 3 +1 -1 1 +create or replace view v1 as select - 2 || 3, - (2 || 3), (- 2) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 or 3 AS `- 2 || 3`,-(2 or 3) AS `- (2 || 3)`,-2 or 3 AS `(- 2) || 3` +select - 2 || 3, - (2 || 3), (- 2) || 3 union select * from v1; +- 2 || 3 - (2 || 3) (- 2) || 3 +1 -1 1 +create or replace view v1 as select - 0 XOR 3, - (0 XOR 3), (- 0) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 xor 3 AS `- 0 XOR 3`,-(0 xor 3) AS `- (0 XOR 3)`,0 xor 3 AS `(- 0) XOR 3` +select - 0 XOR 3, - (0 XOR 3), (- 0) XOR 3 union select * from v1; +- 0 XOR 3 - (0 XOR 3) (- 0) XOR 3 +1 -1 1 +create or replace view v1 as select - 2 AND 3, - (2 AND 3), (- 2) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 and 3 AS `- 2 AND 3`,-(2 and 3) AS `- (2 AND 3)`,-2 and 3 AS `(- 2) AND 3` +select - 2 AND 3, - (2 AND 3), (- 2) AND 3 union select * from v1; +- 2 AND 3 - (2 AND 3) (- 2) AND 3 +1 -1 1 +create or replace view v1 as select - 2 && 3, - (2 && 3), (- 2) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 and 3 AS `- 2 && 3`,-(2 and 3) AS `- (2 && 3)`,-2 and 3 AS `(- 2) && 3` +select - 2 && 3, - (2 && 3), (- 2) && 3 union select * from v1; +- 2 && 3 - (2 && 3) (- 2) && 3 +1 -1 1 +create or replace view v1 as select - 2 = 2, - (2 = 2), (- 2) = 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 = 2 AS `- 2 = 2`,-(2 = 2) AS `- (2 = 2)`,-2 = 2 AS `(- 2) = 2` +select - 2 = 2, - (2 = 2), (- 2) = 2 union select * from v1; +- 2 = 2 - (2 = 2) (- 2) = 2 +0 -1 0 +create or replace view v1 as select - 2 <=> 2, - (2 <=> 2), (- 2) <=> 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 <=> 2 AS `- 2 <=> 2`,-(2 <=> 2) AS `- (2 <=> 2)`,-2 <=> 2 AS `(- 2) <=> 2` +select - 2 <=> 2, - (2 <=> 2), (- 2) <=> 2 union select * from v1; +- 2 <=> 2 - (2 <=> 2) (- 2) <=> 2 +0 -1 0 +create or replace view v1 as select - 2 >= 1, - (2 >= 1), (- 2) >= 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 >= 1 AS `- 2 >= 1`,-(2 >= 1) AS `- (2 >= 1)`,-2 >= 1 AS `(- 2) >= 1` +select - 2 >= 1, - (2 >= 1), (- 2) >= 1 union select * from v1; +- 2 >= 1 - (2 >= 1) (- 2) >= 1 +0 -1 0 +create or replace view v1 as select - 2 <= 3, - (2 <= 3), (- 2) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 <= 3 AS `- 2 <= 3`,-(2 <= 3) AS `- (2 <= 3)`,-2 <= 3 AS `(- 2) <= 3` +select - 2 <= 3, - (2 <= 3), (- 2) <= 3 union select * from v1; +- 2 <= 3 - (2 <= 3) (- 2) <= 3 +1 -1 1 +create or replace view v1 as select - 2 < 3, - (2 < 3), (- 2) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 < 3 AS `- 2 < 3`,-(2 < 3) AS `- (2 < 3)`,-2 < 3 AS `(- 2) < 3` +select - 2 < 3, - (2 < 3), (- 2) < 3 union select * from v1; +- 2 < 3 - (2 < 3) (- 2) < 3 +1 -1 1 +create or replace view v1 as select - 2 <> 3, - (2 <> 3), (- 2) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 <> 3 AS `- 2 <> 3`,-(2 <> 3) AS `- (2 <> 3)`,-2 <> 3 AS `(- 2) <> 3` +select - 2 <> 3, - (2 <> 3), (- 2) <> 3 union select * from v1; +- 2 <> 3 - (2 <> 3) (- 2) <> 3 +1 -1 1 +create or replace view v1 as select - 2 > 1, - (2 > 1), (- 2) > 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 > 1 AS `- 2 > 1`,-(2 > 1) AS `- (2 > 1)`,-2 > 1 AS `(- 2) > 1` +select - 2 > 1, - (2 > 1), (- 2) > 1 union select * from v1; +- 2 > 1 - (2 > 1) (- 2) > 1 +0 -1 0 +create or replace view v1 as select - 2 != 3, - (2 != 3), (- 2) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 <> 3 AS `- 2 != 3`,-(2 <> 3) AS `- (2 != 3)`,-2 <> 3 AS `(- 2) != 3` +select - 2 != 3, - (2 != 3), (- 2) != 3 union select * from v1; +- 2 != 3 - (2 != 3) (- 2) != 3 +1 -1 1 +create or replace view v1 as select - 2 LIKE 2, - (2 LIKE 2), (- 2) LIKE 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 like 2 AS `- 2 LIKE 2`,-(2 like 2) AS `- (2 LIKE 2)`,-2 like 2 AS `(- 2) LIKE 2` +select - 2 LIKE 2, - (2 LIKE 2), (- 2) LIKE 2 union select * from v1; +- 2 LIKE 2 - (2 LIKE 2) (- 2) LIKE 2 +0 -1 0 +create or replace view v1 as select - 2 REGEXP 2, - (2 REGEXP 2), (- 2) REGEXP 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 regexp 2 AS `- 2 REGEXP 2`,-(2 regexp 2) AS `- (2 REGEXP 2)`,-2 regexp 2 AS `(- 2) REGEXP 2` +select - 2 REGEXP 2, - (2 REGEXP 2), (- 2) REGEXP 2 union select * from v1; +- 2 REGEXP 2 - (2 REGEXP 2) (- 2) REGEXP 2 +1 -1 1 +create or replace view v1 as select - 2 | 3, - (2 | 3), (- 2) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 | 3 AS `- 2 | 3`,-(2 | 3) AS `- (2 | 3)`,-2 | 3 AS `(- 2) | 3` +select - 2 | 3, - (2 | 3), (- 2) | 3 union select * from v1; +- 2 | 3 - (2 | 3) (- 2) | 3 +18446744073709551615 -3 18446744073709551615 +create or replace view v1 as select - 2 & 3, - (2 & 3), (- 2) & 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 & 3 AS `- 2 & 3`,-(2 & 3) AS `- (2 & 3)`,-2 & 3 AS `(- 2) & 3` +select - 2 & 3, - (2 & 3), (- 2) & 3 union select * from v1; +- 2 & 3 - (2 & 3) (- 2) & 3 +2 -2 2 +create or replace view v1 as select - 2 << 3, - (2 << 3), (- 2) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 << 3 AS `- 2 << 3`,-(2 << 3) AS `- (2 << 3)`,-2 << 3 AS `(- 2) << 3` +select - 2 << 3, - (2 << 3), (- 2) << 3 union select * from v1; +- 2 << 3 - (2 << 3) (- 2) << 3 +18446744073709551600 -16 18446744073709551600 +create or replace view v1 as select - 2 >> 3, - (2 >> 3), (- 2) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 >> 3 AS `- 2 >> 3`,-(2 >> 3) AS `- (2 >> 3)`,-2 >> 3 AS `(- 2) >> 3` +select - 2 >> 3, - (2 >> 3), (- 2) >> 3 union select * from v1; +- 2 >> 3 - (2 >> 3) (- 2) >> 3 +2305843009213693951 0 2305843009213693951 +create or replace view v1 as select - '2000-01-01' +INTERVAL 1 DAY, - ('2000-01-01' +INTERVAL 1 DAY), (- '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -'2000-01-01' + interval 1 day AS `- '2000-01-01' +INTERVAL 1 DAY`,-('2000-01-01' + interval 1 day) AS `- ('2000-01-01' +INTERVAL 1 DAY)`,-'2000-01-01' + interval 1 day AS `(- '2000-01-01') +INTERVAL 1 DAY` +select - '2000-01-01' +INTERVAL 1 DAY, - ('2000-01-01' +INTERVAL 1 DAY), (- '2000-01-01') +INTERVAL 1 DAY union select * from v1; +- '2000-01-01' +INTERVAL 1 DAY - ('2000-01-01' +INTERVAL 1 DAY) (- '2000-01-01') +INTERVAL 1 DAY +NULL -20000102 NULL +create or replace view v1 as select - 2 + 3, - (2 + 3), (- 2) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 + 3 AS `- 2 + 3`,-(2 + 3) AS `- (2 + 3)`,-2 + 3 AS `(- 2) + 3` +select - 2 + 3, - (2 + 3), (- 2) + 3 union select * from v1; +- 2 + 3 - (2 + 3) (- 2) + 3 +1 -5 1 +create or replace view v1 as select - 2 - 3, - (2 - 3), (- 2) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 - 3 AS `- 2 - 3`,-(2 - 3) AS `- (2 - 3)`,-2 - 3 AS `(- 2) - 3` +select - 2 - 3, - (2 - 3), (- 2) - 3 union select * from v1; +- 2 - 3 - (2 - 3) (- 2) - 3 +-5 1 -5 +create or replace view v1 as select - 2 ^ 3, - (2 ^ 3), (- 2) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 ^ 3 AS `- 2 ^ 3`,-(2 ^ 3) AS `- (2 ^ 3)`,-2 ^ 3 AS `(- 2) ^ 3` +select - 2 ^ 3, - (2 ^ 3), (- 2) ^ 3 union select * from v1; +- 2 ^ 3 - (2 ^ 3) (- 2) ^ 3 +18446744073709551613 -1 18446744073709551613 +create or replace view v1 as select - 2 BETWEEN 1 AND 3, - (2 BETWEEN 1 AND 3), (- 2) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 between 1 and 3 AS `- 2 BETWEEN 1 AND 3`,-(2 between 1 and 3) AS `- (2 BETWEEN 1 AND 3)`,-2 between 1 and 3 AS `(- 2) BETWEEN 1 AND 3` +select - 2 BETWEEN 1 AND 3, - (2 BETWEEN 1 AND 3), (- 2) BETWEEN 1 AND 3 union select * from v1; +- 2 BETWEEN 1 AND 3 - (2 BETWEEN 1 AND 3) (- 2) BETWEEN 1 AND 3 +0 -1 0 +create or replace view v1 as select ~ 2 IS TRUE, ~ (2 IS TRUE), (~ 2) IS TRUE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 is true AS `~ 2 IS TRUE`,~(2 is true) AS `~ (2 IS TRUE)`,~2 is true AS `(~ 2) IS TRUE` +select ~ 2 IS TRUE, ~ (2 IS TRUE), (~ 2) IS TRUE union select * from v1; +~ 2 IS TRUE ~ (2 IS TRUE) (~ 2) IS TRUE +1 18446744073709551614 1 +create or replace view v1 as select charset(~ 2 COLLATE latin1_bin), charset(~ (2 COLLATE latin1_bin)), charset((~ 2) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(~2 collate latin1_bin) AS `charset(~ 2 COLLATE latin1_bin)`,charset(~2 collate latin1_bin) AS `charset(~ (2 COLLATE latin1_bin))`,charset((~2) collate latin1_bin) AS `charset((~ 2) COLLATE latin1_bin)` +select charset(~ 2 COLLATE latin1_bin), charset(~ (2 COLLATE latin1_bin)), charset((~ 2) COLLATE latin1_bin) union select * from v1; +charset(~ 2 COLLATE latin1_bin) charset(~ (2 COLLATE latin1_bin)) charset((~ 2) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select ~ 2 IN (0,1), ~ (2 IN (0,1)), (~ 2) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 in (0,1) AS `~ 2 IN (0,1)`,~(2 in (0,1)) AS `~ (2 IN (0,1))`,~2 in (0,1) AS `(~ 2) IN (0,1)` +select ~ 2 IN (0,1), ~ (2 IN (0,1)), (~ 2) IN (0,1) union select * from v1; +~ 2 IN (0,1) ~ (2 IN (0,1)) (~ 2) IN (0,1) +0 18446744073709551615 0 +create or replace view v1 as select ~ 2 OR 3, ~ (2 OR 3), (~ 2) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 or 3 AS `~ 2 OR 3`,~(2 or 3) AS `~ (2 OR 3)`,~2 or 3 AS `(~ 2) OR 3` +select ~ 2 OR 3, ~ (2 OR 3), (~ 2) OR 3 union select * from v1; +~ 2 OR 3 ~ (2 OR 3) (~ 2) OR 3 +1 18446744073709551614 1 +create or replace view v1 as select ~ 2 || 3, ~ (2 || 3), (~ 2) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 or 3 AS `~ 2 || 3`,~(2 or 3) AS `~ (2 || 3)`,~2 or 3 AS `(~ 2) || 3` +select ~ 2 || 3, ~ (2 || 3), (~ 2) || 3 union select * from v1; +~ 2 || 3 ~ (2 || 3) (~ 2) || 3 +1 18446744073709551614 1 +create or replace view v1 as select ~ 2 XOR 3, ~ (2 XOR 3), (~ 2) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 xor 3 AS `~ 2 XOR 3`,~(2 xor 3) AS `~ (2 XOR 3)`,~2 xor 3 AS `(~ 2) XOR 3` +select ~ 2 XOR 3, ~ (2 XOR 3), (~ 2) XOR 3 union select * from v1; +~ 2 XOR 3 ~ (2 XOR 3) (~ 2) XOR 3 +0 18446744073709551615 0 +create or replace view v1 as select ~ 2 AND 3, ~ (2 AND 3), (~ 2) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 and 3 AS `~ 2 AND 3`,~(2 and 3) AS `~ (2 AND 3)`,~2 and 3 AS `(~ 2) AND 3` +select ~ 2 AND 3, ~ (2 AND 3), (~ 2) AND 3 union select * from v1; +~ 2 AND 3 ~ (2 AND 3) (~ 2) AND 3 +1 18446744073709551614 1 +create or replace view v1 as select ~ 2 && 3, ~ (2 && 3), (~ 2) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 and 3 AS `~ 2 && 3`,~(2 and 3) AS `~ (2 && 3)`,~2 and 3 AS `(~ 2) && 3` +select ~ 2 && 3, ~ (2 && 3), (~ 2) && 3 union select * from v1; +~ 2 && 3 ~ (2 && 3) (~ 2) && 3 +1 18446744073709551614 1 +create or replace view v1 as select ~ 2 = 3, ~ (2 = 3), (~ 2) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 = 3 AS `~ 2 = 3`,~(2 = 3) AS `~ (2 = 3)`,~2 = 3 AS `(~ 2) = 3` +select ~ 2 = 3, ~ (2 = 3), (~ 2) = 3 union select * from v1; +~ 2 = 3 ~ (2 = 3) (~ 2) = 3 +0 18446744073709551615 0 +create or replace view v1 as select ~ 2 <=> 3, ~ (2 <=> 3), (~ 2) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 <=> 3 AS `~ 2 <=> 3`,~(2 <=> 3) AS `~ (2 <=> 3)`,~2 <=> 3 AS `(~ 2) <=> 3` +select ~ 2 <=> 3, ~ (2 <=> 3), (~ 2) <=> 3 union select * from v1; +~ 2 <=> 3 ~ (2 <=> 3) (~ 2) <=> 3 +0 18446744073709551615 0 +create or replace view v1 as select ~ 2 >= 3, ~ (2 >= 3), (~ 2) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 >= 3 AS `~ 2 >= 3`,~(2 >= 3) AS `~ (2 >= 3)`,~2 >= 3 AS `(~ 2) >= 3` +select ~ 2 >= 3, ~ (2 >= 3), (~ 2) >= 3 union select * from v1; +~ 2 >= 3 ~ (2 >= 3) (~ 2) >= 3 +1 18446744073709551615 1 +create or replace view v1 as select ~ 2 <= 3, ~ (2 <= 3), (~ 2) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 <= 3 AS `~ 2 <= 3`,~(2 <= 3) AS `~ (2 <= 3)`,~2 <= 3 AS `(~ 2) <= 3` +select ~ 2 <= 3, ~ (2 <= 3), (~ 2) <= 3 union select * from v1; +~ 2 <= 3 ~ (2 <= 3) (~ 2) <= 3 +0 18446744073709551614 0 +create or replace view v1 as select ~ 2 < 3, ~ (2 < 3), (~ 2) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 < 3 AS `~ 2 < 3`,~(2 < 3) AS `~ (2 < 3)`,~2 < 3 AS `(~ 2) < 3` +select ~ 2 < 3, ~ (2 < 3), (~ 2) < 3 union select * from v1; +~ 2 < 3 ~ (2 < 3) (~ 2) < 3 +0 18446744073709551614 0 +create or replace view v1 as select ~ 2 <> 3, ~ (2 <> 3), (~ 2) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 <> 3 AS `~ 2 <> 3`,~(2 <> 3) AS `~ (2 <> 3)`,~2 <> 3 AS `(~ 2) <> 3` +select ~ 2 <> 3, ~ (2 <> 3), (~ 2) <> 3 union select * from v1; +~ 2 <> 3 ~ (2 <> 3) (~ 2) <> 3 +1 18446744073709551614 1 +create or replace view v1 as select ~ 2 > 3, ~ (2 > 3), (~ 2) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 > 3 AS `~ 2 > 3`,~(2 > 3) AS `~ (2 > 3)`,~2 > 3 AS `(~ 2) > 3` +select ~ 2 > 3, ~ (2 > 3), (~ 2) > 3 union select * from v1; +~ 2 > 3 ~ (2 > 3) (~ 2) > 3 +1 18446744073709551615 1 +create or replace view v1 as select ~ 2 != 3, ~ (2 != 3), (~ 2) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 <> 3 AS `~ 2 != 3`,~(2 <> 3) AS `~ (2 != 3)`,~2 <> 3 AS `(~ 2) != 3` +select ~ 2 != 3, ~ (2 != 3), (~ 2) != 3 union select * from v1; +~ 2 != 3 ~ (2 != 3) (~ 2) != 3 +1 18446744073709551614 1 +create or replace view v1 as select ~ 2 LIKE 3, ~ (2 LIKE 3), (~ 2) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 like 3 AS `~ 2 LIKE 3`,~(2 like 3) AS `~ (2 LIKE 3)`,~2 like 3 AS `(~ 2) LIKE 3` +select ~ 2 LIKE 3, ~ (2 LIKE 3), (~ 2) LIKE 3 union select * from v1; +~ 2 LIKE 3 ~ (2 LIKE 3) (~ 2) LIKE 3 +0 18446744073709551615 0 +create or replace view v1 as select ~ 2 REGEXP 3, ~ (2 REGEXP 3), (~ 2) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 regexp 3 AS `~ 2 REGEXP 3`,~(2 regexp 3) AS `~ (2 REGEXP 3)`,~2 regexp 3 AS `(~ 2) REGEXP 3` +select ~ 2 REGEXP 3, ~ (2 REGEXP 3), (~ 2) REGEXP 3 union select * from v1; +~ 2 REGEXP 3 ~ (2 REGEXP 3) (~ 2) REGEXP 3 +1 18446744073709551615 1 +create or replace view v1 as select ~ 2 | 3, ~ (2 | 3), (~ 2) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 | 3 AS `~ 2 | 3`,~(2 | 3) AS `~ (2 | 3)`,~2 | 3 AS `(~ 2) | 3` +select ~ 2 | 3, ~ (2 | 3), (~ 2) | 3 union select * from v1; +~ 2 | 3 ~ (2 | 3) (~ 2) | 3 +18446744073709551615 18446744073709551612 18446744073709551615 +create or replace view v1 as select ~ 2 & 3, ~ (2 & 3), (~ 2) & 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 & 3 AS `~ 2 & 3`,~(2 & 3) AS `~ (2 & 3)`,~2 & 3 AS `(~ 2) & 3` +select ~ 2 & 3, ~ (2 & 3), (~ 2) & 3 union select * from v1; +~ 2 & 3 ~ (2 & 3) (~ 2) & 3 +1 18446744073709551613 1 +create or replace view v1 as select ~ 2 << 3, ~ (2 << 3), (~ 2) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 << 3 AS `~ 2 << 3`,~(2 << 3) AS `~ (2 << 3)`,~2 << 3 AS `(~ 2) << 3` +select ~ 2 << 3, ~ (2 << 3), (~ 2) << 3 union select * from v1; +~ 2 << 3 ~ (2 << 3) (~ 2) << 3 +18446744073709551592 18446744073709551599 18446744073709551592 +create or replace view v1 as select ~ 2 >> 3, ~ (2 >> 3), (~ 2) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 >> 3 AS `~ 2 >> 3`,~(2 >> 3) AS `~ (2 >> 3)`,~2 >> 3 AS `(~ 2) >> 3` +select ~ 2 >> 3, ~ (2 >> 3), (~ 2) >> 3 union select * from v1; +~ 2 >> 3 ~ (2 >> 3) (~ 2) >> 3 +2305843009213693951 18446744073709551615 2305843009213693951 +create or replace view v1 as select ~ '2000-01-01' +INTERVAL 1 DAY, ~ ('2000-01-01' +INTERVAL 1 DAY), (~ '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~'2000-01-01' + interval 1 day AS `~ '2000-01-01' +INTERVAL 1 DAY`,~('2000-01-01' + interval 1 day) AS `~ ('2000-01-01' +INTERVAL 1 DAY)`,~'2000-01-01' + interval 1 day AS `(~ '2000-01-01') +INTERVAL 1 DAY` +select ~ '2000-01-01' +INTERVAL 1 DAY, ~ ('2000-01-01' +INTERVAL 1 DAY), (~ '2000-01-01') +INTERVAL 1 DAY union select * from v1; +~ '2000-01-01' +INTERVAL 1 DAY ~ ('2000-01-01' +INTERVAL 1 DAY) (~ '2000-01-01') +INTERVAL 1 DAY +NULL 18446744073689551513 NULL +create or replace view v1 as select ~ 10000 + 3, ~ (10000 + 3), (~ 10000) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~10000 + 3 AS `~ 10000 + 3`,~(10000 + 3) AS `~ (10000 + 3)`,~10000 + 3 AS `(~ 10000) + 3` +select ~ 10000 + 3, ~ (10000 + 3), (~ 10000) + 3 union select * from v1; +~ 10000 + 3 ~ (10000 + 3) (~ 10000) + 3 +18446744073709541618 18446744073709541612 18446744073709541618 +create or replace view v1 as select ~ 2 - 3, ~ (2 - 3), (~ 2) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 - 3 AS `~ 2 - 3`,~(2 - 3) AS `~ (2 - 3)`,~2 - 3 AS `(~ 2) - 3` +select ~ 2 - 3, ~ (2 - 3), (~ 2) - 3 union select * from v1; +~ 2 - 3 ~ (2 - 3) (~ 2) - 3 +18446744073709551610 0 18446744073709551610 +create or replace view v1 as select ~ 10000000000000000000 * 2, ~ (100 * 2), (~ 10000000000000000000) * 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~10000000000000000000 * 2 AS `~ 10000000000000000000 * 2`,~(100 * 2) AS `~ (100 * 2)`,~10000000000000000000 * 2 AS `(~ 10000000000000000000) * 2` +select ~ 10000000000000000000 * 2, ~ (100 * 2), (~ 10000000000000000000) * 2 union select * from v1; +~ 10000000000000000000 * 2 ~ (100 * 2) (~ 10000000000000000000) * 2 +16893488147419103230 18446744073709551415 16893488147419103230 +create or replace view v1 as select ~ 2 / 3, ~ (2 / 3), (~ 2) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 / 3 AS `~ 2 / 3`,~(2 / 3) AS `~ (2 / 3)`,~2 / 3 AS `(~ 2) / 3` +select ~ 2 / 3, ~ (2 / 3), (~ 2) / 3 union select * from v1; +~ 2 / 3 ~ (2 / 3) (~ 2) / 3 +6148914691236517204.3333 18446744073709551614 6148914691236517204.3333 +create or replace view v1 as select ~ 2 DIV 3, ~ (2 DIV 3), (~ 2) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 DIV 3 AS `~ 2 DIV 3`,~(2 DIV 3) AS `~ (2 DIV 3)`,~2 DIV 3 AS `(~ 2) DIV 3` +select ~ 2 DIV 3, ~ (2 DIV 3), (~ 2) DIV 3 union select * from v1; +~ 2 DIV 3 ~ (2 DIV 3) (~ 2) DIV 3 +6148914691236517204 18446744073709551615 6148914691236517204 +create or replace view v1 as select ~ 2 MOD 3, ~ (2 MOD 3), (~ 2) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 % 3 AS `~ 2 MOD 3`,~(2 % 3) AS `~ (2 MOD 3)`,~2 % 3 AS `(~ 2) MOD 3` +select ~ 2 MOD 3, ~ (2 MOD 3), (~ 2) MOD 3 union select * from v1; +~ 2 MOD 3 ~ (2 MOD 3) (~ 2) MOD 3 +1 18446744073709551613 1 +create or replace view v1 as select ~ 2 % 3, ~ (2 % 3), (~ 2) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 % 3 AS `~ 2 % 3`,~(2 % 3) AS `~ (2 % 3)`,~2 % 3 AS `(~ 2) % 3` +select ~ 2 % 3, ~ (2 % 3), (~ 2) % 3 union select * from v1; +~ 2 % 3 ~ (2 % 3) (~ 2) % 3 +1 18446744073709551613 1 +create or replace view v1 as select ~ 2 BETWEEN 1 AND 3, ~ (2 BETWEEN 1 AND 3), (~ 2) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 between 1 and 3 AS `~ 2 BETWEEN 1 AND 3`,~(2 between 1 and 3) AS `~ (2 BETWEEN 1 AND 3)`,~2 between 1 and 3 AS `(~ 2) BETWEEN 1 AND 3` +select ~ 2 BETWEEN 1 AND 3, ~ (2 BETWEEN 1 AND 3), (~ 2) BETWEEN 1 AND 3 union select * from v1; +~ 2 BETWEEN 1 AND 3 ~ (2 BETWEEN 1 AND 3) (~ 2) BETWEEN 1 AND 3 +0 18446744073709551614 0 +create or replace view v1 as select charset(! 2 COLLATE latin1_bin), charset(! (2 COLLATE latin1_bin)), charset((! 2) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(!2 collate latin1_bin) AS `charset(! 2 COLLATE latin1_bin)`,charset(!2 collate latin1_bin) AS `charset(! (2 COLLATE latin1_bin))`,charset((!2) collate latin1_bin) AS `charset((! 2) COLLATE latin1_bin)` +select charset(! 2 COLLATE latin1_bin), charset(! (2 COLLATE latin1_bin)), charset((! 2) COLLATE latin1_bin) union select * from v1; +charset(! 2 COLLATE latin1_bin) charset(! (2 COLLATE latin1_bin)) charset((! 2) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select ! 2 IN (0,2), ! (2 IN (0,2)), (! 2) IN (0,2); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 in (0,2) AS `! 2 IN (0,2)`,2 not in (0,2) AS `! (2 IN (0,2))`,!2 in (0,2) AS `(! 2) IN (0,2)` +select ! 2 IN (0,2), ! (2 IN (0,2)), (! 2) IN (0,2) union select * from v1; +! 2 IN (0,2) ! (2 IN (0,2)) (! 2) IN (0,2) +1 0 1 +create or replace view v1 as select ! 2 OR 3, ! (2 OR 3), (! 2) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 or 3 AS `! 2 OR 3`,!2 and !3 AS `! (2 OR 3)`,!2 or 3 AS `(! 2) OR 3` +select ! 2 OR 3, ! (2 OR 3), (! 2) OR 3 union select * from v1; +! 2 OR 3 ! (2 OR 3) (! 2) OR 3 +1 0 1 +create or replace view v1 as select ! 2 || 3, ! (2 || 3), (! 2) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 or 3 AS `! 2 || 3`,!2 and !3 AS `! (2 || 3)`,!2 or 3 AS `(! 2) || 3` +select ! 2 || 3, ! (2 || 3), (! 2) || 3 union select * from v1; +! 2 || 3 ! (2 || 3) (! 2) || 3 +1 0 1 +create or replace view v1 as select ! 2 AND 0, ! (2 AND 0), (! 2) AND 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 and 0 AS `! 2 AND 0`,!2 or !0 AS `! (2 AND 0)`,!2 and 0 AS `(! 2) AND 0` +select ! 2 AND 0, ! (2 AND 0), (! 2) AND 0 union select * from v1; +! 2 AND 0 ! (2 AND 0) (! 2) AND 0 +0 1 0 +create or replace view v1 as select ! 2 && 0, ! (2 && 0), (! 2) && 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 and 0 AS `! 2 && 0`,!2 or !0 AS `! (2 && 0)`,!2 and 0 AS `(! 2) && 0` +select ! 2 && 0, ! (2 && 0), (! 2) && 0 union select * from v1; +! 2 && 0 ! (2 && 0) (! 2) && 0 +0 1 0 +create or replace view v1 as select ! 2 = 3, ! (2 = 3), (! 2) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 = 3 AS `! 2 = 3`,2 <> 3 AS `! (2 = 3)`,!2 = 3 AS `(! 2) = 3` +select ! 2 = 3, ! (2 = 3), (! 2) = 3 union select * from v1; +! 2 = 3 ! (2 = 3) (! 2) = 3 +0 1 0 +create or replace view v1 as select ! 2 <=> 3, ! (2 <=> 3), (! 2) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 <=> 3 AS `! 2 <=> 3`,!(2 <=> 3) AS `! (2 <=> 3)`,!2 <=> 3 AS `(! 2) <=> 3` +select ! 2 <=> 3, ! (2 <=> 3), (! 2) <=> 3 union select * from v1; +! 2 <=> 3 ! (2 <=> 3) (! 2) <=> 3 +0 1 0 +create or replace view v1 as select ! 2 >= 3, ! (2 >= 3), (! 2) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 >= 3 AS `! 2 >= 3`,2 < 3 AS `! (2 >= 3)`,!2 >= 3 AS `(! 2) >= 3` +select ! 2 >= 3, ! (2 >= 3), (! 2) >= 3 union select * from v1; +! 2 >= 3 ! (2 >= 3) (! 2) >= 3 +0 1 0 +create or replace view v1 as select ! 2 <= 3, ! (2 <= 3), (! 2) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 <= 3 AS `! 2 <= 3`,2 > 3 AS `! (2 <= 3)`,!2 <= 3 AS `(! 2) <= 3` +select ! 2 <= 3, ! (2 <= 3), (! 2) <= 3 union select * from v1; +! 2 <= 3 ! (2 <= 3) (! 2) <= 3 +1 0 1 +create or replace view v1 as select ! 2 < 3, ! (2 < 3), (! 2) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 < 3 AS `! 2 < 3`,2 >= 3 AS `! (2 < 3)`,!2 < 3 AS `(! 2) < 3` +select ! 2 < 3, ! (2 < 3), (! 2) < 3 union select * from v1; +! 2 < 3 ! (2 < 3) (! 2) < 3 +1 0 1 +create or replace view v1 as select ! 2 <> 3, ! (2 <> 3), (! 2) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 <> 3 AS `! 2 <> 3`,2 = 3 AS `! (2 <> 3)`,!2 <> 3 AS `(! 2) <> 3` +select ! 2 <> 3, ! (2 <> 3), (! 2) <> 3 union select * from v1; +! 2 <> 3 ! (2 <> 3) (! 2) <> 3 +1 0 1 +create or replace view v1 as select ! 2 > 3, ! (2 > 3), (! 2) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 > 3 AS `! 2 > 3`,2 <= 3 AS `! (2 > 3)`,!2 > 3 AS `(! 2) > 3` +select ! 2 > 3, ! (2 > 3), (! 2) > 3 union select * from v1; +! 2 > 3 ! (2 > 3) (! 2) > 3 +0 1 0 +create or replace view v1 as select ! 2 != 3, ! (2 != 3), (! 2) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 <> 3 AS `! 2 != 3`,2 = 3 AS `! (2 != 3)`,!2 <> 3 AS `(! 2) != 3` +select ! 2 != 3, ! (2 != 3), (! 2) != 3 union select * from v1; +! 2 != 3 ! (2 != 3) (! 2) != 3 +1 0 1 +create or replace view v1 as select ! 2 LIKE 3, ! (2 LIKE 3), (! 2) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 like 3 AS `! 2 LIKE 3`,2 not like 3 AS `! (2 LIKE 3)`,!2 like 3 AS `(! 2) LIKE 3` +select ! 2 LIKE 3, ! (2 LIKE 3), (! 2) LIKE 3 union select * from v1; +! 2 LIKE 3 ! (2 LIKE 3) (! 2) LIKE 3 +0 1 0 +create or replace view v1 as select ! 2 REGEXP 3, ! (2 REGEXP 3), (! 2) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 regexp 3 AS `! 2 REGEXP 3`,!(2 regexp 3) AS `! (2 REGEXP 3)`,!2 regexp 3 AS `(! 2) REGEXP 3` +select ! 2 REGEXP 3, ! (2 REGEXP 3), (! 2) REGEXP 3 union select * from v1; +! 2 REGEXP 3 ! (2 REGEXP 3) (! 2) REGEXP 3 +0 1 0 +create or replace view v1 as select ! 2 | 3, ! (2 | 3), (! 2) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 | 3 AS `! 2 | 3`,!(2 | 3) AS `! (2 | 3)`,!2 | 3 AS `(! 2) | 3` +select ! 2 | 3, ! (2 | 3), (! 2) | 3 union select * from v1; +! 2 | 3 ! (2 | 3) (! 2) | 3 +3 0 3 +create or replace view v1 as select ! 2 & 0, ! (2 & 0), (! 2) & 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 & 0 AS `! 2 & 0`,!(2 & 0) AS `! (2 & 0)`,!2 & 0 AS `(! 2) & 0` +select ! 2 & 0, ! (2 & 0), (! 2) & 0 union select * from v1; +! 2 & 0 ! (2 & 0) (! 2) & 0 +0 1 0 +create or replace view v1 as select ! 0 << 3, ! (0 << 3), (! 0) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !0 << 3 AS `! 0 << 3`,!(0 << 3) AS `! (0 << 3)`,!0 << 3 AS `(! 0) << 3` +select ! 0 << 3, ! (0 << 3), (! 0) << 3 union select * from v1; +! 0 << 3 ! (0 << 3) (! 0) << 3 +8 1 8 +create or replace view v1 as select ! 2 >> 3, ! (2 >> 3), (! 2) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 >> 3 AS `! 2 >> 3`,!(2 >> 3) AS `! (2 >> 3)`,!2 >> 3 AS `(! 2) >> 3` +select ! 2 >> 3, ! (2 >> 3), (! 2) >> 3 union select * from v1; +! 2 >> 3 ! (2 >> 3) (! 2) >> 3 +0 1 0 +create or replace view v1 as select ! '2000-01-01' +INTERVAL 1 DAY, ! ('2000-01-01' +INTERVAL 1 DAY), (! '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !'2000-01-01' + interval 1 day AS `! '2000-01-01' +INTERVAL 1 DAY`,!('2000-01-01' + interval 1 day) AS `! ('2000-01-01' +INTERVAL 1 DAY)`,!'2000-01-01' + interval 1 day AS `(! '2000-01-01') +INTERVAL 1 DAY` +select ! '2000-01-01' +INTERVAL 1 DAY, ! ('2000-01-01' +INTERVAL 1 DAY), (! '2000-01-01') +INTERVAL 1 DAY union select * from v1; +! '2000-01-01' +INTERVAL 1 DAY ! ('2000-01-01' +INTERVAL 1 DAY) (! '2000-01-01') +INTERVAL 1 DAY +NULL 0 NULL +create or replace view v1 as select ! 2 + 3, ! (2 + 3), (! 2) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 + 3 AS `! 2 + 3`,!(2 + 3) AS `! (2 + 3)`,!2 + 3 AS `(! 2) + 3` +select ! 2 + 3, ! (2 + 3), (! 2) + 3 union select * from v1; +! 2 + 3 ! (2 + 3) (! 2) + 3 +3 0 3 +create or replace view v1 as select ! 2 - 3, ! (2 - 3), (! 2) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 - 3 AS `! 2 - 3`,!(2 - 3) AS `! (2 - 3)`,!2 - 3 AS `(! 2) - 3` +select ! 2 - 3, ! (2 - 3), (! 2) - 3 union select * from v1; +! 2 - 3 ! (2 - 3) (! 2) - 3 +-3 0 -3 +create or replace view v1 as select ! 0 * 3, ! (0 * 3), (! 0) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !0 * 3 AS `! 0 * 3`,!(0 * 3) AS `! (0 * 3)`,!0 * 3 AS `(! 0) * 3` +select ! 0 * 3, ! (0 * 3), (! 0) * 3 union select * from v1; +! 0 * 3 ! (0 * 3) (! 0) * 3 +3 1 3 +create or replace view v1 as select ! 0 / 3, ! (0 / 3), (! 0) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !0 / 3 AS `! 0 / 3`,!(0 / 3) AS `! (0 / 3)`,!0 / 3 AS `(! 0) / 3` +select ! 0 / 3, ! (0 / 3), (! 0) / 3 union select * from v1; +! 0 / 3 ! (0 / 3) (! 0) / 3 +0.3333 1 0.3333 +create or replace view v1 as select ! 2 DIV 3, ! (2 DIV 3), (! 2) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 DIV 3 AS `! 2 DIV 3`,!(2 DIV 3) AS `! (2 DIV 3)`,!2 DIV 3 AS `(! 2) DIV 3` +select ! 2 DIV 3, ! (2 DIV 3), (! 2) DIV 3 union select * from v1; +! 2 DIV 3 ! (2 DIV 3) (! 2) DIV 3 +0 1 0 +create or replace view v1 as select ! 6 MOD 3, ! (6 MOD 3), (! 6) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !6 % 3 AS `! 6 MOD 3`,!(6 % 3) AS `! (6 MOD 3)`,!6 % 3 AS `(! 6) MOD 3` +select ! 6 MOD 3, ! (6 MOD 3), (! 6) MOD 3 union select * from v1; +! 6 MOD 3 ! (6 MOD 3) (! 6) MOD 3 +0 1 0 +create or replace view v1 as select ! 6 % 3, ! (6 % 3), (! 6) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !6 % 3 AS `! 6 % 3`,!(6 % 3) AS `! (6 % 3)`,!6 % 3 AS `(! 6) % 3` +select ! 6 % 3, ! (6 % 3), (! 6) % 3 union select * from v1; +! 6 % 3 ! (6 % 3) (! 6) % 3 +0 1 0 +create or replace view v1 as select ! 2 ^ 3, ! (2 ^ 3), (! 2) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 ^ 3 AS `! 2 ^ 3`,!(2 ^ 3) AS `! (2 ^ 3)`,!2 ^ 3 AS `(! 2) ^ 3` +select ! 2 ^ 3, ! (2 ^ 3), (! 2) ^ 3 union select * from v1; +! 2 ^ 3 ! (2 ^ 3) (! 2) ^ 3 +3 0 3 +create or replace view v1 as select ! 2 BETWEEN 3 AND 4, ! (2 BETWEEN 3 AND 4), (! 2) BETWEEN 3 AND 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 between 3 and 4 AS `! 2 BETWEEN 3 AND 4`,2 not between 3 and 4 AS `! (2 BETWEEN 3 AND 4)`,!2 between 3 and 4 AS `(! 2) BETWEEN 3 AND 4` +select ! 2 BETWEEN 3 AND 4, ! (2 BETWEEN 3 AND 4), (! 2) BETWEEN 3 AND 4 union select * from v1; +! 2 BETWEEN 3 AND 4 ! (2 BETWEEN 3 AND 4) (! 2) BETWEEN 3 AND 4 +0 1 0 +create or replace view v1 as select CHARSET(BINARY '2' COLLATE latin1_bin), CHARSET(BINARY ('2' COLLATE latin1_bin)), 'error'/*CHARSET((BINARY '2') COLLATE latin1_bin)*/; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(cast('2' collate latin1_bin as char charset binary)) AS `CHARSET(BINARY '2' COLLATE latin1_bin)`,charset(cast('2' collate latin1_bin as char charset binary)) AS `CHARSET(BINARY ('2' COLLATE latin1_bin))`,'error' AS `error` +select CHARSET(BINARY '2' COLLATE latin1_bin), CHARSET(BINARY ('2' COLLATE latin1_bin)), 'error'/*CHARSET((BINARY '2') COLLATE latin1_bin)*/ union select * from v1; +CHARSET(BINARY '2' COLLATE latin1_bin) CHARSET(BINARY ('2' COLLATE latin1_bin)) error +binary binary error +create or replace view v1 as select BINARY 'c' IN ('C','X'), BINARY ('c' IN ('C','X')), (BINARY 'c') IN ('C','X'); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast('c' as char charset binary) in ('C','X') AS `BINARY 'c' IN ('C','X')`,cast('c' in ('C','X') as char charset binary) AS `BINARY ('c' IN ('C','X'))`,cast('c' as char charset binary) in ('C','X') AS `(BINARY 'c') IN ('C','X')` +select BINARY 'c' IN ('C','X'), BINARY ('c' IN ('C','X')), (BINARY 'c') IN ('C','X') union select * from v1; +BINARY 'c' IN ('C','X') BINARY ('c' IN ('C','X')) (BINARY 'c') IN ('C','X') +0 1 0 +create or replace view v1 as select BINARY 'c' = 'C', BINARY ('c' = 'C'), (BINARY 'c') = 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast('c' as char charset binary) = 'C' AS `BINARY 'c' = 'C'`,cast('c' = 'C' as char charset binary) AS `BINARY ('c' = 'C')`,cast('c' as char charset binary) = 'C' AS `(BINARY 'c') = 'C'` +select BINARY 'c' = 'C', BINARY ('c' = 'C'), (BINARY 'c') = 'C' union select * from v1; +BINARY 'c' = 'C' BINARY ('c' = 'C') (BINARY 'c') = 'C' +0 1 0 +create or replace view v1 as select BINARY 'c' <=> 'C', BINARY ('c' <=> 'C'), (BINARY 'c') <=> 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast('c' as char charset binary) <=> 'C' AS `BINARY 'c' <=> 'C'`,cast('c' <=> 'C' as char charset binary) AS `BINARY ('c' <=> 'C')`,cast('c' as char charset binary) <=> 'C' AS `(BINARY 'c') <=> 'C'` +select BINARY 'c' <=> 'C', BINARY ('c' <=> 'C'), (BINARY 'c') <=> 'C' union select * from v1; +BINARY 'c' <=> 'C' BINARY ('c' <=> 'C') (BINARY 'c') <=> 'C' +0 1 0 +create or replace view v1 as select BINARY 'c' >= 'D', BINARY ('c' >= 'D'), (BINARY 'c') >= 'D'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast('c' as char charset binary) >= 'D' AS `BINARY 'c' >= 'D'`,cast('c' >= 'D' as char charset binary) AS `BINARY ('c' >= 'D')`,cast('c' as char charset binary) >= 'D' AS `(BINARY 'c') >= 'D'` +select BINARY 'c' >= 'D', BINARY ('c' >= 'D'), (BINARY 'c') >= 'D' union select * from v1; +BINARY 'c' >= 'D' BINARY ('c' >= 'D') (BINARY 'c') >= 'D' +1 0 1 +create or replace view v1 as select BINARY 'c' <= 'C', BINARY ('c' <= 'C'), (BINARY 'c') <= 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast('c' as char charset binary) <= 'C' AS `BINARY 'c' <= 'C'`,cast('c' <= 'C' as char charset binary) AS `BINARY ('c' <= 'C')`,cast('c' as char charset binary) <= 'C' AS `(BINARY 'c') <= 'C'` +select BINARY 'c' <= 'C', BINARY ('c' <= 'C'), (BINARY 'c') <= 'C' union select * from v1; +BINARY 'c' <= 'C' BINARY ('c' <= 'C') (BINARY 'c') <= 'C' +0 1 0 +create or replace view v1 as select BINARY 'c' < 'D', BINARY ('c' < 'D'), (BINARY 'c') < 'D'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast('c' as char charset binary) < 'D' AS `BINARY 'c' < 'D'`,cast('c' < 'D' as char charset binary) AS `BINARY ('c' < 'D')`,cast('c' as char charset binary) < 'D' AS `(BINARY 'c') < 'D'` +select BINARY 'c' < 'D', BINARY ('c' < 'D'), (BINARY 'c') < 'D' union select * from v1; +BINARY 'c' < 'D' BINARY ('c' < 'D') (BINARY 'c') < 'D' +0 1 0 +create or replace view v1 as select BINARY 'c' <> 'C', BINARY ('c' <> 'C'), (BINARY 'c') <> 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast('c' as char charset binary) <> 'C' AS `BINARY 'c' <> 'C'`,cast('c' <> 'C' as char charset binary) AS `BINARY ('c' <> 'C')`,cast('c' as char charset binary) <> 'C' AS `(BINARY 'c') <> 'C'` +select BINARY 'c' <> 'C', BINARY ('c' <> 'C'), (BINARY 'c') <> 'C' union select * from v1; +BINARY 'c' <> 'C' BINARY ('c' <> 'C') (BINARY 'c') <> 'C' +1 0 1 +create or replace view v1 as select BINARY 'c' > 'C', BINARY ('c' > 'C'), (BINARY 'c') > 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast('c' as char charset binary) > 'C' AS `BINARY 'c' > 'C'`,cast('c' > 'C' as char charset binary) AS `BINARY ('c' > 'C')`,cast('c' as char charset binary) > 'C' AS `(BINARY 'c') > 'C'` +select BINARY 'c' > 'C', BINARY ('c' > 'C'), (BINARY 'c') > 'C' union select * from v1; +BINARY 'c' > 'C' BINARY ('c' > 'C') (BINARY 'c') > 'C' +1 0 1 +create or replace view v1 as select BINARY 'c' != 'C', BINARY ('c' != 'C'), (BINARY 'c') != 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast('c' as char charset binary) <> 'C' AS `BINARY 'c' != 'C'`,cast('c' <> 'C' as char charset binary) AS `BINARY ('c' != 'C')`,cast('c' as char charset binary) <> 'C' AS `(BINARY 'c') != 'C'` +select BINARY 'c' != 'C', BINARY ('c' != 'C'), (BINARY 'c') != 'C' union select * from v1; +BINARY 'c' != 'C' BINARY ('c' != 'C') (BINARY 'c') != 'C' +1 0 1 +create or replace view v1 as select BINARY 'c' LIKE 'C', BINARY ('c' LIKE 'C'), (BINARY 'c') LIKE 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast('c' as char charset binary) like 'C' AS `BINARY 'c' LIKE 'C'`,cast('c' like 'C' as char charset binary) AS `BINARY ('c' LIKE 'C')`,cast('c' as char charset binary) like 'C' AS `(BINARY 'c') LIKE 'C'` +select BINARY 'c' LIKE 'C', BINARY ('c' LIKE 'C'), (BINARY 'c') LIKE 'C' union select * from v1; +BINARY 'c' LIKE 'C' BINARY ('c' LIKE 'C') (BINARY 'c') LIKE 'C' +0 1 0 +create or replace view v1 as select BINARY 'c' REGEXP 'C', BINARY ('c' REGEXP 'C'), (BINARY 'c') REGEXP 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast('c' as char charset binary) regexp 'C' AS `BINARY 'c' REGEXP 'C'`,cast('c' regexp 'C' as char charset binary) AS `BINARY ('c' REGEXP 'C')`,cast('c' as char charset binary) regexp 'C' AS `(BINARY 'c') REGEXP 'C'` +select BINARY 'c' REGEXP 'C', BINARY ('c' REGEXP 'C'), (BINARY 'c') REGEXP 'C' union select * from v1; +BINARY 'c' REGEXP 'C' BINARY ('c' REGEXP 'C') (BINARY 'c') REGEXP 'C' +0 1 0 +create or replace view v1 as select BINARY 'c' BETWEEN 'A' AND 'D', BINARY ('c' BETWEEN 'A' AND 'D'), (BINARY 'c') BETWEEN 'A' AND 'D'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast('c' as char charset binary) between 'A' and 'D' AS `BINARY 'c' BETWEEN 'A' AND 'D'`,cast('c' between 'A' and 'D' as char charset binary) AS `BINARY ('c' BETWEEN 'A' AND 'D')`,cast('c' as char charset binary) between 'A' and 'D' AS `(BINARY 'c') BETWEEN 'A' AND 'D'` +select BINARY 'c' BETWEEN 'A' AND 'D', BINARY ('c' BETWEEN 'A' AND 'D'), (BINARY 'c') BETWEEN 'A' AND 'D' union select * from v1; +BINARY 'c' BETWEEN 'A' AND 'D' BINARY ('c' BETWEEN 'A' AND 'D') (BINARY 'c') BETWEEN 'A' AND 'D' +0 1 0 +create or replace view v1 as select 2 OR 3 IS FALSE, 2 OR (3 IS FALSE), (2 OR 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 is false AS `2 OR 3 IS FALSE`,2 or 3 is false AS `2 OR (3 IS FALSE)`,(2 or 3) is false AS `(2 OR 3) IS FALSE` +select 2 OR 3 IS FALSE, 2 OR (3 IS FALSE), (2 OR 3) IS FALSE union select * from v1; +2 OR 3 IS FALSE 2 OR (3 IS FALSE) (2 OR 3) IS FALSE +1 1 0 +create or replace view v1 as select charset(2 OR 3 COLLATE latin1_bin), charset(2 OR (3 COLLATE latin1_bin)), charset((2 OR 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 or 3 collate latin1_bin) AS `charset(2 OR 3 COLLATE latin1_bin)`,charset(2 or 3 collate latin1_bin) AS `charset(2 OR (3 COLLATE latin1_bin))`,charset((2 or 3) collate latin1_bin) AS `charset((2 OR 3) COLLATE latin1_bin)` +select charset(2 OR 3 COLLATE latin1_bin), charset(2 OR (3 COLLATE latin1_bin)), charset((2 OR 3) COLLATE latin1_bin) union select * from v1; +charset(2 OR 3 COLLATE latin1_bin) charset(2 OR (3 COLLATE latin1_bin)) charset((2 OR 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 0 OR 3 IN (3,10), 0 OR (3 IN (3,10)), (0 OR 3) IN (3,10); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 or 3 in (3,10) AS `0 OR 3 IN (3,10)`,0 or 3 in (3,10) AS `0 OR (3 IN (3,10))`,(0 or 3) in (3,10) AS `(0 OR 3) IN (3,10)` +select 0 OR 3 IN (3,10), 0 OR (3 IN (3,10)), (0 OR 3) IN (3,10) union select * from v1; +0 OR 3 IN (3,10) 0 OR (3 IN (3,10)) (0 OR 3) IN (3,10) +1 1 0 +create or replace view v1 as select 1 OR 0 XOR 1, 1 OR (0 XOR 1), (1 OR 0) XOR 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 or 0 xor 1 AS `1 OR 0 XOR 1`,1 or 0 xor 1 AS `1 OR (0 XOR 1)`,(1 or 0) xor 1 AS `(1 OR 0) XOR 1` +select 1 OR 0 XOR 1, 1 OR (0 XOR 1), (1 OR 0) XOR 1 union select * from v1; +1 OR 0 XOR 1 1 OR (0 XOR 1) (1 OR 0) XOR 1 +1 1 0 +create or replace view v1 as select 1 OR 1 AND 0, 1 OR (1 AND 0), (1 OR 1) AND 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 or 1 and 0 AS `1 OR 1 AND 0`,1 or 1 and 0 AS `1 OR (1 AND 0)`,(1 or 1) and 0 AS `(1 OR 1) AND 0` +select 1 OR 1 AND 0, 1 OR (1 AND 0), (1 OR 1) AND 0 union select * from v1; +1 OR 1 AND 0 1 OR (1 AND 0) (1 OR 1) AND 0 +1 1 0 +create or replace view v1 as select 1 OR 1 && 0, 1 OR (1 && 0), (1 OR 1) && 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 or 1 and 0 AS `1 OR 1 && 0`,1 or 1 and 0 AS `1 OR (1 && 0)`,(1 or 1) and 0 AS `(1 OR 1) && 0` +select 1 OR 1 && 0, 1 OR (1 && 0), (1 OR 1) && 0 union select * from v1; +1 OR 1 && 0 1 OR (1 && 0) (1 OR 1) && 0 +1 1 0 +create or replace view v1 as select 2 OR 3 = 3, 2 OR (3 = 3), (2 OR 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 = 3 AS `2 OR 3 = 3`,2 or 3 = 3 AS `2 OR (3 = 3)`,(2 or 3) = 3 AS `(2 OR 3) = 3` +select 2 OR 3 = 3, 2 OR (3 = 3), (2 OR 3) = 3 union select * from v1; +2 OR 3 = 3 2 OR (3 = 3) (2 OR 3) = 3 +1 1 0 +create or replace view v1 as select 2 OR 3 <=> 3, 2 OR (3 <=> 3), (2 OR 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 <=> 3 AS `2 OR 3 <=> 3`,2 or 3 <=> 3 AS `2 OR (3 <=> 3)`,(2 or 3) <=> 3 AS `(2 OR 3) <=> 3` +select 2 OR 3 <=> 3, 2 OR (3 <=> 3), (2 OR 3) <=> 3 union select * from v1; +2 OR 3 <=> 3 2 OR (3 <=> 3) (2 OR 3) <=> 3 +1 1 0 +create or replace view v1 as select 2 OR 3 >= 3, 2 OR (3 >= 3), (2 OR 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 >= 3 AS `2 OR 3 >= 3`,2 or 3 >= 3 AS `2 OR (3 >= 3)`,(2 or 3) >= 3 AS `(2 OR 3) >= 3` +select 2 OR 3 >= 3, 2 OR (3 >= 3), (2 OR 3) >= 3 union select * from v1; +2 OR 3 >= 3 2 OR (3 >= 3) (2 OR 3) >= 3 +1 1 0 +create or replace view v1 as select 2 OR 3 <= 0, 2 OR (3 <= 0), (2 OR 3) <= 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 <= 0 AS `2 OR 3 <= 0`,2 or 3 <= 0 AS `2 OR (3 <= 0)`,(2 or 3) <= 0 AS `(2 OR 3) <= 0` +select 2 OR 3 <= 0, 2 OR (3 <= 0), (2 OR 3) <= 0 union select * from v1; +2 OR 3 <= 0 2 OR (3 <= 0) (2 OR 3) <= 0 +1 1 0 +create or replace view v1 as select 2 OR 3 < 0, 2 OR (3 < 0), (2 OR 3) < 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 < 0 AS `2 OR 3 < 0`,2 or 3 < 0 AS `2 OR (3 < 0)`,(2 or 3) < 0 AS `(2 OR 3) < 0` +select 2 OR 3 < 0, 2 OR (3 < 0), (2 OR 3) < 0 union select * from v1; +2 OR 3 < 0 2 OR (3 < 0) (2 OR 3) < 0 +1 1 0 +create or replace view v1 as select 0 OR 3 <> 3, 0 OR (3 <> 3), (0 OR 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 or 3 <> 3 AS `0 OR 3 <> 3`,0 or 3 <> 3 AS `0 OR (3 <> 3)`,(0 or 3) <> 3 AS `(0 OR 3) <> 3` +select 0 OR 3 <> 3, 0 OR (3 <> 3), (0 OR 3) <> 3 union select * from v1; +0 OR 3 <> 3 0 OR (3 <> 3) (0 OR 3) <> 3 +0 0 1 +create or replace view v1 as select 2 OR 3 > 3, 2 OR (3 > 3), (2 OR 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 > 3 AS `2 OR 3 > 3`,2 or 3 > 3 AS `2 OR (3 > 3)`,(2 or 3) > 3 AS `(2 OR 3) > 3` +select 2 OR 3 > 3, 2 OR (3 > 3), (2 OR 3) > 3 union select * from v1; +2 OR 3 > 3 2 OR (3 > 3) (2 OR 3) > 3 +1 1 0 +create or replace view v1 as select 0 OR 3 != 3, 0 OR (3 != 3), (0 OR 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 or 3 <> 3 AS `0 OR 3 != 3`,0 or 3 <> 3 AS `0 OR (3 != 3)`,(0 or 3) <> 3 AS `(0 OR 3) != 3` +select 0 OR 3 != 3, 0 OR (3 != 3), (0 OR 3) != 3 union select * from v1; +0 OR 3 != 3 0 OR (3 != 3) (0 OR 3) != 3 +0 0 1 +create or replace view v1 as select 2 OR 3 LIKE 3, 2 OR (3 LIKE 3), (2 OR 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 like 3 AS `2 OR 3 LIKE 3`,2 or 3 like 3 AS `2 OR (3 LIKE 3)`,(2 or 3) like 3 AS `(2 OR 3) LIKE 3` +select 2 OR 3 LIKE 3, 2 OR (3 LIKE 3), (2 OR 3) LIKE 3 union select * from v1; +2 OR 3 LIKE 3 2 OR (3 LIKE 3) (2 OR 3) LIKE 3 +1 1 0 +create or replace view v1 as select 2 OR 3 REGEXP 3, 2 OR (3 REGEXP 3), (2 OR 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 regexp 3 AS `2 OR 3 REGEXP 3`,2 or 3 regexp 3 AS `2 OR (3 REGEXP 3)`,(2 or 3) regexp 3 AS `(2 OR 3) REGEXP 3` +select 2 OR 3 REGEXP 3, 2 OR (3 REGEXP 3), (2 OR 3) REGEXP 3 union select * from v1; +2 OR 3 REGEXP 3 2 OR (3 REGEXP 3) (2 OR 3) REGEXP 3 +1 1 0 +create or replace view v1 as select 2 OR 3 | 3, 2 OR (3 | 3), (2 OR 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 | 3 AS `2 OR 3 | 3`,2 or 3 | 3 AS `2 OR (3 | 3)`,(2 or 3) | 3 AS `(2 OR 3) | 3` +select 2 OR 3 | 3, 2 OR (3 | 3), (2 OR 3) | 3 union select * from v1; +2 OR 3 | 3 2 OR (3 | 3) (2 OR 3) | 3 +1 1 3 +create or replace view v1 as select 0 OR 2 & 2, 0 OR (2 & 2), (0 OR 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 or 2 & 2 AS `0 OR 2 & 2`,0 or 2 & 2 AS `0 OR (2 & 2)`,(0 or 2) & 2 AS `(0 OR 2) & 2` +select 0 OR 2 & 2, 0 OR (2 & 2), (0 OR 2) & 2 union select * from v1; +0 OR 2 & 2 0 OR (2 & 2) (0 OR 2) & 2 +1 1 0 +create or replace view v1 as select 2 OR 3 << 3, 2 OR (3 << 3), (2 OR 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 << 3 AS `2 OR 3 << 3`,2 or 3 << 3 AS `2 OR (3 << 3)`,(2 or 3) << 3 AS `(2 OR 3) << 3` +select 2 OR 3 << 3, 2 OR (3 << 3), (2 OR 3) << 3 union select * from v1; +2 OR 3 << 3 2 OR (3 << 3) (2 OR 3) << 3 +1 1 8 +create or replace view v1 as select 2 OR 3 >> 3, 2 OR (3 >> 3), (2 OR 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 >> 3 AS `2 OR 3 >> 3`,2 or 3 >> 3 AS `2 OR (3 >> 3)`,(2 or 3) >> 3 AS `(2 OR 3) >> 3` +select 2 OR 3 >> 3, 2 OR (3 >> 3), (2 OR 3) >> 3 union select * from v1; +2 OR 3 >> 3 2 OR (3 >> 3) (2 OR 3) >> 3 +1 1 0 +create or replace view v1 as select 2 OR '2000-01-01' +INTERVAL 1 DAY, 2 OR ('2000-01-01' +INTERVAL 1 DAY), (2 OR '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or '2000-01-01' + interval 1 day AS `2 OR '2000-01-01' +INTERVAL 1 DAY`,2 or '2000-01-01' + interval 1 day AS `2 OR ('2000-01-01' +INTERVAL 1 DAY)`,(2 or '2000-01-01') + interval 1 day AS `(2 OR '2000-01-01') +INTERVAL 1 DAY` +select 2 OR '2000-01-01' +INTERVAL 1 DAY, 2 OR ('2000-01-01' +INTERVAL 1 DAY), (2 OR '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 OR '2000-01-01' +INTERVAL 1 DAY 2 OR ('2000-01-01' +INTERVAL 1 DAY) (2 OR '2000-01-01') +INTERVAL 1 DAY +1 1 NULL +create or replace view v1 as select 2 OR 3 + 3, 2 OR (3 + 3), (2 OR 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 + 3 AS `2 OR 3 + 3`,2 or 3 + 3 AS `2 OR (3 + 3)`,(2 or 3) + 3 AS `(2 OR 3) + 3` +select 2 OR 3 + 3, 2 OR (3 + 3), (2 OR 3) + 3 union select * from v1; +2 OR 3 + 3 2 OR (3 + 3) (2 OR 3) + 3 +1 1 4 +create or replace view v1 as select 2 OR 3 - 3, 2 OR (3 - 3), (2 OR 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 - 3 AS `2 OR 3 - 3`,2 or 3 - 3 AS `2 OR (3 - 3)`,(2 or 3) - 3 AS `(2 OR 3) - 3` +select 2 OR 3 - 3, 2 OR (3 - 3), (2 OR 3) - 3 union select * from v1; +2 OR 3 - 3 2 OR (3 - 3) (2 OR 3) - 3 +1 1 -2 +create or replace view v1 as select 2 OR 3 * 3, 2 OR (3 * 3), (2 OR 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 * 3 AS `2 OR 3 * 3`,2 or 3 * 3 AS `2 OR (3 * 3)`,(2 or 3) * 3 AS `(2 OR 3) * 3` +select 2 OR 3 * 3, 2 OR (3 * 3), (2 OR 3) * 3 union select * from v1; +2 OR 3 * 3 2 OR (3 * 3) (2 OR 3) * 3 +1 1 3 +create or replace view v1 as select 2 OR 3 / 3, 2 OR (3 / 3), (2 OR 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 / 3 AS `2 OR 3 / 3`,2 or 3 / 3 AS `2 OR (3 / 3)`,(2 or 3) / 3 AS `(2 OR 3) / 3` +select 2 OR 3 / 3, 2 OR (3 / 3), (2 OR 3) / 3 union select * from v1; +2 OR 3 / 3 2 OR (3 / 3) (2 OR 3) / 3 +1 1 0.3333 +create or replace view v1 as select 2 OR 3 DIV 3, 2 OR (3 DIV 3), (2 OR 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 DIV 3 AS `2 OR 3 DIV 3`,2 or 3 DIV 3 AS `2 OR (3 DIV 3)`,(2 or 3) DIV 3 AS `(2 OR 3) DIV 3` +select 2 OR 3 DIV 3, 2 OR (3 DIV 3), (2 OR 3) DIV 3 union select * from v1; +2 OR 3 DIV 3 2 OR (3 DIV 3) (2 OR 3) DIV 3 +1 1 0 +create or replace view v1 as select 0 OR 3 MOD 3, 0 OR (3 MOD 3), (0 OR 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 or 3 % 3 AS `0 OR 3 MOD 3`,0 or 3 % 3 AS `0 OR (3 MOD 3)`,(0 or 3) % 3 AS `(0 OR 3) MOD 3` +select 0 OR 3 MOD 3, 0 OR (3 MOD 3), (0 OR 3) MOD 3 union select * from v1; +0 OR 3 MOD 3 0 OR (3 MOD 3) (0 OR 3) MOD 3 +0 0 1 +create or replace view v1 as select 0 OR 3 % 3, 0 OR (3 % 3), (0 OR 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 or 3 % 3 AS `0 OR 3 % 3`,0 or 3 % 3 AS `0 OR (3 % 3)`,(0 or 3) % 3 AS `(0 OR 3) % 3` +select 0 OR 3 % 3, 0 OR (3 % 3), (0 OR 3) % 3 union select * from v1; +0 OR 3 % 3 0 OR (3 % 3) (0 OR 3) % 3 +0 0 1 +create or replace view v1 as select 2 OR 3 ^ 3, 2 OR (3 ^ 3), (2 OR 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 ^ 3 AS `2 OR 3 ^ 3`,2 or 3 ^ 3 AS `2 OR (3 ^ 3)`,(2 or 3) ^ 3 AS `(2 OR 3) ^ 3` +select 2 OR 3 ^ 3, 2 OR (3 ^ 3), (2 OR 3) ^ 3 union select * from v1; +2 OR 3 ^ 3 2 OR (3 ^ 3) (2 OR 3) ^ 3 +1 1 2 +create or replace view v1 as select 2 OR 3 BETWEEN 2 AND 3, 2 OR (3 BETWEEN 2 AND 3), (2 OR 3) BETWEEN 2 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 between 2 and 3 AS `2 OR 3 BETWEEN 2 AND 3`,2 or 3 between 2 and 3 AS `2 OR (3 BETWEEN 2 AND 3)`,(2 or 3) between 2 and 3 AS `(2 OR 3) BETWEEN 2 AND 3` +select 2 OR 3 BETWEEN 2 AND 3, 2 OR (3 BETWEEN 2 AND 3), (2 OR 3) BETWEEN 2 AND 3 union select * from v1; +2 OR 3 BETWEEN 2 AND 3 2 OR (3 BETWEEN 2 AND 3) (2 OR 3) BETWEEN 2 AND 3 +1 1 0 +create or replace view v1 as select 2 || 3 IS FALSE, 2 || (3 IS FALSE), (2 || 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 is false AS `2 || 3 IS FALSE`,2 or 3 is false AS `2 || (3 IS FALSE)`,(2 or 3) is false AS `(2 || 3) IS FALSE` +select 2 || 3 IS FALSE, 2 || (3 IS FALSE), (2 || 3) IS FALSE union select * from v1; +2 || 3 IS FALSE 2 || (3 IS FALSE) (2 || 3) IS FALSE +1 1 0 +create or replace view v1 as select charset(2 || 3 COLLATE latin1_bin), charset(2 || (3 COLLATE latin1_bin)), charset((2 || 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 or 3 collate latin1_bin) AS `charset(2 || 3 COLLATE latin1_bin)`,charset(2 or 3 collate latin1_bin) AS `charset(2 || (3 COLLATE latin1_bin))`,charset((2 or 3) collate latin1_bin) AS `charset((2 || 3) COLLATE latin1_bin)` +select charset(2 || 3 COLLATE latin1_bin), charset(2 || (3 COLLATE latin1_bin)), charset((2 || 3) COLLATE latin1_bin) union select * from v1; +charset(2 || 3 COLLATE latin1_bin) charset(2 || (3 COLLATE latin1_bin)) charset((2 || 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 0 || 3 IN (3,10), 0 || (3 IN (3,10)), (0 || 3) IN (3,10); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 or 3 in (3,10) AS `0 || 3 IN (3,10)`,0 or 3 in (3,10) AS `0 || (3 IN (3,10))`,(0 or 3) in (3,10) AS `(0 || 3) IN (3,10)` +select 0 || 3 IN (3,10), 0 || (3 IN (3,10)), (0 || 3) IN (3,10) union select * from v1; +0 || 3 IN (3,10) 0 || (3 IN (3,10)) (0 || 3) IN (3,10) +1 1 0 +create or replace view v1 as select 1 || 0 XOR 1, 1 || (0 XOR 1), (1 || 0) XOR 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 or 0 xor 1 AS `1 || 0 XOR 1`,1 or 0 xor 1 AS `1 || (0 XOR 1)`,(1 or 0) xor 1 AS `(1 || 0) XOR 1` +select 1 || 0 XOR 1, 1 || (0 XOR 1), (1 || 0) XOR 1 union select * from v1; +1 || 0 XOR 1 1 || (0 XOR 1) (1 || 0) XOR 1 +1 1 0 +create or replace view v1 as select 1 || 1 AND 0, 1 || (1 AND 0), (1 || 1) AND 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 or 1 and 0 AS `1 || 1 AND 0`,1 or 1 and 0 AS `1 || (1 AND 0)`,(1 or 1) and 0 AS `(1 || 1) AND 0` +select 1 || 1 AND 0, 1 || (1 AND 0), (1 || 1) AND 0 union select * from v1; +1 || 1 AND 0 1 || (1 AND 0) (1 || 1) AND 0 +1 1 0 +create or replace view v1 as select 1 || 1 && 0, 1 || (1 && 0), (1 || 1) && 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 or 1 and 0 AS `1 || 1 && 0`,1 or 1 and 0 AS `1 || (1 && 0)`,(1 or 1) and 0 AS `(1 || 1) && 0` +select 1 || 1 && 0, 1 || (1 && 0), (1 || 1) && 0 union select * from v1; +1 || 1 && 0 1 || (1 && 0) (1 || 1) && 0 +1 1 0 +create or replace view v1 as select 2 || 3 = 3, 2 || (3 = 3), (2 || 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 = 3 AS `2 || 3 = 3`,2 or 3 = 3 AS `2 || (3 = 3)`,(2 or 3) = 3 AS `(2 || 3) = 3` +select 2 || 3 = 3, 2 || (3 = 3), (2 || 3) = 3 union select * from v1; +2 || 3 = 3 2 || (3 = 3) (2 || 3) = 3 +1 1 0 +create or replace view v1 as select 2 || 3 <=> 3, 2 || (3 <=> 3), (2 || 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 <=> 3 AS `2 || 3 <=> 3`,2 or 3 <=> 3 AS `2 || (3 <=> 3)`,(2 or 3) <=> 3 AS `(2 || 3) <=> 3` +select 2 || 3 <=> 3, 2 || (3 <=> 3), (2 || 3) <=> 3 union select * from v1; +2 || 3 <=> 3 2 || (3 <=> 3) (2 || 3) <=> 3 +1 1 0 +create or replace view v1 as select 2 || 3 >= 3, 2 || (3 >= 3), (2 || 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 >= 3 AS `2 || 3 >= 3`,2 or 3 >= 3 AS `2 || (3 >= 3)`,(2 or 3) >= 3 AS `(2 || 3) >= 3` +select 2 || 3 >= 3, 2 || (3 >= 3), (2 || 3) >= 3 union select * from v1; +2 || 3 >= 3 2 || (3 >= 3) (2 || 3) >= 3 +1 1 0 +create or replace view v1 as select 2 || 3 <= 0, 2 || (3 <= 0), (2 || 3) <= 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 <= 0 AS `2 || 3 <= 0`,2 or 3 <= 0 AS `2 || (3 <= 0)`,(2 or 3) <= 0 AS `(2 || 3) <= 0` +select 2 || 3 <= 0, 2 || (3 <= 0), (2 || 3) <= 0 union select * from v1; +2 || 3 <= 0 2 || (3 <= 0) (2 || 3) <= 0 +1 1 0 +create or replace view v1 as select 2 || 3 < 0, 2 || (3 < 0), (2 || 3) < 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 < 0 AS `2 || 3 < 0`,2 or 3 < 0 AS `2 || (3 < 0)`,(2 or 3) < 0 AS `(2 || 3) < 0` +select 2 || 3 < 0, 2 || (3 < 0), (2 || 3) < 0 union select * from v1; +2 || 3 < 0 2 || (3 < 0) (2 || 3) < 0 +1 1 0 +create or replace view v1 as select 0 || 3 <> 3, 0 || (3 <> 3), (0 || 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 or 3 <> 3 AS `0 || 3 <> 3`,0 or 3 <> 3 AS `0 || (3 <> 3)`,(0 or 3) <> 3 AS `(0 || 3) <> 3` +select 0 || 3 <> 3, 0 || (3 <> 3), (0 || 3) <> 3 union select * from v1; +0 || 3 <> 3 0 || (3 <> 3) (0 || 3) <> 3 +0 0 1 +create or replace view v1 as select 2 || 3 > 3, 2 || (3 > 3), (2 || 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 > 3 AS `2 || 3 > 3`,2 or 3 > 3 AS `2 || (3 > 3)`,(2 or 3) > 3 AS `(2 || 3) > 3` +select 2 || 3 > 3, 2 || (3 > 3), (2 || 3) > 3 union select * from v1; +2 || 3 > 3 2 || (3 > 3) (2 || 3) > 3 +1 1 0 +create or replace view v1 as select 0 || 3 != 3, 0 || (3 != 3), (0 || 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 or 3 <> 3 AS `0 || 3 != 3`,0 or 3 <> 3 AS `0 || (3 != 3)`,(0 or 3) <> 3 AS `(0 || 3) != 3` +select 0 || 3 != 3, 0 || (3 != 3), (0 || 3) != 3 union select * from v1; +0 || 3 != 3 0 || (3 != 3) (0 || 3) != 3 +0 0 1 +create or replace view v1 as select 2 || 3 LIKE 3, 2 || (3 LIKE 3), (2 || 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 like 3 AS `2 || 3 LIKE 3`,2 or 3 like 3 AS `2 || (3 LIKE 3)`,(2 or 3) like 3 AS `(2 || 3) LIKE 3` +select 2 || 3 LIKE 3, 2 || (3 LIKE 3), (2 || 3) LIKE 3 union select * from v1; +2 || 3 LIKE 3 2 || (3 LIKE 3) (2 || 3) LIKE 3 +1 1 0 +create or replace view v1 as select 2 || 3 REGEXP 3, 2 || (3 REGEXP 3), (2 || 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 regexp 3 AS `2 || 3 REGEXP 3`,2 or 3 regexp 3 AS `2 || (3 REGEXP 3)`,(2 or 3) regexp 3 AS `(2 || 3) REGEXP 3` +select 2 || 3 REGEXP 3, 2 || (3 REGEXP 3), (2 || 3) REGEXP 3 union select * from v1; +2 || 3 REGEXP 3 2 || (3 REGEXP 3) (2 || 3) REGEXP 3 +1 1 0 +create or replace view v1 as select 2 || 3 | 3, 2 || (3 | 3), (2 || 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 | 3 AS `2 || 3 | 3`,2 or 3 | 3 AS `2 || (3 | 3)`,(2 or 3) | 3 AS `(2 || 3) | 3` +select 2 || 3 | 3, 2 || (3 | 3), (2 || 3) | 3 union select * from v1; +2 || 3 | 3 2 || (3 | 3) (2 || 3) | 3 +1 1 3 +create or replace view v1 as select 0 || 2 & 2, 0 || (2 & 2), (0 || 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 or 2 & 2 AS `0 || 2 & 2`,0 or 2 & 2 AS `0 || (2 & 2)`,(0 or 2) & 2 AS `(0 || 2) & 2` +select 0 || 2 & 2, 0 || (2 & 2), (0 || 2) & 2 union select * from v1; +0 || 2 & 2 0 || (2 & 2) (0 || 2) & 2 +1 1 0 +create or replace view v1 as select 2 || 3 << 3, 2 || (3 << 3), (2 || 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 << 3 AS `2 || 3 << 3`,2 or 3 << 3 AS `2 || (3 << 3)`,(2 or 3) << 3 AS `(2 || 3) << 3` +select 2 || 3 << 3, 2 || (3 << 3), (2 || 3) << 3 union select * from v1; +2 || 3 << 3 2 || (3 << 3) (2 || 3) << 3 +1 1 8 +create or replace view v1 as select 2 || 3 >> 3, 2 || (3 >> 3), (2 || 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 >> 3 AS `2 || 3 >> 3`,2 or 3 >> 3 AS `2 || (3 >> 3)`,(2 or 3) >> 3 AS `(2 || 3) >> 3` +select 2 || 3 >> 3, 2 || (3 >> 3), (2 || 3) >> 3 union select * from v1; +2 || 3 >> 3 2 || (3 >> 3) (2 || 3) >> 3 +1 1 0 +create or replace view v1 as select 2 || '2000-01-01' +INTERVAL 1 DAY, 2 || ('2000-01-01' +INTERVAL 1 DAY), (2 || '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or '2000-01-01' + interval 1 day AS `2 || '2000-01-01' +INTERVAL 1 DAY`,2 or '2000-01-01' + interval 1 day AS `2 || ('2000-01-01' +INTERVAL 1 DAY)`,(2 or '2000-01-01') + interval 1 day AS `(2 || '2000-01-01') +INTERVAL 1 DAY` +select 2 || '2000-01-01' +INTERVAL 1 DAY, 2 || ('2000-01-01' +INTERVAL 1 DAY), (2 || '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 || '2000-01-01' +INTERVAL 1 DAY 2 || ('2000-01-01' +INTERVAL 1 DAY) (2 || '2000-01-01') +INTERVAL 1 DAY +1 1 NULL +create or replace view v1 as select 2 || 3 + 3, 2 || (3 + 3), (2 || 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 + 3 AS `2 || 3 + 3`,2 or 3 + 3 AS `2 || (3 + 3)`,(2 or 3) + 3 AS `(2 || 3) + 3` +select 2 || 3 + 3, 2 || (3 + 3), (2 || 3) + 3 union select * from v1; +2 || 3 + 3 2 || (3 + 3) (2 || 3) + 3 +1 1 4 +create or replace view v1 as select 2 || 3 - 3, 2 || (3 - 3), (2 || 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 - 3 AS `2 || 3 - 3`,2 or 3 - 3 AS `2 || (3 - 3)`,(2 or 3) - 3 AS `(2 || 3) - 3` +select 2 || 3 - 3, 2 || (3 - 3), (2 || 3) - 3 union select * from v1; +2 || 3 - 3 2 || (3 - 3) (2 || 3) - 3 +1 1 -2 +create or replace view v1 as select 2 || 3 * 3, 2 || (3 * 3), (2 || 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 * 3 AS `2 || 3 * 3`,2 or 3 * 3 AS `2 || (3 * 3)`,(2 or 3) * 3 AS `(2 || 3) * 3` +select 2 || 3 * 3, 2 || (3 * 3), (2 || 3) * 3 union select * from v1; +2 || 3 * 3 2 || (3 * 3) (2 || 3) * 3 +1 1 3 +create or replace view v1 as select 2 || 3 / 3, 2 || (3 / 3), (2 || 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 / 3 AS `2 || 3 / 3`,2 or 3 / 3 AS `2 || (3 / 3)`,(2 or 3) / 3 AS `(2 || 3) / 3` +select 2 || 3 / 3, 2 || (3 / 3), (2 || 3) / 3 union select * from v1; +2 || 3 / 3 2 || (3 / 3) (2 || 3) / 3 +1 1 0.3333 +create or replace view v1 as select 2 || 3 DIV 3, 2 || (3 DIV 3), (2 || 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 DIV 3 AS `2 || 3 DIV 3`,2 or 3 DIV 3 AS `2 || (3 DIV 3)`,(2 or 3) DIV 3 AS `(2 || 3) DIV 3` +select 2 || 3 DIV 3, 2 || (3 DIV 3), (2 || 3) DIV 3 union select * from v1; +2 || 3 DIV 3 2 || (3 DIV 3) (2 || 3) DIV 3 +1 1 0 +create or replace view v1 as select 0 || 3 MOD 3, 0 || (3 MOD 3), (0 || 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 or 3 % 3 AS `0 || 3 MOD 3`,0 or 3 % 3 AS `0 || (3 MOD 3)`,(0 or 3) % 3 AS `(0 || 3) MOD 3` +select 0 || 3 MOD 3, 0 || (3 MOD 3), (0 || 3) MOD 3 union select * from v1; +0 || 3 MOD 3 0 || (3 MOD 3) (0 || 3) MOD 3 +0 0 1 +create or replace view v1 as select 0 || 3 % 3, 0 || (3 % 3), (0 || 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 or 3 % 3 AS `0 || 3 % 3`,0 or 3 % 3 AS `0 || (3 % 3)`,(0 or 3) % 3 AS `(0 || 3) % 3` +select 0 || 3 % 3, 0 || (3 % 3), (0 || 3) % 3 union select * from v1; +0 || 3 % 3 0 || (3 % 3) (0 || 3) % 3 +0 0 1 +create or replace view v1 as select 2 || 3 ^ 3, 2 || (3 ^ 3), (2 || 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 ^ 3 AS `2 || 3 ^ 3`,2 or 3 ^ 3 AS `2 || (3 ^ 3)`,(2 or 3) ^ 3 AS `(2 || 3) ^ 3` +select 2 || 3 ^ 3, 2 || (3 ^ 3), (2 || 3) ^ 3 union select * from v1; +2 || 3 ^ 3 2 || (3 ^ 3) (2 || 3) ^ 3 +1 1 2 +create or replace view v1 as select 2 || 3 BETWEEN 2 AND 3, 2 || (3 BETWEEN 2 AND 3), (2 || 3) BETWEEN 2 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or 3 between 2 and 3 AS `2 || 3 BETWEEN 2 AND 3`,2 or 3 between 2 and 3 AS `2 || (3 BETWEEN 2 AND 3)`,(2 or 3) between 2 and 3 AS `(2 || 3) BETWEEN 2 AND 3` +select 2 || 3 BETWEEN 2 AND 3, 2 || (3 BETWEEN 2 AND 3), (2 || 3) BETWEEN 2 AND 3 union select * from v1; +2 || 3 BETWEEN 2 AND 3 2 || (3 BETWEEN 2 AND 3) (2 || 3) BETWEEN 2 AND 3 +1 1 0 +create or replace view v1 as select charset(2 XOR 3 COLLATE latin1_bin), charset(2 XOR (3 COLLATE latin1_bin)), charset((2 XOR 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 xor 3 collate latin1_bin) AS `charset(2 XOR 3 COLLATE latin1_bin)`,charset(2 xor 3 collate latin1_bin) AS `charset(2 XOR (3 COLLATE latin1_bin))`,charset((2 xor 3) collate latin1_bin) AS `charset((2 XOR 3) COLLATE latin1_bin)` +select charset(2 XOR 3 COLLATE latin1_bin), charset(2 XOR (3 COLLATE latin1_bin)), charset((2 XOR 3) COLLATE latin1_bin) union select * from v1; +charset(2 XOR 3 COLLATE latin1_bin) charset(2 XOR (3 COLLATE latin1_bin)) charset((2 XOR 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 XOR 3 IN (4,5), 2 XOR (3 IN (4,5)), (2 XOR 3) IN (4,5); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 3 in (4,5) AS `2 XOR 3 IN (4,5)`,2 xor 3 in (4,5) AS `2 XOR (3 IN (4,5))`,(2 xor 3) in (4,5) AS `(2 XOR 3) IN (4,5)` +select 2 XOR 3 IN (4,5), 2 XOR (3 IN (4,5)), (2 XOR 3) IN (4,5) union select * from v1; +2 XOR 3 IN (4,5) 2 XOR (3 IN (4,5)) (2 XOR 3) IN (4,5) +1 1 0 +create or replace view v1 as select 2 XOR 3 OR 3, 2 XOR (3 OR 3), (2 XOR 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 3 or 3 AS `2 XOR 3 OR 3`,2 xor (3 or 3) AS `2 XOR (3 OR 3)`,2 xor 3 or 3 AS `(2 XOR 3) OR 3` +select 2 XOR 3 OR 3, 2 XOR (3 OR 3), (2 XOR 3) OR 3 union select * from v1; +2 XOR 3 OR 3 2 XOR (3 OR 3) (2 XOR 3) OR 3 +1 0 1 +create or replace view v1 as select 2 XOR 3 || 3, 2 XOR (3 || 3), (2 XOR 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 3 or 3 AS `2 XOR 3 || 3`,2 xor (3 or 3) AS `2 XOR (3 || 3)`,2 xor 3 or 3 AS `(2 XOR 3) || 3` +select 2 XOR 3 || 3, 2 XOR (3 || 3), (2 XOR 3) || 3 union select * from v1; +2 XOR 3 || 3 2 XOR (3 || 3) (2 XOR 3) || 3 +1 0 1 +create or replace view v1 as select 2 XOR 0 AND 0, 2 XOR (0 AND 0), (2 XOR 0) AND 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 0 and 0 AS `2 XOR 0 AND 0`,2 xor 0 and 0 AS `2 XOR (0 AND 0)`,(2 xor 0) and 0 AS `(2 XOR 0) AND 0` +select 2 XOR 0 AND 0, 2 XOR (0 AND 0), (2 XOR 0) AND 0 union select * from v1; +2 XOR 0 AND 0 2 XOR (0 AND 0) (2 XOR 0) AND 0 +1 1 0 +create or replace view v1 as select 2 XOR 0 && 0, 2 XOR (0 && 0), (2 XOR 0) && 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 0 and 0 AS `2 XOR 0 && 0`,2 xor 0 and 0 AS `2 XOR (0 && 0)`,(2 xor 0) and 0 AS `(2 XOR 0) && 0` +select 2 XOR 0 && 0, 2 XOR (0 && 0), (2 XOR 0) && 0 union select * from v1; +2 XOR 0 && 0 2 XOR (0 && 0) (2 XOR 0) && 0 +1 1 0 +create or replace view v1 as select 2 XOR 2 = 3, 2 XOR (2 = 3), (2 XOR 2) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 2 = 3 AS `2 XOR 2 = 3`,2 xor 2 = 3 AS `2 XOR (2 = 3)`,(2 xor 2) = 3 AS `(2 XOR 2) = 3` +select 2 XOR 2 = 3, 2 XOR (2 = 3), (2 XOR 2) = 3 union select * from v1; +2 XOR 2 = 3 2 XOR (2 = 3) (2 XOR 2) = 3 +1 1 0 +create or replace view v1 as select NULL XOR 3 <=> 3, NULL XOR (3 <=> 3), (NULL XOR 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select NULL xor 3 <=> 3 AS `NULL XOR 3 <=> 3`,NULL xor 3 <=> 3 AS `NULL XOR (3 <=> 3)`,(NULL xor 3) <=> 3 AS `(NULL XOR 3) <=> 3` +select NULL XOR 3 <=> 3, NULL XOR (3 <=> 3), (NULL XOR 3) <=> 3 union select * from v1; +NULL XOR 3 <=> 3 NULL XOR (3 <=> 3) (NULL XOR 3) <=> 3 +NULL NULL 0 +create or replace view v1 as select 2 XOR 1 >= 3, 2 XOR (1 >= 3), (2 XOR 1) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 1 >= 3 AS `2 XOR 1 >= 3`,2 xor 1 >= 3 AS `2 XOR (1 >= 3)`,(2 xor 1) >= 3 AS `(2 XOR 1) >= 3` +select 2 XOR 1 >= 3, 2 XOR (1 >= 3), (2 XOR 1) >= 3 union select * from v1; +2 XOR 1 >= 3 2 XOR (1 >= 3) (2 XOR 1) >= 3 +1 1 0 +create or replace view v1 as select 2 XOR 3 <= 3, 2 XOR (3 <= 3), (2 XOR 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 3 <= 3 AS `2 XOR 3 <= 3`,2 xor 3 <= 3 AS `2 XOR (3 <= 3)`,(2 xor 3) <= 3 AS `(2 XOR 3) <= 3` +select 2 XOR 3 <= 3, 2 XOR (3 <= 3), (2 XOR 3) <= 3 union select * from v1; +2 XOR 3 <= 3 2 XOR (3 <= 3) (2 XOR 3) <= 3 +0 0 1 +create or replace view v1 as select 2 XOR 1 < 3, 2 XOR (1 < 3), (2 XOR 1) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 1 < 3 AS `2 XOR 1 < 3`,2 xor 1 < 3 AS `2 XOR (1 < 3)`,(2 xor 1) < 3 AS `(2 XOR 1) < 3` +select 2 XOR 1 < 3, 2 XOR (1 < 3), (2 XOR 1) < 3 union select * from v1; +2 XOR 1 < 3 2 XOR (1 < 3) (2 XOR 1) < 3 +0 0 1 +create or replace view v1 as select 2 XOR 2 <> 3, 2 XOR (2 <> 3), (2 XOR 2) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 2 <> 3 AS `2 XOR 2 <> 3`,2 xor 2 <> 3 AS `2 XOR (2 <> 3)`,(2 xor 2) <> 3 AS `(2 XOR 2) <> 3` +select 2 XOR 2 <> 3, 2 XOR (2 <> 3), (2 XOR 2) <> 3 union select * from v1; +2 XOR 2 <> 3 2 XOR (2 <> 3) (2 XOR 2) <> 3 +0 0 1 +create or replace view v1 as select 2 XOR 3 > 3, 2 XOR (3 > 3), (2 XOR 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 3 > 3 AS `2 XOR 3 > 3`,2 xor 3 > 3 AS `2 XOR (3 > 3)`,(2 xor 3) > 3 AS `(2 XOR 3) > 3` +select 2 XOR 3 > 3, 2 XOR (3 > 3), (2 XOR 3) > 3 union select * from v1; +2 XOR 3 > 3 2 XOR (3 > 3) (2 XOR 3) > 3 +1 1 0 +create or replace view v1 as select 2 XOR 2 != 3, 2 XOR (2 != 3), (2 XOR 2) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 2 <> 3 AS `2 XOR 2 != 3`,2 xor 2 <> 3 AS `2 XOR (2 != 3)`,(2 xor 2) <> 3 AS `(2 XOR 2) != 3` +select 2 XOR 2 != 3, 2 XOR (2 != 3), (2 XOR 2) != 3 union select * from v1; +2 XOR 2 != 3 2 XOR (2 != 3) (2 XOR 2) != 3 +0 0 1 +create or replace view v1 as select 2 XOR 1 LIKE 3, 2 XOR (1 LIKE 3), (2 XOR 1) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 1 like 3 AS `2 XOR 1 LIKE 3`,2 xor 1 like 3 AS `2 XOR (1 LIKE 3)`,(2 xor 1) like 3 AS `(2 XOR 1) LIKE 3` +select 2 XOR 1 LIKE 3, 2 XOR (1 LIKE 3), (2 XOR 1) LIKE 3 union select * from v1; +2 XOR 1 LIKE 3 2 XOR (1 LIKE 3) (2 XOR 1) LIKE 3 +1 1 0 +create or replace view v1 as select 2 XOR 1 REGEXP 3, 2 XOR (1 REGEXP 3), (2 XOR 1) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 1 regexp 3 AS `2 XOR 1 REGEXP 3`,2 xor 1 regexp 3 AS `2 XOR (1 REGEXP 3)`,(2 xor 1) regexp 3 AS `(2 XOR 1) REGEXP 3` +select 2 XOR 1 REGEXP 3, 2 XOR (1 REGEXP 3), (2 XOR 1) REGEXP 3 union select * from v1; +2 XOR 1 REGEXP 3 2 XOR (1 REGEXP 3) (2 XOR 1) REGEXP 3 +1 1 0 +create or replace view v1 as select 2 XOR 3 | 3, 2 XOR (3 | 3), (2 XOR 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 3 | 3 AS `2 XOR 3 | 3`,2 xor 3 | 3 AS `2 XOR (3 | 3)`,(2 xor 3) | 3 AS `(2 XOR 3) | 3` +select 2 XOR 3 | 3, 2 XOR (3 | 3), (2 XOR 3) | 3 union select * from v1; +2 XOR 3 | 3 2 XOR (3 | 3) (2 XOR 3) | 3 +0 0 3 +create or replace view v1 as select 2 XOR 0 & 0, 2 XOR (0 & 0), (2 XOR 0) & 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 0 & 0 AS `2 XOR 0 & 0`,2 xor 0 & 0 AS `2 XOR (0 & 0)`,(2 xor 0) & 0 AS `(2 XOR 0) & 0` +select 2 XOR 0 & 0, 2 XOR (0 & 0), (2 XOR 0) & 0 union select * from v1; +2 XOR 0 & 0 2 XOR (0 & 0) (2 XOR 0) & 0 +1 1 0 +create or replace view v1 as select 0 XOR 3 << 3, 0 XOR (3 << 3), (0 XOR 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 xor 3 << 3 AS `0 XOR 3 << 3`,0 xor 3 << 3 AS `0 XOR (3 << 3)`,(0 xor 3) << 3 AS `(0 XOR 3) << 3` +select 0 XOR 3 << 3, 0 XOR (3 << 3), (0 XOR 3) << 3 union select * from v1; +0 XOR 3 << 3 0 XOR (3 << 3) (0 XOR 3) << 3 +1 1 8 +create or replace view v1 as select 2 XOR 3 >> 3, 2 XOR (3 >> 3), (2 XOR 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 3 >> 3 AS `2 XOR 3 >> 3`,2 xor 3 >> 3 AS `2 XOR (3 >> 3)`,(2 xor 3) >> 3 AS `(2 XOR 3) >> 3` +select 2 XOR 3 >> 3, 2 XOR (3 >> 3), (2 XOR 3) >> 3 union select * from v1; +2 XOR 3 >> 3 2 XOR (3 >> 3) (2 XOR 3) >> 3 +1 1 0 +create or replace view v1 as select 2 XOR '2000-01-01' +INTERVAL 1 DAY, 2 XOR ('2000-01-01' +INTERVAL 1 DAY), (2 XOR '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor '2000-01-01' + interval 1 day AS `2 XOR '2000-01-01' +INTERVAL 1 DAY`,2 xor '2000-01-01' + interval 1 day AS `2 XOR ('2000-01-01' +INTERVAL 1 DAY)`,(2 xor '2000-01-01') + interval 1 day AS `(2 XOR '2000-01-01') +INTERVAL 1 DAY` +select 2 XOR '2000-01-01' +INTERVAL 1 DAY, 2 XOR ('2000-01-01' +INTERVAL 1 DAY), (2 XOR '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 XOR '2000-01-01' +INTERVAL 1 DAY 2 XOR ('2000-01-01' +INTERVAL 1 DAY) (2 XOR '2000-01-01') +INTERVAL 1 DAY +0 0 NULL +create or replace view v1 as select 2 XOR 3 + 3, 2 XOR (3 + 3), (2 XOR 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 3 + 3 AS `2 XOR 3 + 3`,2 xor 3 + 3 AS `2 XOR (3 + 3)`,(2 xor 3) + 3 AS `(2 XOR 3) + 3` +select 2 XOR 3 + 3, 2 XOR (3 + 3), (2 XOR 3) + 3 union select * from v1; +2 XOR 3 + 3 2 XOR (3 + 3) (2 XOR 3) + 3 +0 0 3 +create or replace view v1 as select 2 XOR 3 - 3, 2 XOR (3 - 3), (2 XOR 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 3 - 3 AS `2 XOR 3 - 3`,2 xor 3 - 3 AS `2 XOR (3 - 3)`,(2 xor 3) - 3 AS `(2 XOR 3) - 3` +select 2 XOR 3 - 3, 2 XOR (3 - 3), (2 XOR 3) - 3 union select * from v1; +2 XOR 3 - 3 2 XOR (3 - 3) (2 XOR 3) - 3 +1 1 -3 +create or replace view v1 as select 0 XOR 3 * 3, 0 XOR (3 * 3), (0 XOR 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 xor 3 * 3 AS `0 XOR 3 * 3`,0 xor 3 * 3 AS `0 XOR (3 * 3)`,(0 xor 3) * 3 AS `(0 XOR 3) * 3` +select 0 XOR 3 * 3, 0 XOR (3 * 3), (0 XOR 3) * 3 union select * from v1; +0 XOR 3 * 3 0 XOR (3 * 3) (0 XOR 3) * 3 +1 1 3 +create or replace view v1 as select 0 XOR 3 / 3, 0 XOR (3 / 3), (0 XOR 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 xor 3 / 3 AS `0 XOR 3 / 3`,0 xor 3 / 3 AS `0 XOR (3 / 3)`,(0 xor 3) / 3 AS `(0 XOR 3) / 3` +select 0 XOR 3 / 3, 0 XOR (3 / 3), (0 XOR 3) / 3 union select * from v1; +0 XOR 3 / 3 0 XOR (3 / 3) (0 XOR 3) / 3 +1 1 0.3333 +create or replace view v1 as select 0 XOR 3 DIV 3, 0 XOR (3 DIV 3), (0 XOR 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 xor 3 DIV 3 AS `0 XOR 3 DIV 3`,0 xor 3 DIV 3 AS `0 XOR (3 DIV 3)`,(0 xor 3) DIV 3 AS `(0 XOR 3) DIV 3` +select 0 XOR 3 DIV 3, 0 XOR (3 DIV 3), (0 XOR 3) DIV 3 union select * from v1; +0 XOR 3 DIV 3 0 XOR (3 DIV 3) (0 XOR 3) DIV 3 +1 1 0 +create or replace view v1 as select 2 XOR 3 MOD 3, 2 XOR (3 MOD 3), (2 XOR 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 3 % 3 AS `2 XOR 3 MOD 3`,2 xor 3 % 3 AS `2 XOR (3 MOD 3)`,(2 xor 3) % 3 AS `(2 XOR 3) MOD 3` +select 2 XOR 3 MOD 3, 2 XOR (3 MOD 3), (2 XOR 3) MOD 3 union select * from v1; +2 XOR 3 MOD 3 2 XOR (3 MOD 3) (2 XOR 3) MOD 3 +1 1 0 +create or replace view v1 as select 2 XOR 3 % 3, 2 XOR (3 % 3), (2 XOR 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 3 % 3 AS `2 XOR 3 % 3`,2 xor 3 % 3 AS `2 XOR (3 % 3)`,(2 xor 3) % 3 AS `(2 XOR 3) % 3` +select 2 XOR 3 % 3, 2 XOR (3 % 3), (2 XOR 3) % 3 union select * from v1; +2 XOR 3 % 3 2 XOR (3 % 3) (2 XOR 3) % 3 +1 1 0 +create or replace view v1 as select 2 XOR 3 ^ 3, 2 XOR (3 ^ 3), (2 XOR 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 3 ^ 3 AS `2 XOR 3 ^ 3`,2 xor 3 ^ 3 AS `2 XOR (3 ^ 3)`,(2 xor 3) ^ 3 AS `(2 XOR 3) ^ 3` +select 2 XOR 3 ^ 3, 2 XOR (3 ^ 3), (2 XOR 3) ^ 3 union select * from v1; +2 XOR 3 ^ 3 2 XOR (3 ^ 3) (2 XOR 3) ^ 3 +1 1 3 +create or replace view v1 as select 2 XOR 3 BETWEEN 0 AND 3, 2 XOR (3 BETWEEN 0 AND 3), (2 XOR 3) BETWEEN 0 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 3 between 0 and 3 AS `2 XOR 3 BETWEEN 0 AND 3`,2 xor 3 between 0 and 3 AS `2 XOR (3 BETWEEN 0 AND 3)`,(2 xor 3) between 0 and 3 AS `(2 XOR 3) BETWEEN 0 AND 3` +select 2 XOR 3 BETWEEN 0 AND 3, 2 XOR (3 BETWEEN 0 AND 3), (2 XOR 3) BETWEEN 0 AND 3 union select * from v1; +2 XOR 3 BETWEEN 0 AND 3 2 XOR (3 BETWEEN 0 AND 3) (2 XOR 3) BETWEEN 0 AND 3 +0 0 1 +create or replace view v1 as select 0 AND 3 IS FALSE, 0 AND (3 IS FALSE), (0 AND 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 and 3 is false AS `0 AND 3 IS FALSE`,0 and 3 is false AS `0 AND (3 IS FALSE)`,(0 and 3) is false AS `(0 AND 3) IS FALSE` +select 0 AND 3 IS FALSE, 0 AND (3 IS FALSE), (0 AND 3) IS FALSE union select * from v1; +0 AND 3 IS FALSE 0 AND (3 IS FALSE) (0 AND 3) IS FALSE +0 0 1 +create or replace view v1 as select charset(2 AND 3 COLLATE latin1_bin), charset(2 AND (3 COLLATE latin1_bin)), charset((2 AND 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 and 3 collate latin1_bin) AS `charset(2 AND 3 COLLATE latin1_bin)`,charset(2 and 3 collate latin1_bin) AS `charset(2 AND (3 COLLATE latin1_bin))`,charset((2 and 3) collate latin1_bin) AS `charset((2 AND 3) COLLATE latin1_bin)` +select charset(2 AND 3 COLLATE latin1_bin), charset(2 AND (3 COLLATE latin1_bin)), charset((2 AND 3) COLLATE latin1_bin) union select * from v1; +charset(2 AND 3 COLLATE latin1_bin) charset(2 AND (3 COLLATE latin1_bin)) charset((2 AND 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 AND 3 IN (0,1), 2 AND (3 IN (0,1)), (2 AND 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 in (0,1) AS `2 AND 3 IN (0,1)`,2 and 3 in (0,1) AS `2 AND (3 IN (0,1))`,(2 and 3) in (0,1) AS `(2 AND 3) IN (0,1)` +select 2 AND 3 IN (0,1), 2 AND (3 IN (0,1)), (2 AND 3) IN (0,1) union select * from v1; +2 AND 3 IN (0,1) 2 AND (3 IN (0,1)) (2 AND 3) IN (0,1) +0 0 1 +create or replace view v1 as select 0 AND 3 OR 3, 0 AND (3 OR 3), (0 AND 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 and 3 or 3 AS `0 AND 3 OR 3`,0 and (3 or 3) AS `0 AND (3 OR 3)`,0 and 3 or 3 AS `(0 AND 3) OR 3` +select 0 AND 3 OR 3, 0 AND (3 OR 3), (0 AND 3) OR 3 union select * from v1; +0 AND 3 OR 3 0 AND (3 OR 3) (0 AND 3) OR 3 +1 0 1 +create or replace view v1 as select 0 AND 3 || 3, 0 AND (3 || 3), (0 AND 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 and 3 or 3 AS `0 AND 3 || 3`,0 and (3 or 3) AS `0 AND (3 || 3)`,0 and 3 or 3 AS `(0 AND 3) || 3` +select 0 AND 3 || 3, 0 AND (3 || 3), (0 AND 3) || 3 union select * from v1; +0 AND 3 || 3 0 AND (3 || 3) (0 AND 3) || 3 +1 0 1 +create or replace view v1 as select 0 AND 3 XOR 3, 0 AND (3 XOR 3), (0 AND 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 and 3 xor 3 AS `0 AND 3 XOR 3`,0 and (3 xor 3) AS `0 AND (3 XOR 3)`,0 and 3 xor 3 AS `(0 AND 3) XOR 3` +select 0 AND 3 XOR 3, 0 AND (3 XOR 3), (0 AND 3) XOR 3 union select * from v1; +0 AND 3 XOR 3 0 AND (3 XOR 3) (0 AND 3) XOR 3 +1 0 1 +create or replace view v1 as select 2 AND 3 = 3, 2 AND (3 = 3), (2 AND 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 = 3 AS `2 AND 3 = 3`,2 and 3 = 3 AS `2 AND (3 = 3)`,(2 and 3) = 3 AS `(2 AND 3) = 3` +select 2 AND 3 = 3, 2 AND (3 = 3), (2 AND 3) = 3 union select * from v1; +2 AND 3 = 3 2 AND (3 = 3) (2 AND 3) = 3 +1 1 0 +create or replace view v1 as select 2 AND 3 <=> 3, 2 AND (3 <=> 3), (2 AND 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 <=> 3 AS `2 AND 3 <=> 3`,2 and 3 <=> 3 AS `2 AND (3 <=> 3)`,(2 and 3) <=> 3 AS `(2 AND 3) <=> 3` +select 2 AND 3 <=> 3, 2 AND (3 <=> 3), (2 AND 3) <=> 3 union select * from v1; +2 AND 3 <=> 3 2 AND (3 <=> 3) (2 AND 3) <=> 3 +1 1 0 +create or replace view v1 as select 2 AND 3 >= 3, 2 AND (3 >= 3), (2 AND 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 >= 3 AS `2 AND 3 >= 3`,2 and 3 >= 3 AS `2 AND (3 >= 3)`,(2 and 3) >= 3 AS `(2 AND 3) >= 3` +select 2 AND 3 >= 3, 2 AND (3 >= 3), (2 AND 3) >= 3 union select * from v1; +2 AND 3 >= 3 2 AND (3 >= 3) (2 AND 3) >= 3 +1 1 0 +create or replace view v1 as select 2 AND 4 <= 3, 2 AND (4 <= 3), (2 AND 4) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 4 <= 3 AS `2 AND 4 <= 3`,2 and 4 <= 3 AS `2 AND (4 <= 3)`,(2 and 4) <= 3 AS `(2 AND 4) <= 3` +select 2 AND 4 <= 3, 2 AND (4 <= 3), (2 AND 4) <= 3 union select * from v1; +2 AND 4 <= 3 2 AND (4 <= 3) (2 AND 4) <= 3 +0 0 1 +create or replace view v1 as select 2 AND 3 < 3, 2 AND (3 < 3), (2 AND 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 < 3 AS `2 AND 3 < 3`,2 and 3 < 3 AS `2 AND (3 < 3)`,(2 and 3) < 3 AS `(2 AND 3) < 3` +select 2 AND 3 < 3, 2 AND (3 < 3), (2 AND 3) < 3 union select * from v1; +2 AND 3 < 3 2 AND (3 < 3) (2 AND 3) < 3 +0 0 1 +create or replace view v1 as select 2 AND 3 <> 3, 2 AND (3 <> 3), (2 AND 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 <> 3 AS `2 AND 3 <> 3`,2 and 3 <> 3 AS `2 AND (3 <> 3)`,(2 and 3) <> 3 AS `(2 AND 3) <> 3` +select 2 AND 3 <> 3, 2 AND (3 <> 3), (2 AND 3) <> 3 union select * from v1; +2 AND 3 <> 3 2 AND (3 <> 3) (2 AND 3) <> 3 +0 0 1 +create or replace view v1 as select 2 AND 3 > 1, 2 AND (3 > 1), (2 AND 3) > 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 > 1 AS `2 AND 3 > 1`,2 and 3 > 1 AS `2 AND (3 > 1)`,(2 and 3) > 1 AS `(2 AND 3) > 1` +select 2 AND 3 > 1, 2 AND (3 > 1), (2 AND 3) > 1 union select * from v1; +2 AND 3 > 1 2 AND (3 > 1) (2 AND 3) > 1 +1 1 0 +create or replace view v1 as select 2 AND 3 != 3, 2 AND (3 != 3), (2 AND 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 <> 3 AS `2 AND 3 != 3`,2 and 3 <> 3 AS `2 AND (3 != 3)`,(2 and 3) <> 3 AS `(2 AND 3) != 3` +select 2 AND 3 != 3, 2 AND (3 != 3), (2 AND 3) != 3 union select * from v1; +2 AND 3 != 3 2 AND (3 != 3) (2 AND 3) != 3 +0 0 1 +create or replace view v1 as select 2 AND 3 LIKE 3, 2 AND (3 LIKE 3), (2 AND 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 like 3 AS `2 AND 3 LIKE 3`,2 and 3 like 3 AS `2 AND (3 LIKE 3)`,(2 and 3) like 3 AS `(2 AND 3) LIKE 3` +select 2 AND 3 LIKE 3, 2 AND (3 LIKE 3), (2 AND 3) LIKE 3 union select * from v1; +2 AND 3 LIKE 3 2 AND (3 LIKE 3) (2 AND 3) LIKE 3 +1 1 0 +create or replace view v1 as select 2 AND 3 REGEXP 3, 2 AND (3 REGEXP 3), (2 AND 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 regexp 3 AS `2 AND 3 REGEXP 3`,2 and 3 regexp 3 AS `2 AND (3 REGEXP 3)`,(2 and 3) regexp 3 AS `(2 AND 3) REGEXP 3` +select 2 AND 3 REGEXP 3, 2 AND (3 REGEXP 3), (2 AND 3) REGEXP 3 union select * from v1; +2 AND 3 REGEXP 3 2 AND (3 REGEXP 3) (2 AND 3) REGEXP 3 +1 1 0 +create or replace view v1 as select 2 AND 3 | 3, 2 AND (3 | 3), (2 AND 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 | 3 AS `2 AND 3 | 3`,2 and 3 | 3 AS `2 AND (3 | 3)`,(2 and 3) | 3 AS `(2 AND 3) | 3` +select 2 AND 3 | 3, 2 AND (3 | 3), (2 AND 3) | 3 union select * from v1; +2 AND 3 | 3 2 AND (3 | 3) (2 AND 3) | 3 +1 1 3 +create or replace view v1 as select 2 AND 2 & 2, 2 AND (2 & 2), (2 AND 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 2 & 2 AS `2 AND 2 & 2`,2 and 2 & 2 AS `2 AND (2 & 2)`,(2 and 2) & 2 AS `(2 AND 2) & 2` +select 2 AND 2 & 2, 2 AND (2 & 2), (2 AND 2) & 2 union select * from v1; +2 AND 2 & 2 2 AND (2 & 2) (2 AND 2) & 2 +1 1 0 +create or replace view v1 as select 2 AND 3 << 3, 2 AND (3 << 3), (2 AND 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 << 3 AS `2 AND 3 << 3`,2 and 3 << 3 AS `2 AND (3 << 3)`,(2 and 3) << 3 AS `(2 AND 3) << 3` +select 2 AND 3 << 3, 2 AND (3 << 3), (2 AND 3) << 3 union select * from v1; +2 AND 3 << 3 2 AND (3 << 3) (2 AND 3) << 3 +1 1 8 +create or replace view v1 as select 2 AND 3 >> 1, 2 AND (3 >> 1), (2 AND 3) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 >> 1 AS `2 AND 3 >> 1`,2 and 3 >> 1 AS `2 AND (3 >> 1)`,(2 and 3) >> 1 AS `(2 AND 3) >> 1` +select 2 AND 3 >> 1, 2 AND (3 >> 1), (2 AND 3) >> 1 union select * from v1; +2 AND 3 >> 1 2 AND (3 >> 1) (2 AND 3) >> 1 +1 1 0 +create or replace view v1 as select 2 AND '2000-01-01' +INTERVAL 1 DAY, 2 AND ('2000-01-01' +INTERVAL 1 DAY), (2 AND '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and '2000-01-01' + interval 1 day AS `2 AND '2000-01-01' +INTERVAL 1 DAY`,2 and '2000-01-01' + interval 1 day AS `2 AND ('2000-01-01' +INTERVAL 1 DAY)`,(2 and '2000-01-01') + interval 1 day AS `(2 AND '2000-01-01') +INTERVAL 1 DAY` +select 2 AND '2000-01-01' +INTERVAL 1 DAY, 2 AND ('2000-01-01' +INTERVAL 1 DAY), (2 AND '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 AND '2000-01-01' +INTERVAL 1 DAY 2 AND ('2000-01-01' +INTERVAL 1 DAY) (2 AND '2000-01-01') +INTERVAL 1 DAY +1 1 NULL +create or replace view v1 as select 2 AND 3 + 3, 2 AND (3 + 3), (2 AND 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 + 3 AS `2 AND 3 + 3`,2 and 3 + 3 AS `2 AND (3 + 3)`,(2 and 3) + 3 AS `(2 AND 3) + 3` +select 2 AND 3 + 3, 2 AND (3 + 3), (2 AND 3) + 3 union select * from v1; +2 AND 3 + 3 2 AND (3 + 3) (2 AND 3) + 3 +1 1 4 +create or replace view v1 as select 2 AND 3 - 3, 2 AND (3 - 3), (2 AND 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 - 3 AS `2 AND 3 - 3`,2 and 3 - 3 AS `2 AND (3 - 3)`,(2 and 3) - 3 AS `(2 AND 3) - 3` +select 2 AND 3 - 3, 2 AND (3 - 3), (2 AND 3) - 3 union select * from v1; +2 AND 3 - 3 2 AND (3 - 3) (2 AND 3) - 3 +0 0 -2 +create or replace view v1 as select 2 AND 3 * 3, 2 AND (3 * 3), (2 AND 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 * 3 AS `2 AND 3 * 3`,2 and 3 * 3 AS `2 AND (3 * 3)`,(2 and 3) * 3 AS `(2 AND 3) * 3` +select 2 AND 3 * 3, 2 AND (3 * 3), (2 AND 3) * 3 union select * from v1; +2 AND 3 * 3 2 AND (3 * 3) (2 AND 3) * 3 +1 1 3 +create or replace view v1 as select 2 AND 3 / 3, 2 AND (3 / 3), (2 AND 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 / 3 AS `2 AND 3 / 3`,2 and 3 / 3 AS `2 AND (3 / 3)`,(2 and 3) / 3 AS `(2 AND 3) / 3` +select 2 AND 3 / 3, 2 AND (3 / 3), (2 AND 3) / 3 union select * from v1; +2 AND 3 / 3 2 AND (3 / 3) (2 AND 3) / 3 +1 1 0.3333 +create or replace view v1 as select 2 AND 3 DIV 3, 2 AND (3 DIV 3), (2 AND 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 DIV 3 AS `2 AND 3 DIV 3`,2 and 3 DIV 3 AS `2 AND (3 DIV 3)`,(2 and 3) DIV 3 AS `(2 AND 3) DIV 3` +select 2 AND 3 DIV 3, 2 AND (3 DIV 3), (2 AND 3) DIV 3 union select * from v1; +2 AND 3 DIV 3 2 AND (3 DIV 3) (2 AND 3) DIV 3 +1 1 0 +create or replace view v1 as select 2 AND 3 MOD 3, 2 AND (3 MOD 3), (2 AND 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 % 3 AS `2 AND 3 MOD 3`,2 and 3 % 3 AS `2 AND (3 MOD 3)`,(2 and 3) % 3 AS `(2 AND 3) MOD 3` +select 2 AND 3 MOD 3, 2 AND (3 MOD 3), (2 AND 3) MOD 3 union select * from v1; +2 AND 3 MOD 3 2 AND (3 MOD 3) (2 AND 3) MOD 3 +0 0 1 +create or replace view v1 as select 2 AND 3 % 3, 2 AND (3 % 3), (2 AND 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 % 3 AS `2 AND 3 % 3`,2 and 3 % 3 AS `2 AND (3 % 3)`,(2 and 3) % 3 AS `(2 AND 3) % 3` +select 2 AND 3 % 3, 2 AND (3 % 3), (2 AND 3) % 3 union select * from v1; +2 AND 3 % 3 2 AND (3 % 3) (2 AND 3) % 3 +0 0 1 +create or replace view v1 as select 2 AND 3 ^ 3, 2 AND (3 ^ 3), (2 AND 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 ^ 3 AS `2 AND 3 ^ 3`,2 and 3 ^ 3 AS `2 AND (3 ^ 3)`,(2 and 3) ^ 3 AS `(2 AND 3) ^ 3` +select 2 AND 3 ^ 3, 2 AND (3 ^ 3), (2 AND 3) ^ 3 union select * from v1; +2 AND 3 ^ 3 2 AND (3 ^ 3) (2 AND 3) ^ 3 +0 0 2 +create or replace view v1 as select 2 AND 3 BETWEEN 2 AND 3, 2 AND (3 BETWEEN 2 AND 3), (2 AND 3) BETWEEN 2 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 between 2 and 3 AS `2 AND 3 BETWEEN 2 AND 3`,2 and 3 between 2 and 3 AS `2 AND (3 BETWEEN 2 AND 3)`,(2 and 3) between 2 and 3 AS `(2 AND 3) BETWEEN 2 AND 3` +select 2 AND 3 BETWEEN 2 AND 3, 2 AND (3 BETWEEN 2 AND 3), (2 AND 3) BETWEEN 2 AND 3 union select * from v1; +2 AND 3 BETWEEN 2 AND 3 2 AND (3 BETWEEN 2 AND 3) (2 AND 3) BETWEEN 2 AND 3 +1 1 0 +create or replace view v1 as select 0 && 3 IS FALSE, 0 && (3 IS FALSE), (0 && 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 and 3 is false AS `0 && 3 IS FALSE`,0 and 3 is false AS `0 && (3 IS FALSE)`,(0 and 3) is false AS `(0 && 3) IS FALSE` +select 0 && 3 IS FALSE, 0 && (3 IS FALSE), (0 && 3) IS FALSE union select * from v1; +0 && 3 IS FALSE 0 && (3 IS FALSE) (0 && 3) IS FALSE +0 0 1 +create or replace view v1 as select charset(2 && 3 COLLATE latin1_bin), charset(2 && (3 COLLATE latin1_bin)), charset((2 && 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 and 3 collate latin1_bin) AS `charset(2 && 3 COLLATE latin1_bin)`,charset(2 and 3 collate latin1_bin) AS `charset(2 && (3 COLLATE latin1_bin))`,charset((2 and 3) collate latin1_bin) AS `charset((2 && 3) COLLATE latin1_bin)` +select charset(2 && 3 COLLATE latin1_bin), charset(2 && (3 COLLATE latin1_bin)), charset((2 && 3) COLLATE latin1_bin) union select * from v1; +charset(2 && 3 COLLATE latin1_bin) charset(2 && (3 COLLATE latin1_bin)) charset((2 && 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 && 3 IN (0,1), 2 && (3 IN (0,1)), (2 && 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 in (0,1) AS `2 && 3 IN (0,1)`,2 and 3 in (0,1) AS `2 && (3 IN (0,1))`,(2 and 3) in (0,1) AS `(2 && 3) IN (0,1)` +select 2 && 3 IN (0,1), 2 && (3 IN (0,1)), (2 && 3) IN (0,1) union select * from v1; +2 && 3 IN (0,1) 2 && (3 IN (0,1)) (2 && 3) IN (0,1) +0 0 1 +create or replace view v1 as select 0 && 3 OR 3, 0 && (3 OR 3), (0 && 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 and 3 or 3 AS `0 && 3 OR 3`,0 and (3 or 3) AS `0 && (3 OR 3)`,0 and 3 or 3 AS `(0 && 3) OR 3` +select 0 && 3 OR 3, 0 && (3 OR 3), (0 && 3) OR 3 union select * from v1; +0 && 3 OR 3 0 && (3 OR 3) (0 && 3) OR 3 +1 0 1 +create or replace view v1 as select 0 && 3 || 3, 0 && (3 || 3), (0 && 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 and 3 or 3 AS `0 && 3 || 3`,0 and (3 or 3) AS `0 && (3 || 3)`,0 and 3 or 3 AS `(0 && 3) || 3` +select 0 && 3 || 3, 0 && (3 || 3), (0 && 3) || 3 union select * from v1; +0 && 3 || 3 0 && (3 || 3) (0 && 3) || 3 +1 0 1 +create or replace view v1 as select 0 && 3 XOR 3, 0 && (3 XOR 3), (0 && 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 and 3 xor 3 AS `0 && 3 XOR 3`,0 and (3 xor 3) AS `0 && (3 XOR 3)`,0 and 3 xor 3 AS `(0 && 3) XOR 3` +select 0 && 3 XOR 3, 0 && (3 XOR 3), (0 && 3) XOR 3 union select * from v1; +0 && 3 XOR 3 0 && (3 XOR 3) (0 && 3) XOR 3 +1 0 1 +create or replace view v1 as select 2 && 3 = 3, 2 && (3 = 3), (2 && 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 = 3 AS `2 && 3 = 3`,2 and 3 = 3 AS `2 && (3 = 3)`,(2 and 3) = 3 AS `(2 && 3) = 3` +select 2 && 3 = 3, 2 && (3 = 3), (2 && 3) = 3 union select * from v1; +2 && 3 = 3 2 && (3 = 3) (2 && 3) = 3 +1 1 0 +create or replace view v1 as select 2 && 3 <=> 3, 2 && (3 <=> 3), (2 && 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 <=> 3 AS `2 && 3 <=> 3`,2 and 3 <=> 3 AS `2 && (3 <=> 3)`,(2 and 3) <=> 3 AS `(2 && 3) <=> 3` +select 2 && 3 <=> 3, 2 && (3 <=> 3), (2 && 3) <=> 3 union select * from v1; +2 && 3 <=> 3 2 && (3 <=> 3) (2 && 3) <=> 3 +1 1 0 +create or replace view v1 as select 2 && 3 >= 3, 2 && (3 >= 3), (2 && 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 >= 3 AS `2 && 3 >= 3`,2 and 3 >= 3 AS `2 && (3 >= 3)`,(2 and 3) >= 3 AS `(2 && 3) >= 3` +select 2 && 3 >= 3, 2 && (3 >= 3), (2 && 3) >= 3 union select * from v1; +2 && 3 >= 3 2 && (3 >= 3) (2 && 3) >= 3 +1 1 0 +create or replace view v1 as select 2 && 4 <= 3, 2 && (4 <= 3), (2 && 4) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 4 <= 3 AS `2 && 4 <= 3`,2 and 4 <= 3 AS `2 && (4 <= 3)`,(2 and 4) <= 3 AS `(2 && 4) <= 3` +select 2 && 4 <= 3, 2 && (4 <= 3), (2 && 4) <= 3 union select * from v1; +2 && 4 <= 3 2 && (4 <= 3) (2 && 4) <= 3 +0 0 1 +create or replace view v1 as select 2 && 3 < 3, 2 && (3 < 3), (2 && 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 < 3 AS `2 && 3 < 3`,2 and 3 < 3 AS `2 && (3 < 3)`,(2 and 3) < 3 AS `(2 && 3) < 3` +select 2 && 3 < 3, 2 && (3 < 3), (2 && 3) < 3 union select * from v1; +2 && 3 < 3 2 && (3 < 3) (2 && 3) < 3 +0 0 1 +create or replace view v1 as select 2 && 3 <> 3, 2 && (3 <> 3), (2 && 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 <> 3 AS `2 && 3 <> 3`,2 and 3 <> 3 AS `2 && (3 <> 3)`,(2 and 3) <> 3 AS `(2 && 3) <> 3` +select 2 && 3 <> 3, 2 && (3 <> 3), (2 && 3) <> 3 union select * from v1; +2 && 3 <> 3 2 && (3 <> 3) (2 && 3) <> 3 +0 0 1 +create or replace view v1 as select 2 && 3 > 1, 2 && (3 > 1), (2 && 3) > 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 > 1 AS `2 && 3 > 1`,2 and 3 > 1 AS `2 && (3 > 1)`,(2 and 3) > 1 AS `(2 && 3) > 1` +select 2 && 3 > 1, 2 && (3 > 1), (2 && 3) > 1 union select * from v1; +2 && 3 > 1 2 && (3 > 1) (2 && 3) > 1 +1 1 0 +create or replace view v1 as select 2 && 3 != 3, 2 && (3 != 3), (2 && 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 <> 3 AS `2 && 3 != 3`,2 and 3 <> 3 AS `2 && (3 != 3)`,(2 and 3) <> 3 AS `(2 && 3) != 3` +select 2 && 3 != 3, 2 && (3 != 3), (2 && 3) != 3 union select * from v1; +2 && 3 != 3 2 && (3 != 3) (2 && 3) != 3 +0 0 1 +create or replace view v1 as select 2 && 3 LIKE 3, 2 && (3 LIKE 3), (2 && 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 like 3 AS `2 && 3 LIKE 3`,2 and 3 like 3 AS `2 && (3 LIKE 3)`,(2 and 3) like 3 AS `(2 && 3) LIKE 3` +select 2 && 3 LIKE 3, 2 && (3 LIKE 3), (2 && 3) LIKE 3 union select * from v1; +2 && 3 LIKE 3 2 && (3 LIKE 3) (2 && 3) LIKE 3 +1 1 0 +create or replace view v1 as select 2 && 3 REGEXP 3, 2 && (3 REGEXP 3), (2 && 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 regexp 3 AS `2 && 3 REGEXP 3`,2 and 3 regexp 3 AS `2 && (3 REGEXP 3)`,(2 and 3) regexp 3 AS `(2 && 3) REGEXP 3` +select 2 && 3 REGEXP 3, 2 && (3 REGEXP 3), (2 && 3) REGEXP 3 union select * from v1; +2 && 3 REGEXP 3 2 && (3 REGEXP 3) (2 && 3) REGEXP 3 +1 1 0 +create or replace view v1 as select 2 && 3 | 3, 2 && (3 | 3), (2 && 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 | 3 AS `2 && 3 | 3`,2 and 3 | 3 AS `2 && (3 | 3)`,(2 and 3) | 3 AS `(2 && 3) | 3` +select 2 && 3 | 3, 2 && (3 | 3), (2 && 3) | 3 union select * from v1; +2 && 3 | 3 2 && (3 | 3) (2 && 3) | 3 +1 1 3 +create or replace view v1 as select 2 && 2 & 2, 2 && (2 & 2), (2 && 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 2 & 2 AS `2 && 2 & 2`,2 and 2 & 2 AS `2 && (2 & 2)`,(2 and 2) & 2 AS `(2 && 2) & 2` +select 2 && 2 & 2, 2 && (2 & 2), (2 && 2) & 2 union select * from v1; +2 && 2 & 2 2 && (2 & 2) (2 && 2) & 2 +1 1 0 +create or replace view v1 as select 2 && 3 << 3, 2 && (3 << 3), (2 && 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 << 3 AS `2 && 3 << 3`,2 and 3 << 3 AS `2 && (3 << 3)`,(2 and 3) << 3 AS `(2 && 3) << 3` +select 2 && 3 << 3, 2 && (3 << 3), (2 && 3) << 3 union select * from v1; +2 && 3 << 3 2 && (3 << 3) (2 && 3) << 3 +1 1 8 +create or replace view v1 as select 2 && 3 >> 1, 2 && (3 >> 1), (2 && 3) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 >> 1 AS `2 && 3 >> 1`,2 and 3 >> 1 AS `2 && (3 >> 1)`,(2 and 3) >> 1 AS `(2 && 3) >> 1` +select 2 && 3 >> 1, 2 && (3 >> 1), (2 && 3) >> 1 union select * from v1; +2 && 3 >> 1 2 && (3 >> 1) (2 && 3) >> 1 +1 1 0 +create or replace view v1 as select 2 && '2000-01-01' +INTERVAL 1 DAY, 2 && ('2000-01-01' +INTERVAL 1 DAY), (2 && '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and '2000-01-01' + interval 1 day AS `2 && '2000-01-01' +INTERVAL 1 DAY`,2 and '2000-01-01' + interval 1 day AS `2 && ('2000-01-01' +INTERVAL 1 DAY)`,(2 and '2000-01-01') + interval 1 day AS `(2 && '2000-01-01') +INTERVAL 1 DAY` +select 2 && '2000-01-01' +INTERVAL 1 DAY, 2 && ('2000-01-01' +INTERVAL 1 DAY), (2 && '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 && '2000-01-01' +INTERVAL 1 DAY 2 && ('2000-01-01' +INTERVAL 1 DAY) (2 && '2000-01-01') +INTERVAL 1 DAY +1 1 NULL +create or replace view v1 as select 2 && 3 + 3, 2 && (3 + 3), (2 && 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 + 3 AS `2 && 3 + 3`,2 and 3 + 3 AS `2 && (3 + 3)`,(2 and 3) + 3 AS `(2 && 3) + 3` +select 2 && 3 + 3, 2 && (3 + 3), (2 && 3) + 3 union select * from v1; +2 && 3 + 3 2 && (3 + 3) (2 && 3) + 3 +1 1 4 +create or replace view v1 as select 2 && 3 - 3, 2 && (3 - 3), (2 && 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 - 3 AS `2 && 3 - 3`,2 and 3 - 3 AS `2 && (3 - 3)`,(2 and 3) - 3 AS `(2 && 3) - 3` +select 2 && 3 - 3, 2 && (3 - 3), (2 && 3) - 3 union select * from v1; +2 && 3 - 3 2 && (3 - 3) (2 && 3) - 3 +0 0 -2 +create or replace view v1 as select 2 && 3 * 3, 2 && (3 * 3), (2 && 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 * 3 AS `2 && 3 * 3`,2 and 3 * 3 AS `2 && (3 * 3)`,(2 and 3) * 3 AS `(2 && 3) * 3` +select 2 && 3 * 3, 2 && (3 * 3), (2 && 3) * 3 union select * from v1; +2 && 3 * 3 2 && (3 * 3) (2 && 3) * 3 +1 1 3 +create or replace view v1 as select 2 && 3 / 3, 2 && (3 / 3), (2 && 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 / 3 AS `2 && 3 / 3`,2 and 3 / 3 AS `2 && (3 / 3)`,(2 and 3) / 3 AS `(2 && 3) / 3` +select 2 && 3 / 3, 2 && (3 / 3), (2 && 3) / 3 union select * from v1; +2 && 3 / 3 2 && (3 / 3) (2 && 3) / 3 +1 1 0.3333 +create or replace view v1 as select 2 && 3 DIV 3, 2 && (3 DIV 3), (2 && 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 DIV 3 AS `2 && 3 DIV 3`,2 and 3 DIV 3 AS `2 && (3 DIV 3)`,(2 and 3) DIV 3 AS `(2 && 3) DIV 3` +select 2 && 3 DIV 3, 2 && (3 DIV 3), (2 && 3) DIV 3 union select * from v1; +2 && 3 DIV 3 2 && (3 DIV 3) (2 && 3) DIV 3 +1 1 0 +create or replace view v1 as select 2 && 3 MOD 3, 2 && (3 MOD 3), (2 && 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 % 3 AS `2 && 3 MOD 3`,2 and 3 % 3 AS `2 && (3 MOD 3)`,(2 and 3) % 3 AS `(2 && 3) MOD 3` +select 2 && 3 MOD 3, 2 && (3 MOD 3), (2 && 3) MOD 3 union select * from v1; +2 && 3 MOD 3 2 && (3 MOD 3) (2 && 3) MOD 3 +0 0 1 +create or replace view v1 as select 2 && 3 % 3, 2 && (3 % 3), (2 && 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 % 3 AS `2 && 3 % 3`,2 and 3 % 3 AS `2 && (3 % 3)`,(2 and 3) % 3 AS `(2 && 3) % 3` +select 2 && 3 % 3, 2 && (3 % 3), (2 && 3) % 3 union select * from v1; +2 && 3 % 3 2 && (3 % 3) (2 && 3) % 3 +0 0 1 +create or replace view v1 as select 2 && 3 ^ 3, 2 && (3 ^ 3), (2 && 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 ^ 3 AS `2 && 3 ^ 3`,2 and 3 ^ 3 AS `2 && (3 ^ 3)`,(2 and 3) ^ 3 AS `(2 && 3) ^ 3` +select 2 && 3 ^ 3, 2 && (3 ^ 3), (2 && 3) ^ 3 union select * from v1; +2 && 3 ^ 3 2 && (3 ^ 3) (2 && 3) ^ 3 +0 0 2 +create or replace view v1 as select 2 && 3 BETWEEN 2 AND 3, 2 && (3 BETWEEN 2 AND 3), (2 && 3) BETWEEN 2 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 between 2 and 3 AS `2 && 3 BETWEEN 2 AND 3`,2 and 3 between 2 and 3 AS `2 && (3 BETWEEN 2 AND 3)`,(2 and 3) between 2 and 3 AS `(2 && 3) BETWEEN 2 AND 3` +select 2 && 3 BETWEEN 2 AND 3, 2 && (3 BETWEEN 2 AND 3), (2 && 3) BETWEEN 2 AND 3 union select * from v1; +2 && 3 BETWEEN 2 AND 3 2 && (3 BETWEEN 2 AND 3) (2 && 3) BETWEEN 2 AND 3 +1 1 0 +create or replace view v1 as select 2 = 3 IS FALSE, 2 = (3 IS FALSE), (2 = 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 3 is false AS `2 = 3 IS FALSE`,2 = (3 is false) AS `2 = (3 IS FALSE)`,2 = 3 is false AS `(2 = 3) IS FALSE` +select 2 = 3 IS FALSE, 2 = (3 IS FALSE), (2 = 3) IS FALSE union select * from v1; +2 = 3 IS FALSE 2 = (3 IS FALSE) (2 = 3) IS FALSE +1 0 1 +create or replace view v1 as select charset(2 = 3 COLLATE latin1_bin), charset(2 = (3 COLLATE latin1_bin)), charset((2 = 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 = 3 collate latin1_bin) AS `charset(2 = 3 COLLATE latin1_bin)`,charset(2 = 3 collate latin1_bin) AS `charset(2 = (3 COLLATE latin1_bin))`,charset((2 = 3) collate latin1_bin) AS `charset((2 = 3) COLLATE latin1_bin)` +select charset(2 = 3 COLLATE latin1_bin), charset(2 = (3 COLLATE latin1_bin)), charset((2 = 3) COLLATE latin1_bin) union select * from v1; +charset(2 = 3 COLLATE latin1_bin) charset(2 = (3 COLLATE latin1_bin)) charset((2 = 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 = 3 IN (0,1), 2 = (3 IN (0,1)), (2 = 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = (3 in (0,1)) AS `2 = 3 IN (0,1)`,2 = (3 in (0,1)) AS `2 = (3 IN (0,1))`,2 = 3 in (0,1) AS `(2 = 3) IN (0,1)` +select 2 = 3 IN (0,1), 2 = (3 IN (0,1)), (2 = 3) IN (0,1) union select * from v1; +2 = 3 IN (0,1) 2 = (3 IN (0,1)) (2 = 3) IN (0,1) +0 0 1 +0 0 0 +create or replace view v1 as select 2 = 3 OR 3, 2 = (3 OR 3), (2 = 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 3 or 3 AS `2 = 3 OR 3`,2 = (3 or 3) AS `2 = (3 OR 3)`,2 = 3 or 3 AS `(2 = 3) OR 3` +select 2 = 3 OR 3, 2 = (3 OR 3), (2 = 3) OR 3 union select * from v1; +2 = 3 OR 3 2 = (3 OR 3) (2 = 3) OR 3 +1 0 1 +create or replace view v1 as select 2 = 3 || 3, 2 = (3 || 3), (2 = 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 3 or 3 AS `2 = 3 || 3`,2 = (3 or 3) AS `2 = (3 || 3)`,2 = 3 or 3 AS `(2 = 3) || 3` +select 2 = 3 || 3, 2 = (3 || 3), (2 = 3) || 3 union select * from v1; +2 = 3 || 3 2 = (3 || 3) (2 = 3) || 3 +1 0 1 +create or replace view v1 as select 2 = 3 XOR 3, 2 = (3 XOR 3), (2 = 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 3 xor 3 AS `2 = 3 XOR 3`,2 = (3 xor 3) AS `2 = (3 XOR 3)`,2 = 3 xor 3 AS `(2 = 3) XOR 3` +select 2 = 3 XOR 3, 2 = (3 XOR 3), (2 = 3) XOR 3 union select * from v1; +2 = 3 XOR 3 2 = (3 XOR 3) (2 = 3) XOR 3 +1 0 1 +create or replace view v1 as select 2 = 2 AND 2, 2 = (2 AND 2), (2 = 2) AND 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 2 and 2 AS `2 = 2 AND 2`,2 = (2 and 2) AS `2 = (2 AND 2)`,2 = 2 and 2 AS `(2 = 2) AND 2` +select 2 = 2 AND 2, 2 = (2 AND 2), (2 = 2) AND 2 union select * from v1; +2 = 2 AND 2 2 = (2 AND 2) (2 = 2) AND 2 +1 0 1 +create or replace view v1 as select 2 = 2 && 2, 2 = (2 && 2), (2 = 2) && 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 2 and 2 AS `2 = 2 && 2`,2 = (2 and 2) AS `2 = (2 && 2)`,2 = 2 and 2 AS `(2 = 2) && 2` +select 2 = 2 && 2, 2 = (2 && 2), (2 = 2) && 2 union select * from v1; +2 = 2 && 2 2 = (2 && 2) (2 = 2) && 2 +1 0 1 +create or replace view v1 as select 1 = 3 = 3, 1 = (3 = 3), (1 = 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 = 3 = 3 AS `1 = 3 = 3`,1 = (3 = 3) AS `1 = (3 = 3)`,1 = 3 = 3 AS `(1 = 3) = 3` +select 1 = 3 = 3, 1 = (3 = 3), (1 = 3) = 3 union select * from v1; +1 = 3 = 3 1 = (3 = 3) (1 = 3) = 3 +0 1 0 +create or replace view v1 as select 1 = 3 <=> 3, 1 = (3 <=> 3), (1 = 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 = 3 <=> 3 AS `1 = 3 <=> 3`,1 = (3 <=> 3) AS `1 = (3 <=> 3)`,1 = 3 <=> 3 AS `(1 = 3) <=> 3` +select 1 = 3 <=> 3, 1 = (3 <=> 3), (1 = 3) <=> 3 union select * from v1; +1 = 3 <=> 3 1 = (3 <=> 3) (1 = 3) <=> 3 +0 1 0 +create or replace view v1 as select 1 = 3 >= 3, 1 = (3 >= 3), (1 = 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 = 3 >= 3 AS `1 = 3 >= 3`,1 = (3 >= 3) AS `1 = (3 >= 3)`,1 = 3 >= 3 AS `(1 = 3) >= 3` +select 1 = 3 >= 3, 1 = (3 >= 3), (1 = 3) >= 3 union select * from v1; +1 = 3 >= 3 1 = (3 >= 3) (1 = 3) >= 3 +0 1 0 +create or replace view v1 as select 2 = 3 <= 3, 2 = (3 <= 3), (2 = 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 3 <= 3 AS `2 = 3 <= 3`,2 = (3 <= 3) AS `2 = (3 <= 3)`,2 = 3 <= 3 AS `(2 = 3) <= 3` +select 2 = 3 <= 3, 2 = (3 <= 3), (2 = 3) <= 3 union select * from v1; +2 = 3 <= 3 2 = (3 <= 3) (2 = 3) <= 3 +1 0 1 +create or replace view v1 as select 2 = 3 < 3, 2 = (3 < 3), (2 = 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 3 < 3 AS `2 = 3 < 3`,2 = (3 < 3) AS `2 = (3 < 3)`,2 = 3 < 3 AS `(2 = 3) < 3` +select 2 = 3 < 3, 2 = (3 < 3), (2 = 3) < 3 union select * from v1; +2 = 3 < 3 2 = (3 < 3) (2 = 3) < 3 +1 0 1 +create or replace view v1 as select 2 = 3 <> 3, 2 = (3 <> 3), (2 = 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 3 <> 3 AS `2 = 3 <> 3`,2 = (3 <> 3) AS `2 = (3 <> 3)`,2 = 3 <> 3 AS `(2 = 3) <> 3` +select 2 = 3 <> 3, 2 = (3 <> 3), (2 = 3) <> 3 union select * from v1; +2 = 3 <> 3 2 = (3 <> 3) (2 = 3) <> 3 +1 0 1 +create or replace view v1 as select 0 = 3 > 3, 0 = (3 > 3), (0 = 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 = 3 > 3 AS `0 = 3 > 3`,0 = (3 > 3) AS `0 = (3 > 3)`,0 = 3 > 3 AS `(0 = 3) > 3` +select 0 = 3 > 3, 0 = (3 > 3), (0 = 3) > 3 union select * from v1; +0 = 3 > 3 0 = (3 > 3) (0 = 3) > 3 +0 1 0 +create or replace view v1 as select 2 = 3 != 3, 2 = (3 != 3), (2 = 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 3 <> 3 AS `2 = 3 != 3`,2 = (3 <> 3) AS `2 = (3 != 3)`,2 = 3 <> 3 AS `(2 = 3) != 3` +select 2 = 3 != 3, 2 = (3 != 3), (2 = 3) != 3 union select * from v1; +2 = 3 != 3 2 = (3 != 3) (2 = 3) != 3 +1 0 1 +create or replace view v1 as select 1 = 3 LIKE 3, 1 = (3 LIKE 3), (1 = 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 = (3 like 3) AS `1 = 3 LIKE 3`,1 = (3 like 3) AS `1 = (3 LIKE 3)`,1 = 3 like 3 AS `(1 = 3) LIKE 3` +select 1 = 3 LIKE 3, 1 = (3 LIKE 3), (1 = 3) LIKE 3 union select * from v1; +1 = 3 LIKE 3 1 = (3 LIKE 3) (1 = 3) LIKE 3 +1 1 0 +1 1 1 +create or replace view v1 as select 1 = 3 REGEXP 3, 1 = (3 REGEXP 3), (1 = 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 = (3 regexp 3) AS `1 = 3 REGEXP 3`,1 = (3 regexp 3) AS `1 = (3 REGEXP 3)`,1 = 3 regexp 3 AS `(1 = 3) REGEXP 3` +select 1 = 3 REGEXP 3, 1 = (3 REGEXP 3), (1 = 3) REGEXP 3 union select * from v1; +1 = 3 REGEXP 3 1 = (3 REGEXP 3) (1 = 3) REGEXP 3 +1 1 0 +1 1 1 +create or replace view v1 as select 2 = 3 | 3, 2 = (3 | 3), (2 = 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 3 | 3 AS `2 = 3 | 3`,2 = 3 | 3 AS `2 = (3 | 3)`,(2 = 3) | 3 AS `(2 = 3) | 3` +select 2 = 3 | 3, 2 = (3 | 3), (2 = 3) | 3 union select * from v1; +2 = 3 | 3 2 = (3 | 3) (2 = 3) | 3 +0 0 3 +create or replace view v1 as select 2 = 3 & 2, 2 = (3 & 2), (2 = 3) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 3 & 2 AS `2 = 3 & 2`,2 = 3 & 2 AS `2 = (3 & 2)`,(2 = 3) & 2 AS `(2 = 3) & 2` +select 2 = 3 & 2, 2 = (3 & 2), (2 = 3) & 2 union select * from v1; +2 = 3 & 2 2 = (3 & 2) (2 = 3) & 2 +1 1 0 +create or replace view v1 as select 3 = 3 << 3, 3 = (3 << 3), (3 = 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 = 3 << 3 AS `3 = 3 << 3`,3 = 3 << 3 AS `3 = (3 << 3)`,(3 = 3) << 3 AS `(3 = 3) << 3` +select 3 = 3 << 3, 3 = (3 << 3), (3 = 3) << 3 union select * from v1; +3 = 3 << 3 3 = (3 << 3) (3 = 3) << 3 +0 0 8 +create or replace view v1 as select 1 = 3 >> 1, 1 = (3 >> 1), (1 = 3) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 = 3 >> 1 AS `1 = 3 >> 1`,1 = 3 >> 1 AS `1 = (3 >> 1)`,(1 = 3) >> 1 AS `(1 = 3) >> 1` +select 1 = 3 >> 1, 1 = (3 >> 1), (1 = 3) >> 1 union select * from v1; +1 = 3 >> 1 1 = (3 >> 1) (1 = 3) >> 1 +1 1 0 +create or replace view v1 as select 2 = '2000-01-01' +INTERVAL 1 DAY, 2 = ('2000-01-01' +INTERVAL 1 DAY), (2 = '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = '2000-01-01' + interval 1 day AS `2 = '2000-01-01' +INTERVAL 1 DAY`,2 = '2000-01-01' + interval 1 day AS `2 = ('2000-01-01' +INTERVAL 1 DAY)`,(2 = '2000-01-01') + interval 1 day AS `(2 = '2000-01-01') +INTERVAL 1 DAY` +select 2 = '2000-01-01' +INTERVAL 1 DAY, 2 = ('2000-01-01' +INTERVAL 1 DAY), (2 = '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 = '2000-01-01' +INTERVAL 1 DAY 2 = ('2000-01-01' +INTERVAL 1 DAY) (2 = '2000-01-01') +INTERVAL 1 DAY +0 0 NULL +create or replace view v1 as select 2 = 3 + 3, 2 = (3 + 3), (2 = 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 3 + 3 AS `2 = 3 + 3`,2 = 3 + 3 AS `2 = (3 + 3)`,(2 = 3) + 3 AS `(2 = 3) + 3` +select 2 = 3 + 3, 2 = (3 + 3), (2 = 3) + 3 union select * from v1; +2 = 3 + 3 2 = (3 + 3) (2 = 3) + 3 +0 0 3 +create or replace view v1 as select 2 = 3 - 3, 2 = (3 - 3), (2 = 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 3 - 3 AS `2 = 3 - 3`,2 = 3 - 3 AS `2 = (3 - 3)`,(2 = 3) - 3 AS `(2 = 3) - 3` +select 2 = 3 - 3, 2 = (3 - 3), (2 = 3) - 3 union select * from v1; +2 = 3 - 3 2 = (3 - 3) (2 = 3) - 3 +0 0 -3 +create or replace view v1 as select 3 = 3 * 3, 3 = (3 * 3), (3 = 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 = 3 * 3 AS `3 = 3 * 3`,3 = 3 * 3 AS `3 = (3 * 3)`,(3 = 3) * 3 AS `(3 = 3) * 3` +select 3 = 3 * 3, 3 = (3 * 3), (3 = 3) * 3 union select * from v1; +3 = 3 * 3 3 = (3 * 3) (3 = 3) * 3 +0 0 3 +create or replace view v1 as select 3 = 9 / 3, 3 = (9 / 3), (3 = 9) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 = 9 / 3 AS `3 = 9 / 3`,3 = 9 / 3 AS `3 = (9 / 3)`,(3 = 9) / 3 AS `(3 = 9) / 3` +select 3 = 9 / 3, 3 = (9 / 3), (3 = 9) / 3 union select * from v1; +3 = 9 / 3 3 = (9 / 3) (3 = 9) / 3 +1 1 0.0000 +create or replace view v1 as select 3 = 9 DIV 3, 3 = (9 DIV 3), (3 = 9) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 = 9 DIV 3 AS `3 = 9 DIV 3`,3 = 9 DIV 3 AS `3 = (9 DIV 3)`,(3 = 9) DIV 3 AS `(3 = 9) DIV 3` +select 3 = 9 DIV 3, 3 = (9 DIV 3), (3 = 9) DIV 3 union select * from v1; +3 = 9 DIV 3 3 = (9 DIV 3) (3 = 9) DIV 3 +1 1 0 +create or replace view v1 as select 3 = 3 MOD 3, 3 = (3 MOD 3), (3 = 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 = 3 % 3 AS `3 = 3 MOD 3`,3 = 3 % 3 AS `3 = (3 MOD 3)`,(3 = 3) % 3 AS `(3 = 3) MOD 3` +select 3 = 3 MOD 3, 3 = (3 MOD 3), (3 = 3) MOD 3 union select * from v1; +3 = 3 MOD 3 3 = (3 MOD 3) (3 = 3) MOD 3 +0 0 1 +create or replace view v1 as select 3 = 3 % 3, 3 = (3 % 3), (3 = 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 = 3 % 3 AS `3 = 3 % 3`,3 = 3 % 3 AS `3 = (3 % 3)`,(3 = 3) % 3 AS `(3 = 3) % 3` +select 3 = 3 % 3, 3 = (3 % 3), (3 = 3) % 3 union select * from v1; +3 = 3 % 3 3 = (3 % 3) (3 = 3) % 3 +0 0 1 +create or replace view v1 as select 2 = 3 ^ 3, 2 = (3 ^ 3), (2 = 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = 3 ^ 3 AS `2 = 3 ^ 3`,2 = 3 ^ 3 AS `2 = (3 ^ 3)`,(2 = 3) ^ 3 AS `(2 = 3) ^ 3` +select 2 = 3 ^ 3, 2 = (3 ^ 3), (2 = 3) ^ 3 union select * from v1; +2 = 3 ^ 3 2 = (3 ^ 3) (2 = 3) ^ 3 +0 0 3 +create or replace view v1 as select 1 = 3 BETWEEN 1 AND 3, 1 = (3 BETWEEN 1 AND 3), (1 = 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 = (3 between 1 and 3) AS `1 = 3 BETWEEN 1 AND 3`,1 = (3 between 1 and 3) AS `1 = (3 BETWEEN 1 AND 3)`,1 = 3 between 1 and 3 AS `(1 = 3) BETWEEN 1 AND 3` +select 1 = 3 BETWEEN 1 AND 3, 1 = (3 BETWEEN 1 AND 3), (1 = 3) BETWEEN 1 AND 3 union select * from v1; +1 = 3 BETWEEN 1 AND 3 1 = (3 BETWEEN 1 AND 3) (1 = 3) BETWEEN 1 AND 3 +1 1 0 +1 1 1 +create or replace view v1 as select 2 <=> 3 IS FALSE, 2 <=> (3 IS FALSE), (2 <=> 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> 3 is false AS `2 <=> 3 IS FALSE`,2 <=> (3 is false) AS `2 <=> (3 IS FALSE)`,2 <=> 3 is false AS `(2 <=> 3) IS FALSE` +select 2 <=> 3 IS FALSE, 2 <=> (3 IS FALSE), (2 <=> 3) IS FALSE union select * from v1; +2 <=> 3 IS FALSE 2 <=> (3 IS FALSE) (2 <=> 3) IS FALSE +1 0 1 +create or replace view v1 as select charset(2 <=> 3 COLLATE latin1_bin), charset(2 <=> (3 COLLATE latin1_bin)), charset((2 <=> 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 <=> 3 collate latin1_bin) AS `charset(2 <=> 3 COLLATE latin1_bin)`,charset(2 <=> 3 collate latin1_bin) AS `charset(2 <=> (3 COLLATE latin1_bin))`,charset((2 <=> 3) collate latin1_bin) AS `charset((2 <=> 3) COLLATE latin1_bin)` +select charset(2 <=> 3 COLLATE latin1_bin), charset(2 <=> (3 COLLATE latin1_bin)), charset((2 <=> 3) COLLATE latin1_bin) union select * from v1; +charset(2 <=> 3 COLLATE latin1_bin) charset(2 <=> (3 COLLATE latin1_bin)) charset((2 <=> 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 <=> 3 IN (0,1), 2 <=> (3 IN (0,1)), (2 <=> 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> (3 in (0,1)) AS `2 <=> 3 IN (0,1)`,2 <=> (3 in (0,1)) AS `2 <=> (3 IN (0,1))`,2 <=> 3 in (0,1) AS `(2 <=> 3) IN (0,1)` +select 2 <=> 3 IN (0,1), 2 <=> (3 IN (0,1)), (2 <=> 3) IN (0,1) union select * from v1; +2 <=> 3 IN (0,1) 2 <=> (3 IN (0,1)) (2 <=> 3) IN (0,1) +0 0 1 +0 0 0 +create or replace view v1 as select 2 <=> 3 OR 3, 2 <=> (3 OR 3), (2 <=> 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> 3 or 3 AS `2 <=> 3 OR 3`,2 <=> (3 or 3) AS `2 <=> (3 OR 3)`,2 <=> 3 or 3 AS `(2 <=> 3) OR 3` +select 2 <=> 3 OR 3, 2 <=> (3 OR 3), (2 <=> 3) OR 3 union select * from v1; +2 <=> 3 OR 3 2 <=> (3 OR 3) (2 <=> 3) OR 3 +1 0 1 +create or replace view v1 as select 2 <=> 3 || 3, 2 <=> (3 || 3), (2 <=> 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> 3 or 3 AS `2 <=> 3 || 3`,2 <=> (3 or 3) AS `2 <=> (3 || 3)`,2 <=> 3 or 3 AS `(2 <=> 3) || 3` +select 2 <=> 3 || 3, 2 <=> (3 || 3), (2 <=> 3) || 3 union select * from v1; +2 <=> 3 || 3 2 <=> (3 || 3) (2 <=> 3) || 3 +1 0 1 +create or replace view v1 as select 2 <=> 3 XOR 3, 2 <=> (3 XOR 3), (2 <=> 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> 3 xor 3 AS `2 <=> 3 XOR 3`,2 <=> (3 xor 3) AS `2 <=> (3 XOR 3)`,2 <=> 3 xor 3 AS `(2 <=> 3) XOR 3` +select 2 <=> 3 XOR 3, 2 <=> (3 XOR 3), (2 <=> 3) XOR 3 union select * from v1; +2 <=> 3 XOR 3 2 <=> (3 XOR 3) (2 <=> 3) XOR 3 +1 0 1 +create or replace view v1 as select 2 <=> 2 AND 2, 2 <=> (2 AND 2), (2 <=> 2) AND 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> 2 and 2 AS `2 <=> 2 AND 2`,2 <=> (2 and 2) AS `2 <=> (2 AND 2)`,2 <=> 2 and 2 AS `(2 <=> 2) AND 2` +select 2 <=> 2 AND 2, 2 <=> (2 AND 2), (2 <=> 2) AND 2 union select * from v1; +2 <=> 2 AND 2 2 <=> (2 AND 2) (2 <=> 2) AND 2 +1 0 1 +create or replace view v1 as select 2 <=> 2 && 2, 2 <=> (2 && 2), (2 <=> 2) && 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> 2 and 2 AS `2 <=> 2 && 2`,2 <=> (2 and 2) AS `2 <=> (2 && 2)`,2 <=> 2 and 2 AS `(2 <=> 2) && 2` +select 2 <=> 2 && 2, 2 <=> (2 && 2), (2 <=> 2) && 2 union select * from v1; +2 <=> 2 && 2 2 <=> (2 && 2) (2 <=> 2) && 2 +1 0 1 +create or replace view v1 as select 1 <=> 3 = 3, 1 <=> (3 = 3), (1 <=> 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 <=> 3 = 3 AS `1 <=> 3 = 3`,1 <=> (3 = 3) AS `1 <=> (3 = 3)`,1 <=> 3 = 3 AS `(1 <=> 3) = 3` +select 1 <=> 3 = 3, 1 <=> (3 = 3), (1 <=> 3) = 3 union select * from v1; +1 <=> 3 = 3 1 <=> (3 = 3) (1 <=> 3) = 3 +0 1 0 +create or replace view v1 as select 1 <=> 3 <=> 3, 1 <=> (3 <=> 3), (1 <=> 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 <=> 3 <=> 3 AS `1 <=> 3 <=> 3`,1 <=> (3 <=> 3) AS `1 <=> (3 <=> 3)`,1 <=> 3 <=> 3 AS `(1 <=> 3) <=> 3` +select 1 <=> 3 <=> 3, 1 <=> (3 <=> 3), (1 <=> 3) <=> 3 union select * from v1; +1 <=> 3 <=> 3 1 <=> (3 <=> 3) (1 <=> 3) <=> 3 +0 1 0 +create or replace view v1 as select 1 <=> 3 >= 3, 1 <=> (3 >= 3), (1 <=> 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 <=> 3 >= 3 AS `1 <=> 3 >= 3`,1 <=> (3 >= 3) AS `1 <=> (3 >= 3)`,1 <=> 3 >= 3 AS `(1 <=> 3) >= 3` +select 1 <=> 3 >= 3, 1 <=> (3 >= 3), (1 <=> 3) >= 3 union select * from v1; +1 <=> 3 >= 3 1 <=> (3 >= 3) (1 <=> 3) >= 3 +0 1 0 +create or replace view v1 as select 2 <=> 3 <= 3, 2 <=> (3 <= 3), (2 <=> 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> 3 <= 3 AS `2 <=> 3 <= 3`,2 <=> (3 <= 3) AS `2 <=> (3 <= 3)`,2 <=> 3 <= 3 AS `(2 <=> 3) <= 3` +select 2 <=> 3 <= 3, 2 <=> (3 <= 3), (2 <=> 3) <= 3 union select * from v1; +2 <=> 3 <= 3 2 <=> (3 <= 3) (2 <=> 3) <= 3 +1 0 1 +create or replace view v1 as select 2 <=> 3 < 3, 2 <=> (3 < 3), (2 <=> 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> 3 < 3 AS `2 <=> 3 < 3`,2 <=> (3 < 3) AS `2 <=> (3 < 3)`,2 <=> 3 < 3 AS `(2 <=> 3) < 3` +select 2 <=> 3 < 3, 2 <=> (3 < 3), (2 <=> 3) < 3 union select * from v1; +2 <=> 3 < 3 2 <=> (3 < 3) (2 <=> 3) < 3 +1 0 1 +create or replace view v1 as select 2 <=> 3 <> 3, 2 <=> (3 <> 3), (2 <=> 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> 3 <> 3 AS `2 <=> 3 <> 3`,2 <=> (3 <> 3) AS `2 <=> (3 <> 3)`,2 <=> 3 <> 3 AS `(2 <=> 3) <> 3` +select 2 <=> 3 <> 3, 2 <=> (3 <> 3), (2 <=> 3) <> 3 union select * from v1; +2 <=> 3 <> 3 2 <=> (3 <> 3) (2 <=> 3) <> 3 +1 0 1 +create or replace view v1 as select 0 <=> 3 > 3, 0 <=> (3 > 3), (0 <=> 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 <=> 3 > 3 AS `0 <=> 3 > 3`,0 <=> (3 > 3) AS `0 <=> (3 > 3)`,0 <=> 3 > 3 AS `(0 <=> 3) > 3` +select 0 <=> 3 > 3, 0 <=> (3 > 3), (0 <=> 3) > 3 union select * from v1; +0 <=> 3 > 3 0 <=> (3 > 3) (0 <=> 3) > 3 +0 1 0 +create or replace view v1 as select 2 <=> 3 != 3, 2 <=> (3 != 3), (2 <=> 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> 3 <> 3 AS `2 <=> 3 != 3`,2 <=> (3 <> 3) AS `2 <=> (3 != 3)`,2 <=> 3 <> 3 AS `(2 <=> 3) != 3` +select 2 <=> 3 != 3, 2 <=> (3 != 3), (2 <=> 3) != 3 union select * from v1; +2 <=> 3 != 3 2 <=> (3 != 3) (2 <=> 3) != 3 +1 0 1 +create or replace view v1 as select 1 <=> 3 LIKE 3, 1 <=> (3 LIKE 3), (1 <=> 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 <=> (3 like 3) AS `1 <=> 3 LIKE 3`,1 <=> (3 like 3) AS `1 <=> (3 LIKE 3)`,1 <=> 3 like 3 AS `(1 <=> 3) LIKE 3` +select 1 <=> 3 LIKE 3, 1 <=> (3 LIKE 3), (1 <=> 3) LIKE 3 union select * from v1; +1 <=> 3 LIKE 3 1 <=> (3 LIKE 3) (1 <=> 3) LIKE 3 +1 1 0 +1 1 1 +create or replace view v1 as select 1 <=> 3 REGEXP 3, 1 <=> (3 REGEXP 3), (1 <=> 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 <=> (3 regexp 3) AS `1 <=> 3 REGEXP 3`,1 <=> (3 regexp 3) AS `1 <=> (3 REGEXP 3)`,1 <=> 3 regexp 3 AS `(1 <=> 3) REGEXP 3` +select 1 <=> 3 REGEXP 3, 1 <=> (3 REGEXP 3), (1 <=> 3) REGEXP 3 union select * from v1; +1 <=> 3 REGEXP 3 1 <=> (3 REGEXP 3) (1 <=> 3) REGEXP 3 +1 1 0 +1 1 1 +create or replace view v1 as select 2 <=> 3 | 3, 2 <=> (3 | 3), (2 <=> 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> 3 | 3 AS `2 <=> 3 | 3`,2 <=> 3 | 3 AS `2 <=> (3 | 3)`,(2 <=> 3) | 3 AS `(2 <=> 3) | 3` +select 2 <=> 3 | 3, 2 <=> (3 | 3), (2 <=> 3) | 3 union select * from v1; +2 <=> 3 | 3 2 <=> (3 | 3) (2 <=> 3) | 3 +0 0 3 +create or replace view v1 as select 2 <=> 3 & 2, 2 <=> (3 & 2), (2 <=> 3) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> 3 & 2 AS `2 <=> 3 & 2`,2 <=> 3 & 2 AS `2 <=> (3 & 2)`,(2 <=> 3) & 2 AS `(2 <=> 3) & 2` +select 2 <=> 3 & 2, 2 <=> (3 & 2), (2 <=> 3) & 2 union select * from v1; +2 <=> 3 & 2 2 <=> (3 & 2) (2 <=> 3) & 2 +1 1 0 +create or replace view v1 as select 3 <=> 3 << 3, 3 <=> (3 << 3), (3 <=> 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 <=> 3 << 3 AS `3 <=> 3 << 3`,3 <=> 3 << 3 AS `3 <=> (3 << 3)`,(3 <=> 3) << 3 AS `(3 <=> 3) << 3` +select 3 <=> 3 << 3, 3 <=> (3 << 3), (3 <=> 3) << 3 union select * from v1; +3 <=> 3 << 3 3 <=> (3 << 3) (3 <=> 3) << 3 +0 0 8 +create or replace view v1 as select 1 <=> 3 >> 1, 1 <=> (3 >> 1), (1 <=> 3) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 <=> 3 >> 1 AS `1 <=> 3 >> 1`,1 <=> 3 >> 1 AS `1 <=> (3 >> 1)`,(1 <=> 3) >> 1 AS `(1 <=> 3) >> 1` +select 1 <=> 3 >> 1, 1 <=> (3 >> 1), (1 <=> 3) >> 1 union select * from v1; +1 <=> 3 >> 1 1 <=> (3 >> 1) (1 <=> 3) >> 1 +1 1 0 +create or replace view v1 as select 2 <=> '2000-01-01' +INTERVAL 1 DAY, 2 <=> ('2000-01-01' +INTERVAL 1 DAY), (2 <=> '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> '2000-01-01' + interval 1 day AS `2 <=> '2000-01-01' +INTERVAL 1 DAY`,2 <=> '2000-01-01' + interval 1 day AS `2 <=> ('2000-01-01' +INTERVAL 1 DAY)`,(2 <=> '2000-01-01') + interval 1 day AS `(2 <=> '2000-01-01') +INTERVAL 1 DAY` +select 2 <=> '2000-01-01' +INTERVAL 1 DAY, 2 <=> ('2000-01-01' +INTERVAL 1 DAY), (2 <=> '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 <=> '2000-01-01' +INTERVAL 1 DAY 2 <=> ('2000-01-01' +INTERVAL 1 DAY) (2 <=> '2000-01-01') +INTERVAL 1 DAY +0 0 NULL +create or replace view v1 as select 2 <=> 3 + 3, 2 <=> (3 + 3), (2 <=> 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> 3 + 3 AS `2 <=> 3 + 3`,2 <=> 3 + 3 AS `2 <=> (3 + 3)`,(2 <=> 3) + 3 AS `(2 <=> 3) + 3` +select 2 <=> 3 + 3, 2 <=> (3 + 3), (2 <=> 3) + 3 union select * from v1; +2 <=> 3 + 3 2 <=> (3 + 3) (2 <=> 3) + 3 +0 0 3 +create or replace view v1 as select 2 <=> 3 - 3, 2 <=> (3 - 3), (2 <=> 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> 3 - 3 AS `2 <=> 3 - 3`,2 <=> 3 - 3 AS `2 <=> (3 - 3)`,(2 <=> 3) - 3 AS `(2 <=> 3) - 3` +select 2 <=> 3 - 3, 2 <=> (3 - 3), (2 <=> 3) - 3 union select * from v1; +2 <=> 3 - 3 2 <=> (3 - 3) (2 <=> 3) - 3 +0 0 -3 +create or replace view v1 as select 3 <=> 3 * 3, 3 <=> (3 * 3), (3 <=> 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 <=> 3 * 3 AS `3 <=> 3 * 3`,3 <=> 3 * 3 AS `3 <=> (3 * 3)`,(3 <=> 3) * 3 AS `(3 <=> 3) * 3` +select 3 <=> 3 * 3, 3 <=> (3 * 3), (3 <=> 3) * 3 union select * from v1; +3 <=> 3 * 3 3 <=> (3 * 3) (3 <=> 3) * 3 +0 0 3 +create or replace view v1 as select 3 <=> 9 / 3, 3 <=> (9 / 3), (3 <=> 9) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 <=> 9 / 3 AS `3 <=> 9 / 3`,3 <=> 9 / 3 AS `3 <=> (9 / 3)`,(3 <=> 9) / 3 AS `(3 <=> 9) / 3` +select 3 <=> 9 / 3, 3 <=> (9 / 3), (3 <=> 9) / 3 union select * from v1; +3 <=> 9 / 3 3 <=> (9 / 3) (3 <=> 9) / 3 +1 1 0.0000 +create or replace view v1 as select 3 <=> 9 DIV 3, 3 <=> (9 DIV 3), (3 <=> 9) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 <=> 9 DIV 3 AS `3 <=> 9 DIV 3`,3 <=> 9 DIV 3 AS `3 <=> (9 DIV 3)`,(3 <=> 9) DIV 3 AS `(3 <=> 9) DIV 3` +select 3 <=> 9 DIV 3, 3 <=> (9 DIV 3), (3 <=> 9) DIV 3 union select * from v1; +3 <=> 9 DIV 3 3 <=> (9 DIV 3) (3 <=> 9) DIV 3 +1 1 0 +create or replace view v1 as select 3 <=> 3 MOD 3, 3 <=> (3 MOD 3), (3 <=> 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 <=> 3 % 3 AS `3 <=> 3 MOD 3`,3 <=> 3 % 3 AS `3 <=> (3 MOD 3)`,(3 <=> 3) % 3 AS `(3 <=> 3) MOD 3` +select 3 <=> 3 MOD 3, 3 <=> (3 MOD 3), (3 <=> 3) MOD 3 union select * from v1; +3 <=> 3 MOD 3 3 <=> (3 MOD 3) (3 <=> 3) MOD 3 +0 0 1 +create or replace view v1 as select 3 <=> 3 % 3, 3 <=> (3 % 3), (3 <=> 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 <=> 3 % 3 AS `3 <=> 3 % 3`,3 <=> 3 % 3 AS `3 <=> (3 % 3)`,(3 <=> 3) % 3 AS `(3 <=> 3) % 3` +select 3 <=> 3 % 3, 3 <=> (3 % 3), (3 <=> 3) % 3 union select * from v1; +3 <=> 3 % 3 3 <=> (3 % 3) (3 <=> 3) % 3 +0 0 1 +create or replace view v1 as select 2 <=> 3 ^ 3, 2 <=> (3 ^ 3), (2 <=> 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> 3 ^ 3 AS `2 <=> 3 ^ 3`,2 <=> 3 ^ 3 AS `2 <=> (3 ^ 3)`,(2 <=> 3) ^ 3 AS `(2 <=> 3) ^ 3` +select 2 <=> 3 ^ 3, 2 <=> (3 ^ 3), (2 <=> 3) ^ 3 union select * from v1; +2 <=> 3 ^ 3 2 <=> (3 ^ 3) (2 <=> 3) ^ 3 +0 0 3 +create or replace view v1 as select 1 <=> 3 BETWEEN 1 AND 3, 1 <=> (3 BETWEEN 1 AND 3), (1 <=> 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 <=> (3 between 1 and 3) AS `1 <=> 3 BETWEEN 1 AND 3`,1 <=> (3 between 1 and 3) AS `1 <=> (3 BETWEEN 1 AND 3)`,1 <=> 3 between 1 and 3 AS `(1 <=> 3) BETWEEN 1 AND 3` +select 1 <=> 3 BETWEEN 1 AND 3, 1 <=> (3 BETWEEN 1 AND 3), (1 <=> 3) BETWEEN 1 AND 3 union select * from v1; +1 <=> 3 BETWEEN 1 AND 3 1 <=> (3 BETWEEN 1 AND 3) (1 <=> 3) BETWEEN 1 AND 3 +1 1 0 +1 1 1 +create or replace view v1 as select 4 >= 3 IS FALSE, 4 >= (3 IS FALSE), (4 >= 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 4 >= 3 is false AS `4 >= 3 IS FALSE`,4 >= (3 is false) AS `4 >= (3 IS FALSE)`,4 >= 3 is false AS `(4 >= 3) IS FALSE` +select 4 >= 3 IS FALSE, 4 >= (3 IS FALSE), (4 >= 3) IS FALSE union select * from v1; +4 >= 3 IS FALSE 4 >= (3 IS FALSE) (4 >= 3) IS FALSE +0 1 0 +create or replace view v1 as select charset(2 >= 3 COLLATE latin1_bin), charset(2 >= (3 COLLATE latin1_bin)), charset((2 >= 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 >= 3 collate latin1_bin) AS `charset(2 >= 3 COLLATE latin1_bin)`,charset(2 >= 3 collate latin1_bin) AS `charset(2 >= (3 COLLATE latin1_bin))`,charset((2 >= 3) collate latin1_bin) AS `charset((2 >= 3) COLLATE latin1_bin)` +select charset(2 >= 3 COLLATE latin1_bin), charset(2 >= (3 COLLATE latin1_bin)), charset((2 >= 3) COLLATE latin1_bin) union select * from v1; +charset(2 >= 3 COLLATE latin1_bin) charset(2 >= (3 COLLATE latin1_bin)) charset((2 >= 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 >= 3 IN (1,1), 2 >= (3 IN (1,1)), (2 >= 3) IN (1,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= (3 in (1,1)) AS `2 >= 3 IN (1,1)`,2 >= (3 in (1,1)) AS `2 >= (3 IN (1,1))`,2 >= 3 in (1,1) AS `(2 >= 3) IN (1,1)` +select 2 >= 3 IN (1,1), 2 >= (3 IN (1,1)), (2 >= 3) IN (1,1) union select * from v1; +2 >= 3 IN (1,1) 2 >= (3 IN (1,1)) (2 >= 3) IN (1,1) +1 1 0 +1 1 1 +create or replace view v1 as select 2 >= 3 OR 0, 2 >= (3 OR 0), (2 >= 3) OR 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 or 0 AS `2 >= 3 OR 0`,2 >= (3 or 0) AS `2 >= (3 OR 0)`,2 >= 3 or 0 AS `(2 >= 3) OR 0` +select 2 >= 3 OR 0, 2 >= (3 OR 0), (2 >= 3) OR 0 union select * from v1; +2 >= 3 OR 0 2 >= (3 OR 0) (2 >= 3) OR 0 +0 1 0 +create or replace view v1 as select 2 >= 3 || 0, 2 >= (3 || 0), (2 >= 3) || 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 or 0 AS `2 >= 3 || 0`,2 >= (3 or 0) AS `2 >= (3 || 0)`,2 >= 3 or 0 AS `(2 >= 3) || 0` +select 2 >= 3 || 0, 2 >= (3 || 0), (2 >= 3) || 0 union select * from v1; +2 >= 3 || 0 2 >= (3 || 0) (2 >= 3) || 0 +0 1 0 +create or replace view v1 as select 2 >= 3 XOR 0, 2 >= (3 XOR 0), (2 >= 3) XOR 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 xor 0 AS `2 >= 3 XOR 0`,2 >= (3 xor 0) AS `2 >= (3 XOR 0)`,2 >= 3 xor 0 AS `(2 >= 3) XOR 0` +select 2 >= 3 XOR 0, 2 >= (3 XOR 0), (2 >= 3) XOR 0 union select * from v1; +2 >= 3 XOR 0 2 >= (3 XOR 0) (2 >= 3) XOR 0 +0 1 0 +create or replace view v1 as select 2 >= 3 AND 3, 2 >= (3 AND 3), (2 >= 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 and 3 AS `2 >= 3 AND 3`,2 >= (3 and 3) AS `2 >= (3 AND 3)`,2 >= 3 and 3 AS `(2 >= 3) AND 3` +select 2 >= 3 AND 3, 2 >= (3 AND 3), (2 >= 3) AND 3 union select * from v1; +2 >= 3 AND 3 2 >= (3 AND 3) (2 >= 3) AND 3 +0 1 0 +create or replace view v1 as select 2 >= 3 && 3, 2 >= (3 && 3), (2 >= 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 and 3 AS `2 >= 3 && 3`,2 >= (3 and 3) AS `2 >= (3 && 3)`,2 >= 3 and 3 AS `(2 >= 3) && 3` +select 2 >= 3 && 3, 2 >= (3 && 3), (2 >= 3) && 3 union select * from v1; +2 >= 3 && 3 2 >= (3 && 3) (2 >= 3) && 3 +0 1 0 +create or replace view v1 as select 2 >= 3 = 3, 2 >= (3 = 3), (2 >= 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 = 3 AS `2 >= 3 = 3`,2 >= (3 = 3) AS `2 >= (3 = 3)`,2 >= 3 = 3 AS `(2 >= 3) = 3` +select 2 >= 3 = 3, 2 >= (3 = 3), (2 >= 3) = 3 union select * from v1; +2 >= 3 = 3 2 >= (3 = 3) (2 >= 3) = 3 +0 1 0 +create or replace view v1 as select 2 >= 3 <=> 3, 2 >= (3 <=> 3), (2 >= 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 <=> 3 AS `2 >= 3 <=> 3`,2 >= (3 <=> 3) AS `2 >= (3 <=> 3)`,2 >= 3 <=> 3 AS `(2 >= 3) <=> 3` +select 2 >= 3 <=> 3, 2 >= (3 <=> 3), (2 >= 3) <=> 3 union select * from v1; +2 >= 3 <=> 3 2 >= (3 <=> 3) (2 >= 3) <=> 3 +0 1 0 +create or replace view v1 as select 2 >= 3 >= 3, 2 >= (3 >= 3), (2 >= 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 >= 3 AS `2 >= 3 >= 3`,2 >= (3 >= 3) AS `2 >= (3 >= 3)`,2 >= 3 >= 3 AS `(2 >= 3) >= 3` +select 2 >= 3 >= 3, 2 >= (3 >= 3), (2 >= 3) >= 3 union select * from v1; +2 >= 3 >= 3 2 >= (3 >= 3) (2 >= 3) >= 3 +0 1 0 +create or replace view v1 as select 0 >= 3 <= 3, 0 >= (3 <= 3), (0 >= 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 >= 3 <= 3 AS `0 >= 3 <= 3`,0 >= (3 <= 3) AS `0 >= (3 <= 3)`,0 >= 3 <= 3 AS `(0 >= 3) <= 3` +select 0 >= 3 <= 3, 0 >= (3 <= 3), (0 >= 3) <= 3 union select * from v1; +0 >= 3 <= 3 0 >= (3 <= 3) (0 >= 3) <= 3 +1 0 1 +create or replace view v1 as select 0 >= 2 < 3, 0 >= (2 < 3), (0 >= 2) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 >= 2 < 3 AS `0 >= 2 < 3`,0 >= (2 < 3) AS `0 >= (2 < 3)`,0 >= 2 < 3 AS `(0 >= 2) < 3` +select 0 >= 2 < 3, 0 >= (2 < 3), (0 >= 2) < 3 union select * from v1; +0 >= 2 < 3 0 >= (2 < 3) (0 >= 2) < 3 +1 0 1 +create or replace view v1 as select 2 >= 3 <> 0, 2 >= (3 <> 0), (2 >= 3) <> 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 <> 0 AS `2 >= 3 <> 0`,2 >= (3 <> 0) AS `2 >= (3 <> 0)`,2 >= 3 <> 0 AS `(2 >= 3) <> 0` +select 2 >= 3 <> 0, 2 >= (3 <> 0), (2 >= 3) <> 0 union select * from v1; +2 >= 3 <> 0 2 >= (3 <> 0) (2 >= 3) <> 0 +0 1 0 +create or replace view v1 as select 2 >= 3 > 3, 2 >= (3 > 3), (2 >= 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 > 3 AS `2 >= 3 > 3`,2 >= (3 > 3) AS `2 >= (3 > 3)`,2 >= 3 > 3 AS `(2 >= 3) > 3` +select 2 >= 3 > 3, 2 >= (3 > 3), (2 >= 3) > 3 union select * from v1; +2 >= 3 > 3 2 >= (3 > 3) (2 >= 3) > 3 +0 1 0 +create or replace view v1 as select 2 >= 3 != 0, 2 >= (3 != 0), (2 >= 3) != 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 <> 0 AS `2 >= 3 != 0`,2 >= (3 <> 0) AS `2 >= (3 != 0)`,2 >= 3 <> 0 AS `(2 >= 3) != 0` +select 2 >= 3 != 0, 2 >= (3 != 0), (2 >= 3) != 0 union select * from v1; +2 >= 3 != 0 2 >= (3 != 0) (2 >= 3) != 0 +0 1 0 +create or replace view v1 as select 2 >= 3 LIKE 3, 2 >= (3 LIKE 3), (2 >= 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= (3 like 3) AS `2 >= 3 LIKE 3`,2 >= (3 like 3) AS `2 >= (3 LIKE 3)`,2 >= 3 like 3 AS `(2 >= 3) LIKE 3` +select 2 >= 3 LIKE 3, 2 >= (3 LIKE 3), (2 >= 3) LIKE 3 union select * from v1; +2 >= 3 LIKE 3 2 >= (3 LIKE 3) (2 >= 3) LIKE 3 +1 1 0 +1 1 1 +create or replace view v1 as select 2 >= 3 REGEXP 3, 2 >= (3 REGEXP 3), (2 >= 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= (3 regexp 3) AS `2 >= 3 REGEXP 3`,2 >= (3 regexp 3) AS `2 >= (3 REGEXP 3)`,2 >= 3 regexp 3 AS `(2 >= 3) REGEXP 3` +select 2 >= 3 REGEXP 3, 2 >= (3 REGEXP 3), (2 >= 3) REGEXP 3 union select * from v1; +2 >= 3 REGEXP 3 2 >= (3 REGEXP 3) (2 >= 3) REGEXP 3 +1 1 0 +1 1 1 +create or replace view v1 as select 2 >= 3 | 3, 2 >= (3 | 3), (2 >= 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 | 3 AS `2 >= 3 | 3`,2 >= 3 | 3 AS `2 >= (3 | 3)`,(2 >= 3) | 3 AS `(2 >= 3) | 3` +select 2 >= 3 | 3, 2 >= (3 | 3), (2 >= 3) | 3 union select * from v1; +2 >= 3 | 3 2 >= (3 | 3) (2 >= 3) | 3 +0 0 3 +create or replace view v1 as select 2 >= 3 & 1, 2 >= (3 & 1), (2 >= 3) & 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 & 1 AS `2 >= 3 & 1`,2 >= 3 & 1 AS `2 >= (3 & 1)`,(2 >= 3) & 1 AS `(2 >= 3) & 1` +select 2 >= 3 & 1, 2 >= (3 & 1), (2 >= 3) & 1 union select * from v1; +2 >= 3 & 1 2 >= (3 & 1) (2 >= 3) & 1 +1 1 0 +create or replace view v1 as select 3 >= 3 << 3, 3 >= (3 << 3), (3 >= 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 >= 3 << 3 AS `3 >= 3 << 3`,3 >= 3 << 3 AS `3 >= (3 << 3)`,(3 >= 3) << 3 AS `(3 >= 3) << 3` +select 3 >= 3 << 3, 3 >= (3 << 3), (3 >= 3) << 3 union select * from v1; +3 >= 3 << 3 3 >= (3 << 3) (3 >= 3) << 3 +0 0 8 +create or replace view v1 as select 2 >= 3 >> 3, 2 >= (3 >> 3), (2 >= 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 >> 3 AS `2 >= 3 >> 3`,2 >= 3 >> 3 AS `2 >= (3 >> 3)`,(2 >= 3) >> 3 AS `(2 >= 3) >> 3` +select 2 >= 3 >> 3, 2 >= (3 >> 3), (2 >= 3) >> 3 union select * from v1; +2 >= 3 >> 3 2 >= (3 >> 3) (2 >= 3) >> 3 +1 1 0 +create or replace view v1 as select 2 >= '2000-01-01' +INTERVAL 1 DAY, 2 >= ('2000-01-01' +INTERVAL 1 DAY), (2 >= '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= '2000-01-01' + interval 1 day AS `2 >= '2000-01-01' +INTERVAL 1 DAY`,2 >= '2000-01-01' + interval 1 day AS `2 >= ('2000-01-01' +INTERVAL 1 DAY)`,(2 >= '2000-01-01') + interval 1 day AS `(2 >= '2000-01-01') +INTERVAL 1 DAY` +select 2 >= '2000-01-01' +INTERVAL 1 DAY, 2 >= ('2000-01-01' +INTERVAL 1 DAY), (2 >= '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 >= '2000-01-01' +INTERVAL 1 DAY 2 >= ('2000-01-01' +INTERVAL 1 DAY) (2 >= '2000-01-01') +INTERVAL 1 DAY +0 0 NULL +create or replace view v1 as select 2 >= 3 + 3, 2 >= (3 + 3), (2 >= 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 + 3 AS `2 >= 3 + 3`,2 >= 3 + 3 AS `2 >= (3 + 3)`,(2 >= 3) + 3 AS `(2 >= 3) + 3` +select 2 >= 3 + 3, 2 >= (3 + 3), (2 >= 3) + 3 union select * from v1; +2 >= 3 + 3 2 >= (3 + 3) (2 >= 3) + 3 +0 0 3 +create or replace view v1 as select 2 >= 3 - 3, 2 >= (3 - 3), (2 >= 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 - 3 AS `2 >= 3 - 3`,2 >= 3 - 3 AS `2 >= (3 - 3)`,(2 >= 3) - 3 AS `(2 >= 3) - 3` +select 2 >= 3 - 3, 2 >= (3 - 3), (2 >= 3) - 3 union select * from v1; +2 >= 3 - 3 2 >= (3 - 3) (2 >= 3) - 3 +1 1 -3 +create or replace view v1 as select 3 >= 3 * 3, 3 >= (3 * 3), (3 >= 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 >= 3 * 3 AS `3 >= 3 * 3`,3 >= 3 * 3 AS `3 >= (3 * 3)`,(3 >= 3) * 3 AS `(3 >= 3) * 3` +select 3 >= 3 * 3, 3 >= (3 * 3), (3 >= 3) * 3 union select * from v1; +3 >= 3 * 3 3 >= (3 * 3) (3 >= 3) * 3 +0 0 3 +create or replace view v1 as select 2 >= 3 / 3, 2 >= (3 / 3), (2 >= 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 / 3 AS `2 >= 3 / 3`,2 >= 3 / 3 AS `2 >= (3 / 3)`,(2 >= 3) / 3 AS `(2 >= 3) / 3` +select 2 >= 3 / 3, 2 >= (3 / 3), (2 >= 3) / 3 union select * from v1; +2 >= 3 / 3 2 >= (3 / 3) (2 >= 3) / 3 +1 1 0.0000 +create or replace view v1 as select 2 >= 3 DIV 3, 2 >= (3 DIV 3), (2 >= 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 DIV 3 AS `2 >= 3 DIV 3`,2 >= 3 DIV 3 AS `2 >= (3 DIV 3)`,(2 >= 3) DIV 3 AS `(2 >= 3) DIV 3` +select 2 >= 3 DIV 3, 2 >= (3 DIV 3), (2 >= 3) DIV 3 union select * from v1; +2 >= 3 DIV 3 2 >= (3 DIV 3) (2 >= 3) DIV 3 +1 1 0 +create or replace view v1 as select 2 >= 3 MOD 3, 2 >= (3 MOD 3), (2 >= 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 % 3 AS `2 >= 3 MOD 3`,2 >= 3 % 3 AS `2 >= (3 MOD 3)`,(2 >= 3) % 3 AS `(2 >= 3) MOD 3` +select 2 >= 3 MOD 3, 2 >= (3 MOD 3), (2 >= 3) MOD 3 union select * from v1; +2 >= 3 MOD 3 2 >= (3 MOD 3) (2 >= 3) MOD 3 +1 1 0 +create or replace view v1 as select 2 >= 3 % 3, 2 >= (3 % 3), (2 >= 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 % 3 AS `2 >= 3 % 3`,2 >= 3 % 3 AS `2 >= (3 % 3)`,(2 >= 3) % 3 AS `(2 >= 3) % 3` +select 2 >= 3 % 3, 2 >= (3 % 3), (2 >= 3) % 3 union select * from v1; +2 >= 3 % 3 2 >= (3 % 3) (2 >= 3) % 3 +1 1 0 +create or replace view v1 as select 2 >= 3 ^ 3, 2 >= (3 ^ 3), (2 >= 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= 3 ^ 3 AS `2 >= 3 ^ 3`,2 >= 3 ^ 3 AS `2 >= (3 ^ 3)`,(2 >= 3) ^ 3 AS `(2 >= 3) ^ 3` +select 2 >= 3 ^ 3, 2 >= (3 ^ 3), (2 >= 3) ^ 3 union select * from v1; +2 >= 3 ^ 3 2 >= (3 ^ 3) (2 >= 3) ^ 3 +1 1 3 +create or replace view v1 as select 2 >= 3 BETWEEN 1 AND 3, 2 >= (3 BETWEEN 1 AND 3), (2 >= 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= (3 between 1 and 3) AS `2 >= 3 BETWEEN 1 AND 3`,2 >= (3 between 1 and 3) AS `2 >= (3 BETWEEN 1 AND 3)`,2 >= 3 between 1 and 3 AS `(2 >= 3) BETWEEN 1 AND 3` +select 2 >= 3 BETWEEN 1 AND 3, 2 >= (3 BETWEEN 1 AND 3), (2 >= 3) BETWEEN 1 AND 3 union select * from v1; +2 >= 3 BETWEEN 1 AND 3 2 >= (3 BETWEEN 1 AND 3) (2 >= 3) BETWEEN 1 AND 3 +1 1 0 +1 1 1 +create or replace view v1 as select 2 <= 1 IS FALSE, 2 <= (1 IS FALSE), (2 <= 1) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 1 is false AS `2 <= 1 IS FALSE`,2 <= (1 is false) AS `2 <= (1 IS FALSE)`,2 <= 1 is false AS `(2 <= 1) IS FALSE` +select 2 <= 1 IS FALSE, 2 <= (1 IS FALSE), (2 <= 1) IS FALSE union select * from v1; +2 <= 1 IS FALSE 2 <= (1 IS FALSE) (2 <= 1) IS FALSE +1 0 1 +create or replace view v1 as select charset(2 <= 3 COLLATE latin1_bin), charset(2 <= (3 COLLATE latin1_bin)), charset((2 <= 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 <= 3 collate latin1_bin) AS `charset(2 <= 3 COLLATE latin1_bin)`,charset(2 <= 3 collate latin1_bin) AS `charset(2 <= (3 COLLATE latin1_bin))`,charset((2 <= 3) collate latin1_bin) AS `charset((2 <= 3) COLLATE latin1_bin)` +select charset(2 <= 3 COLLATE latin1_bin), charset(2 <= (3 COLLATE latin1_bin)), charset((2 <= 3) COLLATE latin1_bin) union select * from v1; +charset(2 <= 3 COLLATE latin1_bin) charset(2 <= (3 COLLATE latin1_bin)) charset((2 <= 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 <= 3 IN (0,1), 2 <= (3 IN (0,1)), (2 <= 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= (3 in (0,1)) AS `2 <= 3 IN (0,1)`,2 <= (3 in (0,1)) AS `2 <= (3 IN (0,1))`,2 <= 3 in (0,1) AS `(2 <= 3) IN (0,1)` +select 2 <= 3 IN (0,1), 2 <= (3 IN (0,1)), (2 <= 3) IN (0,1) union select * from v1; +2 <= 3 IN (0,1) 2 <= (3 IN (0,1)) (2 <= 3) IN (0,1) +0 0 1 +0 0 0 +create or replace view v1 as select 2 <= 3 OR 3, 2 <= (3 OR 3), (2 <= 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 or 3 AS `2 <= 3 OR 3`,2 <= (3 or 3) AS `2 <= (3 OR 3)`,2 <= 3 or 3 AS `(2 <= 3) OR 3` +select 2 <= 3 OR 3, 2 <= (3 OR 3), (2 <= 3) OR 3 union select * from v1; +2 <= 3 OR 3 2 <= (3 OR 3) (2 <= 3) OR 3 +1 0 1 +create or replace view v1 as select 2 <= 3 || 3, 2 <= (3 || 3), (2 <= 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 or 3 AS `2 <= 3 || 3`,2 <= (3 or 3) AS `2 <= (3 || 3)`,2 <= 3 or 3 AS `(2 <= 3) || 3` +select 2 <= 3 || 3, 2 <= (3 || 3), (2 <= 3) || 3 union select * from v1; +2 <= 3 || 3 2 <= (3 || 3) (2 <= 3) || 3 +1 0 1 +create or replace view v1 as select 2 <= 1 XOR 1, 2 <= (1 XOR 1), (2 <= 1) XOR 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 1 xor 1 AS `2 <= 1 XOR 1`,2 <= (1 xor 1) AS `2 <= (1 XOR 1)`,2 <= 1 xor 1 AS `(2 <= 1) XOR 1` +select 2 <= 1 XOR 1, 2 <= (1 XOR 1), (2 <= 1) XOR 1 union select * from v1; +2 <= 1 XOR 1 2 <= (1 XOR 1) (2 <= 1) XOR 1 +1 0 1 +create or replace view v1 as select 2 <= 3 AND 3, 2 <= (3 AND 3), (2 <= 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 and 3 AS `2 <= 3 AND 3`,2 <= (3 and 3) AS `2 <= (3 AND 3)`,2 <= 3 and 3 AS `(2 <= 3) AND 3` +select 2 <= 3 AND 3, 2 <= (3 AND 3), (2 <= 3) AND 3 union select * from v1; +2 <= 3 AND 3 2 <= (3 AND 3) (2 <= 3) AND 3 +1 0 1 +create or replace view v1 as select 2 <= 3 && 3, 2 <= (3 && 3), (2 <= 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 and 3 AS `2 <= 3 && 3`,2 <= (3 and 3) AS `2 <= (3 && 3)`,2 <= 3 and 3 AS `(2 <= 3) && 3` +select 2 <= 3 && 3, 2 <= (3 && 3), (2 <= 3) && 3 union select * from v1; +2 <= 3 && 3 2 <= (3 && 3) (2 <= 3) && 3 +1 0 1 +create or replace view v1 as select 2 <= 0 = 0, 2 <= (0 = 0), (2 <= 0) = 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 0 = 0 AS `2 <= 0 = 0`,2 <= (0 = 0) AS `2 <= (0 = 0)`,2 <= 0 = 0 AS `(2 <= 0) = 0` +select 2 <= 0 = 0, 2 <= (0 = 0), (2 <= 0) = 0 union select * from v1; +2 <= 0 = 0 2 <= (0 = 0) (2 <= 0) = 0 +1 0 1 +create or replace view v1 as select 2 <= 0 <=> 0, 2 <= (0 <=> 0), (2 <= 0) <=> 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 0 <=> 0 AS `2 <= 0 <=> 0`,2 <= (0 <=> 0) AS `2 <= (0 <=> 0)`,2 <= 0 <=> 0 AS `(2 <= 0) <=> 0` +select 2 <= 0 <=> 0, 2 <= (0 <=> 0), (2 <= 0) <=> 0 union select * from v1; +2 <= 0 <=> 0 2 <= (0 <=> 0) (2 <= 0) <=> 0 +1 0 1 +create or replace view v1 as select 2 <= 0 >= 0, 2 <= (0 >= 0), (2 <= 0) >= 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 0 >= 0 AS `2 <= 0 >= 0`,2 <= (0 >= 0) AS `2 <= (0 >= 0)`,2 <= 0 >= 0 AS `(2 <= 0) >= 0` +select 2 <= 0 >= 0, 2 <= (0 >= 0), (2 <= 0) >= 0 union select * from v1; +2 <= 0 >= 0 2 <= (0 >= 0) (2 <= 0) >= 0 +1 0 1 +create or replace view v1 as select 2 <= 3 <= 3, 2 <= (3 <= 3), (2 <= 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 <= 3 AS `2 <= 3 <= 3`,2 <= (3 <= 3) AS `2 <= (3 <= 3)`,2 <= 3 <= 3 AS `(2 <= 3) <= 3` +select 2 <= 3 <= 3, 2 <= (3 <= 3), (2 <= 3) <= 3 union select * from v1; +2 <= 3 <= 3 2 <= (3 <= 3) (2 <= 3) <= 3 +1 0 1 +create or replace view v1 as select 2 <= 3 < 3, 2 <= (3 < 3), (2 <= 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 < 3 AS `2 <= 3 < 3`,2 <= (3 < 3) AS `2 <= (3 < 3)`,2 <= 3 < 3 AS `(2 <= 3) < 3` +select 2 <= 3 < 3, 2 <= (3 < 3), (2 <= 3) < 3 union select * from v1; +2 <= 3 < 3 2 <= (3 < 3) (2 <= 3) < 3 +1 0 1 +create or replace view v1 as select 2 <= 3 <> 3, 2 <= (3 <> 3), (2 <= 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 <> 3 AS `2 <= 3 <> 3`,2 <= (3 <> 3) AS `2 <= (3 <> 3)`,2 <= 3 <> 3 AS `(2 <= 3) <> 3` +select 2 <= 3 <> 3, 2 <= (3 <> 3), (2 <= 3) <> 3 union select * from v1; +2 <= 3 <> 3 2 <= (3 <> 3) (2 <= 3) <> 3 +1 0 1 +create or replace view v1 as select 2 <= 3 > 0, 2 <= (3 > 0), (2 <= 3) > 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 > 0 AS `2 <= 3 > 0`,2 <= (3 > 0) AS `2 <= (3 > 0)`,2 <= 3 > 0 AS `(2 <= 3) > 0` +select 2 <= 3 > 0, 2 <= (3 > 0), (2 <= 3) > 0 union select * from v1; +2 <= 3 > 0 2 <= (3 > 0) (2 <= 3) > 0 +1 0 1 +create or replace view v1 as select 2 <= 3 != 3, 2 <= (3 != 3), (2 <= 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 <> 3 AS `2 <= 3 != 3`,2 <= (3 <> 3) AS `2 <= (3 != 3)`,2 <= 3 <> 3 AS `(2 <= 3) != 3` +select 2 <= 3 != 3, 2 <= (3 != 3), (2 <= 3) != 3 union select * from v1; +2 <= 3 != 3 2 <= (3 != 3) (2 <= 3) != 3 +1 0 1 +create or replace view v1 as select 2 <= 0 LIKE 0, 2 <= (0 LIKE 0), (2 <= 0) LIKE 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= (0 like 0) AS `2 <= 0 LIKE 0`,2 <= (0 like 0) AS `2 <= (0 LIKE 0)`,2 <= 0 like 0 AS `(2 <= 0) LIKE 0` +select 2 <= 0 LIKE 0, 2 <= (0 LIKE 0), (2 <= 0) LIKE 0 union select * from v1; +2 <= 0 LIKE 0 2 <= (0 LIKE 0) (2 <= 0) LIKE 0 +0 0 1 +0 0 0 +create or replace view v1 as select 2 <= 0 REGEXP 0, 2 <= (0 REGEXP 0), (2 <= 0) REGEXP 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= (0 regexp 0) AS `2 <= 0 REGEXP 0`,2 <= (0 regexp 0) AS `2 <= (0 REGEXP 0)`,2 <= 0 regexp 0 AS `(2 <= 0) REGEXP 0` +select 2 <= 0 REGEXP 0, 2 <= (0 REGEXP 0), (2 <= 0) REGEXP 0 union select * from v1; +2 <= 0 REGEXP 0 2 <= (0 REGEXP 0) (2 <= 0) REGEXP 0 +0 0 1 +0 0 0 +create or replace view v1 as select 2 <= 3 | 3, 2 <= (3 | 3), (2 <= 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 | 3 AS `2 <= 3 | 3`,2 <= 3 | 3 AS `2 <= (3 | 3)`,(2 <= 3) | 3 AS `(2 <= 3) | 3` +select 2 <= 3 | 3, 2 <= (3 | 3), (2 <= 3) | 3 union select * from v1; +2 <= 3 | 3 2 <= (3 | 3) (2 <= 3) | 3 +1 1 3 +create or replace view v1 as select 2 <= 3 & 2, 2 <= (3 & 2), (2 <= 3) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 & 2 AS `2 <= 3 & 2`,2 <= 3 & 2 AS `2 <= (3 & 2)`,(2 <= 3) & 2 AS `(2 <= 3) & 2` +select 2 <= 3 & 2, 2 <= (3 & 2), (2 <= 3) & 2 union select * from v1; +2 <= 3 & 2 2 <= (3 & 2) (2 <= 3) & 2 +1 1 0 +create or replace view v1 as select 2 <= 3 << 3, 2 <= (3 << 3), (2 <= 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 << 3 AS `2 <= 3 << 3`,2 <= 3 << 3 AS `2 <= (3 << 3)`,(2 <= 3) << 3 AS `(2 <= 3) << 3` +select 2 <= 3 << 3, 2 <= (3 << 3), (2 <= 3) << 3 union select * from v1; +2 <= 3 << 3 2 <= (3 << 3) (2 <= 3) << 3 +1 1 8 +create or replace view v1 as select 0 <= 3 >> 1, 0 <= (3 >> 1), (0 <= 3) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 <= 3 >> 1 AS `0 <= 3 >> 1`,0 <= 3 >> 1 AS `0 <= (3 >> 1)`,(0 <= 3) >> 1 AS `(0 <= 3) >> 1` +select 0 <= 3 >> 1, 0 <= (3 >> 1), (0 <= 3) >> 1 union select * from v1; +0 <= 3 >> 1 0 <= (3 >> 1) (0 <= 3) >> 1 +1 1 0 +create or replace view v1 as select 2 <= '2000-01-01' +INTERVAL 1 DAY, 2 <= ('2000-01-01' +INTERVAL 1 DAY), (2 <= '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= '2000-01-01' + interval 1 day AS `2 <= '2000-01-01' +INTERVAL 1 DAY`,2 <= '2000-01-01' + interval 1 day AS `2 <= ('2000-01-01' +INTERVAL 1 DAY)`,(2 <= '2000-01-01') + interval 1 day AS `(2 <= '2000-01-01') +INTERVAL 1 DAY` +select 2 <= '2000-01-01' +INTERVAL 1 DAY, 2 <= ('2000-01-01' +INTERVAL 1 DAY), (2 <= '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 <= '2000-01-01' +INTERVAL 1 DAY 2 <= ('2000-01-01' +INTERVAL 1 DAY) (2 <= '2000-01-01') +INTERVAL 1 DAY +1 1 NULL +create or replace view v1 as select 2 <= 3 + 3, 2 <= (3 + 3), (2 <= 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 + 3 AS `2 <= 3 + 3`,2 <= 3 + 3 AS `2 <= (3 + 3)`,(2 <= 3) + 3 AS `(2 <= 3) + 3` +select 2 <= 3 + 3, 2 <= (3 + 3), (2 <= 3) + 3 union select * from v1; +2 <= 3 + 3 2 <= (3 + 3) (2 <= 3) + 3 +1 1 4 +create or replace view v1 as select 2 <= 3 - 3, 2 <= (3 - 3), (2 <= 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 - 3 AS `2 <= 3 - 3`,2 <= 3 - 3 AS `2 <= (3 - 3)`,(2 <= 3) - 3 AS `(2 <= 3) - 3` +select 2 <= 3 - 3, 2 <= (3 - 3), (2 <= 3) - 3 union select * from v1; +2 <= 3 - 3 2 <= (3 - 3) (2 <= 3) - 3 +0 0 -2 +create or replace view v1 as select 2 <= 3 * 3, 2 <= (3 * 3), (2 <= 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 * 3 AS `2 <= 3 * 3`,2 <= 3 * 3 AS `2 <= (3 * 3)`,(2 <= 3) * 3 AS `(2 <= 3) * 3` +select 2 <= 3 * 3, 2 <= (3 * 3), (2 <= 3) * 3 union select * from v1; +2 <= 3 * 3 2 <= (3 * 3) (2 <= 3) * 3 +1 1 3 +create or replace view v1 as select 2 <= 3 / 3, 2 <= (3 / 3), (2 <= 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 / 3 AS `2 <= 3 / 3`,2 <= 3 / 3 AS `2 <= (3 / 3)`,(2 <= 3) / 3 AS `(2 <= 3) / 3` +select 2 <= 3 / 3, 2 <= (3 / 3), (2 <= 3) / 3 union select * from v1; +2 <= 3 / 3 2 <= (3 / 3) (2 <= 3) / 3 +0 0 0.3333 +create or replace view v1 as select 2 <= 9 DIV 3, 2 <= (9 DIV 3), (2 <= 9) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 9 DIV 3 AS `2 <= 9 DIV 3`,2 <= 9 DIV 3 AS `2 <= (9 DIV 3)`,(2 <= 9) DIV 3 AS `(2 <= 9) DIV 3` +select 2 <= 9 DIV 3, 2 <= (9 DIV 3), (2 <= 9) DIV 3 union select * from v1; +2 <= 9 DIV 3 2 <= (9 DIV 3) (2 <= 9) DIV 3 +1 1 0 +create or replace view v1 as select 2 <= 3 MOD 3, 2 <= (3 MOD 3), (2 <= 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 % 3 AS `2 <= 3 MOD 3`,2 <= 3 % 3 AS `2 <= (3 MOD 3)`,(2 <= 3) % 3 AS `(2 <= 3) MOD 3` +select 2 <= 3 MOD 3, 2 <= (3 MOD 3), (2 <= 3) MOD 3 union select * from v1; +2 <= 3 MOD 3 2 <= (3 MOD 3) (2 <= 3) MOD 3 +0 0 1 +create or replace view v1 as select 2 <= 3 % 3, 2 <= (3 % 3), (2 <= 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 % 3 AS `2 <= 3 % 3`,2 <= 3 % 3 AS `2 <= (3 % 3)`,(2 <= 3) % 3 AS `(2 <= 3) % 3` +select 2 <= 3 % 3, 2 <= (3 % 3), (2 <= 3) % 3 union select * from v1; +2 <= 3 % 3 2 <= (3 % 3) (2 <= 3) % 3 +0 0 1 +create or replace view v1 as select 2 <= 3 ^ 3, 2 <= (3 ^ 3), (2 <= 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= 3 ^ 3 AS `2 <= 3 ^ 3`,2 <= 3 ^ 3 AS `2 <= (3 ^ 3)`,(2 <= 3) ^ 3 AS `(2 <= 3) ^ 3` +select 2 <= 3 ^ 3, 2 <= (3 ^ 3), (2 <= 3) ^ 3 union select * from v1; +2 <= 3 ^ 3 2 <= (3 ^ 3) (2 <= 3) ^ 3 +0 0 2 +create or replace view v1 as select 2 <= 3 BETWEEN 1 AND 3, 2 <= (3 BETWEEN 1 AND 3), (2 <= 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= (3 between 1 and 3) AS `2 <= 3 BETWEEN 1 AND 3`,2 <= (3 between 1 and 3) AS `2 <= (3 BETWEEN 1 AND 3)`,2 <= 3 between 1 and 3 AS `(2 <= 3) BETWEEN 1 AND 3` +select 2 <= 3 BETWEEN 1 AND 3, 2 <= (3 BETWEEN 1 AND 3), (2 <= 3) BETWEEN 1 AND 3 union select * from v1; +2 <= 3 BETWEEN 1 AND 3 2 <= (3 BETWEEN 1 AND 3) (2 <= 3) BETWEEN 1 AND 3 +0 0 1 +0 0 0 +create or replace view v1 as select 2 < 1 IS FALSE, 2 < (1 IS FALSE), (2 < 1) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 1 is false AS `2 < 1 IS FALSE`,2 < (1 is false) AS `2 < (1 IS FALSE)`,2 < 1 is false AS `(2 < 1) IS FALSE` +select 2 < 1 IS FALSE, 2 < (1 IS FALSE), (2 < 1) IS FALSE union select * from v1; +2 < 1 IS FALSE 2 < (1 IS FALSE) (2 < 1) IS FALSE +1 0 1 +create or replace view v1 as select charset(2 < 3 COLLATE latin1_bin), charset(2 < (3 COLLATE latin1_bin)), charset((2 < 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 < 3 collate latin1_bin) AS `charset(2 < 3 COLLATE latin1_bin)`,charset(2 < 3 collate latin1_bin) AS `charset(2 < (3 COLLATE latin1_bin))`,charset((2 < 3) collate latin1_bin) AS `charset((2 < 3) COLLATE latin1_bin)` +select charset(2 < 3 COLLATE latin1_bin), charset(2 < (3 COLLATE latin1_bin)), charset((2 < 3) COLLATE latin1_bin) union select * from v1; +charset(2 < 3 COLLATE latin1_bin) charset(2 < (3 COLLATE latin1_bin)) charset((2 < 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 < 3 IN (0,1), 2 < (3 IN (0,1)), (2 < 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < (3 in (0,1)) AS `2 < 3 IN (0,1)`,2 < (3 in (0,1)) AS `2 < (3 IN (0,1))`,2 < 3 in (0,1) AS `(2 < 3) IN (0,1)` +select 2 < 3 IN (0,1), 2 < (3 IN (0,1)), (2 < 3) IN (0,1) union select * from v1; +2 < 3 IN (0,1) 2 < (3 IN (0,1)) (2 < 3) IN (0,1) +0 0 1 +0 0 0 +create or replace view v1 as select 2 < 3 OR 3, 2 < (3 OR 3), (2 < 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 or 3 AS `2 < 3 OR 3`,2 < (3 or 3) AS `2 < (3 OR 3)`,2 < 3 or 3 AS `(2 < 3) OR 3` +select 2 < 3 OR 3, 2 < (3 OR 3), (2 < 3) OR 3 union select * from v1; +2 < 3 OR 3 2 < (3 OR 3) (2 < 3) OR 3 +1 0 1 +create or replace view v1 as select 2 < 3 || 3, 2 < (3 || 3), (2 < 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 or 3 AS `2 < 3 || 3`,2 < (3 or 3) AS `2 < (3 || 3)`,2 < 3 or 3 AS `(2 < 3) || 3` +select 2 < 3 || 3, 2 < (3 || 3), (2 < 3) || 3 union select * from v1; +2 < 3 || 3 2 < (3 || 3) (2 < 3) || 3 +1 0 1 +create or replace view v1 as select 2 < 3 XOR 0, 2 < (3 XOR 0), (2 < 3) XOR 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 xor 0 AS `2 < 3 XOR 0`,2 < (3 xor 0) AS `2 < (3 XOR 0)`,2 < 3 xor 0 AS `(2 < 3) XOR 0` +select 2 < 3 XOR 0, 2 < (3 XOR 0), (2 < 3) XOR 0 union select * from v1; +2 < 3 XOR 0 2 < (3 XOR 0) (2 < 3) XOR 0 +1 0 1 +create or replace view v1 as select 2 < 3 AND 3, 2 < (3 AND 3), (2 < 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 and 3 AS `2 < 3 AND 3`,2 < (3 and 3) AS `2 < (3 AND 3)`,2 < 3 and 3 AS `(2 < 3) AND 3` +select 2 < 3 AND 3, 2 < (3 AND 3), (2 < 3) AND 3 union select * from v1; +2 < 3 AND 3 2 < (3 AND 3) (2 < 3) AND 3 +1 0 1 +create or replace view v1 as select 2 < 3 && 3, 2 < (3 && 3), (2 < 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 and 3 AS `2 < 3 && 3`,2 < (3 and 3) AS `2 < (3 && 3)`,2 < 3 and 3 AS `(2 < 3) && 3` +select 2 < 3 && 3, 2 < (3 && 3), (2 < 3) && 3 union select * from v1; +2 < 3 && 3 2 < (3 && 3) (2 < 3) && 3 +1 0 1 +create or replace view v1 as select 2 < 3 = 1, 2 < (3 = 1), (2 < 3) = 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 = 1 AS `2 < 3 = 1`,2 < (3 = 1) AS `2 < (3 = 1)`,2 < 3 = 1 AS `(2 < 3) = 1` +select 2 < 3 = 1, 2 < (3 = 1), (2 < 3) = 1 union select * from v1; +2 < 3 = 1 2 < (3 = 1) (2 < 3) = 1 +1 0 1 +create or replace view v1 as select 2 < 3 <=> 1, 2 < (3 <=> 1), (2 < 3) <=> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 <=> 1 AS `2 < 3 <=> 1`,2 < (3 <=> 1) AS `2 < (3 <=> 1)`,2 < 3 <=> 1 AS `(2 < 3) <=> 1` +select 2 < 3 <=> 1, 2 < (3 <=> 1), (2 < 3) <=> 1 union select * from v1; +2 < 3 <=> 1 2 < (3 <=> 1) (2 < 3) <=> 1 +1 0 1 +create or replace view v1 as select 2 < 3 >= 1, 2 < (3 >= 1), (2 < 3) >= 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 >= 1 AS `2 < 3 >= 1`,2 < (3 >= 1) AS `2 < (3 >= 1)`,2 < 3 >= 1 AS `(2 < 3) >= 1` +select 2 < 3 >= 1, 2 < (3 >= 1), (2 < 3) >= 1 union select * from v1; +2 < 3 >= 1 2 < (3 >= 1) (2 < 3) >= 1 +1 0 1 +create or replace view v1 as select 2 < 3 <= 3, 2 < (3 <= 3), (2 < 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 <= 3 AS `2 < 3 <= 3`,2 < (3 <= 3) AS `2 < (3 <= 3)`,2 < 3 <= 3 AS `(2 < 3) <= 3` +select 2 < 3 <= 3, 2 < (3 <= 3), (2 < 3) <= 3 union select * from v1; +2 < 3 <= 3 2 < (3 <= 3) (2 < 3) <= 3 +1 0 1 +create or replace view v1 as select 2 < 3 < 3, 2 < (3 < 3), (2 < 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 < 3 AS `2 < 3 < 3`,2 < (3 < 3) AS `2 < (3 < 3)`,2 < 3 < 3 AS `(2 < 3) < 3` +select 2 < 3 < 3, 2 < (3 < 3), (2 < 3) < 3 union select * from v1; +2 < 3 < 3 2 < (3 < 3) (2 < 3) < 3 +1 0 1 +create or replace view v1 as select 2 < 3 <> 3, 2 < (3 <> 3), (2 < 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 <> 3 AS `2 < 3 <> 3`,2 < (3 <> 3) AS `2 < (3 <> 3)`,2 < 3 <> 3 AS `(2 < 3) <> 3` +select 2 < 3 <> 3, 2 < (3 <> 3), (2 < 3) <> 3 union select * from v1; +2 < 3 <> 3 2 < (3 <> 3) (2 < 3) <> 3 +1 0 1 +create or replace view v1 as select 2 < 3 > 0, 2 < (3 > 0), (2 < 3) > 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 > 0 AS `2 < 3 > 0`,2 < (3 > 0) AS `2 < (3 > 0)`,2 < 3 > 0 AS `(2 < 3) > 0` +select 2 < 3 > 0, 2 < (3 > 0), (2 < 3) > 0 union select * from v1; +2 < 3 > 0 2 < (3 > 0) (2 < 3) > 0 +1 0 1 +create or replace view v1 as select 2 < 3 != 3, 2 < (3 != 3), (2 < 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 <> 3 AS `2 < 3 != 3`,2 < (3 <> 3) AS `2 < (3 != 3)`,2 < 3 <> 3 AS `(2 < 3) != 3` +select 2 < 3 != 3, 2 < (3 != 3), (2 < 3) != 3 union select * from v1; +2 < 3 != 3 2 < (3 != 3) (2 < 3) != 3 +1 0 1 +create or replace view v1 as select 2 < 3 LIKE 1, 2 < (3 LIKE 1), (2 < 3) LIKE 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < (3 like 1) AS `2 < 3 LIKE 1`,2 < (3 like 1) AS `2 < (3 LIKE 1)`,2 < 3 like 1 AS `(2 < 3) LIKE 1` +select 2 < 3 LIKE 1, 2 < (3 LIKE 1), (2 < 3) LIKE 1 union select * from v1; +2 < 3 LIKE 1 2 < (3 LIKE 1) (2 < 3) LIKE 1 +0 0 1 +0 0 0 +create or replace view v1 as select 2 < 3 REGEXP 1, 2 < (3 REGEXP 1), (2 < 3) REGEXP 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < (3 regexp 1) AS `2 < 3 REGEXP 1`,2 < (3 regexp 1) AS `2 < (3 REGEXP 1)`,2 < 3 regexp 1 AS `(2 < 3) REGEXP 1` +select 2 < 3 REGEXP 1, 2 < (3 REGEXP 1), (2 < 3) REGEXP 1 union select * from v1; +2 < 3 REGEXP 1 2 < (3 REGEXP 1) (2 < 3) REGEXP 1 +0 0 1 +0 0 0 +create or replace view v1 as select 2 < 3 | 3, 2 < (3 | 3), (2 < 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 | 3 AS `2 < 3 | 3`,2 < 3 | 3 AS `2 < (3 | 3)`,(2 < 3) | 3 AS `(2 < 3) | 3` +select 2 < 3 | 3, 2 < (3 | 3), (2 < 3) | 3 union select * from v1; +2 < 3 | 3 2 < (3 | 3) (2 < 3) | 3 +1 1 3 +create or replace view v1 as select 2 < 4 & 4, 2 < (4 & 4), (2 < 4) & 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 4 & 4 AS `2 < 4 & 4`,2 < 4 & 4 AS `2 < (4 & 4)`,(2 < 4) & 4 AS `(2 < 4) & 4` +select 2 < 4 & 4, 2 < (4 & 4), (2 < 4) & 4 union select * from v1; +2 < 4 & 4 2 < (4 & 4) (2 < 4) & 4 +1 1 0 +create or replace view v1 as select 2 < 3 << 3, 2 < (3 << 3), (2 < 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 << 3 AS `2 < 3 << 3`,2 < 3 << 3 AS `2 < (3 << 3)`,(2 < 3) << 3 AS `(2 < 3) << 3` +select 2 < 3 << 3, 2 < (3 << 3), (2 < 3) << 3 union select * from v1; +2 < 3 << 3 2 < (3 << 3) (2 < 3) << 3 +1 1 8 +create or replace view v1 as select 0 < 3 >> 1, 0 < (3 >> 1), (0 < 3) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 < 3 >> 1 AS `0 < 3 >> 1`,0 < 3 >> 1 AS `0 < (3 >> 1)`,(0 < 3) >> 1 AS `(0 < 3) >> 1` +select 0 < 3 >> 1, 0 < (3 >> 1), (0 < 3) >> 1 union select * from v1; +0 < 3 >> 1 0 < (3 >> 1) (0 < 3) >> 1 +1 1 0 +create or replace view v1 as select 2 < '2000-01-01' +INTERVAL 1 DAY, 2 < ('2000-01-01' +INTERVAL 1 DAY), (2 < '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < '2000-01-01' + interval 1 day AS `2 < '2000-01-01' +INTERVAL 1 DAY`,2 < '2000-01-01' + interval 1 day AS `2 < ('2000-01-01' +INTERVAL 1 DAY)`,(2 < '2000-01-01') + interval 1 day AS `(2 < '2000-01-01') +INTERVAL 1 DAY` +select 2 < '2000-01-01' +INTERVAL 1 DAY, 2 < ('2000-01-01' +INTERVAL 1 DAY), (2 < '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 < '2000-01-01' +INTERVAL 1 DAY 2 < ('2000-01-01' +INTERVAL 1 DAY) (2 < '2000-01-01') +INTERVAL 1 DAY +1 1 NULL +create or replace view v1 as select 2 < 3 + 3, 2 < (3 + 3), (2 < 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 + 3 AS `2 < 3 + 3`,2 < 3 + 3 AS `2 < (3 + 3)`,(2 < 3) + 3 AS `(2 < 3) + 3` +select 2 < 3 + 3, 2 < (3 + 3), (2 < 3) + 3 union select * from v1; +2 < 3 + 3 2 < (3 + 3) (2 < 3) + 3 +1 1 4 +create or replace view v1 as select 2 < 3 - 3, 2 < (3 - 3), (2 < 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 - 3 AS `2 < 3 - 3`,2 < 3 - 3 AS `2 < (3 - 3)`,(2 < 3) - 3 AS `(2 < 3) - 3` +select 2 < 3 - 3, 2 < (3 - 3), (2 < 3) - 3 union select * from v1; +2 < 3 - 3 2 < (3 - 3) (2 < 3) - 3 +0 0 -2 +create or replace view v1 as select 2 < 3 * 3, 2 < (3 * 3), (2 < 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 * 3 AS `2 < 3 * 3`,2 < 3 * 3 AS `2 < (3 * 3)`,(2 < 3) * 3 AS `(2 < 3) * 3` +select 2 < 3 * 3, 2 < (3 * 3), (2 < 3) * 3 union select * from v1; +2 < 3 * 3 2 < (3 * 3) (2 < 3) * 3 +1 1 3 +create or replace view v1 as select 2 < 3 / 3, 2 < (3 / 3), (2 < 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 / 3 AS `2 < 3 / 3`,2 < 3 / 3 AS `2 < (3 / 3)`,(2 < 3) / 3 AS `(2 < 3) / 3` +select 2 < 3 / 3, 2 < (3 / 3), (2 < 3) / 3 union select * from v1; +2 < 3 / 3 2 < (3 / 3) (2 < 3) / 3 +0 0 0.3333 +create or replace view v1 as select 2 < 9 DIV 3, 2 < (9 DIV 3), (2 < 9) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 9 DIV 3 AS `2 < 9 DIV 3`,2 < 9 DIV 3 AS `2 < (9 DIV 3)`,(2 < 9) DIV 3 AS `(2 < 9) DIV 3` +select 2 < 9 DIV 3, 2 < (9 DIV 3), (2 < 9) DIV 3 union select * from v1; +2 < 9 DIV 3 2 < (9 DIV 3) (2 < 9) DIV 3 +1 1 0 +create or replace view v1 as select 2 < 3 MOD 3, 2 < (3 MOD 3), (2 < 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 % 3 AS `2 < 3 MOD 3`,2 < 3 % 3 AS `2 < (3 MOD 3)`,(2 < 3) % 3 AS `(2 < 3) MOD 3` +select 2 < 3 MOD 3, 2 < (3 MOD 3), (2 < 3) MOD 3 union select * from v1; +2 < 3 MOD 3 2 < (3 MOD 3) (2 < 3) MOD 3 +0 0 1 +create or replace view v1 as select 2 < 3 % 3, 2 < (3 % 3), (2 < 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 % 3 AS `2 < 3 % 3`,2 < 3 % 3 AS `2 < (3 % 3)`,(2 < 3) % 3 AS `(2 < 3) % 3` +select 2 < 3 % 3, 2 < (3 % 3), (2 < 3) % 3 union select * from v1; +2 < 3 % 3 2 < (3 % 3) (2 < 3) % 3 +0 0 1 +create or replace view v1 as select 2 < 3 ^ 3, 2 < (3 ^ 3), (2 < 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < 3 ^ 3 AS `2 < 3 ^ 3`,2 < 3 ^ 3 AS `2 < (3 ^ 3)`,(2 < 3) ^ 3 AS `(2 < 3) ^ 3` +select 2 < 3 ^ 3, 2 < (3 ^ 3), (2 < 3) ^ 3 union select * from v1; +2 < 3 ^ 3 2 < (3 ^ 3) (2 < 3) ^ 3 +0 0 2 +create or replace view v1 as select 2 < 3 BETWEEN 1 AND 3, 2 < (3 BETWEEN 1 AND 3), (2 < 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < (3 between 1 and 3) AS `2 < 3 BETWEEN 1 AND 3`,2 < (3 between 1 and 3) AS `2 < (3 BETWEEN 1 AND 3)`,2 < 3 between 1 and 3 AS `(2 < 3) BETWEEN 1 AND 3` +select 2 < 3 BETWEEN 1 AND 3, 2 < (3 BETWEEN 1 AND 3), (2 < 3) BETWEEN 1 AND 3 union select * from v1; +2 < 3 BETWEEN 1 AND 3 2 < (3 BETWEEN 1 AND 3) (2 < 3) BETWEEN 1 AND 3 +0 0 1 +0 0 0 +create or replace view v1 as select 2 <> 3 IS FALSE, 2 <> (3 IS FALSE), (2 <> 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 is false AS `2 <> 3 IS FALSE`,2 <> (3 is false) AS `2 <> (3 IS FALSE)`,2 <> 3 is false AS `(2 <> 3) IS FALSE` +select 2 <> 3 IS FALSE, 2 <> (3 IS FALSE), (2 <> 3) IS FALSE union select * from v1; +2 <> 3 IS FALSE 2 <> (3 IS FALSE) (2 <> 3) IS FALSE +0 1 0 +create or replace view v1 as select charset(2 <> 3 COLLATE latin1_bin), charset(2 <> (3 COLLATE latin1_bin)), charset((2 <> 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 <> 3 collate latin1_bin) AS `charset(2 <> 3 COLLATE latin1_bin)`,charset(2 <> 3 collate latin1_bin) AS `charset(2 <> (3 COLLATE latin1_bin))`,charset((2 <> 3) collate latin1_bin) AS `charset((2 <> 3) COLLATE latin1_bin)` +select charset(2 <> 3 COLLATE latin1_bin), charset(2 <> (3 COLLATE latin1_bin)), charset((2 <> 3) COLLATE latin1_bin) union select * from v1; +charset(2 <> 3 COLLATE latin1_bin) charset(2 <> (3 COLLATE latin1_bin)) charset((2 <> 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 <> 3 IN (0,0), 2 <> (3 IN (0,0)), (2 <> 3) IN (0,0); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> (3 in (0,0)) AS `2 <> 3 IN (0,0)`,2 <> (3 in (0,0)) AS `2 <> (3 IN (0,0))`,2 <> 3 in (0,0) AS `(2 <> 3) IN (0,0)` +select 2 <> 3 IN (0,0), 2 <> (3 IN (0,0)), (2 <> 3) IN (0,0) union select * from v1; +2 <> 3 IN (0,0) 2 <> (3 IN (0,0)) (2 <> 3) IN (0,0) +1 1 0 +1 1 1 +create or replace view v1 as select 1 <> 3 OR 3, 1 <> (3 OR 3), (1 <> 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 <> 3 or 3 AS `1 <> 3 OR 3`,1 <> (3 or 3) AS `1 <> (3 OR 3)`,1 <> 3 or 3 AS `(1 <> 3) OR 3` +select 1 <> 3 OR 3, 1 <> (3 OR 3), (1 <> 3) OR 3 union select * from v1; +1 <> 3 OR 3 1 <> (3 OR 3) (1 <> 3) OR 3 +1 0 1 +create or replace view v1 as select 1 <> 3 || 3, 1 <> (3 || 3), (1 <> 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 <> 3 or 3 AS `1 <> 3 || 3`,1 <> (3 or 3) AS `1 <> (3 || 3)`,1 <> 3 or 3 AS `(1 <> 3) || 3` +select 1 <> 3 || 3, 1 <> (3 || 3), (1 <> 3) || 3 union select * from v1; +1 <> 3 || 3 1 <> (3 || 3) (1 <> 3) || 3 +1 0 1 +create or replace view v1 as select 2 <> 3 XOR 3, 2 <> (3 XOR 3), (2 <> 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 xor 3 AS `2 <> 3 XOR 3`,2 <> (3 xor 3) AS `2 <> (3 XOR 3)`,2 <> 3 xor 3 AS `(2 <> 3) XOR 3` +select 2 <> 3 XOR 3, 2 <> (3 XOR 3), (2 <> 3) XOR 3 union select * from v1; +2 <> 3 XOR 3 2 <> (3 XOR 3) (2 <> 3) XOR 3 +0 1 0 +create or replace view v1 as select 3 <> 3 AND 3, 3 <> (3 AND 3), (3 <> 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 <> 3 and 3 AS `3 <> 3 AND 3`,3 <> (3 and 3) AS `3 <> (3 AND 3)`,3 <> 3 and 3 AS `(3 <> 3) AND 3` +select 3 <> 3 AND 3, 3 <> (3 AND 3), (3 <> 3) AND 3 union select * from v1; +3 <> 3 AND 3 3 <> (3 AND 3) (3 <> 3) AND 3 +0 1 0 +create or replace view v1 as select 3 <> 3 && 3, 3 <> (3 && 3), (3 <> 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 <> 3 and 3 AS `3 <> 3 && 3`,3 <> (3 and 3) AS `3 <> (3 && 3)`,3 <> 3 and 3 AS `(3 <> 3) && 3` +select 3 <> 3 && 3, 3 <> (3 && 3), (3 <> 3) && 3 union select * from v1; +3 <> 3 && 3 3 <> (3 && 3) (3 <> 3) && 3 +0 1 0 +create or replace view v1 as select 2 <> 3 = 3, 2 <> (3 = 3), (2 <> 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 = 3 AS `2 <> 3 = 3`,2 <> (3 = 3) AS `2 <> (3 = 3)`,2 <> 3 = 3 AS `(2 <> 3) = 3` +select 2 <> 3 = 3, 2 <> (3 = 3), (2 <> 3) = 3 union select * from v1; +2 <> 3 = 3 2 <> (3 = 3) (2 <> 3) = 3 +0 1 0 +create or replace view v1 as select 2 <> 3 <=> 3, 2 <> (3 <=> 3), (2 <> 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 <=> 3 AS `2 <> 3 <=> 3`,2 <> (3 <=> 3) AS `2 <> (3 <=> 3)`,2 <> 3 <=> 3 AS `(2 <> 3) <=> 3` +select 2 <> 3 <=> 3, 2 <> (3 <=> 3), (2 <> 3) <=> 3 union select * from v1; +2 <> 3 <=> 3 2 <> (3 <=> 3) (2 <> 3) <=> 3 +0 1 0 +create or replace view v1 as select 2 <> 3 >= 3, 2 <> (3 >= 3), (2 <> 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 >= 3 AS `2 <> 3 >= 3`,2 <> (3 >= 3) AS `2 <> (3 >= 3)`,2 <> 3 >= 3 AS `(2 <> 3) >= 3` +select 2 <> 3 >= 3, 2 <> (3 >= 3), (2 <> 3) >= 3 union select * from v1; +2 <> 3 >= 3 2 <> (3 >= 3) (2 <> 3) >= 3 +0 1 0 +create or replace view v1 as select 1 <> 3 <= 3, 1 <> (3 <= 3), (1 <> 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 <> 3 <= 3 AS `1 <> 3 <= 3`,1 <> (3 <= 3) AS `1 <> (3 <= 3)`,1 <> 3 <= 3 AS `(1 <> 3) <= 3` +select 1 <> 3 <= 3, 1 <> (3 <= 3), (1 <> 3) <= 3 union select * from v1; +1 <> 3 <= 3 1 <> (3 <= 3) (1 <> 3) <= 3 +1 0 1 +create or replace view v1 as select 0 <> 3 < 3, 0 <> (3 < 3), (0 <> 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 <> 3 < 3 AS `0 <> 3 < 3`,0 <> (3 < 3) AS `0 <> (3 < 3)`,0 <> 3 < 3 AS `(0 <> 3) < 3` +select 0 <> 3 < 3, 0 <> (3 < 3), (0 <> 3) < 3 union select * from v1; +0 <> 3 < 3 0 <> (3 < 3) (0 <> 3) < 3 +1 0 1 +create or replace view v1 as select 0 <> 3 <> 3, 0 <> (3 <> 3), (0 <> 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 <> 3 <> 3 AS `0 <> 3 <> 3`,0 <> (3 <> 3) AS `0 <> (3 <> 3)`,0 <> 3 <> 3 AS `(0 <> 3) <> 3` +select 0 <> 3 <> 3, 0 <> (3 <> 3), (0 <> 3) <> 3 union select * from v1; +0 <> 3 <> 3 0 <> (3 <> 3) (0 <> 3) <> 3 +1 0 1 +create or replace view v1 as select 2 <> 3 > 3, 2 <> (3 > 3), (2 <> 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 > 3 AS `2 <> 3 > 3`,2 <> (3 > 3) AS `2 <> (3 > 3)`,2 <> 3 > 3 AS `(2 <> 3) > 3` +select 2 <> 3 > 3, 2 <> (3 > 3), (2 <> 3) > 3 union select * from v1; +2 <> 3 > 3 2 <> (3 > 3) (2 <> 3) > 3 +0 1 0 +create or replace view v1 as select 0 <> 3 != 3, 0 <> (3 != 3), (0 <> 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 <> 3 <> 3 AS `0 <> 3 != 3`,0 <> (3 <> 3) AS `0 <> (3 != 3)`,0 <> 3 <> 3 AS `(0 <> 3) != 3` +select 0 <> 3 != 3, 0 <> (3 != 3), (0 <> 3) != 3 union select * from v1; +0 <> 3 != 3 0 <> (3 != 3) (0 <> 3) != 3 +1 0 1 +create or replace view v1 as select 2 <> 3 LIKE 3, 2 <> (3 LIKE 3), (2 <> 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> (3 like 3) AS `2 <> 3 LIKE 3`,2 <> (3 like 3) AS `2 <> (3 LIKE 3)`,2 <> 3 like 3 AS `(2 <> 3) LIKE 3` +select 2 <> 3 LIKE 3, 2 <> (3 LIKE 3), (2 <> 3) LIKE 3 union select * from v1; +2 <> 3 LIKE 3 2 <> (3 LIKE 3) (2 <> 3) LIKE 3 +1 1 0 +1 1 1 +create or replace view v1 as select 2 <> 3 REGEXP 3, 2 <> (3 REGEXP 3), (2 <> 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> (3 regexp 3) AS `2 <> 3 REGEXP 3`,2 <> (3 regexp 3) AS `2 <> (3 REGEXP 3)`,2 <> 3 regexp 3 AS `(2 <> 3) REGEXP 3` +select 2 <> 3 REGEXP 3, 2 <> (3 REGEXP 3), (2 <> 3) REGEXP 3 union select * from v1; +2 <> 3 REGEXP 3 2 <> (3 REGEXP 3) (2 <> 3) REGEXP 3 +1 1 0 +1 1 1 +create or replace view v1 as select 2 <> 3 | 3, 2 <> (3 | 3), (2 <> 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 | 3 AS `2 <> 3 | 3`,2 <> 3 | 3 AS `2 <> (3 | 3)`,(2 <> 3) | 3 AS `(2 <> 3) | 3` +select 2 <> 3 | 3, 2 <> (3 | 3), (2 <> 3) | 3 union select * from v1; +2 <> 3 | 3 2 <> (3 | 3) (2 <> 3) | 3 +1 1 3 +create or replace view v1 as select 2 <> 4 & 4, 2 <> (4 & 4), (2 <> 4) & 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 4 & 4 AS `2 <> 4 & 4`,2 <> 4 & 4 AS `2 <> (4 & 4)`,(2 <> 4) & 4 AS `(2 <> 4) & 4` +select 2 <> 4 & 4, 2 <> (4 & 4), (2 <> 4) & 4 union select * from v1; +2 <> 4 & 4 2 <> (4 & 4) (2 <> 4) & 4 +1 1 0 +create or replace view v1 as select 2 <> 3 << 3, 2 <> (3 << 3), (2 <> 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 << 3 AS `2 <> 3 << 3`,2 <> 3 << 3 AS `2 <> (3 << 3)`,(2 <> 3) << 3 AS `(2 <> 3) << 3` +select 2 <> 3 << 3, 2 <> (3 << 3), (2 <> 3) << 3 union select * from v1; +2 <> 3 << 3 2 <> (3 << 3) (2 <> 3) << 3 +1 1 8 +create or replace view v1 as select 2 <> 3 >> 3, 2 <> (3 >> 3), (2 <> 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 >> 3 AS `2 <> 3 >> 3`,2 <> 3 >> 3 AS `2 <> (3 >> 3)`,(2 <> 3) >> 3 AS `(2 <> 3) >> 3` +select 2 <> 3 >> 3, 2 <> (3 >> 3), (2 <> 3) >> 3 union select * from v1; +2 <> 3 >> 3 2 <> (3 >> 3) (2 <> 3) >> 3 +1 1 0 +create or replace view v1 as select 2 <> '2000-01-01' +INTERVAL 1 DAY, 2 <> ('2000-01-01' +INTERVAL 1 DAY), (2 <> '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> '2000-01-01' + interval 1 day AS `2 <> '2000-01-01' +INTERVAL 1 DAY`,2 <> '2000-01-01' + interval 1 day AS `2 <> ('2000-01-01' +INTERVAL 1 DAY)`,(2 <> '2000-01-01') + interval 1 day AS `(2 <> '2000-01-01') +INTERVAL 1 DAY` +select 2 <> '2000-01-01' +INTERVAL 1 DAY, 2 <> ('2000-01-01' +INTERVAL 1 DAY), (2 <> '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 <> '2000-01-01' +INTERVAL 1 DAY 2 <> ('2000-01-01' +INTERVAL 1 DAY) (2 <> '2000-01-01') +INTERVAL 1 DAY +1 1 NULL +create or replace view v1 as select 2 <> 3 + 3, 2 <> (3 + 3), (2 <> 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 + 3 AS `2 <> 3 + 3`,2 <> 3 + 3 AS `2 <> (3 + 3)`,(2 <> 3) + 3 AS `(2 <> 3) + 3` +select 2 <> 3 + 3, 2 <> (3 + 3), (2 <> 3) + 3 union select * from v1; +2 <> 3 + 3 2 <> (3 + 3) (2 <> 3) + 3 +1 1 4 +create or replace view v1 as select 2 <> 3 - 3, 2 <> (3 - 3), (2 <> 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 - 3 AS `2 <> 3 - 3`,2 <> 3 - 3 AS `2 <> (3 - 3)`,(2 <> 3) - 3 AS `(2 <> 3) - 3` +select 2 <> 3 - 3, 2 <> (3 - 3), (2 <> 3) - 3 union select * from v1; +2 <> 3 - 3 2 <> (3 - 3) (2 <> 3) - 3 +1 1 -2 +create or replace view v1 as select 2 <> 3 * 3, 2 <> (3 * 3), (2 <> 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 * 3 AS `2 <> 3 * 3`,2 <> 3 * 3 AS `2 <> (3 * 3)`,(2 <> 3) * 3 AS `(2 <> 3) * 3` +select 2 <> 3 * 3, 2 <> (3 * 3), (2 <> 3) * 3 union select * from v1; +2 <> 3 * 3 2 <> (3 * 3) (2 <> 3) * 3 +1 1 3 +create or replace view v1 as select 2 <> 3 / 3, 2 <> (3 / 3), (2 <> 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 / 3 AS `2 <> 3 / 3`,2 <> 3 / 3 AS `2 <> (3 / 3)`,(2 <> 3) / 3 AS `(2 <> 3) / 3` +select 2 <> 3 / 3, 2 <> (3 / 3), (2 <> 3) / 3 union select * from v1; +2 <> 3 / 3 2 <> (3 / 3) (2 <> 3) / 3 +1 1 0.3333 +create or replace view v1 as select 2 <> 3 DIV 3, 2 <> (3 DIV 3), (2 <> 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 DIV 3 AS `2 <> 3 DIV 3`,2 <> 3 DIV 3 AS `2 <> (3 DIV 3)`,(2 <> 3) DIV 3 AS `(2 <> 3) DIV 3` +select 2 <> 3 DIV 3, 2 <> (3 DIV 3), (2 <> 3) DIV 3 union select * from v1; +2 <> 3 DIV 3 2 <> (3 DIV 3) (2 <> 3) DIV 3 +1 1 0 +create or replace view v1 as select 3 <> 3 MOD 3, 3 <> (3 MOD 3), (3 <> 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 <> 3 % 3 AS `3 <> 3 MOD 3`,3 <> 3 % 3 AS `3 <> (3 MOD 3)`,(3 <> 3) % 3 AS `(3 <> 3) MOD 3` +select 3 <> 3 MOD 3, 3 <> (3 MOD 3), (3 <> 3) MOD 3 union select * from v1; +3 <> 3 MOD 3 3 <> (3 MOD 3) (3 <> 3) MOD 3 +1 1 0 +create or replace view v1 as select 3 <> 3 % 3, 3 <> (3 % 3), (3 <> 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 <> 3 % 3 AS `3 <> 3 % 3`,3 <> 3 % 3 AS `3 <> (3 % 3)`,(3 <> 3) % 3 AS `(3 <> 3) % 3` +select 3 <> 3 % 3, 3 <> (3 % 3), (3 <> 3) % 3 union select * from v1; +3 <> 3 % 3 3 <> (3 % 3) (3 <> 3) % 3 +1 1 0 +create or replace view v1 as select 2 <> 3 ^ 3, 2 <> (3 ^ 3), (2 <> 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 ^ 3 AS `2 <> 3 ^ 3`,2 <> 3 ^ 3 AS `2 <> (3 ^ 3)`,(2 <> 3) ^ 3 AS `(2 <> 3) ^ 3` +select 2 <> 3 ^ 3, 2 <> (3 ^ 3), (2 <> 3) ^ 3 union select * from v1; +2 <> 3 ^ 3 2 <> (3 ^ 3) (2 <> 3) ^ 3 +1 1 2 +create or replace view v1 as select 2 <> 3 BETWEEN 2 AND 3, 2 <> (3 BETWEEN 2 AND 3), (2 <> 3) BETWEEN 2 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> (3 between 2 and 3) AS `2 <> 3 BETWEEN 2 AND 3`,2 <> (3 between 2 and 3) AS `2 <> (3 BETWEEN 2 AND 3)`,2 <> 3 between 2 and 3 AS `(2 <> 3) BETWEEN 2 AND 3` +select 2 <> 3 BETWEEN 2 AND 3, 2 <> (3 BETWEEN 2 AND 3), (2 <> 3) BETWEEN 2 AND 3 union select * from v1; +2 <> 3 BETWEEN 2 AND 3 2 <> (3 BETWEEN 2 AND 3) (2 <> 3) BETWEEN 2 AND 3 +1 1 0 +1 1 1 +create or replace view v1 as select 2 > 0 IS FALSE, 2 > (0 IS FALSE), (2 > 0) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 0 is false AS `2 > 0 IS FALSE`,2 > (0 is false) AS `2 > (0 IS FALSE)`,2 > 0 is false AS `(2 > 0) IS FALSE` +select 2 > 0 IS FALSE, 2 > (0 IS FALSE), (2 > 0) IS FALSE union select * from v1; +2 > 0 IS FALSE 2 > (0 IS FALSE) (2 > 0) IS FALSE +0 1 0 +create or replace view v1 as select charset(2 > 3 COLLATE latin1_bin), charset(2 > (3 COLLATE latin1_bin)), charset((2 > 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 > 3 collate latin1_bin) AS `charset(2 > 3 COLLATE latin1_bin)`,charset(2 > 3 collate latin1_bin) AS `charset(2 > (3 COLLATE latin1_bin))`,charset((2 > 3) collate latin1_bin) AS `charset((2 > 3) COLLATE latin1_bin)` +select charset(2 > 3 COLLATE latin1_bin), charset(2 > (3 COLLATE latin1_bin)), charset((2 > 3) COLLATE latin1_bin) union select * from v1; +charset(2 > 3 COLLATE latin1_bin) charset(2 > (3 COLLATE latin1_bin)) charset((2 > 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 > 3 IN (1,1), 2 > (3 IN (1,1)), (2 > 3) IN (1,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > (3 in (1,1)) AS `2 > 3 IN (1,1)`,2 > (3 in (1,1)) AS `2 > (3 IN (1,1))`,2 > 3 in (1,1) AS `(2 > 3) IN (1,1)` +select 2 > 3 IN (1,1), 2 > (3 IN (1,1)), (2 > 3) IN (1,1) union select * from v1; +2 > 3 IN (1,1) 2 > (3 IN (1,1)) (2 > 3) IN (1,1) +1 1 0 +1 1 1 +create or replace view v1 as select 0 > 3 OR 3, 0 > (3 OR 3), (0 > 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 > 3 or 3 AS `0 > 3 OR 3`,0 > (3 or 3) AS `0 > (3 OR 3)`,0 > 3 or 3 AS `(0 > 3) OR 3` +select 0 > 3 OR 3, 0 > (3 OR 3), (0 > 3) OR 3 union select * from v1; +0 > 3 OR 3 0 > (3 OR 3) (0 > 3) OR 3 +1 0 1 +create or replace view v1 as select 0 > 3 || 3, 0 > (3 || 3), (0 > 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 > 3 or 3 AS `0 > 3 || 3`,0 > (3 or 3) AS `0 > (3 || 3)`,0 > 3 or 3 AS `(0 > 3) || 3` +select 0 > 3 || 3, 0 > (3 || 3), (0 > 3) || 3 union select * from v1; +0 > 3 || 3 0 > (3 || 3) (0 > 3) || 3 +1 0 1 +create or replace view v1 as select 4 > 3 XOR 3, 4 > (3 XOR 3), (4 > 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 4 > 3 xor 3 AS `4 > 3 XOR 3`,4 > (3 xor 3) AS `4 > (3 XOR 3)`,4 > 3 xor 3 AS `(4 > 3) XOR 3` +select 4 > 3 XOR 3, 4 > (3 XOR 3), (4 > 3) XOR 3 union select * from v1; +4 > 3 XOR 3 4 > (3 XOR 3) (4 > 3) XOR 3 +0 1 0 +create or replace view v1 as select 2 > 3 AND 3, 2 > (3 AND 3), (2 > 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 and 3 AS `2 > 3 AND 3`,2 > (3 and 3) AS `2 > (3 AND 3)`,2 > 3 and 3 AS `(2 > 3) AND 3` +select 2 > 3 AND 3, 2 > (3 AND 3), (2 > 3) AND 3 union select * from v1; +2 > 3 AND 3 2 > (3 AND 3) (2 > 3) AND 3 +0 1 0 +create or replace view v1 as select 2 > 3 && 3, 2 > (3 && 3), (2 > 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 and 3 AS `2 > 3 && 3`,2 > (3 and 3) AS `2 > (3 && 3)`,2 > 3 and 3 AS `(2 > 3) && 3` +select 2 > 3 && 3, 2 > (3 && 3), (2 > 3) && 3 union select * from v1; +2 > 3 && 3 2 > (3 && 3) (2 > 3) && 3 +0 1 0 +create or replace view v1 as select 2 > 3 = 3, 2 > (3 = 3), (2 > 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 = 3 AS `2 > 3 = 3`,2 > (3 = 3) AS `2 > (3 = 3)`,2 > 3 = 3 AS `(2 > 3) = 3` +select 2 > 3 = 3, 2 > (3 = 3), (2 > 3) = 3 union select * from v1; +2 > 3 = 3 2 > (3 = 3) (2 > 3) = 3 +0 1 0 +create or replace view v1 as select 2 > 3 <=> 3, 2 > (3 <=> 3), (2 > 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 <=> 3 AS `2 > 3 <=> 3`,2 > (3 <=> 3) AS `2 > (3 <=> 3)`,2 > 3 <=> 3 AS `(2 > 3) <=> 3` +select 2 > 3 <=> 3, 2 > (3 <=> 3), (2 > 3) <=> 3 union select * from v1; +2 > 3 <=> 3 2 > (3 <=> 3) (2 > 3) <=> 3 +0 1 0 +create or replace view v1 as select 2 > 3 >= 3, 2 > (3 >= 3), (2 > 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 >= 3 AS `2 > 3 >= 3`,2 > (3 >= 3) AS `2 > (3 >= 3)`,2 > 3 >= 3 AS `(2 > 3) >= 3` +select 2 > 3 >= 3, 2 > (3 >= 3), (2 > 3) >= 3 union select * from v1; +2 > 3 >= 3 2 > (3 >= 3) (2 > 3) >= 3 +0 1 0 +create or replace view v1 as select 2 > 0 <= 0, 2 > (0 <= 0), (2 > 0) <= 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 0 <= 0 AS `2 > 0 <= 0`,2 > (0 <= 0) AS `2 > (0 <= 0)`,2 > 0 <= 0 AS `(2 > 0) <= 0` +select 2 > 0 <= 0, 2 > (0 <= 0), (2 > 0) <= 0 union select * from v1; +2 > 0 <= 0 2 > (0 <= 0) (2 > 0) <= 0 +0 1 0 +create or replace view v1 as select 2 > 0 < 0, 2 > (0 < 0), (2 > 0) < 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 0 < 0 AS `2 > 0 < 0`,2 > (0 < 0) AS `2 > (0 < 0)`,2 > 0 < 0 AS `(2 > 0) < 0` +select 2 > 0 < 0, 2 > (0 < 0), (2 > 0) < 0 union select * from v1; +2 > 0 < 0 2 > (0 < 0) (2 > 0) < 0 +0 1 0 +create or replace view v1 as select 2 > 1 <> 1, 2 > (1 <> 1), (2 > 1) <> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 1 <> 1 AS `2 > 1 <> 1`,2 > (1 <> 1) AS `2 > (1 <> 1)`,2 > 1 <> 1 AS `(2 > 1) <> 1` +select 2 > 1 <> 1, 2 > (1 <> 1), (2 > 1) <> 1 union select * from v1; +2 > 1 <> 1 2 > (1 <> 1) (2 > 1) <> 1 +0 1 0 +create or replace view v1 as select 2 > 3 > 3, 2 > (3 > 3), (2 > 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 > 3 AS `2 > 3 > 3`,2 > (3 > 3) AS `2 > (3 > 3)`,2 > 3 > 3 AS `(2 > 3) > 3` +select 2 > 3 > 3, 2 > (3 > 3), (2 > 3) > 3 union select * from v1; +2 > 3 > 3 2 > (3 > 3) (2 > 3) > 3 +0 1 0 +create or replace view v1 as select 2 > 1 != 1, 2 > (1 != 1), (2 > 1) != 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 1 <> 1 AS `2 > 1 != 1`,2 > (1 <> 1) AS `2 > (1 != 1)`,2 > 1 <> 1 AS `(2 > 1) != 1` +select 2 > 1 != 1, 2 > (1 != 1), (2 > 1) != 1 union select * from v1; +2 > 1 != 1 2 > (1 != 1) (2 > 1) != 1 +0 1 0 +create or replace view v1 as select 2 > 3 LIKE 3, 2 > (3 LIKE 3), (2 > 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > (3 like 3) AS `2 > 3 LIKE 3`,2 > (3 like 3) AS `2 > (3 LIKE 3)`,2 > 3 like 3 AS `(2 > 3) LIKE 3` +select 2 > 3 LIKE 3, 2 > (3 LIKE 3), (2 > 3) LIKE 3 union select * from v1; +2 > 3 LIKE 3 2 > (3 LIKE 3) (2 > 3) LIKE 3 +1 1 0 +1 1 1 +create or replace view v1 as select 2 > 3 REGEXP 3, 2 > (3 REGEXP 3), (2 > 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > (3 regexp 3) AS `2 > 3 REGEXP 3`,2 > (3 regexp 3) AS `2 > (3 REGEXP 3)`,2 > 3 regexp 3 AS `(2 > 3) REGEXP 3` +select 2 > 3 REGEXP 3, 2 > (3 REGEXP 3), (2 > 3) REGEXP 3 union select * from v1; +2 > 3 REGEXP 3 2 > (3 REGEXP 3) (2 > 3) REGEXP 3 +1 1 0 +1 1 1 +create or replace view v1 as select 2 > 3 | 3, 2 > (3 | 3), (2 > 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 | 3 AS `2 > 3 | 3`,2 > 3 | 3 AS `2 > (3 | 3)`,(2 > 3) | 3 AS `(2 > 3) | 3` +select 2 > 3 | 3, 2 > (3 | 3), (2 > 3) | 3 union select * from v1; +2 > 3 | 3 2 > (3 | 3) (2 > 3) | 3 +0 0 3 +create or replace view v1 as select 4 > 2 & 2, 4 > (2 & 2), (4 > 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 4 > 2 & 2 AS `4 > 2 & 2`,4 > 2 & 2 AS `4 > (2 & 2)`,(4 > 2) & 2 AS `(4 > 2) & 2` +select 4 > 2 & 2, 4 > (2 & 2), (4 > 2) & 2 union select * from v1; +4 > 2 & 2 4 > (2 & 2) (4 > 2) & 2 +1 1 0 +create or replace view v1 as select 4 > 3 << 3, 4 > (3 << 3), (4 > 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 4 > 3 << 3 AS `4 > 3 << 3`,4 > 3 << 3 AS `4 > (3 << 3)`,(4 > 3) << 3 AS `(4 > 3) << 3` +select 4 > 3 << 3, 4 > (3 << 3), (4 > 3) << 3 union select * from v1; +4 > 3 << 3 4 > (3 << 3) (4 > 3) << 3 +0 0 8 +create or replace view v1 as select 2 > 3 >> 3, 2 > (3 >> 3), (2 > 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 >> 3 AS `2 > 3 >> 3`,2 > 3 >> 3 AS `2 > (3 >> 3)`,(2 > 3) >> 3 AS `(2 > 3) >> 3` +select 2 > 3 >> 3, 2 > (3 >> 3), (2 > 3) >> 3 union select * from v1; +2 > 3 >> 3 2 > (3 >> 3) (2 > 3) >> 3 +1 1 0 +create or replace view v1 as select 2 > '2000-01-01' +INTERVAL 1 DAY, 2 > ('2000-01-01' +INTERVAL 1 DAY), (2 > '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > '2000-01-01' + interval 1 day AS `2 > '2000-01-01' +INTERVAL 1 DAY`,2 > '2000-01-01' + interval 1 day AS `2 > ('2000-01-01' +INTERVAL 1 DAY)`,(2 > '2000-01-01') + interval 1 day AS `(2 > '2000-01-01') +INTERVAL 1 DAY` +select 2 > '2000-01-01' +INTERVAL 1 DAY, 2 > ('2000-01-01' +INTERVAL 1 DAY), (2 > '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 > '2000-01-01' +INTERVAL 1 DAY 2 > ('2000-01-01' +INTERVAL 1 DAY) (2 > '2000-01-01') +INTERVAL 1 DAY +0 0 NULL +create or replace view v1 as select 2 > 3 + 3, 2 > (3 + 3), (2 > 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 + 3 AS `2 > 3 + 3`,2 > 3 + 3 AS `2 > (3 + 3)`,(2 > 3) + 3 AS `(2 > 3) + 3` +select 2 > 3 + 3, 2 > (3 + 3), (2 > 3) + 3 union select * from v1; +2 > 3 + 3 2 > (3 + 3) (2 > 3) + 3 +0 0 3 +create or replace view v1 as select 2 > 3 - 3, 2 > (3 - 3), (2 > 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 - 3 AS `2 > 3 - 3`,2 > 3 - 3 AS `2 > (3 - 3)`,(2 > 3) - 3 AS `(2 > 3) - 3` +select 2 > 3 - 3, 2 > (3 - 3), (2 > 3) - 3 union select * from v1; +2 > 3 - 3 2 > (3 - 3) (2 > 3) - 3 +1 1 -3 +create or replace view v1 as select 4 > 3 * 3, 4 > (3 * 3), (4 > 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 4 > 3 * 3 AS `4 > 3 * 3`,4 > 3 * 3 AS `4 > (3 * 3)`,(4 > 3) * 3 AS `(4 > 3) * 3` +select 4 > 3 * 3, 4 > (3 * 3), (4 > 3) * 3 union select * from v1; +4 > 3 * 3 4 > (3 * 3) (4 > 3) * 3 +0 0 3 +create or replace view v1 as select 2 > 3 / 3, 2 > (3 / 3), (2 > 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 / 3 AS `2 > 3 / 3`,2 > 3 / 3 AS `2 > (3 / 3)`,(2 > 3) / 3 AS `(2 > 3) / 3` +select 2 > 3 / 3, 2 > (3 / 3), (2 > 3) / 3 union select * from v1; +2 > 3 / 3 2 > (3 / 3) (2 > 3) / 3 +1 1 0.0000 +create or replace view v1 as select 2 > 3 DIV 3, 2 > (3 DIV 3), (2 > 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 DIV 3 AS `2 > 3 DIV 3`,2 > 3 DIV 3 AS `2 > (3 DIV 3)`,(2 > 3) DIV 3 AS `(2 > 3) DIV 3` +select 2 > 3 DIV 3, 2 > (3 DIV 3), (2 > 3) DIV 3 union select * from v1; +2 > 3 DIV 3 2 > (3 DIV 3) (2 > 3) DIV 3 +1 1 0 +create or replace view v1 as select 2 > 3 MOD 3, 2 > (3 MOD 3), (2 > 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 % 3 AS `2 > 3 MOD 3`,2 > 3 % 3 AS `2 > (3 MOD 3)`,(2 > 3) % 3 AS `(2 > 3) MOD 3` +select 2 > 3 MOD 3, 2 > (3 MOD 3), (2 > 3) MOD 3 union select * from v1; +2 > 3 MOD 3 2 > (3 MOD 3) (2 > 3) MOD 3 +1 1 0 +create or replace view v1 as select 2 > 3 % 3, 2 > (3 % 3), (2 > 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 % 3 AS `2 > 3 % 3`,2 > 3 % 3 AS `2 > (3 % 3)`,(2 > 3) % 3 AS `(2 > 3) % 3` +select 2 > 3 % 3, 2 > (3 % 3), (2 > 3) % 3 union select * from v1; +2 > 3 % 3 2 > (3 % 3) (2 > 3) % 3 +1 1 0 +create or replace view v1 as select 2 > 3 ^ 3, 2 > (3 ^ 3), (2 > 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > 3 ^ 3 AS `2 > 3 ^ 3`,2 > 3 ^ 3 AS `2 > (3 ^ 3)`,(2 > 3) ^ 3 AS `(2 > 3) ^ 3` +select 2 > 3 ^ 3, 2 > (3 ^ 3), (2 > 3) ^ 3 union select * from v1; +2 > 3 ^ 3 2 > (3 ^ 3) (2 > 3) ^ 3 +1 1 3 +create or replace view v1 as select 2 > 3 BETWEEN 1 AND 3, 2 > (3 BETWEEN 1 AND 3), (2 > 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > (3 between 1 and 3) AS `2 > 3 BETWEEN 1 AND 3`,2 > (3 between 1 and 3) AS `2 > (3 BETWEEN 1 AND 3)`,2 > 3 between 1 and 3 AS `(2 > 3) BETWEEN 1 AND 3` +select 2 > 3 BETWEEN 1 AND 3, 2 > (3 BETWEEN 1 AND 3), (2 > 3) BETWEEN 1 AND 3 union select * from v1; +2 > 3 BETWEEN 1 AND 3 2 > (3 BETWEEN 1 AND 3) (2 > 3) BETWEEN 1 AND 3 +1 1 0 +1 1 1 +create or replace view v1 as select 2 != 3 IS FALSE, 2 != (3 IS FALSE), (2 != 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 is false AS `2 != 3 IS FALSE`,2 <> (3 is false) AS `2 != (3 IS FALSE)`,2 <> 3 is false AS `(2 != 3) IS FALSE` +select 2 != 3 IS FALSE, 2 != (3 IS FALSE), (2 != 3) IS FALSE union select * from v1; +2 != 3 IS FALSE 2 != (3 IS FALSE) (2 != 3) IS FALSE +0 1 0 +create or replace view v1 as select charset(2 != 3 COLLATE latin1_bin), charset(2 != (3 COLLATE latin1_bin)), charset((2 != 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 <> 3 collate latin1_bin) AS `charset(2 != 3 COLLATE latin1_bin)`,charset(2 <> 3 collate latin1_bin) AS `charset(2 != (3 COLLATE latin1_bin))`,charset((2 <> 3) collate latin1_bin) AS `charset((2 != 3) COLLATE latin1_bin)` +select charset(2 != 3 COLLATE latin1_bin), charset(2 != (3 COLLATE latin1_bin)), charset((2 != 3) COLLATE latin1_bin) union select * from v1; +charset(2 != 3 COLLATE latin1_bin) charset(2 != (3 COLLATE latin1_bin)) charset((2 != 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 != 3 IN (0,0), 2 != (3 IN (0,0)), (2 != 3) IN (0,0); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> (3 in (0,0)) AS `2 != 3 IN (0,0)`,2 <> (3 in (0,0)) AS `2 != (3 IN (0,0))`,2 <> 3 in (0,0) AS `(2 != 3) IN (0,0)` +select 2 != 3 IN (0,0), 2 != (3 IN (0,0)), (2 != 3) IN (0,0) union select * from v1; +2 != 3 IN (0,0) 2 != (3 IN (0,0)) (2 != 3) IN (0,0) +1 1 0 +1 1 1 +create or replace view v1 as select 1 != 3 OR 3, 1 != (3 OR 3), (1 != 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 <> 3 or 3 AS `1 != 3 OR 3`,1 <> (3 or 3) AS `1 != (3 OR 3)`,1 <> 3 or 3 AS `(1 != 3) OR 3` +select 1 != 3 OR 3, 1 != (3 OR 3), (1 != 3) OR 3 union select * from v1; +1 != 3 OR 3 1 != (3 OR 3) (1 != 3) OR 3 +1 0 1 +create or replace view v1 as select 1 != 3 || 3, 1 != (3 || 3), (1 != 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 <> 3 or 3 AS `1 != 3 || 3`,1 <> (3 or 3) AS `1 != (3 || 3)`,1 <> 3 or 3 AS `(1 != 3) || 3` +select 1 != 3 || 3, 1 != (3 || 3), (1 != 3) || 3 union select * from v1; +1 != 3 || 3 1 != (3 || 3) (1 != 3) || 3 +1 0 1 +create or replace view v1 as select 2 != 3 XOR 3, 2 != (3 XOR 3), (2 != 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 xor 3 AS `2 != 3 XOR 3`,2 <> (3 xor 3) AS `2 != (3 XOR 3)`,2 <> 3 xor 3 AS `(2 != 3) XOR 3` +select 2 != 3 XOR 3, 2 != (3 XOR 3), (2 != 3) XOR 3 union select * from v1; +2 != 3 XOR 3 2 != (3 XOR 3) (2 != 3) XOR 3 +0 1 0 +create or replace view v1 as select 3 != 3 AND 3, 3 != (3 AND 3), (3 != 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 <> 3 and 3 AS `3 != 3 AND 3`,3 <> (3 and 3) AS `3 != (3 AND 3)`,3 <> 3 and 3 AS `(3 != 3) AND 3` +select 3 != 3 AND 3, 3 != (3 AND 3), (3 != 3) AND 3 union select * from v1; +3 != 3 AND 3 3 != (3 AND 3) (3 != 3) AND 3 +0 1 0 +create or replace view v1 as select 3 != 3 && 3, 3 != (3 && 3), (3 != 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 <> 3 and 3 AS `3 != 3 && 3`,3 <> (3 and 3) AS `3 != (3 && 3)`,3 <> 3 and 3 AS `(3 != 3) && 3` +select 3 != 3 && 3, 3 != (3 && 3), (3 != 3) && 3 union select * from v1; +3 != 3 && 3 3 != (3 && 3) (3 != 3) && 3 +0 1 0 +create or replace view v1 as select 2 != 3 = 3, 2 != (3 = 3), (2 != 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 = 3 AS `2 != 3 = 3`,2 <> (3 = 3) AS `2 != (3 = 3)`,2 <> 3 = 3 AS `(2 != 3) = 3` +select 2 != 3 = 3, 2 != (3 = 3), (2 != 3) = 3 union select * from v1; +2 != 3 = 3 2 != (3 = 3) (2 != 3) = 3 +0 1 0 +create or replace view v1 as select 2 != 3 <=> 3, 2 != (3 <=> 3), (2 != 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 <=> 3 AS `2 != 3 <=> 3`,2 <> (3 <=> 3) AS `2 != (3 <=> 3)`,2 <> 3 <=> 3 AS `(2 != 3) <=> 3` +select 2 != 3 <=> 3, 2 != (3 <=> 3), (2 != 3) <=> 3 union select * from v1; +2 != 3 <=> 3 2 != (3 <=> 3) (2 != 3) <=> 3 +0 1 0 +create or replace view v1 as select 2 != 3 >= 3, 2 != (3 >= 3), (2 != 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 >= 3 AS `2 != 3 >= 3`,2 <> (3 >= 3) AS `2 != (3 >= 3)`,2 <> 3 >= 3 AS `(2 != 3) >= 3` +select 2 != 3 >= 3, 2 != (3 >= 3), (2 != 3) >= 3 union select * from v1; +2 != 3 >= 3 2 != (3 >= 3) (2 != 3) >= 3 +0 1 0 +create or replace view v1 as select 1 != 3 <= 3, 1 != (3 <= 3), (1 != 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 <> 3 <= 3 AS `1 != 3 <= 3`,1 <> (3 <= 3) AS `1 != (3 <= 3)`,1 <> 3 <= 3 AS `(1 != 3) <= 3` +select 1 != 3 <= 3, 1 != (3 <= 3), (1 != 3) <= 3 union select * from v1; +1 != 3 <= 3 1 != (3 <= 3) (1 != 3) <= 3 +1 0 1 +create or replace view v1 as select 0 != 3 < 3, 0 != (3 < 3), (0 != 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 <> 3 < 3 AS `0 != 3 < 3`,0 <> (3 < 3) AS `0 != (3 < 3)`,0 <> 3 < 3 AS `(0 != 3) < 3` +select 0 != 3 < 3, 0 != (3 < 3), (0 != 3) < 3 union select * from v1; +0 != 3 < 3 0 != (3 < 3) (0 != 3) < 3 +1 0 1 +create or replace view v1 as select 0 != 3 <> 3, 0 != (3 <> 3), (0 != 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 <> 3 <> 3 AS `0 != 3 <> 3`,0 <> (3 <> 3) AS `0 != (3 <> 3)`,0 <> 3 <> 3 AS `(0 != 3) <> 3` +select 0 != 3 <> 3, 0 != (3 <> 3), (0 != 3) <> 3 union select * from v1; +0 != 3 <> 3 0 != (3 <> 3) (0 != 3) <> 3 +1 0 1 +create or replace view v1 as select 2 != 3 > 3, 2 != (3 > 3), (2 != 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 > 3 AS `2 != 3 > 3`,2 <> (3 > 3) AS `2 != (3 > 3)`,2 <> 3 > 3 AS `(2 != 3) > 3` +select 2 != 3 > 3, 2 != (3 > 3), (2 != 3) > 3 union select * from v1; +2 != 3 > 3 2 != (3 > 3) (2 != 3) > 3 +0 1 0 +create or replace view v1 as select 0 != 3 != 3, 0 != (3 != 3), (0 != 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 <> 3 <> 3 AS `0 != 3 != 3`,0 <> (3 <> 3) AS `0 != (3 != 3)`,0 <> 3 <> 3 AS `(0 != 3) != 3` +select 0 != 3 != 3, 0 != (3 != 3), (0 != 3) != 3 union select * from v1; +0 != 3 != 3 0 != (3 != 3) (0 != 3) != 3 +1 0 1 +create or replace view v1 as select 2 != 3 LIKE 3, 2 != (3 LIKE 3), (2 != 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> (3 like 3) AS `2 != 3 LIKE 3`,2 <> (3 like 3) AS `2 != (3 LIKE 3)`,2 <> 3 like 3 AS `(2 != 3) LIKE 3` +select 2 != 3 LIKE 3, 2 != (3 LIKE 3), (2 != 3) LIKE 3 union select * from v1; +2 != 3 LIKE 3 2 != (3 LIKE 3) (2 != 3) LIKE 3 +1 1 0 +1 1 1 +create or replace view v1 as select 2 != 3 REGEXP 3, 2 != (3 REGEXP 3), (2 != 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> (3 regexp 3) AS `2 != 3 REGEXP 3`,2 <> (3 regexp 3) AS `2 != (3 REGEXP 3)`,2 <> 3 regexp 3 AS `(2 != 3) REGEXP 3` +select 2 != 3 REGEXP 3, 2 != (3 REGEXP 3), (2 != 3) REGEXP 3 union select * from v1; +2 != 3 REGEXP 3 2 != (3 REGEXP 3) (2 != 3) REGEXP 3 +1 1 0 +1 1 1 +create or replace view v1 as select 2 != 3 | 3, 2 != (3 | 3), (2 != 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 | 3 AS `2 != 3 | 3`,2 <> 3 | 3 AS `2 != (3 | 3)`,(2 <> 3) | 3 AS `(2 != 3) | 3` +select 2 != 3 | 3, 2 != (3 | 3), (2 != 3) | 3 union select * from v1; +2 != 3 | 3 2 != (3 | 3) (2 != 3) | 3 +1 1 3 +create or replace view v1 as select 2 != 4 & 4, 2 != (4 & 4), (2 != 4) & 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 4 & 4 AS `2 != 4 & 4`,2 <> 4 & 4 AS `2 != (4 & 4)`,(2 <> 4) & 4 AS `(2 != 4) & 4` +select 2 != 4 & 4, 2 != (4 & 4), (2 != 4) & 4 union select * from v1; +2 != 4 & 4 2 != (4 & 4) (2 != 4) & 4 +1 1 0 +create or replace view v1 as select 2 != 3 << 3, 2 != (3 << 3), (2 != 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 << 3 AS `2 != 3 << 3`,2 <> 3 << 3 AS `2 != (3 << 3)`,(2 <> 3) << 3 AS `(2 != 3) << 3` +select 2 != 3 << 3, 2 != (3 << 3), (2 != 3) << 3 union select * from v1; +2 != 3 << 3 2 != (3 << 3) (2 != 3) << 3 +1 1 8 +create or replace view v1 as select 2 != 3 >> 3, 2 != (3 >> 3), (2 != 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 >> 3 AS `2 != 3 >> 3`,2 <> 3 >> 3 AS `2 != (3 >> 3)`,(2 <> 3) >> 3 AS `(2 != 3) >> 3` +select 2 != 3 >> 3, 2 != (3 >> 3), (2 != 3) >> 3 union select * from v1; +2 != 3 >> 3 2 != (3 >> 3) (2 != 3) >> 3 +1 1 0 +create or replace view v1 as select 2 != '2000-01-01' +INTERVAL 1 DAY, 2 != ('2000-01-01' +INTERVAL 1 DAY), (2 != '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> '2000-01-01' + interval 1 day AS `2 != '2000-01-01' +INTERVAL 1 DAY`,2 <> '2000-01-01' + interval 1 day AS `2 != ('2000-01-01' +INTERVAL 1 DAY)`,(2 <> '2000-01-01') + interval 1 day AS `(2 != '2000-01-01') +INTERVAL 1 DAY` +select 2 != '2000-01-01' +INTERVAL 1 DAY, 2 != ('2000-01-01' +INTERVAL 1 DAY), (2 != '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 != '2000-01-01' +INTERVAL 1 DAY 2 != ('2000-01-01' +INTERVAL 1 DAY) (2 != '2000-01-01') +INTERVAL 1 DAY +1 1 NULL +create or replace view v1 as select 2 != 3 + 3, 2 != (3 + 3), (2 != 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 + 3 AS `2 != 3 + 3`,2 <> 3 + 3 AS `2 != (3 + 3)`,(2 <> 3) + 3 AS `(2 != 3) + 3` +select 2 != 3 + 3, 2 != (3 + 3), (2 != 3) + 3 union select * from v1; +2 != 3 + 3 2 != (3 + 3) (2 != 3) + 3 +1 1 4 +create or replace view v1 as select 2 != 3 - 3, 2 != (3 - 3), (2 != 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 - 3 AS `2 != 3 - 3`,2 <> 3 - 3 AS `2 != (3 - 3)`,(2 <> 3) - 3 AS `(2 != 3) - 3` +select 2 != 3 - 3, 2 != (3 - 3), (2 != 3) - 3 union select * from v1; +2 != 3 - 3 2 != (3 - 3) (2 != 3) - 3 +1 1 -2 +create or replace view v1 as select 2 != 3 * 3, 2 != (3 * 3), (2 != 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 * 3 AS `2 != 3 * 3`,2 <> 3 * 3 AS `2 != (3 * 3)`,(2 <> 3) * 3 AS `(2 != 3) * 3` +select 2 != 3 * 3, 2 != (3 * 3), (2 != 3) * 3 union select * from v1; +2 != 3 * 3 2 != (3 * 3) (2 != 3) * 3 +1 1 3 +create or replace view v1 as select 2 != 3 / 3, 2 != (3 / 3), (2 != 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 / 3 AS `2 != 3 / 3`,2 <> 3 / 3 AS `2 != (3 / 3)`,(2 <> 3) / 3 AS `(2 != 3) / 3` +select 2 != 3 / 3, 2 != (3 / 3), (2 != 3) / 3 union select * from v1; +2 != 3 / 3 2 != (3 / 3) (2 != 3) / 3 +1 1 0.3333 +create or replace view v1 as select 2 != 3 DIV 3, 2 != (3 DIV 3), (2 != 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 DIV 3 AS `2 != 3 DIV 3`,2 <> 3 DIV 3 AS `2 != (3 DIV 3)`,(2 <> 3) DIV 3 AS `(2 != 3) DIV 3` +select 2 != 3 DIV 3, 2 != (3 DIV 3), (2 != 3) DIV 3 union select * from v1; +2 != 3 DIV 3 2 != (3 DIV 3) (2 != 3) DIV 3 +1 1 0 +create or replace view v1 as select 3 != 3 MOD 3, 3 != (3 MOD 3), (3 != 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 <> 3 % 3 AS `3 != 3 MOD 3`,3 <> 3 % 3 AS `3 != (3 MOD 3)`,(3 <> 3) % 3 AS `(3 != 3) MOD 3` +select 3 != 3 MOD 3, 3 != (3 MOD 3), (3 != 3) MOD 3 union select * from v1; +3 != 3 MOD 3 3 != (3 MOD 3) (3 != 3) MOD 3 +1 1 0 +create or replace view v1 as select 3 != 3 % 3, 3 != (3 % 3), (3 != 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 <> 3 % 3 AS `3 != 3 % 3`,3 <> 3 % 3 AS `3 != (3 % 3)`,(3 <> 3) % 3 AS `(3 != 3) % 3` +select 3 != 3 % 3, 3 != (3 % 3), (3 != 3) % 3 union select * from v1; +3 != 3 % 3 3 != (3 % 3) (3 != 3) % 3 +1 1 0 +create or replace view v1 as select 2 != 3 ^ 3, 2 != (3 ^ 3), (2 != 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> 3 ^ 3 AS `2 != 3 ^ 3`,2 <> 3 ^ 3 AS `2 != (3 ^ 3)`,(2 <> 3) ^ 3 AS `(2 != 3) ^ 3` +select 2 != 3 ^ 3, 2 != (3 ^ 3), (2 != 3) ^ 3 union select * from v1; +2 != 3 ^ 3 2 != (3 ^ 3) (2 != 3) ^ 3 +1 1 2 +create or replace view v1 as select 2 != 3 BETWEEN 2 AND 3, 2 != (3 BETWEEN 2 AND 3), (2 != 3) BETWEEN 2 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> (3 between 2 and 3) AS `2 != 3 BETWEEN 2 AND 3`,2 <> (3 between 2 and 3) AS `2 != (3 BETWEEN 2 AND 3)`,2 <> 3 between 2 and 3 AS `(2 != 3) BETWEEN 2 AND 3` +select 2 != 3 BETWEEN 2 AND 3, 2 != (3 BETWEEN 2 AND 3), (2 != 3) BETWEEN 2 AND 3 union select * from v1; +2 != 3 BETWEEN 2 AND 3 2 != (3 BETWEEN 2 AND 3) (2 != 3) BETWEEN 2 AND 3 +1 1 0 +1 1 1 +create or replace view v1 as select 2 LIKE 3 IS FALSE, 2 LIKE (3 IS FALSE), (2 LIKE 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 is false AS `2 LIKE 3 IS FALSE`,2 like 3 is false AS `2 LIKE (3 IS FALSE)`,2 like 3 is false AS `(2 LIKE 3) IS FALSE` +select 2 LIKE 3 IS FALSE, 2 LIKE (3 IS FALSE), (2 LIKE 3) IS FALSE union select * from v1; +2 LIKE 3 IS FALSE 2 LIKE (3 IS FALSE) (2 LIKE 3) IS FALSE +1 0 1 +1 1 1 +create or replace view v1 as select charset(2 LIKE 3 COLLATE latin1_bin), charset(2 LIKE (3 COLLATE latin1_bin)), charset((2 LIKE 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 like 3 collate latin1_bin) AS `charset(2 LIKE 3 COLLATE latin1_bin)`,charset(2 like 3 collate latin1_bin) AS `charset(2 LIKE (3 COLLATE latin1_bin))`,charset((2 like 3) collate latin1_bin) AS `charset((2 LIKE 3) COLLATE latin1_bin)` +select charset(2 LIKE 3 COLLATE latin1_bin), charset(2 LIKE (3 COLLATE latin1_bin)), charset((2 LIKE 3) COLLATE latin1_bin) union select * from v1; +charset(2 LIKE 3 COLLATE latin1_bin) charset(2 LIKE (3 COLLATE latin1_bin)) charset((2 LIKE 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 LIKE 3 IN (0,1), 2 LIKE (3 IN (0,1)), (2 LIKE 3) IN (0,1); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (0,1), 2 LIKE (3 IN (0,1)), (2 LIKE 3) IN (0,1)' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 like 3 collate latin1_bin) AS `charset(2 LIKE 3 COLLATE latin1_bin)`,charset(2 like 3 collate latin1_bin) AS `charset(2 LIKE (3 COLLATE latin1_bin))`,charset((2 like 3) collate latin1_bin) AS `charset((2 LIKE 3) COLLATE latin1_bin)` +select 2 LIKE 3 IN (0,1), 2 LIKE (3 IN (0,1)), (2 LIKE 3) IN (0,1) union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (0,1), 2 LIKE (3 IN (0,1)), (2 LIKE 3) IN (0,1) union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 3 OR 3, 2 LIKE (3 OR 3), (2 LIKE 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 or 3 AS `2 LIKE 3 OR 3`,2 like (3 or 3) AS `2 LIKE (3 OR 3)`,2 like 3 or 3 AS `(2 LIKE 3) OR 3` +select 2 LIKE 3 OR 3, 2 LIKE (3 OR 3), (2 LIKE 3) OR 3 union select * from v1; +2 LIKE 3 OR 3 2 LIKE (3 OR 3) (2 LIKE 3) OR 3 +1 0 1 +create or replace view v1 as select 2 LIKE 3 || 3, 2 LIKE (3 || 3), (2 LIKE 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 or 3 AS `2 LIKE 3 || 3`,2 like (3 or 3) AS `2 LIKE (3 || 3)`,2 like 3 or 3 AS `(2 LIKE 3) || 3` +select 2 LIKE 3 || 3, 2 LIKE (3 || 3), (2 LIKE 3) || 3 union select * from v1; +2 LIKE 3 || 3 2 LIKE (3 || 3) (2 LIKE 3) || 3 +1 0 1 +create or replace view v1 as select 2 LIKE 3 XOR 3, 2 LIKE (3 XOR 3), (2 LIKE 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 xor 3 AS `2 LIKE 3 XOR 3`,2 like (3 xor 3) AS `2 LIKE (3 XOR 3)`,2 like 3 xor 3 AS `(2 LIKE 3) XOR 3` +select 2 LIKE 3 XOR 3, 2 LIKE (3 XOR 3), (2 LIKE 3) XOR 3 union select * from v1; +2 LIKE 3 XOR 3 2 LIKE (3 XOR 3) (2 LIKE 3) XOR 3 +1 0 1 +create or replace view v1 as select 2 LIKE 2 AND 2, 2 LIKE (2 AND 2), (2 LIKE 2) AND 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 2 and 2 AS `2 LIKE 2 AND 2`,2 like (2 and 2) AS `2 LIKE (2 AND 2)`,2 like 2 and 2 AS `(2 LIKE 2) AND 2` +select 2 LIKE 2 AND 2, 2 LIKE (2 AND 2), (2 LIKE 2) AND 2 union select * from v1; +2 LIKE 2 AND 2 2 LIKE (2 AND 2) (2 LIKE 2) AND 2 +1 0 1 +create or replace view v1 as select 2 LIKE 2 && 2, 2 LIKE (2 && 2), (2 LIKE 2) && 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 2 and 2 AS `2 LIKE 2 && 2`,2 like (2 and 2) AS `2 LIKE (2 && 2)`,2 like 2 and 2 AS `(2 LIKE 2) && 2` +select 2 LIKE 2 && 2, 2 LIKE (2 && 2), (2 LIKE 2) && 2 union select * from v1; +2 LIKE 2 && 2 2 LIKE (2 && 2) (2 LIKE 2) && 2 +1 0 1 +create or replace view v1 as select 2 LIKE 2 = 1, 2 LIKE (2 = 1), (2 LIKE 2) = 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 2 = 1 AS `2 LIKE 2 = 1`,2 like 2 = 1 AS `2 LIKE (2 = 1)`,2 like 2 = 1 AS `(2 LIKE 2) = 1` +select 2 LIKE 2 = 1, 2 LIKE (2 = 1), (2 LIKE 2) = 1 union select * from v1; +2 LIKE 2 = 1 2 LIKE (2 = 1) (2 LIKE 2) = 1 +1 0 1 +1 1 1 +create or replace view v1 as select 2 LIKE 2 <=> 1, 2 LIKE (2 <=> 1), (2 LIKE 2) <=> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 2 <=> 1 AS `2 LIKE 2 <=> 1`,2 like 2 <=> 1 AS `2 LIKE (2 <=> 1)`,2 like 2 <=> 1 AS `(2 LIKE 2) <=> 1` +select 2 LIKE 2 <=> 1, 2 LIKE (2 <=> 1), (2 LIKE 2) <=> 1 union select * from v1; +2 LIKE 2 <=> 1 2 LIKE (2 <=> 1) (2 LIKE 2) <=> 1 +1 0 1 +1 1 1 +create or replace view v1 as select 2 LIKE 2 >= 1, 2 LIKE (2 >= 1), (2 LIKE 2) >= 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 2 >= 1 AS `2 LIKE 2 >= 1`,2 like 2 >= 1 AS `2 LIKE (2 >= 1)`,2 like 2 >= 1 AS `(2 LIKE 2) >= 1` +select 2 LIKE 2 >= 1, 2 LIKE (2 >= 1), (2 LIKE 2) >= 1 union select * from v1; +2 LIKE 2 >= 1 2 LIKE (2 >= 1) (2 LIKE 2) >= 1 +1 0 1 +1 1 1 +create or replace view v1 as select 2 LIKE 3 <= 3, 2 LIKE (3 <= 3), (2 LIKE 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <= 3 AS `2 LIKE 3 <= 3`,2 like 3 <= 3 AS `2 LIKE (3 <= 3)`,2 like 3 <= 3 AS `(2 LIKE 3) <= 3` +select 2 LIKE 3 <= 3, 2 LIKE (3 <= 3), (2 LIKE 3) <= 3 union select * from v1; +2 LIKE 3 <= 3 2 LIKE (3 <= 3) (2 LIKE 3) <= 3 +1 0 1 +1 1 1 +create or replace view v1 as select 2 LIKE 3 < 3, 2 LIKE (3 < 3), (2 LIKE 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 < 3 AS `2 LIKE 3 < 3`,2 like 3 < 3 AS `2 LIKE (3 < 3)`,2 like 3 < 3 AS `(2 LIKE 3) < 3` +select 2 LIKE 3 < 3, 2 LIKE (3 < 3), (2 LIKE 3) < 3 union select * from v1; +2 LIKE 3 < 3 2 LIKE (3 < 3) (2 LIKE 3) < 3 +1 0 1 +1 1 1 +create or replace view v1 as select 2 LIKE 3 <> 3, 2 LIKE (3 <> 3), (2 LIKE 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 <> 3`,2 like 3 <> 3 AS `2 LIKE (3 <> 3)`,2 like 3 <> 3 AS `(2 LIKE 3) <> 3` +select 2 LIKE 3 <> 3, 2 LIKE (3 <> 3), (2 LIKE 3) <> 3 union select * from v1; +2 LIKE 3 <> 3 2 LIKE (3 <> 3) (2 LIKE 3) <> 3 +1 0 1 +1 1 1 +create or replace view v1 as select 2 LIKE 2 > 0, 2 LIKE (2 > 0), (2 LIKE 2) > 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 2 > 0 AS `2 LIKE 2 > 0`,2 like 2 > 0 AS `2 LIKE (2 > 0)`,2 like 2 > 0 AS `(2 LIKE 2) > 0` +select 2 LIKE 2 > 0, 2 LIKE (2 > 0), (2 LIKE 2) > 0 union select * from v1; +2 LIKE 2 > 0 2 LIKE (2 > 0) (2 LIKE 2) > 0 +1 0 1 +1 1 1 +create or replace view v1 as select 2 LIKE 3 != 3, 2 LIKE (3 != 3), (2 LIKE 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 3 != 3, 2 LIKE (3 != 3), (2 LIKE 3) != 3 union select * from v1; +2 LIKE 3 != 3 2 LIKE (3 != 3) (2 LIKE 3) != 3 +1 0 1 +1 1 1 +create or replace view v1 as select 2 LIKE 2 LIKE 1, 2 LIKE (2 LIKE 1), (2 LIKE 2) LIKE 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE 1, 2 LIKE (2 LIKE 1), (2 LIKE 2) LIKE 1' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 2 LIKE 1, 2 LIKE (2 LIKE 1), (2 LIKE 2) LIKE 1 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE 1, 2 LIKE (2 LIKE 1), (2 LIKE 2) LIKE 1 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 2 REGEXP 1, 2 LIKE (2 REGEXP 1), (2 LIKE 2) REGEXP 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'REGEXP 1, 2 LIKE (2 REGEXP 1), (2 LIKE 2) REGEXP 1' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 2 REGEXP 1, 2 LIKE (2 REGEXP 1), (2 LIKE 2) REGEXP 1 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'REGEXP 1, 2 LIKE (2 REGEXP 1), (2 LIKE 2) REGEXP 1 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 3 | 3, 2 LIKE (3 | 3), (2 LIKE 3) | 3; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '| 3, 2 LIKE (3 | 3), (2 LIKE 3) | 3' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 3 | 3, 2 LIKE (3 | 3), (2 LIKE 3) | 3 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '| 3, 2 LIKE (3 | 3), (2 LIKE 3) | 3 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 2 & 2, 2 LIKE (2 & 2), (2 LIKE 2) & 2; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '& 2, 2 LIKE (2 & 2), (2 LIKE 2) & 2' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 2 & 2, 2 LIKE (2 & 2), (2 LIKE 2) & 2 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '& 2, 2 LIKE (2 & 2), (2 LIKE 2) & 2 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 2 << 2, 2 LIKE (2 << 2), (2 LIKE 2) << 2; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '<< 2, 2 LIKE (2 << 2), (2 LIKE 2) << 2' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 2 << 2, 2 LIKE (2 << 2), (2 LIKE 2) << 2 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '<< 2, 2 LIKE (2 << 2), (2 LIKE 2) << 2 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 4 >> 1, 2 LIKE (4 >> 1), (2 LIKE 4) >> 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '>> 1, 2 LIKE (4 >> 1), (2 LIKE 4) >> 1' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 4 >> 1, 2 LIKE (4 >> 1), (2 LIKE 4) >> 1 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '>> 1, 2 LIKE (4 >> 1), (2 LIKE 4) >> 1 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE '2000-01-01' +INTERVAL 1 DAY, 2 LIKE ('2000-01-01' +INTERVAL 1 DAY), (2 LIKE '2000-01-01') +INTERVAL 1 DAY; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+INTERVAL 1 DAY, 2 LIKE ('2000-01-01' +INTERVAL 1 DAY), (2 LIKE '2000-01-01')...' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE '2000-01-01' +INTERVAL 1 DAY, 2 LIKE ('2000-01-01' +INTERVAL 1 DAY), (2 LIKE '2000-01-01') +INTERVAL 1 DAY union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+INTERVAL 1 DAY, 2 LIKE ('2000-01-01' +INTERVAL 1 DAY), (2 LIKE '2000-01-01')...' at line 1 +create or replace view v1 as select 2 LIKE 3 + 3, 2 LIKE (3 + 3), (2 LIKE 3) + 3; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+ 3, 2 LIKE (3 + 3), (2 LIKE 3) + 3' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 3 + 3, 2 LIKE (3 + 3), (2 LIKE 3) + 3 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+ 3, 2 LIKE (3 + 3), (2 LIKE 3) + 3 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 3 - 3, 2 LIKE (3 - 3), (2 LIKE 3) - 3; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '- 3, 2 LIKE (3 - 3), (2 LIKE 3) - 3' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 3 - 3, 2 LIKE (3 - 3), (2 LIKE 3) - 3 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '- 3, 2 LIKE (3 - 3), (2 LIKE 3) - 3 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 2 * 2, 2 LIKE (2 * 2), (2 LIKE 2) * 2; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '* 2, 2 LIKE (2 * 2), (2 LIKE 2) * 2' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 2 * 2, 2 LIKE (2 * 2), (2 LIKE 2) * 2 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '* 2, 2 LIKE (2 * 2), (2 LIKE 2) * 2 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 2 / 2, 2 LIKE (2 / 2), (2 LIKE 2) / 2; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '/ 2, 2 LIKE (2 / 2), (2 LIKE 2) / 2' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 2 / 2, 2 LIKE (2 / 2), (2 LIKE 2) / 2 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '/ 2, 2 LIKE (2 / 2), (2 LIKE 2) / 2 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 4 DIV 2, 2 LIKE (4 DIV 2), (2 LIKE 4) DIV 2; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'DIV 2, 2 LIKE (4 DIV 2), (2 LIKE 4) DIV 2' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 4 DIV 2, 2 LIKE (4 DIV 2), (2 LIKE 4) DIV 2 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'DIV 2, 2 LIKE (4 DIV 2), (2 LIKE 4) DIV 2 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 2 MOD 2, 2 LIKE (2 MOD 2), (2 LIKE 2) MOD 2; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'MOD 2, 2 LIKE (2 MOD 2), (2 LIKE 2) MOD 2' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 2 MOD 2, 2 LIKE (2 MOD 2), (2 LIKE 2) MOD 2 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'MOD 2, 2 LIKE (2 MOD 2), (2 LIKE 2) MOD 2 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 2 % 2, 2 LIKE (2 % 2), (2 LIKE 2) % 2; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '% 2, 2 LIKE (2 % 2), (2 LIKE 2) % 2' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 2 % 2, 2 LIKE (2 % 2), (2 LIKE 2) % 2 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '% 2, 2 LIKE (2 % 2), (2 LIKE 2) % 2 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 3 ^ 3, 2 LIKE (3 ^ 3), (2 LIKE 3) ^ 3; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '^ 3, 2 LIKE (3 ^ 3), (2 LIKE 3) ^ 3' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 3 ^ 3, 2 LIKE (3 ^ 3), (2 LIKE 3) ^ 3 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '^ 3, 2 LIKE (3 ^ 3), (2 LIKE 3) ^ 3 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 2 BETWEEN 1 AND 3, 2 LIKE (2 BETWEEN 1 AND 3), (2 LIKE 2) BETWEEN 1 AND 3; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'BETWEEN 1 AND 3, 2 LIKE (2 BETWEEN 1 AND 3), (2 LIKE 2) BETWEEN 1 AND 3' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 LIKE 2 BETWEEN 1 AND 3, 2 LIKE (2 BETWEEN 1 AND 3), (2 LIKE 2) BETWEEN 1 AND 3 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'BETWEEN 1 AND 3, 2 LIKE (2 BETWEEN 1 AND 3), (2 LIKE 2) BETWEEN 1 AND 3 union...' at line 1 +create or replace view v1 as select 2 REGEXP 3 IS FALSE, 2 REGEXP (3 IS FALSE), (2 REGEXP 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 3 is false AS `2 REGEXP 3 IS FALSE`,2 regexp (3 is false) AS `2 REGEXP (3 IS FALSE)`,2 regexp 3 is false AS `(2 REGEXP 3) IS FALSE` +select 2 REGEXP 3 IS FALSE, 2 REGEXP (3 IS FALSE), (2 REGEXP 3) IS FALSE union select * from v1; +2 REGEXP 3 IS FALSE 2 REGEXP (3 IS FALSE) (2 REGEXP 3) IS FALSE +1 0 1 +create or replace view v1 as select charset(2 REGEXP 3 COLLATE latin1_bin), charset(2 REGEXP (3 COLLATE latin1_bin)), charset((2 REGEXP 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 regexp 3 collate latin1_bin) AS `charset(2 REGEXP 3 COLLATE latin1_bin)`,charset(2 regexp 3 collate latin1_bin) AS `charset(2 REGEXP (3 COLLATE latin1_bin))`,charset((2 regexp 3) collate latin1_bin) AS `charset((2 REGEXP 3) COLLATE latin1_bin)` +select charset(2 REGEXP 3 COLLATE latin1_bin), charset(2 REGEXP (3 COLLATE latin1_bin)), charset((2 REGEXP 3) COLLATE latin1_bin) union select * from v1; +charset(2 REGEXP 3 COLLATE latin1_bin) charset(2 REGEXP (3 COLLATE latin1_bin)) charset((2 REGEXP 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 REGEXP 3 IN (0,1), 2 REGEXP (3 IN (0,1)), (2 REGEXP 3) IN (0,1); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (0,1), 2 REGEXP (3 IN (0,1)), (2 REGEXP 3) IN (0,1)' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 regexp 3 collate latin1_bin) AS `charset(2 REGEXP 3 COLLATE latin1_bin)`,charset(2 regexp 3 collate latin1_bin) AS `charset(2 REGEXP (3 COLLATE latin1_bin))`,charset((2 regexp 3) collate latin1_bin) AS `charset((2 REGEXP 3) COLLATE latin1_bin)` +select 2 REGEXP 3 IN (0,1), 2 REGEXP (3 IN (0,1)), (2 REGEXP 3) IN (0,1) union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (0,1), 2 REGEXP (3 IN (0,1)), (2 REGEXP 3) IN (0,1) union select * from v1' at line 1 +create or replace view v1 as select 2 REGEXP 3 OR 3, 2 REGEXP (3 OR 3), (2 REGEXP 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 3 or 3 AS `2 REGEXP 3 OR 3`,2 regexp (3 or 3) AS `2 REGEXP (3 OR 3)`,2 regexp 3 or 3 AS `(2 REGEXP 3) OR 3` +select 2 REGEXP 3 OR 3, 2 REGEXP (3 OR 3), (2 REGEXP 3) OR 3 union select * from v1; +2 REGEXP 3 OR 3 2 REGEXP (3 OR 3) (2 REGEXP 3) OR 3 +1 0 1 +create or replace view v1 as select 2 REGEXP 3 || 3, 2 REGEXP (3 || 3), (2 REGEXP 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 3 or 3 AS `2 REGEXP 3 || 3`,2 regexp (3 or 3) AS `2 REGEXP (3 || 3)`,2 regexp 3 or 3 AS `(2 REGEXP 3) || 3` +select 2 REGEXP 3 || 3, 2 REGEXP (3 || 3), (2 REGEXP 3) || 3 union select * from v1; +2 REGEXP 3 || 3 2 REGEXP (3 || 3) (2 REGEXP 3) || 3 +1 0 1 +create or replace view v1 as select 2 REGEXP 3 XOR 3, 2 REGEXP (3 XOR 3), (2 REGEXP 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 3 xor 3 AS `2 REGEXP 3 XOR 3`,2 regexp (3 xor 3) AS `2 REGEXP (3 XOR 3)`,2 regexp 3 xor 3 AS `(2 REGEXP 3) XOR 3` +select 2 REGEXP 3 XOR 3, 2 REGEXP (3 XOR 3), (2 REGEXP 3) XOR 3 union select * from v1; +2 REGEXP 3 XOR 3 2 REGEXP (3 XOR 3) (2 REGEXP 3) XOR 3 +1 0 1 +create or replace view v1 as select 2 REGEXP 2 AND 2, 2 REGEXP (2 AND 2), (2 REGEXP 2) AND 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 2 and 2 AS `2 REGEXP 2 AND 2`,2 regexp (2 and 2) AS `2 REGEXP (2 AND 2)`,2 regexp 2 and 2 AS `(2 REGEXP 2) AND 2` +select 2 REGEXP 2 AND 2, 2 REGEXP (2 AND 2), (2 REGEXP 2) AND 2 union select * from v1; +2 REGEXP 2 AND 2 2 REGEXP (2 AND 2) (2 REGEXP 2) AND 2 +1 0 1 +create or replace view v1 as select 2 REGEXP 2 && 2, 2 REGEXP (2 && 2), (2 REGEXP 2) && 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 2 and 2 AS `2 REGEXP 2 && 2`,2 regexp (2 and 2) AS `2 REGEXP (2 && 2)`,2 regexp 2 and 2 AS `(2 REGEXP 2) && 2` +select 2 REGEXP 2 && 2, 2 REGEXP (2 && 2), (2 REGEXP 2) && 2 union select * from v1; +2 REGEXP 2 && 2 2 REGEXP (2 && 2) (2 REGEXP 2) && 2 +1 0 1 +create or replace view v1 as select 2 REGEXP 2 = 1, 2 REGEXP (2 = 1), (2 REGEXP 2) = 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 2 = 1 AS `2 REGEXP 2 = 1`,2 regexp (2 = 1) AS `2 REGEXP (2 = 1)`,2 regexp 2 = 1 AS `(2 REGEXP 2) = 1` +select 2 REGEXP 2 = 1, 2 REGEXP (2 = 1), (2 REGEXP 2) = 1 union select * from v1; +2 REGEXP 2 = 1 2 REGEXP (2 = 1) (2 REGEXP 2) = 1 +1 0 1 +create or replace view v1 as select 2 REGEXP 2 <=> 1, 2 REGEXP (2 <=> 1), (2 REGEXP 2) <=> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 2 <=> 1 AS `2 REGEXP 2 <=> 1`,2 regexp (2 <=> 1) AS `2 REGEXP (2 <=> 1)`,2 regexp 2 <=> 1 AS `(2 REGEXP 2) <=> 1` +select 2 REGEXP 2 <=> 1, 2 REGEXP (2 <=> 1), (2 REGEXP 2) <=> 1 union select * from v1; +2 REGEXP 2 <=> 1 2 REGEXP (2 <=> 1) (2 REGEXP 2) <=> 1 +1 0 1 +create or replace view v1 as select 2 REGEXP 2 >= 1, 2 REGEXP (2 >= 1), (2 REGEXP 2) >= 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 2 >= 1 AS `2 REGEXP 2 >= 1`,2 regexp (2 >= 1) AS `2 REGEXP (2 >= 1)`,2 regexp 2 >= 1 AS `(2 REGEXP 2) >= 1` +select 2 REGEXP 2 >= 1, 2 REGEXP (2 >= 1), (2 REGEXP 2) >= 1 union select * from v1; +2 REGEXP 2 >= 1 2 REGEXP (2 >= 1) (2 REGEXP 2) >= 1 +1 0 1 +create or replace view v1 as select 2 REGEXP 3 <= 3, 2 REGEXP (3 <= 3), (2 REGEXP 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 3 <= 3 AS `2 REGEXP 3 <= 3`,2 regexp (3 <= 3) AS `2 REGEXP (3 <= 3)`,2 regexp 3 <= 3 AS `(2 REGEXP 3) <= 3` +select 2 REGEXP 3 <= 3, 2 REGEXP (3 <= 3), (2 REGEXP 3) <= 3 union select * from v1; +2 REGEXP 3 <= 3 2 REGEXP (3 <= 3) (2 REGEXP 3) <= 3 +1 0 1 +create or replace view v1 as select 2 REGEXP 3 < 3, 2 REGEXP (3 < 3), (2 REGEXP 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 3 < 3 AS `2 REGEXP 3 < 3`,2 regexp (3 < 3) AS `2 REGEXP (3 < 3)`,2 regexp 3 < 3 AS `(2 REGEXP 3) < 3` +select 2 REGEXP 3 < 3, 2 REGEXP (3 < 3), (2 REGEXP 3) < 3 union select * from v1; +2 REGEXP 3 < 3 2 REGEXP (3 < 3) (2 REGEXP 3) < 3 +1 0 1 +create or replace view v1 as select 2 REGEXP 3 <> 3, 2 REGEXP (3 <> 3), (2 REGEXP 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 3 <> 3 AS `2 REGEXP 3 <> 3`,2 regexp (3 <> 3) AS `2 REGEXP (3 <> 3)`,2 regexp 3 <> 3 AS `(2 REGEXP 3) <> 3` +select 2 REGEXP 3 <> 3, 2 REGEXP (3 <> 3), (2 REGEXP 3) <> 3 union select * from v1; +2 REGEXP 3 <> 3 2 REGEXP (3 <> 3) (2 REGEXP 3) <> 3 +1 0 1 +create or replace view v1 as select 2 REGEXP 2 > 0, 2 REGEXP (2 > 0), (2 REGEXP 2) > 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 2 > 0 AS `2 REGEXP 2 > 0`,2 regexp (2 > 0) AS `2 REGEXP (2 > 0)`,2 regexp 2 > 0 AS `(2 REGEXP 2) > 0` +select 2 REGEXP 2 > 0, 2 REGEXP (2 > 0), (2 REGEXP 2) > 0 union select * from v1; +2 REGEXP 2 > 0 2 REGEXP (2 > 0) (2 REGEXP 2) > 0 +1 0 1 +create or replace view v1 as select 2 REGEXP 3 != 3, 2 REGEXP (3 != 3), (2 REGEXP 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 3 <> 3 AS `2 REGEXP 3 != 3`,2 regexp (3 <> 3) AS `2 REGEXP (3 != 3)`,2 regexp 3 <> 3 AS `(2 REGEXP 3) != 3` +select 2 REGEXP 3 != 3, 2 REGEXP (3 != 3), (2 REGEXP 3) != 3 union select * from v1; +2 REGEXP 3 != 3 2 REGEXP (3 != 3) (2 REGEXP 3) != 3 +1 0 1 +create or replace view v1 as select 1 REGEXP 3 LIKE 3, 1 REGEXP (3 LIKE 3), (1 REGEXP 3) LIKE 3; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE 3, 1 REGEXP (3 LIKE 3), (1 REGEXP 3) LIKE 3' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 3 <> 3 AS `2 REGEXP 3 != 3`,2 regexp (3 <> 3) AS `2 REGEXP (3 != 3)`,2 regexp 3 <> 3 AS `(2 REGEXP 3) != 3` +select 1 REGEXP 3 LIKE 3, 1 REGEXP (3 LIKE 3), (1 REGEXP 3) LIKE 3 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE 3, 1 REGEXP (3 LIKE 3), (1 REGEXP 3) LIKE 3 union select * from v1' at line 1 +create or replace view v1 as select 1 REGEXP 3 REGEXP 3, 1 REGEXP (3 REGEXP 3), (1 REGEXP 3) REGEXP 3; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'REGEXP 3, 1 REGEXP (3 REGEXP 3), (1 REGEXP 3) REGEXP 3' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 3 <> 3 AS `2 REGEXP 3 != 3`,2 regexp (3 <> 3) AS `2 REGEXP (3 != 3)`,2 regexp 3 <> 3 AS `(2 REGEXP 3) != 3` +select 1 REGEXP 3 REGEXP 3, 1 REGEXP (3 REGEXP 3), (1 REGEXP 3) REGEXP 3 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'REGEXP 3, 1 REGEXP (3 REGEXP 3), (1 REGEXP 3) REGEXP 3 union select * from v1' at line 1 +create or replace view v1 as select 2 REGEXP 3 | 3, 2 REGEXP (3 | 3), (2 REGEXP 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 3 | 3 AS `2 REGEXP 3 | 3`,2 regexp 3 | 3 AS `2 REGEXP (3 | 3)`,(2 regexp 3) | 3 AS `(2 REGEXP 3) | 3` +select 2 REGEXP 3 | 3, 2 REGEXP (3 | 3), (2 REGEXP 3) | 3 union select * from v1; +2 REGEXP 3 | 3 2 REGEXP (3 | 3) (2 REGEXP 3) | 3 +0 0 3 +create or replace view v1 as select 2 REGEXP 2 & 2, 2 REGEXP (2 & 2), (2 REGEXP 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 2 & 2 AS `2 REGEXP 2 & 2`,2 regexp 2 & 2 AS `2 REGEXP (2 & 2)`,(2 regexp 2) & 2 AS `(2 REGEXP 2) & 2` +select 2 REGEXP 2 & 2, 2 REGEXP (2 & 2), (2 REGEXP 2) & 2 union select * from v1; +2 REGEXP 2 & 2 2 REGEXP (2 & 2) (2 REGEXP 2) & 2 +1 1 0 +create or replace view v1 as select 2 REGEXP 2 << 2, 2 REGEXP (2 << 2), (2 REGEXP 2) << 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 2 << 2 AS `2 REGEXP 2 << 2`,2 regexp 2 << 2 AS `2 REGEXP (2 << 2)`,(2 regexp 2) << 2 AS `(2 REGEXP 2) << 2` +select 2 REGEXP 2 << 2, 2 REGEXP (2 << 2), (2 REGEXP 2) << 2 union select * from v1; +2 REGEXP 2 << 2 2 REGEXP (2 << 2) (2 REGEXP 2) << 2 +0 0 4 +create or replace view v1 as select 2 REGEXP 4 >> 1, 2 REGEXP (4 >> 1), (2 REGEXP 4) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 4 >> 1 AS `2 REGEXP 4 >> 1`,2 regexp 4 >> 1 AS `2 REGEXP (4 >> 1)`,(2 regexp 4) >> 1 AS `(2 REGEXP 4) >> 1` +select 2 REGEXP 4 >> 1, 2 REGEXP (4 >> 1), (2 REGEXP 4) >> 1 union select * from v1; +2 REGEXP 4 >> 1 2 REGEXP (4 >> 1) (2 REGEXP 4) >> 1 +1 1 0 +create or replace view v1 as select 2 REGEXP '2000-01-01' +INTERVAL 1 DAY, 2 REGEXP ('2000-01-01' +INTERVAL 1 DAY), (2 REGEXP '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp '2000-01-01' + interval 1 day AS `2 REGEXP '2000-01-01' +INTERVAL 1 DAY`,2 regexp '2000-01-01' + interval 1 day AS `2 REGEXP ('2000-01-01' +INTERVAL 1 DAY)`,(2 regexp '2000-01-01') + interval 1 day AS `(2 REGEXP '2000-01-01') +INTERVAL 1 DAY` +select 2 REGEXP '2000-01-01' +INTERVAL 1 DAY, 2 REGEXP ('2000-01-01' +INTERVAL 1 DAY), (2 REGEXP '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 REGEXP '2000-01-01' +INTERVAL 1 DAY 2 REGEXP ('2000-01-01' +INTERVAL 1 DAY) (2 REGEXP '2000-01-01') +INTERVAL 1 DAY +0 0 NULL +create or replace view v1 as select 2 REGEXP 3 + 3, 2 REGEXP (3 + 3), (2 REGEXP 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 3 + 3 AS `2 REGEXP 3 + 3`,2 regexp 3 + 3 AS `2 REGEXP (3 + 3)`,(2 regexp 3) + 3 AS `(2 REGEXP 3) + 3` +select 2 REGEXP 3 + 3, 2 REGEXP (3 + 3), (2 REGEXP 3) + 3 union select * from v1; +2 REGEXP 3 + 3 2 REGEXP (3 + 3) (2 REGEXP 3) + 3 +0 0 3 +create or replace view v1 as select 2 REGEXP 3 - 3, 2 REGEXP (3 - 3), (2 REGEXP 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 3 - 3 AS `2 REGEXP 3 - 3`,2 regexp 3 - 3 AS `2 REGEXP (3 - 3)`,(2 regexp 3) - 3 AS `(2 REGEXP 3) - 3` +select 2 REGEXP 3 - 3, 2 REGEXP (3 - 3), (2 REGEXP 3) - 3 union select * from v1; +2 REGEXP 3 - 3 2 REGEXP (3 - 3) (2 REGEXP 3) - 3 +0 0 -3 +create or replace view v1 as select 2 REGEXP 2 * 2, 2 REGEXP (2 * 2), (2 REGEXP 2) * 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 2 * 2 AS `2 REGEXP 2 * 2`,2 regexp 2 * 2 AS `2 REGEXP (2 * 2)`,(2 regexp 2) * 2 AS `(2 REGEXP 2) * 2` +select 2 REGEXP 2 * 2, 2 REGEXP (2 * 2), (2 REGEXP 2) * 2 union select * from v1; +2 REGEXP 2 * 2 2 REGEXP (2 * 2) (2 REGEXP 2) * 2 +0 0 2 +create or replace view v1 as select 2 REGEXP 2 / 2, 2 REGEXP (2 / 2), (2 REGEXP 2) / 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 2 / 2 AS `2 REGEXP 2 / 2`,2 regexp 2 / 2 AS `2 REGEXP (2 / 2)`,(2 regexp 2) / 2 AS `(2 REGEXP 2) / 2` +select 2 REGEXP 2 / 2, 2 REGEXP (2 / 2), (2 REGEXP 2) / 2 union select * from v1; +2 REGEXP 2 / 2 2 REGEXP (2 / 2) (2 REGEXP 2) / 2 +0 0 0.5000 +create or replace view v1 as select 2 REGEXP 4 DIV 2, 2 REGEXP (4 DIV 2), (2 REGEXP 4) DIV 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 4 DIV 2 AS `2 REGEXP 4 DIV 2`,2 regexp 4 DIV 2 AS `2 REGEXP (4 DIV 2)`,(2 regexp 4) DIV 2 AS `(2 REGEXP 4) DIV 2` +select 2 REGEXP 4 DIV 2, 2 REGEXP (4 DIV 2), (2 REGEXP 4) DIV 2 union select * from v1; +2 REGEXP 4 DIV 2 2 REGEXP (4 DIV 2) (2 REGEXP 4) DIV 2 +1 1 0 +create or replace view v1 as select 2 REGEXP 2 MOD 2, 2 REGEXP (2 MOD 2), (2 REGEXP 2) MOD 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 2 % 2 AS `2 REGEXP 2 MOD 2`,2 regexp 2 % 2 AS `2 REGEXP (2 MOD 2)`,(2 regexp 2) % 2 AS `(2 REGEXP 2) MOD 2` +select 2 REGEXP 2 MOD 2, 2 REGEXP (2 MOD 2), (2 REGEXP 2) MOD 2 union select * from v1; +2 REGEXP 2 MOD 2 2 REGEXP (2 MOD 2) (2 REGEXP 2) MOD 2 +0 0 1 +create or replace view v1 as select 2 REGEXP 2 % 2, 2 REGEXP (2 % 2), (2 REGEXP 2) % 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 2 % 2 AS `2 REGEXP 2 % 2`,2 regexp 2 % 2 AS `2 REGEXP (2 % 2)`,(2 regexp 2) % 2 AS `(2 REGEXP 2) % 2` +select 2 REGEXP 2 % 2, 2 REGEXP (2 % 2), (2 REGEXP 2) % 2 union select * from v1; +2 REGEXP 2 % 2 2 REGEXP (2 % 2) (2 REGEXP 2) % 2 +0 0 1 +create or replace view v1 as select 2 REGEXP 3 ^ 3, 2 REGEXP (3 ^ 3), (2 REGEXP 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 3 ^ 3 AS `2 REGEXP 3 ^ 3`,2 regexp 3 ^ 3 AS `2 REGEXP (3 ^ 3)`,(2 regexp 3) ^ 3 AS `(2 REGEXP 3) ^ 3` +select 2 REGEXP 3 ^ 3, 2 REGEXP (3 ^ 3), (2 REGEXP 3) ^ 3 union select * from v1; +2 REGEXP 3 ^ 3 2 REGEXP (3 ^ 3) (2 REGEXP 3) ^ 3 +0 0 3 +create or replace view v1 as select 2 REGEXP 2 BETWEEN 1 AND 3, 2 REGEXP (2 BETWEEN 1 AND 3), (2 REGEXP 2) BETWEEN 1 AND 3; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'BETWEEN 1 AND 3, 2 REGEXP (2 BETWEEN 1 AND 3), (2 REGEXP 2) BETWEEN 1 AND 3' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp 3 ^ 3 AS `2 REGEXP 3 ^ 3`,2 regexp 3 ^ 3 AS `2 REGEXP (3 ^ 3)`,(2 regexp 3) ^ 3 AS `(2 REGEXP 3) ^ 3` +select 2 REGEXP 2 BETWEEN 1 AND 3, 2 REGEXP (2 BETWEEN 1 AND 3), (2 REGEXP 2) BETWEEN 1 AND 3 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'BETWEEN 1 AND 3, 2 REGEXP (2 BETWEEN 1 AND 3), (2 REGEXP 2) BETWEEN 1 AND 3 u...' at line 1 +create or replace view v1 as select 2 | 3 IS FALSE, 2 | (3 IS FALSE), (2 | 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 is false AS `2 | 3 IS FALSE`,2 | (3 is false) AS `2 | (3 IS FALSE)`,2 | 3 is false AS `(2 | 3) IS FALSE` +select 2 | 3 IS FALSE, 2 | (3 IS FALSE), (2 | 3) IS FALSE union select * from v1; +2 | 3 IS FALSE 2 | (3 IS FALSE) (2 | 3) IS FALSE +0 2 0 +create or replace view v1 as select charset(2 | 3 COLLATE latin1_bin), charset(2 | (3 COLLATE latin1_bin)), charset((2 | 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 | 3 collate latin1_bin) AS `charset(2 | 3 COLLATE latin1_bin)`,charset(2 | 3 collate latin1_bin) AS `charset(2 | (3 COLLATE latin1_bin))`,charset((2 | 3) collate latin1_bin) AS `charset((2 | 3) COLLATE latin1_bin)` +select charset(2 | 3 COLLATE latin1_bin), charset(2 | (3 COLLATE latin1_bin)), charset((2 | 3) COLLATE latin1_bin) union select * from v1; +charset(2 | 3 COLLATE latin1_bin) charset(2 | (3 COLLATE latin1_bin)) charset((2 | 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 | 3 IN (0,1), 2 | (3 IN (0,1)), (2 | 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 in (0,1) AS `2 | 3 IN (0,1)`,2 | (3 in (0,1)) AS `2 | (3 IN (0,1))`,2 | 3 in (0,1) AS `(2 | 3) IN (0,1)` +select 2 | 3 IN (0,1), 2 | (3 IN (0,1)), (2 | 3) IN (0,1) union select * from v1; +2 | 3 IN (0,1) 2 | (3 IN (0,1)) (2 | 3) IN (0,1) +0 2 0 +create or replace view v1 as select 2 | 3 OR 3, 2 | (3 OR 3), (2 | 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 or 3 AS `2 | 3 OR 3`,2 | (3 or 3) AS `2 | (3 OR 3)`,2 | 3 or 3 AS `(2 | 3) OR 3` +select 2 | 3 OR 3, 2 | (3 OR 3), (2 | 3) OR 3 union select * from v1; +2 | 3 OR 3 2 | (3 OR 3) (2 | 3) OR 3 +1 3 1 +create or replace view v1 as select 2 | 3 || 3, 2 | (3 || 3), (2 | 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 or 3 AS `2 | 3 || 3`,2 | (3 or 3) AS `2 | (3 || 3)`,2 | 3 or 3 AS `(2 | 3) || 3` +select 2 | 3 || 3, 2 | (3 || 3), (2 | 3) || 3 union select * from v1; +2 | 3 || 3 2 | (3 || 3) (2 | 3) || 3 +1 3 1 +create or replace view v1 as select 2 | 3 XOR 3, 2 | (3 XOR 3), (2 | 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 xor 3 AS `2 | 3 XOR 3`,2 | (3 xor 3) AS `2 | (3 XOR 3)`,2 | 3 xor 3 AS `(2 | 3) XOR 3` +select 2 | 3 XOR 3, 2 | (3 XOR 3), (2 | 3) XOR 3 union select * from v1; +2 | 3 XOR 3 2 | (3 XOR 3) (2 | 3) XOR 3 +0 2 0 +create or replace view v1 as select 2 | 3 AND 3, 2 | (3 AND 3), (2 | 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 and 3 AS `2 | 3 AND 3`,2 | (3 and 3) AS `2 | (3 AND 3)`,2 | 3 and 3 AS `(2 | 3) AND 3` +select 2 | 3 AND 3, 2 | (3 AND 3), (2 | 3) AND 3 union select * from v1; +2 | 3 AND 3 2 | (3 AND 3) (2 | 3) AND 3 +1 3 1 +create or replace view v1 as select 2 | 3 && 3, 2 | (3 && 3), (2 | 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 and 3 AS `2 | 3 && 3`,2 | (3 and 3) AS `2 | (3 && 3)`,2 | 3 and 3 AS `(2 | 3) && 3` +select 2 | 3 && 3, 2 | (3 && 3), (2 | 3) && 3 union select * from v1; +2 | 3 && 3 2 | (3 && 3) (2 | 3) && 3 +1 3 1 +create or replace view v1 as select 2 | 3 = 3, 2 | (3 = 3), (2 | 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 = 3 AS `2 | 3 = 3`,2 | (3 = 3) AS `2 | (3 = 3)`,2 | 3 = 3 AS `(2 | 3) = 3` +select 2 | 3 = 3, 2 | (3 = 3), (2 | 3) = 3 union select * from v1; +2 | 3 = 3 2 | (3 = 3) (2 | 3) = 3 +1 3 1 +create or replace view v1 as select 2 | 3 <=> 3, 2 | (3 <=> 3), (2 | 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 <=> 3 AS `2 | 3 <=> 3`,2 | (3 <=> 3) AS `2 | (3 <=> 3)`,2 | 3 <=> 3 AS `(2 | 3) <=> 3` +select 2 | 3 <=> 3, 2 | (3 <=> 3), (2 | 3) <=> 3 union select * from v1; +2 | 3 <=> 3 2 | (3 <=> 3) (2 | 3) <=> 3 +1 3 1 +create or replace view v1 as select 2 | 3 >= 3, 2 | (3 >= 3), (2 | 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 >= 3 AS `2 | 3 >= 3`,2 | (3 >= 3) AS `2 | (3 >= 3)`,2 | 3 >= 3 AS `(2 | 3) >= 3` +select 2 | 3 >= 3, 2 | (3 >= 3), (2 | 3) >= 3 union select * from v1; +2 | 3 >= 3 2 | (3 >= 3) (2 | 3) >= 3 +1 3 1 +create or replace view v1 as select 2 | 3 <= 3, 2 | (3 <= 3), (2 | 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 <= 3 AS `2 | 3 <= 3`,2 | (3 <= 3) AS `2 | (3 <= 3)`,2 | 3 <= 3 AS `(2 | 3) <= 3` +select 2 | 3 <= 3, 2 | (3 <= 3), (2 | 3) <= 3 union select * from v1; +2 | 3 <= 3 2 | (3 <= 3) (2 | 3) <= 3 +1 3 1 +create or replace view v1 as select 2 | 3 < 3, 2 | (3 < 3), (2 | 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 < 3 AS `2 | 3 < 3`,2 | (3 < 3) AS `2 | (3 < 3)`,2 | 3 < 3 AS `(2 | 3) < 3` +select 2 | 3 < 3, 2 | (3 < 3), (2 | 3) < 3 union select * from v1; +2 | 3 < 3 2 | (3 < 3) (2 | 3) < 3 +0 2 0 +create or replace view v1 as select 2 | 3 <> 3, 2 | (3 <> 3), (2 | 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 <> 3 AS `2 | 3 <> 3`,2 | (3 <> 3) AS `2 | (3 <> 3)`,2 | 3 <> 3 AS `(2 | 3) <> 3` +select 2 | 3 <> 3, 2 | (3 <> 3), (2 | 3) <> 3 union select * from v1; +2 | 3 <> 3 2 | (3 <> 3) (2 | 3) <> 3 +0 2 0 +create or replace view v1 as select 2 | 3 > 3, 2 | (3 > 3), (2 | 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 > 3 AS `2 | 3 > 3`,2 | (3 > 3) AS `2 | (3 > 3)`,2 | 3 > 3 AS `(2 | 3) > 3` +select 2 | 3 > 3, 2 | (3 > 3), (2 | 3) > 3 union select * from v1; +2 | 3 > 3 2 | (3 > 3) (2 | 3) > 3 +0 2 0 +create or replace view v1 as select 2 | 3 != 3, 2 | (3 != 3), (2 | 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 <> 3 AS `2 | 3 != 3`,2 | (3 <> 3) AS `2 | (3 != 3)`,2 | 3 <> 3 AS `(2 | 3) != 3` +select 2 | 3 != 3, 2 | (3 != 3), (2 | 3) != 3 union select * from v1; +2 | 3 != 3 2 | (3 != 3) (2 | 3) != 3 +0 2 0 +create or replace view v1 as select 2 | 3 LIKE 3, 2 | (3 LIKE 3), (2 | 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 like 3 AS `2 | 3 LIKE 3`,2 | (3 like 3) AS `2 | (3 LIKE 3)`,2 | 3 like 3 AS `(2 | 3) LIKE 3` +select 2 | 3 LIKE 3, 2 | (3 LIKE 3), (2 | 3) LIKE 3 union select * from v1; +2 | 3 LIKE 3 2 | (3 LIKE 3) (2 | 3) LIKE 3 +1 3 1 +create or replace view v1 as select 2 | 3 REGEXP 3, 2 | (3 REGEXP 3), (2 | 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 regexp 3 AS `2 | 3 REGEXP 3`,2 | (3 regexp 3) AS `2 | (3 REGEXP 3)`,2 | 3 regexp 3 AS `(2 | 3) REGEXP 3` +select 2 | 3 REGEXP 3, 2 | (3 REGEXP 3), (2 | 3) REGEXP 3 union select * from v1; +2 | 3 REGEXP 3 2 | (3 REGEXP 3) (2 | 3) REGEXP 3 +1 3 1 +create or replace view v1 as select 2 | 0 & 0, 2 | (0 & 0), (2 | 0) & 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 0 & 0 AS `2 | 0 & 0`,2 | 0 & 0 AS `2 | (0 & 0)`,(2 | 0) & 0 AS `(2 | 0) & 0` +select 2 | 0 & 0, 2 | (0 & 0), (2 | 0) & 0 union select * from v1; +2 | 0 & 0 2 | (0 & 0) (2 | 0) & 0 +2 2 0 +create or replace view v1 as select 2 | 3 << 3, 2 | (3 << 3), (2 | 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 << 3 AS `2 | 3 << 3`,2 | 3 << 3 AS `2 | (3 << 3)`,(2 | 3) << 3 AS `(2 | 3) << 3` +select 2 | 3 << 3, 2 | (3 << 3), (2 | 3) << 3 union select * from v1; +2 | 3 << 3 2 | (3 << 3) (2 | 3) << 3 +26 26 24 +create or replace view v1 as select 2 | 3 >> 3, 2 | (3 >> 3), (2 | 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 >> 3 AS `2 | 3 >> 3`,2 | 3 >> 3 AS `2 | (3 >> 3)`,(2 | 3) >> 3 AS `(2 | 3) >> 3` +select 2 | 3 >> 3, 2 | (3 >> 3), (2 | 3) >> 3 union select * from v1; +2 | 3 >> 3 2 | (3 >> 3) (2 | 3) >> 3 +2 2 0 +create or replace view v1 as select 2 | '2000-01-01' +INTERVAL 1 DAY, 2 | ('2000-01-01' +INTERVAL 1 DAY), (2 | '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | '2000-01-01' + interval 1 day AS `2 | '2000-01-01' +INTERVAL 1 DAY`,2 | '2000-01-01' + interval 1 day AS `2 | ('2000-01-01' +INTERVAL 1 DAY)`,(2 | '2000-01-01') + interval 1 day AS `(2 | '2000-01-01') +INTERVAL 1 DAY` +select 2 | '2000-01-01' +INTERVAL 1 DAY, 2 | ('2000-01-01' +INTERVAL 1 DAY), (2 | '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 | '2000-01-01' +INTERVAL 1 DAY 2 | ('2000-01-01' +INTERVAL 1 DAY) (2 | '2000-01-01') +INTERVAL 1 DAY +20000102 20000102 NULL +create or replace view v1 as select 2 | 1 + 1, 2 | (1 + 1), (2 | 1) + 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 1 + 1 AS `2 | 1 + 1`,2 | 1 + 1 AS `2 | (1 + 1)`,(2 | 1) + 1 AS `(2 | 1) + 1` +select 2 | 1 + 1, 2 | (1 + 1), (2 | 1) + 1 union select * from v1; +2 | 1 + 1 2 | (1 + 1) (2 | 1) + 1 +2 2 4 +create or replace view v1 as select 2 | 3 - 3, 2 | (3 - 3), (2 | 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 - 3 AS `2 | 3 - 3`,2 | 3 - 3 AS `2 | (3 - 3)`,(2 | 3) - 3 AS `(2 | 3) - 3` +select 2 | 3 - 3, 2 | (3 - 3), (2 | 3) - 3 union select * from v1; +2 | 3 - 3 2 | (3 - 3) (2 | 3) - 3 +2 2 0 +create or replace view v1 as select 2 | 3 * 3, 2 | (3 * 3), (2 | 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 * 3 AS `2 | 3 * 3`,2 | 3 * 3 AS `2 | (3 * 3)`,(2 | 3) * 3 AS `(2 | 3) * 3` +select 2 | 3 * 3, 2 | (3 * 3), (2 | 3) * 3 union select * from v1; +2 | 3 * 3 2 | (3 * 3) (2 | 3) * 3 +11 11 9 +create or replace view v1 as select 2 | 3 / 3, 2 | (3 / 3), (2 | 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 / 3 AS `2 | 3 / 3`,2 | 3 / 3 AS `2 | (3 / 3)`,(2 | 3) / 3 AS `(2 | 3) / 3` +select 2 | 3 / 3, 2 | (3 / 3), (2 | 3) / 3 union select * from v1; +2 | 3 / 3 2 | (3 / 3) (2 | 3) / 3 +3 3 1.0000 +create or replace view v1 as select 2 | 3 DIV 3, 2 | (3 DIV 3), (2 | 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 DIV 3 AS `2 | 3 DIV 3`,2 | 3 DIV 3 AS `2 | (3 DIV 3)`,(2 | 3) DIV 3 AS `(2 | 3) DIV 3` +select 2 | 3 DIV 3, 2 | (3 DIV 3), (2 | 3) DIV 3 union select * from v1; +2 | 3 DIV 3 2 | (3 DIV 3) (2 | 3) DIV 3 +3 3 1 +create or replace view v1 as select 2 | 3 MOD 3, 2 | (3 MOD 3), (2 | 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 % 3 AS `2 | 3 MOD 3`,2 | 3 % 3 AS `2 | (3 MOD 3)`,(2 | 3) % 3 AS `(2 | 3) MOD 3` +select 2 | 3 MOD 3, 2 | (3 MOD 3), (2 | 3) MOD 3 union select * from v1; +2 | 3 MOD 3 2 | (3 MOD 3) (2 | 3) MOD 3 +2 2 0 +create or replace view v1 as select 2 | 3 % 3, 2 | (3 % 3), (2 | 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 % 3 AS `2 | 3 % 3`,2 | 3 % 3 AS `2 | (3 % 3)`,(2 | 3) % 3 AS `(2 | 3) % 3` +select 2 | 3 % 3, 2 | (3 % 3), (2 | 3) % 3 union select * from v1; +2 | 3 % 3 2 | (3 % 3) (2 | 3) % 3 +2 2 0 +create or replace view v1 as select 2 | 3 ^ 3, 2 | (3 ^ 3), (2 | 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 ^ 3 AS `2 | 3 ^ 3`,2 | 3 ^ 3 AS `2 | (3 ^ 3)`,(2 | 3) ^ 3 AS `(2 | 3) ^ 3` +select 2 | 3 ^ 3, 2 | (3 ^ 3), (2 | 3) ^ 3 union select * from v1; +2 | 3 ^ 3 2 | (3 ^ 3) (2 | 3) ^ 3 +2 2 0 +create or replace view v1 as select 2 | 3 BETWEEN 1 AND 3, 2 | (3 BETWEEN 1 AND 3), (2 | 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 between 1 and 3 AS `2 | 3 BETWEEN 1 AND 3`,2 | (3 between 1 and 3) AS `2 | (3 BETWEEN 1 AND 3)`,2 | 3 between 1 and 3 AS `(2 | 3) BETWEEN 1 AND 3` +select 2 | 3 BETWEEN 1 AND 3, 2 | (3 BETWEEN 1 AND 3), (2 | 3) BETWEEN 1 AND 3 union select * from v1; +2 | 3 BETWEEN 1 AND 3 2 | (3 BETWEEN 1 AND 3) (2 | 3) BETWEEN 1 AND 3 +1 3 1 +create or replace view v1 as select 2 & 1 IS FALSE, 2 & (1 IS FALSE), (2 & 1) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 1 is false AS `2 & 1 IS FALSE`,2 & (1 is false) AS `2 & (1 IS FALSE)`,2 & 1 is false AS `(2 & 1) IS FALSE` +select 2 & 1 IS FALSE, 2 & (1 IS FALSE), (2 & 1) IS FALSE union select * from v1; +2 & 1 IS FALSE 2 & (1 IS FALSE) (2 & 1) IS FALSE +1 0 1 +create or replace view v1 as select charset(2 & 3 COLLATE latin1_bin), charset(2 & (3 COLLATE latin1_bin)), charset((2 & 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 & 3 collate latin1_bin) AS `charset(2 & 3 COLLATE latin1_bin)`,charset(2 & 3 collate latin1_bin) AS `charset(2 & (3 COLLATE latin1_bin))`,charset((2 & 3) collate latin1_bin) AS `charset((2 & 3) COLLATE latin1_bin)` +select charset(2 & 3 COLLATE latin1_bin), charset(2 & (3 COLLATE latin1_bin)), charset((2 & 3) COLLATE latin1_bin) union select * from v1; +charset(2 & 3 COLLATE latin1_bin) charset(2 & (3 COLLATE latin1_bin)) charset((2 & 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 & 4 IN (0,1), 2 & (4 IN (0,1)), (2 & 4) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 4 in (0,1) AS `2 & 4 IN (0,1)`,2 & (4 in (0,1)) AS `2 & (4 IN (0,1))`,2 & 4 in (0,1) AS `(2 & 4) IN (0,1)` +select 2 & 4 IN (0,1), 2 & (4 IN (0,1)), (2 & 4) IN (0,1) union select * from v1; +2 & 4 IN (0,1) 2 & (4 IN (0,1)) (2 & 4) IN (0,1) +1 0 1 +create or replace view v1 as select 2 & 3 OR 3, 2 & (3 OR 3), (2 & 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 or 3 AS `2 & 3 OR 3`,2 & (3 or 3) AS `2 & (3 OR 3)`,2 & 3 or 3 AS `(2 & 3) OR 3` +select 2 & 3 OR 3, 2 & (3 OR 3), (2 & 3) OR 3 union select * from v1; +2 & 3 OR 3 2 & (3 OR 3) (2 & 3) OR 3 +1 0 1 +create or replace view v1 as select 2 & 3 || 3, 2 & (3 || 3), (2 & 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 or 3 AS `2 & 3 || 3`,2 & (3 or 3) AS `2 & (3 || 3)`,2 & 3 or 3 AS `(2 & 3) || 3` +select 2 & 3 || 3, 2 & (3 || 3), (2 & 3) || 3 union select * from v1; +2 & 3 || 3 2 & (3 || 3) (2 & 3) || 3 +1 0 1 +create or replace view v1 as select 2 & 1 XOR 1, 2 & (1 XOR 1), (2 & 1) XOR 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 1 xor 1 AS `2 & 1 XOR 1`,2 & (1 xor 1) AS `2 & (1 XOR 1)`,2 & 1 xor 1 AS `(2 & 1) XOR 1` +select 2 & 1 XOR 1, 2 & (1 XOR 1), (2 & 1) XOR 1 union select * from v1; +2 & 1 XOR 1 2 & (1 XOR 1) (2 & 1) XOR 1 +1 0 1 +create or replace view v1 as select 2 & 3 AND 3, 2 & (3 AND 3), (2 & 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 and 3 AS `2 & 3 AND 3`,2 & (3 and 3) AS `2 & (3 AND 3)`,2 & 3 and 3 AS `(2 & 3) AND 3` +select 2 & 3 AND 3, 2 & (3 AND 3), (2 & 3) AND 3 union select * from v1; +2 & 3 AND 3 2 & (3 AND 3) (2 & 3) AND 3 +1 0 1 +create or replace view v1 as select 2 & 3 && 3, 2 & (3 && 3), (2 & 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 and 3 AS `2 & 3 && 3`,2 & (3 and 3) AS `2 & (3 && 3)`,2 & 3 and 3 AS `(2 & 3) && 3` +select 2 & 3 && 3, 2 & (3 && 3), (2 & 3) && 3 union select * from v1; +2 & 3 && 3 2 & (3 && 3) (2 & 3) && 3 +1 0 1 +create or replace view v1 as select 2 & 3 = 2, 2 & (3 = 2), (2 & 3) = 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 = 2 AS `2 & 3 = 2`,2 & (3 = 2) AS `2 & (3 = 2)`,2 & 3 = 2 AS `(2 & 3) = 2` +select 2 & 3 = 2, 2 & (3 = 2), (2 & 3) = 2 union select * from v1; +2 & 3 = 2 2 & (3 = 2) (2 & 3) = 2 +1 0 1 +create or replace view v1 as select 2 & 3 <=> 2, 2 & (3 <=> 2), (2 & 3) <=> 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 <=> 2 AS `2 & 3 <=> 2`,2 & (3 <=> 2) AS `2 & (3 <=> 2)`,2 & 3 <=> 2 AS `(2 & 3) <=> 2` +select 2 & 3 <=> 2, 2 & (3 <=> 2), (2 & 3) <=> 2 union select * from v1; +2 & 3 <=> 2 2 & (3 <=> 2) (2 & 3) <=> 2 +1 0 1 +create or replace view v1 as select 2 & 3 >= 2, 2 & (3 >= 2), (2 & 3) >= 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 >= 2 AS `2 & 3 >= 2`,2 & (3 >= 2) AS `2 & (3 >= 2)`,2 & 3 >= 2 AS `(2 & 3) >= 2` +select 2 & 3 >= 2, 2 & (3 >= 2), (2 & 3) >= 2 union select * from v1; +2 & 3 >= 2 2 & (3 >= 2) (2 & 3) >= 2 +1 0 1 +create or replace view v1 as select 2 & 3 <= 3, 2 & (3 <= 3), (2 & 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 <= 3 AS `2 & 3 <= 3`,2 & (3 <= 3) AS `2 & (3 <= 3)`,2 & 3 <= 3 AS `(2 & 3) <= 3` +select 2 & 3 <= 3, 2 & (3 <= 3), (2 & 3) <= 3 union select * from v1; +2 & 3 <= 3 2 & (3 <= 3) (2 & 3) <= 3 +1 0 1 +create or replace view v1 as select 2 & 3 < 3, 2 & (3 < 3), (2 & 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 < 3 AS `2 & 3 < 3`,2 & (3 < 3) AS `2 & (3 < 3)`,2 & 3 < 3 AS `(2 & 3) < 3` +select 2 & 3 < 3, 2 & (3 < 3), (2 & 3) < 3 union select * from v1; +2 & 3 < 3 2 & (3 < 3) (2 & 3) < 3 +1 0 1 +create or replace view v1 as select 2 & 3 <> 3, 2 & (3 <> 3), (2 & 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 <> 3 AS `2 & 3 <> 3`,2 & (3 <> 3) AS `2 & (3 <> 3)`,2 & 3 <> 3 AS `(2 & 3) <> 3` +select 2 & 3 <> 3, 2 & (3 <> 3), (2 & 3) <> 3 union select * from v1; +2 & 3 <> 3 2 & (3 <> 3) (2 & 3) <> 3 +1 0 1 +create or replace view v1 as select 2 & 3 > 1, 2 & (3 > 1), (2 & 3) > 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 > 1 AS `2 & 3 > 1`,2 & (3 > 1) AS `2 & (3 > 1)`,2 & 3 > 1 AS `(2 & 3) > 1` +select 2 & 3 > 1, 2 & (3 > 1), (2 & 3) > 1 union select * from v1; +2 & 3 > 1 2 & (3 > 1) (2 & 3) > 1 +1 0 1 +create or replace view v1 as select 2 & 3 != 3, 2 & (3 != 3), (2 & 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 <> 3 AS `2 & 3 != 3`,2 & (3 <> 3) AS `2 & (3 != 3)`,2 & 3 <> 3 AS `(2 & 3) != 3` +select 2 & 3 != 3, 2 & (3 != 3), (2 & 3) != 3 union select * from v1; +2 & 3 != 3 2 & (3 != 3) (2 & 3) != 3 +1 0 1 +create or replace view v1 as select 2 & 3 LIKE 2, 2 & (3 LIKE 2), (2 & 3) LIKE 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 like 2 AS `2 & 3 LIKE 2`,2 & (3 like 2) AS `2 & (3 LIKE 2)`,2 & 3 like 2 AS `(2 & 3) LIKE 2` +select 2 & 3 LIKE 2, 2 & (3 LIKE 2), (2 & 3) LIKE 2 union select * from v1; +2 & 3 LIKE 2 2 & (3 LIKE 2) (2 & 3) LIKE 2 +1 0 1 +create or replace view v1 as select 2 & 3 REGEXP 2, 2 & (3 REGEXP 2), (2 & 3) REGEXP 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 regexp 2 AS `2 & 3 REGEXP 2`,2 & (3 regexp 2) AS `2 & (3 REGEXP 2)`,2 & 3 regexp 2 AS `(2 & 3) REGEXP 2` +select 2 & 3 REGEXP 2, 2 & (3 REGEXP 2), (2 & 3) REGEXP 2 union select * from v1; +2 & 3 REGEXP 2 2 & (3 REGEXP 2) (2 & 3) REGEXP 2 +1 0 1 +create or replace view v1 as select 2 & 3 | 3, 2 & (3 | 3), (2 & 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 | 3 AS `2 & 3 | 3`,2 & (3 | 3) AS `2 & (3 | 3)`,2 & 3 | 3 AS `(2 & 3) | 3` +select 2 & 3 | 3, 2 & (3 | 3), (2 & 3) | 3 union select * from v1; +2 & 3 | 3 2 & (3 | 3) (2 & 3) | 3 +3 2 3 +create or replace view v1 as select 2 & 3 << 3, 2 & (3 << 3), (2 & 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 << 3 AS `2 & 3 << 3`,2 & 3 << 3 AS `2 & (3 << 3)`,(2 & 3) << 3 AS `(2 & 3) << 3` +select 2 & 3 << 3, 2 & (3 << 3), (2 & 3) << 3 union select * from v1; +2 & 3 << 3 2 & (3 << 3) (2 & 3) << 3 +0 0 16 +create or replace view v1 as select 2 & 3 >> 1, 2 & (3 >> 1), (2 & 3) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 >> 1 AS `2 & 3 >> 1`,2 & 3 >> 1 AS `2 & (3 >> 1)`,(2 & 3) >> 1 AS `(2 & 3) >> 1` +select 2 & 3 >> 1, 2 & (3 >> 1), (2 & 3) >> 1 union select * from v1; +2 & 3 >> 1 2 & (3 >> 1) (2 & 3) >> 1 +0 0 1 +create or replace view v1 as select 2 & '2000-01-01' +INTERVAL 1 DAY, 2 & ('2000-01-01' +INTERVAL 1 DAY), (2 & '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & '2000-01-01' + interval 1 day AS `2 & '2000-01-01' +INTERVAL 1 DAY`,2 & '2000-01-01' + interval 1 day AS `2 & ('2000-01-01' +INTERVAL 1 DAY)`,(2 & '2000-01-01') + interval 1 day AS `(2 & '2000-01-01') +INTERVAL 1 DAY` +select 2 & '2000-01-01' +INTERVAL 1 DAY, 2 & ('2000-01-01' +INTERVAL 1 DAY), (2 & '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 & '2000-01-01' +INTERVAL 1 DAY 2 & ('2000-01-01' +INTERVAL 1 DAY) (2 & '2000-01-01') +INTERVAL 1 DAY +2 2 NULL +create or replace view v1 as select 2 & 3 + 3, 2 & (3 + 3), (2 & 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 + 3 AS `2 & 3 + 3`,2 & 3 + 3 AS `2 & (3 + 3)`,(2 & 3) + 3 AS `(2 & 3) + 3` +select 2 & 3 + 3, 2 & (3 + 3), (2 & 3) + 3 union select * from v1; +2 & 3 + 3 2 & (3 + 3) (2 & 3) + 3 +2 2 5 +create or replace view v1 as select 6 & 4 - 3, 6 & (4 - 3), (6 & 4) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 6 & 4 - 3 AS `6 & 4 - 3`,6 & 4 - 3 AS `6 & (4 - 3)`,(6 & 4) - 3 AS `(6 & 4) - 3` +select 6 & 4 - 3, 6 & (4 - 3), (6 & 4) - 3 union select * from v1; +6 & 4 - 3 6 & (4 - 3) (6 & 4) - 3 +0 0 1 +create or replace view v1 as select 2 & 3 * 3, 2 & (3 * 3), (2 & 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 * 3 AS `2 & 3 * 3`,2 & 3 * 3 AS `2 & (3 * 3)`,(2 & 3) * 3 AS `(2 & 3) * 3` +select 2 & 3 * 3, 2 & (3 * 3), (2 & 3) * 3 union select * from v1; +2 & 3 * 3 2 & (3 * 3) (2 & 3) * 3 +0 0 6 +create or replace view v1 as select 2 & 3 / 3, 2 & (3 / 3), (2 & 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 / 3 AS `2 & 3 / 3`,2 & 3 / 3 AS `2 & (3 / 3)`,(2 & 3) / 3 AS `(2 & 3) / 3` +select 2 & 3 / 3, 2 & (3 / 3), (2 & 3) / 3 union select * from v1; +2 & 3 / 3 2 & (3 / 3) (2 & 3) / 3 +0 0 0.6667 +create or replace view v1 as select 2 & 3 DIV 2, 2 & (3 DIV 2), (2 & 3) DIV 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 DIV 2 AS `2 & 3 DIV 2`,2 & 3 DIV 2 AS `2 & (3 DIV 2)`,(2 & 3) DIV 2 AS `(2 & 3) DIV 2` +select 2 & 3 DIV 2, 2 & (3 DIV 2), (2 & 3) DIV 2 union select * from v1; +2 & 3 DIV 2 2 & (3 DIV 2) (2 & 3) DIV 2 +0 0 1 +create or replace view v1 as select 2 & 3 MOD 3, 2 & (3 MOD 3), (2 & 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 % 3 AS `2 & 3 MOD 3`,2 & 3 % 3 AS `2 & (3 MOD 3)`,(2 & 3) % 3 AS `(2 & 3) MOD 3` +select 2 & 3 MOD 3, 2 & (3 MOD 3), (2 & 3) MOD 3 union select * from v1; +2 & 3 MOD 3 2 & (3 MOD 3) (2 & 3) MOD 3 +0 0 2 +create or replace view v1 as select 2 & 3 % 3, 2 & (3 % 3), (2 & 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 % 3 AS `2 & 3 % 3`,2 & 3 % 3 AS `2 & (3 % 3)`,(2 & 3) % 3 AS `(2 & 3) % 3` +select 2 & 3 % 3, 2 & (3 % 3), (2 & 3) % 3 union select * from v1; +2 & 3 % 3 2 & (3 % 3) (2 & 3) % 3 +0 0 2 +create or replace view v1 as select 2 & 3 ^ 3, 2 & (3 ^ 3), (2 & 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 ^ 3 AS `2 & 3 ^ 3`,2 & 3 ^ 3 AS `2 & (3 ^ 3)`,(2 & 3) ^ 3 AS `(2 & 3) ^ 3` +select 2 & 3 ^ 3, 2 & (3 ^ 3), (2 & 3) ^ 3 union select * from v1; +2 & 3 ^ 3 2 & (3 ^ 3) (2 & 3) ^ 3 +0 0 1 +create or replace view v1 as select 2 & 3 BETWEEN 1 AND 3, 2 & (3 BETWEEN 1 AND 3), (2 & 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 3 between 1 and 3 AS `2 & 3 BETWEEN 1 AND 3`,2 & (3 between 1 and 3) AS `2 & (3 BETWEEN 1 AND 3)`,2 & 3 between 1 and 3 AS `(2 & 3) BETWEEN 1 AND 3` +select 2 & 3 BETWEEN 1 AND 3, 2 & (3 BETWEEN 1 AND 3), (2 & 3) BETWEEN 1 AND 3 union select * from v1; +2 & 3 BETWEEN 1 AND 3 2 & (3 BETWEEN 1 AND 3) (2 & 3) BETWEEN 1 AND 3 +1 0 1 +create or replace view v1 as select 2 << 3 IS FALSE, 2 << (3 IS FALSE), (2 << 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 is false AS `2 << 3 IS FALSE`,2 << (3 is false) AS `2 << (3 IS FALSE)`,2 << 3 is false AS `(2 << 3) IS FALSE` +select 2 << 3 IS FALSE, 2 << (3 IS FALSE), (2 << 3) IS FALSE union select * from v1; +2 << 3 IS FALSE 2 << (3 IS FALSE) (2 << 3) IS FALSE +0 2 0 +create or replace view v1 as select charset(2 << 3 COLLATE latin1_bin), charset(2 << (3 COLLATE latin1_bin)), charset((2 << 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 << 3 collate latin1_bin) AS `charset(2 << 3 COLLATE latin1_bin)`,charset(2 << 3 collate latin1_bin) AS `charset(2 << (3 COLLATE latin1_bin))`,charset((2 << 3) collate latin1_bin) AS `charset((2 << 3) COLLATE latin1_bin)` +select charset(2 << 3 COLLATE latin1_bin), charset(2 << (3 COLLATE latin1_bin)), charset((2 << 3) COLLATE latin1_bin) union select * from v1; +charset(2 << 3 COLLATE latin1_bin) charset(2 << (3 COLLATE latin1_bin)) charset((2 << 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 << 3 IN (0,1), 2 << (3 IN (0,1)), (2 << 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 in (0,1) AS `2 << 3 IN (0,1)`,2 << (3 in (0,1)) AS `2 << (3 IN (0,1))`,2 << 3 in (0,1) AS `(2 << 3) IN (0,1)` +select 2 << 3 IN (0,1), 2 << (3 IN (0,1)), (2 << 3) IN (0,1) union select * from v1; +2 << 3 IN (0,1) 2 << (3 IN (0,1)) (2 << 3) IN (0,1) +0 2 0 +create or replace view v1 as select 2 << 3 OR 3, 2 << (3 OR 3), (2 << 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 or 3 AS `2 << 3 OR 3`,2 << (3 or 3) AS `2 << (3 OR 3)`,2 << 3 or 3 AS `(2 << 3) OR 3` +select 2 << 3 OR 3, 2 << (3 OR 3), (2 << 3) OR 3 union select * from v1; +2 << 3 OR 3 2 << (3 OR 3) (2 << 3) OR 3 +1 4 1 +create or replace view v1 as select 2 << 3 || 3, 2 << (3 || 3), (2 << 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 or 3 AS `2 << 3 || 3`,2 << (3 or 3) AS `2 << (3 || 3)`,2 << 3 or 3 AS `(2 << 3) || 3` +select 2 << 3 || 3, 2 << (3 || 3), (2 << 3) || 3 union select * from v1; +2 << 3 || 3 2 << (3 || 3) (2 << 3) || 3 +1 4 1 +create or replace view v1 as select 2 << 3 XOR 3, 2 << (3 XOR 3), (2 << 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 xor 3 AS `2 << 3 XOR 3`,2 << (3 xor 3) AS `2 << (3 XOR 3)`,2 << 3 xor 3 AS `(2 << 3) XOR 3` +select 2 << 3 XOR 3, 2 << (3 XOR 3), (2 << 3) XOR 3 union select * from v1; +2 << 3 XOR 3 2 << (3 XOR 3) (2 << 3) XOR 3 +0 2 0 +create or replace view v1 as select 2 << 3 AND 3, 2 << (3 AND 3), (2 << 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 and 3 AS `2 << 3 AND 3`,2 << (3 and 3) AS `2 << (3 AND 3)`,2 << 3 and 3 AS `(2 << 3) AND 3` +select 2 << 3 AND 3, 2 << (3 AND 3), (2 << 3) AND 3 union select * from v1; +2 << 3 AND 3 2 << (3 AND 3) (2 << 3) AND 3 +1 4 1 +create or replace view v1 as select 2 << 3 && 3, 2 << (3 && 3), (2 << 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 and 3 AS `2 << 3 && 3`,2 << (3 and 3) AS `2 << (3 && 3)`,2 << 3 and 3 AS `(2 << 3) && 3` +select 2 << 3 && 3, 2 << (3 && 3), (2 << 3) && 3 union select * from v1; +2 << 3 && 3 2 << (3 && 3) (2 << 3) && 3 +1 4 1 +create or replace view v1 as select 2 << 3 = 3, 2 << (3 = 3), (2 << 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 = 3 AS `2 << 3 = 3`,2 << (3 = 3) AS `2 << (3 = 3)`,2 << 3 = 3 AS `(2 << 3) = 3` +select 2 << 3 = 3, 2 << (3 = 3), (2 << 3) = 3 union select * from v1; +2 << 3 = 3 2 << (3 = 3) (2 << 3) = 3 +0 4 0 +create or replace view v1 as select 2 << 3 <=> 3, 2 << (3 <=> 3), (2 << 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 <=> 3 AS `2 << 3 <=> 3`,2 << (3 <=> 3) AS `2 << (3 <=> 3)`,2 << 3 <=> 3 AS `(2 << 3) <=> 3` +select 2 << 3 <=> 3, 2 << (3 <=> 3), (2 << 3) <=> 3 union select * from v1; +2 << 3 <=> 3 2 << (3 <=> 3) (2 << 3) <=> 3 +0 4 0 +create or replace view v1 as select 2 << 3 >= 3, 2 << (3 >= 3), (2 << 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 >= 3 AS `2 << 3 >= 3`,2 << (3 >= 3) AS `2 << (3 >= 3)`,2 << 3 >= 3 AS `(2 << 3) >= 3` +select 2 << 3 >= 3, 2 << (3 >= 3), (2 << 3) >= 3 union select * from v1; +2 << 3 >= 3 2 << (3 >= 3) (2 << 3) >= 3 +1 4 1 +create or replace view v1 as select 2 << 3 <= 3, 2 << (3 <= 3), (2 << 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 <= 3 AS `2 << 3 <= 3`,2 << (3 <= 3) AS `2 << (3 <= 3)`,2 << 3 <= 3 AS `(2 << 3) <= 3` +select 2 << 3 <= 3, 2 << (3 <= 3), (2 << 3) <= 3 union select * from v1; +2 << 3 <= 3 2 << (3 <= 3) (2 << 3) <= 3 +0 4 0 +create or replace view v1 as select 2 << 3 < 3, 2 << (3 < 3), (2 << 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 < 3 AS `2 << 3 < 3`,2 << (3 < 3) AS `2 << (3 < 3)`,2 << 3 < 3 AS `(2 << 3) < 3` +select 2 << 3 < 3, 2 << (3 < 3), (2 << 3) < 3 union select * from v1; +2 << 3 < 3 2 << (3 < 3) (2 << 3) < 3 +0 2 0 +create or replace view v1 as select 2 << 3 <> 3, 2 << (3 <> 3), (2 << 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 <> 3 AS `2 << 3 <> 3`,2 << (3 <> 3) AS `2 << (3 <> 3)`,2 << 3 <> 3 AS `(2 << 3) <> 3` +select 2 << 3 <> 3, 2 << (3 <> 3), (2 << 3) <> 3 union select * from v1; +2 << 3 <> 3 2 << (3 <> 3) (2 << 3) <> 3 +1 2 1 +create or replace view v1 as select 2 << 3 > 3, 2 << (3 > 3), (2 << 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 > 3 AS `2 << 3 > 3`,2 << (3 > 3) AS `2 << (3 > 3)`,2 << 3 > 3 AS `(2 << 3) > 3` +select 2 << 3 > 3, 2 << (3 > 3), (2 << 3) > 3 union select * from v1; +2 << 3 > 3 2 << (3 > 3) (2 << 3) > 3 +1 2 1 +create or replace view v1 as select 2 << 3 != 3, 2 << (3 != 3), (2 << 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 <> 3 AS `2 << 3 != 3`,2 << (3 <> 3) AS `2 << (3 != 3)`,2 << 3 <> 3 AS `(2 << 3) != 3` +select 2 << 3 != 3, 2 << (3 != 3), (2 << 3) != 3 union select * from v1; +2 << 3 != 3 2 << (3 != 3) (2 << 3) != 3 +1 2 1 +create or replace view v1 as select 2 << 3 LIKE 3, 2 << (3 LIKE 3), (2 << 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 like 3 AS `2 << 3 LIKE 3`,2 << (3 like 3) AS `2 << (3 LIKE 3)`,2 << 3 like 3 AS `(2 << 3) LIKE 3` +select 2 << 3 LIKE 3, 2 << (3 LIKE 3), (2 << 3) LIKE 3 union select * from v1; +2 << 3 LIKE 3 2 << (3 LIKE 3) (2 << 3) LIKE 3 +0 4 0 +create or replace view v1 as select 2 << 3 REGEXP 3, 2 << (3 REGEXP 3), (2 << 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 regexp 3 AS `2 << 3 REGEXP 3`,2 << (3 regexp 3) AS `2 << (3 REGEXP 3)`,2 << 3 regexp 3 AS `(2 << 3) REGEXP 3` +select 2 << 3 REGEXP 3, 2 << (3 REGEXP 3), (2 << 3) REGEXP 3 union select * from v1; +2 << 3 REGEXP 3 2 << (3 REGEXP 3) (2 << 3) REGEXP 3 +0 4 0 +create or replace view v1 as select 2 << 3 | 3, 2 << (3 | 3), (2 << 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 | 3 AS `2 << 3 | 3`,2 << (3 | 3) AS `2 << (3 | 3)`,2 << 3 | 3 AS `(2 << 3) | 3` +select 2 << 3 | 3, 2 << (3 | 3), (2 << 3) | 3 union select * from v1; +2 << 3 | 3 2 << (3 | 3) (2 << 3) | 3 +19 16 19 +create or replace view v1 as select 2 << 3 & 3, 2 << (3 & 3), (2 << 3) & 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 & 3 AS `2 << 3 & 3`,2 << (3 & 3) AS `2 << (3 & 3)`,2 << 3 & 3 AS `(2 << 3) & 3` +select 2 << 3 & 3, 2 << (3 & 3), (2 << 3) & 3 union select * from v1; +2 << 3 & 3 2 << (3 & 3) (2 << 3) & 3 +0 16 0 +create or replace view v1 as select 2 << 3 << 3, 2 << (3 << 3), (2 << 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 << 3 AS `2 << 3 << 3`,2 << (3 << 3) AS `2 << (3 << 3)`,2 << 3 << 3 AS `(2 << 3) << 3` +select 2 << 3 << 3, 2 << (3 << 3), (2 << 3) << 3 union select * from v1; +2 << 3 << 3 2 << (3 << 3) (2 << 3) << 3 +128 33554432 128 +create or replace view v1 as select 2 << 2 >> 3, 2 << (2 >> 3), (2 << 2) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 2 >> 3 AS `2 << 2 >> 3`,2 << (2 >> 3) AS `2 << (2 >> 3)`,2 << 2 >> 3 AS `(2 << 2) >> 3` +select 2 << 2 >> 3, 2 << (2 >> 3), (2 << 2) >> 3 union select * from v1; +2 << 2 >> 3 2 << (2 >> 3) (2 << 2) >> 3 +1 2 1 +create or replace view v1 as select 2 << '2000-01-01' +INTERVAL 1 DAY, 2 << ('2000-01-01' +INTERVAL 1 DAY), (2 << '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << '2000-01-01' + interval 1 day AS `2 << '2000-01-01' +INTERVAL 1 DAY`,2 << '2000-01-01' + interval 1 day AS `2 << ('2000-01-01' +INTERVAL 1 DAY)`,(2 << '2000-01-01') + interval 1 day AS `(2 << '2000-01-01') +INTERVAL 1 DAY` +select 2 << '2000-01-01' +INTERVAL 1 DAY, 2 << ('2000-01-01' +INTERVAL 1 DAY), (2 << '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 << '2000-01-01' +INTERVAL 1 DAY 2 << ('2000-01-01' +INTERVAL 1 DAY) (2 << '2000-01-01') +INTERVAL 1 DAY +0 0 NULL +create or replace view v1 as select 2 << 3 + 3, 2 << (3 + 3), (2 << 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 + 3 AS `2 << 3 + 3`,2 << 3 + 3 AS `2 << (3 + 3)`,(2 << 3) + 3 AS `(2 << 3) + 3` +select 2 << 3 + 3, 2 << (3 + 3), (2 << 3) + 3 union select * from v1; +2 << 3 + 3 2 << (3 + 3) (2 << 3) + 3 +128 128 19 +create or replace view v1 as select 2 << 3 - 3, 2 << (3 - 3), (2 << 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 - 3 AS `2 << 3 - 3`,2 << 3 - 3 AS `2 << (3 - 3)`,(2 << 3) - 3 AS `(2 << 3) - 3` +select 2 << 3 - 3, 2 << (3 - 3), (2 << 3) - 3 union select * from v1; +2 << 3 - 3 2 << (3 - 3) (2 << 3) - 3 +2 2 13 +create or replace view v1 as select 2 << 3 * 3, 2 << (3 * 3), (2 << 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 * 3 AS `2 << 3 * 3`,2 << 3 * 3 AS `2 << (3 * 3)`,(2 << 3) * 3 AS `(2 << 3) * 3` +select 2 << 3 * 3, 2 << (3 * 3), (2 << 3) * 3 union select * from v1; +2 << 3 * 3 2 << (3 * 3) (2 << 3) * 3 +1024 1024 48 +create or replace view v1 as select 2 << 3 / 3, 2 << (3 / 3), (2 << 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 / 3 AS `2 << 3 / 3`,2 << 3 / 3 AS `2 << (3 / 3)`,(2 << 3) / 3 AS `(2 << 3) / 3` +select 2 << 3 / 3, 2 << (3 / 3), (2 << 3) / 3 union select * from v1; +2 << 3 / 3 2 << (3 / 3) (2 << 3) / 3 +4 4 5.3333 +create or replace view v1 as select 2 << 3 DIV 3, 2 << (3 DIV 3), (2 << 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 DIV 3 AS `2 << 3 DIV 3`,2 << 3 DIV 3 AS `2 << (3 DIV 3)`,(2 << 3) DIV 3 AS `(2 << 3) DIV 3` +select 2 << 3 DIV 3, 2 << (3 DIV 3), (2 << 3) DIV 3 union select * from v1; +2 << 3 DIV 3 2 << (3 DIV 3) (2 << 3) DIV 3 +4 4 5 +create or replace view v1 as select 2 << 3 MOD 3, 2 << (3 MOD 3), (2 << 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 % 3 AS `2 << 3 MOD 3`,2 << 3 % 3 AS `2 << (3 MOD 3)`,(2 << 3) % 3 AS `(2 << 3) MOD 3` +select 2 << 3 MOD 3, 2 << (3 MOD 3), (2 << 3) MOD 3 union select * from v1; +2 << 3 MOD 3 2 << (3 MOD 3) (2 << 3) MOD 3 +2 2 1 +create or replace view v1 as select 2 << 3 % 3, 2 << (3 % 3), (2 << 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 % 3 AS `2 << 3 % 3`,2 << 3 % 3 AS `2 << (3 % 3)`,(2 << 3) % 3 AS `(2 << 3) % 3` +select 2 << 3 % 3, 2 << (3 % 3), (2 << 3) % 3 union select * from v1; +2 << 3 % 3 2 << (3 % 3) (2 << 3) % 3 +2 2 1 +create or replace view v1 as select 2 << 3 ^ 3, 2 << (3 ^ 3), (2 << 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 ^ 3 AS `2 << 3 ^ 3`,2 << 3 ^ 3 AS `2 << (3 ^ 3)`,(2 << 3) ^ 3 AS `(2 << 3) ^ 3` +select 2 << 3 ^ 3, 2 << (3 ^ 3), (2 << 3) ^ 3 union select * from v1; +2 << 3 ^ 3 2 << (3 ^ 3) (2 << 3) ^ 3 +2 2 19 +create or replace view v1 as select 2 << 3 BETWEEN 1 AND 3, 2 << (3 BETWEEN 1 AND 3), (2 << 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 between 1 and 3 AS `2 << 3 BETWEEN 1 AND 3`,2 << (3 between 1 and 3) AS `2 << (3 BETWEEN 1 AND 3)`,2 << 3 between 1 and 3 AS `(2 << 3) BETWEEN 1 AND 3` +select 2 << 3 BETWEEN 1 AND 3, 2 << (3 BETWEEN 1 AND 3), (2 << 3) BETWEEN 1 AND 3 union select * from v1; +2 << 3 BETWEEN 1 AND 3 2 << (3 BETWEEN 1 AND 3) (2 << 3) BETWEEN 1 AND 3 +0 4 0 +create or replace view v1 as select 2 >> 3 IS FALSE, 2 >> (3 IS FALSE), (2 >> 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 is false AS `2 >> 3 IS FALSE`,2 >> (3 is false) AS `2 >> (3 IS FALSE)`,2 >> 3 is false AS `(2 >> 3) IS FALSE` +select 2 >> 3 IS FALSE, 2 >> (3 IS FALSE), (2 >> 3) IS FALSE union select * from v1; +2 >> 3 IS FALSE 2 >> (3 IS FALSE) (2 >> 3) IS FALSE +1 2 1 +create or replace view v1 as select charset(2 >> 3 COLLATE latin1_bin), charset(2 >> (3 COLLATE latin1_bin)), charset((2 >> 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 >> 3 collate latin1_bin) AS `charset(2 >> 3 COLLATE latin1_bin)`,charset(2 >> 3 collate latin1_bin) AS `charset(2 >> (3 COLLATE latin1_bin))`,charset((2 >> 3) collate latin1_bin) AS `charset((2 >> 3) COLLATE latin1_bin)` +select charset(2 >> 3 COLLATE latin1_bin), charset(2 >> (3 COLLATE latin1_bin)), charset((2 >> 3) COLLATE latin1_bin) union select * from v1; +charset(2 >> 3 COLLATE latin1_bin) charset(2 >> (3 COLLATE latin1_bin)) charset((2 >> 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 >> 3 IN (0,1), 2 >> (3 IN (0,1)), (2 >> 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 in (0,1) AS `2 >> 3 IN (0,1)`,2 >> (3 in (0,1)) AS `2 >> (3 IN (0,1))`,2 >> 3 in (0,1) AS `(2 >> 3) IN (0,1)` +select 2 >> 3 IN (0,1), 2 >> (3 IN (0,1)), (2 >> 3) IN (0,1) union select * from v1; +2 >> 3 IN (0,1) 2 >> (3 IN (0,1)) (2 >> 3) IN (0,1) +1 2 1 +create or replace view v1 as select 2 >> 3 OR 0, 2 >> (3 OR 0), (2 >> 3) OR 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 or 0 AS `2 >> 3 OR 0`,2 >> (3 or 0) AS `2 >> (3 OR 0)`,2 >> 3 or 0 AS `(2 >> 3) OR 0` +select 2 >> 3 OR 0, 2 >> (3 OR 0), (2 >> 3) OR 0 union select * from v1; +2 >> 3 OR 0 2 >> (3 OR 0) (2 >> 3) OR 0 +0 1 0 +create or replace view v1 as select 2 >> 3 || 0, 2 >> (3 || 0), (2 >> 3) || 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 or 0 AS `2 >> 3 || 0`,2 >> (3 or 0) AS `2 >> (3 || 0)`,2 >> 3 or 0 AS `(2 >> 3) || 0` +select 2 >> 3 || 0, 2 >> (3 || 0), (2 >> 3) || 0 union select * from v1; +2 >> 3 || 0 2 >> (3 || 0) (2 >> 3) || 0 +0 1 0 +create or replace view v1 as select 2 >> 3 XOR 3, 2 >> (3 XOR 3), (2 >> 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 xor 3 AS `2 >> 3 XOR 3`,2 >> (3 xor 3) AS `2 >> (3 XOR 3)`,2 >> 3 xor 3 AS `(2 >> 3) XOR 3` +select 2 >> 3 XOR 3, 2 >> (3 XOR 3), (2 >> 3) XOR 3 union select * from v1; +2 >> 3 XOR 3 2 >> (3 XOR 3) (2 >> 3) XOR 3 +1 2 1 +create or replace view v1 as select 2 >> 3 AND 3, 2 >> (3 AND 3), (2 >> 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 and 3 AS `2 >> 3 AND 3`,2 >> (3 and 3) AS `2 >> (3 AND 3)`,2 >> 3 and 3 AS `(2 >> 3) AND 3` +select 2 >> 3 AND 3, 2 >> (3 AND 3), (2 >> 3) AND 3 union select * from v1; +2 >> 3 AND 3 2 >> (3 AND 3) (2 >> 3) AND 3 +0 1 0 +create or replace view v1 as select 2 >> 3 && 3, 2 >> (3 && 3), (2 >> 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 and 3 AS `2 >> 3 && 3`,2 >> (3 and 3) AS `2 >> (3 && 3)`,2 >> 3 and 3 AS `(2 >> 3) && 3` +select 2 >> 3 && 3, 2 >> (3 && 3), (2 >> 3) && 3 union select * from v1; +2 >> 3 && 3 2 >> (3 && 3) (2 >> 3) && 3 +0 1 0 +create or replace view v1 as select 2 >> 3 = 3, 2 >> (3 = 3), (2 >> 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 = 3 AS `2 >> 3 = 3`,2 >> (3 = 3) AS `2 >> (3 = 3)`,2 >> 3 = 3 AS `(2 >> 3) = 3` +select 2 >> 3 = 3, 2 >> (3 = 3), (2 >> 3) = 3 union select * from v1; +2 >> 3 = 3 2 >> (3 = 3) (2 >> 3) = 3 +0 1 0 +create or replace view v1 as select 2 >> 3 <=> 3, 2 >> (3 <=> 3), (2 >> 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 <=> 3 AS `2 >> 3 <=> 3`,2 >> (3 <=> 3) AS `2 >> (3 <=> 3)`,2 >> 3 <=> 3 AS `(2 >> 3) <=> 3` +select 2 >> 3 <=> 3, 2 >> (3 <=> 3), (2 >> 3) <=> 3 union select * from v1; +2 >> 3 <=> 3 2 >> (3 <=> 3) (2 >> 3) <=> 3 +0 1 0 +create or replace view v1 as select 2 >> 3 >= 3, 2 >> (3 >= 3), (2 >> 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 >= 3 AS `2 >> 3 >= 3`,2 >> (3 >= 3) AS `2 >> (3 >= 3)`,2 >> 3 >= 3 AS `(2 >> 3) >= 3` +select 2 >> 3 >= 3, 2 >> (3 >= 3), (2 >> 3) >= 3 union select * from v1; +2 >> 3 >= 3 2 >> (3 >= 3) (2 >> 3) >= 3 +0 1 0 +create or replace view v1 as select 2 >> 3 <= 0, 2 >> (3 <= 0), (2 >> 3) <= 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 <= 0 AS `2 >> 3 <= 0`,2 >> (3 <= 0) AS `2 >> (3 <= 0)`,2 >> 3 <= 0 AS `(2 >> 3) <= 0` +select 2 >> 3 <= 0, 2 >> (3 <= 0), (2 >> 3) <= 0 union select * from v1; +2 >> 3 <= 0 2 >> (3 <= 0) (2 >> 3) <= 0 +1 2 1 +create or replace view v1 as select 2 >> 3 < 3, 2 >> (3 < 3), (2 >> 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 < 3 AS `2 >> 3 < 3`,2 >> (3 < 3) AS `2 >> (3 < 3)`,2 >> 3 < 3 AS `(2 >> 3) < 3` +select 2 >> 3 < 3, 2 >> (3 < 3), (2 >> 3) < 3 union select * from v1; +2 >> 3 < 3 2 >> (3 < 3) (2 >> 3) < 3 +1 2 1 +create or replace view v1 as select 2 >> 3 <> 3, 2 >> (3 <> 3), (2 >> 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 <> 3 AS `2 >> 3 <> 3`,2 >> (3 <> 3) AS `2 >> (3 <> 3)`,2 >> 3 <> 3 AS `(2 >> 3) <> 3` +select 2 >> 3 <> 3, 2 >> (3 <> 3), (2 >> 3) <> 3 union select * from v1; +2 >> 3 <> 3 2 >> (3 <> 3) (2 >> 3) <> 3 +1 2 1 +create or replace view v1 as select 2 >> 3 > 3, 2 >> (3 > 3), (2 >> 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 > 3 AS `2 >> 3 > 3`,2 >> (3 > 3) AS `2 >> (3 > 3)`,2 >> 3 > 3 AS `(2 >> 3) > 3` +select 2 >> 3 > 3, 2 >> (3 > 3), (2 >> 3) > 3 union select * from v1; +2 >> 3 > 3 2 >> (3 > 3) (2 >> 3) > 3 +0 2 0 +create or replace view v1 as select 2 >> 3 != 3, 2 >> (3 != 3), (2 >> 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 <> 3 AS `2 >> 3 != 3`,2 >> (3 <> 3) AS `2 >> (3 != 3)`,2 >> 3 <> 3 AS `(2 >> 3) != 3` +select 2 >> 3 != 3, 2 >> (3 != 3), (2 >> 3) != 3 union select * from v1; +2 >> 3 != 3 2 >> (3 != 3) (2 >> 3) != 3 +1 2 1 +create or replace view v1 as select 2 >> 3 LIKE 3, 2 >> (3 LIKE 3), (2 >> 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 like 3 AS `2 >> 3 LIKE 3`,2 >> (3 like 3) AS `2 >> (3 LIKE 3)`,2 >> 3 like 3 AS `(2 >> 3) LIKE 3` +select 2 >> 3 LIKE 3, 2 >> (3 LIKE 3), (2 >> 3) LIKE 3 union select * from v1; +2 >> 3 LIKE 3 2 >> (3 LIKE 3) (2 >> 3) LIKE 3 +0 1 0 +create or replace view v1 as select 2 >> 3 REGEXP 3, 2 >> (3 REGEXP 3), (2 >> 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 regexp 3 AS `2 >> 3 REGEXP 3`,2 >> (3 regexp 3) AS `2 >> (3 REGEXP 3)`,2 >> 3 regexp 3 AS `(2 >> 3) REGEXP 3` +select 2 >> 3 REGEXP 3, 2 >> (3 REGEXP 3), (2 >> 3) REGEXP 3 union select * from v1; +2 >> 3 REGEXP 3 2 >> (3 REGEXP 3) (2 >> 3) REGEXP 3 +0 1 0 +create or replace view v1 as select 2 >> 3 | 3, 2 >> (3 | 3), (2 >> 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 | 3 AS `2 >> 3 | 3`,2 >> (3 | 3) AS `2 >> (3 | 3)`,2 >> 3 | 3 AS `(2 >> 3) | 3` +select 2 >> 3 | 3, 2 >> (3 | 3), (2 >> 3) | 3 union select * from v1; +2 >> 3 | 3 2 >> (3 | 3) (2 >> 3) | 3 +3 0 3 +create or replace view v1 as select 2 >> 3 & 1, 2 >> (3 & 1), (2 >> 3) & 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 & 1 AS `2 >> 3 & 1`,2 >> (3 & 1) AS `2 >> (3 & 1)`,2 >> 3 & 1 AS `(2 >> 3) & 1` +select 2 >> 3 & 1, 2 >> (3 & 1), (2 >> 3) & 1 union select * from v1; +2 >> 3 & 1 2 >> (3 & 1) (2 >> 3) & 1 +0 1 0 +create or replace view v1 as select 2 >> 1 << 3, 2 >> (1 << 3), (2 >> 1) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 1 << 3 AS `2 >> 1 << 3`,2 >> (1 << 3) AS `2 >> (1 << 3)`,2 >> 1 << 3 AS `(2 >> 1) << 3` +select 2 >> 1 << 3, 2 >> (1 << 3), (2 >> 1) << 3 union select * from v1; +2 >> 1 << 3 2 >> (1 << 3) (2 >> 1) << 3 +8 0 8 +create or replace view v1 as select 2 >> 3 >> 3, 2 >> (3 >> 3), (2 >> 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 >> 3 AS `2 >> 3 >> 3`,2 >> (3 >> 3) AS `2 >> (3 >> 3)`,2 >> 3 >> 3 AS `(2 >> 3) >> 3` +select 2 >> 3 >> 3, 2 >> (3 >> 3), (2 >> 3) >> 3 union select * from v1; +2 >> 3 >> 3 2 >> (3 >> 3) (2 >> 3) >> 3 +0 2 0 +create or replace view v1 as select 2 >> '2000-01-01' +INTERVAL 1 DAY, 2 >> ('2000-01-01' +INTERVAL 1 DAY), (2 >> '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> '2000-01-01' + interval 1 day AS `2 >> '2000-01-01' +INTERVAL 1 DAY`,2 >> '2000-01-01' + interval 1 day AS `2 >> ('2000-01-01' +INTERVAL 1 DAY)`,(2 >> '2000-01-01') + interval 1 day AS `(2 >> '2000-01-01') +INTERVAL 1 DAY` +select 2 >> '2000-01-01' +INTERVAL 1 DAY, 2 >> ('2000-01-01' +INTERVAL 1 DAY), (2 >> '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 >> '2000-01-01' +INTERVAL 1 DAY 2 >> ('2000-01-01' +INTERVAL 1 DAY) (2 >> '2000-01-01') +INTERVAL 1 DAY +0 0 NULL +create or replace view v1 as select 2 >> 3 + 3, 2 >> (3 + 3), (2 >> 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 + 3 AS `2 >> 3 + 3`,2 >> 3 + 3 AS `2 >> (3 + 3)`,(2 >> 3) + 3 AS `(2 >> 3) + 3` +select 2 >> 3 + 3, 2 >> (3 + 3), (2 >> 3) + 3 union select * from v1; +2 >> 3 + 3 2 >> (3 + 3) (2 >> 3) + 3 +0 0 3 +create or replace view v1 as select 2 >> 1 - 1, 2 >> (1 - 1), (2 >> 1) - 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 1 - 1 AS `2 >> 1 - 1`,2 >> 1 - 1 AS `2 >> (1 - 1)`,(2 >> 1) - 1 AS `(2 >> 1) - 1` +select 2 >> 1 - 1, 2 >> (1 - 1), (2 >> 1) - 1 union select * from v1; +2 >> 1 - 1 2 >> (1 - 1) (2 >> 1) - 1 +2 2 0 +create or replace view v1 as select 2 >> 1 * 3, 2 >> (1 * 3), (2 >> 1) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 1 * 3 AS `2 >> 1 * 3`,2 >> 1 * 3 AS `2 >> (1 * 3)`,(2 >> 1) * 3 AS `(2 >> 1) * 3` +select 2 >> 1 * 3, 2 >> (1 * 3), (2 >> 1) * 3 union select * from v1; +2 >> 1 * 3 2 >> (1 * 3) (2 >> 1) * 3 +0 0 3 +create or replace view v1 as select 2 >> 3 / 3, 2 >> (3 / 3), (2 >> 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 / 3 AS `2 >> 3 / 3`,2 >> 3 / 3 AS `2 >> (3 / 3)`,(2 >> 3) / 3 AS `(2 >> 3) / 3` +select 2 >> 3 / 3, 2 >> (3 / 3), (2 >> 3) / 3 union select * from v1; +2 >> 3 / 3 2 >> (3 / 3) (2 >> 3) / 3 +1 1 0.0000 +create or replace view v1 as select 2 >> 3 DIV 3, 2 >> (3 DIV 3), (2 >> 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 DIV 3 AS `2 >> 3 DIV 3`,2 >> 3 DIV 3 AS `2 >> (3 DIV 3)`,(2 >> 3) DIV 3 AS `(2 >> 3) DIV 3` +select 2 >> 3 DIV 3, 2 >> (3 DIV 3), (2 >> 3) DIV 3 union select * from v1; +2 >> 3 DIV 3 2 >> (3 DIV 3) (2 >> 3) DIV 3 +1 1 0 +create or replace view v1 as select 2 >> 3 MOD 3, 2 >> (3 MOD 3), (2 >> 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 % 3 AS `2 >> 3 MOD 3`,2 >> 3 % 3 AS `2 >> (3 MOD 3)`,(2 >> 3) % 3 AS `(2 >> 3) MOD 3` +select 2 >> 3 MOD 3, 2 >> (3 MOD 3), (2 >> 3) MOD 3 union select * from v1; +2 >> 3 MOD 3 2 >> (3 MOD 3) (2 >> 3) MOD 3 +2 2 0 +create or replace view v1 as select 2 >> 3 % 3, 2 >> (3 % 3), (2 >> 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 % 3 AS `2 >> 3 % 3`,2 >> 3 % 3 AS `2 >> (3 % 3)`,(2 >> 3) % 3 AS `(2 >> 3) % 3` +select 2 >> 3 % 3, 2 >> (3 % 3), (2 >> 3) % 3 union select * from v1; +2 >> 3 % 3 2 >> (3 % 3) (2 >> 3) % 3 +2 2 0 +create or replace view v1 as select 2 >> 3 ^ 3, 2 >> (3 ^ 3), (2 >> 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 ^ 3 AS `2 >> 3 ^ 3`,2 >> 3 ^ 3 AS `2 >> (3 ^ 3)`,(2 >> 3) ^ 3 AS `(2 >> 3) ^ 3` +select 2 >> 3 ^ 3, 2 >> (3 ^ 3), (2 >> 3) ^ 3 union select * from v1; +2 >> 3 ^ 3 2 >> (3 ^ 3) (2 >> 3) ^ 3 +2 2 3 +create or replace view v1 as select 2 >> 3 BETWEEN 1 AND 3, 2 >> (3 BETWEEN 1 AND 3), (2 >> 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 between 1 and 3 AS `2 >> 3 BETWEEN 1 AND 3`,2 >> (3 between 1 and 3) AS `2 >> (3 BETWEEN 1 AND 3)`,2 >> 3 between 1 and 3 AS `(2 >> 3) BETWEEN 1 AND 3` +select 2 >> 3 BETWEEN 1 AND 3, 2 >> (3 BETWEEN 1 AND 3), (2 >> 3) BETWEEN 1 AND 3 union select * from v1; +2 >> 3 BETWEEN 1 AND 3 2 >> (3 BETWEEN 1 AND 3) (2 >> 3) BETWEEN 1 AND 3 +0 1 0 +create or replace view v1 as select 2 + 3 IS FALSE, 2 + (3 IS FALSE), (2 + 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 is false AS `2 + 3 IS FALSE`,2 + (3 is false) AS `2 + (3 IS FALSE)`,2 + 3 is false AS `(2 + 3) IS FALSE` +select 2 + 3 IS FALSE, 2 + (3 IS FALSE), (2 + 3) IS FALSE union select * from v1; +2 + 3 IS FALSE 2 + (3 IS FALSE) (2 + 3) IS FALSE +0 2 0 +create or replace view v1 as select charset(2 + 3 COLLATE latin1_bin), charset(2 + (3 COLLATE latin1_bin)), charset((2 + 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 + 3 collate latin1_bin) AS `charset(2 + 3 COLLATE latin1_bin)`,charset(2 + 3 collate latin1_bin) AS `charset(2 + (3 COLLATE latin1_bin))`,charset((2 + 3) collate latin1_bin) AS `charset((2 + 3) COLLATE latin1_bin)` +select charset(2 + 3 COLLATE latin1_bin), charset(2 + (3 COLLATE latin1_bin)), charset((2 + 3) COLLATE latin1_bin) union select * from v1; +charset(2 + 3 COLLATE latin1_bin) charset(2 + (3 COLLATE latin1_bin)) charset((2 + 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 + 3 IN (0,1), 2 + (3 IN (0,1)), (2 + 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 in (0,1) AS `2 + 3 IN (0,1)`,2 + (3 in (0,1)) AS `2 + (3 IN (0,1))`,2 + 3 in (0,1) AS `(2 + 3) IN (0,1)` +select 2 + 3 IN (0,1), 2 + (3 IN (0,1)), (2 + 3) IN (0,1) union select * from v1; +2 + 3 IN (0,1) 2 + (3 IN (0,1)) (2 + 3) IN (0,1) +0 2 0 +create or replace view v1 as select 2 + 3 OR 3, 2 + (3 OR 3), (2 + 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 or 3 AS `2 + 3 OR 3`,2 + (3 or 3) AS `2 + (3 OR 3)`,2 + 3 or 3 AS `(2 + 3) OR 3` +select 2 + 3 OR 3, 2 + (3 OR 3), (2 + 3) OR 3 union select * from v1; +2 + 3 OR 3 2 + (3 OR 3) (2 + 3) OR 3 +1 3 1 +create or replace view v1 as select 2 + 3 || 3, 2 + (3 || 3), (2 + 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 or 3 AS `2 + 3 || 3`,2 + (3 or 3) AS `2 + (3 || 3)`,2 + 3 or 3 AS `(2 + 3) || 3` +select 2 + 3 || 3, 2 + (3 || 3), (2 + 3) || 3 union select * from v1; +2 + 3 || 3 2 + (3 || 3) (2 + 3) || 3 +1 3 1 +create or replace view v1 as select 2 + 3 XOR 3, 2 + (3 XOR 3), (2 + 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 xor 3 AS `2 + 3 XOR 3`,2 + (3 xor 3) AS `2 + (3 XOR 3)`,2 + 3 xor 3 AS `(2 + 3) XOR 3` +select 2 + 3 XOR 3, 2 + (3 XOR 3), (2 + 3) XOR 3 union select * from v1; +2 + 3 XOR 3 2 + (3 XOR 3) (2 + 3) XOR 3 +0 2 0 +create or replace view v1 as select 2 + 3 AND 3, 2 + (3 AND 3), (2 + 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 and 3 AS `2 + 3 AND 3`,2 + (3 and 3) AS `2 + (3 AND 3)`,2 + 3 and 3 AS `(2 + 3) AND 3` +select 2 + 3 AND 3, 2 + (3 AND 3), (2 + 3) AND 3 union select * from v1; +2 + 3 AND 3 2 + (3 AND 3) (2 + 3) AND 3 +1 3 1 +create or replace view v1 as select 2 + 3 && 3, 2 + (3 && 3), (2 + 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 and 3 AS `2 + 3 && 3`,2 + (3 and 3) AS `2 + (3 && 3)`,2 + 3 and 3 AS `(2 + 3) && 3` +select 2 + 3 && 3, 2 + (3 && 3), (2 + 3) && 3 union select * from v1; +2 + 3 && 3 2 + (3 && 3) (2 + 3) && 3 +1 3 1 +create or replace view v1 as select 2 + 3 = 3, 2 + (3 = 3), (2 + 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 = 3 AS `2 + 3 = 3`,2 + (3 = 3) AS `2 + (3 = 3)`,2 + 3 = 3 AS `(2 + 3) = 3` +select 2 + 3 = 3, 2 + (3 = 3), (2 + 3) = 3 union select * from v1; +2 + 3 = 3 2 + (3 = 3) (2 + 3) = 3 +0 3 0 +create or replace view v1 as select 2 + 3 <=> 3, 2 + (3 <=> 3), (2 + 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 <=> 3 AS `2 + 3 <=> 3`,2 + (3 <=> 3) AS `2 + (3 <=> 3)`,2 + 3 <=> 3 AS `(2 + 3) <=> 3` +select 2 + 3 <=> 3, 2 + (3 <=> 3), (2 + 3) <=> 3 union select * from v1; +2 + 3 <=> 3 2 + (3 <=> 3) (2 + 3) <=> 3 +0 3 0 +create or replace view v1 as select 2 + 3 >= 3, 2 + (3 >= 3), (2 + 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 >= 3 AS `2 + 3 >= 3`,2 + (3 >= 3) AS `2 + (3 >= 3)`,2 + 3 >= 3 AS `(2 + 3) >= 3` +select 2 + 3 >= 3, 2 + (3 >= 3), (2 + 3) >= 3 union select * from v1; +2 + 3 >= 3 2 + (3 >= 3) (2 + 3) >= 3 +1 3 1 +create or replace view v1 as select 2 + 3 <= 3, 2 + (3 <= 3), (2 + 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 <= 3 AS `2 + 3 <= 3`,2 + (3 <= 3) AS `2 + (3 <= 3)`,2 + 3 <= 3 AS `(2 + 3) <= 3` +select 2 + 3 <= 3, 2 + (3 <= 3), (2 + 3) <= 3 union select * from v1; +2 + 3 <= 3 2 + (3 <= 3) (2 + 3) <= 3 +0 3 0 +create or replace view v1 as select 2 + 3 < 3, 2 + (3 < 3), (2 + 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 < 3 AS `2 + 3 < 3`,2 + (3 < 3) AS `2 + (3 < 3)`,2 + 3 < 3 AS `(2 + 3) < 3` +select 2 + 3 < 3, 2 + (3 < 3), (2 + 3) < 3 union select * from v1; +2 + 3 < 3 2 + (3 < 3) (2 + 3) < 3 +0 2 0 +create or replace view v1 as select 2 + 3 <> 3, 2 + (3 <> 3), (2 + 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 <> 3 AS `2 + 3 <> 3`,2 + (3 <> 3) AS `2 + (3 <> 3)`,2 + 3 <> 3 AS `(2 + 3) <> 3` +select 2 + 3 <> 3, 2 + (3 <> 3), (2 + 3) <> 3 union select * from v1; +2 + 3 <> 3 2 + (3 <> 3) (2 + 3) <> 3 +1 2 1 +create or replace view v1 as select 2 + 3 > 3, 2 + (3 > 3), (2 + 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 > 3 AS `2 + 3 > 3`,2 + (3 > 3) AS `2 + (3 > 3)`,2 + 3 > 3 AS `(2 + 3) > 3` +select 2 + 3 > 3, 2 + (3 > 3), (2 + 3) > 3 union select * from v1; +2 + 3 > 3 2 + (3 > 3) (2 + 3) > 3 +1 2 1 +create or replace view v1 as select 2 + 3 != 3, 2 + (3 != 3), (2 + 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 <> 3 AS `2 + 3 != 3`,2 + (3 <> 3) AS `2 + (3 != 3)`,2 + 3 <> 3 AS `(2 + 3) != 3` +select 2 + 3 != 3, 2 + (3 != 3), (2 + 3) != 3 union select * from v1; +2 + 3 != 3 2 + (3 != 3) (2 + 3) != 3 +1 2 1 +create or replace view v1 as select 2 + 3 LIKE 3, 2 + (3 LIKE 3), (2 + 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 like 3 AS `2 + 3 LIKE 3`,2 + (3 like 3) AS `2 + (3 LIKE 3)`,2 + 3 like 3 AS `(2 + 3) LIKE 3` +select 2 + 3 LIKE 3, 2 + (3 LIKE 3), (2 + 3) LIKE 3 union select * from v1; +2 + 3 LIKE 3 2 + (3 LIKE 3) (2 + 3) LIKE 3 +0 3 0 +create or replace view v1 as select 2 + 3 REGEXP 3, 2 + (3 REGEXP 3), (2 + 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 regexp 3 AS `2 + 3 REGEXP 3`,2 + (3 regexp 3) AS `2 + (3 REGEXP 3)`,2 + 3 regexp 3 AS `(2 + 3) REGEXP 3` +select 2 + 3 REGEXP 3, 2 + (3 REGEXP 3), (2 + 3) REGEXP 3 union select * from v1; +2 + 3 REGEXP 3 2 + (3 REGEXP 3) (2 + 3) REGEXP 3 +0 3 0 +create or replace view v1 as select 2 + 3 | 3, 2 + (3 | 3), (2 + 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 | 3 AS `2 + 3 | 3`,2 + (3 | 3) AS `2 + (3 | 3)`,2 + 3 | 3 AS `(2 + 3) | 3` +select 2 + 3 | 3, 2 + (3 | 3), (2 + 3) | 3 union select * from v1; +2 + 3 | 3 2 + (3 | 3) (2 + 3) | 3 +7 5 7 +create or replace view v1 as select 2 + 3 & 3, 2 + (3 & 3), (2 + 3) & 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 & 3 AS `2 + 3 & 3`,2 + (3 & 3) AS `2 + (3 & 3)`,2 + 3 & 3 AS `(2 + 3) & 3` +select 2 + 3 & 3, 2 + (3 & 3), (2 + 3) & 3 union select * from v1; +2 + 3 & 3 2 + (3 & 3) (2 + 3) & 3 +1 5 1 +create or replace view v1 as select 2 + 3 << 3, 2 + (3 << 3), (2 + 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 << 3 AS `2 + 3 << 3`,2 + (3 << 3) AS `2 + (3 << 3)`,2 + 3 << 3 AS `(2 + 3) << 3` +select 2 + 3 << 3, 2 + (3 << 3), (2 + 3) << 3 union select * from v1; +2 + 3 << 3 2 + (3 << 3) (2 + 3) << 3 +40 26 40 +create or replace view v1 as select 2 + 3 >> 3, 2 + (3 >> 3), (2 + 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 >> 3 AS `2 + 3 >> 3`,2 + (3 >> 3) AS `2 + (3 >> 3)`,2 + 3 >> 3 AS `(2 + 3) >> 3` +select 2 + 3 >> 3, 2 + (3 >> 3), (2 + 3) >> 3 union select * from v1; +2 + 3 >> 3 2 + (3 >> 3) (2 + 3) >> 3 +0 2 0 +create or replace view v1 as select 2 + '2000-01-01' +INTERVAL 1 DAY, 2 + ('2000-01-01' +INTERVAL 1 DAY), (2 + '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + '2000-01-01' + interval 1 day AS `2 + '2000-01-01' +INTERVAL 1 DAY`,2 + ('2000-01-01' + interval 1 day) AS `2 + ('2000-01-01' +INTERVAL 1 DAY)`,2 + '2000-01-01' + interval 1 day AS `(2 + '2000-01-01') +INTERVAL 1 DAY` +select 2 + '2000-01-01' +INTERVAL 1 DAY, 2 + ('2000-01-01' +INTERVAL 1 DAY), (2 + '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 + '2000-01-01' +INTERVAL 1 DAY 2 + ('2000-01-01' +INTERVAL 1 DAY) (2 + '2000-01-01') +INTERVAL 1 DAY +NULL 20000104 NULL +create or replace view v1 as select 2 + 3 * 3, 2 + (3 * 3), (2 + 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 * 3 AS `2 + 3 * 3`,2 + 3 * 3 AS `2 + (3 * 3)`,(2 + 3) * 3 AS `(2 + 3) * 3` +select 2 + 3 * 3, 2 + (3 * 3), (2 + 3) * 3 union select * from v1; +2 + 3 * 3 2 + (3 * 3) (2 + 3) * 3 +11 11 15 +create or replace view v1 as select 2 + 3 / 3, 2 + (3 / 3), (2 + 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 / 3 AS `2 + 3 / 3`,2 + 3 / 3 AS `2 + (3 / 3)`,(2 + 3) / 3 AS `(2 + 3) / 3` +select 2 + 3 / 3, 2 + (3 / 3), (2 + 3) / 3 union select * from v1; +2 + 3 / 3 2 + (3 / 3) (2 + 3) / 3 +3.0000 3.0000 1.6667 +create or replace view v1 as select 2 + 3 DIV 3, 2 + (3 DIV 3), (2 + 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 DIV 3 AS `2 + 3 DIV 3`,2 + 3 DIV 3 AS `2 + (3 DIV 3)`,(2 + 3) DIV 3 AS `(2 + 3) DIV 3` +select 2 + 3 DIV 3, 2 + (3 DIV 3), (2 + 3) DIV 3 union select * from v1; +2 + 3 DIV 3 2 + (3 DIV 3) (2 + 3) DIV 3 +3 3 1 +create or replace view v1 as select 2 + 1 MOD 3, 2 + (1 MOD 3), (2 + 1) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 1 % 3 AS `2 + 1 MOD 3`,2 + 1 % 3 AS `2 + (1 MOD 3)`,(2 + 1) % 3 AS `(2 + 1) MOD 3` +select 2 + 1 MOD 3, 2 + (1 MOD 3), (2 + 1) MOD 3 union select * from v1; +2 + 1 MOD 3 2 + (1 MOD 3) (2 + 1) MOD 3 +3 3 0 +create or replace view v1 as select 2 + 1 % 3, 2 + (1 % 3), (2 + 1) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 1 % 3 AS `2 + 1 % 3`,2 + 1 % 3 AS `2 + (1 % 3)`,(2 + 1) % 3 AS `(2 + 1) % 3` +select 2 + 1 % 3, 2 + (1 % 3), (2 + 1) % 3 union select * from v1; +2 + 1 % 3 2 + (1 % 3) (2 + 1) % 3 +3 3 0 +create or replace view v1 as select 2 + 3 ^ 3, 2 + (3 ^ 3), (2 + 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 ^ 3 AS `2 + 3 ^ 3`,2 + 3 ^ 3 AS `2 + (3 ^ 3)`,(2 + 3) ^ 3 AS `(2 + 3) ^ 3` +select 2 + 3 ^ 3, 2 + (3 ^ 3), (2 + 3) ^ 3 union select * from v1; +2 + 3 ^ 3 2 + (3 ^ 3) (2 + 3) ^ 3 +2 2 6 +create or replace view v1 as select 2 + 3 BETWEEN 1 AND 3, 2 + (3 BETWEEN 1 AND 3), (2 + 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 between 1 and 3 AS `2 + 3 BETWEEN 1 AND 3`,2 + (3 between 1 and 3) AS `2 + (3 BETWEEN 1 AND 3)`,2 + 3 between 1 and 3 AS `(2 + 3) BETWEEN 1 AND 3` +select 2 + 3 BETWEEN 1 AND 3, 2 + (3 BETWEEN 1 AND 3), (2 + 3) BETWEEN 1 AND 3 union select * from v1; +2 + 3 BETWEEN 1 AND 3 2 + (3 BETWEEN 1 AND 3) (2 + 3) BETWEEN 1 AND 3 +0 3 0 +create or replace view v1 as select 2 - 3 IS FALSE, 2 - (3 IS FALSE), (2 - 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 is false AS `2 - 3 IS FALSE`,2 - (3 is false) AS `2 - (3 IS FALSE)`,2 - 3 is false AS `(2 - 3) IS FALSE` +select 2 - 3 IS FALSE, 2 - (3 IS FALSE), (2 - 3) IS FALSE union select * from v1; +2 - 3 IS FALSE 2 - (3 IS FALSE) (2 - 3) IS FALSE +0 2 0 +create or replace view v1 as select charset(2 - 3 COLLATE latin1_bin), charset(2 - (3 COLLATE latin1_bin)), charset((2 - 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 - 3 collate latin1_bin) AS `charset(2 - 3 COLLATE latin1_bin)`,charset(2 - 3 collate latin1_bin) AS `charset(2 - (3 COLLATE latin1_bin))`,charset((2 - 3) collate latin1_bin) AS `charset((2 - 3) COLLATE latin1_bin)` +select charset(2 - 3 COLLATE latin1_bin), charset(2 - (3 COLLATE latin1_bin)), charset((2 - 3) COLLATE latin1_bin) union select * from v1; +charset(2 - 3 COLLATE latin1_bin) charset(2 - (3 COLLATE latin1_bin)) charset((2 - 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 - 3 IN (0,1), 2 - (3 IN (0,1)), (2 - 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 in (0,1) AS `2 - 3 IN (0,1)`,2 - (3 in (0,1)) AS `2 - (3 IN (0,1))`,2 - 3 in (0,1) AS `(2 - 3) IN (0,1)` +select 2 - 3 IN (0,1), 2 - (3 IN (0,1)), (2 - 3) IN (0,1) union select * from v1; +2 - 3 IN (0,1) 2 - (3 IN (0,1)) (2 - 3) IN (0,1) +0 2 0 +create or replace view v1 as select 2 - 2 OR 0, 2 - (2 OR 0), (2 - 2) OR 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 2 or 0 AS `2 - 2 OR 0`,2 - (2 or 0) AS `2 - (2 OR 0)`,2 - 2 or 0 AS `(2 - 2) OR 0` +select 2 - 2 OR 0, 2 - (2 OR 0), (2 - 2) OR 0 union select * from v1; +2 - 2 OR 0 2 - (2 OR 0) (2 - 2) OR 0 +0 1 0 +create or replace view v1 as select 2 - 2 || 0, 2 - (2 || 0), (2 - 2) || 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 2 or 0 AS `2 - 2 || 0`,2 - (2 or 0) AS `2 - (2 || 0)`,2 - 2 or 0 AS `(2 - 2) || 0` +select 2 - 2 || 0, 2 - (2 || 0), (2 - 2) || 0 union select * from v1; +2 - 2 || 0 2 - (2 || 0) (2 - 2) || 0 +0 1 0 +create or replace view v1 as select 2 - 3 XOR 3, 2 - (3 XOR 3), (2 - 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 xor 3 AS `2 - 3 XOR 3`,2 - (3 xor 3) AS `2 - (3 XOR 3)`,2 - 3 xor 3 AS `(2 - 3) XOR 3` +select 2 - 3 XOR 3, 2 - (3 XOR 3), (2 - 3) XOR 3 union select * from v1; +2 - 3 XOR 3 2 - (3 XOR 3) (2 - 3) XOR 3 +0 2 0 +create or replace view v1 as select 2 - 2 AND 2, 2 - (2 AND 2), (2 - 2) AND 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 2 and 2 AS `2 - 2 AND 2`,2 - (2 and 2) AS `2 - (2 AND 2)`,2 - 2 and 2 AS `(2 - 2) AND 2` +select 2 - 2 AND 2, 2 - (2 AND 2), (2 - 2) AND 2 union select * from v1; +2 - 2 AND 2 2 - (2 AND 2) (2 - 2) AND 2 +0 1 0 +create or replace view v1 as select 2 - 2 && 2, 2 - (2 && 2), (2 - 2) && 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 2 and 2 AS `2 - 2 && 2`,2 - (2 and 2) AS `2 - (2 && 2)`,2 - 2 and 2 AS `(2 - 2) && 2` +select 2 - 2 && 2, 2 - (2 && 2), (2 - 2) && 2 union select * from v1; +2 - 2 && 2 2 - (2 && 2) (2 - 2) && 2 +0 1 0 +create or replace view v1 as select 2 - 3 = 3, 2 - (3 = 3), (2 - 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 = 3 AS `2 - 3 = 3`,2 - (3 = 3) AS `2 - (3 = 3)`,2 - 3 = 3 AS `(2 - 3) = 3` +select 2 - 3 = 3, 2 - (3 = 3), (2 - 3) = 3 union select * from v1; +2 - 3 = 3 2 - (3 = 3) (2 - 3) = 3 +0 1 0 +create or replace view v1 as select 2 - 3 <=> 3, 2 - (3 <=> 3), (2 - 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 <=> 3 AS `2 - 3 <=> 3`,2 - (3 <=> 3) AS `2 - (3 <=> 3)`,2 - 3 <=> 3 AS `(2 - 3) <=> 3` +select 2 - 3 <=> 3, 2 - (3 <=> 3), (2 - 3) <=> 3 union select * from v1; +2 - 3 <=> 3 2 - (3 <=> 3) (2 - 3) <=> 3 +0 1 0 +create or replace view v1 as select 2 - 3 >= 3, 2 - (3 >= 3), (2 - 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 >= 3 AS `2 - 3 >= 3`,2 - (3 >= 3) AS `2 - (3 >= 3)`,2 - 3 >= 3 AS `(2 - 3) >= 3` +select 2 - 3 >= 3, 2 - (3 >= 3), (2 - 3) >= 3 union select * from v1; +2 - 3 >= 3 2 - (3 >= 3) (2 - 3) >= 3 +0 1 0 +create or replace view v1 as select 2 - 3 <= 2, 2 - (3 <= 2), (2 - 3) <= 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 <= 2 AS `2 - 3 <= 2`,2 - (3 <= 2) AS `2 - (3 <= 2)`,2 - 3 <= 2 AS `(2 - 3) <= 2` +select 2 - 3 <= 2, 2 - (3 <= 2), (2 - 3) <= 2 union select * from v1; +2 - 3 <= 2 2 - (3 <= 2) (2 - 3) <= 2 +1 2 1 +create or replace view v1 as select 2 - 3 < 3, 2 - (3 < 3), (2 - 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 < 3 AS `2 - 3 < 3`,2 - (3 < 3) AS `2 - (3 < 3)`,2 - 3 < 3 AS `(2 - 3) < 3` +select 2 - 3 < 3, 2 - (3 < 3), (2 - 3) < 3 union select * from v1; +2 - 3 < 3 2 - (3 < 3) (2 - 3) < 3 +1 2 1 +create or replace view v1 as select 2 - 3 <> 3, 2 - (3 <> 3), (2 - 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 <> 3 AS `2 - 3 <> 3`,2 - (3 <> 3) AS `2 - (3 <> 3)`,2 - 3 <> 3 AS `(2 - 3) <> 3` +select 2 - 3 <> 3, 2 - (3 <> 3), (2 - 3) <> 3 union select * from v1; +2 - 3 <> 3 2 - (3 <> 3) (2 - 3) <> 3 +1 2 1 +create or replace view v1 as select 2 - 3 > 3, 2 - (3 > 3), (2 - 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 > 3 AS `2 - 3 > 3`,2 - (3 > 3) AS `2 - (3 > 3)`,2 - 3 > 3 AS `(2 - 3) > 3` +select 2 - 3 > 3, 2 - (3 > 3), (2 - 3) > 3 union select * from v1; +2 - 3 > 3 2 - (3 > 3) (2 - 3) > 3 +0 2 0 +create or replace view v1 as select 2 - 3 != 3, 2 - (3 != 3), (2 - 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 <> 3 AS `2 - 3 != 3`,2 - (3 <> 3) AS `2 - (3 != 3)`,2 - 3 <> 3 AS `(2 - 3) != 3` +select 2 - 3 != 3, 2 - (3 != 3), (2 - 3) != 3 union select * from v1; +2 - 3 != 3 2 - (3 != 3) (2 - 3) != 3 +1 2 1 +create or replace view v1 as select 2 - 3 LIKE 3, 2 - (3 LIKE 3), (2 - 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 like 3 AS `2 - 3 LIKE 3`,2 - (3 like 3) AS `2 - (3 LIKE 3)`,2 - 3 like 3 AS `(2 - 3) LIKE 3` +select 2 - 3 LIKE 3, 2 - (3 LIKE 3), (2 - 3) LIKE 3 union select * from v1; +2 - 3 LIKE 3 2 - (3 LIKE 3) (2 - 3) LIKE 3 +0 1 0 +create or replace view v1 as select 2 - 3 REGEXP 3, 2 - (3 REGEXP 3), (2 - 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 regexp 3 AS `2 - 3 REGEXP 3`,2 - (3 regexp 3) AS `2 - (3 REGEXP 3)`,2 - 3 regexp 3 AS `(2 - 3) REGEXP 3` +select 2 - 3 REGEXP 3, 2 - (3 REGEXP 3), (2 - 3) REGEXP 3 union select * from v1; +2 - 3 REGEXP 3 2 - (3 REGEXP 3) (2 - 3) REGEXP 3 +0 1 0 +create or replace view v1 as select 2 - 0 | 1, 2 - (0 | 1), (2 - 0) | 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 0 | 1 AS `2 - 0 | 1`,2 - (0 | 1) AS `2 - (0 | 1)`,2 - 0 | 1 AS `(2 - 0) | 1` +select 2 - 0 | 1, 2 - (0 | 1), (2 - 0) | 1 union select * from v1; +2 - 0 | 1 2 - (0 | 1) (2 - 0) | 1 +3 1 3 +create or replace view v1 as select 2 - 1 & 2, 2 - (1 & 2), (2 - 1) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 1 & 2 AS `2 - 1 & 2`,2 - (1 & 2) AS `2 - (1 & 2)`,2 - 1 & 2 AS `(2 - 1) & 2` +select 2 - 1 & 2, 2 - (1 & 2), (2 - 1) & 2 union select * from v1; +2 - 1 & 2 2 - (1 & 2) (2 - 1) & 2 +0 2 0 +create or replace view v1 as select 2 - 1 << 1, 2 - (1 << 1), (2 - 1) << 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 1 << 1 AS `2 - 1 << 1`,2 - (1 << 1) AS `2 - (1 << 1)`,2 - 1 << 1 AS `(2 - 1) << 1` +select 2 - 1 << 1, 2 - (1 << 1), (2 - 1) << 1 union select * from v1; +2 - 1 << 1 2 - (1 << 1) (2 - 1) << 1 +2 0 2 +create or replace view v1 as select 2 - 3 >> 3, 2 - (3 >> 3), (2 - 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 >> 3 AS `2 - 3 >> 3`,2 - (3 >> 3) AS `2 - (3 >> 3)`,2 - 3 >> 3 AS `(2 - 3) >> 3` +select 2 - 3 >> 3, 2 - (3 >> 3), (2 - 3) >> 3 union select * from v1; +2 - 3 >> 3 2 - (3 >> 3) (2 - 3) >> 3 +2305843009213693951 2 2305843009213693951 +create or replace view v1 as select 2 - '2000-01-01' +INTERVAL 1 DAY, 2 - ('2000-01-01' +INTERVAL 1 DAY), (2 - '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - '2000-01-01' + interval 1 day AS `2 - '2000-01-01' +INTERVAL 1 DAY`,2 - ('2000-01-01' + interval 1 day) AS `2 - ('2000-01-01' +INTERVAL 1 DAY)`,2 - '2000-01-01' + interval 1 day AS `(2 - '2000-01-01') +INTERVAL 1 DAY` +select 2 - '2000-01-01' +INTERVAL 1 DAY, 2 - ('2000-01-01' +INTERVAL 1 DAY), (2 - '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 - '2000-01-01' +INTERVAL 1 DAY 2 - ('2000-01-01' +INTERVAL 1 DAY) (2 - '2000-01-01') +INTERVAL 1 DAY +NULL -20000100 NULL +create or replace view v1 as select 2 - 3 + 3, 2 - (3 + 3), (2 - 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 + 3 AS `2 - 3 + 3`,2 - (3 + 3) AS `2 - (3 + 3)`,2 - 3 + 3 AS `(2 - 3) + 3` +select 2 - 3 + 3, 2 - (3 + 3), (2 - 3) + 3 union select * from v1; +2 - 3 + 3 2 - (3 + 3) (2 - 3) + 3 +2 -4 2 +create or replace view v1 as select 2 - 3 - 3, 2 - (3 - 3), (2 - 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 - 3 AS `2 - 3 - 3`,2 - (3 - 3) AS `2 - (3 - 3)`,2 - 3 - 3 AS `(2 - 3) - 3` +select 2 - 3 - 3, 2 - (3 - 3), (2 - 3) - 3 union select * from v1; +2 - 3 - 3 2 - (3 - 3) (2 - 3) - 3 +-4 2 -4 +create or replace view v1 as select 2 - 3 * 3, 2 - (3 * 3), (2 - 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 * 3 AS `2 - 3 * 3`,2 - 3 * 3 AS `2 - (3 * 3)`,(2 - 3) * 3 AS `(2 - 3) * 3` +select 2 - 3 * 3, 2 - (3 * 3), (2 - 3) * 3 union select * from v1; +2 - 3 * 3 2 - (3 * 3) (2 - 3) * 3 +-7 -7 -3 +create or replace view v1 as select 2 - 3 / 3, 2 - (3 / 3), (2 - 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 / 3 AS `2 - 3 / 3`,2 - 3 / 3 AS `2 - (3 / 3)`,(2 - 3) / 3 AS `(2 - 3) / 3` +select 2 - 3 / 3, 2 - (3 / 3), (2 - 3) / 3 union select * from v1; +2 - 3 / 3 2 - (3 / 3) (2 - 3) / 3 +1.0000 1.0000 -0.3333 +create or replace view v1 as select 2 - 3 DIV 3, 2 - (3 DIV 3), (2 - 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 DIV 3 AS `2 - 3 DIV 3`,2 - 3 DIV 3 AS `2 - (3 DIV 3)`,(2 - 3) DIV 3 AS `(2 - 3) DIV 3` +select 2 - 3 DIV 3, 2 - (3 DIV 3), (2 - 3) DIV 3 union select * from v1; +2 - 3 DIV 3 2 - (3 DIV 3) (2 - 3) DIV 3 +1 1 0 +create or replace view v1 as select 2 - 3 MOD 3, 2 - (3 MOD 3), (2 - 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 % 3 AS `2 - 3 MOD 3`,2 - 3 % 3 AS `2 - (3 MOD 3)`,(2 - 3) % 3 AS `(2 - 3) MOD 3` +select 2 - 3 MOD 3, 2 - (3 MOD 3), (2 - 3) MOD 3 union select * from v1; +2 - 3 MOD 3 2 - (3 MOD 3) (2 - 3) MOD 3 +2 2 -1 +create or replace view v1 as select 2 - 3 % 3, 2 - (3 % 3), (2 - 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 % 3 AS `2 - 3 % 3`,2 - 3 % 3 AS `2 - (3 % 3)`,(2 - 3) % 3 AS `(2 - 3) % 3` +select 2 - 3 % 3, 2 - (3 % 3), (2 - 3) % 3 union select * from v1; +2 - 3 % 3 2 - (3 % 3) (2 - 3) % 3 +2 2 -1 +create or replace view v1 as select 2 - 3 ^ 3, 2 - (3 ^ 3), (2 - 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 ^ 3 AS `2 - 3 ^ 3`,2 - 3 ^ 3 AS `2 - (3 ^ 3)`,(2 - 3) ^ 3 AS `(2 - 3) ^ 3` +select 2 - 3 ^ 3, 2 - (3 ^ 3), (2 - 3) ^ 3 union select * from v1; +2 - 3 ^ 3 2 - (3 ^ 3) (2 - 3) ^ 3 +2 2 18446744073709551612 +create or replace view v1 as select 2 - 3 BETWEEN 1 AND 3, 2 - (3 BETWEEN 1 AND 3), (2 - 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 between 1 and 3 AS `2 - 3 BETWEEN 1 AND 3`,2 - (3 between 1 and 3) AS `2 - (3 BETWEEN 1 AND 3)`,2 - 3 between 1 and 3 AS `(2 - 3) BETWEEN 1 AND 3` +select 2 - 3 BETWEEN 1 AND 3, 2 - (3 BETWEEN 1 AND 3), (2 - 3) BETWEEN 1 AND 3 union select * from v1; +2 - 3 BETWEEN 1 AND 3 2 - (3 BETWEEN 1 AND 3) (2 - 3) BETWEEN 1 AND 3 +0 1 0 +create or replace view v1 as select 2 * 0 IS FALSE, 2 * (0 IS FALSE), (2 * 0) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 0 is false AS `2 * 0 IS FALSE`,2 * (0 is false) AS `2 * (0 IS FALSE)`,2 * 0 is false AS `(2 * 0) IS FALSE` +select 2 * 0 IS FALSE, 2 * (0 IS FALSE), (2 * 0) IS FALSE union select * from v1; +2 * 0 IS FALSE 2 * (0 IS FALSE) (2 * 0) IS FALSE +1 2 1 +create or replace view v1 as select charset(2 * 3 COLLATE latin1_bin), charset(2 * (3 COLLATE latin1_bin)), charset((2 * 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 * 3 collate latin1_bin) AS `charset(2 * 3 COLLATE latin1_bin)`,charset(2 * 3 collate latin1_bin) AS `charset(2 * (3 COLLATE latin1_bin))`,charset((2 * 3) collate latin1_bin) AS `charset((2 * 3) COLLATE latin1_bin)` +select charset(2 * 3 COLLATE latin1_bin), charset(2 * (3 COLLATE latin1_bin)), charset((2 * 3) COLLATE latin1_bin) union select * from v1; +charset(2 * 3 COLLATE latin1_bin) charset(2 * (3 COLLATE latin1_bin)) charset((2 * 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 * 0 IN (0,1), 2 * (0 IN (0,1)), (2 * 0) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 0 in (0,1) AS `2 * 0 IN (0,1)`,2 * (0 in (0,1)) AS `2 * (0 IN (0,1))`,2 * 0 in (0,1) AS `(2 * 0) IN (0,1)` +select 2 * 0 IN (0,1), 2 * (0 IN (0,1)), (2 * 0) IN (0,1) union select * from v1; +2 * 0 IN (0,1) 2 * (0 IN (0,1)) (2 * 0) IN (0,1) +1 2 1 +create or replace view v1 as select 2 * 3 OR 3, 2 * (3 OR 3), (2 * 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 or 3 AS `2 * 3 OR 3`,2 * (3 or 3) AS `2 * (3 OR 3)`,2 * 3 or 3 AS `(2 * 3) OR 3` +select 2 * 3 OR 3, 2 * (3 OR 3), (2 * 3) OR 3 union select * from v1; +2 * 3 OR 3 2 * (3 OR 3) (2 * 3) OR 3 +1 2 1 +create or replace view v1 as select 2 * 3 || 3, 2 * (3 || 3), (2 * 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 or 3 AS `2 * 3 || 3`,2 * (3 or 3) AS `2 * (3 || 3)`,2 * 3 or 3 AS `(2 * 3) || 3` +select 2 * 3 || 3, 2 * (3 || 3), (2 * 3) || 3 union select * from v1; +2 * 3 || 3 2 * (3 || 3) (2 * 3) || 3 +1 2 1 +create or replace view v1 as select 2 * 3 XOR 0, 2 * (3 XOR 0), (2 * 3) XOR 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 xor 0 AS `2 * 3 XOR 0`,2 * (3 xor 0) AS `2 * (3 XOR 0)`,2 * 3 xor 0 AS `(2 * 3) XOR 0` +select 2 * 3 XOR 0, 2 * (3 XOR 0), (2 * 3) XOR 0 union select * from v1; +2 * 3 XOR 0 2 * (3 XOR 0) (2 * 3) XOR 0 +1 2 1 +create or replace view v1 as select 2 * 3 AND 3, 2 * (3 AND 3), (2 * 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 and 3 AS `2 * 3 AND 3`,2 * (3 and 3) AS `2 * (3 AND 3)`,2 * 3 and 3 AS `(2 * 3) AND 3` +select 2 * 3 AND 3, 2 * (3 AND 3), (2 * 3) AND 3 union select * from v1; +2 * 3 AND 3 2 * (3 AND 3) (2 * 3) AND 3 +1 2 1 +create or replace view v1 as select 2 * 3 && 3, 2 * (3 && 3), (2 * 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 and 3 AS `2 * 3 && 3`,2 * (3 and 3) AS `2 * (3 && 3)`,2 * 3 and 3 AS `(2 * 3) && 3` +select 2 * 3 && 3, 2 * (3 && 3), (2 * 3) && 3 union select * from v1; +2 * 3 && 3 2 * (3 && 3) (2 * 3) && 3 +1 2 1 +create or replace view v1 as select 2 * 3 = 3, 2 * (3 = 3), (2 * 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 = 3 AS `2 * 3 = 3`,2 * (3 = 3) AS `2 * (3 = 3)`,2 * 3 = 3 AS `(2 * 3) = 3` +select 2 * 3 = 3, 2 * (3 = 3), (2 * 3) = 3 union select * from v1; +2 * 3 = 3 2 * (3 = 3) (2 * 3) = 3 +0 2 0 +create or replace view v1 as select 2 * 3 <=> 3, 2 * (3 <=> 3), (2 * 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 <=> 3 AS `2 * 3 <=> 3`,2 * (3 <=> 3) AS `2 * (3 <=> 3)`,2 * 3 <=> 3 AS `(2 * 3) <=> 3` +select 2 * 3 <=> 3, 2 * (3 <=> 3), (2 * 3) <=> 3 union select * from v1; +2 * 3 <=> 3 2 * (3 <=> 3) (2 * 3) <=> 3 +0 2 0 +create or replace view v1 as select 2 * 3 >= 3, 2 * (3 >= 3), (2 * 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 >= 3 AS `2 * 3 >= 3`,2 * (3 >= 3) AS `2 * (3 >= 3)`,2 * 3 >= 3 AS `(2 * 3) >= 3` +select 2 * 3 >= 3, 2 * (3 >= 3), (2 * 3) >= 3 union select * from v1; +2 * 3 >= 3 2 * (3 >= 3) (2 * 3) >= 3 +1 2 1 +create or replace view v1 as select 2 * 3 <= 3, 2 * (3 <= 3), (2 * 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 <= 3 AS `2 * 3 <= 3`,2 * (3 <= 3) AS `2 * (3 <= 3)`,2 * 3 <= 3 AS `(2 * 3) <= 3` +select 2 * 3 <= 3, 2 * (3 <= 3), (2 * 3) <= 3 union select * from v1; +2 * 3 <= 3 2 * (3 <= 3) (2 * 3) <= 3 +0 2 0 +create or replace view v1 as select 2 * 0 < 3, 2 * (0 < 3), (2 * 0) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 0 < 3 AS `2 * 0 < 3`,2 * (0 < 3) AS `2 * (0 < 3)`,2 * 0 < 3 AS `(2 * 0) < 3` +select 2 * 0 < 3, 2 * (0 < 3), (2 * 0) < 3 union select * from v1; +2 * 0 < 3 2 * (0 < 3) (2 * 0) < 3 +1 2 1 +create or replace view v1 as select 2 * 3 <> 3, 2 * (3 <> 3), (2 * 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 <> 3 AS `2 * 3 <> 3`,2 * (3 <> 3) AS `2 * (3 <> 3)`,2 * 3 <> 3 AS `(2 * 3) <> 3` +select 2 * 3 <> 3, 2 * (3 <> 3), (2 * 3) <> 3 union select * from v1; +2 * 3 <> 3 2 * (3 <> 3) (2 * 3) <> 3 +1 0 1 +create or replace view v1 as select 2 * 3 > 3, 2 * (3 > 3), (2 * 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 > 3 AS `2 * 3 > 3`,2 * (3 > 3) AS `2 * (3 > 3)`,2 * 3 > 3 AS `(2 * 3) > 3` +select 2 * 3 > 3, 2 * (3 > 3), (2 * 3) > 3 union select * from v1; +2 * 3 > 3 2 * (3 > 3) (2 * 3) > 3 +1 0 1 +create or replace view v1 as select 2 * 3 != 3, 2 * (3 != 3), (2 * 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 <> 3 AS `2 * 3 != 3`,2 * (3 <> 3) AS `2 * (3 != 3)`,2 * 3 <> 3 AS `(2 * 3) != 3` +select 2 * 3 != 3, 2 * (3 != 3), (2 * 3) != 3 union select * from v1; +2 * 3 != 3 2 * (3 != 3) (2 * 3) != 3 +1 0 1 +create or replace view v1 as select 2 * 3 LIKE 3, 2 * (3 LIKE 3), (2 * 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 like 3 AS `2 * 3 LIKE 3`,2 * (3 like 3) AS `2 * (3 LIKE 3)`,2 * 3 like 3 AS `(2 * 3) LIKE 3` +select 2 * 3 LIKE 3, 2 * (3 LIKE 3), (2 * 3) LIKE 3 union select * from v1; +2 * 3 LIKE 3 2 * (3 LIKE 3) (2 * 3) LIKE 3 +0 2 0 +create or replace view v1 as select 2 * 3 REGEXP 3, 2 * (3 REGEXP 3), (2 * 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 regexp 3 AS `2 * 3 REGEXP 3`,2 * (3 regexp 3) AS `2 * (3 REGEXP 3)`,2 * 3 regexp 3 AS `(2 * 3) REGEXP 3` +select 2 * 3 REGEXP 3, 2 * (3 REGEXP 3), (2 * 3) REGEXP 3 union select * from v1; +2 * 3 REGEXP 3 2 * (3 REGEXP 3) (2 * 3) REGEXP 3 +0 2 0 +create or replace view v1 as select 2 * 3 | 3, 2 * (3 | 3), (2 * 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 | 3 AS `2 * 3 | 3`,2 * (3 | 3) AS `2 * (3 | 3)`,2 * 3 | 3 AS `(2 * 3) | 3` +select 2 * 3 | 3, 2 * (3 | 3), (2 * 3) | 3 union select * from v1; +2 * 3 | 3 2 * (3 | 3) (2 * 3) | 3 +7 6 7 +create or replace view v1 as select 2 * 3 & 3, 2 * (3 & 3), (2 * 3) & 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 & 3 AS `2 * 3 & 3`,2 * (3 & 3) AS `2 * (3 & 3)`,2 * 3 & 3 AS `(2 * 3) & 3` +select 2 * 3 & 3, 2 * (3 & 3), (2 * 3) & 3 union select * from v1; +2 * 3 & 3 2 * (3 & 3) (2 * 3) & 3 +2 6 2 +create or replace view v1 as select 2 * 3 >> 2, 2 * (3 >> 2), (2 * 3) >> 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 >> 2 AS `2 * 3 >> 2`,2 * (3 >> 2) AS `2 * (3 >> 2)`,2 * 3 >> 2 AS `(2 * 3) >> 2` +select 2 * 3 >> 2, 2 * (3 >> 2), (2 * 3) >> 2 union select * from v1; +2 * 3 >> 2 2 * (3 >> 2) (2 * 3) >> 2 +1 0 1 +create or replace view v1 as select 2 * '2000-01-01' +INTERVAL 1 DAY, 2 * ('2000-01-01' +INTERVAL 1 DAY), (2 * '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * '2000-01-01' + interval 1 day AS `2 * '2000-01-01' +INTERVAL 1 DAY`,2 * ('2000-01-01' + interval 1 day) AS `2 * ('2000-01-01' +INTERVAL 1 DAY)`,2 * '2000-01-01' + interval 1 day AS `(2 * '2000-01-01') +INTERVAL 1 DAY` +select 2 * '2000-01-01' +INTERVAL 1 DAY, 2 * ('2000-01-01' +INTERVAL 1 DAY), (2 * '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 * '2000-01-01' +INTERVAL 1 DAY 2 * ('2000-01-01' +INTERVAL 1 DAY) (2 * '2000-01-01') +INTERVAL 1 DAY +NULL 40000204 NULL +create or replace view v1 as select 2 * 3 + 3, 2 * (3 + 3), (2 * 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 + 3 AS `2 * 3 + 3`,2 * (3 + 3) AS `2 * (3 + 3)`,2 * 3 + 3 AS `(2 * 3) + 3` +select 2 * 3 + 3, 2 * (3 + 3), (2 * 3) + 3 union select * from v1; +2 * 3 + 3 2 * (3 + 3) (2 * 3) + 3 +9 12 9 +create or replace view v1 as select 2 * 3 - 3, 2 * (3 - 3), (2 * 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 - 3 AS `2 * 3 - 3`,2 * (3 - 3) AS `2 * (3 - 3)`,2 * 3 - 3 AS `(2 * 3) - 3` +select 2 * 3 - 3, 2 * (3 - 3), (2 * 3) - 3 union select * from v1; +2 * 3 - 3 2 * (3 - 3) (2 * 3) - 3 +3 0 3 +create or replace view v1 as select 2 * 3 DIV 2, 2 * (3 DIV 2), (2 * 3) DIV 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 DIV 2 AS `2 * 3 DIV 2`,2 * (3 DIV 2) AS `2 * (3 DIV 2)`,2 * 3 DIV 2 AS `(2 * 3) DIV 2` +select 2 * 3 DIV 2, 2 * (3 DIV 2), (2 * 3) DIV 2 union select * from v1; +2 * 3 DIV 2 2 * (3 DIV 2) (2 * 3) DIV 2 +3 2 3 +create or replace view v1 as select 2 * 3 MOD 2, 2 * (3 MOD 2), (2 * 3) MOD 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 % 2 AS `2 * 3 MOD 2`,2 * (3 % 2) AS `2 * (3 MOD 2)`,2 * 3 % 2 AS `(2 * 3) MOD 2` +select 2 * 3 MOD 2, 2 * (3 MOD 2), (2 * 3) MOD 2 union select * from v1; +2 * 3 MOD 2 2 * (3 MOD 2) (2 * 3) MOD 2 +0 2 0 +create or replace view v1 as select 2 * 3 % 2, 2 * (3 % 2), (2 * 3) % 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 % 2 AS `2 * 3 % 2`,2 * (3 % 2) AS `2 * (3 % 2)`,2 * 3 % 2 AS `(2 * 3) % 2` +select 2 * 3 % 2, 2 * (3 % 2), (2 * 3) % 2 union select * from v1; +2 * 3 % 2 2 * (3 % 2) (2 * 3) % 2 +0 2 0 +create or replace view v1 as select 2 * 3 ^ 3, 2 * (3 ^ 3), (2 * 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 ^ 3 AS `2 * 3 ^ 3`,2 * 3 ^ 3 AS `2 * (3 ^ 3)`,(2 * 3) ^ 3 AS `(2 * 3) ^ 3` +select 2 * 3 ^ 3, 2 * (3 ^ 3), (2 * 3) ^ 3 union select * from v1; +2 * 3 ^ 3 2 * (3 ^ 3) (2 * 3) ^ 3 +0 0 5 +create or replace view v1 as select 2 * 3 BETWEEN 1 AND 3, 2 * (3 BETWEEN 1 AND 3), (2 * 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 3 between 1 and 3 AS `2 * 3 BETWEEN 1 AND 3`,2 * (3 between 1 and 3) AS `2 * (3 BETWEEN 1 AND 3)`,2 * 3 between 1 and 3 AS `(2 * 3) BETWEEN 1 AND 3` +select 2 * 3 BETWEEN 1 AND 3, 2 * (3 BETWEEN 1 AND 3), (2 * 3) BETWEEN 1 AND 3 union select * from v1; +2 * 3 BETWEEN 1 AND 3 2 * (3 BETWEEN 1 AND 3) (2 * 3) BETWEEN 1 AND 3 +0 2 0 +create or replace view v1 as select 2 / 3 IS FALSE, 2 / (3 IS FALSE), (2 / 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 is false AS `2 / 3 IS FALSE`,2 / (3 is false) AS `2 / (3 IS FALSE)`,2 / 3 is false AS `(2 / 3) IS FALSE` +select 2 / 3 IS FALSE, 2 / (3 IS FALSE), (2 / 3) IS FALSE union select * from v1; +2 / 3 IS FALSE 2 / (3 IS FALSE) (2 / 3) IS FALSE +0 NULL 0 +create or replace view v1 as select charset(2 / 3 COLLATE latin1_bin), charset(2 / (3 COLLATE latin1_bin)), charset((2 / 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 / 3 collate latin1_bin) AS `charset(2 / 3 COLLATE latin1_bin)`,charset(2 / 3 collate latin1_bin) AS `charset(2 / (3 COLLATE latin1_bin))`,charset((2 / 3) collate latin1_bin) AS `charset((2 / 3) COLLATE latin1_bin)` +select charset(2 / 3 COLLATE latin1_bin), charset(2 / (3 COLLATE latin1_bin)), charset((2 / 3) COLLATE latin1_bin) union select * from v1; +charset(2 / 3 COLLATE latin1_bin) charset(2 / (3 COLLATE latin1_bin)) charset((2 / 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 / 3 IN (0,1), 2 / (3 IN (0,1)), (2 / 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 in (0,1) AS `2 / 3 IN (0,1)`,2 / (3 in (0,1)) AS `2 / (3 IN (0,1))`,2 / 3 in (0,1) AS `(2 / 3) IN (0,1)` +select 2 / 3 IN (0,1), 2 / (3 IN (0,1)), (2 / 3) IN (0,1) union select * from v1; +2 / 3 IN (0,1) 2 / (3 IN (0,1)) (2 / 3) IN (0,1) +0 NULL 0 +create or replace view v1 as select 2 / 3 OR 3, 2 / (3 OR 3), (2 / 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 or 3 AS `2 / 3 OR 3`,2 / (3 or 3) AS `2 / (3 OR 3)`,2 / 3 or 3 AS `(2 / 3) OR 3` +select 2 / 3 OR 3, 2 / (3 OR 3), (2 / 3) OR 3 union select * from v1; +2 / 3 OR 3 2 / (3 OR 3) (2 / 3) OR 3 +1 2.0000 1 +create or replace view v1 as select 2 / 3 || 3, 2 / (3 || 3), (2 / 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 or 3 AS `2 / 3 || 3`,2 / (3 or 3) AS `2 / (3 || 3)`,2 / 3 or 3 AS `(2 / 3) || 3` +select 2 / 3 || 3, 2 / (3 || 3), (2 / 3) || 3 union select * from v1; +2 / 3 || 3 2 / (3 || 3) (2 / 3) || 3 +1 2.0000 1 +create or replace view v1 as select 2 / 3 XOR 3, 2 / (3 XOR 3), (2 / 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 xor 3 AS `2 / 3 XOR 3`,2 / (3 xor 3) AS `2 / (3 XOR 3)`,2 / 3 xor 3 AS `(2 / 3) XOR 3` +select 2 / 3 XOR 3, 2 / (3 XOR 3), (2 / 3) XOR 3 union select * from v1; +2 / 3 XOR 3 2 / (3 XOR 3) (2 / 3) XOR 3 +0 NULL 0 +create or replace view v1 as select 2 / 3 AND 3, 2 / (3 AND 3), (2 / 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 and 3 AS `2 / 3 AND 3`,2 / (3 and 3) AS `2 / (3 AND 3)`,2 / 3 and 3 AS `(2 / 3) AND 3` +select 2 / 3 AND 3, 2 / (3 AND 3), (2 / 3) AND 3 union select * from v1; +2 / 3 AND 3 2 / (3 AND 3) (2 / 3) AND 3 +1 2.0000 1 +create or replace view v1 as select 2 / 3 && 3, 2 / (3 && 3), (2 / 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 and 3 AS `2 / 3 && 3`,2 / (3 and 3) AS `2 / (3 && 3)`,2 / 3 and 3 AS `(2 / 3) && 3` +select 2 / 3 && 3, 2 / (3 && 3), (2 / 3) && 3 union select * from v1; +2 / 3 && 3 2 / (3 && 3) (2 / 3) && 3 +1 2.0000 1 +create or replace view v1 as select 2 / 3 = 3, 2 / (3 = 3), (2 / 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 = 3 AS `2 / 3 = 3`,2 / (3 = 3) AS `2 / (3 = 3)`,2 / 3 = 3 AS `(2 / 3) = 3` +select 2 / 3 = 3, 2 / (3 = 3), (2 / 3) = 3 union select * from v1; +2 / 3 = 3 2 / (3 = 3) (2 / 3) = 3 +0 2.0000 0 +create or replace view v1 as select 2 / 3 <=> 3, 2 / (3 <=> 3), (2 / 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 <=> 3 AS `2 / 3 <=> 3`,2 / (3 <=> 3) AS `2 / (3 <=> 3)`,2 / 3 <=> 3 AS `(2 / 3) <=> 3` +select 2 / 3 <=> 3, 2 / (3 <=> 3), (2 / 3) <=> 3 union select * from v1; +2 / 3 <=> 3 2 / (3 <=> 3) (2 / 3) <=> 3 +0 2.0000 0 +create or replace view v1 as select 2 / 3 >= 3, 2 / (3 >= 3), (2 / 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 >= 3 AS `2 / 3 >= 3`,2 / (3 >= 3) AS `2 / (3 >= 3)`,2 / 3 >= 3 AS `(2 / 3) >= 3` +select 2 / 3 >= 3, 2 / (3 >= 3), (2 / 3) >= 3 union select * from v1; +2 / 3 >= 3 2 / (3 >= 3) (2 / 3) >= 3 +0 2.0000 0 +create or replace view v1 as select 2 / 3 <= 3, 2 / (3 <= 3), (2 / 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 <= 3 AS `2 / 3 <= 3`,2 / (3 <= 3) AS `2 / (3 <= 3)`,2 / 3 <= 3 AS `(2 / 3) <= 3` +select 2 / 3 <= 3, 2 / (3 <= 3), (2 / 3) <= 3 union select * from v1; +2 / 3 <= 3 2 / (3 <= 3) (2 / 3) <= 3 +1 2.0000 1 +create or replace view v1 as select 2 / 3 < 3, 2 / (3 < 3), (2 / 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 < 3 AS `2 / 3 < 3`,2 / (3 < 3) AS `2 / (3 < 3)`,2 / 3 < 3 AS `(2 / 3) < 3` +select 2 / 3 < 3, 2 / (3 < 3), (2 / 3) < 3 union select * from v1; +2 / 3 < 3 2 / (3 < 3) (2 / 3) < 3 +1 NULL 1 +create or replace view v1 as select 2 / 3 <> 3, 2 / (3 <> 3), (2 / 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 <> 3 AS `2 / 3 <> 3`,2 / (3 <> 3) AS `2 / (3 <> 3)`,2 / 3 <> 3 AS `(2 / 3) <> 3` +select 2 / 3 <> 3, 2 / (3 <> 3), (2 / 3) <> 3 union select * from v1; +2 / 3 <> 3 2 / (3 <> 3) (2 / 3) <> 3 +1 NULL 1 +create or replace view v1 as select 2 / 3 > 3, 2 / (3 > 3), (2 / 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 > 3 AS `2 / 3 > 3`,2 / (3 > 3) AS `2 / (3 > 3)`,2 / 3 > 3 AS `(2 / 3) > 3` +select 2 / 3 > 3, 2 / (3 > 3), (2 / 3) > 3 union select * from v1; +2 / 3 > 3 2 / (3 > 3) (2 / 3) > 3 +0 NULL 0 +create or replace view v1 as select 2 / 3 != 3, 2 / (3 != 3), (2 / 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 <> 3 AS `2 / 3 != 3`,2 / (3 <> 3) AS `2 / (3 != 3)`,2 / 3 <> 3 AS `(2 / 3) != 3` +select 2 / 3 != 3, 2 / (3 != 3), (2 / 3) != 3 union select * from v1; +2 / 3 != 3 2 / (3 != 3) (2 / 3) != 3 +1 NULL 1 +create or replace view v1 as select 2 / 3 LIKE 3, 2 / (3 LIKE 3), (2 / 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 like 3 AS `2 / 3 LIKE 3`,2 / (3 like 3) AS `2 / (3 LIKE 3)`,2 / 3 like 3 AS `(2 / 3) LIKE 3` +select 2 / 3 LIKE 3, 2 / (3 LIKE 3), (2 / 3) LIKE 3 union select * from v1; +2 / 3 LIKE 3 2 / (3 LIKE 3) (2 / 3) LIKE 3 +0 2.0000 0 +create or replace view v1 as select 2 / 3 REGEXP 3, 2 / (3 REGEXP 3), (2 / 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 regexp 3 AS `2 / 3 REGEXP 3`,2 / (3 regexp 3) AS `2 / (3 REGEXP 3)`,2 / 3 regexp 3 AS `(2 / 3) REGEXP 3` +select 2 / 3 REGEXP 3, 2 / (3 REGEXP 3), (2 / 3) REGEXP 3 union select * from v1; +2 / 3 REGEXP 3 2 / (3 REGEXP 3) (2 / 3) REGEXP 3 +0 2.0000 0 +create or replace view v1 as select 2 / 3 | 3, 2 / (3 | 3), (2 / 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 | 3 AS `2 / 3 | 3`,2 / (3 | 3) AS `2 / (3 | 3)`,2 / 3 | 3 AS `(2 / 3) | 3` +select 2 / 3 | 3, 2 / (3 | 3), (2 / 3) | 3 union select * from v1; +2 / 3 | 3 2 / (3 | 3) (2 / 3) | 3 +3 0.6667 3 +create or replace view v1 as select 2 / 3 & 3, 2 / (3 & 3), (2 / 3) & 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 & 3 AS `2 / 3 & 3`,2 / (3 & 3) AS `2 / (3 & 3)`,2 / 3 & 3 AS `(2 / 3) & 3` +select 2 / 3 & 3, 2 / (3 & 3), (2 / 3) & 3 union select * from v1; +2 / 3 & 3 2 / (3 & 3) (2 / 3) & 3 +1 0.6667 1 +create or replace view v1 as select 2 / 3 << 3, 2 / (3 << 3), (2 / 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 << 3 AS `2 / 3 << 3`,2 / (3 << 3) AS `2 / (3 << 3)`,2 / 3 << 3 AS `(2 / 3) << 3` +select 2 / 3 << 3, 2 / (3 << 3), (2 / 3) << 3 union select * from v1; +2 / 3 << 3 2 / (3 << 3) (2 / 3) << 3 +8 0.0833 8 +create or replace view v1 as select 2 / 3 >> 3, 2 / (3 >> 3), (2 / 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 >> 3 AS `2 / 3 >> 3`,2 / (3 >> 3) AS `2 / (3 >> 3)`,2 / 3 >> 3 AS `(2 / 3) >> 3` +select 2 / 3 >> 3, 2 / (3 >> 3), (2 / 3) >> 3 union select * from v1; +2 / 3 >> 3 2 / (3 >> 3) (2 / 3) >> 3 +0 NULL 0 +create or replace view v1 as select 2 / '2000-01-01' +INTERVAL 1 DAY, 2 / ('2000-01-01' +INTERVAL 1 DAY), (2 / '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / '2000-01-01' + interval 1 day AS `2 / '2000-01-01' +INTERVAL 1 DAY`,2 / ('2000-01-01' + interval 1 day) AS `2 / ('2000-01-01' +INTERVAL 1 DAY)`,2 / '2000-01-01' + interval 1 day AS `(2 / '2000-01-01') +INTERVAL 1 DAY` +select 2 / '2000-01-01' +INTERVAL 1 DAY, 2 / ('2000-01-01' +INTERVAL 1 DAY), (2 / '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 / '2000-01-01' +INTERVAL 1 DAY 2 / ('2000-01-01' +INTERVAL 1 DAY) (2 / '2000-01-01') +INTERVAL 1 DAY +NULL 0.0000 NULL +NULL 0.0000 NULL +create or replace view v1 as select 2 / 3 + 3, 2 / (3 + 3), (2 / 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 + 3 AS `2 / 3 + 3`,2 / (3 + 3) AS `2 / (3 + 3)`,2 / 3 + 3 AS `(2 / 3) + 3` +select 2 / 3 + 3, 2 / (3 + 3), (2 / 3) + 3 union select * from v1; +2 / 3 + 3 2 / (3 + 3) (2 / 3) + 3 +3.6667 0.3333 3.6667 +create or replace view v1 as select 2 / 3 - 3, 2 / (3 - 3), (2 / 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 - 3 AS `2 / 3 - 3`,2 / (3 - 3) AS `2 / (3 - 3)`,2 / 3 - 3 AS `(2 / 3) - 3` +select 2 / 3 - 3, 2 / (3 - 3), (2 / 3) - 3 union select * from v1; +2 / 3 - 3 2 / (3 - 3) (2 / 3) - 3 +-2.3333 NULL -2.3333 +create or replace view v1 as select 2 / 3 * 3, 2 / (3 * 3), (2 / 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 * 3 AS `2 / 3 * 3`,2 / (3 * 3) AS `2 / (3 * 3)`,2 / 3 * 3 AS `(2 / 3) * 3` +select 2 / 3 * 3, 2 / (3 * 3), (2 / 3) * 3 union select * from v1; +2 / 3 * 3 2 / (3 * 3) (2 / 3) * 3 +2.0001 0.2222 2.0001 +create or replace view v1 as select 2 / 3 / 3, 2 / (3 / 3), (2 / 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 / 3 AS `2 / 3 / 3`,2 / (3 / 3) AS `2 / (3 / 3)`,2 / 3 / 3 AS `(2 / 3) / 3` +select 2 / 3 / 3, 2 / (3 / 3), (2 / 3) / 3 union select * from v1; +2 / 3 / 3 2 / (3 / 3) (2 / 3) / 3 +0.22223333 2.0000 0.22223333 +create or replace view v1 as select 2 / 3 DIV 3, 2 / (3 DIV 3), (2 / 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 DIV 3 AS `2 / 3 DIV 3`,2 / (3 DIV 3) AS `2 / (3 DIV 3)`,2 / 3 DIV 3 AS `(2 / 3) DIV 3` +select 2 / 3 DIV 3, 2 / (3 DIV 3), (2 / 3) DIV 3 union select * from v1; +2 / 3 DIV 3 2 / (3 DIV 3) (2 / 3) DIV 3 +0 2.0000 0 +create or replace view v1 as select 2 / 3 MOD 3, 2 / (3 MOD 3), (2 / 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 % 3 AS `2 / 3 MOD 3`,2 / (3 % 3) AS `2 / (3 MOD 3)`,2 / 3 % 3 AS `(2 / 3) MOD 3` +select 2 / 3 MOD 3, 2 / (3 MOD 3), (2 / 3) MOD 3 union select * from v1; +2 / 3 MOD 3 2 / (3 MOD 3) (2 / 3) MOD 3 +0.6667 NULL 0.6667 +create or replace view v1 as select 2 / 3 % 3, 2 / (3 % 3), (2 / 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 % 3 AS `2 / 3 % 3`,2 / (3 % 3) AS `2 / (3 % 3)`,2 / 3 % 3 AS `(2 / 3) % 3` +select 2 / 3 % 3, 2 / (3 % 3), (2 / 3) % 3 union select * from v1; +2 / 3 % 3 2 / (3 % 3) (2 / 3) % 3 +0.6667 NULL 0.6667 +create or replace view v1 as select 2 / 3 ^ 3, 2 / (3 ^ 3), (2 / 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 ^ 3 AS `2 / 3 ^ 3`,2 / 3 ^ 3 AS `2 / (3 ^ 3)`,(2 / 3) ^ 3 AS `(2 / 3) ^ 3` +select 2 / 3 ^ 3, 2 / (3 ^ 3), (2 / 3) ^ 3 union select * from v1; +2 / 3 ^ 3 2 / (3 ^ 3) (2 / 3) ^ 3 +NULL NULL 2 +create or replace view v1 as select 2 / 3 BETWEEN 1 AND 3, 2 / (3 BETWEEN 1 AND 3), (2 / 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 between 1 and 3 AS `2 / 3 BETWEEN 1 AND 3`,2 / (3 between 1 and 3) AS `2 / (3 BETWEEN 1 AND 3)`,2 / 3 between 1 and 3 AS `(2 / 3) BETWEEN 1 AND 3` +select 2 / 3 BETWEEN 1 AND 3, 2 / (3 BETWEEN 1 AND 3), (2 / 3) BETWEEN 1 AND 3 union select * from v1; +2 / 3 BETWEEN 1 AND 3 2 / (3 BETWEEN 1 AND 3) (2 / 3) BETWEEN 1 AND 3 +0 2.0000 0 +create or replace view v1 as select 2 DIV 3 IS FALSE, 2 DIV (3 IS FALSE), (2 DIV 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 is false AS `2 DIV 3 IS FALSE`,2 DIV (3 is false) AS `2 DIV (3 IS FALSE)`,2 DIV 3 is false AS `(2 DIV 3) IS FALSE` +select 2 DIV 3 IS FALSE, 2 DIV (3 IS FALSE), (2 DIV 3) IS FALSE union select * from v1; +2 DIV 3 IS FALSE 2 DIV (3 IS FALSE) (2 DIV 3) IS FALSE +1 NULL 1 +create or replace view v1 as select charset(2 DIV 3 COLLATE latin1_bin), charset(2 DIV (3 COLLATE latin1_bin)), charset((2 DIV 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 DIV 3 collate latin1_bin) AS `charset(2 DIV 3 COLLATE latin1_bin)`,charset(2 DIV 3 collate latin1_bin) AS `charset(2 DIV (3 COLLATE latin1_bin))`,charset((2 DIV 3) collate latin1_bin) AS `charset((2 DIV 3) COLLATE latin1_bin)` +select charset(2 DIV 3 COLLATE latin1_bin), charset(2 DIV (3 COLLATE latin1_bin)), charset((2 DIV 3) COLLATE latin1_bin) union select * from v1; +charset(2 DIV 3 COLLATE latin1_bin) charset(2 DIV (3 COLLATE latin1_bin)) charset((2 DIV 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 DIV 3 IN (0,1), 2 DIV (3 IN (0,1)), (2 DIV 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 in (0,1) AS `2 DIV 3 IN (0,1)`,2 DIV (3 in (0,1)) AS `2 DIV (3 IN (0,1))`,2 DIV 3 in (0,1) AS `(2 DIV 3) IN (0,1)` +select 2 DIV 3 IN (0,1), 2 DIV (3 IN (0,1)), (2 DIV 3) IN (0,1) union select * from v1; +2 DIV 3 IN (0,1) 2 DIV (3 IN (0,1)) (2 DIV 3) IN (0,1) +1 NULL 1 +create or replace view v1 as select 2 DIV 3 OR 3, 2 DIV (3 OR 3), (2 DIV 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 or 3 AS `2 DIV 3 OR 3`,2 DIV (3 or 3) AS `2 DIV (3 OR 3)`,2 DIV 3 or 3 AS `(2 DIV 3) OR 3` +select 2 DIV 3 OR 3, 2 DIV (3 OR 3), (2 DIV 3) OR 3 union select * from v1; +2 DIV 3 OR 3 2 DIV (3 OR 3) (2 DIV 3) OR 3 +1 2 1 +create or replace view v1 as select 2 DIV 3 || 3, 2 DIV (3 || 3), (2 DIV 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 or 3 AS `2 DIV 3 || 3`,2 DIV (3 or 3) AS `2 DIV (3 || 3)`,2 DIV 3 or 3 AS `(2 DIV 3) || 3` +select 2 DIV 3 || 3, 2 DIV (3 || 3), (2 DIV 3) || 3 union select * from v1; +2 DIV 3 || 3 2 DIV (3 || 3) (2 DIV 3) || 3 +1 2 1 +create or replace view v1 as select 2 DIV 3 XOR 3, 2 DIV (3 XOR 3), (2 DIV 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 xor 3 AS `2 DIV 3 XOR 3`,2 DIV (3 xor 3) AS `2 DIV (3 XOR 3)`,2 DIV 3 xor 3 AS `(2 DIV 3) XOR 3` +select 2 DIV 3 XOR 3, 2 DIV (3 XOR 3), (2 DIV 3) XOR 3 union select * from v1; +2 DIV 3 XOR 3 2 DIV (3 XOR 3) (2 DIV 3) XOR 3 +1 NULL 1 +create or replace view v1 as select 2 DIV 3 AND 3, 2 DIV (3 AND 3), (2 DIV 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 and 3 AS `2 DIV 3 AND 3`,2 DIV (3 and 3) AS `2 DIV (3 AND 3)`,2 DIV 3 and 3 AS `(2 DIV 3) AND 3` +select 2 DIV 3 AND 3, 2 DIV (3 AND 3), (2 DIV 3) AND 3 union select * from v1; +2 DIV 3 AND 3 2 DIV (3 AND 3) (2 DIV 3) AND 3 +0 2 0 +create or replace view v1 as select 2 DIV 3 && 3, 2 DIV (3 && 3), (2 DIV 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 and 3 AS `2 DIV 3 && 3`,2 DIV (3 and 3) AS `2 DIV (3 && 3)`,2 DIV 3 and 3 AS `(2 DIV 3) && 3` +select 2 DIV 3 && 3, 2 DIV (3 && 3), (2 DIV 3) && 3 union select * from v1; +2 DIV 3 && 3 2 DIV (3 && 3) (2 DIV 3) && 3 +0 2 0 +create or replace view v1 as select 2 DIV 3 = 3, 2 DIV (3 = 3), (2 DIV 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 = 3 AS `2 DIV 3 = 3`,2 DIV (3 = 3) AS `2 DIV (3 = 3)`,2 DIV 3 = 3 AS `(2 DIV 3) = 3` +select 2 DIV 3 = 3, 2 DIV (3 = 3), (2 DIV 3) = 3 union select * from v1; +2 DIV 3 = 3 2 DIV (3 = 3) (2 DIV 3) = 3 +0 2 0 +create or replace view v1 as select 2 DIV 3 <=> 3, 2 DIV (3 <=> 3), (2 DIV 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 <=> 3 AS `2 DIV 3 <=> 3`,2 DIV (3 <=> 3) AS `2 DIV (3 <=> 3)`,2 DIV 3 <=> 3 AS `(2 DIV 3) <=> 3` +select 2 DIV 3 <=> 3, 2 DIV (3 <=> 3), (2 DIV 3) <=> 3 union select * from v1; +2 DIV 3 <=> 3 2 DIV (3 <=> 3) (2 DIV 3) <=> 3 +0 2 0 +create or replace view v1 as select 2 DIV 3 >= 3, 2 DIV (3 >= 3), (2 DIV 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 >= 3 AS `2 DIV 3 >= 3`,2 DIV (3 >= 3) AS `2 DIV (3 >= 3)`,2 DIV 3 >= 3 AS `(2 DIV 3) >= 3` +select 2 DIV 3 >= 3, 2 DIV (3 >= 3), (2 DIV 3) >= 3 union select * from v1; +2 DIV 3 >= 3 2 DIV (3 >= 3) (2 DIV 3) >= 3 +0 2 0 +create or replace view v1 as select 2 DIV 3 <= 3, 2 DIV (3 <= 3), (2 DIV 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 <= 3 AS `2 DIV 3 <= 3`,2 DIV (3 <= 3) AS `2 DIV (3 <= 3)`,2 DIV 3 <= 3 AS `(2 DIV 3) <= 3` +select 2 DIV 3 <= 3, 2 DIV (3 <= 3), (2 DIV 3) <= 3 union select * from v1; +2 DIV 3 <= 3 2 DIV (3 <= 3) (2 DIV 3) <= 3 +1 2 1 +create or replace view v1 as select 2 DIV 3 < 3, 2 DIV (3 < 3), (2 DIV 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 < 3 AS `2 DIV 3 < 3`,2 DIV (3 < 3) AS `2 DIV (3 < 3)`,2 DIV 3 < 3 AS `(2 DIV 3) < 3` +select 2 DIV 3 < 3, 2 DIV (3 < 3), (2 DIV 3) < 3 union select * from v1; +2 DIV 3 < 3 2 DIV (3 < 3) (2 DIV 3) < 3 +1 NULL 1 +create or replace view v1 as select 2 DIV 3 <> 3, 2 DIV (3 <> 3), (2 DIV 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 <> 3 AS `2 DIV 3 <> 3`,2 DIV (3 <> 3) AS `2 DIV (3 <> 3)`,2 DIV 3 <> 3 AS `(2 DIV 3) <> 3` +select 2 DIV 3 <> 3, 2 DIV (3 <> 3), (2 DIV 3) <> 3 union select * from v1; +2 DIV 3 <> 3 2 DIV (3 <> 3) (2 DIV 3) <> 3 +1 NULL 1 +create or replace view v1 as select 2 DIV 3 > 3, 2 DIV (3 > 3), (2 DIV 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 > 3 AS `2 DIV 3 > 3`,2 DIV (3 > 3) AS `2 DIV (3 > 3)`,2 DIV 3 > 3 AS `(2 DIV 3) > 3` +select 2 DIV 3 > 3, 2 DIV (3 > 3), (2 DIV 3) > 3 union select * from v1; +2 DIV 3 > 3 2 DIV (3 > 3) (2 DIV 3) > 3 +0 NULL 0 +create or replace view v1 as select 2 DIV 3 != 3, 2 DIV (3 != 3), (2 DIV 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 <> 3 AS `2 DIV 3 != 3`,2 DIV (3 <> 3) AS `2 DIV (3 != 3)`,2 DIV 3 <> 3 AS `(2 DIV 3) != 3` +select 2 DIV 3 != 3, 2 DIV (3 != 3), (2 DIV 3) != 3 union select * from v1; +2 DIV 3 != 3 2 DIV (3 != 3) (2 DIV 3) != 3 +1 NULL 1 +create or replace view v1 as select 2 DIV 3 LIKE 3, 2 DIV (3 LIKE 3), (2 DIV 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 like 3 AS `2 DIV 3 LIKE 3`,2 DIV (3 like 3) AS `2 DIV (3 LIKE 3)`,2 DIV 3 like 3 AS `(2 DIV 3) LIKE 3` +select 2 DIV 3 LIKE 3, 2 DIV (3 LIKE 3), (2 DIV 3) LIKE 3 union select * from v1; +2 DIV 3 LIKE 3 2 DIV (3 LIKE 3) (2 DIV 3) LIKE 3 +0 2 0 +create or replace view v1 as select 2 DIV 3 REGEXP 3, 2 DIV (3 REGEXP 3), (2 DIV 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 regexp 3 AS `2 DIV 3 REGEXP 3`,2 DIV (3 regexp 3) AS `2 DIV (3 REGEXP 3)`,2 DIV 3 regexp 3 AS `(2 DIV 3) REGEXP 3` +select 2 DIV 3 REGEXP 3, 2 DIV (3 REGEXP 3), (2 DIV 3) REGEXP 3 union select * from v1; +2 DIV 3 REGEXP 3 2 DIV (3 REGEXP 3) (2 DIV 3) REGEXP 3 +0 2 0 +create or replace view v1 as select 2 DIV 3 | 3, 2 DIV (3 | 3), (2 DIV 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 | 3 AS `2 DIV 3 | 3`,2 DIV (3 | 3) AS `2 DIV (3 | 3)`,2 DIV 3 | 3 AS `(2 DIV 3) | 3` +select 2 DIV 3 | 3, 2 DIV (3 | 3), (2 DIV 3) | 3 union select * from v1; +2 DIV 3 | 3 2 DIV (3 | 3) (2 DIV 3) | 3 +3 0 3 +create or replace view v1 as select 2 DIV 3 & 1, 2 DIV (3 & 1), (2 DIV 3) & 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 & 1 AS `2 DIV 3 & 1`,2 DIV (3 & 1) AS `2 DIV (3 & 1)`,2 DIV 3 & 1 AS `(2 DIV 3) & 1` +select 2 DIV 3 & 1, 2 DIV (3 & 1), (2 DIV 3) & 1 union select * from v1; +2 DIV 3 & 1 2 DIV (3 & 1) (2 DIV 3) & 1 +0 2 0 +create or replace view v1 as select 4 DIV 3 << 3, 4 DIV (3 << 3), (4 DIV 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 4 DIV 3 << 3 AS `4 DIV 3 << 3`,4 DIV (3 << 3) AS `4 DIV (3 << 3)`,4 DIV 3 << 3 AS `(4 DIV 3) << 3` +select 4 DIV 3 << 3, 4 DIV (3 << 3), (4 DIV 3) << 3 union select * from v1; +4 DIV 3 << 3 4 DIV (3 << 3) (4 DIV 3) << 3 +8 0 8 +create or replace view v1 as select 2 DIV 3 >> 3, 2 DIV (3 >> 3), (2 DIV 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 >> 3 AS `2 DIV 3 >> 3`,2 DIV (3 >> 3) AS `2 DIV (3 >> 3)`,2 DIV 3 >> 3 AS `(2 DIV 3) >> 3` +select 2 DIV 3 >> 3, 2 DIV (3 >> 3), (2 DIV 3) >> 3 union select * from v1; +2 DIV 3 >> 3 2 DIV (3 >> 3) (2 DIV 3) >> 3 +0 NULL 0 +create or replace view v1 as select 2 DIV '2000-01-01' +INTERVAL 1 DAY, 2 DIV ('2000-01-01' +INTERVAL 1 DAY), (2 DIV '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV '2000-01-01' + interval 1 day AS `2 DIV '2000-01-01' +INTERVAL 1 DAY`,2 DIV ('2000-01-01' + interval 1 day) AS `2 DIV ('2000-01-01' +INTERVAL 1 DAY)`,2 DIV '2000-01-01' + interval 1 day AS `(2 DIV '2000-01-01') +INTERVAL 1 DAY` +select 2 DIV '2000-01-01' +INTERVAL 1 DAY, 2 DIV ('2000-01-01' +INTERVAL 1 DAY), (2 DIV '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 DIV '2000-01-01' +INTERVAL 1 DAY 2 DIV ('2000-01-01' +INTERVAL 1 DAY) (2 DIV '2000-01-01') +INTERVAL 1 DAY +NULL 0 NULL +create or replace view v1 as select 2 DIV 3 + 3, 2 DIV (3 + 3), (2 DIV 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 + 3 AS `2 DIV 3 + 3`,2 DIV (3 + 3) AS `2 DIV (3 + 3)`,2 DIV 3 + 3 AS `(2 DIV 3) + 3` +select 2 DIV 3 + 3, 2 DIV (3 + 3), (2 DIV 3) + 3 union select * from v1; +2 DIV 3 + 3 2 DIV (3 + 3) (2 DIV 3) + 3 +3 0 3 +create or replace view v1 as select 2 DIV 3 - 3, 2 DIV (3 - 3), (2 DIV 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 - 3 AS `2 DIV 3 - 3`,2 DIV (3 - 3) AS `2 DIV (3 - 3)`,2 DIV 3 - 3 AS `(2 DIV 3) - 3` +select 2 DIV 3 - 3, 2 DIV (3 - 3), (2 DIV 3) - 3 union select * from v1; +2 DIV 3 - 3 2 DIV (3 - 3) (2 DIV 3) - 3 +-3 NULL -3 +create or replace view v1 as select 4 DIV 3 * 3, 4 DIV (3 * 3), (4 DIV 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 4 DIV 3 * 3 AS `4 DIV 3 * 3`,4 DIV (3 * 3) AS `4 DIV (3 * 3)`,4 DIV 3 * 3 AS `(4 DIV 3) * 3` +select 4 DIV 3 * 3, 4 DIV (3 * 3), (4 DIV 3) * 3 union select * from v1; +4 DIV 3 * 3 4 DIV (3 * 3) (4 DIV 3) * 3 +3 0 3 +create or replace view v1 as select 2 DIV 3 / 3, 2 DIV (3 / 3), (2 DIV 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 / 3 AS `2 DIV 3 / 3`,2 DIV (3 / 3) AS `2 DIV (3 / 3)`,2 DIV 3 / 3 AS `(2 DIV 3) / 3` +select 2 DIV 3 / 3, 2 DIV (3 / 3), (2 DIV 3) / 3 union select * from v1; +2 DIV 3 / 3 2 DIV (3 / 3) (2 DIV 3) / 3 +0.0000 2 0.0000 +create or replace view v1 as select 2 DIV 3 DIV 3, 2 DIV (3 DIV 3), (2 DIV 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 DIV 3 AS `2 DIV 3 DIV 3`,2 DIV (3 DIV 3) AS `2 DIV (3 DIV 3)`,2 DIV 3 DIV 3 AS `(2 DIV 3) DIV 3` +select 2 DIV 3 DIV 3, 2 DIV (3 DIV 3), (2 DIV 3) DIV 3 union select * from v1; +2 DIV 3 DIV 3 2 DIV (3 DIV 3) (2 DIV 3) DIV 3 +0 2 0 +create or replace view v1 as select 2 DIV 3 MOD 3, 2 DIV (3 MOD 3), (2 DIV 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 % 3 AS `2 DIV 3 MOD 3`,2 DIV (3 % 3) AS `2 DIV (3 MOD 3)`,2 DIV 3 % 3 AS `(2 DIV 3) MOD 3` +select 2 DIV 3 MOD 3, 2 DIV (3 MOD 3), (2 DIV 3) MOD 3 union select * from v1; +2 DIV 3 MOD 3 2 DIV (3 MOD 3) (2 DIV 3) MOD 3 +0 NULL 0 +create or replace view v1 as select 2 DIV 3 % 3, 2 DIV (3 % 3), (2 DIV 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 % 3 AS `2 DIV 3 % 3`,2 DIV (3 % 3) AS `2 DIV (3 % 3)`,2 DIV 3 % 3 AS `(2 DIV 3) % 3` +select 2 DIV 3 % 3, 2 DIV (3 % 3), (2 DIV 3) % 3 union select * from v1; +2 DIV 3 % 3 2 DIV (3 % 3) (2 DIV 3) % 3 +0 NULL 0 +create or replace view v1 as select 2 DIV 3 ^ 3, 2 DIV (3 ^ 3), (2 DIV 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 ^ 3 AS `2 DIV 3 ^ 3`,2 DIV 3 ^ 3 AS `2 DIV (3 ^ 3)`,(2 DIV 3) ^ 3 AS `(2 DIV 3) ^ 3` +select 2 DIV 3 ^ 3, 2 DIV (3 ^ 3), (2 DIV 3) ^ 3 union select * from v1; +2 DIV 3 ^ 3 2 DIV (3 ^ 3) (2 DIV 3) ^ 3 +NULL NULL 3 +create or replace view v1 as select 2 DIV 3 BETWEEN 1 AND 3, 2 DIV (3 BETWEEN 1 AND 3), (2 DIV 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 between 1 and 3 AS `2 DIV 3 BETWEEN 1 AND 3`,2 DIV (3 between 1 and 3) AS `2 DIV (3 BETWEEN 1 AND 3)`,2 DIV 3 between 1 and 3 AS `(2 DIV 3) BETWEEN 1 AND 3` +select 2 DIV 3 BETWEEN 1 AND 3, 2 DIV (3 BETWEEN 1 AND 3), (2 DIV 3) BETWEEN 1 AND 3 union select * from v1; +2 DIV 3 BETWEEN 1 AND 3 2 DIV (3 BETWEEN 1 AND 3) (2 DIV 3) BETWEEN 1 AND 3 +0 2 0 +create or replace view v1 as select 2 MOD 3 IS FALSE, 2 MOD (3 IS FALSE), (2 MOD 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 is false AS `2 MOD 3 IS FALSE`,2 % (3 is false) AS `2 MOD (3 IS FALSE)`,2 % 3 is false AS `(2 MOD 3) IS FALSE` +select 2 MOD 3 IS FALSE, 2 MOD (3 IS FALSE), (2 MOD 3) IS FALSE union select * from v1; +2 MOD 3 IS FALSE 2 MOD (3 IS FALSE) (2 MOD 3) IS FALSE +0 NULL 0 +create or replace view v1 as select charset(2 MOD 3 COLLATE latin1_bin), charset(2 MOD (3 COLLATE latin1_bin)), charset((2 MOD 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 % 3 collate latin1_bin) AS `charset(2 MOD 3 COLLATE latin1_bin)`,charset(2 % 3 collate latin1_bin) AS `charset(2 MOD (3 COLLATE latin1_bin))`,charset((2 % 3) collate latin1_bin) AS `charset((2 MOD 3) COLLATE latin1_bin)` +select charset(2 MOD 3 COLLATE latin1_bin), charset(2 MOD (3 COLLATE latin1_bin)), charset((2 MOD 3) COLLATE latin1_bin) union select * from v1; +charset(2 MOD 3 COLLATE latin1_bin) charset(2 MOD (3 COLLATE latin1_bin)) charset((2 MOD 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 MOD 3 IN (0,1), 2 MOD (3 IN (0,1)), (2 MOD 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 in (0,1) AS `2 MOD 3 IN (0,1)`,2 % (3 in (0,1)) AS `2 MOD (3 IN (0,1))`,2 % 3 in (0,1) AS `(2 MOD 3) IN (0,1)` +select 2 MOD 3 IN (0,1), 2 MOD (3 IN (0,1)), (2 MOD 3) IN (0,1) union select * from v1; +2 MOD 3 IN (0,1) 2 MOD (3 IN (0,1)) (2 MOD 3) IN (0,1) +0 NULL 0 +create or replace view v1 as select 2 MOD 3 OR 3, 2 MOD (3 OR 3), (2 MOD 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 or 3 AS `2 MOD 3 OR 3`,2 % (3 or 3) AS `2 MOD (3 OR 3)`,2 % 3 or 3 AS `(2 MOD 3) OR 3` +select 2 MOD 3 OR 3, 2 MOD (3 OR 3), (2 MOD 3) OR 3 union select * from v1; +2 MOD 3 OR 3 2 MOD (3 OR 3) (2 MOD 3) OR 3 +1 0 1 +create or replace view v1 as select 2 MOD 3 || 3, 2 MOD (3 || 3), (2 MOD 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 or 3 AS `2 MOD 3 || 3`,2 % (3 or 3) AS `2 MOD (3 || 3)`,2 % 3 or 3 AS `(2 MOD 3) || 3` +select 2 MOD 3 || 3, 2 MOD (3 || 3), (2 MOD 3) || 3 union select * from v1; +2 MOD 3 || 3 2 MOD (3 || 3) (2 MOD 3) || 3 +1 0 1 +create or replace view v1 as select 2 MOD 3 XOR 3, 2 MOD (3 XOR 3), (2 MOD 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 xor 3 AS `2 MOD 3 XOR 3`,2 % (3 xor 3) AS `2 MOD (3 XOR 3)`,2 % 3 xor 3 AS `(2 MOD 3) XOR 3` +select 2 MOD 3 XOR 3, 2 MOD (3 XOR 3), (2 MOD 3) XOR 3 union select * from v1; +2 MOD 3 XOR 3 2 MOD (3 XOR 3) (2 MOD 3) XOR 3 +0 NULL 0 +create or replace view v1 as select 2 MOD 3 AND 3, 2 MOD (3 AND 3), (2 MOD 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 and 3 AS `2 MOD 3 AND 3`,2 % (3 and 3) AS `2 MOD (3 AND 3)`,2 % 3 and 3 AS `(2 MOD 3) AND 3` +select 2 MOD 3 AND 3, 2 MOD (3 AND 3), (2 MOD 3) AND 3 union select * from v1; +2 MOD 3 AND 3 2 MOD (3 AND 3) (2 MOD 3) AND 3 +1 0 1 +create or replace view v1 as select 2 MOD 3 && 3, 2 MOD (3 && 3), (2 MOD 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 and 3 AS `2 MOD 3 && 3`,2 % (3 and 3) AS `2 MOD (3 && 3)`,2 % 3 and 3 AS `(2 MOD 3) && 3` +select 2 MOD 3 && 3, 2 MOD (3 && 3), (2 MOD 3) && 3 union select * from v1; +2 MOD 3 && 3 2 MOD (3 && 3) (2 MOD 3) && 3 +1 0 1 +create or replace view v1 as select 2 MOD 3 = 2, 2 MOD (3 = 2), (2 MOD 3) = 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 = 2 AS `2 MOD 3 = 2`,2 % (3 = 2) AS `2 MOD (3 = 2)`,2 % 3 = 2 AS `(2 MOD 3) = 2` +select 2 MOD 3 = 2, 2 MOD (3 = 2), (2 MOD 3) = 2 union select * from v1; +2 MOD 3 = 2 2 MOD (3 = 2) (2 MOD 3) = 2 +1 NULL 1 +create or replace view v1 as select 2 MOD 3 <=> 2, 2 MOD (3 <=> 2), (2 MOD 3) <=> 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 <=> 2 AS `2 MOD 3 <=> 2`,2 % (3 <=> 2) AS `2 MOD (3 <=> 2)`,2 % 3 <=> 2 AS `(2 MOD 3) <=> 2` +select 2 MOD 3 <=> 2, 2 MOD (3 <=> 2), (2 MOD 3) <=> 2 union select * from v1; +2 MOD 3 <=> 2 2 MOD (3 <=> 2) (2 MOD 3) <=> 2 +1 NULL 1 +create or replace view v1 as select 2 MOD 3 >= 1, 2 MOD (3 >= 1), (2 MOD 3) >= 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 >= 1 AS `2 MOD 3 >= 1`,2 % (3 >= 1) AS `2 MOD (3 >= 1)`,2 % 3 >= 1 AS `(2 MOD 3) >= 1` +select 2 MOD 3 >= 1, 2 MOD (3 >= 1), (2 MOD 3) >= 1 union select * from v1; +2 MOD 3 >= 1 2 MOD (3 >= 1) (2 MOD 3) >= 1 +1 0 1 +create or replace view v1 as select 2 MOD 3 <= 3, 2 MOD (3 <= 3), (2 MOD 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 <= 3 AS `2 MOD 3 <= 3`,2 % (3 <= 3) AS `2 MOD (3 <= 3)`,2 % 3 <= 3 AS `(2 MOD 3) <= 3` +select 2 MOD 3 <= 3, 2 MOD (3 <= 3), (2 MOD 3) <= 3 union select * from v1; +2 MOD 3 <= 3 2 MOD (3 <= 3) (2 MOD 3) <= 3 +1 0 1 +create or replace view v1 as select 2 MOD 3 < 3, 2 MOD (3 < 3), (2 MOD 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 < 3 AS `2 MOD 3 < 3`,2 % (3 < 3) AS `2 MOD (3 < 3)`,2 % 3 < 3 AS `(2 MOD 3) < 3` +select 2 MOD 3 < 3, 2 MOD (3 < 3), (2 MOD 3) < 3 union select * from v1; +2 MOD 3 < 3 2 MOD (3 < 3) (2 MOD 3) < 3 +1 NULL 1 +create or replace view v1 as select 2 MOD 3 <> 3, 2 MOD (3 <> 3), (2 MOD 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 <> 3 AS `2 MOD 3 <> 3`,2 % (3 <> 3) AS `2 MOD (3 <> 3)`,2 % 3 <> 3 AS `(2 MOD 3) <> 3` +select 2 MOD 3 <> 3, 2 MOD (3 <> 3), (2 MOD 3) <> 3 union select * from v1; +2 MOD 3 <> 3 2 MOD (3 <> 3) (2 MOD 3) <> 3 +1 NULL 1 +create or replace view v1 as select 2 MOD 3 > 3, 2 MOD (3 > 3), (2 MOD 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 > 3 AS `2 MOD 3 > 3`,2 % (3 > 3) AS `2 MOD (3 > 3)`,2 % 3 > 3 AS `(2 MOD 3) > 3` +select 2 MOD 3 > 3, 2 MOD (3 > 3), (2 MOD 3) > 3 union select * from v1; +2 MOD 3 > 3 2 MOD (3 > 3) (2 MOD 3) > 3 +0 NULL 0 +create or replace view v1 as select 2 MOD 3 != 3, 2 MOD (3 != 3), (2 MOD 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 <> 3 AS `2 MOD 3 != 3`,2 % (3 <> 3) AS `2 MOD (3 != 3)`,2 % 3 <> 3 AS `(2 MOD 3) != 3` +select 2 MOD 3 != 3, 2 MOD (3 != 3), (2 MOD 3) != 3 union select * from v1; +2 MOD 3 != 3 2 MOD (3 != 3) (2 MOD 3) != 3 +1 NULL 1 +create or replace view v1 as select 2 MOD 3 LIKE 2, 2 MOD (3 LIKE 2), (2 MOD 3) LIKE 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 like 2 AS `2 MOD 3 LIKE 2`,2 % (3 like 2) AS `2 MOD (3 LIKE 2)`,2 % 3 like 2 AS `(2 MOD 3) LIKE 2` +select 2 MOD 3 LIKE 2, 2 MOD (3 LIKE 2), (2 MOD 3) LIKE 2 union select * from v1; +2 MOD 3 LIKE 2 2 MOD (3 LIKE 2) (2 MOD 3) LIKE 2 +1 NULL 1 +create or replace view v1 as select 2 MOD 3 REGEXP 2, 2 MOD (3 REGEXP 2), (2 MOD 3) REGEXP 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 regexp 2 AS `2 MOD 3 REGEXP 2`,2 % (3 regexp 2) AS `2 MOD (3 REGEXP 2)`,2 % 3 regexp 2 AS `(2 MOD 3) REGEXP 2` +select 2 MOD 3 REGEXP 2, 2 MOD (3 REGEXP 2), (2 MOD 3) REGEXP 2 union select * from v1; +2 MOD 3 REGEXP 2 2 MOD (3 REGEXP 2) (2 MOD 3) REGEXP 2 +1 NULL 1 +create or replace view v1 as select 2 MOD 3 | 3, 2 MOD (3 | 3), (2 MOD 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 | 3 AS `2 MOD 3 | 3`,2 % (3 | 3) AS `2 MOD (3 | 3)`,2 % 3 | 3 AS `(2 MOD 3) | 3` +select 2 MOD 3 | 3, 2 MOD (3 | 3), (2 MOD 3) | 3 union select * from v1; +2 MOD 3 | 3 2 MOD (3 | 3) (2 MOD 3) | 3 +3 2 3 +create or replace view v1 as select 2 MOD 4 & 4, 2 MOD (4 & 4), (2 MOD 4) & 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 4 & 4 AS `2 MOD 4 & 4`,2 % (4 & 4) AS `2 MOD (4 & 4)`,2 % 4 & 4 AS `(2 MOD 4) & 4` +select 2 MOD 4 & 4, 2 MOD (4 & 4), (2 MOD 4) & 4 union select * from v1; +2 MOD 4 & 4 2 MOD (4 & 4) (2 MOD 4) & 4 +0 2 0 +create or replace view v1 as select 2 MOD 3 << 3, 2 MOD (3 << 3), (2 MOD 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 << 3 AS `2 MOD 3 << 3`,2 % (3 << 3) AS `2 MOD (3 << 3)`,2 % 3 << 3 AS `(2 MOD 3) << 3` +select 2 MOD 3 << 3, 2 MOD (3 << 3), (2 MOD 3) << 3 union select * from v1; +2 MOD 3 << 3 2 MOD (3 << 3) (2 MOD 3) << 3 +16 2 16 +create or replace view v1 as select 2 MOD 3 >> 3, 2 MOD (3 >> 3), (2 MOD 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 >> 3 AS `2 MOD 3 >> 3`,2 % (3 >> 3) AS `2 MOD (3 >> 3)`,2 % 3 >> 3 AS `(2 MOD 3) >> 3` +select 2 MOD 3 >> 3, 2 MOD (3 >> 3), (2 MOD 3) >> 3 union select * from v1; +2 MOD 3 >> 3 2 MOD (3 >> 3) (2 MOD 3) >> 3 +0 NULL 0 +create or replace view v1 as select 2 MOD '2000-01-01' +INTERVAL 1 DAY, 2 MOD ('2000-01-01' +INTERVAL 1 DAY), (2 MOD '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % '2000-01-01' + interval 1 day AS `2 MOD '2000-01-01' +INTERVAL 1 DAY`,2 % ('2000-01-01' + interval 1 day) AS `2 MOD ('2000-01-01' +INTERVAL 1 DAY)`,2 % '2000-01-01' + interval 1 day AS `(2 MOD '2000-01-01') +INTERVAL 1 DAY` +select 2 MOD '2000-01-01' +INTERVAL 1 DAY, 2 MOD ('2000-01-01' +INTERVAL 1 DAY), (2 MOD '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 MOD '2000-01-01' +INTERVAL 1 DAY 2 MOD ('2000-01-01' +INTERVAL 1 DAY) (2 MOD '2000-01-01') +INTERVAL 1 DAY +NULL 2 NULL +create or replace view v1 as select 2 MOD 3 + 3, 2 MOD (3 + 3), (2 MOD 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 + 3 AS `2 MOD 3 + 3`,2 % (3 + 3) AS `2 MOD (3 + 3)`,2 % 3 + 3 AS `(2 MOD 3) + 3` +select 2 MOD 3 + 3, 2 MOD (3 + 3), (2 MOD 3) + 3 union select * from v1; +2 MOD 3 + 3 2 MOD (3 + 3) (2 MOD 3) + 3 +5 2 5 +create or replace view v1 as select 2 MOD 3 - 3, 2 MOD (3 - 3), (2 MOD 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 - 3 AS `2 MOD 3 - 3`,2 % (3 - 3) AS `2 MOD (3 - 3)`,2 % 3 - 3 AS `(2 MOD 3) - 3` +select 2 MOD 3 - 3, 2 MOD (3 - 3), (2 MOD 3) - 3 union select * from v1; +2 MOD 3 - 3 2 MOD (3 - 3) (2 MOD 3) - 3 +-1 NULL -1 +create or replace view v1 as select 2 MOD 3 * 3, 2 MOD (3 * 3), (2 MOD 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 * 3 AS `2 MOD 3 * 3`,2 % (3 * 3) AS `2 MOD (3 * 3)`,2 % 3 * 3 AS `(2 MOD 3) * 3` +select 2 MOD 3 * 3, 2 MOD (3 * 3), (2 MOD 3) * 3 union select * from v1; +2 MOD 3 * 3 2 MOD (3 * 3) (2 MOD 3) * 3 +6 2 6 +create or replace view v1 as select 2 MOD 3 / 3, 2 MOD (3 / 3), (2 MOD 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 / 3 AS `2 MOD 3 / 3`,2 % (3 / 3) AS `2 MOD (3 / 3)`,2 % 3 / 3 AS `(2 MOD 3) / 3` +select 2 MOD 3 / 3, 2 MOD (3 / 3), (2 MOD 3) / 3 union select * from v1; +2 MOD 3 / 3 2 MOD (3 / 3) (2 MOD 3) / 3 +0.6667 0.0000 0.6667 +create or replace view v1 as select 3 MOD 4 DIV 3, 3 MOD (4 DIV 3), (3 MOD 4) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 % 4 DIV 3 AS `3 MOD 4 DIV 3`,3 % (4 DIV 3) AS `3 MOD (4 DIV 3)`,3 % 4 DIV 3 AS `(3 MOD 4) DIV 3` +select 3 MOD 4 DIV 3, 3 MOD (4 DIV 3), (3 MOD 4) DIV 3 union select * from v1; +3 MOD 4 DIV 3 3 MOD (4 DIV 3) (3 MOD 4) DIV 3 +1 0 1 +create or replace view v1 as select 2 MOD 3 MOD 3, 2 MOD (3 MOD 3), (2 MOD 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 % 3 AS `2 MOD 3 MOD 3`,2 % (3 % 3) AS `2 MOD (3 MOD 3)`,2 % 3 % 3 AS `(2 MOD 3) MOD 3` +select 2 MOD 3 MOD 3, 2 MOD (3 MOD 3), (2 MOD 3) MOD 3 union select * from v1; +2 MOD 3 MOD 3 2 MOD (3 MOD 3) (2 MOD 3) MOD 3 +2 NULL 2 +create or replace view v1 as select 2 MOD 3 % 3, 2 MOD (3 % 3), (2 MOD 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 % 3 AS `2 MOD 3 % 3`,2 % (3 % 3) AS `2 MOD (3 % 3)`,2 % 3 % 3 AS `(2 MOD 3) % 3` +select 2 MOD 3 % 3, 2 MOD (3 % 3), (2 MOD 3) % 3 union select * from v1; +2 MOD 3 % 3 2 MOD (3 % 3) (2 MOD 3) % 3 +2 NULL 2 +create or replace view v1 as select 2 MOD 3 ^ 3, 2 MOD (3 ^ 3), (2 MOD 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 ^ 3 AS `2 MOD 3 ^ 3`,2 % 3 ^ 3 AS `2 MOD (3 ^ 3)`,(2 % 3) ^ 3 AS `(2 MOD 3) ^ 3` +select 2 MOD 3 ^ 3, 2 MOD (3 ^ 3), (2 MOD 3) ^ 3 union select * from v1; +2 MOD 3 ^ 3 2 MOD (3 ^ 3) (2 MOD 3) ^ 3 +NULL NULL 1 +create or replace view v1 as select 2 MOD 3 BETWEEN 1 AND 3, 2 MOD (3 BETWEEN 1 AND 3), (2 MOD 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 between 1 and 3 AS `2 MOD 3 BETWEEN 1 AND 3`,2 % (3 between 1 and 3) AS `2 MOD (3 BETWEEN 1 AND 3)`,2 % 3 between 1 and 3 AS `(2 MOD 3) BETWEEN 1 AND 3` +select 2 MOD 3 BETWEEN 1 AND 3, 2 MOD (3 BETWEEN 1 AND 3), (2 MOD 3) BETWEEN 1 AND 3 union select * from v1; +2 MOD 3 BETWEEN 1 AND 3 2 MOD (3 BETWEEN 1 AND 3) (2 MOD 3) BETWEEN 1 AND 3 +1 0 1 +create or replace view v1 as select 2 % 3 IS FALSE, 2 % (3 IS FALSE), (2 % 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 is false AS `2 % 3 IS FALSE`,2 % (3 is false) AS `2 % (3 IS FALSE)`,2 % 3 is false AS `(2 % 3) IS FALSE` +select 2 % 3 IS FALSE, 2 % (3 IS FALSE), (2 % 3) IS FALSE union select * from v1; +2 % 3 IS FALSE 2 % (3 IS FALSE) (2 % 3) IS FALSE +0 NULL 0 +create or replace view v1 as select charset(2 % 3 COLLATE latin1_bin), charset(2 % (3 COLLATE latin1_bin)), charset((2 % 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 % 3 collate latin1_bin) AS `charset(2 % 3 COLLATE latin1_bin)`,charset(2 % 3 collate latin1_bin) AS `charset(2 % (3 COLLATE latin1_bin))`,charset((2 % 3) collate latin1_bin) AS `charset((2 % 3) COLLATE latin1_bin)` +select charset(2 % 3 COLLATE latin1_bin), charset(2 % (3 COLLATE latin1_bin)), charset((2 % 3) COLLATE latin1_bin) union select * from v1; +charset(2 % 3 COLLATE latin1_bin) charset(2 % (3 COLLATE latin1_bin)) charset((2 % 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 % 3 IN (0,1), 2 % (3 IN (0,1)), (2 % 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 in (0,1) AS `2 % 3 IN (0,1)`,2 % (3 in (0,1)) AS `2 % (3 IN (0,1))`,2 % 3 in (0,1) AS `(2 % 3) IN (0,1)` +select 2 % 3 IN (0,1), 2 % (3 IN (0,1)), (2 % 3) IN (0,1) union select * from v1; +2 % 3 IN (0,1) 2 % (3 IN (0,1)) (2 % 3) IN (0,1) +0 NULL 0 +create or replace view v1 as select 2 % 3 OR 3, 2 % (3 OR 3), (2 % 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 or 3 AS `2 % 3 OR 3`,2 % (3 or 3) AS `2 % (3 OR 3)`,2 % 3 or 3 AS `(2 % 3) OR 3` +select 2 % 3 OR 3, 2 % (3 OR 3), (2 % 3) OR 3 union select * from v1; +2 % 3 OR 3 2 % (3 OR 3) (2 % 3) OR 3 +1 0 1 +create or replace view v1 as select 2 % 3 || 3, 2 % (3 || 3), (2 % 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 or 3 AS `2 % 3 || 3`,2 % (3 or 3) AS `2 % (3 || 3)`,2 % 3 or 3 AS `(2 % 3) || 3` +select 2 % 3 || 3, 2 % (3 || 3), (2 % 3) || 3 union select * from v1; +2 % 3 || 3 2 % (3 || 3) (2 % 3) || 3 +1 0 1 +create or replace view v1 as select 2 % 3 XOR 3, 2 % (3 XOR 3), (2 % 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 xor 3 AS `2 % 3 XOR 3`,2 % (3 xor 3) AS `2 % (3 XOR 3)`,2 % 3 xor 3 AS `(2 % 3) XOR 3` +select 2 % 3 XOR 3, 2 % (3 XOR 3), (2 % 3) XOR 3 union select * from v1; +2 % 3 XOR 3 2 % (3 XOR 3) (2 % 3) XOR 3 +0 NULL 0 +create or replace view v1 as select 2 % 3 AND 3, 2 % (3 AND 3), (2 % 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 and 3 AS `2 % 3 AND 3`,2 % (3 and 3) AS `2 % (3 AND 3)`,2 % 3 and 3 AS `(2 % 3) AND 3` +select 2 % 3 AND 3, 2 % (3 AND 3), (2 % 3) AND 3 union select * from v1; +2 % 3 AND 3 2 % (3 AND 3) (2 % 3) AND 3 +1 0 1 +create or replace view v1 as select 2 % 3 && 3, 2 % (3 && 3), (2 % 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 and 3 AS `2 % 3 && 3`,2 % (3 and 3) AS `2 % (3 && 3)`,2 % 3 and 3 AS `(2 % 3) && 3` +select 2 % 3 && 3, 2 % (3 && 3), (2 % 3) && 3 union select * from v1; +2 % 3 && 3 2 % (3 && 3) (2 % 3) && 3 +1 0 1 +create or replace view v1 as select 2 % 3 = 2, 2 % (3 = 2), (2 % 3) = 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 = 2 AS `2 % 3 = 2`,2 % (3 = 2) AS `2 % (3 = 2)`,2 % 3 = 2 AS `(2 % 3) = 2` +select 2 % 3 = 2, 2 % (3 = 2), (2 % 3) = 2 union select * from v1; +2 % 3 = 2 2 % (3 = 2) (2 % 3) = 2 +1 NULL 1 +create or replace view v1 as select 2 % 3 <=> 2, 2 % (3 <=> 2), (2 % 3) <=> 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 <=> 2 AS `2 % 3 <=> 2`,2 % (3 <=> 2) AS `2 % (3 <=> 2)`,2 % 3 <=> 2 AS `(2 % 3) <=> 2` +select 2 % 3 <=> 2, 2 % (3 <=> 2), (2 % 3) <=> 2 union select * from v1; +2 % 3 <=> 2 2 % (3 <=> 2) (2 % 3) <=> 2 +1 NULL 1 +create or replace view v1 as select 2 % 3 >= 1, 2 % (3 >= 1), (2 % 3) >= 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 >= 1 AS `2 % 3 >= 1`,2 % (3 >= 1) AS `2 % (3 >= 1)`,2 % 3 >= 1 AS `(2 % 3) >= 1` +select 2 % 3 >= 1, 2 % (3 >= 1), (2 % 3) >= 1 union select * from v1; +2 % 3 >= 1 2 % (3 >= 1) (2 % 3) >= 1 +1 0 1 +create or replace view v1 as select 2 % 3 <= 3, 2 % (3 <= 3), (2 % 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 <= 3 AS `2 % 3 <= 3`,2 % (3 <= 3) AS `2 % (3 <= 3)`,2 % 3 <= 3 AS `(2 % 3) <= 3` +select 2 % 3 <= 3, 2 % (3 <= 3), (2 % 3) <= 3 union select * from v1; +2 % 3 <= 3 2 % (3 <= 3) (2 % 3) <= 3 +1 0 1 +create or replace view v1 as select 2 % 3 < 3, 2 % (3 < 3), (2 % 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 < 3 AS `2 % 3 < 3`,2 % (3 < 3) AS `2 % (3 < 3)`,2 % 3 < 3 AS `(2 % 3) < 3` +select 2 % 3 < 3, 2 % (3 < 3), (2 % 3) < 3 union select * from v1; +2 % 3 < 3 2 % (3 < 3) (2 % 3) < 3 +1 NULL 1 +create or replace view v1 as select 2 % 3 <> 3, 2 % (3 <> 3), (2 % 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 <> 3 AS `2 % 3 <> 3`,2 % (3 <> 3) AS `2 % (3 <> 3)`,2 % 3 <> 3 AS `(2 % 3) <> 3` +select 2 % 3 <> 3, 2 % (3 <> 3), (2 % 3) <> 3 union select * from v1; +2 % 3 <> 3 2 % (3 <> 3) (2 % 3) <> 3 +1 NULL 1 +create or replace view v1 as select 2 % 3 > 3, 2 % (3 > 3), (2 % 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 > 3 AS `2 % 3 > 3`,2 % (3 > 3) AS `2 % (3 > 3)`,2 % 3 > 3 AS `(2 % 3) > 3` +select 2 % 3 > 3, 2 % (3 > 3), (2 % 3) > 3 union select * from v1; +2 % 3 > 3 2 % (3 > 3) (2 % 3) > 3 +0 NULL 0 +create or replace view v1 as select 2 % 3 != 3, 2 % (3 != 3), (2 % 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 <> 3 AS `2 % 3 != 3`,2 % (3 <> 3) AS `2 % (3 != 3)`,2 % 3 <> 3 AS `(2 % 3) != 3` +select 2 % 3 != 3, 2 % (3 != 3), (2 % 3) != 3 union select * from v1; +2 % 3 != 3 2 % (3 != 3) (2 % 3) != 3 +1 NULL 1 +create or replace view v1 as select 2 % 3 LIKE 2, 2 % (3 LIKE 2), (2 % 3) LIKE 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 like 2 AS `2 % 3 LIKE 2`,2 % (3 like 2) AS `2 % (3 LIKE 2)`,2 % 3 like 2 AS `(2 % 3) LIKE 2` +select 2 % 3 LIKE 2, 2 % (3 LIKE 2), (2 % 3) LIKE 2 union select * from v1; +2 % 3 LIKE 2 2 % (3 LIKE 2) (2 % 3) LIKE 2 +1 NULL 1 +create or replace view v1 as select 2 % 3 REGEXP 2, 2 % (3 REGEXP 2), (2 % 3) REGEXP 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 regexp 2 AS `2 % 3 REGEXP 2`,2 % (3 regexp 2) AS `2 % (3 REGEXP 2)`,2 % 3 regexp 2 AS `(2 % 3) REGEXP 2` +select 2 % 3 REGEXP 2, 2 % (3 REGEXP 2), (2 % 3) REGEXP 2 union select * from v1; +2 % 3 REGEXP 2 2 % (3 REGEXP 2) (2 % 3) REGEXP 2 +1 NULL 1 +create or replace view v1 as select 2 % 3 | 3, 2 % (3 | 3), (2 % 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 | 3 AS `2 % 3 | 3`,2 % (3 | 3) AS `2 % (3 | 3)`,2 % 3 | 3 AS `(2 % 3) | 3` +select 2 % 3 | 3, 2 % (3 | 3), (2 % 3) | 3 union select * from v1; +2 % 3 | 3 2 % (3 | 3) (2 % 3) | 3 +3 2 3 +create or replace view v1 as select 2 % 4 & 4, 2 % (4 & 4), (2 % 4) & 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 4 & 4 AS `2 % 4 & 4`,2 % (4 & 4) AS `2 % (4 & 4)`,2 % 4 & 4 AS `(2 % 4) & 4` +select 2 % 4 & 4, 2 % (4 & 4), (2 % 4) & 4 union select * from v1; +2 % 4 & 4 2 % (4 & 4) (2 % 4) & 4 +0 2 0 +create or replace view v1 as select 2 % 3 << 3, 2 % (3 << 3), (2 % 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 << 3 AS `2 % 3 << 3`,2 % (3 << 3) AS `2 % (3 << 3)`,2 % 3 << 3 AS `(2 % 3) << 3` +select 2 % 3 << 3, 2 % (3 << 3), (2 % 3) << 3 union select * from v1; +2 % 3 << 3 2 % (3 << 3) (2 % 3) << 3 +16 2 16 +create or replace view v1 as select 2 % 3 >> 3, 2 % (3 >> 3), (2 % 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 >> 3 AS `2 % 3 >> 3`,2 % (3 >> 3) AS `2 % (3 >> 3)`,2 % 3 >> 3 AS `(2 % 3) >> 3` +select 2 % 3 >> 3, 2 % (3 >> 3), (2 % 3) >> 3 union select * from v1; +2 % 3 >> 3 2 % (3 >> 3) (2 % 3) >> 3 +0 NULL 0 +create or replace view v1 as select 2 % '2000-01-01' +INTERVAL 1 DAY, 2 % ('2000-01-01' +INTERVAL 1 DAY), (2 % '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % '2000-01-01' + interval 1 day AS `2 % '2000-01-01' +INTERVAL 1 DAY`,2 % ('2000-01-01' + interval 1 day) AS `2 % ('2000-01-01' +INTERVAL 1 DAY)`,2 % '2000-01-01' + interval 1 day AS `(2 % '2000-01-01') +INTERVAL 1 DAY` +select 2 % '2000-01-01' +INTERVAL 1 DAY, 2 % ('2000-01-01' +INTERVAL 1 DAY), (2 % '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 % '2000-01-01' +INTERVAL 1 DAY 2 % ('2000-01-01' +INTERVAL 1 DAY) (2 % '2000-01-01') +INTERVAL 1 DAY +NULL 2 NULL +create or replace view v1 as select 2 % 3 + 3, 2 % (3 + 3), (2 % 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 + 3 AS `2 % 3 + 3`,2 % (3 + 3) AS `2 % (3 + 3)`,2 % 3 + 3 AS `(2 % 3) + 3` +select 2 % 3 + 3, 2 % (3 + 3), (2 % 3) + 3 union select * from v1; +2 % 3 + 3 2 % (3 + 3) (2 % 3) + 3 +5 2 5 +create or replace view v1 as select 2 % 3 - 3, 2 % (3 - 3), (2 % 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 - 3 AS `2 % 3 - 3`,2 % (3 - 3) AS `2 % (3 - 3)`,2 % 3 - 3 AS `(2 % 3) - 3` +select 2 % 3 - 3, 2 % (3 - 3), (2 % 3) - 3 union select * from v1; +2 % 3 - 3 2 % (3 - 3) (2 % 3) - 3 +-1 NULL -1 +create or replace view v1 as select 2 % 3 * 3, 2 % (3 * 3), (2 % 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 * 3 AS `2 % 3 * 3`,2 % (3 * 3) AS `2 % (3 * 3)`,2 % 3 * 3 AS `(2 % 3) * 3` +select 2 % 3 * 3, 2 % (3 * 3), (2 % 3) * 3 union select * from v1; +2 % 3 * 3 2 % (3 * 3) (2 % 3) * 3 +6 2 6 +create or replace view v1 as select 2 % 3 / 3, 2 % (3 / 3), (2 % 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 / 3 AS `2 % 3 / 3`,2 % (3 / 3) AS `2 % (3 / 3)`,2 % 3 / 3 AS `(2 % 3) / 3` +select 2 % 3 / 3, 2 % (3 / 3), (2 % 3) / 3 union select * from v1; +2 % 3 / 3 2 % (3 / 3) (2 % 3) / 3 +0.6667 0.0000 0.6667 +create or replace view v1 as select 3 % 4 DIV 3, 3 % (4 DIV 3), (3 % 4) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 % 4 DIV 3 AS `3 % 4 DIV 3`,3 % (4 DIV 3) AS `3 % (4 DIV 3)`,3 % 4 DIV 3 AS `(3 % 4) DIV 3` +select 3 % 4 DIV 3, 3 % (4 DIV 3), (3 % 4) DIV 3 union select * from v1; +3 % 4 DIV 3 3 % (4 DIV 3) (3 % 4) DIV 3 +1 0 1 +create or replace view v1 as select 2 % 3 MOD 3, 2 % (3 MOD 3), (2 % 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 % 3 AS `2 % 3 MOD 3`,2 % (3 % 3) AS `2 % (3 MOD 3)`,2 % 3 % 3 AS `(2 % 3) MOD 3` +select 2 % 3 MOD 3, 2 % (3 MOD 3), (2 % 3) MOD 3 union select * from v1; +2 % 3 MOD 3 2 % (3 MOD 3) (2 % 3) MOD 3 +2 NULL 2 +create or replace view v1 as select 2 % 3 % 3, 2 % (3 % 3), (2 % 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 % 3 AS `2 % 3 % 3`,2 % (3 % 3) AS `2 % (3 % 3)`,2 % 3 % 3 AS `(2 % 3) % 3` +select 2 % 3 % 3, 2 % (3 % 3), (2 % 3) % 3 union select * from v1; +2 % 3 % 3 2 % (3 % 3) (2 % 3) % 3 +2 NULL 2 +create or replace view v1 as select 2 % 3 ^ 3, 2 % (3 ^ 3), (2 % 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 ^ 3 AS `2 % 3 ^ 3`,2 % 3 ^ 3 AS `2 % (3 ^ 3)`,(2 % 3) ^ 3 AS `(2 % 3) ^ 3` +select 2 % 3 ^ 3, 2 % (3 ^ 3), (2 % 3) ^ 3 union select * from v1; +2 % 3 ^ 3 2 % (3 ^ 3) (2 % 3) ^ 3 +NULL NULL 1 +create or replace view v1 as select 2 % 3 BETWEEN 1 AND 3, 2 % (3 BETWEEN 1 AND 3), (2 % 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 between 1 and 3 AS `2 % 3 BETWEEN 1 AND 3`,2 % (3 between 1 and 3) AS `2 % (3 BETWEEN 1 AND 3)`,2 % 3 between 1 and 3 AS `(2 % 3) BETWEEN 1 AND 3` +select 2 % 3 BETWEEN 1 AND 3, 2 % (3 BETWEEN 1 AND 3), (2 % 3) BETWEEN 1 AND 3 union select * from v1; +2 % 3 BETWEEN 1 AND 3 2 % (3 BETWEEN 1 AND 3) (2 % 3) BETWEEN 1 AND 3 +1 0 1 +create or replace view v1 as select 2 ^ 3 IS FALSE, 2 ^ (3 IS FALSE), (2 ^ 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 is false AS `2 ^ 3 IS FALSE`,2 ^ (3 is false) AS `2 ^ (3 IS FALSE)`,2 ^ 3 is false AS `(2 ^ 3) IS FALSE` +select 2 ^ 3 IS FALSE, 2 ^ (3 IS FALSE), (2 ^ 3) IS FALSE union select * from v1; +2 ^ 3 IS FALSE 2 ^ (3 IS FALSE) (2 ^ 3) IS FALSE +0 2 0 +create or replace view v1 as select charset(2 ^ 3 COLLATE latin1_bin), charset(2 ^ (3 COLLATE latin1_bin)), charset((2 ^ 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 ^ 3 collate latin1_bin) AS `charset(2 ^ 3 COLLATE latin1_bin)`,charset(2 ^ 3 collate latin1_bin) AS `charset(2 ^ (3 COLLATE latin1_bin))`,charset((2 ^ 3) collate latin1_bin) AS `charset((2 ^ 3) COLLATE latin1_bin)` +select charset(2 ^ 3 COLLATE latin1_bin), charset(2 ^ (3 COLLATE latin1_bin)), charset((2 ^ 3) COLLATE latin1_bin) union select * from v1; +charset(2 ^ 3 COLLATE latin1_bin) charset(2 ^ (3 COLLATE latin1_bin)) charset((2 ^ 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 ^ 3 IN (0,1), 2 ^ (3 IN (0,1)), (2 ^ 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 in (0,1) AS `2 ^ 3 IN (0,1)`,2 ^ (3 in (0,1)) AS `2 ^ (3 IN (0,1))`,2 ^ 3 in (0,1) AS `(2 ^ 3) IN (0,1)` +select 2 ^ 3 IN (0,1), 2 ^ (3 IN (0,1)), (2 ^ 3) IN (0,1) union select * from v1; +2 ^ 3 IN (0,1) 2 ^ (3 IN (0,1)) (2 ^ 3) IN (0,1) +1 2 1 +create or replace view v1 as select 2 ^ 3 OR 3, 2 ^ (3 OR 3), (2 ^ 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 or 3 AS `2 ^ 3 OR 3`,2 ^ (3 or 3) AS `2 ^ (3 OR 3)`,2 ^ 3 or 3 AS `(2 ^ 3) OR 3` +select 2 ^ 3 OR 3, 2 ^ (3 OR 3), (2 ^ 3) OR 3 union select * from v1; +2 ^ 3 OR 3 2 ^ (3 OR 3) (2 ^ 3) OR 3 +1 3 1 +create or replace view v1 as select 2 ^ 3 || 3, 2 ^ (3 || 3), (2 ^ 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 or 3 AS `2 ^ 3 || 3`,2 ^ (3 or 3) AS `2 ^ (3 || 3)`,2 ^ 3 or 3 AS `(2 ^ 3) || 3` +select 2 ^ 3 || 3, 2 ^ (3 || 3), (2 ^ 3) || 3 union select * from v1; +2 ^ 3 || 3 2 ^ (3 || 3) (2 ^ 3) || 3 +1 3 1 +create or replace view v1 as select 2 ^ 3 XOR 3, 2 ^ (3 XOR 3), (2 ^ 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 xor 3 AS `2 ^ 3 XOR 3`,2 ^ (3 xor 3) AS `2 ^ (3 XOR 3)`,2 ^ 3 xor 3 AS `(2 ^ 3) XOR 3` +select 2 ^ 3 XOR 3, 2 ^ (3 XOR 3), (2 ^ 3) XOR 3 union select * from v1; +2 ^ 3 XOR 3 2 ^ (3 XOR 3) (2 ^ 3) XOR 3 +0 2 0 +create or replace view v1 as select 2 ^ 3 AND 3, 2 ^ (3 AND 3), (2 ^ 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 and 3 AS `2 ^ 3 AND 3`,2 ^ (3 and 3) AS `2 ^ (3 AND 3)`,2 ^ 3 and 3 AS `(2 ^ 3) AND 3` +select 2 ^ 3 AND 3, 2 ^ (3 AND 3), (2 ^ 3) AND 3 union select * from v1; +2 ^ 3 AND 3 2 ^ (3 AND 3) (2 ^ 3) AND 3 +1 3 1 +create or replace view v1 as select 2 ^ 3 && 3, 2 ^ (3 && 3), (2 ^ 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 and 3 AS `2 ^ 3 && 3`,2 ^ (3 and 3) AS `2 ^ (3 && 3)`,2 ^ 3 and 3 AS `(2 ^ 3) && 3` +select 2 ^ 3 && 3, 2 ^ (3 && 3), (2 ^ 3) && 3 union select * from v1; +2 ^ 3 && 3 2 ^ (3 && 3) (2 ^ 3) && 3 +1 3 1 +create or replace view v1 as select 2 ^ 3 = 3, 2 ^ (3 = 3), (2 ^ 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 = 3 AS `2 ^ 3 = 3`,2 ^ (3 = 3) AS `2 ^ (3 = 3)`,2 ^ 3 = 3 AS `(2 ^ 3) = 3` +select 2 ^ 3 = 3, 2 ^ (3 = 3), (2 ^ 3) = 3 union select * from v1; +2 ^ 3 = 3 2 ^ (3 = 3) (2 ^ 3) = 3 +0 3 0 +create or replace view v1 as select 2 ^ 3 <=> 3, 2 ^ (3 <=> 3), (2 ^ 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 <=> 3 AS `2 ^ 3 <=> 3`,2 ^ (3 <=> 3) AS `2 ^ (3 <=> 3)`,2 ^ 3 <=> 3 AS `(2 ^ 3) <=> 3` +select 2 ^ 3 <=> 3, 2 ^ (3 <=> 3), (2 ^ 3) <=> 3 union select * from v1; +2 ^ 3 <=> 3 2 ^ (3 <=> 3) (2 ^ 3) <=> 3 +0 3 0 +create or replace view v1 as select 2 ^ 3 >= 3, 2 ^ (3 >= 3), (2 ^ 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 >= 3 AS `2 ^ 3 >= 3`,2 ^ (3 >= 3) AS `2 ^ (3 >= 3)`,2 ^ 3 >= 3 AS `(2 ^ 3) >= 3` +select 2 ^ 3 >= 3, 2 ^ (3 >= 3), (2 ^ 3) >= 3 union select * from v1; +2 ^ 3 >= 3 2 ^ (3 >= 3) (2 ^ 3) >= 3 +0 3 0 +create or replace view v1 as select 2 ^ 3 <= 3, 2 ^ (3 <= 3), (2 ^ 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 <= 3 AS `2 ^ 3 <= 3`,2 ^ (3 <= 3) AS `2 ^ (3 <= 3)`,2 ^ 3 <= 3 AS `(2 ^ 3) <= 3` +select 2 ^ 3 <= 3, 2 ^ (3 <= 3), (2 ^ 3) <= 3 union select * from v1; +2 ^ 3 <= 3 2 ^ (3 <= 3) (2 ^ 3) <= 3 +1 3 1 +create or replace view v1 as select 2 ^ 3 < 3, 2 ^ (3 < 3), (2 ^ 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 < 3 AS `2 ^ 3 < 3`,2 ^ (3 < 3) AS `2 ^ (3 < 3)`,2 ^ 3 < 3 AS `(2 ^ 3) < 3` +select 2 ^ 3 < 3, 2 ^ (3 < 3), (2 ^ 3) < 3 union select * from v1; +2 ^ 3 < 3 2 ^ (3 < 3) (2 ^ 3) < 3 +1 2 1 +create or replace view v1 as select 2 ^ 3 <> 3, 2 ^ (3 <> 3), (2 ^ 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 <> 3 AS `2 ^ 3 <> 3`,2 ^ (3 <> 3) AS `2 ^ (3 <> 3)`,2 ^ 3 <> 3 AS `(2 ^ 3) <> 3` +select 2 ^ 3 <> 3, 2 ^ (3 <> 3), (2 ^ 3) <> 3 union select * from v1; +2 ^ 3 <> 3 2 ^ (3 <> 3) (2 ^ 3) <> 3 +1 2 1 +create or replace view v1 as select 2 ^ 3 > 3, 2 ^ (3 > 3), (2 ^ 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 > 3 AS `2 ^ 3 > 3`,2 ^ (3 > 3) AS `2 ^ (3 > 3)`,2 ^ 3 > 3 AS `(2 ^ 3) > 3` +select 2 ^ 3 > 3, 2 ^ (3 > 3), (2 ^ 3) > 3 union select * from v1; +2 ^ 3 > 3 2 ^ (3 > 3) (2 ^ 3) > 3 +0 2 0 +create or replace view v1 as select 2 ^ 3 != 3, 2 ^ (3 != 3), (2 ^ 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 <> 3 AS `2 ^ 3 != 3`,2 ^ (3 <> 3) AS `2 ^ (3 != 3)`,2 ^ 3 <> 3 AS `(2 ^ 3) != 3` +select 2 ^ 3 != 3, 2 ^ (3 != 3), (2 ^ 3) != 3 union select * from v1; +2 ^ 3 != 3 2 ^ (3 != 3) (2 ^ 3) != 3 +1 2 1 +create or replace view v1 as select 2 ^ 3 LIKE 3, 2 ^ (3 LIKE 3), (2 ^ 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 like 3 AS `2 ^ 3 LIKE 3`,2 ^ (3 like 3) AS `2 ^ (3 LIKE 3)`,2 ^ 3 like 3 AS `(2 ^ 3) LIKE 3` +select 2 ^ 3 LIKE 3, 2 ^ (3 LIKE 3), (2 ^ 3) LIKE 3 union select * from v1; +2 ^ 3 LIKE 3 2 ^ (3 LIKE 3) (2 ^ 3) LIKE 3 +0 3 0 +create or replace view v1 as select 2 ^ 3 REGEXP 3, 2 ^ (3 REGEXP 3), (2 ^ 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 regexp 3 AS `2 ^ 3 REGEXP 3`,2 ^ (3 regexp 3) AS `2 ^ (3 REGEXP 3)`,2 ^ 3 regexp 3 AS `(2 ^ 3) REGEXP 3` +select 2 ^ 3 REGEXP 3, 2 ^ (3 REGEXP 3), (2 ^ 3) REGEXP 3 union select * from v1; +2 ^ 3 REGEXP 3 2 ^ (3 REGEXP 3) (2 ^ 3) REGEXP 3 +0 3 0 +create or replace view v1 as select 2 ^ 3 | 3, 2 ^ (3 | 3), (2 ^ 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 | 3 AS `2 ^ 3 | 3`,2 ^ (3 | 3) AS `2 ^ (3 | 3)`,2 ^ 3 | 3 AS `(2 ^ 3) | 3` +select 2 ^ 3 | 3, 2 ^ (3 | 3), (2 ^ 3) | 3 union select * from v1; +2 ^ 3 | 3 2 ^ (3 | 3) (2 ^ 3) | 3 +3 1 3 +create or replace view v1 as select 2 ^ 0 & 0, 2 ^ (0 & 0), (2 ^ 0) & 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 0 & 0 AS `2 ^ 0 & 0`,2 ^ (0 & 0) AS `2 ^ (0 & 0)`,2 ^ 0 & 0 AS `(2 ^ 0) & 0` +select 2 ^ 0 & 0, 2 ^ (0 & 0), (2 ^ 0) & 0 union select * from v1; +2 ^ 0 & 0 2 ^ (0 & 0) (2 ^ 0) & 0 +0 2 0 +create or replace view v1 as select 2 ^ 3 << 3, 2 ^ (3 << 3), (2 ^ 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 << 3 AS `2 ^ 3 << 3`,2 ^ (3 << 3) AS `2 ^ (3 << 3)`,2 ^ 3 << 3 AS `(2 ^ 3) << 3` +select 2 ^ 3 << 3, 2 ^ (3 << 3), (2 ^ 3) << 3 union select * from v1; +2 ^ 3 << 3 2 ^ (3 << 3) (2 ^ 3) << 3 +8 26 8 +create or replace view v1 as select 2 ^ 3 >> 3, 2 ^ (3 >> 3), (2 ^ 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 >> 3 AS `2 ^ 3 >> 3`,2 ^ (3 >> 3) AS `2 ^ (3 >> 3)`,2 ^ 3 >> 3 AS `(2 ^ 3) >> 3` +select 2 ^ 3 >> 3, 2 ^ (3 >> 3), (2 ^ 3) >> 3 union select * from v1; +2 ^ 3 >> 3 2 ^ (3 >> 3) (2 ^ 3) >> 3 +0 2 0 +create or replace view v1 as select 2 ^ '2000-01-01' +INTERVAL 1 DAY, 2 ^ ('2000-01-01' +INTERVAL 1 DAY), (2 ^ '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ '2000-01-01' + interval 1 day AS `2 ^ '2000-01-01' +INTERVAL 1 DAY`,2 ^ ('2000-01-01' + interval 1 day) AS `2 ^ ('2000-01-01' +INTERVAL 1 DAY)`,2 ^ '2000-01-01' + interval 1 day AS `(2 ^ '2000-01-01') +INTERVAL 1 DAY` +select 2 ^ '2000-01-01' +INTERVAL 1 DAY, 2 ^ ('2000-01-01' +INTERVAL 1 DAY), (2 ^ '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 ^ '2000-01-01' +INTERVAL 1 DAY 2 ^ ('2000-01-01' +INTERVAL 1 DAY) (2 ^ '2000-01-01') +INTERVAL 1 DAY +NULL 20000100 NULL +create or replace view v1 as select 2 ^ 3 + 1, 2 ^ (3 + 1), (2 ^ 3) + 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 + 1 AS `2 ^ 3 + 1`,2 ^ (3 + 1) AS `2 ^ (3 + 1)`,2 ^ 3 + 1 AS `(2 ^ 3) + 1` +select 2 ^ 3 + 1, 2 ^ (3 + 1), (2 ^ 3) + 1 union select * from v1; +2 ^ 3 + 1 2 ^ (3 + 1) (2 ^ 3) + 1 +2 6 2 +create or replace view v1 as select 5 ^ 1 - 1, 5 ^ (1 - 1), (5 ^ 1) - 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 5 ^ 1 - 1 AS `5 ^ 1 - 1`,5 ^ (1 - 1) AS `5 ^ (1 - 1)`,5 ^ 1 - 1 AS `(5 ^ 1) - 1` +select 5 ^ 1 - 1, 5 ^ (1 - 1), (5 ^ 1) - 1 union select * from v1; +5 ^ 1 - 1 5 ^ (1 - 1) (5 ^ 1) - 1 +3 5 3 +create or replace view v1 as select 2 ^ 3 * 3, 2 ^ (3 * 3), (2 ^ 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 * 3 AS `2 ^ 3 * 3`,2 ^ (3 * 3) AS `2 ^ (3 * 3)`,2 ^ 3 * 3 AS `(2 ^ 3) * 3` +select 2 ^ 3 * 3, 2 ^ (3 * 3), (2 ^ 3) * 3 union select * from v1; +2 ^ 3 * 3 2 ^ (3 * 3) (2 ^ 3) * 3 +3 11 3 +create or replace view v1 as select 2 ^ 3 / 3, 2 ^ (3 / 3), (2 ^ 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 / 3 AS `2 ^ 3 / 3`,2 ^ (3 / 3) AS `2 ^ (3 / 3)`,2 ^ 3 / 3 AS `(2 ^ 3) / 3` +select 2 ^ 3 / 3, 2 ^ (3 / 3), (2 ^ 3) / 3 union select * from v1; +2 ^ 3 / 3 2 ^ (3 / 3) (2 ^ 3) / 3 +0.3333 3 0.3333 +create or replace view v1 as select 2 ^ 3 DIV 3, 2 ^ (3 DIV 3), (2 ^ 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 DIV 3 AS `2 ^ 3 DIV 3`,2 ^ (3 DIV 3) AS `2 ^ (3 DIV 3)`,2 ^ 3 DIV 3 AS `(2 ^ 3) DIV 3` +select 2 ^ 3 DIV 3, 2 ^ (3 DIV 3), (2 ^ 3) DIV 3 union select * from v1; +2 ^ 3 DIV 3 2 ^ (3 DIV 3) (2 ^ 3) DIV 3 +0 3 0 +create or replace view v1 as select 2 ^ 3 MOD 3, 2 ^ (3 MOD 3), (2 ^ 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 % 3 AS `2 ^ 3 MOD 3`,2 ^ (3 % 3) AS `2 ^ (3 MOD 3)`,2 ^ 3 % 3 AS `(2 ^ 3) MOD 3` +select 2 ^ 3 MOD 3, 2 ^ (3 MOD 3), (2 ^ 3) MOD 3 union select * from v1; +2 ^ 3 MOD 3 2 ^ (3 MOD 3) (2 ^ 3) MOD 3 +1 2 1 +create or replace view v1 as select 2 ^ 3 % 3, 2 ^ (3 % 3), (2 ^ 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 % 3 AS `2 ^ 3 % 3`,2 ^ (3 % 3) AS `2 ^ (3 % 3)`,2 ^ 3 % 3 AS `(2 ^ 3) % 3` +select 2 ^ 3 % 3, 2 ^ (3 % 3), (2 ^ 3) % 3 union select * from v1; +2 ^ 3 % 3 2 ^ (3 % 3) (2 ^ 3) % 3 +1 2 1 +create or replace view v1 as select 2 ^ 3 BETWEEN 1 AND 3, 2 ^ (3 BETWEEN 1 AND 3), (2 ^ 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 between 1 and 3 AS `2 ^ 3 BETWEEN 1 AND 3`,2 ^ (3 between 1 and 3) AS `2 ^ (3 BETWEEN 1 AND 3)`,2 ^ 3 between 1 and 3 AS `(2 ^ 3) BETWEEN 1 AND 3` +select 2 ^ 3 BETWEEN 1 AND 3, 2 ^ (3 BETWEEN 1 AND 3), (2 ^ 3) BETWEEN 1 AND 3 union select * from v1; +2 ^ 3 BETWEEN 1 AND 3 2 ^ (3 BETWEEN 1 AND 3) (2 ^ 3) BETWEEN 1 AND 3 +1 3 1 +create or replace view v1 as select 2 BETWEEN 1 AND 1 IS FALSE, 2 BETWEEN 1 AND (1 IS FALSE), (2 BETWEEN 1 AND 1) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select (2 between 1 and 1) is false AS `2 BETWEEN 1 AND 1 IS FALSE`,2 between 1 and 1 is false AS `2 BETWEEN 1 AND (1 IS FALSE)`,(2 between 1 and 1) is false AS `(2 BETWEEN 1 AND 1) IS FALSE` +select 2 BETWEEN 1 AND 1 IS FALSE, 2 BETWEEN 1 AND (1 IS FALSE), (2 BETWEEN 1 AND 1) IS FALSE union select * from v1; +2 BETWEEN 1 AND 1 IS FALSE 2 BETWEEN 1 AND (1 IS FALSE) (2 BETWEEN 1 AND 1) IS FALSE +1 0 1 +1 1 1 +create or replace view v1 as select charset(2 BETWEEN 1 AND 3 COLLATE latin1_bin), charset(2 BETWEEN 1 AND (3 COLLATE latin1_bin)), charset((2 BETWEEN 1 AND 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 between 1 and 3 collate latin1_bin) AS `charset(2 BETWEEN 1 AND 3 COLLATE latin1_bin)`,charset(2 between 1 and 3 collate latin1_bin) AS `charset(2 BETWEEN 1 AND (3 COLLATE latin1_bin))`,charset((2 between 1 and 3) collate latin1_bin) AS `charset((2 BETWEEN 1 AND 3) COLLATE latin1_bin)` +select charset(2 BETWEEN 1 AND 3 COLLATE latin1_bin), charset(2 BETWEEN 1 AND (3 COLLATE latin1_bin)), charset((2 BETWEEN 1 AND 3) COLLATE latin1_bin) union select * from v1; +charset(2 BETWEEN 1 AND 3 COLLATE latin1_bin) charset(2 BETWEEN 1 AND (3 COLLATE latin1_bin)) charset((2 BETWEEN 1 AND 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 IN (0,1), 2 BETWEEN 1 AND (3 IN (0,1)), (2 BETWEEN 1 AND 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 in (0,1) AS `2 BETWEEN 1 AND 3 IN (0,1)`,2 between 1 and 3 in (0,1) AS `2 BETWEEN 1 AND (3 IN (0,1))`,(2 between 1 and 3) in (0,1) AS `(2 BETWEEN 1 AND 3) IN (0,1)` +select 2 BETWEEN 1 AND 3 IN (0,1), 2 BETWEEN 1 AND (3 IN (0,1)), (2 BETWEEN 1 AND 3) IN (0,1) union select * from v1; +2 BETWEEN 1 AND 3 IN (0,1) 2 BETWEEN 1 AND (3 IN (0,1)) (2 BETWEEN 1 AND 3) IN (0,1) +0 0 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 OR 3, 2 BETWEEN 1 AND (3 OR 3), (2 BETWEEN 1 AND 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 or 3 AS `2 BETWEEN 1 AND 3 OR 3`,2 between 1 and (3 or 3) AS `2 BETWEEN 1 AND (3 OR 3)`,2 between 1 and 3 or 3 AS `(2 BETWEEN 1 AND 3) OR 3` +select 2 BETWEEN 1 AND 3 OR 3, 2 BETWEEN 1 AND (3 OR 3), (2 BETWEEN 1 AND 3) OR 3 union select * from v1; +2 BETWEEN 1 AND 3 OR 3 2 BETWEEN 1 AND (3 OR 3) (2 BETWEEN 1 AND 3) OR 3 +1 0 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 || 3, 2 BETWEEN 1 AND (3 || 3), (2 BETWEEN 1 AND 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 or 3 AS `2 BETWEEN 1 AND 3 || 3`,2 between 1 and (3 or 3) AS `2 BETWEEN 1 AND (3 || 3)`,2 between 1 and 3 or 3 AS `(2 BETWEEN 1 AND 3) || 3` +select 2 BETWEEN 1 AND 3 || 3, 2 BETWEEN 1 AND (3 || 3), (2 BETWEEN 1 AND 3) || 3 union select * from v1; +2 BETWEEN 1 AND 3 || 3 2 BETWEEN 1 AND (3 || 3) (2 BETWEEN 1 AND 3) || 3 +1 0 1 +create or replace view v1 as select 2 BETWEEN 1 AND 1 XOR 1, 2 BETWEEN 1 AND (1 XOR 1), (2 BETWEEN 1 AND 1) XOR 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 1 xor 1 AS `2 BETWEEN 1 AND 1 XOR 1`,2 between 1 and (1 xor 1) AS `2 BETWEEN 1 AND (1 XOR 1)`,2 between 1 and 1 xor 1 AS `(2 BETWEEN 1 AND 1) XOR 1` +select 2 BETWEEN 1 AND 1 XOR 1, 2 BETWEEN 1 AND (1 XOR 1), (2 BETWEEN 1 AND 1) XOR 1 union select * from v1; +2 BETWEEN 1 AND 1 XOR 1 2 BETWEEN 1 AND (1 XOR 1) (2 BETWEEN 1 AND 1) XOR 1 +1 0 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 AND 3, 2 BETWEEN 1 AND (3 AND 3), (2 BETWEEN 1 AND 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 and 3 AS `2 BETWEEN 1 AND 3 AND 3`,2 between 1 and (3 and 3) AS `2 BETWEEN 1 AND (3 AND 3)`,2 between 1 and 3 and 3 AS `(2 BETWEEN 1 AND 3) AND 3` +select 2 BETWEEN 1 AND 3 AND 3, 2 BETWEEN 1 AND (3 AND 3), (2 BETWEEN 1 AND 3) AND 3 union select * from v1; +2 BETWEEN 1 AND 3 AND 3 2 BETWEEN 1 AND (3 AND 3) (2 BETWEEN 1 AND 3) AND 3 +1 0 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 && 3, 2 BETWEEN 1 AND (3 && 3), (2 BETWEEN 1 AND 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 and 3 AS `2 BETWEEN 1 AND 3 && 3`,2 between 1 and (3 and 3) AS `2 BETWEEN 1 AND (3 && 3)`,2 between 1 and 3 and 3 AS `(2 BETWEEN 1 AND 3) && 3` +select 2 BETWEEN 1 AND 3 && 3, 2 BETWEEN 1 AND (3 && 3), (2 BETWEEN 1 AND 3) && 3 union select * from v1; +2 BETWEEN 1 AND 3 && 3 2 BETWEEN 1 AND (3 && 3) (2 BETWEEN 1 AND 3) && 3 +1 0 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 = 1, 2 BETWEEN 1 AND (3 = 1), (2 BETWEEN 1 AND 3) = 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select (2 between 1 and 3) = 1 AS `2 BETWEEN 1 AND 3 = 1`,2 between 1 and 3 = 1 AS `2 BETWEEN 1 AND (3 = 1)`,(2 between 1 and 3) = 1 AS `(2 BETWEEN 1 AND 3) = 1` +select 2 BETWEEN 1 AND 3 = 1, 2 BETWEEN 1 AND (3 = 1), (2 BETWEEN 1 AND 3) = 1 union select * from v1; +2 BETWEEN 1 AND 3 = 1 2 BETWEEN 1 AND (3 = 1) (2 BETWEEN 1 AND 3) = 1 +1 0 1 +1 1 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 <=> 1, 2 BETWEEN 1 AND (3 <=> 1), (2 BETWEEN 1 AND 3) <=> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select (2 between 1 and 3) <=> 1 AS `2 BETWEEN 1 AND 3 <=> 1`,2 between 1 and 3 <=> 1 AS `2 BETWEEN 1 AND (3 <=> 1)`,(2 between 1 and 3) <=> 1 AS `(2 BETWEEN 1 AND 3) <=> 1` +select 2 BETWEEN 1 AND 3 <=> 1, 2 BETWEEN 1 AND (3 <=> 1), (2 BETWEEN 1 AND 3) <=> 1 union select * from v1; +2 BETWEEN 1 AND 3 <=> 1 2 BETWEEN 1 AND (3 <=> 1) (2 BETWEEN 1 AND 3) <=> 1 +1 0 1 +1 1 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 >= 1, 2 BETWEEN 1 AND (3 >= 1), (2 BETWEEN 1 AND 3) >= 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select (2 between 1 and 3) >= 1 AS `2 BETWEEN 1 AND 3 >= 1`,2 between 1 and 3 >= 1 AS `2 BETWEEN 1 AND (3 >= 1)`,(2 between 1 and 3) >= 1 AS `(2 BETWEEN 1 AND 3) >= 1` +select 2 BETWEEN 1 AND 3 >= 1, 2 BETWEEN 1 AND (3 >= 1), (2 BETWEEN 1 AND 3) >= 1 union select * from v1; +2 BETWEEN 1 AND 3 >= 1 2 BETWEEN 1 AND (3 >= 1) (2 BETWEEN 1 AND 3) >= 1 +1 0 1 +1 1 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 <= 3, 2 BETWEEN 1 AND (3 <= 3), (2 BETWEEN 1 AND 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select (2 between 1 and 3) <= 3 AS `2 BETWEEN 1 AND 3 <= 3`,2 between 1 and 3 <= 3 AS `2 BETWEEN 1 AND (3 <= 3)`,(2 between 1 and 3) <= 3 AS `(2 BETWEEN 1 AND 3) <= 3` +select 2 BETWEEN 1 AND 3 <= 3, 2 BETWEEN 1 AND (3 <= 3), (2 BETWEEN 1 AND 3) <= 3 union select * from v1; +2 BETWEEN 1 AND 3 <= 3 2 BETWEEN 1 AND (3 <= 3) (2 BETWEEN 1 AND 3) <= 3 +1 0 1 +1 1 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 < 3, 2 BETWEEN 1 AND (3 < 3), (2 BETWEEN 1 AND 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select (2 between 1 and 3) < 3 AS `2 BETWEEN 1 AND 3 < 3`,2 between 1 and 3 < 3 AS `2 BETWEEN 1 AND (3 < 3)`,(2 between 1 and 3) < 3 AS `(2 BETWEEN 1 AND 3) < 3` +select 2 BETWEEN 1 AND 3 < 3, 2 BETWEEN 1 AND (3 < 3), (2 BETWEEN 1 AND 3) < 3 union select * from v1; +2 BETWEEN 1 AND 3 < 3 2 BETWEEN 1 AND (3 < 3) (2 BETWEEN 1 AND 3) < 3 +1 0 1 +1 1 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 <> 3, 2 BETWEEN 1 AND (3 <> 3), (2 BETWEEN 1 AND 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select (2 between 1 and 3) <> 3 AS `2 BETWEEN 1 AND 3 <> 3`,2 between 1 and 3 <> 3 AS `2 BETWEEN 1 AND (3 <> 3)`,(2 between 1 and 3) <> 3 AS `(2 BETWEEN 1 AND 3) <> 3` +select 2 BETWEEN 1 AND 3 <> 3, 2 BETWEEN 1 AND (3 <> 3), (2 BETWEEN 1 AND 3) <> 3 union select * from v1; +2 BETWEEN 1 AND 3 <> 3 2 BETWEEN 1 AND (3 <> 3) (2 BETWEEN 1 AND 3) <> 3 +1 0 1 +1 1 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 > 0, 2 BETWEEN 1 AND (3 > 0), (2 BETWEEN 1 AND 3) > 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select (2 between 1 and 3) > 0 AS `2 BETWEEN 1 AND 3 > 0`,2 between 1 and 3 > 0 AS `2 BETWEEN 1 AND (3 > 0)`,(2 between 1 and 3) > 0 AS `(2 BETWEEN 1 AND 3) > 0` +select 2 BETWEEN 1 AND 3 > 0, 2 BETWEEN 1 AND (3 > 0), (2 BETWEEN 1 AND 3) > 0 union select * from v1; +2 BETWEEN 1 AND 3 > 0 2 BETWEEN 1 AND (3 > 0) (2 BETWEEN 1 AND 3) > 0 +1 0 1 +1 1 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 != 3, 2 BETWEEN 1 AND (3 != 3), (2 BETWEEN 1 AND 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select (2 between 1 and 3) <> 3 AS `2 BETWEEN 1 AND 3 != 3`,2 between 1 and 3 <> 3 AS `2 BETWEEN 1 AND (3 != 3)`,(2 between 1 and 3) <> 3 AS `(2 BETWEEN 1 AND 3) != 3` +select 2 BETWEEN 1 AND 3 != 3, 2 BETWEEN 1 AND (3 != 3), (2 BETWEEN 1 AND 3) != 3 union select * from v1; +2 BETWEEN 1 AND 3 != 3 2 BETWEEN 1 AND (3 != 3) (2 BETWEEN 1 AND 3) != 3 +1 0 1 +1 1 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 LIKE 1, 2 BETWEEN 1 AND (3 LIKE 1), (2 BETWEEN 1 AND 3) LIKE 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 like 1 AS `2 BETWEEN 1 AND 3 LIKE 1`,2 between 1 and 3 like 1 AS `2 BETWEEN 1 AND (3 LIKE 1)`,(2 between 1 and 3) like 1 AS `(2 BETWEEN 1 AND 3) LIKE 1` +select 2 BETWEEN 1 AND 3 LIKE 1, 2 BETWEEN 1 AND (3 LIKE 1), (2 BETWEEN 1 AND 3) LIKE 1 union select * from v1; +2 BETWEEN 1 AND 3 LIKE 1 2 BETWEEN 1 AND (3 LIKE 1) (2 BETWEEN 1 AND 3) LIKE 1 +0 0 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 REGEXP 1, 2 BETWEEN 1 AND (3 REGEXP 1), (2 BETWEEN 1 AND 3) REGEXP 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 regexp 1 AS `2 BETWEEN 1 AND 3 REGEXP 1`,2 between 1 and 3 regexp 1 AS `2 BETWEEN 1 AND (3 REGEXP 1)`,(2 between 1 and 3) regexp 1 AS `(2 BETWEEN 1 AND 3) REGEXP 1` +select 2 BETWEEN 1 AND 3 REGEXP 1, 2 BETWEEN 1 AND (3 REGEXP 1), (2 BETWEEN 1 AND 3) REGEXP 1 union select * from v1; +2 BETWEEN 1 AND 3 REGEXP 1 2 BETWEEN 1 AND (3 REGEXP 1) (2 BETWEEN 1 AND 3) REGEXP 1 +0 0 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 | 3, 2 BETWEEN 1 AND (3 | 3), (2 BETWEEN 1 AND 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 | 3 AS `2 BETWEEN 1 AND 3 | 3`,2 between 1 and 3 | 3 AS `2 BETWEEN 1 AND (3 | 3)`,(2 between 1 and 3) | 3 AS `(2 BETWEEN 1 AND 3) | 3` +select 2 BETWEEN 1 AND 3 | 3, 2 BETWEEN 1 AND (3 | 3), (2 BETWEEN 1 AND 3) | 3 union select * from v1; +2 BETWEEN 1 AND 3 | 3 2 BETWEEN 1 AND (3 | 3) (2 BETWEEN 1 AND 3) | 3 +1 1 3 +create or replace view v1 as select 2 BETWEEN 1 AND 2 & 2, 2 BETWEEN 1 AND (2 & 2), (2 BETWEEN 1 AND 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 2 & 2 AS `2 BETWEEN 1 AND 2 & 2`,2 between 1 and 2 & 2 AS `2 BETWEEN 1 AND (2 & 2)`,(2 between 1 and 2) & 2 AS `(2 BETWEEN 1 AND 2) & 2` +select 2 BETWEEN 1 AND 2 & 2, 2 BETWEEN 1 AND (2 & 2), (2 BETWEEN 1 AND 2) & 2 union select * from v1; +2 BETWEEN 1 AND 2 & 2 2 BETWEEN 1 AND (2 & 2) (2 BETWEEN 1 AND 2) & 2 +1 1 0 +create or replace view v1 as select 2 BETWEEN 1 AND 3 << 3, 2 BETWEEN 1 AND (3 << 3), (2 BETWEEN 1 AND 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 << 3 AS `2 BETWEEN 1 AND 3 << 3`,2 between 1 and 3 << 3 AS `2 BETWEEN 1 AND (3 << 3)`,(2 between 1 and 3) << 3 AS `(2 BETWEEN 1 AND 3) << 3` +select 2 BETWEEN 1 AND 3 << 3, 2 BETWEEN 1 AND (3 << 3), (2 BETWEEN 1 AND 3) << 3 union select * from v1; +2 BETWEEN 1 AND 3 << 3 2 BETWEEN 1 AND (3 << 3) (2 BETWEEN 1 AND 3) << 3 +1 1 8 +create or replace view v1 as select 2 BETWEEN 1 AND 4 >> 1, 2 BETWEEN 1 AND (4 >> 1), (2 BETWEEN 1 AND 4) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 4 >> 1 AS `2 BETWEEN 1 AND 4 >> 1`,2 between 1 and 4 >> 1 AS `2 BETWEEN 1 AND (4 >> 1)`,(2 between 1 and 4) >> 1 AS `(2 BETWEEN 1 AND 4) >> 1` +select 2 BETWEEN 1 AND 4 >> 1, 2 BETWEEN 1 AND (4 >> 1), (2 BETWEEN 1 AND 4) >> 1 union select * from v1; +2 BETWEEN 1 AND 4 >> 1 2 BETWEEN 1 AND (4 >> 1) (2 BETWEEN 1 AND 4) >> 1 +1 1 0 +create or replace view v1 as select 2 BETWEEN 1 AND '2000-01-01' +INTERVAL 1 DAY, 2 BETWEEN 1 AND ('2000-01-01' +INTERVAL 1 DAY), (2 BETWEEN 1 AND '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and '2000-01-01' + interval 1 day AS `2 BETWEEN 1 AND '2000-01-01' +INTERVAL 1 DAY`,2 between 1 and '2000-01-01' + interval 1 day AS `2 BETWEEN 1 AND ('2000-01-01' +INTERVAL 1 DAY)`,(2 between 1 and '2000-01-01') + interval 1 day AS `(2 BETWEEN 1 AND '2000-01-01') +INTERVAL 1 DAY` +select 2 BETWEEN 1 AND '2000-01-01' +INTERVAL 1 DAY, 2 BETWEEN 1 AND ('2000-01-01' +INTERVAL 1 DAY), (2 BETWEEN 1 AND '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 BETWEEN 1 AND '2000-01-01' +INTERVAL 1 DAY 2 BETWEEN 1 AND ('2000-01-01' +INTERVAL 1 DAY) (2 BETWEEN 1 AND '2000-01-01') +INTERVAL 1 DAY +1 1 NULL +create or replace view v1 as select 2 BETWEEN 1 AND 3 + 3, 2 BETWEEN 1 AND (3 + 3), (2 BETWEEN 1 AND 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 + 3 AS `2 BETWEEN 1 AND 3 + 3`,2 between 1 and 3 + 3 AS `2 BETWEEN 1 AND (3 + 3)`,(2 between 1 and 3) + 3 AS `(2 BETWEEN 1 AND 3) + 3` +select 2 BETWEEN 1 AND 3 + 3, 2 BETWEEN 1 AND (3 + 3), (2 BETWEEN 1 AND 3) + 3 union select * from v1; +2 BETWEEN 1 AND 3 + 3 2 BETWEEN 1 AND (3 + 3) (2 BETWEEN 1 AND 3) + 3 +1 1 4 +create or replace view v1 as select 2 BETWEEN 1 AND 3 - 3, 2 BETWEEN 1 AND (3 - 3), (2 BETWEEN 1 AND 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 - 3 AS `2 BETWEEN 1 AND 3 - 3`,2 between 1 and 3 - 3 AS `2 BETWEEN 1 AND (3 - 3)`,(2 between 1 and 3) - 3 AS `(2 BETWEEN 1 AND 3) - 3` +select 2 BETWEEN 1 AND 3 - 3, 2 BETWEEN 1 AND (3 - 3), (2 BETWEEN 1 AND 3) - 3 union select * from v1; +2 BETWEEN 1 AND 3 - 3 2 BETWEEN 1 AND (3 - 3) (2 BETWEEN 1 AND 3) - 3 +0 0 -2 +create or replace view v1 as select 2 BETWEEN 1 AND 3 * 3, 2 BETWEEN 1 AND (3 * 3), (2 BETWEEN 1 AND 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 * 3 AS `2 BETWEEN 1 AND 3 * 3`,2 between 1 and 3 * 3 AS `2 BETWEEN 1 AND (3 * 3)`,(2 between 1 and 3) * 3 AS `(2 BETWEEN 1 AND 3) * 3` +select 2 BETWEEN 1 AND 3 * 3, 2 BETWEEN 1 AND (3 * 3), (2 BETWEEN 1 AND 3) * 3 union select * from v1; +2 BETWEEN 1 AND 3 * 3 2 BETWEEN 1 AND (3 * 3) (2 BETWEEN 1 AND 3) * 3 +1 1 3 +create or replace view v1 as select 2 BETWEEN 1 AND 3 / 3, 2 BETWEEN 1 AND (3 / 3), (2 BETWEEN 1 AND 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 / 3 AS `2 BETWEEN 1 AND 3 / 3`,2 between 1 and 3 / 3 AS `2 BETWEEN 1 AND (3 / 3)`,(2 between 1 and 3) / 3 AS `(2 BETWEEN 1 AND 3) / 3` +select 2 BETWEEN 1 AND 3 / 3, 2 BETWEEN 1 AND (3 / 3), (2 BETWEEN 1 AND 3) / 3 union select * from v1; +2 BETWEEN 1 AND 3 / 3 2 BETWEEN 1 AND (3 / 3) (2 BETWEEN 1 AND 3) / 3 +0 0 0.3333 +create or replace view v1 as select 2 BETWEEN 1 AND 4 DIV 2, 2 BETWEEN 1 AND (4 DIV 2), (2 BETWEEN 1 AND 4) DIV 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 4 DIV 2 AS `2 BETWEEN 1 AND 4 DIV 2`,2 between 1 and 4 DIV 2 AS `2 BETWEEN 1 AND (4 DIV 2)`,(2 between 1 and 4) DIV 2 AS `(2 BETWEEN 1 AND 4) DIV 2` +select 2 BETWEEN 1 AND 4 DIV 2, 2 BETWEEN 1 AND (4 DIV 2), (2 BETWEEN 1 AND 4) DIV 2 union select * from v1; +2 BETWEEN 1 AND 4 DIV 2 2 BETWEEN 1 AND (4 DIV 2) (2 BETWEEN 1 AND 4) DIV 2 +1 1 0 +create or replace view v1 as select 2 BETWEEN 1 AND 3 MOD 3, 2 BETWEEN 1 AND (3 MOD 3), (2 BETWEEN 1 AND 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 % 3 AS `2 BETWEEN 1 AND 3 MOD 3`,2 between 1 and 3 % 3 AS `2 BETWEEN 1 AND (3 MOD 3)`,(2 between 1 and 3) % 3 AS `(2 BETWEEN 1 AND 3) MOD 3` +select 2 BETWEEN 1 AND 3 MOD 3, 2 BETWEEN 1 AND (3 MOD 3), (2 BETWEEN 1 AND 3) MOD 3 union select * from v1; +2 BETWEEN 1 AND 3 MOD 3 2 BETWEEN 1 AND (3 MOD 3) (2 BETWEEN 1 AND 3) MOD 3 +0 0 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 % 3, 2 BETWEEN 1 AND (3 % 3), (2 BETWEEN 1 AND 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 % 3 AS `2 BETWEEN 1 AND 3 % 3`,2 between 1 and 3 % 3 AS `2 BETWEEN 1 AND (3 % 3)`,(2 between 1 and 3) % 3 AS `(2 BETWEEN 1 AND 3) % 3` +select 2 BETWEEN 1 AND 3 % 3, 2 BETWEEN 1 AND (3 % 3), (2 BETWEEN 1 AND 3) % 3 union select * from v1; +2 BETWEEN 1 AND 3 % 3 2 BETWEEN 1 AND (3 % 3) (2 BETWEEN 1 AND 3) % 3 +0 0 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 ^ 3, 2 BETWEEN 1 AND (3 ^ 3), (2 BETWEEN 1 AND 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 ^ 3 AS `2 BETWEEN 1 AND 3 ^ 3`,2 between 1 and 3 ^ 3 AS `2 BETWEEN 1 AND (3 ^ 3)`,(2 between 1 and 3) ^ 3 AS `(2 BETWEEN 1 AND 3) ^ 3` +select 2 BETWEEN 1 AND 3 ^ 3, 2 BETWEEN 1 AND (3 ^ 3), (2 BETWEEN 1 AND 3) ^ 3 union select * from v1; +2 BETWEEN 1 AND 3 ^ 3 2 BETWEEN 1 AND (3 ^ 3) (2 BETWEEN 1 AND 3) ^ 3 +0 0 2 +create or replace view v1 as select 2 BETWEEN 1 AND 3 BETWEEN 1 AND 3, 2 BETWEEN 1 AND (3 BETWEEN 1 AND 3), (2 BETWEEN 1 AND 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 between 1 and 3 AS `2 BETWEEN 1 AND 3 BETWEEN 1 AND 3`,2 between 1 and 3 between 1 and 3 AS `2 BETWEEN 1 AND (3 BETWEEN 1 AND 3)`,2 between 1 and 3 between 1 and 3 AS `(2 BETWEEN 1 AND 3) BETWEEN 1 AND 3` +select 2 BETWEEN 1 AND 3 BETWEEN 1 AND 3, 2 BETWEEN 1 AND (3 BETWEEN 1 AND 3), (2 BETWEEN 1 AND 3) BETWEEN 1 AND 3 union select * from v1; +2 BETWEEN 1 AND 3 BETWEEN 1 AND 3 2 BETWEEN 1 AND (3 BETWEEN 1 AND 3) (2 BETWEEN 1 AND 3) BETWEEN 1 AND 3 +0 0 1 +0 0 0 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 IS FALSE, 2 LIKE 2 ESCAPE (3 IS FALSE), (2 LIKE 2 ESCAPE 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 2 escape 3 is false AS `2 LIKE 2 ESCAPE 3 IS FALSE`,2 like 2 escape 3 is false AS `2 LIKE 2 ESCAPE (3 IS FALSE)`,2 like 2 escape 3 is false AS `(2 LIKE 2 ESCAPE 3) IS FALSE` +select 2 LIKE 2 ESCAPE 3 IS FALSE, 2 LIKE 2 ESCAPE (3 IS FALSE), (2 LIKE 2 ESCAPE 3) IS FALSE union select * from v1; +2 LIKE 2 ESCAPE 3 IS FALSE 2 LIKE 2 ESCAPE (3 IS FALSE) (2 LIKE 2 ESCAPE 3) IS FALSE +0 1 0 +0 0 0 +create or replace view v1 as select charset(2 LIKE 1 ESCAPE 3 COLLATE latin1_bin), charset(2 LIKE 1 ESCAPE (3 COLLATE latin1_bin)), charset((2 LIKE 1 ESCAPE 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 like 1 escape 3 collate latin1_bin) AS `charset(2 LIKE 1 ESCAPE 3 COLLATE latin1_bin)`,charset(2 like 1 escape 3 collate latin1_bin) AS `charset(2 LIKE 1 ESCAPE (3 COLLATE latin1_bin))`,charset((2 like 1 escape 3) collate latin1_bin) AS `charset((2 LIKE 1 ESCAPE 3) COLLATE latin1_bin)` +select charset(2 LIKE 1 ESCAPE 3 COLLATE latin1_bin), charset(2 LIKE 1 ESCAPE (3 COLLATE latin1_bin)), charset((2 LIKE 1 ESCAPE 3) COLLATE latin1_bin) union select * from v1; +charset(2 LIKE 1 ESCAPE 3 COLLATE latin1_bin) charset(2 LIKE 1 ESCAPE (3 COLLATE latin1_bin)) charset((2 LIKE 1 ESCAPE 3) COLLATE latin1_bin) +binary binary latin1 +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 IN(0,1), 2 LIKE 1 ESCAPE (3 IN(0,1)), (2 LIKE 1 ESCAPE 3) IN(0,1); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN(0,1), 2 LIKE 1 ESCAPE (3 IN(0,1)), (2 LIKE 1 ESCAPE 3) IN(0,1)' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 like 1 escape 3 collate latin1_bin) AS `charset(2 LIKE 1 ESCAPE 3 COLLATE latin1_bin)`,charset(2 like 1 escape 3 collate latin1_bin) AS `charset(2 LIKE 1 ESCAPE (3 COLLATE latin1_bin))`,charset((2 like 1 escape 3) collate latin1_bin) AS `charset((2 LIKE 1 ESCAPE 3) COLLATE latin1_bin)` +select 2 LIKE 1 ESCAPE 3 IN(0,1), 2 LIKE 1 ESCAPE (3 IN(0,1)), (2 LIKE 1 ESCAPE 3) IN(0,1) union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN(0,1), 2 LIKE 1 ESCAPE (3 IN(0,1)), (2 LIKE 1 ESCAPE 3) IN(0,1) union selec...' at line 1 +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 OR 4, 2 LIKE 1 ESCAPE (3 OR 4), (2 LIKE 1 ESCAPE 3) OR 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 or 4 AS `2 LIKE 1 ESCAPE 3 OR 4`,2 like 1 escape 3 or 4 AS `2 LIKE 1 ESCAPE (3 OR 4)`,2 like 1 escape 3 or 4 AS `(2 LIKE 1 ESCAPE 3) OR 4` +select 2 LIKE 1 ESCAPE 3 OR 4, 2 LIKE 1 ESCAPE (3 OR 4), (2 LIKE 1 ESCAPE 3) OR 4 union select * from v1; +2 LIKE 1 ESCAPE 3 OR 4 2 LIKE 1 ESCAPE (3 OR 4) (2 LIKE 1 ESCAPE 3) OR 4 +1 0 1 +1 1 1 +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 || 4, 2 LIKE 1 ESCAPE (3 || 4), (2 LIKE 1 ESCAPE 3) || 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 or 4 AS `2 LIKE 1 ESCAPE 3 || 4`,2 like 1 escape 3 or 4 AS `2 LIKE 1 ESCAPE (3 || 4)`,2 like 1 escape 3 or 4 AS `(2 LIKE 1 ESCAPE 3) || 4` +select 2 LIKE 1 ESCAPE 3 || 4, 2 LIKE 1 ESCAPE (3 || 4), (2 LIKE 1 ESCAPE 3) || 4 union select * from v1; +2 LIKE 1 ESCAPE 3 || 4 2 LIKE 1 ESCAPE (3 || 4) (2 LIKE 1 ESCAPE 3) || 4 +1 0 1 +1 1 1 +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 XOR 4, 2 LIKE 1 ESCAPE (3 XOR 4), (2 LIKE 1 ESCAPE 3) XOR 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 xor 4 AS `2 LIKE 1 ESCAPE 3 XOR 4`,2 like 1 escape 3 xor 4 AS `2 LIKE 1 ESCAPE (3 XOR 4)`,2 like 1 escape 3 xor 4 AS `(2 LIKE 1 ESCAPE 3) XOR 4` +select 2 LIKE 1 ESCAPE 3 XOR 4, 2 LIKE 1 ESCAPE (3 XOR 4), (2 LIKE 1 ESCAPE 3) XOR 4 union select * from v1; +2 LIKE 1 ESCAPE 3 XOR 4 2 LIKE 1 ESCAPE (3 XOR 4) (2 LIKE 1 ESCAPE 3) XOR 4 +1 0 1 +1 1 1 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 AND 0, 2 LIKE 2 ESCAPE (3 AND 0), (2 LIKE 2 ESCAPE 3) AND 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 2 escape 3 and 0 AS `2 LIKE 2 ESCAPE 3 AND 0`,2 like 2 escape 3 and 0 AS `2 LIKE 2 ESCAPE (3 AND 0)`,2 like 2 escape 3 and 0 AS `(2 LIKE 2 ESCAPE 3) AND 0` +select 2 LIKE 2 ESCAPE 3 AND 0, 2 LIKE 2 ESCAPE (3 AND 0), (2 LIKE 2 ESCAPE 3) AND 0 union select * from v1; +2 LIKE 2 ESCAPE 3 AND 0 2 LIKE 2 ESCAPE (3 AND 0) (2 LIKE 2 ESCAPE 3) AND 0 +0 1 0 +0 0 0 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 && 0, 2 LIKE 2 ESCAPE (3 && 0), (2 LIKE 2 ESCAPE 3) && 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 2 escape 3 and 0 AS `2 LIKE 2 ESCAPE 3 && 0`,2 like 2 escape 3 and 0 AS `2 LIKE 2 ESCAPE (3 && 0)`,2 like 2 escape 3 and 0 AS `(2 LIKE 2 ESCAPE 3) && 0` +select 2 LIKE 2 ESCAPE 3 && 0, 2 LIKE 2 ESCAPE (3 && 0), (2 LIKE 2 ESCAPE 3) && 0 union select * from v1; +2 LIKE 2 ESCAPE 3 && 0 2 LIKE 2 ESCAPE (3 && 0) (2 LIKE 2 ESCAPE 3) && 0 +0 1 0 +0 0 0 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 = 4, 2 LIKE 2 ESCAPE (3 = 4), (2 LIKE 2 ESCAPE 3) = 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 2 escape 3 = 4 AS `2 LIKE 2 ESCAPE 3 = 4`,2 like 2 escape 3 = 4 AS `2 LIKE 2 ESCAPE (3 = 4)`,2 like 2 escape 3 = 4 AS `(2 LIKE 2 ESCAPE 3) = 4` +select 2 LIKE 2 ESCAPE 3 = 4, 2 LIKE 2 ESCAPE (3 = 4), (2 LIKE 2 ESCAPE 3) = 4 union select * from v1; +2 LIKE 2 ESCAPE 3 = 4 2 LIKE 2 ESCAPE (3 = 4) (2 LIKE 2 ESCAPE 3) = 4 +0 1 0 +0 0 0 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 <=> 4, 2 LIKE 2 ESCAPE (3 <=> 4), (2 LIKE 2 ESCAPE 3) <=> 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 2 escape 3 <=> 4 AS `2 LIKE 2 ESCAPE 3 <=> 4`,2 like 2 escape 3 <=> 4 AS `2 LIKE 2 ESCAPE (3 <=> 4)`,2 like 2 escape 3 <=> 4 AS `(2 LIKE 2 ESCAPE 3) <=> 4` +select 2 LIKE 2 ESCAPE 3 <=> 4, 2 LIKE 2 ESCAPE (3 <=> 4), (2 LIKE 2 ESCAPE 3) <=> 4 union select * from v1; +2 LIKE 2 ESCAPE 3 <=> 4 2 LIKE 2 ESCAPE (3 <=> 4) (2 LIKE 2 ESCAPE 3) <=> 4 +0 1 0 +0 0 0 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 >= 4, 2 LIKE 2 ESCAPE (3 >= 4), (2 LIKE 2 ESCAPE 3) >= 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 2 escape 3 >= 4 AS `2 LIKE 2 ESCAPE 3 >= 4`,2 like 2 escape 3 >= 4 AS `2 LIKE 2 ESCAPE (3 >= 4)`,2 like 2 escape 3 >= 4 AS `(2 LIKE 2 ESCAPE 3) >= 4` +select 2 LIKE 2 ESCAPE 3 >= 4, 2 LIKE 2 ESCAPE (3 >= 4), (2 LIKE 2 ESCAPE 3) >= 4 union select * from v1; +2 LIKE 2 ESCAPE 3 >= 4 2 LIKE 2 ESCAPE (3 >= 4) (2 LIKE 2 ESCAPE 3) >= 4 +0 1 0 +0 0 0 +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 <= 4, 2 LIKE 1 ESCAPE (3 <= 4), (2 LIKE 1 ESCAPE 3) <= 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <= 4 AS `2 LIKE 1 ESCAPE 3 <= 4`,2 like 1 escape 3 <= 4 AS `2 LIKE 1 ESCAPE (3 <= 4)`,2 like 1 escape 3 <= 4 AS `(2 LIKE 1 ESCAPE 3) <= 4` +select 2 LIKE 1 ESCAPE 3 <= 4, 2 LIKE 1 ESCAPE (3 <= 4), (2 LIKE 1 ESCAPE 3) <= 4 union select * from v1; +2 LIKE 1 ESCAPE 3 <= 4 2 LIKE 1 ESCAPE (3 <= 4) (2 LIKE 1 ESCAPE 3) <= 4 +1 0 1 +1 1 1 +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 < 4, 2 LIKE 1 ESCAPE (3 < 4), (2 LIKE 1 ESCAPE 3) < 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 < 4 AS `2 LIKE 1 ESCAPE 3 < 4`,2 like 1 escape 3 < 4 AS `2 LIKE 1 ESCAPE (3 < 4)`,2 like 1 escape 3 < 4 AS `(2 LIKE 1 ESCAPE 3) < 4` +select 2 LIKE 1 ESCAPE 3 < 4, 2 LIKE 1 ESCAPE (3 < 4), (2 LIKE 1 ESCAPE 3) < 4 union select * from v1; +2 LIKE 1 ESCAPE 3 < 4 2 LIKE 1 ESCAPE (3 < 4) (2 LIKE 1 ESCAPE 3) < 4 +1 0 1 +1 1 1 +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 <> 4, 2 LIKE 1 ESCAPE (3 <> 4), (2 LIKE 1 ESCAPE 3) <> 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 <> 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 <> 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) <> 4` +select 2 LIKE 1 ESCAPE 3 <> 4, 2 LIKE 1 ESCAPE (3 <> 4), (2 LIKE 1 ESCAPE 3) <> 4 union select * from v1; +2 LIKE 1 ESCAPE 3 <> 4 2 LIKE 1 ESCAPE (3 <> 4) (2 LIKE 1 ESCAPE 3) <> 4 +1 0 1 +1 1 1 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 > 4, 2 LIKE 2 ESCAPE (3 > 4), (2 LIKE 2 ESCAPE 3) > 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 2 escape 3 > 4 AS `2 LIKE 2 ESCAPE 3 > 4`,2 like 2 escape 3 > 4 AS `2 LIKE 2 ESCAPE (3 > 4)`,2 like 2 escape 3 > 4 AS `(2 LIKE 2 ESCAPE 3) > 4` +select 2 LIKE 2 ESCAPE 3 > 4, 2 LIKE 2 ESCAPE (3 > 4), (2 LIKE 2 ESCAPE 3) > 4 union select * from v1; +2 LIKE 2 ESCAPE 3 > 4 2 LIKE 2 ESCAPE (3 > 4) (2 LIKE 2 ESCAPE 3) > 4 +0 1 0 +0 0 0 +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 != 4, 2 LIKE 1 ESCAPE (3 != 4), (2 LIKE 1 ESCAPE 3) != 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 1 ESCAPE 3 != 4, 2 LIKE 1 ESCAPE (3 != 4), (2 LIKE 1 ESCAPE 3) != 4 union select * from v1; +2 LIKE 1 ESCAPE 3 != 4 2 LIKE 1 ESCAPE (3 != 4) (2 LIKE 1 ESCAPE 3) != 4 +1 0 1 +1 1 1 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 LIKE 4, 2 LIKE 2 ESCAPE (3 LIKE 4), (2 LIKE 2 ESCAPE 3) LIKE 4; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE 4, 2 LIKE 2 ESCAPE (3 LIKE 4), (2 LIKE 2 ESCAPE 3) LIKE 4' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 2 ESCAPE 3 LIKE 4, 2 LIKE 2 ESCAPE (3 LIKE 4), (2 LIKE 2 ESCAPE 3) LIKE 4 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE 4, 2 LIKE 2 ESCAPE (3 LIKE 4), (2 LIKE 2 ESCAPE 3) LIKE 4 union select *...' at line 1 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 REGEXP 4, 2 LIKE 2 ESCAPE (3 REGEXP 4), (2 LIKE 2 ESCAPE 3) REGEXP 4; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'REGEXP 4, 2 LIKE 2 ESCAPE (3 REGEXP 4), (2 LIKE 2 ESCAPE 3) REGEXP 4' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 2 ESCAPE 3 REGEXP 4, 2 LIKE 2 ESCAPE (3 REGEXP 4), (2 LIKE 2 ESCAPE 3) REGEXP 4 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'REGEXP 4, 2 LIKE 2 ESCAPE (3 REGEXP 4), (2 LIKE 2 ESCAPE 3) REGEXP 4 union se...' at line 1 +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 | 4, 2 LIKE 1 ESCAPE (3 | 4), (2 LIKE 1 ESCAPE 3) | 4; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '| 4, 2 LIKE 1 ESCAPE (3 | 4), (2 LIKE 1 ESCAPE 3) | 4' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 1 ESCAPE 3 | 4, 2 LIKE 1 ESCAPE (3 | 4), (2 LIKE 1 ESCAPE 3) | 4 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '| 4, 2 LIKE 1 ESCAPE (3 | 4), (2 LIKE 1 ESCAPE 3) | 4 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 & 4, 2 LIKE 2 ESCAPE (3 & 4), (2 LIKE 2 ESCAPE 3) & 4; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '& 4, 2 LIKE 2 ESCAPE (3 & 4), (2 LIKE 2 ESCAPE 3) & 4' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 2 ESCAPE 3 & 4, 2 LIKE 2 ESCAPE (3 & 4), (2 LIKE 2 ESCAPE 3) & 4 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '& 4, 2 LIKE 2 ESCAPE (3 & 4), (2 LIKE 2 ESCAPE 3) & 4 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 2 ESCAPE 1 << 1, 2 LIKE 2 ESCAPE (1 << 1), (2 LIKE 2 ESCAPE 1) << 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '<< 1, 2 LIKE 2 ESCAPE (1 << 1), (2 LIKE 2 ESCAPE 1) << 1' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 2 ESCAPE 1 << 1, 2 LIKE 2 ESCAPE (1 << 1), (2 LIKE 2 ESCAPE 1) << 1 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '<< 1, 2 LIKE 2 ESCAPE (1 << 1), (2 LIKE 2 ESCAPE 1) << 1 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 >> 4, 2 LIKE 2 ESCAPE (3 >> 4), (2 LIKE 2 ESCAPE 3) >> 4; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '>> 4, 2 LIKE 2 ESCAPE (3 >> 4), (2 LIKE 2 ESCAPE 3) >> 4' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 2 ESCAPE 3 >> 4, 2 LIKE 2 ESCAPE (3 >> 4), (2 LIKE 2 ESCAPE 3) >> 4 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '>> 4, 2 LIKE 2 ESCAPE (3 >> 4), (2 LIKE 2 ESCAPE 3) >> 4 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 +INTERVAL 1 DAY, 2 LIKE 1 ESCAPE (3 +INTERVAL 1 DAY), (2 LIKE 1 ESCAPE 3) +INTERVAL 1 DAY; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+INTERVAL 1 DAY, 2 LIKE 1 ESCAPE (3 +INTERVAL 1 DAY), (2 LIKE 1 ESCAPE 3) +IN...' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 1 ESCAPE 3 +INTERVAL 1 DAY, 2 LIKE 1 ESCAPE (3 +INTERVAL 1 DAY), (2 LIKE 1 ESCAPE 3) +INTERVAL 1 DAY union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+INTERVAL 1 DAY, 2 LIKE 1 ESCAPE (3 +INTERVAL 1 DAY), (2 LIKE 1 ESCAPE 3) +IN...' at line 1 +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 + 4, 2 LIKE 1 ESCAPE (3 + 4), (2 LIKE 1 ESCAPE 3) + 4; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+ 4, 2 LIKE 1 ESCAPE (3 + 4), (2 LIKE 1 ESCAPE 3) + 4' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 1 ESCAPE 3 + 4, 2 LIKE 1 ESCAPE (3 + 4), (2 LIKE 1 ESCAPE 3) + 4 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+ 4, 2 LIKE 1 ESCAPE (3 + 4), (2 LIKE 1 ESCAPE 3) + 4 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 2 ESCAPE 1 - 1, 2 LIKE 2 ESCAPE (1 - 1), (2 LIKE 2 ESCAPE 1) - 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '- 1, 2 LIKE 2 ESCAPE (1 - 1), (2 LIKE 2 ESCAPE 1) - 1' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 2 ESCAPE 1 - 1, 2 LIKE 2 ESCAPE (1 - 1), (2 LIKE 2 ESCAPE 1) - 1 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '- 1, 2 LIKE 2 ESCAPE (1 - 1), (2 LIKE 2 ESCAPE 1) - 1 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 * 0, 2 LIKE 2 ESCAPE (3 * 0), (2 LIKE 2 ESCAPE 3) * 0; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '* 0, 2 LIKE 2 ESCAPE (3 * 0), (2 LIKE 2 ESCAPE 3) * 0' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 2 ESCAPE 3 * 0, 2 LIKE 2 ESCAPE (3 * 0), (2 LIKE 2 ESCAPE 3) * 0 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '* 0, 2 LIKE 2 ESCAPE (3 * 0), (2 LIKE 2 ESCAPE 3) * 0 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 DIV 3, 2 LIKE 2 ESCAPE (3 DIV 3), (2 LIKE 2 ESCAPE 3) DIV 3; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'DIV 3, 2 LIKE 2 ESCAPE (3 DIV 3), (2 LIKE 2 ESCAPE 3) DIV 3' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 2 ESCAPE 3 DIV 3, 2 LIKE 2 ESCAPE (3 DIV 3), (2 LIKE 2 ESCAPE 3) DIV 3 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'DIV 3, 2 LIKE 2 ESCAPE (3 DIV 3), (2 LIKE 2 ESCAPE 3) DIV 3 union select * fr...' at line 1 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 MOD 1, 2 LIKE 2 ESCAPE (3 MOD 1), (2 LIKE 2 ESCAPE 3) MOD 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'MOD 1, 2 LIKE 2 ESCAPE (3 MOD 1), (2 LIKE 2 ESCAPE 3) MOD 1' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 2 ESCAPE 3 MOD 1, 2 LIKE 2 ESCAPE (3 MOD 1), (2 LIKE 2 ESCAPE 3) MOD 1 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'MOD 1, 2 LIKE 2 ESCAPE (3 MOD 1), (2 LIKE 2 ESCAPE 3) MOD 1 union select * fr...' at line 1 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 % 1, 2 LIKE 2 ESCAPE (3 % 1), (2 LIKE 2 ESCAPE 3) % 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '% 1, 2 LIKE 2 ESCAPE (3 % 1), (2 LIKE 2 ESCAPE 3) % 1' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 2 ESCAPE 3 % 1, 2 LIKE 2 ESCAPE (3 % 1), (2 LIKE 2 ESCAPE 3) % 1 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '% 1, 2 LIKE 2 ESCAPE (3 % 1), (2 LIKE 2 ESCAPE 3) % 1 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 ^ 4, 2 LIKE 1 ESCAPE (3 ^ 4), (2 LIKE 1 ESCAPE 3) ^ 4; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '^ 4, 2 LIKE 1 ESCAPE (3 ^ 4), (2 LIKE 1 ESCAPE 3) ^ 4' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 1 ESCAPE 3 ^ 4, 2 LIKE 1 ESCAPE (3 ^ 4), (2 LIKE 1 ESCAPE 3) ^ 4 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '^ 4, 2 LIKE 1 ESCAPE (3 ^ 4), (2 LIKE 1 ESCAPE 3) ^ 4 union select * from v1' at line 1 +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 BETWEEN 2 AND 4, 2 LIKE 2 ESCAPE (3 BETWEEN 2 AND 4), (2 LIKE 2 ESCAPE 3) BETWEEN 2 AND 4; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'BETWEEN 2 AND 4, 2 LIKE 2 ESCAPE (3 BETWEEN 2 AND 4), (2 LIKE 2 ESCAPE 3) BET...' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 LIKE 2 ESCAPE 3 BETWEEN 2 AND 4, 2 LIKE 2 ESCAPE (3 BETWEEN 2 AND 4), (2 LIKE 2 ESCAPE 3) BETWEEN 2 AND 4 union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'BETWEEN 2 AND 4, 2 LIKE 2 ESCAPE (3 BETWEEN 2 AND 4), (2 LIKE 2 ESCAPE 3) BET...' at line 1 +create or replace view v1 as select NOT 2 IN (SELECT 0 UNION SELECT 2), NOT (2 IN (SELECT 0 UNION SELECT 2)), (NOT 2) IN (SELECT 0 UNION SELECT 2); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(2 in (select 0 union select 2)) AS `NOT 2 IN (SELECT 0 UNION SELECT 2)`,!(2 in (select 0 union select 2)) AS `NOT (2 IN (SELECT 0 UNION SELECT 2))`,!2 in (select 0 union select 2) AS `(NOT 2) IN (SELECT 0 UNION SELECT 2)` +select NOT 2 IN (SELECT 0 UNION SELECT 2), NOT (2 IN (SELECT 0 UNION SELECT 2)), (NOT 2) IN (SELECT 0 UNION SELECT 2) union select * from v1; +NOT 2 IN (SELECT 0 UNION SELECT 2) NOT (2 IN (SELECT 0 UNION SELECT 2)) (NOT 2) IN (SELECT 0 UNION SELECT 2) +0 0 1 +create or replace view v1 as select - 2 IN (SELECT 2 UNION SELECT 1), - (2 IN (SELECT 2 UNION SELECT 1)), (- 2) IN (SELECT 2 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -2 in (select 2 union select 1) AS `- 2 IN (SELECT 2 UNION SELECT 1)`,-(2 in (select 2 union select 1)) AS `- (2 IN (SELECT 2 UNION SELECT 1))`,-2 in (select 2 union select 1) AS `(- 2) IN (SELECT 2 UNION SELECT 1)` +select - 2 IN (SELECT 2 UNION SELECT 1), - (2 IN (SELECT 2 UNION SELECT 1)), (- 2) IN (SELECT 2 UNION SELECT 1) union select * from v1; +- 2 IN (SELECT 2 UNION SELECT 1) - (2 IN (SELECT 2 UNION SELECT 1)) (- 2) IN (SELECT 2 UNION SELECT 1) +0 -1 0 +create or replace view v1 as select ~ 2 IN (SELECT 0 UNION SELECT 1), ~ (2 IN (SELECT 0 UNION SELECT 1)), (~ 2) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select ~2 in (select 0 union select 1) AS `~ 2 IN (SELECT 0 UNION SELECT 1)`,~(2 in (select 0 union select 1)) AS `~ (2 IN (SELECT 0 UNION SELECT 1))`,~2 in (select 0 union select 1) AS `(~ 2) IN (SELECT 0 UNION SELECT 1)` +select ~ 2 IN (SELECT 0 UNION SELECT 1), ~ (2 IN (SELECT 0 UNION SELECT 1)), (~ 2) IN (SELECT 0 UNION SELECT 1) union select * from v1; +~ 2 IN (SELECT 0 UNION SELECT 1) ~ (2 IN (SELECT 0 UNION SELECT 1)) (~ 2) IN (SELECT 0 UNION SELECT 1) +0 18446744073709551615 0 +create or replace view v1 as select ! 2 IN (SELECT 0 UNION SELECT 2), ! (2 IN (SELECT 0 UNION SELECT 2)), (! 2) IN (SELECT 0 UNION SELECT 2); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !2 in (select 0 union select 2) AS `! 2 IN (SELECT 0 UNION SELECT 2)`,!(2 in (select 0 union select 2)) AS `! (2 IN (SELECT 0 UNION SELECT 2))`,!2 in (select 0 union select 2) AS `(! 2) IN (SELECT 0 UNION SELECT 2)` +select ! 2 IN (SELECT 0 UNION SELECT 2), ! (2 IN (SELECT 0 UNION SELECT 2)), (! 2) IN (SELECT 0 UNION SELECT 2) union select * from v1; +! 2 IN (SELECT 0 UNION SELECT 2) ! (2 IN (SELECT 0 UNION SELECT 2)) (! 2) IN (SELECT 0 UNION SELECT 2) +1 0 1 +create or replace view v1 as select BINARY 'c' IN (SELECT 'C' UNION SELECT 'X'), BINARY ('c' IN (SELECT 'C' UNION SELECT 'X')), (BINARY 'c') IN (SELECT 'C' UNION SELECT 'X'); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast('c' as char charset binary) in (select 'C' union select 'X') AS `BINARY 'c' IN (SELECT 'C' UNION SELECT 'X')`,cast('c' in (select 'C' union select 'X') as char charset binary) AS `BINARY ('c' IN (SELECT 'C' UNION SELECT 'X'))`,cast('c' as char charset binary) in (select 'C' union select 'X') AS `(BINARY 'c') IN (SELECT 'C' UNION SELECT 'X')` +select BINARY 'c' IN (SELECT 'C' UNION SELECT 'X'), BINARY ('c' IN (SELECT 'C' UNION SELECT 'X')), (BINARY 'c') IN (SELECT 'C' UNION SELECT 'X') union select * from v1; +BINARY 'c' IN (SELECT 'C' UNION SELECT 'X') BINARY ('c' IN (SELECT 'C' UNION SELECT 'X')) (BINARY 'c') IN (SELECT 'C' UNION SELECT 'X') +0 1 0 +create or replace view v1 as select 0 OR 3 IN (SELECT 3 UNION SELECT 10), 0 OR (3 IN (SELECT 3 UNION SELECT 10)), (0 OR 3) IN (SELECT 3 UNION SELECT 10); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 or 3 in (select 3 union select 10) AS `0 OR 3 IN (SELECT 3 UNION SELECT 10)`,0 or 3 in (select 3 union select 10) AS `0 OR (3 IN (SELECT 3 UNION SELECT 10))`,0 or 3 in (select 3 union select 10) AS `(0 OR 3) IN (SELECT 3 UNION SELECT 10)` +select 0 OR 3 IN (SELECT 3 UNION SELECT 10), 0 OR (3 IN (SELECT 3 UNION SELECT 10)), (0 OR 3) IN (SELECT 3 UNION SELECT 10) union select * from v1; +0 OR 3 IN (SELECT 3 UNION SELECT 10) 0 OR (3 IN (SELECT 3 UNION SELECT 10)) (0 OR 3) IN (SELECT 3 UNION SELECT 10) +1 1 0 +1 1 1 +create or replace view v1 as select 0 || 3 IN (SELECT 3 UNION SELECT 10), 0 || (3 IN (SELECT 3 UNION SELECT 10)), (0 || 3) IN (SELECT 3 UNION SELECT 10); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 or 3 in (select 3 union select 10) AS `0 || 3 IN (SELECT 3 UNION SELECT 10)`,0 or 3 in (select 3 union select 10) AS `0 || (3 IN (SELECT 3 UNION SELECT 10))`,0 or 3 in (select 3 union select 10) AS `(0 || 3) IN (SELECT 3 UNION SELECT 10)` +select 0 || 3 IN (SELECT 3 UNION SELECT 10), 0 || (3 IN (SELECT 3 UNION SELECT 10)), (0 || 3) IN (SELECT 3 UNION SELECT 10) union select * from v1; +0 || 3 IN (SELECT 3 UNION SELECT 10) 0 || (3 IN (SELECT 3 UNION SELECT 10)) (0 || 3) IN (SELECT 3 UNION SELECT 10) +1 1 0 +1 1 1 +create or replace view v1 as select 2 XOR 3 IN (SELECT 4 UNION SELECT 5), 2 XOR (3 IN (SELECT 4 UNION SELECT 5)), (2 XOR 3) IN (SELECT 4 UNION SELECT 5); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor 3 in (select 4 union select 5) AS `2 XOR 3 IN (SELECT 4 UNION SELECT 5)`,2 xor 3 in (select 4 union select 5) AS `2 XOR (3 IN (SELECT 4 UNION SELECT 5))`,2 xor 3 in (select 4 union select 5) AS `(2 XOR 3) IN (SELECT 4 UNION SELECT 5)` +select 2 XOR 3 IN (SELECT 4 UNION SELECT 5), 2 XOR (3 IN (SELECT 4 UNION SELECT 5)), (2 XOR 3) IN (SELECT 4 UNION SELECT 5) union select * from v1; +2 XOR 3 IN (SELECT 4 UNION SELECT 5) 2 XOR (3 IN (SELECT 4 UNION SELECT 5)) (2 XOR 3) IN (SELECT 4 UNION SELECT 5) +1 1 0 +1 1 1 +create or replace view v1 as select 2 AND 3 IN (SELECT 0 UNION SELECT 1), 2 AND (3 IN (SELECT 0 UNION SELECT 1)), (2 AND 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 in (select 0 union select 1) AS `2 AND 3 IN (SELECT 0 UNION SELECT 1)`,2 and 3 in (select 0 union select 1) AS `2 AND (3 IN (SELECT 0 UNION SELECT 1))`,2 and 3 in (select 0 union select 1) AS `(2 AND 3) IN (SELECT 0 UNION SELECT 1)` +select 2 AND 3 IN (SELECT 0 UNION SELECT 1), 2 AND (3 IN (SELECT 0 UNION SELECT 1)), (2 AND 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 AND 3 IN (SELECT 0 UNION SELECT 1) 2 AND (3 IN (SELECT 0 UNION SELECT 1)) (2 AND 3) IN (SELECT 0 UNION SELECT 1) +0 0 1 +0 0 0 +create or replace view v1 as select 2 && 3 IN (SELECT 0 UNION SELECT 1), 2 && (3 IN (SELECT 0 UNION SELECT 1)), (2 && 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 and 3 in (select 0 union select 1) AS `2 && 3 IN (SELECT 0 UNION SELECT 1)`,2 and 3 in (select 0 union select 1) AS `2 && (3 IN (SELECT 0 UNION SELECT 1))`,2 and 3 in (select 0 union select 1) AS `(2 && 3) IN (SELECT 0 UNION SELECT 1)` +select 2 && 3 IN (SELECT 0 UNION SELECT 1), 2 && (3 IN (SELECT 0 UNION SELECT 1)), (2 && 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 && 3 IN (SELECT 0 UNION SELECT 1) 2 && (3 IN (SELECT 0 UNION SELECT 1)) (2 && 3) IN (SELECT 0 UNION SELECT 1) +0 0 1 +0 0 0 +create or replace view v1 as select 2 = 3 IN (SELECT 0 UNION SELECT 1), 2 = (3 IN (SELECT 0 UNION SELECT 1)), (2 = 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = (3 in (select 0 union select 1)) AS `2 = 3 IN (SELECT 0 UNION SELECT 1)`,2 = (3 in (select 0 union select 1)) AS `2 = (3 IN (SELECT 0 UNION SELECT 1))`,2 = 3 in (select 0 union select 1) AS `(2 = 3) IN (SELECT 0 UNION SELECT 1)` +select 2 = 3 IN (SELECT 0 UNION SELECT 1), 2 = (3 IN (SELECT 0 UNION SELECT 1)), (2 = 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 = 3 IN (SELECT 0 UNION SELECT 1) 2 = (3 IN (SELECT 0 UNION SELECT 1)) (2 = 3) IN (SELECT 0 UNION SELECT 1) +0 0 1 +0 0 0 +create or replace view v1 as select 2 <=> 3 IN (SELECT 0 UNION SELECT 1), 2 <=> (3 IN (SELECT 0 UNION SELECT 1)), (2 <=> 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> (3 in (select 0 union select 1)) AS `2 <=> 3 IN (SELECT 0 UNION SELECT 1)`,2 <=> (3 in (select 0 union select 1)) AS `2 <=> (3 IN (SELECT 0 UNION SELECT 1))`,2 <=> 3 in (select 0 union select 1) AS `(2 <=> 3) IN (SELECT 0 UNION SELECT 1)` +select 2 <=> 3 IN (SELECT 0 UNION SELECT 1), 2 <=> (3 IN (SELECT 0 UNION SELECT 1)), (2 <=> 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 <=> 3 IN (SELECT 0 UNION SELECT 1) 2 <=> (3 IN (SELECT 0 UNION SELECT 1)) (2 <=> 3) IN (SELECT 0 UNION SELECT 1) +0 0 1 +0 0 0 +create or replace view v1 as select 2 >= 3 IN (SELECT 1 UNION SELECT 1), 2 >= (3 IN (SELECT 1 UNION SELECT 1)), (2 >= 3) IN (SELECT 1 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= (3 in (select 1 union select 1)) AS `2 >= 3 IN (SELECT 1 UNION SELECT 1)`,2 >= (3 in (select 1 union select 1)) AS `2 >= (3 IN (SELECT 1 UNION SELECT 1))`,2 >= 3 in (select 1 union select 1) AS `(2 >= 3) IN (SELECT 1 UNION SELECT 1)` +select 2 >= 3 IN (SELECT 1 UNION SELECT 1), 2 >= (3 IN (SELECT 1 UNION SELECT 1)), (2 >= 3) IN (SELECT 1 UNION SELECT 1) union select * from v1; +2 >= 3 IN (SELECT 1 UNION SELECT 1) 2 >= (3 IN (SELECT 1 UNION SELECT 1)) (2 >= 3) IN (SELECT 1 UNION SELECT 1) +1 1 0 +1 1 1 +create or replace view v1 as select 2 <= 3 IN (SELECT 0 UNION SELECT 1), 2 <= (3 IN (SELECT 0 UNION SELECT 1)), (2 <= 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= (3 in (select 0 union select 1)) AS `2 <= 3 IN (SELECT 0 UNION SELECT 1)`,2 <= (3 in (select 0 union select 1)) AS `2 <= (3 IN (SELECT 0 UNION SELECT 1))`,2 <= 3 in (select 0 union select 1) AS `(2 <= 3) IN (SELECT 0 UNION SELECT 1)` +select 2 <= 3 IN (SELECT 0 UNION SELECT 1), 2 <= (3 IN (SELECT 0 UNION SELECT 1)), (2 <= 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 <= 3 IN (SELECT 0 UNION SELECT 1) 2 <= (3 IN (SELECT 0 UNION SELECT 1)) (2 <= 3) IN (SELECT 0 UNION SELECT 1) +0 0 1 +0 0 0 +create or replace view v1 as select 2 < 3 IN (SELECT 0 UNION SELECT 1), 2 < (3 IN (SELECT 0 UNION SELECT 1)), (2 < 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < (3 in (select 0 union select 1)) AS `2 < 3 IN (SELECT 0 UNION SELECT 1)`,2 < (3 in (select 0 union select 1)) AS `2 < (3 IN (SELECT 0 UNION SELECT 1))`,2 < 3 in (select 0 union select 1) AS `(2 < 3) IN (SELECT 0 UNION SELECT 1)` +select 2 < 3 IN (SELECT 0 UNION SELECT 1), 2 < (3 IN (SELECT 0 UNION SELECT 1)), (2 < 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 < 3 IN (SELECT 0 UNION SELECT 1) 2 < (3 IN (SELECT 0 UNION SELECT 1)) (2 < 3) IN (SELECT 0 UNION SELECT 1) +0 0 1 +0 0 0 +create or replace view v1 as select 2 <> 3 IN (SELECT 0 UNION SELECT 0), 2 <> (3 IN (SELECT 0 UNION SELECT 0)), (2 <> 3) IN (SELECT 0 UNION SELECT 0); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> (3 in (select 0 union select 0)) AS `2 <> 3 IN (SELECT 0 UNION SELECT 0)`,2 <> (3 in (select 0 union select 0)) AS `2 <> (3 IN (SELECT 0 UNION SELECT 0))`,2 <> 3 in (select 0 union select 0) AS `(2 <> 3) IN (SELECT 0 UNION SELECT 0)` +select 2 <> 3 IN (SELECT 0 UNION SELECT 0), 2 <> (3 IN (SELECT 0 UNION SELECT 0)), (2 <> 3) IN (SELECT 0 UNION SELECT 0) union select * from v1; +2 <> 3 IN (SELECT 0 UNION SELECT 0) 2 <> (3 IN (SELECT 0 UNION SELECT 0)) (2 <> 3) IN (SELECT 0 UNION SELECT 0) +1 1 0 +1 1 1 +create or replace view v1 as select 2 > 3 IN (SELECT 1 UNION SELECT 1), 2 > (3 IN (SELECT 1 UNION SELECT 1)), (2 > 3) IN (SELECT 1 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 > (3 in (select 1 union select 1)) AS `2 > 3 IN (SELECT 1 UNION SELECT 1)`,2 > (3 in (select 1 union select 1)) AS `2 > (3 IN (SELECT 1 UNION SELECT 1))`,2 > 3 in (select 1 union select 1) AS `(2 > 3) IN (SELECT 1 UNION SELECT 1)` +select 2 > 3 IN (SELECT 1 UNION SELECT 1), 2 > (3 IN (SELECT 1 UNION SELECT 1)), (2 > 3) IN (SELECT 1 UNION SELECT 1) union select * from v1; +2 > 3 IN (SELECT 1 UNION SELECT 1) 2 > (3 IN (SELECT 1 UNION SELECT 1)) (2 > 3) IN (SELECT 1 UNION SELECT 1) +1 1 0 +1 1 1 +create or replace view v1 as select 2 != 3 IN (SELECT 0 UNION SELECT 0), 2 != (3 IN (SELECT 0 UNION SELECT 0)), (2 != 3) IN (SELECT 0 UNION SELECT 0); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> (3 in (select 0 union select 0)) AS `2 != 3 IN (SELECT 0 UNION SELECT 0)`,2 <> (3 in (select 0 union select 0)) AS `2 != (3 IN (SELECT 0 UNION SELECT 0))`,2 <> 3 in (select 0 union select 0) AS `(2 != 3) IN (SELECT 0 UNION SELECT 0)` +select 2 != 3 IN (SELECT 0 UNION SELECT 0), 2 != (3 IN (SELECT 0 UNION SELECT 0)), (2 != 3) IN (SELECT 0 UNION SELECT 0) union select * from v1; +2 != 3 IN (SELECT 0 UNION SELECT 0) 2 != (3 IN (SELECT 0 UNION SELECT 0)) (2 != 3) IN (SELECT 0 UNION SELECT 0) +1 1 0 +1 1 1 +create or replace view v1 as select 2 LIKE 3 IN (SELECT 0 UNION SELECT 1), 2 LIKE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIKE 3) IN (SELECT 0 UNION SELECT 1); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (SELECT 0 UNION SELECT 1), 2 LIKE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIK...' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> (3 in (select 0 union select 0)) AS `2 != 3 IN (SELECT 0 UNION SELECT 0)`,2 <> (3 in (select 0 union select 0)) AS `2 != (3 IN (SELECT 0 UNION SELECT 0))`,2 <> 3 in (select 0 union select 0) AS `(2 != 3) IN (SELECT 0 UNION SELECT 0)` +select 2 LIKE 3 IN (SELECT 0 UNION SELECT 1), 2 LIKE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIKE 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (SELECT 0 UNION SELECT 1), 2 LIKE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIK...' at line 1 +create or replace view v1 as select 2 REGEXP 3 IN (SELECT 0 UNION SELECT 1), 2 REGEXP (3 IN (SELECT 0 UNION SELECT 1)), (2 REGEXP 3) IN (SELECT 0 UNION SELECT 1); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (SELECT 0 UNION SELECT 1), 2 REGEXP (3 IN (SELECT 0 UNION SELECT 1)), (2 R...' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <> (3 in (select 0 union select 0)) AS `2 != 3 IN (SELECT 0 UNION SELECT 0)`,2 <> (3 in (select 0 union select 0)) AS `2 != (3 IN (SELECT 0 UNION SELECT 0))`,2 <> 3 in (select 0 union select 0) AS `(2 != 3) IN (SELECT 0 UNION SELECT 0)` +select 2 REGEXP 3 IN (SELECT 0 UNION SELECT 1), 2 REGEXP (3 IN (SELECT 0 UNION SELECT 1)), (2 REGEXP 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (SELECT 0 UNION SELECT 1), 2 REGEXP (3 IN (SELECT 0 UNION SELECT 1)), (2 R...' at line 1 +create or replace view v1 as select 2 | 3 IN (SELECT 0 UNION SELECT 1), 2 | (3 IN (SELECT 0 UNION SELECT 1)), (2 | 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | 3 in (select 0 union select 1) AS `2 | 3 IN (SELECT 0 UNION SELECT 1)`,2 | (3 in (select 0 union select 1)) AS `2 | (3 IN (SELECT 0 UNION SELECT 1))`,2 | 3 in (select 0 union select 1) AS `(2 | 3) IN (SELECT 0 UNION SELECT 1)` +select 2 | 3 IN (SELECT 0 UNION SELECT 1), 2 | (3 IN (SELECT 0 UNION SELECT 1)), (2 | 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 | 3 IN (SELECT 0 UNION SELECT 1) 2 | (3 IN (SELECT 0 UNION SELECT 1)) (2 | 3) IN (SELECT 0 UNION SELECT 1) +0 2 0 +create or replace view v1 as select 2 & 4 IN (SELECT 0 UNION SELECT 1), 2 & (4 IN (SELECT 0 UNION SELECT 1)), (2 & 4) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & 4 in (select 0 union select 1) AS `2 & 4 IN (SELECT 0 UNION SELECT 1)`,2 & (4 in (select 0 union select 1)) AS `2 & (4 IN (SELECT 0 UNION SELECT 1))`,2 & 4 in (select 0 union select 1) AS `(2 & 4) IN (SELECT 0 UNION SELECT 1)` +select 2 & 4 IN (SELECT 0 UNION SELECT 1), 2 & (4 IN (SELECT 0 UNION SELECT 1)), (2 & 4) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 & 4 IN (SELECT 0 UNION SELECT 1) 2 & (4 IN (SELECT 0 UNION SELECT 1)) (2 & 4) IN (SELECT 0 UNION SELECT 1) +1 0 1 +create or replace view v1 as select 2 << 3 IN (SELECT 0 UNION SELECT 1), 2 << (3 IN (SELECT 0 UNION SELECT 1)), (2 << 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << 3 in (select 0 union select 1) AS `2 << 3 IN (SELECT 0 UNION SELECT 1)`,2 << (3 in (select 0 union select 1)) AS `2 << (3 IN (SELECT 0 UNION SELECT 1))`,2 << 3 in (select 0 union select 1) AS `(2 << 3) IN (SELECT 0 UNION SELECT 1)` +select 2 << 3 IN (SELECT 0 UNION SELECT 1), 2 << (3 IN (SELECT 0 UNION SELECT 1)), (2 << 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 << 3 IN (SELECT 0 UNION SELECT 1) 2 << (3 IN (SELECT 0 UNION SELECT 1)) (2 << 3) IN (SELECT 0 UNION SELECT 1) +0 2 0 +create or replace view v1 as select 2 >> 3 IN (SELECT 0 UNION SELECT 1), 2 >> (3 IN (SELECT 0 UNION SELECT 1)), (2 >> 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> 3 in (select 0 union select 1) AS `2 >> 3 IN (SELECT 0 UNION SELECT 1)`,2 >> (3 in (select 0 union select 1)) AS `2 >> (3 IN (SELECT 0 UNION SELECT 1))`,2 >> 3 in (select 0 union select 1) AS `(2 >> 3) IN (SELECT 0 UNION SELECT 1)` +select 2 >> 3 IN (SELECT 0 UNION SELECT 1), 2 >> (3 IN (SELECT 0 UNION SELECT 1)), (2 >> 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 >> 3 IN (SELECT 0 UNION SELECT 1) 2 >> (3 IN (SELECT 0 UNION SELECT 1)) (2 >> 3) IN (SELECT 0 UNION SELECT 1) +1 2 1 +create or replace view v1 as select 2 + 3 IN (SELECT 0 UNION SELECT 1), 2 + (3 IN (SELECT 0 UNION SELECT 1)), (2 + 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + 3 in (select 0 union select 1) AS `2 + 3 IN (SELECT 0 UNION SELECT 1)`,2 + (3 in (select 0 union select 1)) AS `2 + (3 IN (SELECT 0 UNION SELECT 1))`,2 + 3 in (select 0 union select 1) AS `(2 + 3) IN (SELECT 0 UNION SELECT 1)` +select 2 + 3 IN (SELECT 0 UNION SELECT 1), 2 + (3 IN (SELECT 0 UNION SELECT 1)), (2 + 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 + 3 IN (SELECT 0 UNION SELECT 1) 2 + (3 IN (SELECT 0 UNION SELECT 1)) (2 + 3) IN (SELECT 0 UNION SELECT 1) +0 2 0 +create or replace view v1 as select 2 - 3 IN (SELECT 0 UNION SELECT 1), 2 - (3 IN (SELECT 0 UNION SELECT 1)), (2 - 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - 3 in (select 0 union select 1) AS `2 - 3 IN (SELECT 0 UNION SELECT 1)`,2 - (3 in (select 0 union select 1)) AS `2 - (3 IN (SELECT 0 UNION SELECT 1))`,2 - 3 in (select 0 union select 1) AS `(2 - 3) IN (SELECT 0 UNION SELECT 1)` +select 2 - 3 IN (SELECT 0 UNION SELECT 1), 2 - (3 IN (SELECT 0 UNION SELECT 1)), (2 - 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 - 3 IN (SELECT 0 UNION SELECT 1) 2 - (3 IN (SELECT 0 UNION SELECT 1)) (2 - 3) IN (SELECT 0 UNION SELECT 1) +0 2 0 +create or replace view v1 as select 2 * 0 IN (SELECT 0 UNION SELECT 1), 2 * (0 IN (SELECT 0 UNION SELECT 1)), (2 * 0) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * 0 in (select 0 union select 1) AS `2 * 0 IN (SELECT 0 UNION SELECT 1)`,2 * (0 in (select 0 union select 1)) AS `2 * (0 IN (SELECT 0 UNION SELECT 1))`,2 * 0 in (select 0 union select 1) AS `(2 * 0) IN (SELECT 0 UNION SELECT 1)` +select 2 * 0 IN (SELECT 0 UNION SELECT 1), 2 * (0 IN (SELECT 0 UNION SELECT 1)), (2 * 0) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 * 0 IN (SELECT 0 UNION SELECT 1) 2 * (0 IN (SELECT 0 UNION SELECT 1)) (2 * 0) IN (SELECT 0 UNION SELECT 1) +1 2 1 +create or replace view v1 as select 2 / 3 IN (SELECT 0 UNION SELECT 1), 2 / (3 IN (SELECT 0 UNION SELECT 1)), (2 / 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / 3 in (select 0 union select 1) AS `2 / 3 IN (SELECT 0 UNION SELECT 1)`,2 / (3 in (select 0 union select 1)) AS `2 / (3 IN (SELECT 0 UNION SELECT 1))`,2 / 3 in (select 0 union select 1) AS `(2 / 3) IN (SELECT 0 UNION SELECT 1)` +select 2 / 3 IN (SELECT 0 UNION SELECT 1), 2 / (3 IN (SELECT 0 UNION SELECT 1)), (2 / 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 / 3 IN (SELECT 0 UNION SELECT 1) 2 / (3 IN (SELECT 0 UNION SELECT 1)) (2 / 3) IN (SELECT 0 UNION SELECT 1) +0 NULL 0 +create or replace view v1 as select 2 DIV 3 IN (SELECT 0 UNION SELECT 1), 2 DIV (3 IN (SELECT 0 UNION SELECT 1)), (2 DIV 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV 3 in (select 0 union select 1) AS `2 DIV 3 IN (SELECT 0 UNION SELECT 1)`,2 DIV (3 in (select 0 union select 1)) AS `2 DIV (3 IN (SELECT 0 UNION SELECT 1))`,2 DIV 3 in (select 0 union select 1) AS `(2 DIV 3) IN (SELECT 0 UNION SELECT 1)` +select 2 DIV 3 IN (SELECT 0 UNION SELECT 1), 2 DIV (3 IN (SELECT 0 UNION SELECT 1)), (2 DIV 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 DIV 3 IN (SELECT 0 UNION SELECT 1) 2 DIV (3 IN (SELECT 0 UNION SELECT 1)) (2 DIV 3) IN (SELECT 0 UNION SELECT 1) +1 NULL 1 +create or replace view v1 as select 2 MOD 3 IN (SELECT 0 UNION SELECT 1), 2 MOD (3 IN (SELECT 0 UNION SELECT 1)), (2 MOD 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 in (select 0 union select 1) AS `2 MOD 3 IN (SELECT 0 UNION SELECT 1)`,2 % (3 in (select 0 union select 1)) AS `2 MOD (3 IN (SELECT 0 UNION SELECT 1))`,2 % 3 in (select 0 union select 1) AS `(2 MOD 3) IN (SELECT 0 UNION SELECT 1)` +select 2 MOD 3 IN (SELECT 0 UNION SELECT 1), 2 MOD (3 IN (SELECT 0 UNION SELECT 1)), (2 MOD 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 MOD 3 IN (SELECT 0 UNION SELECT 1) 2 MOD (3 IN (SELECT 0 UNION SELECT 1)) (2 MOD 3) IN (SELECT 0 UNION SELECT 1) +0 NULL 0 +create or replace view v1 as select 2 % 3 IN (SELECT 0 UNION SELECT 1), 2 % (3 IN (SELECT 0 UNION SELECT 1)), (2 % 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % 3 in (select 0 union select 1) AS `2 % 3 IN (SELECT 0 UNION SELECT 1)`,2 % (3 in (select 0 union select 1)) AS `2 % (3 IN (SELECT 0 UNION SELECT 1))`,2 % 3 in (select 0 union select 1) AS `(2 % 3) IN (SELECT 0 UNION SELECT 1)` +select 2 % 3 IN (SELECT 0 UNION SELECT 1), 2 % (3 IN (SELECT 0 UNION SELECT 1)), (2 % 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 % 3 IN (SELECT 0 UNION SELECT 1) 2 % (3 IN (SELECT 0 UNION SELECT 1)) (2 % 3) IN (SELECT 0 UNION SELECT 1) +0 NULL 0 +create or replace view v1 as select 2 ^ 3 IN (SELECT 0 UNION SELECT 1), 2 ^ (3 IN (SELECT 0 UNION SELECT 1)), (2 ^ 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ 3 in (select 0 union select 1) AS `2 ^ 3 IN (SELECT 0 UNION SELECT 1)`,2 ^ (3 in (select 0 union select 1)) AS `2 ^ (3 IN (SELECT 0 UNION SELECT 1))`,2 ^ 3 in (select 0 union select 1) AS `(2 ^ 3) IN (SELECT 0 UNION SELECT 1)` +select 2 ^ 3 IN (SELECT 0 UNION SELECT 1), 2 ^ (3 IN (SELECT 0 UNION SELECT 1)), (2 ^ 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 ^ 3 IN (SELECT 0 UNION SELECT 1) 2 ^ (3 IN (SELECT 0 UNION SELECT 1)) (2 ^ 3) IN (SELECT 0 UNION SELECT 1) +1 2 1 +create or replace view v1 as select 2 BETWEEN 1 AND 3 IN (SELECT 0 UNION SELECT 1), 2 BETWEEN 1 AND (3 IN (SELECT 0 UNION SELECT 1)), (2 BETWEEN 1 AND 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 in (select 0 union select 1) AS `2 BETWEEN 1 AND 3 IN (SELECT 0 UNION SELECT 1)`,2 between 1 and 3 in (select 0 union select 1) AS `2 BETWEEN 1 AND (3 IN (SELECT 0 UNION SELECT 1))`,2 between 1 and 3 in (select 0 union select 1) AS `(2 BETWEEN 1 AND 3) IN (SELECT 0 UNION SELECT 1)` +select 2 BETWEEN 1 AND 3 IN (SELECT 0 UNION SELECT 1), 2 BETWEEN 1 AND (3 IN (SELECT 0 UNION SELECT 1)), (2 BETWEEN 1 AND 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +2 BETWEEN 1 AND 3 IN (SELECT 0 UNION SELECT 1) 2 BETWEEN 1 AND (3 IN (SELECT 0 UNION SELECT 1)) (2 BETWEEN 1 AND 3) IN (SELECT 0 UNION SELECT 1) +0 0 1 +0 0 0 +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 IN (SELECT 0 UNION SELECT 1), 2 LIKE 1 ESCAPE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIKE 1 ESCAPE 3) IN (SELECT 0 UNION SELECT 1); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (SELECT 0 UNION SELECT 1), 2 LIKE 1 ESCAPE (3 IN (SELECT 0 UNION SELECT 1)...' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and 3 in (select 0 union select 1) AS `2 BETWEEN 1 AND 3 IN (SELECT 0 UNION SELECT 1)`,2 between 1 and 3 in (select 0 union select 1) AS `2 BETWEEN 1 AND (3 IN (SELECT 0 UNION SELECT 1))`,2 between 1 and 3 in (select 0 union select 1) AS `(2 BETWEEN 1 AND 3) IN (SELECT 0 UNION SELECT 1)` +select 2 LIKE 1 ESCAPE 3 IN (SELECT 0 UNION SELECT 1), 2 LIKE 1 ESCAPE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIKE 1 ESCAPE 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (SELECT 0 UNION SELECT 1), 2 LIKE 1 ESCAPE (3 IN (SELECT 0 UNION SELECT 1)...' at line 1 +create or replace view v1 as select 3 BETWEEN 1 AND 2 AND NULL, 3 BETWEEN (1 AND 2) AND NULL, 3 BETWEEN 1 AND (2 AND NULL), (3 BETWEEN 1 AND 2) AND NULL; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 3 between 1 and 2 and NULL AS `3 BETWEEN 1 AND 2 AND NULL`,3 between (1 and 2) and NULL AS `3 BETWEEN (1 AND 2) AND NULL`,3 between 1 and (2 and NULL) AS `3 BETWEEN 1 AND (2 AND NULL)`,3 between 1 and 2 and NULL AS `(3 BETWEEN 1 AND 2) AND NULL` +select 3 BETWEEN 1 AND 2 AND NULL, 3 BETWEEN (1 AND 2) AND NULL, 3 BETWEEN 1 AND (2 AND NULL), (3 BETWEEN 1 AND 2) AND NULL union select * from v1; +3 BETWEEN 1 AND 2 AND NULL 3 BETWEEN (1 AND 2) AND NULL 3 BETWEEN 1 AND (2 AND NULL) (3 BETWEEN 1 AND 2) AND NULL +0 NULL NULL 0 +set sql_mode=PIPES_AS_CONCAT; +create or replace view v1 as select 2 OR 3 || 3, 2 OR (3 || 3), (2 OR 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 or concat(3,3) AS `2 OR 3 || 3`,2 or concat(3,3) AS `2 OR (3 || 3)`,concat(2 or 3,3) AS `(2 OR 3) || 3` +select 2 OR 3 || 3, 2 OR (3 || 3), (2 OR 3) || 3 union select * from v1; +2 OR 3 || 3 2 OR (3 || 3) (2 OR 3) || 3 +1 1 13 +create or replace view v1 as select 2 || 3 OR 3, 2 || (3 OR 3), (2 || 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) or 3 AS `2 || 3 OR 3`,concat(2,3 or 3) AS `2 || (3 OR 3)`,concat(2,3) or 3 AS `(2 || 3) OR 3` +select 2 || 3 OR 3, 2 || (3 OR 3), (2 || 3) OR 3 union select * from v1; +2 || 3 OR 3 2 || (3 OR 3) (2 || 3) OR 3 +1 21 1 +create or replace view v1 as select NOT 2 || 3, NOT (2 || 3), (NOT 2) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !concat(2,3) AS `NOT 2 || 3`,!concat(2,3) AS `NOT (2 || 3)`,concat(!2,3) AS `(NOT 2) || 3` +select NOT 2 || 3, NOT (2 || 3), (NOT 2) || 3 union select * from v1; +NOT 2 || 3 NOT (2 || 3) (NOT 2) || 3 +0 0 03 +create or replace view v1 as select - '2 ' || 3, - ('2 ' || 3), (- '2 ') || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(-'2 ',3) AS `- '2 ' || 3`,-concat('2 ',3) AS `- ('2 ' || 3)`,concat(-'2 ',3) AS `(- '2 ') || 3` +select - '2 ' || 3, - ('2 ' || 3), (- '2 ') || 3 union select * from v1; +- '2 ' || 3 - ('2 ' || 3) (- '2 ') || 3 +-23 -2 -23 +create or replace view v1 as select ~ 2 || 3, ~ (2 || 3), (~ 2) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(~2,3) AS `~ 2 || 3`,~concat(2,3) AS `~ (2 || 3)`,concat(~2,3) AS `(~ 2) || 3` +select ~ 2 || 3, ~ (2 || 3), (~ 2) || 3 union select * from v1; +~ 2 || 3 ~ (2 || 3) (~ 2) || 3 +184467440737095516133 18446744073709551592 184467440737095516133 +create or replace view v1 as select ! 2 || 3, ! (2 || 3), (! 2) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(!2,3) AS `! 2 || 3`,!concat(2,3) AS `! (2 || 3)`,concat(!2,3) AS `(! 2) || 3` +select ! 2 || 3, ! (2 || 3), (! 2) || 3 union select * from v1; +! 2 || 3 ! (2 || 3) (! 2) || 3 +03 0 03 +create or replace view v1 as select 2 || 3 IS FALSE, 2 || (3 IS FALSE), (2 || 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) is false AS `2 || 3 IS FALSE`,concat(2,3 is false) AS `2 || (3 IS FALSE)`,concat(2,3) is false AS `(2 || 3) IS FALSE` +select 2 || 3 IS FALSE, 2 || (3 IS FALSE), (2 || 3) IS FALSE union select * from v1; +2 || 3 IS FALSE 2 || (3 IS FALSE) (2 || 3) IS FALSE +0 20 0 +create or replace view v1 as select 0 || 3 IN (3,10), 0 || (3 IN (3,10)), (0 || 3) IN (3,10); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(0,3) in (3,10) AS `0 || 3 IN (3,10)`,concat(0,3 in (3,10)) AS `0 || (3 IN (3,10))`,concat(0,3) in (3,10) AS `(0 || 3) IN (3,10)` +select 0 || 3 IN (3,10), 0 || (3 IN (3,10)), (0 || 3) IN (3,10) union select * from v1; +0 || 3 IN (3,10) 0 || (3 IN (3,10)) (0 || 3) IN (3,10) +1 01 1 +create or replace view v1 as select 1 || 0 XOR 1, 1 || (0 XOR 1), (1 || 0) XOR 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(1,0) xor 1 AS `1 || 0 XOR 1`,concat(1,0 xor 1) AS `1 || (0 XOR 1)`,concat(1,0) xor 1 AS `(1 || 0) XOR 1` +select 1 || 0 XOR 1, 1 || (0 XOR 1), (1 || 0) XOR 1 union select * from v1; +1 || 0 XOR 1 1 || (0 XOR 1) (1 || 0) XOR 1 +0 11 0 +create or replace view v1 as select 1 || 1 AND 0, 1 || (1 AND 0), (1 || 1) AND 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(1,1) and 0 AS `1 || 1 AND 0`,concat(1,1 and 0) AS `1 || (1 AND 0)`,concat(1,1) and 0 AS `(1 || 1) AND 0` +select 1 || 1 AND 0, 1 || (1 AND 0), (1 || 1) AND 0 union select * from v1; +1 || 1 AND 0 1 || (1 AND 0) (1 || 1) AND 0 +0 10 0 +create or replace view v1 as select 1 || 1 && 0, 1 || (1 && 0), (1 || 1) && 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(1,1) and 0 AS `1 || 1 && 0`,concat(1,1 and 0) AS `1 || (1 && 0)`,concat(1,1) and 0 AS `(1 || 1) && 0` +select 1 || 1 && 0, 1 || (1 && 0), (1 || 1) && 0 union select * from v1; +1 || 1 && 0 1 || (1 && 0) (1 || 1) && 0 +0 10 0 +create or replace view v1 as select 2 || 3 = 3, 2 || (3 = 3), (2 || 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) = 3 AS `2 || 3 = 3`,concat(2,3 = 3) AS `2 || (3 = 3)`,concat(2,3) = 3 AS `(2 || 3) = 3` +select 2 || 3 = 3, 2 || (3 = 3), (2 || 3) = 3 union select * from v1; +2 || 3 = 3 2 || (3 = 3) (2 || 3) = 3 +0 21 0 +create or replace view v1 as select 2 || 3 <=> 3, 2 || (3 <=> 3), (2 || 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) <=> 3 AS `2 || 3 <=> 3`,concat(2,3 <=> 3) AS `2 || (3 <=> 3)`,concat(2,3) <=> 3 AS `(2 || 3) <=> 3` +select 2 || 3 <=> 3, 2 || (3 <=> 3), (2 || 3) <=> 3 union select * from v1; +2 || 3 <=> 3 2 || (3 <=> 3) (2 || 3) <=> 3 +0 21 0 +create or replace view v1 as select 2 || 3 >= 3, 2 || (3 >= 3), (2 || 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) >= 3 AS `2 || 3 >= 3`,concat(2,3 >= 3) AS `2 || (3 >= 3)`,concat(2,3) >= 3 AS `(2 || 3) >= 3` +select 2 || 3 >= 3, 2 || (3 >= 3), (2 || 3) >= 3 union select * from v1; +2 || 3 >= 3 2 || (3 >= 3) (2 || 3) >= 3 +1 21 1 +create or replace view v1 as select 2 || 3 <= 0, 2 || (3 <= 0), (2 || 3) <= 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) <= 0 AS `2 || 3 <= 0`,concat(2,3 <= 0) AS `2 || (3 <= 0)`,concat(2,3) <= 0 AS `(2 || 3) <= 0` +select 2 || 3 <= 0, 2 || (3 <= 0), (2 || 3) <= 0 union select * from v1; +2 || 3 <= 0 2 || (3 <= 0) (2 || 3) <= 0 +0 20 0 +create or replace view v1 as select 2 || 3 < 0, 2 || (3 < 0), (2 || 3) < 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) < 0 AS `2 || 3 < 0`,concat(2,3 < 0) AS `2 || (3 < 0)`,concat(2,3) < 0 AS `(2 || 3) < 0` +select 2 || 3 < 0, 2 || (3 < 0), (2 || 3) < 0 union select * from v1; +2 || 3 < 0 2 || (3 < 0) (2 || 3) < 0 +0 20 0 +create or replace view v1 as select 0 || 3 <> 3, 0 || (3 <> 3), (0 || 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(0,3) <> 3 AS `0 || 3 <> 3`,concat(0,3 <> 3) AS `0 || (3 <> 3)`,concat(0,3) <> 3 AS `(0 || 3) <> 3` +select 0 || 3 <> 3, 0 || (3 <> 3), (0 || 3) <> 3 union select * from v1; +0 || 3 <> 3 0 || (3 <> 3) (0 || 3) <> 3 +0 00 0 +create or replace view v1 as select 2 || 3 > 3, 2 || (3 > 3), (2 || 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) > 3 AS `2 || 3 > 3`,concat(2,3 > 3) AS `2 || (3 > 3)`,concat(2,3) > 3 AS `(2 || 3) > 3` +select 2 || 3 > 3, 2 || (3 > 3), (2 || 3) > 3 union select * from v1; +2 || 3 > 3 2 || (3 > 3) (2 || 3) > 3 +1 20 1 +create or replace view v1 as select 0 || 3 != 3, 0 || (3 != 3), (0 || 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(0,3) <> 3 AS `0 || 3 != 3`,concat(0,3 <> 3) AS `0 || (3 != 3)`,concat(0,3) <> 3 AS `(0 || 3) != 3` +select 0 || 3 != 3, 0 || (3 != 3), (0 || 3) != 3 union select * from v1; +0 || 3 != 3 0 || (3 != 3) (0 || 3) != 3 +0 00 0 +create or replace view v1 as select 2 || 3 LIKE 3, 2 || (3 LIKE 3), (2 || 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) like 3 AS `2 || 3 LIKE 3`,concat(2,3 like 3) AS `2 || (3 LIKE 3)`,concat(2,3) like 3 AS `(2 || 3) LIKE 3` +select 2 || 3 LIKE 3, 2 || (3 LIKE 3), (2 || 3) LIKE 3 union select * from v1; +2 || 3 LIKE 3 2 || (3 LIKE 3) (2 || 3) LIKE 3 +0 21 0 +create or replace view v1 as select 2 || 3 REGEXP 3, 2 || (3 REGEXP 3), (2 || 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) regexp 3 AS `2 || 3 REGEXP 3`,concat(2,3 regexp 3) AS `2 || (3 REGEXP 3)`,concat(2,3) regexp 3 AS `(2 || 3) REGEXP 3` +select 2 || 3 REGEXP 3, 2 || (3 REGEXP 3), (2 || 3) REGEXP 3 union select * from v1; +2 || 3 REGEXP 3 2 || (3 REGEXP 3) (2 || 3) REGEXP 3 +1 21 1 +create or replace view v1 as select 2 || ' 3' | 3, 2 || (' 3' | 3), (2 || ' 3') | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,' 3') | 3 AS `2 || ' 3' | 3`,concat(2,' 3' | 3) AS `2 || (' 3' | 3)`,concat(2,' 3') | 3 AS `(2 || ' 3') | 3` +select 2 || ' 3' | 3, 2 || (' 3' | 3), (2 || ' 3') | 3 union select * from v1; +2 || ' 3' | 3 2 || (' 3' | 3) (2 || ' 3') | 3 +3 23 3 +create or replace view v1 as select 0 || 2 & 2, 0 || (2 & 2), (0 || 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(0,2) & 2 AS `0 || 2 & 2`,concat(0,2 & 2) AS `0 || (2 & 2)`,concat(0,2) & 2 AS `(0 || 2) & 2` +select 0 || 2 & 2, 0 || (2 & 2), (0 || 2) & 2 union select * from v1; +0 || 2 & 2 0 || (2 & 2) (0 || 2) & 2 +2 02 2 +create or replace view v1 as select 2 || 3 << 3, 2 || (3 << 3), (2 || 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) << 3 AS `2 || 3 << 3`,concat(2,3 << 3) AS `2 || (3 << 3)`,concat(2,3) << 3 AS `(2 || 3) << 3` +select 2 || 3 << 3, 2 || (3 << 3), (2 || 3) << 3 union select * from v1; +2 || 3 << 3 2 || (3 << 3) (2 || 3) << 3 +184 224 184 +create or replace view v1 as select 2 || 3 >> 3, 2 || (3 >> 3), (2 || 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) >> 3 AS `2 || 3 >> 3`,concat(2,3 >> 3) AS `2 || (3 >> 3)`,concat(2,3) >> 3 AS `(2 || 3) >> 3` +select 2 || 3 >> 3, 2 || (3 >> 3), (2 || 3) >> 3 union select * from v1; +2 || 3 >> 3 2 || (3 >> 3) (2 || 3) >> 3 +2 20 2 +create or replace view v1 as select 2 || '2000-01-01' +INTERVAL 1 DAY, 2 || ('2000-01-01' +INTERVAL 1 DAY), (2 || '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,'2000-01-01') + interval 1 day AS `2 || '2000-01-01' +INTERVAL 1 DAY`,concat(2,'2000-01-01' + interval 1 day) AS `2 || ('2000-01-01' +INTERVAL 1 DAY)`,concat(2,'2000-01-01') + interval 1 day AS `(2 || '2000-01-01') +INTERVAL 1 DAY` +select 2 || '2000-01-01' +INTERVAL 1 DAY, 2 || ('2000-01-01' +INTERVAL 1 DAY), (2 || '2000-01-01') +INTERVAL 1 DAY union select * from v1; +2 || '2000-01-01' +INTERVAL 1 DAY 2 || ('2000-01-01' +INTERVAL 1 DAY) (2 || '2000-01-01') +INTERVAL 1 DAY +NULL 22000-01-02 NULL +create or replace view v1 as select 2 || ' 3' + 3, 2 || (' 3' + 3), (2 || ' 3') + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,' 3') + 3 AS `2 || ' 3' + 3`,concat(2,' 3' + 3) AS `2 || (' 3' + 3)`,concat(2,' 3') + 3 AS `(2 || ' 3') + 3` +select 2 || ' 3' + 3, 2 || (' 3' + 3), (2 || ' 3') + 3 union select * from v1; +2 || ' 3' + 3 2 || (' 3' + 3) (2 || ' 3') + 3 +5 26 5 +create or replace view v1 as select 2 || ' 3' - 3, 2 || (' 3' - 3), (2 || ' 3') - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,' 3') - 3 AS `2 || ' 3' - 3`,concat(2,' 3' - 3) AS `2 || (' 3' - 3)`,concat(2,' 3') - 3 AS `(2 || ' 3') - 3` +select 2 || ' 3' - 3, 2 || (' 3' - 3), (2 || ' 3') - 3 union select * from v1; +2 || ' 3' - 3 2 || (' 3' - 3) (2 || ' 3') - 3 +-1 20 -1 +create or replace view v1 as select 2 || 3 * 3, 2 || (3 * 3), (2 || 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) * 3 AS `2 || 3 * 3`,concat(2,3 * 3) AS `2 || (3 * 3)`,concat(2,3) * 3 AS `(2 || 3) * 3` +select 2 || 3 * 3, 2 || (3 * 3), (2 || 3) * 3 union select * from v1; +2 || 3 * 3 2 || (3 * 3) (2 || 3) * 3 +69 29 69 +create or replace view v1 as select 2 || 3 / 3, 2 || (3 / 3), (2 || 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) / 3 AS `2 || 3 / 3`,concat(2,3 / 3) AS `2 || (3 / 3)`,concat(2,3) / 3 AS `(2 || 3) / 3` +select 2 || 3 / 3, 2 || (3 / 3), (2 || 3) / 3 union select * from v1; +2 || 3 / 3 2 || (3 / 3) (2 || 3) / 3 +7.666666666666667 21.0000 7.666666666666667 +create or replace view v1 as select 2 || 3 DIV 3, 2 || (3 DIV 3), (2 || 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) DIV 3 AS `2 || 3 DIV 3`,concat(2,3 DIV 3) AS `2 || (3 DIV 3)`,concat(2,3) DIV 3 AS `(2 || 3) DIV 3` +select 2 || 3 DIV 3, 2 || (3 DIV 3), (2 || 3) DIV 3 union select * from v1; +2 || 3 DIV 3 2 || (3 DIV 3) (2 || 3) DIV 3 +7 21 7 +create or replace view v1 as select 0 || 3 MOD 3, 0 || (3 MOD 3), (0 || 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(0,3) % 3 AS `0 || 3 MOD 3`,concat(0,3 % 3) AS `0 || (3 MOD 3)`,concat(0,3) % 3 AS `(0 || 3) MOD 3` +select 0 || 3 MOD 3, 0 || (3 MOD 3), (0 || 3) MOD 3 union select * from v1; +0 || 3 MOD 3 0 || (3 MOD 3) (0 || 3) MOD 3 +0 00 0 +create or replace view v1 as select 0 || 3 % 3, 0 || (3 % 3), (0 || 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(0,3) % 3 AS `0 || 3 % 3`,concat(0,3 % 3) AS `0 || (3 % 3)`,concat(0,3) % 3 AS `(0 || 3) % 3` +select 0 || 3 % 3, 0 || (3 % 3), (0 || 3) % 3 union select * from v1; +0 || 3 % 3 0 || (3 % 3) (0 || 3) % 3 +0 00 0 +create or replace view v1 as select 2 || ' 3' ^ 3, 2 || (' 3' ^ 3), (2 || ' 3') ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,' 3') ^ 3 AS `2 || ' 3' ^ 3`,concat(2,' 3' ^ 3) AS `2 || (' 3' ^ 3)`,concat(2,' 3') ^ 3 AS `(2 || ' 3') ^ 3` +select 2 || ' 3' ^ 3, 2 || (' 3' ^ 3), (2 || ' 3') ^ 3 union select * from v1; +2 || ' 3' ^ 3 2 || (' 3' ^ 3) (2 || ' 3') ^ 3 +1 20 1 +create or replace view v1 as select 2 || 3 BETWEEN 2 AND 3, 2 || (3 BETWEEN 2 AND 3), (2 || 3) BETWEEN 2 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select concat(2,3) between 2 and 3 AS `2 || 3 BETWEEN 2 AND 3`,concat(2,3 between 2 and 3) AS `2 || (3 BETWEEN 2 AND 3)`,concat(2,3) between 2 and 3 AS `(2 || 3) BETWEEN 2 AND 3` +select 2 || 3 BETWEEN 2 AND 3, 2 || (3 BETWEEN 2 AND 3), (2 || 3) BETWEEN 2 AND 3 union select * from v1; +2 || 3 BETWEEN 2 AND 3 2 || (3 BETWEEN 2 AND 3) (2 || 3) BETWEEN 2 AND 3 +0 21 0 +create or replace view v1 as select 2 XOR 3 || 3, 2 XOR (3 || 3), (2 XOR 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 xor concat(3,3) AS `2 XOR 3 || 3`,2 xor concat(3,3) AS `2 XOR (3 || 3)`,concat(2 xor 3,3) AS `(2 XOR 3) || 3` +select 2 XOR 3 || 3, 2 XOR (3 || 3), (2 XOR 3) || 3 union select * from v1; +2 XOR 3 || 3 2 XOR (3 || 3) (2 XOR 3) || 3 +0 0 03 +create or replace view v1 as select 0 AND 3 || 3, 0 AND (3 || 3), (0 AND 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 and concat(3,3) AS `0 AND 3 || 3`,0 and concat(3,3) AS `0 AND (3 || 3)`,concat(0 and 3,3) AS `(0 AND 3) || 3` +select 0 AND 3 || 3, 0 AND (3 || 3), (0 AND 3) || 3 union select * from v1; +0 AND 3 || 3 0 AND (3 || 3) (0 AND 3) || 3 +0 0 03 +create or replace view v1 as select 0 && 3 || 3, 0 && (3 || 3), (0 && 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 and concat(3,3) AS `0 && 3 || 3`,0 and concat(3,3) AS `0 && (3 || 3)`,concat(0 and 3,3) AS `(0 && 3) || 3` +select 0 && 3 || 3, 0 && (3 || 3), (0 && 3) || 3 union select * from v1; +0 && 3 || 3 0 && (3 || 3) (0 && 3) || 3 +0 0 03 +create or replace view v1 as select 2 = 3 || 3, 2 = (3 || 3), (2 = 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 = concat(3,3) AS `2 = 3 || 3`,2 = concat(3,3) AS `2 = (3 || 3)`,concat(2 = 3,3) AS `(2 = 3) || 3` +select 2 = 3 || 3, 2 = (3 || 3), (2 = 3) || 3 union select * from v1; +2 = 3 || 3 2 = (3 || 3) (2 = 3) || 3 +0 0 03 +create or replace view v1 as select 2 <=> 3 || 3, 2 <=> (3 || 3), (2 <=> 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <=> concat(3,3) AS `2 <=> 3 || 3`,2 <=> concat(3,3) AS `2 <=> (3 || 3)`,concat(2 <=> 3,3) AS `(2 <=> 3) || 3` +select 2 <=> 3 || 3, 2 <=> (3 || 3), (2 <=> 3) || 3 union select * from v1; +2 <=> 3 || 3 2 <=> (3 || 3) (2 <=> 3) || 3 +0 0 03 +create or replace view v1 as select 2 >= 3 || 0, 2 >= (3 || 0), (2 >= 3) || 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >= concat(3,0) AS `2 >= 3 || 0`,2 >= concat(3,0) AS `2 >= (3 || 0)`,concat(2 >= 3,0) AS `(2 >= 3) || 0` +select 2 >= 3 || 0, 2 >= (3 || 0), (2 >= 3) || 0 union select * from v1; +2 >= 3 || 0 2 >= (3 || 0) (2 >= 3) || 0 +0 0 00 +create or replace view v1 as select 2 <= 3 || 3, 2 <= (3 || 3), (2 <= 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 <= concat(3,3) AS `2 <= 3 || 3`,2 <= concat(3,3) AS `2 <= (3 || 3)`,concat(2 <= 3,3) AS `(2 <= 3) || 3` +select 2 <= 3 || 3, 2 <= (3 || 3), (2 <= 3) || 3 union select * from v1; +2 <= 3 || 3 2 <= (3 || 3) (2 <= 3) || 3 +1 1 13 +create or replace view v1 as select 2 < 3 || 3, 2 < (3 || 3), (2 < 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 < concat(3,3) AS `2 < 3 || 3`,2 < concat(3,3) AS `2 < (3 || 3)`,concat(2 < 3,3) AS `(2 < 3) || 3` +select 2 < 3 || 3, 2 < (3 || 3), (2 < 3) || 3 union select * from v1; +2 < 3 || 3 2 < (3 || 3) (2 < 3) || 3 +1 1 13 +create or replace view v1 as select 1 <> 3 || 3, 1 <> (3 || 3), (1 <> 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 <> concat(3,3) AS `1 <> 3 || 3`,1 <> concat(3,3) AS `1 <> (3 || 3)`,concat(1 <> 3,3) AS `(1 <> 3) || 3` +select 1 <> 3 || 3, 1 <> (3 || 3), (1 <> 3) || 3 union select * from v1; +1 <> 3 || 3 1 <> (3 || 3) (1 <> 3) || 3 +1 1 13 +create or replace view v1 as select 0 > 3 || 3, 0 > (3 || 3), (0 > 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 0 > concat(3,3) AS `0 > 3 || 3`,0 > concat(3,3) AS `0 > (3 || 3)`,concat(0 > 3,3) AS `(0 > 3) || 3` +select 0 > 3 || 3, 0 > (3 || 3), (0 > 3) || 3 union select * from v1; +0 > 3 || 3 0 > (3 || 3) (0 > 3) || 3 +0 0 03 +create or replace view v1 as select 1 != 3 || 3, 1 != (3 || 3), (1 != 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 <> concat(3,3) AS `1 != 3 || 3`,1 <> concat(3,3) AS `1 != (3 || 3)`,concat(1 <> 3,3) AS `(1 != 3) || 3` +select 1 != 3 || 3, 1 != (3 || 3), (1 != 3) || 3 union select * from v1; +1 != 3 || 3 1 != (3 || 3) (1 != 3) || 3 +1 1 13 +create or replace view v1 as select 2 LIKE 3 || 3, 2 LIKE (3 || 3), (2 LIKE 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 like concat(3,3) AS `2 LIKE 3 || 3`,2 like concat(3,3) AS `2 LIKE (3 || 3)`,concat(2 like 3,3) AS `(2 LIKE 3) || 3` +select 2 LIKE 3 || 3, 2 LIKE (3 || 3), (2 LIKE 3) || 3 union select * from v1; +2 LIKE 3 || 3 2 LIKE (3 || 3) (2 LIKE 3) || 3 +0 0 03 +create or replace view v1 as select 2 REGEXP 3 || 3, 2 REGEXP (3 || 3), (2 REGEXP 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 regexp concat(3,3) AS `2 REGEXP 3 || 3`,2 regexp concat(3,3) AS `2 REGEXP (3 || 3)`,concat(2 regexp 3,3) AS `(2 REGEXP 3) || 3` +select 2 REGEXP 3 || 3, 2 REGEXP (3 || 3), (2 REGEXP 3) || 3 union select * from v1; +2 REGEXP 3 || 3 2 REGEXP (3 || 3) (2 REGEXP 3) || 3 +0 0 03 +create or replace view v1 as select 2 | 3 || 3, 2 | (3 || 3), (2 | 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 | concat(3,3) AS `2 | 3 || 3`,2 | concat(3,3) AS `2 | (3 || 3)`,concat(2 | 3,3) AS `(2 | 3) || 3` +select 2 | 3 || 3, 2 | (3 || 3), (2 | 3) || 3 union select * from v1; +2 | 3 || 3 2 | (3 || 3) (2 | 3) || 3 +35 35 33 +create or replace view v1 as select 2 & 3 || 3, 2 & (3 || 3), (2 & 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 & concat(3,3) AS `2 & 3 || 3`,2 & concat(3,3) AS `2 & (3 || 3)`,concat(2 & 3,3) AS `(2 & 3) || 3` +select 2 & 3 || 3, 2 & (3 || 3), (2 & 3) || 3 union select * from v1; +2 & 3 || 3 2 & (3 || 3) (2 & 3) || 3 +0 0 23 +create or replace view v1 as select 2 << 3 || 3, 2 << (3 || 3), (2 << 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 << concat(3,3) AS `2 << 3 || 3`,2 << concat(3,3) AS `2 << (3 || 3)`,concat(2 << 3,3) AS `(2 << 3) || 3` +select 2 << 3 || 3, 2 << (3 || 3), (2 << 3) || 3 union select * from v1; +2 << 3 || 3 2 << (3 || 3) (2 << 3) || 3 +17179869184 17179869184 163 +create or replace view v1 as select 2 >> 3 || 0, 2 >> (3 || 0), (2 >> 3) || 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 >> concat(3,0) AS `2 >> 3 || 0`,2 >> concat(3,0) AS `2 >> (3 || 0)`,concat(2 >> 3,0) AS `(2 >> 3) || 0` +select 2 >> 3 || 0, 2 >> (3 || 0), (2 >> 3) || 0 union select * from v1; +2 >> 3 || 0 2 >> (3 || 0) (2 >> 3) || 0 +0 0 00 +create or replace view v1 as select 2 + 3 || 3, 2 + (3 || 3), (2 + 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 + concat(3,3) AS `2 + 3 || 3`,2 + concat(3,3) AS `2 + (3 || 3)`,concat(2 + 3,3) AS `(2 + 3) || 3` +select 2 + 3 || 3, 2 + (3 || 3), (2 + 3) || 3 union select * from v1; +2 + 3 || 3 2 + (3 || 3) (2 + 3) || 3 +35 35 53 +create or replace view v1 as select 2 - 2 || 0, 2 - (2 || 0), (2 - 2) || 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 - concat(2,0) AS `2 - 2 || 0`,2 - concat(2,0) AS `2 - (2 || 0)`,concat(2 - 2,0) AS `(2 - 2) || 0` +select 2 - 2 || 0, 2 - (2 || 0), (2 - 2) || 0 union select * from v1; +2 - 2 || 0 2 - (2 || 0) (2 - 2) || 0 +-18 -18 00 +create or replace view v1 as select 2 * 3 || 3, 2 * (3 || 3), (2 * 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 * concat(3,3) AS `2 * 3 || 3`,2 * concat(3,3) AS `2 * (3 || 3)`,concat(2 * 3,3) AS `(2 * 3) || 3` +select 2 * 3 || 3, 2 * (3 || 3), (2 * 3) || 3 union select * from v1; +2 * 3 || 3 2 * (3 || 3) (2 * 3) || 3 +66 66 63 +create or replace view v1 as select 2 / 3 || 3, 2 / (3 || 3), (2 / 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 / concat(3,3) AS `2 / 3 || 3`,2 / concat(3,3) AS `2 / (3 || 3)`,concat(2 / 3,3) AS `(2 / 3) || 3` +select 2 / 3 || 3, 2 / (3 || 3), (2 / 3) || 3 union select * from v1; +2 / 3 || 3 2 / (3 || 3) (2 / 3) || 3 +0.06060606060606061 0.06060606060606061 0.66673 +create or replace view v1 as select 2 DIV 3 || 3, 2 DIV (3 || 3), (2 DIV 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 DIV concat(3,3) AS `2 DIV 3 || 3`,2 DIV concat(3,3) AS `2 DIV (3 || 3)`,concat(2 DIV 3,3) AS `(2 DIV 3) || 3` +select 2 DIV 3 || 3, 2 DIV (3 || 3), (2 DIV 3) || 3 union select * from v1; +2 DIV 3 || 3 2 DIV (3 || 3) (2 DIV 3) || 3 +0 0 03 +create or replace view v1 as select 2 MOD 3 || 3, 2 MOD (3 || 3), (2 MOD 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % concat(3,3) AS `2 MOD 3 || 3`,2 % concat(3,3) AS `2 MOD (3 || 3)`,concat(2 % 3,3) AS `(2 MOD 3) || 3` +select 2 MOD 3 || 3, 2 MOD (3 || 3), (2 MOD 3) || 3 union select * from v1; +2 MOD 3 || 3 2 MOD (3 || 3) (2 MOD 3) || 3 +2 2 23 +create or replace view v1 as select 2 % 3 || 3, 2 % (3 || 3), (2 % 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 % concat(3,3) AS `2 % 3 || 3`,2 % concat(3,3) AS `2 % (3 || 3)`,concat(2 % 3,3) AS `(2 % 3) || 3` +select 2 % 3 || 3, 2 % (3 || 3), (2 % 3) || 3 union select * from v1; +2 % 3 || 3 2 % (3 || 3) (2 % 3) || 3 +2 2 23 +create or replace view v1 as select 2 ^ 3 || 3, 2 ^ (3 || 3), (2 ^ 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 ^ concat(3,3) AS `2 ^ 3 || 3`,2 ^ concat(3,3) AS `2 ^ (3 || 3)`,concat(2 ^ 3,3) AS `(2 ^ 3) || 3` +select 2 ^ 3 || 3, 2 ^ (3 || 3), (2 ^ 3) || 3 union select * from v1; +2 ^ 3 || 3 2 ^ (3 || 3) (2 ^ 3) || 3 +35 35 13 +create or replace view v1 as select 2 BETWEEN 1 AND 3 || 3, 2 BETWEEN 1 AND (3 || 3), (2 BETWEEN 1 AND 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 2 between 1 and concat(3,3) AS `2 BETWEEN 1 AND 3 || 3`,2 between 1 and concat(3,3) AS `2 BETWEEN 1 AND (3 || 3)`,concat(2 between 1 and 3,3) AS `(2 BETWEEN 1 AND 3) || 3` +select 2 BETWEEN 1 AND 3 || 3, 2 BETWEEN 1 AND (3 || 3), (2 BETWEEN 1 AND 3) || 3 union select * from v1; +2 BETWEEN 1 AND 3 || 3 2 BETWEEN 1 AND (3 || 3) (2 BETWEEN 1 AND 3) || 3 +1 1 13 +create or replace view v1 as select charset(2 LIKE 1 ESCAPE 3 || ''), charset(2 LIKE 1 ESCAPE (3 || '')), charset((2 LIKE 1 ESCAPE 3) || ''); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select charset(2 like 1 escape concat(3,'')) AS `charset(2 LIKE 1 ESCAPE 3 || '')`,charset(2 like 1 escape concat(3,'')) AS `charset(2 LIKE 1 ESCAPE (3 || ''))`,charset(concat(2 like 1 escape 3,'')) AS `charset((2 LIKE 1 ESCAPE 3) || '')` +select charset(2 LIKE 1 ESCAPE 3 || ''), charset(2 LIKE 1 ESCAPE (3 || '')), charset((2 LIKE 1 ESCAPE 3) || '') union select * from v1; +charset(2 LIKE 1 ESCAPE 3 || '') charset(2 LIKE 1 ESCAPE (3 || '')) charset((2 LIKE 1 ESCAPE 3) || '') +binary binary latin1 +create or replace view v1 as select ! - 1, - ! 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !-1 AS `! - 1`,-!1 AS `- ! 1` +create or replace view v1 as select ! BINARY 1, BINARY ! 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !cast(1 as char charset binary) AS `! BINARY 1`,cast(!1 as char charset binary) AS `BINARY ! 1` +create or replace view v1 as select ! NOT 1, NOT ! 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NOT 1, NOT ! 1' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !cast(1 as char charset binary) AS `! BINARY 1`,cast(!1 as char charset binary) AS `BINARY ! 1` +create or replace view v1 as select ! ~ 1, ~ ! 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select !(~1) AS `! ~ 1`,~!1 AS `~ ! 1` +create or replace view v1 as select - BINARY 1, BINARY - 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -cast(1 as char charset binary) AS `- BINARY 1`,cast(-1 as char charset binary) AS `BINARY - 1` +create or replace view v1 as select - NOT 1, NOT - 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NOT 1, NOT - 1' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -cast(1 as char charset binary) AS `- BINARY 1`,cast(-1 as char charset binary) AS `BINARY - 1` +create or replace view v1 as select - ~ 1, ~ - 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -~1 AS `- ~ 1`,~-1 AS `~ - 1` +create or replace view v1 as select BINARY NOT 1, NOT BINARY 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NOT 1, NOT BINARY 1' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select -~1 AS `- ~ 1`,~-1 AS `~ - 1` +create or replace view v1 as select BINARY ~ 1, ~ BINARY 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast(~1 as char charset binary) AS `BINARY ~ 1`,~cast(1 as char charset binary) AS `~ BINARY 1` +create or replace view v1 as select NOT ~ 1, ~ NOT 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NOT 1' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast(~1 as char charset binary) AS `BINARY ~ 1`,~cast(1 as char charset binary) AS `~ BINARY 1` +create or replace view v1 as select 1 IS TRUE IS FALSE, 2 IS FALSE IS UNKNOWN, 3 IS UNKNOWN IS NULL, 4 IS NULL IS TRUE; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IS FALSE, 2 IS FALSE IS UNKNOWN, 3 IS UNKNOWN IS NULL, 4 IS NULL IS TRUE' at line 1 +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select cast(~1 as char charset binary) AS `BINARY ~ 1`,~cast(1 as char charset binary) AS `~ BINARY 1` +drop view v1; diff --git a/mysql-test/t/precedence.test b/mysql-test/t/precedence.test new file mode 100644 index 00000000000..28e915a118c --- /dev/null +++ b/mysql-test/t/precedence.test @@ -0,0 +1,4789 @@ +# +# A fairly exhastive test for operator precedence +# + +disable_abort_on_error; +disable_warnings; + +#################### I couldn't come up with a test where precedence changes the result here +# +#create or replace view v1 as select BINARY 2 IS TRUE, BINARY (2 IS TRUE), (BINARY 2) IS TRUE; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 IS TRUE, BINARY (2 IS TRUE), (BINARY 2) IS TRUE union select * from v1; +# +#create or replace view v1 as select BINARY 2 OR 3, BINARY (2 OR 3), (BINARY 2) OR 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 OR 3, BINARY (2 OR 3), (BINARY 2) OR 3 union select * from v1; +# +#create or replace view v1 as select BINARY 2 || 3, BINARY (2 || 3), (BINARY 2) || 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 || 3, BINARY (2 || 3), (BINARY 2) || 3 union select * from v1; +# +#create or replace view v1 as select BINARY 2 XOR 3, BINARY (2 XOR 3), (BINARY 2) XOR 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 XOR 3, BINARY (2 XOR 3), (BINARY 2) XOR 3 union select * from v1; +# +#create or replace view v1 as select BINARY 2 AND 3, BINARY (2 AND 3), (BINARY 2) AND 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 AND 3, BINARY (2 AND 3), (BINARY 2) AND 3 union select * from v1; +# +#create or replace view v1 as select BINARY 2 && 3, BINARY (2 && 3), (BINARY 2) && 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 && 3, BINARY (2 && 3), (BINARY 2) && 3 union select * from v1; +# +#create or replace view v1 as select BINARY 2 | 3, BINARY (2 | 3), (BINARY 2) | 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 | 3, BINARY (2 | 3), (BINARY 2) | 3 union select * from v1; +# +#create or replace view v1 as select BINARY 2 & 3, BINARY (2 & 3), (BINARY 2) & 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 & 3, BINARY (2 & 3), (BINARY 2) & 3 union select * from v1; +# +#create or replace view v1 as select BINARY 2 << 3, BINARY (2 << 3), (BINARY 2) << 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 << 3, BINARY (2 << 3), (BINARY 2) << 3 union select * from v1; +# +#create or replace view v1 as select BINARY 2 >> 3, BINARY (2 >> 3), (BINARY 2) >> 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 >> 3, BINARY (2 >> 3), (BINARY 2) >> 3 union select * from v1; +# +#create or replace view v1 as select BINARY '2000-01-01' +INTERVAL 1 DAY, BINARY ('2000-01-01' +INTERVAL 1 DAY), (BINARY '2000-01-01') +INTERVAL 1 DAY; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY '2000-01-01' +INTERVAL 1 DAY, BINARY ('2000-01-01' +INTERVAL 1 DAY), (BINARY '2000-01-01') +INTERVAL 1 DAY union select * from v1; +# +#create or replace view v1 as select BINARY 2 + 3, BINARY (2 + 3), (BINARY 2) + 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 + 3, BINARY (2 + 3), (BINARY 2) + 3 union select * from v1; +# +#create or replace view v1 as select BINARY 2 - 3, BINARY (2 - 3), (BINARY 2) - 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 - 3, BINARY (2 - 3), (BINARY 2) - 3 union select * from v1; +# +#create or replace view v1 as select BINARY 2 * 3, BINARY (2 * 3), (BINARY 2) * 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 * 3, BINARY (2 * 3), (BINARY 2) * 3 union select * from v1; +# +#create or replace view v1 as select BINARY 2 / 3, BINARY (2 / 3), (BINARY 2) / 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 / 3, BINARY (2 / 3), (BINARY 2) / 3 union select * from v1; +# +#create or replace view v1 as select BINARY 2 DIV 3, BINARY (2 DIV 3), (BINARY 2) DIV 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 DIV 3, BINARY (2 DIV 3), (BINARY 2) DIV 3 union select * from v1; +# +#create or replace view v1 as select BINARY 2 MOD 3, BINARY (2 MOD 3), (BINARY 2) MOD 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 MOD 3, BINARY (2 MOD 3), (BINARY 2) MOD 3 union select * from v1; +# +#create or replace view v1 as select BINARY 2 % 3, BINARY (2 % 3), (BINARY 2) % 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 % 3, BINARY (2 % 3), (BINARY 2) % 3 union select * from v1; +# +#create or replace view v1 as select BINARY 2 ^ 3, BINARY (2 ^ 3), (BINARY 2) ^ 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select BINARY 2 ^ 3, BINARY (2 ^ 3), (BINARY 2) ^ 3 union select * from v1; +# +#set sql_mode=PIPES_AS_CONCAT; +#create or replace view v1 as select 2 || 3 COLLATE latin1_bin, 2 || (3 COLLATE latin1_bin), (2 || 3) COLLATE latin1_bin; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 || 3 COLLATE latin1_bin, 2 || (3 COLLATE latin1_bin), (2 || 3) COLLATE latin1_bin union select * from v1; + +########################## The result doesn't depend on the precedence +# +#create or replace view v1 as select NOT 2 XOR 0, NOT (2 XOR 0), (NOT 2) XOR 0; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select NOT 2 XOR 0, NOT (2 XOR 0), (NOT 2) XOR 0 union select * from v1; +# +#create or replace view v1 as select - 2 * 3, - (2 * 3), (- 2) * 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select - 2 * 3, - (2 * 3), (- 2) * 3 union select * from v1; +# +#create or replace view v1 as select - 2 / 3, - (2 / 3), (- 2) / 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select - 2 / 3, - (2 / 3), (- 2) / 3 union select * from v1; +# +#create or replace view v1 as select - 2 DIV 3, - (2 DIV 3), (- 2) DIV 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select - 2 DIV 3, - (2 DIV 3), (- 2) DIV 3 union select * from v1; +# +#create or replace view v1 as select - 2 MOD 3, - (2 MOD 3), (- 2) MOD 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select - 2 MOD 3, - (2 MOD 3), (- 2) MOD 3 union select * from v1; +# +#create or replace view v1 as select - 2 % 3, - (2 % 3), (- 2) % 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select - 2 % 3, - (2 % 3), (- 2) % 3 union select * from v1; +# +#create or replace view v1 as select ~ 2 ^ 3, ~ (2 ^ 3), (~ 2) ^ 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select ~ 2 ^ 3, ~ (2 ^ 3), (~ 2) ^ 3 union select * from v1; +# +#create or replace view v1 as select ! 2 XOR 3, ! (2 XOR 3), (! 2) XOR 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select ! 2 XOR 3, ! (2 XOR 3), (! 2) XOR 3 union select * from v1; +# +#create or replace view v1 as select 2 OR 3 OR 3, 2 OR (3 OR 3), (2 OR 3) OR 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 OR 3 OR 3, 2 OR (3 OR 3), (2 OR 3) OR 3 union select * from v1; +# +#create or replace view v1 as select 2 OR 3 || 3, 2 OR (3 || 3), (2 OR 3) || 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 OR 3 || 3, 2 OR (3 || 3), (2 OR 3) || 3 union select * from v1; +# +#create or replace view v1 as select 2 || 3 OR 3, 2 || (3 OR 3), (2 || 3) OR 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 || 3 OR 3, 2 || (3 OR 3), (2 || 3) OR 3 union select * from v1; +# +#create or replace view v1 as select 2 || 3 || 3, 2 || (3 || 3), (2 || 3) || 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 || 3 || 3, 2 || (3 || 3), (2 || 3) || 3 union select * from v1; +# +#create or replace view v1 as select 2 XOR 3 IS FALSE, 2 XOR (3 IS FALSE), (2 XOR 3) IS FALSE; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 XOR 3 IS FALSE, 2 XOR (3 IS FALSE), (2 XOR 3) IS FALSE union select * from v1; +# +#create or replace view v1 as select 2 XOR 3 XOR 3, 2 XOR (3 XOR 3), (2 XOR 3) XOR 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 XOR 3 XOR 3, 2 XOR (3 XOR 3), (2 XOR 3) XOR 3 union select * from v1; +# +#create or replace view v1 as select 2 AND 3 AND 3, 2 AND (3 AND 3), (2 AND 3) AND 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 AND 3 AND 3, 2 AND (3 AND 3), (2 AND 3) AND 3 union select * from v1; +# +#create or replace view v1 as select 2 AND 3 && 3, 2 AND (3 && 3), (2 AND 3) && 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 AND 3 && 3, 2 AND (3 && 3), (2 AND 3) && 3 union select * from v1; +# +#create or replace view v1 as select 2 && 3 AND 3, 2 && (3 AND 3), (2 && 3) AND 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 && 3 AND 3, 2 && (3 AND 3), (2 && 3) AND 3 union select * from v1; +# +#create or replace view v1 as select 2 && 3 && 3, 2 && (3 && 3), (2 && 3) && 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 && 3 && 3, 2 && (3 && 3), (2 && 3) && 3 union select * from v1; +# +#create or replace view v1 as select 2 | 3 | 3, 2 | (3 | 3), (2 | 3) | 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 | 3 | 3, 2 | (3 | 3), (2 | 3) | 3 union select * from v1; +# +#create or replace view v1 as select 2 & 3 & 3, 2 & (3 & 3), (2 & 3) & 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 & 3 & 3, 2 & (3 & 3), (2 & 3) & 3 union select * from v1; +# +#create or replace view v1 as select 2 + 3 + 3, 2 + (3 + 3), (2 + 3) + 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 + 3 + 3, 2 + (3 + 3), (2 + 3) + 3 union select * from v1; +# +#create or replace view v1 as select 2 + 3 - 3, 2 + (3 - 3), (2 + 3) - 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 + 3 - 3, 2 + (3 - 3), (2 + 3) - 3 union select * from v1; +# +#create or replace view v1 as select 2 * 3 << 3, 2 * (3 << 3), (2 * 3) << 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 * 3 << 3, 2 * (3 << 3), (2 * 3) << 3 union select * from v1; +# +#create or replace view v1 as select 2 * 3 * 3, 2 * (3 * 3), (2 * 3) * 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 * 3 * 3, 2 * (3 * 3), (2 * 3) * 3 union select * from v1; +# +#create or replace view v1 as select 2 * 3 / 3, 2 * (3 / 3), (2 * 3) / 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 * 3 / 3, 2 * (3 / 3), (2 * 3) / 3 union select * from v1; +# +#create or replace view v1 as select 2 ^ 3 ^ 3, 2 ^ (3 ^ 3), (2 ^ 3) ^ 3; +#Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +#select 2 ^ 3 ^ 3, 2 ^ (3 ^ 3), (2 ^ 3) ^ 3 union select * from v1; + +create or replace view v1 as select NOT NULL IS TRUE, NOT (NULL IS TRUE), (NOT NULL) IS TRUE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT NULL IS TRUE, NOT (NULL IS TRUE), (NOT NULL) IS TRUE union select * from v1; + +create or replace view v1 as select ! NULL IS TRUE, ! (NULL IS TRUE), (! NULL) IS TRUE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! NULL IS TRUE, ! (NULL IS TRUE), (! NULL) IS TRUE union select * from v1; + +create or replace view v1 as select charset(NOT 2 COLLATE latin1_bin), charset(NOT (2 COLLATE latin1_bin)), charset((NOT 2) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(NOT 2 COLLATE latin1_bin), charset(NOT (2 COLLATE latin1_bin)), charset((NOT 2) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select NOT 2 IN (0,2), NOT (2 IN (0,2)), (NOT 2) IN (0,2); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 IN (0,2), NOT (2 IN (0,2)), (NOT 2) IN (0,2) union select * from v1; + +create or replace view v1 as select NOT 2 OR 3, NOT (2 OR 3), (NOT 2) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 OR 3, NOT (2 OR 3), (NOT 2) OR 3 union select * from v1; + +create or replace view v1 as select NOT 2 || 3, NOT (2 || 3), (NOT 2) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 || 3, NOT (2 || 3), (NOT 2) || 3 union select * from v1; + +create or replace view v1 as select NOT 2 AND 0, NOT (2 AND 0), (NOT 2) AND 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 AND 0, NOT (2 AND 0), (NOT 2) AND 0 union select * from v1; + +create or replace view v1 as select NOT 2 && 0, NOT (2 && 0), (NOT 2) && 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 && 0, NOT (2 && 0), (NOT 2) && 0 union select * from v1; + +create or replace view v1 as select NOT 2 = 3, NOT (2 = 3), (NOT 2) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 = 3, NOT (2 = 3), (NOT 2) = 3 union select * from v1; + +create or replace view v1 as select NOT 2 <=> 3, NOT (2 <=> 3), (NOT 2) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 <=> 3, NOT (2 <=> 3), (NOT 2) <=> 3 union select * from v1; + +create or replace view v1 as select NOT 2 >= 3, NOT (2 >= 3), (NOT 2) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 >= 3, NOT (2 >= 3), (NOT 2) >= 3 union select * from v1; + +create or replace view v1 as select NOT 2 <= 3, NOT (2 <= 3), (NOT 2) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 <= 3, NOT (2 <= 3), (NOT 2) <= 3 union select * from v1; + +create or replace view v1 as select NOT 2 < 3, NOT (2 < 3), (NOT 2) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 < 3, NOT (2 < 3), (NOT 2) < 3 union select * from v1; + +create or replace view v1 as select NOT 2 <> 3, NOT (2 <> 3), (NOT 2) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 <> 3, NOT (2 <> 3), (NOT 2) <> 3 union select * from v1; + +create or replace view v1 as select NOT 2 > 3, NOT (2 > 3), (NOT 2) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 > 3, NOT (2 > 3), (NOT 2) > 3 union select * from v1; + +create or replace view v1 as select NOT 2 != 3, NOT (2 != 3), (NOT 2) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 != 3, NOT (2 != 3), (NOT 2) != 3 union select * from v1; + +create or replace view v1 as select NOT 2 LIKE 3, NOT (2 LIKE 3), (NOT 2) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 LIKE 3, NOT (2 LIKE 3), (NOT 2) LIKE 3 union select * from v1; + +create or replace view v1 as select NOT 2 REGEXP 3, NOT (2 REGEXP 3), (NOT 2) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 REGEXP 3, NOT (2 REGEXP 3), (NOT 2) REGEXP 3 union select * from v1; + +create or replace view v1 as select NOT 2 | 3, NOT (2 | 3), (NOT 2) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 | 3, NOT (2 | 3), (NOT 2) | 3 union select * from v1; + +create or replace view v1 as select NOT 0 & 2, NOT (0 & 2), (NOT 0) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 0 & 2, NOT (0 & 2), (NOT 0) & 2 union select * from v1; + +create or replace view v1 as select NOT 0 << 3, NOT (0 << 3), (NOT 0) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 0 << 3, NOT (0 << 3), (NOT 0) << 3 union select * from v1; + +create or replace view v1 as select NOT 2 >> 3, NOT (2 >> 3), (NOT 2) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 >> 3, NOT (2 >> 3), (NOT 2) >> 3 union select * from v1; + +create or replace view v1 as select NOT '2000-01-01' +INTERVAL 1 DAY, NOT ('2000-01-01' +INTERVAL 1 DAY), (NOT '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT '2000-01-01' +INTERVAL 1 DAY, NOT ('2000-01-01' +INTERVAL 1 DAY), (NOT '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select NOT 2 + 3, NOT (2 + 3), (NOT 2) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 + 3, NOT (2 + 3), (NOT 2) + 3 union select * from v1; + +create or replace view v1 as select NOT 2 - 3, NOT (2 - 3), (NOT 2) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 - 3, NOT (2 - 3), (NOT 2) - 3 union select * from v1; + +create or replace view v1 as select NOT 0 * 3, NOT (0 * 3), (NOT 0) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 0 * 3, NOT (0 * 3), (NOT 0) * 3 union select * from v1; + +create or replace view v1 as select NOT 0 / 3, NOT (0 / 3), (NOT 0) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 0 / 3, NOT (0 / 3), (NOT 0) / 3 union select * from v1; + +create or replace view v1 as select NOT 2 DIV 3, NOT (2 DIV 3), (NOT 2) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 DIV 3, NOT (2 DIV 3), (NOT 2) DIV 3 union select * from v1; + +create or replace view v1 as select NOT 6 MOD 3, NOT (6 MOD 3), (NOT 6) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 6 MOD 3, NOT (6 MOD 3), (NOT 6) MOD 3 union select * from v1; + +create or replace view v1 as select NOT 6 % 3, NOT (6 % 3), (NOT 6) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 6 % 3, NOT (6 % 3), (NOT 6) % 3 union select * from v1; + +create or replace view v1 as select NOT 2 ^ 3, NOT (2 ^ 3), (NOT 2) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 ^ 3, NOT (2 ^ 3), (NOT 2) ^ 3 union select * from v1; + +create or replace view v1 as select NOT 2 BETWEEN 3 AND 4, NOT (2 BETWEEN 3 AND 4), (NOT 2) BETWEEN 3 AND 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 BETWEEN 3 AND 4, NOT (2 BETWEEN 3 AND 4), (NOT 2) BETWEEN 3 AND 4 union select * from v1; + +create or replace view v1 as select - 2 IS TRUE, - (2 IS TRUE), (- 2) IS TRUE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 IS TRUE, - (2 IS TRUE), (- 2) IS TRUE union select * from v1; + +create or replace view v1 as select charset(- "2" COLLATE latin1_bin), charset(- ("2" COLLATE latin1_bin)), charset((- "2") COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(- "2" COLLATE latin1_bin), charset(- ("2" COLLATE latin1_bin)), charset((- "2") COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select - 2 IN (2,1), - (2 IN (2,1)), (- 2) IN (2,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 IN (2,1), - (2 IN (2,1)), (- 2) IN (2,1) union select * from v1; + +create or replace view v1 as select - 2 OR 3, - (2 OR 3), (- 2) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 OR 3, - (2 OR 3), (- 2) OR 3 union select * from v1; + +create or replace view v1 as select - 2 || 3, - (2 || 3), (- 2) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 || 3, - (2 || 3), (- 2) || 3 union select * from v1; + +create or replace view v1 as select - 0 XOR 3, - (0 XOR 3), (- 0) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 0 XOR 3, - (0 XOR 3), (- 0) XOR 3 union select * from v1; + +create or replace view v1 as select - 2 AND 3, - (2 AND 3), (- 2) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 AND 3, - (2 AND 3), (- 2) AND 3 union select * from v1; + +create or replace view v1 as select - 2 && 3, - (2 && 3), (- 2) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 && 3, - (2 && 3), (- 2) && 3 union select * from v1; + +create or replace view v1 as select - 2 = 2, - (2 = 2), (- 2) = 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 = 2, - (2 = 2), (- 2) = 2 union select * from v1; + +create or replace view v1 as select - 2 <=> 2, - (2 <=> 2), (- 2) <=> 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 <=> 2, - (2 <=> 2), (- 2) <=> 2 union select * from v1; + +create or replace view v1 as select - 2 >= 1, - (2 >= 1), (- 2) >= 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 >= 1, - (2 >= 1), (- 2) >= 1 union select * from v1; + +create or replace view v1 as select - 2 <= 3, - (2 <= 3), (- 2) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 <= 3, - (2 <= 3), (- 2) <= 3 union select * from v1; + +create or replace view v1 as select - 2 < 3, - (2 < 3), (- 2) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 < 3, - (2 < 3), (- 2) < 3 union select * from v1; + +create or replace view v1 as select - 2 <> 3, - (2 <> 3), (- 2) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 <> 3, - (2 <> 3), (- 2) <> 3 union select * from v1; + +create or replace view v1 as select - 2 > 1, - (2 > 1), (- 2) > 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 > 1, - (2 > 1), (- 2) > 1 union select * from v1; + +create or replace view v1 as select - 2 != 3, - (2 != 3), (- 2) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 != 3, - (2 != 3), (- 2) != 3 union select * from v1; + +create or replace view v1 as select - 2 LIKE 2, - (2 LIKE 2), (- 2) LIKE 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 LIKE 2, - (2 LIKE 2), (- 2) LIKE 2 union select * from v1; + +create or replace view v1 as select - 2 REGEXP 2, - (2 REGEXP 2), (- 2) REGEXP 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 REGEXP 2, - (2 REGEXP 2), (- 2) REGEXP 2 union select * from v1; + +create or replace view v1 as select - 2 | 3, - (2 | 3), (- 2) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 | 3, - (2 | 3), (- 2) | 3 union select * from v1; + +create or replace view v1 as select - 2 & 3, - (2 & 3), (- 2) & 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 & 3, - (2 & 3), (- 2) & 3 union select * from v1; + +create or replace view v1 as select - 2 << 3, - (2 << 3), (- 2) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 << 3, - (2 << 3), (- 2) << 3 union select * from v1; + +create or replace view v1 as select - 2 >> 3, - (2 >> 3), (- 2) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 >> 3, - (2 >> 3), (- 2) >> 3 union select * from v1; + +create or replace view v1 as select - '2000-01-01' +INTERVAL 1 DAY, - ('2000-01-01' +INTERVAL 1 DAY), (- '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - '2000-01-01' +INTERVAL 1 DAY, - ('2000-01-01' +INTERVAL 1 DAY), (- '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select - 2 + 3, - (2 + 3), (- 2) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 + 3, - (2 + 3), (- 2) + 3 union select * from v1; + +create or replace view v1 as select - 2 - 3, - (2 - 3), (- 2) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 - 3, - (2 - 3), (- 2) - 3 union select * from v1; + +create or replace view v1 as select - 2 ^ 3, - (2 ^ 3), (- 2) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 ^ 3, - (2 ^ 3), (- 2) ^ 3 union select * from v1; + +create or replace view v1 as select - 2 BETWEEN 1 AND 3, - (2 BETWEEN 1 AND 3), (- 2) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 BETWEEN 1 AND 3, - (2 BETWEEN 1 AND 3), (- 2) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select ~ 2 IS TRUE, ~ (2 IS TRUE), (~ 2) IS TRUE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 IS TRUE, ~ (2 IS TRUE), (~ 2) IS TRUE union select * from v1; + +create or replace view v1 as select charset(~ 2 COLLATE latin1_bin), charset(~ (2 COLLATE latin1_bin)), charset((~ 2) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(~ 2 COLLATE latin1_bin), charset(~ (2 COLLATE latin1_bin)), charset((~ 2) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select ~ 2 IN (0,1), ~ (2 IN (0,1)), (~ 2) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 IN (0,1), ~ (2 IN (0,1)), (~ 2) IN (0,1) union select * from v1; + +create or replace view v1 as select ~ 2 OR 3, ~ (2 OR 3), (~ 2) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 OR 3, ~ (2 OR 3), (~ 2) OR 3 union select * from v1; + +create or replace view v1 as select ~ 2 || 3, ~ (2 || 3), (~ 2) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 || 3, ~ (2 || 3), (~ 2) || 3 union select * from v1; + +create or replace view v1 as select ~ 2 XOR 3, ~ (2 XOR 3), (~ 2) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 XOR 3, ~ (2 XOR 3), (~ 2) XOR 3 union select * from v1; + +create or replace view v1 as select ~ 2 AND 3, ~ (2 AND 3), (~ 2) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 AND 3, ~ (2 AND 3), (~ 2) AND 3 union select * from v1; + +create or replace view v1 as select ~ 2 && 3, ~ (2 && 3), (~ 2) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 && 3, ~ (2 && 3), (~ 2) && 3 union select * from v1; + +create or replace view v1 as select ~ 2 = 3, ~ (2 = 3), (~ 2) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 = 3, ~ (2 = 3), (~ 2) = 3 union select * from v1; + +create or replace view v1 as select ~ 2 <=> 3, ~ (2 <=> 3), (~ 2) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 <=> 3, ~ (2 <=> 3), (~ 2) <=> 3 union select * from v1; + +create or replace view v1 as select ~ 2 >= 3, ~ (2 >= 3), (~ 2) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 >= 3, ~ (2 >= 3), (~ 2) >= 3 union select * from v1; + +create or replace view v1 as select ~ 2 <= 3, ~ (2 <= 3), (~ 2) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 <= 3, ~ (2 <= 3), (~ 2) <= 3 union select * from v1; + +create or replace view v1 as select ~ 2 < 3, ~ (2 < 3), (~ 2) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 < 3, ~ (2 < 3), (~ 2) < 3 union select * from v1; + +create or replace view v1 as select ~ 2 <> 3, ~ (2 <> 3), (~ 2) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 <> 3, ~ (2 <> 3), (~ 2) <> 3 union select * from v1; + +create or replace view v1 as select ~ 2 > 3, ~ (2 > 3), (~ 2) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 > 3, ~ (2 > 3), (~ 2) > 3 union select * from v1; + +create or replace view v1 as select ~ 2 != 3, ~ (2 != 3), (~ 2) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 != 3, ~ (2 != 3), (~ 2) != 3 union select * from v1; + +create or replace view v1 as select ~ 2 LIKE 3, ~ (2 LIKE 3), (~ 2) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 LIKE 3, ~ (2 LIKE 3), (~ 2) LIKE 3 union select * from v1; + +create or replace view v1 as select ~ 2 REGEXP 3, ~ (2 REGEXP 3), (~ 2) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 REGEXP 3, ~ (2 REGEXP 3), (~ 2) REGEXP 3 union select * from v1; + +create or replace view v1 as select ~ 2 | 3, ~ (2 | 3), (~ 2) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 | 3, ~ (2 | 3), (~ 2) | 3 union select * from v1; + +create or replace view v1 as select ~ 2 & 3, ~ (2 & 3), (~ 2) & 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 & 3, ~ (2 & 3), (~ 2) & 3 union select * from v1; + +create or replace view v1 as select ~ 2 << 3, ~ (2 << 3), (~ 2) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 << 3, ~ (2 << 3), (~ 2) << 3 union select * from v1; + +create or replace view v1 as select ~ 2 >> 3, ~ (2 >> 3), (~ 2) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 >> 3, ~ (2 >> 3), (~ 2) >> 3 union select * from v1; + +create or replace view v1 as select ~ '2000-01-01' +INTERVAL 1 DAY, ~ ('2000-01-01' +INTERVAL 1 DAY), (~ '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ '2000-01-01' +INTERVAL 1 DAY, ~ ('2000-01-01' +INTERVAL 1 DAY), (~ '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select ~ 10000 + 3, ~ (10000 + 3), (~ 10000) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 10000 + 3, ~ (10000 + 3), (~ 10000) + 3 union select * from v1; + +create or replace view v1 as select ~ 2 - 3, ~ (2 - 3), (~ 2) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 - 3, ~ (2 - 3), (~ 2) - 3 union select * from v1; + +create or replace view v1 as select ~ 10000000000000000000 * 2, ~ (100 * 2), (~ 10000000000000000000) * 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 10000000000000000000 * 2, ~ (100 * 2), (~ 10000000000000000000) * 2 union select * from v1; + +create or replace view v1 as select ~ 2 / 3, ~ (2 / 3), (~ 2) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 / 3, ~ (2 / 3), (~ 2) / 3 union select * from v1; + +create or replace view v1 as select ~ 2 DIV 3, ~ (2 DIV 3), (~ 2) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 DIV 3, ~ (2 DIV 3), (~ 2) DIV 3 union select * from v1; + +create or replace view v1 as select ~ 2 MOD 3, ~ (2 MOD 3), (~ 2) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 MOD 3, ~ (2 MOD 3), (~ 2) MOD 3 union select * from v1; + +create or replace view v1 as select ~ 2 % 3, ~ (2 % 3), (~ 2) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 % 3, ~ (2 % 3), (~ 2) % 3 union select * from v1; + +create or replace view v1 as select ~ 2 BETWEEN 1 AND 3, ~ (2 BETWEEN 1 AND 3), (~ 2) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 BETWEEN 1 AND 3, ~ (2 BETWEEN 1 AND 3), (~ 2) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select charset(! 2 COLLATE latin1_bin), charset(! (2 COLLATE latin1_bin)), charset((! 2) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(! 2 COLLATE latin1_bin), charset(! (2 COLLATE latin1_bin)), charset((! 2) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select ! 2 IN (0,2), ! (2 IN (0,2)), (! 2) IN (0,2); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 IN (0,2), ! (2 IN (0,2)), (! 2) IN (0,2) union select * from v1; + +create or replace view v1 as select ! 2 OR 3, ! (2 OR 3), (! 2) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 OR 3, ! (2 OR 3), (! 2) OR 3 union select * from v1; + +create or replace view v1 as select ! 2 || 3, ! (2 || 3), (! 2) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 || 3, ! (2 || 3), (! 2) || 3 union select * from v1; + +create or replace view v1 as select ! 2 AND 0, ! (2 AND 0), (! 2) AND 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 AND 0, ! (2 AND 0), (! 2) AND 0 union select * from v1; + +create or replace view v1 as select ! 2 && 0, ! (2 && 0), (! 2) && 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 && 0, ! (2 && 0), (! 2) && 0 union select * from v1; + +create or replace view v1 as select ! 2 = 3, ! (2 = 3), (! 2) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 = 3, ! (2 = 3), (! 2) = 3 union select * from v1; + +create or replace view v1 as select ! 2 <=> 3, ! (2 <=> 3), (! 2) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 <=> 3, ! (2 <=> 3), (! 2) <=> 3 union select * from v1; + +create or replace view v1 as select ! 2 >= 3, ! (2 >= 3), (! 2) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 >= 3, ! (2 >= 3), (! 2) >= 3 union select * from v1; + +create or replace view v1 as select ! 2 <= 3, ! (2 <= 3), (! 2) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 <= 3, ! (2 <= 3), (! 2) <= 3 union select * from v1; + +create or replace view v1 as select ! 2 < 3, ! (2 < 3), (! 2) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 < 3, ! (2 < 3), (! 2) < 3 union select * from v1; + +create or replace view v1 as select ! 2 <> 3, ! (2 <> 3), (! 2) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 <> 3, ! (2 <> 3), (! 2) <> 3 union select * from v1; + +create or replace view v1 as select ! 2 > 3, ! (2 > 3), (! 2) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 > 3, ! (2 > 3), (! 2) > 3 union select * from v1; + +create or replace view v1 as select ! 2 != 3, ! (2 != 3), (! 2) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 != 3, ! (2 != 3), (! 2) != 3 union select * from v1; + +create or replace view v1 as select ! 2 LIKE 3, ! (2 LIKE 3), (! 2) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 LIKE 3, ! (2 LIKE 3), (! 2) LIKE 3 union select * from v1; + +create or replace view v1 as select ! 2 REGEXP 3, ! (2 REGEXP 3), (! 2) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 REGEXP 3, ! (2 REGEXP 3), (! 2) REGEXP 3 union select * from v1; + +create or replace view v1 as select ! 2 | 3, ! (2 | 3), (! 2) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 | 3, ! (2 | 3), (! 2) | 3 union select * from v1; + +create or replace view v1 as select ! 2 & 0, ! (2 & 0), (! 2) & 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 & 0, ! (2 & 0), (! 2) & 0 union select * from v1; + +create or replace view v1 as select ! 0 << 3, ! (0 << 3), (! 0) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 0 << 3, ! (0 << 3), (! 0) << 3 union select * from v1; + +create or replace view v1 as select ! 2 >> 3, ! (2 >> 3), (! 2) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 >> 3, ! (2 >> 3), (! 2) >> 3 union select * from v1; + +create or replace view v1 as select ! '2000-01-01' +INTERVAL 1 DAY, ! ('2000-01-01' +INTERVAL 1 DAY), (! '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! '2000-01-01' +INTERVAL 1 DAY, ! ('2000-01-01' +INTERVAL 1 DAY), (! '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select ! 2 + 3, ! (2 + 3), (! 2) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 + 3, ! (2 + 3), (! 2) + 3 union select * from v1; + +create or replace view v1 as select ! 2 - 3, ! (2 - 3), (! 2) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 - 3, ! (2 - 3), (! 2) - 3 union select * from v1; + +create or replace view v1 as select ! 0 * 3, ! (0 * 3), (! 0) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 0 * 3, ! (0 * 3), (! 0) * 3 union select * from v1; + +create or replace view v1 as select ! 0 / 3, ! (0 / 3), (! 0) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 0 / 3, ! (0 / 3), (! 0) / 3 union select * from v1; + +create or replace view v1 as select ! 2 DIV 3, ! (2 DIV 3), (! 2) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 DIV 3, ! (2 DIV 3), (! 2) DIV 3 union select * from v1; + +create or replace view v1 as select ! 6 MOD 3, ! (6 MOD 3), (! 6) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 6 MOD 3, ! (6 MOD 3), (! 6) MOD 3 union select * from v1; + +create or replace view v1 as select ! 6 % 3, ! (6 % 3), (! 6) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 6 % 3, ! (6 % 3), (! 6) % 3 union select * from v1; + +create or replace view v1 as select ! 2 ^ 3, ! (2 ^ 3), (! 2) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 ^ 3, ! (2 ^ 3), (! 2) ^ 3 union select * from v1; + +create or replace view v1 as select ! 2 BETWEEN 3 AND 4, ! (2 BETWEEN 3 AND 4), (! 2) BETWEEN 3 AND 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 BETWEEN 3 AND 4, ! (2 BETWEEN 3 AND 4), (! 2) BETWEEN 3 AND 4 union select * from v1; + +create or replace view v1 as select CHARSET(BINARY '2' COLLATE latin1_bin), CHARSET(BINARY ('2' COLLATE latin1_bin)), 'error'/*CHARSET((BINARY '2') COLLATE latin1_bin)*/; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select CHARSET(BINARY '2' COLLATE latin1_bin), CHARSET(BINARY ('2' COLLATE latin1_bin)), 'error'/*CHARSET((BINARY '2') COLLATE latin1_bin)*/ union select * from v1; + +create or replace view v1 as select BINARY 'c' IN ('C','X'), BINARY ('c' IN ('C','X')), (BINARY 'c') IN ('C','X'); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select BINARY 'c' IN ('C','X'), BINARY ('c' IN ('C','X')), (BINARY 'c') IN ('C','X') union select * from v1; + +create or replace view v1 as select BINARY 'c' = 'C', BINARY ('c' = 'C'), (BINARY 'c') = 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select BINARY 'c' = 'C', BINARY ('c' = 'C'), (BINARY 'c') = 'C' union select * from v1; + +create or replace view v1 as select BINARY 'c' <=> 'C', BINARY ('c' <=> 'C'), (BINARY 'c') <=> 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select BINARY 'c' <=> 'C', BINARY ('c' <=> 'C'), (BINARY 'c') <=> 'C' union select * from v1; + +create or replace view v1 as select BINARY 'c' >= 'D', BINARY ('c' >= 'D'), (BINARY 'c') >= 'D'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select BINARY 'c' >= 'D', BINARY ('c' >= 'D'), (BINARY 'c') >= 'D' union select * from v1; + +create or replace view v1 as select BINARY 'c' <= 'C', BINARY ('c' <= 'C'), (BINARY 'c') <= 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select BINARY 'c' <= 'C', BINARY ('c' <= 'C'), (BINARY 'c') <= 'C' union select * from v1; + +create or replace view v1 as select BINARY 'c' < 'D', BINARY ('c' < 'D'), (BINARY 'c') < 'D'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select BINARY 'c' < 'D', BINARY ('c' < 'D'), (BINARY 'c') < 'D' union select * from v1; + +create or replace view v1 as select BINARY 'c' <> 'C', BINARY ('c' <> 'C'), (BINARY 'c') <> 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select BINARY 'c' <> 'C', BINARY ('c' <> 'C'), (BINARY 'c') <> 'C' union select * from v1; + +create or replace view v1 as select BINARY 'c' > 'C', BINARY ('c' > 'C'), (BINARY 'c') > 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select BINARY 'c' > 'C', BINARY ('c' > 'C'), (BINARY 'c') > 'C' union select * from v1; + +create or replace view v1 as select BINARY 'c' != 'C', BINARY ('c' != 'C'), (BINARY 'c') != 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select BINARY 'c' != 'C', BINARY ('c' != 'C'), (BINARY 'c') != 'C' union select * from v1; + +create or replace view v1 as select BINARY 'c' LIKE 'C', BINARY ('c' LIKE 'C'), (BINARY 'c') LIKE 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select BINARY 'c' LIKE 'C', BINARY ('c' LIKE 'C'), (BINARY 'c') LIKE 'C' union select * from v1; + +create or replace view v1 as select BINARY 'c' REGEXP 'C', BINARY ('c' REGEXP 'C'), (BINARY 'c') REGEXP 'C'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select BINARY 'c' REGEXP 'C', BINARY ('c' REGEXP 'C'), (BINARY 'c') REGEXP 'C' union select * from v1; + +create or replace view v1 as select BINARY 'c' BETWEEN 'A' AND 'D', BINARY ('c' BETWEEN 'A' AND 'D'), (BINARY 'c') BETWEEN 'A' AND 'D'; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select BINARY 'c' BETWEEN 'A' AND 'D', BINARY ('c' BETWEEN 'A' AND 'D'), (BINARY 'c') BETWEEN 'A' AND 'D' union select * from v1; + +create or replace view v1 as select 2 OR 3 IS FALSE, 2 OR (3 IS FALSE), (2 OR 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 IS FALSE, 2 OR (3 IS FALSE), (2 OR 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 OR 3 COLLATE latin1_bin), charset(2 OR (3 COLLATE latin1_bin)), charset((2 OR 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 OR 3 COLLATE latin1_bin), charset(2 OR (3 COLLATE latin1_bin)), charset((2 OR 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 0 OR 3 IN (3,10), 0 OR (3 IN (3,10)), (0 OR 3) IN (3,10); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 OR 3 IN (3,10), 0 OR (3 IN (3,10)), (0 OR 3) IN (3,10) union select * from v1; + +create or replace view v1 as select 1 OR 0 XOR 1, 1 OR (0 XOR 1), (1 OR 0) XOR 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 OR 0 XOR 1, 1 OR (0 XOR 1), (1 OR 0) XOR 1 union select * from v1; + +create or replace view v1 as select 1 OR 1 AND 0, 1 OR (1 AND 0), (1 OR 1) AND 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 OR 1 AND 0, 1 OR (1 AND 0), (1 OR 1) AND 0 union select * from v1; + +create or replace view v1 as select 1 OR 1 && 0, 1 OR (1 && 0), (1 OR 1) && 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 OR 1 && 0, 1 OR (1 && 0), (1 OR 1) && 0 union select * from v1; + +create or replace view v1 as select 2 OR 3 = 3, 2 OR (3 = 3), (2 OR 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 = 3, 2 OR (3 = 3), (2 OR 3) = 3 union select * from v1; + +create or replace view v1 as select 2 OR 3 <=> 3, 2 OR (3 <=> 3), (2 OR 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 <=> 3, 2 OR (3 <=> 3), (2 OR 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 OR 3 >= 3, 2 OR (3 >= 3), (2 OR 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 >= 3, 2 OR (3 >= 3), (2 OR 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 OR 3 <= 0, 2 OR (3 <= 0), (2 OR 3) <= 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 <= 0, 2 OR (3 <= 0), (2 OR 3) <= 0 union select * from v1; + +create or replace view v1 as select 2 OR 3 < 0, 2 OR (3 < 0), (2 OR 3) < 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 < 0, 2 OR (3 < 0), (2 OR 3) < 0 union select * from v1; + +create or replace view v1 as select 0 OR 3 <> 3, 0 OR (3 <> 3), (0 OR 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 OR 3 <> 3, 0 OR (3 <> 3), (0 OR 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 OR 3 > 3, 2 OR (3 > 3), (2 OR 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 > 3, 2 OR (3 > 3), (2 OR 3) > 3 union select * from v1; + +create or replace view v1 as select 0 OR 3 != 3, 0 OR (3 != 3), (0 OR 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 OR 3 != 3, 0 OR (3 != 3), (0 OR 3) != 3 union select * from v1; + +create or replace view v1 as select 2 OR 3 LIKE 3, 2 OR (3 LIKE 3), (2 OR 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 LIKE 3, 2 OR (3 LIKE 3), (2 OR 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 OR 3 REGEXP 3, 2 OR (3 REGEXP 3), (2 OR 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 REGEXP 3, 2 OR (3 REGEXP 3), (2 OR 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 OR 3 | 3, 2 OR (3 | 3), (2 OR 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 | 3, 2 OR (3 | 3), (2 OR 3) | 3 union select * from v1; + +create or replace view v1 as select 0 OR 2 & 2, 0 OR (2 & 2), (0 OR 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 OR 2 & 2, 0 OR (2 & 2), (0 OR 2) & 2 union select * from v1; + +create or replace view v1 as select 2 OR 3 << 3, 2 OR (3 << 3), (2 OR 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 << 3, 2 OR (3 << 3), (2 OR 3) << 3 union select * from v1; + +create or replace view v1 as select 2 OR 3 >> 3, 2 OR (3 >> 3), (2 OR 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 >> 3, 2 OR (3 >> 3), (2 OR 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 OR '2000-01-01' +INTERVAL 1 DAY, 2 OR ('2000-01-01' +INTERVAL 1 DAY), (2 OR '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR '2000-01-01' +INTERVAL 1 DAY, 2 OR ('2000-01-01' +INTERVAL 1 DAY), (2 OR '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 OR 3 + 3, 2 OR (3 + 3), (2 OR 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 + 3, 2 OR (3 + 3), (2 OR 3) + 3 union select * from v1; + +create or replace view v1 as select 2 OR 3 - 3, 2 OR (3 - 3), (2 OR 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 - 3, 2 OR (3 - 3), (2 OR 3) - 3 union select * from v1; + +create or replace view v1 as select 2 OR 3 * 3, 2 OR (3 * 3), (2 OR 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 * 3, 2 OR (3 * 3), (2 OR 3) * 3 union select * from v1; + +create or replace view v1 as select 2 OR 3 / 3, 2 OR (3 / 3), (2 OR 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 / 3, 2 OR (3 / 3), (2 OR 3) / 3 union select * from v1; + +create or replace view v1 as select 2 OR 3 DIV 3, 2 OR (3 DIV 3), (2 OR 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 DIV 3, 2 OR (3 DIV 3), (2 OR 3) DIV 3 union select * from v1; + +create or replace view v1 as select 0 OR 3 MOD 3, 0 OR (3 MOD 3), (0 OR 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 OR 3 MOD 3, 0 OR (3 MOD 3), (0 OR 3) MOD 3 union select * from v1; + +create or replace view v1 as select 0 OR 3 % 3, 0 OR (3 % 3), (0 OR 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 OR 3 % 3, 0 OR (3 % 3), (0 OR 3) % 3 union select * from v1; + +create or replace view v1 as select 2 OR 3 ^ 3, 2 OR (3 ^ 3), (2 OR 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 ^ 3, 2 OR (3 ^ 3), (2 OR 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 OR 3 BETWEEN 2 AND 3, 2 OR (3 BETWEEN 2 AND 3), (2 OR 3) BETWEEN 2 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 BETWEEN 2 AND 3, 2 OR (3 BETWEEN 2 AND 3), (2 OR 3) BETWEEN 2 AND 3 union select * from v1; + +create or replace view v1 as select 2 || 3 IS FALSE, 2 || (3 IS FALSE), (2 || 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 IS FALSE, 2 || (3 IS FALSE), (2 || 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 || 3 COLLATE latin1_bin), charset(2 || (3 COLLATE latin1_bin)), charset((2 || 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 || 3 COLLATE latin1_bin), charset(2 || (3 COLLATE latin1_bin)), charset((2 || 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 0 || 3 IN (3,10), 0 || (3 IN (3,10)), (0 || 3) IN (3,10); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 || 3 IN (3,10), 0 || (3 IN (3,10)), (0 || 3) IN (3,10) union select * from v1; + +create or replace view v1 as select 1 || 0 XOR 1, 1 || (0 XOR 1), (1 || 0) XOR 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 || 0 XOR 1, 1 || (0 XOR 1), (1 || 0) XOR 1 union select * from v1; + +create or replace view v1 as select 1 || 1 AND 0, 1 || (1 AND 0), (1 || 1) AND 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 || 1 AND 0, 1 || (1 AND 0), (1 || 1) AND 0 union select * from v1; + +create or replace view v1 as select 1 || 1 && 0, 1 || (1 && 0), (1 || 1) && 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 || 1 && 0, 1 || (1 && 0), (1 || 1) && 0 union select * from v1; + +create or replace view v1 as select 2 || 3 = 3, 2 || (3 = 3), (2 || 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 = 3, 2 || (3 = 3), (2 || 3) = 3 union select * from v1; + +create or replace view v1 as select 2 || 3 <=> 3, 2 || (3 <=> 3), (2 || 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 <=> 3, 2 || (3 <=> 3), (2 || 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 || 3 >= 3, 2 || (3 >= 3), (2 || 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 >= 3, 2 || (3 >= 3), (2 || 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 || 3 <= 0, 2 || (3 <= 0), (2 || 3) <= 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 <= 0, 2 || (3 <= 0), (2 || 3) <= 0 union select * from v1; + +create or replace view v1 as select 2 || 3 < 0, 2 || (3 < 0), (2 || 3) < 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 < 0, 2 || (3 < 0), (2 || 3) < 0 union select * from v1; + +create or replace view v1 as select 0 || 3 <> 3, 0 || (3 <> 3), (0 || 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 || 3 <> 3, 0 || (3 <> 3), (0 || 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 || 3 > 3, 2 || (3 > 3), (2 || 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 > 3, 2 || (3 > 3), (2 || 3) > 3 union select * from v1; + +create or replace view v1 as select 0 || 3 != 3, 0 || (3 != 3), (0 || 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 || 3 != 3, 0 || (3 != 3), (0 || 3) != 3 union select * from v1; + +create or replace view v1 as select 2 || 3 LIKE 3, 2 || (3 LIKE 3), (2 || 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 LIKE 3, 2 || (3 LIKE 3), (2 || 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 || 3 REGEXP 3, 2 || (3 REGEXP 3), (2 || 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 REGEXP 3, 2 || (3 REGEXP 3), (2 || 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 || 3 | 3, 2 || (3 | 3), (2 || 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 | 3, 2 || (3 | 3), (2 || 3) | 3 union select * from v1; + +create or replace view v1 as select 0 || 2 & 2, 0 || (2 & 2), (0 || 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 || 2 & 2, 0 || (2 & 2), (0 || 2) & 2 union select * from v1; + +create or replace view v1 as select 2 || 3 << 3, 2 || (3 << 3), (2 || 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 << 3, 2 || (3 << 3), (2 || 3) << 3 union select * from v1; + +create or replace view v1 as select 2 || 3 >> 3, 2 || (3 >> 3), (2 || 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 >> 3, 2 || (3 >> 3), (2 || 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 || '2000-01-01' +INTERVAL 1 DAY, 2 || ('2000-01-01' +INTERVAL 1 DAY), (2 || '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || '2000-01-01' +INTERVAL 1 DAY, 2 || ('2000-01-01' +INTERVAL 1 DAY), (2 || '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 || 3 + 3, 2 || (3 + 3), (2 || 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 + 3, 2 || (3 + 3), (2 || 3) + 3 union select * from v1; + +create or replace view v1 as select 2 || 3 - 3, 2 || (3 - 3), (2 || 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 - 3, 2 || (3 - 3), (2 || 3) - 3 union select * from v1; + +create or replace view v1 as select 2 || 3 * 3, 2 || (3 * 3), (2 || 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 * 3, 2 || (3 * 3), (2 || 3) * 3 union select * from v1; + +create or replace view v1 as select 2 || 3 / 3, 2 || (3 / 3), (2 || 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 / 3, 2 || (3 / 3), (2 || 3) / 3 union select * from v1; + +create or replace view v1 as select 2 || 3 DIV 3, 2 || (3 DIV 3), (2 || 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 DIV 3, 2 || (3 DIV 3), (2 || 3) DIV 3 union select * from v1; + +create or replace view v1 as select 0 || 3 MOD 3, 0 || (3 MOD 3), (0 || 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 || 3 MOD 3, 0 || (3 MOD 3), (0 || 3) MOD 3 union select * from v1; + +create or replace view v1 as select 0 || 3 % 3, 0 || (3 % 3), (0 || 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 || 3 % 3, 0 || (3 % 3), (0 || 3) % 3 union select * from v1; + +create or replace view v1 as select 2 || 3 ^ 3, 2 || (3 ^ 3), (2 || 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 ^ 3, 2 || (3 ^ 3), (2 || 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 || 3 BETWEEN 2 AND 3, 2 || (3 BETWEEN 2 AND 3), (2 || 3) BETWEEN 2 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 BETWEEN 2 AND 3, 2 || (3 BETWEEN 2 AND 3), (2 || 3) BETWEEN 2 AND 3 union select * from v1; + +create or replace view v1 as select charset(2 XOR 3 COLLATE latin1_bin), charset(2 XOR (3 COLLATE latin1_bin)), charset((2 XOR 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 XOR 3 COLLATE latin1_bin), charset(2 XOR (3 COLLATE latin1_bin)), charset((2 XOR 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 XOR 3 IN (4,5), 2 XOR (3 IN (4,5)), (2 XOR 3) IN (4,5); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 3 IN (4,5), 2 XOR (3 IN (4,5)), (2 XOR 3) IN (4,5) union select * from v1; + +create or replace view v1 as select 2 XOR 3 OR 3, 2 XOR (3 OR 3), (2 XOR 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 3 OR 3, 2 XOR (3 OR 3), (2 XOR 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 XOR 3 || 3, 2 XOR (3 || 3), (2 XOR 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 3 || 3, 2 XOR (3 || 3), (2 XOR 3) || 3 union select * from v1; + +create or replace view v1 as select 2 XOR 0 AND 0, 2 XOR (0 AND 0), (2 XOR 0) AND 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 0 AND 0, 2 XOR (0 AND 0), (2 XOR 0) AND 0 union select * from v1; + +create or replace view v1 as select 2 XOR 0 && 0, 2 XOR (0 && 0), (2 XOR 0) && 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 0 && 0, 2 XOR (0 && 0), (2 XOR 0) && 0 union select * from v1; + +create or replace view v1 as select 2 XOR 2 = 3, 2 XOR (2 = 3), (2 XOR 2) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 2 = 3, 2 XOR (2 = 3), (2 XOR 2) = 3 union select * from v1; + +create or replace view v1 as select NULL XOR 3 <=> 3, NULL XOR (3 <=> 3), (NULL XOR 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NULL XOR 3 <=> 3, NULL XOR (3 <=> 3), (NULL XOR 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 XOR 1 >= 3, 2 XOR (1 >= 3), (2 XOR 1) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 1 >= 3, 2 XOR (1 >= 3), (2 XOR 1) >= 3 union select * from v1; + +create or replace view v1 as select 2 XOR 3 <= 3, 2 XOR (3 <= 3), (2 XOR 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 3 <= 3, 2 XOR (3 <= 3), (2 XOR 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 XOR 1 < 3, 2 XOR (1 < 3), (2 XOR 1) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 1 < 3, 2 XOR (1 < 3), (2 XOR 1) < 3 union select * from v1; + +create or replace view v1 as select 2 XOR 2 <> 3, 2 XOR (2 <> 3), (2 XOR 2) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 2 <> 3, 2 XOR (2 <> 3), (2 XOR 2) <> 3 union select * from v1; + +create or replace view v1 as select 2 XOR 3 > 3, 2 XOR (3 > 3), (2 XOR 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 3 > 3, 2 XOR (3 > 3), (2 XOR 3) > 3 union select * from v1; + +create or replace view v1 as select 2 XOR 2 != 3, 2 XOR (2 != 3), (2 XOR 2) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 2 != 3, 2 XOR (2 != 3), (2 XOR 2) != 3 union select * from v1; + +create or replace view v1 as select 2 XOR 1 LIKE 3, 2 XOR (1 LIKE 3), (2 XOR 1) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 1 LIKE 3, 2 XOR (1 LIKE 3), (2 XOR 1) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 XOR 1 REGEXP 3, 2 XOR (1 REGEXP 3), (2 XOR 1) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 1 REGEXP 3, 2 XOR (1 REGEXP 3), (2 XOR 1) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 XOR 3 | 3, 2 XOR (3 | 3), (2 XOR 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 3 | 3, 2 XOR (3 | 3), (2 XOR 3) | 3 union select * from v1; + +create or replace view v1 as select 2 XOR 0 & 0, 2 XOR (0 & 0), (2 XOR 0) & 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 0 & 0, 2 XOR (0 & 0), (2 XOR 0) & 0 union select * from v1; + +create or replace view v1 as select 0 XOR 3 << 3, 0 XOR (3 << 3), (0 XOR 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 XOR 3 << 3, 0 XOR (3 << 3), (0 XOR 3) << 3 union select * from v1; + +create or replace view v1 as select 2 XOR 3 >> 3, 2 XOR (3 >> 3), (2 XOR 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 3 >> 3, 2 XOR (3 >> 3), (2 XOR 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 XOR '2000-01-01' +INTERVAL 1 DAY, 2 XOR ('2000-01-01' +INTERVAL 1 DAY), (2 XOR '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR '2000-01-01' +INTERVAL 1 DAY, 2 XOR ('2000-01-01' +INTERVAL 1 DAY), (2 XOR '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 XOR 3 + 3, 2 XOR (3 + 3), (2 XOR 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 3 + 3, 2 XOR (3 + 3), (2 XOR 3) + 3 union select * from v1; + +create or replace view v1 as select 2 XOR 3 - 3, 2 XOR (3 - 3), (2 XOR 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 3 - 3, 2 XOR (3 - 3), (2 XOR 3) - 3 union select * from v1; + +create or replace view v1 as select 0 XOR 3 * 3, 0 XOR (3 * 3), (0 XOR 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 XOR 3 * 3, 0 XOR (3 * 3), (0 XOR 3) * 3 union select * from v1; + +create or replace view v1 as select 0 XOR 3 / 3, 0 XOR (3 / 3), (0 XOR 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 XOR 3 / 3, 0 XOR (3 / 3), (0 XOR 3) / 3 union select * from v1; + +create or replace view v1 as select 0 XOR 3 DIV 3, 0 XOR (3 DIV 3), (0 XOR 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 XOR 3 DIV 3, 0 XOR (3 DIV 3), (0 XOR 3) DIV 3 union select * from v1; + +create or replace view v1 as select 2 XOR 3 MOD 3, 2 XOR (3 MOD 3), (2 XOR 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 3 MOD 3, 2 XOR (3 MOD 3), (2 XOR 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 XOR 3 % 3, 2 XOR (3 % 3), (2 XOR 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 3 % 3, 2 XOR (3 % 3), (2 XOR 3) % 3 union select * from v1; + +create or replace view v1 as select 2 XOR 3 ^ 3, 2 XOR (3 ^ 3), (2 XOR 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 3 ^ 3, 2 XOR (3 ^ 3), (2 XOR 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 XOR 3 BETWEEN 0 AND 3, 2 XOR (3 BETWEEN 0 AND 3), (2 XOR 3) BETWEEN 0 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 3 BETWEEN 0 AND 3, 2 XOR (3 BETWEEN 0 AND 3), (2 XOR 3) BETWEEN 0 AND 3 union select * from v1; + +create or replace view v1 as select 0 AND 3 IS FALSE, 0 AND (3 IS FALSE), (0 AND 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 AND 3 IS FALSE, 0 AND (3 IS FALSE), (0 AND 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 AND 3 COLLATE latin1_bin), charset(2 AND (3 COLLATE latin1_bin)), charset((2 AND 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 AND 3 COLLATE latin1_bin), charset(2 AND (3 COLLATE latin1_bin)), charset((2 AND 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 AND 3 IN (0,1), 2 AND (3 IN (0,1)), (2 AND 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 IN (0,1), 2 AND (3 IN (0,1)), (2 AND 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 0 AND 3 OR 3, 0 AND (3 OR 3), (0 AND 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 AND 3 OR 3, 0 AND (3 OR 3), (0 AND 3) OR 3 union select * from v1; + +create or replace view v1 as select 0 AND 3 || 3, 0 AND (3 || 3), (0 AND 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 AND 3 || 3, 0 AND (3 || 3), (0 AND 3) || 3 union select * from v1; + +create or replace view v1 as select 0 AND 3 XOR 3, 0 AND (3 XOR 3), (0 AND 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 AND 3 XOR 3, 0 AND (3 XOR 3), (0 AND 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 = 3, 2 AND (3 = 3), (2 AND 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 = 3, 2 AND (3 = 3), (2 AND 3) = 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 <=> 3, 2 AND (3 <=> 3), (2 AND 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 <=> 3, 2 AND (3 <=> 3), (2 AND 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 >= 3, 2 AND (3 >= 3), (2 AND 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 >= 3, 2 AND (3 >= 3), (2 AND 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 AND 4 <= 3, 2 AND (4 <= 3), (2 AND 4) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 4 <= 3, 2 AND (4 <= 3), (2 AND 4) <= 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 < 3, 2 AND (3 < 3), (2 AND 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 < 3, 2 AND (3 < 3), (2 AND 3) < 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 <> 3, 2 AND (3 <> 3), (2 AND 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 <> 3, 2 AND (3 <> 3), (2 AND 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 > 1, 2 AND (3 > 1), (2 AND 3) > 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 > 1, 2 AND (3 > 1), (2 AND 3) > 1 union select * from v1; + +create or replace view v1 as select 2 AND 3 != 3, 2 AND (3 != 3), (2 AND 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 != 3, 2 AND (3 != 3), (2 AND 3) != 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 LIKE 3, 2 AND (3 LIKE 3), (2 AND 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 LIKE 3, 2 AND (3 LIKE 3), (2 AND 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 REGEXP 3, 2 AND (3 REGEXP 3), (2 AND 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 REGEXP 3, 2 AND (3 REGEXP 3), (2 AND 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 | 3, 2 AND (3 | 3), (2 AND 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 | 3, 2 AND (3 | 3), (2 AND 3) | 3 union select * from v1; + +create or replace view v1 as select 2 AND 2 & 2, 2 AND (2 & 2), (2 AND 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 2 & 2, 2 AND (2 & 2), (2 AND 2) & 2 union select * from v1; + +create or replace view v1 as select 2 AND 3 << 3, 2 AND (3 << 3), (2 AND 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 << 3, 2 AND (3 << 3), (2 AND 3) << 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 >> 1, 2 AND (3 >> 1), (2 AND 3) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 >> 1, 2 AND (3 >> 1), (2 AND 3) >> 1 union select * from v1; + +create or replace view v1 as select 2 AND '2000-01-01' +INTERVAL 1 DAY, 2 AND ('2000-01-01' +INTERVAL 1 DAY), (2 AND '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND '2000-01-01' +INTERVAL 1 DAY, 2 AND ('2000-01-01' +INTERVAL 1 DAY), (2 AND '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 AND 3 + 3, 2 AND (3 + 3), (2 AND 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 + 3, 2 AND (3 + 3), (2 AND 3) + 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 - 3, 2 AND (3 - 3), (2 AND 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 - 3, 2 AND (3 - 3), (2 AND 3) - 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 * 3, 2 AND (3 * 3), (2 AND 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 * 3, 2 AND (3 * 3), (2 AND 3) * 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 / 3, 2 AND (3 / 3), (2 AND 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 / 3, 2 AND (3 / 3), (2 AND 3) / 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 DIV 3, 2 AND (3 DIV 3), (2 AND 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 DIV 3, 2 AND (3 DIV 3), (2 AND 3) DIV 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 MOD 3, 2 AND (3 MOD 3), (2 AND 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 MOD 3, 2 AND (3 MOD 3), (2 AND 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 % 3, 2 AND (3 % 3), (2 AND 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 % 3, 2 AND (3 % 3), (2 AND 3) % 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 ^ 3, 2 AND (3 ^ 3), (2 AND 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 ^ 3, 2 AND (3 ^ 3), (2 AND 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 AND 3 BETWEEN 2 AND 3, 2 AND (3 BETWEEN 2 AND 3), (2 AND 3) BETWEEN 2 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 BETWEEN 2 AND 3, 2 AND (3 BETWEEN 2 AND 3), (2 AND 3) BETWEEN 2 AND 3 union select * from v1; + +create or replace view v1 as select 0 && 3 IS FALSE, 0 && (3 IS FALSE), (0 && 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 && 3 IS FALSE, 0 && (3 IS FALSE), (0 && 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 && 3 COLLATE latin1_bin), charset(2 && (3 COLLATE latin1_bin)), charset((2 && 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 && 3 COLLATE latin1_bin), charset(2 && (3 COLLATE latin1_bin)), charset((2 && 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 && 3 IN (0,1), 2 && (3 IN (0,1)), (2 && 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 IN (0,1), 2 && (3 IN (0,1)), (2 && 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 0 && 3 OR 3, 0 && (3 OR 3), (0 && 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 && 3 OR 3, 0 && (3 OR 3), (0 && 3) OR 3 union select * from v1; + +create or replace view v1 as select 0 && 3 || 3, 0 && (3 || 3), (0 && 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 && 3 || 3, 0 && (3 || 3), (0 && 3) || 3 union select * from v1; + +create or replace view v1 as select 0 && 3 XOR 3, 0 && (3 XOR 3), (0 && 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 && 3 XOR 3, 0 && (3 XOR 3), (0 && 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 && 3 = 3, 2 && (3 = 3), (2 && 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 = 3, 2 && (3 = 3), (2 && 3) = 3 union select * from v1; + +create or replace view v1 as select 2 && 3 <=> 3, 2 && (3 <=> 3), (2 && 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 <=> 3, 2 && (3 <=> 3), (2 && 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 && 3 >= 3, 2 && (3 >= 3), (2 && 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 >= 3, 2 && (3 >= 3), (2 && 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 && 4 <= 3, 2 && (4 <= 3), (2 && 4) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 4 <= 3, 2 && (4 <= 3), (2 && 4) <= 3 union select * from v1; + +create or replace view v1 as select 2 && 3 < 3, 2 && (3 < 3), (2 && 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 < 3, 2 && (3 < 3), (2 && 3) < 3 union select * from v1; + +create or replace view v1 as select 2 && 3 <> 3, 2 && (3 <> 3), (2 && 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 <> 3, 2 && (3 <> 3), (2 && 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 && 3 > 1, 2 && (3 > 1), (2 && 3) > 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 > 1, 2 && (3 > 1), (2 && 3) > 1 union select * from v1; + +create or replace view v1 as select 2 && 3 != 3, 2 && (3 != 3), (2 && 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 != 3, 2 && (3 != 3), (2 && 3) != 3 union select * from v1; + +create or replace view v1 as select 2 && 3 LIKE 3, 2 && (3 LIKE 3), (2 && 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 LIKE 3, 2 && (3 LIKE 3), (2 && 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 && 3 REGEXP 3, 2 && (3 REGEXP 3), (2 && 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 REGEXP 3, 2 && (3 REGEXP 3), (2 && 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 && 3 | 3, 2 && (3 | 3), (2 && 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 | 3, 2 && (3 | 3), (2 && 3) | 3 union select * from v1; + +create or replace view v1 as select 2 && 2 & 2, 2 && (2 & 2), (2 && 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 2 & 2, 2 && (2 & 2), (2 && 2) & 2 union select * from v1; + +create or replace view v1 as select 2 && 3 << 3, 2 && (3 << 3), (2 && 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 << 3, 2 && (3 << 3), (2 && 3) << 3 union select * from v1; + +create or replace view v1 as select 2 && 3 >> 1, 2 && (3 >> 1), (2 && 3) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 >> 1, 2 && (3 >> 1), (2 && 3) >> 1 union select * from v1; + +create or replace view v1 as select 2 && '2000-01-01' +INTERVAL 1 DAY, 2 && ('2000-01-01' +INTERVAL 1 DAY), (2 && '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && '2000-01-01' +INTERVAL 1 DAY, 2 && ('2000-01-01' +INTERVAL 1 DAY), (2 && '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 && 3 + 3, 2 && (3 + 3), (2 && 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 + 3, 2 && (3 + 3), (2 && 3) + 3 union select * from v1; + +create or replace view v1 as select 2 && 3 - 3, 2 && (3 - 3), (2 && 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 - 3, 2 && (3 - 3), (2 && 3) - 3 union select * from v1; + +create or replace view v1 as select 2 && 3 * 3, 2 && (3 * 3), (2 && 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 * 3, 2 && (3 * 3), (2 && 3) * 3 union select * from v1; + +create or replace view v1 as select 2 && 3 / 3, 2 && (3 / 3), (2 && 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 / 3, 2 && (3 / 3), (2 && 3) / 3 union select * from v1; + +create or replace view v1 as select 2 && 3 DIV 3, 2 && (3 DIV 3), (2 && 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 DIV 3, 2 && (3 DIV 3), (2 && 3) DIV 3 union select * from v1; + +create or replace view v1 as select 2 && 3 MOD 3, 2 && (3 MOD 3), (2 && 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 MOD 3, 2 && (3 MOD 3), (2 && 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 && 3 % 3, 2 && (3 % 3), (2 && 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 % 3, 2 && (3 % 3), (2 && 3) % 3 union select * from v1; + +create or replace view v1 as select 2 && 3 ^ 3, 2 && (3 ^ 3), (2 && 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 ^ 3, 2 && (3 ^ 3), (2 && 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 && 3 BETWEEN 2 AND 3, 2 && (3 BETWEEN 2 AND 3), (2 && 3) BETWEEN 2 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 BETWEEN 2 AND 3, 2 && (3 BETWEEN 2 AND 3), (2 && 3) BETWEEN 2 AND 3 union select * from v1; + +create or replace view v1 as select 2 = 3 IS FALSE, 2 = (3 IS FALSE), (2 = 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 IS FALSE, 2 = (3 IS FALSE), (2 = 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 = 3 COLLATE latin1_bin), charset(2 = (3 COLLATE latin1_bin)), charset((2 = 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 = 3 COLLATE latin1_bin), charset(2 = (3 COLLATE latin1_bin)), charset((2 = 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 = 3 IN (0,1), 2 = (3 IN (0,1)), (2 = 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 IN (0,1), 2 = (3 IN (0,1)), (2 = 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 = 3 OR 3, 2 = (3 OR 3), (2 = 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 OR 3, 2 = (3 OR 3), (2 = 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 = 3 || 3, 2 = (3 || 3), (2 = 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 || 3, 2 = (3 || 3), (2 = 3) || 3 union select * from v1; + +create or replace view v1 as select 2 = 3 XOR 3, 2 = (3 XOR 3), (2 = 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 XOR 3, 2 = (3 XOR 3), (2 = 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 = 2 AND 2, 2 = (2 AND 2), (2 = 2) AND 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 2 AND 2, 2 = (2 AND 2), (2 = 2) AND 2 union select * from v1; + +create or replace view v1 as select 2 = 2 && 2, 2 = (2 && 2), (2 = 2) && 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 2 && 2, 2 = (2 && 2), (2 = 2) && 2 union select * from v1; + +create or replace view v1 as select 1 = 3 = 3, 1 = (3 = 3), (1 = 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 = 3 = 3, 1 = (3 = 3), (1 = 3) = 3 union select * from v1; + +create or replace view v1 as select 1 = 3 <=> 3, 1 = (3 <=> 3), (1 = 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 = 3 <=> 3, 1 = (3 <=> 3), (1 = 3) <=> 3 union select * from v1; + +create or replace view v1 as select 1 = 3 >= 3, 1 = (3 >= 3), (1 = 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 = 3 >= 3, 1 = (3 >= 3), (1 = 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 = 3 <= 3, 2 = (3 <= 3), (2 = 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 <= 3, 2 = (3 <= 3), (2 = 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 = 3 < 3, 2 = (3 < 3), (2 = 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 < 3, 2 = (3 < 3), (2 = 3) < 3 union select * from v1; + +create or replace view v1 as select 2 = 3 <> 3, 2 = (3 <> 3), (2 = 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 <> 3, 2 = (3 <> 3), (2 = 3) <> 3 union select * from v1; + +create or replace view v1 as select 0 = 3 > 3, 0 = (3 > 3), (0 = 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 = 3 > 3, 0 = (3 > 3), (0 = 3) > 3 union select * from v1; + +create or replace view v1 as select 2 = 3 != 3, 2 = (3 != 3), (2 = 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 != 3, 2 = (3 != 3), (2 = 3) != 3 union select * from v1; + +create or replace view v1 as select 1 = 3 LIKE 3, 1 = (3 LIKE 3), (1 = 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 = 3 LIKE 3, 1 = (3 LIKE 3), (1 = 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 1 = 3 REGEXP 3, 1 = (3 REGEXP 3), (1 = 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 = 3 REGEXP 3, 1 = (3 REGEXP 3), (1 = 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 = 3 | 3, 2 = (3 | 3), (2 = 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 | 3, 2 = (3 | 3), (2 = 3) | 3 union select * from v1; + +create or replace view v1 as select 2 = 3 & 2, 2 = (3 & 2), (2 = 3) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 & 2, 2 = (3 & 2), (2 = 3) & 2 union select * from v1; + +create or replace view v1 as select 3 = 3 << 3, 3 = (3 << 3), (3 = 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 = 3 << 3, 3 = (3 << 3), (3 = 3) << 3 union select * from v1; + +create or replace view v1 as select 1 = 3 >> 1, 1 = (3 >> 1), (1 = 3) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 = 3 >> 1, 1 = (3 >> 1), (1 = 3) >> 1 union select * from v1; + +create or replace view v1 as select 2 = '2000-01-01' +INTERVAL 1 DAY, 2 = ('2000-01-01' +INTERVAL 1 DAY), (2 = '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = '2000-01-01' +INTERVAL 1 DAY, 2 = ('2000-01-01' +INTERVAL 1 DAY), (2 = '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 = 3 + 3, 2 = (3 + 3), (2 = 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 + 3, 2 = (3 + 3), (2 = 3) + 3 union select * from v1; + +create or replace view v1 as select 2 = 3 - 3, 2 = (3 - 3), (2 = 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 - 3, 2 = (3 - 3), (2 = 3) - 3 union select * from v1; + +create or replace view v1 as select 3 = 3 * 3, 3 = (3 * 3), (3 = 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 = 3 * 3, 3 = (3 * 3), (3 = 3) * 3 union select * from v1; + +create or replace view v1 as select 3 = 9 / 3, 3 = (9 / 3), (3 = 9) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 = 9 / 3, 3 = (9 / 3), (3 = 9) / 3 union select * from v1; + +create or replace view v1 as select 3 = 9 DIV 3, 3 = (9 DIV 3), (3 = 9) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 = 9 DIV 3, 3 = (9 DIV 3), (3 = 9) DIV 3 union select * from v1; + +create or replace view v1 as select 3 = 3 MOD 3, 3 = (3 MOD 3), (3 = 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 = 3 MOD 3, 3 = (3 MOD 3), (3 = 3) MOD 3 union select * from v1; + +create or replace view v1 as select 3 = 3 % 3, 3 = (3 % 3), (3 = 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 = 3 % 3, 3 = (3 % 3), (3 = 3) % 3 union select * from v1; + +create or replace view v1 as select 2 = 3 ^ 3, 2 = (3 ^ 3), (2 = 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 ^ 3, 2 = (3 ^ 3), (2 = 3) ^ 3 union select * from v1; + +create or replace view v1 as select 1 = 3 BETWEEN 1 AND 3, 1 = (3 BETWEEN 1 AND 3), (1 = 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 = 3 BETWEEN 1 AND 3, 1 = (3 BETWEEN 1 AND 3), (1 = 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 <=> 3 IS FALSE, 2 <=> (3 IS FALSE), (2 <=> 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 IS FALSE, 2 <=> (3 IS FALSE), (2 <=> 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 <=> 3 COLLATE latin1_bin), charset(2 <=> (3 COLLATE latin1_bin)), charset((2 <=> 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 <=> 3 COLLATE latin1_bin), charset(2 <=> (3 COLLATE latin1_bin)), charset((2 <=> 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 <=> 3 IN (0,1), 2 <=> (3 IN (0,1)), (2 <=> 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 IN (0,1), 2 <=> (3 IN (0,1)), (2 <=> 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 <=> 3 OR 3, 2 <=> (3 OR 3), (2 <=> 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 OR 3, 2 <=> (3 OR 3), (2 <=> 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 <=> 3 || 3, 2 <=> (3 || 3), (2 <=> 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 || 3, 2 <=> (3 || 3), (2 <=> 3) || 3 union select * from v1; + +create or replace view v1 as select 2 <=> 3 XOR 3, 2 <=> (3 XOR 3), (2 <=> 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 XOR 3, 2 <=> (3 XOR 3), (2 <=> 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 <=> 2 AND 2, 2 <=> (2 AND 2), (2 <=> 2) AND 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 2 AND 2, 2 <=> (2 AND 2), (2 <=> 2) AND 2 union select * from v1; + +create or replace view v1 as select 2 <=> 2 && 2, 2 <=> (2 && 2), (2 <=> 2) && 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 2 && 2, 2 <=> (2 && 2), (2 <=> 2) && 2 union select * from v1; + +create or replace view v1 as select 1 <=> 3 = 3, 1 <=> (3 = 3), (1 <=> 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 <=> 3 = 3, 1 <=> (3 = 3), (1 <=> 3) = 3 union select * from v1; + +create or replace view v1 as select 1 <=> 3 <=> 3, 1 <=> (3 <=> 3), (1 <=> 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 <=> 3 <=> 3, 1 <=> (3 <=> 3), (1 <=> 3) <=> 3 union select * from v1; + +create or replace view v1 as select 1 <=> 3 >= 3, 1 <=> (3 >= 3), (1 <=> 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 <=> 3 >= 3, 1 <=> (3 >= 3), (1 <=> 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 <=> 3 <= 3, 2 <=> (3 <= 3), (2 <=> 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 <= 3, 2 <=> (3 <= 3), (2 <=> 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 <=> 3 < 3, 2 <=> (3 < 3), (2 <=> 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 < 3, 2 <=> (3 < 3), (2 <=> 3) < 3 union select * from v1; + +create or replace view v1 as select 2 <=> 3 <> 3, 2 <=> (3 <> 3), (2 <=> 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 <> 3, 2 <=> (3 <> 3), (2 <=> 3) <> 3 union select * from v1; + +create or replace view v1 as select 0 <=> 3 > 3, 0 <=> (3 > 3), (0 <=> 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 <=> 3 > 3, 0 <=> (3 > 3), (0 <=> 3) > 3 union select * from v1; + +create or replace view v1 as select 2 <=> 3 != 3, 2 <=> (3 != 3), (2 <=> 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 != 3, 2 <=> (3 != 3), (2 <=> 3) != 3 union select * from v1; + +create or replace view v1 as select 1 <=> 3 LIKE 3, 1 <=> (3 LIKE 3), (1 <=> 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 <=> 3 LIKE 3, 1 <=> (3 LIKE 3), (1 <=> 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 1 <=> 3 REGEXP 3, 1 <=> (3 REGEXP 3), (1 <=> 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 <=> 3 REGEXP 3, 1 <=> (3 REGEXP 3), (1 <=> 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 <=> 3 | 3, 2 <=> (3 | 3), (2 <=> 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 | 3, 2 <=> (3 | 3), (2 <=> 3) | 3 union select * from v1; + +create or replace view v1 as select 2 <=> 3 & 2, 2 <=> (3 & 2), (2 <=> 3) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 & 2, 2 <=> (3 & 2), (2 <=> 3) & 2 union select * from v1; + +create or replace view v1 as select 3 <=> 3 << 3, 3 <=> (3 << 3), (3 <=> 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 <=> 3 << 3, 3 <=> (3 << 3), (3 <=> 3) << 3 union select * from v1; + +create or replace view v1 as select 1 <=> 3 >> 1, 1 <=> (3 >> 1), (1 <=> 3) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 <=> 3 >> 1, 1 <=> (3 >> 1), (1 <=> 3) >> 1 union select * from v1; + +create or replace view v1 as select 2 <=> '2000-01-01' +INTERVAL 1 DAY, 2 <=> ('2000-01-01' +INTERVAL 1 DAY), (2 <=> '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> '2000-01-01' +INTERVAL 1 DAY, 2 <=> ('2000-01-01' +INTERVAL 1 DAY), (2 <=> '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 <=> 3 + 3, 2 <=> (3 + 3), (2 <=> 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 + 3, 2 <=> (3 + 3), (2 <=> 3) + 3 union select * from v1; + +create or replace view v1 as select 2 <=> 3 - 3, 2 <=> (3 - 3), (2 <=> 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 - 3, 2 <=> (3 - 3), (2 <=> 3) - 3 union select * from v1; + +create or replace view v1 as select 3 <=> 3 * 3, 3 <=> (3 * 3), (3 <=> 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 <=> 3 * 3, 3 <=> (3 * 3), (3 <=> 3) * 3 union select * from v1; + +create or replace view v1 as select 3 <=> 9 / 3, 3 <=> (9 / 3), (3 <=> 9) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 <=> 9 / 3, 3 <=> (9 / 3), (3 <=> 9) / 3 union select * from v1; + +create or replace view v1 as select 3 <=> 9 DIV 3, 3 <=> (9 DIV 3), (3 <=> 9) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 <=> 9 DIV 3, 3 <=> (9 DIV 3), (3 <=> 9) DIV 3 union select * from v1; + +create or replace view v1 as select 3 <=> 3 MOD 3, 3 <=> (3 MOD 3), (3 <=> 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 <=> 3 MOD 3, 3 <=> (3 MOD 3), (3 <=> 3) MOD 3 union select * from v1; + +create or replace view v1 as select 3 <=> 3 % 3, 3 <=> (3 % 3), (3 <=> 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 <=> 3 % 3, 3 <=> (3 % 3), (3 <=> 3) % 3 union select * from v1; + +create or replace view v1 as select 2 <=> 3 ^ 3, 2 <=> (3 ^ 3), (2 <=> 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 ^ 3, 2 <=> (3 ^ 3), (2 <=> 3) ^ 3 union select * from v1; + +create or replace view v1 as select 1 <=> 3 BETWEEN 1 AND 3, 1 <=> (3 BETWEEN 1 AND 3), (1 <=> 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 <=> 3 BETWEEN 1 AND 3, 1 <=> (3 BETWEEN 1 AND 3), (1 <=> 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 4 >= 3 IS FALSE, 4 >= (3 IS FALSE), (4 >= 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 4 >= 3 IS FALSE, 4 >= (3 IS FALSE), (4 >= 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 >= 3 COLLATE latin1_bin), charset(2 >= (3 COLLATE latin1_bin)), charset((2 >= 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 >= 3 COLLATE latin1_bin), charset(2 >= (3 COLLATE latin1_bin)), charset((2 >= 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 >= 3 IN (1,1), 2 >= (3 IN (1,1)), (2 >= 3) IN (1,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 IN (1,1), 2 >= (3 IN (1,1)), (2 >= 3) IN (1,1) union select * from v1; + +create or replace view v1 as select 2 >= 3 OR 0, 2 >= (3 OR 0), (2 >= 3) OR 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 OR 0, 2 >= (3 OR 0), (2 >= 3) OR 0 union select * from v1; + +create or replace view v1 as select 2 >= 3 || 0, 2 >= (3 || 0), (2 >= 3) || 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 || 0, 2 >= (3 || 0), (2 >= 3) || 0 union select * from v1; + +create or replace view v1 as select 2 >= 3 XOR 0, 2 >= (3 XOR 0), (2 >= 3) XOR 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 XOR 0, 2 >= (3 XOR 0), (2 >= 3) XOR 0 union select * from v1; + +create or replace view v1 as select 2 >= 3 AND 3, 2 >= (3 AND 3), (2 >= 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 AND 3, 2 >= (3 AND 3), (2 >= 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 && 3, 2 >= (3 && 3), (2 >= 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 && 3, 2 >= (3 && 3), (2 >= 3) && 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 = 3, 2 >= (3 = 3), (2 >= 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 = 3, 2 >= (3 = 3), (2 >= 3) = 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 <=> 3, 2 >= (3 <=> 3), (2 >= 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 <=> 3, 2 >= (3 <=> 3), (2 >= 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 >= 3, 2 >= (3 >= 3), (2 >= 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 >= 3, 2 >= (3 >= 3), (2 >= 3) >= 3 union select * from v1; + +create or replace view v1 as select 0 >= 3 <= 3, 0 >= (3 <= 3), (0 >= 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 >= 3 <= 3, 0 >= (3 <= 3), (0 >= 3) <= 3 union select * from v1; + +create or replace view v1 as select 0 >= 2 < 3, 0 >= (2 < 3), (0 >= 2) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 >= 2 < 3, 0 >= (2 < 3), (0 >= 2) < 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 <> 0, 2 >= (3 <> 0), (2 >= 3) <> 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 <> 0, 2 >= (3 <> 0), (2 >= 3) <> 0 union select * from v1; + +create or replace view v1 as select 2 >= 3 > 3, 2 >= (3 > 3), (2 >= 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 > 3, 2 >= (3 > 3), (2 >= 3) > 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 != 0, 2 >= (3 != 0), (2 >= 3) != 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 != 0, 2 >= (3 != 0), (2 >= 3) != 0 union select * from v1; + +create or replace view v1 as select 2 >= 3 LIKE 3, 2 >= (3 LIKE 3), (2 >= 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 LIKE 3, 2 >= (3 LIKE 3), (2 >= 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 REGEXP 3, 2 >= (3 REGEXP 3), (2 >= 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 REGEXP 3, 2 >= (3 REGEXP 3), (2 >= 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 | 3, 2 >= (3 | 3), (2 >= 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 | 3, 2 >= (3 | 3), (2 >= 3) | 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 & 1, 2 >= (3 & 1), (2 >= 3) & 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 & 1, 2 >= (3 & 1), (2 >= 3) & 1 union select * from v1; + +create or replace view v1 as select 3 >= 3 << 3, 3 >= (3 << 3), (3 >= 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 >= 3 << 3, 3 >= (3 << 3), (3 >= 3) << 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 >> 3, 2 >= (3 >> 3), (2 >= 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 >> 3, 2 >= (3 >> 3), (2 >= 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 >= '2000-01-01' +INTERVAL 1 DAY, 2 >= ('2000-01-01' +INTERVAL 1 DAY), (2 >= '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= '2000-01-01' +INTERVAL 1 DAY, 2 >= ('2000-01-01' +INTERVAL 1 DAY), (2 >= '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 >= 3 + 3, 2 >= (3 + 3), (2 >= 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 + 3, 2 >= (3 + 3), (2 >= 3) + 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 - 3, 2 >= (3 - 3), (2 >= 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 - 3, 2 >= (3 - 3), (2 >= 3) - 3 union select * from v1; + +create or replace view v1 as select 3 >= 3 * 3, 3 >= (3 * 3), (3 >= 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 >= 3 * 3, 3 >= (3 * 3), (3 >= 3) * 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 / 3, 2 >= (3 / 3), (2 >= 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 / 3, 2 >= (3 / 3), (2 >= 3) / 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 DIV 3, 2 >= (3 DIV 3), (2 >= 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 DIV 3, 2 >= (3 DIV 3), (2 >= 3) DIV 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 MOD 3, 2 >= (3 MOD 3), (2 >= 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 MOD 3, 2 >= (3 MOD 3), (2 >= 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 % 3, 2 >= (3 % 3), (2 >= 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 % 3, 2 >= (3 % 3), (2 >= 3) % 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 ^ 3, 2 >= (3 ^ 3), (2 >= 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 ^ 3, 2 >= (3 ^ 3), (2 >= 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 BETWEEN 1 AND 3, 2 >= (3 BETWEEN 1 AND 3), (2 >= 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 BETWEEN 1 AND 3, 2 >= (3 BETWEEN 1 AND 3), (2 >= 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 <= 1 IS FALSE, 2 <= (1 IS FALSE), (2 <= 1) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 1 IS FALSE, 2 <= (1 IS FALSE), (2 <= 1) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 <= 3 COLLATE latin1_bin), charset(2 <= (3 COLLATE latin1_bin)), charset((2 <= 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 <= 3 COLLATE latin1_bin), charset(2 <= (3 COLLATE latin1_bin)), charset((2 <= 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 <= 3 IN (0,1), 2 <= (3 IN (0,1)), (2 <= 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 IN (0,1), 2 <= (3 IN (0,1)), (2 <= 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 <= 3 OR 3, 2 <= (3 OR 3), (2 <= 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 OR 3, 2 <= (3 OR 3), (2 <= 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 <= 3 || 3, 2 <= (3 || 3), (2 <= 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 || 3, 2 <= (3 || 3), (2 <= 3) || 3 union select * from v1; + +create or replace view v1 as select 2 <= 1 XOR 1, 2 <= (1 XOR 1), (2 <= 1) XOR 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 1 XOR 1, 2 <= (1 XOR 1), (2 <= 1) XOR 1 union select * from v1; + +create or replace view v1 as select 2 <= 3 AND 3, 2 <= (3 AND 3), (2 <= 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 AND 3, 2 <= (3 AND 3), (2 <= 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 <= 3 && 3, 2 <= (3 && 3), (2 <= 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 && 3, 2 <= (3 && 3), (2 <= 3) && 3 union select * from v1; + +create or replace view v1 as select 2 <= 0 = 0, 2 <= (0 = 0), (2 <= 0) = 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 0 = 0, 2 <= (0 = 0), (2 <= 0) = 0 union select * from v1; + +create or replace view v1 as select 2 <= 0 <=> 0, 2 <= (0 <=> 0), (2 <= 0) <=> 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 0 <=> 0, 2 <= (0 <=> 0), (2 <= 0) <=> 0 union select * from v1; + +create or replace view v1 as select 2 <= 0 >= 0, 2 <= (0 >= 0), (2 <= 0) >= 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 0 >= 0, 2 <= (0 >= 0), (2 <= 0) >= 0 union select * from v1; + +create or replace view v1 as select 2 <= 3 <= 3, 2 <= (3 <= 3), (2 <= 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 <= 3, 2 <= (3 <= 3), (2 <= 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 <= 3 < 3, 2 <= (3 < 3), (2 <= 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 < 3, 2 <= (3 < 3), (2 <= 3) < 3 union select * from v1; + +create or replace view v1 as select 2 <= 3 <> 3, 2 <= (3 <> 3), (2 <= 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 <> 3, 2 <= (3 <> 3), (2 <= 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 <= 3 > 0, 2 <= (3 > 0), (2 <= 3) > 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 > 0, 2 <= (3 > 0), (2 <= 3) > 0 union select * from v1; + +create or replace view v1 as select 2 <= 3 != 3, 2 <= (3 != 3), (2 <= 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 != 3, 2 <= (3 != 3), (2 <= 3) != 3 union select * from v1; + +create or replace view v1 as select 2 <= 0 LIKE 0, 2 <= (0 LIKE 0), (2 <= 0) LIKE 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 0 LIKE 0, 2 <= (0 LIKE 0), (2 <= 0) LIKE 0 union select * from v1; + +create or replace view v1 as select 2 <= 0 REGEXP 0, 2 <= (0 REGEXP 0), (2 <= 0) REGEXP 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 0 REGEXP 0, 2 <= (0 REGEXP 0), (2 <= 0) REGEXP 0 union select * from v1; + +create or replace view v1 as select 2 <= 3 | 3, 2 <= (3 | 3), (2 <= 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 | 3, 2 <= (3 | 3), (2 <= 3) | 3 union select * from v1; + +create or replace view v1 as select 2 <= 3 & 2, 2 <= (3 & 2), (2 <= 3) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 & 2, 2 <= (3 & 2), (2 <= 3) & 2 union select * from v1; + +create or replace view v1 as select 2 <= 3 << 3, 2 <= (3 << 3), (2 <= 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 << 3, 2 <= (3 << 3), (2 <= 3) << 3 union select * from v1; + +create or replace view v1 as select 0 <= 3 >> 1, 0 <= (3 >> 1), (0 <= 3) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 <= 3 >> 1, 0 <= (3 >> 1), (0 <= 3) >> 1 union select * from v1; + +create or replace view v1 as select 2 <= '2000-01-01' +INTERVAL 1 DAY, 2 <= ('2000-01-01' +INTERVAL 1 DAY), (2 <= '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= '2000-01-01' +INTERVAL 1 DAY, 2 <= ('2000-01-01' +INTERVAL 1 DAY), (2 <= '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 <= 3 + 3, 2 <= (3 + 3), (2 <= 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 + 3, 2 <= (3 + 3), (2 <= 3) + 3 union select * from v1; + +create or replace view v1 as select 2 <= 3 - 3, 2 <= (3 - 3), (2 <= 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 - 3, 2 <= (3 - 3), (2 <= 3) - 3 union select * from v1; + +create or replace view v1 as select 2 <= 3 * 3, 2 <= (3 * 3), (2 <= 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 * 3, 2 <= (3 * 3), (2 <= 3) * 3 union select * from v1; + +create or replace view v1 as select 2 <= 3 / 3, 2 <= (3 / 3), (2 <= 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 / 3, 2 <= (3 / 3), (2 <= 3) / 3 union select * from v1; + +create or replace view v1 as select 2 <= 9 DIV 3, 2 <= (9 DIV 3), (2 <= 9) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 9 DIV 3, 2 <= (9 DIV 3), (2 <= 9) DIV 3 union select * from v1; + +create or replace view v1 as select 2 <= 3 MOD 3, 2 <= (3 MOD 3), (2 <= 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 MOD 3, 2 <= (3 MOD 3), (2 <= 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 <= 3 % 3, 2 <= (3 % 3), (2 <= 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 % 3, 2 <= (3 % 3), (2 <= 3) % 3 union select * from v1; + +create or replace view v1 as select 2 <= 3 ^ 3, 2 <= (3 ^ 3), (2 <= 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 ^ 3, 2 <= (3 ^ 3), (2 <= 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 <= 3 BETWEEN 1 AND 3, 2 <= (3 BETWEEN 1 AND 3), (2 <= 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 BETWEEN 1 AND 3, 2 <= (3 BETWEEN 1 AND 3), (2 <= 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 < 1 IS FALSE, 2 < (1 IS FALSE), (2 < 1) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 1 IS FALSE, 2 < (1 IS FALSE), (2 < 1) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 < 3 COLLATE latin1_bin), charset(2 < (3 COLLATE latin1_bin)), charset((2 < 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 < 3 COLLATE latin1_bin), charset(2 < (3 COLLATE latin1_bin)), charset((2 < 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 < 3 IN (0,1), 2 < (3 IN (0,1)), (2 < 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 IN (0,1), 2 < (3 IN (0,1)), (2 < 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 < 3 OR 3, 2 < (3 OR 3), (2 < 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 OR 3, 2 < (3 OR 3), (2 < 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 < 3 || 3, 2 < (3 || 3), (2 < 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 || 3, 2 < (3 || 3), (2 < 3) || 3 union select * from v1; + +create or replace view v1 as select 2 < 3 XOR 0, 2 < (3 XOR 0), (2 < 3) XOR 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 XOR 0, 2 < (3 XOR 0), (2 < 3) XOR 0 union select * from v1; + +create or replace view v1 as select 2 < 3 AND 3, 2 < (3 AND 3), (2 < 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 AND 3, 2 < (3 AND 3), (2 < 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 < 3 && 3, 2 < (3 && 3), (2 < 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 && 3, 2 < (3 && 3), (2 < 3) && 3 union select * from v1; + +create or replace view v1 as select 2 < 3 = 1, 2 < (3 = 1), (2 < 3) = 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 = 1, 2 < (3 = 1), (2 < 3) = 1 union select * from v1; + +create or replace view v1 as select 2 < 3 <=> 1, 2 < (3 <=> 1), (2 < 3) <=> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 <=> 1, 2 < (3 <=> 1), (2 < 3) <=> 1 union select * from v1; + +create or replace view v1 as select 2 < 3 >= 1, 2 < (3 >= 1), (2 < 3) >= 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 >= 1, 2 < (3 >= 1), (2 < 3) >= 1 union select * from v1; + +create or replace view v1 as select 2 < 3 <= 3, 2 < (3 <= 3), (2 < 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 <= 3, 2 < (3 <= 3), (2 < 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 < 3 < 3, 2 < (3 < 3), (2 < 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 < 3, 2 < (3 < 3), (2 < 3) < 3 union select * from v1; + +create or replace view v1 as select 2 < 3 <> 3, 2 < (3 <> 3), (2 < 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 <> 3, 2 < (3 <> 3), (2 < 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 < 3 > 0, 2 < (3 > 0), (2 < 3) > 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 > 0, 2 < (3 > 0), (2 < 3) > 0 union select * from v1; + +create or replace view v1 as select 2 < 3 != 3, 2 < (3 != 3), (2 < 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 != 3, 2 < (3 != 3), (2 < 3) != 3 union select * from v1; + +create or replace view v1 as select 2 < 3 LIKE 1, 2 < (3 LIKE 1), (2 < 3) LIKE 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 LIKE 1, 2 < (3 LIKE 1), (2 < 3) LIKE 1 union select * from v1; + +create or replace view v1 as select 2 < 3 REGEXP 1, 2 < (3 REGEXP 1), (2 < 3) REGEXP 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 REGEXP 1, 2 < (3 REGEXP 1), (2 < 3) REGEXP 1 union select * from v1; + +create or replace view v1 as select 2 < 3 | 3, 2 < (3 | 3), (2 < 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 | 3, 2 < (3 | 3), (2 < 3) | 3 union select * from v1; + +create or replace view v1 as select 2 < 4 & 4, 2 < (4 & 4), (2 < 4) & 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 4 & 4, 2 < (4 & 4), (2 < 4) & 4 union select * from v1; + +create or replace view v1 as select 2 < 3 << 3, 2 < (3 << 3), (2 < 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 << 3, 2 < (3 << 3), (2 < 3) << 3 union select * from v1; + +create or replace view v1 as select 0 < 3 >> 1, 0 < (3 >> 1), (0 < 3) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 < 3 >> 1, 0 < (3 >> 1), (0 < 3) >> 1 union select * from v1; + +create or replace view v1 as select 2 < '2000-01-01' +INTERVAL 1 DAY, 2 < ('2000-01-01' +INTERVAL 1 DAY), (2 < '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < '2000-01-01' +INTERVAL 1 DAY, 2 < ('2000-01-01' +INTERVAL 1 DAY), (2 < '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 < 3 + 3, 2 < (3 + 3), (2 < 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 + 3, 2 < (3 + 3), (2 < 3) + 3 union select * from v1; + +create or replace view v1 as select 2 < 3 - 3, 2 < (3 - 3), (2 < 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 - 3, 2 < (3 - 3), (2 < 3) - 3 union select * from v1; + +create or replace view v1 as select 2 < 3 * 3, 2 < (3 * 3), (2 < 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 * 3, 2 < (3 * 3), (2 < 3) * 3 union select * from v1; + +create or replace view v1 as select 2 < 3 / 3, 2 < (3 / 3), (2 < 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 / 3, 2 < (3 / 3), (2 < 3) / 3 union select * from v1; + +create or replace view v1 as select 2 < 9 DIV 3, 2 < (9 DIV 3), (2 < 9) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 9 DIV 3, 2 < (9 DIV 3), (2 < 9) DIV 3 union select * from v1; + +create or replace view v1 as select 2 < 3 MOD 3, 2 < (3 MOD 3), (2 < 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 MOD 3, 2 < (3 MOD 3), (2 < 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 < 3 % 3, 2 < (3 % 3), (2 < 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 % 3, 2 < (3 % 3), (2 < 3) % 3 union select * from v1; + +create or replace view v1 as select 2 < 3 ^ 3, 2 < (3 ^ 3), (2 < 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 ^ 3, 2 < (3 ^ 3), (2 < 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 < 3 BETWEEN 1 AND 3, 2 < (3 BETWEEN 1 AND 3), (2 < 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 BETWEEN 1 AND 3, 2 < (3 BETWEEN 1 AND 3), (2 < 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 IS FALSE, 2 <> (3 IS FALSE), (2 <> 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 IS FALSE, 2 <> (3 IS FALSE), (2 <> 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 <> 3 COLLATE latin1_bin), charset(2 <> (3 COLLATE latin1_bin)), charset((2 <> 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 <> 3 COLLATE latin1_bin), charset(2 <> (3 COLLATE latin1_bin)), charset((2 <> 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 <> 3 IN (0,0), 2 <> (3 IN (0,0)), (2 <> 3) IN (0,0); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 IN (0,0), 2 <> (3 IN (0,0)), (2 <> 3) IN (0,0) union select * from v1; + +create or replace view v1 as select 1 <> 3 OR 3, 1 <> (3 OR 3), (1 <> 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 <> 3 OR 3, 1 <> (3 OR 3), (1 <> 3) OR 3 union select * from v1; + +create or replace view v1 as select 1 <> 3 || 3, 1 <> (3 || 3), (1 <> 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 <> 3 || 3, 1 <> (3 || 3), (1 <> 3) || 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 XOR 3, 2 <> (3 XOR 3), (2 <> 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 XOR 3, 2 <> (3 XOR 3), (2 <> 3) XOR 3 union select * from v1; + +create or replace view v1 as select 3 <> 3 AND 3, 3 <> (3 AND 3), (3 <> 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 <> 3 AND 3, 3 <> (3 AND 3), (3 <> 3) AND 3 union select * from v1; + +create or replace view v1 as select 3 <> 3 && 3, 3 <> (3 && 3), (3 <> 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 <> 3 && 3, 3 <> (3 && 3), (3 <> 3) && 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 = 3, 2 <> (3 = 3), (2 <> 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 = 3, 2 <> (3 = 3), (2 <> 3) = 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 <=> 3, 2 <> (3 <=> 3), (2 <> 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 <=> 3, 2 <> (3 <=> 3), (2 <> 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 >= 3, 2 <> (3 >= 3), (2 <> 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 >= 3, 2 <> (3 >= 3), (2 <> 3) >= 3 union select * from v1; + +create or replace view v1 as select 1 <> 3 <= 3, 1 <> (3 <= 3), (1 <> 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 <> 3 <= 3, 1 <> (3 <= 3), (1 <> 3) <= 3 union select * from v1; + +create or replace view v1 as select 0 <> 3 < 3, 0 <> (3 < 3), (0 <> 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 <> 3 < 3, 0 <> (3 < 3), (0 <> 3) < 3 union select * from v1; + +create or replace view v1 as select 0 <> 3 <> 3, 0 <> (3 <> 3), (0 <> 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 <> 3 <> 3, 0 <> (3 <> 3), (0 <> 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 > 3, 2 <> (3 > 3), (2 <> 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 > 3, 2 <> (3 > 3), (2 <> 3) > 3 union select * from v1; + +create or replace view v1 as select 0 <> 3 != 3, 0 <> (3 != 3), (0 <> 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 <> 3 != 3, 0 <> (3 != 3), (0 <> 3) != 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 LIKE 3, 2 <> (3 LIKE 3), (2 <> 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 LIKE 3, 2 <> (3 LIKE 3), (2 <> 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 REGEXP 3, 2 <> (3 REGEXP 3), (2 <> 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 REGEXP 3, 2 <> (3 REGEXP 3), (2 <> 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 | 3, 2 <> (3 | 3), (2 <> 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 | 3, 2 <> (3 | 3), (2 <> 3) | 3 union select * from v1; + +create or replace view v1 as select 2 <> 4 & 4, 2 <> (4 & 4), (2 <> 4) & 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 4 & 4, 2 <> (4 & 4), (2 <> 4) & 4 union select * from v1; + +create or replace view v1 as select 2 <> 3 << 3, 2 <> (3 << 3), (2 <> 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 << 3, 2 <> (3 << 3), (2 <> 3) << 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 >> 3, 2 <> (3 >> 3), (2 <> 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 >> 3, 2 <> (3 >> 3), (2 <> 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 <> '2000-01-01' +INTERVAL 1 DAY, 2 <> ('2000-01-01' +INTERVAL 1 DAY), (2 <> '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> '2000-01-01' +INTERVAL 1 DAY, 2 <> ('2000-01-01' +INTERVAL 1 DAY), (2 <> '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 <> 3 + 3, 2 <> (3 + 3), (2 <> 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 + 3, 2 <> (3 + 3), (2 <> 3) + 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 - 3, 2 <> (3 - 3), (2 <> 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 - 3, 2 <> (3 - 3), (2 <> 3) - 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 * 3, 2 <> (3 * 3), (2 <> 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 * 3, 2 <> (3 * 3), (2 <> 3) * 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 / 3, 2 <> (3 / 3), (2 <> 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 / 3, 2 <> (3 / 3), (2 <> 3) / 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 DIV 3, 2 <> (3 DIV 3), (2 <> 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 DIV 3, 2 <> (3 DIV 3), (2 <> 3) DIV 3 union select * from v1; + +create or replace view v1 as select 3 <> 3 MOD 3, 3 <> (3 MOD 3), (3 <> 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 <> 3 MOD 3, 3 <> (3 MOD 3), (3 <> 3) MOD 3 union select * from v1; + +create or replace view v1 as select 3 <> 3 % 3, 3 <> (3 % 3), (3 <> 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 <> 3 % 3, 3 <> (3 % 3), (3 <> 3) % 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 ^ 3, 2 <> (3 ^ 3), (2 <> 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 ^ 3, 2 <> (3 ^ 3), (2 <> 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 <> 3 BETWEEN 2 AND 3, 2 <> (3 BETWEEN 2 AND 3), (2 <> 3) BETWEEN 2 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 BETWEEN 2 AND 3, 2 <> (3 BETWEEN 2 AND 3), (2 <> 3) BETWEEN 2 AND 3 union select * from v1; + +create or replace view v1 as select 2 > 0 IS FALSE, 2 > (0 IS FALSE), (2 > 0) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 0 IS FALSE, 2 > (0 IS FALSE), (2 > 0) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 > 3 COLLATE latin1_bin), charset(2 > (3 COLLATE latin1_bin)), charset((2 > 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 > 3 COLLATE latin1_bin), charset(2 > (3 COLLATE latin1_bin)), charset((2 > 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 > 3 IN (1,1), 2 > (3 IN (1,1)), (2 > 3) IN (1,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 IN (1,1), 2 > (3 IN (1,1)), (2 > 3) IN (1,1) union select * from v1; + +create or replace view v1 as select 0 > 3 OR 3, 0 > (3 OR 3), (0 > 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 > 3 OR 3, 0 > (3 OR 3), (0 > 3) OR 3 union select * from v1; + +create or replace view v1 as select 0 > 3 || 3, 0 > (3 || 3), (0 > 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 > 3 || 3, 0 > (3 || 3), (0 > 3) || 3 union select * from v1; + +create or replace view v1 as select 4 > 3 XOR 3, 4 > (3 XOR 3), (4 > 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 4 > 3 XOR 3, 4 > (3 XOR 3), (4 > 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 > 3 AND 3, 2 > (3 AND 3), (2 > 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 AND 3, 2 > (3 AND 3), (2 > 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 > 3 && 3, 2 > (3 && 3), (2 > 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 && 3, 2 > (3 && 3), (2 > 3) && 3 union select * from v1; + +create or replace view v1 as select 2 > 3 = 3, 2 > (3 = 3), (2 > 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 = 3, 2 > (3 = 3), (2 > 3) = 3 union select * from v1; + +create or replace view v1 as select 2 > 3 <=> 3, 2 > (3 <=> 3), (2 > 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 <=> 3, 2 > (3 <=> 3), (2 > 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 > 3 >= 3, 2 > (3 >= 3), (2 > 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 >= 3, 2 > (3 >= 3), (2 > 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 > 0 <= 0, 2 > (0 <= 0), (2 > 0) <= 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 0 <= 0, 2 > (0 <= 0), (2 > 0) <= 0 union select * from v1; + +create or replace view v1 as select 2 > 0 < 0, 2 > (0 < 0), (2 > 0) < 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 0 < 0, 2 > (0 < 0), (2 > 0) < 0 union select * from v1; + +create or replace view v1 as select 2 > 1 <> 1, 2 > (1 <> 1), (2 > 1) <> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 1 <> 1, 2 > (1 <> 1), (2 > 1) <> 1 union select * from v1; + +create or replace view v1 as select 2 > 3 > 3, 2 > (3 > 3), (2 > 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 > 3, 2 > (3 > 3), (2 > 3) > 3 union select * from v1; + +create or replace view v1 as select 2 > 1 != 1, 2 > (1 != 1), (2 > 1) != 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 1 != 1, 2 > (1 != 1), (2 > 1) != 1 union select * from v1; + +create or replace view v1 as select 2 > 3 LIKE 3, 2 > (3 LIKE 3), (2 > 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 LIKE 3, 2 > (3 LIKE 3), (2 > 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 > 3 REGEXP 3, 2 > (3 REGEXP 3), (2 > 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 REGEXP 3, 2 > (3 REGEXP 3), (2 > 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 > 3 | 3, 2 > (3 | 3), (2 > 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 | 3, 2 > (3 | 3), (2 > 3) | 3 union select * from v1; + +create or replace view v1 as select 4 > 2 & 2, 4 > (2 & 2), (4 > 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 4 > 2 & 2, 4 > (2 & 2), (4 > 2) & 2 union select * from v1; + +create or replace view v1 as select 4 > 3 << 3, 4 > (3 << 3), (4 > 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 4 > 3 << 3, 4 > (3 << 3), (4 > 3) << 3 union select * from v1; + +create or replace view v1 as select 2 > 3 >> 3, 2 > (3 >> 3), (2 > 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 >> 3, 2 > (3 >> 3), (2 > 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 > '2000-01-01' +INTERVAL 1 DAY, 2 > ('2000-01-01' +INTERVAL 1 DAY), (2 > '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > '2000-01-01' +INTERVAL 1 DAY, 2 > ('2000-01-01' +INTERVAL 1 DAY), (2 > '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 > 3 + 3, 2 > (3 + 3), (2 > 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 + 3, 2 > (3 + 3), (2 > 3) + 3 union select * from v1; + +create or replace view v1 as select 2 > 3 - 3, 2 > (3 - 3), (2 > 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 - 3, 2 > (3 - 3), (2 > 3) - 3 union select * from v1; + +create or replace view v1 as select 4 > 3 * 3, 4 > (3 * 3), (4 > 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 4 > 3 * 3, 4 > (3 * 3), (4 > 3) * 3 union select * from v1; + +create or replace view v1 as select 2 > 3 / 3, 2 > (3 / 3), (2 > 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 / 3, 2 > (3 / 3), (2 > 3) / 3 union select * from v1; + +create or replace view v1 as select 2 > 3 DIV 3, 2 > (3 DIV 3), (2 > 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 DIV 3, 2 > (3 DIV 3), (2 > 3) DIV 3 union select * from v1; + +create or replace view v1 as select 2 > 3 MOD 3, 2 > (3 MOD 3), (2 > 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 MOD 3, 2 > (3 MOD 3), (2 > 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 > 3 % 3, 2 > (3 % 3), (2 > 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 % 3, 2 > (3 % 3), (2 > 3) % 3 union select * from v1; + +create or replace view v1 as select 2 > 3 ^ 3, 2 > (3 ^ 3), (2 > 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 ^ 3, 2 > (3 ^ 3), (2 > 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 > 3 BETWEEN 1 AND 3, 2 > (3 BETWEEN 1 AND 3), (2 > 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 BETWEEN 1 AND 3, 2 > (3 BETWEEN 1 AND 3), (2 > 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 != 3 IS FALSE, 2 != (3 IS FALSE), (2 != 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 IS FALSE, 2 != (3 IS FALSE), (2 != 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 != 3 COLLATE latin1_bin), charset(2 != (3 COLLATE latin1_bin)), charset((2 != 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 != 3 COLLATE latin1_bin), charset(2 != (3 COLLATE latin1_bin)), charset((2 != 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 != 3 IN (0,0), 2 != (3 IN (0,0)), (2 != 3) IN (0,0); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 IN (0,0), 2 != (3 IN (0,0)), (2 != 3) IN (0,0) union select * from v1; + +create or replace view v1 as select 1 != 3 OR 3, 1 != (3 OR 3), (1 != 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 != 3 OR 3, 1 != (3 OR 3), (1 != 3) OR 3 union select * from v1; + +create or replace view v1 as select 1 != 3 || 3, 1 != (3 || 3), (1 != 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 != 3 || 3, 1 != (3 || 3), (1 != 3) || 3 union select * from v1; + +create or replace view v1 as select 2 != 3 XOR 3, 2 != (3 XOR 3), (2 != 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 XOR 3, 2 != (3 XOR 3), (2 != 3) XOR 3 union select * from v1; + +create or replace view v1 as select 3 != 3 AND 3, 3 != (3 AND 3), (3 != 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 != 3 AND 3, 3 != (3 AND 3), (3 != 3) AND 3 union select * from v1; + +create or replace view v1 as select 3 != 3 && 3, 3 != (3 && 3), (3 != 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 != 3 && 3, 3 != (3 && 3), (3 != 3) && 3 union select * from v1; + +create or replace view v1 as select 2 != 3 = 3, 2 != (3 = 3), (2 != 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 = 3, 2 != (3 = 3), (2 != 3) = 3 union select * from v1; + +create or replace view v1 as select 2 != 3 <=> 3, 2 != (3 <=> 3), (2 != 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 <=> 3, 2 != (3 <=> 3), (2 != 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 != 3 >= 3, 2 != (3 >= 3), (2 != 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 >= 3, 2 != (3 >= 3), (2 != 3) >= 3 union select * from v1; + +create or replace view v1 as select 1 != 3 <= 3, 1 != (3 <= 3), (1 != 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 != 3 <= 3, 1 != (3 <= 3), (1 != 3) <= 3 union select * from v1; + +create or replace view v1 as select 0 != 3 < 3, 0 != (3 < 3), (0 != 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 != 3 < 3, 0 != (3 < 3), (0 != 3) < 3 union select * from v1; + +create or replace view v1 as select 0 != 3 <> 3, 0 != (3 <> 3), (0 != 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 != 3 <> 3, 0 != (3 <> 3), (0 != 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 != 3 > 3, 2 != (3 > 3), (2 != 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 > 3, 2 != (3 > 3), (2 != 3) > 3 union select * from v1; + +create or replace view v1 as select 0 != 3 != 3, 0 != (3 != 3), (0 != 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 != 3 != 3, 0 != (3 != 3), (0 != 3) != 3 union select * from v1; + +create or replace view v1 as select 2 != 3 LIKE 3, 2 != (3 LIKE 3), (2 != 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 LIKE 3, 2 != (3 LIKE 3), (2 != 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 != 3 REGEXP 3, 2 != (3 REGEXP 3), (2 != 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 REGEXP 3, 2 != (3 REGEXP 3), (2 != 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 != 3 | 3, 2 != (3 | 3), (2 != 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 | 3, 2 != (3 | 3), (2 != 3) | 3 union select * from v1; + +create or replace view v1 as select 2 != 4 & 4, 2 != (4 & 4), (2 != 4) & 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 4 & 4, 2 != (4 & 4), (2 != 4) & 4 union select * from v1; + +create or replace view v1 as select 2 != 3 << 3, 2 != (3 << 3), (2 != 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 << 3, 2 != (3 << 3), (2 != 3) << 3 union select * from v1; + +create or replace view v1 as select 2 != 3 >> 3, 2 != (3 >> 3), (2 != 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 >> 3, 2 != (3 >> 3), (2 != 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 != '2000-01-01' +INTERVAL 1 DAY, 2 != ('2000-01-01' +INTERVAL 1 DAY), (2 != '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != '2000-01-01' +INTERVAL 1 DAY, 2 != ('2000-01-01' +INTERVAL 1 DAY), (2 != '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 != 3 + 3, 2 != (3 + 3), (2 != 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 + 3, 2 != (3 + 3), (2 != 3) + 3 union select * from v1; + +create or replace view v1 as select 2 != 3 - 3, 2 != (3 - 3), (2 != 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 - 3, 2 != (3 - 3), (2 != 3) - 3 union select * from v1; + +create or replace view v1 as select 2 != 3 * 3, 2 != (3 * 3), (2 != 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 * 3, 2 != (3 * 3), (2 != 3) * 3 union select * from v1; + +create or replace view v1 as select 2 != 3 / 3, 2 != (3 / 3), (2 != 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 / 3, 2 != (3 / 3), (2 != 3) / 3 union select * from v1; + +create or replace view v1 as select 2 != 3 DIV 3, 2 != (3 DIV 3), (2 != 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 DIV 3, 2 != (3 DIV 3), (2 != 3) DIV 3 union select * from v1; + +create or replace view v1 as select 3 != 3 MOD 3, 3 != (3 MOD 3), (3 != 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 != 3 MOD 3, 3 != (3 MOD 3), (3 != 3) MOD 3 union select * from v1; + +create or replace view v1 as select 3 != 3 % 3, 3 != (3 % 3), (3 != 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 != 3 % 3, 3 != (3 % 3), (3 != 3) % 3 union select * from v1; + +create or replace view v1 as select 2 != 3 ^ 3, 2 != (3 ^ 3), (2 != 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 ^ 3, 2 != (3 ^ 3), (2 != 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 != 3 BETWEEN 2 AND 3, 2 != (3 BETWEEN 2 AND 3), (2 != 3) BETWEEN 2 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 BETWEEN 2 AND 3, 2 != (3 BETWEEN 2 AND 3), (2 != 3) BETWEEN 2 AND 3 union select * from v1; + +create or replace view v1 as select 2 LIKE 3 IS FALSE, 2 LIKE (3 IS FALSE), (2 LIKE 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 3 IS FALSE, 2 LIKE (3 IS FALSE), (2 LIKE 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 LIKE 3 COLLATE latin1_bin), charset(2 LIKE (3 COLLATE latin1_bin)), charset((2 LIKE 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 LIKE 3 COLLATE latin1_bin), charset(2 LIKE (3 COLLATE latin1_bin)), charset((2 LIKE 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 LIKE 3 IN (0,1), 2 LIKE (3 IN (0,1)), (2 LIKE 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 3 IN (0,1), 2 LIKE (3 IN (0,1)), (2 LIKE 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 LIKE 3 OR 3, 2 LIKE (3 OR 3), (2 LIKE 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 3 OR 3, 2 LIKE (3 OR 3), (2 LIKE 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 LIKE 3 || 3, 2 LIKE (3 || 3), (2 LIKE 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 3 || 3, 2 LIKE (3 || 3), (2 LIKE 3) || 3 union select * from v1; + +create or replace view v1 as select 2 LIKE 3 XOR 3, 2 LIKE (3 XOR 3), (2 LIKE 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 3 XOR 3, 2 LIKE (3 XOR 3), (2 LIKE 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 AND 2, 2 LIKE (2 AND 2), (2 LIKE 2) AND 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 AND 2, 2 LIKE (2 AND 2), (2 LIKE 2) AND 2 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 && 2, 2 LIKE (2 && 2), (2 LIKE 2) && 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 && 2, 2 LIKE (2 && 2), (2 LIKE 2) && 2 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 = 1, 2 LIKE (2 = 1), (2 LIKE 2) = 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 = 1, 2 LIKE (2 = 1), (2 LIKE 2) = 1 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 <=> 1, 2 LIKE (2 <=> 1), (2 LIKE 2) <=> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 <=> 1, 2 LIKE (2 <=> 1), (2 LIKE 2) <=> 1 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 >= 1, 2 LIKE (2 >= 1), (2 LIKE 2) >= 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 >= 1, 2 LIKE (2 >= 1), (2 LIKE 2) >= 1 union select * from v1; + +create or replace view v1 as select 2 LIKE 3 <= 3, 2 LIKE (3 <= 3), (2 LIKE 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 3 <= 3, 2 LIKE (3 <= 3), (2 LIKE 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 LIKE 3 < 3, 2 LIKE (3 < 3), (2 LIKE 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 3 < 3, 2 LIKE (3 < 3), (2 LIKE 3) < 3 union select * from v1; + +create or replace view v1 as select 2 LIKE 3 <> 3, 2 LIKE (3 <> 3), (2 LIKE 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 3 <> 3, 2 LIKE (3 <> 3), (2 LIKE 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 > 0, 2 LIKE (2 > 0), (2 LIKE 2) > 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 > 0, 2 LIKE (2 > 0), (2 LIKE 2) > 0 union select * from v1; + +create or replace view v1 as select 2 LIKE 3 != 3, 2 LIKE (3 != 3), (2 LIKE 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 3 != 3, 2 LIKE (3 != 3), (2 LIKE 3) != 3 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 LIKE 1, 2 LIKE (2 LIKE 1), (2 LIKE 2) LIKE 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 LIKE 1, 2 LIKE (2 LIKE 1), (2 LIKE 2) LIKE 1 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 REGEXP 1, 2 LIKE (2 REGEXP 1), (2 LIKE 2) REGEXP 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 REGEXP 1, 2 LIKE (2 REGEXP 1), (2 LIKE 2) REGEXP 1 union select * from v1; + +create or replace view v1 as select 2 LIKE 3 | 3, 2 LIKE (3 | 3), (2 LIKE 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 3 | 3, 2 LIKE (3 | 3), (2 LIKE 3) | 3 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 & 2, 2 LIKE (2 & 2), (2 LIKE 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 & 2, 2 LIKE (2 & 2), (2 LIKE 2) & 2 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 << 2, 2 LIKE (2 << 2), (2 LIKE 2) << 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 << 2, 2 LIKE (2 << 2), (2 LIKE 2) << 2 union select * from v1; + +create or replace view v1 as select 2 LIKE 4 >> 1, 2 LIKE (4 >> 1), (2 LIKE 4) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 4 >> 1, 2 LIKE (4 >> 1), (2 LIKE 4) >> 1 union select * from v1; + +create or replace view v1 as select 2 LIKE '2000-01-01' +INTERVAL 1 DAY, 2 LIKE ('2000-01-01' +INTERVAL 1 DAY), (2 LIKE '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE '2000-01-01' +INTERVAL 1 DAY, 2 LIKE ('2000-01-01' +INTERVAL 1 DAY), (2 LIKE '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 LIKE 3 + 3, 2 LIKE (3 + 3), (2 LIKE 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 3 + 3, 2 LIKE (3 + 3), (2 LIKE 3) + 3 union select * from v1; + +create or replace view v1 as select 2 LIKE 3 - 3, 2 LIKE (3 - 3), (2 LIKE 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 3 - 3, 2 LIKE (3 - 3), (2 LIKE 3) - 3 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 * 2, 2 LIKE (2 * 2), (2 LIKE 2) * 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 * 2, 2 LIKE (2 * 2), (2 LIKE 2) * 2 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 / 2, 2 LIKE (2 / 2), (2 LIKE 2) / 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 / 2, 2 LIKE (2 / 2), (2 LIKE 2) / 2 union select * from v1; + +create or replace view v1 as select 2 LIKE 4 DIV 2, 2 LIKE (4 DIV 2), (2 LIKE 4) DIV 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 4 DIV 2, 2 LIKE (4 DIV 2), (2 LIKE 4) DIV 2 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 MOD 2, 2 LIKE (2 MOD 2), (2 LIKE 2) MOD 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 MOD 2, 2 LIKE (2 MOD 2), (2 LIKE 2) MOD 2 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 % 2, 2 LIKE (2 % 2), (2 LIKE 2) % 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 % 2, 2 LIKE (2 % 2), (2 LIKE 2) % 2 union select * from v1; + +create or replace view v1 as select 2 LIKE 3 ^ 3, 2 LIKE (3 ^ 3), (2 LIKE 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 3 ^ 3, 2 LIKE (3 ^ 3), (2 LIKE 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 BETWEEN 1 AND 3, 2 LIKE (2 BETWEEN 1 AND 3), (2 LIKE 2) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 BETWEEN 1 AND 3, 2 LIKE (2 BETWEEN 1 AND 3), (2 LIKE 2) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 REGEXP 3 IS FALSE, 2 REGEXP (3 IS FALSE), (2 REGEXP 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 3 IS FALSE, 2 REGEXP (3 IS FALSE), (2 REGEXP 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 REGEXP 3 COLLATE latin1_bin), charset(2 REGEXP (3 COLLATE latin1_bin)), charset((2 REGEXP 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 REGEXP 3 COLLATE latin1_bin), charset(2 REGEXP (3 COLLATE latin1_bin)), charset((2 REGEXP 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 REGEXP 3 IN (0,1), 2 REGEXP (3 IN (0,1)), (2 REGEXP 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 3 IN (0,1), 2 REGEXP (3 IN (0,1)), (2 REGEXP 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 REGEXP 3 OR 3, 2 REGEXP (3 OR 3), (2 REGEXP 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 3 OR 3, 2 REGEXP (3 OR 3), (2 REGEXP 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 REGEXP 3 || 3, 2 REGEXP (3 || 3), (2 REGEXP 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 3 || 3, 2 REGEXP (3 || 3), (2 REGEXP 3) || 3 union select * from v1; + +create or replace view v1 as select 2 REGEXP 3 XOR 3, 2 REGEXP (3 XOR 3), (2 REGEXP 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 3 XOR 3, 2 REGEXP (3 XOR 3), (2 REGEXP 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 REGEXP 2 AND 2, 2 REGEXP (2 AND 2), (2 REGEXP 2) AND 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 2 AND 2, 2 REGEXP (2 AND 2), (2 REGEXP 2) AND 2 union select * from v1; + +create or replace view v1 as select 2 REGEXP 2 && 2, 2 REGEXP (2 && 2), (2 REGEXP 2) && 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 2 && 2, 2 REGEXP (2 && 2), (2 REGEXP 2) && 2 union select * from v1; + +create or replace view v1 as select 2 REGEXP 2 = 1, 2 REGEXP (2 = 1), (2 REGEXP 2) = 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 2 = 1, 2 REGEXP (2 = 1), (2 REGEXP 2) = 1 union select * from v1; + +create or replace view v1 as select 2 REGEXP 2 <=> 1, 2 REGEXP (2 <=> 1), (2 REGEXP 2) <=> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 2 <=> 1, 2 REGEXP (2 <=> 1), (2 REGEXP 2) <=> 1 union select * from v1; + +create or replace view v1 as select 2 REGEXP 2 >= 1, 2 REGEXP (2 >= 1), (2 REGEXP 2) >= 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 2 >= 1, 2 REGEXP (2 >= 1), (2 REGEXP 2) >= 1 union select * from v1; + +create or replace view v1 as select 2 REGEXP 3 <= 3, 2 REGEXP (3 <= 3), (2 REGEXP 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 3 <= 3, 2 REGEXP (3 <= 3), (2 REGEXP 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 REGEXP 3 < 3, 2 REGEXP (3 < 3), (2 REGEXP 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 3 < 3, 2 REGEXP (3 < 3), (2 REGEXP 3) < 3 union select * from v1; + +create or replace view v1 as select 2 REGEXP 3 <> 3, 2 REGEXP (3 <> 3), (2 REGEXP 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 3 <> 3, 2 REGEXP (3 <> 3), (2 REGEXP 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 REGEXP 2 > 0, 2 REGEXP (2 > 0), (2 REGEXP 2) > 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 2 > 0, 2 REGEXP (2 > 0), (2 REGEXP 2) > 0 union select * from v1; + +create or replace view v1 as select 2 REGEXP 3 != 3, 2 REGEXP (3 != 3), (2 REGEXP 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 3 != 3, 2 REGEXP (3 != 3), (2 REGEXP 3) != 3 union select * from v1; + +create or replace view v1 as select 1 REGEXP 3 LIKE 3, 1 REGEXP (3 LIKE 3), (1 REGEXP 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 REGEXP 3 LIKE 3, 1 REGEXP (3 LIKE 3), (1 REGEXP 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 1 REGEXP 3 REGEXP 3, 1 REGEXP (3 REGEXP 3), (1 REGEXP 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 REGEXP 3 REGEXP 3, 1 REGEXP (3 REGEXP 3), (1 REGEXP 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 REGEXP 3 | 3, 2 REGEXP (3 | 3), (2 REGEXP 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 3 | 3, 2 REGEXP (3 | 3), (2 REGEXP 3) | 3 union select * from v1; + +create or replace view v1 as select 2 REGEXP 2 & 2, 2 REGEXP (2 & 2), (2 REGEXP 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 2 & 2, 2 REGEXP (2 & 2), (2 REGEXP 2) & 2 union select * from v1; + +create or replace view v1 as select 2 REGEXP 2 << 2, 2 REGEXP (2 << 2), (2 REGEXP 2) << 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 2 << 2, 2 REGEXP (2 << 2), (2 REGEXP 2) << 2 union select * from v1; + +create or replace view v1 as select 2 REGEXP 4 >> 1, 2 REGEXP (4 >> 1), (2 REGEXP 4) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 4 >> 1, 2 REGEXP (4 >> 1), (2 REGEXP 4) >> 1 union select * from v1; + +create or replace view v1 as select 2 REGEXP '2000-01-01' +INTERVAL 1 DAY, 2 REGEXP ('2000-01-01' +INTERVAL 1 DAY), (2 REGEXP '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP '2000-01-01' +INTERVAL 1 DAY, 2 REGEXP ('2000-01-01' +INTERVAL 1 DAY), (2 REGEXP '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 REGEXP 3 + 3, 2 REGEXP (3 + 3), (2 REGEXP 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 3 + 3, 2 REGEXP (3 + 3), (2 REGEXP 3) + 3 union select * from v1; + +create or replace view v1 as select 2 REGEXP 3 - 3, 2 REGEXP (3 - 3), (2 REGEXP 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 3 - 3, 2 REGEXP (3 - 3), (2 REGEXP 3) - 3 union select * from v1; + +create or replace view v1 as select 2 REGEXP 2 * 2, 2 REGEXP (2 * 2), (2 REGEXP 2) * 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 2 * 2, 2 REGEXP (2 * 2), (2 REGEXP 2) * 2 union select * from v1; + +create or replace view v1 as select 2 REGEXP 2 / 2, 2 REGEXP (2 / 2), (2 REGEXP 2) / 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 2 / 2, 2 REGEXP (2 / 2), (2 REGEXP 2) / 2 union select * from v1; + +create or replace view v1 as select 2 REGEXP 4 DIV 2, 2 REGEXP (4 DIV 2), (2 REGEXP 4) DIV 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 4 DIV 2, 2 REGEXP (4 DIV 2), (2 REGEXP 4) DIV 2 union select * from v1; + +create or replace view v1 as select 2 REGEXP 2 MOD 2, 2 REGEXP (2 MOD 2), (2 REGEXP 2) MOD 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 2 MOD 2, 2 REGEXP (2 MOD 2), (2 REGEXP 2) MOD 2 union select * from v1; + +create or replace view v1 as select 2 REGEXP 2 % 2, 2 REGEXP (2 % 2), (2 REGEXP 2) % 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 2 % 2, 2 REGEXP (2 % 2), (2 REGEXP 2) % 2 union select * from v1; + +create or replace view v1 as select 2 REGEXP 3 ^ 3, 2 REGEXP (3 ^ 3), (2 REGEXP 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 3 ^ 3, 2 REGEXP (3 ^ 3), (2 REGEXP 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 REGEXP 2 BETWEEN 1 AND 3, 2 REGEXP (2 BETWEEN 1 AND 3), (2 REGEXP 2) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 2 BETWEEN 1 AND 3, 2 REGEXP (2 BETWEEN 1 AND 3), (2 REGEXP 2) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 | 3 IS FALSE, 2 | (3 IS FALSE), (2 | 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 IS FALSE, 2 | (3 IS FALSE), (2 | 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 | 3 COLLATE latin1_bin), charset(2 | (3 COLLATE latin1_bin)), charset((2 | 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 | 3 COLLATE latin1_bin), charset(2 | (3 COLLATE latin1_bin)), charset((2 | 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 | 3 IN (0,1), 2 | (3 IN (0,1)), (2 | 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 IN (0,1), 2 | (3 IN (0,1)), (2 | 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 | 3 OR 3, 2 | (3 OR 3), (2 | 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 OR 3, 2 | (3 OR 3), (2 | 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 | 3 || 3, 2 | (3 || 3), (2 | 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 || 3, 2 | (3 || 3), (2 | 3) || 3 union select * from v1; + +create or replace view v1 as select 2 | 3 XOR 3, 2 | (3 XOR 3), (2 | 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 XOR 3, 2 | (3 XOR 3), (2 | 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 | 3 AND 3, 2 | (3 AND 3), (2 | 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 AND 3, 2 | (3 AND 3), (2 | 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 | 3 && 3, 2 | (3 && 3), (2 | 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 && 3, 2 | (3 && 3), (2 | 3) && 3 union select * from v1; + +create or replace view v1 as select 2 | 3 = 3, 2 | (3 = 3), (2 | 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 = 3, 2 | (3 = 3), (2 | 3) = 3 union select * from v1; + +create or replace view v1 as select 2 | 3 <=> 3, 2 | (3 <=> 3), (2 | 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 <=> 3, 2 | (3 <=> 3), (2 | 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 | 3 >= 3, 2 | (3 >= 3), (2 | 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 >= 3, 2 | (3 >= 3), (2 | 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 | 3 <= 3, 2 | (3 <= 3), (2 | 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 <= 3, 2 | (3 <= 3), (2 | 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 | 3 < 3, 2 | (3 < 3), (2 | 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 < 3, 2 | (3 < 3), (2 | 3) < 3 union select * from v1; + +create or replace view v1 as select 2 | 3 <> 3, 2 | (3 <> 3), (2 | 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 <> 3, 2 | (3 <> 3), (2 | 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 | 3 > 3, 2 | (3 > 3), (2 | 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 > 3, 2 | (3 > 3), (2 | 3) > 3 union select * from v1; + +create or replace view v1 as select 2 | 3 != 3, 2 | (3 != 3), (2 | 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 != 3, 2 | (3 != 3), (2 | 3) != 3 union select * from v1; + +create or replace view v1 as select 2 | 3 LIKE 3, 2 | (3 LIKE 3), (2 | 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 LIKE 3, 2 | (3 LIKE 3), (2 | 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 | 3 REGEXP 3, 2 | (3 REGEXP 3), (2 | 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 REGEXP 3, 2 | (3 REGEXP 3), (2 | 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 | 0 & 0, 2 | (0 & 0), (2 | 0) & 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 0 & 0, 2 | (0 & 0), (2 | 0) & 0 union select * from v1; + +create or replace view v1 as select 2 | 3 << 3, 2 | (3 << 3), (2 | 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 << 3, 2 | (3 << 3), (2 | 3) << 3 union select * from v1; + +create or replace view v1 as select 2 | 3 >> 3, 2 | (3 >> 3), (2 | 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 >> 3, 2 | (3 >> 3), (2 | 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 | '2000-01-01' +INTERVAL 1 DAY, 2 | ('2000-01-01' +INTERVAL 1 DAY), (2 | '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | '2000-01-01' +INTERVAL 1 DAY, 2 | ('2000-01-01' +INTERVAL 1 DAY), (2 | '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 | 1 + 1, 2 | (1 + 1), (2 | 1) + 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 1 + 1, 2 | (1 + 1), (2 | 1) + 1 union select * from v1; + +create or replace view v1 as select 2 | 3 - 3, 2 | (3 - 3), (2 | 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 - 3, 2 | (3 - 3), (2 | 3) - 3 union select * from v1; + +create or replace view v1 as select 2 | 3 * 3, 2 | (3 * 3), (2 | 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 * 3, 2 | (3 * 3), (2 | 3) * 3 union select * from v1; + +create or replace view v1 as select 2 | 3 / 3, 2 | (3 / 3), (2 | 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 / 3, 2 | (3 / 3), (2 | 3) / 3 union select * from v1; + +create or replace view v1 as select 2 | 3 DIV 3, 2 | (3 DIV 3), (2 | 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 DIV 3, 2 | (3 DIV 3), (2 | 3) DIV 3 union select * from v1; + +create or replace view v1 as select 2 | 3 MOD 3, 2 | (3 MOD 3), (2 | 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 MOD 3, 2 | (3 MOD 3), (2 | 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 | 3 % 3, 2 | (3 % 3), (2 | 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 % 3, 2 | (3 % 3), (2 | 3) % 3 union select * from v1; + +create or replace view v1 as select 2 | 3 ^ 3, 2 | (3 ^ 3), (2 | 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 ^ 3, 2 | (3 ^ 3), (2 | 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 | 3 BETWEEN 1 AND 3, 2 | (3 BETWEEN 1 AND 3), (2 | 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 BETWEEN 1 AND 3, 2 | (3 BETWEEN 1 AND 3), (2 | 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 & 1 IS FALSE, 2 & (1 IS FALSE), (2 & 1) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 1 IS FALSE, 2 & (1 IS FALSE), (2 & 1) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 & 3 COLLATE latin1_bin), charset(2 & (3 COLLATE latin1_bin)), charset((2 & 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 & 3 COLLATE latin1_bin), charset(2 & (3 COLLATE latin1_bin)), charset((2 & 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 & 4 IN (0,1), 2 & (4 IN (0,1)), (2 & 4) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 4 IN (0,1), 2 & (4 IN (0,1)), (2 & 4) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 & 3 OR 3, 2 & (3 OR 3), (2 & 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 OR 3, 2 & (3 OR 3), (2 & 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 & 3 || 3, 2 & (3 || 3), (2 & 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 || 3, 2 & (3 || 3), (2 & 3) || 3 union select * from v1; + +create or replace view v1 as select 2 & 1 XOR 1, 2 & (1 XOR 1), (2 & 1) XOR 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 1 XOR 1, 2 & (1 XOR 1), (2 & 1) XOR 1 union select * from v1; + +create or replace view v1 as select 2 & 3 AND 3, 2 & (3 AND 3), (2 & 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 AND 3, 2 & (3 AND 3), (2 & 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 & 3 && 3, 2 & (3 && 3), (2 & 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 && 3, 2 & (3 && 3), (2 & 3) && 3 union select * from v1; + +create or replace view v1 as select 2 & 3 = 2, 2 & (3 = 2), (2 & 3) = 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 = 2, 2 & (3 = 2), (2 & 3) = 2 union select * from v1; + +create or replace view v1 as select 2 & 3 <=> 2, 2 & (3 <=> 2), (2 & 3) <=> 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 <=> 2, 2 & (3 <=> 2), (2 & 3) <=> 2 union select * from v1; + +create or replace view v1 as select 2 & 3 >= 2, 2 & (3 >= 2), (2 & 3) >= 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 >= 2, 2 & (3 >= 2), (2 & 3) >= 2 union select * from v1; + +create or replace view v1 as select 2 & 3 <= 3, 2 & (3 <= 3), (2 & 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 <= 3, 2 & (3 <= 3), (2 & 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 & 3 < 3, 2 & (3 < 3), (2 & 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 < 3, 2 & (3 < 3), (2 & 3) < 3 union select * from v1; + +create or replace view v1 as select 2 & 3 <> 3, 2 & (3 <> 3), (2 & 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 <> 3, 2 & (3 <> 3), (2 & 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 & 3 > 1, 2 & (3 > 1), (2 & 3) > 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 > 1, 2 & (3 > 1), (2 & 3) > 1 union select * from v1; + +create or replace view v1 as select 2 & 3 != 3, 2 & (3 != 3), (2 & 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 != 3, 2 & (3 != 3), (2 & 3) != 3 union select * from v1; + +create or replace view v1 as select 2 & 3 LIKE 2, 2 & (3 LIKE 2), (2 & 3) LIKE 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 LIKE 2, 2 & (3 LIKE 2), (2 & 3) LIKE 2 union select * from v1; + +create or replace view v1 as select 2 & 3 REGEXP 2, 2 & (3 REGEXP 2), (2 & 3) REGEXP 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 REGEXP 2, 2 & (3 REGEXP 2), (2 & 3) REGEXP 2 union select * from v1; + +create or replace view v1 as select 2 & 3 | 3, 2 & (3 | 3), (2 & 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 | 3, 2 & (3 | 3), (2 & 3) | 3 union select * from v1; + +create or replace view v1 as select 2 & 3 << 3, 2 & (3 << 3), (2 & 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 << 3, 2 & (3 << 3), (2 & 3) << 3 union select * from v1; + +create or replace view v1 as select 2 & 3 >> 1, 2 & (3 >> 1), (2 & 3) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 >> 1, 2 & (3 >> 1), (2 & 3) >> 1 union select * from v1; + +create or replace view v1 as select 2 & '2000-01-01' +INTERVAL 1 DAY, 2 & ('2000-01-01' +INTERVAL 1 DAY), (2 & '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & '2000-01-01' +INTERVAL 1 DAY, 2 & ('2000-01-01' +INTERVAL 1 DAY), (2 & '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 & 3 + 3, 2 & (3 + 3), (2 & 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 + 3, 2 & (3 + 3), (2 & 3) + 3 union select * from v1; + +create or replace view v1 as select 6 & 4 - 3, 6 & (4 - 3), (6 & 4) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 6 & 4 - 3, 6 & (4 - 3), (6 & 4) - 3 union select * from v1; + +create or replace view v1 as select 2 & 3 * 3, 2 & (3 * 3), (2 & 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 * 3, 2 & (3 * 3), (2 & 3) * 3 union select * from v1; + +create or replace view v1 as select 2 & 3 / 3, 2 & (3 / 3), (2 & 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 / 3, 2 & (3 / 3), (2 & 3) / 3 union select * from v1; + +create or replace view v1 as select 2 & 3 DIV 2, 2 & (3 DIV 2), (2 & 3) DIV 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 DIV 2, 2 & (3 DIV 2), (2 & 3) DIV 2 union select * from v1; + +create or replace view v1 as select 2 & 3 MOD 3, 2 & (3 MOD 3), (2 & 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 MOD 3, 2 & (3 MOD 3), (2 & 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 & 3 % 3, 2 & (3 % 3), (2 & 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 % 3, 2 & (3 % 3), (2 & 3) % 3 union select * from v1; + +create or replace view v1 as select 2 & 3 ^ 3, 2 & (3 ^ 3), (2 & 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 ^ 3, 2 & (3 ^ 3), (2 & 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 & 3 BETWEEN 1 AND 3, 2 & (3 BETWEEN 1 AND 3), (2 & 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 BETWEEN 1 AND 3, 2 & (3 BETWEEN 1 AND 3), (2 & 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 << 3 IS FALSE, 2 << (3 IS FALSE), (2 << 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 IS FALSE, 2 << (3 IS FALSE), (2 << 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 << 3 COLLATE latin1_bin), charset(2 << (3 COLLATE latin1_bin)), charset((2 << 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 << 3 COLLATE latin1_bin), charset(2 << (3 COLLATE latin1_bin)), charset((2 << 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 << 3 IN (0,1), 2 << (3 IN (0,1)), (2 << 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 IN (0,1), 2 << (3 IN (0,1)), (2 << 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 << 3 OR 3, 2 << (3 OR 3), (2 << 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 OR 3, 2 << (3 OR 3), (2 << 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 << 3 || 3, 2 << (3 || 3), (2 << 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 || 3, 2 << (3 || 3), (2 << 3) || 3 union select * from v1; + +create or replace view v1 as select 2 << 3 XOR 3, 2 << (3 XOR 3), (2 << 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 XOR 3, 2 << (3 XOR 3), (2 << 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 << 3 AND 3, 2 << (3 AND 3), (2 << 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 AND 3, 2 << (3 AND 3), (2 << 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 << 3 && 3, 2 << (3 && 3), (2 << 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 && 3, 2 << (3 && 3), (2 << 3) && 3 union select * from v1; + +create or replace view v1 as select 2 << 3 = 3, 2 << (3 = 3), (2 << 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 = 3, 2 << (3 = 3), (2 << 3) = 3 union select * from v1; + +create or replace view v1 as select 2 << 3 <=> 3, 2 << (3 <=> 3), (2 << 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 <=> 3, 2 << (3 <=> 3), (2 << 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 << 3 >= 3, 2 << (3 >= 3), (2 << 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 >= 3, 2 << (3 >= 3), (2 << 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 << 3 <= 3, 2 << (3 <= 3), (2 << 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 <= 3, 2 << (3 <= 3), (2 << 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 << 3 < 3, 2 << (3 < 3), (2 << 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 < 3, 2 << (3 < 3), (2 << 3) < 3 union select * from v1; + +create or replace view v1 as select 2 << 3 <> 3, 2 << (3 <> 3), (2 << 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 <> 3, 2 << (3 <> 3), (2 << 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 << 3 > 3, 2 << (3 > 3), (2 << 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 > 3, 2 << (3 > 3), (2 << 3) > 3 union select * from v1; + +create or replace view v1 as select 2 << 3 != 3, 2 << (3 != 3), (2 << 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 != 3, 2 << (3 != 3), (2 << 3) != 3 union select * from v1; + +create or replace view v1 as select 2 << 3 LIKE 3, 2 << (3 LIKE 3), (2 << 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 LIKE 3, 2 << (3 LIKE 3), (2 << 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 << 3 REGEXP 3, 2 << (3 REGEXP 3), (2 << 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 REGEXP 3, 2 << (3 REGEXP 3), (2 << 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 << 3 | 3, 2 << (3 | 3), (2 << 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 | 3, 2 << (3 | 3), (2 << 3) | 3 union select * from v1; + +create or replace view v1 as select 2 << 3 & 3, 2 << (3 & 3), (2 << 3) & 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 & 3, 2 << (3 & 3), (2 << 3) & 3 union select * from v1; + +create or replace view v1 as select 2 << 3 << 3, 2 << (3 << 3), (2 << 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 << 3, 2 << (3 << 3), (2 << 3) << 3 union select * from v1; + +create or replace view v1 as select 2 << 2 >> 3, 2 << (2 >> 3), (2 << 2) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 2 >> 3, 2 << (2 >> 3), (2 << 2) >> 3 union select * from v1; + +create or replace view v1 as select 2 << '2000-01-01' +INTERVAL 1 DAY, 2 << ('2000-01-01' +INTERVAL 1 DAY), (2 << '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << '2000-01-01' +INTERVAL 1 DAY, 2 << ('2000-01-01' +INTERVAL 1 DAY), (2 << '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 << 3 + 3, 2 << (3 + 3), (2 << 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 + 3, 2 << (3 + 3), (2 << 3) + 3 union select * from v1; + +create or replace view v1 as select 2 << 3 - 3, 2 << (3 - 3), (2 << 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 - 3, 2 << (3 - 3), (2 << 3) - 3 union select * from v1; + +create or replace view v1 as select 2 << 3 * 3, 2 << (3 * 3), (2 << 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 * 3, 2 << (3 * 3), (2 << 3) * 3 union select * from v1; + +create or replace view v1 as select 2 << 3 / 3, 2 << (3 / 3), (2 << 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 / 3, 2 << (3 / 3), (2 << 3) / 3 union select * from v1; + +create or replace view v1 as select 2 << 3 DIV 3, 2 << (3 DIV 3), (2 << 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 DIV 3, 2 << (3 DIV 3), (2 << 3) DIV 3 union select * from v1; + +create or replace view v1 as select 2 << 3 MOD 3, 2 << (3 MOD 3), (2 << 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 MOD 3, 2 << (3 MOD 3), (2 << 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 << 3 % 3, 2 << (3 % 3), (2 << 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 % 3, 2 << (3 % 3), (2 << 3) % 3 union select * from v1; + +create or replace view v1 as select 2 << 3 ^ 3, 2 << (3 ^ 3), (2 << 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 ^ 3, 2 << (3 ^ 3), (2 << 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 << 3 BETWEEN 1 AND 3, 2 << (3 BETWEEN 1 AND 3), (2 << 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 BETWEEN 1 AND 3, 2 << (3 BETWEEN 1 AND 3), (2 << 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 IS FALSE, 2 >> (3 IS FALSE), (2 >> 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 IS FALSE, 2 >> (3 IS FALSE), (2 >> 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 >> 3 COLLATE latin1_bin), charset(2 >> (3 COLLATE latin1_bin)), charset((2 >> 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 >> 3 COLLATE latin1_bin), charset(2 >> (3 COLLATE latin1_bin)), charset((2 >> 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 >> 3 IN (0,1), 2 >> (3 IN (0,1)), (2 >> 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 IN (0,1), 2 >> (3 IN (0,1)), (2 >> 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 >> 3 OR 0, 2 >> (3 OR 0), (2 >> 3) OR 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 OR 0, 2 >> (3 OR 0), (2 >> 3) OR 0 union select * from v1; + +create or replace view v1 as select 2 >> 3 || 0, 2 >> (3 || 0), (2 >> 3) || 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 || 0, 2 >> (3 || 0), (2 >> 3) || 0 union select * from v1; + +create or replace view v1 as select 2 >> 3 XOR 3, 2 >> (3 XOR 3), (2 >> 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 XOR 3, 2 >> (3 XOR 3), (2 >> 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 AND 3, 2 >> (3 AND 3), (2 >> 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 AND 3, 2 >> (3 AND 3), (2 >> 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 && 3, 2 >> (3 && 3), (2 >> 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 && 3, 2 >> (3 && 3), (2 >> 3) && 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 = 3, 2 >> (3 = 3), (2 >> 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 = 3, 2 >> (3 = 3), (2 >> 3) = 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 <=> 3, 2 >> (3 <=> 3), (2 >> 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 <=> 3, 2 >> (3 <=> 3), (2 >> 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 >= 3, 2 >> (3 >= 3), (2 >> 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 >= 3, 2 >> (3 >= 3), (2 >> 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 <= 0, 2 >> (3 <= 0), (2 >> 3) <= 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 <= 0, 2 >> (3 <= 0), (2 >> 3) <= 0 union select * from v1; + +create or replace view v1 as select 2 >> 3 < 3, 2 >> (3 < 3), (2 >> 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 < 3, 2 >> (3 < 3), (2 >> 3) < 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 <> 3, 2 >> (3 <> 3), (2 >> 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 <> 3, 2 >> (3 <> 3), (2 >> 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 > 3, 2 >> (3 > 3), (2 >> 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 > 3, 2 >> (3 > 3), (2 >> 3) > 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 != 3, 2 >> (3 != 3), (2 >> 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 != 3, 2 >> (3 != 3), (2 >> 3) != 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 LIKE 3, 2 >> (3 LIKE 3), (2 >> 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 LIKE 3, 2 >> (3 LIKE 3), (2 >> 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 REGEXP 3, 2 >> (3 REGEXP 3), (2 >> 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 REGEXP 3, 2 >> (3 REGEXP 3), (2 >> 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 | 3, 2 >> (3 | 3), (2 >> 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 | 3, 2 >> (3 | 3), (2 >> 3) | 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 & 1, 2 >> (3 & 1), (2 >> 3) & 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 & 1, 2 >> (3 & 1), (2 >> 3) & 1 union select * from v1; + +create or replace view v1 as select 2 >> 1 << 3, 2 >> (1 << 3), (2 >> 1) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 1 << 3, 2 >> (1 << 3), (2 >> 1) << 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 >> 3, 2 >> (3 >> 3), (2 >> 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 >> 3, 2 >> (3 >> 3), (2 >> 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 >> '2000-01-01' +INTERVAL 1 DAY, 2 >> ('2000-01-01' +INTERVAL 1 DAY), (2 >> '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> '2000-01-01' +INTERVAL 1 DAY, 2 >> ('2000-01-01' +INTERVAL 1 DAY), (2 >> '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 >> 3 + 3, 2 >> (3 + 3), (2 >> 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 + 3, 2 >> (3 + 3), (2 >> 3) + 3 union select * from v1; + +create or replace view v1 as select 2 >> 1 - 1, 2 >> (1 - 1), (2 >> 1) - 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 1 - 1, 2 >> (1 - 1), (2 >> 1) - 1 union select * from v1; + +create or replace view v1 as select 2 >> 1 * 3, 2 >> (1 * 3), (2 >> 1) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 1 * 3, 2 >> (1 * 3), (2 >> 1) * 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 / 3, 2 >> (3 / 3), (2 >> 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 / 3, 2 >> (3 / 3), (2 >> 3) / 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 DIV 3, 2 >> (3 DIV 3), (2 >> 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 DIV 3, 2 >> (3 DIV 3), (2 >> 3) DIV 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 MOD 3, 2 >> (3 MOD 3), (2 >> 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 MOD 3, 2 >> (3 MOD 3), (2 >> 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 % 3, 2 >> (3 % 3), (2 >> 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 % 3, 2 >> (3 % 3), (2 >> 3) % 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 ^ 3, 2 >> (3 ^ 3), (2 >> 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 ^ 3, 2 >> (3 ^ 3), (2 >> 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 BETWEEN 1 AND 3, 2 >> (3 BETWEEN 1 AND 3), (2 >> 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 BETWEEN 1 AND 3, 2 >> (3 BETWEEN 1 AND 3), (2 >> 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 + 3 IS FALSE, 2 + (3 IS FALSE), (2 + 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 IS FALSE, 2 + (3 IS FALSE), (2 + 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 + 3 COLLATE latin1_bin), charset(2 + (3 COLLATE latin1_bin)), charset((2 + 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 + 3 COLLATE latin1_bin), charset(2 + (3 COLLATE latin1_bin)), charset((2 + 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 + 3 IN (0,1), 2 + (3 IN (0,1)), (2 + 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 IN (0,1), 2 + (3 IN (0,1)), (2 + 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 + 3 OR 3, 2 + (3 OR 3), (2 + 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 OR 3, 2 + (3 OR 3), (2 + 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 + 3 || 3, 2 + (3 || 3), (2 + 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 || 3, 2 + (3 || 3), (2 + 3) || 3 union select * from v1; + +create or replace view v1 as select 2 + 3 XOR 3, 2 + (3 XOR 3), (2 + 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 XOR 3, 2 + (3 XOR 3), (2 + 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 + 3 AND 3, 2 + (3 AND 3), (2 + 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 AND 3, 2 + (3 AND 3), (2 + 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 + 3 && 3, 2 + (3 && 3), (2 + 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 && 3, 2 + (3 && 3), (2 + 3) && 3 union select * from v1; + +create or replace view v1 as select 2 + 3 = 3, 2 + (3 = 3), (2 + 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 = 3, 2 + (3 = 3), (2 + 3) = 3 union select * from v1; + +create or replace view v1 as select 2 + 3 <=> 3, 2 + (3 <=> 3), (2 + 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 <=> 3, 2 + (3 <=> 3), (2 + 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 + 3 >= 3, 2 + (3 >= 3), (2 + 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 >= 3, 2 + (3 >= 3), (2 + 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 + 3 <= 3, 2 + (3 <= 3), (2 + 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 <= 3, 2 + (3 <= 3), (2 + 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 + 3 < 3, 2 + (3 < 3), (2 + 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 < 3, 2 + (3 < 3), (2 + 3) < 3 union select * from v1; + +create or replace view v1 as select 2 + 3 <> 3, 2 + (3 <> 3), (2 + 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 <> 3, 2 + (3 <> 3), (2 + 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 + 3 > 3, 2 + (3 > 3), (2 + 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 > 3, 2 + (3 > 3), (2 + 3) > 3 union select * from v1; + +create or replace view v1 as select 2 + 3 != 3, 2 + (3 != 3), (2 + 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 != 3, 2 + (3 != 3), (2 + 3) != 3 union select * from v1; + +create or replace view v1 as select 2 + 3 LIKE 3, 2 + (3 LIKE 3), (2 + 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 LIKE 3, 2 + (3 LIKE 3), (2 + 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 + 3 REGEXP 3, 2 + (3 REGEXP 3), (2 + 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 REGEXP 3, 2 + (3 REGEXP 3), (2 + 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 + 3 | 3, 2 + (3 | 3), (2 + 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 | 3, 2 + (3 | 3), (2 + 3) | 3 union select * from v1; + +create or replace view v1 as select 2 + 3 & 3, 2 + (3 & 3), (2 + 3) & 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 & 3, 2 + (3 & 3), (2 + 3) & 3 union select * from v1; + +create or replace view v1 as select 2 + 3 << 3, 2 + (3 << 3), (2 + 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 << 3, 2 + (3 << 3), (2 + 3) << 3 union select * from v1; + +create or replace view v1 as select 2 + 3 >> 3, 2 + (3 >> 3), (2 + 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 >> 3, 2 + (3 >> 3), (2 + 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 + '2000-01-01' +INTERVAL 1 DAY, 2 + ('2000-01-01' +INTERVAL 1 DAY), (2 + '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + '2000-01-01' +INTERVAL 1 DAY, 2 + ('2000-01-01' +INTERVAL 1 DAY), (2 + '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 + 3 * 3, 2 + (3 * 3), (2 + 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 * 3, 2 + (3 * 3), (2 + 3) * 3 union select * from v1; + +create or replace view v1 as select 2 + 3 / 3, 2 + (3 / 3), (2 + 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 / 3, 2 + (3 / 3), (2 + 3) / 3 union select * from v1; + +create or replace view v1 as select 2 + 3 DIV 3, 2 + (3 DIV 3), (2 + 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 DIV 3, 2 + (3 DIV 3), (2 + 3) DIV 3 union select * from v1; + +create or replace view v1 as select 2 + 1 MOD 3, 2 + (1 MOD 3), (2 + 1) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 1 MOD 3, 2 + (1 MOD 3), (2 + 1) MOD 3 union select * from v1; + +create or replace view v1 as select 2 + 1 % 3, 2 + (1 % 3), (2 + 1) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 1 % 3, 2 + (1 % 3), (2 + 1) % 3 union select * from v1; + +create or replace view v1 as select 2 + 3 ^ 3, 2 + (3 ^ 3), (2 + 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 ^ 3, 2 + (3 ^ 3), (2 + 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 + 3 BETWEEN 1 AND 3, 2 + (3 BETWEEN 1 AND 3), (2 + 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 BETWEEN 1 AND 3, 2 + (3 BETWEEN 1 AND 3), (2 + 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 - 3 IS FALSE, 2 - (3 IS FALSE), (2 - 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 IS FALSE, 2 - (3 IS FALSE), (2 - 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 - 3 COLLATE latin1_bin), charset(2 - (3 COLLATE latin1_bin)), charset((2 - 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 - 3 COLLATE latin1_bin), charset(2 - (3 COLLATE latin1_bin)), charset((2 - 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 - 3 IN (0,1), 2 - (3 IN (0,1)), (2 - 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 IN (0,1), 2 - (3 IN (0,1)), (2 - 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 - 2 OR 0, 2 - (2 OR 0), (2 - 2) OR 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 2 OR 0, 2 - (2 OR 0), (2 - 2) OR 0 union select * from v1; + +create or replace view v1 as select 2 - 2 || 0, 2 - (2 || 0), (2 - 2) || 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 2 || 0, 2 - (2 || 0), (2 - 2) || 0 union select * from v1; + +create or replace view v1 as select 2 - 3 XOR 3, 2 - (3 XOR 3), (2 - 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 XOR 3, 2 - (3 XOR 3), (2 - 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 - 2 AND 2, 2 - (2 AND 2), (2 - 2) AND 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 2 AND 2, 2 - (2 AND 2), (2 - 2) AND 2 union select * from v1; + +create or replace view v1 as select 2 - 2 && 2, 2 - (2 && 2), (2 - 2) && 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 2 && 2, 2 - (2 && 2), (2 - 2) && 2 union select * from v1; + +create or replace view v1 as select 2 - 3 = 3, 2 - (3 = 3), (2 - 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 = 3, 2 - (3 = 3), (2 - 3) = 3 union select * from v1; + +create or replace view v1 as select 2 - 3 <=> 3, 2 - (3 <=> 3), (2 - 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 <=> 3, 2 - (3 <=> 3), (2 - 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 - 3 >= 3, 2 - (3 >= 3), (2 - 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 >= 3, 2 - (3 >= 3), (2 - 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 - 3 <= 2, 2 - (3 <= 2), (2 - 3) <= 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 <= 2, 2 - (3 <= 2), (2 - 3) <= 2 union select * from v1; + +create or replace view v1 as select 2 - 3 < 3, 2 - (3 < 3), (2 - 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 < 3, 2 - (3 < 3), (2 - 3) < 3 union select * from v1; + +create or replace view v1 as select 2 - 3 <> 3, 2 - (3 <> 3), (2 - 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 <> 3, 2 - (3 <> 3), (2 - 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 - 3 > 3, 2 - (3 > 3), (2 - 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 > 3, 2 - (3 > 3), (2 - 3) > 3 union select * from v1; + +create or replace view v1 as select 2 - 3 != 3, 2 - (3 != 3), (2 - 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 != 3, 2 - (3 != 3), (2 - 3) != 3 union select * from v1; + +create or replace view v1 as select 2 - 3 LIKE 3, 2 - (3 LIKE 3), (2 - 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 LIKE 3, 2 - (3 LIKE 3), (2 - 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 - 3 REGEXP 3, 2 - (3 REGEXP 3), (2 - 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 REGEXP 3, 2 - (3 REGEXP 3), (2 - 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 - 0 | 1, 2 - (0 | 1), (2 - 0) | 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 0 | 1, 2 - (0 | 1), (2 - 0) | 1 union select * from v1; + +create or replace view v1 as select 2 - 1 & 2, 2 - (1 & 2), (2 - 1) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 1 & 2, 2 - (1 & 2), (2 - 1) & 2 union select * from v1; + +create or replace view v1 as select 2 - 1 << 1, 2 - (1 << 1), (2 - 1) << 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 1 << 1, 2 - (1 << 1), (2 - 1) << 1 union select * from v1; + +create or replace view v1 as select 2 - 3 >> 3, 2 - (3 >> 3), (2 - 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 >> 3, 2 - (3 >> 3), (2 - 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 - '2000-01-01' +INTERVAL 1 DAY, 2 - ('2000-01-01' +INTERVAL 1 DAY), (2 - '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - '2000-01-01' +INTERVAL 1 DAY, 2 - ('2000-01-01' +INTERVAL 1 DAY), (2 - '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 - 3 + 3, 2 - (3 + 3), (2 - 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 + 3, 2 - (3 + 3), (2 - 3) + 3 union select * from v1; + +create or replace view v1 as select 2 - 3 - 3, 2 - (3 - 3), (2 - 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 - 3, 2 - (3 - 3), (2 - 3) - 3 union select * from v1; + +create or replace view v1 as select 2 - 3 * 3, 2 - (3 * 3), (2 - 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 * 3, 2 - (3 * 3), (2 - 3) * 3 union select * from v1; + +create or replace view v1 as select 2 - 3 / 3, 2 - (3 / 3), (2 - 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 / 3, 2 - (3 / 3), (2 - 3) / 3 union select * from v1; + +create or replace view v1 as select 2 - 3 DIV 3, 2 - (3 DIV 3), (2 - 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 DIV 3, 2 - (3 DIV 3), (2 - 3) DIV 3 union select * from v1; + +create or replace view v1 as select 2 - 3 MOD 3, 2 - (3 MOD 3), (2 - 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 MOD 3, 2 - (3 MOD 3), (2 - 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 - 3 % 3, 2 - (3 % 3), (2 - 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 % 3, 2 - (3 % 3), (2 - 3) % 3 union select * from v1; + +create or replace view v1 as select 2 - 3 ^ 3, 2 - (3 ^ 3), (2 - 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 ^ 3, 2 - (3 ^ 3), (2 - 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 - 3 BETWEEN 1 AND 3, 2 - (3 BETWEEN 1 AND 3), (2 - 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 BETWEEN 1 AND 3, 2 - (3 BETWEEN 1 AND 3), (2 - 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 * 0 IS FALSE, 2 * (0 IS FALSE), (2 * 0) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 0 IS FALSE, 2 * (0 IS FALSE), (2 * 0) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 * 3 COLLATE latin1_bin), charset(2 * (3 COLLATE latin1_bin)), charset((2 * 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 * 3 COLLATE latin1_bin), charset(2 * (3 COLLATE latin1_bin)), charset((2 * 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 * 0 IN (0,1), 2 * (0 IN (0,1)), (2 * 0) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 0 IN (0,1), 2 * (0 IN (0,1)), (2 * 0) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 * 3 OR 3, 2 * (3 OR 3), (2 * 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 OR 3, 2 * (3 OR 3), (2 * 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 * 3 || 3, 2 * (3 || 3), (2 * 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 || 3, 2 * (3 || 3), (2 * 3) || 3 union select * from v1; + +create or replace view v1 as select 2 * 3 XOR 0, 2 * (3 XOR 0), (2 * 3) XOR 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 XOR 0, 2 * (3 XOR 0), (2 * 3) XOR 0 union select * from v1; + +create or replace view v1 as select 2 * 3 AND 3, 2 * (3 AND 3), (2 * 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 AND 3, 2 * (3 AND 3), (2 * 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 * 3 && 3, 2 * (3 && 3), (2 * 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 && 3, 2 * (3 && 3), (2 * 3) && 3 union select * from v1; + +create or replace view v1 as select 2 * 3 = 3, 2 * (3 = 3), (2 * 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 = 3, 2 * (3 = 3), (2 * 3) = 3 union select * from v1; + +create or replace view v1 as select 2 * 3 <=> 3, 2 * (3 <=> 3), (2 * 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 <=> 3, 2 * (3 <=> 3), (2 * 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 * 3 >= 3, 2 * (3 >= 3), (2 * 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 >= 3, 2 * (3 >= 3), (2 * 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 * 3 <= 3, 2 * (3 <= 3), (2 * 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 <= 3, 2 * (3 <= 3), (2 * 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 * 0 < 3, 2 * (0 < 3), (2 * 0) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 0 < 3, 2 * (0 < 3), (2 * 0) < 3 union select * from v1; + +create or replace view v1 as select 2 * 3 <> 3, 2 * (3 <> 3), (2 * 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 <> 3, 2 * (3 <> 3), (2 * 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 * 3 > 3, 2 * (3 > 3), (2 * 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 > 3, 2 * (3 > 3), (2 * 3) > 3 union select * from v1; + +create or replace view v1 as select 2 * 3 != 3, 2 * (3 != 3), (2 * 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 != 3, 2 * (3 != 3), (2 * 3) != 3 union select * from v1; + +create or replace view v1 as select 2 * 3 LIKE 3, 2 * (3 LIKE 3), (2 * 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 LIKE 3, 2 * (3 LIKE 3), (2 * 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 * 3 REGEXP 3, 2 * (3 REGEXP 3), (2 * 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 REGEXP 3, 2 * (3 REGEXP 3), (2 * 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 * 3 | 3, 2 * (3 | 3), (2 * 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 | 3, 2 * (3 | 3), (2 * 3) | 3 union select * from v1; + +create or replace view v1 as select 2 * 3 & 3, 2 * (3 & 3), (2 * 3) & 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 & 3, 2 * (3 & 3), (2 * 3) & 3 union select * from v1; + +create or replace view v1 as select 2 * 3 >> 2, 2 * (3 >> 2), (2 * 3) >> 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 >> 2, 2 * (3 >> 2), (2 * 3) >> 2 union select * from v1; + +create or replace view v1 as select 2 * '2000-01-01' +INTERVAL 1 DAY, 2 * ('2000-01-01' +INTERVAL 1 DAY), (2 * '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * '2000-01-01' +INTERVAL 1 DAY, 2 * ('2000-01-01' +INTERVAL 1 DAY), (2 * '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 * 3 + 3, 2 * (3 + 3), (2 * 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 + 3, 2 * (3 + 3), (2 * 3) + 3 union select * from v1; + +create or replace view v1 as select 2 * 3 - 3, 2 * (3 - 3), (2 * 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 - 3, 2 * (3 - 3), (2 * 3) - 3 union select * from v1; + +create or replace view v1 as select 2 * 3 DIV 2, 2 * (3 DIV 2), (2 * 3) DIV 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 DIV 2, 2 * (3 DIV 2), (2 * 3) DIV 2 union select * from v1; + +create or replace view v1 as select 2 * 3 MOD 2, 2 * (3 MOD 2), (2 * 3) MOD 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 MOD 2, 2 * (3 MOD 2), (2 * 3) MOD 2 union select * from v1; + +create or replace view v1 as select 2 * 3 % 2, 2 * (3 % 2), (2 * 3) % 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 % 2, 2 * (3 % 2), (2 * 3) % 2 union select * from v1; + +create or replace view v1 as select 2 * 3 ^ 3, 2 * (3 ^ 3), (2 * 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 ^ 3, 2 * (3 ^ 3), (2 * 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 * 3 BETWEEN 1 AND 3, 2 * (3 BETWEEN 1 AND 3), (2 * 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 BETWEEN 1 AND 3, 2 * (3 BETWEEN 1 AND 3), (2 * 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 / 3 IS FALSE, 2 / (3 IS FALSE), (2 / 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 IS FALSE, 2 / (3 IS FALSE), (2 / 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 / 3 COLLATE latin1_bin), charset(2 / (3 COLLATE latin1_bin)), charset((2 / 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 / 3 COLLATE latin1_bin), charset(2 / (3 COLLATE latin1_bin)), charset((2 / 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 / 3 IN (0,1), 2 / (3 IN (0,1)), (2 / 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 IN (0,1), 2 / (3 IN (0,1)), (2 / 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 / 3 OR 3, 2 / (3 OR 3), (2 / 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 OR 3, 2 / (3 OR 3), (2 / 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 / 3 || 3, 2 / (3 || 3), (2 / 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 || 3, 2 / (3 || 3), (2 / 3) || 3 union select * from v1; + +create or replace view v1 as select 2 / 3 XOR 3, 2 / (3 XOR 3), (2 / 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 XOR 3, 2 / (3 XOR 3), (2 / 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 / 3 AND 3, 2 / (3 AND 3), (2 / 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 AND 3, 2 / (3 AND 3), (2 / 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 / 3 && 3, 2 / (3 && 3), (2 / 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 && 3, 2 / (3 && 3), (2 / 3) && 3 union select * from v1; + +create or replace view v1 as select 2 / 3 = 3, 2 / (3 = 3), (2 / 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 = 3, 2 / (3 = 3), (2 / 3) = 3 union select * from v1; + +create or replace view v1 as select 2 / 3 <=> 3, 2 / (3 <=> 3), (2 / 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 <=> 3, 2 / (3 <=> 3), (2 / 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 / 3 >= 3, 2 / (3 >= 3), (2 / 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 >= 3, 2 / (3 >= 3), (2 / 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 / 3 <= 3, 2 / (3 <= 3), (2 / 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 <= 3, 2 / (3 <= 3), (2 / 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 / 3 < 3, 2 / (3 < 3), (2 / 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 < 3, 2 / (3 < 3), (2 / 3) < 3 union select * from v1; + +create or replace view v1 as select 2 / 3 <> 3, 2 / (3 <> 3), (2 / 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 <> 3, 2 / (3 <> 3), (2 / 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 / 3 > 3, 2 / (3 > 3), (2 / 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 > 3, 2 / (3 > 3), (2 / 3) > 3 union select * from v1; + +create or replace view v1 as select 2 / 3 != 3, 2 / (3 != 3), (2 / 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 != 3, 2 / (3 != 3), (2 / 3) != 3 union select * from v1; + +create or replace view v1 as select 2 / 3 LIKE 3, 2 / (3 LIKE 3), (2 / 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 LIKE 3, 2 / (3 LIKE 3), (2 / 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 / 3 REGEXP 3, 2 / (3 REGEXP 3), (2 / 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 REGEXP 3, 2 / (3 REGEXP 3), (2 / 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 / 3 | 3, 2 / (3 | 3), (2 / 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 | 3, 2 / (3 | 3), (2 / 3) | 3 union select * from v1; + +create or replace view v1 as select 2 / 3 & 3, 2 / (3 & 3), (2 / 3) & 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 & 3, 2 / (3 & 3), (2 / 3) & 3 union select * from v1; + +create or replace view v1 as select 2 / 3 << 3, 2 / (3 << 3), (2 / 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 << 3, 2 / (3 << 3), (2 / 3) << 3 union select * from v1; + +create or replace view v1 as select 2 / 3 >> 3, 2 / (3 >> 3), (2 / 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 >> 3, 2 / (3 >> 3), (2 / 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 / '2000-01-01' +INTERVAL 1 DAY, 2 / ('2000-01-01' +INTERVAL 1 DAY), (2 / '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / '2000-01-01' +INTERVAL 1 DAY, 2 / ('2000-01-01' +INTERVAL 1 DAY), (2 / '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 / 3 + 3, 2 / (3 + 3), (2 / 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 + 3, 2 / (3 + 3), (2 / 3) + 3 union select * from v1; + +create or replace view v1 as select 2 / 3 - 3, 2 / (3 - 3), (2 / 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 - 3, 2 / (3 - 3), (2 / 3) - 3 union select * from v1; + +create or replace view v1 as select 2 / 3 * 3, 2 / (3 * 3), (2 / 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 * 3, 2 / (3 * 3), (2 / 3) * 3 union select * from v1; + +create or replace view v1 as select 2 / 3 / 3, 2 / (3 / 3), (2 / 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 / 3, 2 / (3 / 3), (2 / 3) / 3 union select * from v1; + +create or replace view v1 as select 2 / 3 DIV 3, 2 / (3 DIV 3), (2 / 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 DIV 3, 2 / (3 DIV 3), (2 / 3) DIV 3 union select * from v1; + +create or replace view v1 as select 2 / 3 MOD 3, 2 / (3 MOD 3), (2 / 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 MOD 3, 2 / (3 MOD 3), (2 / 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 / 3 % 3, 2 / (3 % 3), (2 / 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 % 3, 2 / (3 % 3), (2 / 3) % 3 union select * from v1; + +create or replace view v1 as select 2 / 3 ^ 3, 2 / (3 ^ 3), (2 / 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 ^ 3, 2 / (3 ^ 3), (2 / 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 / 3 BETWEEN 1 AND 3, 2 / (3 BETWEEN 1 AND 3), (2 / 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 BETWEEN 1 AND 3, 2 / (3 BETWEEN 1 AND 3), (2 / 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 IS FALSE, 2 DIV (3 IS FALSE), (2 DIV 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 IS FALSE, 2 DIV (3 IS FALSE), (2 DIV 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 DIV 3 COLLATE latin1_bin), charset(2 DIV (3 COLLATE latin1_bin)), charset((2 DIV 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 DIV 3 COLLATE latin1_bin), charset(2 DIV (3 COLLATE latin1_bin)), charset((2 DIV 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 DIV 3 IN (0,1), 2 DIV (3 IN (0,1)), (2 DIV 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 IN (0,1), 2 DIV (3 IN (0,1)), (2 DIV 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 DIV 3 OR 3, 2 DIV (3 OR 3), (2 DIV 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 OR 3, 2 DIV (3 OR 3), (2 DIV 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 || 3, 2 DIV (3 || 3), (2 DIV 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 || 3, 2 DIV (3 || 3), (2 DIV 3) || 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 XOR 3, 2 DIV (3 XOR 3), (2 DIV 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 XOR 3, 2 DIV (3 XOR 3), (2 DIV 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 AND 3, 2 DIV (3 AND 3), (2 DIV 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 AND 3, 2 DIV (3 AND 3), (2 DIV 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 && 3, 2 DIV (3 && 3), (2 DIV 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 && 3, 2 DIV (3 && 3), (2 DIV 3) && 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 = 3, 2 DIV (3 = 3), (2 DIV 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 = 3, 2 DIV (3 = 3), (2 DIV 3) = 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 <=> 3, 2 DIV (3 <=> 3), (2 DIV 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 <=> 3, 2 DIV (3 <=> 3), (2 DIV 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 >= 3, 2 DIV (3 >= 3), (2 DIV 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 >= 3, 2 DIV (3 >= 3), (2 DIV 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 <= 3, 2 DIV (3 <= 3), (2 DIV 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 <= 3, 2 DIV (3 <= 3), (2 DIV 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 < 3, 2 DIV (3 < 3), (2 DIV 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 < 3, 2 DIV (3 < 3), (2 DIV 3) < 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 <> 3, 2 DIV (3 <> 3), (2 DIV 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 <> 3, 2 DIV (3 <> 3), (2 DIV 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 > 3, 2 DIV (3 > 3), (2 DIV 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 > 3, 2 DIV (3 > 3), (2 DIV 3) > 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 != 3, 2 DIV (3 != 3), (2 DIV 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 != 3, 2 DIV (3 != 3), (2 DIV 3) != 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 LIKE 3, 2 DIV (3 LIKE 3), (2 DIV 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 LIKE 3, 2 DIV (3 LIKE 3), (2 DIV 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 REGEXP 3, 2 DIV (3 REGEXP 3), (2 DIV 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 REGEXP 3, 2 DIV (3 REGEXP 3), (2 DIV 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 | 3, 2 DIV (3 | 3), (2 DIV 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 | 3, 2 DIV (3 | 3), (2 DIV 3) | 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 & 1, 2 DIV (3 & 1), (2 DIV 3) & 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 & 1, 2 DIV (3 & 1), (2 DIV 3) & 1 union select * from v1; + +create or replace view v1 as select 4 DIV 3 << 3, 4 DIV (3 << 3), (4 DIV 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 4 DIV 3 << 3, 4 DIV (3 << 3), (4 DIV 3) << 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 >> 3, 2 DIV (3 >> 3), (2 DIV 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 >> 3, 2 DIV (3 >> 3), (2 DIV 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 DIV '2000-01-01' +INTERVAL 1 DAY, 2 DIV ('2000-01-01' +INTERVAL 1 DAY), (2 DIV '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV '2000-01-01' +INTERVAL 1 DAY, 2 DIV ('2000-01-01' +INTERVAL 1 DAY), (2 DIV '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 DIV 3 + 3, 2 DIV (3 + 3), (2 DIV 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 + 3, 2 DIV (3 + 3), (2 DIV 3) + 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 - 3, 2 DIV (3 - 3), (2 DIV 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 - 3, 2 DIV (3 - 3), (2 DIV 3) - 3 union select * from v1; + +create or replace view v1 as select 4 DIV 3 * 3, 4 DIV (3 * 3), (4 DIV 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 4 DIV 3 * 3, 4 DIV (3 * 3), (4 DIV 3) * 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 / 3, 2 DIV (3 / 3), (2 DIV 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 / 3, 2 DIV (3 / 3), (2 DIV 3) / 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 DIV 3, 2 DIV (3 DIV 3), (2 DIV 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 DIV 3, 2 DIV (3 DIV 3), (2 DIV 3) DIV 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 MOD 3, 2 DIV (3 MOD 3), (2 DIV 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 MOD 3, 2 DIV (3 MOD 3), (2 DIV 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 % 3, 2 DIV (3 % 3), (2 DIV 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 % 3, 2 DIV (3 % 3), (2 DIV 3) % 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 ^ 3, 2 DIV (3 ^ 3), (2 DIV 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 ^ 3, 2 DIV (3 ^ 3), (2 DIV 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 BETWEEN 1 AND 3, 2 DIV (3 BETWEEN 1 AND 3), (2 DIV 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 BETWEEN 1 AND 3, 2 DIV (3 BETWEEN 1 AND 3), (2 DIV 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 IS FALSE, 2 MOD (3 IS FALSE), (2 MOD 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 IS FALSE, 2 MOD (3 IS FALSE), (2 MOD 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 MOD 3 COLLATE latin1_bin), charset(2 MOD (3 COLLATE latin1_bin)), charset((2 MOD 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 MOD 3 COLLATE latin1_bin), charset(2 MOD (3 COLLATE latin1_bin)), charset((2 MOD 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 MOD 3 IN (0,1), 2 MOD (3 IN (0,1)), (2 MOD 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 IN (0,1), 2 MOD (3 IN (0,1)), (2 MOD 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 MOD 3 OR 3, 2 MOD (3 OR 3), (2 MOD 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 OR 3, 2 MOD (3 OR 3), (2 MOD 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 || 3, 2 MOD (3 || 3), (2 MOD 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 || 3, 2 MOD (3 || 3), (2 MOD 3) || 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 XOR 3, 2 MOD (3 XOR 3), (2 MOD 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 XOR 3, 2 MOD (3 XOR 3), (2 MOD 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 AND 3, 2 MOD (3 AND 3), (2 MOD 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 AND 3, 2 MOD (3 AND 3), (2 MOD 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 && 3, 2 MOD (3 && 3), (2 MOD 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 && 3, 2 MOD (3 && 3), (2 MOD 3) && 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 = 2, 2 MOD (3 = 2), (2 MOD 3) = 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 = 2, 2 MOD (3 = 2), (2 MOD 3) = 2 union select * from v1; + +create or replace view v1 as select 2 MOD 3 <=> 2, 2 MOD (3 <=> 2), (2 MOD 3) <=> 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 <=> 2, 2 MOD (3 <=> 2), (2 MOD 3) <=> 2 union select * from v1; + +create or replace view v1 as select 2 MOD 3 >= 1, 2 MOD (3 >= 1), (2 MOD 3) >= 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 >= 1, 2 MOD (3 >= 1), (2 MOD 3) >= 1 union select * from v1; + +create or replace view v1 as select 2 MOD 3 <= 3, 2 MOD (3 <= 3), (2 MOD 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 <= 3, 2 MOD (3 <= 3), (2 MOD 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 < 3, 2 MOD (3 < 3), (2 MOD 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 < 3, 2 MOD (3 < 3), (2 MOD 3) < 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 <> 3, 2 MOD (3 <> 3), (2 MOD 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 <> 3, 2 MOD (3 <> 3), (2 MOD 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 > 3, 2 MOD (3 > 3), (2 MOD 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 > 3, 2 MOD (3 > 3), (2 MOD 3) > 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 != 3, 2 MOD (3 != 3), (2 MOD 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 != 3, 2 MOD (3 != 3), (2 MOD 3) != 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 LIKE 2, 2 MOD (3 LIKE 2), (2 MOD 3) LIKE 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 LIKE 2, 2 MOD (3 LIKE 2), (2 MOD 3) LIKE 2 union select * from v1; + +create or replace view v1 as select 2 MOD 3 REGEXP 2, 2 MOD (3 REGEXP 2), (2 MOD 3) REGEXP 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 REGEXP 2, 2 MOD (3 REGEXP 2), (2 MOD 3) REGEXP 2 union select * from v1; + +create or replace view v1 as select 2 MOD 3 | 3, 2 MOD (3 | 3), (2 MOD 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 | 3, 2 MOD (3 | 3), (2 MOD 3) | 3 union select * from v1; + +create or replace view v1 as select 2 MOD 4 & 4, 2 MOD (4 & 4), (2 MOD 4) & 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 4 & 4, 2 MOD (4 & 4), (2 MOD 4) & 4 union select * from v1; + +create or replace view v1 as select 2 MOD 3 << 3, 2 MOD (3 << 3), (2 MOD 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 << 3, 2 MOD (3 << 3), (2 MOD 3) << 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 >> 3, 2 MOD (3 >> 3), (2 MOD 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 >> 3, 2 MOD (3 >> 3), (2 MOD 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 MOD '2000-01-01' +INTERVAL 1 DAY, 2 MOD ('2000-01-01' +INTERVAL 1 DAY), (2 MOD '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD '2000-01-01' +INTERVAL 1 DAY, 2 MOD ('2000-01-01' +INTERVAL 1 DAY), (2 MOD '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 MOD 3 + 3, 2 MOD (3 + 3), (2 MOD 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 + 3, 2 MOD (3 + 3), (2 MOD 3) + 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 - 3, 2 MOD (3 - 3), (2 MOD 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 - 3, 2 MOD (3 - 3), (2 MOD 3) - 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 * 3, 2 MOD (3 * 3), (2 MOD 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 * 3, 2 MOD (3 * 3), (2 MOD 3) * 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 / 3, 2 MOD (3 / 3), (2 MOD 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 / 3, 2 MOD (3 / 3), (2 MOD 3) / 3 union select * from v1; + +create or replace view v1 as select 3 MOD 4 DIV 3, 3 MOD (4 DIV 3), (3 MOD 4) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 MOD 4 DIV 3, 3 MOD (4 DIV 3), (3 MOD 4) DIV 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 MOD 3, 2 MOD (3 MOD 3), (2 MOD 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 MOD 3, 2 MOD (3 MOD 3), (2 MOD 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 % 3, 2 MOD (3 % 3), (2 MOD 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 % 3, 2 MOD (3 % 3), (2 MOD 3) % 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 ^ 3, 2 MOD (3 ^ 3), (2 MOD 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 ^ 3, 2 MOD (3 ^ 3), (2 MOD 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 BETWEEN 1 AND 3, 2 MOD (3 BETWEEN 1 AND 3), (2 MOD 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 BETWEEN 1 AND 3, 2 MOD (3 BETWEEN 1 AND 3), (2 MOD 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 % 3 IS FALSE, 2 % (3 IS FALSE), (2 % 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 IS FALSE, 2 % (3 IS FALSE), (2 % 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 % 3 COLLATE latin1_bin), charset(2 % (3 COLLATE latin1_bin)), charset((2 % 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 % 3 COLLATE latin1_bin), charset(2 % (3 COLLATE latin1_bin)), charset((2 % 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 % 3 IN (0,1), 2 % (3 IN (0,1)), (2 % 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 IN (0,1), 2 % (3 IN (0,1)), (2 % 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 % 3 OR 3, 2 % (3 OR 3), (2 % 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 OR 3, 2 % (3 OR 3), (2 % 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 % 3 || 3, 2 % (3 || 3), (2 % 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 || 3, 2 % (3 || 3), (2 % 3) || 3 union select * from v1; + +create or replace view v1 as select 2 % 3 XOR 3, 2 % (3 XOR 3), (2 % 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 XOR 3, 2 % (3 XOR 3), (2 % 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 % 3 AND 3, 2 % (3 AND 3), (2 % 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 AND 3, 2 % (3 AND 3), (2 % 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 % 3 && 3, 2 % (3 && 3), (2 % 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 && 3, 2 % (3 && 3), (2 % 3) && 3 union select * from v1; + +create or replace view v1 as select 2 % 3 = 2, 2 % (3 = 2), (2 % 3) = 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 = 2, 2 % (3 = 2), (2 % 3) = 2 union select * from v1; + +create or replace view v1 as select 2 % 3 <=> 2, 2 % (3 <=> 2), (2 % 3) <=> 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 <=> 2, 2 % (3 <=> 2), (2 % 3) <=> 2 union select * from v1; + +create or replace view v1 as select 2 % 3 >= 1, 2 % (3 >= 1), (2 % 3) >= 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 >= 1, 2 % (3 >= 1), (2 % 3) >= 1 union select * from v1; + +create or replace view v1 as select 2 % 3 <= 3, 2 % (3 <= 3), (2 % 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 <= 3, 2 % (3 <= 3), (2 % 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 % 3 < 3, 2 % (3 < 3), (2 % 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 < 3, 2 % (3 < 3), (2 % 3) < 3 union select * from v1; + +create or replace view v1 as select 2 % 3 <> 3, 2 % (3 <> 3), (2 % 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 <> 3, 2 % (3 <> 3), (2 % 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 % 3 > 3, 2 % (3 > 3), (2 % 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 > 3, 2 % (3 > 3), (2 % 3) > 3 union select * from v1; + +create or replace view v1 as select 2 % 3 != 3, 2 % (3 != 3), (2 % 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 != 3, 2 % (3 != 3), (2 % 3) != 3 union select * from v1; + +create or replace view v1 as select 2 % 3 LIKE 2, 2 % (3 LIKE 2), (2 % 3) LIKE 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 LIKE 2, 2 % (3 LIKE 2), (2 % 3) LIKE 2 union select * from v1; + +create or replace view v1 as select 2 % 3 REGEXP 2, 2 % (3 REGEXP 2), (2 % 3) REGEXP 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 REGEXP 2, 2 % (3 REGEXP 2), (2 % 3) REGEXP 2 union select * from v1; + +create or replace view v1 as select 2 % 3 | 3, 2 % (3 | 3), (2 % 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 | 3, 2 % (3 | 3), (2 % 3) | 3 union select * from v1; + +create or replace view v1 as select 2 % 4 & 4, 2 % (4 & 4), (2 % 4) & 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 4 & 4, 2 % (4 & 4), (2 % 4) & 4 union select * from v1; + +create or replace view v1 as select 2 % 3 << 3, 2 % (3 << 3), (2 % 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 << 3, 2 % (3 << 3), (2 % 3) << 3 union select * from v1; + +create or replace view v1 as select 2 % 3 >> 3, 2 % (3 >> 3), (2 % 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 >> 3, 2 % (3 >> 3), (2 % 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 % '2000-01-01' +INTERVAL 1 DAY, 2 % ('2000-01-01' +INTERVAL 1 DAY), (2 % '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % '2000-01-01' +INTERVAL 1 DAY, 2 % ('2000-01-01' +INTERVAL 1 DAY), (2 % '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 % 3 + 3, 2 % (3 + 3), (2 % 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 + 3, 2 % (3 + 3), (2 % 3) + 3 union select * from v1; + +create or replace view v1 as select 2 % 3 - 3, 2 % (3 - 3), (2 % 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 - 3, 2 % (3 - 3), (2 % 3) - 3 union select * from v1; + +create or replace view v1 as select 2 % 3 * 3, 2 % (3 * 3), (2 % 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 * 3, 2 % (3 * 3), (2 % 3) * 3 union select * from v1; + +create or replace view v1 as select 2 % 3 / 3, 2 % (3 / 3), (2 % 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 / 3, 2 % (3 / 3), (2 % 3) / 3 union select * from v1; + +create or replace view v1 as select 3 % 4 DIV 3, 3 % (4 DIV 3), (3 % 4) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 % 4 DIV 3, 3 % (4 DIV 3), (3 % 4) DIV 3 union select * from v1; + +create or replace view v1 as select 2 % 3 MOD 3, 2 % (3 MOD 3), (2 % 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 MOD 3, 2 % (3 MOD 3), (2 % 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 % 3 % 3, 2 % (3 % 3), (2 % 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 % 3, 2 % (3 % 3), (2 % 3) % 3 union select * from v1; + +create or replace view v1 as select 2 % 3 ^ 3, 2 % (3 ^ 3), (2 % 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 ^ 3, 2 % (3 ^ 3), (2 % 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 % 3 BETWEEN 1 AND 3, 2 % (3 BETWEEN 1 AND 3), (2 % 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 BETWEEN 1 AND 3, 2 % (3 BETWEEN 1 AND 3), (2 % 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 IS FALSE, 2 ^ (3 IS FALSE), (2 ^ 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 IS FALSE, 2 ^ (3 IS FALSE), (2 ^ 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 ^ 3 COLLATE latin1_bin), charset(2 ^ (3 COLLATE latin1_bin)), charset((2 ^ 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 ^ 3 COLLATE latin1_bin), charset(2 ^ (3 COLLATE latin1_bin)), charset((2 ^ 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 ^ 3 IN (0,1), 2 ^ (3 IN (0,1)), (2 ^ 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 IN (0,1), 2 ^ (3 IN (0,1)), (2 ^ 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 ^ 3 OR 3, 2 ^ (3 OR 3), (2 ^ 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 OR 3, 2 ^ (3 OR 3), (2 ^ 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 || 3, 2 ^ (3 || 3), (2 ^ 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 || 3, 2 ^ (3 || 3), (2 ^ 3) || 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 XOR 3, 2 ^ (3 XOR 3), (2 ^ 3) XOR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 XOR 3, 2 ^ (3 XOR 3), (2 ^ 3) XOR 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 AND 3, 2 ^ (3 AND 3), (2 ^ 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 AND 3, 2 ^ (3 AND 3), (2 ^ 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 && 3, 2 ^ (3 && 3), (2 ^ 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 && 3, 2 ^ (3 && 3), (2 ^ 3) && 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 = 3, 2 ^ (3 = 3), (2 ^ 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 = 3, 2 ^ (3 = 3), (2 ^ 3) = 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 <=> 3, 2 ^ (3 <=> 3), (2 ^ 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 <=> 3, 2 ^ (3 <=> 3), (2 ^ 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 >= 3, 2 ^ (3 >= 3), (2 ^ 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 >= 3, 2 ^ (3 >= 3), (2 ^ 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 <= 3, 2 ^ (3 <= 3), (2 ^ 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 <= 3, 2 ^ (3 <= 3), (2 ^ 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 < 3, 2 ^ (3 < 3), (2 ^ 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 < 3, 2 ^ (3 < 3), (2 ^ 3) < 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 <> 3, 2 ^ (3 <> 3), (2 ^ 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 <> 3, 2 ^ (3 <> 3), (2 ^ 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 > 3, 2 ^ (3 > 3), (2 ^ 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 > 3, 2 ^ (3 > 3), (2 ^ 3) > 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 != 3, 2 ^ (3 != 3), (2 ^ 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 != 3, 2 ^ (3 != 3), (2 ^ 3) != 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 LIKE 3, 2 ^ (3 LIKE 3), (2 ^ 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 LIKE 3, 2 ^ (3 LIKE 3), (2 ^ 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 REGEXP 3, 2 ^ (3 REGEXP 3), (2 ^ 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 REGEXP 3, 2 ^ (3 REGEXP 3), (2 ^ 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 | 3, 2 ^ (3 | 3), (2 ^ 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 | 3, 2 ^ (3 | 3), (2 ^ 3) | 3 union select * from v1; + +create or replace view v1 as select 2 ^ 0 & 0, 2 ^ (0 & 0), (2 ^ 0) & 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 0 & 0, 2 ^ (0 & 0), (2 ^ 0) & 0 union select * from v1; + +create or replace view v1 as select 2 ^ 3 << 3, 2 ^ (3 << 3), (2 ^ 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 << 3, 2 ^ (3 << 3), (2 ^ 3) << 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 >> 3, 2 ^ (3 >> 3), (2 ^ 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 >> 3, 2 ^ (3 >> 3), (2 ^ 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 ^ '2000-01-01' +INTERVAL 1 DAY, 2 ^ ('2000-01-01' +INTERVAL 1 DAY), (2 ^ '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ '2000-01-01' +INTERVAL 1 DAY, 2 ^ ('2000-01-01' +INTERVAL 1 DAY), (2 ^ '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 ^ 3 + 1, 2 ^ (3 + 1), (2 ^ 3) + 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 + 1, 2 ^ (3 + 1), (2 ^ 3) + 1 union select * from v1; + +create or replace view v1 as select 5 ^ 1 - 1, 5 ^ (1 - 1), (5 ^ 1) - 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 5 ^ 1 - 1, 5 ^ (1 - 1), (5 ^ 1) - 1 union select * from v1; + +create or replace view v1 as select 2 ^ 3 * 3, 2 ^ (3 * 3), (2 ^ 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 * 3, 2 ^ (3 * 3), (2 ^ 3) * 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 / 3, 2 ^ (3 / 3), (2 ^ 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 / 3, 2 ^ (3 / 3), (2 ^ 3) / 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 DIV 3, 2 ^ (3 DIV 3), (2 ^ 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 DIV 3, 2 ^ (3 DIV 3), (2 ^ 3) DIV 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 MOD 3, 2 ^ (3 MOD 3), (2 ^ 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 MOD 3, 2 ^ (3 MOD 3), (2 ^ 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 % 3, 2 ^ (3 % 3), (2 ^ 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 % 3, 2 ^ (3 % 3), (2 ^ 3) % 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 BETWEEN 1 AND 3, 2 ^ (3 BETWEEN 1 AND 3), (2 ^ 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 BETWEEN 1 AND 3, 2 ^ (3 BETWEEN 1 AND 3), (2 ^ 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 1 IS FALSE, 2 BETWEEN 1 AND (1 IS FALSE), (2 BETWEEN 1 AND 1) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 1 IS FALSE, 2 BETWEEN 1 AND (1 IS FALSE), (2 BETWEEN 1 AND 1) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 BETWEEN 1 AND 3 COLLATE latin1_bin), charset(2 BETWEEN 1 AND (3 COLLATE latin1_bin)), charset((2 BETWEEN 1 AND 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 BETWEEN 1 AND 3 COLLATE latin1_bin), charset(2 BETWEEN 1 AND (3 COLLATE latin1_bin)), charset((2 BETWEEN 1 AND 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 IN (0,1), 2 BETWEEN 1 AND (3 IN (0,1)), (2 BETWEEN 1 AND 3) IN (0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 IN (0,1), 2 BETWEEN 1 AND (3 IN (0,1)), (2 BETWEEN 1 AND 3) IN (0,1) union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 OR 3, 2 BETWEEN 1 AND (3 OR 3), (2 BETWEEN 1 AND 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 OR 3, 2 BETWEEN 1 AND (3 OR 3), (2 BETWEEN 1 AND 3) OR 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 || 3, 2 BETWEEN 1 AND (3 || 3), (2 BETWEEN 1 AND 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 || 3, 2 BETWEEN 1 AND (3 || 3), (2 BETWEEN 1 AND 3) || 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 1 XOR 1, 2 BETWEEN 1 AND (1 XOR 1), (2 BETWEEN 1 AND 1) XOR 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 1 XOR 1, 2 BETWEEN 1 AND (1 XOR 1), (2 BETWEEN 1 AND 1) XOR 1 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 AND 3, 2 BETWEEN 1 AND (3 AND 3), (2 BETWEEN 1 AND 3) AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 AND 3, 2 BETWEEN 1 AND (3 AND 3), (2 BETWEEN 1 AND 3) AND 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 && 3, 2 BETWEEN 1 AND (3 && 3), (2 BETWEEN 1 AND 3) && 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 && 3, 2 BETWEEN 1 AND (3 && 3), (2 BETWEEN 1 AND 3) && 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 = 1, 2 BETWEEN 1 AND (3 = 1), (2 BETWEEN 1 AND 3) = 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 = 1, 2 BETWEEN 1 AND (3 = 1), (2 BETWEEN 1 AND 3) = 1 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 <=> 1, 2 BETWEEN 1 AND (3 <=> 1), (2 BETWEEN 1 AND 3) <=> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 <=> 1, 2 BETWEEN 1 AND (3 <=> 1), (2 BETWEEN 1 AND 3) <=> 1 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 >= 1, 2 BETWEEN 1 AND (3 >= 1), (2 BETWEEN 1 AND 3) >= 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 >= 1, 2 BETWEEN 1 AND (3 >= 1), (2 BETWEEN 1 AND 3) >= 1 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 <= 3, 2 BETWEEN 1 AND (3 <= 3), (2 BETWEEN 1 AND 3) <= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 <= 3, 2 BETWEEN 1 AND (3 <= 3), (2 BETWEEN 1 AND 3) <= 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 < 3, 2 BETWEEN 1 AND (3 < 3), (2 BETWEEN 1 AND 3) < 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 < 3, 2 BETWEEN 1 AND (3 < 3), (2 BETWEEN 1 AND 3) < 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 <> 3, 2 BETWEEN 1 AND (3 <> 3), (2 BETWEEN 1 AND 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 <> 3, 2 BETWEEN 1 AND (3 <> 3), (2 BETWEEN 1 AND 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 > 0, 2 BETWEEN 1 AND (3 > 0), (2 BETWEEN 1 AND 3) > 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 > 0, 2 BETWEEN 1 AND (3 > 0), (2 BETWEEN 1 AND 3) > 0 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 != 3, 2 BETWEEN 1 AND (3 != 3), (2 BETWEEN 1 AND 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 != 3, 2 BETWEEN 1 AND (3 != 3), (2 BETWEEN 1 AND 3) != 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 LIKE 1, 2 BETWEEN 1 AND (3 LIKE 1), (2 BETWEEN 1 AND 3) LIKE 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 LIKE 1, 2 BETWEEN 1 AND (3 LIKE 1), (2 BETWEEN 1 AND 3) LIKE 1 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 REGEXP 1, 2 BETWEEN 1 AND (3 REGEXP 1), (2 BETWEEN 1 AND 3) REGEXP 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 REGEXP 1, 2 BETWEEN 1 AND (3 REGEXP 1), (2 BETWEEN 1 AND 3) REGEXP 1 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 | 3, 2 BETWEEN 1 AND (3 | 3), (2 BETWEEN 1 AND 3) | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 | 3, 2 BETWEEN 1 AND (3 | 3), (2 BETWEEN 1 AND 3) | 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 2 & 2, 2 BETWEEN 1 AND (2 & 2), (2 BETWEEN 1 AND 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 2 & 2, 2 BETWEEN 1 AND (2 & 2), (2 BETWEEN 1 AND 2) & 2 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 << 3, 2 BETWEEN 1 AND (3 << 3), (2 BETWEEN 1 AND 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 << 3, 2 BETWEEN 1 AND (3 << 3), (2 BETWEEN 1 AND 3) << 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 4 >> 1, 2 BETWEEN 1 AND (4 >> 1), (2 BETWEEN 1 AND 4) >> 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 4 >> 1, 2 BETWEEN 1 AND (4 >> 1), (2 BETWEEN 1 AND 4) >> 1 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND '2000-01-01' +INTERVAL 1 DAY, 2 BETWEEN 1 AND ('2000-01-01' +INTERVAL 1 DAY), (2 BETWEEN 1 AND '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND '2000-01-01' +INTERVAL 1 DAY, 2 BETWEEN 1 AND ('2000-01-01' +INTERVAL 1 DAY), (2 BETWEEN 1 AND '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 + 3, 2 BETWEEN 1 AND (3 + 3), (2 BETWEEN 1 AND 3) + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 + 3, 2 BETWEEN 1 AND (3 + 3), (2 BETWEEN 1 AND 3) + 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 - 3, 2 BETWEEN 1 AND (3 - 3), (2 BETWEEN 1 AND 3) - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 - 3, 2 BETWEEN 1 AND (3 - 3), (2 BETWEEN 1 AND 3) - 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 * 3, 2 BETWEEN 1 AND (3 * 3), (2 BETWEEN 1 AND 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 * 3, 2 BETWEEN 1 AND (3 * 3), (2 BETWEEN 1 AND 3) * 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 / 3, 2 BETWEEN 1 AND (3 / 3), (2 BETWEEN 1 AND 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 / 3, 2 BETWEEN 1 AND (3 / 3), (2 BETWEEN 1 AND 3) / 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 4 DIV 2, 2 BETWEEN 1 AND (4 DIV 2), (2 BETWEEN 1 AND 4) DIV 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 4 DIV 2, 2 BETWEEN 1 AND (4 DIV 2), (2 BETWEEN 1 AND 4) DIV 2 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 MOD 3, 2 BETWEEN 1 AND (3 MOD 3), (2 BETWEEN 1 AND 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 MOD 3, 2 BETWEEN 1 AND (3 MOD 3), (2 BETWEEN 1 AND 3) MOD 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 % 3, 2 BETWEEN 1 AND (3 % 3), (2 BETWEEN 1 AND 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 % 3, 2 BETWEEN 1 AND (3 % 3), (2 BETWEEN 1 AND 3) % 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 ^ 3, 2 BETWEEN 1 AND (3 ^ 3), (2 BETWEEN 1 AND 3) ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 ^ 3, 2 BETWEEN 1 AND (3 ^ 3), (2 BETWEEN 1 AND 3) ^ 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 BETWEEN 1 AND 3, 2 BETWEEN 1 AND (3 BETWEEN 1 AND 3), (2 BETWEEN 1 AND 3) BETWEEN 1 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 BETWEEN 1 AND 3, 2 BETWEEN 1 AND (3 BETWEEN 1 AND 3), (2 BETWEEN 1 AND 3) BETWEEN 1 AND 3 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 IS FALSE, 2 LIKE 2 ESCAPE (3 IS FALSE), (2 LIKE 2 ESCAPE 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 IS FALSE, 2 LIKE 2 ESCAPE (3 IS FALSE), (2 LIKE 2 ESCAPE 3) IS FALSE union select * from v1; + +create or replace view v1 as select charset(2 LIKE 1 ESCAPE 3 COLLATE latin1_bin), charset(2 LIKE 1 ESCAPE (3 COLLATE latin1_bin)), charset((2 LIKE 1 ESCAPE 3) COLLATE latin1_bin); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 LIKE 1 ESCAPE 3 COLLATE latin1_bin), charset(2 LIKE 1 ESCAPE (3 COLLATE latin1_bin)), charset((2 LIKE 1 ESCAPE 3) COLLATE latin1_bin) union select * from v1; + +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 IN(0,1), 2 LIKE 1 ESCAPE (3 IN(0,1)), (2 LIKE 1 ESCAPE 3) IN(0,1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 1 ESCAPE 3 IN(0,1), 2 LIKE 1 ESCAPE (3 IN(0,1)), (2 LIKE 1 ESCAPE 3) IN(0,1) union select * from v1; + +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 OR 4, 2 LIKE 1 ESCAPE (3 OR 4), (2 LIKE 1 ESCAPE 3) OR 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 1 ESCAPE 3 OR 4, 2 LIKE 1 ESCAPE (3 OR 4), (2 LIKE 1 ESCAPE 3) OR 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 || 4, 2 LIKE 1 ESCAPE (3 || 4), (2 LIKE 1 ESCAPE 3) || 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 1 ESCAPE 3 || 4, 2 LIKE 1 ESCAPE (3 || 4), (2 LIKE 1 ESCAPE 3) || 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 XOR 4, 2 LIKE 1 ESCAPE (3 XOR 4), (2 LIKE 1 ESCAPE 3) XOR 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 1 ESCAPE 3 XOR 4, 2 LIKE 1 ESCAPE (3 XOR 4), (2 LIKE 1 ESCAPE 3) XOR 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 AND 0, 2 LIKE 2 ESCAPE (3 AND 0), (2 LIKE 2 ESCAPE 3) AND 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 AND 0, 2 LIKE 2 ESCAPE (3 AND 0), (2 LIKE 2 ESCAPE 3) AND 0 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 && 0, 2 LIKE 2 ESCAPE (3 && 0), (2 LIKE 2 ESCAPE 3) && 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 && 0, 2 LIKE 2 ESCAPE (3 && 0), (2 LIKE 2 ESCAPE 3) && 0 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 = 4, 2 LIKE 2 ESCAPE (3 = 4), (2 LIKE 2 ESCAPE 3) = 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 = 4, 2 LIKE 2 ESCAPE (3 = 4), (2 LIKE 2 ESCAPE 3) = 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 <=> 4, 2 LIKE 2 ESCAPE (3 <=> 4), (2 LIKE 2 ESCAPE 3) <=> 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 <=> 4, 2 LIKE 2 ESCAPE (3 <=> 4), (2 LIKE 2 ESCAPE 3) <=> 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 >= 4, 2 LIKE 2 ESCAPE (3 >= 4), (2 LIKE 2 ESCAPE 3) >= 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 >= 4, 2 LIKE 2 ESCAPE (3 >= 4), (2 LIKE 2 ESCAPE 3) >= 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 <= 4, 2 LIKE 1 ESCAPE (3 <= 4), (2 LIKE 1 ESCAPE 3) <= 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 1 ESCAPE 3 <= 4, 2 LIKE 1 ESCAPE (3 <= 4), (2 LIKE 1 ESCAPE 3) <= 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 < 4, 2 LIKE 1 ESCAPE (3 < 4), (2 LIKE 1 ESCAPE 3) < 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 1 ESCAPE 3 < 4, 2 LIKE 1 ESCAPE (3 < 4), (2 LIKE 1 ESCAPE 3) < 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 <> 4, 2 LIKE 1 ESCAPE (3 <> 4), (2 LIKE 1 ESCAPE 3) <> 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 1 ESCAPE 3 <> 4, 2 LIKE 1 ESCAPE (3 <> 4), (2 LIKE 1 ESCAPE 3) <> 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 > 4, 2 LIKE 2 ESCAPE (3 > 4), (2 LIKE 2 ESCAPE 3) > 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 > 4, 2 LIKE 2 ESCAPE (3 > 4), (2 LIKE 2 ESCAPE 3) > 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 != 4, 2 LIKE 1 ESCAPE (3 != 4), (2 LIKE 1 ESCAPE 3) != 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 1 ESCAPE 3 != 4, 2 LIKE 1 ESCAPE (3 != 4), (2 LIKE 1 ESCAPE 3) != 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 LIKE 4, 2 LIKE 2 ESCAPE (3 LIKE 4), (2 LIKE 2 ESCAPE 3) LIKE 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 LIKE 4, 2 LIKE 2 ESCAPE (3 LIKE 4), (2 LIKE 2 ESCAPE 3) LIKE 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 REGEXP 4, 2 LIKE 2 ESCAPE (3 REGEXP 4), (2 LIKE 2 ESCAPE 3) REGEXP 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 REGEXP 4, 2 LIKE 2 ESCAPE (3 REGEXP 4), (2 LIKE 2 ESCAPE 3) REGEXP 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 | 4, 2 LIKE 1 ESCAPE (3 | 4), (2 LIKE 1 ESCAPE 3) | 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 1 ESCAPE 3 | 4, 2 LIKE 1 ESCAPE (3 | 4), (2 LIKE 1 ESCAPE 3) | 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 & 4, 2 LIKE 2 ESCAPE (3 & 4), (2 LIKE 2 ESCAPE 3) & 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 & 4, 2 LIKE 2 ESCAPE (3 & 4), (2 LIKE 2 ESCAPE 3) & 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 1 << 1, 2 LIKE 2 ESCAPE (1 << 1), (2 LIKE 2 ESCAPE 1) << 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 1 << 1, 2 LIKE 2 ESCAPE (1 << 1), (2 LIKE 2 ESCAPE 1) << 1 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 >> 4, 2 LIKE 2 ESCAPE (3 >> 4), (2 LIKE 2 ESCAPE 3) >> 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 >> 4, 2 LIKE 2 ESCAPE (3 >> 4), (2 LIKE 2 ESCAPE 3) >> 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 +INTERVAL 1 DAY, 2 LIKE 1 ESCAPE (3 +INTERVAL 1 DAY), (2 LIKE 1 ESCAPE 3) +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 1 ESCAPE 3 +INTERVAL 1 DAY, 2 LIKE 1 ESCAPE (3 +INTERVAL 1 DAY), (2 LIKE 1 ESCAPE 3) +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 + 4, 2 LIKE 1 ESCAPE (3 + 4), (2 LIKE 1 ESCAPE 3) + 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 1 ESCAPE 3 + 4, 2 LIKE 1 ESCAPE (3 + 4), (2 LIKE 1 ESCAPE 3) + 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 1 - 1, 2 LIKE 2 ESCAPE (1 - 1), (2 LIKE 2 ESCAPE 1) - 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 1 - 1, 2 LIKE 2 ESCAPE (1 - 1), (2 LIKE 2 ESCAPE 1) - 1 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 * 0, 2 LIKE 2 ESCAPE (3 * 0), (2 LIKE 2 ESCAPE 3) * 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 * 0, 2 LIKE 2 ESCAPE (3 * 0), (2 LIKE 2 ESCAPE 3) * 0 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 DIV 3, 2 LIKE 2 ESCAPE (3 DIV 3), (2 LIKE 2 ESCAPE 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 DIV 3, 2 LIKE 2 ESCAPE (3 DIV 3), (2 LIKE 2 ESCAPE 3) DIV 3 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 MOD 1, 2 LIKE 2 ESCAPE (3 MOD 1), (2 LIKE 2 ESCAPE 3) MOD 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 MOD 1, 2 LIKE 2 ESCAPE (3 MOD 1), (2 LIKE 2 ESCAPE 3) MOD 1 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 % 1, 2 LIKE 2 ESCAPE (3 % 1), (2 LIKE 2 ESCAPE 3) % 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 % 1, 2 LIKE 2 ESCAPE (3 % 1), (2 LIKE 2 ESCAPE 3) % 1 union select * from v1; + +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 ^ 4, 2 LIKE 1 ESCAPE (3 ^ 4), (2 LIKE 1 ESCAPE 3) ^ 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 1 ESCAPE 3 ^ 4, 2 LIKE 1 ESCAPE (3 ^ 4), (2 LIKE 1 ESCAPE 3) ^ 4 union select * from v1; + +create or replace view v1 as select 2 LIKE 2 ESCAPE 3 BETWEEN 2 AND 4, 2 LIKE 2 ESCAPE (3 BETWEEN 2 AND 4), (2 LIKE 2 ESCAPE 3) BETWEEN 2 AND 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 2 ESCAPE 3 BETWEEN 2 AND 4, 2 LIKE 2 ESCAPE (3 BETWEEN 2 AND 4), (2 LIKE 2 ESCAPE 3) BETWEEN 2 AND 4 union select * from v1; + +create or replace view v1 as select NOT 2 IN (SELECT 0 UNION SELECT 2), NOT (2 IN (SELECT 0 UNION SELECT 2)), (NOT 2) IN (SELECT 0 UNION SELECT 2); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 IN (SELECT 0 UNION SELECT 2), NOT (2 IN (SELECT 0 UNION SELECT 2)), (NOT 2) IN (SELECT 0 UNION SELECT 2) union select * from v1; + +create or replace view v1 as select - 2 IN (SELECT 2 UNION SELECT 1), - (2 IN (SELECT 2 UNION SELECT 1)), (- 2) IN (SELECT 2 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - 2 IN (SELECT 2 UNION SELECT 1), - (2 IN (SELECT 2 UNION SELECT 1)), (- 2) IN (SELECT 2 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select ~ 2 IN (SELECT 0 UNION SELECT 1), ~ (2 IN (SELECT 0 UNION SELECT 1)), (~ 2) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 IN (SELECT 0 UNION SELECT 1), ~ (2 IN (SELECT 0 UNION SELECT 1)), (~ 2) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select ! 2 IN (SELECT 0 UNION SELECT 2), ! (2 IN (SELECT 0 UNION SELECT 2)), (! 2) IN (SELECT 0 UNION SELECT 2); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 IN (SELECT 0 UNION SELECT 2), ! (2 IN (SELECT 0 UNION SELECT 2)), (! 2) IN (SELECT 0 UNION SELECT 2) union select * from v1; + +create or replace view v1 as select BINARY 'c' IN (SELECT 'C' UNION SELECT 'X'), BINARY ('c' IN (SELECT 'C' UNION SELECT 'X')), (BINARY 'c') IN (SELECT 'C' UNION SELECT 'X'); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select BINARY 'c' IN (SELECT 'C' UNION SELECT 'X'), BINARY ('c' IN (SELECT 'C' UNION SELECT 'X')), (BINARY 'c') IN (SELECT 'C' UNION SELECT 'X') union select * from v1; + +create or replace view v1 as select 0 OR 3 IN (SELECT 3 UNION SELECT 10), 0 OR (3 IN (SELECT 3 UNION SELECT 10)), (0 OR 3) IN (SELECT 3 UNION SELECT 10); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 OR 3 IN (SELECT 3 UNION SELECT 10), 0 OR (3 IN (SELECT 3 UNION SELECT 10)), (0 OR 3) IN (SELECT 3 UNION SELECT 10) union select * from v1; + +create or replace view v1 as select 0 || 3 IN (SELECT 3 UNION SELECT 10), 0 || (3 IN (SELECT 3 UNION SELECT 10)), (0 || 3) IN (SELECT 3 UNION SELECT 10); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 || 3 IN (SELECT 3 UNION SELECT 10), 0 || (3 IN (SELECT 3 UNION SELECT 10)), (0 || 3) IN (SELECT 3 UNION SELECT 10) union select * from v1; + +create or replace view v1 as select 2 XOR 3 IN (SELECT 4 UNION SELECT 5), 2 XOR (3 IN (SELECT 4 UNION SELECT 5)), (2 XOR 3) IN (SELECT 4 UNION SELECT 5); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 3 IN (SELECT 4 UNION SELECT 5), 2 XOR (3 IN (SELECT 4 UNION SELECT 5)), (2 XOR 3) IN (SELECT 4 UNION SELECT 5) union select * from v1; + +create or replace view v1 as select 2 AND 3 IN (SELECT 0 UNION SELECT 1), 2 AND (3 IN (SELECT 0 UNION SELECT 1)), (2 AND 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 AND 3 IN (SELECT 0 UNION SELECT 1), 2 AND (3 IN (SELECT 0 UNION SELECT 1)), (2 AND 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 && 3 IN (SELECT 0 UNION SELECT 1), 2 && (3 IN (SELECT 0 UNION SELECT 1)), (2 && 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 && 3 IN (SELECT 0 UNION SELECT 1), 2 && (3 IN (SELECT 0 UNION SELECT 1)), (2 && 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 = 3 IN (SELECT 0 UNION SELECT 1), 2 = (3 IN (SELECT 0 UNION SELECT 1)), (2 = 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 IN (SELECT 0 UNION SELECT 1), 2 = (3 IN (SELECT 0 UNION SELECT 1)), (2 = 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 <=> 3 IN (SELECT 0 UNION SELECT 1), 2 <=> (3 IN (SELECT 0 UNION SELECT 1)), (2 <=> 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 IN (SELECT 0 UNION SELECT 1), 2 <=> (3 IN (SELECT 0 UNION SELECT 1)), (2 <=> 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 >= 3 IN (SELECT 1 UNION SELECT 1), 2 >= (3 IN (SELECT 1 UNION SELECT 1)), (2 >= 3) IN (SELECT 1 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 IN (SELECT 1 UNION SELECT 1), 2 >= (3 IN (SELECT 1 UNION SELECT 1)), (2 >= 3) IN (SELECT 1 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 <= 3 IN (SELECT 0 UNION SELECT 1), 2 <= (3 IN (SELECT 0 UNION SELECT 1)), (2 <= 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 IN (SELECT 0 UNION SELECT 1), 2 <= (3 IN (SELECT 0 UNION SELECT 1)), (2 <= 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 < 3 IN (SELECT 0 UNION SELECT 1), 2 < (3 IN (SELECT 0 UNION SELECT 1)), (2 < 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 IN (SELECT 0 UNION SELECT 1), 2 < (3 IN (SELECT 0 UNION SELECT 1)), (2 < 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 <> 3 IN (SELECT 0 UNION SELECT 0), 2 <> (3 IN (SELECT 0 UNION SELECT 0)), (2 <> 3) IN (SELECT 0 UNION SELECT 0); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <> 3 IN (SELECT 0 UNION SELECT 0), 2 <> (3 IN (SELECT 0 UNION SELECT 0)), (2 <> 3) IN (SELECT 0 UNION SELECT 0) union select * from v1; + +create or replace view v1 as select 2 > 3 IN (SELECT 1 UNION SELECT 1), 2 > (3 IN (SELECT 1 UNION SELECT 1)), (2 > 3) IN (SELECT 1 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 > 3 IN (SELECT 1 UNION SELECT 1), 2 > (3 IN (SELECT 1 UNION SELECT 1)), (2 > 3) IN (SELECT 1 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 != 3 IN (SELECT 0 UNION SELECT 0), 2 != (3 IN (SELECT 0 UNION SELECT 0)), (2 != 3) IN (SELECT 0 UNION SELECT 0); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 != 3 IN (SELECT 0 UNION SELECT 0), 2 != (3 IN (SELECT 0 UNION SELECT 0)), (2 != 3) IN (SELECT 0 UNION SELECT 0) union select * from v1; + +create or replace view v1 as select 2 LIKE 3 IN (SELECT 0 UNION SELECT 1), 2 LIKE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIKE 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 3 IN (SELECT 0 UNION SELECT 1), 2 LIKE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIKE 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 REGEXP 3 IN (SELECT 0 UNION SELECT 1), 2 REGEXP (3 IN (SELECT 0 UNION SELECT 1)), (2 REGEXP 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 3 IN (SELECT 0 UNION SELECT 1), 2 REGEXP (3 IN (SELECT 0 UNION SELECT 1)), (2 REGEXP 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 | 3 IN (SELECT 0 UNION SELECT 1), 2 | (3 IN (SELECT 0 UNION SELECT 1)), (2 | 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 IN (SELECT 0 UNION SELECT 1), 2 | (3 IN (SELECT 0 UNION SELECT 1)), (2 | 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 & 4 IN (SELECT 0 UNION SELECT 1), 2 & (4 IN (SELECT 0 UNION SELECT 1)), (2 & 4) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 4 IN (SELECT 0 UNION SELECT 1), 2 & (4 IN (SELECT 0 UNION SELECT 1)), (2 & 4) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 << 3 IN (SELECT 0 UNION SELECT 1), 2 << (3 IN (SELECT 0 UNION SELECT 1)), (2 << 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 IN (SELECT 0 UNION SELECT 1), 2 << (3 IN (SELECT 0 UNION SELECT 1)), (2 << 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 >> 3 IN (SELECT 0 UNION SELECT 1), 2 >> (3 IN (SELECT 0 UNION SELECT 1)), (2 >> 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 IN (SELECT 0 UNION SELECT 1), 2 >> (3 IN (SELECT 0 UNION SELECT 1)), (2 >> 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 + 3 IN (SELECT 0 UNION SELECT 1), 2 + (3 IN (SELECT 0 UNION SELECT 1)), (2 + 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 IN (SELECT 0 UNION SELECT 1), 2 + (3 IN (SELECT 0 UNION SELECT 1)), (2 + 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 - 3 IN (SELECT 0 UNION SELECT 1), 2 - (3 IN (SELECT 0 UNION SELECT 1)), (2 - 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 3 IN (SELECT 0 UNION SELECT 1), 2 - (3 IN (SELECT 0 UNION SELECT 1)), (2 - 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 * 0 IN (SELECT 0 UNION SELECT 1), 2 * (0 IN (SELECT 0 UNION SELECT 1)), (2 * 0) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 0 IN (SELECT 0 UNION SELECT 1), 2 * (0 IN (SELECT 0 UNION SELECT 1)), (2 * 0) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 / 3 IN (SELECT 0 UNION SELECT 1), 2 / (3 IN (SELECT 0 UNION SELECT 1)), (2 / 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 IN (SELECT 0 UNION SELECT 1), 2 / (3 IN (SELECT 0 UNION SELECT 1)), (2 / 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 DIV 3 IN (SELECT 0 UNION SELECT 1), 2 DIV (3 IN (SELECT 0 UNION SELECT 1)), (2 DIV 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 IN (SELECT 0 UNION SELECT 1), 2 DIV (3 IN (SELECT 0 UNION SELECT 1)), (2 DIV 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 MOD 3 IN (SELECT 0 UNION SELECT 1), 2 MOD (3 IN (SELECT 0 UNION SELECT 1)), (2 MOD 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 IN (SELECT 0 UNION SELECT 1), 2 MOD (3 IN (SELECT 0 UNION SELECT 1)), (2 MOD 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 % 3 IN (SELECT 0 UNION SELECT 1), 2 % (3 IN (SELECT 0 UNION SELECT 1)), (2 % 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 IN (SELECT 0 UNION SELECT 1), 2 % (3 IN (SELECT 0 UNION SELECT 1)), (2 % 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 ^ 3 IN (SELECT 0 UNION SELECT 1), 2 ^ (3 IN (SELECT 0 UNION SELECT 1)), (2 ^ 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 IN (SELECT 0 UNION SELECT 1), 2 ^ (3 IN (SELECT 0 UNION SELECT 1)), (2 ^ 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 IN (SELECT 0 UNION SELECT 1), 2 BETWEEN 1 AND (3 IN (SELECT 0 UNION SELECT 1)), (2 BETWEEN 1 AND 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 IN (SELECT 0 UNION SELECT 1), 2 BETWEEN 1 AND (3 IN (SELECT 0 UNION SELECT 1)), (2 BETWEEN 1 AND 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 2 LIKE 1 ESCAPE 3 IN (SELECT 0 UNION SELECT 1), 2 LIKE 1 ESCAPE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIKE 1 ESCAPE 3) IN (SELECT 0 UNION SELECT 1); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 1 ESCAPE 3 IN (SELECT 0 UNION SELECT 1), 2 LIKE 1 ESCAPE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIKE 1 ESCAPE 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; + +create or replace view v1 as select 3 BETWEEN 1 AND 2 AND NULL, 3 BETWEEN (1 AND 2) AND NULL, 3 BETWEEN 1 AND (2 AND NULL), (3 BETWEEN 1 AND 2) AND NULL; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 3 BETWEEN 1 AND 2 AND NULL, 3 BETWEEN (1 AND 2) AND NULL, 3 BETWEEN 1 AND (2 AND NULL), (3 BETWEEN 1 AND 2) AND NULL union select * from v1; + +set sql_mode=PIPES_AS_CONCAT; +create or replace view v1 as select 2 OR 3 || 3, 2 OR (3 || 3), (2 OR 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 OR 3 || 3, 2 OR (3 || 3), (2 OR 3) || 3 union select * from v1; + +create or replace view v1 as select 2 || 3 OR 3, 2 || (3 OR 3), (2 || 3) OR 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 OR 3, 2 || (3 OR 3), (2 || 3) OR 3 union select * from v1; + +create or replace view v1 as select NOT 2 || 3, NOT (2 || 3), (NOT 2) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select NOT 2 || 3, NOT (2 || 3), (NOT 2) || 3 union select * from v1; + +create or replace view v1 as select - '2 ' || 3, - ('2 ' || 3), (- '2 ') || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select - '2 ' || 3, - ('2 ' || 3), (- '2 ') || 3 union select * from v1; + +create or replace view v1 as select ~ 2 || 3, ~ (2 || 3), (~ 2) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ~ 2 || 3, ~ (2 || 3), (~ 2) || 3 union select * from v1; + +create or replace view v1 as select ! 2 || 3, ! (2 || 3), (! 2) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select ! 2 || 3, ! (2 || 3), (! 2) || 3 union select * from v1; + +create or replace view v1 as select 2 || 3 IS FALSE, 2 || (3 IS FALSE), (2 || 3) IS FALSE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 IS FALSE, 2 || (3 IS FALSE), (2 || 3) IS FALSE union select * from v1; + +create or replace view v1 as select 0 || 3 IN (3,10), 0 || (3 IN (3,10)), (0 || 3) IN (3,10); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 || 3 IN (3,10), 0 || (3 IN (3,10)), (0 || 3) IN (3,10) union select * from v1; + +create or replace view v1 as select 1 || 0 XOR 1, 1 || (0 XOR 1), (1 || 0) XOR 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 || 0 XOR 1, 1 || (0 XOR 1), (1 || 0) XOR 1 union select * from v1; + +create or replace view v1 as select 1 || 1 AND 0, 1 || (1 AND 0), (1 || 1) AND 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 || 1 AND 0, 1 || (1 AND 0), (1 || 1) AND 0 union select * from v1; + +create or replace view v1 as select 1 || 1 && 0, 1 || (1 && 0), (1 || 1) && 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 || 1 && 0, 1 || (1 && 0), (1 || 1) && 0 union select * from v1; + +create or replace view v1 as select 2 || 3 = 3, 2 || (3 = 3), (2 || 3) = 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 = 3, 2 || (3 = 3), (2 || 3) = 3 union select * from v1; + +create or replace view v1 as select 2 || 3 <=> 3, 2 || (3 <=> 3), (2 || 3) <=> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 <=> 3, 2 || (3 <=> 3), (2 || 3) <=> 3 union select * from v1; + +create or replace view v1 as select 2 || 3 >= 3, 2 || (3 >= 3), (2 || 3) >= 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 >= 3, 2 || (3 >= 3), (2 || 3) >= 3 union select * from v1; + +create or replace view v1 as select 2 || 3 <= 0, 2 || (3 <= 0), (2 || 3) <= 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 <= 0, 2 || (3 <= 0), (2 || 3) <= 0 union select * from v1; + +create or replace view v1 as select 2 || 3 < 0, 2 || (3 < 0), (2 || 3) < 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 < 0, 2 || (3 < 0), (2 || 3) < 0 union select * from v1; + +create or replace view v1 as select 0 || 3 <> 3, 0 || (3 <> 3), (0 || 3) <> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 || 3 <> 3, 0 || (3 <> 3), (0 || 3) <> 3 union select * from v1; + +create or replace view v1 as select 2 || 3 > 3, 2 || (3 > 3), (2 || 3) > 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 > 3, 2 || (3 > 3), (2 || 3) > 3 union select * from v1; + +create or replace view v1 as select 0 || 3 != 3, 0 || (3 != 3), (0 || 3) != 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 || 3 != 3, 0 || (3 != 3), (0 || 3) != 3 union select * from v1; + +create or replace view v1 as select 2 || 3 LIKE 3, 2 || (3 LIKE 3), (2 || 3) LIKE 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 LIKE 3, 2 || (3 LIKE 3), (2 || 3) LIKE 3 union select * from v1; + +create or replace view v1 as select 2 || 3 REGEXP 3, 2 || (3 REGEXP 3), (2 || 3) REGEXP 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 REGEXP 3, 2 || (3 REGEXP 3), (2 || 3) REGEXP 3 union select * from v1; + +create or replace view v1 as select 2 || ' 3' | 3, 2 || (' 3' | 3), (2 || ' 3') | 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || ' 3' | 3, 2 || (' 3' | 3), (2 || ' 3') | 3 union select * from v1; + +create or replace view v1 as select 0 || 2 & 2, 0 || (2 & 2), (0 || 2) & 2; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 || 2 & 2, 0 || (2 & 2), (0 || 2) & 2 union select * from v1; + +create or replace view v1 as select 2 || 3 << 3, 2 || (3 << 3), (2 || 3) << 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 << 3, 2 || (3 << 3), (2 || 3) << 3 union select * from v1; + +create or replace view v1 as select 2 || 3 >> 3, 2 || (3 >> 3), (2 || 3) >> 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 >> 3, 2 || (3 >> 3), (2 || 3) >> 3 union select * from v1; + +create or replace view v1 as select 2 || '2000-01-01' +INTERVAL 1 DAY, 2 || ('2000-01-01' +INTERVAL 1 DAY), (2 || '2000-01-01') +INTERVAL 1 DAY; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || '2000-01-01' +INTERVAL 1 DAY, 2 || ('2000-01-01' +INTERVAL 1 DAY), (2 || '2000-01-01') +INTERVAL 1 DAY union select * from v1; + +create or replace view v1 as select 2 || ' 3' + 3, 2 || (' 3' + 3), (2 || ' 3') + 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || ' 3' + 3, 2 || (' 3' + 3), (2 || ' 3') + 3 union select * from v1; + +create or replace view v1 as select 2 || ' 3' - 3, 2 || (' 3' - 3), (2 || ' 3') - 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || ' 3' - 3, 2 || (' 3' - 3), (2 || ' 3') - 3 union select * from v1; + +create or replace view v1 as select 2 || 3 * 3, 2 || (3 * 3), (2 || 3) * 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 * 3, 2 || (3 * 3), (2 || 3) * 3 union select * from v1; + +create or replace view v1 as select 2 || 3 / 3, 2 || (3 / 3), (2 || 3) / 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 / 3, 2 || (3 / 3), (2 || 3) / 3 union select * from v1; + +create or replace view v1 as select 2 || 3 DIV 3, 2 || (3 DIV 3), (2 || 3) DIV 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 DIV 3, 2 || (3 DIV 3), (2 || 3) DIV 3 union select * from v1; + +create or replace view v1 as select 0 || 3 MOD 3, 0 || (3 MOD 3), (0 || 3) MOD 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 || 3 MOD 3, 0 || (3 MOD 3), (0 || 3) MOD 3 union select * from v1; + +create or replace view v1 as select 0 || 3 % 3, 0 || (3 % 3), (0 || 3) % 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 || 3 % 3, 0 || (3 % 3), (0 || 3) % 3 union select * from v1; + +create or replace view v1 as select 2 || ' 3' ^ 3, 2 || (' 3' ^ 3), (2 || ' 3') ^ 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || ' 3' ^ 3, 2 || (' 3' ^ 3), (2 || ' 3') ^ 3 union select * from v1; + +create or replace view v1 as select 2 || 3 BETWEEN 2 AND 3, 2 || (3 BETWEEN 2 AND 3), (2 || 3) BETWEEN 2 AND 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 || 3 BETWEEN 2 AND 3, 2 || (3 BETWEEN 2 AND 3), (2 || 3) BETWEEN 2 AND 3 union select * from v1; + +create or replace view v1 as select 2 XOR 3 || 3, 2 XOR (3 || 3), (2 XOR 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 XOR 3 || 3, 2 XOR (3 || 3), (2 XOR 3) || 3 union select * from v1; + +create or replace view v1 as select 0 AND 3 || 3, 0 AND (3 || 3), (0 AND 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 AND 3 || 3, 0 AND (3 || 3), (0 AND 3) || 3 union select * from v1; + +create or replace view v1 as select 0 && 3 || 3, 0 && (3 || 3), (0 && 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 && 3 || 3, 0 && (3 || 3), (0 && 3) || 3 union select * from v1; + +create or replace view v1 as select 2 = 3 || 3, 2 = (3 || 3), (2 = 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 = 3 || 3, 2 = (3 || 3), (2 = 3) || 3 union select * from v1; + +create or replace view v1 as select 2 <=> 3 || 3, 2 <=> (3 || 3), (2 <=> 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <=> 3 || 3, 2 <=> (3 || 3), (2 <=> 3) || 3 union select * from v1; + +create or replace view v1 as select 2 >= 3 || 0, 2 >= (3 || 0), (2 >= 3) || 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >= 3 || 0, 2 >= (3 || 0), (2 >= 3) || 0 union select * from v1; + +create or replace view v1 as select 2 <= 3 || 3, 2 <= (3 || 3), (2 <= 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 <= 3 || 3, 2 <= (3 || 3), (2 <= 3) || 3 union select * from v1; + +create or replace view v1 as select 2 < 3 || 3, 2 < (3 || 3), (2 < 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 < 3 || 3, 2 < (3 || 3), (2 < 3) || 3 union select * from v1; + +create or replace view v1 as select 1 <> 3 || 3, 1 <> (3 || 3), (1 <> 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 <> 3 || 3, 1 <> (3 || 3), (1 <> 3) || 3 union select * from v1; + +create or replace view v1 as select 0 > 3 || 3, 0 > (3 || 3), (0 > 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 0 > 3 || 3, 0 > (3 || 3), (0 > 3) || 3 union select * from v1; + +create or replace view v1 as select 1 != 3 || 3, 1 != (3 || 3), (1 != 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 1 != 3 || 3, 1 != (3 || 3), (1 != 3) || 3 union select * from v1; + +create or replace view v1 as select 2 LIKE 3 || 3, 2 LIKE (3 || 3), (2 LIKE 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 LIKE 3 || 3, 2 LIKE (3 || 3), (2 LIKE 3) || 3 union select * from v1; + +create or replace view v1 as select 2 REGEXP 3 || 3, 2 REGEXP (3 || 3), (2 REGEXP 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 REGEXP 3 || 3, 2 REGEXP (3 || 3), (2 REGEXP 3) || 3 union select * from v1; + +create or replace view v1 as select 2 | 3 || 3, 2 | (3 || 3), (2 | 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 | 3 || 3, 2 | (3 || 3), (2 | 3) || 3 union select * from v1; + +create or replace view v1 as select 2 & 3 || 3, 2 & (3 || 3), (2 & 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 & 3 || 3, 2 & (3 || 3), (2 & 3) || 3 union select * from v1; + +create or replace view v1 as select 2 << 3 || 3, 2 << (3 || 3), (2 << 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 << 3 || 3, 2 << (3 || 3), (2 << 3) || 3 union select * from v1; + +create or replace view v1 as select 2 >> 3 || 0, 2 >> (3 || 0), (2 >> 3) || 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 >> 3 || 0, 2 >> (3 || 0), (2 >> 3) || 0 union select * from v1; + +create or replace view v1 as select 2 + 3 || 3, 2 + (3 || 3), (2 + 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 + 3 || 3, 2 + (3 || 3), (2 + 3) || 3 union select * from v1; + +create or replace view v1 as select 2 - 2 || 0, 2 - (2 || 0), (2 - 2) || 0; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 - 2 || 0, 2 - (2 || 0), (2 - 2) || 0 union select * from v1; + +create or replace view v1 as select 2 * 3 || 3, 2 * (3 || 3), (2 * 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 * 3 || 3, 2 * (3 || 3), (2 * 3) || 3 union select * from v1; + +create or replace view v1 as select 2 / 3 || 3, 2 / (3 || 3), (2 / 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 / 3 || 3, 2 / (3 || 3), (2 / 3) || 3 union select * from v1; + +create or replace view v1 as select 2 DIV 3 || 3, 2 DIV (3 || 3), (2 DIV 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 DIV 3 || 3, 2 DIV (3 || 3), (2 DIV 3) || 3 union select * from v1; + +create or replace view v1 as select 2 MOD 3 || 3, 2 MOD (3 || 3), (2 MOD 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 MOD 3 || 3, 2 MOD (3 || 3), (2 MOD 3) || 3 union select * from v1; + +create or replace view v1 as select 2 % 3 || 3, 2 % (3 || 3), (2 % 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 % 3 || 3, 2 % (3 || 3), (2 % 3) || 3 union select * from v1; + +create or replace view v1 as select 2 ^ 3 || 3, 2 ^ (3 || 3), (2 ^ 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 ^ 3 || 3, 2 ^ (3 || 3), (2 ^ 3) || 3 union select * from v1; + +create or replace view v1 as select 2 BETWEEN 1 AND 3 || 3, 2 BETWEEN 1 AND (3 || 3), (2 BETWEEN 1 AND 3) || 3; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select 2 BETWEEN 1 AND 3 || 3, 2 BETWEEN 1 AND (3 || 3), (2 BETWEEN 1 AND 3) || 3 union select * from v1; + +create or replace view v1 as select charset(2 LIKE 1 ESCAPE 3 || ''), charset(2 LIKE 1 ESCAPE (3 || '')), charset((2 LIKE 1 ESCAPE 3) || ''); +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +select charset(2 LIKE 1 ESCAPE 3 || ''), charset(2 LIKE 1 ESCAPE (3 || '')), charset((2 LIKE 1 ESCAPE 3) || '') union select * from v1; + +# not precedence tests as such, but still tests of Item::print, parentheses and enum precedence + +create or replace view v1 as select ! - 1, - ! 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; + +create or replace view v1 as select ! BINARY 1, BINARY ! 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; + +create or replace view v1 as select ! NOT 1, NOT ! 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; + +create or replace view v1 as select ! ~ 1, ~ ! 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; + +create or replace view v1 as select - BINARY 1, BINARY - 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; + +create or replace view v1 as select - NOT 1, NOT - 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; + +create or replace view v1 as select - ~ 1, ~ - 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; + +create or replace view v1 as select BINARY NOT 1, NOT BINARY 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; + +create or replace view v1 as select BINARY ~ 1, ~ BINARY 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; + +create or replace view v1 as select NOT ~ 1, ~ NOT 1; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; + +create or replace view v1 as select 1 IS TRUE IS FALSE, 2 IS FALSE IS UNKNOWN, 3 IS UNKNOWN IS NULL, 4 IS NULL IS TRUE; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; + +drop view v1; From 8c83e6eadf496267762313d577653d56bf98d945 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 16 Oct 2020 14:32:14 +0200 Subject: [PATCH 212/323] cleanup: remove redundant ADDINTERVAL_PRECEDENCE expression between INTERVAL and the unit doesns not need any precedence rules, there's no ambiguity there --- sql/item.h | 3 +-- sql/item_timefunc.cc | 4 ++-- sql/item_timefunc.h | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/sql/item.h b/sql/item.h index 6c48d570203..604f656aa7a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -87,7 +87,7 @@ enum precedence { BITOR_PRECEDENCE, // | BITAND_PRECEDENCE, // & SHIFT_PRECEDENCE, // <<, >> - ADDINTERVAL_PRECEDENCE, // first argument in +INTERVAL + INTERVAL_PRECEDENCE, // first argument in +INTERVAL ADD_PRECEDENCE, // +, - MUL_PRECEDENCE, // *, /, DIV, %, MOD BITXOR_PRECEDENCE, // ^ @@ -95,7 +95,6 @@ enum precedence { NEG_PRECEDENCE, // unary -, ~ BANG_PRECEDENCE, // !, NOT (if HIGH_NOT_PRECEDENCE) COLLATE_PRECEDENCE, // BINARY, COLLATE - INTERVAL_PRECEDENCE, // INTERVAL DEFAULT_PRECEDENCE, HIGHEST_PRECEDENCE }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 194933a4c54..a40c2e18b91 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2250,9 +2250,9 @@ static const char *interval_names[]= void Item_date_add_interval::print(String *str, enum_query_type query_type) { - args[0]->print_parenthesised(str, query_type, ADDINTERVAL_PRECEDENCE); + args[0]->print_parenthesised(str, query_type, INTERVAL_PRECEDENCE); str->append(date_sub_interval?" - interval ":" + interval "); - args[1]->print_parenthesised(str, query_type, INTERVAL_PRECEDENCE); + args[1]->print(str, query_type); str->append(' '); str->append(interval_names[int_type]); } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index f25fe3a551f..5c2c2ebe1ac 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -942,7 +942,7 @@ public: bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); bool eq(const Item *item, bool binary_cmp) const; void print(String *str, enum_query_type query_type); - enum precedence precedence() const { return ADDINTERVAL_PRECEDENCE; } + enum precedence precedence() const { return INTERVAL_PRECEDENCE; } bool need_parentheses_in_default() { return true; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } From 7f974e5ad3317168f174465dc61c0feb27c04162 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 16 Oct 2020 15:07:34 +0200 Subject: [PATCH 213/323] cleanup: remove redundant BANG_PRECEDENCE prefix unary operators don't need to have different precedence, the syntax unambiguously specifies in what order they apply --- mysql-test/r/precedence.result | 2 +- sql/item.h | 3 +-- sql/item_cmpfunc.h | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/precedence.result b/mysql-test/r/precedence.result index be07af1c550..2a797467758 100644 --- a/mysql-test/r/precedence.result +++ b/mysql-test/r/precedence.result @@ -8068,7 +8068,7 @@ select !cast(1 as char charset binary) AS `! BINARY 1`,cast(!1 as char charset b create or replace view v1 as select ! ~ 1, ~ ! 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select !(~1) AS `! ~ 1`,~!1 AS `~ ! 1` +select !~1 AS `! ~ 1`,~!1 AS `~ ! 1` create or replace view v1 as select - BINARY 1, BINARY - 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition diff --git a/sql/item.h b/sql/item.h index 604f656aa7a..b789f703c2e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -92,8 +92,7 @@ enum precedence { MUL_PRECEDENCE, // *, /, DIV, %, MOD BITXOR_PRECEDENCE, // ^ PIPES_PRECEDENCE, // || (if PIPES_AS_CONCAT) - NEG_PRECEDENCE, // unary -, ~ - BANG_PRECEDENCE, // !, NOT (if HIGH_NOT_PRECEDENCE) + NEG_PRECEDENCE, // unary -, ~, !, NOT (if HIGH_NOT_PRECEDENCE) COLLATE_PRECEDENCE, // BINARY, COLLATE DEFAULT_PRECEDENCE, HIGHEST_PRECEDENCE diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index cad179dff74..579b1bde1ce 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -574,7 +574,7 @@ public: longlong val_int(); enum Functype functype() const { return NOT_FUNC; } const char *func_name() const { return "not"; } - enum precedence precedence() const { return BANG_PRECEDENCE; } + enum precedence precedence() const { return NEG_PRECEDENCE; } Item *neg_transformer(THD *thd); bool fix_fields(THD *, Item **); virtual void print(String *str, enum_query_type query_type); From 05a878c139963d4859ef8f2c974fee5dae56ee51 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 5 Oct 2020 12:50:51 +0200 Subject: [PATCH 214/323] precedence bugfixing fix printing precedence for BETWEEN, LIKE/ESCAPE, REGEXP, IN don't use precedence for printing CASE/WHEN/THEN/ELSE/END fix parsing precedence of BETWEEN, LIKE/ESCAPE, REGEXP, IN support predicate arguments for IN, BETWEEN, SOUNDS LIKE, LIKE/ESCAPE, REGEXP use %nonassoc for unary operators fix parsing of IS TRUE/FALSE/UNKNOWN/NULL remove parser_precedence test as superseded by the precedence test --- mysql-test/r/derived_cond_pushdown.result | 16 +- mysql-test/r/func_test.result | 9 - mysql-test/r/parser.result | 17 + mysql-test/r/parser_precedence.result | 748 ------------------ mysql-test/r/precedence.result | 480 +++++------ .../innodb/r/innodb-virtual-columns.result | 50 +- mysql-test/t/func_test.test | 8 - mysql-test/t/parser.test | 14 + mysql-test/t/parser_precedence.test | 335 -------- sql/item.h | 7 +- sql/item_cmpfunc.cc | 14 +- sql/item_cmpfunc.h | 7 +- sql/item_func.cc | 3 +- sql/item_subselect.cc | 2 +- sql/item_subselect.h | 2 +- sql/sql_yacc.yy | 127 +-- 16 files changed, 349 insertions(+), 1490 deletions(-) delete mode 100644 mysql-test/r/parser_precedence.result delete mode 100644 mysql-test/t/parser_precedence.test diff --git a/mysql-test/r/derived_cond_pushdown.result b/mysql-test/r/derived_cond_pushdown.result index e2c24639cc7..d4e8feff740 100644 --- a/mysql-test/r/derived_cond_pushdown.result +++ b/mysql-test/r/derived_cond_pushdown.result @@ -10052,11 +10052,11 @@ EXPLAIN "access_type": "ALL", "rows": 3, "filtered": 100, - "attached_condition": "case when (tab2.max_a = 1 or tab2.max_a = 2) then 1 else 0 end = 1", + "attached_condition": "case when tab2.max_a = 1 or tab2.max_a = 2 then 1 else 0 end = 1", "materialized": { "query_block": { "select_id": 3, - "having_condition": "case when (max_a = 1 or max_a = 2) then 1 else 0 end = 1", + "having_condition": "case when max_a = 1 or max_a = 2 then 1 else 0 end = 1", "filesort": { "sort_key": "t1.b", "temporary_table": { @@ -10101,11 +10101,11 @@ EXPLAIN "access_type": "ALL", "rows": 3, "filtered": 100, - "attached_condition": "case when (tab2.max_a = 1 or tab2.max_a > 2 and tab2.max_a < 4) then 1 else 0 end = 1", + "attached_condition": "case when tab2.max_a = 1 or tab2.max_a > 2 and tab2.max_a < 4 then 1 else 0 end = 1", "materialized": { "query_block": { "select_id": 3, - "having_condition": "case when (max_a = 1 or max_a > 2 and max_a < 4) then 1 else 0 end = 1", + "having_condition": "case when max_a = 1 or max_a > 2 and max_a < 4 then 1 else 0 end = 1", "filesort": { "sort_key": "t1.b", "temporary_table": { @@ -10150,11 +10150,11 @@ EXPLAIN "access_type": "ALL", "rows": 3, "filtered": 100, - "attached_condition": "case when (tab2.max_a > 1 and (tab2.max_a = 2 or tab2.max_a > 2)) then 1 else 0 end = 1", + "attached_condition": "case when tab2.max_a > 1 and (tab2.max_a = 2 or tab2.max_a > 2) then 1 else 0 end = 1", "materialized": { "query_block": { "select_id": 3, - "having_condition": "case when (max_a > 1 and (max_a = 2 or max_a > 2)) then 1 else 0 end = 1", + "having_condition": "case when max_a > 1 and (max_a = 2 or max_a > 2) then 1 else 0 end = 1", "filesort": { "sort_key": "t1.b", "temporary_table": { @@ -10199,7 +10199,7 @@ EXPLAIN "access_type": "ALL", "rows": 3, "filtered": 100, - "attached_condition": "case when (tab2.b = 2 or tab2.b = 4) then 1 else 0 end = 1", + "attached_condition": "case when tab2.b = 2 or tab2.b = 4 then 1 else 0 end = 1", "materialized": { "query_block": { "select_id": 3, @@ -10211,7 +10211,7 @@ EXPLAIN "access_type": "ALL", "rows": 3, "filtered": 100, - "attached_condition": "case when (t1.b = 2 or t1.b = 4) then 1 else 0 end = 1" + "attached_condition": "case when t1.b = 2 or t1.b = 4 then 1 else 0 end = 1" } } } diff --git a/mysql-test/r/func_test.result b/mysql-test/r/func_test.result index 94cf6d3e6fa..c2a1ea1137d 100644 --- a/mysql-test/r/func_test.result +++ b/mysql-test/r/func_test.result @@ -89,15 +89,6 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select -1 AS `- a` from dual drop table t1; -select 5 between 0 and 10 between 0 and 1,(5 between 0 and 10) between 0 and 1; -5 between 0 and 10 between 0 and 1 (5 between 0 and 10) between 0 and 1 -0 1 -select 1 and 2 between 2 and 10, 2 between 2 and 10 and 1; -1 and 2 between 2 and 10 2 between 2 and 10 and 1 -1 1 -select 1 and 0 or 2, 2 or 1 and 0; -1 and 0 or 2 2 or 1 and 0 -1 1 select _koi8r'a' = _koi8r'A'; _koi8r'a' = _koi8r'A' 1 diff --git a/mysql-test/r/parser.result b/mysql-test/r/parser.result index 45fcca146fe..9ae5b654eed 100644 --- a/mysql-test/r/parser.result +++ b/mysql-test/r/parser.result @@ -1321,3 +1321,20 @@ t1 CREATE TABLE `t1` ( UNIQUE KEY `id` (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +create or replace view v1 as select 1 between (2 between 3 and 4) and 5; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 between 2 between 3 and 4 and 5 AS `1 between (2 between 3 and 4) and 5` +create or replace view v1 as select 1 between (2 in (3,4)) and 5; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 between 2 in (3,4) and 5 AS `1 between (2 in (3,4)) and 5` +create or replace view v1 as select 1 between (2 like 3) and 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 between 2 like 3 and 4 AS `1 between (2 like 3) and 4` +create or replace view v1 as select 1 not between (2 like 3) and 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +view_definition +select 1 not between 2 like 3 and 4 AS `1 not between (2 like 3) and 4` +drop view v1; diff --git a/mysql-test/r/parser_precedence.result b/mysql-test/r/parser_precedence.result deleted file mode 100644 index f23295bd61b..00000000000 --- a/mysql-test/r/parser_precedence.result +++ /dev/null @@ -1,748 +0,0 @@ -drop table if exists t1_30237_bool; -set sql_mode=NO_UNSIGNED_SUBTRACTION; -create table t1_30237_bool(A boolean, B boolean, C boolean); -insert into t1_30237_bool values -(FALSE, FALSE, FALSE), -(FALSE, FALSE, NULL), -(FALSE, FALSE, TRUE), -(FALSE, NULL, FALSE), -(FALSE, NULL, NULL), -(FALSE, NULL, TRUE), -(FALSE, TRUE, FALSE), -(FALSE, TRUE, NULL), -(FALSE, TRUE, TRUE), -(NULL, FALSE, FALSE), -(NULL, FALSE, NULL), -(NULL, FALSE, TRUE), -(NULL, NULL, FALSE), -(NULL, NULL, NULL), -(NULL, NULL, TRUE), -(NULL, TRUE, FALSE), -(NULL, TRUE, NULL), -(NULL, TRUE, TRUE), -(TRUE, FALSE, FALSE), -(TRUE, FALSE, NULL), -(TRUE, FALSE, TRUE), -(TRUE, NULL, FALSE), -(TRUE, NULL, NULL), -(TRUE, NULL, TRUE), -(TRUE, TRUE, FALSE), -(TRUE, TRUE, NULL), -(TRUE, TRUE, TRUE) ; -Testing OR, XOR, AND -select A, B, A OR B, A XOR B, A AND B -from t1_30237_bool where C is null order by A, B; -A B A OR B A XOR B A AND B -NULL NULL NULL NULL NULL -NULL 0 NULL NULL 0 -NULL 1 1 NULL NULL -0 NULL NULL NULL 0 -0 0 0 0 0 -0 1 1 1 0 -1 NULL 1 NULL NULL -1 0 1 1 0 -1 1 1 0 1 -Testing that OR is associative -select A, B, C, (A OR B) OR C, A OR (B OR C), A OR B OR C -from t1_30237_bool order by A, B, C; -A B C (A OR B) OR C A OR (B OR C) A OR B OR C -NULL NULL NULL NULL NULL NULL -NULL NULL 0 NULL NULL NULL -NULL NULL 1 1 1 1 -NULL 0 NULL NULL NULL NULL -NULL 0 0 NULL NULL NULL -NULL 0 1 1 1 1 -NULL 1 NULL 1 1 1 -NULL 1 0 1 1 1 -NULL 1 1 1 1 1 -0 NULL NULL NULL NULL NULL -0 NULL 0 NULL NULL NULL -0 NULL 1 1 1 1 -0 0 NULL NULL NULL NULL -0 0 0 0 0 0 -0 0 1 1 1 1 -0 1 NULL 1 1 1 -0 1 0 1 1 1 -0 1 1 1 1 1 -1 NULL NULL 1 1 1 -1 NULL 0 1 1 1 -1 NULL 1 1 1 1 -1 0 NULL 1 1 1 -1 0 0 1 1 1 -1 0 1 1 1 1 -1 1 NULL 1 1 1 -1 1 0 1 1 1 -1 1 1 1 1 1 -select count(*) from t1_30237_bool -where ((A OR B) OR C) != (A OR (B OR C)); -count(*) -0 -Testing that XOR is associative -select A, B, C, (A XOR B) XOR C, A XOR (B XOR C), A XOR B XOR C -from t1_30237_bool order by A, B, C; -A B C (A XOR B) XOR C A XOR (B XOR C) A XOR B XOR C -NULL NULL NULL NULL NULL NULL -NULL NULL 0 NULL NULL NULL -NULL NULL 1 NULL NULL NULL -NULL 0 NULL NULL NULL NULL -NULL 0 0 NULL NULL NULL -NULL 0 1 NULL NULL NULL -NULL 1 NULL NULL NULL NULL -NULL 1 0 NULL NULL NULL -NULL 1 1 NULL NULL NULL -0 NULL NULL NULL NULL NULL -0 NULL 0 NULL NULL NULL -0 NULL 1 NULL NULL NULL -0 0 NULL NULL NULL NULL -0 0 0 0 0 0 -0 0 1 1 1 1 -0 1 NULL NULL NULL NULL -0 1 0 1 1 1 -0 1 1 0 0 0 -1 NULL NULL NULL NULL NULL -1 NULL 0 NULL NULL NULL -1 NULL 1 NULL NULL NULL -1 0 NULL NULL NULL NULL -1 0 0 1 1 1 -1 0 1 0 0 0 -1 1 NULL NULL NULL NULL -1 1 0 0 0 0 -1 1 1 1 1 1 -select count(*) from t1_30237_bool -where ((A XOR B) XOR C) != (A XOR (B XOR C)); -count(*) -0 -Testing that AND is associative -select A, B, C, (A AND B) AND C, A AND (B AND C), A AND B AND C -from t1_30237_bool order by A, B, C; -A B C (A AND B) AND C A AND (B AND C) A AND B AND C -NULL NULL NULL NULL NULL NULL -NULL NULL 0 0 0 0 -NULL NULL 1 NULL NULL NULL -NULL 0 NULL 0 0 0 -NULL 0 0 0 0 0 -NULL 0 1 0 0 0 -NULL 1 NULL NULL NULL NULL -NULL 1 0 0 0 0 -NULL 1 1 NULL NULL NULL -0 NULL NULL 0 0 0 -0 NULL 0 0 0 0 -0 NULL 1 0 0 0 -0 0 NULL 0 0 0 -0 0 0 0 0 0 -0 0 1 0 0 0 -0 1 NULL 0 0 0 -0 1 0 0 0 0 -0 1 1 0 0 0 -1 NULL NULL NULL NULL NULL -1 NULL 0 0 0 0 -1 NULL 1 NULL NULL NULL -1 0 NULL 0 0 0 -1 0 0 0 0 0 -1 0 1 0 0 0 -1 1 NULL NULL NULL NULL -1 1 0 0 0 0 -1 1 1 1 1 1 -select count(*) from t1_30237_bool -where ((A AND B) AND C) != (A AND (B AND C)); -count(*) -0 -Testing that AND has precedence over OR -select A, B, C, (A OR B) AND C, A OR (B AND C), A OR B AND C -from t1_30237_bool order by A, B, C; -A B C (A OR B) AND C A OR (B AND C) A OR B AND C -NULL NULL NULL NULL NULL NULL -NULL NULL 0 0 NULL NULL -NULL NULL 1 NULL NULL NULL -NULL 0 NULL NULL NULL NULL -NULL 0 0 0 NULL NULL -NULL 0 1 NULL NULL NULL -NULL 1 NULL NULL NULL NULL -NULL 1 0 0 NULL NULL -NULL 1 1 1 1 1 -0 NULL NULL NULL NULL NULL -0 NULL 0 0 0 0 -0 NULL 1 NULL NULL NULL -0 0 NULL 0 0 0 -0 0 0 0 0 0 -0 0 1 0 0 0 -0 1 NULL NULL NULL NULL -0 1 0 0 0 0 -0 1 1 1 1 1 -1 NULL NULL NULL 1 1 -1 NULL 0 0 1 1 -1 NULL 1 1 1 1 -1 0 NULL NULL 1 1 -1 0 0 0 1 1 -1 0 1 1 1 1 -1 1 NULL NULL 1 1 -1 1 0 0 1 1 -1 1 1 1 1 1 -select count(*) from t1_30237_bool -where (A OR (B AND C)) != (A OR B AND C); -count(*) -0 -select A, B, C, (A AND B) OR C, A AND (B OR C), A AND B OR C -from t1_30237_bool order by A, B, C; -A B C (A AND B) OR C A AND (B OR C) A AND B OR C -NULL NULL NULL NULL NULL NULL -NULL NULL 0 NULL NULL NULL -NULL NULL 1 1 NULL 1 -NULL 0 NULL NULL NULL NULL -NULL 0 0 0 0 0 -NULL 0 1 1 NULL 1 -NULL 1 NULL NULL NULL NULL -NULL 1 0 NULL NULL NULL -NULL 1 1 1 NULL 1 -0 NULL NULL NULL 0 NULL -0 NULL 0 0 0 0 -0 NULL 1 1 0 1 -0 0 NULL NULL 0 NULL -0 0 0 0 0 0 -0 0 1 1 0 1 -0 1 NULL NULL 0 NULL -0 1 0 0 0 0 -0 1 1 1 0 1 -1 NULL NULL NULL NULL NULL -1 NULL 0 NULL NULL NULL -1 NULL 1 1 1 1 -1 0 NULL NULL NULL NULL -1 0 0 0 0 0 -1 0 1 1 1 1 -1 1 NULL 1 1 1 -1 1 0 1 1 1 -1 1 1 1 1 1 -select count(*) from t1_30237_bool -where ((A AND B) OR C) != (A AND B OR C); -count(*) -0 -Testing that AND has precedence over XOR -select A, B, C, (A XOR B) AND C, A XOR (B AND C), A XOR B AND C -from t1_30237_bool order by A, B, C; -A B C (A XOR B) AND C A XOR (B AND C) A XOR B AND C -NULL NULL NULL NULL NULL NULL -NULL NULL 0 0 NULL NULL -NULL NULL 1 NULL NULL NULL -NULL 0 NULL NULL NULL NULL -NULL 0 0 0 NULL NULL -NULL 0 1 NULL NULL NULL -NULL 1 NULL NULL NULL NULL -NULL 1 0 0 NULL NULL -NULL 1 1 NULL NULL NULL -0 NULL NULL NULL NULL NULL -0 NULL 0 0 0 0 -0 NULL 1 NULL NULL NULL -0 0 NULL 0 0 0 -0 0 0 0 0 0 -0 0 1 0 0 0 -0 1 NULL NULL NULL NULL -0 1 0 0 0 0 -0 1 1 1 1 1 -1 NULL NULL NULL NULL NULL -1 NULL 0 0 1 1 -1 NULL 1 NULL NULL NULL -1 0 NULL NULL 1 1 -1 0 0 0 1 1 -1 0 1 1 1 1 -1 1 NULL 0 NULL NULL -1 1 0 0 1 1 -1 1 1 0 0 0 -select count(*) from t1_30237_bool -where (A XOR (B AND C)) != (A XOR B AND C); -count(*) -0 -select A, B, C, (A AND B) XOR C, A AND (B XOR C), A AND B XOR C -from t1_30237_bool order by A, B, C; -A B C (A AND B) XOR C A AND (B XOR C) A AND B XOR C -NULL NULL NULL NULL NULL NULL -NULL NULL 0 NULL NULL NULL -NULL NULL 1 NULL NULL NULL -NULL 0 NULL NULL NULL NULL -NULL 0 0 0 0 0 -NULL 0 1 1 NULL 1 -NULL 1 NULL NULL NULL NULL -NULL 1 0 NULL NULL NULL -NULL 1 1 NULL 0 NULL -0 NULL NULL NULL 0 NULL -0 NULL 0 0 0 0 -0 NULL 1 1 0 1 -0 0 NULL NULL 0 NULL -0 0 0 0 0 0 -0 0 1 1 0 1 -0 1 NULL NULL 0 NULL -0 1 0 0 0 0 -0 1 1 1 0 1 -1 NULL NULL NULL NULL NULL -1 NULL 0 NULL NULL NULL -1 NULL 1 NULL NULL NULL -1 0 NULL NULL NULL NULL -1 0 0 0 0 0 -1 0 1 1 1 1 -1 1 NULL NULL NULL NULL -1 1 0 1 1 1 -1 1 1 0 0 0 -select count(*) from t1_30237_bool -where ((A AND B) XOR C) != (A AND B XOR C); -count(*) -0 -Testing that XOR has precedence over OR -select A, B, C, (A XOR B) OR C, A XOR (B OR C), A XOR B OR C -from t1_30237_bool order by A, B, C; -A B C (A XOR B) OR C A XOR (B OR C) A XOR B OR C -NULL NULL NULL NULL NULL NULL -NULL NULL 0 NULL NULL NULL -NULL NULL 1 1 NULL 1 -NULL 0 NULL NULL NULL NULL -NULL 0 0 NULL NULL NULL -NULL 0 1 1 NULL 1 -NULL 1 NULL NULL NULL NULL -NULL 1 0 NULL NULL NULL -NULL 1 1 1 NULL 1 -0 NULL NULL NULL NULL NULL -0 NULL 0 NULL NULL NULL -0 NULL 1 1 1 1 -0 0 NULL NULL NULL NULL -0 0 0 0 0 0 -0 0 1 1 1 1 -0 1 NULL 1 1 1 -0 1 0 1 1 1 -0 1 1 1 1 1 -1 NULL NULL NULL NULL NULL -1 NULL 0 NULL NULL NULL -1 NULL 1 1 0 1 -1 0 NULL 1 NULL 1 -1 0 0 1 1 1 -1 0 1 1 0 1 -1 1 NULL NULL 0 NULL -1 1 0 0 0 0 -1 1 1 1 0 1 -select count(*) from t1_30237_bool -where ((A XOR B) OR C) != (A XOR B OR C); -count(*) -0 -select A, B, C, (A OR B) XOR C, A OR (B XOR C), A OR B XOR C -from t1_30237_bool order by A, B, C; -A B C (A OR B) XOR C A OR (B XOR C) A OR B XOR C -NULL NULL NULL NULL NULL NULL -NULL NULL 0 NULL NULL NULL -NULL NULL 1 NULL NULL NULL -NULL 0 NULL NULL NULL NULL -NULL 0 0 NULL NULL NULL -NULL 0 1 NULL 1 1 -NULL 1 NULL NULL NULL NULL -NULL 1 0 1 1 1 -NULL 1 1 0 NULL NULL -0 NULL NULL NULL NULL NULL -0 NULL 0 NULL NULL NULL -0 NULL 1 NULL NULL NULL -0 0 NULL NULL NULL NULL -0 0 0 0 0 0 -0 0 1 1 1 1 -0 1 NULL NULL NULL NULL -0 1 0 1 1 1 -0 1 1 0 0 0 -1 NULL NULL NULL 1 1 -1 NULL 0 1 1 1 -1 NULL 1 0 1 1 -1 0 NULL NULL 1 1 -1 0 0 1 1 1 -1 0 1 0 1 1 -1 1 NULL NULL 1 1 -1 1 0 1 1 1 -1 1 1 0 1 1 -select count(*) from t1_30237_bool -where (A OR (B XOR C)) != (A OR B XOR C); -count(*) -0 -drop table t1_30237_bool; -Testing that NOT has precedence over OR -select (NOT FALSE) OR TRUE, NOT (FALSE OR TRUE), NOT FALSE OR TRUE; -(NOT FALSE) OR TRUE NOT (FALSE OR TRUE) NOT FALSE OR TRUE -1 0 1 -Testing that NOT has precedence over XOR -select (NOT FALSE) XOR FALSE, NOT (FALSE XOR FALSE), NOT FALSE XOR FALSE; -(NOT FALSE) XOR FALSE NOT (FALSE XOR FALSE) NOT FALSE XOR FALSE -1 1 1 -Testing that NOT has precedence over AND -select (NOT FALSE) AND FALSE, NOT (FALSE AND FALSE), NOT FALSE AND FALSE; -(NOT FALSE) AND FALSE NOT (FALSE AND FALSE) NOT FALSE AND FALSE -0 1 0 -Testing that NOT is associative -select NOT NOT TRUE, NOT NOT NOT FALSE; -NOT NOT TRUE NOT NOT NOT FALSE -1 1 -Testing that IS has precedence over NOT -select (NOT NULL) IS TRUE, NOT (NULL IS TRUE), NOT NULL IS TRUE; -(NOT NULL) IS TRUE NOT (NULL IS TRUE) NOT NULL IS TRUE -0 1 1 -select (NOT NULL) IS NOT TRUE, NOT (NULL IS NOT TRUE), NOT NULL IS NOT TRUE; -(NOT NULL) IS NOT TRUE NOT (NULL IS NOT TRUE) NOT NULL IS NOT TRUE -1 0 0 -select (NOT NULL) IS FALSE, NOT (NULL IS FALSE), NOT NULL IS FALSE; -(NOT NULL) IS FALSE NOT (NULL IS FALSE) NOT NULL IS FALSE -0 1 1 -select (NOT NULL) IS NOT FALSE, NOT (NULL IS NOT FALSE), NOT NULL IS NOT FALSE; -(NOT NULL) IS NOT FALSE NOT (NULL IS NOT FALSE) NOT NULL IS NOT FALSE -1 0 0 -select (NOT TRUE) IS UNKNOWN, NOT (TRUE IS UNKNOWN), NOT TRUE IS UNKNOWN; -(NOT TRUE) IS UNKNOWN NOT (TRUE IS UNKNOWN) NOT TRUE IS UNKNOWN -0 1 1 -select (NOT TRUE) IS NOT UNKNOWN, NOT (TRUE IS NOT UNKNOWN), NOT TRUE IS NOT UNKNOWN; -(NOT TRUE) IS NOT UNKNOWN NOT (TRUE IS NOT UNKNOWN) NOT TRUE IS NOT UNKNOWN -1 0 0 -select (NOT TRUE) IS NULL, NOT (TRUE IS NULL), NOT TRUE IS NULL; -(NOT TRUE) IS NULL NOT (TRUE IS NULL) NOT TRUE IS NULL -0 1 1 -select (NOT TRUE) IS NOT NULL, NOT (TRUE IS NOT NULL), NOT TRUE IS NOT NULL; -(NOT TRUE) IS NOT NULL NOT (TRUE IS NOT NULL) NOT TRUE IS NOT NULL -1 0 0 -Testing that IS [NOT] TRUE/FALSE/UNKNOWN predicates are not associative -select TRUE IS TRUE IS TRUE IS TRUE; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IS TRUE IS TRUE' at line 1 -select FALSE IS NOT TRUE IS NOT TRUE IS NOT TRUE; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IS NOT TRUE IS NOT TRUE' at line 1 -select NULL IS FALSE IS FALSE IS FALSE; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IS FALSE IS FALSE' at line 1 -select TRUE IS NOT FALSE IS NOT FALSE IS NOT FALSE; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IS NOT FALSE IS NOT FALSE' at line 1 -select FALSE IS UNKNOWN IS UNKNOWN IS UNKNOWN; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IS UNKNOWN IS UNKNOWN' at line 1 -select TRUE IS NOT UNKNOWN IS NOT UNKNOWN IS NOT UNKNOWN; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IS NOT UNKNOWN IS NOT UNKNOWN' at line 1 -Testing that IS [NOT] NULL predicates are associative -select FALSE IS NULL IS NULL IS NULL; -FALSE IS NULL IS NULL IS NULL -0 -select TRUE IS NOT NULL IS NOT NULL IS NOT NULL; -TRUE IS NOT NULL IS NOT NULL IS NOT NULL -1 -Testing that comparison operators are left associative -select 1 <=> 2 <=> 2, (1 <=> 2) <=> 2, 1 <=> (2 <=> 2); -1 <=> 2 <=> 2 (1 <=> 2) <=> 2 1 <=> (2 <=> 2) -0 0 1 -select 1 = 2 = 2, (1 = 2) = 2, 1 = (2 = 2); -1 = 2 = 2 (1 = 2) = 2 1 = (2 = 2) -0 0 1 -select 1 != 2 != 3, (1 != 2) != 3, 1 != (2 != 3); -1 != 2 != 3 (1 != 2) != 3 1 != (2 != 3) -1 1 0 -select 1 <> 2 <> 3, (1 <> 2) <> 3, 1 <> (2 <> 3); -1 <> 2 <> 3 (1 <> 2) <> 3 1 <> (2 <> 3) -1 1 0 -select 1 < 2 < 3, (1 < 2) < 3, 1 < (2 < 3); -1 < 2 < 3 (1 < 2) < 3 1 < (2 < 3) -1 1 0 -select 3 <= 2 <= 1, (3 <= 2) <= 1, 3 <= (2 <= 1); -3 <= 2 <= 1 (3 <= 2) <= 1 3 <= (2 <= 1) -1 1 0 -select 1 > 2 > 3, (1 > 2) > 3, 1 > (2 > 3); -1 > 2 > 3 (1 > 2) > 3 1 > (2 > 3) -0 0 1 -select 1 >= 2 >= 3, (1 >= 2) >= 3, 1 >= (2 >= 3); -1 >= 2 >= 3 (1 >= 2) >= 3 1 >= (2 >= 3) -0 0 1 -Testing that | is associative -select 0xF0 | 0x0F | 0x55, (0xF0 | 0x0F) | 0x55, 0xF0 | (0x0F | 0x55); -0xF0 | 0x0F | 0x55 (0xF0 | 0x0F) | 0x55 0xF0 | (0x0F | 0x55) -255 255 255 -Testing that & is associative -select 0xF5 & 0x5F & 0x55, (0xF5 & 0x5F) & 0x55, 0xF5 & (0x5F & 0x55); -0xF5 & 0x5F & 0x55 (0xF5 & 0x5F) & 0x55 0xF5 & (0x5F & 0x55) -85 85 85 -Testing that << is left associative -select 4 << 3 << 2, (4 << 3) << 2, 4 << (3 << 2); -4 << 3 << 2 (4 << 3) << 2 4 << (3 << 2) -128 128 16384 -Testing that >> is left associative -select 256 >> 3 >> 2, (256 >> 3) >> 2, 256 >> (3 >> 2); -256 >> 3 >> 2 (256 >> 3) >> 2 256 >> (3 >> 2) -8 8 256 -Testing that & has precedence over | -select 0xF0 & 0x0F | 0x55, (0xF0 & 0x0F) | 0x55, 0xF0 & (0x0F | 0x55); -0xF0 & 0x0F | 0x55 (0xF0 & 0x0F) | 0x55 0xF0 & (0x0F | 0x55) -85 85 80 -select 0x55 | 0xF0 & 0x0F, (0x55 | 0xF0) & 0x0F, 0x55 | (0xF0 & 0x0F); -0x55 | 0xF0 & 0x0F (0x55 | 0xF0) & 0x0F 0x55 | (0xF0 & 0x0F) -85 5 85 -Testing that << has precedence over | -select 0x0F << 4 | 0x0F, (0x0F << 4) | 0x0F, 0x0F << (4 | 0x0F); -0x0F << 4 | 0x0F (0x0F << 4) | 0x0F 0x0F << (4 | 0x0F) -255 255 491520 -select 0x0F | 0x0F << 4, (0x0F | 0x0F) << 4, 0x0F | (0x0F << 4); -0x0F | 0x0F << 4 (0x0F | 0x0F) << 4 0x0F | (0x0F << 4) -255 240 255 -Testing that >> has precedence over | -select 0xF0 >> 4 | 0xFF, (0xF0 >> 4) | 0xFF, 0xF0 >> (4 | 0xFF); -0xF0 >> 4 | 0xFF (0xF0 >> 4) | 0xFF 0xF0 >> (4 | 0xFF) -255 255 0 -select 0xFF | 0xF0 >> 4, (0xFF | 0xF0) >> 4, 0xFF | (0xF0 >> 4); -0xFF | 0xF0 >> 4 (0xFF | 0xF0) >> 4 0xFF | (0xF0 >> 4) -255 15 255 -Testing that << has precedence over & -select 0x0F << 4 & 0xF0, (0x0F << 4) & 0xF0, 0x0F << (4 & 0xF0); -0x0F << 4 & 0xF0 (0x0F << 4) & 0xF0 0x0F << (4 & 0xF0) -240 240 15 -select 0xF0 & 0x0F << 4, (0xF0 & 0x0F) << 4, 0xF0 & (0x0F << 4); -0xF0 & 0x0F << 4 (0xF0 & 0x0F) << 4 0xF0 & (0x0F << 4) -240 0 240 -Testing that >> has precedence over & -select 0xF0 >> 4 & 0x55, (0xF0 >> 4) & 0x55, 0xF0 >> (4 & 0x55); -0xF0 >> 4 & 0x55 (0xF0 >> 4) & 0x55 0xF0 >> (4 & 0x55) -5 5 15 -select 0x0F & 0xF0 >> 4, (0x0F & 0xF0) >> 4, 0x0F & (0xF0 >> 4); -0x0F & 0xF0 >> 4 (0x0F & 0xF0) >> 4 0x0F & (0xF0 >> 4) -15 0 15 -Testing that >> and << have the same precedence -select 0xFF >> 4 << 2, (0xFF >> 4) << 2, 0xFF >> (4 << 2); -0xFF >> 4 << 2 (0xFF >> 4) << 2 0xFF >> (4 << 2) -60 60 0 -select 0x0F << 4 >> 2, (0x0F << 4) >> 2, 0x0F << (4 >> 2); -0x0F << 4 >> 2 (0x0F << 4) >> 2 0x0F << (4 >> 2) -60 60 30 -Testing that binary + is associative -select 1 + 2 + 3, (1 + 2) + 3, 1 + (2 + 3); -1 + 2 + 3 (1 + 2) + 3 1 + (2 + 3) -6 6 6 -Testing that binary - is left associative -select 1 - 2 - 3, (1 - 2) - 3, 1 - (2 - 3); -1 - 2 - 3 (1 - 2) - 3 1 - (2 - 3) --4 -4 2 -Testing that binary + and binary - have the same precedence -select 1 + 2 - 3, (1 + 2) - 3, 1 + (2 - 3); -1 + 2 - 3 (1 + 2) - 3 1 + (2 - 3) -0 0 0 -select 1 - 2 + 3, (1 - 2) + 3, 1 - (2 + 3); -1 - 2 + 3 (1 - 2) + 3 1 - (2 + 3) -2 2 -4 -Testing that binary + has precedence over | -select 0xF0 + 0x0F | 0x55, (0xF0 + 0x0F) | 0x55, 0xF0 + (0x0F | 0x55); -0xF0 + 0x0F | 0x55 (0xF0 + 0x0F) | 0x55 0xF0 + (0x0F | 0x55) -255 255 335 -select 0x55 | 0xF0 + 0x0F, (0x55 | 0xF0) + 0x0F, 0x55 | (0xF0 + 0x0F); -0x55 | 0xF0 + 0x0F (0x55 | 0xF0) + 0x0F 0x55 | (0xF0 + 0x0F) -255 260 255 -Testing that binary + has precedence over & -select 0xF0 + 0x0F & 0x55, (0xF0 + 0x0F) & 0x55, 0xF0 + (0x0F & 0x55); -0xF0 + 0x0F & 0x55 (0xF0 + 0x0F) & 0x55 0xF0 + (0x0F & 0x55) -85 85 245 -select 0x55 & 0xF0 + 0x0F, (0x55 & 0xF0) + 0x0F, 0x55 & (0xF0 + 0x0F); -0x55 & 0xF0 + 0x0F (0x55 & 0xF0) + 0x0F 0x55 & (0xF0 + 0x0F) -85 95 85 -Testing that binary + has precedence over << -select 2 + 3 << 4, (2 + 3) << 4, 2 + (3 << 4); -2 + 3 << 4 (2 + 3) << 4 2 + (3 << 4) -80 80 50 -select 3 << 4 + 2, (3 << 4) + 2, 3 << (4 + 2); -3 << 4 + 2 (3 << 4) + 2 3 << (4 + 2) -192 50 192 -Testing that binary + has precedence over >> -select 4 + 3 >> 2, (4 + 3) >> 2, 4 + (3 >> 2); -4 + 3 >> 2 (4 + 3) >> 2 4 + (3 >> 2) -1 1 4 -select 3 >> 2 + 1, (3 >> 2) + 1, 3 >> (2 + 1); -3 >> 2 + 1 (3 >> 2) + 1 3 >> (2 + 1) -0 1 0 -Testing that binary - has precedence over | -select 0xFF - 0x0F | 0x55, (0xFF - 0x0F) | 0x55, 0xFF - (0x0F | 0x55); -0xFF - 0x0F | 0x55 (0xFF - 0x0F) | 0x55 0xFF - (0x0F | 0x55) -245 245 160 -select 0x55 | 0xFF - 0xF0, (0x55 | 0xFF) - 0xF0, 0x55 | (0xFF - 0xF0); -0x55 | 0xFF - 0xF0 (0x55 | 0xFF) - 0xF0 0x55 | (0xFF - 0xF0) -95 15 95 -Testing that binary - has precedence over & -select 0xFF - 0xF0 & 0x55, (0xFF - 0xF0) & 0x55, 0xFF - (0xF0 & 0x55); -0xFF - 0xF0 & 0x55 (0xFF - 0xF0) & 0x55 0xFF - (0xF0 & 0x55) -5 5 175 -select 0x55 & 0xFF - 0xF0, (0x55 & 0xFF) - 0xF0, 0x55 & (0xFF - 0xF0); -0x55 & 0xFF - 0xF0 (0x55 & 0xFF) - 0xF0 0x55 & (0xFF - 0xF0) -5 -155 5 -Testing that binary - has precedence over << -select 16 - 3 << 2, (16 - 3) << 2, 16 - (3 << 2); -16 - 3 << 2 (16 - 3) << 2 16 - (3 << 2) -52 52 4 -select 4 << 3 - 2, (4 << 3) - 2, 4 << (3 - 2); -4 << 3 - 2 (4 << 3) - 2 4 << (3 - 2) -8 30 8 -Testing that binary - has precedence over >> -select 16 - 3 >> 2, (16 - 3) >> 2, 16 - (3 >> 2); -16 - 3 >> 2 (16 - 3) >> 2 16 - (3 >> 2) -3 3 16 -select 16 >> 3 - 2, (16 >> 3) - 2, 16 >> (3 - 2); -16 >> 3 - 2 (16 >> 3) - 2 16 >> (3 - 2) -8 0 8 -Testing that * is associative -select 2 * 3 * 4, (2 * 3) * 4, 2 * (3 * 4); -2 * 3 * 4 (2 * 3) * 4 2 * (3 * 4) -24 24 24 -Testing that * has precedence over | -select 2 * 0x40 | 0x0F, (2 * 0x40) | 0x0F, 2 * (0x40 | 0x0F); -2 * 0x40 | 0x0F (2 * 0x40) | 0x0F 2 * (0x40 | 0x0F) -143 143 158 -select 0x0F | 2 * 0x40, (0x0F | 2) * 0x40, 0x0F | (2 * 0x40); -0x0F | 2 * 0x40 (0x0F | 2) * 0x40 0x0F | (2 * 0x40) -143 960 143 -Testing that * has precedence over & -select 2 * 0x40 & 0x55, (2 * 0x40) & 0x55, 2 * (0x40 & 0x55); -2 * 0x40 & 0x55 (2 * 0x40) & 0x55 2 * (0x40 & 0x55) -0 0 128 -select 0xF0 & 2 * 0x40, (0xF0 & 2) * 0x40, 0xF0 & (2 * 0x40); -0xF0 & 2 * 0x40 (0xF0 & 2) * 0x40 0xF0 & (2 * 0x40) -128 0 128 -Testing that * has precedence over << -select 5 * 3 << 4, (5 * 3) << 4, 5 * (3 << 4); -5 * 3 << 4 (5 * 3) << 4 5 * (3 << 4) -240 240 240 -select 2 << 3 * 4, (2 << 3) * 4, 2 << (3 * 4); -2 << 3 * 4 (2 << 3) * 4 2 << (3 * 4) -8192 64 8192 -Testing that * has precedence over >> -select 3 * 4 >> 2, (3 * 4) >> 2, 3 * (4 >> 2); -3 * 4 >> 2 (3 * 4) >> 2 3 * (4 >> 2) -3 3 3 -select 4 >> 2 * 3, (4 >> 2) * 3, 4 >> (2 * 3); -4 >> 2 * 3 (4 >> 2) * 3 4 >> (2 * 3) -0 3 0 -Testing that * has precedence over binary + -select 2 * 3 + 4, (2 * 3) + 4, 2 * (3 + 4); -2 * 3 + 4 (2 * 3) + 4 2 * (3 + 4) -10 10 14 -select 2 + 3 * 4, (2 + 3) * 4, 2 + (3 * 4); -2 + 3 * 4 (2 + 3) * 4 2 + (3 * 4) -14 20 14 -Testing that * has precedence over binary - -select 4 * 3 - 2, (4 * 3) - 2, 4 * (3 - 2); -4 * 3 - 2 (4 * 3) - 2 4 * (3 - 2) -10 10 4 -select 4 - 3 * 2, (4 - 3) * 2, 4 - (3 * 2); -4 - 3 * 2 (4 - 3) * 2 4 - (3 * 2) --2 2 -2 -Testing that / is left associative -select 15 / 5 / 3, (15 / 5) / 3, 15 / (5 / 3); -15 / 5 / 3 (15 / 5) / 3 15 / (5 / 3) -1.00000000 1.00000000 8.9998 -Testing that / has precedence over | -select 105 / 5 | 2, (105 / 5) | 2, 105 / (5 | 2); -105 / 5 | 2 (105 / 5) | 2 105 / (5 | 2) -23 23 15.0000 -select 105 | 2 / 5, (105 | 2) / 5, 105 | (2 / 5); -105 | 2 / 5 (105 | 2) / 5 105 | (2 / 5) -105 21.4000 105 -Testing that / has precedence over & -select 105 / 5 & 0x0F, (105 / 5) & 0x0F, 105 / (5 & 0x0F); -105 / 5 & 0x0F (105 / 5) & 0x0F 105 / (5 & 0x0F) -5 5 21.0000 -select 0x0F & 105 / 5, (0x0F & 105) / 5, 0x0F & (105 / 5); -0x0F & 105 / 5 (0x0F & 105) / 5 0x0F & (105 / 5) -5 1.8000 5 -Testing that / has precedence over << -select 0x80 / 4 << 2, (0x80 / 4) << 2, 0x80 / (4 << 2); -0x80 / 4 << 2 (0x80 / 4) << 2 0x80 / (4 << 2) -128 128 8.0000 -select 0x80 << 4 / 2, (0x80 << 4) / 2, 0x80 << (4 / 2); -0x80 << 4 / 2 (0x80 << 4) / 2 0x80 << (4 / 2) -512 1024.0000 512 -Testing that / has precedence over >> -select 0x80 / 4 >> 2, (0x80 / 4) >> 2, 0x80 / (4 >> 2); -0x80 / 4 >> 2 (0x80 / 4) >> 2 0x80 / (4 >> 2) -8 8 128.0000 -select 0x80 >> 4 / 2, (0x80 >> 4) / 2, 0x80 >> (4 / 2); -0x80 >> 4 / 2 (0x80 >> 4) / 2 0x80 >> (4 / 2) -32 4.0000 32 -Testing that / has precedence over binary + -select 0x80 / 2 + 2, (0x80 / 2) + 2, 0x80 / (2 + 2); -0x80 / 2 + 2 (0x80 / 2) + 2 0x80 / (2 + 2) -66.0000 66.0000 32.0000 -select 0x80 + 2 / 2, (0x80 + 2) / 2, 0x80 + (2 / 2); -0x80 + 2 / 2 (0x80 + 2) / 2 0x80 + (2 / 2) -129.0000 65.0000 129.0000 -Testing that / has precedence over binary - -select 0x80 / 4 - 2, (0x80 / 4) - 2, 0x80 / (4 - 2); -0x80 / 4 - 2 (0x80 / 4) - 2 0x80 / (4 - 2) -30.0000 30.0000 64.0000 -select 0x80 - 4 / 2, (0x80 - 4) / 2, 0x80 - (4 / 2); -0x80 - 4 / 2 (0x80 - 4) / 2 0x80 - (4 / 2) -126.0000 62.0000 126.0000 -Testing that ^ is associative -select 0xFF ^ 0xF0 ^ 0x0F, (0xFF ^ 0xF0) ^ 0x0F, 0xFF ^ (0xF0 ^ 0x0F); -0xFF ^ 0xF0 ^ 0x0F (0xFF ^ 0xF0) ^ 0x0F 0xFF ^ (0xF0 ^ 0x0F) -0 0 0 -select 0xFF ^ 0xF0 ^ 0x55, (0xFF ^ 0xF0) ^ 0x55, 0xFF ^ (0xF0 ^ 0x55); -0xFF ^ 0xF0 ^ 0x55 (0xFF ^ 0xF0) ^ 0x55 0xFF ^ (0xF0 ^ 0x55) -90 90 90 -Testing that ^ has precedence over | -select 0xFF ^ 0xF0 | 0x0F, (0xFF ^ 0xF0) | 0x0F, 0xFF ^ (0xF0 | 0x0F); -0xFF ^ 0xF0 | 0x0F (0xFF ^ 0xF0) | 0x0F 0xFF ^ (0xF0 | 0x0F) -15 15 0 -select 0xF0 | 0xFF ^ 0xF0, (0xF0 | 0xFF) ^ 0xF0, 0xF0 | (0xFF ^ 0xF0); -0xF0 | 0xFF ^ 0xF0 (0xF0 | 0xFF) ^ 0xF0 0xF0 | (0xFF ^ 0xF0) -255 15 255 -Testing that ^ has precedence over & -select 0xFF ^ 0xF0 & 0x0F, (0xFF ^ 0xF0) & 0x0F, 0xFF ^ (0xF0 & 0x0F); -0xFF ^ 0xF0 & 0x0F (0xFF ^ 0xF0) & 0x0F 0xFF ^ (0xF0 & 0x0F) -15 15 255 -select 0x0F & 0xFF ^ 0xF0, (0x0F & 0xFF) ^ 0xF0, 0x0F & (0xFF ^ 0xF0); -0x0F & 0xFF ^ 0xF0 (0x0F & 0xFF) ^ 0xF0 0x0F & (0xFF ^ 0xF0) -15 255 15 -Testing that ^ has precedence over << -select 0xFF ^ 0xF0 << 2, (0xFF ^ 0xF0) << 2, 0xFF ^ (0xF0 << 2); -0xFF ^ 0xF0 << 2 (0xFF ^ 0xF0) << 2 0xFF ^ (0xF0 << 2) -60 60 831 -select 0x0F << 2 ^ 0xFF, (0x0F << 2) ^ 0xFF, 0x0F << (2 ^ 0xFF); -0x0F << 2 ^ 0xFF (0x0F << 2) ^ 0xFF 0x0F << (2 ^ 0xFF) -0 195 0 -Testing that ^ has precedence over >> -select 0xFF ^ 0xF0 >> 2, (0xFF ^ 0xF0) >> 2, 0xFF ^ (0xF0 >> 2); -0xFF ^ 0xF0 >> 2 (0xFF ^ 0xF0) >> 2 0xFF ^ (0xF0 >> 2) -3 3 195 -select 0xFF >> 2 ^ 0xF0, (0xFF >> 2) ^ 0xF0, 0xFF >> (2 ^ 0xF0); -0xFF >> 2 ^ 0xF0 (0xFF >> 2) ^ 0xF0 0xFF >> (2 ^ 0xF0) -0 207 0 -Testing that ^ has precedence over binary + -select 0xFF ^ 0xF0 + 0x0F, (0xFF ^ 0xF0) + 0x0F, 0xFF ^ (0xF0 + 0x0F); -0xFF ^ 0xF0 + 0x0F (0xFF ^ 0xF0) + 0x0F 0xFF ^ (0xF0 + 0x0F) -30 30 0 -select 0x0F + 0xFF ^ 0xF0, (0x0F + 0xFF) ^ 0xF0, 0x0F + (0xFF ^ 0xF0); -0x0F + 0xFF ^ 0xF0 (0x0F + 0xFF) ^ 0xF0 0x0F + (0xFF ^ 0xF0) -30 510 30 -Testing that ^ has precedence over binary - -select 0xFF ^ 0xF0 - 1, (0xFF ^ 0xF0) - 1, 0xFF ^ (0xF0 - 1); -0xFF ^ 0xF0 - 1 (0xFF ^ 0xF0) - 1 0xFF ^ (0xF0 - 1) -14 14 16 -select 0x55 - 0x0F ^ 0x55, (0x55 - 0x0F) ^ 0x55, 0x55 - (0x0F ^ 0x55); -0x55 - 0x0F ^ 0x55 (0x55 - 0x0F) ^ 0x55 0x55 - (0x0F ^ 0x55) --5 19 -5 -Testing that ^ has precedence over * -select 0xFF ^ 0xF0 * 2, (0xFF ^ 0xF0) * 2, 0xFF ^ (0xF0 * 2); -0xFF ^ 0xF0 * 2 (0xFF ^ 0xF0) * 2 0xFF ^ (0xF0 * 2) -30 30 287 -select 2 * 0xFF ^ 0xF0, (2 * 0xFF) ^ 0xF0, 2 * (0xFF ^ 0xF0); -2 * 0xFF ^ 0xF0 (2 * 0xFF) ^ 0xF0 2 * (0xFF ^ 0xF0) -30 270 30 -Testing that ^ has precedence over / -select 0xFF ^ 0xF0 / 2, (0xFF ^ 0xF0) / 2, 0xFF ^ (0xF0 / 2); -0xFF ^ 0xF0 / 2 (0xFF ^ 0xF0) / 2 0xFF ^ (0xF0 / 2) -7.5000 7.5000 135 -select 0xF2 / 2 ^ 0xF0, (0xF2 / 2) ^ 0xF0, 0xF2 / (2 ^ 0xF0); -0xF2 / 2 ^ 0xF0 (0xF2 / 2) ^ 0xF0 0xF2 / (2 ^ 0xF0) -1.0000 137 1.0000 -Testing that ^ has precedence over % -select 0xFF ^ 0xF0 % 0x20, (0xFF ^ 0xF0) % 0x20, 0xFF ^ (0xF0 % 0x20); -0xFF ^ 0xF0 % 0x20 (0xFF ^ 0xF0) % 0x20 0xFF ^ (0xF0 % 0x20) -15 15 239 -select 0xFF % 0x20 ^ 0xF0, (0xFF % 0x20) ^ 0xF0, 0xFF % (0x20 ^ 0xF0); -0xFF % 0x20 ^ 0xF0 (0xFF % 0x20) ^ 0xF0 0xFF % (0x20 ^ 0xF0) -47 239 47 -Testing that ^ has precedence over DIV -select 0xFF ^ 0xF0 DIV 2, (0xFF ^ 0xF0) DIV 2, 0xFF ^ (0xF0 DIV 2); -0xFF ^ 0xF0 DIV 2 (0xFF ^ 0xF0) DIV 2 0xFF ^ (0xF0 DIV 2) -7 7 135 -select 0xF2 DIV 2 ^ 0xF0, (0xF2 DIV 2) ^ 0xF0, 0xF2 DIV (2 ^ 0xF0); -0xF2 DIV 2 ^ 0xF0 (0xF2 DIV 2) ^ 0xF0 0xF2 DIV (2 ^ 0xF0) -1 137 1 -Testing that ^ has precedence over MOD -select 0xFF ^ 0xF0 MOD 0x20, (0xFF ^ 0xF0) MOD 0x20, 0xFF ^ (0xF0 MOD 0x20); -0xFF ^ 0xF0 MOD 0x20 (0xFF ^ 0xF0) MOD 0x20 0xFF ^ (0xF0 MOD 0x20) -15 15 239 -select 0xFF MOD 0x20 ^ 0xF0, (0xFF MOD 0x20) ^ 0xF0, 0xFF MOD (0x20 ^ 0xF0); -0xFF MOD 0x20 ^ 0xF0 (0xFF MOD 0x20) ^ 0xF0 0xFF MOD (0x20 ^ 0xF0) -47 239 47 diff --git a/mysql-test/r/precedence.result b/mysql-test/r/precedence.result index 2a797467758..7584375061d 100644 --- a/mysql-test/r/precedence.result +++ b/mysql-test/r/precedence.result @@ -1996,11 +1996,10 @@ binary binary latin1 create or replace view v1 as select 2 = 3 IN (0,1), 2 = (3 IN (0,1)), (2 = 3) IN (0,1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 = (3 in (0,1)) AS `2 = 3 IN (0,1)`,2 = (3 in (0,1)) AS `2 = (3 IN (0,1))`,2 = 3 in (0,1) AS `(2 = 3) IN (0,1)` +select 2 = 3 in (0,1) AS `2 = 3 IN (0,1)`,2 = 3 in (0,1) AS `2 = (3 IN (0,1))`,(2 = 3) in (0,1) AS `(2 = 3) IN (0,1)` select 2 = 3 IN (0,1), 2 = (3 IN (0,1)), (2 = 3) IN (0,1) union select * from v1; 2 = 3 IN (0,1) 2 = (3 IN (0,1)) (2 = 3) IN (0,1) 0 0 1 -0 0 0 create or replace view v1 as select 2 = 3 OR 3, 2 = (3 OR 3), (2 = 3) OR 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -2095,19 +2094,17 @@ select 2 = 3 != 3, 2 = (3 != 3), (2 = 3) != 3 union select * from v1; create or replace view v1 as select 1 = 3 LIKE 3, 1 = (3 LIKE 3), (1 = 3) LIKE 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 1 = (3 like 3) AS `1 = 3 LIKE 3`,1 = (3 like 3) AS `1 = (3 LIKE 3)`,1 = 3 like 3 AS `(1 = 3) LIKE 3` +select 1 = 3 like 3 AS `1 = 3 LIKE 3`,1 = 3 like 3 AS `1 = (3 LIKE 3)`,(1 = 3) like 3 AS `(1 = 3) LIKE 3` select 1 = 3 LIKE 3, 1 = (3 LIKE 3), (1 = 3) LIKE 3 union select * from v1; 1 = 3 LIKE 3 1 = (3 LIKE 3) (1 = 3) LIKE 3 1 1 0 -1 1 1 create or replace view v1 as select 1 = 3 REGEXP 3, 1 = (3 REGEXP 3), (1 = 3) REGEXP 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 1 = (3 regexp 3) AS `1 = 3 REGEXP 3`,1 = (3 regexp 3) AS `1 = (3 REGEXP 3)`,1 = 3 regexp 3 AS `(1 = 3) REGEXP 3` +select 1 = 3 regexp 3 AS `1 = 3 REGEXP 3`,1 = 3 regexp 3 AS `1 = (3 REGEXP 3)`,(1 = 3) regexp 3 AS `(1 = 3) REGEXP 3` select 1 = 3 REGEXP 3, 1 = (3 REGEXP 3), (1 = 3) REGEXP 3 union select * from v1; 1 = 3 REGEXP 3 1 = (3 REGEXP 3) (1 = 3) REGEXP 3 1 1 0 -1 1 1 create or replace view v1 as select 2 = 3 | 3, 2 = (3 | 3), (2 = 3) | 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -2202,11 +2199,10 @@ select 2 = 3 ^ 3, 2 = (3 ^ 3), (2 = 3) ^ 3 union select * from v1; create or replace view v1 as select 1 = 3 BETWEEN 1 AND 3, 1 = (3 BETWEEN 1 AND 3), (1 = 3) BETWEEN 1 AND 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 1 = (3 between 1 and 3) AS `1 = 3 BETWEEN 1 AND 3`,1 = (3 between 1 and 3) AS `1 = (3 BETWEEN 1 AND 3)`,1 = 3 between 1 and 3 AS `(1 = 3) BETWEEN 1 AND 3` +select 1 = 3 between 1 and 3 AS `1 = 3 BETWEEN 1 AND 3`,1 = 3 between 1 and 3 AS `1 = (3 BETWEEN 1 AND 3)`,(1 = 3) between 1 and 3 AS `(1 = 3) BETWEEN 1 AND 3` select 1 = 3 BETWEEN 1 AND 3, 1 = (3 BETWEEN 1 AND 3), (1 = 3) BETWEEN 1 AND 3 union select * from v1; 1 = 3 BETWEEN 1 AND 3 1 = (3 BETWEEN 1 AND 3) (1 = 3) BETWEEN 1 AND 3 1 1 0 -1 1 1 create or replace view v1 as select 2 <=> 3 IS FALSE, 2 <=> (3 IS FALSE), (2 <=> 3) IS FALSE; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -2224,11 +2220,10 @@ binary binary latin1 create or replace view v1 as select 2 <=> 3 IN (0,1), 2 <=> (3 IN (0,1)), (2 <=> 3) IN (0,1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <=> (3 in (0,1)) AS `2 <=> 3 IN (0,1)`,2 <=> (3 in (0,1)) AS `2 <=> (3 IN (0,1))`,2 <=> 3 in (0,1) AS `(2 <=> 3) IN (0,1)` +select 2 <=> 3 in (0,1) AS `2 <=> 3 IN (0,1)`,2 <=> 3 in (0,1) AS `2 <=> (3 IN (0,1))`,(2 <=> 3) in (0,1) AS `(2 <=> 3) IN (0,1)` select 2 <=> 3 IN (0,1), 2 <=> (3 IN (0,1)), (2 <=> 3) IN (0,1) union select * from v1; 2 <=> 3 IN (0,1) 2 <=> (3 IN (0,1)) (2 <=> 3) IN (0,1) 0 0 1 -0 0 0 create or replace view v1 as select 2 <=> 3 OR 3, 2 <=> (3 OR 3), (2 <=> 3) OR 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -2323,19 +2318,17 @@ select 2 <=> 3 != 3, 2 <=> (3 != 3), (2 <=> 3) != 3 union select * from v1; create or replace view v1 as select 1 <=> 3 LIKE 3, 1 <=> (3 LIKE 3), (1 <=> 3) LIKE 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 1 <=> (3 like 3) AS `1 <=> 3 LIKE 3`,1 <=> (3 like 3) AS `1 <=> (3 LIKE 3)`,1 <=> 3 like 3 AS `(1 <=> 3) LIKE 3` +select 1 <=> 3 like 3 AS `1 <=> 3 LIKE 3`,1 <=> 3 like 3 AS `1 <=> (3 LIKE 3)`,(1 <=> 3) like 3 AS `(1 <=> 3) LIKE 3` select 1 <=> 3 LIKE 3, 1 <=> (3 LIKE 3), (1 <=> 3) LIKE 3 union select * from v1; 1 <=> 3 LIKE 3 1 <=> (3 LIKE 3) (1 <=> 3) LIKE 3 1 1 0 -1 1 1 create or replace view v1 as select 1 <=> 3 REGEXP 3, 1 <=> (3 REGEXP 3), (1 <=> 3) REGEXP 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 1 <=> (3 regexp 3) AS `1 <=> 3 REGEXP 3`,1 <=> (3 regexp 3) AS `1 <=> (3 REGEXP 3)`,1 <=> 3 regexp 3 AS `(1 <=> 3) REGEXP 3` +select 1 <=> 3 regexp 3 AS `1 <=> 3 REGEXP 3`,1 <=> 3 regexp 3 AS `1 <=> (3 REGEXP 3)`,(1 <=> 3) regexp 3 AS `(1 <=> 3) REGEXP 3` select 1 <=> 3 REGEXP 3, 1 <=> (3 REGEXP 3), (1 <=> 3) REGEXP 3 union select * from v1; 1 <=> 3 REGEXP 3 1 <=> (3 REGEXP 3) (1 <=> 3) REGEXP 3 1 1 0 -1 1 1 create or replace view v1 as select 2 <=> 3 | 3, 2 <=> (3 | 3), (2 <=> 3) | 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -2430,11 +2423,10 @@ select 2 <=> 3 ^ 3, 2 <=> (3 ^ 3), (2 <=> 3) ^ 3 union select * from v1; create or replace view v1 as select 1 <=> 3 BETWEEN 1 AND 3, 1 <=> (3 BETWEEN 1 AND 3), (1 <=> 3) BETWEEN 1 AND 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 1 <=> (3 between 1 and 3) AS `1 <=> 3 BETWEEN 1 AND 3`,1 <=> (3 between 1 and 3) AS `1 <=> (3 BETWEEN 1 AND 3)`,1 <=> 3 between 1 and 3 AS `(1 <=> 3) BETWEEN 1 AND 3` +select 1 <=> 3 between 1 and 3 AS `1 <=> 3 BETWEEN 1 AND 3`,1 <=> 3 between 1 and 3 AS `1 <=> (3 BETWEEN 1 AND 3)`,(1 <=> 3) between 1 and 3 AS `(1 <=> 3) BETWEEN 1 AND 3` select 1 <=> 3 BETWEEN 1 AND 3, 1 <=> (3 BETWEEN 1 AND 3), (1 <=> 3) BETWEEN 1 AND 3 union select * from v1; 1 <=> 3 BETWEEN 1 AND 3 1 <=> (3 BETWEEN 1 AND 3) (1 <=> 3) BETWEEN 1 AND 3 1 1 0 -1 1 1 create or replace view v1 as select 4 >= 3 IS FALSE, 4 >= (3 IS FALSE), (4 >= 3) IS FALSE; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -2452,11 +2444,10 @@ binary binary latin1 create or replace view v1 as select 2 >= 3 IN (1,1), 2 >= (3 IN (1,1)), (2 >= 3) IN (1,1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 >= (3 in (1,1)) AS `2 >= 3 IN (1,1)`,2 >= (3 in (1,1)) AS `2 >= (3 IN (1,1))`,2 >= 3 in (1,1) AS `(2 >= 3) IN (1,1)` +select 2 >= 3 in (1,1) AS `2 >= 3 IN (1,1)`,2 >= 3 in (1,1) AS `2 >= (3 IN (1,1))`,(2 >= 3) in (1,1) AS `(2 >= 3) IN (1,1)` select 2 >= 3 IN (1,1), 2 >= (3 IN (1,1)), (2 >= 3) IN (1,1) union select * from v1; 2 >= 3 IN (1,1) 2 >= (3 IN (1,1)) (2 >= 3) IN (1,1) 1 1 0 -1 1 1 create or replace view v1 as select 2 >= 3 OR 0, 2 >= (3 OR 0), (2 >= 3) OR 0; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -2551,19 +2542,17 @@ select 2 >= 3 != 0, 2 >= (3 != 0), (2 >= 3) != 0 union select * from v1; create or replace view v1 as select 2 >= 3 LIKE 3, 2 >= (3 LIKE 3), (2 >= 3) LIKE 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 >= (3 like 3) AS `2 >= 3 LIKE 3`,2 >= (3 like 3) AS `2 >= (3 LIKE 3)`,2 >= 3 like 3 AS `(2 >= 3) LIKE 3` +select 2 >= 3 like 3 AS `2 >= 3 LIKE 3`,2 >= 3 like 3 AS `2 >= (3 LIKE 3)`,(2 >= 3) like 3 AS `(2 >= 3) LIKE 3` select 2 >= 3 LIKE 3, 2 >= (3 LIKE 3), (2 >= 3) LIKE 3 union select * from v1; 2 >= 3 LIKE 3 2 >= (3 LIKE 3) (2 >= 3) LIKE 3 1 1 0 -1 1 1 create or replace view v1 as select 2 >= 3 REGEXP 3, 2 >= (3 REGEXP 3), (2 >= 3) REGEXP 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 >= (3 regexp 3) AS `2 >= 3 REGEXP 3`,2 >= (3 regexp 3) AS `2 >= (3 REGEXP 3)`,2 >= 3 regexp 3 AS `(2 >= 3) REGEXP 3` +select 2 >= 3 regexp 3 AS `2 >= 3 REGEXP 3`,2 >= 3 regexp 3 AS `2 >= (3 REGEXP 3)`,(2 >= 3) regexp 3 AS `(2 >= 3) REGEXP 3` select 2 >= 3 REGEXP 3, 2 >= (3 REGEXP 3), (2 >= 3) REGEXP 3 union select * from v1; 2 >= 3 REGEXP 3 2 >= (3 REGEXP 3) (2 >= 3) REGEXP 3 1 1 0 -1 1 1 create or replace view v1 as select 2 >= 3 | 3, 2 >= (3 | 3), (2 >= 3) | 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -2658,11 +2647,10 @@ select 2 >= 3 ^ 3, 2 >= (3 ^ 3), (2 >= 3) ^ 3 union select * from v1; create or replace view v1 as select 2 >= 3 BETWEEN 1 AND 3, 2 >= (3 BETWEEN 1 AND 3), (2 >= 3) BETWEEN 1 AND 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 >= (3 between 1 and 3) AS `2 >= 3 BETWEEN 1 AND 3`,2 >= (3 between 1 and 3) AS `2 >= (3 BETWEEN 1 AND 3)`,2 >= 3 between 1 and 3 AS `(2 >= 3) BETWEEN 1 AND 3` +select 2 >= 3 between 1 and 3 AS `2 >= 3 BETWEEN 1 AND 3`,2 >= 3 between 1 and 3 AS `2 >= (3 BETWEEN 1 AND 3)`,(2 >= 3) between 1 and 3 AS `(2 >= 3) BETWEEN 1 AND 3` select 2 >= 3 BETWEEN 1 AND 3, 2 >= (3 BETWEEN 1 AND 3), (2 >= 3) BETWEEN 1 AND 3 union select * from v1; 2 >= 3 BETWEEN 1 AND 3 2 >= (3 BETWEEN 1 AND 3) (2 >= 3) BETWEEN 1 AND 3 1 1 0 -1 1 1 create or replace view v1 as select 2 <= 1 IS FALSE, 2 <= (1 IS FALSE), (2 <= 1) IS FALSE; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -2680,11 +2668,10 @@ binary binary latin1 create or replace view v1 as select 2 <= 3 IN (0,1), 2 <= (3 IN (0,1)), (2 <= 3) IN (0,1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <= (3 in (0,1)) AS `2 <= 3 IN (0,1)`,2 <= (3 in (0,1)) AS `2 <= (3 IN (0,1))`,2 <= 3 in (0,1) AS `(2 <= 3) IN (0,1)` +select 2 <= 3 in (0,1) AS `2 <= 3 IN (0,1)`,2 <= 3 in (0,1) AS `2 <= (3 IN (0,1))`,(2 <= 3) in (0,1) AS `(2 <= 3) IN (0,1)` select 2 <= 3 IN (0,1), 2 <= (3 IN (0,1)), (2 <= 3) IN (0,1) union select * from v1; 2 <= 3 IN (0,1) 2 <= (3 IN (0,1)) (2 <= 3) IN (0,1) 0 0 1 -0 0 0 create or replace view v1 as select 2 <= 3 OR 3, 2 <= (3 OR 3), (2 <= 3) OR 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -2779,19 +2766,17 @@ select 2 <= 3 != 3, 2 <= (3 != 3), (2 <= 3) != 3 union select * from v1; create or replace view v1 as select 2 <= 0 LIKE 0, 2 <= (0 LIKE 0), (2 <= 0) LIKE 0; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <= (0 like 0) AS `2 <= 0 LIKE 0`,2 <= (0 like 0) AS `2 <= (0 LIKE 0)`,2 <= 0 like 0 AS `(2 <= 0) LIKE 0` +select 2 <= 0 like 0 AS `2 <= 0 LIKE 0`,2 <= 0 like 0 AS `2 <= (0 LIKE 0)`,(2 <= 0) like 0 AS `(2 <= 0) LIKE 0` select 2 <= 0 LIKE 0, 2 <= (0 LIKE 0), (2 <= 0) LIKE 0 union select * from v1; 2 <= 0 LIKE 0 2 <= (0 LIKE 0) (2 <= 0) LIKE 0 0 0 1 -0 0 0 create or replace view v1 as select 2 <= 0 REGEXP 0, 2 <= (0 REGEXP 0), (2 <= 0) REGEXP 0; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <= (0 regexp 0) AS `2 <= 0 REGEXP 0`,2 <= (0 regexp 0) AS `2 <= (0 REGEXP 0)`,2 <= 0 regexp 0 AS `(2 <= 0) REGEXP 0` +select 2 <= 0 regexp 0 AS `2 <= 0 REGEXP 0`,2 <= 0 regexp 0 AS `2 <= (0 REGEXP 0)`,(2 <= 0) regexp 0 AS `(2 <= 0) REGEXP 0` select 2 <= 0 REGEXP 0, 2 <= (0 REGEXP 0), (2 <= 0) REGEXP 0 union select * from v1; 2 <= 0 REGEXP 0 2 <= (0 REGEXP 0) (2 <= 0) REGEXP 0 0 0 1 -0 0 0 create or replace view v1 as select 2 <= 3 | 3, 2 <= (3 | 3), (2 <= 3) | 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -2886,11 +2871,10 @@ select 2 <= 3 ^ 3, 2 <= (3 ^ 3), (2 <= 3) ^ 3 union select * from v1; create or replace view v1 as select 2 <= 3 BETWEEN 1 AND 3, 2 <= (3 BETWEEN 1 AND 3), (2 <= 3) BETWEEN 1 AND 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <= (3 between 1 and 3) AS `2 <= 3 BETWEEN 1 AND 3`,2 <= (3 between 1 and 3) AS `2 <= (3 BETWEEN 1 AND 3)`,2 <= 3 between 1 and 3 AS `(2 <= 3) BETWEEN 1 AND 3` +select 2 <= 3 between 1 and 3 AS `2 <= 3 BETWEEN 1 AND 3`,2 <= 3 between 1 and 3 AS `2 <= (3 BETWEEN 1 AND 3)`,(2 <= 3) between 1 and 3 AS `(2 <= 3) BETWEEN 1 AND 3` select 2 <= 3 BETWEEN 1 AND 3, 2 <= (3 BETWEEN 1 AND 3), (2 <= 3) BETWEEN 1 AND 3 union select * from v1; 2 <= 3 BETWEEN 1 AND 3 2 <= (3 BETWEEN 1 AND 3) (2 <= 3) BETWEEN 1 AND 3 0 0 1 -0 0 0 create or replace view v1 as select 2 < 1 IS FALSE, 2 < (1 IS FALSE), (2 < 1) IS FALSE; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -2908,11 +2892,10 @@ binary binary latin1 create or replace view v1 as select 2 < 3 IN (0,1), 2 < (3 IN (0,1)), (2 < 3) IN (0,1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 < (3 in (0,1)) AS `2 < 3 IN (0,1)`,2 < (3 in (0,1)) AS `2 < (3 IN (0,1))`,2 < 3 in (0,1) AS `(2 < 3) IN (0,1)` +select 2 < 3 in (0,1) AS `2 < 3 IN (0,1)`,2 < 3 in (0,1) AS `2 < (3 IN (0,1))`,(2 < 3) in (0,1) AS `(2 < 3) IN (0,1)` select 2 < 3 IN (0,1), 2 < (3 IN (0,1)), (2 < 3) IN (0,1) union select * from v1; 2 < 3 IN (0,1) 2 < (3 IN (0,1)) (2 < 3) IN (0,1) 0 0 1 -0 0 0 create or replace view v1 as select 2 < 3 OR 3, 2 < (3 OR 3), (2 < 3) OR 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -3007,19 +2990,17 @@ select 2 < 3 != 3, 2 < (3 != 3), (2 < 3) != 3 union select * from v1; create or replace view v1 as select 2 < 3 LIKE 1, 2 < (3 LIKE 1), (2 < 3) LIKE 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 < (3 like 1) AS `2 < 3 LIKE 1`,2 < (3 like 1) AS `2 < (3 LIKE 1)`,2 < 3 like 1 AS `(2 < 3) LIKE 1` +select 2 < 3 like 1 AS `2 < 3 LIKE 1`,2 < 3 like 1 AS `2 < (3 LIKE 1)`,(2 < 3) like 1 AS `(2 < 3) LIKE 1` select 2 < 3 LIKE 1, 2 < (3 LIKE 1), (2 < 3) LIKE 1 union select * from v1; 2 < 3 LIKE 1 2 < (3 LIKE 1) (2 < 3) LIKE 1 0 0 1 -0 0 0 create or replace view v1 as select 2 < 3 REGEXP 1, 2 < (3 REGEXP 1), (2 < 3) REGEXP 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 < (3 regexp 1) AS `2 < 3 REGEXP 1`,2 < (3 regexp 1) AS `2 < (3 REGEXP 1)`,2 < 3 regexp 1 AS `(2 < 3) REGEXP 1` +select 2 < 3 regexp 1 AS `2 < 3 REGEXP 1`,2 < 3 regexp 1 AS `2 < (3 REGEXP 1)`,(2 < 3) regexp 1 AS `(2 < 3) REGEXP 1` select 2 < 3 REGEXP 1, 2 < (3 REGEXP 1), (2 < 3) REGEXP 1 union select * from v1; 2 < 3 REGEXP 1 2 < (3 REGEXP 1) (2 < 3) REGEXP 1 0 0 1 -0 0 0 create or replace view v1 as select 2 < 3 | 3, 2 < (3 | 3), (2 < 3) | 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -3114,11 +3095,10 @@ select 2 < 3 ^ 3, 2 < (3 ^ 3), (2 < 3) ^ 3 union select * from v1; create or replace view v1 as select 2 < 3 BETWEEN 1 AND 3, 2 < (3 BETWEEN 1 AND 3), (2 < 3) BETWEEN 1 AND 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 < (3 between 1 and 3) AS `2 < 3 BETWEEN 1 AND 3`,2 < (3 between 1 and 3) AS `2 < (3 BETWEEN 1 AND 3)`,2 < 3 between 1 and 3 AS `(2 < 3) BETWEEN 1 AND 3` +select 2 < 3 between 1 and 3 AS `2 < 3 BETWEEN 1 AND 3`,2 < 3 between 1 and 3 AS `2 < (3 BETWEEN 1 AND 3)`,(2 < 3) between 1 and 3 AS `(2 < 3) BETWEEN 1 AND 3` select 2 < 3 BETWEEN 1 AND 3, 2 < (3 BETWEEN 1 AND 3), (2 < 3) BETWEEN 1 AND 3 union select * from v1; 2 < 3 BETWEEN 1 AND 3 2 < (3 BETWEEN 1 AND 3) (2 < 3) BETWEEN 1 AND 3 0 0 1 -0 0 0 create or replace view v1 as select 2 <> 3 IS FALSE, 2 <> (3 IS FALSE), (2 <> 3) IS FALSE; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -3136,11 +3116,10 @@ binary binary latin1 create or replace view v1 as select 2 <> 3 IN (0,0), 2 <> (3 IN (0,0)), (2 <> 3) IN (0,0); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <> (3 in (0,0)) AS `2 <> 3 IN (0,0)`,2 <> (3 in (0,0)) AS `2 <> (3 IN (0,0))`,2 <> 3 in (0,0) AS `(2 <> 3) IN (0,0)` +select 2 <> 3 in (0,0) AS `2 <> 3 IN (0,0)`,2 <> 3 in (0,0) AS `2 <> (3 IN (0,0))`,(2 <> 3) in (0,0) AS `(2 <> 3) IN (0,0)` select 2 <> 3 IN (0,0), 2 <> (3 IN (0,0)), (2 <> 3) IN (0,0) union select * from v1; 2 <> 3 IN (0,0) 2 <> (3 IN (0,0)) (2 <> 3) IN (0,0) 1 1 0 -1 1 1 create or replace view v1 as select 1 <> 3 OR 3, 1 <> (3 OR 3), (1 <> 3) OR 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -3235,19 +3214,17 @@ select 0 <> 3 != 3, 0 <> (3 != 3), (0 <> 3) != 3 union select * from v1; create or replace view v1 as select 2 <> 3 LIKE 3, 2 <> (3 LIKE 3), (2 <> 3) LIKE 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <> (3 like 3) AS `2 <> 3 LIKE 3`,2 <> (3 like 3) AS `2 <> (3 LIKE 3)`,2 <> 3 like 3 AS `(2 <> 3) LIKE 3` +select 2 <> 3 like 3 AS `2 <> 3 LIKE 3`,2 <> 3 like 3 AS `2 <> (3 LIKE 3)`,(2 <> 3) like 3 AS `(2 <> 3) LIKE 3` select 2 <> 3 LIKE 3, 2 <> (3 LIKE 3), (2 <> 3) LIKE 3 union select * from v1; 2 <> 3 LIKE 3 2 <> (3 LIKE 3) (2 <> 3) LIKE 3 1 1 0 -1 1 1 create or replace view v1 as select 2 <> 3 REGEXP 3, 2 <> (3 REGEXP 3), (2 <> 3) REGEXP 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <> (3 regexp 3) AS `2 <> 3 REGEXP 3`,2 <> (3 regexp 3) AS `2 <> (3 REGEXP 3)`,2 <> 3 regexp 3 AS `(2 <> 3) REGEXP 3` +select 2 <> 3 regexp 3 AS `2 <> 3 REGEXP 3`,2 <> 3 regexp 3 AS `2 <> (3 REGEXP 3)`,(2 <> 3) regexp 3 AS `(2 <> 3) REGEXP 3` select 2 <> 3 REGEXP 3, 2 <> (3 REGEXP 3), (2 <> 3) REGEXP 3 union select * from v1; 2 <> 3 REGEXP 3 2 <> (3 REGEXP 3) (2 <> 3) REGEXP 3 1 1 0 -1 1 1 create or replace view v1 as select 2 <> 3 | 3, 2 <> (3 | 3), (2 <> 3) | 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -3342,11 +3319,10 @@ select 2 <> 3 ^ 3, 2 <> (3 ^ 3), (2 <> 3) ^ 3 union select * from v1; create or replace view v1 as select 2 <> 3 BETWEEN 2 AND 3, 2 <> (3 BETWEEN 2 AND 3), (2 <> 3) BETWEEN 2 AND 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <> (3 between 2 and 3) AS `2 <> 3 BETWEEN 2 AND 3`,2 <> (3 between 2 and 3) AS `2 <> (3 BETWEEN 2 AND 3)`,2 <> 3 between 2 and 3 AS `(2 <> 3) BETWEEN 2 AND 3` +select 2 <> 3 between 2 and 3 AS `2 <> 3 BETWEEN 2 AND 3`,2 <> 3 between 2 and 3 AS `2 <> (3 BETWEEN 2 AND 3)`,(2 <> 3) between 2 and 3 AS `(2 <> 3) BETWEEN 2 AND 3` select 2 <> 3 BETWEEN 2 AND 3, 2 <> (3 BETWEEN 2 AND 3), (2 <> 3) BETWEEN 2 AND 3 union select * from v1; 2 <> 3 BETWEEN 2 AND 3 2 <> (3 BETWEEN 2 AND 3) (2 <> 3) BETWEEN 2 AND 3 1 1 0 -1 1 1 create or replace view v1 as select 2 > 0 IS FALSE, 2 > (0 IS FALSE), (2 > 0) IS FALSE; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -3364,11 +3340,10 @@ binary binary latin1 create or replace view v1 as select 2 > 3 IN (1,1), 2 > (3 IN (1,1)), (2 > 3) IN (1,1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 > (3 in (1,1)) AS `2 > 3 IN (1,1)`,2 > (3 in (1,1)) AS `2 > (3 IN (1,1))`,2 > 3 in (1,1) AS `(2 > 3) IN (1,1)` +select 2 > 3 in (1,1) AS `2 > 3 IN (1,1)`,2 > 3 in (1,1) AS `2 > (3 IN (1,1))`,(2 > 3) in (1,1) AS `(2 > 3) IN (1,1)` select 2 > 3 IN (1,1), 2 > (3 IN (1,1)), (2 > 3) IN (1,1) union select * from v1; 2 > 3 IN (1,1) 2 > (3 IN (1,1)) (2 > 3) IN (1,1) 1 1 0 -1 1 1 create or replace view v1 as select 0 > 3 OR 3, 0 > (3 OR 3), (0 > 3) OR 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -3463,19 +3438,17 @@ select 2 > 1 != 1, 2 > (1 != 1), (2 > 1) != 1 union select * from v1; create or replace view v1 as select 2 > 3 LIKE 3, 2 > (3 LIKE 3), (2 > 3) LIKE 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 > (3 like 3) AS `2 > 3 LIKE 3`,2 > (3 like 3) AS `2 > (3 LIKE 3)`,2 > 3 like 3 AS `(2 > 3) LIKE 3` +select 2 > 3 like 3 AS `2 > 3 LIKE 3`,2 > 3 like 3 AS `2 > (3 LIKE 3)`,(2 > 3) like 3 AS `(2 > 3) LIKE 3` select 2 > 3 LIKE 3, 2 > (3 LIKE 3), (2 > 3) LIKE 3 union select * from v1; 2 > 3 LIKE 3 2 > (3 LIKE 3) (2 > 3) LIKE 3 1 1 0 -1 1 1 create or replace view v1 as select 2 > 3 REGEXP 3, 2 > (3 REGEXP 3), (2 > 3) REGEXP 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 > (3 regexp 3) AS `2 > 3 REGEXP 3`,2 > (3 regexp 3) AS `2 > (3 REGEXP 3)`,2 > 3 regexp 3 AS `(2 > 3) REGEXP 3` +select 2 > 3 regexp 3 AS `2 > 3 REGEXP 3`,2 > 3 regexp 3 AS `2 > (3 REGEXP 3)`,(2 > 3) regexp 3 AS `(2 > 3) REGEXP 3` select 2 > 3 REGEXP 3, 2 > (3 REGEXP 3), (2 > 3) REGEXP 3 union select * from v1; 2 > 3 REGEXP 3 2 > (3 REGEXP 3) (2 > 3) REGEXP 3 1 1 0 -1 1 1 create or replace view v1 as select 2 > 3 | 3, 2 > (3 | 3), (2 > 3) | 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -3570,11 +3543,10 @@ select 2 > 3 ^ 3, 2 > (3 ^ 3), (2 > 3) ^ 3 union select * from v1; create or replace view v1 as select 2 > 3 BETWEEN 1 AND 3, 2 > (3 BETWEEN 1 AND 3), (2 > 3) BETWEEN 1 AND 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 > (3 between 1 and 3) AS `2 > 3 BETWEEN 1 AND 3`,2 > (3 between 1 and 3) AS `2 > (3 BETWEEN 1 AND 3)`,2 > 3 between 1 and 3 AS `(2 > 3) BETWEEN 1 AND 3` +select 2 > 3 between 1 and 3 AS `2 > 3 BETWEEN 1 AND 3`,2 > 3 between 1 and 3 AS `2 > (3 BETWEEN 1 AND 3)`,(2 > 3) between 1 and 3 AS `(2 > 3) BETWEEN 1 AND 3` select 2 > 3 BETWEEN 1 AND 3, 2 > (3 BETWEEN 1 AND 3), (2 > 3) BETWEEN 1 AND 3 union select * from v1; 2 > 3 BETWEEN 1 AND 3 2 > (3 BETWEEN 1 AND 3) (2 > 3) BETWEEN 1 AND 3 1 1 0 -1 1 1 create or replace view v1 as select 2 != 3 IS FALSE, 2 != (3 IS FALSE), (2 != 3) IS FALSE; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -3592,11 +3564,10 @@ binary binary latin1 create or replace view v1 as select 2 != 3 IN (0,0), 2 != (3 IN (0,0)), (2 != 3) IN (0,0); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <> (3 in (0,0)) AS `2 != 3 IN (0,0)`,2 <> (3 in (0,0)) AS `2 != (3 IN (0,0))`,2 <> 3 in (0,0) AS `(2 != 3) IN (0,0)` +select 2 <> 3 in (0,0) AS `2 != 3 IN (0,0)`,2 <> 3 in (0,0) AS `2 != (3 IN (0,0))`,(2 <> 3) in (0,0) AS `(2 != 3) IN (0,0)` select 2 != 3 IN (0,0), 2 != (3 IN (0,0)), (2 != 3) IN (0,0) union select * from v1; 2 != 3 IN (0,0) 2 != (3 IN (0,0)) (2 != 3) IN (0,0) 1 1 0 -1 1 1 create or replace view v1 as select 1 != 3 OR 3, 1 != (3 OR 3), (1 != 3) OR 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -3691,19 +3662,17 @@ select 0 != 3 != 3, 0 != (3 != 3), (0 != 3) != 3 union select * from v1; create or replace view v1 as select 2 != 3 LIKE 3, 2 != (3 LIKE 3), (2 != 3) LIKE 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <> (3 like 3) AS `2 != 3 LIKE 3`,2 <> (3 like 3) AS `2 != (3 LIKE 3)`,2 <> 3 like 3 AS `(2 != 3) LIKE 3` +select 2 <> 3 like 3 AS `2 != 3 LIKE 3`,2 <> 3 like 3 AS `2 != (3 LIKE 3)`,(2 <> 3) like 3 AS `(2 != 3) LIKE 3` select 2 != 3 LIKE 3, 2 != (3 LIKE 3), (2 != 3) LIKE 3 union select * from v1; 2 != 3 LIKE 3 2 != (3 LIKE 3) (2 != 3) LIKE 3 1 1 0 -1 1 1 create or replace view v1 as select 2 != 3 REGEXP 3, 2 != (3 REGEXP 3), (2 != 3) REGEXP 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <> (3 regexp 3) AS `2 != 3 REGEXP 3`,2 <> (3 regexp 3) AS `2 != (3 REGEXP 3)`,2 <> 3 regexp 3 AS `(2 != 3) REGEXP 3` +select 2 <> 3 regexp 3 AS `2 != 3 REGEXP 3`,2 <> 3 regexp 3 AS `2 != (3 REGEXP 3)`,(2 <> 3) regexp 3 AS `(2 != 3) REGEXP 3` select 2 != 3 REGEXP 3, 2 != (3 REGEXP 3), (2 != 3) REGEXP 3 union select * from v1; 2 != 3 REGEXP 3 2 != (3 REGEXP 3) (2 != 3) REGEXP 3 1 1 0 -1 1 1 create or replace view v1 as select 2 != 3 | 3, 2 != (3 | 3), (2 != 3) | 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -3798,19 +3767,17 @@ select 2 != 3 ^ 3, 2 != (3 ^ 3), (2 != 3) ^ 3 union select * from v1; create or replace view v1 as select 2 != 3 BETWEEN 2 AND 3, 2 != (3 BETWEEN 2 AND 3), (2 != 3) BETWEEN 2 AND 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <> (3 between 2 and 3) AS `2 != 3 BETWEEN 2 AND 3`,2 <> (3 between 2 and 3) AS `2 != (3 BETWEEN 2 AND 3)`,2 <> 3 between 2 and 3 AS `(2 != 3) BETWEEN 2 AND 3` +select 2 <> 3 between 2 and 3 AS `2 != 3 BETWEEN 2 AND 3`,2 <> 3 between 2 and 3 AS `2 != (3 BETWEEN 2 AND 3)`,(2 <> 3) between 2 and 3 AS `(2 != 3) BETWEEN 2 AND 3` select 2 != 3 BETWEEN 2 AND 3, 2 != (3 BETWEEN 2 AND 3), (2 != 3) BETWEEN 2 AND 3 union select * from v1; 2 != 3 BETWEEN 2 AND 3 2 != (3 BETWEEN 2 AND 3) (2 != 3) BETWEEN 2 AND 3 1 1 0 -1 1 1 create or replace view v1 as select 2 LIKE 3 IS FALSE, 2 LIKE (3 IS FALSE), (2 LIKE 3) IS FALSE; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 is false AS `2 LIKE 3 IS FALSE`,2 like 3 is false AS `2 LIKE (3 IS FALSE)`,2 like 3 is false AS `(2 LIKE 3) IS FALSE` +select 2 like 3 is false AS `2 LIKE 3 IS FALSE`,2 like (3 is false) AS `2 LIKE (3 IS FALSE)`,2 like 3 is false AS `(2 LIKE 3) IS FALSE` select 2 LIKE 3 IS FALSE, 2 LIKE (3 IS FALSE), (2 LIKE 3) IS FALSE union select * from v1; 2 LIKE 3 IS FALSE 2 LIKE (3 IS FALSE) (2 LIKE 3) IS FALSE 1 0 1 -1 1 1 create or replace view v1 as select charset(2 LIKE 3 COLLATE latin1_bin), charset(2 LIKE (3 COLLATE latin1_bin)), charset((2 LIKE 3) COLLATE latin1_bin); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -3819,12 +3786,12 @@ select charset(2 LIKE 3 COLLATE latin1_bin), charset(2 LIKE (3 COLLATE latin1_bi charset(2 LIKE 3 COLLATE latin1_bin) charset(2 LIKE (3 COLLATE latin1_bin)) charset((2 LIKE 3) COLLATE latin1_bin) binary binary latin1 create or replace view v1 as select 2 LIKE 3 IN (0,1), 2 LIKE (3 IN (0,1)), (2 LIKE 3) IN (0,1); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (0,1), 2 LIKE (3 IN (0,1)), (2 LIKE 3) IN (0,1)' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select charset(2 like 3 collate latin1_bin) AS `charset(2 LIKE 3 COLLATE latin1_bin)`,charset(2 like 3 collate latin1_bin) AS `charset(2 LIKE (3 COLLATE latin1_bin))`,charset((2 like 3) collate latin1_bin) AS `charset((2 LIKE 3) COLLATE latin1_bin)` +select 2 like 3 in (0,1) AS `2 LIKE 3 IN (0,1)`,2 like (3 in (0,1)) AS `2 LIKE (3 IN (0,1))`,2 like 3 in (0,1) AS `(2 LIKE 3) IN (0,1)` select 2 LIKE 3 IN (0,1), 2 LIKE (3 IN (0,1)), (2 LIKE 3) IN (0,1) union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (0,1), 2 LIKE (3 IN (0,1)), (2 LIKE 3) IN (0,1) union select * from v1' at line 1 +2 LIKE 3 IN (0,1) 2 LIKE (3 IN (0,1)) (2 LIKE 3) IN (0,1) +1 0 1 create or replace view v1 as select 2 LIKE 3 OR 3, 2 LIKE (3 OR 3), (2 LIKE 3) OR 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -3863,179 +3830,171 @@ select 2 LIKE 2 && 2, 2 LIKE (2 && 2), (2 LIKE 2) && 2 union select * from v1; create or replace view v1 as select 2 LIKE 2 = 1, 2 LIKE (2 = 1), (2 LIKE 2) = 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 2 = 1 AS `2 LIKE 2 = 1`,2 like 2 = 1 AS `2 LIKE (2 = 1)`,2 like 2 = 1 AS `(2 LIKE 2) = 1` +select 2 like 2 = 1 AS `2 LIKE 2 = 1`,2 like (2 = 1) AS `2 LIKE (2 = 1)`,2 like 2 = 1 AS `(2 LIKE 2) = 1` select 2 LIKE 2 = 1, 2 LIKE (2 = 1), (2 LIKE 2) = 1 union select * from v1; 2 LIKE 2 = 1 2 LIKE (2 = 1) (2 LIKE 2) = 1 1 0 1 -1 1 1 create or replace view v1 as select 2 LIKE 2 <=> 1, 2 LIKE (2 <=> 1), (2 LIKE 2) <=> 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 2 <=> 1 AS `2 LIKE 2 <=> 1`,2 like 2 <=> 1 AS `2 LIKE (2 <=> 1)`,2 like 2 <=> 1 AS `(2 LIKE 2) <=> 1` +select 2 like 2 <=> 1 AS `2 LIKE 2 <=> 1`,2 like (2 <=> 1) AS `2 LIKE (2 <=> 1)`,2 like 2 <=> 1 AS `(2 LIKE 2) <=> 1` select 2 LIKE 2 <=> 1, 2 LIKE (2 <=> 1), (2 LIKE 2) <=> 1 union select * from v1; 2 LIKE 2 <=> 1 2 LIKE (2 <=> 1) (2 LIKE 2) <=> 1 1 0 1 -1 1 1 create or replace view v1 as select 2 LIKE 2 >= 1, 2 LIKE (2 >= 1), (2 LIKE 2) >= 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 2 >= 1 AS `2 LIKE 2 >= 1`,2 like 2 >= 1 AS `2 LIKE (2 >= 1)`,2 like 2 >= 1 AS `(2 LIKE 2) >= 1` +select 2 like 2 >= 1 AS `2 LIKE 2 >= 1`,2 like (2 >= 1) AS `2 LIKE (2 >= 1)`,2 like 2 >= 1 AS `(2 LIKE 2) >= 1` select 2 LIKE 2 >= 1, 2 LIKE (2 >= 1), (2 LIKE 2) >= 1 union select * from v1; 2 LIKE 2 >= 1 2 LIKE (2 >= 1) (2 LIKE 2) >= 1 1 0 1 -1 1 1 create or replace view v1 as select 2 LIKE 3 <= 3, 2 LIKE (3 <= 3), (2 LIKE 3) <= 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <= 3 AS `2 LIKE 3 <= 3`,2 like 3 <= 3 AS `2 LIKE (3 <= 3)`,2 like 3 <= 3 AS `(2 LIKE 3) <= 3` +select 2 like 3 <= 3 AS `2 LIKE 3 <= 3`,2 like (3 <= 3) AS `2 LIKE (3 <= 3)`,2 like 3 <= 3 AS `(2 LIKE 3) <= 3` select 2 LIKE 3 <= 3, 2 LIKE (3 <= 3), (2 LIKE 3) <= 3 union select * from v1; 2 LIKE 3 <= 3 2 LIKE (3 <= 3) (2 LIKE 3) <= 3 1 0 1 -1 1 1 create or replace view v1 as select 2 LIKE 3 < 3, 2 LIKE (3 < 3), (2 LIKE 3) < 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 < 3 AS `2 LIKE 3 < 3`,2 like 3 < 3 AS `2 LIKE (3 < 3)`,2 like 3 < 3 AS `(2 LIKE 3) < 3` +select 2 like 3 < 3 AS `2 LIKE 3 < 3`,2 like (3 < 3) AS `2 LIKE (3 < 3)`,2 like 3 < 3 AS `(2 LIKE 3) < 3` select 2 LIKE 3 < 3, 2 LIKE (3 < 3), (2 LIKE 3) < 3 union select * from v1; 2 LIKE 3 < 3 2 LIKE (3 < 3) (2 LIKE 3) < 3 1 0 1 -1 1 1 create or replace view v1 as select 2 LIKE 3 <> 3, 2 LIKE (3 <> 3), (2 LIKE 3) <> 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 <> 3`,2 like 3 <> 3 AS `2 LIKE (3 <> 3)`,2 like 3 <> 3 AS `(2 LIKE 3) <> 3` +select 2 like 3 <> 3 AS `2 LIKE 3 <> 3`,2 like (3 <> 3) AS `2 LIKE (3 <> 3)`,2 like 3 <> 3 AS `(2 LIKE 3) <> 3` select 2 LIKE 3 <> 3, 2 LIKE (3 <> 3), (2 LIKE 3) <> 3 union select * from v1; 2 LIKE 3 <> 3 2 LIKE (3 <> 3) (2 LIKE 3) <> 3 1 0 1 -1 1 1 create or replace view v1 as select 2 LIKE 2 > 0, 2 LIKE (2 > 0), (2 LIKE 2) > 0; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 2 > 0 AS `2 LIKE 2 > 0`,2 like 2 > 0 AS `2 LIKE (2 > 0)`,2 like 2 > 0 AS `(2 LIKE 2) > 0` +select 2 like 2 > 0 AS `2 LIKE 2 > 0`,2 like (2 > 0) AS `2 LIKE (2 > 0)`,2 like 2 > 0 AS `(2 LIKE 2) > 0` select 2 LIKE 2 > 0, 2 LIKE (2 > 0), (2 LIKE 2) > 0 union select * from v1; 2 LIKE 2 > 0 2 LIKE (2 > 0) (2 LIKE 2) > 0 1 0 1 -1 1 1 create or replace view v1 as select 2 LIKE 3 != 3, 2 LIKE (3 != 3), (2 LIKE 3) != 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like (3 <> 3) AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` select 2 LIKE 3 != 3, 2 LIKE (3 != 3), (2 LIKE 3) != 3 union select * from v1; 2 LIKE 3 != 3 2 LIKE (3 != 3) (2 LIKE 3) != 3 1 0 1 -1 1 1 create or replace view v1 as select 2 LIKE 2 LIKE 1, 2 LIKE (2 LIKE 1), (2 LIKE 2) LIKE 1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE 1, 2 LIKE (2 LIKE 1), (2 LIKE 2) LIKE 1' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 2 like 1 AS `2 LIKE 2 LIKE 1`,2 like (2 like 1) AS `2 LIKE (2 LIKE 1)`,2 like 2 like 1 AS `(2 LIKE 2) LIKE 1` select 2 LIKE 2 LIKE 1, 2 LIKE (2 LIKE 1), (2 LIKE 2) LIKE 1 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE 1, 2 LIKE (2 LIKE 1), (2 LIKE 2) LIKE 1 union select * from v1' at line 1 +2 LIKE 2 LIKE 1 2 LIKE (2 LIKE 1) (2 LIKE 2) LIKE 1 +1 0 1 create or replace view v1 as select 2 LIKE 2 REGEXP 1, 2 LIKE (2 REGEXP 1), (2 LIKE 2) REGEXP 1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'REGEXP 1, 2 LIKE (2 REGEXP 1), (2 LIKE 2) REGEXP 1' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 2 regexp 1 AS `2 LIKE 2 REGEXP 1`,2 like (2 regexp 1) AS `2 LIKE (2 REGEXP 1)`,2 like 2 regexp 1 AS `(2 LIKE 2) REGEXP 1` select 2 LIKE 2 REGEXP 1, 2 LIKE (2 REGEXP 1), (2 LIKE 2) REGEXP 1 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'REGEXP 1, 2 LIKE (2 REGEXP 1), (2 LIKE 2) REGEXP 1 union select * from v1' at line 1 +2 LIKE 2 REGEXP 1 2 LIKE (2 REGEXP 1) (2 LIKE 2) REGEXP 1 +1 0 1 create or replace view v1 as select 2 LIKE 3 | 3, 2 LIKE (3 | 3), (2 LIKE 3) | 3; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '| 3, 2 LIKE (3 | 3), (2 LIKE 3) | 3' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 3 | 3 AS `2 LIKE 3 | 3`,2 like 3 | 3 AS `2 LIKE (3 | 3)`,(2 like 3) | 3 AS `(2 LIKE 3) | 3` select 2 LIKE 3 | 3, 2 LIKE (3 | 3), (2 LIKE 3) | 3 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '| 3, 2 LIKE (3 | 3), (2 LIKE 3) | 3 union select * from v1' at line 1 +2 LIKE 3 | 3 2 LIKE (3 | 3) (2 LIKE 3) | 3 +0 0 3 create or replace view v1 as select 2 LIKE 2 & 2, 2 LIKE (2 & 2), (2 LIKE 2) & 2; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '& 2, 2 LIKE (2 & 2), (2 LIKE 2) & 2' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 2 & 2 AS `2 LIKE 2 & 2`,2 like 2 & 2 AS `2 LIKE (2 & 2)`,(2 like 2) & 2 AS `(2 LIKE 2) & 2` select 2 LIKE 2 & 2, 2 LIKE (2 & 2), (2 LIKE 2) & 2 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '& 2, 2 LIKE (2 & 2), (2 LIKE 2) & 2 union select * from v1' at line 1 +2 LIKE 2 & 2 2 LIKE (2 & 2) (2 LIKE 2) & 2 +1 1 0 create or replace view v1 as select 2 LIKE 2 << 2, 2 LIKE (2 << 2), (2 LIKE 2) << 2; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '<< 2, 2 LIKE (2 << 2), (2 LIKE 2) << 2' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 2 << 2 AS `2 LIKE 2 << 2`,2 like 2 << 2 AS `2 LIKE (2 << 2)`,(2 like 2) << 2 AS `(2 LIKE 2) << 2` select 2 LIKE 2 << 2, 2 LIKE (2 << 2), (2 LIKE 2) << 2 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '<< 2, 2 LIKE (2 << 2), (2 LIKE 2) << 2 union select * from v1' at line 1 +2 LIKE 2 << 2 2 LIKE (2 << 2) (2 LIKE 2) << 2 +0 0 4 create or replace view v1 as select 2 LIKE 4 >> 1, 2 LIKE (4 >> 1), (2 LIKE 4) >> 1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '>> 1, 2 LIKE (4 >> 1), (2 LIKE 4) >> 1' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 4 >> 1 AS `2 LIKE 4 >> 1`,2 like 4 >> 1 AS `2 LIKE (4 >> 1)`,(2 like 4) >> 1 AS `(2 LIKE 4) >> 1` select 2 LIKE 4 >> 1, 2 LIKE (4 >> 1), (2 LIKE 4) >> 1 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '>> 1, 2 LIKE (4 >> 1), (2 LIKE 4) >> 1 union select * from v1' at line 1 +2 LIKE 4 >> 1 2 LIKE (4 >> 1) (2 LIKE 4) >> 1 +1 1 0 create or replace view v1 as select 2 LIKE '2000-01-01' +INTERVAL 1 DAY, 2 LIKE ('2000-01-01' +INTERVAL 1 DAY), (2 LIKE '2000-01-01') +INTERVAL 1 DAY; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+INTERVAL 1 DAY, 2 LIKE ('2000-01-01' +INTERVAL 1 DAY), (2 LIKE '2000-01-01')...' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like '2000-01-01' + interval 1 day AS `2 LIKE '2000-01-01' +INTERVAL 1 DAY`,2 like '2000-01-01' + interval 1 day AS `2 LIKE ('2000-01-01' +INTERVAL 1 DAY)`,(2 like '2000-01-01') + interval 1 day AS `(2 LIKE '2000-01-01') +INTERVAL 1 DAY` select 2 LIKE '2000-01-01' +INTERVAL 1 DAY, 2 LIKE ('2000-01-01' +INTERVAL 1 DAY), (2 LIKE '2000-01-01') +INTERVAL 1 DAY union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+INTERVAL 1 DAY, 2 LIKE ('2000-01-01' +INTERVAL 1 DAY), (2 LIKE '2000-01-01')...' at line 1 +2 LIKE '2000-01-01' +INTERVAL 1 DAY 2 LIKE ('2000-01-01' +INTERVAL 1 DAY) (2 LIKE '2000-01-01') +INTERVAL 1 DAY +0 0 NULL create or replace view v1 as select 2 LIKE 3 + 3, 2 LIKE (3 + 3), (2 LIKE 3) + 3; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+ 3, 2 LIKE (3 + 3), (2 LIKE 3) + 3' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 3 + 3 AS `2 LIKE 3 + 3`,2 like 3 + 3 AS `2 LIKE (3 + 3)`,(2 like 3) + 3 AS `(2 LIKE 3) + 3` select 2 LIKE 3 + 3, 2 LIKE (3 + 3), (2 LIKE 3) + 3 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+ 3, 2 LIKE (3 + 3), (2 LIKE 3) + 3 union select * from v1' at line 1 +2 LIKE 3 + 3 2 LIKE (3 + 3) (2 LIKE 3) + 3 +0 0 3 create or replace view v1 as select 2 LIKE 3 - 3, 2 LIKE (3 - 3), (2 LIKE 3) - 3; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '- 3, 2 LIKE (3 - 3), (2 LIKE 3) - 3' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 3 - 3 AS `2 LIKE 3 - 3`,2 like 3 - 3 AS `2 LIKE (3 - 3)`,(2 like 3) - 3 AS `(2 LIKE 3) - 3` select 2 LIKE 3 - 3, 2 LIKE (3 - 3), (2 LIKE 3) - 3 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '- 3, 2 LIKE (3 - 3), (2 LIKE 3) - 3 union select * from v1' at line 1 +2 LIKE 3 - 3 2 LIKE (3 - 3) (2 LIKE 3) - 3 +0 0 -3 create or replace view v1 as select 2 LIKE 2 * 2, 2 LIKE (2 * 2), (2 LIKE 2) * 2; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '* 2, 2 LIKE (2 * 2), (2 LIKE 2) * 2' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 2 * 2 AS `2 LIKE 2 * 2`,2 like 2 * 2 AS `2 LIKE (2 * 2)`,(2 like 2) * 2 AS `(2 LIKE 2) * 2` select 2 LIKE 2 * 2, 2 LIKE (2 * 2), (2 LIKE 2) * 2 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '* 2, 2 LIKE (2 * 2), (2 LIKE 2) * 2 union select * from v1' at line 1 +2 LIKE 2 * 2 2 LIKE (2 * 2) (2 LIKE 2) * 2 +0 0 2 create or replace view v1 as select 2 LIKE 2 / 2, 2 LIKE (2 / 2), (2 LIKE 2) / 2; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '/ 2, 2 LIKE (2 / 2), (2 LIKE 2) / 2' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 2 / 2 AS `2 LIKE 2 / 2`,2 like 2 / 2 AS `2 LIKE (2 / 2)`,(2 like 2) / 2 AS `(2 LIKE 2) / 2` select 2 LIKE 2 / 2, 2 LIKE (2 / 2), (2 LIKE 2) / 2 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '/ 2, 2 LIKE (2 / 2), (2 LIKE 2) / 2 union select * from v1' at line 1 +2 LIKE 2 / 2 2 LIKE (2 / 2) (2 LIKE 2) / 2 +0 0 0.5000 create or replace view v1 as select 2 LIKE 4 DIV 2, 2 LIKE (4 DIV 2), (2 LIKE 4) DIV 2; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'DIV 2, 2 LIKE (4 DIV 2), (2 LIKE 4) DIV 2' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 4 DIV 2 AS `2 LIKE 4 DIV 2`,2 like 4 DIV 2 AS `2 LIKE (4 DIV 2)`,(2 like 4) DIV 2 AS `(2 LIKE 4) DIV 2` select 2 LIKE 4 DIV 2, 2 LIKE (4 DIV 2), (2 LIKE 4) DIV 2 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'DIV 2, 2 LIKE (4 DIV 2), (2 LIKE 4) DIV 2 union select * from v1' at line 1 +2 LIKE 4 DIV 2 2 LIKE (4 DIV 2) (2 LIKE 4) DIV 2 +1 1 0 create or replace view v1 as select 2 LIKE 2 MOD 2, 2 LIKE (2 MOD 2), (2 LIKE 2) MOD 2; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'MOD 2, 2 LIKE (2 MOD 2), (2 LIKE 2) MOD 2' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 2 % 2 AS `2 LIKE 2 MOD 2`,2 like 2 % 2 AS `2 LIKE (2 MOD 2)`,(2 like 2) % 2 AS `(2 LIKE 2) MOD 2` select 2 LIKE 2 MOD 2, 2 LIKE (2 MOD 2), (2 LIKE 2) MOD 2 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'MOD 2, 2 LIKE (2 MOD 2), (2 LIKE 2) MOD 2 union select * from v1' at line 1 +2 LIKE 2 MOD 2 2 LIKE (2 MOD 2) (2 LIKE 2) MOD 2 +0 0 1 create or replace view v1 as select 2 LIKE 2 % 2, 2 LIKE (2 % 2), (2 LIKE 2) % 2; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '% 2, 2 LIKE (2 % 2), (2 LIKE 2) % 2' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 2 % 2 AS `2 LIKE 2 % 2`,2 like 2 % 2 AS `2 LIKE (2 % 2)`,(2 like 2) % 2 AS `(2 LIKE 2) % 2` select 2 LIKE 2 % 2, 2 LIKE (2 % 2), (2 LIKE 2) % 2 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '% 2, 2 LIKE (2 % 2), (2 LIKE 2) % 2 union select * from v1' at line 1 +2 LIKE 2 % 2 2 LIKE (2 % 2) (2 LIKE 2) % 2 +0 0 1 create or replace view v1 as select 2 LIKE 3 ^ 3, 2 LIKE (3 ^ 3), (2 LIKE 3) ^ 3; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '^ 3, 2 LIKE (3 ^ 3), (2 LIKE 3) ^ 3' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 3 ^ 3 AS `2 LIKE 3 ^ 3`,2 like 3 ^ 3 AS `2 LIKE (3 ^ 3)`,(2 like 3) ^ 3 AS `(2 LIKE 3) ^ 3` select 2 LIKE 3 ^ 3, 2 LIKE (3 ^ 3), (2 LIKE 3) ^ 3 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '^ 3, 2 LIKE (3 ^ 3), (2 LIKE 3) ^ 3 union select * from v1' at line 1 +2 LIKE 3 ^ 3 2 LIKE (3 ^ 3) (2 LIKE 3) ^ 3 +0 0 3 create or replace view v1 as select 2 LIKE 2 BETWEEN 1 AND 3, 2 LIKE (2 BETWEEN 1 AND 3), (2 LIKE 2) BETWEEN 1 AND 3; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'BETWEEN 1 AND 3, 2 LIKE (2 BETWEEN 1 AND 3), (2 LIKE 2) BETWEEN 1 AND 3' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 3 <> 3 AS `2 LIKE 3 != 3`,2 like 3 <> 3 AS `2 LIKE (3 != 3)`,2 like 3 <> 3 AS `(2 LIKE 3) != 3` +select 2 like 2 between 1 and 3 AS `2 LIKE 2 BETWEEN 1 AND 3`,2 like (2 between 1 and 3) AS `2 LIKE (2 BETWEEN 1 AND 3)`,2 like 2 between 1 and 3 AS `(2 LIKE 2) BETWEEN 1 AND 3` select 2 LIKE 2 BETWEEN 1 AND 3, 2 LIKE (2 BETWEEN 1 AND 3), (2 LIKE 2) BETWEEN 1 AND 3 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'BETWEEN 1 AND 3, 2 LIKE (2 BETWEEN 1 AND 3), (2 LIKE 2) BETWEEN 1 AND 3 union...' at line 1 +2 LIKE 2 BETWEEN 1 AND 3 2 LIKE (2 BETWEEN 1 AND 3) (2 LIKE 2) BETWEEN 1 AND 3 +1 0 1 create or replace view v1 as select 2 REGEXP 3 IS FALSE, 2 REGEXP (3 IS FALSE), (2 REGEXP 3) IS FALSE; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -4051,12 +4010,12 @@ select charset(2 REGEXP 3 COLLATE latin1_bin), charset(2 REGEXP (3 COLLATE latin charset(2 REGEXP 3 COLLATE latin1_bin) charset(2 REGEXP (3 COLLATE latin1_bin)) charset((2 REGEXP 3) COLLATE latin1_bin) binary binary latin1 create or replace view v1 as select 2 REGEXP 3 IN (0,1), 2 REGEXP (3 IN (0,1)), (2 REGEXP 3) IN (0,1); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (0,1), 2 REGEXP (3 IN (0,1)), (2 REGEXP 3) IN (0,1)' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select charset(2 regexp 3 collate latin1_bin) AS `charset(2 REGEXP 3 COLLATE latin1_bin)`,charset(2 regexp 3 collate latin1_bin) AS `charset(2 REGEXP (3 COLLATE latin1_bin))`,charset((2 regexp 3) collate latin1_bin) AS `charset((2 REGEXP 3) COLLATE latin1_bin)` +select 2 regexp 3 in (0,1) AS `2 REGEXP 3 IN (0,1)`,2 regexp (3 in (0,1)) AS `2 REGEXP (3 IN (0,1))`,2 regexp 3 in (0,1) AS `(2 REGEXP 3) IN (0,1)` select 2 REGEXP 3 IN (0,1), 2 REGEXP (3 IN (0,1)), (2 REGEXP 3) IN (0,1) union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (0,1), 2 REGEXP (3 IN (0,1)), (2 REGEXP 3) IN (0,1) union select * from v1' at line 1 +2 REGEXP 3 IN (0,1) 2 REGEXP (3 IN (0,1)) (2 REGEXP 3) IN (0,1) +1 0 1 create or replace view v1 as select 2 REGEXP 3 OR 3, 2 REGEXP (3 OR 3), (2 REGEXP 3) OR 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -4149,19 +4108,19 @@ select 2 REGEXP 3 != 3, 2 REGEXP (3 != 3), (2 REGEXP 3) != 3 union select * from 2 REGEXP 3 != 3 2 REGEXP (3 != 3) (2 REGEXP 3) != 3 1 0 1 create or replace view v1 as select 1 REGEXP 3 LIKE 3, 1 REGEXP (3 LIKE 3), (1 REGEXP 3) LIKE 3; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE 3, 1 REGEXP (3 LIKE 3), (1 REGEXP 3) LIKE 3' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 regexp 3 <> 3 AS `2 REGEXP 3 != 3`,2 regexp (3 <> 3) AS `2 REGEXP (3 != 3)`,2 regexp 3 <> 3 AS `(2 REGEXP 3) != 3` +select 1 regexp 3 like 3 AS `1 REGEXP 3 LIKE 3`,1 regexp (3 like 3) AS `1 REGEXP (3 LIKE 3)`,1 regexp 3 like 3 AS `(1 REGEXP 3) LIKE 3` select 1 REGEXP 3 LIKE 3, 1 REGEXP (3 LIKE 3), (1 REGEXP 3) LIKE 3 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE 3, 1 REGEXP (3 LIKE 3), (1 REGEXP 3) LIKE 3 union select * from v1' at line 1 +1 REGEXP 3 LIKE 3 1 REGEXP (3 LIKE 3) (1 REGEXP 3) LIKE 3 +0 1 0 create or replace view v1 as select 1 REGEXP 3 REGEXP 3, 1 REGEXP (3 REGEXP 3), (1 REGEXP 3) REGEXP 3; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'REGEXP 3, 1 REGEXP (3 REGEXP 3), (1 REGEXP 3) REGEXP 3' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 regexp 3 <> 3 AS `2 REGEXP 3 != 3`,2 regexp (3 <> 3) AS `2 REGEXP (3 != 3)`,2 regexp 3 <> 3 AS `(2 REGEXP 3) != 3` +select 1 regexp 3 regexp 3 AS `1 REGEXP 3 REGEXP 3`,1 regexp (3 regexp 3) AS `1 REGEXP (3 REGEXP 3)`,1 regexp 3 regexp 3 AS `(1 REGEXP 3) REGEXP 3` select 1 REGEXP 3 REGEXP 3, 1 REGEXP (3 REGEXP 3), (1 REGEXP 3) REGEXP 3 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'REGEXP 3, 1 REGEXP (3 REGEXP 3), (1 REGEXP 3) REGEXP 3 union select * from v1' at line 1 +1 REGEXP 3 REGEXP 3 1 REGEXP (3 REGEXP 3) (1 REGEXP 3) REGEXP 3 +0 1 0 create or replace view v1 as select 2 REGEXP 3 | 3, 2 REGEXP (3 | 3), (2 REGEXP 3) | 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -4254,12 +4213,12 @@ select 2 REGEXP 3 ^ 3, 2 REGEXP (3 ^ 3), (2 REGEXP 3) ^ 3 union select * from v1 2 REGEXP 3 ^ 3 2 REGEXP (3 ^ 3) (2 REGEXP 3) ^ 3 0 0 3 create or replace view v1 as select 2 REGEXP 2 BETWEEN 1 AND 3, 2 REGEXP (2 BETWEEN 1 AND 3), (2 REGEXP 2) BETWEEN 1 AND 3; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'BETWEEN 1 AND 3, 2 REGEXP (2 BETWEEN 1 AND 3), (2 REGEXP 2) BETWEEN 1 AND 3' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 regexp 3 ^ 3 AS `2 REGEXP 3 ^ 3`,2 regexp 3 ^ 3 AS `2 REGEXP (3 ^ 3)`,(2 regexp 3) ^ 3 AS `(2 REGEXP 3) ^ 3` +select 2 regexp 2 between 1 and 3 AS `2 REGEXP 2 BETWEEN 1 AND 3`,2 regexp (2 between 1 and 3) AS `2 REGEXP (2 BETWEEN 1 AND 3)`,2 regexp 2 between 1 and 3 AS `(2 REGEXP 2) BETWEEN 1 AND 3` select 2 REGEXP 2 BETWEEN 1 AND 3, 2 REGEXP (2 BETWEEN 1 AND 3), (2 REGEXP 2) BETWEEN 1 AND 3 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'BETWEEN 1 AND 3, 2 REGEXP (2 BETWEEN 1 AND 3), (2 REGEXP 2) BETWEEN 1 AND 3 u...' at line 1 +2 REGEXP 2 BETWEEN 1 AND 3 2 REGEXP (2 BETWEEN 1 AND 3) (2 REGEXP 2) BETWEEN 1 AND 3 +1 0 1 create or replace view v1 as select 2 | 3 IS FALSE, 2 | (3 IS FALSE), (2 | 3) IS FALSE; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -6896,11 +6855,10 @@ select 2 ^ 3 BETWEEN 1 AND 3, 2 ^ (3 BETWEEN 1 AND 3), (2 ^ 3) BETWEEN 1 AND 3 u create or replace view v1 as select 2 BETWEEN 1 AND 1 IS FALSE, 2 BETWEEN 1 AND (1 IS FALSE), (2 BETWEEN 1 AND 1) IS FALSE; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select (2 between 1 and 1) is false AS `2 BETWEEN 1 AND 1 IS FALSE`,2 between 1 and 1 is false AS `2 BETWEEN 1 AND (1 IS FALSE)`,(2 between 1 and 1) is false AS `(2 BETWEEN 1 AND 1) IS FALSE` +select 2 between 1 and 1 is false AS `2 BETWEEN 1 AND 1 IS FALSE`,2 between 1 and (1 is false) AS `2 BETWEEN 1 AND (1 IS FALSE)`,2 between 1 and 1 is false AS `(2 BETWEEN 1 AND 1) IS FALSE` select 2 BETWEEN 1 AND 1 IS FALSE, 2 BETWEEN 1 AND (1 IS FALSE), (2 BETWEEN 1 AND 1) IS FALSE union select * from v1; 2 BETWEEN 1 AND 1 IS FALSE 2 BETWEEN 1 AND (1 IS FALSE) (2 BETWEEN 1 AND 1) IS FALSE 1 0 1 -1 1 1 create or replace view v1 as select charset(2 BETWEEN 1 AND 3 COLLATE latin1_bin), charset(2 BETWEEN 1 AND (3 COLLATE latin1_bin)), charset((2 BETWEEN 1 AND 3) COLLATE latin1_bin); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -6953,67 +6911,59 @@ select 2 BETWEEN 1 AND 3 && 3, 2 BETWEEN 1 AND (3 && 3), (2 BETWEEN 1 AND 3) && create or replace view v1 as select 2 BETWEEN 1 AND 3 = 1, 2 BETWEEN 1 AND (3 = 1), (2 BETWEEN 1 AND 3) = 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select (2 between 1 and 3) = 1 AS `2 BETWEEN 1 AND 3 = 1`,2 between 1 and 3 = 1 AS `2 BETWEEN 1 AND (3 = 1)`,(2 between 1 and 3) = 1 AS `(2 BETWEEN 1 AND 3) = 1` +select 2 between 1 and 3 = 1 AS `2 BETWEEN 1 AND 3 = 1`,2 between 1 and (3 = 1) AS `2 BETWEEN 1 AND (3 = 1)`,2 between 1 and 3 = 1 AS `(2 BETWEEN 1 AND 3) = 1` select 2 BETWEEN 1 AND 3 = 1, 2 BETWEEN 1 AND (3 = 1), (2 BETWEEN 1 AND 3) = 1 union select * from v1; 2 BETWEEN 1 AND 3 = 1 2 BETWEEN 1 AND (3 = 1) (2 BETWEEN 1 AND 3) = 1 1 0 1 -1 1 1 create or replace view v1 as select 2 BETWEEN 1 AND 3 <=> 1, 2 BETWEEN 1 AND (3 <=> 1), (2 BETWEEN 1 AND 3) <=> 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select (2 between 1 and 3) <=> 1 AS `2 BETWEEN 1 AND 3 <=> 1`,2 between 1 and 3 <=> 1 AS `2 BETWEEN 1 AND (3 <=> 1)`,(2 between 1 and 3) <=> 1 AS `(2 BETWEEN 1 AND 3) <=> 1` +select 2 between 1 and 3 <=> 1 AS `2 BETWEEN 1 AND 3 <=> 1`,2 between 1 and (3 <=> 1) AS `2 BETWEEN 1 AND (3 <=> 1)`,2 between 1 and 3 <=> 1 AS `(2 BETWEEN 1 AND 3) <=> 1` select 2 BETWEEN 1 AND 3 <=> 1, 2 BETWEEN 1 AND (3 <=> 1), (2 BETWEEN 1 AND 3) <=> 1 union select * from v1; 2 BETWEEN 1 AND 3 <=> 1 2 BETWEEN 1 AND (3 <=> 1) (2 BETWEEN 1 AND 3) <=> 1 1 0 1 -1 1 1 create or replace view v1 as select 2 BETWEEN 1 AND 3 >= 1, 2 BETWEEN 1 AND (3 >= 1), (2 BETWEEN 1 AND 3) >= 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select (2 between 1 and 3) >= 1 AS `2 BETWEEN 1 AND 3 >= 1`,2 between 1 and 3 >= 1 AS `2 BETWEEN 1 AND (3 >= 1)`,(2 between 1 and 3) >= 1 AS `(2 BETWEEN 1 AND 3) >= 1` +select 2 between 1 and 3 >= 1 AS `2 BETWEEN 1 AND 3 >= 1`,2 between 1 and (3 >= 1) AS `2 BETWEEN 1 AND (3 >= 1)`,2 between 1 and 3 >= 1 AS `(2 BETWEEN 1 AND 3) >= 1` select 2 BETWEEN 1 AND 3 >= 1, 2 BETWEEN 1 AND (3 >= 1), (2 BETWEEN 1 AND 3) >= 1 union select * from v1; 2 BETWEEN 1 AND 3 >= 1 2 BETWEEN 1 AND (3 >= 1) (2 BETWEEN 1 AND 3) >= 1 1 0 1 -1 1 1 create or replace view v1 as select 2 BETWEEN 1 AND 3 <= 3, 2 BETWEEN 1 AND (3 <= 3), (2 BETWEEN 1 AND 3) <= 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select (2 between 1 and 3) <= 3 AS `2 BETWEEN 1 AND 3 <= 3`,2 between 1 and 3 <= 3 AS `2 BETWEEN 1 AND (3 <= 3)`,(2 between 1 and 3) <= 3 AS `(2 BETWEEN 1 AND 3) <= 3` +select 2 between 1 and 3 <= 3 AS `2 BETWEEN 1 AND 3 <= 3`,2 between 1 and (3 <= 3) AS `2 BETWEEN 1 AND (3 <= 3)`,2 between 1 and 3 <= 3 AS `(2 BETWEEN 1 AND 3) <= 3` select 2 BETWEEN 1 AND 3 <= 3, 2 BETWEEN 1 AND (3 <= 3), (2 BETWEEN 1 AND 3) <= 3 union select * from v1; 2 BETWEEN 1 AND 3 <= 3 2 BETWEEN 1 AND (3 <= 3) (2 BETWEEN 1 AND 3) <= 3 1 0 1 -1 1 1 create or replace view v1 as select 2 BETWEEN 1 AND 3 < 3, 2 BETWEEN 1 AND (3 < 3), (2 BETWEEN 1 AND 3) < 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select (2 between 1 and 3) < 3 AS `2 BETWEEN 1 AND 3 < 3`,2 between 1 and 3 < 3 AS `2 BETWEEN 1 AND (3 < 3)`,(2 between 1 and 3) < 3 AS `(2 BETWEEN 1 AND 3) < 3` +select 2 between 1 and 3 < 3 AS `2 BETWEEN 1 AND 3 < 3`,2 between 1 and (3 < 3) AS `2 BETWEEN 1 AND (3 < 3)`,2 between 1 and 3 < 3 AS `(2 BETWEEN 1 AND 3) < 3` select 2 BETWEEN 1 AND 3 < 3, 2 BETWEEN 1 AND (3 < 3), (2 BETWEEN 1 AND 3) < 3 union select * from v1; 2 BETWEEN 1 AND 3 < 3 2 BETWEEN 1 AND (3 < 3) (2 BETWEEN 1 AND 3) < 3 1 0 1 -1 1 1 create or replace view v1 as select 2 BETWEEN 1 AND 3 <> 3, 2 BETWEEN 1 AND (3 <> 3), (2 BETWEEN 1 AND 3) <> 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select (2 between 1 and 3) <> 3 AS `2 BETWEEN 1 AND 3 <> 3`,2 between 1 and 3 <> 3 AS `2 BETWEEN 1 AND (3 <> 3)`,(2 between 1 and 3) <> 3 AS `(2 BETWEEN 1 AND 3) <> 3` +select 2 between 1 and 3 <> 3 AS `2 BETWEEN 1 AND 3 <> 3`,2 between 1 and (3 <> 3) AS `2 BETWEEN 1 AND (3 <> 3)`,2 between 1 and 3 <> 3 AS `(2 BETWEEN 1 AND 3) <> 3` select 2 BETWEEN 1 AND 3 <> 3, 2 BETWEEN 1 AND (3 <> 3), (2 BETWEEN 1 AND 3) <> 3 union select * from v1; 2 BETWEEN 1 AND 3 <> 3 2 BETWEEN 1 AND (3 <> 3) (2 BETWEEN 1 AND 3) <> 3 1 0 1 -1 1 1 create or replace view v1 as select 2 BETWEEN 1 AND 3 > 0, 2 BETWEEN 1 AND (3 > 0), (2 BETWEEN 1 AND 3) > 0; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select (2 between 1 and 3) > 0 AS `2 BETWEEN 1 AND 3 > 0`,2 between 1 and 3 > 0 AS `2 BETWEEN 1 AND (3 > 0)`,(2 between 1 and 3) > 0 AS `(2 BETWEEN 1 AND 3) > 0` +select 2 between 1 and 3 > 0 AS `2 BETWEEN 1 AND 3 > 0`,2 between 1 and (3 > 0) AS `2 BETWEEN 1 AND (3 > 0)`,2 between 1 and 3 > 0 AS `(2 BETWEEN 1 AND 3) > 0` select 2 BETWEEN 1 AND 3 > 0, 2 BETWEEN 1 AND (3 > 0), (2 BETWEEN 1 AND 3) > 0 union select * from v1; 2 BETWEEN 1 AND 3 > 0 2 BETWEEN 1 AND (3 > 0) (2 BETWEEN 1 AND 3) > 0 1 0 1 -1 1 1 create or replace view v1 as select 2 BETWEEN 1 AND 3 != 3, 2 BETWEEN 1 AND (3 != 3), (2 BETWEEN 1 AND 3) != 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select (2 between 1 and 3) <> 3 AS `2 BETWEEN 1 AND 3 != 3`,2 between 1 and 3 <> 3 AS `2 BETWEEN 1 AND (3 != 3)`,(2 between 1 and 3) <> 3 AS `(2 BETWEEN 1 AND 3) != 3` +select 2 between 1 and 3 <> 3 AS `2 BETWEEN 1 AND 3 != 3`,2 between 1 and (3 <> 3) AS `2 BETWEEN 1 AND (3 != 3)`,2 between 1 and 3 <> 3 AS `(2 BETWEEN 1 AND 3) != 3` select 2 BETWEEN 1 AND 3 != 3, 2 BETWEEN 1 AND (3 != 3), (2 BETWEEN 1 AND 3) != 3 union select * from v1; 2 BETWEEN 1 AND 3 != 3 2 BETWEEN 1 AND (3 != 3) (2 BETWEEN 1 AND 3) != 3 1 0 1 -1 1 1 create or replace view v1 as select 2 BETWEEN 1 AND 3 LIKE 1, 2 BETWEEN 1 AND (3 LIKE 1), (2 BETWEEN 1 AND 3) LIKE 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -7122,19 +7072,17 @@ select 2 BETWEEN 1 AND 3 ^ 3, 2 BETWEEN 1 AND (3 ^ 3), (2 BETWEEN 1 AND 3) ^ 3 u create or replace view v1 as select 2 BETWEEN 1 AND 3 BETWEEN 1 AND 3, 2 BETWEEN 1 AND (3 BETWEEN 1 AND 3), (2 BETWEEN 1 AND 3) BETWEEN 1 AND 3; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 between 1 and 3 between 1 and 3 AS `2 BETWEEN 1 AND 3 BETWEEN 1 AND 3`,2 between 1 and 3 between 1 and 3 AS `2 BETWEEN 1 AND (3 BETWEEN 1 AND 3)`,2 between 1 and 3 between 1 and 3 AS `(2 BETWEEN 1 AND 3) BETWEEN 1 AND 3` +select 2 between 1 and 3 between 1 and 3 AS `2 BETWEEN 1 AND 3 BETWEEN 1 AND 3`,2 between 1 and 3 between 1 and 3 AS `2 BETWEEN 1 AND (3 BETWEEN 1 AND 3)`,(2 between 1 and 3) between 1 and 3 AS `(2 BETWEEN 1 AND 3) BETWEEN 1 AND 3` select 2 BETWEEN 1 AND 3 BETWEEN 1 AND 3, 2 BETWEEN 1 AND (3 BETWEEN 1 AND 3), (2 BETWEEN 1 AND 3) BETWEEN 1 AND 3 union select * from v1; 2 BETWEEN 1 AND 3 BETWEEN 1 AND 3 2 BETWEEN 1 AND (3 BETWEEN 1 AND 3) (2 BETWEEN 1 AND 3) BETWEEN 1 AND 3 0 0 1 -0 0 0 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 IS FALSE, 2 LIKE 2 ESCAPE (3 IS FALSE), (2 LIKE 2 ESCAPE 3) IS FALSE; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 2 escape 3 is false AS `2 LIKE 2 ESCAPE 3 IS FALSE`,2 like 2 escape 3 is false AS `2 LIKE 2 ESCAPE (3 IS FALSE)`,2 like 2 escape 3 is false AS `(2 LIKE 2 ESCAPE 3) IS FALSE` +select 2 like 2 escape 3 is false AS `2 LIKE 2 ESCAPE 3 IS FALSE`,2 like 2 escape (3 is false) AS `2 LIKE 2 ESCAPE (3 IS FALSE)`,2 like 2 escape 3 is false AS `(2 LIKE 2 ESCAPE 3) IS FALSE` select 2 LIKE 2 ESCAPE 3 IS FALSE, 2 LIKE 2 ESCAPE (3 IS FALSE), (2 LIKE 2 ESCAPE 3) IS FALSE union select * from v1; 2 LIKE 2 ESCAPE 3 IS FALSE 2 LIKE 2 ESCAPE (3 IS FALSE) (2 LIKE 2 ESCAPE 3) IS FALSE 0 1 0 -0 0 0 create or replace view v1 as select charset(2 LIKE 1 ESCAPE 3 COLLATE latin1_bin), charset(2 LIKE 1 ESCAPE (3 COLLATE latin1_bin)), charset((2 LIKE 1 ESCAPE 3) COLLATE latin1_bin); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -7143,221 +7091,208 @@ select charset(2 LIKE 1 ESCAPE 3 COLLATE latin1_bin), charset(2 LIKE 1 ESCAPE (3 charset(2 LIKE 1 ESCAPE 3 COLLATE latin1_bin) charset(2 LIKE 1 ESCAPE (3 COLLATE latin1_bin)) charset((2 LIKE 1 ESCAPE 3) COLLATE latin1_bin) binary binary latin1 create or replace view v1 as select 2 LIKE 1 ESCAPE 3 IN(0,1), 2 LIKE 1 ESCAPE (3 IN(0,1)), (2 LIKE 1 ESCAPE 3) IN(0,1); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN(0,1), 2 LIKE 1 ESCAPE (3 IN(0,1)), (2 LIKE 1 ESCAPE 3) IN(0,1)' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select charset(2 like 1 escape 3 collate latin1_bin) AS `charset(2 LIKE 1 ESCAPE 3 COLLATE latin1_bin)`,charset(2 like 1 escape 3 collate latin1_bin) AS `charset(2 LIKE 1 ESCAPE (3 COLLATE latin1_bin))`,charset((2 like 1 escape 3) collate latin1_bin) AS `charset((2 LIKE 1 ESCAPE 3) COLLATE latin1_bin)` +select 2 like 1 escape 3 in (0,1) AS `2 LIKE 1 ESCAPE 3 IN(0,1)`,2 like 1 escape (3 in (0,1)) AS `2 LIKE 1 ESCAPE (3 IN(0,1))`,2 like 1 escape 3 in (0,1) AS `(2 LIKE 1 ESCAPE 3) IN(0,1)` select 2 LIKE 1 ESCAPE 3 IN(0,1), 2 LIKE 1 ESCAPE (3 IN(0,1)), (2 LIKE 1 ESCAPE 3) IN(0,1) union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN(0,1), 2 LIKE 1 ESCAPE (3 IN(0,1)), (2 LIKE 1 ESCAPE 3) IN(0,1) union selec...' at line 1 +2 LIKE 1 ESCAPE 3 IN(0,1) 2 LIKE 1 ESCAPE (3 IN(0,1)) (2 LIKE 1 ESCAPE 3) IN(0,1) +1 0 1 create or replace view v1 as select 2 LIKE 1 ESCAPE 3 OR 4, 2 LIKE 1 ESCAPE (3 OR 4), (2 LIKE 1 ESCAPE 3) OR 4; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 or 4 AS `2 LIKE 1 ESCAPE 3 OR 4`,2 like 1 escape 3 or 4 AS `2 LIKE 1 ESCAPE (3 OR 4)`,2 like 1 escape 3 or 4 AS `(2 LIKE 1 ESCAPE 3) OR 4` +select 2 like 1 escape 3 or 4 AS `2 LIKE 1 ESCAPE 3 OR 4`,2 like 1 escape (3 or 4) AS `2 LIKE 1 ESCAPE (3 OR 4)`,2 like 1 escape 3 or 4 AS `(2 LIKE 1 ESCAPE 3) OR 4` select 2 LIKE 1 ESCAPE 3 OR 4, 2 LIKE 1 ESCAPE (3 OR 4), (2 LIKE 1 ESCAPE 3) OR 4 union select * from v1; 2 LIKE 1 ESCAPE 3 OR 4 2 LIKE 1 ESCAPE (3 OR 4) (2 LIKE 1 ESCAPE 3) OR 4 1 0 1 -1 1 1 create or replace view v1 as select 2 LIKE 1 ESCAPE 3 || 4, 2 LIKE 1 ESCAPE (3 || 4), (2 LIKE 1 ESCAPE 3) || 4; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 or 4 AS `2 LIKE 1 ESCAPE 3 || 4`,2 like 1 escape 3 or 4 AS `2 LIKE 1 ESCAPE (3 || 4)`,2 like 1 escape 3 or 4 AS `(2 LIKE 1 ESCAPE 3) || 4` +select 2 like 1 escape 3 or 4 AS `2 LIKE 1 ESCAPE 3 || 4`,2 like 1 escape (3 or 4) AS `2 LIKE 1 ESCAPE (3 || 4)`,2 like 1 escape 3 or 4 AS `(2 LIKE 1 ESCAPE 3) || 4` select 2 LIKE 1 ESCAPE 3 || 4, 2 LIKE 1 ESCAPE (3 || 4), (2 LIKE 1 ESCAPE 3) || 4 union select * from v1; 2 LIKE 1 ESCAPE 3 || 4 2 LIKE 1 ESCAPE (3 || 4) (2 LIKE 1 ESCAPE 3) || 4 1 0 1 -1 1 1 create or replace view v1 as select 2 LIKE 1 ESCAPE 3 XOR 4, 2 LIKE 1 ESCAPE (3 XOR 4), (2 LIKE 1 ESCAPE 3) XOR 4; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 xor 4 AS `2 LIKE 1 ESCAPE 3 XOR 4`,2 like 1 escape 3 xor 4 AS `2 LIKE 1 ESCAPE (3 XOR 4)`,2 like 1 escape 3 xor 4 AS `(2 LIKE 1 ESCAPE 3) XOR 4` +select 2 like 1 escape 3 xor 4 AS `2 LIKE 1 ESCAPE 3 XOR 4`,2 like 1 escape (3 xor 4) AS `2 LIKE 1 ESCAPE (3 XOR 4)`,2 like 1 escape 3 xor 4 AS `(2 LIKE 1 ESCAPE 3) XOR 4` select 2 LIKE 1 ESCAPE 3 XOR 4, 2 LIKE 1 ESCAPE (3 XOR 4), (2 LIKE 1 ESCAPE 3) XOR 4 union select * from v1; 2 LIKE 1 ESCAPE 3 XOR 4 2 LIKE 1 ESCAPE (3 XOR 4) (2 LIKE 1 ESCAPE 3) XOR 4 1 0 1 -1 1 1 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 AND 0, 2 LIKE 2 ESCAPE (3 AND 0), (2 LIKE 2 ESCAPE 3) AND 0; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 2 escape 3 and 0 AS `2 LIKE 2 ESCAPE 3 AND 0`,2 like 2 escape 3 and 0 AS `2 LIKE 2 ESCAPE (3 AND 0)`,2 like 2 escape 3 and 0 AS `(2 LIKE 2 ESCAPE 3) AND 0` +select 2 like 2 escape 3 and 0 AS `2 LIKE 2 ESCAPE 3 AND 0`,2 like 2 escape (3 and 0) AS `2 LIKE 2 ESCAPE (3 AND 0)`,2 like 2 escape 3 and 0 AS `(2 LIKE 2 ESCAPE 3) AND 0` select 2 LIKE 2 ESCAPE 3 AND 0, 2 LIKE 2 ESCAPE (3 AND 0), (2 LIKE 2 ESCAPE 3) AND 0 union select * from v1; 2 LIKE 2 ESCAPE 3 AND 0 2 LIKE 2 ESCAPE (3 AND 0) (2 LIKE 2 ESCAPE 3) AND 0 0 1 0 -0 0 0 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 && 0, 2 LIKE 2 ESCAPE (3 && 0), (2 LIKE 2 ESCAPE 3) && 0; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 2 escape 3 and 0 AS `2 LIKE 2 ESCAPE 3 && 0`,2 like 2 escape 3 and 0 AS `2 LIKE 2 ESCAPE (3 && 0)`,2 like 2 escape 3 and 0 AS `(2 LIKE 2 ESCAPE 3) && 0` +select 2 like 2 escape 3 and 0 AS `2 LIKE 2 ESCAPE 3 && 0`,2 like 2 escape (3 and 0) AS `2 LIKE 2 ESCAPE (3 && 0)`,2 like 2 escape 3 and 0 AS `(2 LIKE 2 ESCAPE 3) && 0` select 2 LIKE 2 ESCAPE 3 && 0, 2 LIKE 2 ESCAPE (3 && 0), (2 LIKE 2 ESCAPE 3) && 0 union select * from v1; 2 LIKE 2 ESCAPE 3 && 0 2 LIKE 2 ESCAPE (3 && 0) (2 LIKE 2 ESCAPE 3) && 0 0 1 0 -0 0 0 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 = 4, 2 LIKE 2 ESCAPE (3 = 4), (2 LIKE 2 ESCAPE 3) = 4; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 2 escape 3 = 4 AS `2 LIKE 2 ESCAPE 3 = 4`,2 like 2 escape 3 = 4 AS `2 LIKE 2 ESCAPE (3 = 4)`,2 like 2 escape 3 = 4 AS `(2 LIKE 2 ESCAPE 3) = 4` +select 2 like 2 escape 3 = 4 AS `2 LIKE 2 ESCAPE 3 = 4`,2 like 2 escape (3 = 4) AS `2 LIKE 2 ESCAPE (3 = 4)`,2 like 2 escape 3 = 4 AS `(2 LIKE 2 ESCAPE 3) = 4` select 2 LIKE 2 ESCAPE 3 = 4, 2 LIKE 2 ESCAPE (3 = 4), (2 LIKE 2 ESCAPE 3) = 4 union select * from v1; 2 LIKE 2 ESCAPE 3 = 4 2 LIKE 2 ESCAPE (3 = 4) (2 LIKE 2 ESCAPE 3) = 4 0 1 0 -0 0 0 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 <=> 4, 2 LIKE 2 ESCAPE (3 <=> 4), (2 LIKE 2 ESCAPE 3) <=> 4; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 2 escape 3 <=> 4 AS `2 LIKE 2 ESCAPE 3 <=> 4`,2 like 2 escape 3 <=> 4 AS `2 LIKE 2 ESCAPE (3 <=> 4)`,2 like 2 escape 3 <=> 4 AS `(2 LIKE 2 ESCAPE 3) <=> 4` +select 2 like 2 escape 3 <=> 4 AS `2 LIKE 2 ESCAPE 3 <=> 4`,2 like 2 escape (3 <=> 4) AS `2 LIKE 2 ESCAPE (3 <=> 4)`,2 like 2 escape 3 <=> 4 AS `(2 LIKE 2 ESCAPE 3) <=> 4` select 2 LIKE 2 ESCAPE 3 <=> 4, 2 LIKE 2 ESCAPE (3 <=> 4), (2 LIKE 2 ESCAPE 3) <=> 4 union select * from v1; 2 LIKE 2 ESCAPE 3 <=> 4 2 LIKE 2 ESCAPE (3 <=> 4) (2 LIKE 2 ESCAPE 3) <=> 4 0 1 0 -0 0 0 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 >= 4, 2 LIKE 2 ESCAPE (3 >= 4), (2 LIKE 2 ESCAPE 3) >= 4; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 2 escape 3 >= 4 AS `2 LIKE 2 ESCAPE 3 >= 4`,2 like 2 escape 3 >= 4 AS `2 LIKE 2 ESCAPE (3 >= 4)`,2 like 2 escape 3 >= 4 AS `(2 LIKE 2 ESCAPE 3) >= 4` +select 2 like 2 escape 3 >= 4 AS `2 LIKE 2 ESCAPE 3 >= 4`,2 like 2 escape (3 >= 4) AS `2 LIKE 2 ESCAPE (3 >= 4)`,2 like 2 escape 3 >= 4 AS `(2 LIKE 2 ESCAPE 3) >= 4` select 2 LIKE 2 ESCAPE 3 >= 4, 2 LIKE 2 ESCAPE (3 >= 4), (2 LIKE 2 ESCAPE 3) >= 4 union select * from v1; 2 LIKE 2 ESCAPE 3 >= 4 2 LIKE 2 ESCAPE (3 >= 4) (2 LIKE 2 ESCAPE 3) >= 4 0 1 0 -0 0 0 create or replace view v1 as select 2 LIKE 1 ESCAPE 3 <= 4, 2 LIKE 1 ESCAPE (3 <= 4), (2 LIKE 1 ESCAPE 3) <= 4; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <= 4 AS `2 LIKE 1 ESCAPE 3 <= 4`,2 like 1 escape 3 <= 4 AS `2 LIKE 1 ESCAPE (3 <= 4)`,2 like 1 escape 3 <= 4 AS `(2 LIKE 1 ESCAPE 3) <= 4` +select 2 like 1 escape 3 <= 4 AS `2 LIKE 1 ESCAPE 3 <= 4`,2 like 1 escape (3 <= 4) AS `2 LIKE 1 ESCAPE (3 <= 4)`,2 like 1 escape 3 <= 4 AS `(2 LIKE 1 ESCAPE 3) <= 4` select 2 LIKE 1 ESCAPE 3 <= 4, 2 LIKE 1 ESCAPE (3 <= 4), (2 LIKE 1 ESCAPE 3) <= 4 union select * from v1; 2 LIKE 1 ESCAPE 3 <= 4 2 LIKE 1 ESCAPE (3 <= 4) (2 LIKE 1 ESCAPE 3) <= 4 1 0 1 -1 1 1 create or replace view v1 as select 2 LIKE 1 ESCAPE 3 < 4, 2 LIKE 1 ESCAPE (3 < 4), (2 LIKE 1 ESCAPE 3) < 4; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 < 4 AS `2 LIKE 1 ESCAPE 3 < 4`,2 like 1 escape 3 < 4 AS `2 LIKE 1 ESCAPE (3 < 4)`,2 like 1 escape 3 < 4 AS `(2 LIKE 1 ESCAPE 3) < 4` +select 2 like 1 escape 3 < 4 AS `2 LIKE 1 ESCAPE 3 < 4`,2 like 1 escape (3 < 4) AS `2 LIKE 1 ESCAPE (3 < 4)`,2 like 1 escape 3 < 4 AS `(2 LIKE 1 ESCAPE 3) < 4` select 2 LIKE 1 ESCAPE 3 < 4, 2 LIKE 1 ESCAPE (3 < 4), (2 LIKE 1 ESCAPE 3) < 4 union select * from v1; 2 LIKE 1 ESCAPE 3 < 4 2 LIKE 1 ESCAPE (3 < 4) (2 LIKE 1 ESCAPE 3) < 4 1 0 1 -1 1 1 create or replace view v1 as select 2 LIKE 1 ESCAPE 3 <> 4, 2 LIKE 1 ESCAPE (3 <> 4), (2 LIKE 1 ESCAPE 3) <> 4; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 <> 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 <> 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) <> 4` +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 <> 4`,2 like 1 escape (3 <> 4) AS `2 LIKE 1 ESCAPE (3 <> 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) <> 4` select 2 LIKE 1 ESCAPE 3 <> 4, 2 LIKE 1 ESCAPE (3 <> 4), (2 LIKE 1 ESCAPE 3) <> 4 union select * from v1; 2 LIKE 1 ESCAPE 3 <> 4 2 LIKE 1 ESCAPE (3 <> 4) (2 LIKE 1 ESCAPE 3) <> 4 1 0 1 -1 1 1 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 > 4, 2 LIKE 2 ESCAPE (3 > 4), (2 LIKE 2 ESCAPE 3) > 4; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 2 escape 3 > 4 AS `2 LIKE 2 ESCAPE 3 > 4`,2 like 2 escape 3 > 4 AS `2 LIKE 2 ESCAPE (3 > 4)`,2 like 2 escape 3 > 4 AS `(2 LIKE 2 ESCAPE 3) > 4` +select 2 like 2 escape 3 > 4 AS `2 LIKE 2 ESCAPE 3 > 4`,2 like 2 escape (3 > 4) AS `2 LIKE 2 ESCAPE (3 > 4)`,2 like 2 escape 3 > 4 AS `(2 LIKE 2 ESCAPE 3) > 4` select 2 LIKE 2 ESCAPE 3 > 4, 2 LIKE 2 ESCAPE (3 > 4), (2 LIKE 2 ESCAPE 3) > 4 union select * from v1; 2 LIKE 2 ESCAPE 3 > 4 2 LIKE 2 ESCAPE (3 > 4) (2 LIKE 2 ESCAPE 3) > 4 0 1 0 -0 0 0 create or replace view v1 as select 2 LIKE 1 ESCAPE 3 != 4, 2 LIKE 1 ESCAPE (3 != 4), (2 LIKE 1 ESCAPE 3) != 4; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape (3 <> 4) AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` select 2 LIKE 1 ESCAPE 3 != 4, 2 LIKE 1 ESCAPE (3 != 4), (2 LIKE 1 ESCAPE 3) != 4 union select * from v1; 2 LIKE 1 ESCAPE 3 != 4 2 LIKE 1 ESCAPE (3 != 4) (2 LIKE 1 ESCAPE 3) != 4 1 0 1 -1 1 1 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 LIKE 4, 2 LIKE 2 ESCAPE (3 LIKE 4), (2 LIKE 2 ESCAPE 3) LIKE 4; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE 4, 2 LIKE 2 ESCAPE (3 LIKE 4), (2 LIKE 2 ESCAPE 3) LIKE 4' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 2 escape 3 like 4 AS `2 LIKE 2 ESCAPE 3 LIKE 4`,2 like 2 escape (3 like 4) AS `2 LIKE 2 ESCAPE (3 LIKE 4)`,2 like 2 escape 3 like 4 AS `(2 LIKE 2 ESCAPE 3) LIKE 4` select 2 LIKE 2 ESCAPE 3 LIKE 4, 2 LIKE 2 ESCAPE (3 LIKE 4), (2 LIKE 2 ESCAPE 3) LIKE 4 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE 4, 2 LIKE 2 ESCAPE (3 LIKE 4), (2 LIKE 2 ESCAPE 3) LIKE 4 union select *...' at line 1 +2 LIKE 2 ESCAPE 3 LIKE 4 2 LIKE 2 ESCAPE (3 LIKE 4) (2 LIKE 2 ESCAPE 3) LIKE 4 +0 1 0 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 REGEXP 4, 2 LIKE 2 ESCAPE (3 REGEXP 4), (2 LIKE 2 ESCAPE 3) REGEXP 4; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'REGEXP 4, 2 LIKE 2 ESCAPE (3 REGEXP 4), (2 LIKE 2 ESCAPE 3) REGEXP 4' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 2 escape 3 regexp 4 AS `2 LIKE 2 ESCAPE 3 REGEXP 4`,2 like 2 escape (3 regexp 4) AS `2 LIKE 2 ESCAPE (3 REGEXP 4)`,2 like 2 escape 3 regexp 4 AS `(2 LIKE 2 ESCAPE 3) REGEXP 4` select 2 LIKE 2 ESCAPE 3 REGEXP 4, 2 LIKE 2 ESCAPE (3 REGEXP 4), (2 LIKE 2 ESCAPE 3) REGEXP 4 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'REGEXP 4, 2 LIKE 2 ESCAPE (3 REGEXP 4), (2 LIKE 2 ESCAPE 3) REGEXP 4 union se...' at line 1 +2 LIKE 2 ESCAPE 3 REGEXP 4 2 LIKE 2 ESCAPE (3 REGEXP 4) (2 LIKE 2 ESCAPE 3) REGEXP 4 +0 1 0 create or replace view v1 as select 2 LIKE 1 ESCAPE 3 | 4, 2 LIKE 1 ESCAPE (3 | 4), (2 LIKE 1 ESCAPE 3) | 4; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '| 4, 2 LIKE 1 ESCAPE (3 | 4), (2 LIKE 1 ESCAPE 3) | 4' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 1 escape 3 | 4 AS `2 LIKE 1 ESCAPE 3 | 4`,2 like 1 escape 3 | 4 AS `2 LIKE 1 ESCAPE (3 | 4)`,(2 like 1 escape 3) | 4 AS `(2 LIKE 1 ESCAPE 3) | 4` select 2 LIKE 1 ESCAPE 3 | 4, 2 LIKE 1 ESCAPE (3 | 4), (2 LIKE 1 ESCAPE 3) | 4 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '| 4, 2 LIKE 1 ESCAPE (3 | 4), (2 LIKE 1 ESCAPE 3) | 4 union select * from v1' at line 1 +2 LIKE 1 ESCAPE 3 | 4 2 LIKE 1 ESCAPE (3 | 4) (2 LIKE 1 ESCAPE 3) | 4 +0 0 4 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 & 4, 2 LIKE 2 ESCAPE (3 & 4), (2 LIKE 2 ESCAPE 3) & 4; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '& 4, 2 LIKE 2 ESCAPE (3 & 4), (2 LIKE 2 ESCAPE 3) & 4' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 2 escape 3 & 4 AS `2 LIKE 2 ESCAPE 3 & 4`,2 like 2 escape 3 & 4 AS `2 LIKE 2 ESCAPE (3 & 4)`,(2 like 2 escape 3) & 4 AS `(2 LIKE 2 ESCAPE 3) & 4` select 2 LIKE 2 ESCAPE 3 & 4, 2 LIKE 2 ESCAPE (3 & 4), (2 LIKE 2 ESCAPE 3) & 4 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '& 4, 2 LIKE 2 ESCAPE (3 & 4), (2 LIKE 2 ESCAPE 3) & 4 union select * from v1' at line 1 +2 LIKE 2 ESCAPE 3 & 4 2 LIKE 2 ESCAPE (3 & 4) (2 LIKE 2 ESCAPE 3) & 4 +1 1 0 create or replace view v1 as select 2 LIKE 2 ESCAPE 1 << 1, 2 LIKE 2 ESCAPE (1 << 1), (2 LIKE 2 ESCAPE 1) << 1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '<< 1, 2 LIKE 2 ESCAPE (1 << 1), (2 LIKE 2 ESCAPE 1) << 1' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 2 escape 1 << 1 AS `2 LIKE 2 ESCAPE 1 << 1`,2 like 2 escape 1 << 1 AS `2 LIKE 2 ESCAPE (1 << 1)`,(2 like 2 escape 1) << 1 AS `(2 LIKE 2 ESCAPE 1) << 1` select 2 LIKE 2 ESCAPE 1 << 1, 2 LIKE 2 ESCAPE (1 << 1), (2 LIKE 2 ESCAPE 1) << 1 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '<< 1, 2 LIKE 2 ESCAPE (1 << 1), (2 LIKE 2 ESCAPE 1) << 1 union select * from v1' at line 1 +2 LIKE 2 ESCAPE 1 << 1 2 LIKE 2 ESCAPE (1 << 1) (2 LIKE 2 ESCAPE 1) << 1 +1 1 2 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 >> 4, 2 LIKE 2 ESCAPE (3 >> 4), (2 LIKE 2 ESCAPE 3) >> 4; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '>> 4, 2 LIKE 2 ESCAPE (3 >> 4), (2 LIKE 2 ESCAPE 3) >> 4' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 2 escape 3 >> 4 AS `2 LIKE 2 ESCAPE 3 >> 4`,2 like 2 escape 3 >> 4 AS `2 LIKE 2 ESCAPE (3 >> 4)`,(2 like 2 escape 3) >> 4 AS `(2 LIKE 2 ESCAPE 3) >> 4` select 2 LIKE 2 ESCAPE 3 >> 4, 2 LIKE 2 ESCAPE (3 >> 4), (2 LIKE 2 ESCAPE 3) >> 4 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '>> 4, 2 LIKE 2 ESCAPE (3 >> 4), (2 LIKE 2 ESCAPE 3) >> 4 union select * from v1' at line 1 +2 LIKE 2 ESCAPE 3 >> 4 2 LIKE 2 ESCAPE (3 >> 4) (2 LIKE 2 ESCAPE 3) >> 4 +1 1 0 create or replace view v1 as select 2 LIKE 1 ESCAPE 3 +INTERVAL 1 DAY, 2 LIKE 1 ESCAPE (3 +INTERVAL 1 DAY), (2 LIKE 1 ESCAPE 3) +INTERVAL 1 DAY; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+INTERVAL 1 DAY, 2 LIKE 1 ESCAPE (3 +INTERVAL 1 DAY), (2 LIKE 1 ESCAPE 3) +IN...' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 1 escape 3 + interval 1 day AS `2 LIKE 1 ESCAPE 3 +INTERVAL 1 DAY`,2 like 1 escape 3 + interval 1 day AS `2 LIKE 1 ESCAPE (3 +INTERVAL 1 DAY)`,(2 like 1 escape 3) + interval 1 day AS `(2 LIKE 1 ESCAPE 3) +INTERVAL 1 DAY` select 2 LIKE 1 ESCAPE 3 +INTERVAL 1 DAY, 2 LIKE 1 ESCAPE (3 +INTERVAL 1 DAY), (2 LIKE 1 ESCAPE 3) +INTERVAL 1 DAY union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+INTERVAL 1 DAY, 2 LIKE 1 ESCAPE (3 +INTERVAL 1 DAY), (2 LIKE 1 ESCAPE 3) +IN...' at line 1 +2 LIKE 1 ESCAPE 3 +INTERVAL 1 DAY 2 LIKE 1 ESCAPE (3 +INTERVAL 1 DAY) (2 LIKE 1 ESCAPE 3) +INTERVAL 1 DAY +0 0 NULL create or replace view v1 as select 2 LIKE 1 ESCAPE 3 + 4, 2 LIKE 1 ESCAPE (3 + 4), (2 LIKE 1 ESCAPE 3) + 4; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+ 4, 2 LIKE 1 ESCAPE (3 + 4), (2 LIKE 1 ESCAPE 3) + 4' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 1 escape 3 + 4 AS `2 LIKE 1 ESCAPE 3 + 4`,2 like 1 escape 3 + 4 AS `2 LIKE 1 ESCAPE (3 + 4)`,(2 like 1 escape 3) + 4 AS `(2 LIKE 1 ESCAPE 3) + 4` select 2 LIKE 1 ESCAPE 3 + 4, 2 LIKE 1 ESCAPE (3 + 4), (2 LIKE 1 ESCAPE 3) + 4 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '+ 4, 2 LIKE 1 ESCAPE (3 + 4), (2 LIKE 1 ESCAPE 3) + 4 union select * from v1' at line 1 +2 LIKE 1 ESCAPE 3 + 4 2 LIKE 1 ESCAPE (3 + 4) (2 LIKE 1 ESCAPE 3) + 4 +0 0 4 create or replace view v1 as select 2 LIKE 2 ESCAPE 1 - 1, 2 LIKE 2 ESCAPE (1 - 1), (2 LIKE 2 ESCAPE 1) - 1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '- 1, 2 LIKE 2 ESCAPE (1 - 1), (2 LIKE 2 ESCAPE 1) - 1' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 2 escape 1 - 1 AS `2 LIKE 2 ESCAPE 1 - 1`,2 like 2 escape 1 - 1 AS `2 LIKE 2 ESCAPE (1 - 1)`,(2 like 2 escape 1) - 1 AS `(2 LIKE 2 ESCAPE 1) - 1` select 2 LIKE 2 ESCAPE 1 - 1, 2 LIKE 2 ESCAPE (1 - 1), (2 LIKE 2 ESCAPE 1) - 1 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '- 1, 2 LIKE 2 ESCAPE (1 - 1), (2 LIKE 2 ESCAPE 1) - 1 union select * from v1' at line 1 +2 LIKE 2 ESCAPE 1 - 1 2 LIKE 2 ESCAPE (1 - 1) (2 LIKE 2 ESCAPE 1) - 1 +1 1 0 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 * 0, 2 LIKE 2 ESCAPE (3 * 0), (2 LIKE 2 ESCAPE 3) * 0; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '* 0, 2 LIKE 2 ESCAPE (3 * 0), (2 LIKE 2 ESCAPE 3) * 0' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 2 escape 3 * 0 AS `2 LIKE 2 ESCAPE 3 * 0`,2 like 2 escape 3 * 0 AS `2 LIKE 2 ESCAPE (3 * 0)`,(2 like 2 escape 3) * 0 AS `(2 LIKE 2 ESCAPE 3) * 0` select 2 LIKE 2 ESCAPE 3 * 0, 2 LIKE 2 ESCAPE (3 * 0), (2 LIKE 2 ESCAPE 3) * 0 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '* 0, 2 LIKE 2 ESCAPE (3 * 0), (2 LIKE 2 ESCAPE 3) * 0 union select * from v1' at line 1 +2 LIKE 2 ESCAPE 3 * 0 2 LIKE 2 ESCAPE (3 * 0) (2 LIKE 2 ESCAPE 3) * 0 +1 1 0 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 DIV 3, 2 LIKE 2 ESCAPE (3 DIV 3), (2 LIKE 2 ESCAPE 3) DIV 3; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'DIV 3, 2 LIKE 2 ESCAPE (3 DIV 3), (2 LIKE 2 ESCAPE 3) DIV 3' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 2 escape 3 DIV 3 AS `2 LIKE 2 ESCAPE 3 DIV 3`,2 like 2 escape 3 DIV 3 AS `2 LIKE 2 ESCAPE (3 DIV 3)`,(2 like 2 escape 3) DIV 3 AS `(2 LIKE 2 ESCAPE 3) DIV 3` select 2 LIKE 2 ESCAPE 3 DIV 3, 2 LIKE 2 ESCAPE (3 DIV 3), (2 LIKE 2 ESCAPE 3) DIV 3 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'DIV 3, 2 LIKE 2 ESCAPE (3 DIV 3), (2 LIKE 2 ESCAPE 3) DIV 3 union select * fr...' at line 1 +2 LIKE 2 ESCAPE 3 DIV 3 2 LIKE 2 ESCAPE (3 DIV 3) (2 LIKE 2 ESCAPE 3) DIV 3 +1 1 0 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 MOD 1, 2 LIKE 2 ESCAPE (3 MOD 1), (2 LIKE 2 ESCAPE 3) MOD 1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'MOD 1, 2 LIKE 2 ESCAPE (3 MOD 1), (2 LIKE 2 ESCAPE 3) MOD 1' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 2 escape 3 % 1 AS `2 LIKE 2 ESCAPE 3 MOD 1`,2 like 2 escape 3 % 1 AS `2 LIKE 2 ESCAPE (3 MOD 1)`,(2 like 2 escape 3) % 1 AS `(2 LIKE 2 ESCAPE 3) MOD 1` select 2 LIKE 2 ESCAPE 3 MOD 1, 2 LIKE 2 ESCAPE (3 MOD 1), (2 LIKE 2 ESCAPE 3) MOD 1 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'MOD 1, 2 LIKE 2 ESCAPE (3 MOD 1), (2 LIKE 2 ESCAPE 3) MOD 1 union select * fr...' at line 1 +2 LIKE 2 ESCAPE 3 MOD 1 2 LIKE 2 ESCAPE (3 MOD 1) (2 LIKE 2 ESCAPE 3) MOD 1 +1 1 0 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 % 1, 2 LIKE 2 ESCAPE (3 % 1), (2 LIKE 2 ESCAPE 3) % 1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '% 1, 2 LIKE 2 ESCAPE (3 % 1), (2 LIKE 2 ESCAPE 3) % 1' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 2 escape 3 % 1 AS `2 LIKE 2 ESCAPE 3 % 1`,2 like 2 escape 3 % 1 AS `2 LIKE 2 ESCAPE (3 % 1)`,(2 like 2 escape 3) % 1 AS `(2 LIKE 2 ESCAPE 3) % 1` select 2 LIKE 2 ESCAPE 3 % 1, 2 LIKE 2 ESCAPE (3 % 1), (2 LIKE 2 ESCAPE 3) % 1 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '% 1, 2 LIKE 2 ESCAPE (3 % 1), (2 LIKE 2 ESCAPE 3) % 1 union select * from v1' at line 1 +2 LIKE 2 ESCAPE 3 % 1 2 LIKE 2 ESCAPE (3 % 1) (2 LIKE 2 ESCAPE 3) % 1 +1 1 0 create or replace view v1 as select 2 LIKE 1 ESCAPE 3 ^ 4, 2 LIKE 1 ESCAPE (3 ^ 4), (2 LIKE 1 ESCAPE 3) ^ 4; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '^ 4, 2 LIKE 1 ESCAPE (3 ^ 4), (2 LIKE 1 ESCAPE 3) ^ 4' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 1 escape 3 ^ 4 AS `2 LIKE 1 ESCAPE 3 ^ 4`,2 like 1 escape 3 ^ 4 AS `2 LIKE 1 ESCAPE (3 ^ 4)`,(2 like 1 escape 3) ^ 4 AS `(2 LIKE 1 ESCAPE 3) ^ 4` select 2 LIKE 1 ESCAPE 3 ^ 4, 2 LIKE 1 ESCAPE (3 ^ 4), (2 LIKE 1 ESCAPE 3) ^ 4 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '^ 4, 2 LIKE 1 ESCAPE (3 ^ 4), (2 LIKE 1 ESCAPE 3) ^ 4 union select * from v1' at line 1 +2 LIKE 1 ESCAPE 3 ^ 4 2 LIKE 1 ESCAPE (3 ^ 4) (2 LIKE 1 ESCAPE 3) ^ 4 +0 0 4 create or replace view v1 as select 2 LIKE 2 ESCAPE 3 BETWEEN 2 AND 4, 2 LIKE 2 ESCAPE (3 BETWEEN 2 AND 4), (2 LIKE 2 ESCAPE 3) BETWEEN 2 AND 4; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'BETWEEN 2 AND 4, 2 LIKE 2 ESCAPE (3 BETWEEN 2 AND 4), (2 LIKE 2 ESCAPE 3) BET...' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE 3 != 4`,2 like 1 escape 3 <> 4 AS `2 LIKE 1 ESCAPE (3 != 4)`,2 like 1 escape 3 <> 4 AS `(2 LIKE 1 ESCAPE 3) != 4` +select 2 like 2 escape 3 between 2 and 4 AS `2 LIKE 2 ESCAPE 3 BETWEEN 2 AND 4`,2 like 2 escape (3 between 2 and 4) AS `2 LIKE 2 ESCAPE (3 BETWEEN 2 AND 4)`,2 like 2 escape 3 between 2 and 4 AS `(2 LIKE 2 ESCAPE 3) BETWEEN 2 AND 4` select 2 LIKE 2 ESCAPE 3 BETWEEN 2 AND 4, 2 LIKE 2 ESCAPE (3 BETWEEN 2 AND 4), (2 LIKE 2 ESCAPE 3) BETWEEN 2 AND 4 union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'BETWEEN 2 AND 4, 2 LIKE 2 ESCAPE (3 BETWEEN 2 AND 4), (2 LIKE 2 ESCAPE 3) BET...' at line 1 +2 LIKE 2 ESCAPE 3 BETWEEN 2 AND 4 2 LIKE 2 ESCAPE (3 BETWEEN 2 AND 4) (2 LIKE 2 ESCAPE 3) BETWEEN 2 AND 4 +0 1 0 create or replace view v1 as select NOT 2 IN (SELECT 0 UNION SELECT 2), NOT (2 IN (SELECT 0 UNION SELECT 2)), (NOT 2) IN (SELECT 0 UNION SELECT 2); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -7396,121 +7331,108 @@ BINARY 'c' IN (SELECT 'C' UNION SELECT 'X') BINARY ('c' IN (SELECT 'C' UNION SEL create or replace view v1 as select 0 OR 3 IN (SELECT 3 UNION SELECT 10), 0 OR (3 IN (SELECT 3 UNION SELECT 10)), (0 OR 3) IN (SELECT 3 UNION SELECT 10); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 0 or 3 in (select 3 union select 10) AS `0 OR 3 IN (SELECT 3 UNION SELECT 10)`,0 or 3 in (select 3 union select 10) AS `0 OR (3 IN (SELECT 3 UNION SELECT 10))`,0 or 3 in (select 3 union select 10) AS `(0 OR 3) IN (SELECT 3 UNION SELECT 10)` +select 0 or 3 in (select 3 union select 10) AS `0 OR 3 IN (SELECT 3 UNION SELECT 10)`,0 or 3 in (select 3 union select 10) AS `0 OR (3 IN (SELECT 3 UNION SELECT 10))`,(0 or 3) in (select 3 union select 10) AS `(0 OR 3) IN (SELECT 3 UNION SELECT 10)` select 0 OR 3 IN (SELECT 3 UNION SELECT 10), 0 OR (3 IN (SELECT 3 UNION SELECT 10)), (0 OR 3) IN (SELECT 3 UNION SELECT 10) union select * from v1; 0 OR 3 IN (SELECT 3 UNION SELECT 10) 0 OR (3 IN (SELECT 3 UNION SELECT 10)) (0 OR 3) IN (SELECT 3 UNION SELECT 10) 1 1 0 -1 1 1 create or replace view v1 as select 0 || 3 IN (SELECT 3 UNION SELECT 10), 0 || (3 IN (SELECT 3 UNION SELECT 10)), (0 || 3) IN (SELECT 3 UNION SELECT 10); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 0 or 3 in (select 3 union select 10) AS `0 || 3 IN (SELECT 3 UNION SELECT 10)`,0 or 3 in (select 3 union select 10) AS `0 || (3 IN (SELECT 3 UNION SELECT 10))`,0 or 3 in (select 3 union select 10) AS `(0 || 3) IN (SELECT 3 UNION SELECT 10)` +select 0 or 3 in (select 3 union select 10) AS `0 || 3 IN (SELECT 3 UNION SELECT 10)`,0 or 3 in (select 3 union select 10) AS `0 || (3 IN (SELECT 3 UNION SELECT 10))`,(0 or 3) in (select 3 union select 10) AS `(0 || 3) IN (SELECT 3 UNION SELECT 10)` select 0 || 3 IN (SELECT 3 UNION SELECT 10), 0 || (3 IN (SELECT 3 UNION SELECT 10)), (0 || 3) IN (SELECT 3 UNION SELECT 10) union select * from v1; 0 || 3 IN (SELECT 3 UNION SELECT 10) 0 || (3 IN (SELECT 3 UNION SELECT 10)) (0 || 3) IN (SELECT 3 UNION SELECT 10) 1 1 0 -1 1 1 create or replace view v1 as select 2 XOR 3 IN (SELECT 4 UNION SELECT 5), 2 XOR (3 IN (SELECT 4 UNION SELECT 5)), (2 XOR 3) IN (SELECT 4 UNION SELECT 5); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 xor 3 in (select 4 union select 5) AS `2 XOR 3 IN (SELECT 4 UNION SELECT 5)`,2 xor 3 in (select 4 union select 5) AS `2 XOR (3 IN (SELECT 4 UNION SELECT 5))`,2 xor 3 in (select 4 union select 5) AS `(2 XOR 3) IN (SELECT 4 UNION SELECT 5)` +select 2 xor 3 in (select 4 union select 5) AS `2 XOR 3 IN (SELECT 4 UNION SELECT 5)`,2 xor 3 in (select 4 union select 5) AS `2 XOR (3 IN (SELECT 4 UNION SELECT 5))`,(2 xor 3) in (select 4 union select 5) AS `(2 XOR 3) IN (SELECT 4 UNION SELECT 5)` select 2 XOR 3 IN (SELECT 4 UNION SELECT 5), 2 XOR (3 IN (SELECT 4 UNION SELECT 5)), (2 XOR 3) IN (SELECT 4 UNION SELECT 5) union select * from v1; 2 XOR 3 IN (SELECT 4 UNION SELECT 5) 2 XOR (3 IN (SELECT 4 UNION SELECT 5)) (2 XOR 3) IN (SELECT 4 UNION SELECT 5) 1 1 0 -1 1 1 create or replace view v1 as select 2 AND 3 IN (SELECT 0 UNION SELECT 1), 2 AND (3 IN (SELECT 0 UNION SELECT 1)), (2 AND 3) IN (SELECT 0 UNION SELECT 1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 and 3 in (select 0 union select 1) AS `2 AND 3 IN (SELECT 0 UNION SELECT 1)`,2 and 3 in (select 0 union select 1) AS `2 AND (3 IN (SELECT 0 UNION SELECT 1))`,2 and 3 in (select 0 union select 1) AS `(2 AND 3) IN (SELECT 0 UNION SELECT 1)` +select 2 and 3 in (select 0 union select 1) AS `2 AND 3 IN (SELECT 0 UNION SELECT 1)`,2 and 3 in (select 0 union select 1) AS `2 AND (3 IN (SELECT 0 UNION SELECT 1))`,(2 and 3) in (select 0 union select 1) AS `(2 AND 3) IN (SELECT 0 UNION SELECT 1)` select 2 AND 3 IN (SELECT 0 UNION SELECT 1), 2 AND (3 IN (SELECT 0 UNION SELECT 1)), (2 AND 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; 2 AND 3 IN (SELECT 0 UNION SELECT 1) 2 AND (3 IN (SELECT 0 UNION SELECT 1)) (2 AND 3) IN (SELECT 0 UNION SELECT 1) 0 0 1 -0 0 0 create or replace view v1 as select 2 && 3 IN (SELECT 0 UNION SELECT 1), 2 && (3 IN (SELECT 0 UNION SELECT 1)), (2 && 3) IN (SELECT 0 UNION SELECT 1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 and 3 in (select 0 union select 1) AS `2 && 3 IN (SELECT 0 UNION SELECT 1)`,2 and 3 in (select 0 union select 1) AS `2 && (3 IN (SELECT 0 UNION SELECT 1))`,2 and 3 in (select 0 union select 1) AS `(2 && 3) IN (SELECT 0 UNION SELECT 1)` +select 2 and 3 in (select 0 union select 1) AS `2 && 3 IN (SELECT 0 UNION SELECT 1)`,2 and 3 in (select 0 union select 1) AS `2 && (3 IN (SELECT 0 UNION SELECT 1))`,(2 and 3) in (select 0 union select 1) AS `(2 && 3) IN (SELECT 0 UNION SELECT 1)` select 2 && 3 IN (SELECT 0 UNION SELECT 1), 2 && (3 IN (SELECT 0 UNION SELECT 1)), (2 && 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; 2 && 3 IN (SELECT 0 UNION SELECT 1) 2 && (3 IN (SELECT 0 UNION SELECT 1)) (2 && 3) IN (SELECT 0 UNION SELECT 1) 0 0 1 -0 0 0 create or replace view v1 as select 2 = 3 IN (SELECT 0 UNION SELECT 1), 2 = (3 IN (SELECT 0 UNION SELECT 1)), (2 = 3) IN (SELECT 0 UNION SELECT 1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 = (3 in (select 0 union select 1)) AS `2 = 3 IN (SELECT 0 UNION SELECT 1)`,2 = (3 in (select 0 union select 1)) AS `2 = (3 IN (SELECT 0 UNION SELECT 1))`,2 = 3 in (select 0 union select 1) AS `(2 = 3) IN (SELECT 0 UNION SELECT 1)` +select 2 = 3 in (select 0 union select 1) AS `2 = 3 IN (SELECT 0 UNION SELECT 1)`,2 = 3 in (select 0 union select 1) AS `2 = (3 IN (SELECT 0 UNION SELECT 1))`,(2 = 3) in (select 0 union select 1) AS `(2 = 3) IN (SELECT 0 UNION SELECT 1)` select 2 = 3 IN (SELECT 0 UNION SELECT 1), 2 = (3 IN (SELECT 0 UNION SELECT 1)), (2 = 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; 2 = 3 IN (SELECT 0 UNION SELECT 1) 2 = (3 IN (SELECT 0 UNION SELECT 1)) (2 = 3) IN (SELECT 0 UNION SELECT 1) 0 0 1 -0 0 0 create or replace view v1 as select 2 <=> 3 IN (SELECT 0 UNION SELECT 1), 2 <=> (3 IN (SELECT 0 UNION SELECT 1)), (2 <=> 3) IN (SELECT 0 UNION SELECT 1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <=> (3 in (select 0 union select 1)) AS `2 <=> 3 IN (SELECT 0 UNION SELECT 1)`,2 <=> (3 in (select 0 union select 1)) AS `2 <=> (3 IN (SELECT 0 UNION SELECT 1))`,2 <=> 3 in (select 0 union select 1) AS `(2 <=> 3) IN (SELECT 0 UNION SELECT 1)` +select 2 <=> 3 in (select 0 union select 1) AS `2 <=> 3 IN (SELECT 0 UNION SELECT 1)`,2 <=> 3 in (select 0 union select 1) AS `2 <=> (3 IN (SELECT 0 UNION SELECT 1))`,(2 <=> 3) in (select 0 union select 1) AS `(2 <=> 3) IN (SELECT 0 UNION SELECT 1)` select 2 <=> 3 IN (SELECT 0 UNION SELECT 1), 2 <=> (3 IN (SELECT 0 UNION SELECT 1)), (2 <=> 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; 2 <=> 3 IN (SELECT 0 UNION SELECT 1) 2 <=> (3 IN (SELECT 0 UNION SELECT 1)) (2 <=> 3) IN (SELECT 0 UNION SELECT 1) 0 0 1 -0 0 0 create or replace view v1 as select 2 >= 3 IN (SELECT 1 UNION SELECT 1), 2 >= (3 IN (SELECT 1 UNION SELECT 1)), (2 >= 3) IN (SELECT 1 UNION SELECT 1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 >= (3 in (select 1 union select 1)) AS `2 >= 3 IN (SELECT 1 UNION SELECT 1)`,2 >= (3 in (select 1 union select 1)) AS `2 >= (3 IN (SELECT 1 UNION SELECT 1))`,2 >= 3 in (select 1 union select 1) AS `(2 >= 3) IN (SELECT 1 UNION SELECT 1)` +select 2 >= 3 in (select 1 union select 1) AS `2 >= 3 IN (SELECT 1 UNION SELECT 1)`,2 >= 3 in (select 1 union select 1) AS `2 >= (3 IN (SELECT 1 UNION SELECT 1))`,(2 >= 3) in (select 1 union select 1) AS `(2 >= 3) IN (SELECT 1 UNION SELECT 1)` select 2 >= 3 IN (SELECT 1 UNION SELECT 1), 2 >= (3 IN (SELECT 1 UNION SELECT 1)), (2 >= 3) IN (SELECT 1 UNION SELECT 1) union select * from v1; 2 >= 3 IN (SELECT 1 UNION SELECT 1) 2 >= (3 IN (SELECT 1 UNION SELECT 1)) (2 >= 3) IN (SELECT 1 UNION SELECT 1) 1 1 0 -1 1 1 create or replace view v1 as select 2 <= 3 IN (SELECT 0 UNION SELECT 1), 2 <= (3 IN (SELECT 0 UNION SELECT 1)), (2 <= 3) IN (SELECT 0 UNION SELECT 1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <= (3 in (select 0 union select 1)) AS `2 <= 3 IN (SELECT 0 UNION SELECT 1)`,2 <= (3 in (select 0 union select 1)) AS `2 <= (3 IN (SELECT 0 UNION SELECT 1))`,2 <= 3 in (select 0 union select 1) AS `(2 <= 3) IN (SELECT 0 UNION SELECT 1)` +select 2 <= 3 in (select 0 union select 1) AS `2 <= 3 IN (SELECT 0 UNION SELECT 1)`,2 <= 3 in (select 0 union select 1) AS `2 <= (3 IN (SELECT 0 UNION SELECT 1))`,(2 <= 3) in (select 0 union select 1) AS `(2 <= 3) IN (SELECT 0 UNION SELECT 1)` select 2 <= 3 IN (SELECT 0 UNION SELECT 1), 2 <= (3 IN (SELECT 0 UNION SELECT 1)), (2 <= 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; 2 <= 3 IN (SELECT 0 UNION SELECT 1) 2 <= (3 IN (SELECT 0 UNION SELECT 1)) (2 <= 3) IN (SELECT 0 UNION SELECT 1) 0 0 1 -0 0 0 create or replace view v1 as select 2 < 3 IN (SELECT 0 UNION SELECT 1), 2 < (3 IN (SELECT 0 UNION SELECT 1)), (2 < 3) IN (SELECT 0 UNION SELECT 1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 < (3 in (select 0 union select 1)) AS `2 < 3 IN (SELECT 0 UNION SELECT 1)`,2 < (3 in (select 0 union select 1)) AS `2 < (3 IN (SELECT 0 UNION SELECT 1))`,2 < 3 in (select 0 union select 1) AS `(2 < 3) IN (SELECT 0 UNION SELECT 1)` +select 2 < 3 in (select 0 union select 1) AS `2 < 3 IN (SELECT 0 UNION SELECT 1)`,2 < 3 in (select 0 union select 1) AS `2 < (3 IN (SELECT 0 UNION SELECT 1))`,(2 < 3) in (select 0 union select 1) AS `(2 < 3) IN (SELECT 0 UNION SELECT 1)` select 2 < 3 IN (SELECT 0 UNION SELECT 1), 2 < (3 IN (SELECT 0 UNION SELECT 1)), (2 < 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; 2 < 3 IN (SELECT 0 UNION SELECT 1) 2 < (3 IN (SELECT 0 UNION SELECT 1)) (2 < 3) IN (SELECT 0 UNION SELECT 1) 0 0 1 -0 0 0 create or replace view v1 as select 2 <> 3 IN (SELECT 0 UNION SELECT 0), 2 <> (3 IN (SELECT 0 UNION SELECT 0)), (2 <> 3) IN (SELECT 0 UNION SELECT 0); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <> (3 in (select 0 union select 0)) AS `2 <> 3 IN (SELECT 0 UNION SELECT 0)`,2 <> (3 in (select 0 union select 0)) AS `2 <> (3 IN (SELECT 0 UNION SELECT 0))`,2 <> 3 in (select 0 union select 0) AS `(2 <> 3) IN (SELECT 0 UNION SELECT 0)` +select 2 <> 3 in (select 0 union select 0) AS `2 <> 3 IN (SELECT 0 UNION SELECT 0)`,2 <> 3 in (select 0 union select 0) AS `2 <> (3 IN (SELECT 0 UNION SELECT 0))`,(2 <> 3) in (select 0 union select 0) AS `(2 <> 3) IN (SELECT 0 UNION SELECT 0)` select 2 <> 3 IN (SELECT 0 UNION SELECT 0), 2 <> (3 IN (SELECT 0 UNION SELECT 0)), (2 <> 3) IN (SELECT 0 UNION SELECT 0) union select * from v1; 2 <> 3 IN (SELECT 0 UNION SELECT 0) 2 <> (3 IN (SELECT 0 UNION SELECT 0)) (2 <> 3) IN (SELECT 0 UNION SELECT 0) 1 1 0 -1 1 1 create or replace view v1 as select 2 > 3 IN (SELECT 1 UNION SELECT 1), 2 > (3 IN (SELECT 1 UNION SELECT 1)), (2 > 3) IN (SELECT 1 UNION SELECT 1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 > (3 in (select 1 union select 1)) AS `2 > 3 IN (SELECT 1 UNION SELECT 1)`,2 > (3 in (select 1 union select 1)) AS `2 > (3 IN (SELECT 1 UNION SELECT 1))`,2 > 3 in (select 1 union select 1) AS `(2 > 3) IN (SELECT 1 UNION SELECT 1)` +select 2 > 3 in (select 1 union select 1) AS `2 > 3 IN (SELECT 1 UNION SELECT 1)`,2 > 3 in (select 1 union select 1) AS `2 > (3 IN (SELECT 1 UNION SELECT 1))`,(2 > 3) in (select 1 union select 1) AS `(2 > 3) IN (SELECT 1 UNION SELECT 1)` select 2 > 3 IN (SELECT 1 UNION SELECT 1), 2 > (3 IN (SELECT 1 UNION SELECT 1)), (2 > 3) IN (SELECT 1 UNION SELECT 1) union select * from v1; 2 > 3 IN (SELECT 1 UNION SELECT 1) 2 > (3 IN (SELECT 1 UNION SELECT 1)) (2 > 3) IN (SELECT 1 UNION SELECT 1) 1 1 0 -1 1 1 create or replace view v1 as select 2 != 3 IN (SELECT 0 UNION SELECT 0), 2 != (3 IN (SELECT 0 UNION SELECT 0)), (2 != 3) IN (SELECT 0 UNION SELECT 0); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <> (3 in (select 0 union select 0)) AS `2 != 3 IN (SELECT 0 UNION SELECT 0)`,2 <> (3 in (select 0 union select 0)) AS `2 != (3 IN (SELECT 0 UNION SELECT 0))`,2 <> 3 in (select 0 union select 0) AS `(2 != 3) IN (SELECT 0 UNION SELECT 0)` +select 2 <> 3 in (select 0 union select 0) AS `2 != 3 IN (SELECT 0 UNION SELECT 0)`,2 <> 3 in (select 0 union select 0) AS `2 != (3 IN (SELECT 0 UNION SELECT 0))`,(2 <> 3) in (select 0 union select 0) AS `(2 != 3) IN (SELECT 0 UNION SELECT 0)` select 2 != 3 IN (SELECT 0 UNION SELECT 0), 2 != (3 IN (SELECT 0 UNION SELECT 0)), (2 != 3) IN (SELECT 0 UNION SELECT 0) union select * from v1; 2 != 3 IN (SELECT 0 UNION SELECT 0) 2 != (3 IN (SELECT 0 UNION SELECT 0)) (2 != 3) IN (SELECT 0 UNION SELECT 0) 1 1 0 -1 1 1 create or replace view v1 as select 2 LIKE 3 IN (SELECT 0 UNION SELECT 1), 2 LIKE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIKE 3) IN (SELECT 0 UNION SELECT 1); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (SELECT 0 UNION SELECT 1), 2 LIKE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIK...' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <> (3 in (select 0 union select 0)) AS `2 != 3 IN (SELECT 0 UNION SELECT 0)`,2 <> (3 in (select 0 union select 0)) AS `2 != (3 IN (SELECT 0 UNION SELECT 0))`,2 <> 3 in (select 0 union select 0) AS `(2 != 3) IN (SELECT 0 UNION SELECT 0)` +select 2 like 3 in (select 0 union select 1) AS `2 LIKE 3 IN (SELECT 0 UNION SELECT 1)`,2 like (3 in (select 0 union select 1)) AS `2 LIKE (3 IN (SELECT 0 UNION SELECT 1))`,2 like 3 in (select 0 union select 1) AS `(2 LIKE 3) IN (SELECT 0 UNION SELECT 1)` select 2 LIKE 3 IN (SELECT 0 UNION SELECT 1), 2 LIKE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIKE 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (SELECT 0 UNION SELECT 1), 2 LIKE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIK...' at line 1 +2 LIKE 3 IN (SELECT 0 UNION SELECT 1) 2 LIKE (3 IN (SELECT 0 UNION SELECT 1)) (2 LIKE 3) IN (SELECT 0 UNION SELECT 1) +1 0 1 create or replace view v1 as select 2 REGEXP 3 IN (SELECT 0 UNION SELECT 1), 2 REGEXP (3 IN (SELECT 0 UNION SELECT 1)), (2 REGEXP 3) IN (SELECT 0 UNION SELECT 1); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (SELECT 0 UNION SELECT 1), 2 REGEXP (3 IN (SELECT 0 UNION SELECT 1)), (2 R...' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 <> (3 in (select 0 union select 0)) AS `2 != 3 IN (SELECT 0 UNION SELECT 0)`,2 <> (3 in (select 0 union select 0)) AS `2 != (3 IN (SELECT 0 UNION SELECT 0))`,2 <> 3 in (select 0 union select 0) AS `(2 != 3) IN (SELECT 0 UNION SELECT 0)` +select 2 regexp 3 in (select 0 union select 1) AS `2 REGEXP 3 IN (SELECT 0 UNION SELECT 1)`,2 regexp (3 in (select 0 union select 1)) AS `2 REGEXP (3 IN (SELECT 0 UNION SELECT 1))`,2 regexp 3 in (select 0 union select 1) AS `(2 REGEXP 3) IN (SELECT 0 UNION SELECT 1)` select 2 REGEXP 3 IN (SELECT 0 UNION SELECT 1), 2 REGEXP (3 IN (SELECT 0 UNION SELECT 1)), (2 REGEXP 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (SELECT 0 UNION SELECT 1), 2 REGEXP (3 IN (SELECT 0 UNION SELECT 1)), (2 R...' at line 1 +2 REGEXP 3 IN (SELECT 0 UNION SELECT 1) 2 REGEXP (3 IN (SELECT 0 UNION SELECT 1)) (2 REGEXP 3) IN (SELECT 0 UNION SELECT 1) +1 0 1 create or replace view v1 as select 2 | 3 IN (SELECT 0 UNION SELECT 1), 2 | (3 IN (SELECT 0 UNION SELECT 1)), (2 | 3) IN (SELECT 0 UNION SELECT 1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -7598,18 +7520,17 @@ select 2 ^ 3 IN (SELECT 0 UNION SELECT 1), 2 ^ (3 IN (SELECT 0 UNION SELECT 1)), create or replace view v1 as select 2 BETWEEN 1 AND 3 IN (SELECT 0 UNION SELECT 1), 2 BETWEEN 1 AND (3 IN (SELECT 0 UNION SELECT 1)), (2 BETWEEN 1 AND 3) IN (SELECT 0 UNION SELECT 1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 between 1 and 3 in (select 0 union select 1) AS `2 BETWEEN 1 AND 3 IN (SELECT 0 UNION SELECT 1)`,2 between 1 and 3 in (select 0 union select 1) AS `2 BETWEEN 1 AND (3 IN (SELECT 0 UNION SELECT 1))`,2 between 1 and 3 in (select 0 union select 1) AS `(2 BETWEEN 1 AND 3) IN (SELECT 0 UNION SELECT 1)` +select 2 between 1 and 3 in (select 0 union select 1) AS `2 BETWEEN 1 AND 3 IN (SELECT 0 UNION SELECT 1)`,2 between 1 and 3 in (select 0 union select 1) AS `2 BETWEEN 1 AND (3 IN (SELECT 0 UNION SELECT 1))`,(2 between 1 and 3) in (select 0 union select 1) AS `(2 BETWEEN 1 AND 3) IN (SELECT 0 UNION SELECT 1)` select 2 BETWEEN 1 AND 3 IN (SELECT 0 UNION SELECT 1), 2 BETWEEN 1 AND (3 IN (SELECT 0 UNION SELECT 1)), (2 BETWEEN 1 AND 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; 2 BETWEEN 1 AND 3 IN (SELECT 0 UNION SELECT 1) 2 BETWEEN 1 AND (3 IN (SELECT 0 UNION SELECT 1)) (2 BETWEEN 1 AND 3) IN (SELECT 0 UNION SELECT 1) 0 0 1 -0 0 0 create or replace view v1 as select 2 LIKE 1 ESCAPE 3 IN (SELECT 0 UNION SELECT 1), 2 LIKE 1 ESCAPE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIKE 1 ESCAPE 3) IN (SELECT 0 UNION SELECT 1); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (SELECT 0 UNION SELECT 1), 2 LIKE 1 ESCAPE (3 IN (SELECT 0 UNION SELECT 1)...' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select 2 between 1 and 3 in (select 0 union select 1) AS `2 BETWEEN 1 AND 3 IN (SELECT 0 UNION SELECT 1)`,2 between 1 and 3 in (select 0 union select 1) AS `2 BETWEEN 1 AND (3 IN (SELECT 0 UNION SELECT 1))`,2 between 1 and 3 in (select 0 union select 1) AS `(2 BETWEEN 1 AND 3) IN (SELECT 0 UNION SELECT 1)` +select 2 like 1 escape 3 in (select 0 union select 1) AS `2 LIKE 1 ESCAPE 3 IN (SELECT 0 UNION SELECT 1)`,2 like 1 escape (3 in (select 0 union select 1)) AS `2 LIKE 1 ESCAPE (3 IN (SELECT 0 UNION SELECT 1))`,2 like 1 escape 3 in (select 0 union select 1) AS `(2 LIKE 1 ESCAPE 3) IN (SELECT 0 UNION SELECT 1)` select 2 LIKE 1 ESCAPE 3 IN (SELECT 0 UNION SELECT 1), 2 LIKE 1 ESCAPE (3 IN (SELECT 0 UNION SELECT 1)), (2 LIKE 1 ESCAPE 3) IN (SELECT 0 UNION SELECT 1) union select * from v1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IN (SELECT 0 UNION SELECT 1), 2 LIKE 1 ESCAPE (3 IN (SELECT 0 UNION SELECT 1)...' at line 1 +2 LIKE 1 ESCAPE 3 IN (SELECT 0 UNION SELECT 1) 2 LIKE 1 ESCAPE (3 IN (SELECT 0 UNION SELECT 1)) (2 LIKE 1 ESCAPE 3) IN (SELECT 0 UNION SELECT 1) +1 0 1 create or replace view v1 as select 3 BETWEEN 1 AND 2 AND NULL, 3 BETWEEN (1 AND 2) AND NULL, 3 BETWEEN 1 AND (2 AND NULL), (3 BETWEEN 1 AND 2) AND NULL; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -8097,8 +8018,7 @@ Select view_definition from information_schema.views where table_schema='test' a view_definition select cast(~1 as char charset binary) AS `BINARY ~ 1`,~cast(1 as char charset binary) AS `~ BINARY 1` create or replace view v1 as select 1 IS TRUE IS FALSE, 2 IS FALSE IS UNKNOWN, 3 IS UNKNOWN IS NULL, 4 IS NULL IS TRUE; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IS FALSE, 2 IS FALSE IS UNKNOWN, 3 IS UNKNOWN IS NULL, 4 IS NULL IS TRUE' at line 1 Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select cast(~1 as char charset binary) AS `BINARY ~ 1`,~cast(1 as char charset binary) AS `~ BINARY 1` +select 1 is true is false AS `1 IS TRUE IS FALSE`,/*always not null*/ 1 is null AS `2 IS FALSE IS UNKNOWN`,/*always not null*/ 1 is null AS `3 IS UNKNOWN IS NULL`,/*always not null*/ 1 is null is true AS `4 IS NULL IS TRUE` drop view v1; diff --git a/mysql-test/suite/innodb/r/innodb-virtual-columns.result b/mysql-test/suite/innodb/r/innodb-virtual-columns.result index de97d933ad9..20cd55bd7b0 100644 --- a/mysql-test/suite/innodb/r/innodb-virtual-columns.result +++ b/mysql-test/suite/innodb/r/innodb-virtual-columns.result @@ -30,7 +30,7 @@ grad_degree CREATE TABLE `grad_degree` ( `plan` varchar(10) NOT NULL, `admit_term` char(4) NOT NULL, `wdraw_rsn` varchar(4) NOT NULL DEFAULT '', - `ofis_deg_status` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed' else 'Not Completed' end) VIRTUAL, + `ofis_deg_status` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed' else 'Not Completed' end) VIRTUAL, `deg_start_term` char(4) NOT NULL DEFAULT '' COMMENT 'Educated guess at the beginning of the data', `deg_as_of_term` char(4) NOT NULL COMMENT 'In most cases also end term', PRIMARY KEY (`student_id`,`plan`,`admit_term`) @@ -136,14 +136,14 @@ grad_degree CREATE TABLE `grad_degree` ( `plan` varchar(10) NOT NULL, `admit_term` char(4) NOT NULL, `wdraw_rsn` varchar(4) NOT NULL DEFAULT '', - `ofis_deg_status` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed' else 'Not Completed' end) VIRTUAL, - `ofis_deg_status2` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress2' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed2' else 'Not Completed2' end) VIRTUAL, - `ofis_deg_status3` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress3' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed3' else 'Not Completed3' end) VIRTUAL, - `ofis_deg_status4` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress4' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed4' else 'Not Completed4' end) VIRTUAL, - `ofis_deg_status5` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress5' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed5' else 'Not Completed5' end) VIRTUAL, - `ofis_deg_status6` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress6' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed6' else 'Not Completed6' end) VIRTUAL, - `ofis_deg_status7` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress7' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed7' else 'Not Completed7' end) VIRTUAL, - `ofis_deg_status8` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress8' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed8' else 'Not Completed8' end) VIRTUAL, + `ofis_deg_status` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed' else 'Not Completed' end) VIRTUAL, + `ofis_deg_status2` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress2' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed2' else 'Not Completed2' end) VIRTUAL, + `ofis_deg_status3` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress3' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed3' else 'Not Completed3' end) VIRTUAL, + `ofis_deg_status4` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress4' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed4' else 'Not Completed4' end) VIRTUAL, + `ofis_deg_status5` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress5' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed5' else 'Not Completed5' end) VIRTUAL, + `ofis_deg_status6` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress6' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed6' else 'Not Completed6' end) VIRTUAL, + `ofis_deg_status7` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress7' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed7' else 'Not Completed7' end) VIRTUAL, + `ofis_deg_status8` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress8' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed8' else 'Not Completed8' end) VIRTUAL, `deg_start_term` char(4) NOT NULL DEFAULT '' COMMENT 'Educated guess at the beginning of the data', `deg_as_of_term` char(4) NOT NULL COMMENT 'In most cases also end term', PRIMARY KEY (`student_id`,`plan`,`admit_term`) @@ -193,14 +193,14 @@ grad_degree CREATE TABLE `grad_degree` ( `plan` varchar(10) NOT NULL, `admit_term` char(4) NOT NULL, `wdraw_rsn` varchar(4) NOT NULL DEFAULT '', - `ofis_deg_status` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed' else 'Not Completed' end) VIRTUAL, - `ofis_deg_status2` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress2' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed2' else 'Not Completed2' end) VIRTUAL, - `ofis_deg_status3` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress3' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed3' else 'Not Completed3' end) VIRTUAL, - `ofis_deg_status4` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress4' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed4' else 'Not Completed4' end) VIRTUAL, - `ofis_deg_status5` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress5' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed5' else 'Not Completed5' end) VIRTUAL, - `ofis_deg_status6` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress6' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed6' else 'Not Completed6' end) VIRTUAL, - `ofis_deg_status7` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress7' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed7' else 'Not Completed7' end) VIRTUAL, - `ofis_deg_status8` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress8' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed8' else 'Not Completed8' end) VIRTUAL, + `ofis_deg_status` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed' else 'Not Completed' end) VIRTUAL, + `ofis_deg_status2` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress2' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed2' else 'Not Completed2' end) VIRTUAL, + `ofis_deg_status3` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress3' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed3' else 'Not Completed3' end) VIRTUAL, + `ofis_deg_status4` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress4' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed4' else 'Not Completed4' end) VIRTUAL, + `ofis_deg_status5` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress5' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed5' else 'Not Completed5' end) VIRTUAL, + `ofis_deg_status6` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress6' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed6' else 'Not Completed6' end) VIRTUAL, + `ofis_deg_status7` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress7' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed7' else 'Not Completed7' end) VIRTUAL, + `ofis_deg_status8` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress8' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed8' else 'Not Completed8' end) VIRTUAL, `deg_as_of_term` char(4) NOT NULL COMMENT 'In most cases also end term', PRIMARY KEY (`student_id`,`plan`,`admit_term`), KEY `grad_degree_as_of_term_ndx` (`deg_as_of_term`) @@ -270,14 +270,14 @@ grad_degree CREATE TABLE `grad_degree` ( `plan` varchar(10) NOT NULL, `admit_term` char(4) NOT NULL, `wdraw_rsn` varchar(4) NOT NULL DEFAULT '', - `ofis_deg_status` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed' else 'Not Completed' end) VIRTUAL, - `ofis_deg_status2` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress2' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed2' else 'Not Completed2' end) VIRTUAL, - `ofis_deg_status3` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress3' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed3' else 'Not Completed3' end) VIRTUAL, - `ofis_deg_status4` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress4' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed4' else 'Not Completed4' end) VIRTUAL, - `ofis_deg_status5` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress5' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed5' else 'Not Completed5' end) VIRTUAL, - `ofis_deg_status6` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress6' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed6' else 'Not Completed6' end) VIRTUAL, - `ofis_deg_status7` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress7' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed7' else 'Not Completed7' end) VIRTUAL, - `ofis_deg_status8` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress8' when (`wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC') then 'Completed8' else 'Not Completed8' end) VIRTUAL, + `ofis_deg_status` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed' else 'Not Completed' end) VIRTUAL, + `ofis_deg_status2` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress2' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed2' else 'Not Completed2' end) VIRTUAL, + `ofis_deg_status3` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress3' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed3' else 'Not Completed3' end) VIRTUAL, + `ofis_deg_status4` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress4' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed4' else 'Not Completed4' end) VIRTUAL, + `ofis_deg_status5` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress5' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed5' else 'Not Completed5' end) VIRTUAL, + `ofis_deg_status6` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress6' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed6' else 'Not Completed6' end) VIRTUAL, + `ofis_deg_status7` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress7' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed7' else 'Not Completed7' end) VIRTUAL, + `ofis_deg_status8` varchar(15) GENERATED ALWAYS AS (case when `wdraw_rsn` = '' then 'In progress8' when `wdraw_rsn` = 'DCMP' or `wdraw_rsn` = 'TRDC' then 'Completed8' else 'Not Completed8' end) VIRTUAL, `deg_start_term` char(4) NOT NULL DEFAULT '' COMMENT 'Educated guess at the beginning of the data', `deg_as_of_term` char(4) NOT NULL COMMENT 'In most cases also end term', PRIMARY KEY (`student_id`,`plan`,`admit_term`) diff --git a/mysql-test/t/func_test.test b/mysql-test/t/func_test.test index 9bdbe5bc4e4..570fd0ae87a 100644 --- a/mysql-test/t/func_test.test +++ b/mysql-test/t/func_test.test @@ -35,14 +35,6 @@ select - a from t1; explain extended select - a from t1; drop table t1; -# -# Wrong usage of functions -# - -select 5 between 0 and 10 between 0 and 1,(5 between 0 and 10) between 0 and 1; -select 1 and 2 between 2 and 10, 2 between 2 and 10 and 1; -select 1 and 0 or 2, 2 or 1 and 0; - # # Coercibility # diff --git a/mysql-test/t/parser.test b/mysql-test/t/parser.test index 7e11a71c500..c5bd31c576e 100644 --- a/mysql-test/t/parser.test +++ b/mysql-test/t/parser.test @@ -1351,3 +1351,17 @@ create function fs() returns serial return 1; create table t1 ( id serial ); show create table t1; drop table t1; + +# +# BETWEEN syntax +# +create or replace view v1 as select 1 between (2 between 3 and 4) and 5; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +create or replace view v1 as select 1 between (2 in (3,4)) and 5; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +create or replace view v1 as select 1 between (2 like 3) and 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; +create or replace view v1 as select 1 not between (2 like 3) and 4; +Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; + +drop view v1; diff --git a/mysql-test/t/parser_precedence.test b/mysql-test/t/parser_precedence.test deleted file mode 100644 index 7b69bc9c6da..00000000000 --- a/mysql-test/t/parser_precedence.test +++ /dev/null @@ -1,335 +0,0 @@ - ---disable_warnings -drop table if exists t1_30237_bool; ---enable_warnings - -set sql_mode=NO_UNSIGNED_SUBTRACTION; - -create table t1_30237_bool(A boolean, B boolean, C boolean); - -insert into t1_30237_bool values -(FALSE, FALSE, FALSE), -(FALSE, FALSE, NULL), -(FALSE, FALSE, TRUE), -(FALSE, NULL, FALSE), -(FALSE, NULL, NULL), -(FALSE, NULL, TRUE), -(FALSE, TRUE, FALSE), -(FALSE, TRUE, NULL), -(FALSE, TRUE, TRUE), -(NULL, FALSE, FALSE), -(NULL, FALSE, NULL), -(NULL, FALSE, TRUE), -(NULL, NULL, FALSE), -(NULL, NULL, NULL), -(NULL, NULL, TRUE), -(NULL, TRUE, FALSE), -(NULL, TRUE, NULL), -(NULL, TRUE, TRUE), -(TRUE, FALSE, FALSE), -(TRUE, FALSE, NULL), -(TRUE, FALSE, TRUE), -(TRUE, NULL, FALSE), -(TRUE, NULL, NULL), -(TRUE, NULL, TRUE), -(TRUE, TRUE, FALSE), -(TRUE, TRUE, NULL), -(TRUE, TRUE, TRUE) ; - ---echo Testing OR, XOR, AND -select A, B, A OR B, A XOR B, A AND B - from t1_30237_bool where C is null order by A, B; - ---echo Testing that OR is associative -select A, B, C, (A OR B) OR C, A OR (B OR C), A OR B OR C - from t1_30237_bool order by A, B, C; - -select count(*) from t1_30237_bool - where ((A OR B) OR C) != (A OR (B OR C)); - ---echo Testing that XOR is associative -select A, B, C, (A XOR B) XOR C, A XOR (B XOR C), A XOR B XOR C - from t1_30237_bool order by A, B, C; - -select count(*) from t1_30237_bool - where ((A XOR B) XOR C) != (A XOR (B XOR C)); - ---echo Testing that AND is associative -select A, B, C, (A AND B) AND C, A AND (B AND C), A AND B AND C - from t1_30237_bool order by A, B, C; - -select count(*) from t1_30237_bool - where ((A AND B) AND C) != (A AND (B AND C)); - ---echo Testing that AND has precedence over OR -select A, B, C, (A OR B) AND C, A OR (B AND C), A OR B AND C - from t1_30237_bool order by A, B, C; -select count(*) from t1_30237_bool - where (A OR (B AND C)) != (A OR B AND C); -select A, B, C, (A AND B) OR C, A AND (B OR C), A AND B OR C - from t1_30237_bool order by A, B, C; -select count(*) from t1_30237_bool - where ((A AND B) OR C) != (A AND B OR C); - ---echo Testing that AND has precedence over XOR -select A, B, C, (A XOR B) AND C, A XOR (B AND C), A XOR B AND C - from t1_30237_bool order by A, B, C; -select count(*) from t1_30237_bool - where (A XOR (B AND C)) != (A XOR B AND C); -select A, B, C, (A AND B) XOR C, A AND (B XOR C), A AND B XOR C - from t1_30237_bool order by A, B, C; -select count(*) from t1_30237_bool - where ((A AND B) XOR C) != (A AND B XOR C); - ---echo Testing that XOR has precedence over OR -select A, B, C, (A XOR B) OR C, A XOR (B OR C), A XOR B OR C - from t1_30237_bool order by A, B, C; -select count(*) from t1_30237_bool - where ((A XOR B) OR C) != (A XOR B OR C); -select A, B, C, (A OR B) XOR C, A OR (B XOR C), A OR B XOR C - from t1_30237_bool order by A, B, C; -select count(*) from t1_30237_bool - where (A OR (B XOR C)) != (A OR B XOR C); - -drop table t1_30237_bool; - ---echo Testing that NOT has precedence over OR -select (NOT FALSE) OR TRUE, NOT (FALSE OR TRUE), NOT FALSE OR TRUE; - ---echo Testing that NOT has precedence over XOR -select (NOT FALSE) XOR FALSE, NOT (FALSE XOR FALSE), NOT FALSE XOR FALSE; - ---echo Testing that NOT has precedence over AND -select (NOT FALSE) AND FALSE, NOT (FALSE AND FALSE), NOT FALSE AND FALSE; - ---echo Testing that NOT is associative -select NOT NOT TRUE, NOT NOT NOT FALSE; - ---echo Testing that IS has precedence over NOT -select (NOT NULL) IS TRUE, NOT (NULL IS TRUE), NOT NULL IS TRUE; -select (NOT NULL) IS NOT TRUE, NOT (NULL IS NOT TRUE), NOT NULL IS NOT TRUE; -select (NOT NULL) IS FALSE, NOT (NULL IS FALSE), NOT NULL IS FALSE; -select (NOT NULL) IS NOT FALSE, NOT (NULL IS NOT FALSE), NOT NULL IS NOT FALSE; -select (NOT TRUE) IS UNKNOWN, NOT (TRUE IS UNKNOWN), NOT TRUE IS UNKNOWN; -select (NOT TRUE) IS NOT UNKNOWN, NOT (TRUE IS NOT UNKNOWN), NOT TRUE IS NOT UNKNOWN; -select (NOT TRUE) IS NULL, NOT (TRUE IS NULL), NOT TRUE IS NULL; -select (NOT TRUE) IS NOT NULL, NOT (TRUE IS NOT NULL), NOT TRUE IS NOT NULL; - ---echo Testing that IS [NOT] TRUE/FALSE/UNKNOWN predicates are not associative -# Documenting existing behavior in 5.0.48 --- error ER_PARSE_ERROR -select TRUE IS TRUE IS TRUE IS TRUE; --- error ER_PARSE_ERROR -select FALSE IS NOT TRUE IS NOT TRUE IS NOT TRUE; --- error ER_PARSE_ERROR -select NULL IS FALSE IS FALSE IS FALSE; --- error ER_PARSE_ERROR -select TRUE IS NOT FALSE IS NOT FALSE IS NOT FALSE; --- error ER_PARSE_ERROR -select FALSE IS UNKNOWN IS UNKNOWN IS UNKNOWN; --- error ER_PARSE_ERROR -select TRUE IS NOT UNKNOWN IS NOT UNKNOWN IS NOT UNKNOWN; - ---echo Testing that IS [NOT] NULL predicates are associative -# Documenting existing behavior in 5.0.48 -select FALSE IS NULL IS NULL IS NULL; -select TRUE IS NOT NULL IS NOT NULL IS NOT NULL; - ---echo Testing that comparison operators are left associative -select 1 <=> 2 <=> 2, (1 <=> 2) <=> 2, 1 <=> (2 <=> 2); -select 1 = 2 = 2, (1 = 2) = 2, 1 = (2 = 2); -select 1 != 2 != 3, (1 != 2) != 3, 1 != (2 != 3); -select 1 <> 2 <> 3, (1 <> 2) <> 3, 1 <> (2 <> 3); -select 1 < 2 < 3, (1 < 2) < 3, 1 < (2 < 3); -select 3 <= 2 <= 1, (3 <= 2) <= 1, 3 <= (2 <= 1); -select 1 > 2 > 3, (1 > 2) > 3, 1 > (2 > 3); -select 1 >= 2 >= 3, (1 >= 2) >= 3, 1 >= (2 >= 3); - --- echo Testing that | is associative -select 0xF0 | 0x0F | 0x55, (0xF0 | 0x0F) | 0x55, 0xF0 | (0x0F | 0x55); - --- echo Testing that & is associative -select 0xF5 & 0x5F & 0x55, (0xF5 & 0x5F) & 0x55, 0xF5 & (0x5F & 0x55); - --- echo Testing that << is left associative -select 4 << 3 << 2, (4 << 3) << 2, 4 << (3 << 2); - --- echo Testing that >> is left associative -select 256 >> 3 >> 2, (256 >> 3) >> 2, 256 >> (3 >> 2); - ---echo Testing that & has precedence over | -select 0xF0 & 0x0F | 0x55, (0xF0 & 0x0F) | 0x55, 0xF0 & (0x0F | 0x55); -select 0x55 | 0xF0 & 0x0F, (0x55 | 0xF0) & 0x0F, 0x55 | (0xF0 & 0x0F); - ---echo Testing that << has precedence over | -select 0x0F << 4 | 0x0F, (0x0F << 4) | 0x0F, 0x0F << (4 | 0x0F); -select 0x0F | 0x0F << 4, (0x0F | 0x0F) << 4, 0x0F | (0x0F << 4); - ---echo Testing that >> has precedence over | -select 0xF0 >> 4 | 0xFF, (0xF0 >> 4) | 0xFF, 0xF0 >> (4 | 0xFF); -select 0xFF | 0xF0 >> 4, (0xFF | 0xF0) >> 4, 0xFF | (0xF0 >> 4); - ---echo Testing that << has precedence over & -select 0x0F << 4 & 0xF0, (0x0F << 4) & 0xF0, 0x0F << (4 & 0xF0); -select 0xF0 & 0x0F << 4, (0xF0 & 0x0F) << 4, 0xF0 & (0x0F << 4); - ---echo Testing that >> has precedence over & -select 0xF0 >> 4 & 0x55, (0xF0 >> 4) & 0x55, 0xF0 >> (4 & 0x55); -select 0x0F & 0xF0 >> 4, (0x0F & 0xF0) >> 4, 0x0F & (0xF0 >> 4); - ---echo Testing that >> and << have the same precedence -select 0xFF >> 4 << 2, (0xFF >> 4) << 2, 0xFF >> (4 << 2); -select 0x0F << 4 >> 2, (0x0F << 4) >> 2, 0x0F << (4 >> 2); - ---echo Testing that binary + is associative -select 1 + 2 + 3, (1 + 2) + 3, 1 + (2 + 3); - ---echo Testing that binary - is left associative -select 1 - 2 - 3, (1 - 2) - 3, 1 - (2 - 3); - ---echo Testing that binary + and binary - have the same precedence -# evaluated left to right -select 1 + 2 - 3, (1 + 2) - 3, 1 + (2 - 3); -select 1 - 2 + 3, (1 - 2) + 3, 1 - (2 + 3); - ---echo Testing that binary + has precedence over | -select 0xF0 + 0x0F | 0x55, (0xF0 + 0x0F) | 0x55, 0xF0 + (0x0F | 0x55); -select 0x55 | 0xF0 + 0x0F, (0x55 | 0xF0) + 0x0F, 0x55 | (0xF0 + 0x0F); - ---echo Testing that binary + has precedence over & -select 0xF0 + 0x0F & 0x55, (0xF0 + 0x0F) & 0x55, 0xF0 + (0x0F & 0x55); -select 0x55 & 0xF0 + 0x0F, (0x55 & 0xF0) + 0x0F, 0x55 & (0xF0 + 0x0F); - ---echo Testing that binary + has precedence over << -select 2 + 3 << 4, (2 + 3) << 4, 2 + (3 << 4); -select 3 << 4 + 2, (3 << 4) + 2, 3 << (4 + 2); - ---echo Testing that binary + has precedence over >> -select 4 + 3 >> 2, (4 + 3) >> 2, 4 + (3 >> 2); -select 3 >> 2 + 1, (3 >> 2) + 1, 3 >> (2 + 1); - ---echo Testing that binary - has precedence over | -select 0xFF - 0x0F | 0x55, (0xFF - 0x0F) | 0x55, 0xFF - (0x0F | 0x55); -select 0x55 | 0xFF - 0xF0, (0x55 | 0xFF) - 0xF0, 0x55 | (0xFF - 0xF0); - ---echo Testing that binary - has precedence over & -select 0xFF - 0xF0 & 0x55, (0xFF - 0xF0) & 0x55, 0xFF - (0xF0 & 0x55); -select 0x55 & 0xFF - 0xF0, (0x55 & 0xFF) - 0xF0, 0x55 & (0xFF - 0xF0); - ---echo Testing that binary - has precedence over << -select 16 - 3 << 2, (16 - 3) << 2, 16 - (3 << 2); -select 4 << 3 - 2, (4 << 3) - 2, 4 << (3 - 2); - ---echo Testing that binary - has precedence over >> -select 16 - 3 >> 2, (16 - 3) >> 2, 16 - (3 >> 2); -select 16 >> 3 - 2, (16 >> 3) - 2, 16 >> (3 - 2); - ---echo Testing that * is associative -select 2 * 3 * 4, (2 * 3) * 4, 2 * (3 * 4); - ---echo Testing that * has precedence over | -select 2 * 0x40 | 0x0F, (2 * 0x40) | 0x0F, 2 * (0x40 | 0x0F); -select 0x0F | 2 * 0x40, (0x0F | 2) * 0x40, 0x0F | (2 * 0x40); - ---echo Testing that * has precedence over & -select 2 * 0x40 & 0x55, (2 * 0x40) & 0x55, 2 * (0x40 & 0x55); -select 0xF0 & 2 * 0x40, (0xF0 & 2) * 0x40, 0xF0 & (2 * 0x40); - ---echo Testing that * has precedence over << -# Actually, can't prove it for the first case, -# since << is a multiplication by a power of 2, -# and * is associative -select 5 * 3 << 4, (5 * 3) << 4, 5 * (3 << 4); -select 2 << 3 * 4, (2 << 3) * 4, 2 << (3 * 4); - ---echo Testing that * has precedence over >> -# >> is a multiplication by a (negative) power of 2, -# see above. -select 3 * 4 >> 2, (3 * 4) >> 2, 3 * (4 >> 2); -select 4 >> 2 * 3, (4 >> 2) * 3, 4 >> (2 * 3); - ---echo Testing that * has precedence over binary + -select 2 * 3 + 4, (2 * 3) + 4, 2 * (3 + 4); -select 2 + 3 * 4, (2 + 3) * 4, 2 + (3 * 4); - ---echo Testing that * has precedence over binary - -select 4 * 3 - 2, (4 * 3) - 2, 4 * (3 - 2); -select 4 - 3 * 2, (4 - 3) * 2, 4 - (3 * 2); - ---echo Testing that / is left associative -select 15 / 5 / 3, (15 / 5) / 3, 15 / (5 / 3); - ---echo Testing that / has precedence over | -select 105 / 5 | 2, (105 / 5) | 2, 105 / (5 | 2); -select 105 | 2 / 5, (105 | 2) / 5, 105 | (2 / 5); - ---echo Testing that / has precedence over & -select 105 / 5 & 0x0F, (105 / 5) & 0x0F, 105 / (5 & 0x0F); -select 0x0F & 105 / 5, (0x0F & 105) / 5, 0x0F & (105 / 5); - ---echo Testing that / has precedence over << -select 0x80 / 4 << 2, (0x80 / 4) << 2, 0x80 / (4 << 2); -select 0x80 << 4 / 2, (0x80 << 4) / 2, 0x80 << (4 / 2); - ---echo Testing that / has precedence over >> -select 0x80 / 4 >> 2, (0x80 / 4) >> 2, 0x80 / (4 >> 2); -select 0x80 >> 4 / 2, (0x80 >> 4) / 2, 0x80 >> (4 / 2); - ---echo Testing that / has precedence over binary + -select 0x80 / 2 + 2, (0x80 / 2) + 2, 0x80 / (2 + 2); -select 0x80 + 2 / 2, (0x80 + 2) / 2, 0x80 + (2 / 2); - ---echo Testing that / has precedence over binary - -select 0x80 / 4 - 2, (0x80 / 4) - 2, 0x80 / (4 - 2); -select 0x80 - 4 / 2, (0x80 - 4) / 2, 0x80 - (4 / 2); - -# TODO: %, DIV, MOD - ---echo Testing that ^ is associative -select 0xFF ^ 0xF0 ^ 0x0F, (0xFF ^ 0xF0) ^ 0x0F, 0xFF ^ (0xF0 ^ 0x0F); -select 0xFF ^ 0xF0 ^ 0x55, (0xFF ^ 0xF0) ^ 0x55, 0xFF ^ (0xF0 ^ 0x55); - ---echo Testing that ^ has precedence over | -select 0xFF ^ 0xF0 | 0x0F, (0xFF ^ 0xF0) | 0x0F, 0xFF ^ (0xF0 | 0x0F); -select 0xF0 | 0xFF ^ 0xF0, (0xF0 | 0xFF) ^ 0xF0, 0xF0 | (0xFF ^ 0xF0); - ---echo Testing that ^ has precedence over & -select 0xFF ^ 0xF0 & 0x0F, (0xFF ^ 0xF0) & 0x0F, 0xFF ^ (0xF0 & 0x0F); -select 0x0F & 0xFF ^ 0xF0, (0x0F & 0xFF) ^ 0xF0, 0x0F & (0xFF ^ 0xF0); - ---echo Testing that ^ has precedence over << -select 0xFF ^ 0xF0 << 2, (0xFF ^ 0xF0) << 2, 0xFF ^ (0xF0 << 2); -select 0x0F << 2 ^ 0xFF, (0x0F << 2) ^ 0xFF, 0x0F << (2 ^ 0xFF); - ---echo Testing that ^ has precedence over >> -select 0xFF ^ 0xF0 >> 2, (0xFF ^ 0xF0) >> 2, 0xFF ^ (0xF0 >> 2); -select 0xFF >> 2 ^ 0xF0, (0xFF >> 2) ^ 0xF0, 0xFF >> (2 ^ 0xF0); - ---echo Testing that ^ has precedence over binary + -select 0xFF ^ 0xF0 + 0x0F, (0xFF ^ 0xF0) + 0x0F, 0xFF ^ (0xF0 + 0x0F); -select 0x0F + 0xFF ^ 0xF0, (0x0F + 0xFF) ^ 0xF0, 0x0F + (0xFF ^ 0xF0); - ---echo Testing that ^ has precedence over binary - -select 0xFF ^ 0xF0 - 1, (0xFF ^ 0xF0) - 1, 0xFF ^ (0xF0 - 1); -select 0x55 - 0x0F ^ 0x55, (0x55 - 0x0F) ^ 0x55, 0x55 - (0x0F ^ 0x55); - ---echo Testing that ^ has precedence over * -select 0xFF ^ 0xF0 * 2, (0xFF ^ 0xF0) * 2, 0xFF ^ (0xF0 * 2); -select 2 * 0xFF ^ 0xF0, (2 * 0xFF) ^ 0xF0, 2 * (0xFF ^ 0xF0); - ---echo Testing that ^ has precedence over / -select 0xFF ^ 0xF0 / 2, (0xFF ^ 0xF0) / 2, 0xFF ^ (0xF0 / 2); -select 0xF2 / 2 ^ 0xF0, (0xF2 / 2) ^ 0xF0, 0xF2 / (2 ^ 0xF0); - ---echo Testing that ^ has precedence over % -select 0xFF ^ 0xF0 % 0x20, (0xFF ^ 0xF0) % 0x20, 0xFF ^ (0xF0 % 0x20); -select 0xFF % 0x20 ^ 0xF0, (0xFF % 0x20) ^ 0xF0, 0xFF % (0x20 ^ 0xF0); - ---echo Testing that ^ has precedence over DIV -select 0xFF ^ 0xF0 DIV 2, (0xFF ^ 0xF0) DIV 2, 0xFF ^ (0xF0 DIV 2); -select 0xF2 DIV 2 ^ 0xF0, (0xF2 DIV 2) ^ 0xF0, 0xF2 DIV (2 ^ 0xF0); - ---echo Testing that ^ has precedence over MOD -select 0xFF ^ 0xF0 MOD 0x20, (0xFF ^ 0xF0) MOD 0x20, 0xFF ^ (0xF0 MOD 0x20); -select 0xFF MOD 0x20 ^ 0xF0, (0xFF MOD 0x20) ^ 0xF0, 0xFF MOD (0x20 ^ 0xF0); - diff --git a/sql/item.h b/sql/item.h index b789f703c2e..a49f9e8e5e4 100644 --- a/sql/item.h +++ b/sql/item.h @@ -82,8 +82,9 @@ enum precedence { XOR_PRECEDENCE, // XOR AND_PRECEDENCE, // AND, && NOT_PRECEDENCE, // NOT (unless HIGH_NOT_PRECEDENCE) - BETWEEN_PRECEDENCE, // BETWEEN, CASE, WHEN, THEN, ELSE - CMP_PRECEDENCE, // =, <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN + CMP_PRECEDENCE, // =, <=>, >=, >, <=, <, <>, !=, IS + BETWEEN_PRECEDENCE, // BETWEEN + IN_PRECEDENCE, // IN, LIKE, REGEXP BITOR_PRECEDENCE, // | BITAND_PRECEDENCE, // & SHIFT_PRECEDENCE, // <<, >> @@ -1381,6 +1382,8 @@ public: mysql_register_view(). */ virtual enum precedence precedence() const { return DEFAULT_PRECEDENCE; } + enum precedence higher_precedence() const + { return (enum precedence)(precedence() + 1); } void print_parenthesised(String *str, enum_query_type query_type, enum precedence parent_prec); /** diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 69c7eb33852..d3a59e5b4f0 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2312,7 +2312,7 @@ longlong Item_func_between::val_int() void Item_func_between::print(String *str, enum_query_type query_type) { - args[0]->print_parenthesised(str, query_type, precedence()); + args[0]->print_parenthesised(str, query_type, higher_precedence()); if (negated) str->append(STRING_WITH_LEN(" not")); str->append(STRING_WITH_LEN(" between ")); @@ -3375,15 +3375,15 @@ void Item_func_case::print(String *str, enum_query_type query_type) for (uint i= first_expr_num + 1 ; i < nwhens + first_expr_num + 1; i++) { str->append(STRING_WITH_LEN("when ")); - args[i]->print_parenthesised(str, query_type, precedence()); + args[i]->print(str, query_type); str->append(STRING_WITH_LEN(" then ")); - args[i+nwhens]->print_parenthesised(str, query_type, precedence()); + args[i+nwhens]->print(str, query_type); str->append(' '); } if (else_expr_num != -1) { str->append(STRING_WITH_LEN("else ")); - args[else_expr_num]->print_parenthesised(str, query_type, precedence()); + args[else_expr_num]->print(str, query_type); str->append(' '); } str->append(STRING_WITH_LEN("end")); @@ -5243,12 +5243,14 @@ void Item_func_like::print(String *str, enum_query_type query_type) str->append(STRING_WITH_LEN(" not ")); str->append(func_name()); str->append(' '); - args[1]->print_parenthesised(str, query_type, precedence()); if (escape_used_in_parsing) { + args[1]->print_parenthesised(str, query_type, precedence()); str->append(STRING_WITH_LEN(" escape ")); - escape_item->print(str, query_type); + escape_item->print_parenthesised(str, query_type, higher_precedence()); } + else + args[1]->print_parenthesised(str, query_type, higher_precedence()); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 579b1bde1ce..22736339bf6 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1590,7 +1590,6 @@ public: uint decimal_precision() const; table_map not_null_tables() const { return 0; } const char *func_name() const { return "case"; } - enum precedence precedence() const { return BETWEEN_PRECEDENCE; } virtual void print(String *str, enum_query_type query_type); Item *find_item(String *str); CHARSET_INFO *compare_collation() const { return cmp_collation.collation; } @@ -1704,7 +1703,7 @@ public: virtual void print(String *str, enum_query_type query_type); enum Functype functype() const { return IN_FUNC; } const char *func_name() const { return "in"; } - enum precedence precedence() const { return CMP_PRECEDENCE; } + enum precedence precedence() const { return IN_PRECEDENCE; } bool eval_not_null_tables(void *opt_arg); void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); bool count_sargable_conds(void *arg); @@ -1999,7 +1998,7 @@ public: return this; } const char *func_name() const { return "like"; } - enum precedence precedence() const { return CMP_PRECEDENCE; } + enum precedence precedence() const { return IN_PRECEDENCE; } bool fix_fields(THD *thd, Item **ref); bool fix_length_and_dec() { @@ -2127,7 +2126,7 @@ public: bool fix_fields(THD *thd, Item **ref); bool fix_length_and_dec(); const char *func_name() const { return "regexp"; } - enum precedence precedence() const { return CMP_PRECEDENCE; } + enum precedence precedence() const { return IN_PRECEDENCE; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } void print(String *str, enum_query_type query_type) { diff --git a/sql/item_func.cc b/sql/item_func.cc index 9d588ce0eb1..cc4a0157d1a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -481,8 +481,7 @@ void Item_func::print_op(String *str, enum_query_type query_type) str->append(func_name()); str->append(' '); } - args[arg_count-1]->print_parenthesised(str, query_type, - (enum precedence)(precedence() + 1)); + args[arg_count-1]->print_parenthesised(str, query_type, higher_precedence()); } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 0499a677be9..802bfca64b7 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -3283,7 +3283,7 @@ void Item_in_subselect::print(String *str, enum_query_type query_type) str->append(STRING_WITH_LEN("")); else { - left_expr->print(str, query_type); + left_expr->print_parenthesised(str, query_type, precedence()); str->append(STRING_WITH_LEN(" in ")); } Item_subselect::print(str, query_type); diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 816073ed5d3..2292c22480f 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -628,7 +628,7 @@ public: bool val_bool(); bool test_limit(st_select_lex_unit *unit); void print(String *str, enum_query_type query_type); - enum precedence precedence() const { return CMP_PRECEDENCE; } + enum precedence precedence() const { return IN_PRECEDENCE; } bool fix_fields(THD *thd, Item **ref); bool fix_length_and_dec(); void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 138d5e13701..2eabc4f0a6d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -149,6 +149,14 @@ void LEX::parse_error() } +static Item* escape(THD *thd) +{ + thd->lex->escape_used= false; + const char *esc= thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES ? "" : "\\"; + return new (thd->mem_root) Item_string_ascii(thd, esc, MY_TEST(esc[0])); +} + + /** @brief Bison callback to report a syntax/OOM error @@ -1022,10 +1030,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %parse-param { THD *thd } %lex-param { THD *thd } /* - Currently there are 102 shift/reduce conflicts. + Currently there are 105 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 101 +%expect 105 /* Comments for TOKENS. @@ -1721,17 +1729,19 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %left OR_OR_SYM OR_SYM OR2_SYM %left XOR %left AND_SYM AND_AND_SYM -%left BETWEEN_SYM CASE_SYM WHEN_SYM THEN_SYM ELSE -%left '=' EQUAL_SYM GE '>' LE '<' NE IS LIKE REGEXP IN_SYM +%nonassoc NOT_SYM +%left '=' EQUAL_SYM GE '>' LE '<' NE +%nonassoc IS +%right BETWEEN_SYM +%left LIKE REGEXP IN_SYM %left '|' %left '&' %left SHIFT_LEFT SHIFT_RIGHT %left '-' '+' %left '*' '/' '%' DIV_SYM MOD_SYM %left '^' -%left NEG '~' -%right NOT_SYM NOT2_SYM -%right BINARY COLLATE_SYM +%nonassoc NEG '~' NOT2_SYM BINARY +%nonassoc COLLATE_SYM %left INTERVAL_SYM %type @@ -1831,7 +1841,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); table_wild simple_expr column_default_non_parenthesized_expr udf_expr expr_or_default set_expr_or_default geometry_function signed_literal expr_or_literal - opt_escape sp_opt_default simple_ident_nospvar simple_ident_q field_or_var limit_option @@ -8915,37 +8924,49 @@ expr: if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri IS TRUE_SYM %prec IS + | expr IS TRUE_SYM %prec IS { $$= new (thd->mem_root) Item_func_istrue(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri IS not TRUE_SYM %prec IS + | expr IS not TRUE_SYM %prec IS { $$= new (thd->mem_root) Item_func_isnottrue(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri IS FALSE_SYM %prec IS + | expr IS FALSE_SYM %prec IS { $$= new (thd->mem_root) Item_func_isfalse(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri IS not FALSE_SYM %prec IS + | expr IS not FALSE_SYM %prec IS { $$= new (thd->mem_root) Item_func_isnotfalse(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri IS UNKNOWN_SYM %prec IS + | expr IS UNKNOWN_SYM %prec IS { $$= new (thd->mem_root) Item_func_isnull(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri IS not UNKNOWN_SYM %prec IS + | expr IS not UNKNOWN_SYM %prec IS + { + $$= new (thd->mem_root) Item_func_isnotnull(thd, $1); + if ($$ == NULL) + MYSQL_YYABORT; + } + | expr IS NULL_SYM %prec IS + { + $$= new (thd->mem_root) Item_func_isnull(thd, $1); + if ($$ == NULL) + MYSQL_YYABORT; + } + | expr IS not NULL_SYM %prec IS { $$= new (thd->mem_root) Item_func_isnotnull(thd, $1); if ($$ == NULL) @@ -8955,19 +8976,7 @@ expr: ; bool_pri: - bool_pri IS NULL_SYM %prec IS - { - $$= new (thd->mem_root) Item_func_isnull(thd, $1); - if ($$ == NULL) - MYSQL_YYABORT; - } - | bool_pri IS not NULL_SYM %prec IS - { - $$= new (thd->mem_root) Item_func_isnotnull(thd, $1); - if ($$ == NULL) - MYSQL_YYABORT; - } - | bool_pri EQUAL_SYM predicate %prec EQUAL_SYM + bool_pri EQUAL_SYM predicate %prec EQUAL_SYM { $$= new (thd->mem_root) Item_func_equal(thd, $1, $3); if ($$ == NULL) @@ -8989,13 +8998,13 @@ bool_pri: ; predicate: - bit_expr IN_SYM '(' subselect ')' + predicate IN_SYM '(' subselect ')' { $$= new (thd->mem_root) Item_in_subselect(thd, $1, $4); if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr not IN_SYM '(' subselect ')' + | predicate not IN_SYM '(' subselect ')' { Item *item= new (thd->mem_root) Item_in_subselect(thd, $1, $5); if (item == NULL) @@ -9004,13 +9013,13 @@ predicate: if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr IN_SYM '(' expr ')' + | predicate IN_SYM '(' expr ')' { $$= handle_sql2003_note184_exception(thd, $1, true, $4); if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr IN_SYM '(' expr ',' expr_list ')' + | predicate IN_SYM '(' expr ',' expr_list ')' { $6->push_front($4, thd->mem_root); $6->push_front($1, thd->mem_root); @@ -9018,13 +9027,13 @@ predicate: if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr not IN_SYM '(' expr ')' + | predicate not IN_SYM '(' expr ')' { $$= handle_sql2003_note184_exception(thd, $1, false, $5); if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr not IN_SYM '(' expr ',' expr_list ')' + | predicate not IN_SYM '(' expr ',' expr_list ')' { $7->push_front($5, thd->mem_root); $7->push_front($1, thd->mem_root); @@ -9033,13 +9042,13 @@ predicate: MYSQL_YYABORT; $$= item->neg_transformer(thd); } - | bit_expr BETWEEN_SYM bit_expr AND_SYM predicate + | predicate BETWEEN_SYM predicate AND_SYM predicate %prec BETWEEN_SYM { $$= new (thd->mem_root) Item_func_between(thd, $1, $3, $5); if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate + | predicate not BETWEEN_SYM predicate AND_SYM predicate %prec BETWEEN_SYM { Item_func_between *item; item= new (thd->mem_root) Item_func_between(thd, $1, $4, $6); @@ -9047,7 +9056,7 @@ predicate: MYSQL_YYABORT; $$= item->neg_transformer(thd); } - | bit_expr SOUNDS_SYM LIKE bit_expr + | predicate SOUNDS_SYM LIKE predicate { Item *item1= new (thd->mem_root) Item_func_soundex(thd, $1); Item *item4= new (thd->mem_root) Item_func_soundex(thd, $4); @@ -9057,28 +9066,41 @@ predicate: if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr LIKE simple_expr opt_escape + | predicate LIKE predicate { - $$= new (thd->mem_root) Item_func_like(thd, $1, $3, $4, - Lex->escape_used); + $$= new (thd->mem_root) Item_func_like(thd, $1, $3, escape(thd), false); if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr not LIKE simple_expr opt_escape + | predicate LIKE predicate ESCAPE_SYM predicate %prec LIKE { - Item *item= new (thd->mem_root) Item_func_like(thd, $1, $4, $5, - Lex->escape_used); + Lex->escape_used= true; + $$= new (thd->mem_root) Item_func_like(thd, $1, $3, $5, true); + if ($$ == NULL) + MYSQL_YYABORT; + } + | predicate not LIKE predicate + { + Item *item= new (thd->mem_root) Item_func_like(thd, $1, $4, escape(thd), false); if (item == NULL) MYSQL_YYABORT; $$= item->neg_transformer(thd); } - | bit_expr REGEXP bit_expr + | predicate not LIKE predicate ESCAPE_SYM predicate %prec LIKE + { + Lex->escape_used= true; + Item *item= new (thd->mem_root) Item_func_like(thd, $1, $4, $6, true); + if (item == NULL) + MYSQL_YYABORT; + $$= item->neg_transformer(thd); + } + | predicate REGEXP predicate { $$= new (thd->mem_root) Item_func_regex(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr not REGEXP bit_expr + | predicate not REGEXP predicate { Item *item= new (thd->mem_root) Item_func_regex(thd, $1, $4); if (item == NULL) @@ -11468,23 +11490,6 @@ opt_having_clause: } ; -opt_escape: - ESCAPE_SYM simple_expr - { - Lex->escape_used= TRUE; - $$= $2; - } - | /* empty */ - { - Lex->escape_used= FALSE; - $$= ((thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) ? - new (thd->mem_root) Item_string_ascii(thd, "", 0) : - new (thd->mem_root) Item_string_ascii(thd, "\\", 1)); - if ($$ == NULL) - MYSQL_YYABORT; - } - ; - /* group by statement in select */ From 8894dae1df87efda299d2c1fbccc4792c9058f45 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 19 Oct 2020 12:57:44 +0200 Subject: [PATCH 215/323] MDEV-17408 VIEW is incorrectly defined for a combination of = and BETWEEN --- mysql-test/r/precedence_bugs.result | 10 ++++++++++ mysql-test/t/precedence_bugs.test | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/mysql-test/r/precedence_bugs.result b/mysql-test/r/precedence_bugs.result index 3da61b6b58a..4b13e820d7f 100644 --- a/mysql-test/r/precedence_bugs.result +++ b/mysql-test/r/precedence_bugs.result @@ -48,3 +48,13 @@ character_set_client latin1 collation_connection latin1_swedish_ci drop view v1; drop table t1; +# +# MDEV-17408 VIEW is incorrectly defined for a combination of = and BETWEEN +# +create view v1 as select 1 like (now() between '2000-01-01' and '2012-12-12' ); +show create view v1; +View v1 +Create View CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 like (current_timestamp() between '2000-01-01' and '2012-12-12') AS `1 like (now() between '2000-01-01' and '2012-12-12' )` +character_set_client latin1 +collation_connection latin1_swedish_ci +drop view v1; diff --git a/mysql-test/t/precedence_bugs.test b/mysql-test/t/precedence_bugs.test index 46a803504f2..6e8e624c840 100644 --- a/mysql-test/t/precedence_bugs.test +++ b/mysql-test/t/precedence_bugs.test @@ -32,3 +32,10 @@ create view v1 as select avg(b) / (2 + a) from t1; query_vertical show create view v1; drop view v1; drop table t1; + +--echo # +--echo # MDEV-17408 VIEW is incorrectly defined for a combination of = and BETWEEN +--echo # +create view v1 as select 1 like (now() between '2000-01-01' and '2012-12-12' ); +query_vertical show create view v1; +drop view v1; From 5a9df1550f256b7be7aaffbf4cbce13d0ca22566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Mon, 12 Oct 2020 13:38:59 +0300 Subject: [PATCH 216/323] MDEV-23941: strings/json_lib.c:893:12: style: Suspicious condition The characters parsed are always ascii characters, hence one byte. This means that the code did not have "incorrect" logic because the boolean condition, if true, would also evaluate to the value of 1. The condition however is semantically wrong, assuming a length is equal to the condition outcome. Change paranthesis to make it also read according to the intent. --- strings/json_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strings/json_lib.c b/strings/json_lib.c index 3ce9b0c503f..3c455c3572c 100644 --- a/strings/json_lib.c +++ b/strings/json_lib.c @@ -890,7 +890,7 @@ int json_read_keyname_chr(json_engine_t *j) case S_QUOTE: for (;;) /* Skip spaces until ':'. */ { - if ((c_len= json_next_char(&j->s) > 0)) + if ((c_len= json_next_char(&j->s)) > 0) { if (j->s.c_next == ':') { From b94e8e4b25e039b5f165339b8ee0fd4af856459c Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Fri, 23 Oct 2020 12:32:49 +0530 Subject: [PATCH 217/323] MDEV-23867: insert... select crash in compute_window_func There are 2 issues here: Issue #1: memory allocation. An IO_CACHE that uses encryption uses a larger buffer (it needs space for the encrypted data, decrypted data, IO_CACHE_CRYPT struct to describe encryption parameters etc). Issue #2: IO_CACHE::seek_not_done When IO_CACHE objects are cloned, they still share the file descriptor. This means, operation on one IO_CACHE may change the file read position which will confuse other IO_CACHEs using it. The fix of these issues would be: Allocate the buffer to also include the extra size needed for encryption. Perform seek again after one IO_CACHE reads the file. --- include/my_sys.h | 9 +- .../encryption/r/tempfiles_encrypted.result | 3896 +++++++++++++++++ .../encryption/t/tempfiles_encrypted.opt | 1 + .../encryption/t/tempfiles_encrypted.test | 31 + mysys/mf_iocache.c | 6 +- sql/mf_iocache_encr.cc | 10 + 6 files changed, 3946 insertions(+), 7 deletions(-) create mode 100644 mysql-test/suite/encryption/r/tempfiles_encrypted.result create mode 100644 mysql-test/suite/encryption/t/tempfiles_encrypted.opt create mode 100644 mysql-test/suite/encryption/t/tempfiles_encrypted.test diff --git a/include/my_sys.h b/include/my_sys.h index fe66aeef48c..08b06951d0d 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -476,18 +476,19 @@ typedef struct st_io_cache /* Used when cacheing files */ partial. */ int seek_not_done,error; - /* buffer_length is memory size allocated for buffer or write_buffer */ + /* length of the buffer used for storing un-encrypted data */ size_t buffer_length; /* read_length is the same as buffer_length except when we use async io */ size_t read_length; myf myflags; /* Flags used to my_read/my_write */ /* - alloced_buffer is 1 if the buffer was allocated by init_io_cache() and - 0 if it was supplied by the user. + alloced_buffer is set to the size of the buffer allocated for the IO_CACHE. + Includes the overhead(storing key to ecnrypt and decrypt) for encryption. + Set to 0 if nothing is allocated. Currently READ_NET is the only one that will use a buffer allocated somewhere else */ - my_bool alloced_buffer; + size_t alloced_buffer; #ifdef HAVE_AIOWAIT /* As inidicated by ifdef, this is for async I/O, which is not currently diff --git a/mysql-test/suite/encryption/r/tempfiles_encrypted.result b/mysql-test/suite/encryption/r/tempfiles_encrypted.result new file mode 100644 index 00000000000..1856c30a36b --- /dev/null +++ b/mysql-test/suite/encryption/r/tempfiles_encrypted.result @@ -0,0 +1,3896 @@ +# +# Tests when the temporary files are encrypted +# +select @@encrypt_tmp_files; +@@encrypt_tmp_files +1 +drop table if exists t1,t2; +drop view if exists v1; +# ######################################################################## +# # Parser tests +# ######################################################################## +# +# Check what happens when one attempts to use window function without OVER clause +create table t1 (a int, b int); +insert into t1 values (1,1),(2,2); +select row_number() from t1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'from t1' at line 1 +select rank() from t1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'from t1' at line 1 +# Attempt to use window function in the WHERE clause +select * from t1 where 1=rank() over (order by a); +ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause +select * from t1 where 1>row_number() over (partition by b order by a); +ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause +drop table t1; +# ######################################################################## +# # Functionality tests +# ######################################################################## +# +# Check if ROW_NUMBER() works in basic cases +create table t1(a int, b int, x char(32)); +insert into t1 values (2, 10, 'xx'); +insert into t1 values (2, 10, 'zz'); +insert into t1 values (2, 20, 'yy'); +insert into t1 values (3, 10, 'xxx'); +insert into t1 values (3, 20, 'vvv'); +select a, row_number() over (partition by a order by b) from t1; +a row_number() over (partition by a order by b) +2 1 +2 2 +2 3 +3 1 +3 2 +select a, b, x, row_number() over (partition by a order by x) from t1; +a b x row_number() over (partition by a order by x) +2 10 xx 1 +2 20 yy 2 +2 10 zz 3 +3 20 vvv 1 +3 10 xxx 2 +drop table t1; +create table t1 (pk int primary key, a int, b int); +insert into t1 values +(1, 10, 22), +(2, 11, 21), +(3, 12, 20), +(4, 13, 19), +(5, 14, 18); +select +pk, a, b, +row_number() over (order by a), +row_number() over (order by b) +from t1 +order by b; +pk a b row_number() over (order by a) row_number() over (order by b) +5 14 18 5 1 +4 13 19 4 2 +3 12 20 3 3 +2 11 21 2 4 +1 10 22 1 5 +drop table t1; +# +# Try RANK() function +# +create table t2 ( +pk int primary key, +a int +); +insert into t2 values +( 1 , 0), +( 2 , 0), +( 3 , 1), +( 4 , 1), +( 8 , 2), +( 5 , 2), +( 6 , 2), +( 7 , 2), +( 9 , 4), +(10 , 4); +select pk, a, rank() over (order by a) from t2; +pk a rank() over (order by a) +1 0 1 +10 4 9 +2 0 1 +3 1 3 +4 1 3 +5 2 5 +6 2 5 +7 2 5 +8 2 5 +9 4 9 +select pk, a, rank() over (order by a desc) from t2; +pk a rank() over (order by a desc) +1 0 9 +10 4 1 +2 0 9 +3 1 7 +4 1 7 +5 2 3 +6 2 3 +7 2 3 +8 2 3 +9 4 1 +drop table t2; +# +# Try Aggregates as window functions. With frames. +# +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (pk int, c int); +insert into t1 select a+1,1 from t0; +update t1 set c=2 where pk not in (1,2,3,4); +select * from t1; +pk c +1 1 +2 1 +3 1 +4 1 +5 2 +6 2 +7 2 +8 2 +9 2 +10 2 +select +pk, c, +count(*) over (partition by c order by pk +rows between 2 preceding and 2 following) as CNT +from t1; +pk c CNT +1 1 3 +2 1 4 +3 1 4 +4 1 3 +5 2 3 +6 2 4 +7 2 5 +8 2 5 +9 2 4 +10 2 3 +select +pk, c, +count(*) over (partition by c order by pk +rows between 1 preceding and 2 following) as CNT +from t1; +pk c CNT +1 1 3 +2 1 4 +3 1 3 +4 1 2 +5 2 3 +6 2 4 +7 2 4 +8 2 4 +9 2 3 +10 2 2 +select +pk, c, +count(*) over (partition by c order by pk +rows between 2 preceding and current row) as CNT +from t1; +pk c CNT +1 1 1 +2 1 2 +3 1 3 +4 1 3 +5 2 1 +6 2 2 +7 2 3 +8 2 3 +9 2 3 +10 2 3 +select +pk,c, +count(*) over (partition by c order by pk rows +between 1 following and 2 following) as CNT +from t1; +pk c CNT +1 1 2 +2 1 2 +3 1 1 +4 1 0 +5 2 2 +6 2 2 +7 2 2 +8 2 2 +9 2 1 +10 2 0 +select +pk,c, +count(*) over (partition by c order by pk rows +between 2 preceding and 1 preceding) as CNT +from t1; +pk c CNT +1 1 0 +2 1 1 +3 1 2 +4 1 2 +5 2 0 +6 2 1 +7 2 2 +8 2 2 +9 2 2 +10 2 2 +select +pk, c, +count(*) over (partition by c order by pk +rows between current row and 1 following) as CNT +from t1; +pk c CNT +1 1 2 +2 1 2 +3 1 2 +4 1 1 +5 2 2 +6 2 2 +7 2 2 +8 2 2 +9 2 2 +10 2 1 +# Check ORDER BY DESC +select +pk, c, +count(*) over (partition by c order by pk desc +rows between 2 preceding and 2 following) as CNT +from t1; +pk c CNT +4 1 3 +3 1 4 +2 1 4 +1 1 3 +10 2 3 +9 2 4 +8 2 5 +7 2 5 +6 2 4 +5 2 3 +drop table t0,t1; +# +# Resolution of window names +# +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (pk int, c int); +insert into t1 select a+1,1 from t0; +update t1 set c=2 where pk not in (1,2,3,4); +select * from t1; +pk c +1 1 +2 1 +3 1 +4 1 +5 2 +6 2 +7 2 +8 2 +9 2 +10 2 +select +pk, c, +count(*) over w1 as CNT +from t1 +window w1 as (partition by c order by pk +rows between 2 preceding and 2 following); +pk c CNT +1 1 3 +2 1 4 +3 1 4 +4 1 3 +5 2 3 +6 2 4 +7 2 5 +8 2 5 +9 2 4 +10 2 3 +select +pk, c, +count(*) over (w1 rows between 2 preceding and 2 following) as CNT +from t1 +window w1 as (partition by c order by pk); +pk c CNT +1 1 3 +2 1 4 +3 1 4 +4 1 3 +5 2 3 +6 2 4 +7 2 5 +8 2 5 +9 2 4 +10 2 3 +select +pk, c, +count(*) over (w1 order by pk rows between 2 preceding and 2 following) as CNT +from t1 +window w1 as (partition by c); +pk c CNT +1 1 3 +2 1 4 +3 1 4 +4 1 3 +5 2 3 +6 2 4 +7 2 5 +8 2 5 +9 2 4 +10 2 3 +select +pk, c, +count(*) over (w2 rows between 2 preceding and 2 following) as CNT +from t1 +window w1 as (partition by c), w2 as (w1 order by pk); +pk c CNT +1 1 3 +2 1 4 +3 1 4 +4 1 3 +5 2 3 +6 2 4 +7 2 5 +8 2 5 +9 2 4 +10 2 3 +select +pk, c, +count(*) over w3 as CNT +from t1 +window +w1 as (partition by c), +w2 as (w1 order by pk), +w3 as (w2 rows between 2 preceding and 2 following); +pk c CNT +1 1 3 +2 1 4 +3 1 4 +4 1 3 +5 2 3 +6 2 4 +7 2 5 +8 2 5 +9 2 4 +10 2 3 +select +pk, c, +count(*) over w as CNT +from t1 +window w1 as (partition by c order by pk +rows between 2 preceding and 2 following); +ERROR HY000: Window specification with name 'w' is not defined +select +pk, c, +count(*) over (w2 rows between 2 preceding and 2 following) as CNT +from t1 +window w1 as (partition by c), w1 as (order by pk); +ERROR HY000: Multiple window specifications with the same name 'w1' +select +pk, c, +count(*) over (w2 rows between 2 preceding and 2 following) as CNT +from t1 +window w1 as (partition by c), w2 as (w partition by c order by pk); +ERROR HY000: Window specification with name 'w' is not defined +select +pk, c, +count(*) over (w2 rows between 2 preceding and 2 following) as CNT +from t1 +window w1 as (partition by c), w2 as (w1 partition by c order by pk); +ERROR HY000: Window specification referencing another one 'w1' cannot contain partition list +select +pk, c, +count(*) over (w2 rows between 2 preceding and 2 following) as CNT +from t1 +window w1 as (partition by c order by pk), w2 as (w1 order by pk); +ERROR HY000: Referenced window specification 'w1' already contains order list +select +pk, c, +count(*) over w3 as CNT +from t1 +window +w1 as (partition by c), +w2 as (w1 order by pk rows between 3 preceding and 2 following), +w3 as (w2 rows between 2 preceding and 2 following); +ERROR HY000: Referenced window specification 'w2' cannot contain window frame +select +pk, c, +count(*) over w1 as CNT +from t1 +window w1 as (partition by c order by pk +rows between unbounded following and 2 following); +ERROR HY000: Unacceptable combination of window frame bound specifications +select +pk, c, +count(*) over (w1 rows between 2 preceding and unbounded preceding) as CNT +from t1 +window w1 as (partition by c order by pk); +ERROR HY000: Unacceptable combination of window frame bound specifications +select +pk, c, +count(*) over (w1 order by pk rows between current row and 2 preceding) as CNT +from t1 +window w1 as (partition by c); +ERROR HY000: Unacceptable combination of window frame bound specifications +select +pk, c, +count(*) over (w2 rows between 2 following and current row) as CNT +from t1 +window w1 as (partition by c), w2 as (w1 order by pk); +ERROR HY000: Unacceptable combination of window frame bound specifications +select +pk, c +from t1 where rank() over w1 > 2 +window w1 as (partition by c order by pk); +ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause +select +c, max(pk) as m +from t1 +group by c + rank() over w1 +window w1 as (order by m); +ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause +select +c, max(pk) as m, rank() over w1 as r +from t1 +group by c+r +window w1 as (order by m); +ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause +select +c, max(pk) as m, rank() over w1 as r +from t1 +group by c having c+r > 3 +window w1 as (order by m); +ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause +select +c, max(pk) as m, rank() over w1 as r, +rank() over (partition by r+1 order by m) +from t1 +group by c +window w1 as (order by m); +ERROR HY000: Window function is not allowed in window specification +select +c, max(pk) as m, rank() over w1 as r, +rank() over (partition by m order by r) +from t1 +group by c +window w1 as (order by m); +ERROR HY000: Window function is not allowed in window specification +select +c, max(pk) as m, rank() over w1 as r, dense_rank() over w2 as dr +from t1 +group by c +window w1 as (order by m), w2 as (partition by r order by m); +ERROR HY000: Window function is not allowed in window specification +select +pk, c, +row_number() over (partition by c order by pk +range between unbounded preceding and current row) as r +from t1; +ERROR HY000: Window frame is not allowed with 'row_number' +select +pk, c, +rank() over w1 as r +from t1 +window w1 as (partition by c order by pk +rows between 2 preceding and 2 following); +ERROR HY000: Window frame is not allowed with 'rank' +select +pk, c, +dense_rank() over (partition by c order by pk +rows between 1 preceding and 1 following) as r +from t1; +ERROR HY000: Window frame is not allowed with 'dense_rank' +select +pk, c, +rank() over w1 as r +from t1 +window w1 as (partition by c); +ERROR HY000: No order list in window specification for 'rank' +select +pk, c, +dense_rank() over (partition by c) as r +from t1; +ERROR HY000: No order list in window specification for 'dense_rank' +drop table t0,t1; +# +# MDEV-9634: Window function produces incorrect value +# +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (part_id int, pk int, a int); +insert into t2 select +if(a<5, 0, 1), a, if(a<5, NULL, 1) from t0; +select * from t2; +part_id pk a +0 0 NULL +0 1 NULL +0 2 NULL +0 3 NULL +0 4 NULL +1 5 1 +1 6 1 +1 7 1 +1 8 1 +1 9 1 +select +part_id, pk, a, +count(a) over (partition by part_id order by pk +rows between 1 preceding and 1 following) as CNT +from t2; +part_id pk a CNT +0 0 NULL 0 +0 1 NULL 0 +0 2 NULL 0 +0 3 NULL 0 +0 4 NULL 0 +1 5 1 2 +1 6 1 3 +1 7 1 3 +1 8 1 3 +1 9 1 2 +drop table t0, t2; +# +# RANGE-type bounds +# +create table t3 ( +pk int, +val int +); +insert into t3 values +(0, 1), +(1, 1), +(2, 1), +(3, 2), +(4, 2), +(5, 2), +(6, 2); +select +val, +count(val) over (order by val +range between current row and +current row) +as CNT +from t3; +val CNT +1 3 +1 3 +1 3 +2 4 +2 4 +2 4 +2 4 +insert into t3 values +(7, 3), +(8, 3); +select +val, +count(val) over (order by val +range between current row and +current row) +as CNT +from t3; +val CNT +1 3 +1 3 +1 3 +2 4 +2 4 +2 4 +2 4 +3 2 +3 2 +drop table t3; +# Now, check with PARTITION BY +create table t4 ( +part_id int, +pk int, +val int +); +insert into t4 values +(1234, 100, 1), +(1234, 101, 1), +(1234, 102, 1), +(1234, 103, 2), +(1234, 104, 2), +(1234, 105, 2), +(1234, 106, 2), +(1234, 107, 3), +(1234, 108, 3), +(5678, 200, 1), +(5678, 201, 1), +(5678, 202, 1), +(5678, 203, 2), +(5678, 204, 2), +(5678, 205, 2), +(5678, 206, 2), +(5678, 207, 3), +(5678, 208, 3); +select +part_id, +val, +count(val) over (partition by part_id +order by val +range between current row and +current row) +as CNT +from t4; +part_id val CNT +1234 1 3 +1234 1 3 +1234 1 3 +1234 2 4 +1234 2 4 +1234 2 4 +1234 2 4 +1234 3 2 +1234 3 2 +5678 1 3 +5678 1 3 +5678 1 3 +5678 2 4 +5678 2 4 +5678 2 4 +5678 2 4 +5678 3 2 +5678 3 2 +# +# Try RANGE UNBOUNDED PRECEDING | FOLLOWING +# +select +part_id, +val, +count(val) over (partition by part_id +order by val +range between unbounded preceding and +current row) +as CNT +from t4; +part_id val CNT +1234 1 3 +1234 1 3 +1234 1 3 +1234 2 7 +1234 2 7 +1234 2 7 +1234 2 7 +1234 3 9 +1234 3 9 +5678 1 3 +5678 1 3 +5678 1 3 +5678 2 7 +5678 2 7 +5678 2 7 +5678 2 7 +5678 3 9 +5678 3 9 +select +part_id, +val, +count(val) over (partition by part_id +order by val +range between current row and +unbounded following) +as CNT +from t4; +part_id val CNT +1234 1 9 +1234 1 9 +1234 1 9 +1234 2 6 +1234 2 6 +1234 2 6 +1234 2 6 +1234 3 2 +1234 3 2 +5678 1 9 +5678 1 9 +5678 1 9 +5678 2 6 +5678 2 6 +5678 2 6 +5678 2 6 +5678 3 2 +5678 3 2 +select +part_id, +val, +count(val) over (partition by part_id +order by val +range between unbounded preceding and +unbounded following) +as CNT +from t4; +part_id val CNT +1234 1 9 +1234 1 9 +1234 1 9 +1234 2 9 +1234 2 9 +1234 2 9 +1234 2 9 +1234 3 9 +1234 3 9 +5678 1 9 +5678 1 9 +5678 1 9 +5678 2 9 +5678 2 9 +5678 2 9 +5678 2 9 +5678 3 9 +5678 3 9 +drop table t4; +# +# MDEV-9695: Wrong window frame when using RANGE BETWEEN N FOLLOWING AND PRECEDING +# +create table t1 (pk int, a int, b int); +insert into t1 values +( 1 , 0, 1), +( 2 , 0, 2), +( 3 , 1, 4), +( 4 , 1, 8), +( 5 , 2, 32), +( 6 , 2, 64), +( 7 , 2, 128), +( 8 , 2, 16); +select pk, a, b, +bit_or(b) over (partition by a order by pk ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) as bit_or +from t1; +pk a b bit_or +1 0 1 3 +2 0 2 3 +3 1 4 12 +4 1 8 12 +5 2 32 96 +6 2 64 224 +7 2 128 208 +8 2 16 144 +# Extra ROWS n PRECEDING tests +select pk, a, b, +bit_or(b) over (partition by a order by pk ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) as bit_or +from t1; +pk a b bit_or +1 0 1 0 +2 0 2 1 +3 1 4 0 +4 1 8 4 +5 2 32 0 +6 2 64 32 +7 2 128 64 +8 2 16 128 +drop table t1; +create table t2 ( +pk int, +a int, +b int +); +insert into t2 values +( 1, 0, 1), +( 2, 0, 2), +( 3, 0, 4), +( 4, 0, 8), +( 5, 1, 16), +( 6, 1, 32), +( 7, 1, 64), +( 8, 1, 128), +( 9, 2, 256), +(10, 2, 512), +(11, 2, 1024), +(12, 2, 2048); +select pk, a, b, +bit_or(b) over (partition by a order by pk ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) as bit_or +from t2; +pk a b bit_or +1 0 1 0 +2 0 2 1 +3 0 4 2 +4 0 8 4 +5 1 16 0 +6 1 32 16 +7 1 64 32 +8 1 128 64 +9 2 256 0 +10 2 512 256 +11 2 1024 512 +12 2 2048 1024 +select pk, a, b, +bit_or(b) over (partition by a order by pk ROWS BETWEEN 2 PRECEDING AND 2 PRECEDING) as bit_or +from t2; +pk a b bit_or +1 0 1 0 +2 0 2 0 +3 0 4 1 +4 0 8 2 +5 1 16 0 +6 1 32 0 +7 1 64 16 +8 1 128 32 +9 2 256 0 +10 2 512 0 +11 2 1024 256 +12 2 2048 512 +select pk, a, b, +bit_or(b) over (partition by a order by pk ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING) as bit_or +from t2; +pk a b bit_or +1 0 1 0 +2 0 2 1 +3 0 4 3 +4 0 8 6 +5 1 16 0 +6 1 32 16 +7 1 64 48 +8 1 128 96 +9 2 256 0 +10 2 512 256 +11 2 1024 768 +12 2 2048 1536 +# Check CURRENT ROW +select pk, a, b, +bit_or(b) over (partition by a order by pk ROWS BETWEEN CURRENT ROW AND CURRENT ROW) as bit_or +from t2; +pk a b bit_or +1 0 1 1 +2 0 2 2 +3 0 4 4 +4 0 8 8 +5 1 16 16 +6 1 32 32 +7 1 64 64 +8 1 128 128 +9 2 256 256 +10 2 512 512 +11 2 1024 1024 +12 2 2048 2048 +drop table t2; +# +# Try RANGE PRECEDING|FOLLWING n +# +create table t1 ( +part_id int, +pk int, +a int +); +insert into t1 values +(10, 1, 1), +(10, 2, 2), +(10, 3, 4), +(10, 4, 8), +(10, 5,26), +(10, 6,27), +(10, 7,40), +(10, 8,71), +(10, 9,72); +select +pk, a, +count(a) over (ORDER BY a +RANGE BETWEEN UNBOUNDED PRECEDING +AND 10 FOLLOWING) as cnt +from t1; +pk a cnt +1 1 4 +2 2 4 +3 4 4 +4 8 4 +5 26 6 +6 27 6 +7 40 7 +8 71 9 +9 72 9 +select +pk, a, +count(a) over (ORDER BY a DESC +RANGE BETWEEN UNBOUNDED PRECEDING +AND 10 FOLLOWING) as cnt +from t1; +pk a cnt +9 72 2 +8 71 2 +7 40 3 +6 27 5 +5 26 5 +4 8 9 +3 4 9 +2 2 9 +1 1 9 +select +pk, a, +count(a) over (ORDER BY a +RANGE BETWEEN UNBOUNDED PRECEDING +AND 1 FOLLOWING) as cnt +from t1; +pk a cnt +1 1 2 +2 2 2 +3 4 3 +4 8 4 +5 26 6 +6 27 6 +7 40 7 +8 71 9 +9 72 9 +select +pk, a, +count(a) over (ORDER BY a +RANGE BETWEEN UNBOUNDED PRECEDING +AND 10 PRECEDING) as cnt +from t1; +pk a cnt +1 1 0 +2 2 0 +3 4 0 +4 8 0 +5 26 4 +6 27 4 +7 40 6 +8 71 7 +9 72 7 +select +pk, a, +count(a) over (ORDER BY a DESC +RANGE BETWEEN UNBOUNDED PRECEDING +AND 10 PRECEDING) as cnt +from t1; +pk a cnt +9 72 0 +8 71 0 +7 40 2 +6 27 3 +5 26 3 +4 8 5 +3 4 5 +2 2 5 +1 1 5 +select +pk, a, +count(a) over (ORDER BY a +RANGE BETWEEN UNBOUNDED PRECEDING +AND 1 PRECEDING) as cnt +from t1; +pk a cnt +1 1 0 +2 2 1 +3 4 2 +4 8 3 +5 26 4 +6 27 5 +7 40 6 +8 71 7 +9 72 8 +select +pk, a, +count(a) over (ORDER BY a +RANGE BETWEEN 1 PRECEDING +AND CURRENT ROW) as cnt +from t1; +pk a cnt +1 1 1 +2 2 2 +3 4 1 +4 8 1 +5 26 1 +6 27 2 +7 40 1 +8 71 1 +9 72 2 +select +pk, a, +count(a) over (ORDER BY a DESC +RANGE BETWEEN 1 PRECEDING +AND CURRENT ROW) as cnt +from t1; +pk a cnt +9 72 1 +8 71 2 +7 40 1 +6 27 1 +5 26 2 +4 8 1 +3 4 1 +2 2 1 +1 1 2 +select +pk, a, +count(a) over (ORDER BY a +RANGE BETWEEN 1 FOLLOWING +AND 3 FOLLOWING) as cnt +from t1; +pk a cnt +1 1 2 +2 2 1 +3 4 0 +4 8 0 +5 26 1 +6 27 0 +7 40 0 +8 71 1 +9 72 0 +# Try CURRENT ROW with[out] DESC +select +pk, a, +count(a) over (ORDER BY a +RANGE BETWEEN CURRENT ROW +AND 1 FOLLOWING) as cnt +from t1; +pk a cnt +1 1 2 +2 2 1 +3 4 1 +4 8 1 +5 26 2 +6 27 1 +7 40 1 +8 71 2 +9 72 1 +select +pk, a, +count(a) over (order by a desc +range between current row +and 1 following) as cnt +from t1; +pk a cnt +9 72 2 +8 71 1 +7 40 1 +6 27 2 +5 26 1 +4 8 1 +3 4 1 +2 2 2 +1 1 1 +insert into t1 select 22, pk, a from t1; +select +part_id, pk, a, +count(a) over (PARTITION BY part_id +ORDER BY a +RANGE BETWEEN UNBOUNDED PRECEDING +AND 10 FOLLOWING) as cnt +from t1; +part_id pk a cnt +10 1 1 4 +10 2 2 4 +10 3 4 4 +10 4 8 4 +10 5 26 6 +10 6 27 6 +10 7 40 7 +10 8 71 9 +10 9 72 9 +22 1 1 4 +22 2 2 4 +22 3 4 4 +22 4 8 4 +22 5 26 6 +22 6 27 6 +22 7 40 7 +22 8 71 9 +22 9 72 9 +select +pk, a, +count(a) over (PARTITION BY part_id +ORDER BY a +RANGE BETWEEN UNBOUNDED PRECEDING +AND 1 PRECEDING) as cnt +from t1; +pk a cnt +1 1 0 +2 2 1 +3 4 2 +4 8 3 +5 26 4 +6 27 5 +7 40 6 +8 71 7 +9 72 8 +1 1 0 +2 2 1 +3 4 2 +4 8 3 +5 26 4 +6 27 5 +7 40 6 +8 71 7 +9 72 8 +drop table t1; +# Try a RANGE frame over non-integer datatype: +create table t1 ( +col1 int, +a decimal(5,3) +); +insert into t1 values (1, 0.45); +insert into t1 values (1, 0.5); +insert into t1 values (1, 0.55); +insert into t1 values (1, 1.21); +insert into t1 values (1, 1.22); +insert into t1 values (1, 3.33); +select +a, +count(col1) over (order by a +range between 0.1 preceding +and 0.1 following) +from t1; +a count(col1) over (order by a +range between 0.1 preceding +and 0.1 following) +0.450 3 +0.500 3 +0.550 3 +1.210 2 +1.220 2 +3.330 1 +drop table t1; +# +# RANGE-type frames and NULL values +# +create table t1 ( +pk int, +a int, +b int +); +insert into t1 values (1, NULL,1); +insert into t1 values (2, NULL,1); +insert into t1 values (3, NULL,1); +insert into t1 values (4, 10 ,1); +insert into t1 values (5, 11 ,1); +insert into t1 values (6, 12 ,1); +insert into t1 values (7, 13 ,1); +insert into t1 values (8, 14 ,1); +select +pk, a, +count(b) over (order by a +range between 2 preceding +and 2 following) as CNT +from t1 +order by a, pk; +pk a CNT +1 NULL 3 +2 NULL 3 +3 NULL 3 +4 10 3 +5 11 4 +6 12 5 +7 13 4 +8 14 3 +drop table t1; +# +# Try ranges that have bound1 > bound2. The standard actually allows them +# +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (pk int, c int); +insert into t1 select a+1,1 from t0; +update t1 set c=2 where pk not in (1,2,3,4); +select * from t1; +pk c +1 1 +2 1 +3 1 +4 1 +5 2 +6 2 +7 2 +8 2 +9 2 +10 2 +select +pk, c, +count(*) over (partition by c +order by pk +rows between 1 preceding +and 2 preceding) +as cnt +from t1; +pk c cnt +1 1 0 +2 1 0 +3 1 0 +4 1 0 +5 2 0 +6 2 0 +7 2 0 +8 2 0 +9 2 0 +10 2 0 +select +pk, c, +sum(c) over (partition by c +order by pk +rows between 1 preceding +and 2 preceding) +as sum +from t1; +pk c sum +1 1 NULL +2 1 NULL +3 1 NULL +4 1 NULL +5 2 NULL +6 2 NULL +7 2 NULL +8 2 NULL +9 2 NULL +10 2 NULL +select +pk, c, +sum(c) over (partition by c +order by pk +rows between 2 following +and 1 following) +as sum +from t1; +pk c sum +1 1 NULL +2 1 NULL +3 1 NULL +4 1 NULL +5 2 NULL +6 2 NULL +7 2 NULL +8 2 NULL +9 2 NULL +10 2 NULL +select +pk, c, +count(*) over (partition by c +order by pk +range between 1 preceding +and 2 preceding) +as cnt +from t1; +pk c cnt +1 1 0 +2 1 0 +3 1 0 +4 1 0 +5 2 0 +6 2 0 +7 2 0 +8 2 0 +9 2 0 +10 2 0 +drop table t0, t1; +# +# Error checking for frame bounds +# +create table t1 (a int, b int, c varchar(32)); +insert into t1 values (1,1,'foo'); +insert into t1 values (2,2,'bar'); +select +count(*) over (order by a,b +range between unbounded preceding and current row) +from t1; +ERROR HY000: RANGE-type frame requires ORDER BY clause with single sort key +select +count(*) over (order by c +range between unbounded preceding and current row) +from t1; +ERROR HY000: Numeric datatype is required for RANGE-type frame +select +count(*) over (order by a +range between 'abcd' preceding and current row) +from t1; +ERROR HY000: Numeric datatype is required for RANGE-type frame +select +count(*) over (order by a +range between current row and 'foo' following) +from t1; +ERROR HY000: Numeric datatype is required for RANGE-type frame +# Try range frame with invalid bounds +select +count(*) over (order by a +rows between 0.5 preceding and current row) +from t1; +ERROR HY000: Integer is required for ROWS-type frame +select +count(*) over (order by a +rows between current row and 3.14 following) +from t1; +ERROR HY000: Integer is required for ROWS-type frame +# +# EXCLUDE clause is parsed but not supported +# +select +count(*) over (order by a +rows between 1 preceding and 1 following +exclude current row) +from t1; +ERROR HY000: Frame exclusion is not supported yet +select +count(*) over (order by a +range between 1 preceding and 1 following +exclude ties) +from t1; +ERROR HY000: Frame exclusion is not supported yet +select +count(*) over (order by a +range between 1 preceding and 1 following +exclude group) +from t1; +ERROR HY000: Frame exclusion is not supported yet +select +count(*) over (order by a +rows between 1 preceding and 1 following +exclude no others) +from t1; +count(*) over (order by a +rows between 1 preceding and 1 following +exclude no others) +2 +2 +drop table t1; +# +# Window function in grouping query +# +create table t1 ( +username varchar(32), +amount int +); +insert into t1 values +('user1',1), +('user1',5), +('user1',3), +('user2',10), +('user2',20), +('user2',30); +select +username, +sum(amount) as s, +rank() over (order by s desc) +from t1 +group by username; +username s rank() over (order by s desc) +user1 9 2 +user2 60 1 +drop table t1; +# +# mdev-9719: Window function in prepared statement +# +create table t1(a int, b int, x char(32)); +insert into t1 values (2, 10, 'xx'); +insert into t1 values (2, 10, 'zz'); +insert into t1 values (2, 20, 'yy'); +insert into t1 values (3, 10, 'xxx'); +insert into t1 values (3, 20, 'vvv'); +prepare stmt from 'select a, row_number() over (partition by a order by b) from t1'; +execute stmt; +a row_number() over (partition by a order by b) +2 1 +2 2 +2 3 +3 1 +3 2 +drop table t1; +# +# mdev-9754: Window name resolution in prepared statement +# +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (pk int, c int); +insert into t1 select a+1,1 from t0; +update t1 set c=2 where pk not in (1,2,3,4); +select * from t1; +pk c +1 1 +2 1 +3 1 +4 1 +5 2 +6 2 +7 2 +8 2 +9 2 +10 2 +prepare stmt from +'select + pk, c, + count(*) over w1 as CNT +from t1 +window w1 as (partition by c order by pk + rows between 2 preceding and 2 following)'; +execute stmt; +pk c CNT +1 1 3 +2 1 4 +3 1 4 +4 1 3 +5 2 3 +6 2 4 +7 2 5 +8 2 5 +9 2 4 +10 2 3 +drop table t0,t1; +# +# EXPLAIN FORMAT=JSON support for window functions +# +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +explain format=json select rank() over (order by a) from t0; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "window_functions_computation": { + "sorts": { + "filesort": { + "sort_key": "t0.a" + } + }, + "temporary_table": { + "table": { + "table_name": "t0", + "access_type": "ALL", + "rows": 10, + "filtered": 100 + } + } + } + } +} +create table t1 (a int, b int, c int); +insert into t1 select a,a,a from t0; +explain format=json +select +a, +rank() over (order by sum(b)) +from t1 +group by a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a", + "window_functions_computation": { + "sorts": { + "filesort": { + "sort_key": "sum(t1.b)" + } + }, + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 10, + "filtered": 100 + } + } + } + } + } +} +explain format=json +select +a, +rank() over (order by sum(b)) +from t1 +group by a +order by null; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "window_functions_computation": { + "sorts": { + "filesort": { + "sort_key": "sum(t1.b)" + } + }, + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 10, + "filtered": 100 + } + } + } + } +} +# +# Check how window function works together with GROUP BY and HAVING +# +select b,max(a) as MX, rank() over (order by b) from t1 group by b having MX in (3,5,7); +b MX rank() over (order by b) +3 3 1 +5 5 2 +7 7 3 +explain format=json +select b,max(a) as MX, rank() over (order by b) from t1 group by b having MX in (3,5,7); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "MX in (3,5,7)", + "filesort": { + "sort_key": "t1.b", + "window_functions_computation": { + "sorts": { + "filesort": { + "sort_key": "t1.b" + } + }, + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 10, + "filtered": 100 + } + } + } + } + } +} +drop table t1; +drop table t0; +# +# Building ordering index for window functions +# +create table t1 ( +pk int primary key, +a int, +b int, +c int +); +insert into t1 values +(101 , 0, 10, 1), +(102 , 0, 10, 2), +(103 , 1, 10, 3), +(104 , 1, 10, 4), +(108 , 2, 10, 5), +(105 , 2, 20, 6), +(106 , 2, 20, 7), +(107 , 2, 20, 8), +(109 , 4, 20, 9), +(110 , 4, 20, 10), +(111 , 5, NULL, 11), +(112 , 5, 1, 12), +(113 , 5, NULL, 13), +(114 , 5, NULL, 14), +(115 , 5, NULL, 15), +(116 , 6, 1, NULL), +(117 , 6, 1, 10), +(118 , 6, 1, 1), +(119 , 6, 1, NULL), +(120 , 6, 1, NULL), +(121 , 6, 1, NULL), +(122 , 6, 1, 2), +(123 , 6, 1, 20), +(124 , 6, 1, -10), +(125 , 6, 1, NULL), +(126 , 6, 1, NULL), +(127 , 6, 1, NULL); +select sum(b) over (partition by a order by b,pk +rows between unbounded preceding and current row) as c1, +avg(b) over (w1 rows between 1 preceding and 1 following) as c2, +sum(c) over (w2 rows between 1 preceding and 1 following) as c5, +avg(b) over (w1 rows between 5 preceding and 5 following) as c3, +sum(b) over (w1 rows between 1 preceding and 1 following) as c4 +from t1 +window w1 as (partition by a order by b,pk), +w2 as (partition by b order by c,pk); +c1 c2 c5 c3 c4 +1 1.0000 42 1.0000 1 +1 1.0000 NULL 1.0000 2 +10 1.0000 NULL 1.0000 3 +10 10.0000 3 10.0000 20 +10 10.0000 9 10.0000 20 +10 15.0000 9 17.5000 30 +11 1.0000 NULL 1.0000 3 +12 1.0000 -10 1.0000 2 +2 1.0000 24 1.0000 3 +20 10.0000 12 10.0000 20 +20 10.0000 6 10.0000 20 +20 20.0000 27 20.0000 40 +3 1.0000 -7 1.0000 3 +30 16.6667 13 17.5000 50 +4 1.0000 NULL 1.0000 3 +40 20.0000 19 20.0000 40 +5 1.0000 NULL 1.0000 3 +50 20.0000 21 17.5000 60 +6 1.0000 NULL 1.0000 3 +7 1.0000 13 1.0000 3 +70 20.0000 24 17.5000 40 +8 1.0000 32 1.0000 3 +9 1.0000 -9 1.0000 3 +NULL 1.0000 29 1.0000 1 +NULL NULL 24 1.0000 NULL +NULL NULL 38 1.0000 NULL +NULL NULL 42 1.0000 NULL +drop table t1; +# +# MDEV-9848: Window functions: reuse sorting and/or scanning +# +create table t1 (a int, b int, c int); +insert into t1 values +(1,3,1), +(2,2,1), +(3,1,1); +# Check using counters +flush status; +select +rank() over (partition by c order by a), +rank() over (partition by c order by b) +from t1; +rank() over (partition by c order by a) rank() over (partition by c order by b) +1 3 +2 2 +3 1 +show status like '%sort%'; +Variable_name Value +Sort_merge_passes 0 +Sort_priority_queue_sorts 0 +Sort_range 0 +Sort_rows 6 +Sort_scan 2 +flush status; +select +rank() over (partition by c order by a), +rank() over (partition by c order by a) +from t1; +rank() over (partition by c order by a) rank() over (partition by c order by a) +1 1 +2 2 +3 3 +show status like '%sort%'; +Variable_name Value +Sort_merge_passes 0 +Sort_priority_queue_sorts 0 +Sort_range 0 +Sort_rows 3 +Sort_scan 1 +explain format=json +select +rank() over (partition by c order by a), +rank() over (partition by c order by a) +from t1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "window_functions_computation": { + "sorts": { + "filesort": { + "sort_key": "t1.c, t1.a" + } + }, + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 3, + "filtered": 100 + } + } + } + } +} +explain format=json +select +rank() over (order by a), +row_number() over (order by a) +from t1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "window_functions_computation": { + "sorts": { + "filesort": { + "sort_key": "t1.a" + } + }, + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 3, + "filtered": 100 + } + } + } + } +} +explain format=json +select +rank() over (partition by c order by a), +count(*) over (partition by c) +from t1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "window_functions_computation": { + "sorts": { + "filesort": { + "sort_key": "t1.c, t1.a" + } + }, + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 3, + "filtered": 100 + } + } + } + } +} +explain format=json +select +count(*) over (partition by c), +rank() over (partition by c order by a) +from t1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "window_functions_computation": { + "sorts": { + "filesort": { + "sort_key": "t1.c, t1.a" + } + }, + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 3, + "filtered": 100 + } + } + } + } +} +drop table t1; +# +# MDEV-9847: Window functions: crash with big_tables=1 +# +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +set @tmp=@@big_tables; +set big_tables=1; +select rank() over (order by a) from t1; +rank() over (order by a) +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +set big_tables=@tmp; +drop table t1; +# +# Check if "ORDER BY window_func" works +# +create table t1 (s1 int, s2 char(5)); +insert into t1 values (1,'a'); +insert into t1 values (null,null); +insert into t1 values (1,null); +insert into t1 values (null,'a'); +insert into t1 values (2,'b'); +insert into t1 values (-1,''); +explain format=json +select *, row_number() over (order by s1, s2) as X from t1 order by X desc; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "row_number() over ( order by t1.s1,t1.s2) desc", + "window_functions_computation": { + "sorts": { + "filesort": { + "sort_key": "t1.s1, t1.s2" + } + }, + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 6, + "filtered": 100 + } + } + } + } + } +} +select *, row_number() over (order by s1, s2) as X from t1 order by X desc; +s1 s2 X +2 b 6 +1 a 5 +1 NULL 4 +-1 3 +NULL a 2 +NULL NULL 1 +drop table t1; +# +# Try window functions that are not directly present in the select list +# +create table t1 (a int, b int); +insert into t1 values +(1,3), +(2,2), +(3,1); +select +a, b, +rank() over (order by a), rank() over (order by b), +rank() over (order by a) - rank() over (order by b) as diff +from +t1; +a b rank() over (order by a) rank() over (order by b) diff +1 3 1 3 -2 +2 2 2 2 0 +3 1 3 1 2 +drop table t1; +create table t1 (i int); +insert into t1 values (1),(2); +SELECT MAX(i) OVER (PARTITION BY (i)) FROM t1; +MAX(i) OVER (PARTITION BY (i)) +1 +2 +drop table t1; +# +# Check the 0 in ROWS 0 PRECEDING +# +create table t1 ( +part_id int, +pk int, +a int +); +insert into t1 values (1, 1, 1); +insert into t1 values (1, 2, 2); +insert into t1 values (1, 3, 4); +insert into t1 values (1, 4, 8); +select +pk, a, +sum(a) over (order by pk rows between 0 preceding and current row) +from t1; +pk a sum(a) over (order by pk rows between 0 preceding and current row) +1 1 1 +2 2 2 +3 4 4 +4 8 8 +select +pk, a, +sum(a) over (order by pk rows between 1 preceding and 0 preceding) +from t1; +pk a sum(a) over (order by pk rows between 1 preceding and 0 preceding) +1 1 1 +2 2 3 +3 4 6 +4 8 12 +insert into t1 values (200, 1, 1); +insert into t1 values (200, 2, 2); +insert into t1 values (200, 3, 4); +insert into t1 values (200, 4, 8); +select +part_id, pk, a, +sum(a) over (partition by part_id order by pk rows between 0 preceding and current row) +from t1; +part_id pk a sum(a) over (partition by part_id order by pk rows between 0 preceding and current row) +1 1 1 1 +1 2 2 2 +1 3 4 4 +1 4 8 8 +200 1 1 1 +200 2 2 2 +200 3 4 4 +200 4 8 8 +select +part_id, pk, a, +sum(a) over (partition by part_id order by pk rows between 1 preceding and 0 preceding) +from t1; +part_id pk a sum(a) over (partition by part_id order by pk rows between 1 preceding and 0 preceding) +1 1 1 1 +1 2 2 3 +1 3 4 6 +1 4 8 12 +200 1 1 1 +200 2 2 3 +200 3 4 6 +200 4 8 12 +drop table t1; +# +# MDEV-9780, The "DISTINCT must not bet converted into GROUP BY when +# window functions are present" part +# +create table t1 (part_id int, a int); +insert into t1 values +(100, 1), +(100, 2), +(100, 2), +(100, 3), +(2000, 1), +(2000, 2), +(2000, 3), +(2000, 3), +(2000, 3); +select rank() over (partition by part_id order by a) from t1; +rank() over (partition by part_id order by a) +1 +2 +2 +4 +1 +2 +3 +3 +3 +select distinct rank() over (partition by part_id order by a) from t1; +rank() over (partition by part_id order by a) +1 +2 +4 +3 +explain format=json +select distinct rank() over (partition by part_id order by a) from t1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "duplicate_removal": { + "window_functions_computation": { + "sorts": { + "filesort": { + "sort_key": "t1.part_id, t1.a" + } + }, + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 9, + "filtered": 100 + } + } + } + } + } +} +drop table t1; +# +# MDEV-9893: Window functions with different ORDER BY lists, +# one of these lists containing an expression +# +create table t1 (s1 int, s2 char(5)); +insert into t1 values (1,'a'); +insert into t1 values (null,null); +insert into t1 values (3,null); +insert into t1 values (4,'a'); +insert into t1 values (2,'b'); +insert into t1 values (-1,''); +select +*, +ROW_NUMBER() OVER (order by s1), +CUME_DIST() OVER (order by -s1) +from t1; +s1 s2 ROW_NUMBER() OVER (order by s1) CUME_DIST() OVER (order by -s1) +-1 2 1.0000000000 +1 a 3 0.8333333333 +2 b 4 0.6666666667 +3 NULL 5 0.5000000000 +4 a 6 0.3333333333 +NULL NULL 1 0.1666666667 +drop table t1; +# +# MDEV-9925: Wrong result with aggregate function as a window function +# +create table t1 (i int); +insert into t1 values (1),(2); +select i, sum(i) over (partition by i) from t1; +i sum(i) over (partition by i) +1 1 +2 2 +drop table t1; +# +# MDEV-9922: Assertion `!join->only_const_tables() && fsort' failed in int create_sort_index +# +create view v1 as select 1 as i; +select rank() over (order by i) from v1; +rank() over (order by i) +1 +drop view v1; +# +# MDEV-10097: Assertion `count > 0' failed in Item_sum_sum::add_helper(bool) +# +CREATE TABLE `orders` ( +`o_orderkey` int(11) NOT NULL, +`o_custkey` int(11) DEFAULT NULL, +PRIMARY KEY (`o_orderkey`) +) DEFAULT CHARSET=latin1; +INSERT INTO `orders` VALUES (59908,242); +INSERT INTO `orders` VALUES (59940,238); +SELECT o_custkey, avg(o_custkey) OVER (PARTITION BY abs(o_custkey) +ORDER BY o_custkey +RANGE BETWEEN 15 FOLLOWING +AND 15 FOLLOWING) from orders; +o_custkey avg(o_custkey) OVER (PARTITION BY abs(o_custkey) +ORDER BY o_custkey +RANGE BETWEEN 15 FOLLOWING +AND 15 FOLLOWING) +238 NULL +242 NULL +DROP table orders; +# +# MDEV-10842: window functions with the same order column +# but different directions +# +create table t1 ( +pk int primary key, +a int, +b int, +c char(10) +); +insert into t1 values +( 1, 0, 1, 'one'), +( 2, 0, 2, 'two'), +( 3, 0, 3, 'three'), +( 4, 1, 1, 'one'), +( 5, 1, 1, 'two'), +( 6, 1, 2, 'three'), +( 7, 2, NULL, 'n_one'), +( 8, 2, 1, 'n_two'), +( 9, 2, 2, 'n_three'), +(10, 2, 0, 'n_four'), +(11, 2, 10, NULL); +select pk, +row_number() over (order by pk desc) as r_desc, +row_number() over (order by pk asc) as r_asc +from t1; +pk r_desc r_asc +11 1 11 +10 2 10 +9 3 9 +8 4 8 +7 5 7 +6 6 6 +5 7 5 +4 8 4 +3 9 3 +2 10 2 +1 11 1 +drop table t1; +# +# MDEV-10874: two window functions with compatible sorting +# +create table t1 ( +pk int primary key, +a int, +b int, +c char(10), +d decimal(10, 3), +e real +); +insert into t1 values +( 1, 0, 1, 'one', 0.1, 0.001), +( 2, 0, 2, 'two', 0.2, 0.002), +( 3, 0, 3, 'three', 0.3, 0.003), +( 4, 1, 2, 'three', 0.4, 0.004), +( 5, 1, 1, 'two', 0.5, 0.005), +( 6, 1, 1, 'one', 0.6, 0.006), +( 7, 2, NULL, 'n_one', 0.5, 0.007), +( 8, 2, 1, 'n_two', NULL, 0.008), +( 9, 2, 2, NULL, 0.7, 0.009), +(10, 2, 0, 'n_four', 0.8, 0.010), +(11, 2, 10, NULL, 0.9, NULL); +select pk, a, d, +sum(d) over (partition by a order by pk +ROWS between 1 preceding and current row) as sum_1, +sum(d) over (order by a +ROWS BETWEEN 1 preceding and 2 following) as sum_2 +from t1; +pk a d sum_1 sum_2 +1 0 0.100 0.100 0.600 +2 0 0.200 0.300 1.000 +3 0 0.300 0.500 1.400 +4 1 0.400 0.400 1.800 +5 1 0.500 0.900 2.000 +6 1 0.600 1.100 1.600 +7 2 0.500 0.500 1.800 +8 2 NULL 0.500 2.000 +9 2 0.700 0.700 2.400 +10 2 0.800 1.500 2.400 +11 2 0.900 1.700 1.700 +explain format=json +select pk, a, d, +sum(d) over (partition by a order by pk +ROWS between 1 preceding and current row) as sum_1, +sum(d) over (order by a +ROWS BETWEEN 1 preceding and 2 following) as sum_2 +from t1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "window_functions_computation": { + "sorts": { + "filesort": { + "sort_key": "t1.a, t1.pk" + } + }, + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 11, + "filtered": 100 + } + } + } + } +} +select pk, a, d, +sum(d) over (partition by a order by pk desc +ROWS between 1 preceding and current row) as sum_1, +sum(d) over (order by a +ROWS BETWEEN 1 preceding and 2 following) as sum_2 +from t1; +pk a d sum_1 sum_2 +3 0 0.300 0.300 0.600 +2 0 0.200 0.500 1.200 +1 0 0.100 0.300 1.400 +6 1 0.600 0.600 1.600 +5 1 0.500 1.100 2.400 +4 1 0.400 0.900 2.600 +11 2 0.900 0.900 2.800 +10 2 0.800 1.700 2.400 +9 2 0.700 1.500 2.000 +8 2 NULL 0.700 1.200 +7 2 0.500 0.500 0.500 +drop table t1; +# +# MDEV-9941: two window functions with compatible partitions +# +create table t1 ( +a int, +b int, +c int +); +insert into t1 values +(10, 1, 1), +(10, 3, 10), +(10, 1, 10), +(10, 3, 100), +(10, 5, 1000), +(10, 1, 100); +explain format=json +select +a,b,c, +row_number() over (partition by a), +row_number() over (partition by a, b) +from t1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "window_functions_computation": { + "sorts": { + "filesort": { + "sort_key": "t1.a, t1.b" + } + }, + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 6, + "filtered": 100 + } + } + } + } +} +drop table t1; +# +# MDEV-10815: Window Function Expressions Wrong Results +# +create table t(a decimal(35,10), b int); +insert into t(a,b) values(1,1); +insert into t(a,b) values(2,1); +insert into t(a,b) values(0,1); +insert into t(a,b) values(1, 2); +insert into t(a,b) values(1.5,2); +insert into t(a,b) values(3, 2); +insert into t(a,b) values(4.5,2); +select a, b, +sum(t.a) over (partition by t.b order by a) as simple_sum, +sum(t.a) over (partition by t.b order by a) + 1 as sum_and_const, +sum(t.b) over (partition by t.b order by a) + sum(t.a) over (partition by t.b order by a) as sum_and_sum +from t +order by t.b, t.a; +a b simple_sum sum_and_const sum_and_sum +0.0000000000 1 0.0000000000 1.0000000000 1.0000000000 +1.0000000000 1 1.0000000000 2.0000000000 3.0000000000 +2.0000000000 1 3.0000000000 4.0000000000 6.0000000000 +1.0000000000 2 1.0000000000 2.0000000000 3.0000000000 +1.5000000000 2 2.5000000000 3.5000000000 6.5000000000 +3.0000000000 2 5.5000000000 6.5000000000 11.5000000000 +4.5000000000 2 10.0000000000 11.0000000000 18.0000000000 +drop table t; +# +# MDEV-10669: Crash in SELECT with window function used +# +create table t(a decimal(35,10), b int); +insert into t(a,b) values(1,1); +insert into t(a,b) values(2,1); +insert into t(a,b) values(0,1); +SELECT (CASE WHEN sum(t.a) over (partition by t.b)=0 THEN null ELSE null END) AS a FROM t; +a +NULL +NULL +NULL +SELECT ifnull(((t.a) / CASE WHEN sum(t.a) over(partition by t.b) =0 then null else null end) ,0) from t; +ifnull(((t.a) / CASE WHEN sum(t.a) over(partition by t.b) =0 then null else null end) ,0) +0.00000000000000 +0.00000000000000 +0.00000000000000 +SELECT sum(t.a) over (partition by t.b order by a), +sqrt(ifnull((sum(t.a) over (partition by t.b order by a)), 0)) +from t; +sum(t.a) over (partition by t.b order by a) sqrt(ifnull((sum(t.a) over (partition by t.b order by a)), 0)) +0.0000000000 0 +1.0000000000 1 +3.0000000000 1.7320508075688772 +drop table t; +# +# MDEV-10868: view definitions with window functions +# +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (pk int, c int); +insert into t1 select a+1,1 from t0; +update t1 set c=2 where pk not in (1,2,3,4); +select * from t1; +pk c +1 1 +2 1 +3 1 +4 1 +5 2 +6 2 +7 2 +8 2 +9 2 +10 2 +select pk, c, c/count(*) over (partition by c order by pk +rows between 1 preceding and 2 following) as CNT +from t1; +pk c CNT +1 1 0.3333 +2 1 0.2500 +3 1 0.3333 +4 1 0.5000 +5 2 0.6667 +6 2 0.5000 +7 2 0.5000 +8 2 0.5000 +9 2 0.6667 +10 2 1.0000 +create view v1 as select pk, c, c/count(*) over (partition by c order by pk +rows between 1 preceding and 2 following) as CNT +from t1; +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`pk` AS `pk`,`t1`.`c` AS `c`,`t1`.`c` / count(0) over ( partition by `t1`.`c` order by `t1`.`pk` rows between 1 preceding and 2 following ) AS `CNT` from `t1` latin1 latin1_swedish_ci +select * from v1; +pk c CNT +1 1 0.3333 +2 1 0.2500 +3 1 0.3333 +4 1 0.5000 +5 2 0.6667 +6 2 0.5000 +7 2 0.5000 +8 2 0.5000 +9 2 0.6667 +10 2 1.0000 +select pk, c, c/count(*) over w1 as CNT from t1 +window w1 as (partition by c order by pk rows between 1 preceding and 2 following); +pk c CNT +1 1 0.3333 +2 1 0.2500 +3 1 0.3333 +4 1 0.5000 +5 2 0.6667 +6 2 0.5000 +7 2 0.5000 +8 2 0.5000 +9 2 0.6667 +10 2 1.0000 +create view v2 as select pk, c, c/count(*) over w1 as CNT from t1 +window w1 as (partition by c order by pk rows between 1 preceding and 2 following); +show create view v2; +View Create View character_set_client collation_connection +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `t1`.`pk` AS `pk`,`t1`.`c` AS `c`,`t1`.`c` / count(0) over ( partition by `t1`.`c` order by `t1`.`pk` rows between 1 preceding and 2 following ) AS `CNT` from `t1` latin1 latin1_swedish_ci +select * from v2; +pk c CNT +1 1 0.3333 +2 1 0.2500 +3 1 0.3333 +4 1 0.5000 +5 2 0.6667 +6 2 0.5000 +7 2 0.5000 +8 2 0.5000 +9 2 0.6667 +10 2 1.0000 +select pk, c, c/count(*) over w1 as CNT from t1 +window w1 as (partition by c order by pk rows unbounded preceding); +pk c CNT +1 1 1.0000 +2 1 0.5000 +3 1 0.3333 +4 1 0.2500 +5 2 2.0000 +6 2 1.0000 +7 2 0.6667 +8 2 0.5000 +9 2 0.4000 +10 2 0.3333 +create view v3 as select pk, c, c/count(*) over w1 as CNT from t1 +window w1 as (partition by c order by pk rows unbounded preceding); +show create view v3; +View Create View character_set_client collation_connection +v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select `t1`.`pk` AS `pk`,`t1`.`c` AS `c`,`t1`.`c` / count(0) over ( partition by `t1`.`c` order by `t1`.`pk` rows between unbounded preceding and current row ) AS `CNT` from `t1` latin1 latin1_swedish_ci +select * from v3; +pk c CNT +1 1 1.0000 +2 1 0.5000 +3 1 0.3333 +4 1 0.2500 +5 2 2.0000 +6 2 1.0000 +7 2 0.6667 +8 2 0.5000 +9 2 0.4000 +10 2 0.3333 +select pk, c, c/count(*) over (partition by c order by pk +range between 3 preceding and current row) as CNT +from t1; +pk c CNT +1 1 1.0000 +2 1 0.5000 +3 1 0.3333 +4 1 0.2500 +5 2 2.0000 +6 2 1.0000 +7 2 0.6667 +8 2 0.5000 +9 2 0.5000 +10 2 0.5000 +create view v4 as select pk, c, c/count(*) over (partition by c order by pk +range between 3 preceding and current row) as CNT +from t1; +show create view v4; +View Create View character_set_client collation_connection +v4 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v4` AS select `t1`.`pk` AS `pk`,`t1`.`c` AS `c`,`t1`.`c` / count(0) over ( partition by `t1`.`c` order by `t1`.`pk` range between 3 preceding and current row ) AS `CNT` from `t1` latin1 latin1_swedish_ci +select * from v4; +pk c CNT +1 1 1.0000 +2 1 0.5000 +3 1 0.3333 +4 1 0.2500 +5 2 2.0000 +6 2 1.0000 +7 2 0.6667 +8 2 0.5000 +9 2 0.5000 +10 2 0.5000 +drop view v1,v2,v3,v4; +drop table t0,t1; +# +# MDEV-10875: window function in subquery +# +CREATE TABLE t1 (i INT); +INSERT INTO t1 VALUES (3),(1); +CREATE TABLE t2 (c VARCHAR(8)); +INSERT INTO t2 VALUES ('foo'),('bar'),('foo'); +SELECT COUNT(*) OVER (PARTITION BY c) FROM t2; +COUNT(*) OVER (PARTITION BY c) +1 +2 +2 +SELECT * FROM t1 WHERE i IN ( SELECT COUNT(*) OVER (PARTITION BY c) FROM t2 ); +i +1 +DROP TABLE t1, t2; +# +# MDEV-9976: window function without PARTITION BY and ORDER BY +# +CREATE TABLE t1 (id int, a int); +INSERT INTO t1 VALUES +(1,1000), (2,1100), (3,1800), (4,1500), (5,1700), (6,1200), +(7,2000), (8,2100), (9,1600); +SELECT id, sum(a) OVER (PARTITION BY id +ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) +FROM t1; +id sum(a) OVER (PARTITION BY id +1 1000 +2 1100 +3 1800 +4 1500 +5 1700 +6 1200 +7 2000 +8 2100 +9 1600 +ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) +SELECT id, sum(a) OVER (ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) +FROM t1; +id sum(a) OVER (ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) +1 14000 +2 13000 +3 5900 +4 10700 +5 7600 +6 11900 +7 4100 +8 2100 +9 9200 +DROP TABLE t1; +# +# MDEV-11867: window function with aggregation +# over the result of grouping +# +create table t1 ( +username varchar(32), +amount int +); +insert into t1 values +('user1',1), +('user1',5), +('user1',3), +('user2',10), +('user2',20), +('user2',30); +select username, sum(amount) as s, avg(sum(amount)) over (order by s desc) +from t1 +group by username; +username s avg(sum(amount)) over (order by s desc) +user1 9 34.5000 +user2 60 60.0000 +select username, sum(amount), avg(sum(amount)) over (order by sum(amount) desc) +from t1 +group by username; +username sum(amount) avg(sum(amount)) over (order by sum(amount) desc) +user1 9 34.5000 +user2 60 60.0000 +drop table t1; +# +# MDEV-11594: window function over implicit grouping +# +create table t1 (id int); +insert into t1 values (1), (2), (3), (2); +select sum(id) over (order by sum(id)) from t1; +sum(id) over (order by sum(id)) +1 +select sum(sum(id)) over (order by sum(id)) from t1; +sum(sum(id)) over (order by sum(id)) +8 +drop table t1; +# +# MDEV-9923: integer constant in order by list +# of window specification +# +create table t1 (id int); +insert into t1 values (1), (2), (3), (2); +select rank() over (order by 1) from t1; +rank() over (order by 1) +1 +1 +1 +1 +select rank() over (order by 2) from t1; +rank() over (order by 2) +1 +1 +1 +1 +select rank() over (partition by id order by 2) from t1; +rank() over (partition by id order by 2) +1 +1 +1 +1 +drop table t1; +# +# MDEV-10660: view using a simple window function +# +create table t1 (id int); +insert into t1 values (1), (2), (3), (2); +create view v1(id,rnk) as +select id, rank() over (order by id) from t1; +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`id` AS `id`,rank() over ( order by `t1`.`id`) AS `rnk` from `t1` latin1 latin1_swedish_ci +select id, rank() over (order by id) from t1; +id rank() over (order by id) +1 1 +2 2 +2 2 +3 4 +select * from v1; +id rnk +1 1 +2 2 +2 2 +3 4 +drop view v1; +drop table t1; +# +# MDEV-11138: window function in the query without tables +# +select row_number() over (); +row_number() over () +1 +select count(*) over (); +count(*) over () +1 +select sum(5) over (); +sum(5) over () +5 +select row_number() over (), sum(5) over (); +row_number() over () sum(5) over () +1 5 +select row_number() over (order by 2); +row_number() over (order by 2) +1 +select row_number() over (partition by 2); +row_number() over (partition by 2) +1 +select row_number() over (partition by 4 order by 1+2); +row_number() over (partition by 4 order by 1+2) +1 +# +# MDEV-11999: execution of prepared statement for +# tableless query with window functions +# +prepare stmt from +"select row_number() over (partition by 4 order by 1+2)"; +execute stmt; +row_number() over (partition by 4 order by 1+2) +1 +execute stmt; +row_number() over (partition by 4 order by 1+2) +1 +deallocate prepare stmt; +# +# MDEV-11745: window function with min/max +# +create table t1 (i int, b int); +insert into t1 values +(1,1),(2,1),(3,1),(4,4),(5,4),(6,4),(7,8),(8,8),(9,8),(10,8); +select b, min(i) over (partition by b) as f +from t1 as tt +order by i; +b f +1 1 +1 1 +1 1 +4 4 +4 4 +4 4 +8 7 +8 7 +8 7 +8 7 +select b, min(i) over (partition by b) as f +from (select * from t1) as tt +order by i; +b f +1 1 +1 1 +1 1 +4 4 +4 4 +4 4 +8 7 +8 7 +8 7 +8 7 +select b, min(i+10) over (partition by b) as f +from t1 as tt +order by i; +b f +1 11 +1 11 +1 11 +4 14 +4 14 +4 14 +8 17 +8 17 +8 17 +8 17 +select b, min(i) over (partition by b) as f +from (select i+10 as i, b from t1) as tt +order by i; +b f +1 11 +1 11 +1 11 +4 14 +4 14 +4 14 +8 17 +8 17 +8 17 +8 17 +select b, min(i+20) over (partition by b) as f +from (select i+10 as i, b from t1) as tt +order by i; +b f +1 31 +1 31 +1 31 +4 34 +4 34 +4 34 +8 37 +8 37 +8 37 +8 37 +select b, max(i) over (partition by b) as f +from t1 as tt +order by i; +b f +1 3 +1 3 +1 3 +4 6 +4 6 +4 6 +8 10 +8 10 +8 10 +8 10 +select b, max(i) over (partition by b) as f +from (select * from t1) as tt +order by i; +b f +1 3 +1 3 +1 3 +4 6 +4 6 +4 6 +8 10 +8 10 +8 10 +8 10 +select b, max(i+10) over (partition by b) as f +from t1 as tt +order by i; +b f +1 13 +1 13 +1 13 +4 16 +4 16 +4 16 +8 20 +8 20 +8 20 +8 20 +select b, max(i) over (partition by b) as f +from (select i+10 as i, b from t1) as tt +order by i; +b f +1 13 +1 13 +1 13 +4 16 +4 16 +4 16 +8 20 +8 20 +8 20 +8 20 +select b, max(i+20) over (partition by b) as f +from (select i+10 as i, b from t1) as tt +order by i; +b f +1 33 +1 33 +1 33 +4 36 +4 36 +4 36 +8 40 +8 40 +8 40 +8 40 +select max(i), max(i), sum(i), count(i) +from t1 as tt +group by b; +max(i) max(i) sum(i) count(i) +3 3 6 3 +6 6 15 3 +10 10 34 4 +select max(i), min(sum(i)) over (partition by count(i)) f +from t1 as tt +group by b; +max(i) f +3 6 +6 6 +10 34 +select max(i), min(sum(i)) over (partition by count(i)) f +from (select * from t1) as tt +group by b; +max(i) f +3 6 +6 6 +10 34 +select max(i+10), min(sum(i)+10) over (partition by count(i)) f +from t1 as tt +group by b; +max(i+10) f +13 16 +16 16 +20 44 +select max(i), max(i), sum(i), count(i) +from (select i+10 as i, b from t1) as tt +group by b; +max(i) max(i) sum(i) count(i) +13 13 36 3 +16 16 45 3 +20 20 74 4 +select max(i), min(sum(i)) over (partition by count(i)) f +from (select i+10 as i, b from t1) as tt +group by b; +max(i) f +13 36 +16 36 +20 74 +select max(i), min(i), min(max(i)-min(i)) over (partition by count(i)) f +from (select i+10 as i, b from t1) as tt +group by b; +max(i) min(i) f +13 11 2 +16 14 2 +20 17 3 +drop table t1; +# +# MDEV-12015: window function over select with WHERE +# that is always FALSE +# +CREATE TABLE t1 (i INT); +INSERT INTO t1 VALUES (3), (1), (2); +SELECT i, ROW_NUMBER() OVER () FROM t1 WHERE 1 = 2; +i ROW_NUMBER() OVER () +SELECT i, COUNT(*) OVER () FROM t1 WHERE 1 = 2; +i COUNT(*) OVER () +DROP TABLE t1; +# +# MDEV-12051: window function in query with implicit grouping +# on always empty set +# +create table t1 (a int, b varchar(8)); +insert into t1 values (1,'foo'),(2,'bar'); +select max(a), row_number() over () from t1 where a > 10; +max(a) row_number() over () +NULL 1 +select max(a), sum(max(a)) over () from t1 where a > 10; +max(a) sum(max(a)) over () +NULL NULL +select max(a), sum(max(a)) over (partition by max(a)) from t1 where a > 10; +max(a) sum(max(a)) over (partition by max(a)) +NULL NULL +select max(a), row_number() over () from t1 where 1 = 2; +max(a) row_number() over () +NULL 1 +select max(a), sum(max(a)) over () from t1 where 1 = 2; +max(a) sum(max(a)) over () +NULL NULL +select max(a), sum(max(a)) over (partition by max(a)) from t1 where 1 = 2; +max(a) sum(max(a)) over (partition by max(a)) +NULL NULL +select max(a), row_number() over () from t1 where 1 = 2 +having max(a) is not null; +max(a) row_number() over () +select max(a), sum(max(a)) over () from t1 where 1 = 2 +having max(a) is not null; +max(a) sum(max(a)) over () +drop table t1; +# +# MDEV-10885: window function in query with implicit grouping +# with constant condition evaluated to false +# +CREATE TABLE t1 (a INT, b VARCHAR(8)); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +CREATE TABLE t2 (c INT); +INSERT INTO t2 VALUES (3),(4); +CREATE TABLE t3 (d INT); +INSERT INTO t3 VALUES (5),(6); +SELECT MAX(a), ROW_NUMBER() OVER (PARTITION BY MAX(a)) FROM t1 +WHERE EXISTS ( SELECT * FROM t2 WHERE c IN ( SELECT MAX(d) FROM t3 ) ); +MAX(a) ROW_NUMBER() OVER (PARTITION BY MAX(a)) +NULL 1 +SELECT MAX(a), COUNT(MAX(a)) OVER (PARTITION BY MAX(a)) FROM t1 +WHERE EXISTS ( SELECT * FROM t2 WHERE c IN ( SELECT MAX(d) FROM t3 ) ); +MAX(a) COUNT(MAX(a)) OVER (PARTITION BY MAX(a)) +NULL 0 +SELECT MAX(a), SUM(MAX(a)) OVER (PARTITION BY MAX(a)) FROM t1 +WHERE EXISTS ( SELECT * FROM t2 WHERE c IN ( SELECT MAX(d) FROM t3 ) ); +MAX(a) SUM(MAX(a)) OVER (PARTITION BY MAX(a)) +NULL NULL +SELECT MAX(a), ROW_NUMBER() OVER (PARTITION BY MAX(a)) FROM t1 +WHERE EXISTS ( SELECT * FROM t2 WHERE c IN ( SELECT MAX(d) FROM t3 ) ) +HAVING MAX(a) IS NOT NULL; +MAX(a) ROW_NUMBER() OVER (PARTITION BY MAX(a)) +SELECT a, MAX(a), ROW_NUMBER() OVER (PARTITION BY b) FROM t1 +WHERE EXISTS ( SELECT * FROM t2 WHERE c IN ( SELECT MAX(d) FROM t3 ) ); +a MAX(a) ROW_NUMBER() OVER (PARTITION BY b) +NULL NULL 1 +SELECT a, COUNT(a), AVG(a) OVER (PARTITION BY b) FROM t1 +WHERE EXISTS ( SELECT * FROM t2 WHERE c IN ( SELECT MAX(d) FROM t3 ) ); +a COUNT(a) AVG(a) OVER (PARTITION BY b) +NULL 0 NULL +SELECT a, MAX(a), AVG(a) OVER (PARTITION BY b) FROM t1 +WHERE EXISTS ( SELECT * FROM t2 WHERE c IN ( SELECT MAX(d) FROM t3 ) ); +a MAX(a) AVG(a) OVER (PARTITION BY b) +NULL NULL NULL +DROP TABLE t1,t2,t3; +# +# MDEV-10859: Wrong result of aggregate window function in query +# with HAVING and no ORDER BY +# +create table empsalary (depname varchar(32), empno smallint primary key, salary int); +insert into empsalary values +('develop', 1, 5000), ('develop', 2, 4000),('sales', 3, '6000'),('sales', 4, 5000); +SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary; +depname empno salary avg(salary) OVER (PARTITION BY depname) +develop 1 5000 4500.0000 +develop 2 4000 4500.0000 +sales 3 6000 5500.0000 +sales 4 5000 5500.0000 +SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary ORDER BY depname; +depname empno salary avg(salary) OVER (PARTITION BY depname) +develop 1 5000 4500.0000 +develop 2 4000 4500.0000 +sales 3 6000 5500.0000 +sales 4 5000 5500.0000 +# +# These last 2 should have the same row results, ignoring order. +# +SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary HAVING empno > 1; +depname empno salary avg(salary) OVER (PARTITION BY depname) +develop 2 4000 4000.0000 +sales 3 6000 5500.0000 +sales 4 5000 5500.0000 +SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary HAVING empno > 1 ORDER BY depname; +depname empno salary avg(salary) OVER (PARTITION BY depname) +develop 2 4000 4000.0000 +sales 3 6000 5500.0000 +sales 4 5000 5500.0000 +drop table empsalary; +# +# MDEV-11868: min(distinct) over () returns wrong value +# +create table TDEC (CDEC int, RNUM int); +create view VDEC as select * from TDEC; +insert into TDEC (CDEC) values (null),(-1),(0),(1),(0),(10); +select TDEC.CDEC, min(TDEC.CDEC) over () from TDEC; +CDEC min(TDEC.CDEC) over () +NULL -1 +-1 -1 +0 -1 +0 -1 +1 -1 +10 -1 +select VDEC.CDEC, min(VDEC.CDEC) over () from VDEC; +CDEC min(VDEC.CDEC) over () +NULL -1 +-1 -1 +0 -1 +0 -1 +1 -1 +10 -1 +select TDEC.CDEC, max(TDEC.CDEC) over () from TDEC; +CDEC max(TDEC.CDEC) over () +NULL 10 +-1 10 +0 10 +0 10 +1 10 +10 10 +select VDEC.CDEC, max(VDEC.CDEC) over () from VDEC; +CDEC max(VDEC.CDEC) over () +NULL 10 +-1 10 +0 10 +0 10 +1 10 +10 10 +select TDEC.CDEC, min(distinct TDEC.CDEC) over () from TDEC; +CDEC min(distinct TDEC.CDEC) over () +NULL -1 +-1 -1 +0 -1 +0 -1 +1 -1 +10 -1 +select VDEC.CDEC, min(distinct VDEC.CDEC) over () from VDEC; +CDEC min(distinct VDEC.CDEC) over () +NULL -1 +-1 -1 +0 -1 +0 -1 +1 -1 +10 -1 +select TDEC.CDEC, max(distinct TDEC.CDEC) over () from TDEC; +CDEC max(distinct TDEC.CDEC) over () +NULL 10 +-1 10 +0 10 +0 10 +1 10 +10 10 +select VDEC.CDEC, max(distinct VDEC.CDEC) over () from VDEC; +CDEC max(distinct VDEC.CDEC) over () +NULL 10 +-1 10 +0 10 +0 10 +1 10 +10 10 +# +# These should be removed once support for them is added. +# +select TDEC.CDEC, count(distinct TDEC.CDEC) over () from TDEC; +ERROR 42000: This version of MariaDB doesn't yet support 'COUNT(DISTINCT) aggregate as window function' +select VDEC.CDEC, count(distinct VDEC.CDEC) over () from VDEC; +ERROR 42000: This version of MariaDB doesn't yet support 'COUNT(DISTINCT) aggregate as window function' +select TDEC.CDEC, sum(distinct TDEC.CDEC) over () from TDEC; +ERROR 42000: This version of MariaDB doesn't yet support 'SUM(DISTINCT) aggregate as window function' +select VDEC.CDEC, sum(distinct VDEC.CDEC) over () from VDEC; +ERROR 42000: This version of MariaDB doesn't yet support 'SUM(DISTINCT) aggregate as window function' +select TDEC.CDEC, avg(distinct TDEC.CDEC) over () from TDEC; +ERROR 42000: This version of MariaDB doesn't yet support 'AVG(DISTINCT) aggregate as window function' +select VDEC.CDEC, avg(distinct VDEC.CDEC) over () from VDEC; +ERROR 42000: This version of MariaDB doesn't yet support 'AVG(DISTINCT) aggregate as window function' +select TDEC.CDEC, GROUP_CONCAT(TDEC.CDEC) over () from TDEC; +ERROR 42000: This version of MariaDB doesn't yet support 'GROUP_CONCAT() aggregate as window function' +select VDEC.CDEC, GROUP_CONCAT(distinct VDEC.CDEC) over () from VDEC; +ERROR 42000: This version of MariaDB doesn't yet support 'GROUP_CONCAT() aggregate as window function' +drop table TDEC; +drop view VDEC; +# +# MDEV-10700: 10.2.2 windowing function returns incorrect result +# +create table t(a int,b int, c int , d int); +insert into t(a,b,c,d) values(1, rand(10)*1000, rand(10)*1000, rand(10)*1000); +insert into t(a,b,c,d) values(1, rand(10)*1000, rand(10)*1000, rand(10)*1000); +replace into t(a,b,c,d) select 1, rand(10)*1000, rand(10)*1000, rand(10)*1000 from t t1, t t2, t t3, t t4, t t5, t t6, t t7, t t8, t t9, t t10, t t11, t t12, t t13, t t14, t t15, t t16, t t17; +select count(distinct s) from (select sum(d) over(partition by a,b,c) as s from t) Z where s > 0; +count(distinct s) +993 +select count(distinct s) from (select sum(d) as s from t group by a,b,c) Z where s > 0; +count(distinct s) +993 +select count(distinct s) from (select sum(d) over(partition by a,b) as s from t) Z where s > 0; +count(distinct s) +993 +select count(distinct s) from (select sum(d) as s from t group by a,b) Z where s > 0; +count(distinct s) +993 +select count(distinct s) from (select sum(d) over(partition by a) as s from t) Z where s > 0; +count(distinct s) +1 +select count(distinct s) from (select sum(d) as s from t group by a) Z where s > 0; +count(distinct s) +1 +drop table t; +# +# MDEV-9924: window function in query with group by optimized away +# +create table t1 (i int); +insert into t1 values (2),(3),(1); +select row_number() over () from t1 group by 1+2; +row_number() over () +1 +select max(i), row_number() over () from t1 group by 1+2; +max(i) row_number() over () +3 1 +select rank() over (order by max(i)) from t1 group by 1+2; +rank() over (order by max(i)) +1 +select i, row_number() over () from t1 group by 1+2; +i row_number() over () +2 1 +select i, rank() over (order by i) rnk from t1 group by 1+2; +i rnk +2 1 +drop table t1; +# +# MDEV-11907: window function as the second operand of division +# +create table t1 (pk int, c int); +insert into t1 values (1,1),(2,1),(3,1),(4,1),(5,2); +set @sql_mode_save= @@sql_mode; +set sql_mode='ERROR_FOR_DIVISION_BY_ZERO'; +select pk, c, c/count(*) over +(partition by c order by pk +rows between 1 preceding and 2 following) as CNT +from t1; +pk c CNT +1 1 0.3333 +2 1 0.2500 +3 1 0.3333 +4 1 0.5000 +5 2 2.0000 +show warnings; +Level Code Message +set sql_mode=@sql_mode_save; +drop table t1; +# +# MDEV-12336: several functions over a window function +# +create table t1 (name varchar(10), cnt int); +insert into t1 values ('Fred', 23), ('Fred', 35), ('Joe', 10); +select q.name, q.row_cnt, +round( 100 * ( q.row_cnt / +sum(q.row_cnt) over +( +order by q.name +rows between +unbounded preceding and +unbounded following +) +),2 +) pct_of_total +from +( +select name, count(*) row_cnt, sum(cnt) sum_cnt +from t1 +group by 1 +) q; +name row_cnt pct_of_total +Fred 2 66.67 +Joe 1 33.33 +drop table t1; +# +# MDEV-11990: window function over min/max aggregation +# +create table t1 (id int); +insert into t1 values (1), (2), (3), (2), (4), (2); +select sum(max(id)) over (order by max(id)) from t1; +sum(max(id)) over (order by max(id)) +4 +explain +select sum(max(id)) over (order by max(id)) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using temporary +create index idx on t1(id); +select sum(max(id)) over (order by max(id)) from t1; +sum(max(id)) over (order by max(id)) +4 +explain +select sum(max(id)) over (order by max(id)) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used +select sum(max(id)) over (order by max(id)) from t1 where id < 3; +sum(max(id)) over (order by max(id)) +2 +select count(max(id)) over (order by max(id)) from t1 where id < 3; +count(max(id)) over (order by max(id)) +1 +select max(id), rank() over (order by max(id)) from t1 where id < 3; +max(id) rank() over (order by max(id)) +2 1 +drop table t1; +# +# main.win failure post MDEV-12336 +# +create table t(a decimal(35,10), b int); +insert into t values (1, 10), (2, 20), (3, 30); +prepare stmt from "SELECT (CASE WHEN sum(t.a) over (partition by t.b)=1 THEN 1000 ELSE 300 END) AS a FROM t"; +execute stmt; +a +1000 +300 +300 +drop table t; +# +# MDEV-12851 case with window functions query crashes server +# +create table t1(dt datetime); +insert into t1 values ('2017-05-17'), ('2017-05-18'); +select dt, +case when (max(dt) over (order by dt rows between 1 following and 1 following) is null) +then '9999-12-31 12:00:00' + else max(dt) over (order by dt rows between 1 following and 1 following) +end x, +case when (max(dt) over (order by dt rows between 1 following and 1 following) is not null) +then '9999-12-31 12:00:00' + else max(dt) over (order by dt rows between 1 following and 1 following) +end x +from t1; +dt x x +2017-05-17 00:00:00 2017-05-18 00:00:00 9999-12-31 12:00:00 +2017-05-18 00:00:00 9999-12-31 12:00:00 NULL +drop table t1; +create table t1(i int); +insert into t1 values (null),(1),(2); +select max(i) over (order by i), +max(i) over (order by i) is null, +max(i) over (order by i) is not null +from t1; +max(i) over (order by i) max(i) over (order by i) is null max(i) over (order by i) is not null +NULL 1 0 +1 0 1 +2 0 1 +drop table t1; +# +# MDEV-13189: Window functions crash when using INTERVAL function +# +create table t1(i int); +insert into t1 values (1),(2),(10),(20),(30); +select sum(i) over (order by i), interval(sum(i) over (order by i), 10, 20) +from t1; +sum(i) over (order by i) interval(sum(i) over (order by i), 10, 20) +1 0 +3 0 +13 1 +33 2 +63 2 +drop table t1; +# +# MDEV-13352: Server crashes in st_join_table::remove_duplicates +# +CREATE TABLE t1 (i INT); +INSERT INTO t1 VALUES (1),(2); +SELECT DISTINCT ROW_NUMBER() OVER(), i FROM t1 WHERE 0; +ROW_NUMBER() OVER() i +SELECT ROW_NUMBER() OVER(), i FROM t1 WHERE 0; +ROW_NUMBER() OVER() i +DROP TABLE t1; +# +# MDEV-13344: Server crashes in in AGGR_OP::put_record on subquery +# with window function and constant table +# (Testcase only) +# +CREATE TABLE t1 (c CHAR(8)) ENGINE=MyISAM; +INSERT IGNORE INTO t1 VALUES ('foo'); +SELECT ('bar',1) IN ( SELECT c, ROW_NUMBER() OVER (PARTITION BY c) FROM t1); +('bar',1) IN ( SELECT c, ROW_NUMBER() OVER (PARTITION BY c) FROM t1) +0 +DROP TABLE t1; +# +# MDEV-13351: Server crashes in st_select_lex::set_explain_type upon UNION with window function +# +CREATE TABLE t1 (i INT); +INSERT INTO t1 VALUES (1),(2); +SELECT Nth_value(i,1) OVER() FROM t1 +UNION ALL +( SELECT Nth_value(i,2) OVER() FROM t1 LIMIT 0 ) +; +Nth_value(i,1) OVER() +1 +1 +DROP TABLE t1; +# +# A regression after MDEV-13351: +# MDEV-13374 : Server crashes in first_linear_tab / st_select_lex::set_explain_type +# upon UNION with aggregate function +# +CREATE TABLE t1 (i INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1),(2); +SELECT i AS fld FROM t1 UNION SELECT COUNT(*) AS fld FROM t1; +fld +1 +2 +DROP TABLE t1; +# +# MDEV-13240 Wrong warning with MAX(datetime_field) OVER (...) +# +CREATE TABLE t1 (dt DATETIME); +INSERT INTO t1 VALUES ('2017-05-17'); +SELECT MAX(dt) OVER (ORDER BY dt ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING) FROM t1; +MAX(dt) OVER (ORDER BY dt ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING) +NULL +DROP TABLE t1; +# +# MDEV-13358 FIRST_VALUE throws SQL Error (1292): Incorrect datetime value +# +CREATE TABLE IF NOT EXISTS `fv_test` ( +`SOME_DATE` datetime NOT NULL +); +INSERT INTO `fv_test` (`SOME_DATE`) VALUES ('2017-07-20 12:47:56'); +CREATE TABLE fv_result +SELECT +FIRST_VALUE(SOME_DATE) OVER(ORDER BY SOME_DATE DESC) AS somedate +FROM fv_test; +SHOW CREATE TABLE fv_result; +Table Create Table +fv_result CREATE TABLE `fv_result` ( + `somedate` datetime DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM fv_result; +somedate +2017-07-20 12:47:56 +DROP TABLE fv_test, fv_result; +# +# MDEV-13649: Server crashes in set_field_to_null_with_conversions or in Field::set_notnull +# +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (0),(1),(2); +SELECT LEAD(a) OVER (PARTITION BY a ORDER BY a) as lead, +a AND LEAD(a) OVER (PARTITION BY a ORDER BY a) AS a_and_lead_part +FROM t1; +lead a_and_lead_part +NULL 0 +NULL NULL +NULL NULL +SELECT a OR LEAD(a) OVER (ORDER BY a) AS a_or_lead_order +FROM t1 +ORDER BY a; +a_or_lead_order +1 +1 +1 +SELECT a AND LEAD(a) OVER (ORDER BY a) AS a_and_lead_order +FROM t1 +ORDER BY a; +a_and_lead_order +0 +1 +NULL +SELECT a XOR LEAD(a) OVER (ORDER BY a) AS a_xor_lead_order +FROM t1 +ORDER BY a; +a_xor_lead_order +1 +0 +NULL +SELECT NOT LEAD(a) OVER (ORDER BY a) AS not_lead_order +FROM t1 +ORDER BY a; +not_lead_order +0 +0 +NULL +SELECT LEAD(a) OVER (ORDER BY a) is not null AS is_not_null_lead_order +FROM t1 +ORDER BY a; +is_not_null_lead_order +1 +1 +0 +drop table t1; +# +# MDEV-13354: Server crashes in find_field_in_tables upon PS with window function and subquery +# +CREATE TABLE t1 (i INT, a char); +INSERT INTO t1 VALUES (1, 'a'),(2, 'b'); +PREPARE stmt FROM "SELECT row_number() over (partition by i order by i), i FROM (SELECT * from t1) as sq"; +EXECUTE stmt; +row_number() over (partition by i order by i) i +1 1 +1 2 +DROP TABLE t1; +# +# MDEV-13384: "window" seems like a reserved column name but it's not listed as one +# +# Currently we allow window as an identifier, except for table aliases. +# +CREATE TABLE door (id INT, window VARCHAR(10)); +SELECT id +FROM door as window; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'window' at line 2 +SELECT id, window +FROM door; +id window +SELECT id, window +FROM door as window; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'window' at line 2 +DROP TABLE door; +# +# MDEV-13352: Server crashes in st_join_table::remove_duplicates +# +CREATE TABLE t1 (i INT); +INSERT INTO t1 VALUES (1),(2); +SELECT DISTINCT ROW_NUMBER() OVER(), i FROM t1 WHERE 0; +ROW_NUMBER() OVER() i +SELECT ROW_NUMBER() OVER(), i FROM t1 WHERE 0; +ROW_NUMBER() OVER() i +DROP TABLE t1; +# +# MDEV-15853: Assertion `tab->filesort_result == 0' failed +# +CREATE TABLE t1 ( a1 int); +insert into t1 values (1),(2),(3); +CREATE TABLE t2 (b1 int, a1 int, a2 int); +insert into t2 values (1,2,3),(2,3,4),(3,4,5); +SELECT COUNT(DISTINCT t2.a2), +rank() OVER (ORDER BY t2.b1) +FROM t2 ,t1 GROUP BY t2.b1 ORDER BY t1.a1; +COUNT(DISTINCT t2.a2) rank() OVER (ORDER BY t2.b1) +1 1 +1 2 +1 3 +DROP TABLE t1,t2; +# +# MDEV-16990: server crashes in base_list_iterator::next +# +CREATE TABLE t1(i int); +insert into t1 values (1),(2); +SELECT DISTINCT row_number() OVER (), MAX(1) FROM t1; +row_number() OVER () MAX(1) +1 1 +SELECT DISTINCT BIT_AND(0) OVER (), MAX(1) FROM t1; +BIT_AND(0) OVER () MAX(1) +0 1 +drop table t1; +# +# MDEV-17525: Window functions not working in ONLY_FULL_GROUP_BY mode +# +CREATE TABLE t1 (name CHAR(10), test CHAR(10), score TINYINT); +INSERT INTO t1 VALUES +('Chun', 'SQL', 75), ('Chun', 'Tuning', 73), +('Esben', 'SQL', 43), ('Esben', 'Tuning', 31), +('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88), +('Tatiana', 'SQL', 87), ('Tatiana', 'Tuning', 83); +SET @save_sql_mode= @@sql_mode; +SET sql_mode = 'ONLY_FULL_GROUP_BY'; +SELECT name, test, score, +AVG(score) OVER (PARTITION BY test) AS average_by_test +FROM t1 +ORDER BY test, name; +name test score average_by_test +Chun SQL 75 65.2500 +Esben SQL 43 65.2500 +Kaolin SQL 56 65.2500 +Tatiana SQL 87 65.2500 +Chun Tuning 73 68.7500 +Esben Tuning 31 68.7500 +Kaolin Tuning 88 68.7500 +Tatiana Tuning 83 68.7500 +set @@sql_mode= @save_sql_mode; +SELECT name, test, score, +AVG(score) OVER (PARTITION BY test) AS average_by_test +FROM t1 +ORDER BY test, name; +name test score average_by_test +Chun SQL 75 65.2500 +Esben SQL 43 65.2500 +Kaolin SQL 56 65.2500 +Tatiana SQL 87 65.2500 +Chun Tuning 73 68.7500 +Esben Tuning 31 68.7500 +Kaolin Tuning 88 68.7500 +Tatiana Tuning 83 68.7500 +drop table t1; +# +# MDEV-12575: Server crash in AGGR_OP::put_record or in JOIN_CACHE::free +# or Invalid write in JOIN::make_aggr_tables_info +# +SELECT DISTINCT BIT_OR(100) OVER () FROM dual +GROUP BY LEFT('2018-08-24', 100) order by 1+2; +BIT_OR(100) OVER () +100 +CREATE TABLE t1 (i INT); +INSERT INTO t1 VALUES (1),(2); +SELECT * FROM ( +SELECT +ROW_NUMBER() OVER(), i, sum(i) +FROM t1 +WHERE 1=0 +limit 0 +) AS sq; +ROW_NUMBER() OVER() i sum(i) +SELECT * FROM ( +SELECT +ROW_NUMBER() OVER(), i, sum(i) +FROM t1 +WHERE 1=0 +GROUP BY i +) AS sq; +ROW_NUMBER() OVER() i sum(i) +drop table t1; +create table t1 (a int); +explain +select distinct 1, row_number() over (order by 1) from t1 where a=0 group by a with rollup; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +select distinct 1, row_number() over (order by 1) from t1 where a=0 group by a with rollup; +1 row_number() over (order by 1) +drop table t1; +explain +SELECT DISTINCT BIT_OR(100) OVER () FROM dual +GROUP BY LEFT('2018-08-24', 100) WITH ROLLUP +HAVING @A := 'qwerty'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible HAVING +SELECT DISTINCT BIT_OR(100) OVER () FROM dual +GROUP BY LEFT('2018-08-24', 100) WITH ROLLUP +HAVING @A := 'qwerty'; +BIT_OR(100) OVER () +explain +SELECT DISTINCT BIT_OR(100) OVER () FROM dual +GROUP BY LEFT('2018-08-24', 100) +HAVING @A := 'qwerty'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible HAVING +SELECT DISTINCT BIT_OR(100) OVER () FROM dual +GROUP BY LEFT('2018-08-24', 100) +HAVING @A := 'qwerty'; +BIT_OR(100) OVER () +create table t1 (a int); +explain +SELECT DISTINCT BIT_OR(100) OVER () FROM t1 +GROUP BY LEFT('2018-08-24', 100) having 1=1 limit 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Zero limit +drop table t1; +# +# MDEV-13170: Database service (MySQL) stops after update with trigger +# +CREATE TABLE t1 ( t1_id int, point_id int, ml_id int, UNIQUE KEY t1_ml_u (ml_id,point_id)) ; +INSERT INTO t1 VALUES (1,1,8884),(2,1,8885); +CREATE TABLE t2 ( db_time datetime, au_nr int, col_id int, new_val int); +CREATE TABLE t3 (id1 int, id2 int, d1 int); +CREATE TRIGGER t1_aurtrg AFTER UPDATE ON t1 FOR EACH ROW begin +CREATE OR REPLACE TEMPORARY TABLE trg_u AS +WITH l AS +(SELECT a.*, +Max(t2.col_id) over (PARTITION BY a.d1), +Max(t2.new_val) over (PARTITION BY a.d1) +FROM +(SELECT d1 , id1, id2 FROM t3) a +JOIN t2 ON (a.d1=t2.db_time AND a.id1=t2.au_nr)) +SELECT 1; +END;// +update t1 set ml_id=8884 where point_id=1; +ERROR 23000: Duplicate entry '8884-1' for key 't1_ml_u' +update t1 set ml_id=8884 where point_id=1; +ERROR 23000: Duplicate entry '8884-1' for key 't1_ml_u' +drop table t1, t2,t3; +CREATE TABLE t1 (i INT, a char); +INSERT INTO t1 VALUES (1, 'a'),(2, 'b'); +create view v1 as select * from t1; +PREPARE stmt FROM "SELECT i, row_number() over (partition by i order by i) FROM v1"; +execute stmt; +i row_number() over (partition by i order by i) +1 1 +2 1 +deallocate prepare stmt; +drop table t1; +drop view v1; +# +# MDEV-17676: Assertion `inited==NONE || (inited==RND && scan)' failed in handler::ha_rnd_init +# +CREATE TABLE t1 (b1 text NOT NULL); +INSERT INTO t1 VALUES ('2'),('1'); +EXPLAIN +SELECT DISTINCT MIN(b1) OVER () FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using temporary +SELECT DISTINCT MIN(b1) OVER () FROM t1; +MIN(b1) OVER () +1 +drop table t1; +# +# MDEV-15424: Unreasonal SQL Error (1356) on select from view +# +create table t1 (id int, n1 int); +insert into t1 values (1,1), (2,1), (3,2), (4,4); +create view v1 as SELECT ifnull(max(n1) over (partition by n1),'aaa') FROM t1; +explain select * from v1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 4 +2 DERIVED t1 ALL NULL NULL NULL NULL 4 Using temporary +select * from v1; +ifnull(max(n1) over (partition by n1),'aaa') +1 +1 +2 +4 +drop table t1; +drop view v1; +# +# MDEV-18431: Select max + row_number giving incorrect result +# +create table t1 (id int, v int); +insert into t1 values (1, 1), (1,2), (1,3), (2, 1), (2, 2); +select e.id, +(select max(t1.v) from t1 where t1.id=e.id) as a, +row_number() over (partition by e.id order by e.v) as b, +(select max(t1.v) from t1 where t1.id=e.id) + (row_number() over (partition by e.id order by e.v)) as sum_a_b +from t1 e; +id a b sum_a_b +1 3 1 4 +1 3 2 5 +1 3 3 6 +2 2 1 3 +2 2 2 4 +drop table t1; +# +# MDEV-15837: Assertion `item1->type() == Item::FIELD_ITEM && item2->type() == Item::FIELD_ITEM' +# failed in compare_order_elements function +# +CREATE TABLE t1 (a1 int); +insert into t1 values (1),(2),(3); +SELECT rank() OVER (ORDER BY 1), ROW_NUMBER() OVER (ORDER BY (EXPORT_SET(5,'Y','N',',',4))) FROM t1; +rank() OVER (ORDER BY 1) ROW_NUMBER() OVER (ORDER BY (EXPORT_SET(5,'Y','N',',',4))) +1 1 +1 2 +1 3 +drop table t1; +# +# MDEV-17781: Server crashes in next_linear_tab +# +CREATE TABLE t1 (i1 int); +explain +(SELECT AVG(0) OVER (), MAX('2') FROM t1) +UNION ALL +(SELECT AVG(0) OVER (), MAX('2') FROM t1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used +2 UNION NULL NULL NULL NULL NULL NULL NULL No tables used +(SELECT AVG(0) OVER (), MAX('2') FROM t1) +UNION ALL +(SELECT AVG(0) OVER (), MAX('2') FROM t1); +AVG(0) OVER () MAX('2') +0.0000 NULL +0.0000 NULL +drop table t1; +# +# MDEV-14791: Crash with order by expression containing window functions +# +CREATE TABLE t1 (b1 int, b2 int); +INSERT INTO t1 VALUES (1,1),(0,0); +explain +SELECT b1 from t1 order by row_number() over (ORDER BY b2) + 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort +SELECT b1 from t1 order by row_number() over (ORDER BY b2) + 1; +b1 +0 +1 +explain +SELECT b1 from t1 order by row_number() over (ORDER BY b2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort +SELECT b1 from t1 order by row_number() over (ORDER BY b2); +b1 +0 +1 +DROP TABLE t1; +CREATE TABLE t1 (a int, b int, c int); +INSERT INTO t1 VALUES (2,3,207), (1,21,909), (7,13,312), (8,64,248); +explain +SELECT * FROM t1 ORDER BY max(t1.a) over (partition by c); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort +SELECT * FROM t1 ORDER BY max(t1.a) over (partition by c); +a b c +1 21 909 +2 3 207 +7 13 312 +8 64 248 +explain +SELECT max(t1.a) over (partition by c) as x, b, c from t1 order by max(t1.a) over (partition by c); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort +SELECT max(t1.a) over (partition by c) as x, b, c from t1 order by max(t1.a) over (partition by c); +x b c +1 21 909 +2 3 207 +7 13 312 +8 64 248 +drop table t1; +# +# MDEV-18373: DENSE_RANK is not calculated correctly +# +create table t1 (a int, b int); +insert into t1 values (60, 1515),(60, 2000),(70, 2000),(55, 1600); +select b, dense_rank() over (order by sum(a)) from t1 group by b; +b dense_rank() over (order by sum(a)) +1515 2 +1600 1 +2000 3 +select b, dense_rank() over (order by sum(a)+1) from t1 group by b; +b dense_rank() over (order by sum(a)+1) +1515 2 +1600 1 +2000 3 +select b, row_number() over (partition by sum(a)) from t1 group by b; +b row_number() over (partition by sum(a)) +1515 1 +1600 1 +2000 1 +select b, row_number() over (partition by sum(a)+1) from t1 group by b; +b row_number() over (partition by sum(a)+1) +1515 1 +1600 1 +2000 1 +drop table t1; +# +# MDEV-18015: Assertion `global_status_var.global_memory_used == 0' failed when using UDF, +# window functions and views +# +create table t1 (id int, n1 int); +insert into t1 values (1,1),(2,1),(3,2),(4,4); +explain +select max(n1) over (partition by 'abc') from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary +select max(n1) over (partition by 'abc') from t1; +max(n1) over (partition by 'abc') +4 +4 +4 +4 +explain +select rank() over (partition by 'abc' order by 'xyz') from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary +select rank() over (partition by 'abc' order by 'xyz') from t1; +rank() over (partition by 'abc' order by 'xyz') +1 +1 +1 +1 +drop table t1; +# +# MDEV-19380: ASAN heap-use-after-free in Protocol::net_store_data +# +CREATE TABLE t1 (i int); +INSERT INTO t1 VALUES (1),(2),(3); +SELECT (SELECT MIN('foo') OVER() FROM t1 LIMIT 1) as x; +x +foo +drop table t1; +# +# MDEV-16579: Wrong result of query using DISTINCT COUNT(*) OVER (*) +# +CREATE TABLE t1 (i int) ; +INSERT INTO t1 VALUES (1),(0),(1),(2),(0),(1),(2),(1),(2); +SELECT DISTINCT COUNT(*) OVER (), MOD(MIN(i),2) FROM t1 GROUP BY i ; +COUNT(*) OVER () MOD(MIN(i),2) +3 0 +3 1 +drop table t1; +# +# MDEV-21318: Wrong results with window functions and implicit grouping +# +CREATE TABLE t1 (a INT); +# +# With empty const table +# The expected result here is 1, NULL +# +explain +SELECT row_number() over(), sum(1) FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found; Using temporary +SELECT row_number() over(), sum(1) FROM t1; +row_number() over() sum(1) +1 NULL +insert into t1 values (2); +# +# Const table has 1 row, but still impossible where +# The expected result here is 1, NULL +# +EXPLAIN SELECT row_number() over(), sum(1) FROM t1 where a=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +SELECT row_number() over(), sum(1) FROM t1 where a=1; +row_number() over() sum(1) +1 NULL +# +# Impossible HAVING +# Empty result is expected +# +EXPLAIN SELECT row_number() over(), sum(1) FROM t1 where a=1 having 1=0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible HAVING +SELECT row_number() over(), sum(1) FROM t1 where a=1 having 1=0; +row_number() over() sum(1) +# +# const table has 1 row, no impossible where +# The expected result here is 1, 2 +# +EXPLAIN SELECT row_number() over(), sum(a) FROM t1 where a=2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 1 Using temporary +SELECT row_number() over(), sum(a) FROM t1 where a=2; +row_number() over() sum(a) +1 2 +drop table t1; +# +# Impossible Where +# +create table t1(a int); +insert into t1 values (1); +# +# Expected result is NULL, 0, NULL +# +EXPLAIN SELECT MAX(a) OVER (), COUNT(a), abs(a) FROM t1 WHERE FALSE; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +SELECT MAX(a) OVER (), COUNT(a), abs(a) FROM t1 WHERE FALSE; +MAX(a) OVER () COUNT(a) abs(a) +NULL 0 NULL +# +# Expected result is 1, 0, NULL +# +EXPLAIN +SELECT MAX(1) OVER (), COUNT(a), abs(a) FROM t1 WHERE FALSE; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +SELECT MAX(1) OVER (), COUNT(a), abs(a) FROM t1 WHERE FALSE; +MAX(1) OVER () COUNT(a) abs(a) +1 0 NULL +drop table t1; +# +# MDEV-22461: JOIN::make_aggr_tables_info(): Assertion `select_options & (1ULL << 17)' failed. +# +CREATE TEMPORARY TABLE t0 (a INT PRIMARY KEY ) ; +INSERT INTO t0 VALUES (1),(2),(3); +SELECT a FROM t0 +WHERE a < 8 +GROUP BY 1.5 +WINDOW v2 AS ( PARTITION BY a ORDER BY a DESC ); +a +1 +SELECT a, ROW_NUMBER() OVER v2 +FROM t0 +WHERE a < 8 +GROUP BY 1.5 +WINDOW v2 AS ( PARTITION BY a ORDER BY a DESC ); +a ROW_NUMBER() OVER v2 +1 1 +drop table t0; +# +# MDEV-16230:Server crashes when Analyze format=json is run with a window function with +# empty PARTITION BY and ORDER BY clauses +# +CREATE TABLE t1(a INT, b INT); +INSERT INTO t1 VALUES (1,1),(2,2),(3,3); +ANALYZE FORMAT=JSON SELECT row_number() OVER() FROM t1; +ANALYZE +{ + "query_block": { + "select_id": 1, + "r_loops": 1, + "r_total_time_ms": "REPLACED", + "window_functions_computation": { + "sorts": { + "filesort": { + "sort_key": "`row_number() OVER()`", + "r_loops": 1, + "r_total_time_ms": "REPLACED", + "r_used_priority_queue": false, + "r_output_rows": 3, + "r_buffer_size": "REPLACED" + } + }, + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "r_loops": 1, + "rows": 3, + "r_rows": 3, + "r_total_time_ms": "REPLACED", + "filtered": 100, + "r_filtered": 100 + } + } + } + } +} +SELECT row_number() OVER() FROM t1; +row_number() OVER() +1 +2 +3 +DROP TABLE t1; +# +# MDEV-22984: Throw an error when arguments to window functions are window functions +# +CREATE TABLE t1(a INT, b INT); +INSERT INTO t1 VALUES (1,1), (2,2), (3,3); +SELECT NTILE(MAX(a) OVER (PARTITION BY a)) OVER (PARTITION BY a ORDER BY b) FROM t1; +ERROR HY000: Window functions can not be used as arguments to group functions. +SELECT FIRST_VALUE(MAX(a) OVER (PARTITION BY a)) OVER (ORDER BY a) AS x FROM t1 GROUP BY a; +ERROR HY000: Window functions can not be used as arguments to group functions. +DROP TABLE t1; +# +# MDEV-12059: Assertion `precision > 0' failed with a window function or window aggregate function +# +CREATE TABLE t1 (d DECIMAL(1,0) UNSIGNED); +INSERT INTO t1 VALUES (1),(2); +SELECT MIN(d) OVER () FROM t1; +MIN(d) OVER () +1 +1 +DROP TABLE t1; +# +# MDEV-22463: Element_type &Bounds_checked_array::operator[](size_t) [Element_type = Item *]: +# Assertion `n < m_size' failed +# +CREATE TABLE t1 (a INT, b INT, c INT, d INT, e INT, f INT, g int, h INT, i INT); +INSERT INTO t1 SELECT seq,seq,seq,seq, seq,seq,seq,seq,seq FROM seq_1_to_5; +SELECT ROW_NUMBER() OVER w2 FROM t1 WINDOW w2 AS (PARTITION BY -1,0,1,2,3,4,5,6); +ROW_NUMBER() OVER w2 +1 +2 +3 +4 +5 +SELECT a FROM t1 ORDER BY ROW_NUMBER() OVER (PARTITION BY -1,1,0,2,3,4,5,6,7,8); +a +1 +2 +3 +4 +5 +SELECT a,b FROM t1 WINDOW w2 AS (PARTITION BY -1,1,0,2,3,4); +a b +1 1 +2 2 +3 3 +4 4 +5 5 +SELECT ROW_NUMBER() OVER w2 FROM t1 WINDOW w2 AS (PARTITION BY -1,0,1,2,3,4,5,6); +ROW_NUMBER() OVER w2 +1 +2 +3 +4 +5 +DROP TABLE t1; +# +# MDEV-18916: crash in Window_spec::print_partition() with decimals +# +SELECT cast((rank() over w1) as decimal (53,56)); +ERROR 42000: Too big scale 56 specified for 'rank() over w1'. Maximum is 38 +SELECT cast((rank() over w1) as decimal (53,30)); +ERROR HY000: Window specification with name 'w1' is not defined +# +# MDEV-15180: server crashed with NTH_VALUE() +# +CREATE TABLE t1 (i1 int, a int); +INSERT INTO t1 VALUES (1, 1), (2, 2),(3, 3); +CREATE TABLE t2 (i2 int); +INSERT INTO t2 VALUES (1),(2),(5),(1),(7),(4),(3); +CREATE VIEW v1 AS (SELECT * FROM t1,t2 WHERE t1.i1=t2.i2) ; +SELECT NTH_VALUE(i1, i1) OVER (PARTITION BY i1) FROM v1; +NTH_VALUE(i1, i1) OVER (PARTITION BY i1) +1 +1 +NULL +NULL +DROP VIEW v1; +DROP TABLE t1,t2; +# +# End of 10.2 tests +# +# +# MDEV-23867: select crash in compute_window_func +# +set @save_sort_buffer_size=@@sort_buffer_size; +set sort_buffer_size= 2000; +CREATE TABLE t1( a INT, b INT, c INT); +INSERT INTO t1 select seq, seq, seq from seq_1_to_5000; +CREATE TABLE t2( a INT, b INT, c INT); +INSERT INTO t2 SELECT a, b, ROW_NUMBER() OVER (PARTITION BY b) FROM t1; +SELECT COUNT(*), MAX(c) FROM t2; +COUNT(*) MAX(c) +5000 1 +CREATE TABLE t3( a INT, b INT, c INT); +INSERT INTO t3 SELECT a, b, SUM(a) OVER () FROM t1; +SELECT COUNT(*), MAX(c) FROM t3; +COUNT(*) MAX(c) +5000 12502500 +set @@sort_buffer_size=@save_sort_buffer_size; +DROP TABLE t1,t2,t3; +# end of 10.2 test diff --git a/mysql-test/suite/encryption/t/tempfiles_encrypted.opt b/mysql-test/suite/encryption/t/tempfiles_encrypted.opt new file mode 100644 index 00000000000..81877a8d1c5 --- /dev/null +++ b/mysql-test/suite/encryption/t/tempfiles_encrypted.opt @@ -0,0 +1 @@ +--encrypt-tmp_files=ON diff --git a/mysql-test/suite/encryption/t/tempfiles_encrypted.test b/mysql-test/suite/encryption/t/tempfiles_encrypted.test new file mode 100644 index 00000000000..7ba63cedaaa --- /dev/null +++ b/mysql-test/suite/encryption/t/tempfiles_encrypted.test @@ -0,0 +1,31 @@ +--echo # +--echo # Tests when the temporary files are encrypted +--echo # + +source include/have_file_key_management_plugin.inc; +source include/have_sequence.inc; +source include/have_innodb.inc; + +select @@encrypt_tmp_files; + +--source t/win.test + +--echo # +--echo # MDEV-23867: select crash in compute_window_func +--echo # + +set @save_sort_buffer_size=@@sort_buffer_size; + +set sort_buffer_size= 2000; +CREATE TABLE t1( a INT, b INT, c INT); +INSERT INTO t1 select seq, seq, seq from seq_1_to_5000; +CREATE TABLE t2( a INT, b INT, c INT); +INSERT INTO t2 SELECT a, b, ROW_NUMBER() OVER (PARTITION BY b) FROM t1; +SELECT COUNT(*), MAX(c) FROM t2; +CREATE TABLE t3( a INT, b INT, c INT); +INSERT INTO t3 SELECT a, b, SUM(a) OVER () FROM t1; +SELECT COUNT(*), MAX(c) FROM t3; +set @@sort_buffer_size=@save_sort_buffer_size; +DROP TABLE t1,t2,t3; + +--echo # end of 10.2 test diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c index 5d74ba42677..e09c7f930c8 100644 --- a/mysys/mf_iocache.c +++ b/mysys/mf_iocache.c @@ -250,7 +250,7 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize, info->write_buffer= info->buffer + cachesize; else info->write_buffer= info->buffer; - info->alloced_buffer= 1; + info->alloced_buffer= buffer_block; break; /* Enough memory found */ } if (cachesize == min_cache) @@ -324,14 +324,14 @@ int init_slave_io_cache(IO_CACHE *master, IO_CACHE *slave) DBUG_ASSERT(!master->share); DBUG_ASSERT(master->alloced_buffer); - if (!(slave_buf= (uchar*)my_malloc(master->buffer_length, MYF(0)))) + if (!(slave_buf= (uchar*)my_malloc(master->alloced_buffer, MYF(0)))) { return 1; } memcpy(slave, master, sizeof(IO_CACHE)); slave->buffer= slave_buf; - memcpy(slave->buffer, master->buffer, master->buffer_length); + memcpy(slave->buffer, master->buffer, master->alloced_buffer); slave->read_pos= slave->buffer + (master->read_pos - master->buffer); slave->read_end= slave->buffer + (master->read_end - master->buffer); diff --git a/sql/mf_iocache_encr.cc b/sql/mf_iocache_encr.cc index d741cf8b837..29d7074aeb1 100644 --- a/sql/mf_iocache_encr.cc +++ b/sql/mf_iocache_encr.cc @@ -71,6 +71,16 @@ static int my_b_encr_read(IO_CACHE *info, uchar *Buffer, size_t Count) DBUG_RETURN(1); } info->seek_not_done= 0; + if (info->next_file_user) + { + IO_CACHE *c; + for (c= info->next_file_user; + c!= info; + c= c->next_file_user) + { + c->seek_not_done= 1; + } + } } do From 9df99151dae05574cf21e7787ffd4fe988a66d77 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Sat, 24 Oct 2020 00:16:56 +0400 Subject: [PATCH 218/323] MDEV-23437 Item_func_json_objectagg::print is not implemented. Fix the Item_func_json_objectagg::fix_fields to save the orig_args. --- mysql-test/main/func_json.result | 5 +++++ mysql-test/main/func_json.test | 4 ++++ sql/item_jsonfunc.cc | 6 ++---- sql/item_jsonfunc.h | 3 +-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index 523048ccb7a..1af786c8d3f 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -1354,6 +1354,11 @@ e JSON_OBJECTAGG(B.a, B.v) 0 {"a1":"1", "a1":"1", "a1":"1"} 0 {"a2":"2", "a2":"2", "a2":"2"} 1 {"b1":"3", "b1":"3", "b1":"3"} +CREATE VIEW v AS SELECT JSON_OBJECTAGG(a, e) FROM t1; +SELECT * FROM v; +JSON_OBJECTAGG(a, e) +{"a1":0, "a2":0, "b1":1} +DROP VIEW v; DROP TABLE t1; # # End of 10.5 tests diff --git a/mysql-test/main/func_json.test b/mysql-test/main/func_json.test index 68d381f5c07..04e16c02e6d 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.test @@ -849,6 +849,10 @@ INSERT INTO t1 VALUES (0, 'a1', '1') , (0, 'a2', '2') , (1, 'b1', '3'); EXPLAIN SELECT B.e, JSON_OBJECTAGG(B.a, B.v) FROM t1 A, t1 B GROUP BY B.e, B.a; SELECT B.e, JSON_OBJECTAGG(B.a, B.v) FROM t1 A, t1 B GROUP BY B.e, B.a; +CREATE VIEW v AS SELECT JSON_OBJECTAGG(a, e) FROM t1; +SELECT * FROM v; + +DROP VIEW v; DROP TABLE t1; --echo # diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index aec3e1edcd3..0299adf42bc 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -3772,6 +3772,8 @@ Item_func_json_objectagg::fix_fields(THD *thd, Item **ref) uint i; /* for loop variable */ DBUG_ASSERT(fixed == 0); + memcpy(orig_args, args, sizeof(Item*) * arg_count); + if (init_sum_func_check(thd)) return TRUE; @@ -3867,7 +3869,3 @@ String* Item_func_json_objectagg::val_str(String* str) } -void Item_func_json_objectagg::print(String *str, enum_query_type query_type) -{ -} - diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index 6bd2a81afc6..ec6c6696001 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -589,7 +589,7 @@ public: void cleanup(); enum Sumfunctype sum_func () const {return JSON_OBJECTAGG_FUNC;} - const char *func_name() const { return "json_objectagg("; } + const char *func_name() const { return "json_objectagg"; } const Type_handler *type_handler() const { if (too_big_for_varchar()) @@ -618,7 +618,6 @@ public: String* val_str(String* str); Item *copy_or_same(THD* thd); void no_rows_in_result() {} - void print(String *str, enum_query_type query_type); Item *get_copy(THD *thd) { return get_item_copy(thd, this); } }; From 64fe9d6d9a03b5c68c85f7322136c95db54afa5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sat, 24 Oct 2020 11:10:37 +0300 Subject: [PATCH 219/323] Do not leak memory in the skipped MDEV-23768 unit test --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index cfc36a46d1c..0cdc1656a70 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit cfc36a46d1cab755e46532bcc6cddab62652c0a0 +Subproject commit 0cdc1656a70c52103b4329debf9ed02ccacfb3c2 From d8fbd463a0458727bd2c9f29e75600aadc89ac58 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 17 Sep 2020 16:04:21 +0200 Subject: [PATCH 220/323] don't use deprecated _LIB_DEPENDS. CMP0073 --- cmake/libutils.cmake | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cmake/libutils.cmake b/cmake/libutils.cmake index 92a5b9f564d..37f9cf196af 100644 --- a/cmake/libutils.cmake +++ b/cmake/libutils.cmake @@ -323,11 +323,14 @@ MACRO(MERGE_LIBRARIES) ENDMACRO() FUNCTION(GET_DEPENDEND_OS_LIBS target result) - FOREACH(lib ${${target}_LIB_DEPENDS}) - IF(NOT TARGET ${lib}) - SET(ret ${ret} ${lib}) - ENDIF() - ENDFOREACH() + GET_TARGET_PROPERTY(DEPS ${target} LINK_LIBRARIES) + IF(DEPS) + FOREACH(lib ${DEPS}) + IF(NOT TARGET ${lib}) + SET(ret ${ret} ${lib}) + ENDIF() + ENDFOREACH() + ENDIF() SET(${result} ${ret} PARENT_SCOPE) ENDFUNCTION() From 3cd4d8ddba69131f26f3773684d4a6c489063fdf Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 17 Sep 2020 16:08:23 +0200 Subject: [PATCH 221/323] parser optimization first try to resolve the function name as a native function, and only then look within pluggable data types --- sql/sql_yacc.yy | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 088e99f25c0..ed361ed5df4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -10594,19 +10594,20 @@ function_call_generic: names are resolved with the following order: - MySQL native functions, - User Defined Functions, + - Constructors, like POINT(1,1) - Stored Functions (assuming the current database) This will be revised with WL#2128 (SQL PATH) */ - if ((h= Type_handler::handler_by_name(thd, $1)) && - (item= h->make_constructor_item(thd, $4))) - { - // Found a constructor with a proper argument count - } - else if ((builder= find_native_function_builder(thd, &$1))) + if ((builder= find_native_function_builder(thd, &$1))) { item= builder->create_func(thd, &$1, $4); } + else if ((h= Type_handler::handler_by_name(thd, $1)) && + (item= h->make_constructor_item(thd, $4))) + { + // Found a constructor with a proper argument count + } else { #ifdef HAVE_DLOPEN From 73a2ae9f89978a7108bdbe8bc450e855f059d3b6 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 19 Sep 2020 19:17:04 +0200 Subject: [PATCH 222/323] MDEV-23764 Slave crashes in ha_storage_engine_is_enabled upon rename of view view_pseudo_hton cannot be dereferenced --- mysql-test/suite/rpl/r/rpl_create_drop_view.result | 3 ++- mysql-test/suite/rpl/t/rpl_create_drop_view.test | 3 ++- sql/sql_rename.cc | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_create_drop_view.result b/mysql-test/suite/rpl/r/rpl_create_drop_view.result index facd40a6018..079eb749b37 100644 --- a/mysql-test/suite/rpl/r/rpl_create_drop_view.result +++ b/mysql-test/suite/rpl/r/rpl_create_drop_view.result @@ -93,7 +93,8 @@ id 80 40 connection master; -DROP VIEW v1; +RENAME TABLE v1 TO v2; +DROP VIEW v2; DROP TABLE t1; DROP VIEW v1; ERROR 42S02: Unknown VIEW: 'test.v1' diff --git a/mysql-test/suite/rpl/t/rpl_create_drop_view.test b/mysql-test/suite/rpl/t/rpl_create_drop_view.test index c26243ab3c6..4abb3ffb252 100644 --- a/mysql-test/suite/rpl/t/rpl_create_drop_view.test +++ b/mysql-test/suite/rpl/t/rpl_create_drop_view.test @@ -38,7 +38,8 @@ SELECT * FROM t1; SELECT * FROM v1; connection master; -DROP VIEW v1; +RENAME TABLE v1 TO v2; +DROP VIEW v2; DROP TABLE t1; --error ER_UNKNOWN_VIEW diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 0ac97bbeafd..77a1e46a75a 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -303,7 +303,8 @@ do_rename(THD *thd, TABLE_LIST *ren_table, const LEX_CSTRING *new_db, DBUG_RETURN(skip_error || if_exists ? 0 : 1); } - if (ha_check_if_updates_are_ignored(thd, hton, "RENAME")) + if (hton != view_pseudo_hton && + ha_check_if_updates_are_ignored(thd, hton, "RENAME")) { /* Shared table. Just drop the old .frm as it's not correct anymore From 606a281162b0576792fd540d167279ed76f32293 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 23 Sep 2020 12:24:16 +0200 Subject: [PATCH 223/323] MDEV-22100 TokuDB compilation error fix TokuDB to compile with the perfschema --- storage/tokudb/ha_tokudb.cc | 6 +++--- storage/tokudb/ha_tokudb_alter_56.cc | 2 +- storage/tokudb/tokudb_memory.h | 12 ------------ 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/storage/tokudb/ha_tokudb.cc b/storage/tokudb/ha_tokudb.cc index 4555ab3a862..53feb5e430a 100644 --- a/storage/tokudb/ha_tokudb.cc +++ b/storage/tokudb/ha_tokudb.cc @@ -6387,7 +6387,7 @@ int ha_tokudb::create_txn(THD* thd, tokudb_trx_data* trx) { "created master %p", trx->all); trx->sp_level = trx->all; - trans_register_ha(thd, true, tokudb_hton); + trans_register_ha(thd, true, tokudb_hton, 0); } DBUG_PRINT("trans", ("starting transaction stmt")); if (trx->stmt) { @@ -6429,7 +6429,7 @@ int ha_tokudb::create_txn(THD* thd, tokudb_trx_data* trx) { trx->sp_level, trx->stmt); reset_stmt_progress(&trx->stmt_progress); - trans_register_ha(thd, false, tokudb_hton); + trans_register_ha(thd, false, tokudb_hton, 0); cleanup: return error; } @@ -6594,7 +6594,7 @@ int ha_tokudb::start_stmt(THD* thd, thr_lock_type lock_type) { share->rows_from_locked_table = added_rows - deleted_rows; } transaction = trx->sub_sp_level; - trans_register_ha(thd, false, tokudb_hton); + trans_register_ha(thd, false, tokudb_hton, 0); cleanup: TOKUDB_HANDLER_DBUG_RETURN(error); } diff --git a/storage/tokudb/ha_tokudb_alter_56.cc b/storage/tokudb/ha_tokudb_alter_56.cc index 4bdf2cf7bda..233d929a509 100644 --- a/storage/tokudb/ha_tokudb_alter_56.cc +++ b/storage/tokudb/ha_tokudb_alter_56.cc @@ -57,7 +57,7 @@ public: expand_varchar_update_needed(false), expand_fixed_update_needed(false), expand_blob_update_needed(false), - optimize_needed(false), + optimize_needed(false), changed_fields(PSI_INSTRUMENT_MEM), table_kc_info(NULL), altered_table_kc_info(NULL) { } diff --git a/storage/tokudb/tokudb_memory.h b/storage/tokudb/tokudb_memory.h index 2687c1cda8e..a12db83e022 100644 --- a/storage/tokudb/tokudb_memory.h +++ b/storage/tokudb/tokudb_memory.h @@ -40,31 +40,19 @@ void* multi_malloc(myf myFlags, ...); inline void* malloc(size_t s, myf flags) { -#if 50700 <= MYSQL_VERSION_ID && MYSQL_VERSION_ID <= 50799 return ::my_malloc(0, s, flags); -#else - return ::my_malloc(s, flags); -#endif } inline void* realloc(void* p, size_t s, myf flags) { if (s == 0) return p; -#if 50700 <= MYSQL_VERSION_ID && MYSQL_VERSION_ID <= 50799 return ::my_realloc(0, p, s, flags); -#else - return ::my_realloc(p, s, flags | MY_ALLOW_ZERO_PTR); -#endif } inline void free(void* ptr) { if (ptr) ::my_free(ptr); } inline char* strdup(const char* p, myf flags) { -#if 50700 <= MYSQL_VERSION_ID && MYSQL_VERSION_ID <= 50799 return ::my_strdup(0, p, flags); -#else - return ::my_strdup(p, flags); -#endif } inline void* multi_malloc(myf myFlags, ...) { va_list args; From e764d11829436321dec08c84251cb28cbae8511c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 25 Sep 2020 12:52:37 +0200 Subject: [PATCH 224/323] fix occasisonal test failures: SELECT without ORDER BY --- .../suite/perfschema/r/dml_file_instances.result | 12 ++++++------ .../suite/perfschema/t/dml_file_instances.test | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/perfschema/r/dml_file_instances.result b/mysql-test/suite/perfschema/r/dml_file_instances.result index a13c570a5ad..2680c07b07c 100644 --- a/mysql-test/suite/perfschema/r/dml_file_instances.result +++ b/mysql-test/suite/perfschema/r/dml_file_instances.result @@ -29,21 +29,21 @@ FILE_NAME CREATE TABLE t_db_26152751 (a INT) ENGINE=MYISAM; SELECT FILE_NAME FROM performance_schema.file_instances WHERE FILE_NAME LIKE "%t_db_26152751%"; FILE_NAME -t_db_26152751.frm -t_db_26152751.MYI t_db_26152751.MYD +t_db_26152751.MYI +t_db_26152751.frm RENAME TABLE t_db_26152751 to t_db_26152751_new; SELECT FILE_NAME FROM performance_schema.file_instances WHERE FILE_NAME LIKE "%t_db_26152751%"; FILE_NAME -t_db_26152751_new.frm -t_db_26152751_new.MYI t_db_26152751_new.MYD +t_db_26152751_new.MYI +t_db_26152751_new.frm RENAME TABLE t_db_26152751_new to t_db_26152751; SELECT FILE_NAME FROM performance_schema.file_instances WHERE FILE_NAME LIKE "%t_db_26152751%"; FILE_NAME -t_db_26152751.frm -t_db_26152751.MYI t_db_26152751.MYD +t_db_26152751.MYI +t_db_26152751.frm ALTER TABLE t_db_26152751 ADD COLUMN b INT; SELECT FILE_NAME FROM performance_schema.file_instances WHERE FILE_NAME LIKE "%t_db_26152751%"; FILE_NAME diff --git a/mysql-test/suite/perfschema/t/dml_file_instances.test b/mysql-test/suite/perfschema/t/dml_file_instances.test index ea3bf0a1917..c708c31ed55 100644 --- a/mysql-test/suite/perfschema/t/dml_file_instances.test +++ b/mysql-test/suite/perfschema/t/dml_file_instances.test @@ -46,16 +46,19 @@ SELECT FILE_NAME FROM performance_schema.file_instances WHERE FILE_NAME LIKE "%t CREATE TABLE t_db_26152751 (a INT) ENGINE=MYISAM; +--sorted_result --replace_regex /.*\/t_db_26152751/t_db_26152751/ SELECT FILE_NAME FROM performance_schema.file_instances WHERE FILE_NAME LIKE "%t_db_26152751%"; RENAME TABLE t_db_26152751 to t_db_26152751_new; +--sorted_result --replace_regex /.*\/t_db_26152751/t_db_26152751/ SELECT FILE_NAME FROM performance_schema.file_instances WHERE FILE_NAME LIKE "%t_db_26152751%"; RENAME TABLE t_db_26152751_new to t_db_26152751; +--sorted_result --replace_regex /.*\/t_db_26152751/t_db_26152751/ SELECT FILE_NAME FROM performance_schema.file_instances WHERE FILE_NAME LIKE "%t_db_26152751%"; From d8515c8d359e92dfc1748df87b98a431e2c1d76f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 27 Aug 2020 18:59:09 +0200 Subject: [PATCH 225/323] S3 plugin fails to load depending on loaded storage engines storage engines are generally initialized in some random order (by iterating the hash of plugin names). S3 fails if it's initialized before Aria. But it looks that while S3 needs Aria, it does not need Aria to be initialized before S3. S3 copies maria_hton and then overwrites every single member of it, so it can handle Aria being initialized after S3. --- storage/maria/ha_maria.cc | 2 +- storage/maria/ha_s3.cc | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 5f195a9eb8e..26066135b2c 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -72,7 +72,7 @@ const char *zerofill_error_msg= corrupted. */ ulonglong maria_recover_options= HA_RECOVER_NONE; -handlerton __attribute__((visibility("default"))) *maria_hton; +handlerton *maria_hton; /* bits in maria_recover_options */ const char *maria_recover_names[]= diff --git a/storage/maria/ha_s3.cc b/storage/maria/ha_s3.cc index e9396329c50..cf2b9098142 100644 --- a/storage/maria/ha_s3.cc +++ b/storage/maria/ha_s3.cc @@ -51,7 +51,11 @@ but the stored block will be the size of the compressed block. Implementation: - The s3 engine inherits from the ha_maria handler + The s3 engine inherits from the ha_maria handler. + + It uses Aria code and relies on Aria being enabled. We don't have to check + that Aria is enabled though, because Aria is a mandatory plugin, and + the server will refuse to start if Aria failed to initialize. s3 will use it's own page cache to not interfere with normal Aria usage but also to ensure that the S3 page cache is large enough @@ -996,14 +1000,7 @@ static int ha_s3_init(void *p) bool res; static const char *no_exts[]= { 0 }; - /* This can happen if Aria fails to start */ - if (!maria_hton) - return HA_ERR_INITIALIZATION; - s3_hton= (handlerton *)p; - - /* Use Aria engine as a base */ - memcpy(s3_hton, maria_hton, sizeof(*s3_hton)); s3_hton->db_type= DB_TYPE_S3; s3_hton->create= s3_create_handler; s3_hton->panic= s3_hton_panic; From f679d72679376d04c863e80bc68d084eb56795a5 Mon Sep 17 00:00:00 2001 From: Vlad Lesin Date: Thu, 30 Nov 2017 00:41:43 +0300 Subject: [PATCH 226/323] MDEV-24017: Blackhole : Specified key was too long; max key length is 1000 bytes The maximum innodb key length is 3500 what is hardcoded in ha_innobase::max_supported_key_length()). The maximum number of innodb indexes is configured with MAX_INDEXES macro (see also MAX_KEY definition). The same is currently implemented for blackhole storage engine. Cherry picked from percona-server 0d90d81c3c507a6b1476246a405504f6e4ef9d4d Original lp bug 1733049 Reviewed-by: daniel@mariadb.org --- mysql-test/r/blackhole.result | 6 ++++++ mysql-test/t/blackhole.test | 16 ++++++++++++++++ storage/blackhole/ha_blackhole.h | 5 +++-- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/blackhole.result b/mysql-test/r/blackhole.result index 36f5459ff85..a7281c42ca7 100644 --- a/mysql-test/r/blackhole.result +++ b/mysql-test/r/blackhole.result @@ -24,3 +24,9 @@ SELECT 0 FROM t1 FORCE INDEX FOR GROUP BY(a) WHERE a = 0 OR b = 0 AND c = 0; 0 DROP TABLE t1; End of 5.6 tests +CREATE TABLE `t` ( +`a` varchar(3000) NOT NULL default '', +PRIMARY KEY (`a`) +) ENGINE=BLACKHOLE; +DROP TABLE `t`; +End of 10.1 tests diff --git a/mysql-test/t/blackhole.test b/mysql-test/t/blackhole.test index 7f394e0f846..c80ceffef4c 100644 --- a/mysql-test/t/blackhole.test +++ b/mysql-test/t/blackhole.test @@ -38,3 +38,19 @@ SELECT 0 FROM t1 FORCE INDEX FOR GROUP BY(a) WHERE a = 0 OR b = 0 AND c = 0; DROP TABLE t1; --echo End of 5.6 tests + +# +# MDEV-24017 / bug 53588 test case. +# +# Create long enough index (between 1000 and 3500). 1000 is the old value, +# 3500 is innodb value (see ha_innobase::max_supported_key_length()). Without +# the fix the test will fail with "Specified key was too long" error. +# +CREATE TABLE `t` ( + `a` varchar(3000) NOT NULL default '', + PRIMARY KEY (`a`) +) ENGINE=BLACKHOLE; + +DROP TABLE `t`; + +--echo End of 10.1 tests diff --git a/storage/blackhole/ha_blackhole.h b/storage/blackhole/ha_blackhole.h index e34386ddf33..07275b8eec1 100644 --- a/storage/blackhole/ha_blackhole.h +++ b/storage/blackhole/ha_blackhole.h @@ -20,6 +20,7 @@ #include "thr_lock.h" /* THR_LOCK */ #include "handler.h" /* handler */ #include "table.h" /* TABLE_SHARE */ +#include "sql_const.h" /* MAX_KEY */ /* Shared structure for correct LOCK operation @@ -65,9 +66,9 @@ public: HA_READ_ORDER | HA_KEYREAD_ONLY); } /* The following defines can be increased if necessary */ -#define BLACKHOLE_MAX_KEY 64 /* Max allowed keys */ +#define BLACKHOLE_MAX_KEY MAX_KEY /* Max allowed keys */ #define BLACKHOLE_MAX_KEY_SEG 16 /* Max segments for key */ -#define BLACKHOLE_MAX_KEY_LENGTH 1000 +#define BLACKHOLE_MAX_KEY_LENGTH 3500 /* Like in InnoDB */ uint max_supported_keys() const { return BLACKHOLE_MAX_KEY; } uint max_supported_key_length() const { return BLACKHOLE_MAX_KEY_LENGTH; } uint max_supported_key_part_length() const { return BLACKHOLE_MAX_KEY_LENGTH; } From 44c958dd7b454ebbdbf7ac8b066592c82dd3409f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Sat, 24 Oct 2020 14:57:16 +0300 Subject: [PATCH 227/323] Fix test failure on wsrep/variables test case. --- mysql-test/include/galera_have_debug_sync.inc | 9 +++++++++ mysql-test/suite/wsrep/t/variables.test | 1 + 2 files changed, 10 insertions(+) create mode 100644 mysql-test/include/galera_have_debug_sync.inc diff --git a/mysql-test/include/galera_have_debug_sync.inc b/mysql-test/include/galera_have_debug_sync.inc new file mode 100644 index 00000000000..21e7b3c88c3 --- /dev/null +++ b/mysql-test/include/galera_have_debug_sync.inc @@ -0,0 +1,9 @@ +--disable_query_log + +--let $galera_have_debug_sync = `SELECT 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_debug_sync_waiters'` + +--if (!$galera_have_debug_sync) { + --skip Test requires Galera debug library with debug_sync functionality +} + +--enable_query_log diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test index 1a2ab2579a5..15b69f8b7f6 100644 --- a/mysql-test/suite/wsrep/t/variables.test +++ b/mysql-test/suite/wsrep/t/variables.test @@ -1,4 +1,5 @@ --source include/have_wsrep.inc +--source include/galera_have_debug_sync.inc SET @wsrep_provider_options_saved= @@global.wsrep_provider_options; SET @wsrep_cluster_address_saved= @@global.wsrep_cluster_address; From 4e987b1c6ba7a0d73c5df54ae0af2805c081b0c3 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Wed, 22 Apr 2020 20:13:21 +0200 Subject: [PATCH 228/323] MDEV-22313: Neither SHOW CREATE USER nor SHOW GRANTS prints a user's default role Reviewed-by: serg@mariadb.com --- mysql-test/r/grant5.result | 32 +++++++++++ .../suite/roles/set_default_role_clear.result | 1 + .../suite/roles/set_default_role_for.result | 2 + .../roles/set_default_role_invalid.result | 3 ++ .../set_default_role_new_connection.result | 2 + mysql-test/t/grant5.test | 18 +++++++ sql/sql_acl.cc | 54 ++++++++++++++++--- 7 files changed, 104 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/grant5.result b/mysql-test/r/grant5.result index 338bbd36e14..a69070e8399 100644 --- a/mysql-test/r/grant5.result +++ b/mysql-test/r/grant5.result @@ -39,3 +39,35 @@ connection default; disconnect u1; drop user u1@localhost; drop database mysqltest1; +CREATE ROLE test_role; +CREATE USER test_user; +GRANT test_role TO test_user; +SET DEFAULT ROLE test_role FOR test_user; +SHOW GRANTS FOR test_user; +Grants for test_user@% +GRANT test_role TO 'test_user'@'%' +GRANT USAGE ON *.* TO 'test_user'@'%' +SET DEFAULT ROLE test_role FOR 'test_user'@'%' +SET DEFAULT ROLE NONE for test_user; +SHOW GRANTS FOR test_user; +Grants for test_user@% +GRANT test_role TO 'test_user'@'%' +GRANT USAGE ON *.* TO 'test_user'@'%' +SET ROLE test_role; +SET DEFAULT ROLE test_role; +SHOW GRANTS; +Grants for root@localhost +GRANT test_role TO 'root'@'localhost' WITH ADMIN OPTION +GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION +GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION +GRANT USAGE ON *.* TO 'test_role' +SET DEFAULT ROLE test_role FOR 'root'@'localhost' +SET DEFAULT ROLE NONE; +SHOW GRANTS; +Grants for root@localhost +GRANT test_role TO 'root'@'localhost' WITH ADMIN OPTION +GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION +GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION +GRANT USAGE ON *.* TO 'test_role' +DROP USER test_user; +DROP ROLE test_role; diff --git a/mysql-test/suite/roles/set_default_role_clear.result b/mysql-test/suite/roles/set_default_role_clear.result index 7f54b5eabcc..3cb13f55b4b 100644 --- a/mysql-test/suite/roles/set_default_role_clear.result +++ b/mysql-test/suite/roles/set_default_role_clear.result @@ -17,6 +17,7 @@ Grants for test_user@localhost GRANT test_role TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' GRANT SELECT ON *.* TO 'test_role' +SET DEFAULT ROLE test_role FOR 'test_user'@'localhost' select user, host, default_role from mysql.user where user='test_user'; user host default_role test_user localhost test_role diff --git a/mysql-test/suite/roles/set_default_role_for.result b/mysql-test/suite/roles/set_default_role_for.result index b55ca49c680..62c31373486 100644 --- a/mysql-test/suite/roles/set_default_role_for.result +++ b/mysql-test/suite/roles/set_default_role_for.result @@ -21,6 +21,7 @@ Grants for user_a@localhost GRANT role_a TO 'user_a'@'localhost' GRANT USAGE ON *.* TO 'user_a'@'localhost' GRANT SELECT ON *.* TO 'role_a' +SET DEFAULT ROLE role_a FOR 'user_a'@'localhost' select user, host, default_role from mysql.user where user like 'user_%'; user host default_role user_a localhost role_a @@ -42,6 +43,7 @@ Grants for user_b@localhost GRANT role_b TO 'user_b'@'localhost' GRANT USAGE ON *.* TO 'user_b'@'localhost' GRANT INSERT, UPDATE ON *.* TO 'role_b' +SET DEFAULT ROLE role_b FOR 'user_b'@'localhost' select user, host, default_role from mysql.user where user like 'user_%'; ERROR 42000: SELECT command denied to user 'user_b'@'localhost' for table 'user' insert ignore into mysql.user (user, host) values ('someuser', 'somehost'); diff --git a/mysql-test/suite/roles/set_default_role_invalid.result b/mysql-test/suite/roles/set_default_role_invalid.result index 74d517b7c8f..53ee464e2c1 100644 --- a/mysql-test/suite/roles/set_default_role_invalid.result +++ b/mysql-test/suite/roles/set_default_role_invalid.result @@ -24,6 +24,7 @@ Grants for test_user@localhost GRANT test_role TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' GRANT SELECT ON *.* TO 'test_role' +SET DEFAULT ROLE test_role FOR 'test_user'@'localhost' select user, host, default_role from mysql.user where user='test_user'; user host default_role test_user localhost test_role @@ -71,6 +72,7 @@ GRANT r1 TO 'b'@'%' GRANT r2 TO 'b'@'%' GRANT USAGE ON *.* TO 'b'@'%' GRANT SELECT ON `mysql`.* TO 'b'@'%' +SET DEFAULT ROLE r2 FOR 'b'@'%' SET DEFAULT ROLE r1 FOR a; ERROR 42000: Access denied for user 'b'@'%' to database 'mysql' SELECT CURRENT_ROLE; @@ -96,6 +98,7 @@ GRANT r1 TO 'b'@'%' GRANT r2 TO 'b'@'%' GRANT USAGE ON *.* TO 'b'@'%' GRANT SELECT, UPDATE ON `mysql`.* TO 'b'@'%' +SET DEFAULT ROLE r2 FOR 'b'@'%' SET DEFAULT ROLE r1 FOR a; ERROR OP000: User `a@%` has not been granted role `r1` SET DEFAULT ROLE invalid_role; diff --git a/mysql-test/suite/roles/set_default_role_new_connection.result b/mysql-test/suite/roles/set_default_role_new_connection.result index a59ecbd75f7..75e4075ff9e 100644 --- a/mysql-test/suite/roles/set_default_role_new_connection.result +++ b/mysql-test/suite/roles/set_default_role_new_connection.result @@ -23,6 +23,7 @@ Grants for test_user@localhost GRANT test_role TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' GRANT SELECT ON *.* TO 'test_role' +SET DEFAULT ROLE test_role FOR 'test_user'@'localhost' select user, host, default_role from mysql.user where user = 'test_user'; user host default_role test_user localhost test_role @@ -51,6 +52,7 @@ Grants for test_user@localhost GRANT test_role TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' GRANT SELECT ON *.* TO 'test_role' +SET DEFAULT ROLE test_role FOR 'test_user'@'localhost' select user, host, default_role from mysql.user where user = 'test_user'; user host default_role test_user localhost test_role diff --git a/mysql-test/t/grant5.test b/mysql-test/t/grant5.test index 74a69952124..944918e63ec 100644 --- a/mysql-test/t/grant5.test +++ b/mysql-test/t/grant5.test @@ -52,6 +52,24 @@ disconnect u1; drop user u1@localhost; drop database mysqltest1; +# +# MDEV-22313: Neither SHOW CREATE USER nor SHOW GRANTS prints a user's default role +# +CREATE ROLE test_role; +CREATE USER test_user; +GRANT test_role TO test_user; +SET DEFAULT ROLE test_role FOR test_user; +SHOW GRANTS FOR test_user; +SET DEFAULT ROLE NONE for test_user; +SHOW GRANTS FOR test_user; +SET ROLE test_role; +SET DEFAULT ROLE test_role; +SHOW GRANTS; +SET DEFAULT ROLE NONE; +SHOW GRANTS; +DROP USER test_user; +DROP ROLE test_role; + # # End of 10.1 tests # diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 894988c4931..641ab69c2a7 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -353,8 +353,9 @@ static void update_hostname(acl_host_and_ip *host, const char *hostname); static ulong get_sort(uint count,...); static bool show_proxy_grants (THD *, const char *, const char *, char *, size_t); -static bool show_role_grants(THD *, const char *, const char *, +static bool show_role_grants(THD *, const char *, ACL_USER_BASE *, char *, size_t); +static bool show_default_role(THD *, ACL_USER *, char *, size_t); static bool show_global_privileges(THD *, ACL_USER_BASE *, bool, char *, size_t); static bool show_database_privileges(THD *, const char *, const char *, @@ -8531,7 +8532,7 @@ static bool print_grants_for_role(THD *thd, ACL_ROLE * role) { char buff[1024]; - if (show_role_grants(thd, role->user.str, "", role, buff, sizeof(buff))) + if (show_role_grants(thd, "", role, buff, sizeof(buff))) return TRUE; if (show_global_privileges(thd, role, TRUE, buff, sizeof(buff))) @@ -8746,7 +8747,7 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user) } /* Show granted roles to acl_user */ - if (show_role_grants(thd, username, hostname, acl_user, buff, sizeof(buff))) + if (show_role_grants(thd, hostname, acl_user, buff, sizeof(buff))) goto end; /* Add first global access grants */ @@ -8795,6 +8796,14 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user) } } + if (username) + { + /* Show default role to acl_user */ + if (show_default_role(thd, acl_user, buff, sizeof(buff))) + goto end; + } + + error= 0; end: mysql_mutex_unlock(&acl_cache->lock); @@ -8821,15 +8830,44 @@ static ROLE_GRANT_PAIR *find_role_grant_pair(const LEX_STRING *u, my_hash_search(&acl_roles_mappings, (uchar*)pair_key.ptr(), key_length); } -static bool show_role_grants(THD *thd, const char *username, - const char *hostname, ACL_USER_BASE *acl_entry, +static bool show_default_role(THD *thd, ACL_USER *acl_entry, + char *buff, size_t buffsize) +{ + Protocol *protocol= thd->protocol; + LEX_STRING def_rolename= acl_entry->default_rolename; + + if (def_rolename.length) + { + String def_str(buff, buffsize, system_charset_info); + def_str.length(0); + def_str.append(STRING_WITH_LEN("SET DEFAULT ROLE ")); + def_str.append(&def_rolename); + def_str.append(" FOR '"); + def_str.append(&acl_entry->user); + DBUG_ASSERT(!(acl_entry->flags & IS_ROLE)); + def_str.append(STRING_WITH_LEN("'@'")); + def_str.append(acl_entry->host.hostname, acl_entry->hostname_length, + system_charset_info); + def_str.append('\''); + protocol->prepare_for_resend(); + protocol->store(def_str.ptr(),def_str.length(),def_str.charset()); + if (protocol->write()) + { + return TRUE; + } + } + return FALSE; +} + +static bool show_role_grants(THD *thd, const char *hostname, + ACL_USER_BASE *acl_entry, char *buff, size_t buffsize) { uint counter; Protocol *protocol= thd->protocol; LEX_STRING host= {const_cast(hostname), strlen(hostname)}; - String grant(buff,sizeof(buff),system_charset_info); + String grant(buff, buffsize, system_charset_info); for (counter= 0; counter < acl_entry->role_grants.elements; counter++) { grant.length(0); @@ -8873,7 +8911,7 @@ static bool show_global_privileges(THD *thd, ACL_USER_BASE *acl_entry, ulong want_access; Protocol *protocol= thd->protocol; - String global(buff,sizeof(buff),system_charset_info); + String global(buff, buffsize, system_charset_info); global.length(0); global.append(STRING_WITH_LEN("GRANT ")); @@ -8952,7 +8990,7 @@ static bool show_database_privileges(THD *thd, const char *username, want_access=acl_db->initial_access; if (want_access) { - String db(buff,sizeof(buff),system_charset_info); + String db(buff, buffsize, system_charset_info); db.length(0); db.append(STRING_WITH_LEN("GRANT ")); From 987df9b37a2198ab70fb12076fa983d2efe408bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sun, 25 Oct 2020 11:48:34 +0200 Subject: [PATCH 229/323] MDEV-23720 Change innodb_log_optimize_ddl=OFF by default MariaDB 10.2.2 inherited from MySQL 5.7 a perceived optimization of ALTER TABLE, which skips the writing of redo log records. In MDEV-16809 we introduced a parameter that allows the redo log to be written, so that Mariabackup would not be impacted, but we kept the MySQL 5.7 behaviour enabled by default (innodb_log_optimize_ddl=ON). As noted in MDEV-19747 (Deprecate and ignore innodb_log_optimize_ddl, implemented in MariaDB 10.5.1), omitting the redo log writes can actually reduce performance, because we will have to wait for the data pages to be written out. When the redo log file is configured to be large enough, it actually can be much faster to write the redo log and avoid the extra page flushing. When the redo log is omitted (innodb_log_optimize_ddl=ON), also Mariabackup may have to perform a lot of extra work, to re-copy the entire data file if it is possible that any log was omitted during the backup. Starting with MariaDB 10.5.1, the parameter innodb_log_optimize_ddl is deprecated and ignored. We hereby deprecate (but will not ignore) the parameter in earlier versions as well. --- mysql-test/suite/mariabackup/mlog_index_load.result | 1 + mysql-test/suite/mariabackup/mlog_index_load.test | 1 + mysql-test/suite/sys_vars/r/sysvars_innodb.result | 4 ++-- storage/innobase/handler/ha_innodb.cc | 8 ++++---- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/mariabackup/mlog_index_load.result b/mysql-test/suite/mariabackup/mlog_index_load.result index bc83981106e..8925e897399 100644 --- a/mysql-test/suite/mariabackup/mlog_index_load.result +++ b/mysql-test/suite/mariabackup/mlog_index_load.result @@ -1,5 +1,6 @@ CREATE TABLE t1(i INT PRIMARY KEY auto_increment, a int) ENGINE INNODB; INSERT INTO t1(a) SELECT * from seq_1_to_10000; +SET GLOBAL innodb_log_optimize_ddl=ON; # xtrabackup backup t1.frm t1.ibd diff --git a/mysql-test/suite/mariabackup/mlog_index_load.test b/mysql-test/suite/mariabackup/mlog_index_load.test index fb29041fd3c..b9fd6f8ca32 100644 --- a/mysql-test/suite/mariabackup/mlog_index_load.test +++ b/mysql-test/suite/mariabackup/mlog_index_load.test @@ -2,6 +2,7 @@ CREATE TABLE t1(i INT PRIMARY KEY auto_increment, a int) ENGINE INNODB; INSERT INTO t1(a) SELECT * from seq_1_to_10000; +SET GLOBAL innodb_log_optimize_ddl=ON; let $targetdir=$MYSQLTEST_VARDIR/tmp/backup; diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result index bed23a777a8..d3d30f8f53f 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result @@ -1568,10 +1568,10 @@ READ_ONLY YES COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME INNODB_LOG_OPTIMIZE_DDL SESSION_VALUE NULL -DEFAULT_VALUE ON +DEFAULT_VALUE OFF VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BOOLEAN -VARIABLE_COMMENT Reduce redo logging when natively creating indexes or rebuilding tables. Setting this OFF avoids delay due to page flushing and allows concurrent backup. +VARIABLE_COMMENT DEPRECATED. Ignored in MariaDB 10.5. Reduce redo logging when natively creating indexes or rebuilding tables. Enabling this may slow down backup and cause delay due to page flushing. NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 637c66612ce..e36dcbad8ff 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -20245,10 +20245,10 @@ static MYSQL_SYSVAR_BOOL(log_compressed_pages, page_zip_log_pages, static MYSQL_SYSVAR_BOOL(log_optimize_ddl, innodb_log_optimize_ddl, PLUGIN_VAR_OPCMDARG, - "Reduce redo logging when natively creating indexes or rebuilding tables." - " Setting this OFF avoids delay due to page flushing and" - " allows concurrent backup.", - NULL, NULL, TRUE); + "DEPRECATED. Ignored in MariaDB 10.5." + " Reduce redo logging when natively creating indexes or rebuilding tables." + " Enabling this may slow down backup and cause delay due to page flushing.", + NULL, NULL, FALSE); static MYSQL_SYSVAR_ULONG(autoextend_increment, sys_tablespace_auto_extend_increment, From 3ba8f619e42bf8e7239ba03400c7a1a09b115e45 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Sun, 25 Oct 2020 11:47:16 +0530 Subject: [PATCH 230/323] MDEV-23370 innodb_fts.innodb_fts_misc failed in buildbot, server crashed in dict_table_autoinc_destroy This issue is caused by MDEV-22456 ad6171b91cac33e70bb28fa6865488b2c65e858c. Fix involves the backported version of 10.4 patch MDEV-22778 5f2628d1eea21d9732f582b77782b072e5e04014 and few parts of MDEV-17441 (e9a5f288f21c15ec6b4d2dd3d654a320904bb1bf). dict_table_t::stats_latch_created: Removed dict_table_t::stats_latch: make value member and always lock it for simplicity even for stats cloned table. zip_pad_info_t::mutex_created: Removed zip_pad_info_t::mutex: make member value instead of pointer os0once.h: Removed dict_table_remove_from_cache_low(): Ensure that fts_free() is always called, even if dict_mem_table_free() is deferred until btr_search_lazy_free(). InnoDB would always zip_pad_info_t::mutex and dict_table_t::autoinc_mutex, even for tables are not in ROW_FORMAT=COMPRESSED nor include any AUTO_INCREMENT column. --- storage/innobase/dict/dict0dict.cc | 150 +++------------------------ storage/innobase/dict/dict0mem.cc | 42 ++++---- storage/innobase/dict/dict0stats.cc | 10 +- storage/innobase/ibuf/ibuf0ibuf.cc | 2 +- storage/innobase/include/dict0dict.h | 25 +---- storage/innobase/include/dict0mem.h | 118 ++++----------------- storage/innobase/include/os0once.h | 118 --------------------- storage/innobase/page/page0zip.cc | 2 +- 8 files changed, 68 insertions(+), 399 deletions(-) delete mode 100644 storage/innobase/include/os0once.h diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index ba0cb9e4d4e..37a8a4387d1 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -60,7 +60,6 @@ extern uint ibuf_debug; #include "lock0lock.h" #include "mach0data.h" #include "mem0mem.h" -#include "os0once.h" #include "page0page.h" #include "page0zip.h" #include "pars0pars.h" @@ -268,76 +267,6 @@ dict_mutex_exit_for_mysql(void) mutex_exit(&dict_sys->mutex); } -/** Allocate and init a dict_table_t's stats latch. -This function must not be called concurrently on the same table object. -@param[in,out] table_void table whose stats latch to create */ -static -void -dict_table_stats_latch_alloc( - void* table_void) -{ - dict_table_t* table = static_cast(table_void); - - /* Note: rw_lock_create() will call the constructor */ - - table->stats_latch = static_cast( - ut_malloc_nokey(sizeof(rw_lock_t))); - - ut_a(table->stats_latch != NULL); - - rw_lock_create(dict_table_stats_key, table->stats_latch, - SYNC_INDEX_TREE); -} - -/** Deinit and free a dict_table_t's stats latch. -This function must not be called concurrently on the same table object. -@param[in,out] table table whose stats latch to free */ -static -void -dict_table_stats_latch_free( - dict_table_t* table) -{ - rw_lock_free(table->stats_latch); - ut_free(table->stats_latch); -} - -/** Create a dict_table_t's stats latch or delay for lazy creation. -This function is only called from either single threaded environment -or from a thread that has not shared the table object with other threads. -@param[in,out] table table whose stats latch to create -@param[in] enabled if false then the latch is disabled -and dict_table_stats_lock()/unlock() become noop on this table. */ -void -dict_table_stats_latch_create( - dict_table_t* table, - bool enabled) -{ - if (!enabled) { - table->stats_latch = NULL; - table->stats_latch_created = os_once::DONE; - return; - } - - /* We create this lazily the first time it is used. */ - table->stats_latch = NULL; - table->stats_latch_created = os_once::NEVER_DONE; -} - -/** Destroy a dict_table_t's stats latch. -This function is only called from either single threaded environment -or from a thread that has not shared the table object with other threads. -@param[in,out] table table whose stats latch to destroy */ -void -dict_table_stats_latch_destroy( - dict_table_t* table) -{ - if (table->stats_latch_created == os_once::DONE - && table->stats_latch != NULL) { - - dict_table_stats_latch_free(table); - } -} - /** Lock the appropriate latch to protect a given table's statistics. @param[in] table table whose stats to lock @param[in] latch_mode RW_S_LATCH or RW_X_LATCH */ @@ -349,23 +278,12 @@ dict_table_stats_lock( ut_ad(table != NULL); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - os_once::do_or_wait_for_done( - &table->stats_latch_created, - dict_table_stats_latch_alloc, table); - - if (table->stats_latch == NULL) { - /* This is a dummy table object that is private in the current - thread and is not shared between multiple threads, thus we - skip any locking. */ - return; - } - switch (latch_mode) { case RW_S_LATCH: - rw_lock_s_lock(table->stats_latch); + rw_lock_s_lock(&table->stats_latch); break; case RW_X_LATCH: - rw_lock_x_lock(table->stats_latch); + rw_lock_x_lock(&table->stats_latch); break; case RW_NO_LATCH: /* fall through */ @@ -385,19 +303,12 @@ dict_table_stats_unlock( ut_ad(table != NULL); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - if (table->stats_latch == NULL) { - /* This is a dummy table object that is private in the current - thread and is not shared between multiple threads, thus we - skip any locking. */ - return; - } - switch (latch_mode) { case RW_S_LATCH: - rw_lock_s_unlock(table->stats_latch); + rw_lock_s_unlock(&table->stats_latch); break; case RW_X_LATCH: - rw_lock_x_unlock(table->stats_latch); + rw_lock_x_unlock(&table->stats_latch); break; case RW_NO_LATCH: /* fall through */ @@ -737,34 +648,6 @@ dict_table_get_nth_v_col_mysql( return(dict_table_get_nth_v_col(table, i)); } -/** Allocate and init the autoinc latch of a given table. -This function must not be called concurrently on the same table object. -@param[in,out] table_void table whose autoinc latch to create */ -static -void -dict_table_autoinc_alloc( - void* table_void) -{ - dict_table_t* table = static_cast(table_void); - table->autoinc_mutex = UT_NEW_NOKEY(ib_mutex_t()); - ut_a(table->autoinc_mutex != NULL); - mutex_create(LATCH_ID_AUTOINC, table->autoinc_mutex); -} - -/** Allocate and init the zip_pad_mutex of a given index. -This function must not be called concurrently on the same index object. -@param[in,out] index_void index whose zip_pad_mutex to create */ -static -void -dict_index_zip_pad_alloc( - void* index_void) -{ - dict_index_t* index = static_cast(index_void); - index->zip_pad.mutex = UT_NEW_NOKEY(SysMutex()); - ut_a(index->zip_pad.mutex != NULL); - mutex_create(LATCH_ID_ZIP_PAD_MUTEX, index->zip_pad.mutex); -} - /********************************************************************//** Acquire the autoinc lock. */ void @@ -772,11 +655,7 @@ dict_table_autoinc_lock( /*====================*/ dict_table_t* table) /*!< in/out: table */ { - os_once::do_or_wait_for_done( - &table->autoinc_mutex_created, - dict_table_autoinc_alloc, table); - - mutex_enter(table->autoinc_mutex); + mysql_mutex_lock(&table->autoinc_mutex); } /** Acquire the zip_pad_mutex latch. @@ -786,11 +665,7 @@ void dict_index_zip_pad_lock( dict_index_t* index) { - os_once::do_or_wait_for_done( - &index->zip_pad.mutex_created, - dict_index_zip_pad_alloc, index); - - mutex_enter(index->zip_pad.mutex); + mysql_mutex_lock(&index->zip_pad.mutex); } /** Get all the FTS indexes on a table. @@ -825,7 +700,7 @@ dict_table_autoinc_unlock( /*======================*/ dict_table_t* table) /*!< in/out: table */ { - mutex_exit(table->autoinc_mutex); + mysql_mutex_unlock(&table->autoinc_mutex); } /** Looks for column n in an index. @@ -1276,6 +1151,8 @@ dict_table_add_to_cache( dict_table_add_system_columns(table, heap); + mysql_mutex_init(0, &table->autoinc_mutex, NULL); + table->cached = TRUE; fold = ut_fold_string(table->name.m_name); @@ -1419,7 +1296,7 @@ dict_index_t *dict_index_t::clone() const (mem_heap_zalloc(heap, n_uniq * sizeof *stat_n_sample_sizes)); index->stat_n_non_null_key_vals= static_cast (mem_heap_zalloc(heap, n_uniq * sizeof *stat_n_non_null_key_vals)); - memset(&index->zip_pad, 0, sizeof index->zip_pad); + mysql_mutex_init(0, &index->zip_pad.mutex, NULL); return index; } @@ -2133,8 +2010,15 @@ dict_table_remove_from_cache_low( UT_DELETE(table->vc_templ); } + mysql_mutex_destroy(&table->autoinc_mutex); #ifdef BTR_CUR_HASH_ADAPT if (UNIV_UNLIKELY(UT_LIST_GET_LEN(table->freed_indexes) != 0)) { + if (table->fts) { + fts_optimize_remove_table(table); + fts_free(table); + table->fts = NULL; + } + table->vc_templ = NULL; table->id = 0; return; diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index 639fdbac22b..11d362d32c6 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -118,20 +118,15 @@ static bool dict_mem_table_is_system(char *name) } } -/**********************************************************************//** -Creates a table memory object. -@return own: table object */ dict_table_t* dict_mem_table_create( -/*==================*/ - const char* name, /*!< in: table name */ - ulint space, /*!< in: space where the clustered index of - the table is placed */ - ulint n_cols, /*!< in: total number of columns including - virtual and non-virtual columns */ - ulint n_v_cols,/*!< in: number of virtual columns */ - ulint flags, /*!< in: table flags */ - ulint flags2) /*!< in: table flags2 */ + const char* name, + ulint space, + ulint n_cols, + ulint n_v_cols, + ulint flags, + ulint flags2, + bool init_stats_latch) { dict_table_t* table; mem_heap_t* heap; @@ -170,16 +165,9 @@ dict_mem_table_create( table->v_cols = static_cast( mem_heap_alloc(heap, n_v_cols * sizeof(*table->v_cols))); - /* true means that the stats latch will be enabled - - dict_table_stats_lock() will not be noop. */ - dict_table_stats_latch_create(table, true); - table->autoinc_lock = static_cast( mem_heap_alloc(heap, lock_get_size())); - /* lazy creation of table autoinc latch */ - dict_table_autoinc_create_lazy(table); - /* If the table has an FTS index or we are in the process of building one, create the table->fts */ if (dict_table_has_fts_index(table) @@ -194,6 +182,12 @@ dict_mem_table_create( new(&table->foreign_set) dict_foreign_set(); new(&table->referenced_set) dict_foreign_set(); + if (init_stats_latch) { + rw_lock_create(dict_table_stats_key, &table->stats_latch, + SYNC_INDEX_TREE); + table->stats_latch_inited = true; + } + return(table); } @@ -222,9 +216,7 @@ dict_mem_table_free( } } - dict_table_autoinc_destroy(table); dict_mem_table_free_foreign_vcol_set(table); - dict_table_stats_latch_destroy(table); table->foreign_set.~dict_foreign_set(); table->referenced_set.~dict_foreign_set(); @@ -245,6 +237,10 @@ dict_mem_table_free( UT_DELETE(table->s_cols); } + if (table->stats_latch_inited) { + rw_lock_free(&table->stats_latch); + } + mem_heap_free(table->heap); } @@ -767,7 +763,7 @@ dict_mem_index_create( dict_mem_fill_index_struct(index, heap, table_name, index_name, space, type, n_fields); - dict_index_zip_pad_mutex_create_lazy(index); + mysql_mutex_init(0, &index->zip_pad.mutex, NULL); if (type & DICT_SPATIAL) { index->rtr_track = static_cast( @@ -1082,7 +1078,7 @@ dict_mem_index_free( ut_ad(index); ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); - dict_index_zip_pad_mutex_destroy(index); + mysql_mutex_destroy(&index->zip_pad.mutex); if (dict_index_is_spatial(index)) { rtr_info_active::iterator it; diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index 563729cd560..5083fda48ee 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -33,6 +33,7 @@ Created Jan 06, 2010 Vasil Dimov #include "pars0pars.h" #include #include "btr0btr.h" +#include "sync0sync.h" #include #include @@ -418,11 +419,6 @@ dict_stats_table_clone_create( t->corrupted = table->corrupted; - /* This private object "t" is not shared with other threads, so - we do not need the stats_latch (thus we pass false below). The - dict_table_stats_lock()/unlock() routines will do nothing. */ - dict_table_stats_latch_create(t, false); - UT_LIST_INIT(t->indexes, &dict_index_t::indexes); #ifdef BTR_CUR_HASH_ADAPT UT_LIST_INIT(t->freed_indexes, &dict_index_t::indexes); @@ -490,6 +486,8 @@ dict_stats_table_clone_create( ut_d(t->magic_n = DICT_TABLE_MAGIC_N); + rw_lock_create(dict_table_stats_key, &t->stats_latch, SYNC_INDEX_TREE); + return(t); } @@ -502,7 +500,7 @@ dict_stats_table_clone_free( /*========================*/ dict_table_t* t) /*!< in: dummy table object to free */ { - dict_table_stats_latch_destroy(t); + rw_lock_free(&t->stats_latch); mem_heap_free(t->heap); } diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index 7068dab77a4..37666cdf372 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -1447,7 +1447,7 @@ ibuf_dummy_index_create( table = dict_mem_table_create("IBUF_DUMMY", DICT_HDR_SPACE, n, 0, - comp ? DICT_TF_COMPACT : 0, 0); + comp ? DICT_TF_COMPACT : 0, 0, false); index = dict_mem_index_create("IBUF_DUMMY", "IBUF_DUMMY", DICT_HDR_SPACE, 0, n); diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 565ea77374d..49e884d064d 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -302,7 +302,7 @@ UNIV_INLINE void dict_table_autoinc_initialize(dict_table_t* table, ib_uint64_t value) { - ut_ad(dict_table_autoinc_own(table)); + mysql_mutex_assert_owner(&table->autoinc_mutex); table->autoinc = value; } @@ -315,7 +315,7 @@ UNIV_INLINE ib_uint64_t dict_table_autoinc_read(const dict_table_t* table) { - ut_ad(dict_table_autoinc_own(table)); + mysql_mutex_assert_owner(&table->autoinc_mutex); return(table->autoinc); } @@ -329,7 +329,7 @@ UNIV_INLINE bool dict_table_autoinc_update_if_greater(dict_table_t* table, ib_uint64_t value) { - ut_ad(dict_table_autoinc_own(table)); + mysql_mutex_assert_owner(&table->autoinc_mutex); if (value > table->autoinc) { @@ -1524,25 +1524,6 @@ void dict_mutex_exit_for_mysql(void); /*===========================*/ -/** Create a dict_table_t's stats latch or delay for lazy creation. -This function is only called from either single threaded environment -or from a thread that has not shared the table object with other threads. -@param[in,out] table table whose stats latch to create -@param[in] enabled if false then the latch is disabled -and dict_table_stats_lock()/unlock() become noop on this table. */ -void -dict_table_stats_latch_create( - dict_table_t* table, - bool enabled); - -/** Destroy a dict_table_t's stats latch. -This function is only called from either single threaded environment -or from a thread that has not shared the table object with other threads. -@param[in,out] table table whose stats latch to destroy */ -void -dict_table_stats_latch_destroy( - dict_table_t* table); - /** Lock the appropriate latch to protect a given table's statistics. @param[in] table table whose stats to lock @param[in] latch_mode RW_S_LATCH or RW_X_LATCH */ diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index e8005cbc352..3c7913d7f39 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -44,7 +44,6 @@ Created 1/8/1996 Heikki Tuuri #include "fts0fts.h" #include "buf0buf.h" #include "gis0type.h" -#include "os0once.h" #include "fil0fil.h" #include #include "fil0crypt.h" @@ -299,21 +298,27 @@ parent table will fail, and user has to drop excessive foreign constraint before proceeds. */ #define FK_MAX_CASCADE_DEL 15 -/**********************************************************************//** -Creates a table memory object. +/** Creates a table memory object. +@param[in] name table name +@param[in] space space where the clustered index + of the table is placed +@param[in] n_cols total number of columns including + virtual and non-virtual columns +@param[in] n_v_cols number of virtual columns +@param[in] flags table flags +@param[in] flags2 table flags2 +@param[in] init_stats_latch whether to init the stats latch @return own: table object */ dict_table_t* dict_mem_table_create( -/*==================*/ - const char* name, /*!< in: table name */ - ulint space, /*!< in: space where the clustered index - of the table is placed */ - ulint n_cols, /*!< in: total number of columns - including virtual and non-virtual - columns */ - ulint n_v_cols, /*!< in: number of virtual columns */ - ulint flags, /*!< in: table flags */ - ulint flags2); /*!< in: table flags2 */ + const char* name, + ulint space, + ulint n_cols, + ulint n_v_cols, + ulint flags, + ulint flags2, + bool init_stats_latch=true); + /****************************************************************//** Free a table memory object. */ void @@ -792,7 +797,7 @@ extern ulong zip_pad_max; an uncompressed page should be left as padding to avoid compression failures. This estimate is based on a self-adapting heuristic. */ struct zip_pad_info_t { - SysMutex* mutex; /*!< mutex protecting the info */ + mysql_mutex_t mutex; /*!< mutex protecting the info */ ulint pad; /*!< number of bytes used as pad */ ulint success;/*!< successful compression ops during current round */ @@ -800,9 +805,6 @@ struct zip_pad_info_t { current round */ ulint n_rounds;/*!< number of currently successful rounds */ - volatile os_once::state_t - mutex_created; - /*!< Creation state of mutex member */ }; /** Number of samples of data size kept when page compression fails for @@ -1692,7 +1694,7 @@ struct dict_table_t { /** Statistics for query optimization. @{ */ /** Creation state of 'stats_latch'. */ - volatile os_once::state_t stats_latch_created; + bool stats_latch_inited; /** This latch protects: dict_table_t::stat_initialized, @@ -1705,7 +1707,7 @@ struct dict_table_t { dict_table_t::indexes*::stat_n_leaf_pages. (*) Those are not always protected for performance reasons. */ - rw_lock_t* stats_latch; + rw_lock_t stats_latch; /** TRUE if statistics have been calculated the first time after database startup or table creation. */ @@ -1829,11 +1831,8 @@ struct dict_table_t { from a select. */ lock_t* autoinc_lock; - /** Creation state of autoinc_mutex member */ - volatile os_once::state_t autoinc_mutex_created; - /** Mutex protecting the autoincrement counter. */ - ib_mutex_t* autoinc_mutex; + mysql_mutex_t autoinc_mutex; /** Autoinc counter value to give to the next inserted row. */ ib_uint64_t autoinc; @@ -1927,64 +1926,6 @@ struct dict_foreign_add_to_referenced_table { } }; -/** Destroy the autoinc latch of the given table. -This function is only called from either single threaded environment -or from a thread that has not shared the table object with other threads. -@param[in,out] table table whose stats latch to destroy */ -inline -void -dict_table_autoinc_destroy( - dict_table_t* table) -{ - if (table->autoinc_mutex_created == os_once::DONE - && table->autoinc_mutex != NULL) { - mutex_free(table->autoinc_mutex); - UT_DELETE(table->autoinc_mutex); - } -} - -/** Request for lazy creation of the autoinc latch of a given table. -This function is only called from either single threaded environment -or from a thread that has not shared the table object with other threads. -@param[in,out] table table whose autoinc latch is to be created. */ -inline -void -dict_table_autoinc_create_lazy( - dict_table_t* table) -{ - table->autoinc_mutex = NULL; - table->autoinc_mutex_created = os_once::NEVER_DONE; -} - -/** Request a lazy creation of dict_index_t::zip_pad::mutex. -This function is only called from either single threaded environment -or from a thread that has not shared the table object with other threads. -@param[in,out] index index whose zip_pad mutex is to be created */ -inline -void -dict_index_zip_pad_mutex_create_lazy( - dict_index_t* index) -{ - index->zip_pad.mutex = NULL; - index->zip_pad.mutex_created = os_once::NEVER_DONE; -} - -/** Destroy the zip_pad_mutex of the given index. -This function is only called from either single threaded environment -or from a thread that has not shared the table object with other threads. -@param[in,out] table table whose stats latch to destroy */ -inline -void -dict_index_zip_pad_mutex_destroy( - dict_index_t* index) -{ - if (index->zip_pad.mutex_created == os_once::DONE - && index->zip_pad.mutex != NULL) { - mutex_free(index->zip_pad.mutex); - UT_DELETE(index->zip_pad.mutex); - } -} - /** Release the zip_pad_mutex of a given index. @param[in,out] index index whose zip_pad_mutex is to be released */ inline @@ -1992,22 +1933,9 @@ void dict_index_zip_pad_unlock( dict_index_t* index) { - mutex_exit(index->zip_pad.mutex); + mysql_mutex_unlock(&index->zip_pad.mutex); } -#ifdef UNIV_DEBUG -/** Check if the current thread owns the autoinc_mutex of a given table. -@param[in] table the autoinc_mutex belongs to this table -@return true, if the current thread owns the autoinc_mutex, false otherwise.*/ -inline -bool -dict_table_autoinc_own( - const dict_table_t* table) -{ - return(mutex_own(table->autoinc_mutex)); -} -#endif /* UNIV_DEBUG */ - /** Check whether the col is used in spatial index or regular index. @param[in] col column to check @return spatial status */ diff --git a/storage/innobase/include/os0once.h b/storage/innobase/include/os0once.h deleted file mode 100644 index ad72370eefa..00000000000 --- a/storage/innobase/include/os0once.h +++ /dev/null @@ -1,118 +0,0 @@ -/***************************************************************************** - -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 Street, Fifth Floor, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/**************************************************//** -@file include/os0once.h -A class that aids executing a given function exactly once in a multi-threaded -environment. - -Created Feb 20, 2014 Vasil Dimov -*******************************************************/ - -#ifndef os0once_h -#define os0once_h - -#include "univ.i" -#include "ut0ut.h" - -/** Execute a given function exactly once in a multi-threaded environment -or wait for the function to be executed by another thread. - -Example usage: -First the user must create a control variable of type os_once::state_t and -assign it os_once::NEVER_DONE. -Then the user must pass this variable, together with a function to be -executed to os_once::do_or_wait_for_done(). - -Multiple threads can call os_once::do_or_wait_for_done() simultaneously with -the same (os_once::state_t) control variable. The provided function will be -called exactly once and when os_once::do_or_wait_for_done() returns then this -function has completed execution, by this or another thread. In other words -os_once::do_or_wait_for_done() will either execute the provided function or -will wait for its execution to complete if it is already called by another -thread or will do nothing if the function has already completed its execution -earlier. - -This mimics pthread_once(3), but unfortunatelly pthread_once(3) does not -support passing arguments to the init_routine() function. We should use -std::call_once() when we start compiling with C++11 enabled. */ -class os_once { -public: - /** Control variables' state type */ - typedef ib_uint32_t state_t; - - /** Not yet executed. */ - static const state_t NEVER_DONE = 0; - - /** Currently being executed by this or another thread. */ - static const state_t IN_PROGRESS = 1; - - /** Finished execution. */ - static const state_t DONE = 2; - - /** Call a given function or wait its execution to complete if it is - already called by another thread. - @param[in,out] state control variable - @param[in] do_func function to call - @param[in,out] do_func_arg an argument to pass to do_func(). */ - static - void - do_or_wait_for_done( - volatile state_t* state, - void (*do_func)(void*), - void* do_func_arg) - { - int32 oldval = NEVER_DONE; - - /* Avoid calling my_atomic_cas32() in the most common case. */ - if (*state == DONE) { - return; - } - - if (my_atomic_cas32((int32*) state, &oldval, IN_PROGRESS)) { - /* We are the first. Call the function. */ - - do_func(do_func_arg); - - my_atomic_store32((int32*) state, DONE); - } else { - /* The state is not NEVER_DONE, so either it is - IN_PROGRESS (somebody is calling the function right - now or DONE (it has already been called and completed). - Wait for it to become DONE. */ - for (;;) { - const state_t s = *state; - - switch (s) { - case DONE: - return; - case IN_PROGRESS: - break; - case NEVER_DONE: - /* fall through */ - default: - ut_error; - } - - UT_RELAX_CPU(); - } - } - } -}; - -#endif /* os0once_h */ diff --git a/storage/innobase/page/page0zip.cc b/storage/innobase/page/page0zip.cc index c722cdd619a..9664bda6fea 100644 --- a/storage/innobase/page/page0zip.cc +++ b/storage/innobase/page/page0zip.cc @@ -1656,7 +1656,7 @@ page_zip_fields_free( { if (index) { dict_table_t* table = index->table; - dict_index_zip_pad_mutex_destroy(index); + mysql_mutex_destroy(&index->zip_pad.mutex); mem_heap_free(index->heap); dict_mem_table_free(table); From 2fdc50367cb31526a8fe2f5b2c89e71350cd4b32 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 25 Oct 2020 19:18:54 +0100 Subject: [PATCH 231/323] remove disable_abort_on_error from precedence.test was left over from testing --- mysql-test/r/precedence.result | 20 ++++++++------------ mysql-test/t/precedence.test | 9 ++++----- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/mysql-test/r/precedence.result b/mysql-test/r/precedence.result index 7584375061d..34304d980c0 100644 --- a/mysql-test/r/precedence.result +++ b/mysql-test/r/precedence.result @@ -7981,11 +7981,10 @@ create or replace view v1 as select ! BINARY 1, BINARY ! 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition select !cast(1 as char charset binary) AS `! BINARY 1`,cast(!1 as char charset binary) AS `BINARY ! 1` -create or replace view v1 as select ! NOT 1, NOT ! 1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NOT 1, NOT ! 1' at line 1 +create or replace view v1 as select ! (NOT 1), NOT ! 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select !cast(1 as char charset binary) AS `! BINARY 1`,cast(!1 as char charset binary) AS `BINARY ! 1` +select 1 <> 0 AS `! (NOT 1)`,1 <> 0 AS `NOT ! 1` create or replace view v1 as select ! ~ 1, ~ ! 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition @@ -7994,29 +7993,26 @@ create or replace view v1 as select - BINARY 1, BINARY - 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition select -cast(1 as char charset binary) AS `- BINARY 1`,cast(-1 as char charset binary) AS `BINARY - 1` -create or replace view v1 as select - NOT 1, NOT - 1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NOT 1, NOT - 1' at line 1 +create or replace view v1 as select - (NOT 1), NOT - 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select -cast(1 as char charset binary) AS `- BINARY 1`,cast(-1 as char charset binary) AS `BINARY - 1` +select -!1 AS `- (NOT 1)`,!-1 AS `NOT - 1` create or replace view v1 as select - ~ 1, ~ - 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition select -~1 AS `- ~ 1`,~-1 AS `~ - 1` -create or replace view v1 as select BINARY NOT 1, NOT BINARY 1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NOT 1, NOT BINARY 1' at line 1 +create or replace view v1 as select BINARY (NOT 1), NOT BINARY 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select -~1 AS `- ~ 1`,~-1 AS `~ - 1` +select cast(!1 as char charset binary) AS `BINARY (NOT 1)`,!cast(1 as char charset binary) AS `NOT BINARY 1` create or replace view v1 as select BINARY ~ 1, ~ BINARY 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition select cast(~1 as char charset binary) AS `BINARY ~ 1`,~cast(1 as char charset binary) AS `~ BINARY 1` -create or replace view v1 as select NOT ~ 1, ~ NOT 1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NOT 1' at line 1 +create or replace view v1 as select NOT ~ 1, ~ (NOT 1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition -select cast(~1 as char charset binary) AS `BINARY ~ 1`,~cast(1 as char charset binary) AS `~ BINARY 1` +select !~1 AS `NOT ~ 1`,~!1 AS `~ (NOT 1)` create or replace view v1 as select 1 IS TRUE IS FALSE, 2 IS FALSE IS UNKNOWN, 3 IS UNKNOWN IS NULL, 4 IS NULL IS TRUE; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; view_definition diff --git a/mysql-test/t/precedence.test b/mysql-test/t/precedence.test index 28e915a118c..ad367c23603 100644 --- a/mysql-test/t/precedence.test +++ b/mysql-test/t/precedence.test @@ -2,7 +2,6 @@ # A fairly exhastive test for operator precedence # -disable_abort_on_error; disable_warnings; #################### I couldn't come up with a test where precedence changes the result here @@ -4759,7 +4758,7 @@ Select view_definition from information_schema.views where table_schema='test' a create or replace view v1 as select ! BINARY 1, BINARY ! 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; -create or replace view v1 as select ! NOT 1, NOT ! 1; +create or replace view v1 as select ! (NOT 1), NOT ! 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; create or replace view v1 as select ! ~ 1, ~ ! 1; @@ -4768,19 +4767,19 @@ Select view_definition from information_schema.views where table_schema='test' a create or replace view v1 as select - BINARY 1, BINARY - 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; -create or replace view v1 as select - NOT 1, NOT - 1; +create or replace view v1 as select - (NOT 1), NOT - 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; create or replace view v1 as select - ~ 1, ~ - 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; -create or replace view v1 as select BINARY NOT 1, NOT BINARY 1; +create or replace view v1 as select BINARY (NOT 1), NOT BINARY 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; create or replace view v1 as select BINARY ~ 1, ~ BINARY 1; Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; -create or replace view v1 as select NOT ~ 1, ~ NOT 1; +create or replace view v1 as select NOT ~ 1, ~ (NOT 1); Select view_definition from information_schema.views where table_schema='test' and table_name='v1'; create or replace view v1 as select 1 IS TRUE IS FALSE, 2 IS FALSE IS UNKNOWN, 3 IS UNKNOWN IS NULL, 4 IS NULL IS TRUE; From 045671d473609fe1947b1ce7775c4aa2e1a6269b Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Sat, 24 Oct 2020 17:58:19 +1100 Subject: [PATCH 232/323] MDEV-23539: aws key plugin - fails to build Recent gcc/clang versions failed to compile the existing code. Updating a later upstream SDK version was simple and required only implementing a flush method. This was left blank as there was no strong requirement to keep the error log atomic or durable. Reviewed-by: wlad@mariadb.com The upstream SDK version added a flush method which was simple to complete. --- extra/aws_sdk/CMakeLists.txt | 2 +- plugin/aws_key_management/aws_key_management_plugin.cc | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/extra/aws_sdk/CMakeLists.txt b/extra/aws_sdk/CMakeLists.txt index 85a196dccce..7c4b8d8195c 100644 --- a/extra/aws_sdk/CMakeLists.txt +++ b/extra/aws_sdk/CMakeLists.txt @@ -34,7 +34,7 @@ ENDFOREACH() IF(CMAKE_VERSION LESS "3.0") SET(GIT_TAG "1.0.8") ELSE() - SET(GIT_TAG "1.2.11") + SET(GIT_TAG "1.8.29") ENDIF() IF(MSVC_CRT_TYPE MATCHES "/MD") diff --git a/plugin/aws_key_management/aws_key_management_plugin.cc b/plugin/aws_key_management/aws_key_management_plugin.cc index 489dd375387..e2182336aa6 100644 --- a/plugin/aws_key_management/aws_key_management_plugin.cc +++ b/plugin/aws_key_management/aws_key_management_plugin.cc @@ -161,6 +161,10 @@ public: { } + virtual void Flush(void) override + { + } + protected: virtual void ProcessFormattedStatement(Aws::String&& statement) override { From e391417f0fdbd746e23808b3d15d6cbe5a3b0aac Mon Sep 17 00:00:00 2001 From: Sachin Agarwal Date: Mon, 26 Oct 2020 12:21:29 +0200 Subject: [PATCH 233/323] Bug #30933728 INNODB FTS PHRASE SEARCH HIT AN ASSERT Problem: In Full-text phrase search, we filter out row that do not contain all the tokens in the phrase. If we do not filter out doc_id that doesn't appear in all the token's doc_id lists then we hit an assert. Fix: if any of the token has last doc_id equal to ith doc_id of the first token doc_id list then filter out rest of the higher doc_ids. RB: 24909 Reviewed by : Annamalai Gurusami This is a cherry-pick of mysql/mysql-server@5aa075277dfe84a17a0331c57a6fe9b91dafb4cf but without a test case, because the test case depends on an n-gram tokenizer that will be missing from MariaDB until MDEV-10267 is added. --- storage/innobase/fts/fts0que.cc | 35 ++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc index be758c13d52..df2b330fe4b 100644 --- a/storage/innobase/fts/fts0que.cc +++ b/storage/innobase/fts/fts0que.cc @@ -4421,24 +4421,27 @@ fts_phrase_or_proximity_search( if (k == ib_vector_size(query->match_array[j])) { end_list = TRUE; - if (match[j]->doc_id != match[0]->doc_id) { - /* no match */ - if (query->flags & FTS_PHRASE) { - ulint s; - - match[0]->doc_id = 0; - - for (s = i + 1; s < n_matched; - s++) { - match[0] = static_cast< - fts_match_t*>( - ib_vector_get( - query->match_array[0], - s)); - match[0]->doc_id = 0; - } + if (query->flags & FTS_PHRASE) { + ulint s; + /* Since i is the last doc id in the + match_array[j], remove all doc ids > i + from the match_array[0]. */ + fts_match_t* match_temp; + for (s = i + 1; s < n_matched; s++) { + match_temp = static_cast< + fts_match_t*>(ib_vector_get( + query->match_array[0], s)); + match_temp->doc_id = 0; } + if (match[j]->doc_id != + match[0]->doc_id) { + /* no match */ + match[0]->doc_id = 0; + } + } + + if (match[j]->doc_id != match[0]->doc_id) { goto func_exit; } } From 1ff8588c3f1f07e7f6e1b00fb5f485488324cc0a Mon Sep 17 00:00:00 2001 From: Sachin Agarwal Date: Fri, 28 Aug 2020 18:18:25 +0530 Subject: [PATCH 234/323] Bug #31228694 FTS QUERY WITH LIMIT HIT AN ASSERT Problem: 1. The server terminates abnormally when phrase search doesn't filter out doc_ids correctly. This problem has been fixed in bug 2. Wrong query result: It's a regression from the bug #22709692 fix. This fix optimize full-text search query with limit clause. when FTS expression involves only union operation, we fetch only number of doc_ids specified with the limit clause. Fulltext phrase search is not an union operation and we consider phrase search with plugin parser a union operation. In phrase search with limit clause, we fetch limited doc_ids for each token and if any of the selected doc_id does not contain all tokens in correct order then we do not include that row_id in the result set. Therefore phrase search gets fewer number of rows than the qualified rows exist in the table. Fix: Added a condition that phrase search with plugin parser is not a union operation. RB: 24925 Reviewed by : Annamalai Gurusami This is a cherry-pick of mysql/mysql-server@5549920b7a33ef33034461d973a9ecb17ce49799 without a test case, because the test case depends on an n-gram tokenizer that will be missing from MariaDB until MDEV-10267 is added. --- storage/innobase/fts/fts0ast.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/storage/innobase/fts/fts0ast.cc b/storage/innobase/fts/fts0ast.cc index e22613a265b..6be4fb0d52b 100644 --- a/storage/innobase/fts/fts0ast.cc +++ b/storage/innobase/fts/fts0ast.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2020, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -557,8 +557,7 @@ fts_ast_node_check_union( fts_ast_node_t* node) { if (node->type == FTS_AST_LIST - || node->type == FTS_AST_SUBEXP_LIST - || node->type == FTS_AST_PARSER_PHRASE_LIST) { + || node->type == FTS_AST_SUBEXP_LIST) { for (node = node->list.head; node; node = node->next) { if (!fts_ast_node_check_union(node)) { @@ -566,6 +565,9 @@ fts_ast_node_check_union( } } + } else if (node->type == FTS_AST_PARSER_PHRASE_LIST) { + /* Phrase search for plugin parser */ + return(false); } else if (node->type == FTS_AST_OPER && (node->oper == FTS_IGNORE || node->oper == FTS_EXIST)) { From 5999d5120e1548eb07856b1d0f5653923c48a64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 26 Oct 2020 15:04:24 +0200 Subject: [PATCH 235/323] MDEV-23399 fixup: Avoid crash on Mariabackup shutdown innodb_preshutdown(): Terminate the encryption threads before the page cleaner thread can be shut down. innodb_shutdown(): Always wait for the encryption threads and page cleaner to shut down. srv_shutdown_all_bg_threads(): Wait for the encryption threads and the page cleaner to shut down. (After an aborted startup, innodb_shutdown() would not be called.) row_get_background_drop_list_len_low(): Remove. os_thread_count: Remove. Alternatively, at the end of srv_shutdown_all_bg_threads() we could try to wait longer for the count to reach 0. On some platforms, an assertion os_thread_count==0 could fail even after a small delay, even though in the core dump all threads would have exited. srv_shutdown_threads(): Renamed from srv_shutdown_all_bg_threads(). Do not wait for the page cleaner to shut down, because the later innodb_shutdown(), which may invoke logs_empty_and_mark_files_at_shutdown(), assumes that it exists. --- extra/mariabackup/xtrabackup.cc | 12 ++--- storage/innobase/buf/buf0flu.cc | 3 ++ storage/innobase/include/os0thread.h | 3 -- storage/innobase/os/os0thread.cc | 11 ----- storage/innobase/srv/srv0start.cc | 65 +++++++++++----------------- 5 files changed, 32 insertions(+), 62 deletions(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index faa9b6ea45d..76dabdbfca1 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -3418,15 +3418,11 @@ xb_data_files_init() return(xb_load_tablespaces()); } -/************************************************************************ -Destroy the tablespace memory cache. */ -static -void -xb_data_files_close() +/** Destroy the tablespace memory cache. */ +static void xb_data_files_close() { - ut_ad(!os_thread_count); - fil_close_all_files(); - buf_dblwr.close(); + fil_close_all_files(); + buf_dblwr.close(); } /*********************************************************************** diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 0f8084886c1..f982c6daaab 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -1987,7 +1987,10 @@ static os_thread_ret_t DECLARE_THREAD(buf_flush_page_cleaner)(void*) buf_flush_wait_batch_end_acquiring_mutex(false); } + mysql_mutex_lock(&buf_pool.flush_list_mutex); buf_page_cleaner_is_active = false; + mysql_cond_broadcast(&buf_pool.done_flush_list); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); my_thread_end(); /* We count the number of threads in os_thread_exit(). A created diff --git a/storage/innobase/include/os0thread.h b/storage/innobase/include/os0thread.h index fe351732bc7..80a71a41b8d 100644 --- a/storage/innobase/include/os0thread.h +++ b/storage/innobase/include/os0thread.h @@ -66,9 +66,6 @@ typedef void* (*os_posix_f_t) (void*); typedef unsigned int mysql_pfs_key_t; #endif /* HAVE_PSI_INTERFACE */ -/** Number of threads active. */ -extern Atomic_counter os_thread_count; - /***************************************************************//** Compares two thread ids for equality. @return TRUE if equal */ diff --git a/storage/innobase/os/os0thread.cc b/storage/innobase/os/os0thread.cc index 9417a49c6a0..47270c05acf 100644 --- a/storage/innobase/os/os0thread.cc +++ b/storage/innobase/os/os0thread.cc @@ -27,9 +27,6 @@ Created 9/8/1995 Heikki Tuuri #include "univ.i" #include "srv0srv.h" -/** Number of threads active. */ -Atomic_counter os_thread_count; - /***************************************************************//** Compares two thread ids for equality. @return TRUE if equal */ @@ -110,8 +107,6 @@ os_thread_t os_thread_create(os_thread_func_t func, void *arg) CloseHandle(handle); - os_thread_count++; - return((os_thread_t)new_thread_id); #else /* _WIN32 else */ @@ -125,8 +120,6 @@ os_thread_t os_thread_create(os_thread_func_t func, void *arg) abort(); } - os_thread_count++; - ret = pthread_create(&new_thread_id, &attr, func, arg); ut_a(ret == 0); @@ -135,8 +128,6 @@ os_thread_t os_thread_create(os_thread_func_t func, void *arg) #endif /* not _WIN32 */ - ut_a(os_thread_count <= srv_max_n_threads); - return((os_thread_t)new_thread_id); } @@ -152,8 +143,6 @@ ATTRIBUTE_NORETURN void os_thread_exit() pfs_delete_thread(); #endif - os_thread_count--; - #ifdef _WIN32 ExitThread(0); #else diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 5f800d390bf..dda741b5f7b 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -822,11 +822,8 @@ srv_open_tmp_tablespace(bool create_new_db) return(err); } -/** -Shutdown all background threads created by InnoDB. */ -static -void -srv_shutdown_all_bg_threads() +/** Shutdown background threads, except the page cleaner. */ +static void srv_shutdown_threads() { ut_ad(!srv_undo_sources); srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS; @@ -838,38 +835,9 @@ srv_shutdown_all_bg_threads() srv_purge_shutdown(); } - /* All threads end up waiting for certain events. Put those events - to the signaled state. Then the threads will exit themselves after - os_event_wait(). */ - for (uint i = 0; i < 1000; ++i) { - /* NOTE: IF YOU CREATE THREADS IN INNODB, YOU MUST EXIT THEM - HERE OR EARLIER */ - - if (!srv_read_only_mode) { - /* b. srv error monitor thread exits automatically, - no need to do anything here */ - if (srv_n_fil_crypt_threads_started) { - os_event_set(fil_crypt_threads_event); - } - } - - if (buf_page_cleaner_is_active) { - ut_ad(!srv_read_only_mode); - - /* e. Exit the buf_flush_page_cleaner */ - mysql_cond_signal(&buf_pool.do_flush_list); - } - - if (!os_thread_count) { - return; - } - - os_thread_sleep(100000); + if (srv_n_fil_crypt_threads) { + fil_crypt_set_thread_cnt(0); } - - ib::warn() << os_thread_count << " threads created by InnoDB" - " had not exited at shutdown!"; - ut_ad(0); } #ifdef UNIV_DEBUG @@ -916,7 +884,7 @@ srv_init_abort_low( } srv_shutdown_bg_undo_sources(); - srv_shutdown_all_bg_threads(); + srv_shutdown_threads(); return(err); } @@ -1972,9 +1940,10 @@ skip_monitors: /** Shut down background threads that can generate undo log. */ void srv_shutdown_bg_undo_sources() { + srv_shutdown_state = SRV_SHUTDOWN_INITIATED; + if (srv_undo_sources) { ut_ad(!srv_read_only_mode); - srv_shutdown_state = SRV_SHUTDOWN_INITIATED; fts_optimize_shutdown(); dict_stats_shutdown(); while (row_get_background_drop_list_len_low()) { @@ -2010,6 +1979,9 @@ void innodb_preshutdown() } srv_shutdown_bg_undo_sources(); srv_purge_shutdown(); + + if (srv_n_fil_crypt_threads) + fil_crypt_set_thread_cnt(0); } @@ -2020,9 +1992,21 @@ void innodb_shutdown() ut_ad(!srv_undo_sources); switch (srv_operation) { case SRV_OPERATION_BACKUP: - case SRV_OPERATION_RESTORE: case SRV_OPERATION_RESTORE_DELTA: + break; + case SRV_OPERATION_RESTORE: case SRV_OPERATION_RESTORE_EXPORT: + srv_shutdown_state = SRV_SHUTDOWN_CLEANUP; + if (!buf_page_cleaner_is_active) { + break; + } + mysql_mutex_lock(&buf_pool.flush_list_mutex); + while (buf_page_cleaner_is_active) { + mysql_cond_signal(&buf_pool.do_flush_list); + mysql_cond_wait(&buf_pool.done_flush_list, + &buf_pool.flush_list_mutex); + } + mysql_mutex_unlock(&buf_pool.flush_list_mutex); break; case SRV_OPERATION_NORMAL: /* Shut down the persistent files. */ @@ -2032,7 +2016,8 @@ void innodb_shutdown() os_aio_free(); fil_close_all_files(); /* Exit any remaining threads. */ - srv_shutdown_all_bg_threads(); + ut_ad(!buf_page_cleaner_is_active); + srv_shutdown_threads(); if (srv_monitor_file) { my_fclose(srv_monitor_file, MYF(MY_WME)); From 59a0236da4810a5ae243e77cb7a9c6262639a6e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 16 Oct 2020 14:38:07 +0300 Subject: [PATCH 236/323] Cleanup: Speed up mariabackup --prepare srv_start(): Avoid trx_lists_init_at_db_start() for normal mariabackup --prepare without --export. --- storage/innobase/srv/srv0start.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index dda741b5f7b..f7fd1a3cec0 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1463,6 +1463,9 @@ file_checked: if (err != DB_SUCCESS) { return srv_init_abort(err); } + if (srv_operation == SRV_OPERATION_RESTORE) { + break; + } trx_lists_init_at_db_start(); break; case SRV_OPERATION_RESTORE_DELTA: From 31cde275c26ba5009d16dfc62654884b94b22322 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 20 Oct 2020 20:10:40 +0300 Subject: [PATCH 237/323] MDEV-23356 InnoDB: Failing assertion: field->col->mtype == type, crash or ASAN failures in row_sel_convert_mysql_key_to_innobase, InnoDB indexes are inconsistent after INDEX changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit innobase_rename_indexes_cache(): fix corruption of index cache. Index ids help distinguish indexes when their names clash. innobase_rename_indexes_cache(): fix corruption of index statistics table. Use unique temporary names to avoid names clashing. Reviewed by: Marko Mäkelä --- .../r/instant_alter_index_rename.result | 36 +++++++++ .../innodb/t/instant_alter_index_rename.test | 20 +++++ storage/innobase/handler/handler0alter.cc | 73 +++++++++++++++---- 3 files changed, 114 insertions(+), 15 deletions(-) diff --git a/mysql-test/suite/innodb/r/instant_alter_index_rename.result b/mysql-test/suite/innodb/r/instant_alter_index_rename.result index 69f7cc8df4c..41dec275d90 100644 --- a/mysql-test/suite/innodb/r/instant_alter_index_rename.result +++ b/mysql-test/suite/innodb/r/instant_alter_index_rename.result @@ -198,3 +198,39 @@ Table Op Msg_type Msg_text test.t1 check status OK DROP TABLE t1; DROP FUNCTION get_index_id; +# +# MDEV-23356 InnoDB: Failing assertion: field->col->mtype == type, crash or ASAN failures in row_sel_convert_mysql_key_to_innobase, InnoDB indexes are inconsistent after INDEX changes +# +CREATE TABLE t1 (a INT, b INT, c CHAR(8), +KEY ind1(c), KEY ind2(b)) ENGINE=InnoDB STATS_PERSISTENT=1; +INSERT INTO t1 SELECT 1, 1, 'a' FROM seq_1_to_100; +SELECT table_name, index_name, stat_name FROM mysql.innodb_index_stats; +table_name index_name stat_name +t1 GEN_CLUST_INDEX n_diff_pfx01 +t1 GEN_CLUST_INDEX n_leaf_pages +t1 GEN_CLUST_INDEX size +t1 ind1 n_diff_pfx01 +t1 ind1 n_diff_pfx02 +t1 ind1 n_leaf_pages +t1 ind1 size +t1 ind2 n_diff_pfx01 +t1 ind2 n_diff_pfx02 +t1 ind2 n_leaf_pages +t1 ind2 size +ALTER TABLE t1 DROP INDEX ind2, ADD INDEX ind3(b), +DROP INDEX ind1, ADD INDEX ind2(c); +SELECT table_name, index_name, stat_name FROM mysql.innodb_index_stats; +table_name index_name stat_name +t1 GEN_CLUST_INDEX n_diff_pfx01 +t1 GEN_CLUST_INDEX n_leaf_pages +t1 GEN_CLUST_INDEX size +t1 ind2 n_diff_pfx01 +t1 ind2 n_diff_pfx02 +t1 ind2 n_leaf_pages +t1 ind2 size +t1 ind3 n_diff_pfx01 +t1 ind3 n_diff_pfx02 +t1 ind3 n_leaf_pages +t1 ind3 size +UPDATE t1 SET a = 1 WHERE c = 'foo'; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/instant_alter_index_rename.test b/mysql-test/suite/innodb/t/instant_alter_index_rename.test index dd6cee7c860..af66c1027cc 100644 --- a/mysql-test/suite/innodb/t/instant_alter_index_rename.test +++ b/mysql-test/suite/innodb/t/instant_alter_index_rename.test @@ -1,5 +1,6 @@ --source include/have_innodb.inc --source include/have_debug.inc +--source include/have_sequence.inc delimiter |; create function get_index_id(tbl_id int, index_name char(100)) @@ -207,3 +208,22 @@ CHECK TABLE t1 EXTENDED ; DROP TABLE t1; DROP FUNCTION get_index_id; + +--echo # +--echo # MDEV-23356 InnoDB: Failing assertion: field->col->mtype == type, crash or ASAN failures in row_sel_convert_mysql_key_to_innobase, InnoDB indexes are inconsistent after INDEX changes +--echo # + +CREATE TABLE t1 (a INT, b INT, c CHAR(8), + KEY ind1(c), KEY ind2(b)) ENGINE=InnoDB STATS_PERSISTENT=1; + +INSERT INTO t1 SELECT 1, 1, 'a' FROM seq_1_to_100; + +SELECT table_name, index_name, stat_name FROM mysql.innodb_index_stats; + +ALTER TABLE t1 DROP INDEX ind2, ADD INDEX ind3(b), + DROP INDEX ind1, ADD INDEX ind2(c); + +SELECT table_name, index_name, stat_name FROM mysql.innodb_index_stats; + +UPDATE t1 SET a = 1 WHERE c = 'foo'; +DROP TABLE t1; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index fef2d9650c0..5700bdcacb6 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -57,6 +57,8 @@ Smart ALTER TABLE #include "ha_innodb.h" #include "ut0stage.h" #include "span.h" +#include +#include using st_::span; /** File format constraint for ALTER TABLE */ @@ -7450,23 +7452,29 @@ innobase_rename_index_cache(dict_index_t* index, const char* new_name) /** Rename the index name in cache. @param[in] ctx alter context @param[in] ha_alter_info Data used during inplace alter. */ -static void innobase_rename_indexes_cache( - const ha_innobase_inplace_ctx* ctx, - const Alter_inplace_info* ha_alter_info) +static void +innobase_rename_indexes_cache(const ha_innobase_inplace_ctx *ctx, + const Alter_inplace_info *ha_alter_info) { - DBUG_ASSERT(ha_alter_info->handler_flags & ALTER_RENAME_INDEX); + DBUG_ASSERT(ha_alter_info->handler_flags & ALTER_RENAME_INDEX); - for (const Alter_inplace_info::Rename_key_pair& pair : - ha_alter_info->rename_keys) { - dict_index_t* index = dict_table_get_index_on_name( - ctx->old_table, pair.old_key->name.str); - ut_ad(index); + std::vector> rename_info; + rename_info.reserve(ha_alter_info->rename_keys.size()); - innobase_rename_index_cache(index, pair.new_key->name.str); - } + for (const Alter_inplace_info::Rename_key_pair &pair : + ha_alter_info->rename_keys) + { + dict_index_t *index= + dict_table_get_index_on_name(ctx->old_table, pair.old_key->name.str); + ut_ad(index); + + rename_info.emplace_back(index, pair.new_key->name.str); + } + + for (const auto &pair : rename_info) + innobase_rename_index_cache(pair.first, pair.second); } - /** Fill the stored column information in s_cols list. @param[in] altered_table mysql table object @param[in] table innodb table object @@ -10600,11 +10608,18 @@ alter_stats_norebuild( } } - for (const Alter_inplace_info::Rename_key_pair& pair : - ha_alter_info->rename_keys) { + for (size_t i = 0; i < ha_alter_info->rename_keys.size(); i++) { + const Alter_inplace_info::Rename_key_pair& pair + = ha_alter_info->rename_keys[i]; + + std::stringstream ss; + ss << TEMP_FILE_PREFIX_INNODB << std::this_thread::get_id() + << i; + auto tmp_name = ss.str(); + dberr_t err = dict_stats_rename_index(ctx->new_table, pair.old_key->name.str, - pair.new_key->name.str); + tmp_name.c_str()); if (err != DB_SUCCESS) { push_warning_printf( @@ -10616,6 +10631,34 @@ alter_stats_norebuild( " statistics storage: %s", ctx->new_table->name.m_name, pair.old_key->name.str, + tmp_name.c_str(), + ut_strerr(err)); + } + } + + for (size_t i = 0; i < ha_alter_info->rename_keys.size(); i++) { + const Alter_inplace_info::Rename_key_pair& pair + = ha_alter_info->rename_keys[i]; + + std::stringstream ss; + ss << TEMP_FILE_PREFIX_INNODB << std::this_thread::get_id() + << i; + auto tmp_name = ss.str(); + + dberr_t err = dict_stats_rename_index(ctx->new_table, + tmp_name.c_str(), + pair.new_key->name.str); + + if (err != DB_SUCCESS) { + push_warning_printf( + thd, + Sql_condition::WARN_LEVEL_WARN, + ER_ERROR_ON_RENAME, + "Error renaming an index of table '%s'" + " from '%s' to '%s' in InnoDB persistent" + " statistics storage: %s", + ctx->new_table->name.m_name, + tmp_name.c_str(), pair.new_key->name.str, ut_strerr(err)); } From bd67cb92846cfac49c5e4afe72ed9884176854dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 26 Oct 2020 17:07:17 +0200 Subject: [PATCH 238/323] MDEV-23399 fixup: Assertion bpage->in_file() failed buf_flush_remove_pages(), buf_flush_dirty_pages(): Because buf_page_t::state() is protected by buf_pool.mutex, which we are not holding, the state may be BUF_BLOCK_REMOVE_HASH when the page is being relocated. Let us relax these assertions similar to buf_flush_validate_low(). The other in_file() assertions in buf0flu.cc look valid. --- storage/innobase/buf/buf0flu.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index f982c6daaab..da25b825e7e 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -204,7 +204,9 @@ void buf_flush_remove_pages(ulint id) for (buf_page_t *bpage= UT_LIST_GET_LAST(buf_pool.flush_list); bpage; ) { - ut_ad(bpage->in_file()); + ut_d(const auto s= bpage->state()); + ut_ad(s == BUF_BLOCK_ZIP_PAGE || s == BUF_BLOCK_FILE_PAGE || + s == BUF_BLOCK_REMOVE_HASH); buf_page_t *prev= UT_LIST_GET_PREV(list, bpage); const page_id_t bpage_id(bpage->id()); @@ -246,7 +248,9 @@ ulint buf_flush_dirty_pages(ulint id) for (buf_page_t *bpage= UT_LIST_GET_FIRST(buf_pool.flush_list); bpage; bpage= UT_LIST_GET_NEXT(list, bpage)) { - ut_ad(bpage->in_file()); + ut_d(const auto s= bpage->state()); + ut_ad(s == BUF_BLOCK_ZIP_PAGE || s == BUF_BLOCK_FILE_PAGE || + s == BUF_BLOCK_REMOVE_HASH); ut_ad(bpage->oldest_modification()); if (id == bpage->id().space()) n++; @@ -2058,8 +2062,9 @@ static void buf_flush_validate_low() original descriptor can have this state and still be in the flush list waiting to acquire the buf_pool.flush_list_mutex to complete the relocation. */ - ut_ad(bpage->in_file() - || bpage->state() == BUF_BLOCK_REMOVE_HASH); + ut_d(const auto s= bpage->state()); + ut_ad(s == BUF_BLOCK_ZIP_PAGE || s == BUF_BLOCK_FILE_PAGE + || s == BUF_BLOCK_REMOVE_HASH); ut_ad(om > 0); bpage = UT_LIST_GET_NEXT(list, bpage); From 3a9a3be1c64b14c05648e87ebe0f1dd96457de41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 26 Oct 2020 16:35:47 +0200 Subject: [PATCH 239/323] MDEV-23855: Improve InnoDB log checkpoint performance After MDEV-15053, MDEV-22871, MDEV-23399 shifted the scalability bottleneck, log checkpoints became a new bottleneck. If innodb_io_capacity is set low or innodb_max_dirty_pct_lwm is set high and the workload fits in the buffer pool, the page cleaner thread will perform very little flushing. When we reach the capacity of the circular redo log file ib_logfile0 and must initiate a checkpoint, some 'furious flushing' will be necessary. (If innodb_flush_sync=OFF, then flushing would continue at the innodb_io_capacity rate, and writers would be throttled.) We have the best chance of advancing the checkpoint LSN immediately after a page flush batch has been completed. Hence, it is best to perform checkpoints after every batch in the page cleaner thread, attempting to run once per second. By initiating high-priority flushing in the page cleaner as early as possible, we aim to make the throughput more stable. The function buf_flush_wait_flushed() used to sleep for 10ms, hoping that the page cleaner thread would do something during that time. The observed end result was that a large number of threads that call log_free_check() would end up sleeping while nothing useful is happening. We will revise the design so that in the default innodb_flush_sync=ON mode, buf_flush_wait_flushed() will wake up the page cleaner thread to perform the necessary flushing, and it will wait for a signal from the page cleaner thread. If innodb_io_capacity is set to a low value (causing the page cleaner to throttle its work), a write workload would initially perform well, until the capacity of the circular ib_logfile0 is reached and log_free_check() will trigger checkpoints. At that point, the extra waiting in buf_flush_wait_flushed() will start reducing throughput. The page cleaner thread will also initiate log checkpoints after each buf_flush_lists() call, because that is the best point of time for the checkpoint LSN to advance by the maximum amount. Even in 'furious flushing' mode we invoke buf_flush_lists() with innodb_io_capacity_max pages at a time, and at the start of each batch (in the log_flush() callback function that runs in a separate task) we will invoke os_aio_wait_until_no_pending_writes(). This tweak allows the checkpoint to advance in smaller steps and significantly reduces the maximum latency. On an Intel Optane 960 NVMe SSD on Linux, it reduced from 4.6 seconds to 74 milliseconds. On Microsoft Windows with a slower SSD, it reduced from more than 180 seconds to 0.6 seconds. We will make innodb_adaptive_flushing=OFF simply flush innodb_io_capacity per second whenever the dirty proportion of buffer pool pages exceeds innodb_max_dirty_pages_pct_lwm. For innodb_adaptive_flushing=ON we try to make page_cleaner_flush_pages_recommendation() more consistent and predictable: if we are below innodb_adaptive_flushing_lwm, let us flush pages according to the return value of af_get_pct_for_dirty(). innodb_max_dirty_pages_pct_lwm: Revert the change of the default value that was made in MDEV-23399. The value innodb_max_dirty_pages_pct_lwm=0 guarantees that a shutdown of an idle server will be fast. Users might be surprised if normal shutdown suddenly became slower when upgrading within a GA release series. innodb_checkpoint_usec: Remove. The master task will no longer perform periodic log checkpoints. It is the duty of the page cleaner thread. log_sys.max_modified_age: Remove. The current span of the buf_pool.flush_list expressed in LSN only matters for adaptive flushing (outside the 'furious flushing' condition). For the correctness of checkpoints, the only thing that matters is the checkpoint age (log_sys.lsn - log_sys.last_checkpoint_lsn). This run-time constant was also reported as log_max_modified_age_sync. log_sys.max_checkpoint_age_async: Remove. This does not serve any purpose, because the checkpoints will now be triggered by the page cleaner thread. We will retain the log_sys.max_checkpoint_age limit for engaging 'furious flushing'. page_cleaner.slot: Remove. It turns out that page_cleaner_slot.flush_list_time was duplicating page_cleaner.slot.flush_time and page_cleaner.slot.flush_list_pass was duplicating page_cleaner.flush_pass. Likewise, there were some redundant monitor counters, because the page cleaner thread no longer performs any buf_pool.LRU flushing, and because there only is one buf_flush_page_cleaner thread. buf_flush_sync_lsn: Protect writes by buf_pool.flush_list_mutex. buf_pool_t::get_oldest_modification(): Add a parameter to specify the return value when no persistent data pages are dirty. Require the caller to hold buf_pool.flush_list_mutex. log_buf_pool_get_oldest_modification(): Take the fall-back LSN as a parameter. All callers will also invoke log_sys.get_lsn(). log_preflush_pool_modified_pages(): Replaced with buf_flush_wait_flushed(). buf_flush_wait_flushed(): Implement two limits. If not enough buffer pool has been flushed, signal the page cleaner (unless innodb_flush_sync=OFF) and wait for the page cleaner to complete. If the page cleaner thread is not running (which can be the case durign shutdown), initiate the flush and wait for it directly. buf_flush_ahead(): If innodb_flush_sync=ON (the default), submit a new buf_flush_sync_lsn target for the page cleaner but do not wait for the flushing to finish. log_get_capacity(), log_get_max_modified_age_async(): Remove, to make it easier to see that af_get_pct_for_lsn() is not acquiring any mutexes. page_cleaner_flush_pages_recommendation(): Protect all access to buf_pool.flush_list with buf_pool.flush_list_mutex. Previously there were some race conditions in the calculation. buf_flush_sync_for_checkpoint(): New function to process buf_flush_sync_lsn in the page cleaner thread. At the end of each batch, we try to wake up any blocked buf_flush_wait_flushed(). If everything up to buf_flush_sync_lsn has been flushed, we will reset buf_flush_sync_lsn=0. The page cleaner thread will keep 'furious flushing' until the limit is reached. Any threads that are waiting in buf_flush_wait_flushed() will be able to resume as soon as their own limit has been satisfied. buf_flush_page_cleaner: Prioritize buf_flush_sync_lsn and do not sleep as long as it is set. Do not update any page_cleaner statistics for this special mode of operation. In the normal mode (buf_flush_sync_lsn is not set for innodb_flush_sync=ON), try to wake up once per second. No longer check whether srv_inc_activity_count() has been called. After each batch, try to perform a log checkpoint, because the best chances for the checkpoint LSN to advance by the maximum amount are upon completing a flushing batch. log_t: Move buf_free, max_buf_free possibly to the same cache line with log_sys.mutex. log_margin_checkpoint_age(): Simplify the logic, and replace a 0.1-second sleep with a call to buf_flush_wait_flushed() to initiate flushing. Moved to the same compilation unit with the only caller. log_close(): Clean up the calculations. (Should be no functional change.) Return whether flush-ahead is needed. Moved to the same compilation unit with the only caller. mtr_t::finish_write(): Return whether flush-ahead is needed. mtr_t::commit(): Invoke buf_flush_ahead() when needed. Let us avoid external calls in mtr_t::commit() and make the logic easier to follow by having related code in a single compilation unit. Also, we will invoke srv_stats.log_write_requests.inc() only once per mini-transaction commit, while not holding mutexes. log_checkpoint_margin(): Only care about log_sys.max_checkpoint_age. Upon reaching log_sys.max_checkpoint_age where we must wait to prevent the log from getting corrupted, let us wait for at most 1MiB of LSN at a time, before rechecking the condition. This should allow writers to proceed even if the redo log capacity has been reached and 'furious flushing' is in progress. We no longer care about log_sys.max_modified_age_sync or log_sys.max_modified_age_async. The log_sys.max_modified_age_sync could be a relic from the time when there was a srv_master_thread that wrote dirty pages to data files. Also, we no longer have any log_sys.max_checkpoint_age_async limit, because log checkpoints will now be triggered by the page cleaner thread upon completing buf_flush_lists(). log_set_capacity(): Simplify the calculations of the limit (no functional change). log_checkpoint_low(): Split from log_checkpoint(). Moved to the same compilation unit with the caller. log_make_checkpoint(): Only wait for everything to be flushed until the current LSN. create_log_file(): After checkpoint, invoke log_write_up_to() to ensure that the FILE_CHECKPOINT record has been written. This avoids ut_ad(!srv_log_file_created) in create_log_file_rename(). srv_start(): Do not call recv_recovery_from_checkpoint_start() if the log has just been created. Set fil_system.space_id_reuse_warned before dict_boot() has been executed, and clear it after recovery has finished. dict_boot(): Initialize fil_system.max_assigned_id. srv_check_activity(): Remove. The activity count is counting transaction commits and therefore mostly interesting for the purge of history. BtrBulk::insert(): Do not explicitly wake up the page cleaner, but do invoke srv_inc_activity_count(), because that counter is still being used in buf_load_throttle_if_needed() for some heuristics. (It might be cleaner to execute buf_load() in the page cleaner thread!) Reviewed by: Vladislav Vaintroub --- extra/mariabackup/xtrabackup.cc | 1 + mysql-test/suite/innodb/r/innodb_scrub.result | 2 + .../r/innodb_skip_innodb_is_tables.result | 8 +- mysql-test/suite/innodb/r/monitor.result | 8 +- .../r/redo_log_during_checkpoint.result | 1 + mysql-test/suite/innodb/t/innodb_scrub.test | 2 + .../innodb/t/redo_log_during_checkpoint.test | 1 + .../r/innodb_max_dirty_pages_pct_basic.result | 4 +- ...nnodb_max_dirty_pages_pct_lwm_basic.result | 8 +- .../suite/sys_vars/r/sysvars_innodb.result | 2 +- storage/innobase/btr/btr0bulk.cc | 4 - storage/innobase/buf/buf0buf.cc | 28 +- storage/innobase/buf/buf0dump.cc | 6 + storage/innobase/buf/buf0flu.cc | 793 +++++++++++------- storage/innobase/buf/buf0rea.cc | 4 + storage/innobase/dict/dict0boot.cc | 5 + storage/innobase/fil/fil0fil.cc | 1 - storage/innobase/handler/ha_innodb.cc | 2 +- storage/innobase/include/buf0buf.h | 14 +- storage/innobase/include/buf0flu.h | 15 +- storage/innobase/include/log0log.h | 85 +- storage/innobase/include/log0log.ic | 12 - storage/innobase/include/mtr0mtr.h | 4 +- storage/innobase/include/srv0mon.h | 8 +- storage/innobase/include/srv0srv.h | 6 - storage/innobase/log/log0log.cc | 626 +------------- storage/innobase/mtr/mtr0mtr.cc | 237 +++++- storage/innobase/srv/srv0mon.cc | 45 +- storage/innobase/srv/srv0srv.cc | 51 +- storage/innobase/srv/srv0start.cc | 16 +- .../r/innodb_i_s_tables_disabled.result | 8 +- 31 files changed, 826 insertions(+), 1181 deletions(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 76dabdbfca1..3189bcd14cb 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -3011,6 +3011,7 @@ void xb_fil_io_init() { fil_system.create(srv_file_per_table ? 50000 : 5000); + fil_system.space_id_reuse_warned = true; } static diff --git a/mysql-test/suite/innodb/r/innodb_scrub.result b/mysql-test/suite/innodb/r/innodb_scrub.result index f783b9f167c..1a4db0b541e 100644 --- a/mysql-test/suite/innodb/r/innodb_scrub.result +++ b/mysql-test/suite/innodb/r/innodb_scrub.result @@ -6,5 +6,7 @@ UNLOCK TABLES; FOUND 500500 /unicycle|repairman/ in t1.ibd DELETE FROM t1; InnoDB 0 transactions not purged +FLUSH TABLE t1 FOR EXPORT; +UNLOCK TABLES; NOT FOUND /unicycle|repairman/ in t1.ibd DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/innodb_skip_innodb_is_tables.result b/mysql-test/suite/innodb/r/innodb_skip_innodb_is_tables.result index 6a597a919e1..775bbc017a1 100644 --- a/mysql-test/suite/innodb/r/innodb_skip_innodb_is_tables.result +++ b/mysql-test/suite/innodb/r/innodb_skip_innodb_is_tables.result @@ -89,12 +89,8 @@ buffer_flush_neighbor buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NU buffer_flush_neighbor_pages buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_member Pages queued as a neighbor batch buffer_flush_n_to_flush_requested buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of pages requested for flushing. buffer_flush_n_to_flush_by_age buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of pages target by LSN Age for flushing. -buffer_flush_adaptive_avg_time_slot buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for adaptive flushing recently per slot. -buffer_flush_adaptive_avg_time_thread buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for adaptive flushing recently per thread. -buffer_flush_adaptive_avg_time_est buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Estimated time (ms) spent for adaptive flushing recently. -buffer_flush_avg_time buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for flushing recently. +buffer_flush_adaptive_avg_time buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for adaptive flushing recently. buffer_flush_adaptive_avg_pass buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of adaptive flushes passed during the recent Avg period. -buffer_flush_avg_pass buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of flushes passed during the recent Avg period. buffer_LRU_get_free_loops buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Total loops in LRU get free. buffer_LRU_get_free_waits buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Total sleep waits in LRU get free. buffer_flush_avg_page_rate buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Average number of pages at which flushing is happening @@ -194,7 +190,6 @@ log_lsn_current recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 log_lsn_checkpoint_age recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value Current LSN value minus LSN at last checkpoint log_lsn_buf_pool_oldest recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value The oldest modified block LSN in the buffer pool log_max_modified_age_async recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value Maximum LSN difference; when exceeded, start asynchronous preflush -log_max_modified_age_sync recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value Maximum LSN difference; when exceeded, start synchronous preflush log_pending_log_flushes recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value Pending log flushes log_pending_checkpoint_writes recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value Pending checkpoints log_num_log_io recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value Number of log I/Os @@ -245,7 +240,6 @@ innodb_log_flush_usec server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NU innodb_dict_lru_usec server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Time (in microseconds) spent to process DICT LRU list innodb_dict_lru_count_active server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of tables evicted from DICT LRU list in the active loop innodb_dict_lru_count_idle server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of tables evicted from DICT LRU list in the idle loop -innodb_checkpoint_usec server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Time (in microseconds) spent by master thread to do checkpoint innodb_dblwr_writes server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 status_counter Number of doublewrite operations that have been performed (innodb_dblwr_writes) innodb_dblwr_pages_written server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 status_counter Number of pages that have been written for doublewrite operations (innodb_dblwr_pages_written) innodb_page_size server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value InnoDB page size in bytes (innodb_page_size) diff --git a/mysql-test/suite/innodb/r/monitor.result b/mysql-test/suite/innodb/r/monitor.result index 4aeab1a8402..7bdcf7acb45 100644 --- a/mysql-test/suite/innodb/r/monitor.result +++ b/mysql-test/suite/innodb/r/monitor.result @@ -55,12 +55,8 @@ buffer_flush_neighbor disabled buffer_flush_neighbor_pages disabled buffer_flush_n_to_flush_requested disabled buffer_flush_n_to_flush_by_age disabled -buffer_flush_adaptive_avg_time_slot disabled -buffer_flush_adaptive_avg_time_thread disabled -buffer_flush_adaptive_avg_time_est disabled -buffer_flush_avg_time disabled +buffer_flush_adaptive_avg_time disabled buffer_flush_adaptive_avg_pass disabled -buffer_flush_avg_pass disabled buffer_LRU_get_free_loops disabled buffer_LRU_get_free_waits disabled buffer_flush_avg_page_rate disabled @@ -160,7 +156,6 @@ log_lsn_current disabled log_lsn_checkpoint_age disabled log_lsn_buf_pool_oldest disabled log_max_modified_age_async disabled -log_max_modified_age_sync disabled log_pending_log_flushes disabled log_pending_checkpoint_writes disabled log_num_log_io disabled @@ -211,7 +206,6 @@ innodb_log_flush_usec disabled innodb_dict_lru_usec disabled innodb_dict_lru_count_active disabled innodb_dict_lru_count_idle disabled -innodb_checkpoint_usec disabled innodb_dblwr_writes disabled innodb_dblwr_pages_written disabled innodb_page_size disabled diff --git a/mysql-test/suite/innodb/r/redo_log_during_checkpoint.result b/mysql-test/suite/innodb/r/redo_log_during_checkpoint.result index 3915b07f12e..c7b4bb4403b 100644 --- a/mysql-test/suite/innodb/r/redo_log_during_checkpoint.result +++ b/mysql-test/suite/innodb/r/redo_log_during_checkpoint.result @@ -10,6 +10,7 @@ set global innodb_log_checkpoint_now = 1; ERROR HY000: Lost connection to MySQL server during query # Skip MLOG_FILE_NAME redo records during recovery DROP DATABASE very_long_database_name; +SET GLOBAL innodb_flush_sync=OFF; SET GLOBAL innodb_page_cleaner_disabled_debug = 1; SET GLOBAL innodb_dict_stats_disabled_debug = 1; SET GLOBAL innodb_master_thread_disabled_debug = 1; diff --git a/mysql-test/suite/innodb/t/innodb_scrub.test b/mysql-test/suite/innodb/t/innodb_scrub.test index c1b7fb4df1d..88b4e9cfd76 100644 --- a/mysql-test/suite/innodb/t/innodb_scrub.test +++ b/mysql-test/suite/innodb/t/innodb_scrub.test @@ -22,5 +22,7 @@ let SEARCH_FILE= $MYSQLD_DATADIR/test/t1.ibd; -- source include/search_pattern_in_file.inc DELETE FROM t1; -- source include/wait_all_purged.inc +FLUSH TABLE t1 FOR EXPORT; +UNLOCK TABLES; -- source include/search_pattern_in_file.inc DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/redo_log_during_checkpoint.test b/mysql-test/suite/innodb/t/redo_log_during_checkpoint.test index 645ae8c7855..85beb3ee1d2 100644 --- a/mysql-test/suite/innodb/t/redo_log_during_checkpoint.test +++ b/mysql-test/suite/innodb/t/redo_log_during_checkpoint.test @@ -44,6 +44,7 @@ set global innodb_log_checkpoint_now = 1; DROP DATABASE very_long_database_name; +SET GLOBAL innodb_flush_sync=OFF; SET GLOBAL innodb_page_cleaner_disabled_debug = 1; SET GLOBAL innodb_dict_stats_disabled_debug = 1; SET GLOBAL innodb_master_thread_disabled_debug = 1; diff --git a/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_basic.result b/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_basic.result index ad0ffe9855a..e83f528a94e 100644 --- a/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_basic.result @@ -7,7 +7,7 @@ SELECT @global_start_value; SET @global_start_max_dirty_lwm_value = @@global.innodb_max_dirty_pages_pct_lwm; SELECT @global_start_max_dirty_lwm_value; @global_start_max_dirty_lwm_value -75 +0 SET @@global.innodb_max_dirty_pages_pct_lwm = 0; SELECT @@global.innodb_max_dirty_pages_pct_lwm; @@global.innodb_max_dirty_pages_pct_lwm @@ -171,5 +171,5 @@ SELECT @@global.innodb_max_dirty_pages_pct; SET @@global.innodb_max_dirty_pages_pct_lwm = @global_start_max_dirty_lwm_value; SELECT @@global.innodb_max_dirty_pages_pct_lwm; @@global.innodb_max_dirty_pages_pct_lwm -75.000000 +0.000000 SET @@global.innodb_max_dirty_pages_pct=@save_innodb_max_dirty_pages_pct; diff --git a/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_lwm_basic.result b/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_lwm_basic.result index 313bdf28e82..641386d5f23 100644 --- a/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_lwm_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_lwm_basic.result @@ -3,7 +3,7 @@ set @@global.innodb_max_dirty_pages_pct=75; SET @pct_lwm_start_value = @@global.innodb_max_dirty_pages_pct_lwm; SELECT @pct_lwm_start_value; @pct_lwm_start_value -75 +0 SET @pct_start_value = @@global.innodb_max_dirty_pages_pct; SELECT @pct_start_value; @pct_start_value @@ -13,13 +13,13 @@ SET @@global.innodb_max_dirty_pages_pct_lwm = 0; SET @@global.innodb_max_dirty_pages_pct_lwm = DEFAULT; SELECT @@global.innodb_max_dirty_pages_pct_lwm; @@global.innodb_max_dirty_pages_pct_lwm -75.000000 +0.000000 '#---------------------FN_DYNVARS_046_02-------------------------#' SET innodb_max_dirty_pages_pct_lwm = 1; ERROR HY000: Variable 'innodb_max_dirty_pages_pct_lwm' is a GLOBAL variable and should be set with SET GLOBAL SELECT @@innodb_max_dirty_pages_pct_lwm; @@innodb_max_dirty_pages_pct_lwm -75.000000 +0.000000 SELECT local.innodb_max_dirty_pages_pct_lwm; ERROR 42S02: Unknown table 'local' in field list SET global innodb_max_dirty_pages_pct_lwm = 0; @@ -130,5 +130,5 @@ SELECT @@global.innodb_max_dirty_pages_pct; SET @@global.innodb_max_dirty_pages_pct_lwm = @pct_lwm_start_value; SELECT @@global.innodb_max_dirty_pages_pct_lwm; @@global.innodb_max_dirty_pages_pct_lwm -75.000000 +0.000000 SET @@global.innodb_max_dirty_pages_pct=@save_innodb_max_dirty_pages_pct; diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result index 5227c08052e..eba68ff6185 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result @@ -1319,7 +1319,7 @@ READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME INNODB_MAX_DIRTY_PAGES_PCT_LWM SESSION_VALUE NULL -DEFAULT_VALUE 75.000000 +DEFAULT_VALUE 0.000000 VARIABLE_SCOPE GLOBAL VARIABLE_TYPE DOUBLE VARIABLE_COMMENT Percentage of dirty pages at which flushing kicks in. diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc index 791d1d84b53..f602e0d19a2 100644 --- a/storage/innobase/btr/btr0bulk.cc +++ b/storage/innobase/btr/btr0bulk.cc @@ -1108,13 +1108,9 @@ BtrBulk::insert( goto func_exit; } - /* Wake up page cleaner to flush dirty pages. */ srv_inc_activity_count(); - mysql_cond_signal(&buf_pool.do_flush_list); - logFreeCheck(); } - } /* Convert tuple to rec. */ diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 0f25232ebba..daf5e1aa511 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -519,31 +519,6 @@ decrypt_failed: ut_ad(node.space->pending_io()); return true; } - -/** -@return the smallest oldest_modification lsn for any page. -@retval 0 if all modified persistent pages have been flushed */ -lsn_t buf_pool_t::get_oldest_modification() -{ - mysql_mutex_lock(&flush_list_mutex); - - /* FIXME: Keep temporary tablespace pages in a separate flush - list. We would only need to write out temporary pages if the - page is about to be evicted from the buffer pool, and the page - contents is still needed (the page has not been freed). */ - const buf_page_t *bpage; - for (bpage= UT_LIST_GET_LAST(flush_list); - bpage && fsp_is_system_temporary(bpage->id().space()); - bpage= UT_LIST_GET_PREV(list, bpage)) - ut_ad(bpage->oldest_modification()); - - lsn_t oldest_lsn= bpage ? bpage->oldest_modification() : 0; - mysql_mutex_unlock(&flush_list_mutex); - - /* The result may become stale as soon as we released the mutex. - On log checkpoint, also log_sys.flush_order_mutex will be needed. */ - return oldest_lsn; -} #endif /* !UNIV_INNOCHECKSUM */ /** Checks if the page is in crc32 checksum format. @@ -3052,12 +3027,13 @@ buf_page_get_low( break; default: ut_error; + case BUF_GET_POSSIBLY_FREED: + break; case BUF_GET_NO_LATCH: ut_ad(rw_latch == RW_NO_LATCH); /* fall through */ case BUF_GET: case BUF_GET_IF_IN_POOL_OR_WATCH: - case BUF_GET_POSSIBLY_FREED: fil_space_t* s = fil_space_acquire_for_io(page_id.space()); ut_ad(s); ut_ad(s->zip_size() == zip_size); diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc index ee9be7e47d2..b66f5e39744 100644 --- a/storage/innobase/buf/buf0dump.cc +++ b/storage/innobase/buf/buf0dump.cc @@ -665,6 +665,12 @@ buf_load() continue; } + if (space->is_stopping()) { + space->release_for_io(); + space = nullptr; + continue; + } + buf_read_page_background(dump[i], zip_size, true); if (buf_load_abort_flag) { diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index da25b825e7e..b69026ef990 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -26,6 +26,7 @@ Created 11/11/1995 Heikki Tuuri *******************************************************/ #include "univ.i" +#include #include #include @@ -52,10 +53,6 @@ Created 11/11/1995 Heikki Tuuri # include "snappy-c.h" #endif -/** Sleep time in microseconds for loop waiting for the oldest -modification lsn */ -static constexpr ulint buf_flush_wait_flushed_sleep_time = 10000; - /** Number of pages flushed via LRU. Protected by buf_pool.mutex. Also included in buf_flush_page_count. */ ulint buf_lru_flush_page_count; @@ -68,41 +65,27 @@ bool buf_page_cleaner_is_active; /** Factor for scan length to determine n_pages for intended oldest LSN progress */ -static ulint buf_flush_lsn_scan_factor = 3; +static constexpr ulint buf_flush_lsn_scan_factor = 3; /** Average redo generation rate */ static lsn_t lsn_avg_rate = 0; -/** Target oldest LSN for the requested flush_sync */ -static std::atomic buf_flush_sync_lsn; +/** Target oldest_modification for the page cleaner; writes are protected by +buf_pool.flush_list_mutex */ +static Atomic_relaxed buf_flush_sync_lsn; #ifdef UNIV_PFS_THREAD mysql_pfs_key_t page_cleaner_thread_key; #endif /* UNIV_PFS_THREAD */ -/** Page cleaner request state for buf_pool */ -struct page_cleaner_slot_t { - ulint n_flushed_list; - /*!< number of flushed pages - by flush_list flushing */ - ulint flush_list_time; - /*!< elapsed time for flush_list - flushing */ - ulint flush_list_pass; - /*!< count to attempt flush_list - flushing */ -}; - /** Page cleaner structure */ -struct page_cleaner_t { - ulint flush_time; /*!< elapsed time to flush - requests for all slots */ - ulint flush_pass; /*!< count to finish to flush - requests for all slots */ - page_cleaner_slot_t slot; -}; - -static page_cleaner_t page_cleaner; +static struct +{ + /** total elapsed time in adaptive flushing, in seconds */ + ulint flush_time; + /** number of adaptive flushing passes */ + ulint flush_pass; +} page_cleaner; #ifdef UNIV_DEBUG my_bool innodb_page_cleaner_disabled_debug; @@ -257,7 +240,7 @@ ulint buf_flush_dirty_pages(ulint id) } mysql_mutex_unlock(&buf_pool.flush_list_mutex); if (n) - buf_flush_lists(ULINT_UNDEFINED, LSN_MAX); + buf_flush_lists(srv_max_io_capacity, LSN_MAX); return n; } @@ -1449,6 +1432,12 @@ static std::atomic_flag log_flush_pending; /** Advance log_sys.get_flushed_lsn() */ static void log_flush(void *) { + /* Between batches, we try to prevent I/O stalls by these calls. + This should not be needed for correctness. */ + os_aio_wait_until_no_pending_writes(); + fil_flush_file_spaces(); + + /* Guarantee progress for buf_flush_lists(). */ log_write_up_to(log_sys.get_lsn(), true); log_flush_pending.clear(); } @@ -1515,65 +1504,199 @@ ulint buf_flush_lists(ulint max_n, lsn_t lsn) return n_flushed; } -/** Request IO burst and wake up the page_cleaner. -@param lsn desired lower bound of oldest_modification */ -static void buf_flush_request_force(lsn_t lsn) + +/** Initiate a log checkpoint, discarding the start of the log. +@param oldest_lsn the checkpoint LSN +@param end_lsn log_sys.get_lsn() +@return true if success, false if a checkpoint write was already running */ +static bool log_checkpoint_low(lsn_t oldest_lsn, lsn_t end_lsn) { - lsn+= lsn_avg_rate * 3; + ut_ad(!srv_read_only_mode); + ut_ad(log_mutex_own()); + ut_ad(oldest_lsn <= end_lsn); + ut_ad(end_lsn == log_sys.get_lsn()); + ut_ad(!recv_no_log_write); - lsn_t o= 0; + ut_ad(oldest_lsn >= log_sys.last_checkpoint_lsn); - while (!buf_flush_sync_lsn.compare_exchange_weak(o, lsn, - std::memory_order_acquire, - std::memory_order_relaxed)) - if (lsn > o) - break; + if (oldest_lsn > log_sys.last_checkpoint_lsn + SIZE_OF_FILE_CHECKPOINT) + /* Some log has been written since the previous checkpoint. */; + else if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED) + /* MariaDB startup expects the redo log file to be logically empty + (not even containing a FILE_CHECKPOINT record) after a clean shutdown. + Perform an extra checkpoint at shutdown. */; + else + { + /* Do nothing, because nothing was logged (other than a + FILE_CHECKPOINT record) since the previous checkpoint. */ + log_mutex_exit(); + return true; + } - mysql_cond_signal(&buf_pool.do_flush_list); + /* Repeat the FILE_MODIFY records after the checkpoint, in case some + log records between the checkpoint and log_sys.lsn need them. + Finally, write a FILE_CHECKPOINT record. Redo log apply expects to + see a FILE_CHECKPOINT after the checkpoint, except on clean + shutdown, where the log will be empty after the checkpoint. + + It is important that we write out the redo log before any further + dirty pages are flushed to the tablespace files. At this point, + because we hold log_sys.mutex, mtr_t::commit() in other threads will + be blocked, and no pages can be added to the flush lists. */ + lsn_t flush_lsn= oldest_lsn; + + if (fil_names_clear(flush_lsn, oldest_lsn != end_lsn || + srv_shutdown_state <= SRV_SHUTDOWN_INITIATED)) + { + flush_lsn= log_sys.get_lsn(); + ut_ad(flush_lsn >= end_lsn + SIZE_OF_FILE_CHECKPOINT); + log_mutex_exit(); + log_write_up_to(flush_lsn, true, true); + log_mutex_enter(); + if (log_sys.last_checkpoint_lsn >= oldest_lsn) + { + log_mutex_exit(); + return true; + } + } + else + ut_ad(oldest_lsn >= log_sys.last_checkpoint_lsn); + + ut_ad(log_sys.get_flushed_lsn() >= flush_lsn); + + if (log_sys.n_pending_checkpoint_writes) + { + /* A checkpoint write is running */ + log_mutex_exit(); + return false; + } + + log_sys.next_checkpoint_lsn= oldest_lsn; + log_write_checkpoint_info(end_lsn); + ut_ad(!log_mutex_own()); + + return true; } -/** Wait until a flush batch of the given lsn ends -@param[in] new_oldest target oldest_modified_lsn to wait for */ -void buf_flush_wait_flushed(lsn_t new_oldest) +/** Make a checkpoint. Note that this function does not flush dirty +blocks from the buffer pool: it only checks what is lsn of the oldest +modification in the pool, and writes information about the lsn in +log file. Use log_make_checkpoint() to flush also the pool. +@retval true if the checkpoint was or had been made +@retval false if a checkpoint write was already running */ +static bool log_checkpoint() { - ut_ad(new_oldest); + if (recv_recovery_is_on()) + recv_sys.apply(true); - if (srv_flush_sync) { - /* wake page cleaner for IO burst */ - buf_flush_request_force(new_oldest); - } + switch (srv_file_flush_method) { + case SRV_NOSYNC: + case SRV_O_DIRECT_NO_FSYNC: + break; + default: + fil_flush_file_spaces(); + } - for (;;) { - /* We don't need to wait for fsync of the flushed - blocks, because anyway we need fsync to make chekpoint. - So, we don't need to wait for the batch end here. */ + log_mutex_enter(); + const lsn_t end_lsn= log_sys.get_lsn(); + log_flush_order_mutex_enter(); + mysql_mutex_lock(&buf_pool.flush_list_mutex); + const lsn_t oldest_lsn= buf_pool.get_oldest_modification(end_lsn); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + log_flush_order_mutex_exit(); + return log_checkpoint_low(oldest_lsn, end_lsn); +} - mysql_mutex_lock(&buf_pool.flush_list_mutex); +/** Make a checkpoint. */ +ATTRIBUTE_COLD void log_make_checkpoint() +{ + buf_flush_wait_flushed(log_sys.get_lsn()); + while (!log_checkpoint()); +} - buf_page_t* bpage; - /* FIXME: Keep temporary tablespace pages in a separate flush - list. We would only need to write out temporary pages if the - page is about to be evicted from the buffer pool, and the page - contents is still needed (the page has not been freed). */ - for (bpage = UT_LIST_GET_LAST(buf_pool.flush_list); - bpage && fsp_is_system_temporary(bpage->id().space()); - bpage = UT_LIST_GET_PREV(list, bpage)) { - ut_ad(bpage->oldest_modification()); - } +/** Wait until all persistent pages are flushed up to a limit. +@param sync_lsn buf_pool.get_oldest_modification(LSN_MAX) to wait for */ +ATTRIBUTE_COLD void buf_flush_wait_flushed(lsn_t sync_lsn) +{ + ut_ad(sync_lsn); + ut_ad(sync_lsn < LSN_MAX); + ut_ad(!log_mutex_own()); + ut_ad(!srv_read_only_mode); - lsn_t oldest = bpage ? bpage->oldest_modification() : 0; + if (recv_recovery_is_on()) + recv_sys.apply(true); - mysql_mutex_unlock(&buf_pool.flush_list_mutex); + mysql_mutex_lock(&buf_pool.flush_list_mutex); - if (oldest == 0 || oldest >= new_oldest) { - break; - } +#if 1 /* FIXME: remove this, and guarantee that the page cleaner serves us */ + if (UNIV_UNLIKELY(!buf_page_cleaner_is_active) + ut_d(|| innodb_page_cleaner_disabled_debug)) + { + for (;;) + { + const lsn_t lsn= buf_pool.get_oldest_modification(sync_lsn); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + if (lsn >= sync_lsn) + return; + ulint n_pages= buf_flush_lists(srv_max_io_capacity, sync_lsn); + buf_flush_wait_batch_end_acquiring_mutex(false); + if (n_pages) + { + MONITOR_INC_VALUE_CUMULATIVE(MONITOR_FLUSH_SYNC_TOTAL_PAGE, + MONITOR_FLUSH_SYNC_COUNT, + MONITOR_FLUSH_SYNC_PAGES, n_pages); + log_checkpoint(); + } + MONITOR_INC(MONITOR_FLUSH_SYNC_WAITS); + mysql_mutex_lock(&buf_pool.flush_list_mutex); + } + return; + } + else if (UNIV_LIKELY(srv_flush_sync)) +#endif + { + if (buf_flush_sync_lsn < sync_lsn) + { + buf_flush_sync_lsn= sync_lsn; + mysql_cond_signal(&buf_pool.do_flush_list); + } + } - /* sleep and retry */ - os_thread_sleep(buf_flush_wait_flushed_sleep_time); + while (buf_pool.get_oldest_modification(sync_lsn) < sync_lsn) + { + tpool::tpool_wait_begin(); + thd_wait_begin(nullptr, THD_WAIT_DISKIO); + mysql_cond_wait(&buf_pool.done_flush_list, &buf_pool.flush_list_mutex); + thd_wait_end(nullptr); + tpool::tpool_wait_end(); - MONITOR_INC(MONITOR_FLUSH_SYNC_WAITS); - } + MONITOR_INC(MONITOR_FLUSH_SYNC_WAITS); + } + + mysql_mutex_unlock(&buf_pool.flush_list_mutex); +} + +/** If innodb_flush_sync=ON, initiate a furious flush. +@param lsn buf_pool.get_oldest_modification(LSN_MAX) target */ +void buf_flush_ahead(lsn_t lsn) +{ + ut_ad(!log_mutex_own()); + ut_ad(!srv_read_only_mode); + + if (recv_recovery_is_on()) + recv_sys.apply(true); + + if (buf_flush_sync_lsn < lsn && + UNIV_LIKELY(srv_flush_sync) && UNIV_LIKELY(buf_page_cleaner_is_active)) + { + mysql_mutex_lock(&buf_pool.flush_list_mutex); + if (buf_flush_sync_lsn < lsn) + { + buf_flush_sync_lsn= lsn; + mysql_cond_signal(&buf_pool.do_flush_list); + } + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + } } /** Wait for pending flushes to complete. */ @@ -1587,29 +1710,84 @@ void buf_flush_wait_batch_end_acquiring_mutex(bool lru) } } +/** Conduct checkpoint-related flushing for innodb_flush_sync=ON, +and try to initiate checkpoints until the target is met. +@param lsn minimum value of buf_pool.get_oldest_modification(LSN_MAX) */ +ATTRIBUTE_COLD static void buf_flush_sync_for_checkpoint(lsn_t lsn) +{ + ut_ad(!srv_read_only_mode); + + for (;;) + { + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + + if (ulint n_flushed= buf_flush_lists(srv_max_io_capacity, lsn)) + { + MONITOR_INC_VALUE_CUMULATIVE(MONITOR_FLUSH_SYNC_TOTAL_PAGE, + MONITOR_FLUSH_SYNC_COUNT, + MONITOR_FLUSH_SYNC_PAGES, n_flushed); + } + + /* Attempt to perform a log checkpoint upon completing each batch. */ + if (recv_recovery_is_on()) + recv_sys.apply(true); + + switch (srv_file_flush_method) { + case SRV_NOSYNC: + case SRV_O_DIRECT_NO_FSYNC: + break; + default: + fil_flush_file_spaces(); + } + + log_mutex_enter(); + const lsn_t newest_lsn= log_sys.get_lsn(); + log_flush_order_mutex_enter(); + mysql_mutex_lock(&buf_pool.flush_list_mutex); + lsn_t measure= buf_pool.get_oldest_modification(0); + log_flush_order_mutex_exit(); + const lsn_t checkpoint_lsn= measure ? measure : newest_lsn; + + if (checkpoint_lsn > log_sys.last_checkpoint_lsn + SIZE_OF_FILE_CHECKPOINT) + { + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + log_checkpoint_low(checkpoint_lsn, newest_lsn); + mysql_mutex_lock(&buf_pool.flush_list_mutex); + measure= buf_pool.get_oldest_modification(LSN_MAX); + } + else + { + log_mutex_exit(); + if (!measure) + measure= LSN_MAX; + } + + ut_ad(!log_mutex_own()); + + /* After attempting log checkpoint, check if we have reached our target. */ + const lsn_t target= buf_flush_sync_lsn; + + if (measure >= target) + buf_flush_sync_lsn= 0; + + /* wake up buf_flush_wait_flushed() */ + mysql_cond_broadcast(&buf_pool.done_flush_list); + + lsn= std::max(lsn, target); + + if (measure >= lsn) + return; + } +} + /*********************************************************************//** Calculates if flushing is required based on number of dirty pages in the buffer pool. +@param dirty_pct 100*flush_list.count / (LRU.count + free.count) @return percent of io_capacity to flush to manage dirty page ratio */ -static -ulint -af_get_pct_for_dirty() +static ulint af_get_pct_for_dirty(double dirty_pct) { - const ulint dirty = UT_LIST_GET_LEN(buf_pool.flush_list); - if (!dirty) { - /* No pages modified */ - return 0; - } - - /* 1 + is there to avoid division by zero (in case the buffer - pool (including the flush_list) was emptied while we are - looking at it) */ - double dirty_pct = 100 * static_cast(dirty) - / static_cast(1 + UT_LIST_GET_LEN(buf_pool.LRU) - + UT_LIST_GET_LEN(buf_pool.free)); - - ut_a(srv_max_dirty_pages_pct_lwm - <= srv_max_buf_pool_modified_pct); + ut_ad(srv_max_dirty_pages_pct_lwm <= srv_max_buf_pool_modified_pct); if (srv_max_dirty_pages_pct_lwm == 0) { /* The user has not set the option to preflush dirty @@ -1620,7 +1798,7 @@ af_get_pct_for_dirty() innodb_io_capacity. */ return(100); } - } else if (dirty_pct >= srv_max_dirty_pages_pct_lwm) { + } else { /* We should start flushing pages gradually. */ return(static_cast((dirty_pct * 100) / (srv_max_buf_pool_modified_pct + 1))); @@ -1638,30 +1816,16 @@ af_get_pct_for_lsn( /*===============*/ lsn_t age) /*!< in: current age of LSN. */ { - lsn_t max_async_age; - lsn_t lsn_age_factor; lsn_t af_lwm = static_cast( srv_adaptive_flushing_lwm - * static_cast(log_get_capacity()) / 100); + * static_cast(log_sys.log_capacity) / 100); if (age < af_lwm) { /* No adaptive flushing. */ return(0); } - max_async_age = log_get_max_modified_age_async(); - - if (age < max_async_age && !srv_adaptive_flushing) { - /* We have still not reached the max_async point and - the user has disabled adaptive flushing. */ - return(0); - } - - /* If we are here then we know that either: - 1) User has enabled adaptive flushing - 2) User may have disabled adaptive flushing but we have reached - max_async_age. */ - lsn_age_factor = (age * 100) / max_async_age; + lsn_t lsn_age_factor = (age * 100) / log_sys.max_modified_age_async; ut_ad(srv_max_io_capacity >= srv_io_capacity); return static_cast( @@ -1671,46 +1835,40 @@ af_get_pct_for_lsn( / 7.5)); } -/*********************************************************************//** -This function is called approximately once every second by the -page_cleaner thread. Based on various factors it decides if there is a -need to do flushing. +/** This function is called approximately once every second by the +page_cleaner thread if innodb_adaptive_flushing=ON. +Based on various factors it decides if there is a need to do flushing. @return number of pages recommended to be flushed -@param last_pages_in the number of pages flushed by the last flush_list - flushing. */ -static -ulint -page_cleaner_flush_pages_recommendation(ulint last_pages_in) +@param last_pages_in number of pages flushed in previous batch +@param oldest_lsn buf_pool.get_oldest_modification(0) +@param dirty_pct 100*flush_list.count / (LRU.count + free.count) */ +static ulint page_cleaner_flush_pages_recommendation(ulint last_pages_in, + lsn_t oldest_lsn, + double dirty_pct) { static lsn_t prev_lsn = 0; static ulint sum_pages = 0; static ulint avg_page_rate = 0; static ulint n_iterations = 0; static time_t prev_time; - lsn_t oldest_lsn; - lsn_t age; lsn_t lsn_rate; ulint n_pages = 0; - ulint pct_for_dirty = 0; - ulint pct_for_lsn = 0; - ulint pct_total = 0; const lsn_t cur_lsn = log_sys.get_lsn(); + ulint pct_for_dirty = af_get_pct_for_dirty(dirty_pct); + ut_ad(oldest_lsn <= cur_lsn); + ulint pct_for_lsn = af_get_pct_for_lsn(cur_lsn - oldest_lsn); + time_t curr_time = time(nullptr); - if (prev_lsn == 0) { - /* First time around. */ + if (!prev_lsn || !pct_for_lsn) { + prev_time = curr_time; prev_lsn = cur_lsn; - prev_time = time(NULL); - return(0); - } - - if (prev_lsn == cur_lsn) { - return(0); + return ulint(double(pct_for_dirty) / 100.0 + * double(srv_io_capacity)); } sum_pages += last_pages_in; - time_t curr_time = time(NULL); double time_elapsed = difftime(curr_time, prev_time); /* We update our variables every srv_flushing_avg_loops @@ -1740,37 +1898,12 @@ page_cleaner_flush_pages_recommendation(ulint last_pages_in) page_cleaner.flush_time = 0; page_cleaner.flush_pass = 0; - ulint list_tm = page_cleaner.slot.flush_list_time; - ulint list_pass = page_cleaner.slot.flush_list_pass; - page_cleaner.slot.flush_list_time = 0; - page_cleaner.slot.flush_list_pass = 0; - - /* minimum values are 1, to avoid dividing by zero. */ - if (list_tm < 1) { - list_tm = 1; - } - if (flush_tm < 1) { - flush_tm = 1; + if (flush_pass) { + flush_tm /= flush_pass; } - if (list_pass < 1) { - list_pass = 1; - } - if (flush_pass < 1) { - flush_pass = 1; - } - - MONITOR_SET(MONITOR_FLUSH_ADAPTIVE_AVG_TIME_SLOT, - list_tm / list_pass); - - MONITOR_SET(MONITOR_FLUSH_ADAPTIVE_AVG_TIME_THREAD, - list_tm / flush_pass); - MONITOR_SET(MONITOR_FLUSH_ADAPTIVE_AVG_TIME_EST, - flush_tm / flush_pass); - MONITOR_SET(MONITOR_FLUSH_AVG_TIME, flush_tm / flush_pass); - - MONITOR_SET(MONITOR_FLUSH_ADAPTIVE_AVG_PASS, list_pass); - MONITOR_SET(MONITOR_FLUSH_AVG_PASS, flush_pass); + MONITOR_SET(MONITOR_FLUSH_ADAPTIVE_AVG_TIME, flush_tm); + MONITOR_SET(MONITOR_FLUSH_ADAPTIVE_AVG_PASS, flush_pass); prev_lsn = cur_lsn; prev_time = curr_time; @@ -1780,30 +1913,24 @@ page_cleaner_flush_pages_recommendation(ulint last_pages_in) sum_pages = 0; } - oldest_lsn = buf_pool.get_oldest_modification(); + mysql_mutex_lock(&buf_pool.flush_list_mutex); - ut_ad(oldest_lsn <= log_get_lsn()); - - age = cur_lsn > oldest_lsn ? cur_lsn - oldest_lsn : 0; - - pct_for_dirty = af_get_pct_for_dirty(); - pct_for_lsn = af_get_pct_for_lsn(age); - - pct_total = ut_max(pct_for_dirty, pct_for_lsn); + ulint pct_total = std::max(pct_for_dirty, pct_for_lsn); /* Estimate pages to be flushed for the lsn progress */ lsn_t target_lsn = oldest_lsn + lsn_avg_rate * buf_flush_lsn_scan_factor; ulint pages_for_lsn = 0; - mysql_mutex_lock(&buf_pool.flush_list_mutex); for (buf_page_t* b = UT_LIST_GET_LAST(buf_pool.flush_list); b != NULL; b = UT_LIST_GET_PREV(list, b)) { if (b->oldest_modification() > target_lsn) { break; } - ++pages_for_lsn; + if (++pages_for_lsn >= srv_max_io_capacity) { + break; + } } mysql_mutex_unlock(&buf_pool.flush_list_mutex); @@ -1812,11 +1939,6 @@ page_cleaner_flush_pages_recommendation(ulint last_pages_in) pages_for_lsn = 1; } - /* Cap the maximum IO capacity that we are going to use by - max_io_capacity. Limit the value to avoid too quick increase */ - pages_for_lsn = std::min( - pages_for_lsn, srv_max_io_capacity * 2); - n_pages = (ulint(double(srv_io_capacity) * double(pct_total) / 100.0) + avg_page_rate + pages_for_lsn) / 3; @@ -1836,183 +1958,222 @@ page_cleaner_flush_pages_recommendation(ulint last_pages_in) return(n_pages); } -/** Initiate a flushing batch. -@param max_n maximum mumber of blocks flushed -@param lsn oldest_modification limit -@return ut_time_ms() at the start of the wait */ -static ulint pc_request_flush_slot(ulint max_n, lsn_t lsn) -{ - ut_ad(max_n); - ut_ad(lsn); - - const ulint flush_start_tm= ut_time_ms(); - page_cleaner.slot.n_flushed_list= buf_flush_lists(max_n, lsn); - page_cleaner.slot.flush_list_time+= ut_time_ms() - flush_start_tm; - page_cleaner.slot.flush_list_pass++; - return flush_start_tm; -} - -#ifdef UNIV_DEBUG -/** Loop used to disable the page cleaner thread. */ -static void buf_flush_page_cleaner_disabled_loop() -{ - while (innodb_page_cleaner_disabled_debug - && srv_shutdown_state == SRV_SHUTDOWN_NONE) { - os_thread_sleep(100000); - } -} -#endif /* UNIV_DEBUG */ - /******************************************************************//** page_cleaner thread tasked with flushing dirty pages from the buffer pools. As of now we'll have only one coordinator. @return a dummy parameter */ static os_thread_ret_t DECLARE_THREAD(buf_flush_page_cleaner)(void*) { - my_thread_init(); + my_thread_init(); #ifdef UNIV_PFS_THREAD - pfs_register_thread(page_cleaner_thread_key); + pfs_register_thread(page_cleaner_thread_key); #endif /* UNIV_PFS_THREAD */ - ut_ad(!srv_read_only_mode); - ut_ad(buf_page_cleaner_is_active); + ut_ad(!srv_read_only_mode); + ut_ad(buf_page_cleaner_is_active); #ifdef UNIV_DEBUG_THREAD_CREATION - ib::info() << "page_cleaner thread running, id " - << os_thread_pf(os_thread_get_curr_id()); + ib::info() << "page_cleaner thread running, id " + << os_thread_pf(os_thread_get_curr_id()); #endif /* UNIV_DEBUG_THREAD_CREATION */ #ifdef UNIV_LINUX - /* linux might be able to set different setting for each thread. - worth to try to set high priority for the page cleaner thread */ - const pid_t tid= static_cast(syscall(SYS_gettid)); - setpriority(PRIO_PROCESS, tid, -20); - if (getpriority(PRIO_PROCESS, tid) != -20) { - ib::info() << "If the mysqld execution user is authorized," - " page cleaner thread priority can be changed." - " See the man page of setpriority()."; - } + /* linux might be able to set different setting for each thread. + worth to try to set high priority for the page cleaner thread */ + const pid_t tid= static_cast(syscall(SYS_gettid)); + setpriority(PRIO_PROCESS, tid, -20); + if (getpriority(PRIO_PROCESS, tid) != -20) + ib::info() << "If the mysqld execution user is authorized," + " page cleaner thread priority can be changed." + " See the man page of setpriority()."; #endif /* UNIV_LINUX */ - ulint curr_time = ut_time_ms(); - ulint n_flushed = 0; - ulint last_activity = srv_get_activity_count(); - ulint last_pages = 0; + ulint last_pages= 0; + timespec abstime; + set_timespec(abstime, 1); - for (ulint next_loop_time = curr_time + 1000; - srv_shutdown_state <= SRV_SHUTDOWN_INITIATED; - curr_time = ut_time_ms()) { - bool sleep_timeout; + mysql_mutex_lock(&buf_pool.flush_list_mutex); - /* The page_cleaner skips sleep if the server is - idle and there are no pending IOs in the buffer pool - and there is work to do. */ - if (next_loop_time <= curr_time) { - sleep_timeout = true; - } else if (!n_flushed || !buf_pool.n_pend_reads - || srv_check_activity(&last_activity)) { - const ulint sleep_ms = std::min(next_loop_time - - curr_time, - 1000); - timespec abstime; - set_timespec_nsec(abstime, 1000000ULL * sleep_ms); - mysql_mutex_lock(&buf_pool.flush_list_mutex); - const auto error = mysql_cond_timedwait( - &buf_pool.do_flush_list, - &buf_pool.flush_list_mutex, - &abstime); - mysql_mutex_unlock(&buf_pool.flush_list_mutex); - sleep_timeout = error == ETIMEDOUT || error == ETIME; - if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED) { - break; - } - } else { - sleep_timeout = false; - } + lsn_t lsn_limit; - if (sleep_timeout) { - /* no activity, slept enough */ - n_flushed = buf_flush_lists(srv_io_capacity, LSN_MAX); - last_pages = n_flushed; + for (;;) + { + lsn_limit= buf_flush_sync_lsn; - if (n_flushed) { - MONITOR_INC_VALUE_CUMULATIVE( - MONITOR_FLUSH_BACKGROUND_TOTAL_PAGE, - MONITOR_FLUSH_BACKGROUND_COUNT, - MONITOR_FLUSH_BACKGROUND_PAGES, - n_flushed); + if (UNIV_UNLIKELY(lsn_limit != 0)) + { +furious_flush: + buf_flush_sync_for_checkpoint(lsn_limit); + last_pages= 0; + set_timespec(abstime, 1); + continue; + } - } - } else if (lsn_t lsn_limit = buf_flush_sync_lsn.exchange( - 0, std::memory_order_release)) { - page_cleaner.flush_time += ut_time_ms() - - pc_request_flush_slot(ULINT_MAX, lsn_limit); - page_cleaner.flush_pass++; - n_flushed = page_cleaner.slot.n_flushed_list; + if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED) + break; - if (n_flushed) { - MONITOR_INC_VALUE_CUMULATIVE( - MONITOR_FLUSH_SYNC_TOTAL_PAGE, - MONITOR_FLUSH_SYNC_COUNT, - MONITOR_FLUSH_SYNC_PAGES, - n_flushed); - } - } else if (!srv_check_activity(&last_activity)) { - /* no activity, but woken up by event */ - n_flushed = 0; - } else if (ulint n= page_cleaner_flush_pages_recommendation( - last_pages)) { - /* Estimate pages from flush_list to be flushed */ - ulint tm= pc_request_flush_slot(n, LSN_MAX); + mysql_cond_timedwait(&buf_pool.do_flush_list, &buf_pool.flush_list_mutex, + &abstime); + set_timespec(abstime, 1); - page_cleaner.flush_time += ut_time_ms() - tm; - page_cleaner.flush_pass++ ; + lsn_limit= buf_flush_sync_lsn; - n_flushed = page_cleaner.slot.n_flushed_list; + if (UNIV_UNLIKELY(lsn_limit != 0)) + goto furious_flush; - if (n_flushed) { - MONITOR_INC_VALUE_CUMULATIVE( - MONITOR_FLUSH_ADAPTIVE_TOTAL_PAGE, - MONITOR_FLUSH_ADAPTIVE_COUNT, - MONITOR_FLUSH_ADAPTIVE_PAGES, - n_flushed); - } - } else { - n_flushed = 0; - } + if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED) + break; - if (!n_flushed) { - next_loop_time = curr_time + 1000; - } + const ulint dirty_blocks= UT_LIST_GET_LEN(buf_pool.flush_list); - ut_d(buf_flush_page_cleaner_disabled_loop()); - } + if (!dirty_blocks) + continue; - if (srv_fast_shutdown != 2) { - buf_flush_wait_batch_end_acquiring_mutex(true); - buf_flush_wait_batch_end_acquiring_mutex(false); - } + /* We perform dirty reads of the LRU+free list lengths here. + Division by zero is not possible, because buf_pool.flush_list is + guaranteed to be nonempty, and it is a subset of buf_pool.LRU. */ + const double dirty_pct= double(dirty_blocks) * 100.0 / + double(UT_LIST_GET_LEN(buf_pool.LRU) + UT_LIST_GET_LEN(buf_pool.free)); - mysql_mutex_lock(&buf_pool.flush_list_mutex); - buf_page_cleaner_is_active = false; - mysql_cond_broadcast(&buf_pool.done_flush_list); - mysql_mutex_unlock(&buf_pool.flush_list_mutex); + if (dirty_pct < srv_max_dirty_pages_pct_lwm) + continue; - my_thread_end(); - /* We count the number of threads in os_thread_exit(). A created - thread should always use that to exit and not use return() to exit. */ - os_thread_exit(); + const lsn_t oldest_lsn= buf_pool.get_oldest_modification(0); - OS_THREAD_DUMMY_RETURN; + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + + ulint n_flushed; + + if (!srv_adaptive_flushing) + { + n_flushed= buf_flush_lists(srv_io_capacity, LSN_MAX); + + if (n_flushed) + { + MONITOR_INC_VALUE_CUMULATIVE(MONITOR_FLUSH_BACKGROUND_TOTAL_PAGE, + MONITOR_FLUSH_BACKGROUND_COUNT, + MONITOR_FLUSH_BACKGROUND_PAGES, + n_flushed); +do_checkpoint: + /* The periodic log_checkpoint() call here makes it harder to + reproduce bugs in crash recovery or mariabackup --prepare, or + in code that writes the redo log records. Omitting the call + here should not affect correctness, because log_free_check() + should still be invoking checkpoints when needed. */ + DBUG_EXECUTE_IF("ib_log_checkpoint_avoid", goto next;); + + if (!recv_recovery_is_on() && srv_operation == SRV_OPERATION_NORMAL) + log_checkpoint(); + } + } + else if (ulint n= page_cleaner_flush_pages_recommendation(last_pages, + oldest_lsn, + dirty_pct)) + { + page_cleaner.flush_pass++; + const ulint tm= ut_time_ms(); + last_pages= n_flushed= buf_flush_lists(n, LSN_MAX); + page_cleaner.flush_time+= ut_time_ms() - tm; + + if (n_flushed) + { + MONITOR_INC_VALUE_CUMULATIVE(MONITOR_FLUSH_ADAPTIVE_TOTAL_PAGE, + MONITOR_FLUSH_ADAPTIVE_COUNT, + MONITOR_FLUSH_ADAPTIVE_PAGES, + n_flushed); + goto do_checkpoint; + } + } + +#ifdef UNIV_DEBUG + while (innodb_page_cleaner_disabled_debug && !buf_flush_sync_lsn && + srv_shutdown_state == SRV_SHUTDOWN_NONE) + os_thread_sleep(100000); +#endif /* UNIV_DEBUG */ + +#ifndef DBUG_OFF +next: +#endif /* !DBUG_OFF */ + mysql_mutex_lock(&buf_pool.flush_list_mutex); + } + + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + + if (srv_fast_shutdown != 2) + { + buf_flush_wait_batch_end_acquiring_mutex(true); + buf_flush_wait_batch_end_acquiring_mutex(false); + } + + log_flush_task.wait(); + + mysql_mutex_lock(&buf_pool.flush_list_mutex); + lsn_limit= buf_flush_sync_lsn; + if (UNIV_UNLIKELY(lsn_limit != 0)) + goto furious_flush; + buf_page_cleaner_is_active= false; + mysql_cond_broadcast(&buf_pool.done_flush_list); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + + my_thread_end(); + /* We count the number of threads in os_thread_exit(). A created + thread should always use that to exit and not use return() to exit. */ + os_thread_exit(); + + OS_THREAD_DUMMY_RETURN; } - /** Initialize page_cleaner. */ -void buf_flush_page_cleaner_init() +ATTRIBUTE_COLD void buf_flush_page_cleaner_init() { ut_ad(!buf_page_cleaner_is_active); + ut_ad(srv_operation == SRV_OPERATION_NORMAL || + srv_operation == SRV_OPERATION_RESTORE || + srv_operation == SRV_OPERATION_RESTORE_EXPORT); + buf_flush_sync_lsn= 0; buf_page_cleaner_is_active= true; os_thread_create(buf_flush_page_cleaner); } +/** @return the number of dirty pages in the buffer pool */ +static ulint buf_flush_list_length() +{ + mysql_mutex_lock(&buf_pool.flush_list_mutex); + const ulint len= UT_LIST_GET_LEN(buf_pool.flush_list); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + return len; +} + +/** Flush the buffer pool on shutdown. */ +ATTRIBUTE_COLD void buf_flush_buffer_pool() +{ + ut_ad(!buf_page_cleaner_is_active); + ut_ad(!buf_flush_sync_lsn); + + service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, + "Waiting to flush the buffer pool"); + + while (buf_pool.n_flush_list || buf_flush_list_length()) + { + buf_flush_lists(srv_max_io_capacity, LSN_MAX); + timespec abstime; + + if (buf_pool.n_flush_list) + { + service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, + "Waiting to flush " ULINTPF " pages", + buf_flush_list_length()); + set_timespec(abstime, INNODB_EXTEND_TIMEOUT_INTERVAL / 2); + mysql_mutex_lock(&buf_pool.mutex); + while (buf_pool.n_flush_list) + mysql_cond_timedwait(&buf_pool.done_flush_list, &buf_pool.mutex, + &abstime); + mysql_mutex_unlock(&buf_pool.mutex); + } + } + + ut_ad(!buf_pool.any_io_pending()); + log_flush_task.wait(); +} + /** Synchronously flush dirty blocks. NOTE: The calling thread is not allowed to hold any buffer page latches! */ void buf_flush_sync() @@ -2021,7 +2182,7 @@ void buf_flush_sync() for (;;) { - const ulint n_flushed= buf_flush_lists(ULINT_UNDEFINED, LSN_MAX); + const ulint n_flushed= buf_flush_lists(srv_max_io_capacity, LSN_MAX); buf_flush_wait_batch_end_acquiring_mutex(false); if (!n_flushed) { diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index f4207ff393e..bc81a8e9b86 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -438,6 +438,8 @@ read_ahead: { if (ibuf_bitmap_page(i, zip_size)) continue; + if (space->is_stopping()) + break; dberr_t err; count+= buf_read_page_low(&err, false, ibuf_mode, i, zip_size, false); } @@ -697,6 +699,8 @@ failed: { if (ibuf_bitmap_page(new_low, zip_size)) continue; + if (space->is_stopping()) + break; dberr_t err; count+= buf_read_page_low(&err, false, ibuf_mode, new_low, zip_size, false); diff --git a/storage/innobase/dict/dict0boot.cc b/storage/innobase/dict/dict0boot.cc index 359684416ed..bd2cf4ffdd8 100644 --- a/storage/innobase/dict/dict0boot.cc +++ b/storage/innobase/dict/dict0boot.cc @@ -273,6 +273,11 @@ dict_boot(void) dict_sys.row_id = DICT_HDR_ROW_ID_WRITE_MARGIN + ut_uint64_align_up(mach_read_from_8(dict_hdr + DICT_HDR_ROW_ID), DICT_HDR_ROW_ID_WRITE_MARGIN); + if (ulint max_space_id = mach_read_from_4(dict_hdr + + DICT_HDR_MAX_SPACE_ID)) { + max_space_id--; + fil_assign_new_space_id(&max_space_id); + } /* Insert into the dictionary cache the descriptions of the basic system tables */ diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 021f2f15e3b..2da60b079f7 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -1142,7 +1142,6 @@ fil_space_create( UT_LIST_INIT(space->chain, &fil_node_t::chain); if ((purpose == FIL_TYPE_TABLESPACE || purpose == FIL_TYPE_IMPORT) - && !recv_recovery_is_on() && id > fil_system.max_assigned_id) { if (!fil_system.space_id_reuse_warned) { fil_system.space_id_reuse_warned = true; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index d6f28192893..97cce77135b 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -19074,7 +19074,7 @@ static MYSQL_SYSVAR_DOUBLE(max_dirty_pages_pct_lwm, srv_max_dirty_pages_pct_lwm, PLUGIN_VAR_RQCMDARG, "Percentage of dirty pages at which flushing kicks in.", - NULL, innodb_max_dirty_pages_pct_lwm_update, 75.0, 0, 99.999, 0); + NULL, innodb_max_dirty_pages_pct_lwm_update, 0, 0, 99.999, 0); static MYSQL_SYSVAR_DOUBLE(adaptive_flushing_lwm, srv_adaptive_flushing_lwm, diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index d5b65bb7ed8..d2b52c4f520 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -1567,8 +1567,18 @@ public: /** @return the smallest oldest_modification lsn for any page - @retval 0 if all modified persistent pages have been flushed */ - lsn_t get_oldest_modification(); + @retval empty_lsn if all modified persistent pages have been flushed */ + lsn_t get_oldest_modification(lsn_t empty_lsn) + { + mysql_mutex_assert_owner(&flush_list_mutex); + const buf_page_t *bpage= UT_LIST_GET_LAST(flush_list); +#if 1 /* MDEV-12227 FIXME: remove this loop */ + for (; bpage && fsp_is_system_temporary(bpage->id().space()); + bpage= UT_LIST_GET_PREV(list, bpage)) + ut_ad(bpage->oldest_modification()); +#endif + return bpage ? bpage->oldest_modification() : empty_lsn; + } /** Determine if a buffer block was created by chunk_t::create(). @param block block descriptor (not dereferenced) diff --git a/storage/innobase/include/buf0flu.h b/storage/innobase/include/buf0flu.h index 12ebf6f01e9..148db809077 100644 --- a/storage/innobase/include/buf0flu.h +++ b/storage/innobase/include/buf0flu.h @@ -104,9 +104,13 @@ ulint buf_flush_lists(ulint max_n, lsn_t lsn); /** Wait until a flush batch ends. @param lru true=buf_pool.LRU; false=buf_pool.flush_list */ void buf_flush_wait_batch_end(bool lru); -/** Wait until a flush batch of the given lsn ends -@param[in] new_oldest target oldest_modified_lsn to wait for */ -void buf_flush_wait_flushed(lsn_t new_oldest); +/** Wait until all persistent pages are flushed up to a limit. +@param sync_lsn buf_pool.get_oldest_modification(LSN_MAX) to wait for */ +ATTRIBUTE_COLD void buf_flush_wait_flushed(lsn_t sync_lsn); +/** If innodb_flush_sync=ON, initiate a furious flush. +@param lsn buf_pool.get_oldest_modification(LSN_MAX) target */ +void buf_flush_ahead(lsn_t lsn); + /********************************************************************//** This function should be called at a mini-transaction commit, if a page was modified in it. Puts the block to the list of modified blocks, if it not @@ -122,11 +126,14 @@ buf_flush_note_modification( set of mtr's */ /** Initialize page_cleaner. */ -void buf_flush_page_cleaner_init(); +ATTRIBUTE_COLD void buf_flush_page_cleaner_init(); /** Wait for pending flushes to complete. */ void buf_flush_wait_batch_end_acquiring_mutex(bool lru); +/** Flush the buffer pool on shutdown. */ +ATTRIBUTE_COLD void buf_flush_buffer_pool(); + #ifdef UNIV_DEBUG /** Validate the flush list. */ void buf_flush_validate(); diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index c80537f809b..b82857a8e0f 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -88,50 +88,12 @@ log_free_check(void); @param[in] len requested minimum size in bytes */ void log_buffer_extend(ulong len); -/** Check margin not to overwrite transaction log from the last checkpoint. -If would estimate the log write to exceed the log_capacity, -waits for the checkpoint is done enough. -@param[in] len length of the data to be written */ - -void -log_margin_checkpoint_age( - ulint len); - -/** Open the log for log_write_low. The log must be closed with log_close. -@param[in] len length of the data to be written -@return start lsn of the log record */ -lsn_t -log_reserve_and_open( - ulint len); -/************************************************************//** -Writes to the log the string given. It is assumed that the caller holds the -log mutex. */ -void -log_write_low( -/*==========*/ - const byte* str, /*!< in: string */ - ulint str_len); /*!< in: string length */ -/************************************************************//** -Closes the log. -@return lsn */ -lsn_t -log_close(void); -/*===========*/ /** Read the current LSN. */ #define log_get_lsn() log_sys.get_lsn() /** Read the durable LSN */ #define log_get_flush_lsn() log_sys.get_flushed_lsn() -/**************************************************************** -Get log_sys::max_modified_age_async. It is OK to read the value without -holding log_sys::mutex because it is constant. -@return max_modified_age_async */ -UNIV_INLINE -lsn_t -log_get_max_modified_age_async(void); -/*================================*/ - /** Calculate the recommended highest values for lsn - last_checkpoint_lsn and lsn - buf_pool.get_oldest_modification(). @param[in] file_size requested innodb_log_file_size @@ -159,30 +121,22 @@ void log_buffer_flush_to_disk( bool sync = true); -/** Make a checkpoint. Note that this function does not flush dirty -blocks from the buffer pool: it only checks what is lsn of the oldest -modification in the pool, and writes information about the lsn in -log file. Use log_make_checkpoint() to flush also the pool. -@return true if success, false if a checkpoint write was already running */ -bool log_checkpoint(); - /** Make a checkpoint */ -void log_make_checkpoint(); +ATTRIBUTE_COLD void log_make_checkpoint(); /** Make a checkpoint at the latest lsn on shutdown. */ -void logs_empty_and_mark_files_at_shutdown(); +ATTRIBUTE_COLD void logs_empty_and_mark_files_at_shutdown(); /** Write checkpoint info to the log header and invoke log_mutex_exit(). @param[in] end_lsn start LSN of the FILE_CHECKPOINT mini-transaction */ -void log_write_checkpoint_info(lsn_t end_lsn); +ATTRIBUTE_COLD void log_write_checkpoint_info(lsn_t end_lsn); /** Checks that there is enough free space in the log to start a new query step. Flushes the log buffer or makes a new checkpoint if necessary. NOTE: this function may only be called if the calling thread owns no synchronization objects! */ -void -log_check_margins(void); +ATTRIBUTE_COLD void log_check_margins(); /************************************************************//** Gets a log block flush bit. @@ -521,10 +475,6 @@ private: std::atomic lsn; /** the first guaranteed-durable log sequence number */ std::atomic flushed_to_disk_lsn; -public: - /** first free offset within the log buffer in use */ - size_t buf_free; -private: /** set when there may be need to flush the log buffer, or preflush buffer pool pages, or initiate a log checkpoint. This must hold if lsn - last_checkpoint_lsn > max_checkpoint_age. */ @@ -534,6 +484,10 @@ public: /** mutex protecting the log */ MY_ALIGNED(CACHE_LINE_SIZE) LogSysMutex mutex; + /** first free offset within the log buffer in use */ + size_t buf_free; + /** recommended maximum size of buf, after which the buffer is flushed */ + size_t max_buf_free; /** mutex to serialize access to the flush list when we are putting dirty blocks in the list. The idea behind this mutex is to be able to release log_sys.mutex during mtr_commit and still ensure that @@ -545,8 +499,6 @@ public: /** log_buffer, writing data to file from this buffer. Before flushing write_buf is swapped with flush_buf */ byte *flush_buf; - /** recommended maximum size of buf, after which the buffer is flushed */ - size_t max_buf_free; /** Log file stuff. Protected by mutex. */ struct file { /** format of the redo log: e.g., FORMAT_10_5 */ @@ -664,17 +616,6 @@ public: buf_pool.get_oldest_modification() is exceeded, we start an asynchronous preflush of pool pages */ - lsn_t max_modified_age_sync; - /*!< when this recommended - value for lsn - - buf_pool.get_oldest_modification() - is exceeded, we start a - synchronous preflush of pool pages */ - lsn_t max_checkpoint_age_async; - /*!< when this checkpoint age - is exceeded we start an - asynchronous writing of a new - checkpoint */ lsn_t max_checkpoint_age; /*!< this is the maximum allowed value for lsn - last_checkpoint_lsn when a @@ -721,7 +662,10 @@ public: { flushed_to_disk_lsn.store(lsn, std::memory_order_relaxed); } bool check_flush_or_checkpoint() const - { return check_flush_or_checkpoint_.load(std::memory_order_relaxed); } + { + return UNIV_UNLIKELY + (check_flush_or_checkpoint_.load(std::memory_order_relaxed)); + } void set_check_flush_or_checkpoint(bool flag= true) { check_flush_or_checkpoint_.store(flag, std::memory_order_relaxed); } @@ -784,11 +728,6 @@ extern log_t log_sys; extern bool log_write_lock_own(); #endif -/** Gets the log capacity. It is OK to read the value without -holding log_sys.mutex because it is constant. -@return log capacity */ -inline lsn_t log_get_capacity(void) { return log_sys.log_capacity; } - /** Calculate the offset of a log sequence number. @param[in] lsn log sequence number @return offset within the log */ diff --git a/storage/innobase/include/log0log.ic b/storage/innobase/include/log0log.ic index 4fdc2b0258e..d7232bc5944 100644 --- a/storage/innobase/include/log0log.ic +++ b/storage/innobase/include/log0log.ic @@ -290,18 +290,6 @@ log_reserve_and_write_fast( return lsn; } -/**************************************************************** -Get log_sys::max_modified_age_async. It is OK to read the value without -holding log_sys::mutex because it is constant. -@return max_modified_age_async */ -UNIV_INLINE -lsn_t -log_get_max_modified_age_async(void) -/*================================*/ -{ - return(log_sys.max_modified_age_async); -} - /***********************************************************************//** Checks if there is need for a log buffer flush or a new checkpoint, and does this if yes. Any database operation should call this when it has modified diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 4487bf94e01..72eadc60ae8 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -628,8 +628,8 @@ private: /** Append the redo log records to the redo log buffer. @param len number of bytes to write - @return start_lsn */ - inline lsn_t finish_write(ulint len); + @return {start_lsn,flush_ahead} */ + inline std::pair finish_write(ulint len); /** Release the resources */ inline void release_resources(); diff --git a/storage/innobase/include/srv0mon.h b/storage/innobase/include/srv0mon.h index a18ff5d49ad..33d8c57a744 100644 --- a/storage/innobase/include/srv0mon.h +++ b/storage/innobase/include/srv0mon.h @@ -195,13 +195,9 @@ enum monitor_id_t { MONITOR_FLUSH_N_TO_FLUSH_REQUESTED, MONITOR_FLUSH_N_TO_FLUSH_BY_AGE, - MONITOR_FLUSH_ADAPTIVE_AVG_TIME_SLOT, - MONITOR_FLUSH_ADAPTIVE_AVG_TIME_THREAD, - MONITOR_FLUSH_ADAPTIVE_AVG_TIME_EST, - MONITOR_FLUSH_AVG_TIME, + MONITOR_FLUSH_ADAPTIVE_AVG_TIME, MONITOR_FLUSH_ADAPTIVE_AVG_PASS, - MONITOR_FLUSH_AVG_PASS, MONITOR_LRU_GET_FREE_LOOPS, MONITOR_LRU_GET_FREE_WAITS, @@ -318,7 +314,6 @@ enum monitor_id_t { MONITOR_LSN_CHECKPOINT_AGE, MONITOR_OVLD_BUF_OLDEST_LSN, MONITOR_OVLD_MAX_AGE_ASYNC, - MONITOR_OVLD_MAX_AGE_SYNC, MONITOR_PENDING_LOG_FLUSH, MONITOR_PENDING_CHECKPOINT_WRITE, MONITOR_LOG_IO, @@ -394,7 +389,6 @@ enum monitor_id_t { MONITOR_SRV_DICT_LRU_MICROSECOND, MONITOR_SRV_DICT_LRU_EVICT_COUNT_ACTIVE, MONITOR_SRV_DICT_LRU_EVICT_COUNT_IDLE, - MONITOR_SRV_CHECKPOINT_MICROSECOND, MONITOR_OVLD_SRV_DBLWR_WRITES, MONITOR_OVLD_SRV_DBLWR_PAGES_WRITTEN, MONITOR_OVLD_SRV_PAGE_SIZE, diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 915cc3ffd4f..44712c5ae66 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -657,12 +657,6 @@ ulint srv_get_activity_count(void); /*========================*/ -/** Check if there has been any activity. -@param[in,out] activity_count recent activity count to be returned -if there is a change -@return FALSE if no change in activity counter. */ -bool srv_check_activity(ulint *activity_count); - /******************************************************************//** Increment the server activity counter. */ void diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 7563f30e8fb..472e39130c3 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -63,14 +63,6 @@ to the InnoDB redo log. */ /** Redo log system */ log_t log_sys; -/* These control how often we print warnings if the last checkpoint is too -old */ -static bool log_has_printed_chkp_warning = false; -static time_t log_last_warning_time; - -static bool log_has_printed_chkp_margine_warning = false; -static time_t log_last_margine_warning_time; - /* A margin for free space in the log buffer before a log entry is catenated */ #define LOG_BUF_WRITE_MARGIN (4 * OS_FILE_LOG_BLOCK_SIZE) @@ -79,31 +71,6 @@ static time_t log_last_margine_warning_time; #define LOG_BUF_FLUSH_MARGIN (LOG_BUF_WRITE_MARGIN \ + (4U << srv_page_size_shift)) -/* This parameter controls asynchronous making of a new checkpoint; the value -should be bigger than LOG_POOL_PREFLUSH_RATIO_SYNC */ - -#define LOG_POOL_CHECKPOINT_RATIO_ASYNC 32 - -/* This parameter controls synchronous preflushing of modified buffer pages */ -#define LOG_POOL_PREFLUSH_RATIO_SYNC 16 - -/* The same ratio for asynchronous preflushing; this value should be less than -the previous */ -#define LOG_POOL_PREFLUSH_RATIO_ASYNC 8 - -/** Return the oldest modified LSN in buf_pool.flush_list, -or the latest LSN if all pages are clean. -@return LSN of oldest modification */ -static lsn_t log_buf_pool_get_oldest_modification() -{ - ut_ad(log_mutex_own()); - log_flush_order_mutex_enter(); - lsn_t lsn= buf_pool.get_oldest_modification(); - log_flush_order_mutex_exit(); - - return lsn ? lsn : log_sys.get_lsn(); -} - /** Extends the log buffer. @param[in] len requested minimum size in bytes */ void log_buffer_extend(ulong len) @@ -151,276 +118,6 @@ void log_buffer_extend(ulong len) << new_buf_size << "."; } -/** Calculate actual length in redo buffer and file including -block header and trailer. -@param[in] len length to write -@return actual length to write including header and trailer. */ -static inline -ulint -log_calculate_actual_len( - ulint len) -{ - ut_ad(log_mutex_own()); - - const ulint framing_size = log_sys.framing_size(); - /* actual length stored per block */ - const ulint len_per_blk = OS_FILE_LOG_BLOCK_SIZE - framing_size; - - /* actual data length in last block already written */ - ulint extra_len = (log_sys.buf_free % OS_FILE_LOG_BLOCK_SIZE); - - ut_ad(extra_len >= LOG_BLOCK_HDR_SIZE); - extra_len -= LOG_BLOCK_HDR_SIZE; - - /* total extra length for block header and trailer */ - extra_len = ((len + extra_len) / len_per_blk) * framing_size; - - return(len + extra_len); -} - -/** Check margin not to overwrite transaction log from the last checkpoint. -If would estimate the log write to exceed the log_capacity, -waits for the checkpoint is done enough. -@param[in] len length of the data to be written */ - -void -log_margin_checkpoint_age( - ulint len) -{ - ulint margin = log_calculate_actual_len(len); - - ut_ad(log_mutex_own()); - - if (margin > log_sys.log_capacity) { - /* return with warning output to avoid deadlock */ - if (!log_has_printed_chkp_margine_warning - || difftime(time(NULL), - log_last_margine_warning_time) > 15) { - log_has_printed_chkp_margine_warning = true; - log_last_margine_warning_time = time(NULL); - - ib::error() << "The transaction log file is too" - " small for the single transaction log (size=" - << len << "). So, the last checkpoint age" - " might exceed the log capacity " - << log_sys.log_capacity << "."; - } - - return; - } - - /* Our margin check should ensure that we never reach this condition. - Try to do checkpoint once. We cannot keep waiting here as it might - result in hang in case the current mtr has latch on oldest lsn */ - const lsn_t lsn = log_sys.get_lsn(); - - if (lsn - log_sys.last_checkpoint_lsn + margin - > log_sys.log_capacity) { - /* The log write of 'len' might overwrite the transaction log - after the last checkpoint. Makes checkpoint. */ - - const bool flushed_enough = lsn - - log_buf_pool_get_oldest_modification() + margin - <= log_sys.log_capacity; - - log_sys.set_check_flush_or_checkpoint(); - log_mutex_exit(); - - DEBUG_SYNC_C("margin_checkpoint_age_rescue"); - - if (!flushed_enough) { - os_thread_sleep(100000); - } - log_checkpoint(); - - log_mutex_enter(); - } - - return; -} - -/** Open the log for log_write_low. The log must be closed with log_close. -@param[in] len length of the data to be written -@return start lsn of the log record */ -lsn_t -log_reserve_and_open( - ulint len) -{ - ulint len_upper_limit; -#ifdef UNIV_DEBUG - ulint count = 0; -#endif /* UNIV_DEBUG */ - -loop: - ut_ad(log_mutex_own()); - - /* Calculate an upper limit for the space the string may take in the - log buffer */ - - len_upper_limit = LOG_BUF_WRITE_MARGIN + srv_log_write_ahead_size - + (5 * len) / 4; - - if (log_sys.buf_free + len_upper_limit > srv_log_buffer_size) { - log_mutex_exit(); - - DEBUG_SYNC_C("log_buf_size_exceeded"); - - /* Not enough free space, do a write of the log buffer */ - log_sys.initiate_write(false); - - srv_stats.log_waits.inc(); - - ut_ad(++count < 50); - - log_mutex_enter(); - goto loop; - } - - return(log_sys.get_lsn()); -} - -/************************************************************//** -Writes to the log the string given. It is assumed that the caller holds the -log mutex. */ -void -log_write_low( -/*==========*/ - const byte* str, /*!< in: string */ - ulint str_len) /*!< in: string length */ -{ - ulint len; - - ut_ad(log_mutex_own()); - const ulint trailer_offset = log_sys.trailer_offset(); -part_loop: - /* Calculate a part length */ - - ulint data_len = (log_sys.buf_free % OS_FILE_LOG_BLOCK_SIZE) + str_len; - - if (data_len <= trailer_offset) { - - /* The string fits within the current log block */ - - len = str_len; - } else { - data_len = trailer_offset; - - len = trailer_offset - - log_sys.buf_free % OS_FILE_LOG_BLOCK_SIZE; - } - - memcpy(log_sys.buf + log_sys.buf_free, str, len); - - str_len -= len; - str = str + len; - - byte* log_block = static_cast( - ut_align_down(log_sys.buf + log_sys.buf_free, - OS_FILE_LOG_BLOCK_SIZE)); - - log_block_set_data_len(log_block, data_len); - lsn_t lsn = log_sys.get_lsn(); - - if (data_len == trailer_offset) { - /* This block became full */ - log_block_set_data_len(log_block, OS_FILE_LOG_BLOCK_SIZE); - log_block_set_checkpoint_no(log_block, - log_sys.next_checkpoint_no); - len += log_sys.framing_size(); - - lsn += len; - - /* Initialize the next block header */ - log_block_init(log_block + OS_FILE_LOG_BLOCK_SIZE, lsn); - } else { - lsn += len; - } - - log_sys.set_lsn(lsn); - log_sys.buf_free += len; - - ut_ad(log_sys.buf_free <= size_t{srv_log_buffer_size}); - - if (str_len > 0) { - goto part_loop; - } - - srv_stats.log_write_requests.inc(); -} - -/************************************************************//** -Closes the log. -@return lsn */ -lsn_t -log_close(void) -/*===========*/ -{ - byte* log_block; - ulint first_rec_group; - lsn_t oldest_lsn; - lsn_t lsn; - lsn_t checkpoint_age; - - ut_ad(log_mutex_own()); - - lsn = log_sys.get_lsn(); - - log_block = static_cast( - ut_align_down(log_sys.buf + log_sys.buf_free, - OS_FILE_LOG_BLOCK_SIZE)); - - first_rec_group = log_block_get_first_rec_group(log_block); - - if (first_rec_group == 0) { - /* We initialized a new log block which was not written - full by the current mtr: the next mtr log record group - will start within this block at the offset data_len */ - - log_block_set_first_rec_group( - log_block, log_block_get_data_len(log_block)); - } - - if (log_sys.buf_free > log_sys.max_buf_free) { - log_sys.set_check_flush_or_checkpoint(); - } - - checkpoint_age = lsn - log_sys.last_checkpoint_lsn; - - if (checkpoint_age >= log_sys.log_capacity) { - DBUG_EXECUTE_IF( - "print_all_chkp_warnings", - log_has_printed_chkp_warning = false;); - - if (!log_has_printed_chkp_warning - || difftime(time(NULL), log_last_warning_time) > 15) { - - log_has_printed_chkp_warning = true; - log_last_warning_time = time(NULL); - - ib::error() << "The age of the last checkpoint is " - << checkpoint_age - << ", which exceeds the log capacity " - << log_sys.log_capacity << "."; - } - } - - if (checkpoint_age <= log_sys.max_modified_age_sync || - log_sys.check_flush_or_checkpoint()) { - goto function_exit; - } - - oldest_lsn = log_buf_pool_get_oldest_modification(); - - if (!oldest_lsn - || lsn - oldest_lsn > log_sys.max_modified_age_sync - || checkpoint_age > log_sys.max_checkpoint_age_async) { - log_sys.set_check_flush_or_checkpoint(); - } -function_exit: - - return(lsn); -} - /** Calculate the recommended highest values for lsn - last_checkpoint_lsn and lsn - buf_pool.get_oldest_modification(). @param[in] file_size requested innodb_log_file_size @@ -465,13 +162,7 @@ log_set_capacity(ulonglong file_size) log_sys.log_capacity = smallest_capacity; - log_sys.max_modified_age_async = margin - - margin / LOG_POOL_PREFLUSH_RATIO_ASYNC; - log_sys.max_modified_age_sync = margin - - margin / LOG_POOL_PREFLUSH_RATIO_SYNC; - - log_sys.max_checkpoint_age_async = margin - margin - / LOG_POOL_CHECKPOINT_RATIO_ASYNC; + log_sys.max_modified_age_async = margin - margin / 8; log_sys.max_checkpoint_age = margin; log_mutex_exit(); @@ -518,8 +209,6 @@ void log_t::create() n_log_ios_old= 0; log_capacity= 0; max_modified_age_async= 0; - max_modified_age_sync= 0; - max_checkpoint_age_async= 0; max_checkpoint_age= 0; next_checkpoint_no= 0; next_checkpoint_lsn= 0; @@ -1151,10 +840,7 @@ log_buffer_flush_to_disk( Tries to establish a big enough margin of free space in the log buffer, such that a new log entry can be catenated without an immediate need for a flush. */ -static -void -log_flush_margin(void) -/*==================*/ +ATTRIBUTE_COLD static void log_flush_margin() { lsn_t lsn = 0; @@ -1172,61 +858,9 @@ log_flush_margin(void) } } -/** Advances the smallest lsn for which there are unflushed dirty blocks in the -buffer pool. -NOTE: this function may only be called if the calling thread owns no -synchronization objects! -@param[in] new_oldest try to advance oldest_modified_lsn at least to -this lsn -@return false if there was a flush batch of the same type running, -which means that we could not start this flush batch */ -static bool log_preflush_pool_modified_pages(lsn_t new_oldest) -{ - bool success; - - if (recv_recovery_is_on()) { - /* If the recovery is running, we must first apply all - log records to their respective file pages to get the - right modify lsn values to these pages: otherwise, there - might be pages on disk which are not yet recovered to the - current lsn, and even after calling this function, we could - not know how up-to-date the disk version of the database is, - and we could not make a new checkpoint on the basis of the - info on the buffer pool only. */ - recv_sys.apply(true); - } - - if (new_oldest == LSN_MAX - || !buf_page_cleaner_is_active - || srv_is_being_started) { - - ulint n_pages = buf_flush_lists(ULINT_UNDEFINED, new_oldest); - - buf_flush_wait_batch_end_acquiring_mutex(false); - - MONITOR_INC(MONITOR_FLUSH_SYNC_WAITS); - - MONITOR_INC_VALUE_CUMULATIVE( - MONITOR_FLUSH_SYNC_TOTAL_PAGE, - MONITOR_FLUSH_SYNC_COUNT, - MONITOR_FLUSH_SYNC_PAGES, - n_pages); - - const lsn_t oldest = buf_pool.get_oldest_modification(); - success = !oldest || oldest >= new_oldest; - } else { - /* better to wait for flushed by page cleaner */ - buf_flush_wait_flushed(new_oldest); - - success = true; - } - - return(success); -} - /** Write checkpoint info to the log header and invoke log_mutex_exit(). @param[in] end_lsn start LSN of the FILE_CHECKPOINT mini-transaction */ -void log_write_checkpoint_info(lsn_t end_lsn) +ATTRIBUTE_COLD void log_write_checkpoint_info(lsn_t end_lsn) { ut_ad(log_mutex_own()); ut_ad(!srv_read_only_mode); @@ -1296,194 +930,40 @@ void log_write_checkpoint_info(lsn_t end_lsn) log_mutex_exit(); } -/** Make a checkpoint. Note that this function does not flush dirty -blocks from the buffer pool: it only checks what is lsn of the oldest -modification in the pool, and writes information about the lsn in -log file. Use log_make_checkpoint() to flush also the pool. -@return true if success, false if a checkpoint write was already running */ -bool log_checkpoint() -{ - lsn_t oldest_lsn; - - ut_ad(!srv_read_only_mode); - - DBUG_EXECUTE_IF("no_checkpoint", - /* We sleep for a long enough time, forcing - the checkpoint doesn't happen any more. */ - os_thread_sleep(360000000);); - - if (recv_recovery_is_on()) { - recv_sys.apply(true); - } - - switch (srv_file_flush_method) { - case SRV_NOSYNC: - break; - case SRV_O_DSYNC: - case SRV_FSYNC: - case SRV_LITTLESYNC: - case SRV_O_DIRECT: - case SRV_O_DIRECT_NO_FSYNC: -#ifdef _WIN32 - case SRV_ALL_O_DIRECT_FSYNC: -#endif - fil_flush_file_spaces(); - } - - log_mutex_enter(); - - ut_ad(!recv_no_log_write); - oldest_lsn = log_buf_pool_get_oldest_modification(); - - /* Because log also contains headers and dummy log records, - log_buf_pool_get_oldest_modification() will return log_sys.lsn - if the buffer pool contains no dirty buffers. - We must make sure that the log is flushed up to that lsn. - If there are dirty buffers in the buffer pool, then our - write-ahead-logging algorithm ensures that the log has been - flushed up to oldest_lsn. */ - - ut_ad(oldest_lsn >= log_sys.last_checkpoint_lsn); - if (oldest_lsn - > log_sys.last_checkpoint_lsn + SIZE_OF_FILE_CHECKPOINT) { - /* Some log has been written since the previous checkpoint. */ - } else if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED) { - /* MariaDB startup expects the redo log file to be - logically empty (not even containing a MLOG_CHECKPOINT record) - after a clean shutdown. Perform an extra checkpoint at - shutdown. */ - } else { - /* Do nothing, because nothing was logged (other than - a FILE_CHECKPOINT marker) since the previous checkpoint. */ - log_mutex_exit(); - return(true); - } - /* Repeat the FILE_MODIFY records after the checkpoint, in - case some log records between the checkpoint and log_sys.lsn - need them. Finally, write a FILE_CHECKPOINT marker. Redo log - apply expects to see a FILE_CHECKPOINT after the checkpoint, - except on clean shutdown, where the log will be empty after - the checkpoint. - It is important that we write out the redo log before any - further dirty pages are flushed to the tablespace files. At - this point, because log_mutex_own(), mtr_commit() in other - threads will be blocked, and no pages can be added to the - flush lists. */ - lsn_t flush_lsn = oldest_lsn; - const lsn_t end_lsn = log_sys.get_lsn(); - const bool do_write - = srv_shutdown_state <= SRV_SHUTDOWN_INITIATED - || flush_lsn != end_lsn; - - if (fil_names_clear(flush_lsn, do_write)) { - flush_lsn = log_sys.get_lsn(); - ut_ad(flush_lsn >= end_lsn + SIZE_OF_FILE_CHECKPOINT); - } - - log_mutex_exit(); - - log_write_up_to(flush_lsn, true, true); - - log_mutex_enter(); - - ut_ad(log_sys.get_flushed_lsn() >= flush_lsn); - ut_ad(flush_lsn >= oldest_lsn); - - if (log_sys.last_checkpoint_lsn >= oldest_lsn) { - log_mutex_exit(); - return(true); - } - - if (log_sys.n_pending_checkpoint_writes > 0) { - /* A checkpoint write is running */ - log_mutex_exit(); - - return(false); - } - - log_sys.next_checkpoint_lsn = oldest_lsn; - log_write_checkpoint_info(end_lsn); - ut_ad(!log_mutex_own()); - - return(true); -} - -/** Make a checkpoint */ -void log_make_checkpoint() -{ - /* Preflush pages synchronously */ - - while (!log_preflush_pool_modified_pages(LSN_MAX)) { - /* Flush as much as we can */ - } - - while (!log_checkpoint()) { - /* Force a checkpoint */ - } -} - /****************************************************************//** -Tries to establish a big enough margin of free space in the log groups, such +Tries to establish a big enough margin of free space in the log, such that a new log entry can be catenated without an immediate need for a checkpoint. NOTE: this function may only be called if the calling thread owns no synchronization objects! */ -static -void -log_checkpoint_margin(void) -/*=======================*/ +ATTRIBUTE_COLD static void log_checkpoint_margin() { - ib_uint64_t advance; - bool success; -loop: - advance = 0; + while (log_sys.check_flush_or_checkpoint()) + { + log_mutex_enter(); + ut_ad(!recv_no_log_write); - log_mutex_enter(); - ut_ad(!recv_no_log_write); + if (!log_sys.check_flush_or_checkpoint()) + { +func_exit: + log_mutex_exit(); + return; + } - if (!log_sys.check_flush_or_checkpoint()) { - log_mutex_exit(); - return; - } + const lsn_t lsn= log_sys.get_lsn(); + const lsn_t checkpoint= log_sys.last_checkpoint_lsn; + const lsn_t sync_lsn= checkpoint + log_sys.max_checkpoint_age; + if (lsn <= sync_lsn) + { + log_sys.set_check_flush_or_checkpoint(false); + goto func_exit; + } - const lsn_t oldest_lsn = log_buf_pool_get_oldest_modification(); - const lsn_t lsn = log_sys.get_lsn(); - const lsn_t age = lsn - oldest_lsn; + log_mutex_exit(); - if (age > log_sys.max_modified_age_sync) { - - /* A flush is urgent: we have to do a synchronous preflush */ - advance = age - log_sys.max_modified_age_sync; - } - - const lsn_t checkpoint_age = lsn - log_sys.last_checkpoint_lsn; - - ut_ad(log_sys.max_checkpoint_age >= log_sys.max_checkpoint_age_async); - const bool do_checkpoint - = checkpoint_age > log_sys.max_checkpoint_age_async; - - if (checkpoint_age <= log_sys.max_checkpoint_age) { - log_sys.set_check_flush_or_checkpoint(false); - } - - log_mutex_exit(); - - if (advance) { - lsn_t new_oldest = oldest_lsn + advance; - - success = log_preflush_pool_modified_pages(new_oldest); - - /* If the flush succeeded, this thread has done its part - and can proceed. If it did not succeed, there was another - thread doing a flush at the same time. */ - if (!success) { - log_sys.set_check_flush_or_checkpoint(); - goto loop; - } - } - - if (do_checkpoint) { - log_checkpoint(); - } + /* We must wait to prevent the tail of the log overwriting the head. */ + buf_flush_wait_flushed(std::min(sync_lsn, checkpoint + (1U << 20))); + os_thread_sleep(10000); /* Sleep 10ms to avoid a thundering herd */ + } } /** @@ -1491,7 +971,7 @@ Checks that there is enough free space in the log to start a new query step. Flushes the log buffer or makes a new checkpoint if necessary. NOTE: this function may only be called if the calling thread owns no synchronization objects! */ -void log_check_margins() +ATTRIBUTE_COLD void log_check_margins() { do { @@ -1504,43 +984,8 @@ void log_check_margins() extern void buf_resize_shutdown(); -/** @return the number of dirty pages in the buffer pool */ -static ulint flush_list_length() -{ - mysql_mutex_lock(&buf_pool.flush_list_mutex); - const ulint len= UT_LIST_GET_LEN(buf_pool.flush_list); - mysql_mutex_unlock(&buf_pool.flush_list_mutex); - return len; -} - -static void flush_buffer_pool() -{ - service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, - "Waiting to flush the buffer pool"); - while (buf_pool.n_flush_list || flush_list_length()) - { - buf_flush_lists(ULINT_UNDEFINED, LSN_MAX); - timespec abstime; - - if (buf_pool.n_flush_list) - { - service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, - "Waiting to flush " ULINTPF " pages", - flush_list_length()); - set_timespec(abstime, INNODB_EXTEND_TIMEOUT_INTERVAL / 2); - mysql_mutex_lock(&buf_pool.mutex); - while (buf_pool.n_flush_list) - mysql_cond_timedwait(&buf_pool.done_flush_list, &buf_pool.mutex, - &abstime); - mysql_mutex_unlock(&buf_pool.mutex); - } - } - - ut_ad(!buf_pool.any_io_pending()); -} - /** Make a checkpoint at the latest lsn on shutdown. */ -void logs_empty_and_mark_files_at_shutdown() +ATTRIBUTE_COLD void logs_empty_and_mark_files_at_shutdown() { lsn_t lsn; ulint count = 0; @@ -1659,7 +1104,7 @@ wait_suspend_loop: goto loop; } else { - flush_buffer_pool(); + buf_flush_buffer_pool(); } if (log_sys.is_initialised()) { @@ -1777,14 +1222,19 @@ log_print( log_mutex_enter(); + const lsn_t lsn= log_sys.get_lsn(); + mysql_mutex_lock(&buf_pool.flush_list_mutex); + const lsn_t pages_flushed = buf_pool.get_oldest_modification(lsn); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + fprintf(file, "Log sequence number " LSN_PF "\n" "Log flushed up to " LSN_PF "\n" "Pages flushed up to " LSN_PF "\n" "Last checkpoint at " LSN_PF "\n", - log_sys.get_lsn(), + lsn, log_sys.get_flushed_lsn(), - log_buf_pool_get_oldest_modification(), + pages_flushed, log_sys.last_checkpoint_lsn); current_time = time(NULL); diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index 17b524f610f..a3a2b8f4f45 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -350,17 +350,6 @@ struct ReleaseBlocks } }; -/** Write the block contents to the REDO log */ -struct mtr_write_log_t { - /** Append a block to the redo log buffer. - @return whether the appending should continue */ - bool operator()(const mtr_buf_t::block_t* block) const - { - log_write_low(block->begin(), block->used()); - return(true); - } -}; - /** Start a mini-transaction. */ void mtr_t::start() { @@ -411,12 +400,12 @@ void mtr_t::commit() { ut_ad(!srv_read_only_mode || m_log_mode == MTR_LOG_NO_REDO); - lsn_t start_lsn; + std::pair lsns; if (const ulint len= prepare_write()) - start_lsn= finish_write(len); + lsns= finish_write(len); else - start_lsn= m_commit_lsn; + lsns= { m_commit_lsn, false }; if (m_made_dirty) log_flush_order_mutex_enter(); @@ -453,12 +442,18 @@ void mtr_t::commit() } m_memo.for_each_block_in_reverse(CIterate - (ReleaseBlocks(start_lsn, m_commit_lsn, + (ReleaseBlocks(lsns.first, m_commit_lsn, m_memo))); if (m_made_dirty) log_flush_order_mutex_exit(); m_memo.for_each_block_in_reverse(CIterate()); + + if (lsns.second) + buf_flush_ahead(m_commit_lsn); + + if (m_made_dirty) + srv_stats.log_write_requests.inc(); } else m_memo.for_each_block_in_reverse(CIterate()); @@ -496,6 +491,7 @@ void mtr_t::commit_files(lsn_t checkpoint_lsn) } finish_write(m_log.size()); + srv_stats.log_write_requests.inc(); release_resources(); if (checkpoint_lsn) { @@ -621,6 +617,200 @@ mtr_t::release_page(const void* ptr, mtr_memo_type_t type) ut_ad(0); } +static bool log_margin_warned; +static time_t log_margin_warn_time; +static bool log_close_warned; +static time_t log_close_warn_time; + +/** Check margin not to overwrite transaction log from the last checkpoint. +If would estimate the log write to exceed the log_capacity, +waits for the checkpoint is done enough. +@param len length of the data to be written */ +static void log_margin_checkpoint_age(ulint len) +{ + const ulint framing_size= log_sys.framing_size(); + /* actual length stored per block */ + const ulint len_per_blk= OS_FILE_LOG_BLOCK_SIZE - framing_size; + + /* actual data length in last block already written */ + ulint extra_len= log_sys.buf_free % OS_FILE_LOG_BLOCK_SIZE; + + ut_ad(extra_len >= LOG_BLOCK_HDR_SIZE); + extra_len-= LOG_BLOCK_HDR_SIZE; + + /* total extra length for block header and trailer */ + extra_len= ((len + extra_len) / len_per_blk) * framing_size; + + const ulint margin= len + extra_len; + + ut_ad(log_mutex_own()); + + const lsn_t lsn= log_sys.get_lsn(); + + if (UNIV_UNLIKELY(margin > log_sys.log_capacity)) + { + time_t t= time(nullptr); + + /* return with warning output to avoid deadlock */ + if (!log_margin_warned || difftime(t, log_margin_warn_time) > 15) + { + log_margin_warned= true; + log_margin_warn_time= t; + + ib::error() << "innodb_log_file_size is too small " + "for mini-transaction size " << len; + } + } + else if (UNIV_LIKELY(lsn + margin <= log_sys.last_checkpoint_lsn + + log_sys.log_capacity)) + return; + + log_sys.set_check_flush_or_checkpoint(); +} + + +/** Open the log for log_write_low(). The log must be closed with log_close(). +@param len length of the data to be written +@return start lsn of the log record */ +static lsn_t log_reserve_and_open(size_t len) +{ + for (ut_d(ulint count= 0);;) + { + ut_ad(log_mutex_own()); + + /* Calculate an upper limit for the space the string may take in + the log buffer */ + + size_t len_upper_limit= (4 * OS_FILE_LOG_BLOCK_SIZE) + + srv_log_write_ahead_size + (5 * len) / 4; + + if (log_sys.buf_free + len_upper_limit <= srv_log_buffer_size) + break; + + log_mutex_exit(); + DEBUG_SYNC_C("log_buf_size_exceeded"); + + /* Not enough free space, do a write of the log buffer */ + log_sys.initiate_write(false); + + srv_stats.log_waits.inc(); + + ut_ad(++count < 50); + + log_mutex_enter(); + } + + return log_sys.get_lsn(); +} + +/** Append data to the log buffer. */ +static void log_write_low(const void *str, size_t size) +{ + ut_ad(log_mutex_own()); + const ulint trailer_offset= log_sys.trailer_offset(); + + do + { + /* Calculate a part length */ + size_t len= size; + size_t data_len= (log_sys.buf_free % OS_FILE_LOG_BLOCK_SIZE) + size; + + if (data_len > trailer_offset) + { + data_len= trailer_offset; + len= trailer_offset - log_sys.buf_free % OS_FILE_LOG_BLOCK_SIZE; + } + + memcpy(log_sys.buf + log_sys.buf_free, str, len); + + size-= len; + str= static_cast(str) + len; + + byte *log_block= static_cast(ut_align_down(log_sys.buf + + log_sys.buf_free, + OS_FILE_LOG_BLOCK_SIZE)); + + log_block_set_data_len(log_block, data_len); + lsn_t lsn= log_sys.get_lsn(); + + if (data_len == trailer_offset) + { + /* This block became full */ + log_block_set_data_len(log_block, OS_FILE_LOG_BLOCK_SIZE); + log_block_set_checkpoint_no(log_block, log_sys.next_checkpoint_no); + len+= log_sys.framing_size(); + lsn+= len; + /* Initialize the next block header */ + log_block_init(log_block + OS_FILE_LOG_BLOCK_SIZE, lsn); + } + else + lsn+= len; + + log_sys.set_lsn(lsn); + log_sys.buf_free+= len; + + ut_ad(log_sys.buf_free <= size_t{srv_log_buffer_size}); + } + while (size); +} + +/** Close the log at mini-transaction commit. +@return whether buffer pool flushing is needed */ +static bool log_close(lsn_t lsn) +{ + ut_ad(log_mutex_own()); + ut_ad(lsn == log_sys.get_lsn()); + + byte *log_block= static_cast(ut_align_down(log_sys.buf + + log_sys.buf_free, + OS_FILE_LOG_BLOCK_SIZE)); + + if (!log_block_get_first_rec_group(log_block)) + { + /* We initialized a new log block which was not written + full by the current mtr: the next mtr log record group + will start within this block at the offset data_len */ + log_block_set_first_rec_group(log_block, + log_block_get_data_len(log_block)); + } + + if (log_sys.buf_free > log_sys.max_buf_free) + log_sys.set_check_flush_or_checkpoint(); + + const lsn_t checkpoint_age= lsn - log_sys.last_checkpoint_lsn; + + if (UNIV_UNLIKELY(checkpoint_age >= log_sys.log_capacity)) + { + time_t t= time(nullptr); + if (!log_close_warned || difftime(t, log_close_warn_time) > 15) + { + log_close_warned= true; + log_close_warn_time= t; + + ib::error() << "The age of the last checkpoint is " << checkpoint_age + << ", which exceeds the log capacity " + << log_sys.log_capacity << "."; + } + } + else if (UNIV_LIKELY(checkpoint_age <= log_sys.max_checkpoint_age)) + return false; + + log_sys.set_check_flush_or_checkpoint(); + return true; +} + +/** Write the block contents to the REDO log */ +struct mtr_write_log +{ + /** Append a block to the redo log buffer. + @return whether the appending should continue */ + bool operator()(const mtr_buf_t::block_t *block) const + { + log_write_low(block->begin(), block->used()); + return true; + } +}; + /** Prepare to write the mini-transaction log to the redo log buffer. @return number of bytes to write in finish_write() */ inline ulint mtr_t::prepare_write() @@ -668,10 +858,10 @@ inline ulint mtr_t::prepare_write() return(len); } -/** Append the redo log records to the redo log buffer -@param[in] len number of bytes to write -@return start_lsn */ -inline lsn_t mtr_t::finish_write(ulint len) +/** Append the redo log records to the redo log buffer. +@param len number of bytes to write +@return {start_lsn,flush_ahead_lsn} */ +inline std::pair mtr_t::finish_write(ulint len) { ut_ad(m_log_mode == MTR_LOG_ALL); ut_ad(log_mutex_own()); @@ -688,18 +878,19 @@ inline lsn_t mtr_t::finish_write(ulint len) &start_lsn); if (m_commit_lsn) { - return start_lsn; + return std::make_pair(start_lsn, false); } } /* Open the database log for log_write_low */ start_lsn = log_reserve_and_open(len); - mtr_write_log_t write_log; + mtr_write_log write_log; m_log.for_each_block(write_log); + m_commit_lsn = log_sys.get_lsn(); + bool flush = log_close(m_commit_lsn); - m_commit_lsn = log_close(); - return start_lsn; + return std::make_pair(start_lsn, flush); } /** Find buffer fix count of the given block acquired by the diff --git a/storage/innobase/srv/srv0mon.cc b/storage/innobase/srv/srv0mon.cc index 81ab97daac9..2af29fded26 100644 --- a/storage/innobase/srv/srv0mon.cc +++ b/storage/innobase/srv/srv0mon.cc @@ -381,36 +381,16 @@ static monitor_info_t innodb_counter_info[] = MONITOR_NONE, MONITOR_DEFAULT_START, MONITOR_FLUSH_N_TO_FLUSH_BY_AGE}, - {"buffer_flush_adaptive_avg_time_slot", "buffer", - "Avg time (ms) spent for adaptive flushing recently per slot.", + {"buffer_flush_adaptive_avg_time", "buffer", + "Avg time (ms) spent for adaptive flushing recently.", MONITOR_NONE, - MONITOR_DEFAULT_START, MONITOR_FLUSH_ADAPTIVE_AVG_TIME_SLOT}, - - {"buffer_flush_adaptive_avg_time_thread", "buffer", - "Avg time (ms) spent for adaptive flushing recently per thread.", - MONITOR_NONE, - MONITOR_DEFAULT_START, MONITOR_FLUSH_ADAPTIVE_AVG_TIME_THREAD}, - - {"buffer_flush_adaptive_avg_time_est", "buffer", - "Estimated time (ms) spent for adaptive flushing recently.", - MONITOR_NONE, - MONITOR_DEFAULT_START, MONITOR_FLUSH_ADAPTIVE_AVG_TIME_EST}, - - {"buffer_flush_avg_time", "buffer", - "Avg time (ms) spent for flushing recently.", - MONITOR_NONE, - MONITOR_DEFAULT_START, MONITOR_FLUSH_AVG_TIME}, + MONITOR_DEFAULT_START, MONITOR_FLUSH_ADAPTIVE_AVG_TIME}, {"buffer_flush_adaptive_avg_pass", "buffer", "Number of adaptive flushes passed during the recent Avg period.", MONITOR_NONE, MONITOR_DEFAULT_START, MONITOR_FLUSH_ADAPTIVE_AVG_PASS}, - {"buffer_flush_avg_pass", "buffer", - "Number of flushes passed during the recent Avg period.", - MONITOR_NONE, - MONITOR_DEFAULT_START, MONITOR_FLUSH_AVG_PASS}, - {"buffer_LRU_get_free_loops", "buffer", "Total loops in LRU get free.", MONITOR_NONE, @@ -868,12 +848,6 @@ static monitor_info_t innodb_counter_info[] = MONITOR_EXISTING | MONITOR_DISPLAY_CURRENT), MONITOR_DEFAULT_START, MONITOR_OVLD_MAX_AGE_ASYNC}, - {"log_max_modified_age_sync", "recovery", - "Maximum LSN difference; when exceeded, start synchronous preflush", - static_cast( - MONITOR_EXISTING | MONITOR_DISPLAY_CURRENT), - MONITOR_DEFAULT_START, MONITOR_OVLD_MAX_AGE_SYNC}, - {"log_pending_log_flushes", "recovery", "Pending log flushes", static_cast( MONITOR_EXISTING | MONITOR_DISPLAY_CURRENT), @@ -1172,11 +1146,6 @@ static monitor_info_t innodb_counter_info[] = MONITOR_NONE, MONITOR_DEFAULT_START, MONITOR_SRV_DICT_LRU_EVICT_COUNT_IDLE}, - {"innodb_checkpoint_usec", "server", - "Time (in microseconds) spent by master thread to do checkpoint", - MONITOR_NONE, - MONITOR_DEFAULT_START, MONITOR_SRV_CHECKPOINT_MICROSECOND}, - {"innodb_dblwr_writes", "server", "Number of doublewrite operations that have been performed" " (innodb_dblwr_writes)", @@ -1956,7 +1925,9 @@ srv_mon_process_existing_counter( break; case MONITOR_OVLD_BUF_OLDEST_LSN: - value = (mon_type_t) buf_pool.get_oldest_modification(); + mysql_mutex_lock(&buf_pool.flush_list_mutex); + value = (mon_type_t) buf_pool.get_oldest_modification(0); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); break; case MONITOR_OVLD_LSN_CHECKPOINT: @@ -1967,10 +1938,6 @@ srv_mon_process_existing_counter( value = log_sys.max_modified_age_async; break; - case MONITOR_OVLD_MAX_AGE_SYNC: - value = log_sys.max_modified_age_sync; - break; - #ifdef BTR_CUR_HASH_ADAPT case MONITOR_OVLD_ADAPTIVE_HASH_SEARCH: value = btr_cur_n_sea; diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 6337428e450..44d33126e48 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -1553,11 +1553,10 @@ srv_get_activity_count(void) return(srv_sys.activity_count); } -/** Check if there has been any activity. -@param[in,out] activity_count recent activity count to be returned -if there is a change -@return FALSE if no change in activity counter. */ -bool srv_check_activity(ulint *activity_count) +/** Check if srv_inc_activity_count() has been called. +@param activity_count copy of srv_sys.activity_count +@return whether the activity_count had changed */ +static bool srv_check_activity(ulint *activity_count) { ulint new_activity_count= srv_sys.activity_count; if (new_activity_count != *activity_count) @@ -1757,28 +1756,6 @@ srv_master_do_active_tasks(void) MONITOR_INC_TIME_IN_MICRO_SECS( MONITOR_SRV_DICT_LRU_MICROSECOND, counter_time); } - - /* The periodic log_checkpoint() call here makes it harder to - reproduce bugs in crash recovery or mariabackup --prepare, or - in code that writes the redo log records. Omitting the call - here should not affect correctness, because log_free_check() - should still be invoking checkpoints when needed. In a - production server, those calls could cause "furious flushing" - and stall the server. Normally we want to perform checkpoints - early and often to avoid those situations. */ - DBUG_EXECUTE_IF("ib_log_checkpoint_avoid", return;); - - if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED) { - return; - } - - /* Make a new checkpoint */ - if (cur_time % SRV_MASTER_CHECKPOINT_INTERVAL == 0) { - srv_main_thread_op_info = "making checkpoint"; - log_checkpoint(); - MONITOR_INC_TIME_IN_MICRO_SECS( - MONITOR_SRV_CHECKPOINT_MICROSECOND, counter_time); - } } /*********************************************************************//** @@ -1837,26 +1814,6 @@ srv_master_do_idle_tasks(void) srv_sync_log_buffer_in_background(); MONITOR_INC_TIME_IN_MICRO_SECS( MONITOR_SRV_LOG_FLUSH_MICROSECOND, counter_time); - - /* The periodic log_checkpoint() call here makes it harder to - reproduce bugs in crash recovery or mariabackup --prepare, or - in code that writes the redo log records. Omitting the call - here should not affect correctness, because log_free_check() - should still be invoking checkpoints when needed. In a - production server, those calls could cause "furious flushing" - and stall the server. Normally we want to perform checkpoints - early and often to avoid those situations. */ - DBUG_EXECUTE_IF("ib_log_checkpoint_avoid", return;); - - if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED) { - return; - } - - /* Make a new checkpoint */ - srv_main_thread_op_info = "making checkpoint"; - log_checkpoint(); - MONITOR_INC_TIME_IN_MICRO_SECS(MONITOR_SRV_CHECKPOINT_MICROSECOND, - counter_time); } /** diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index f7fd1a3cec0..1746d351263 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -327,6 +327,7 @@ static dberr_t create_log_file(lsn_t lsn, std::string& logfile0) log_mutex_exit(); log_make_checkpoint(); + log_write_up_to(LSN_MAX, true); return DB_SUCCESS; } @@ -1297,6 +1298,7 @@ dberr_t srv_start(bool create_new_db) } std::string logfile0; + bool create_new_log = create_new_db; if (create_new_db) { flushed_lsn = log_sys.get_lsn(); log_sys.set_flushed_lsn(flushed_lsn); @@ -1318,7 +1320,8 @@ dberr_t srv_start(bool create_new_db) return srv_init_abort(err); } - if (srv_log_file_size == 0) { + create_new_log = srv_log_file_size == 0; + if (create_new_log) { if (flushed_lsn < lsn_t(1000)) { ib::error() << "Cannot create log file because" @@ -1433,10 +1436,17 @@ file_checked: return(srv_init_abort(err)); } } else { + /* Suppress warnings in fil_space_t::create() for files + that are being read before dict_boot() has recovered + DICT_HDR_MAX_SPACE_ID. */ + fil_system.space_id_reuse_warned = true; + /* We always try to do a recovery, even if the database had been shut down normally: this is the normal startup path */ - err = recv_recovery_from_checkpoint_start(flushed_lsn); + err = create_new_log + ? DB_SUCCESS + : recv_recovery_from_checkpoint_start(flushed_lsn); recv_sys.close_files(); recv_sys.dblwr.pages.clear(); @@ -1492,6 +1502,8 @@ file_checked: } } + fil_system.space_id_reuse_warned = false; + if (!srv_read_only_mode) { const ulint flags = FSP_FLAGS_PAGE_SSIZE(); for (ulint id = 0; id <= srv_undo_tablespaces; id++) { diff --git a/storage/rocksdb/mysql-test/rocksdb/r/innodb_i_s_tables_disabled.result b/storage/rocksdb/mysql-test/rocksdb/r/innodb_i_s_tables_disabled.result index d4623c2f054..ac6e2bcc633 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/innodb_i_s_tables_disabled.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/innodb_i_s_tables_disabled.result @@ -71,12 +71,8 @@ buffer_flush_neighbor buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NU buffer_flush_neighbor_pages buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 set_member Pages queued as a neighbor batch buffer_flush_n_to_flush_requested buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of pages requested for flushing. buffer_flush_n_to_flush_by_age buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of pages target by LSN Age for flushing. -buffer_flush_adaptive_avg_time_slot buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for adaptive flushing recently per slot. -buffer_flush_adaptive_avg_time_thread buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for adaptive flushing recently per thread. -buffer_flush_adaptive_avg_time_est buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Estimated time (ms) spent for adaptive flushing recently. -buffer_flush_avg_time buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for flushing recently. +buffer_flush_adaptive_avg_time buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Avg time (ms) spent for adaptive flushing recently. buffer_flush_adaptive_avg_pass buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of adaptive flushes passed during the recent Avg period. -buffer_flush_avg_pass buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of flushes passed during the recent Avg period. buffer_LRU_get_free_loops buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Total loops in LRU get free. buffer_LRU_get_free_waits buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Total sleep waits in LRU get free. buffer_flush_avg_page_rate buffer 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Average number of pages at which flushing is happening @@ -176,7 +172,6 @@ log_lsn_current recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 log_lsn_checkpoint_age recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value Current LSN value minus LSN at last checkpoint log_lsn_buf_pool_oldest recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value The oldest modified block LSN in the buffer pool log_max_modified_age_async recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value Maximum LSN difference; when exceeded, start asynchronous preflush -log_max_modified_age_sync recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value Maximum LSN difference; when exceeded, start synchronous preflush log_pending_log_flushes recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value Pending log flushes log_pending_checkpoint_writes recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value Pending checkpoints log_num_log_io recovery 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value Number of log I/Os @@ -227,7 +222,6 @@ innodb_log_flush_usec server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NU innodb_dict_lru_usec server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Time (in microseconds) spent to process DICT LRU list innodb_dict_lru_count_active server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of tables evicted from DICT LRU list in the active loop innodb_dict_lru_count_idle server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Number of tables evicted from DICT LRU list in the idle loop -innodb_checkpoint_usec server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 counter Time (in microseconds) spent by master thread to do checkpoint innodb_dblwr_writes server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 status_counter Number of doublewrite operations that have been performed (innodb_dblwr_writes) innodb_dblwr_pages_written server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 status_counter Number of pages that have been written for doublewrite operations (innodb_dblwr_pages_written) innodb_page_size server 0 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL 0 value InnoDB page size in bytes (innodb_page_size) From 45ed9dd957eebc7fc84feb2509f4aa6baa908a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 26 Oct 2020 15:59:30 +0200 Subject: [PATCH 240/323] MDEV-23855: Remove fil_system.LRU and reduce fil_system.mutex contention Also fixes MDEV-23929: innodb_flush_neighbors is not being ignored for system tablespace on SSD When the maximum configured number of file is exceeded, InnoDB will close data files. We used to maintain a fil_system.LRU list and a counter fil_node_t::n_pending to achieve this, at the huge cost of multiple fil_system.mutex operations per I/O operation. fil_node_open_file_low(): Implement a FIFO replacement policy: The last opened file will be moved to the end of fil_system.space_list, and files will be closed from the start of the list. However, we will not move tablespaces in fil_system.space_list while i_s_tablespaces_encryption_fill_table() is executing (producing output for INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION) because it may cause information of some tablespaces to go missing. We also avoid this in mariabackup --backup because datafiles_iter_next() assumes that the ordering is not changed. IORequest: Fold more parameters to IORequest::type. fil_space_t::io(): Replaces fil_io(). fil_space_t::flush(): Replaces fil_flush(). OS_AIO_IBUF: Remove. We will always issue synchronous reads of the change buffer pages in buf_read_page_low(). We will always ignore some errors for background reads. This should reduce fil_system.mutex contention a little. fil_node_t::complete_write(): Replaces fil_node_t::complete_io(). On both read and write completion, fil_space_t::release_for_io() will have to be called. fil_space_t::io(): Do not acquire fil_system.mutex in the normal code path. xb_delta_open_matching_space(): Do not try to open the system tablespace which was already opened. This fixes a file sharing violation in mariabackup --prepare --incremental. Reviewed by: Vladislav Vaintroub --- extra/mariabackup/fil_cur.cc | 25 +- extra/mariabackup/xtrabackup.cc | 63 +- .../t/innodb-remove-encryption.test | 3 + .../t/innodb_encrypt_key_rotation_age.test | 5 + .../r/table_definition_cache_debug.result | 2 +- mysql-test/suite/innodb/t/innodb-trim.test | 12 - .../t/table_definition_cache_debug.test | 2 +- storage/innobase/CMakeLists.txt | 2 +- storage/innobase/btr/btr0cur.cc | 37 +- storage/innobase/buf/buf0buf.cc | 27 +- storage/innobase/buf/buf0dblwr.cc | 88 +- storage/innobase/buf/buf0dump.cc | 45 +- storage/innobase/buf/buf0flu.cc | 240 +-- storage/innobase/buf/buf0rea.cc | 175 +- storage/innobase/dict/dict0crea.cc | 2 +- storage/innobase/dict/dict0load.cc | 8 +- storage/innobase/fil/fil0crypt.cc | 15 +- storage/innobase/fil/fil0fil.cc | 1448 ++++++----------- storage/innobase/fsp/fsp0file.cc | 5 +- storage/innobase/fsp/fsp0space.cc | 2 +- storage/innobase/fsp/fsp0sysspace.cc | 13 +- storage/innobase/handler/i_s.cc | 2 + storage/innobase/ibuf/ibuf0ibuf.cc | 26 +- storage/innobase/include/buf0buf.h | 9 + storage/innobase/include/buf0dblwr.h | 15 +- storage/innobase/include/buf0rea.h | 11 +- storage/innobase/include/fil0fil.h | 429 ++--- storage/innobase/include/fsp0types.h | 10 +- storage/innobase/include/os0api.h | 48 - storage/innobase/include/os0file.h | 193 +-- storage/innobase/include/os0file.ic | 10 +- storage/innobase/include/trx0sys.h | 5 +- storage/innobase/log/log0recv.cc | 13 +- storage/innobase/mtr/mtr0mtr.cc | 4 +- storage/innobase/os/os0file.cc | 136 +- storage/innobase/row/row0import.cc | 13 +- storage/innobase/row/row0quiesce.cc | 2 +- storage/innobase/srv/srv0start.cc | 47 +- storage/innobase/trx/trx0purge.cc | 7 +- 39 files changed, 1301 insertions(+), 1898 deletions(-) delete mode 100644 storage/innobase/include/os0api.h diff --git a/extra/mariabackup/fil_cur.cc b/extra/mariabackup/fil_cur.cc index 8f06005a9e4..7aa20b8700e 100644 --- a/extra/mariabackup/fil_cur.cc +++ b/extra/mariabackup/fil_cur.cc @@ -93,7 +93,6 @@ xb_fil_node_close_file( mutex_enter(&fil_system.mutex); ut_ad(node); - ut_a(node->n_pending == 0); ut_a(node->n_pending_flushes == 0); ut_a(!node->being_extended); @@ -108,20 +107,10 @@ xb_fil_node_close_file( ut_a(ret); node->handle = OS_FILE_CLOSED; + mutex_exit(&fil_system.mutex); ut_a(fil_system.n_open > 0); fil_system.n_open--; - - if (node->space->purpose == FIL_TYPE_TABLESPACE && - fil_is_user_tablespace_id(node->space->id)) { - - ut_a(UT_LIST_GET_LEN(fil_system.LRU) > 0); - - /* The node is in the LRU list, remove it */ - UT_LIST_REMOVE(fil_system.LRU, node); - } - - mutex_exit(&fil_system.mutex); } /************************************************************************ @@ -180,18 +169,8 @@ xb_fil_cur_open( return(XB_FIL_CUR_SKIP); } - mutex_enter(&fil_system.mutex); fil_system.n_open++; - - if (node->space->purpose == FIL_TYPE_TABLESPACE && - fil_is_user_tablespace_id(node->space->id)) { - - /* Put the node to the LRU list */ - UT_LIST_ADD_FIRST(fil_system.LRU, node); - } - - mutex_exit(&fil_system.mutex); } ut_ad(node->is_open()); @@ -427,7 +406,7 @@ xb_fil_cur_read( retry_count = 10; ret = XB_FIL_CUR_SUCCESS; - fil_space_t *space = fil_space_acquire_for_io(cursor->space_id); + fil_space_t *space = fil_space_t::get_for_io(cursor->space_id); if (!space) { return XB_FIL_CUR_ERROR; diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 3189bcd14cb..39025862276 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -3011,6 +3011,7 @@ void xb_fil_io_init() { fil_system.create(srv_file_per_table ? 50000 : 5000); + fil_system.freeze_space_list = 1; fil_system.space_id_reuse_warned = true; } @@ -3087,24 +3088,16 @@ xb_load_single_table_tablespace( bool is_empty_file = file->exists() && file->is_empty_file(); if (err == DB_SUCCESS && file->space_id() != SRV_TMP_SPACE_ID) { - os_offset_t node_size = os_file_get_size(file->handle()); - os_offset_t n_pages; - - ut_a(node_size != (os_offset_t) -1); - - n_pages = node_size / fil_space_t::physical_size(file->flags()); - - space = fil_space_create( + space = fil_space_t::create( name, file->space_id(), file->flags(), FIL_TYPE_TABLESPACE, NULL/* TODO: crypt_data */); ut_a(space != NULL); - space->add(file->filepath(), OS_FILE_CLOSED, uint32_t(n_pages), - false, false); + space->add(file->filepath(), OS_FILE_CLOSED, 0, false, false); /* by opening the tablespace we forcing node and space objects in the cache to be populated with fields from space header */ - space->open(); + space->get_size(); if (srv_operation == SRV_OPERATION_RESTORE_DELTA || xb_close_files) { @@ -3406,19 +3399,6 @@ xb_load_tablespaces() return(DB_SUCCESS); } -/************************************************************************ -Initialize the tablespace memory cache and populate it by scanning for and -opening data files. -@returns DB_SUCCESS or error code.*/ -static -dberr_t -xb_data_files_init() -{ - xb_fil_io_init(); - - return(xb_load_tablespaces()); -} - /** Destroy the tablespace memory cache. */ static void xb_data_files_close() { @@ -4607,6 +4587,22 @@ xb_delta_open_matching_space( return file; } + if (!info.space_id && fil_system.sys_space) { + fil_node_t *node + = UT_LIST_GET_FIRST(fil_system.sys_space->chain); + for (; node; node = UT_LIST_GET_NEXT(chain, node)) { + if (!strcmp(node->name, real_name)) { + break; + } + } + if (node && node->handle != OS_FILE_CLOSED) { + *success = true; + return node->handle; + } + msg("mariabackup: Cannot find file %s\n", real_name); + return OS_FILE_CLOSED; + } + log_mutex_enter(); if (!fil_is_user_tablespace_id(info.space_id)) { found: @@ -4704,8 +4700,8 @@ exit: ut_ad(fil_space_t::zip_size(flags) == info.zip_size); ut_ad(fil_space_t::physical_size(flags) == info.page_size); - if (fil_space_create(dest_space_name, info.space_id, flags, - FIL_TYPE_TABLESPACE, 0)) { + if (fil_space_t::create(dest_space_name, info.space_id, flags, + FIL_TYPE_TABLESPACE, 0)) { *success = xb_space_create_file(real_name, info.space_id, flags, &file); } else { @@ -4925,7 +4921,7 @@ xtrabackup_apply_delta( os_file_close(src_file); os_file_delete(0,src_path); } - if (dst_file != OS_FILE_CLOSED) + if (dst_file != OS_FILE_CLOSED && info.space_id) os_file_close(dst_file); return TRUE; @@ -4933,7 +4929,7 @@ error: aligned_free(incremental_buffer); if (src_file != OS_FILE_CLOSED) os_file_close(src_file); - if (dst_file != OS_FILE_CLOSED) + if (dst_file != OS_FILE_CLOSED && info.space_id) os_file_close(dst_file); msg("Error: xtrabackup_apply_delta(): " "failed to apply %s to %s.\n", src_path, dst_path); @@ -5387,8 +5383,8 @@ static bool xtrabackup_prepare_func(char** argv) srv_allow_writes_event = os_event_create(0); os_event_set(srv_allow_writes_event); #endif - dberr_t err = xb_data_files_init(); - if (err != DB_SUCCESS) { + xb_fil_io_init(); + if (dberr_t err = xb_load_tablespaces()) { msg("mariabackup: error: xb_data_files_init() failed " "with error %s\n", ut_strerr(err)); goto error_cleanup; @@ -5396,7 +5392,8 @@ static bool xtrabackup_prepare_func(char** argv) inc_dir_tables_hash.create(1000); - ok = xtrabackup_apply_deltas(); + ok = fil_system.sys_space->open(false) + && xtrabackup_apply_deltas(); xb_data_files_close(); @@ -5426,6 +5423,8 @@ static bool xtrabackup_prepare_func(char** argv) goto error_cleanup; } + fil_system.freeze_space_list = 0; + /* increase IO threads */ if (srv_n_file_io_threads < 10) { srv_n_read_io_threads = 4; @@ -5447,6 +5446,8 @@ static bool xtrabackup_prepare_func(char** argv) goto error_cleanup; } + ut_ad(!fil_system.freeze_space_list); + if (ok) { msg("Last binlog file %s, position %lld", trx_sys.recovered_binlog_filename, diff --git a/mysql-test/suite/encryption/t/innodb-remove-encryption.test b/mysql-test/suite/encryption/t/innodb-remove-encryption.test index 90c6925d125..aeafd99325b 100644 --- a/mysql-test/suite/encryption/t/innodb-remove-encryption.test +++ b/mysql-test/suite/encryption/t/innodb-remove-encryption.test @@ -29,6 +29,7 @@ create table t1(a int not null primary key, b char(200)) engine=innodb; --source include/wait_condition.inc SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --echo # Success! @@ -41,6 +42,7 @@ SET GLOBAL innodb_encrypt_tables = off; --let $wait_condition=SELECT COUNT(*) = $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND ROTATING_OR_FLUSHING = 0; --source include/wait_condition.inc +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; @@ -51,6 +53,7 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_ --let $restart_parameters=--skip-file-key-management --innodb-encrypt-tables=OFF --innodb-encryption-threads=0 --innodb-tablespaces-encryption -- source include/restart_mysqld.inc +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; diff --git a/mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.test b/mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.test index bc4c43e1ce8..ef38560c469 100644 --- a/mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.test +++ b/mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.test @@ -26,6 +26,7 @@ let $restart_parameters= --innodb_encryption_threads=5 --innodb_encryption_rotat --source include/wait_condition.inc SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --echo # Restart the server with innodb_encryption_rotate_key_age= 0 @@ -45,6 +46,7 @@ create table t4 (f1 int not null)engine=innodb encrypted=NO; SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --echo # Disable encryption when innodb_encryption_rotate_key_age is 0 @@ -57,6 +59,7 @@ set global innodb_encrypt_tables = OFF; --let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND ROTATING_OR_FLUSHING = 0; --source include/wait_condition.inc +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; --echo # Display only encrypted create tables (t3) SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; @@ -73,11 +76,13 @@ set global innodb_encrypt_tables = ON; SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; --echo # Display only unencrypted create tables (t4) +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --let $restart_parameters= -- source include/restart_mysqld.inc SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; DROP TABLE t4, t3, t2, t1; diff --git a/mysql-test/suite/innodb/r/table_definition_cache_debug.result b/mysql-test/suite/innodb/r/table_definition_cache_debug.result index 2c2c6de44ae..df171c89cd4 100644 --- a/mysql-test/suite/innodb/r/table_definition_cache_debug.result +++ b/mysql-test/suite/innodb/r/table_definition_cache_debug.result @@ -1,4 +1,4 @@ -call mtr.add_suppression("InnoDB: innodb_open_files=13 is exceeded"); +call mtr.add_suppression("InnoDB: innodb_open_files=.* is exceeded"); SET @save_tdc= @@GLOBAL.table_definition_cache; SET @save_toc= @@GLOBAL.table_open_cache; SET GLOBAL table_definition_cache= 400; diff --git a/mysql-test/suite/innodb/t/innodb-trim.test b/mysql-test/suite/innodb/t/innodb-trim.test index 0f38ea5ba84..3f8eb5f2c71 100644 --- a/mysql-test/suite/innodb/t/innodb-trim.test +++ b/mysql-test/suite/innodb/t/innodb-trim.test @@ -32,18 +32,6 @@ commit; set autocommit=1; -let $success= `SELECT variable_value FROM information_schema.global_status WHERE variable_name = 'innodb_num_page_compressed_trim_op'`; - -if (!$success) { ---disable_query_log ---disable_result_log - DROP PROCEDURE innodb_insert_proc; - DROP TABLE innodb_page_compressed; ---enable_query_log ---enable_result_log - --skip "Test requires TRIM"; -} - DROP PROCEDURE innodb_insert_proc; DROP TABLE innodb_page_compressed; diff --git a/mysql-test/suite/innodb/t/table_definition_cache_debug.test b/mysql-test/suite/innodb/t/table_definition_cache_debug.test index 70467b53435..6a466af4cc5 100644 --- a/mysql-test/suite/innodb/t/table_definition_cache_debug.test +++ b/mysql-test/suite/innodb/t/table_definition_cache_debug.test @@ -4,7 +4,7 @@ # This test is slow on buildbot. --source include/big_test.inc -call mtr.add_suppression("InnoDB: innodb_open_files=13 is exceeded"); +call mtr.add_suppression("InnoDB: innodb_open_files=.* is exceeded"); SET @save_tdc= @@GLOBAL.table_definition_cache; SET @save_toc= @@GLOBAL.table_open_cache; diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index 4fac94d211e..10f183790a7 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -1,3 +1,4 @@ + # Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2014, 2020, MariaDB Corporation. # @@ -186,7 +187,6 @@ SET(INNOBASE_SOURCES include/mtr0mtr.h include/mtr0mtr.ic include/mtr0types.h - include/os0api.h include/os0event.h include/os0file.h include/os0file.ic diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 81a04701da1..c280ed555fe 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -3304,21 +3304,34 @@ upd_sys: /** Prefetch siblings of the leaf for the pessimistic operation. -@param block leaf page */ -static void btr_cur_prefetch_siblings(const buf_block_t* block) +@param block leaf page +@param index index of the page */ +static void btr_cur_prefetch_siblings(const buf_block_t *block, + const dict_index_t *index) { - const page_t *page= block->frame; - ut_ad(page_is_leaf(page)); + ut_ad(page_is_leaf(block->frame)); + if (index->is_ibuf()) + return; + + const page_t *page= block->frame; uint32_t prev= mach_read_from_4(my_assume_aligned<4>(page + FIL_PAGE_PREV)); uint32_t next= mach_read_from_4(my_assume_aligned<4>(page + FIL_PAGE_NEXT)); if (prev != FIL_NULL) - buf_read_page_background(page_id_t(block->page.id().space(), prev), + { + ut_a(index->table->space->acquire_for_io()); + buf_read_page_background(index->table->space, + page_id_t(block->page.id().space(), prev), block->zip_size(), false); + } if (next != FIL_NULL) - buf_read_page_background(page_id_t(block->page.id().space(), next), + { + ut_a(index->table->space->acquire_for_io()); + buf_read_page_background(index->table->space, + page_id_t(block->page.id().space(), next), block->zip_size(), false); + } } /*************************************************************//** @@ -3436,8 +3449,8 @@ fail: /* prefetch siblings of the leaf for the pessimistic operation, if the page is leaf. */ - if (page_is_leaf(page) && !index->is_ibuf()) { - btr_cur_prefetch_siblings(block); + if (page_is_leaf(page)) { + btr_cur_prefetch_siblings(block, index); } fail_err: @@ -4575,7 +4588,7 @@ any_extern: /* prefetch siblings of the leaf for the pessimistic operation. */ - btr_cur_prefetch_siblings(block); + btr_cur_prefetch_siblings(block, index); return(DB_OVERFLOW); } @@ -4766,10 +4779,10 @@ func_exit: } } - if (err != DB_SUCCESS && !index->is_ibuf()) { + if (err != DB_SUCCESS) { /* prefetch siblings of the leaf for the pessimistic operation. */ - btr_cur_prefetch_siblings(block); + btr_cur_prefetch_siblings(block, index); } return(err); @@ -5481,7 +5494,7 @@ btr_cur_optimistic_delete_func( if (!no_compress_needed) { /* prefetch siblings of the leaf for the pessimistic operation. */ - btr_cur_prefetch_siblings(block); + btr_cur_prefetch_siblings(block, cursor->index); goto func_exit; } diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index daf5e1aa511..2046ffd4273 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -2768,7 +2768,7 @@ buf_zip_decompress( ulint size = page_zip_get_size(&block->page.zip); /* The tablespace will not be found if this function is called during IMPORT. */ - fil_space_t* space= fil_space_acquire_for_io(block->page.id().space()); + fil_space_t* space= fil_space_t::get_for_io(block->page.id().space()); const unsigned key_version = mach_read_from_4( frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION); fil_space_crypt_t* crypt_data = space ? space->crypt_data : NULL; @@ -3034,10 +3034,9 @@ buf_page_get_low( /* fall through */ case BUF_GET: case BUF_GET_IF_IN_POOL_OR_WATCH: - fil_space_t* s = fil_space_acquire_for_io(page_id.space()); + fil_space_t* s = fil_space_get(page_id.space()); ut_ad(s); ut_ad(s->zip_size() == zip_size); - s->release_for_io(); } #endif /* UNIV_DEBUG */ @@ -3107,7 +3106,7 @@ lookup: } /* The call path is buf_read_page() -> - buf_read_page_low() (fil_io()) -> + buf_read_page_low() (fil_space_t::io()) -> buf_page_read_complete() -> buf_decrypt_after_read(). Here fil_space_t* is used and we decrypt -> buf_page_check_corrupt() where page @@ -3161,8 +3160,7 @@ lookup: asserting. */ if (page_id.space() == TRX_SYS_SPACE) { } else if (page_id.space() == SRV_TMP_SPACE_ID) { - } else if (fil_space_t* space - = fil_space_acquire_for_io( + } else if (fil_space_t* space= fil_space_t::get_for_io( page_id.space())) { bool set = dict_set_corrupted_by_space(space); space->release_for_io(); @@ -3376,8 +3374,8 @@ re_evict: if (mode != BUF_GET_IF_IN_POOL && mode != BUF_GET_IF_IN_POOL_OR_WATCH) { } else if (!ibuf_debug) { - } else if (fil_space_t* space = - fil_space_acquire_for_io(page_id.space())) { + } else if (fil_space_t* space + = fil_space_t::get_for_io(page_id.space())) { /* Try to evict the block from the buffer pool, to use the insert buffer (change buffer) as much as possible. */ @@ -4869,17 +4867,4 @@ std::ostream& operator<<(std::ostream &out, const page_id_t page_id) << ", page number=" << page_id.page_no() << "]"; return out; } - -/** -Calculate the length of trim (punch_hole) operation. -@param[in] bpage Page control block -@param[in] write_length Write length -@return length of the trim or zero. */ -ulint -buf_page_get_trim_length( - const buf_page_t* bpage, - ulint write_length) -{ - return bpage->physical_size() - write_length; -} #endif /* !UNIV_INNOCHECKSUM */ diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index ad515e4e194..6b1a32d8930 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -125,7 +125,8 @@ too_small: byte *fseg_header= TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG + trx_sys_block->frame; - for (uint32_t prev_page_no= 0, i= 0; i < 2 * size + FSP_EXTENT_SIZE / 2; i++) + for (uint32_t prev_page_no= 0, i= 0, extent_size= FSP_EXTENT_SIZE; + i < 2 * size + extent_size / 2; i++) { buf_block_t *new_block= fseg_alloc_free_page(fseg_header, prev_page_no + 1, FSP_UP, &mtr); @@ -362,15 +363,13 @@ void buf_dblwr_t::recover() continue; } - fil_space_t* space= fil_space_acquire_for_io(space_id); + fil_space_t *space= fil_space_t::get_for_io(space_id); if (!space) /* The tablespace that this page once belonged to does not exist */ continue; - fil_space_open_if_needed(space); - - if (UNIV_UNLIKELY(page_no >= space->size)) + if (UNIV_UNLIKELY(page_no >= space->get_size())) { /* Do not report the warning for undo tablespaces, because they can be truncated in place. */ @@ -385,7 +384,6 @@ next_page: } const ulint physical_size= space->physical_size(); - const ulint zip_size= space->zip_size(); ut_ad(!buf_is_zeroes(span(page, physical_size))); /* We want to ensure that for partial reads the unread portion of @@ -393,18 +391,15 @@ next_page: memset(read_buf, 0x0, physical_size); /* Read in the actual page from the file */ - fil_io_t fio= fil_io(IORequest(IORequest::READ | IORequest::DBLWR_RECOVER), - true, page_id, zip_size, - 0, physical_size, read_buf, nullptr); + fil_io_t fio= space->io(IORequest(IORequest::DBLWR_RECOVER), + os_offset_t{page_no} * physical_size, + physical_size, read_buf); if (UNIV_UNLIKELY(fio.err != DB_SUCCESS)) ib::warn() << "Double write buffer recovery: " << page_id << " (tablespace '" << space->name << "') read failed with error: " << fio.err; - if (fio.node) - fio.node->space->release_for_io(); - if (buf_is_zeroes(span(read_buf, physical_size))) { /* We will check if the copy in the doublewrite buffer is @@ -425,17 +420,15 @@ next_page: /* Write the good page from the doublewrite buffer to the intended position. */ - fio= fil_io(IORequestWrite, true, page_id, zip_size, 0, physical_size, - page, nullptr); + space->reacquire_for_io(); + fio= space->io(IORequestWrite, + os_offset_t{page_id.page_no()} * physical_size, + physical_size, page); - if (fio.node) - { - ut_ad(fio.err == DB_SUCCESS); + if (fio.err == DB_SUCCESS) ib::info() << "Recovered page " << page_id << " to '" << fio.node->name << "' from the doublewrite buffer."; - fio.node->space->release_for_io(); - goto next_page; - } + goto next_page; } recv_sys.dblwr.pages.clear(); @@ -513,7 +506,7 @@ static void buf_dblwr_check_page_lsn(const page_t* page, const fil_space_t& s) static void buf_dblwr_check_page_lsn(const buf_page_t &b, const byte *page) { - if (fil_space_t *space= fil_space_acquire_for_io(b.id().space())) + if (fil_space_t *space= fil_space_t::get_for_io(b.id().space())) { buf_dblwr_check_page_lsn(page, *space); space->release_for_io(); @@ -577,7 +570,7 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size) #ifdef UNIV_DEBUG for (ulint len2= 0, i= 0; i < old_first_free; len2 += srv_page_size, i++) { - buf_page_t *bpage= buf_block_arr[i].bpage; + buf_page_t *bpage= buf_block_arr[i].request.bpage; if (bpage->zip.data) /* No simple validate for ROW_FORMAT=COMPRESSED pages exists. */ @@ -590,18 +583,22 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size) } #endif /* UNIV_DEBUG */ /* Write out the first block of the doublewrite buffer */ - fil_io_t fio= fil_io(IORequestWrite, true, block1, 0, 0, - std::min(size, old_first_free) << srv_page_size_shift, - write_buf, nullptr); - fio.node->space->release_for_io(); + ut_a(fil_system.sys_space->acquire_for_io()); + fil_system.sys_space->io(IORequestWrite, + os_offset_t{block1.page_no()} << + srv_page_size_shift, + std::min(size, old_first_free) << + srv_page_size_shift, write_buf); if (old_first_free > size) { /* Write out the second block of the doublewrite buffer. */ - fio= fil_io(IORequestWrite, true, block2, 0, 0, - (old_first_free - size) << srv_page_size_shift, - write_buf + (size << srv_page_size_shift), nullptr); - fio.node->space->release_for_io(); + ut_a(fil_system.sys_space->acquire_for_io()); + fil_system.sys_space->io(IORequestWrite, + os_offset_t{block2.page_no()} << + srv_page_size_shift, + (old_first_free - size) << srv_page_size_shift, + write_buf + (size << srv_page_size_shift)); } /* increment the doublewrite flushed pages counter */ @@ -609,7 +606,7 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size) srv_stats.dblwr_writes.inc(); /* Now flush the doublewrite buffer data to disk */ - fil_flush(TRX_SYS_SPACE); + fil_system.sys_space->flush(); /* We know that the writes have been flushed to disk now and in recovery we will find them in the doublewrite buffer @@ -629,8 +626,8 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size) for (ulint i= 0; i < old_first_free; i++) { auto e= buf_block_arr[i]; - buf_page_t* bpage= e.bpage; - ut_a(bpage->in_file()); + buf_page_t* bpage= e.request.bpage; + ut_ad(bpage->in_file()); /* We request frame here to get correct buffer in case of encryption and/or page compression */ @@ -650,8 +647,7 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size) ut_d(buf_dblwr_check_page_lsn(*bpage, static_cast(frame))); } - fil_io(IORequest(IORequest::WRITE, bpage, e.lru), false, - bpage->id(), bpage->zip_size(), 0, e_size, frame, bpage); + e.space->io(e.request, bpage->physical_offset(), e_size, frame, bpage); } return true; @@ -680,12 +676,20 @@ void buf_dblwr_t::flush_buffered_writes() /** Schedule a page write. If the doublewrite memory buffer is full, flush_buffered_writes() will be invoked to make space. -@param bpage buffer pool page to be written -@param lru true=buf_pool.LRU; false=buf_pool.flush_list +@param space tablespace +@param request asynchronous write request @param size payload size in bytes */ -void buf_dblwr_t::add_to_batch(buf_page_t *bpage, bool lru, size_t size) +void buf_dblwr_t::add_to_batch(fil_space_t *space, const IORequest &request, + size_t size) { - ut_ad(bpage->in_file()); + ut_ad(request.is_async()); + ut_ad(request.is_write()); + ut_ad(request.bpage); + ut_ad(request.bpage->in_file()); + ut_ad(space->id == request.bpage->id().space()); + ut_ad(space->pending_io()); + ut_ad(!srv_read_only_mode); + const ulint buf_size= 2 * block_size(); mysql_mutex_lock(&mutex); @@ -707,13 +711,13 @@ void buf_dblwr_t::add_to_batch(buf_page_t *bpage, bool lru, size_t size) /* We request frame here to get correct buffer in case of encryption and/or page compression */ - void *frame= buf_page_get_frame(bpage); + void *frame= buf_page_get_frame(request.bpage); memcpy_aligned(p, frame, size); - ut_ad(!bpage->zip_size() || bpage->zip_size() == size); + ut_ad(!request.bpage->zip_size() || request.bpage->zip_size() == size); ut_ad(reserved == first_free); ut_ad(reserved < buf_size); - buf_block_arr[first_free++]= { bpage, lru, size }; + new (buf_block_arr + first_free++) element{space, request, size}; reserved= first_free; if (first_free != buf_size || !flush_buffered_writes(buf_size / 2)) diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc index b66f5e39744..19a9e09e4a1 100644 --- a/storage/innobase/buf/buf0dump.cc +++ b/storage/innobase/buf/buf0dump.cc @@ -626,6 +626,14 @@ buf_load() so all pages from a given tablespace are consecutive. */ ulint cur_space_id = dump[0].space(); fil_space_t* space = fil_space_acquire_silent(cur_space_id); + if (space) { + bool ok = space->acquire_for_io(); + space->release(); + if (!ok) { + space = nullptr; + } + } + ulint zip_size = space ? space->zip_size() : 0; PSI_stage_progress* pfs_stage_progress __attribute__((unused)) @@ -644,24 +652,34 @@ buf_load() } if (this_space_id != cur_space_id) { - if (space != NULL) { - space->release(); + if (space) { + space->release_for_io(); } cur_space_id = this_space_id; space = fil_space_acquire_silent(cur_space_id); - if (space != NULL) { - zip_size = space->zip_size(); + if (!space) { + continue; } + + bool ok = space->acquire_for_io(); + space->release(); + + if (!ok) { + space = nullptr; + continue; + } + + zip_size = space->zip_size(); } /* JAN: TODO: As we use background page read below, if tablespace is encrypted we cant use it. */ - if (space == NULL || - (space && space->crypt_data && - space->crypt_data->encryption != FIL_ENCRYPTION_OFF && - space->crypt_data->type != CRYPT_SCHEME_UNENCRYPTED)) { + if (!space || dump[i].page_no() >= space->get_size() || + (space->crypt_data && + space->crypt_data->encryption != FIL_ENCRYPTION_OFF && + space->crypt_data->type != CRYPT_SCHEME_UNENCRYPTED)) { continue; } @@ -671,11 +689,12 @@ buf_load() continue; } - buf_read_page_background(dump[i], zip_size, true); + space->reacquire_for_io(); + buf_read_page_background(space, dump[i], zip_size, true); if (buf_load_abort_flag) { - if (space != NULL) { - space->release(); + if (space) { + space->release_for_io(); } buf_load_abort_flag = false; ut_free(dump); @@ -702,8 +721,8 @@ buf_load() #endif } - if (space != NULL) { - space->release(); + if (space) { + space->release_for_io(); } ut_free(dump); diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index b69026ef990..25523ab53f1 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -782,6 +782,11 @@ static bool buf_flush_page(buf_page_t *bpage, bool lru, fil_space_t *space) { ut_ad(bpage->in_file()); ut_ad(bpage->ready_for_flush()); + ut_ad((space->purpose == FIL_TYPE_TEMPORARY) == + (space == fil_system.temp_space)); + ut_ad(space->purpose == FIL_TYPE_TABLESPACE || + space->atomic_write_supported); + ut_ad(space->pending_io()); rw_lock_t *rw_lock; @@ -807,11 +812,6 @@ static bool buf_flush_page(buf_page_t *bpage, bool lru, fil_space_t *space) io_fix and oldest_modification()!=0. Thus, it cannot be relocated in the buffer pool or removed from flush_list or LRU_list. */ - ut_ad((space->purpose == FIL_TYPE_TEMPORARY) == - (space == fil_system.temp_space)); - ut_ad(space->purpose == FIL_TYPE_TABLESPACE || - space->atomic_write_supported); - DBUG_PRINT("ib_buf", ("%s %u page %u:%u", lru ? "LRU" : "flush_list", bpage->id().space(), bpage->id().page_no())); @@ -850,82 +850,66 @@ static bool buf_flush_page(buf_page_t *bpage, bool lru, fil_space_t *space) } } - size_t size, orig_size; - ulint type= IORequest::WRITE; - - if (UNIV_UNLIKELY(!rw_lock)) /* ROW_FORMAT=COMPRESSED */ - { - ut_ad(!space->full_crc32()); - ut_ad(!space->is_compressed()); /* not page_compressed */ - orig_size= size= bpage->zip_size(); - if (status != buf_page_t::FREED) - { - buf_flush_update_zip_checksum(frame, orig_size); - frame= buf_page_encrypt(space, bpage, frame, &size); - } - ut_ad(size == bpage->zip_size()); - } + if (status == buf_page_t::FREED) + buf_release_freed_page(&block->page); else { - byte *page= block->frame; - orig_size= size= block->physical_size(); + space->reacquire_for_io(); + ut_ad(status == buf_page_t::NORMAL || status == buf_page_t::INIT_ON_FLUSH); + size_t size, orig_size; + IORequest::Type type= lru ? IORequest::WRITE_LRU : IORequest::WRITE_ASYNC; - if (status == buf_page_t::FREED); - else if (space->full_crc32()) + if (UNIV_UNLIKELY(!rw_lock)) /* ROW_FORMAT=COMPRESSED */ { - /* innodb_checksum_algorithm=full_crc32 is not implemented for - ROW_FORMAT=COMPRESSED pages. */ - ut_ad(!frame); - page= buf_page_encrypt(space, bpage, page, &size); - buf_flush_init_for_writing(block, page, nullptr, true); + ut_ad(!space->full_crc32()); + ut_ad(!space->is_compressed()); /* not page_compressed */ + orig_size= size= bpage->zip_size(); + buf_flush_update_zip_checksum(frame, size); + frame= buf_page_encrypt(space, bpage, frame, &size); + ut_ad(size == bpage->zip_size()); } else { - buf_flush_init_for_writing(block, page, frame ? &bpage->zip : nullptr, - false); - page= buf_page_encrypt(space, bpage, frame ? frame : page, &size); - } + byte *page= block->frame; + orig_size= size= block->physical_size(); + + if (space->full_crc32()) + { + /* innodb_checksum_algorithm=full_crc32 is not implemented for + ROW_FORMAT=COMPRESSED pages. */ + ut_ad(!frame); + page= buf_page_encrypt(space, bpage, page, &size); + buf_flush_init_for_writing(block, page, nullptr, true); + } + else + { + buf_flush_init_for_writing(block, page, frame ? &bpage->zip : nullptr, + false); + page= buf_page_encrypt(space, bpage, frame ? frame : page, &size); + } #if defined HAVE_FALLOC_PUNCH_HOLE_AND_KEEP_SIZE || defined _WIN32 - if (size != orig_size && space->punch_hole) - type|= IORequest::PUNCH_HOLE; + if (size != orig_size && space->punch_hole) + type= lru ? IORequest::PUNCH_LRU : IORequest::PUNCH; #else DBUG_EXECUTE_IF("ignore_punch_hole", if (size != orig_size && space->punch_hole) - type|= IORequest::PUNCH_HOLE;); + type= lru ? IORequest::PUNCH_LRU : IORequest::PUNCH;); #endif - frame= page; - } - - IORequest request(type, bpage, lru); - - ut_ad(status == bpage->status); - - switch (status) { - default: - ut_ad(status == buf_page_t::FREED); - buf_release_freed_page(bpage); - break; - case buf_page_t::NORMAL: - if (space->use_doublewrite()) - { - ut_ad(!srv_read_only_mode); - if (lru) - buf_pool.n_flush_LRU++; - else - buf_pool.n_flush_list++; - buf_dblwr.add_to_batch(bpage, lru, size); - break; + frame=page; } - /* fall through */ - case buf_page_t::INIT_ON_FLUSH: + + ut_ad(status == bpage->status); + if (lru) buf_pool.n_flush_LRU++; else buf_pool.n_flush_list++; - /* FIXME: pass space to fil_io() */ - fil_io(request, false, bpage->id(), bpage->zip_size(), 0, - bpage->physical_size(), frame, bpage); + if (status != buf_page_t::NORMAL || !space->use_doublewrite()) + space->io(IORequest(type, bpage), + bpage->physical_offset(), size, frame, bpage); + else + buf_dblwr.add_to_batch(space, IORequest(type, bpage), size); } /* Increment the I/O operation count used for selecting LRU policy. */ @@ -973,8 +957,7 @@ static page_id_t buf_flush_check_neighbors(const fil_space_t &space, ? static_cast(s) : read_ahead; page_id_t low= id - (id.page_no() % buf_flush_area); page_id_t high= low + buf_flush_area; - high.set_page_no(std::min(high.page_no(), - static_cast(space.committed_size - 1))); + high.set_page_no(std::min(high.page_no(), space.last_page_number())); if (!contiguous) { @@ -1018,13 +1001,12 @@ static page_id_t buf_flush_check_neighbors(const fil_space_t &space, return i; } +MY_ATTRIBUTE((nonnull)) /** Write punch-hole or zeroes of the freed ranges when innodb_immediate_scrub_data_uncompressed from the freed ranges. -@param[in] space tablespace which contains freed ranges -@param[in] freed_ranges freed ranges of the page to be flushed */ +@param space tablespace which may contain ranges of freed pages */ static void buf_flush_freed_pages(fil_space_t *space) { - ut_ad(space != NULL); const bool punch_hole= space->punch_hole; if (!srv_immediate_scrub_data_uncompressed && !punch_hole) return; @@ -1043,27 +1025,24 @@ static void buf_flush_freed_pages(fil_space_t *space) for (const auto &range : freed_ranges) { - ulint page_size= space->zip_size(); - if (!page_size) - page_size= srv_page_size; + const ulint physical_size= space->physical_size(); if (punch_hole) { - const auto len= (range.last - range.first + 1) * page_size; - const page_id_t page_id(space->id, range.first); - fil_io_t fio= fil_io(IORequestWrite, true, page_id, space->zip_size(), - 0, len, nullptr, nullptr, false, true); - if (fio.node) - fio.node->space->release_for_io(); + space->reacquire_for_io(); + space->io(IORequest(IORequest::PUNCH_RANGE), + os_offset_t{range.first} * physical_size, + (range.last - range.first + 1) * physical_size, + nullptr); } else if (srv_immediate_scrub_data_uncompressed) { - for (auto i= range.first; i <= range.last; i++) + for (os_offset_t i= range.first; i <= range.last; i++) { - const page_id_t page_id(space->id, i); - fil_io(IORequestWrite, false, page_id, space->zip_size(), 0, - space->zip_size() ? space->zip_size() : srv_page_size, - const_cast(field_ref_zero), nullptr, false, false); + space->reacquire_for_io(); + space->io(IORequest(IORequest::WRITE_ASYNC), + i * physical_size, physical_size, + const_cast(field_ref_zero)); } } buf_pool.stat.n_pages_written+= (range.last - range.first + 1); @@ -1093,7 +1072,8 @@ static ulint buf_flush_try_neighbors(fil_space_t *space, ut_ad(page_id >= id); ut_ad(page_id < high); - for (ulint id_fold= id.fold(); id < high; ++id, ++id_fold) + for (ulint id_fold= id.fold(); id < high && !space->is_stopping(); + ++id, ++id_fold) { if (count + n_flushed >= n_to_flush) { @@ -1190,7 +1170,7 @@ static ulint buf_free_from_unzip_LRU_list_batch(ulint max) @retval nullptr if the pages for this tablespace should be discarded */ static fil_space_t *buf_flush_space(const uint32_t id) { - fil_space_t *space= fil_space_acquire_for_io(id); + fil_space_t *space= fil_space_t::get_for_io(id); if (space) buf_flush_freed_pages(space); return space; @@ -1204,6 +1184,37 @@ struct flush_counters_t ulint evicted; }; +/** Try to discard a dirty page. +@param bpage dirty page whose tablespace is not accessible */ +static void buf_flush_discard_page(buf_page_t *bpage) +{ + mysql_mutex_assert_owner(&buf_pool.mutex); + mysql_mutex_assert_not_owner(&buf_pool.flush_list_mutex); + ut_ad(bpage->in_file()); + ut_ad(bpage->oldest_modification()); + + rw_lock_t *rw_lock; + + if (bpage->state() != BUF_BLOCK_FILE_PAGE) + rw_lock= nullptr; + else + { + rw_lock= &reinterpret_cast(bpage)->lock; + if (!rw_lock_sx_lock_nowait(rw_lock, 0)) + return; + } + + bpage->status= buf_page_t::NORMAL; + mysql_mutex_lock(&buf_pool.flush_list_mutex); + buf_flush_remove(bpage); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + + if (rw_lock) + rw_lock_sx_unlock(rw_lock); + + buf_LRU_free_page(bpage, true); +} + /** Flush dirty blocks from the end of the LRU list. @param max maximum number of blocks to make available in buf_pool.free @param n counts of flushed and evicted pages */ @@ -1219,6 +1230,9 @@ static void buf_flush_LRU_list_batch(ulint max, flush_counters_t *n) const auto neighbors= UT_LIST_GET_LEN(buf_pool.LRU) < BUF_LRU_OLD_MIN_LEN ? 0 : srv_flush_neighbors; fil_space_t *space= nullptr; + uint32_t last_space_id= FIL_NULL; + static_assert(FIL_NULL > SRV_TMP_SPACE_ID, "consistency"); + static_assert(FIL_NULL > SRV_SPACE_ID_UPPER_BOUND, "consistency"); for (buf_page_t *bpage= UT_LIST_GET_LAST(buf_pool.LRU); bpage && n->flushed + n->evicted < max && @@ -1244,13 +1258,25 @@ static void buf_flush_LRU_list_batch(ulint max, flush_counters_t *n) const uint32_t space_id= page_id.space(); if (!space || space->id != space_id) { - if (space) - space->release_for_io(); - space= buf_flush_space(space_id); - if (!space) - continue; + if (last_space_id != space_id) + { + if (space) + space->release_for_io(); + space= buf_flush_space(space_id); + last_space_id= space_id; + } + else + ut_ad(!space); } - if (neighbors && space->is_rotational()) + else if (space->is_stopping()) + { + space->release_for_io(); + space= nullptr; + } + + if (!space) + buf_flush_discard_page(bpage); + else if (neighbors && space->is_rotational()) { mysql_mutex_unlock(&buf_pool.mutex); n->flushed+= buf_flush_try_neighbors(space, page_id, neighbors == 1, @@ -1328,6 +1354,9 @@ static ulint buf_do_flush_list_batch(ulint max_n, lsn_t lsn) const auto neighbors= UT_LIST_GET_LEN(buf_pool.LRU) < BUF_LRU_OLD_MIN_LEN ? 0 : srv_flush_neighbors; fil_space_t *space= nullptr; + uint32_t last_space_id= FIL_NULL; + static_assert(FIL_NULL > SRV_TMP_SPACE_ID, "consistency"); + static_assert(FIL_NULL > SRV_SPACE_ID_UPPER_BOUND, "consistency"); /* Start from the end of the list looking for a suitable block to be flushed. */ @@ -1361,17 +1390,29 @@ static ulint buf_do_flush_list_batch(ulint max_n, lsn_t lsn) const uint32_t space_id= page_id.space(); if (!space || space->id != space_id) { - if (space) - space->release_for_io(); - space= buf_flush_space(space_id); - if (!space) - continue; + if (last_space_id != space_id) + { + if (space) + space->release_for_io(); + space= buf_flush_space(space_id); + last_space_id= space_id; + } + else + ut_ad(!space); } - if (neighbors && space->is_rotational()) + else if (space->is_stopping()) + { + space->release_for_io(); + space= nullptr; + } + + if (!space) + buf_flush_discard_page(bpage); + else if (neighbors && space->is_rotational()) { mysql_mutex_unlock(&buf_pool.mutex); count+= buf_flush_try_neighbors(space, page_id, neighbors == 1, - false, count, max_n); + false, count, max_n); reacquire_mutex: mysql_mutex_lock(&buf_pool.mutex); } @@ -1476,10 +1517,9 @@ ulint buf_flush_lists(ulint max_n, lsn_t lsn) while not holding buf_pool.flush_list_mutex */ if (running || !UT_LIST_GET_LEN(buf_pool.flush_list)) { + if (!running) + mysql_cond_broadcast(cond); mysql_mutex_unlock(&buf_pool.mutex); - if (running) - return 0; - mysql_cond_broadcast(cond); return 0; } n_flush++; diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index bc81a8e9b86..daea53ec130 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -261,26 +261,23 @@ flag is cleared and the x-lock released by an i/o-handler thread. @param[out] err DB_SUCCESS or DB_TABLESPACE_DELETED if we are trying to read from a non-existent tablespace +@param[in,out] space tablespace @param[in] sync true if synchronous aio is desired @param[in] mode BUF_READ_IBUF_PAGES_ONLY, ..., @param[in] page_id page id @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 @param[in] unzip true=request uncompressed page -@param[in] ignore whether to ignore out-of-bounds page_id -@return 1 if a read request was queued, 0 if the page already resided -in buf_pool, or if the page is in the doublewrite buffer blocks in -which case it is never read into the pool, or if the tablespace does -not exist or is being dropped */ +@return whether a read request was queued */ static -ulint +bool buf_read_page_low( dberr_t* err, + fil_space_t* space, bool sync, ulint mode, const page_id_t page_id, ulint zip_size, - bool unzip, - bool ignore = false) + bool unzip) { buf_page_t* bpage; @@ -290,17 +287,22 @@ buf_read_page_low( ib::error() << "Trying to read doublewrite buffer page " << page_id; ut_ad(0); - return(0); +nothing_read: + space->release_for_io(); + return false; } - if (ibuf_bitmap_page(page_id, zip_size) || trx_sys_hdr_page(page_id)) { + if (sync) { + } else if (trx_sys_hdr_page(page_id) + || ibuf_bitmap_page(page_id, zip_size) + || (!recv_no_ibuf_operations + && ibuf_page(page_id, zip_size, nullptr))) { /* Trx sys header is so low in the latching order that we play safe and do not leave the i/o-completion to an asynchronous - i/o-thread. Ibuf bitmap pages must always be read with + i/o-thread. Change buffer pages must always be read with syncronous i/o, to make sure they do not get involved in thread deadlocks. */ - sync = true; } @@ -311,20 +313,19 @@ buf_read_page_low( bpage = buf_page_init_for_read(mode, page_id, zip_size, unzip); if (bpage == NULL) { + goto nothing_read; + } - return(0); + ut_ad(bpage->in_file()); + + if (sync) { + thd_wait_begin(nullptr, THD_WAIT_DISKIO); } DBUG_LOG("ib_buf", "read page " << page_id << " zip_size=" << zip_size << " unzip=" << unzip << ',' << (sync ? "sync" : "async")); - ut_ad(bpage->in_file()); - - if (sync) { - thd_wait_begin(NULL, THD_WAIT_DISKIO); - } - void* dst; if (zip_size) { @@ -335,20 +336,18 @@ buf_read_page_low( dst = ((buf_block_t*) bpage)->frame; } - fil_io_t fio = fil_io( - IORequestRead, sync, page_id, zip_size, 0, - zip_size ? zip_size : srv_page_size, - dst, bpage, ignore); + const ulint len = zip_size ? zip_size : srv_page_size; + auto fio = space->io(IORequest(sync + ? IORequest::READ_SYNC + : IORequest::READ_ASYNC), + page_id.page_no() * len, len, dst, bpage); *err= fio.err; if (UNIV_UNLIKELY(fio.err != DB_SUCCESS)) { - if (ignore || fio.err == DB_TABLESPACE_DELETED) { + if (!sync || fio.err == DB_TABLESPACE_DELETED) { buf_pool.corrupted_evict(bpage); - if (sync && fio.node) { - fio.node->space->release_for_io(); - } - return(0); + return false; } ut_error; @@ -357,16 +356,16 @@ buf_read_page_low( if (sync) { thd_wait_end(NULL); - /* The i/o was already completed in fil_io() */ + /* The i/o was already completed in space->io() */ *err = buf_page_read_complete(bpage, *fio.node); - fio.node->space->release_for_io(); + space->release_for_io(); if (*err != DB_SUCCESS) { - return(0); + return false; } } - return(1); + return true; } /** Applies a random read-ahead in buf_pool if there are at least a threshold @@ -411,7 +410,7 @@ buf_read_ahead_random(const page_id_t page_id, ulint zip_size, bool ibuf) ulint count= 5 + buf_read_ahead_area / 8; const page_id_t low= page_id - (page_id.page_no() % buf_read_ahead_area); page_id_t high= low + buf_read_ahead_area; - high.set_page_no(std::min(high.page_no(), space->committed_size - 1)); + high.set_page_no(std::min(high.page_no(), space->last_page_number())); /* Count how many blocks in the area have been recently accessed, that is, reside near the start of the LRU list. */ @@ -427,10 +426,14 @@ buf_read_ahead_random(const page_id_t page_id, ulint zip_size, bool ibuf) goto read_ahead; } +no_read_ahead: space->release(); return 0; read_ahead: + if (!space->acquire_for_io()) + goto no_read_ahead; + /* Read all the suitable blocks within the area */ const ulint ibuf_mode= ibuf ? BUF_READ_IBUF_PAGES_ONLY : BUF_READ_ANY_PAGE; @@ -441,13 +444,16 @@ read_ahead: if (space->is_stopping()) break; dberr_t err; - count+= buf_read_page_low(&err, false, ibuf_mode, i, zip_size, false); + space->reacquire_for_io(); + if (buf_read_page_low(&err, space, false, ibuf_mode, i, zip_size, false)) + count++; } if (count) DBUG_PRINT("ib_buf", ("random read-ahead %zu pages from %s: %u", count, space->chain.start->name, low.page_no())); + space->release_for_io(); space->release(); /* Read ahead is considered one I/O operation for the purpose of @@ -472,41 +478,49 @@ after decryption normal page checksum does not match. @retval DB_TABLESPACE_DELETED if tablespace .ibd file is missing */ dberr_t buf_read_page(const page_id_t page_id, ulint zip_size) { - dberr_t err = DB_SUCCESS; + fil_space_t *space= fil_space_acquire(page_id.space()); + if (!space) + { + ib::info() << "trying to read page " << page_id + << " in nonexisting or being-dropped tablespace"; + return DB_TABLESPACE_DELETED; + } + else if (!space->acquire_for_io()) + { + ib::warn() << "unable to read " << page_id << " from tablespace " + << space->name; + space->release(); + return DB_PAGE_CORRUPTED; + } - ulint count = buf_read_page_low( - &err, true, BUF_READ_ANY_PAGE, page_id, zip_size, false); + space->release(); - srv_stats.buf_pool_reads.add(count); + dberr_t err; + if (buf_read_page_low(&err, space, true, BUF_READ_ANY_PAGE, + page_id, zip_size, false)) + srv_stats.buf_pool_reads.add(1); - if (err == DB_TABLESPACE_DELETED) { - ib::info() << "trying to read page " << page_id - << " in nonexisting or being-dropped tablespace"; - } - - /* Increment number of I/O operations used for LRU policy. */ - buf_LRU_stat_inc_io(); - - return(err); + buf_LRU_stat_inc_io(); + return err; } /** High-level function which reads a page asynchronously from a file to the buffer buf_pool if it is not already there. Sets the io_fix flag and sets an exclusive lock on the buffer frame. The flag is cleared and the x-lock released by the i/o-handler thread. +@param[in,out] space tablespace @param[in] page_id page id @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 @param[in] sync true if synchronous aio is desired */ -void -buf_read_page_background(const page_id_t page_id, ulint zip_size, bool sync) +void buf_read_page_background(fil_space_t *space, const page_id_t page_id, + ulint zip_size, bool sync) { - ulint count; dberr_t err; - count = buf_read_page_low( - &err, sync, - BUF_READ_ANY_PAGE, - page_id, zip_size, false, true); + if (buf_read_page_low(&err, space, sync, BUF_READ_ANY_PAGE, + page_id, zip_size, false)) { + srv_stats.buf_pool_reads.add(1); + } switch (err) { case DB_SUCCESS: @@ -528,8 +542,6 @@ buf_read_page_background(const page_id_t page_id, ulint zip_size, bool sync) << page_id; } - srv_stats.buf_pool_reads.add(count); - /* We do not increment number of I/O operations used for LRU policy here (buf_LRU_stat_inc_io()). We use this in heuristics to decide about evicting uncompressed version of compressed pages from the @@ -598,10 +610,19 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf) fil_space_t *space= fil_space_acquire(page_id.space()); if (!space) return 0; - if (high_1.page_no() >= space->committed_size) + else + { + bool ok= space->acquire_for_io(); + space->release(); + if (!ok) + return 0; + } + + if (high_1.page_no() > space->last_page_number()) { /* The area is not whole. */ - space->release(); +fail: + space->release_for_io(); return 0; } @@ -628,8 +649,7 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf) { hard_fail: hash_lock->read_unlock(); - space->release(); - return 0; + goto fail; } const byte *f; switch (UNIV_EXPECT(bpage->state(), BUF_BLOCK_FILE_PAGE)) { @@ -661,7 +681,7 @@ hard_fail: if (id != new_low && id != new_high_1) /* This is not a border page of the area: return */ goto hard_fail; - if (new_high_1.page_no() >= space->committed_size) + if (new_high_1.page_no() > space->last_page_number()) /* The area is not whole */ goto hard_fail; } @@ -671,8 +691,7 @@ failed: hash_lock->read_unlock(); if (--count) continue; - space->release(); - return 0; + goto fail; } const unsigned accessed= bpage->is_accessed(); @@ -702,7 +721,8 @@ failed: if (space->is_stopping()) break; dberr_t err; - count+= buf_read_page_low(&err, false, ibuf_mode, new_low, zip_size, + space->reacquire_for_io(); + count+= buf_read_page_low(&err, space, false, ibuf_mode, new_low, zip_size, false); } @@ -710,7 +730,7 @@ failed: DBUG_PRINT("ib_buf", ("random read-ahead %zu pages from %s: %u", count, space->chain.start->name, new_low.page_no())); - space->release(); + space->release_for_io(); /* Read ahead is considered one I/O operation for the purpose of LRU policy decision. */ @@ -721,24 +741,19 @@ failed: } /** Issues read requests for pages which recovery wants to read in. -@param[in] sync true if the caller wants this function to wait -for the highest address page to get read in, before this function returns @param[in] space_id tablespace id @param[in] page_nos array of page numbers to read, with the highest page number the last in the array @param[in] n number of page numbers in the array */ -void buf_read_recv_pages(bool sync, ulint space_id, const uint32_t *page_nos, - ulint n) +void buf_read_recv_pages(ulint space_id, const uint32_t* page_nos, ulint n) { - fil_space_t* space = fil_space_get(space_id); + fil_space_t* space = fil_space_t::get_for_io(space_id); - if (space == NULL) { - /* The tablespace is missing: do nothing */ + if (!space) { + /* The tablespace is missing or unreadable: do nothing */ return; } - fil_space_open_if_needed(space); - const ulint zip_size = space->zip_size(); for (ulint i = 0; i < n; i++) { @@ -769,9 +784,10 @@ void buf_read_recv_pages(bool sync, ulint space_id, const uint32_t *page_nos, } dberr_t err; - buf_read_page_low( - &err, sync && i + 1 == n, - BUF_READ_ANY_PAGE, cur_page_id, zip_size, true); + space->reacquire_for_io(); + buf_read_page_low(&err, space, false, + BUF_READ_ANY_PAGE, cur_page_id, zip_size, + true); if (err == DB_DECRYPTION_FAILED || err == DB_PAGE_CORRUPTED) { ib::error() << "Recovery failed to read or decrypt " @@ -779,5 +795,8 @@ void buf_read_recv_pages(bool sync, ulint space_id, const uint32_t *page_nos, } } - DBUG_PRINT("ib_buf", ("recovery read-ahead (%u pages)", n)); + + DBUG_PRINT("ib_buf", ("recovery read (%u pages) for %s", n, + space->chain.start->name)); + space->release_for_io(); } diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index 7a27160ccd5..fb3247ecdcf 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -951,7 +951,7 @@ void dict_drop_index_tree(btr_pcur_t* pcur, trx_t* trx, mtr_t* mtr) if (fil_space_t* s = fil_space_acquire_silent(space_id)) { /* Ensure that the tablespace file exists in order to avoid a crash in buf_page_get_gen(). */ - if (s->size || fil_space_get_size(space_id)) { + if (root_page_no < s->get_size()) { btr_free_if_exists(page_id_t(space_id, root_page_no), s->zip_size(), mach_read_from_8(ptr), mtr); diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index 489f4d491d1..753bcf74967 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -2975,15 +2975,15 @@ err_exit: } if (err == DB_SUCCESS && table->is_readable()) { - if (table->space && !fil_space_get_size(table->space_id)) { + const auto root = dict_table_get_first_index(table)->page; + + if (root >= table->space->get_size()) { corrupted: table->corrupted = true; table->file_unreadable = true; err = DB_CORRUPTION; } else { - const page_id_t page_id( - table->space->id, - dict_table_get_first_index(table)->page); + const page_id_t page_id(table->space->id, root); mtr.start(); buf_block_t* block = buf_page_get( page_id, table->space->zip_size(), diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 5587355f23a..e73337a3bdd 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -975,8 +975,7 @@ static inline void fil_crypt_read_crypt_data(fil_space_t* space) { - if (space->crypt_data || space->size - || !fil_space_get_size(space->id)) { + if (space->crypt_data || space->size || !space->get_size()) { /* The encryption metadata has already been read, or the tablespace is not encrypted and the file has been opened already, or the file cannot be accessed, @@ -2246,15 +2245,9 @@ static void fil_crypt_rotation_list_fill() } /* Ensure that crypt_data has been initialized. */ - if (!space->size) { - ut_d(const fil_space_t* s=) - fil_system.read_page0(space->id); - ut_ad(!s || s == space); - if (!space->size) { - /* Page 0 was not loaded. - Skip this tablespace. */ - goto next; - } + if (!space->get_size()) { + /* Page 0 was not loaded. Skip this tablespace. */ + goto next; } /* Skip ENCRYPTION!=DEFAULT tablespaces. */ diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 2da60b079f7..ad9d2828467 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -49,25 +49,81 @@ Created 10/25/1995 Heikki Tuuri #include "os0event.h" #include "sync0sync.h" #include "buf0flu.h" -#include "os0api.h" #ifdef UNIV_LINUX # include # include # include #endif -/** Tries to close a file in the LRU list. The caller must hold the fil_sys -mutex. -@return true if success, false if should retry later; since i/o's -generally complete in < 100 ms, and as InnoDB writes at most 128 pages -from the buffer pool in a batch, and then immediately flushes the -files, there is a good chance that the next time we find a suitable -node from the LRU list. -@param[in] print_info if true, prints information why it - cannot close a file */ -static -bool -fil_try_to_close_file_in_LRU(bool print_info); +/** Determine if the space id is a user tablespace id or not. +@param space_id tablespace identifier +@return true if it is a user tablespace ID */ +inline bool fil_is_user_tablespace_id(ulint space_id) +{ + return space_id != TRX_SYS_SPACE && space_id != SRV_TMP_SPACE_ID && + !srv_is_undo_tablespace(space_id); +} + +/** Try to close a file. +@return true if success, false if should retry later +@param print_info if true, prints information why it cannot close a file */ +static bool fil_try_to_close_file(bool print_info) +{ + ut_ad(mutex_own(&fil_system.mutex)); + for (fil_space_t *space= UT_LIST_GET_FIRST(fil_system.space_list); space; + space= UT_LIST_GET_NEXT(space_list, space)) + { + switch (space->purpose) { + case FIL_TYPE_TEMPORARY: + continue; + case FIL_TYPE_IMPORT: + break; + case FIL_TYPE_TABLESPACE: + if (!fil_is_user_tablespace_id(space->id)) + continue; + } + + /* We are using an approximation of LRU replacement policy. In + fil_node_open_file_low(), newly opened files are moved to the end + of fil_system.space_list, so that they would be less likely to be + closed here. */ + fil_node_t *node= UT_LIST_GET_FIRST(space->chain); + ut_ad(node); + ut_ad(!UT_LIST_GET_NEXT(chain, node)); + + if (!node->is_open()) + continue; + + if (auto n= space->set_closing()) + { + if (print_info) + ib::info() << "Cannot close file " << node->name + << " because of " << n << " pending operations"; + continue; + } + + if (auto n= node->n_pending_flushes) + { + if (print_info) + ib::info() << "Cannot close file " << node->name + << ", because n_pending_flushes " << n; + continue; + } + + if (node->needs_flush) + { + if (print_info) + ib::info() << "Cannot close file " << node->name + << ", because is should be flushed first"; + continue; + } + + node->close(); + return true; + } + + return false; +} /** Test if a tablespace file can be renamed to a new filepath by checking if that the old filepath exists and the new filepath does not exist. @@ -143,16 +199,7 @@ from a file, versus reading from a raw disk. To have fast access to a tablespace or a log file, we put the data structures to a hash table. Each tablespace and log file is given an unique 32-bit -identifier. - -Some operating systems do not support many open files at the same time, -though NT seems to tolerate at least 900 open files. Therefore, we put the -open files in an LRU-list. If we need to open another file, we may close the -file at the end of the LRU-list. When an i/o-operation is pending on a file, -the file cannot be closed. We take the file nodes with pending i/o-operations -out of the LRU-list and keep a count of pending operations. When an operation -completes, we decrement the count and return the file node to the LRU-list if -the count drops to zero. */ +identifier. */ /** Reference to the server data directory. Usually it is the current working directory ".", but in the MySQL Embedded Server Library @@ -172,18 +219,6 @@ fil_system_t fil_system; /** At this age or older a space/page will be rotated */ UNIV_INTERN extern uint srv_fil_crypt_rotate_key_age; -/** Determine if the space id is a user tablespace id or not. -@param[in] space_id Space ID to check -@return true if it is a user tablespace ID */ -inline -bool -fil_is_user_tablespace_id(ulint space_id) -{ - return(space_id != TRX_SYS_SPACE - && space_id != SRV_TMP_SPACE_ID - && !srv_is_undo_tablespace(space_id)); -} - #ifdef UNIV_DEBUG /** Try fil_validate() every this many times */ # define FIL_VALIDATE_SKIP 17 @@ -205,43 +240,6 @@ fil_validate_skip(void) } #endif /* UNIV_DEBUG */ -/********************************************************************//** -Determines if a file node belongs to the least-recently-used list. -@return true if the file belongs to fil_system.LRU mutex. */ -UNIV_INLINE -bool -fil_space_belongs_in_lru( -/*=====================*/ - const fil_space_t* space) /*!< in: file space */ -{ - switch (space->purpose) { - case FIL_TYPE_TEMPORARY: - return(false); - case FIL_TYPE_TABLESPACE: - return(fil_is_user_tablespace_id(space->id)); - case FIL_TYPE_IMPORT: - return(true); - } - - ut_ad(0); - return(false); -} - -/********************************************************************//** -NOTE: you must call fil_mutex_enter_and_prepare_for_io() first! - -Prepares a file node for i/o. Opens the file if it is closed. Updates the -pending i/o's field in the node and the system appropriately. Takes the node -off the LRU list if it is in the LRU list. The caller must hold the fil_sys -mutex. -@return false if the file can't be opened, otherwise true */ -static -bool -fil_node_prepare_for_io( -/*====================*/ - fil_node_t* node, /*!< in: file node */ - fil_space_t* space); /*!< in: space */ - /*******************************************************************//** Returns the table space by a given id, NULL if not found. It is unsafe to dereference the returned pointer. It is fine to check @@ -351,7 +349,7 @@ static bool fil_comp_algo_validate(const fil_space_t* space) @param[in] is_raw whether this is a raw device @param[in] atomic_write true if atomic write could be enabled @param[in] max_pages maximum number of pages in file, -or ULINT_MAX for unlimited +or UINT32_MAX for unlimited @return file object */ fil_node_t* fil_space_t::add(const char* name, pfs_os_file_t handle, uint32_t size, bool is_raw, bool atomic_write, @@ -387,114 +385,108 @@ fil_node_t* fil_space_t::add(const char* name, pfs_os_file_t handle, this->size += size; UT_LIST_ADD_LAST(chain, node); if (node->is_open()) { - fil_system.n_open++; + ++fil_system.n_open; } mutex_exit(&fil_system.mutex); return node; } -/** Open a file node of a tablespace. -@param[in,out] node File node -@return false if the file can't be opened, otherwise true */ -static bool fil_node_open_file(fil_node_t* node) +/** Open a tablespace file. +@param node data file +@return whether the file was successfully opened */ +static bool fil_node_open_file_low(fil_node_t *node) { - bool success; - bool read_only_mode; - fil_space_t* space = node->space; + ut_ad(!node->is_open()); + ut_ad(node->space->is_closing()); + ut_ad(mutex_own(&fil_system.mutex)); + const auto flags= node->space->flags; + bool o_direct_possible= !FSP_FLAGS_HAS_PAGE_COMPRESSION(flags); + static_assert(((UNIV_ZIP_SIZE_MIN >> 1) << 3) == 4096, "compatibility"); + if (const auto ssize= FSP_FLAGS_GET_ZIP_SSIZE(flags)) + if (ssize < 3) + o_direct_possible= false; - ut_ad(mutex_own(&fil_system.mutex)); - ut_a(node->n_pending == 0); - ut_a(!node->is_open()); + for (;;) + { + bool success; + node->handle= os_file_create(innodb_data_file_key, node->name, + node->is_raw_disk + ? OS_FILE_OPEN_RAW | OS_FILE_ON_ERROR_NO_EXIT + : OS_FILE_OPEN | OS_FILE_ON_ERROR_NO_EXIT, + OS_FILE_AIO, o_direct_possible + ? OS_DATA_FILE : OS_DATA_FILE_NO_O_DIRECT, + srv_read_only_mode, &success); + if (success) + break; - read_only_mode = space->purpose != FIL_TYPE_TEMPORARY - && srv_read_only_mode; + /* The following call prints an error message */ + if (os_file_get_last_error(true) == EMFILE + 100 && + fil_try_to_close_file(true)) + continue; - const bool first_time_open = node->size == 0; + ib::warn() << "Cannot open '" << node->name << "'."; + return false; + } - bool o_direct_possible = !FSP_FLAGS_HAS_PAGE_COMPRESSION(space->flags); - if (const ulint ssize = FSP_FLAGS_GET_ZIP_SSIZE(space->flags)) { - compile_time_assert(((UNIV_ZIP_SIZE_MIN >> 1) << 3) == 4096); - if (ssize < 3) { - o_direct_possible = false; - } - } + if (node->size); + else if (!node->read_page0() || !fil_comp_algo_validate(node->space)) + { + os_file_close(node->handle); + node->handle= OS_FILE_CLOSED; + return false; + } - if (first_time_open - || (space->purpose == FIL_TYPE_TABLESPACE - && node == UT_LIST_GET_FIRST(space->chain) - && srv_startup_is_before_trx_rollback_phase)) { - /* We do not know the size of the file yet. First we - open the file in the normal mode, no async I/O here, - for simplicity. Then do some checks, and close the - file again. NOTE that we could not use the simple - file read function os_file_read() in Windows to read - from a file opened for async I/O! */ + ut_ad(node->is_open()); -retry: - node->handle = os_file_create( - innodb_data_file_key, node->name, - node->is_raw_disk - ? OS_FILE_OPEN_RAW | OS_FILE_ON_ERROR_NO_EXIT - : OS_FILE_OPEN | OS_FILE_ON_ERROR_NO_EXIT, - OS_FILE_AIO, - o_direct_possible - ? OS_DATA_FILE - : OS_DATA_FILE_NO_O_DIRECT, - read_only_mode, - &success); + if (UNIV_LIKELY(!fil_system.freeze_space_list)) + { + /* Move the file last in fil_system.space_list, so that + fil_try_to_close_file() should close it as a last resort. */ + UT_LIST_REMOVE(fil_system.space_list, node->space); + UT_LIST_ADD_LAST(fil_system.space_list, node->space); + } - if (!success) { - /* The following call prints an error message */ - ulint err = os_file_get_last_error(true); - if (err == EMFILE + 100) { - if (fil_try_to_close_file_in_LRU(true)) - goto retry; - } + fil_system.n_open++; + return true; +} - ib::warn() << "Cannot open '" << node->name << "'." - " Have you deleted .ibd files under a" - " running mysqld server?"; - return(false); - } +/** Open a tablespace file. +@param node data file +@return whether the file was successfully opened */ +static bool fil_node_open_file(fil_node_t *node) +{ + ut_ad(mutex_own(&fil_system.mutex)); + ut_ad(!node->is_open()); + ut_ad(fil_is_user_tablespace_id(node->space->id) || + srv_operation == SRV_OPERATION_BACKUP || + srv_operation == SRV_OPERATION_RESTORE || + srv_operation == SRV_OPERATION_RESTORE_DELTA); + ut_ad(node->space->purpose != FIL_TYPE_TEMPORARY); + ut_ad(node->space->pending_io()); - if (!node->read_page0(first_time_open)) { -fail: - os_file_close(node->handle); - node->handle = OS_FILE_CLOSED; - return false; - } + for (ulint count= 0; fil_system.n_open >= srv_max_n_open_files; count++) + { + if (fil_try_to_close_file(count > 1)) + count= 0; + else if (count >= 2) + { + ib::warn() << "innodb_open_files=" << srv_max_n_open_files + << " is exceeded (" << fil_system.n_open + << ") files stay open)"; + break; + } + else + { + mutex_exit(&fil_system.mutex); + os_thread_sleep(20000); + /* Flush tablespaces so that we can close modified files. */ + fil_flush_file_spaces(); + mutex_enter(&fil_system.mutex); + } + } - if (first_time_open && !fil_comp_algo_validate(space)) { - goto fail; - } - - } else { - node->handle = os_file_create( - innodb_data_file_key, node->name, - node->is_raw_disk - ? OS_FILE_OPEN_RAW | OS_FILE_ON_ERROR_NO_EXIT - : OS_FILE_OPEN | OS_FILE_ON_ERROR_NO_EXIT, - OS_FILE_AIO, - o_direct_possible - ? OS_DATA_FILE - : OS_DATA_FILE_NO_O_DIRECT, - read_only_mode, - &success); - } - - ut_a(success); - ut_a(node->is_open()); - - fil_system.n_open++; - - if (fil_space_belongs_in_lru(space)) { - - /* Put the node to the LRU list */ - UT_LIST_ADD_FIRST(fil_system.LRU, node); - } - - return(true); + return fil_node_open_file_low(node); } /** Close the file handle. */ @@ -520,8 +512,9 @@ pfs_os_file_t fil_node_t::detach() void fil_node_t::prepare_to_close_or_detach() { ut_ad(mutex_own(&fil_system.mutex)); + ut_ad(space->is_closing()); + ut_ad(!space->pending_io()); ut_a(is_open()); - ut_a(n_pending == 0); ut_a(n_pending_flushes == 0); ut_a(!being_extended); ut_a(!needs_flush || space->purpose == FIL_TYPE_TEMPORARY || @@ -529,78 +522,13 @@ void fil_node_t::prepare_to_close_or_detach() ut_a(fil_system.n_open > 0); fil_system.n_open--; - - if (fil_space_belongs_in_lru(space)) - { - ut_a(UT_LIST_GET_LEN(fil_system.LRU) > 0); - UT_LIST_REMOVE(fil_system.LRU, this); - } -} - -/** Tries to close a file in the LRU list. The caller must hold the fil_sys -mutex. -@return true if success, false if should retry later; since i/o's -generally complete in < 100 ms, and as InnoDB writes at most 128 pages -from the buffer pool in a batch, and then immediately flushes the -files, there is a good chance that the next time we find a suitable -node from the LRU list. -@param[in] print_info if true, prints information why it - cannot close a file*/ -static -bool -fil_try_to_close_file_in_LRU( - - bool print_info) -{ - fil_node_t* node; - - ut_ad(mutex_own(&fil_system.mutex)); - - if (print_info) { - ib::info() << "fil_sys open file LRU len " - << UT_LIST_GET_LEN(fil_system.LRU); - } - - for (node = UT_LIST_GET_LAST(fil_system.LRU); - node != NULL; - node = UT_LIST_GET_PREV(LRU, node)) { - - if (!node->needs_flush - && node->n_pending_flushes == 0 - && !node->being_extended) { - - node->close(); - - return(true); - } - - if (!print_info) { - continue; - } - - if (const auto n = node->n_pending_flushes) { - ib::info() << "Cannot close file " << node->name - << ", because n_pending_flushes " << n; - } - - if (node->needs_flush) { - ib::warn() << "Cannot close file " << node->name - << ", because is should be flushed first"; - } - - if (node->being_extended) { - ib::info() << "Cannot close file " << node->name - << ", because it is being extended"; - } - } - - return(false); } /** Flush any writes cached by the file system. @param[in,out] space tablespace -@param[in] metadata whether to update file system metadata */ -static void fil_flush_low(fil_space_t* space, bool metadata = false) +@param[in] metadata whether to update file system metadata +@return whether fil_system.mutex was released and reacquired */ +static bool fil_flush_low(fil_space_t* space, bool metadata = false) { ut_ad(mutex_own(&fil_system.mutex)); ut_ad(!space->is_stopping()); @@ -621,9 +549,10 @@ static void fil_flush_low(fil_space_t* space, bool metadata = false) } #endif /* UNIV_DEBUG */ - if (!metadata) return; + if (!metadata) return false; } + bool reacquired = false; /* Prevent dropping of the space while we are flushing */ space->n_pending_flushes++; @@ -653,6 +582,7 @@ static void fil_flush_low(fil_space_t* space, bool metadata = false) mutex_exit(&fil_system.mutex); os_file_flush(node->handle); + reacquired = true; mutex_enter(&fil_system.mutex); @@ -673,6 +603,7 @@ skip_flush: } space->n_pending_flushes--; + return reacquired; } /** Try to extend a tablespace. @@ -692,6 +623,8 @@ fil_space_extend_must_retry( ut_ad(mutex_own(&fil_system.mutex)); ut_ad(UT_LIST_GET_LAST(space->chain) == node); ut_ad(size >= FIL_IBD_FILE_INITIAL_SIZE); + ut_ad(node->space == space); + ut_ad(space->pending_io()); *success = space->size >= size; @@ -712,12 +645,6 @@ fil_space_extend_must_retry( node->being_extended = true; - if (!fil_node_prepare_for_io(node, space)) { - /* The tablespace data file, such as .ibd file, is missing */ - node->being_extended = false; - return(false); - } - /* At this point it is safe to release fil_system.mutex. No other thread can rename, delete, close or extend the file because we have set the node->being_extended flag. */ @@ -765,8 +692,6 @@ fil_space_extend_must_retry( const uint32_t pages_in_MiB = node->size & ~uint32_t((1U << (20U - srv_page_size_shift)) - 1); - node->complete_io(); - /* Keep the last data file size info up to date, rounded to full megabytes */ @@ -790,105 +715,56 @@ fil_space_extend_must_retry( } } -/** Acquire fil_system.mutex and try to make sure we can open at least one -file while holding it. This should be called before calling -fil_node_prepare_for_io(), because that function may need to open a file. */ -static -fil_space_t* -fil_mutex_enter_and_prepare_for_io( - ulint space_id) /*!< in: space id */ +/** @return whether the file is usable for io() */ +ATTRIBUTE_COLD bool fil_space_t::prepare_for_io() { - for (ulint count = 0;;) { - mutex_enter(&fil_system.mutex); + ut_ad(pending_io()); + mutex_enter(&fil_system.mutex); + fil_node_t *node= UT_LIST_GET_LAST(chain); + ut_ad(!id || purpose == FIL_TYPE_TEMPORARY || + node == UT_LIST_GET_FIRST(chain)); - fil_space_t* space = fil_space_get_by_id(space_id); + const bool is_open= node && (node->is_open() || fil_node_open_file(node)); - if (!space) { - return nullptr; - } + if (!is_open) + release_for_io(); + else if (auto desired_size= recv_size) + { + bool success; + while (fil_space_extend_must_retry(this, node, desired_size, &success)) + mutex_enter(&fil_system.mutex); - fil_node_t* node = UT_LIST_GET_LAST(space->chain); - ut_ad(space->id == 0 - || node == UT_LIST_GET_FIRST(space->chain)); + ut_ad(mutex_own(&fil_system.mutex)); + /* Crash recovery requires the file extension to succeed. */ + ut_a(success); + /* InnoDB data files cannot shrink. */ + ut_a(size >= desired_size); + if (desired_size > committed_size) + committed_size= desired_size; - if (space->id == 0) { - /* We keep the system tablespace files always - open; this is important in preventing - deadlocks in this module, as a page read - completion often performs another read from - the insert buffer. The insert buffer is in - tablespace 0, and we cannot end up waiting in - this function. */ - } else if (!node || node->is_open()) { - /* If the file is already open, no need to do - anything; if the space does not exist, we handle the - situation in the function which called this - function */ - } else { - while (fil_system.n_open >= srv_max_n_open_files) { - /* Too many files are open */ - if (fil_try_to_close_file_in_LRU(count > 1)) { - /* No problem */ - } else if (count >= 2) { - ib::warn() << "innodb_open_files=" - << srv_max_n_open_files - << " is exceeded (" - << fil_system.n_open - << ") files stay open)"; - break; - } else { - mutex_exit(&fil_system.mutex); - os_thread_sleep(20000); - /* Flush tablespaces so that we can - close modified files in the LRU list */ - fil_flush_file_spaces(); + /* There could be multiple concurrent I/O requests for this + tablespace (multiple threads trying to extend this tablespace). - count++; - mutex_enter(&fil_system.mutex); - continue; - } - } - } + Also, fil_space_set_recv_size_and_flags() may have been invoked + again during the file extension while fil_system.mutex was not + being held by us. - uint32_t size = space->recv_size; - if (UNIV_UNLIKELY(size != 0)) { - ut_ad(node); - bool success; - if (fil_space_extend_must_retry(space, node, size, - &success)) { - continue; - } + Only if recv_size matches what we read originally, reset the + field. In this way, a subsequent I/O request will handle any + pending fil_space_set_recv_size_and_flags(). */ - ut_ad(mutex_own(&fil_system.mutex)); - /* Crash recovery requires the file extension - to succeed. */ - ut_a(success); - /* InnoDB data files cannot shrink. */ - ut_a(space->size >= size); - if (size > space->committed_size) { - space->committed_size = size; - } + if (desired_size == recv_size) + { + recv_size= 0; + goto clear; + } + } + else +clear: + n_pending_ios.fetch_and(NOT_CLOSING); - /* There could be multiple concurrent I/O requests for - this tablespace (multiple threads trying to extend - this tablespace). - - Also, fil_space_set_recv_size_and_flags() may have been - invoked again during the file extension while - fil_system.mutex was not being held by us. - - Only if space->recv_size matches what we read - originally, reset the field. In this way, a - subsequent I/O request will handle any pending - fil_space_set_recv_size_and_flags(). */ - - if (size == space->recv_size) { - space->recv_size = 0; - } - } - - return space; - } + mutex_exit(&fil_system.mutex); + return is_open; } /** Try to extend a tablespace if it is smaller than the specified size. @@ -897,18 +773,20 @@ fil_mutex_enter_and_prepare_for_io( @return whether the tablespace is at least as big as requested */ bool fil_space_extend(fil_space_t *space, uint32_t size) { - ut_ad(!srv_read_only_mode || space->purpose == FIL_TYPE_TEMPORARY); + ut_ad(!srv_read_only_mode || space->purpose == FIL_TYPE_TEMPORARY); + if (!space->acquire_for_io()) + return false; - bool success; + bool success; - do { - fil_mutex_enter_and_prepare_for_io(space->id); - } while (fil_space_extend_must_retry( - space, UT_LIST_GET_LAST(space->chain), size, - &success)); + do + mutex_enter(&fil_system.mutex); + while (fil_space_extend_must_retry(space, UT_LIST_GET_LAST(space->chain), + size, &success)); - mutex_exit(&fil_system.mutex); - return(success); + mutex_exit(&fil_system.mutex); + space->release_for_io(); + return success; } /** Prepare to free a file from fil_system. */ @@ -927,7 +805,7 @@ pfs_os_file_t fil_node_t::close_to_free(bool detach_handle) fil_system.unflushed_spaces.remove(*space); } - if (n_pending || n_pending_flushes) + if (n_pending_flushes || space->set_closing()) { mutex_exit(&fil_system.mutex); os_thread_sleep(100); @@ -935,11 +813,6 @@ pfs_os_file_t fil_node_t::close_to_free(bool detach_handle) continue; } - if (fil_space_belongs_in_lru(space)) - { - ut_ad(UT_LIST_GET_LEN(fil_system.LRU) > 0); - UT_LIST_REMOVE(fil_system.LRU, this); - } ut_a(!being_extended); if (detach_handle) { @@ -1020,7 +893,7 @@ fil_space_free_low( /* Wait for fil_space_t::release_for_io(); after fil_system_t::detach(), the tablespace cannot be found, so - fil_space_acquire_for_io() would return NULL */ + fil_space_t::get_for_io() would return NULL */ while (space->pending_io()) { os_thread_sleep(100); } @@ -1092,24 +965,19 @@ fil_space_free( return(space != NULL); } -/** Create a space memory object and put it to the fil_system hash table. -Error messages are issued to the server log. -@param[in] name tablespace name -@param[in] id tablespace identifier -@param[in] flags tablespace flags -@param[in] purpose tablespace purpose -@param[in,out] crypt_data encryption information -@param[in] mode encryption mode -@return pointer to created tablespace, to be filled in with fil_space_t::add() -@retval NULL on failure (such as when the same tablespace exists) */ -fil_space_t* -fil_space_create( - const char* name, - ulint id, - ulint flags, - fil_type_t purpose, - fil_space_crypt_t* crypt_data, - fil_encryption_t mode) +/** Create a tablespace in fil_system. +@param name tablespace name +@param id tablespace identifier +@param flags tablespace flags +@param purpose tablespace purpose +@param crypt_data encryption information +@param mode encryption mode +@return pointer to created tablespace, to be filled in with add() +@retval nullptr on failure (such as when the same tablespace exists) */ +fil_space_t *fil_space_t::create(const char *name, ulint id, ulint flags, + fil_type_t purpose, + fil_space_crypt_t *crypt_data, + fil_encryption_t mode) { fil_space_t* space; @@ -1119,19 +987,6 @@ fil_space_create( DBUG_EXECUTE_IF("fil_space_create_failure", return(NULL);); - mutex_enter(&fil_system.mutex); - - space = fil_space_get_by_id(id); - - if (space != NULL) { - ib::error() << "Trying to add tablespace '" << name - << "' with id " << id - << " to the tablespace memory cache, but tablespace '" - << space->name << "' already exists in the cache!"; - mutex_exit(&fil_system.mutex); - return(NULL); - } - /* FIXME: if calloc() is defined as an inline function that calls memset() or bzero(), then GCC 6 -flifetime-dse can optimize it away */ space= new (ut_zalloc_nokey(sizeof(*space))) fil_space_t; @@ -1141,24 +996,12 @@ fil_space_create( UT_LIST_INIT(space->chain, &fil_node_t::chain); - if ((purpose == FIL_TYPE_TABLESPACE || purpose == FIL_TYPE_IMPORT) - && id > fil_system.max_assigned_id) { - if (!fil_system.space_id_reuse_warned) { - fil_system.space_id_reuse_warned = true; - - ib::warn() << "Allocated tablespace ID " << id - << " for " << name << ", old maximum was " - << fil_system.max_assigned_id; - } - - fil_system.max_assigned_id = id; - } - space->purpose = purpose; space->flags = flags; space->magic_n = FIL_SPACE_MAGIC_N; space->crypt_data = crypt_data; + space->n_pending_ios.store(CLOSING, std::memory_order_relaxed); DBUG_LOG("tablespace", "Created metadata for " << id << " name " << name); @@ -1183,6 +1026,34 @@ fil_space_create( space->atomic_write_supported = true; } + mutex_enter(&fil_system.mutex); + + if (const fil_space_t *old_space = fil_space_get_by_id(id)) { + ib::error() << "Trying to add tablespace '" << name + << "' with id " << id + << " to the tablespace memory cache, but tablespace '" + << old_space->name << "' already exists in the cache!"; + mutex_exit(&fil_system.mutex); + rw_lock_free(&space->latch); + space->~fil_space_t(); + ut_free(space->name); + ut_free(space); + return(NULL); + } + + if ((purpose == FIL_TYPE_TABLESPACE || purpose == FIL_TYPE_IMPORT) + && id > fil_system.max_assigned_id) { + if (!fil_system.space_id_reuse_warned) { + fil_system.space_id_reuse_warned = true; + + ib::warn() << "Allocated tablespace ID " << id + << " for " << name << ", old maximum was " + << fil_system.max_assigned_id; + } + + fil_system.max_assigned_id = id; + } + HASH_INSERT(fil_space_t, hash, &fil_system.spaces, id, space); UT_LIST_ADD_LAST(fil_system.space_list, space); @@ -1192,6 +1063,17 @@ fil_space_create( fil_system.max_assigned_id = id; } + switch (id) { + case 0: + ut_ad(!fil_system.sys_space); + fil_system.sys_space = space; + break; + case SRV_TMP_SPACE_ID: + ut_ad(!fil_system.temp_space); + fil_system.temp_space = space; + break; + } + /* Inform key rotation that there could be something to do */ if (purpose == FIL_TYPE_TABLESPACE @@ -1261,62 +1143,33 @@ fil_assign_new_space_id( return(success); } -/** Trigger a call to fil_node_t::read_page0() -@param[in] id tablespace identifier -@return tablespace -@retval NULL if the tablespace does not exist or cannot be read */ -fil_space_t* fil_system_t::read_page0(ulint id) +/** Read the first page of a data file. +@return whether the page was found valid */ +bool fil_space_t::read_page0() { - mutex_exit(&mutex); + ut_ad(fil_system.is_initialised()); + ut_ad(mutex_own(&fil_system.mutex)); + if (size) + return true; - ut_ad(id != 0); + fil_node_t *node= UT_LIST_GET_FIRST(chain); + if (!node) + return false; + ut_ad(!UT_LIST_GET_NEXT(chain, node)); - /* It is possible that the tablespace is dropped while we are - not holding the mutex. */ - fil_space_t* space = fil_mutex_enter_and_prepare_for_io(id); - - if (space == NULL || UT_LIST_GET_LEN(space->chain) == 0) { - return(NULL); - } - - /* The following code must change when InnoDB supports - multiple datafiles per tablespace. */ - ut_a(1 == UT_LIST_GET_LEN(space->chain)); - - fil_node_t* node = UT_LIST_GET_FIRST(space->chain); - - /* It must be a single-table tablespace and we have not opened - the file yet; the following calls will open it and update the - size fields */ - - if (!fil_node_prepare_for_io(node, space)) { - /* The single-table tablespace can't be opened, - because the ibd file is missing. */ - return(NULL); - } - - node->complete_io(); - - return space; + n_pending_ios.fetch_add(1, std::memory_order_acquire); + const bool ok= node->is_open() || fil_node_open_file(node); + release_for_io(); + return ok; } -/*******************************************************************//** -Returns a pointer to the fil_space_t that is in the memory cache -associated with a space id. The caller must lock fil_system.mutex. -@return file_space_t pointer, NULL if space not found */ -UNIV_INLINE -fil_space_t* -fil_space_get_space( -/*================*/ - ulint id) /*!< in: space id */ +/** Look up a tablespace and ensure that its first page has been validated. */ +static fil_space_t *fil_space_get_space(ulint id) { - fil_space_t* space = fil_space_get_by_id(id); - if (space == NULL || space->size != 0) { - return(space); - } - - space = fil_system.read_page0(id); - return(space); + if (fil_space_t *space= fil_space_get_by_id(id)) + if (space->read_page0()) + return space; + return nullptr; } void fil_space_set_recv_size_and_flags(ulint id, uint32_t size, uint32_t flags) @@ -1333,53 +1186,52 @@ void fil_space_set_recv_size_and_flags(ulint id, uint32_t size, uint32_t flags) mutex_exit(&fil_system.mutex); } -/*******************************************************************//** -Returns the size of the space in pages. The tablespace must be cached in the -memory cache. -@return space size, 0 if space not found */ -ulint -fil_space_get_size( -/*===============*/ - ulint id) /*!< in: space id */ -{ - fil_space_t* space; - ulint size; - - ut_ad(fil_system.is_initialised()); - mutex_enter(&fil_system.mutex); - - space = fil_space_get_space(id); - - size = space ? space->size : 0; - - mutex_exit(&fil_system.mutex); - - return(size); -} - -/** Open each file. Only invoked on fil_system.temp_space. +/** Open each file. Never invoked on .ibd files. +@param create_new_db whether to skip the call to fil_node_t::read_page0() @return whether all files were opened */ -bool fil_space_t::open() +bool fil_space_t::open(bool create_new_db) { - ut_ad(fil_system.is_initialised()); + ut_ad(fil_system.is_initialised()); + ut_ad(!id || create_new_db); - mutex_enter(&fil_system.mutex); - ut_ad(this == fil_system.temp_space - || srv_operation == SRV_OPERATION_BACKUP - || srv_operation == SRV_OPERATION_RESTORE - || srv_operation == SRV_OPERATION_RESTORE_DELTA); + bool success= true; + bool skip_read= create_new_db; - for (fil_node_t* node = UT_LIST_GET_FIRST(chain); - node != NULL; - node = UT_LIST_GET_NEXT(chain, node)) { - if (!node->is_open() && !fil_node_open_file(node)) { - mutex_exit(&fil_system.mutex); - return false; - } - } + mutex_enter(&fil_system.mutex); - mutex_exit(&fil_system.mutex); - return true; + for (fil_node_t *node= UT_LIST_GET_FIRST(chain); node; + node= UT_LIST_GET_NEXT(chain, node)) + { + if (!node->is_open() && !fil_node_open_file_low(node)) + { +err_exit: + success= false; + break; + } + + if (create_new_db) + continue; + if (skip_read) + { + size+= node->size; + continue; + } + + if (!node->read_page0()) + { + fil_system.n_open--; + os_file_close(node->handle); + node->handle= OS_FILE_CLOSED; + goto err_exit; + } + + skip_read= true; + } + + if (!create_new_db) + committed_size= size; + mutex_exit(&fil_system.mutex); + return success; } /** Close each file. Only invoked on fil_system.temp_space. */ @@ -1491,7 +1343,6 @@ void fil_system_t::create(ulint hash_size) void fil_system_t::close() { ut_ad(this == &fil_system); - ut_a(!UT_LIST_GET_LEN(LRU)); ut_a(unflushed_spaces.empty()); ut_a(!UT_LIST_GET_LEN(space_list)); ut_ad(!sys_space); @@ -1513,67 +1364,6 @@ void fil_system_t::close() #endif /* UNIV_LINUX */ } -/** Opens all system tablespace data files. They stay open until the -database server shutdown. This should be called at a server startup after the -space objects for the system tablespace have been created. The -purpose of this operation is to make sure we never run out of file descriptors -if we need to read from the insert buffer. */ -void -fil_open_system_tablespace_files() -{ - fil_space_t* space; - - mutex_enter(&fil_system.mutex); - - for (space = UT_LIST_GET_FIRST(fil_system.space_list); - space != NULL; - space = UT_LIST_GET_NEXT(space_list, space)) { - - fil_node_t* node; - - if (fil_space_belongs_in_lru(space)) { - - continue; - } - - for (node = UT_LIST_GET_FIRST(space->chain); - node != NULL; - node = UT_LIST_GET_NEXT(chain, node)) { - - if (!node->is_open()) { - if (!fil_node_open_file(node)) { - /* This func is called during server's - startup. If some file of log or system - tablespace is missing, the server - can't start successfully. So we should - assert for it. */ - ut_a(0); - } - } - - if (srv_max_n_open_files < 10 + fil_system.n_open) { - - ib::warn() << "You must raise the value of" - " innodb_open_files in my.cnf!" - " Remember that InnoDB keeps all" - " log files and all system" - " tablespace files open" - " for the whole time mysqld is" - " running, and needs to open also" - " some .ibd files if the" - " file-per-table storage model is used." - " Current open files " - << fil_system.n_open - << ", max allowed open files " - << srv_max_n_open_files - << "."; - } - } - } - - mutex_exit(&fil_system.mutex); -} - /** Close all tablespace files at shutdown */ void fil_close_all_files() { @@ -1605,21 +1395,21 @@ next: } for (ulint count = 10000; count--; ) { + if (!space->set_closing() + && !node->n_pending_flushes) { + node->close(); + goto next; + } mutex_exit(&fil_system.mutex); os_thread_sleep(100); mutex_enter(&fil_system.mutex); if (!node->is_open()) { goto next; } - if (!node->n_pending - && !node->n_pending_flushes) { - node->close(); - goto next; - } } ib::error() << "File '" << node->name - << "' has " << node->n_pending + << "' has " << space->pending_io() << " operations and " << node->n_pending_flushes << " flushes"; @@ -1670,16 +1460,18 @@ fil_write_flushed_lsn( byte* buf; ut_ad(!srv_read_only_mode); + if (!fil_system.sys_space->acquire_for_io()) { + return DB_ERROR; + } + buf = static_cast(aligned_malloc(srv_page_size, srv_page_size)); - const page_id_t page_id(TRX_SYS_SPACE, 0); - - fil_io_t fio = fil_io(IORequestRead, true, page_id, 0, 0, - srv_page_size, buf, NULL); + auto fio = fil_system.sys_space->io(IORequestRead, 0, srv_page_size, + buf); if (fio.err == DB_SUCCESS) { - fio.node->space->release_for_io(); - mach_write_to_8(buf + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, lsn); + mach_write_to_8(buf + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, + lsn); ulint fsp_flags = mach_read_from_4( buf + FSP_HEADER_OFFSET + FSP_SPACE_FLAGS); @@ -1688,13 +1480,11 @@ fil_write_flushed_lsn( buf_flush_assign_full_crc32_checksum(buf); } - fio = fil_io(IORequestWrite, true, page_id, 0, 0, - srv_page_size, buf, NULL); + fio = fil_system.sys_space->io(IORequestWrite, + 0, srv_page_size, buf); fil_flush_file_spaces(); - } - - if (fio.node) { - fio.node->space->release_for_io(); + } else { + fil_system.sys_space->release_for_io(); } aligned_free(buf); @@ -1735,20 +1525,25 @@ when it could be dropped concurrently. @param[in] id tablespace ID @return the tablespace @retval NULL if missing */ -fil_space_t* -fil_space_acquire_for_io(ulint id) +fil_space_t *fil_space_t::get_for_io(ulint id) { - mutex_enter(&fil_system.mutex); + mutex_enter(&fil_system.mutex); - fil_space_t* space = fil_space_get_by_id(id); + fil_space_t *space= fil_space_get_by_id(id); - if (space) { - space->acquire_for_io(); - } + uint32_t f= space + ? space->n_pending_ios.fetch_add(1, std::memory_order_relaxed) + : 0; - mutex_exit(&fil_system.mutex); + mutex_exit(&fil_system.mutex); - return(space); + if ((f & CLOSING) && !space->prepare_for_io()) + { + // FIXME: issue an error message! + space= nullptr; + } + + return space; } /** Write a log record about a file operation. @@ -1986,12 +1781,12 @@ fil_check_pending_io( /* The following code must change when InnoDB supports multiple datafiles per tablespace. */ - ut_a(UT_LIST_GET_LEN(space->chain) == 1); + ut_ad(UT_LIST_GET_LEN(space->chain) == 1); *node = UT_LIST_GET_FIRST(space->chain); const auto f = space->n_pending_flushes; - const auto p = (*node)->n_pending; + const auto p = space->pending_io(); if (f || p) { ut_a(!(*node)->being_extended); @@ -2105,15 +1900,14 @@ void fil_close_tablespace(ulint id) rw_lock_x_lock(&space->latch); /* Invalidate in the buffer pool all pages belonging to the - tablespace. Since we have set space->stop_new_ops = true, readahead + tablespace. Since we have invoked space->set_stopping(), readahead can no longer read more pages of this tablespace to buf_pool. Thus we can clean the tablespace out of buf_pool - completely and permanently. The flag stop_new_ops also prevents - fil_flush() from being applied to this tablespace. */ + completely and permanently. */ while (buf_flush_dirty_pages(id)); /* Ensure that all asynchronous IO is completed. */ os_aio_wait_until_no_pending_writes(); - fil_flush(id); + ut_ad(space->is_stopping()); /* If the free is successful, the X lock will be released before the space memory data structure is freed. */ @@ -2191,7 +1985,7 @@ dberr_t fil_delete_tablespace(ulint id, bool if_exists, when we checked it above. A write request can be issued any time because we don't check - the ::stop_new_ops flag when queueing a block for write. + fil_space_t::is_stopping() when queueing a block for write. We deal with pending write requests in the following function where we'd minimally evict all dirty pages belonging to this @@ -2199,7 +1993,7 @@ dberr_t fil_delete_tablespace(ulint id, bool if_exists, we'll wait for IO to complete. To deal with potential read requests, we will check the - ::stop_new_ops flag in fil_io(). */ + is_stopping() in fil_space_t::io(). */ err = DB_SUCCESS; buf_flush_remove_pages(id); @@ -2728,14 +2522,14 @@ err_exit: buf_flush_init_for_writing(NULL, page, &page_zip, false); - *err = os_file_write( - IORequestWrite, path, file, page_zip.data, 0, zip_size); + *err = os_file_write(IORequestWrite, path, file, + page_zip.data, 0, zip_size); } else { buf_flush_init_for_writing(NULL, page, NULL, fil_space_t::full_crc32(flags)); - *err = os_file_write( - IORequestWrite, path, file, page, 0, srv_page_size); + *err = os_file_write(IORequestWrite, path, file, + page, 0, srv_page_size); } aligned_free(page); @@ -2763,9 +2557,9 @@ err_exit: } } - fil_space_t* space = fil_space_create(name, space_id, flags, - FIL_TYPE_TABLESPACE, - crypt_data, mode); + fil_space_t* space = fil_space_t::create(name, space_id, flags, + FIL_TYPE_TABLESPACE, + crypt_data, mode); if (!space) { free(crypt_data); *err = DB_ERROR; @@ -3143,7 +2937,7 @@ skip_validate: first_page) : NULL; - fil_space_t* space = fil_space_create( + fil_space_t* space = fil_space_t::create( tablename.m_name, id, flags, purpose, crypt_data); if (!space) { goto error; @@ -3157,11 +2951,17 @@ skip_validate: df_dict.is_open() ? df_dict.filepath() : df_default.filepath(), OS_FILE_CLOSED, 0, false, true); - if (validate && purpose != FIL_TYPE_IMPORT && !srv_read_only_mode) { + if (validate && !srv_read_only_mode) { df_remote.close(); df_dict.close(); df_default.close(); - fsp_flags_try_adjust(space, flags & ~FSP_FLAGS_MEM_MASK); + if (space->acquire_for_io()) { + if (purpose != FIL_TYPE_IMPORT) { + fsp_flags_try_adjust(space, flags + & ~FSP_FLAGS_MEM_MASK); + } + space->release_for_io(); + } } if (err) *err = DB_SUCCESS; @@ -3491,7 +3291,7 @@ fil_ibd_load( ? fil_space_read_crypt_data(fil_space_t::zip_size(flags), first_page) : NULL; - space = fil_space_create( + space = fil_space_t::create( file.name(), space_id, flags, FIL_TYPE_TABLESPACE, crypt_data); if (space == NULL) { @@ -3557,7 +3357,7 @@ void fsp_flags_try_adjust(fil_space_t* space, ulint flags) return; } if (!space->size && (space->purpose != FIL_TYPE_TABLESPACE - || !fil_space_get_size(space->id))) { + || !space->get_size())) { return; } /* This code is executed during server startup while no @@ -3596,7 +3396,7 @@ func_exit: memory cache. Note that if we have not done a crash recovery at the database startup, there may be many tablespaces which are not yet in the memory cache. @param[in] id Tablespace ID -@param[in] name Tablespace name used in fil_space_create(). +@param[in] name Tablespace name used in fil_space_t::create(). @param[in] table_flags table flags @return the tablespace @retval NULL if no matching tablespace exists in the memory cache */ @@ -3648,281 +3448,159 @@ func_exit: /*============================ FILE I/O ================================*/ -/********************************************************************//** -NOTE: you must call fil_mutex_enter_and_prepare_for_io() first! - -Prepares a file node for i/o. Opens the file if it is closed. Updates the -pending i/o's field in the node and the system appropriately. Takes the node -off the LRU list if it is in the LRU list. The caller must hold the fil_sys -mutex. -@return false if the file can't be opened, otherwise true */ -static -bool -fil_node_prepare_for_io( -/*====================*/ - fil_node_t* node, /*!< in: file node */ - fil_space_t* space) /*!< in: space */ -{ - ut_ad(node && space); - ut_ad(mutex_own(&fil_system.mutex)); - - if (fil_system.n_open > srv_max_n_open_files + 5) { - ib::warn() << "Open files " << fil_system.n_open - << " exceeds the limit " << srv_max_n_open_files; - } - - if (!node->is_open()) { - /* File is closed: open it */ - ut_a(node->n_pending == 0); - - if (!fil_node_open_file(node)) { - return(false); - } - } - - if (node->n_pending++ == 0 && fil_space_belongs_in_lru(space)) { - UT_LIST_REMOVE(fil_system.LRU, node); - } - - return(true); -} - /** Report information about an invalid page access. */ ATTRIBUTE_COLD __attribute__((noreturn)) static void -fil_report_invalid_page_access(const page_id_t id, const char *name, - ulint byte_offset, ulint len, bool is_read) +fil_report_invalid_page_access(const char *name, + os_offset_t offset, ulint len, bool is_read) { - ib::fatal() - << "Trying to " << (is_read ? "read " : "write ") - << id - << " which is outside the bounds of tablespace " << name - << ". Byte offset " << byte_offset << ", len " << len; + ib::fatal() << "Trying to " << (is_read ? "read " : "write ") << len + << " bytes at " << offset + << " outside the bounds of the file: " << name; } -/** Reads or writes data. This operation could be asynchronous (aio). -@param[in,out] type IO context -@param[in] sync true if synchronous aio is desired -@param[in] page_id page id -@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 -@param[in] byte_offset remainder of offset in bytes; in aio this - must be divisible by the OS block size -@param[in] len how many bytes to read or write; this must - not cross a file boundary; in aio this must - be a block size multiple -@param[in,out] buf buffer where to store read data or from where - to write; in aio this must be appropriately - aligned -@param[in] message message for aio handler if non-sync aio - used, else ignored -@param[in] ignore whether to ignore errors -@param[in] punch_hole punch the hole to the file for page_compressed - tablespace -@return status and file descriptor */ -fil_io_t -fil_io( - const IORequest& type, - bool sync, - const page_id_t page_id, - ulint zip_size, - ulint byte_offset, - ulint len, - void* buf, - void* message, - bool ignore, - bool punch_hole) +/** Update the data structures on write completion */ +inline void fil_node_t::complete_write() { - os_offset_t offset; + ut_ad(!mutex_own(&fil_system.mutex)); + ut_ad(space->pending_io()); - ut_ad(type.validate()); + if (space->purpose != FIL_TYPE_TEMPORARY && !space->is_stopping() && + srv_file_flush_method != SRV_O_DIRECT_NO_FSYNC) + { + mutex_enter(&fil_system.mutex); + if (!space->is_stopping()) + { + needs_flush= true; - ut_ad(len > 0); - ut_ad(byte_offset < srv_page_size); - ut_ad(!zip_size || byte_offset == 0); - ut_ad(srv_page_size == 1UL << srv_page_size_shift); - compile_time_assert((1U << UNIV_PAGE_SIZE_SHIFT_MAX) - == UNIV_PAGE_SIZE_MAX); - compile_time_assert((1U << UNIV_PAGE_SIZE_SHIFT_MIN) - == UNIV_PAGE_SIZE_MIN); + if (!space->is_in_unflushed_spaces) + { + space->is_in_unflushed_spaces= true; + fil_system.unflushed_spaces.push_front(*space); + } + } + mutex_exit(&fil_system.mutex); + } +#ifdef UNIV_DEBUG + else + { + mutex_enter(&fil_system.mutex); + if (!space->is_stopping()) + { + ut_ad(!space->is_in_unflushed_spaces); + ut_ad(!needs_flush); + } + mutex_exit(&fil_system.mutex); + } +#endif /* UNIV_DEBUG */ +} + +/** Read or write data. +@param type I/O context +@param offset offset in bytes +@param len number of bytes +@param buf the data to be read or written +@param bpage buffer block (for type.is_async() completion callback) +@return status and file descriptor */ +fil_io_t fil_space_t::io(const IORequest &type, os_offset_t offset, size_t len, + void *buf, buf_page_t *bpage) +{ + ut_ad(pending_io()); + ut_ad(offset % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_ad((len % OS_FILE_LOG_BLOCK_SIZE) == 0); ut_ad(fil_validate_skip()); - /* ibuf bitmap pages must be read in the sync AIO mode: */ - ut_ad(recv_no_ibuf_operations - || type.is_write() - || !ibuf_bitmap_page(page_id, zip_size) - || sync); - - ulint mode; - - if (sync) { - mode = OS_AIO_SYNC; - } else if (type.is_read() - && !recv_no_ibuf_operations - && ibuf_page(page_id, zip_size, NULL)) { - mode = OS_AIO_IBUF; - } else { - mode = OS_AIO_NORMAL; - } - if (type.is_read()) { - srv_stats.data_read.add(len); - - } else if (type.is_write()) { - - ut_ad(!srv_read_only_mode - || fsp_is_system_temporary(page_id.space())); - + } else { + ut_ad(type.is_write() || type.type == IORequest::PUNCH_RANGE); + ut_ad(!srv_read_only_mode || this == fil_system.temp_space); srv_stats.data_written.add(len); } - /* Acquire fil_system.mutex and make sure that we can open at - least one file while holding it, if the file is not already open */ - fil_space_t* space = fil_mutex_enter_and_prepare_for_io( - page_id.space()); - - if (!space - || (type.is_read() - && !sync - && space->is_stopping() - && !space->is_being_truncated)) { - - mutex_exit(&fil_system.mutex); - if (!ignore) { - ib::error() - << "Trying to do I/O to a tablespace which" - " does not exist. I/O type: " - << (type.is_read() ? "read" : "write") - << ", page: " << page_id - << ", I/O length: " << len << " bytes"; - } + fil_node_t* node= UT_LIST_GET_FIRST(chain); + ut_ad(node); + if (type.type == IORequest::READ_ASYNC && is_stopping() + && !is_being_truncated) { + release_for_io(); return {DB_TABLESPACE_DELETED, nullptr}; } - ulint cur_page_no = page_id.page_no(); - fil_node_t* node = UT_LIST_GET_FIRST(space->chain); + ulint p = static_cast(offset >> srv_page_size_shift); - for (;;) { - - if (node == NULL) { - if (ignore) { - mutex_exit(&fil_system.mutex); - return {DB_ERROR, nullptr}; - } - - fil_report_invalid_page_access( - page_id, space->name, byte_offset, len, - type.is_read()); - - } else if (fil_is_user_tablespace_id(space->id) - && node->size == 0) { - - /* We do not know the size of a single-table tablespace - before we open the file */ - break; - - } else if (node->size > cur_page_no) { - /* Found! */ - break; - - } else { - cur_page_no -= node->size; + if (UNIV_LIKELY_NULL(UT_LIST_GET_NEXT(chain, node))) { + ut_ad(this == fil_system.sys_space + || this == fil_system.temp_space); + ut_ad(!(offset & ((1 << srv_page_size_shift) - 1))); + while (node->size <= p) { + p -= node->size; node = UT_LIST_GET_NEXT(chain, node); - } - } - - /* Open file if closed */ - if (UNIV_UNLIKELY(!fil_node_prepare_for_io(node, space))) { - ut_ad(fil_is_user_tablespace_id(space->id)); - mutex_exit(&fil_system.mutex); - - if (!ignore) { - ib::error() - << "Trying to do I/O to a tablespace '" - << space->name - << "' which exists without .ibd data file." - " I/O type: " - << (type.is_read() - ? "read" : "write") - << ", page: " - << page_id - << ", I/O length: " << len << " bytes"; + if (!node) { + if (type.type == IORequest::READ_ASYNC) { + release_for_io(); + return {DB_ERROR, nullptr}; + } + fil_report_invalid_page_access(name, offset, + len, + type.is_read()); + } } - return {DB_TABLESPACE_DELETED, nullptr}; + offset = os_offset_t{p} << srv_page_size_shift; } - if (node->size <= cur_page_no) { - if (ignore) { + if (UNIV_UNLIKELY(node->size <= p)) { + if (type.type == IORequest::READ_ASYNC) { + release_for_io(); /* If we can tolerate the non-existent pages, we should return with DB_ERROR and let caller decide what to do. */ - node->complete_io(type.is_write()); - mutex_exit(&fil_system.mutex); return {DB_ERROR, nullptr}; } fil_report_invalid_page_access( - page_id, space->name, byte_offset, len, - type.is_read()); + node->name, offset, len, type.is_read()); } - space->acquire_for_io(); - /* Now we have made the changes in the data structures of fil_system */ - mutex_exit(&fil_system.mutex); + dberr_t err; - if (!zip_size) zip_size = srv_page_size; - - offset = os_offset_t(cur_page_no) * zip_size + byte_offset; - ut_ad(node->size - cur_page_no >= (len + (zip_size - 1)) / zip_size); - - /* Do AIO */ - - ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0); - ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0); - - const char* name = node->name == NULL ? space->name : node->name; - - ut_ad(!type.is_write() - || !fil_is_user_tablespace_id(page_id.space()) - || offset == page_id.page_no() * zip_size); - - dberr_t err = DB_SUCCESS; - - if (punch_hole) { - /* Punch the hole to the file */ + if (type.type == IORequest::PUNCH_RANGE) { err = os_file_punch_hole(node->handle, offset, len); /* Punch hole is not supported, make space not to support punch hole */ if (UNIV_UNLIKELY(err == DB_IO_NO_PUNCH_HOLE)) { - node->space->punch_hole = false; + punch_hole = false; err = DB_SUCCESS; } + goto release_sync_write; } else { - IORequest req_type(type); - req_type.set_fil_node(node); /* Queue the aio request */ err = os_aio( - req_type, - mode, name, node->handle, buf, offset, len, - space->purpose != FIL_TYPE_TEMPORARY - && srv_read_only_mode, - node, message); + IORequest(type, node), + node->name, node->handle, buf, offset, len, + purpose != FIL_TYPE_TEMPORARY && srv_read_only_mode, + node, bpage); } /* We an try to recover the page from the double write buffer if the decompression fails or the page is corrupt. */ - ut_a(type.is_dblwr_recover() || err == DB_SUCCESS); - if (sync) { - mutex_enter(&fil_system.mutex); - node->complete_io(type.is_write()); - mutex_exit(&fil_system.mutex); + ut_a(type.type == IORequest::DBLWR_RECOVER || err == DB_SUCCESS); + if (!type.is_async()) { + if (type.is_write()) { +release_sync_write: + node->complete_write(); +release: + release_for_io(); + } ut_ad(fil_validate_skip()); } + if (err != DB_SUCCESS) { + goto release; + } return {err, node}; } @@ -3941,8 +3619,6 @@ void fil_aio_callback(os_aio_userdata_t *data) return; } - ut_ad(data->type.validate()); - buf_page_t *bpage= static_cast(data->message); if (!bpage) { @@ -3951,14 +3627,9 @@ void fil_aio_callback(os_aio_userdata_t *data) ut_ad(data->type.is_write()); ut_ad(!srv_read_only_mode); write_completed: - mutex_enter(&fil_system.mutex); - node->complete_io(true); - mutex_exit(&fil_system.mutex); - node->space->release_for_io(); - return; + node->complete_write(); } - - if (data->type.is_write()) + else if (data->type.is_write()) { ut_ad(!srv_read_only_mode || node->space->purpose == FIL_TYPE_TEMPORARY); bool dblwr= node->space->use_doublewrite(); @@ -3970,111 +3641,68 @@ write_completed: buf_page_write_complete(bpage, data->type, dblwr); goto write_completed; } - - ut_ad(data->type.is_read()); - - /* IMPORTANT: since i/o handling for reads will read also the insert - buffer in fil_system.sys_space, we have to be very careful not to - introduce deadlocks. We never close the system tablespace (0) data - files via fil_system.LRU and we use a dedicated I/O thread to serve - change buffer requests. */ - const page_id_t id(bpage->id()); - - if (dberr_t err= buf_page_read_complete(bpage, *node)) + else { - if (recv_recovery_is_on() && !srv_force_recovery) - recv_sys.found_corrupt_fs= true; + ut_ad(data->type.is_read()); - ib::error() << "Failed to read page " << id.page_no() - << " from file '" << node->name << "': " << err; + /* IMPORTANT: since i/o handling for reads will read also the insert + buffer in fil_system.sys_space, we have to be very careful not to + introduce deadlocks. We never close the system tablespace (0) data + files via fil_system.LRU and we never issue asynchronous reads of + change buffer pages. */ + const page_id_t id(bpage->id()); + + if (dberr_t err= buf_page_read_complete(bpage, *node)) + { + if (recv_recovery_is_on() && !srv_force_recovery) + recv_sys.found_corrupt_fs= true; + + ib::error() << "Failed to read page " << id.page_no() + << " from file '" << node->name << "': " << err; + } } - mutex_enter(&fil_system.mutex); - node->complete_io(); - mutex_exit(&fil_system.mutex); node->space->release_for_io(); } -/**********************************************************************//** -Flushes to disk possible writes cached by the OS. If the space does not exist -or is being dropped, does not do anything. */ -void -fil_flush( -/*======*/ - ulint space_id) /*!< in: file space id (this can be a group of - log files or a tablespace of the database) */ +/** Flush pending writes from the file system cache to the file */ +void fil_space_t::flush() { - mutex_enter(&fil_system.mutex); - - if (fil_space_t* space = fil_space_get_by_id(space_id)) { - if (space->purpose != FIL_TYPE_TEMPORARY - && !space->is_stopping()) { - fil_flush_low(space); - } - } - - mutex_exit(&fil_system.mutex); -} - -/** Flush a tablespace. -@param[in,out] space tablespace to flush */ -void -fil_flush(fil_space_t* space) -{ - ut_ad(space->pending_io()); - ut_ad(space->purpose == FIL_TYPE_TABLESPACE - || space->purpose == FIL_TYPE_IMPORT); - - if (!space->is_stopping()) { - mutex_enter(&fil_system.mutex); - if (!space->is_stopping()) { - fil_flush_low(space); - } - mutex_exit(&fil_system.mutex); - } + ut_ad(purpose == FIL_TYPE_TABLESPACE || purpose == FIL_TYPE_IMPORT); + if (!is_stopping()) + { + mutex_enter(&fil_system.mutex); + if (!is_stopping()) + fil_flush_low(this); + mutex_exit(&fil_system.mutex); + } } /** Flush to disk the writes in file spaces of the given type possibly cached by the OS. */ void fil_flush_file_spaces() { - ulint* space_ids; - ulint n_space_ids; - - mutex_enter(&fil_system.mutex); - - n_space_ids = fil_system.unflushed_spaces.size(); - if (n_space_ids == 0) { - - mutex_exit(&fil_system.mutex); + if (srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC) { + ut_d(mutex_enter(&fil_system.mutex)); + ut_ad(fil_system.unflushed_spaces.empty()); + ut_d(mutex_exit(&fil_system.mutex)); return; } - space_ids = static_cast( - ut_malloc_nokey(n_space_ids * sizeof(*space_ids))); - - n_space_ids = 0; +rescan: + mutex_enter(&fil_system.mutex); for (sized_ilist::iterator it = fil_system.unflushed_spaces.begin(), end = fil_system.unflushed_spaces.end(); it != end; ++it) { - - if (it->purpose == FIL_TYPE_TABLESPACE && !it->is_stopping()) { - space_ids[n_space_ids++] = it->id; + if (!it->is_stopping() && fil_flush_low(&*it)) { + mutex_exit(&fil_system.mutex); + goto rescan; } } mutex_exit(&fil_system.mutex); - - /* Flush the spaces. It will not hurt to call fil_flush() on - a non-existing space id. */ - for (ulint i = 0; i < n_space_ids; i++) { - - fil_flush(space_ids[i]); - } - - ut_free(space_ids); } /** Functor to validate the file node list of a tablespace. */ @@ -4091,7 +3719,6 @@ struct Check { @param[in] elem file node to visit */ void operator()(const fil_node_t* elem) { - ut_a(elem->is_open() || !elem->n_pending); n_open += elem->is_open(); size += elem->size; } @@ -4128,7 +3755,6 @@ Checks the consistency of the tablespace cache. @return true if ok */ bool fil_validate() { - fil_node_t* fil_node; ulint n_open = 0; mutex_enter(&fil_system.mutex); @@ -4141,18 +3767,6 @@ bool fil_validate() ut_a(fil_system.n_open == n_open); - ut_list_validate(fil_system.LRU); - - for (fil_node = UT_LIST_GET_FIRST(fil_system.LRU); - fil_node != 0; - fil_node = UT_LIST_GET_NEXT(LRU, fil_node)) { - - ut_a(fil_node->n_pending == 0); - ut_a(!fil_node->being_extended); - ut_a(fil_node->is_open()); - ut_a(fil_space_belongs_in_lru(fil_node->space)); - } - mutex_exit(&fil_system.mutex); return(true); diff --git a/storage/innobase/fsp/fsp0file.cc b/storage/innobase/fsp/fsp0file.cc index e8fc47f3e41..57164113647 100644 --- a/storage/innobase/fsp/fsp0file.cc +++ b/storage/innobase/fsp/fsp0file.cc @@ -296,8 +296,6 @@ Datafile::read_first_page(bool read_only_mode) m_first_page = static_cast( aligned_malloc(UNIV_PAGE_SIZE_MAX, srv_page_size)); - constexpr IORequest request(IORequest::READ | - IORequest::DISABLE_PARTIAL_IO_WARNINGS); dberr_t err = DB_ERROR; size_t page_size = UNIV_PAGE_SIZE_MAX; @@ -308,7 +306,8 @@ Datafile::read_first_page(bool read_only_mode) ulint n_read = 0; err = os_file_read_no_error_handling( - request, m_handle, m_first_page, 0, page_size, &n_read); + IORequestReadPartial, m_handle, m_first_page, 0, + page_size, &n_read); if (err == DB_IO_ERROR && n_read >= UNIV_PAGE_SIZE_MIN) { diff --git a/storage/innobase/fsp/fsp0space.cc b/storage/innobase/fsp/fsp0space.cc index 1ed4af86367..b0a80efe7c4 100644 --- a/storage/innobase/fsp/fsp0space.cc +++ b/storage/innobase/fsp/fsp0space.cc @@ -130,7 +130,7 @@ Tablespace::open_or_create(bool is_temp) fsp_flags = FSP_FLAGS_PAGE_SSIZE(); } - space = fil_space_create( + space = fil_space_t::create( m_name, m_space_id, fsp_flags, is_temp ? FIL_TYPE_TEMPORARY : FIL_TYPE_TABLESPACE, diff --git a/storage/innobase/fsp/fsp0sysspace.cc b/storage/innobase/fsp/fsp0sysspace.cc index f8342157560..a2c9e1bc688 100644 --- a/storage/innobase/fsp/fsp0sysspace.cc +++ b/storage/innobase/fsp/fsp0sysspace.cc @@ -906,13 +906,10 @@ SysTablespace::open_or_create( if (it != begin) { } else if (is_temp) { ut_ad(space_id() == SRV_TMP_SPACE_ID); - space = fil_space_create( + space = fil_space_t::create( name(), SRV_TMP_SPACE_ID, flags(), FIL_TYPE_TEMPORARY, NULL); - - mutex_enter(&fil_system.mutex); - fil_system.temp_space = space; - mutex_exit(&fil_system.mutex); + ut_ad(space == fil_system.temp_space); if (!space) { return DB_ERROR; } @@ -920,12 +917,10 @@ SysTablespace::open_or_create( ut_ad(space->full_crc32()); } else { ut_ad(space_id() == TRX_SYS_SPACE); - space = fil_space_create( + space = fil_space_t::create( name(), TRX_SYS_SPACE, it->flags(), FIL_TYPE_TABLESPACE, NULL); - mutex_enter(&fil_system.mutex); - fil_system.sys_space = space; - mutex_exit(&fil_system.mutex); + ut_ad(space == fil_system.sys_space); if (!space) { return DB_ERROR; } diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index de4195b5727..e7e66bb0e8d 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -7044,6 +7044,7 @@ i_s_tablespaces_encryption_fill_table( } mutex_enter(&fil_system.mutex); + fil_system.freeze_space_list++; for (fil_space_t* space = UT_LIST_GET_FIRST(fil_system.space_list); space; space = UT_LIST_GET_NEXT(space_list, space)) { @@ -7060,6 +7061,7 @@ i_s_tablespaces_encryption_fill_table( } } + fil_system.freeze_space_list--; mutex_exit(&fil_system.mutex); DBUG_RETURN(0); } diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index 494ae2798ee..9e9bc241828 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -2300,7 +2300,7 @@ static void ibuf_read_merge_pages(const uint32_t* space_ids, for (ulint i = 0; i < n_stored; i++) { const ulint space_id = space_ids[i]; - fil_space_t* s = fil_space_acquire_for_io(space_id); + fil_space_t* s = fil_space_t::get_for_io(space_id); if (!s) { tablespace_deleted: /* The tablespace was not found: remove all @@ -4631,26 +4631,14 @@ dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) const unsigned zip_size = space->zip_size(); const unsigned physical_size = space->physical_size(); - /* fil_space_t::size and fil_space_t::free_limit would still be 0 - at this point. So, we will have to read page 0. */ - ut_ad(!space->free_limit); - ut_ad(!space->size); + + uint32_t size= std::min(space->free_limit, space->size); + + if (size == 0) { + return(DB_TABLE_NOT_FOUND); + } mtr_t mtr; - uint32_t size; - mtr.start(); - if (buf_block_t* sp = buf_page_get(page_id_t(space->id, 0), - zip_size, - RW_S_LATCH, &mtr)) { - size = std::min( - mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT - + sp->frame), - mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE - + sp->frame)); - } else { - size = 0; - } - mtr.commit(); mutex_enter(&ibuf_mutex); diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index d2b52c4f520..d8e152f1ffa 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -978,6 +978,15 @@ public: return zip.ssize ? (UNIV_ZIP_SIZE_MIN >> 1) << zip.ssize : 0; } + /** @return the byte offset of the page within a file */ + os_offset_t physical_offset() const + { + os_offset_t o= id().page_no(); + return zip.ssize + ? o << (zip.ssize + (UNIV_ZIP_SIZE_SHIFT_MIN - 1)) + : o << srv_page_size_shift; + } + /** @return whether the block is mapped to a data file */ bool in_file() const { diff --git a/storage/innobase/include/buf0dblwr.h b/storage/innobase/include/buf0dblwr.h index 1b9415d38be..aac4715250d 100644 --- a/storage/innobase/include/buf0dblwr.h +++ b/storage/innobase/include/buf0dblwr.h @@ -52,10 +52,10 @@ class buf_dblwr_t struct element { - /** block descriptor */ - buf_page_t *bpage; - /** true=buf_pool.flush_list, false=buf_pool.LRU */ - bool lru; + /** tablespace */ + fil_space_t *space; + /** asynchronous write request */ + IORequest request; /** payload size in bytes */ size_t size; }; @@ -103,10 +103,11 @@ public: /** Schedule a page write. If the doublewrite memory buffer is full, flush_buffered_writes() will be invoked to make space. - @param bpage buffer pool page to be written - @param lru true=buf_pool.LRU; false=buf_pool.flush_list + @param space tablespace + @param request asynchronous write request @param size payload size in bytes */ - void add_to_batch(buf_page_t *bpage, bool lru, size_t size); + void add_to_batch(fil_space_t *space, const IORequest &request, + size_t size) MY_ATTRIBUTE((nonnull)); /** Determine whether the doublewrite buffer is initialized */ bool is_initialised() const diff --git a/storage/innobase/include/buf0rea.h b/storage/innobase/include/buf0rea.h index e111bbd7a02..87c6b5d7e75 100644 --- a/storage/innobase/include/buf0rea.h +++ b/storage/innobase/include/buf0rea.h @@ -46,11 +46,13 @@ dberr_t buf_read_page(const page_id_t page_id, ulint zip_size); buffer buf_pool if it is not already there. Sets the io_fix flag and sets an exclusive lock on the buffer frame. The flag is cleared and the x-lock released by the i/o-handler thread. +@param[in,out] space tablespace @param[in] page_id page id @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 @param[in] sync true if synchronous aio is desired */ -void -buf_read_page_background(const page_id_t page_id, ulint zip_size, bool sync); +void buf_read_page_background(fil_space_t *space, const page_id_t page_id, + ulint zip_size, bool sync) + MY_ATTRIBUTE((nonnull)); /** Applies a random read-ahead in buf_pool if there are at least a threshold value of accessed pages from the random read-ahead area. Does not read any @@ -101,14 +103,11 @@ ulint buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf); /** Issues read requests for pages which recovery wants to read in. -@param[in] sync true if the caller wants this function to wait -for the highest address page to get read in, before this function returns @param[in] space_id tablespace id @param[in] page_nos array of page numbers to read, with the highest page number the last in the array @param[in] n number of page numbers in the array */ -void buf_read_recv_pages(bool sync, ulint space_id, const uint32_t *page_nos, - ulint n); +void buf_read_recv_pages(ulint space_id, const uint32_t* page_nos, ulint n); /** @name Modes used in read-ahead @{ */ /** read only pages belonging to the insert buffer tree */ diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 0fa0c0b598b..57e5c43199b 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -313,6 +313,25 @@ new_range: /** Tablespace or log data space */ #ifndef UNIV_INNOCHECKSUM +struct fil_io_t +{ + /** error code */ + dberr_t err; + /** file; node->space->release_for_io() must follow IORequestRead call */ + fil_node_t *node; +}; + +/** Tablespace encryption mode */ +enum fil_encryption_t +{ + /** Encrypted if innodb_encrypt_tables=ON (srv_encrypt_tables) */ + FIL_ENCRYPTION_DEFAULT, + /** Encrypted */ + FIL_ENCRYPTION_ON, + /** Not encrypted */ + FIL_ENCRYPTION_OFF +}; + struct fil_space_t : ilist_node, ilist_node #else @@ -348,8 +367,6 @@ struct fil_space_t /*!< recovered tablespace size in pages; 0 if no size change was read from the redo log, or if the size change was implemented */ - /** the committed size of the tablespace in pages */ - Atomic_relaxed committed_size; ulint n_reserved_extents; /*!< number of reserved free extents for ongoing operations like B-tree page split */ @@ -357,28 +374,33 @@ struct fil_space_t the tablespace to disk; dropping of the tablespace is forbidden if this is positive */ private: + /** the committed size of the tablespace in pages */ + Atomic_relaxed committed_size; /** Number of pending buffer pool operations accessing the tablespace without holding a table lock or dict_operation_lock S-latch that would prevent the table (and tablespace) from being dropped. An example is encryption key rotation. - The tablespace cannot be dropped while this is nonzero, or while - fil_node_t::n_pending is nonzero. + The tablespace cannot be dropped while this is nonzero. The most significant bit contains the STOP_NEW_OPS flag. */ - Atomic_relaxed n_pending_ops; + Atomic_relaxed n_pending_ops; + /** Number of pending block read or write operations + The tablespace object cannot be freed while this is nonzero, + but it can be detached from fil_system. + + The most significant bit contains the CLOSING flag. */ + std::atomic n_pending_ios; /** Flag in n_pending_ops that indicates that the tablespace is being deleted, and no further operations should be performed */ static constexpr uint32_t STOP_NEW_OPS= ~(~uint32_t(0) >> 1); + /** Flag in n_pending_ios that indicates that the tablespace is a candidate + for being closed, and fil_node_t::is_open() can only be trusted after + acquiring fil_system.mutex and resetting the flag */ + static constexpr uint32_t CLOSING= STOP_NEW_OPS; + static constexpr uint32_t NOT_CLOSING= ~CLOSING; public: - /** Number of pending block read or write operations - (when a write is imminent or a read has recently completed). - The tablespace object cannot be freed while this is nonzero, - but it can be detached from fil_system. - Note that fil_node_t::n_pending tracks actual pending I/O requests. - Protected by fil_system.mutex and std::atomic. */ - std::atomic n_pending_ios; rw_lock_t latch; /*!< latch protecting the file space storage allocation */ UT_LIST_NODE_T(fil_space_t) named_spaces; @@ -476,19 +498,20 @@ public: dberr_t rename(const char* name, const char* path, bool log, bool replace = false); - /** Note that the tablespace has been imported. - Initially, purpose=FIL_TYPE_IMPORT so that no redo log is - written while the space ID is being updated in each page. */ - inline void set_imported(); + /** Note that the tablespace has been imported. + Initially, purpose=FIL_TYPE_IMPORT so that no redo log is + written while the space ID is being updated in each page. */ + inline void set_imported(); - /** @return whether the storage device is rotational (HDD, not SSD) */ - inline bool is_rotational() const; + /** @return whether the storage device is rotational (HDD, not SSD) */ + inline bool is_rotational() const; - /** Open each file. Only invoked on fil_system.temp_space. - @return whether all files were opened */ - bool open(); - /** Close each file. Only invoked on fil_system.temp_space. */ - void close(); + /** Open each file. Never invoked on .ibd files. + @param create_new_db whether to skip the call to fil_node_t::read_page0() + @return whether all files were opened */ + bool open(bool create_new_db); + /** Close each file. Only invoked on fil_system.temp_space. */ + void close(); /** @return whether the tablespace is about to be dropped */ bool is_stopping() const { return n_pending_ops & STOP_NEW_OPS; } @@ -497,17 +520,13 @@ public: size_t referenced() const { return n_pending_ops & ~STOP_NEW_OPS; } /** Note that operations on the tablespace must stop or can resume */ - void set_stopping(bool stopping) - { - ut_d(auto n=) n_pending_ops.fetch_xor(STOP_NEW_OPS); - ut_ad(!(n & STOP_NEW_OPS) == stopping); - } + inline void set_stopping(bool stopping); MY_ATTRIBUTE((warn_unused_result)) /** @return whether a tablespace reference was successfully acquired */ bool acquire() { - size_t n= 0; + uint32_t n= 0; while (!n_pending_ops.compare_exchange_strong(n, n + 1, std::memory_order_acquire, std::memory_order_relaxed)) @@ -523,31 +542,42 @@ public: ut_ad(n & ~STOP_NEW_OPS); return (n & ~STOP_NEW_OPS) == 1; } - /** Acquire a tablespace reference for I/O. */ - void acquire_for_io() { n_pending_ios++; } - /** Release a tablespace reference for I/O. */ - void release_for_io() { ut_d(auto n=) n_pending_ios--; ut_ad(n); } - /** @return whether I/O is pending */ - bool pending_io() const { return n_pending_ios; } - /** @return whether the tablespace file can be closed and reopened */ - bool belongs_in_lru() const + MY_ATTRIBUTE((warn_unused_result)) + /** Acquire a tablespace reference for I/O. + @return whether the file is usable */ + bool acquire_for_io() { - switch (purpose) { - case FIL_TYPE_TEMPORARY: - ut_ad(id == SRV_TMP_SPACE_ID); - return false; - case FIL_TYPE_IMPORT: - ut_ad(id != SRV_TMP_SPACE_ID); - return true; - case FIL_TYPE_TABLESPACE: - ut_ad(id != SRV_TMP_SPACE_ID); - return id && !srv_is_undo_tablespace(id); - } - ut_ad(0); - return false; + return UNIV_LIKELY(!(n_pending_ios.fetch_add(1, std::memory_order_acquire)& + CLOSING)) || + prepare_for_io(); } + /** Acquire another tablespace reference for I/O. */ + inline void reacquire_for_io(); + + /** Release a tablespace reference for I/O. */ + void release_for_io() + { + ut_d(uint32_t n=) n_pending_ios.fetch_sub(1, std::memory_order_release); + ut_ad(n & NOT_CLOSING); + } + /** @return number of pending reads or writes */ + uint32_t pending_io() const + { return n_pending_ios.load(std::memory_order_acquire) & NOT_CLOSING; } + + MY_ATTRIBUTE((warn_unused_result)) + /** Prepare to close the file handle. + @return number of pending operations */ + uint32_t set_closing() + { + return n_pending_ios.fetch_or(CLOSING, std::memory_order_acquire) & + NOT_CLOSING; + } + /** @return whether close() of the file handle has been requested */ + bool is_closing() const + { return n_pending_ios.load(std::memory_order_acquire) & CLOSING; } + /** @return last_freed_lsn */ lsn_t get_last_freed_lsn() { return last_freed_lsn; } /** Update last_freed_lsn */ @@ -835,6 +865,25 @@ public: } #ifndef UNIV_INNOCHECKSUM + MY_ATTRIBUTE((warn_unused_result)) + /** Create a tablespace in fil_system. + @param name tablespace name + @param id tablespace identifier + @param flags tablespace flags + @param purpose tablespace purpose + @param crypt_data encryption information + @param mode encryption mode + @return pointer to created tablespace, to be filled in with add() + @retval nullptr on failure (such as when the same tablespace exists) */ + static fil_space_t *create(const char *name, ulint id, ulint flags, + fil_type_t purpose, fil_space_crypt_t *crypt_data, + fil_encryption_t mode= FIL_ENCRYPTION_DEFAULT); + + /** Acquire a tablespace for reading or writing a block. + @param id tablespace ID + @return the tablespace, or nullptr if missing or inaccessible */ + static fil_space_t *get_for_io(ulint id); + /** Add/remove the free page in the freed ranges list. @param[in] offset page number to be added @param[in] free true if page to be freed */ @@ -863,8 +912,47 @@ public: std::lock_guard freed_lock(freed_range_mutex); freed_ranges.add_range(range); } -#endif /*!UNIV_INNOCHECKSUM */ + /** Set the tablespace size in pages */ + void set_sizes(uint32_t s) + { + ut_ad(id ? !size : (size >= s)); + size= s; committed_size= s; + } + + /** Update committed_size in mtr_t::commit() */ + void set_committed_size() + { + ut_ad(rw_lock_own(&latch, RW_LOCK_X)); + committed_size= size; + } + + /** @return the last persisted page number */ + uint32_t last_page_number() const { return committed_size - 1; } + + /** @return the size in pages (0 if unreadable) */ + inline uint32_t get_size(); + + /** Read or write data. + @param type I/O context + @param offset offset in bytes + @param len number of bytes + @param buf the data to be read or written + @param bpage buffer block (for type.is_async() completion callback) + @return status and file descriptor */ + fil_io_t io(const IORequest &type, os_offset_t offset, size_t len, + void *buf, buf_page_t *bpage= nullptr); + /** Flush pending writes from the file system cache to the file */ + void flush(); + + /** Read the first page of a data file. + @return whether the page was found valid */ + bool read_page0(); + +private: + /** @return whether the file is usable for io() */ + ATTRIBUTE_COLD bool prepare_for_io(); +#endif /*!UNIV_INNOCHECKSUM */ }; #ifndef UNIV_INNOCHECKSUM @@ -892,8 +980,6 @@ struct fil_node_t { uint32_t init_size; /** maximum size of the file in database pages (0 if unlimited) */ uint32_t max_size; - /** count of pending i/o's; is_open must be true if nonzero */ - ulint n_pending; /** count of pending flushes; is_open must be true if nonzero */ ulint n_pending_flushes; /** whether the file is currently being extended */ @@ -902,8 +988,6 @@ struct fil_node_t { bool needs_flush; /** link to other files in this tablespace */ UT_LIST_NODE_T(fil_node_t) chain; - /** link to the fil_system.LRU list (keeping track of open files) */ - UT_LIST_NODE_T(fil_node_t) LRU; /** whether this file could use atomic write (data file) */ bool atomic_write; @@ -921,9 +1005,8 @@ struct fil_node_t { } /** Read the first page of a data file. - @param[in] first whether this is the very first read @return whether the page was found valid */ - bool read_page0(bool first); + bool read_page0(); /** Determine some file metadata when creating or reading the file. @param file the file that is being created, or OS_FILE_CLOSED */ @@ -942,8 +1025,8 @@ struct fil_node_t { @return detached handle or OS_FILE_CLOSED */ pfs_os_file_t close_to_free(bool detach_handle= false); - /** Update the data structures on I/O completion */ - inline void complete_io(bool write= false); + /** Update the data structures on write completion */ + inline void complete_write(); private: /** Does stuff common for close() and detach() */ @@ -953,22 +1036,27 @@ private: /** Value of fil_node_t::magic_n */ #define FIL_NODE_MAGIC_N 89389 +inline void fil_space_t::reacquire_for_io() +{ + ut_d(uint32_t n=) n_pending_ios.fetch_add(1, std::memory_order_relaxed); + ut_ad(n & NOT_CLOSING); + ut_ad(UT_LIST_GET_FIRST(chain)->is_open()); +} + inline void fil_space_t::set_imported() { - ut_ad(purpose == FIL_TYPE_IMPORT); - purpose = FIL_TYPE_TABLESPACE; - UT_LIST_GET_FIRST(chain)->find_metadata(); + ut_ad(purpose == FIL_TYPE_IMPORT); + purpose= FIL_TYPE_TABLESPACE; + UT_LIST_GET_FIRST(chain)->find_metadata(); } inline bool fil_space_t::is_rotational() const { - for (const fil_node_t* node = UT_LIST_GET_FIRST(chain); node; - node = UT_LIST_GET_NEXT(chain, node)) { - if (!node->on_ssd) { - return true; - } - } - return false; + for (const fil_node_t *node= UT_LIST_GET_FIRST(chain); node; + node= UT_LIST_GET_NEXT(chain, node)) + if (!node->on_ssd) + return true; + return false; } /** Common InnoDB file extensions */ @@ -1179,16 +1267,6 @@ index */ #define fil_page_index_page_check(page) \ fil_page_type_is_index(fil_page_get_type(page)) -/** Enum values for encryption table option */ -enum fil_encryption_t { - /** Encrypted if innodb_encrypt_tables=ON (srv_encrypt_tables) */ - FIL_ENCRYPTION_DEFAULT, - /** Encrypted */ - FIL_ENCRYPTION_ON, - /** Not encrypted */ - FIL_ENCRYPTION_OFF -}; - /** Get the file page type. @param[in] page file page @return page type */ @@ -1227,7 +1305,6 @@ struct fil_system_t { */ fil_system_t(): m_initialised(false) { - UT_LIST_INIT(LRU, &fil_node_t::LRU); UT_LIST_INIT(space_list, &fil_space_t::space_list); UT_LIST_INIT(named_spaces, &fil_space_t::named_spaces); } @@ -1275,30 +1352,23 @@ public: fil_space_t* temp_space; /*!< The innodb_temporary tablespace */ /** Map of fil_space_t::id to fil_space_t* */ hash_table_t spaces; - UT_LIST_BASE_NODE_T(fil_node_t) LRU; - /*!< base node for the LRU list of the - most recently used open files with no - pending i/o's; if we start an i/o on - the file, we first remove it from this - list, and return it to the start of - the list when the i/o ends; - log files and the system tablespace are - not put to this list: they are opened - after the startup, and kept open until - shutdown */ sized_ilist unflushed_spaces; /*!< list of those tablespaces whose files contain unflushed writes; those spaces have at least one file node where needs_flush == true */ - ulint n_open; /*!< number of files currently open */ + /** number of currently open files; protected by mutex */ + ulint n_open; ulint max_assigned_id;/*!< maximum space id in the existing tables, or assigned during the time mysqld has been up; at an InnoDB startup we scan the data dictionary and set here the maximum of the space id's of the tables there */ + /** nonzero if fil_node_open_file_low() should avoid moving the tablespace + to the end of space_list, for FIFO policy of try_to_close() */ + ulint freeze_space_list; UT_LIST_BASE_NODE_T(fil_space_t) space_list; /*!< list of all file spaces */ UT_LIST_BASE_NODE_T(fil_space_t) named_spaces; @@ -1312,16 +1382,10 @@ public: key rotation.*/ bool space_id_reuse_warned; - /*!< whether fil_space_create() + /*!< whether fil_space_t::create() has issued a warning about potential space_id reuse */ - /** Trigger a call to fil_node_t::read_page0() - @param[in] id tablespace identifier - @return tablespace - @retval NULL if the tablespace does not exist or cannot be read */ - fil_space_t* read_page0(ulint id); - /** Return the next tablespace from rotation_list. @param space previous tablespace (NULL to start from the start) @param recheck whether the removal condition needs to be rechecked after @@ -1336,63 +1400,28 @@ public: /** The tablespace memory cache. */ extern fil_system_t fil_system; -/** Update the data structures on I/O completion */ -inline void fil_node_t::complete_io(bool write) +/** Note that operations on the tablespace must stop or can resume */ +inline void fil_space_t::set_stopping(bool stopping) { ut_ad(mutex_own(&fil_system.mutex)); + ut_d(auto n=) n_pending_ops.fetch_xor(STOP_NEW_OPS); + ut_ad(!(n & STOP_NEW_OPS) == stopping); +} - if (write) +/** @return the size in pages (0 if unreadable) */ +inline uint32_t fil_space_t::get_size() +{ + if (!size) { - if (srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC) - { - /* We don't need to keep track of unflushed changes as user has - explicitly disabled buffering. */ - ut_ad(!space->is_in_unflushed_spaces); - ut_ad(!needs_flush); - } - else if (!space->is_stopping()) - { - needs_flush= true; - if (!space->is_in_unflushed_spaces) - { - space->is_in_unflushed_spaces= true; - fil_system.unflushed_spaces.push_front(*space); - } - } - } - - switch (n_pending--) { - case 0: - ut_error; - case 1: - if (space->belongs_in_lru()) - /* The node must be put back to the LRU list */ - UT_LIST_ADD_FIRST(fil_system.LRU, this); + mutex_enter(&fil_system.mutex); + read_page0(); + mutex_exit(&fil_system.mutex); } + return size; } #include "fil0crypt.h" -/** Create a space memory object and put it to the fil_system hash table. -Error messages are issued to the server log. -@param[in] name tablespace name -@param[in] id tablespace identifier -@param[in] flags tablespace flags -@param[in] purpose tablespace purpose -@param[in,out] crypt_data encryption information -@param[in] mode encryption mode -@return pointer to created tablespace, to be filled in with fil_space_t::add() -@retval NULL on failure (such as when the same tablespace exists) */ -fil_space_t* -fil_space_create( - const char* name, - ulint id, - ulint flags, - fil_type_t purpose, - fil_space_crypt_t* crypt_data, - fil_encryption_t mode = FIL_ENCRYPTION_DEFAULT) - MY_ATTRIBUTE((warn_unused_result)); - /*******************************************************************//** Assigns a new space id for a new single-table tablespace. This works simply by incrementing the global counter. If 4 billion id's is not enough, we may need @@ -1421,21 +1450,6 @@ fil_space_free( void fil_space_set_recv_size_and_flags(ulint id, uint32_t size, uint32_t flags); -/*******************************************************************//** -Returns the size of the space in pages. The tablespace must be cached in the -memory cache. -@return space size, 0 if space not found */ -ulint -fil_space_get_size( -/*===============*/ - ulint id); /*!< in: space id */ - -/** Opens all system tablespace data files. They stay open until the -database server shutdown. This should be called at a server startup after the -space objects for the system tablespace have been created. The -purpose of this operation is to make sure we never run out of file descriptors -if we need to read from the insert buffer. */ -void fil_open_system_tablespace_files(); /** Close all tablespace files at shutdown */ void fil_close_all_files(); /*******************************************************************//** @@ -1491,14 +1505,6 @@ fil_space_acquire_silent(ulint id) return (fil_space_acquire_low(id, true)); } -/** Acquire a tablespace for reading or writing a block, -when it could be dropped concurrently. -@param[in] id tablespace ID -@return the tablespace -@retval NULL if missing */ -fil_space_t* -fil_space_acquire_for_io(ulint id); - /** Replay a file rename operation if possible. @param[in] space_id tablespace identifier @param[in] name old file name @@ -1674,7 +1680,7 @@ fil_file_readdir_next_file( memory cache. Note that if we have not done a crash recovery at the database startup, there may be many tablespaces which are not yet in the memory cache. @param[in] id Tablespace ID -@param[in] name Tablespace name used in fil_space_create(). +@param[in] name Tablespace name used in fil_space_t::create(). @param[in] table_flags table flags @return the tablespace @retval NULL if no matching tablespace exists in the memory cache */ @@ -1690,70 +1696,6 @@ fil_space_for_table_exists_in_mem( @return whether the tablespace is at least as big as requested */ bool fil_space_extend(fil_space_t *space, uint32_t size); -struct fil_io_t -{ - /** error code */ - dberr_t err; - /** file; node->space->release_for_io() must follow fil_io(sync=true) call */ - fil_node_t *node; -}; - -/** Reads or writes data. This operation could be asynchronous (aio). - -@param[in] type IO context -@param[in] sync true if synchronous aio is desired -@param[in] page_id page id -@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 -@param[in] byte_offset remainder of offset in bytes; in aio this - must be divisible by the OS block size -@param[in] len how many bytes to read or write; this must - not cross a file boundary; in aio this must - be a block size multiple -@param[in,out] buf buffer where to store read data or from where - to write; in aio this must be appropriately - aligned -@param[in] message message for aio handler if non-sync aio - used, else ignored -@param[in] ignore whether to ignore errors -@param[in] punch_hole punch the hole to the file for page_compressed - tablespace -@return status and file descriptor */ -fil_io_t -fil_io( - const IORequest& type, - bool sync, - const page_id_t page_id, - ulint zip_size, - ulint byte_offset, - ulint len, - void* buf, - void* message, - bool ignore = false, - bool punch_hole = false); - -/**********************************************************************//** -Waits for an aio operation to complete. This function is used to write the -handler for completed requests. The aio array of pending requests is divided -into segments (see os0file.cc for more info). The thread specifies which -segment it wants to wait for. */ -void -fil_aio_wait( -/*=========*/ - ulint segment); /*!< in: the number of the segment in the aio - array to wait for */ -/**********************************************************************//** -Flushes to disk possible writes cached by the OS. If the space does not exist -or is being dropped, does not do anything. */ -void -fil_flush( -/*======*/ - ulint space_id); /*!< in: file space id (this can be a group of - log files or a tablespace of the database) */ -/** Flush a tablespace. -@param[in,out] space tablespace to flush */ -void -fil_flush(fil_space_t* space); - /** Flush to disk the writes in file spaces of the given type possibly cached by the OS. */ void fil_flush_file_spaces(); @@ -1846,23 +1788,6 @@ inline bool fil_names_write_if_was_clean(fil_space_t* space) return(was_clean); } -/** During crash recovery, open a tablespace if it had not been opened -yet, to get valid size and flags. -@param[in,out] space tablespace */ -inline void fil_space_open_if_needed(fil_space_t* space) -{ - ut_ad(recv_recovery_is_on()); - - if (space->size == 0) { - /* Initially, size and flags will be set to 0, - until the files are opened for the first time. - fil_space_get_size() will open the file - and adjust the size and flags. */ - ut_d(ulint size =) fil_space_get_size(space->id); - ut_ad(size == space->size); - } -} - /** On a log checkpoint, reset fil_names_dirty_and_write() flags and write out FILE_MODIFY and FILE_CHECKPOINT if needed. @param[in] lsn checkpoint LSN diff --git a/storage/innobase/include/fsp0types.h b/storage/innobase/include/fsp0types.h index 5057ed98aba..f8e4c06baae 100644 --- a/storage/innobase/include/fsp0types.h +++ b/storage/innobase/include/fsp0types.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2014, 2019, MariaDB Corporation. +Copyright (c) 2014, 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 @@ -24,9 +24,7 @@ File space management types Created May 26, 2009 Vasil Dimov *******************************************************/ -#ifndef fsp0types_h -#define fsp0types_h - +#pragma once #include /** The fil_space_t::id of the redo log. All persistent tablespaces @@ -402,4 +400,6 @@ in full crc32 format. */ /* @} */ -#endif /* fsp0types_h */ +struct fil_node_t; +struct fil_space_t; +class buf_page_t; diff --git a/storage/innobase/include/os0api.h b/storage/innobase/include/os0api.h deleted file mode 100644 index bd9dc5b73a1..00000000000 --- a/storage/innobase/include/os0api.h +++ /dev/null @@ -1,48 +0,0 @@ -/*********************************************************************** - -Copyright (c) 2017, 2019, MariaDB Corporation. - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software 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 - -***********************************************************************/ - -/**************************************************//** -@file os0api.h -The interface to the helper functions. -These functions are used on os0file.h where -including full full header is not feasible and -implemented on buf0buf.cc and fil0fil.cc. -*******************************************************/ - -#ifndef OS_API_H -#define OS_API_H 1 - -/** Page control block */ -class buf_page_t; - -/** File Node */ -struct fil_node_t; - -/** -Calculate the length of trim (punch_hole) operation. -@param[in] bpage Page control block -@param[in] write_length Write length -@return length of the trim or zero. */ -ulint -buf_page_get_trim_length( - const buf_page_t* bpage, - ulint write_length) - MY_ATTRIBUTE((warn_unused_result)); - -#endif /* OS_API_H */ diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index def091c9771..0db22abfb19 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -37,7 +37,6 @@ Created 10/21/1995 Heikki Tuuri #define os0file_h #include "fsp0types.h" -#include "os0api.h" #include "tpool.h" #ifndef _WIN32 @@ -46,10 +45,6 @@ Created 10/21/1995 Heikki Tuuri #include #endif /* !_WIN32 */ -/** File node of a tablespace or the log data space */ -struct fil_node_t; -struct fil_space_t; - extern bool os_has_said_disk_full; /** File offset in bytes */ @@ -188,117 +183,75 @@ The I/O context that is passed down to the low level IO code */ class IORequest { public: - constexpr IORequest(ulint type= READ, buf_page_t *bpage= nullptr, - bool lru= false) : - m_bpage(bpage), m_type(static_cast(type)), m_LRU(lru) {} + enum Type + { + /** Synchronous read */ + READ_SYNC= 2, + /** Asynchronous read; some errors will be ignored */ + READ_ASYNC= READ_SYNC | 1, + /** Possibly partial read; only used with + os_file_read_no_error_handling() */ + READ_MAYBE_PARTIAL= READ_SYNC | 4, + /** Read for doublewrite buffer recovery */ + DBLWR_RECOVER= READ_SYNC | 8, + /** Synchronous write */ + WRITE_SYNC= 16, + /** Asynchronous write */ + WRITE_ASYNC= WRITE_SYNC | 1, + /** Write data; evict the block on write completion */ + WRITE_LRU= WRITE_ASYNC | 32, + /** Write data and punch hole for the rest */ + PUNCH= WRITE_ASYNC | 64, + /** Write data and punch hole; evict the block on write completion */ + PUNCH_LRU= PUNCH | WRITE_LRU, + /** Zero out a range of bytes in fil_space_t::io() */ + PUNCH_RANGE= WRITE_SYNC | 128, + }; - /** Flags passed in the request, they can be ORred together. */ - enum { - READ = 1, - WRITE = 2, + constexpr IORequest(Type type= READ_SYNC, buf_page_t *bpage= nullptr) : + bpage(bpage), type(type) {} - /** Double write buffer recovery. */ - DBLWR_RECOVER = 4, + constexpr IORequest(const IORequest &old, fil_node_t *node= nullptr) : + bpage(old.bpage), node(node), type(old.type) {} - /** Enumarations below can be ORed to READ/WRITE above*/ + bool is_read() const { return (type & READ_SYNC) != 0; } + bool is_write() const { return (type & WRITE_SYNC) != 0; } + bool is_LRU() const { return (type & (WRITE_LRU ^ WRITE_ASYNC)) != 0; } + bool is_async() const { return (type & (READ_SYNC ^ READ_ASYNC)) != 0; } - /** Data file */ - DATA_FILE = 8, - - /** Disable partial read warnings */ - DISABLE_PARTIAL_IO_WARNINGS = 32, - - /** Use punch hole if available*/ - PUNCH_HOLE = 64, - }; - - /** @return true if it is a read request */ - bool is_read() const - MY_ATTRIBUTE((warn_unused_result)) - { - return((m_type & READ) == READ); - } - - /** @return true if it is a write request */ - bool is_write() const - MY_ATTRIBUTE((warn_unused_result)) - { - return((m_type & WRITE) == WRITE); - } - - /** @return true if partial read warning disabled */ - bool is_partial_io_warning_disabled() const - MY_ATTRIBUTE((warn_unused_result)) - { - return !!(m_type & DISABLE_PARTIAL_IO_WARNINGS); - } - - /** @return true if punch hole should be used */ - bool punch_hole() const - MY_ATTRIBUTE((warn_unused_result)) - { - return((m_type & PUNCH_HOLE) == PUNCH_HOLE); - } - - /** @return true if the read should be validated */ - bool validate() const - MY_ATTRIBUTE((warn_unused_result)) - { - return(is_read() ^ is_write()); - } - - /** Set the pointer to file node for IO - @param[in] node File node */ - void set_fil_node(fil_node_t *node) { m_fil_node= node; } - - bool operator==(const IORequest& rhs) const - { - return(m_type == rhs.m_type); - } - - /** @return true if the request is from the dblwr recovery */ - bool is_dblwr_recover() const - MY_ATTRIBUTE((warn_unused_result)) - { - return((m_type & DBLWR_RECOVER) == DBLWR_RECOVER); - } - - ulint get_trim_length(ulint write_length) const - { - return (m_bpage ? - buf_page_get_trim_length(m_bpage, write_length) - : 0); - } - - inline bool should_punch_hole() const; - - /** Free storage space associated with a section of the file. - @param[in] fh Open file handle - @param[in] off Starting offset (SEEK_SET) - @param[in] len Size of the hole - @return DB_SUCCESS or error code */ - dberr_t punch_hole(os_file_t fh, os_offset_t off, ulint len); - - /** @return type of page flush (for writes) */ - bool is_LRU() const { return m_LRU; } + /** If requested, free storage space associated with a section of the file. + @param off byte offset from the start (SEEK_SET) + @param len size of the hole in bytes + @return DB_SUCCESS or error code */ + dberr_t maybe_punch_hole(os_offset_t off, ulint len) + { + return off && len && node && (type & (PUNCH ^ WRITE_ASYNC)) + ? punch_hole(off, len) + : DB_SUCCESS; + } private: - /** Page to be written on write operation. */ - buf_page_t* const m_bpage= nullptr; + /** Free storage space associated with a section of the file. + @param off byte offset from the start (SEEK_SET) + @param len size of the hole in bytes + @return DB_SUCCESS or error code */ + dberr_t punch_hole(os_offset_t off, ulint len) const + MY_ATTRIBUTE((nonnull)); - /** File node */ - fil_node_t* m_fil_node= nullptr; +public: + /** Page to be written on write operation */ + buf_page_t* const bpage= nullptr; + + /** File descriptor */ + const fil_node_t *const node= nullptr; /** Request type bit flags */ - const uint16_t m_type; - - /** for writes, type of page flush */ - const bool m_LRU= false; + const Type type; }; -constexpr IORequest IORequestRead(IORequest::READ); -constexpr IORequest IORequestWrite(IORequest::WRITE); - +constexpr IORequest IORequestRead(IORequest::READ_SYNC); +constexpr IORequest IORequestReadPartial(IORequest::READ_MAYBE_PARTIAL); +constexpr IORequest IORequestWrite(IORequest::WRITE_SYNC); /** Sparse file size information. */ struct os_file_size_t { @@ -313,20 +266,6 @@ struct os_file_size_t { /** Win NT does not allow more than 64 */ static const ulint OS_AIO_N_PENDING_IOS_PER_THREAD = 256; -/** Modes for aio operations @{ */ -/** Normal asynchronous i/o not for ibuf pages or ibuf bitmap pages */ -static const ulint OS_AIO_NORMAL = 21; - -/** Asynchronous i/o for ibuf pages or ibuf bitmap pages */ -static const ulint OS_AIO_IBUF = 22; - -/**Calling thread will wait for the i/o to complete, -and perform IO completion routine itself; -can be used for any pages, ibuf or non-ibuf. This is used to save -CPU time, as we can do with fewer thread switches. */ -static const ulint OS_AIO_SYNC = 24; -/* @} */ - extern ulint os_n_file_reads; extern ulint os_n_file_writes; extern ulint os_n_fsyncs; @@ -669,9 +608,9 @@ The wrapper functions have the prefix of "innodb_". */ # define os_file_close(file) \ pfs_os_file_close_func(file, __FILE__, __LINE__) -# define os_aio(type, mode, name, file, buf, offset, \ +# define os_aio(type, name, file, buf, offset, \ n, read_only, message1, message2) \ - pfs_os_aio_func(type, mode, name, file, buf, offset, \ + pfs_os_aio_func(type, name, file, buf, offset, \ n, read_only, message1, message2, \ __FILE__, __LINE__) @@ -859,7 +798,6 @@ function! Performance schema wrapper function of os_aio() which requests an asynchronous I/O operation. @param[in,out] type IO request context -@param[in] mode IO mode @param[in] name Name of the file or path as NUL terminated string @param[in] file Open file handle @@ -879,8 +817,7 @@ an asynchronous I/O operation. UNIV_INLINE dberr_t pfs_os_aio_func( - IORequest& type, - ulint mode, + const IORequest&type, const char* name, pfs_os_file_t file, void* buf, @@ -1013,9 +950,9 @@ to original un-instrumented file I/O APIs */ # define os_file_close(file) os_file_close_func(file) -# define os_aio(type, mode, name, file, buf, offset, \ +# define os_aio(type, name, file, buf, offset, \ n, read_only, message1, message2) \ - os_aio_func(type, mode, name, file, buf, offset, \ + os_aio_func(type, name, file, buf, offset, \ n, read_only, message1, message2) # define os_file_read(type, file, buf, offset, n) \ @@ -1281,7 +1218,6 @@ struct os_aio_userdata_t NOTE! Use the corresponding macro os_aio(), not directly this function! Requests an asynchronous i/o operation. @param[in,out] type IO request context -@param[in] mode IO mode @param[in] name Name of the file or path as NUL terminated string @param[in] file Open file handle @@ -1298,8 +1234,7 @@ Requests an asynchronous i/o operation. @return DB_SUCCESS or error code */ dberr_t os_aio_func( - IORequest& type, - ulint mode, + const IORequest&type, const char* name, pfs_os_file_t file, void* buf, diff --git a/storage/innobase/include/os0file.ic b/storage/innobase/include/os0file.ic index f950113f3c7..1382b79bc12 100644 --- a/storage/innobase/include/os0file.ic +++ b/storage/innobase/include/os0file.ic @@ -206,7 +206,6 @@ function! Performance schema wrapper function of os_aio() which requests an asynchronous i/o operation. @param[in,type] type IO request context -@param[in] mode IO mode @param[in] name Name of the file or path as NUL terminated string @param[in] file Open file handle @@ -226,8 +225,7 @@ an asynchronous i/o operation. UNIV_INLINE dberr_t pfs_os_aio_func( - IORequest& type, - ulint mode, + const IORequest&type, const char* name, pfs_os_file_t file, void* buf, @@ -242,8 +240,6 @@ pfs_os_aio_func( PSI_file_locker_state state; struct PSI_file_locker* locker = NULL; - ut_ad(type.validate()); - /* Register the read or write I/O depending on "type" */ register_pfs_file_io_begin( &state, locker, file, n, @@ -251,7 +247,7 @@ pfs_os_aio_func( src_file, src_line); dberr_t result = os_aio_func( - type, mode, name, file, buf, offset, n, read_only, m1, m2); + type, name, file, buf, offset, n, read_only, m1, m2); register_pfs_file_io_end(locker, n); @@ -284,8 +280,6 @@ pfs_os_file_read_func( PSI_file_locker_state state; struct PSI_file_locker* locker = NULL; - ut_ad(type.validate()); - register_pfs_file_io_begin( &state, locker, file, n, PSI_FILE_READ, src_file, src_line); diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index 0bc8b95dd77..9fe6fcfa262 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -46,10 +46,9 @@ Created 3/26/1996 Heikki Tuuri /** Checks if a page address is the trx sys header page. @param[in] page_id page id @return true if trx sys header page */ -inline bool trx_sys_hdr_page(const page_id_t& page_id) +inline bool trx_sys_hdr_page(const page_id_t page_id) { - return(page_id.space() == TRX_SYS_SPACE - && page_id.page_no() == TRX_SYS_PAGE_NO); + return page_id == page_id_t(TRX_SYS_SPACE, TRX_SYS_PAGE_NO); } /*****************************************************************//** diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index e3ac675cd56..1fe5c70bcf7 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -2060,7 +2060,14 @@ same_page: const bool is_init= (b & 0x70) <= INIT_PAGE; switch (*store) { case STORE_IF_EXISTS: - if (!fil_space_get_size(space_id)) + if (fil_space_t *space= fil_space_acquire_silent(space_id)) + { + const auto size= space->get_size(); + space->release(); + if (!size) + continue; + } + else continue; /* fall through */ case STORE_YES: @@ -2487,7 +2494,7 @@ static void recv_read_in_area(page_id_t page_id) if (p != page_nos) { mutex_exit(&recv_sys.mutex); - buf_read_recv_pages(FALSE, page_id.space(), page_nos, + buf_read_recv_pages(page_id.space(), page_nos, ulint(p - page_nos)); mutex_enter(&recv_sys.mutex); } @@ -2513,7 +2520,7 @@ inline buf_block_t *recv_sys_t::recover_low(const page_id_t page_id, if (end_lsn < i.lsn) DBUG_LOG("ib_log", "skip log for page " << page_id << " LSN " << end_lsn << " < " << i.lsn); - else if (fil_space_t *space= fil_space_acquire_for_io(page_id.space())) + else if (fil_space_t *space= fil_space_t::get_for_io(page_id.space())) { mtr.start(); mtr.set_log_mode(MTR_LOG_NO_REDO); diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index a3a2b8f4f45..e04a2af92c8 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -214,7 +214,7 @@ static void memo_slot_release(mtr_memo_slot_t *slot) case MTR_MEMO_SPACE_X_LOCK: { fil_space_t *space= static_cast(slot->object); - space->committed_size= space->size; + space->set_committed_size(); rw_lock_x_unlock(&space->latch); } break; @@ -256,7 +256,7 @@ struct ReleaseLatches { case MTR_MEMO_SPACE_X_LOCK: { fil_space_t *space= static_cast(slot->object); - space->committed_size= space->size; + space->set_committed_size(); rw_lock_x_unlock(&space->latch); } break; diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index bfe18fd2519..cdf61f12ce4 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -135,7 +135,6 @@ public: static io_slots *read_slots; static io_slots *write_slots; -static io_slots *ibuf_slots; /** Number of retries for partial I/O's */ constexpr ulint NUM_RETRIES_ON_PARTIAL_IO = 10; @@ -3143,14 +3142,7 @@ os_file_io( bytes_returned += n_bytes; - if (offset > 0 - && type.is_write() - && type.punch_hole()) { - *err = type.punch_hole(file, offset, n); - - } else { - *err = DB_SUCCESS; - } + *err = type.maybe_punch_hole(offset, n); return(original_n); } @@ -3161,8 +3153,7 @@ os_file_io( bytes_returned += n_bytes; - if (!type.is_partial_io_warning_disabled()) { - + if (type.type != IORequest::READ_MAYBE_PARTIAL) { const char* op = type.is_read() ? "read" : "written"; @@ -3180,7 +3171,7 @@ os_file_io( *err = DB_IO_ERROR; - if (!type.is_partial_io_warning_disabled()) { + if (type.type != IORequest::READ_MAYBE_PARTIAL) { ib::warn() << "Retry attempts for " << (type.is_read() ? "reading" : "writing") @@ -3208,7 +3199,6 @@ os_file_pwrite( os_offset_t offset, dberr_t* err) { - ut_ad(type.validate()); ut_ad(type.is_write()); ++os_n_file_writes; @@ -3242,7 +3232,6 @@ os_file_write_func( { dberr_t err; - ut_ad(type.validate()); ut_ad(n > 0); WAIT_ALLOW_WRITES(); @@ -3332,7 +3321,6 @@ os_file_read_page( os_bytes_read_since_printout += n; - ut_ad(type.validate()); ut_ad(n > 0); ssize_t n_bytes = os_file_pread(type, file, buf, n, offset, &err); @@ -3657,13 +3645,9 @@ fallback: n_bytes = buf_size; } - dberr_t err; - IORequest request(IORequest::WRITE); - - err = os_file_write( - request, name, file, buf, current_size, n_bytes); - - if (err != DB_SUCCESS) { + if (os_file_write(IORequestWrite, name, + file, buf, current_size, n_bytes) != + DB_SUCCESS) { break; } @@ -3786,18 +3770,11 @@ os_file_punch_hole( #endif /* _WIN32 */ } -inline bool IORequest::should_punch_hole() const -{ - return m_fil_node && m_fil_node->space->punch_hole; -} - /** Free storage space associated with a section of the file. -@param[in] fh Open file handle -@param[in] off Starting offset (SEEK_SET) -@param[in] len Size of the hole +@param off byte offset from the start (SEEK_SET) +@param len size of the hole in bytes @return DB_SUCCESS or error code */ -dberr_t -IORequest::punch_hole(os_file_t fh, os_offset_t off, ulint len) +dberr_t IORequest::punch_hole(os_offset_t off, ulint len) const { /* In this debugging mode, we act as if punch hole is supported, and then skip any calls to actually punch a hole here. @@ -3806,7 +3783,7 @@ IORequest::punch_hole(os_file_t fh, os_offset_t off, ulint len) return(DB_SUCCESS); ); - ulint trim_len = get_trim_length(len); + ulint trim_len = bpage ? bpage->physical_size() - len : 0; if (trim_len == 0) { return(DB_SUCCESS); @@ -3816,11 +3793,11 @@ IORequest::punch_hole(os_file_t fh, os_offset_t off, ulint len) /* Check does file system support punching holes for this tablespace. */ - if (!should_punch_hole()) { + if (!node->space->punch_hole) { return DB_IO_NO_PUNCH_HOLE; } - dberr_t err = os_file_punch_hole(fh, off, trim_len); + dberr_t err = os_file_punch_hole(node->handle, off, trim_len); if (err == DB_SUCCESS) { srv_stats.page_compressed_trim_op.inc(); @@ -3828,7 +3805,7 @@ IORequest::punch_hole(os_file_t fh, os_offset_t off, ulint len) /* If punch hole is not supported, set space so that it is not used. */ if (err == DB_IO_NO_PUNCH_HOLE) { - m_fil_node->space->punch_hole = false; + node->space->punch_hole = false; err = DB_SUCCESS; } } @@ -3885,12 +3862,8 @@ static void io_callback(tpool::aiocb* cb) os_aio_userdata_t data(cb->m_userdata); /* Return cb back to cache*/ if (cb->m_opcode == tpool::aio_opcode::AIO_PREAD) { - if (read_slots->contains(cb)) { - read_slots->release(cb); - } else { - ut_ad(ibuf_slots->contains(cb)); - ibuf_slots->release(cb); - } + ut_ad(read_slots->contains(cb)); + read_slots->release(cb); } else { ut_ad(write_slots->contains(cb)); write_slots->release(cb); @@ -4033,8 +4006,7 @@ bool os_aio_init(ulint n_reader_threads, ulint n_writer_threads, ulint) { int max_write_events= int(n_writer_threads * OS_AIO_N_PENDING_IOS_PER_THREAD); int max_read_events= int(n_reader_threads * OS_AIO_N_PENDING_IOS_PER_THREAD); - int max_ibuf_events = 1 * OS_AIO_N_PENDING_IOS_PER_THREAD; - int max_events = max_read_events + max_write_events + max_ibuf_events; + int max_events = max_read_events + max_write_events; int ret; #if LINUX_NATIVE_AIO @@ -4053,7 +4025,6 @@ bool os_aio_init(ulint n_reader_threads, ulint n_writer_threads, ulint) } read_slots = new io_slots(max_read_events, (uint)n_reader_threads); write_slots = new io_slots(max_write_events, (uint)n_writer_threads); - ibuf_slots = new io_slots(max_ibuf_events, 1); return true; } @@ -4062,10 +4033,8 @@ void os_aio_free() srv_thread_pool->disable_aio(); delete read_slots; delete write_slots; - delete ibuf_slots; read_slots= nullptr; write_slots= nullptr; - ibuf_slots= nullptr; } /** Waits until there are no pending writes. There can @@ -4088,7 +4057,6 @@ void os_aio_wait_until_no_pending_writes() NOTE! Use the corresponding macro os_aio(), not directly this function! Requests an asynchronous i/o operation. @param[in,out] type IO request context -@param[in] mode IO mode @param[in] name Name of the file or path as NUL terminated string @param[in] file Open file handle @@ -4106,8 +4074,7 @@ Requests an asynchronous i/o operation. @return DB_SUCCESS or error code */ dberr_t os_aio_func( - IORequest& type, - ulint mode, + const IORequest&type, const char* name, pfs_os_file_t file, void* buf, @@ -4126,10 +4093,7 @@ os_aio_func( ut_ad((n & 0xFFFFFFFFUL) == n); #endif /* WIN_ASYNC_IO */ - DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28", - mode = OS_AIO_SYNC; os_has_said_disk_full = FALSE;); - - if (mode == OS_AIO_SYNC) { + if (!type.is_async()) { if (type.is_read()) { return(os_file_read_func(type, file, buf, offset, n)); } @@ -4140,21 +4104,15 @@ os_aio_func( } if (type.is_read()) { - ++os_n_file_reads; - } else if (type.is_write()) { - ++os_n_file_writes; + ++os_n_file_reads; } else { - ut_error; + ut_ad(type.is_write()); + ++os_n_file_writes; } compile_time_assert(sizeof(os_aio_userdata_t) <= tpool::MAX_AIO_USERDATA_LEN); os_aio_userdata_t userdata{m1,type,m2}; - io_slots* slots; - if (type.is_read()) { - slots = mode == OS_AIO_IBUF?ibuf_slots: read_slots; - } else { - slots = write_slots; - } + io_slots* slots= type.is_read() ? read_slots : write_slots; tpool::aiocb* cb = slots->acquire(); cb->m_buffer = buf; @@ -4462,12 +4420,11 @@ void fil_node_t::find_metadata(os_file_t file } /** Read the first page of a data file. -@param[in] first whether this is the very first read @return whether the page was found valid */ -bool fil_node_t::read_page0(bool first) +bool fil_node_t::read_page0() { ut_ad(mutex_own(&fil_system.mutex)); - const ulint psize = space->physical_size(); + const unsigned psize = space->physical_size(); #ifndef _WIN32 struct stat statbuf; if (fstat(handle, &statbuf)) { @@ -4479,7 +4436,7 @@ bool fil_node_t::read_page0(bool first) os_offset_t size_bytes = os_file_get_size(handle); ut_a(size_bytes != (os_offset_t) -1); #endif - const ulint min_size = FIL_IBD_FILE_INITIAL_SIZE * psize; + const uint32_t min_size = FIL_IBD_FILE_INITIAL_SIZE * psize; if (size_bytes < min_size) { ib::error() << "The size of the file " << name @@ -4506,7 +4463,7 @@ corrupted: const uint32_t size = fsp_header_get_field(page, FSP_SIZE); const uint32_t free_limit = fsp_header_get_field(page, FSP_FREE_LIMIT); const uint32_t free_len = flst_get_len(FSP_HEADER_OFFSET + FSP_FREE - + page); + + page); if (!fil_space_t::is_valid_flags(flags, space->id)) { ulint cflags = fsp_flags_convert_from_101(flags); if (cflags == ULINT_UNDEFINED) { @@ -4546,41 +4503,26 @@ invalid: return false; } - if (first) { - ut_ad(space->id != TRX_SYS_SPACE); #ifdef UNIV_LINUX - find_metadata(handle, &statbuf); + find_metadata(handle, &statbuf); #else - find_metadata(); + find_metadata(); #endif + /* Truncate the size to a multiple of extent size. */ + ulint mask = psize * FSP_EXTENT_SIZE - 1; - /* Truncate the size to a multiple of extent size. */ - ulint mask = psize * FSP_EXTENT_SIZE - 1; - - if (size_bytes <= mask) { - /* .ibd files start smaller than an - extent size. Do not truncate valid data. */ - } else { - size_bytes &= ~os_offset_t(mask); - } - - space->flags = (space->flags & FSP_FLAGS_MEM_MASK) | flags; - - space->punch_hole = space->is_compressed(); - this->size = uint32_t(size_bytes / psize); - space->committed_size = space->size += this->size; - } else if (space->id != TRX_SYS_SPACE || space->size_in_header) { - /* If this is not the first-time open, do nothing. - For the system tablespace, we always get invoked as - first=false, so we detect the true first-time-open based - on size_in_header and proceed to initialize the data. */ - return true; + if (size_bytes <= mask) { + /* .ibd files start smaller than an + extent size. Do not truncate valid data. */ } else { - /* Initialize the size of predefined tablespaces - to FSP_SIZE. */ - space->committed_size = size; + size_bytes &= ~os_offset_t(mask); } + space->flags = (space->flags & FSP_FLAGS_MEM_MASK) | flags; + + space->punch_hole = space->is_compressed(); + this->size = uint32_t(size_bytes / psize); + space->set_sizes(this->size); ut_ad(space->free_limit == 0 || space->free_limit == free_limit); ut_ad(space->free_len == 0 || space->free_len == free_len); space->size_in_header = size; diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 03706d9ae99..8376fbb4ba6 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -3424,8 +3424,7 @@ fil_iterate( byte* const writeptr = readptr; err = os_file_read_no_error_handling( - IORequest(IORequest::READ - | IORequest::DISABLE_PARTIAL_IO_WARNINGS), + IORequestReadPartial, iter.file, readptr, offset, n_bytes, 0); if (err != DB_SUCCESS) { ib::error() << iter.filepath @@ -3664,9 +3663,7 @@ not_encrypted: /* A page was updated in the set, write back to disk. */ if (updated) { - IORequest write_request(IORequest::WRITE); - - err = os_file_write(write_request, + err = os_file_write(IORequestWrite, iter.filepath, iter.file, writeptr, offset, n_bytes); @@ -3759,10 +3756,8 @@ fil_tablespace_iterate( /* Read the first page and determine the page and zip size. */ - err = os_file_read_no_error_handling( - IORequest(IORequest::READ - | IORequest::DISABLE_PARTIAL_IO_WARNINGS), - file, page, 0, srv_page_size, 0); + err = os_file_read_no_error_handling(IORequestReadPartial, + file, page, 0, srv_page_size, 0); if (err == DB_SUCCESS) { err = callback.init(file_size, block); diff --git a/storage/innobase/row/row0quiesce.cc b/storage/innobase/row/row0quiesce.cc index 0cddde4b3ca..0bdf52dfd56 100644 --- a/storage/innobase/row/row0quiesce.cc +++ b/storage/innobase/row/row0quiesce.cc @@ -545,7 +545,7 @@ row_quiesce_table_start( if (!trx_is_interrupted(trx)) { /* Ensure that all asynchronous IO is completed. */ os_aio_wait_until_no_pending_writes(); - fil_flush(table->space_id); + table->space->flush(); if (row_quiesce_write_cfg(table, trx->mysql_thd) != DB_SUCCESS) { diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 1746d351263..d4ee4dc3c4b 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -229,10 +229,12 @@ srv_file_check_mode( static const char INIT_LOG_FILE0[]= "101"; /** Creates log file. -@param[in] lsn FIL_PAGE_FILE_FLUSH_LSN value -@param[out] logfile0 name of the log file +@param[in] create_new_db whether the database is being initialized +@param[in] lsn FIL_PAGE_FILE_FLUSH_LSN value +@param[out] logfile0 name of the log file @return DB_SUCCESS or error code */ -static dberr_t create_log_file(lsn_t lsn, std::string& logfile0) +static dberr_t create_log_file(bool create_new_db, lsn_t lsn, + std::string& logfile0) { if (srv_read_only_mode) { ib::error() << "Cannot create log file in read-only mode"; @@ -296,7 +298,9 @@ static dberr_t create_log_file(lsn_t lsn, std::string& logfile0) } log_sys.log.open_file(logfile0); - fil_open_system_tablespace_files(); + if (!fil_system.sys_space->open(create_new_db)) { + return DB_ERROR; + } /* Create a log checkpoint. */ log_mutex_enter(); @@ -553,8 +557,8 @@ err_exit: fil_set_max_space_id_if_bigger(space_id); - fil_space_t *space= fil_space_create(undo_name, space_id, fsp_flags, - FIL_TYPE_TABLESPACE, NULL); + fil_space_t *space= fil_space_t::create(undo_name, space_id, fsp_flags, + FIL_TYPE_TABLESPACE, NULL); ut_a(fil_validate()); ut_a(space); @@ -563,20 +567,15 @@ err_exit: if (create) { + space->set_sizes(SRV_UNDO_TABLESPACE_SIZE_IN_PAGES); space->size= file->size= uint32_t(size >> srv_page_size_shift); - space->size_in_header= SRV_UNDO_TABLESPACE_SIZE_IN_PAGES; - space->committed_size= SRV_UNDO_TABLESPACE_SIZE_IN_PAGES; } - else + else if (!file->read_page0()) { - success= file->read_page0(true); - if (!success) - { - os_file_close(file->handle); - file->handle= OS_FILE_CLOSED; - ut_a(fil_system.n_open > 0); - fil_system.n_open--; - } + os_file_close(file->handle); + file->handle= OS_FILE_CLOSED; + ut_a(fil_system.n_open > 0); + fil_system.n_open--; } mutex_exit(&fil_system.mutex); @@ -803,7 +802,7 @@ srv_open_tmp_tablespace(bool create_new_db) true, create_new_db, &sum_of_new_sizes, NULL)) != DB_SUCCESS) { ib::error() << "Unable to create the shared innodb_temporary"; - } else if (fil_system.temp_space->open()) { + } else if (fil_system.temp_space->open(true)) { /* Initialize the header page */ mtr_t mtr; mtr.start(); @@ -1304,7 +1303,7 @@ dberr_t srv_start(bool create_new_db) log_sys.set_flushed_lsn(flushed_lsn); buf_flush_sync(); - err = create_log_file(flushed_lsn, logfile0); + err = create_log_file(true, flushed_lsn, logfile0); if (err != DB_SUCCESS) { return(srv_init_abort(err)); @@ -1333,7 +1332,7 @@ dberr_t srv_start(bool create_new_db) srv_log_file_size = srv_log_file_size_requested; - err = create_log_file(flushed_lsn, logfile0); + err = create_log_file(false, flushed_lsn, logfile0); if (err == DB_SUCCESS) { err = create_log_file_rename(flushed_lsn, @@ -1364,11 +1363,11 @@ dberr_t srv_start(bool create_new_db) file_checked: /* Open log file and data files in the systemtablespace: we keep them open until database shutdown */ - - fil_open_system_tablespace_files(); ut_d(fil_system.sys_space->recv_size = srv_sys_space_size_debug); - err = srv_undo_tablespaces_init(create_new_db); + err = fil_system.sys_space->open(create_new_db) + ? srv_undo_tablespaces_init(create_new_db) + : DB_ERROR; /* If the force recovery is set very high then we carry on regardless of all errors. Basically this is fingers crossed mode. */ @@ -1673,7 +1672,7 @@ file_checked: srv_log_file_size = srv_log_file_size_requested; - err = create_log_file(flushed_lsn, logfile0); + err = create_log_file(false, flushed_lsn, logfile0); if (err == DB_SUCCESS) { err = create_log_file_rename(flushed_lsn, diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index f9f564e1841..c0375f25fa6 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -584,11 +584,10 @@ static void trx_purge_truncate_history() : 0, j = i;; ) { ulint space_id = srv_undo_space_id_start + i; ut_ad(srv_is_undo_tablespace(space_id)); + fil_space_t* space= fil_space_get(space_id); - if (fil_space_get_size(space_id) - > threshold) { - purge_sys.truncate.current - = fil_space_get(space_id); + if (space && space->get_size() > threshold) { + purge_sys.truncate.current = space; break; } From 118e258aaac5da75a2ac4556201aaea3688fac67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 26 Oct 2020 16:04:12 +0200 Subject: [PATCH 241/323] MDEV-23855: Shrink fil_space_t Merge n_pending_ios, n_pending_ops to std::atomic n_pending. Change some more fil_space_t members to uint32_t to reduce the memory footprint. fil_space_t::add(), fil_ibd_create(): Attach the already opened handle to the tablespace, and enforce the fil_system.n_open limit. dict_boot(): Initialize fil_system.max_assigned_id. srv_boot(): Call srv_thread_pool_init() before anything else, so that files should be opened in the correct mode on Windows. fil_ibd_create(): Create the file in OS_FILE_AIO mode, just like fil_node_open_file_low() does it. dict_table_t::is_accessible(): Replaces fil_table_accessible(). Reviewed by: Vladislav Vaintroub --- extra/mariabackup/fil_cur.cc | 5 +- extra/mariabackup/xtrabackup.cc | 10 +- storage/innobase/btr/btr0bulk.cc | 10 +- storage/innobase/btr/btr0cur.cc | 30 +- storage/innobase/buf/buf0buf.cc | 25 +- storage/innobase/buf/buf0dblwr.cc | 16 +- storage/innobase/buf/buf0dump.cc | 32 +- storage/innobase/buf/buf0flu.cc | 22 +- storage/innobase/buf/buf0rea.cc | 43 +- storage/innobase/dict/dict0crea.cc | 2 +- storage/innobase/dict/dict0dict.cc | 2 +- storage/innobase/dict/dict0stats_bg.cc | 2 +- storage/innobase/fil/fil0crypt.cc | 146 +++---- storage/innobase/fil/fil0fil.cc | 557 +++++++++---------------- storage/innobase/fsp/fsp0fsp.cc | 58 +-- storage/innobase/fts/fts0opt.cc | 5 +- storage/innobase/handler/ha_innodb.cc | 2 +- storage/innobase/handler/i_s.cc | 5 +- storage/innobase/ibuf/ibuf0ibuf.cc | 8 +- storage/innobase/include/dict0mem.h | 7 + storage/innobase/include/fil0fil.h | 315 +++++++------- storage/innobase/include/fsp0file.h | 8 + storage/innobase/include/fsp0fsp.h | 4 +- storage/innobase/lock/lock0lock.cc | 2 +- storage/innobase/log/log0recv.cc | 18 +- storage/innobase/os/os0file.cc | 2 +- storage/innobase/row/row0uins.cc | 2 +- storage/innobase/row/row0umod.cc | 2 +- storage/innobase/srv/srv0srv.cc | 2 +- storage/innobase/srv/srv0start.cc | 2 +- storage/innobase/trx/trx0undo.cc | 4 +- 31 files changed, 578 insertions(+), 770 deletions(-) diff --git a/extra/mariabackup/fil_cur.cc b/extra/mariabackup/fil_cur.cc index 7aa20b8700e..4f9e493b347 100644 --- a/extra/mariabackup/fil_cur.cc +++ b/extra/mariabackup/fil_cur.cc @@ -93,7 +93,6 @@ xb_fil_node_close_file( mutex_enter(&fil_system.mutex); ut_ad(node); - ut_a(node->n_pending_flushes == 0); ut_a(!node->being_extended); if (!node->is_open()) { @@ -406,7 +405,7 @@ xb_fil_cur_read( retry_count = 10; ret = XB_FIL_CUR_SUCCESS; - fil_space_t *space = fil_space_t::get_for_io(cursor->space_id); + fil_space_t *space = fil_space_t::get(cursor->space_id); if (!space) { return XB_FIL_CUR_ERROR; @@ -455,7 +454,7 @@ read_retry: posix_fadvise(cursor->file, offset, to_read, POSIX_FADV_DONTNEED); func_exit: - space->release_for_io(); + space->release(); return(ret); } diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 39025862276..c05677b8810 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -3094,10 +3094,10 @@ xb_load_single_table_tablespace( ut_a(space != NULL); - space->add(file->filepath(), OS_FILE_CLOSED, 0, false, false); - /* by opening the tablespace we forcing node and space objects - in the cache to be populated with fields from space header */ - space->get_size(); + space->add(file->filepath(), file->detach(), 0, false, false); + mutex_enter(&fil_system.mutex); + space->read_page0(); + mutex_exit(&fil_system.mutex); if (srv_operation == SRV_OPERATION_RESTORE_DELTA || xb_close_files) { @@ -3402,7 +3402,7 @@ xb_load_tablespaces() /** Destroy the tablespace memory cache. */ static void xb_data_files_close() { - fil_close_all_files(); + fil_space_t::close_all(); buf_dblwr.close(); } diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc index f602e0d19a2..ee1bc20e1c9 100644 --- a/storage/innobase/btr/btr0bulk.cc +++ b/storage/innobase/btr/btr0bulk.cc @@ -60,12 +60,10 @@ PageBulk::init() alloc_mtr.start(); m_index->set_modified(alloc_mtr); - ulint n_reserved; - bool success; - success = fsp_reserve_free_extents(&n_reserved, - m_index->table->space, - 1, FSP_NORMAL, &alloc_mtr); - if (!success) { + uint32_t n_reserved; + if (!fsp_reserve_free_extents(&n_reserved, + m_index->table->space, + 1, FSP_NORMAL, &alloc_mtr)) { alloc_mtr.commit(); m_mtr.commit(); return(DB_OUT_OF_FILE_SPACE); diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index c280ed555fe..fdb56e34d7e 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -3318,20 +3318,16 @@ static void btr_cur_prefetch_siblings(const buf_block_t *block, uint32_t prev= mach_read_from_4(my_assume_aligned<4>(page + FIL_PAGE_PREV)); uint32_t next= mach_read_from_4(my_assume_aligned<4>(page + FIL_PAGE_NEXT)); - if (prev != FIL_NULL) - { - ut_a(index->table->space->acquire_for_io()); + if (prev == FIL_NULL); + else if (index->table->space->acquire()) buf_read_page_background(index->table->space, page_id_t(block->page.id().space(), prev), block->zip_size(), false); - } - if (next != FIL_NULL) - { - ut_a(index->table->space->acquire_for_io()); + if (next == FIL_NULL); + else if (index->table->space->acquire()) buf_read_page_background(index->table->space, page_id_t(block->page.id().space(), next), block->zip_size(), false); - } } /*************************************************************//** @@ -3679,7 +3675,7 @@ btr_cur_pessimistic_insert( dberr_t err; bool inherit = false; bool success; - ulint n_reserved = 0; + uint32_t n_reserved = 0; ut_ad(dtuple_check_typed(entry)); ut_ad(thr || !(~flags & (BTR_NO_LOCKING_FLAG | BTR_NO_UNDO_LOG_FLAG))); @@ -3711,7 +3707,7 @@ btr_cur_pessimistic_insert( of the index tree, so that the insert will not fail because of lack of space */ - ulint n_extents = cursor->tree_height / 16 + 3; + uint32_t n_extents = uint32_t(cursor->tree_height / 16 + 3); success = fsp_reserve_free_extents(&n_reserved, index->table->space, @@ -4878,8 +4874,8 @@ btr_cur_pessimistic_update( dberr_t err; dberr_t optim_err; roll_ptr_t roll_ptr; - ibool was_first; - ulint n_reserved = 0; + bool was_first; + uint32_t n_reserved = 0; *offsets = NULL; *big_rec = NULL; @@ -5041,7 +5037,7 @@ btr_cur_pessimistic_update( of the index tree, so that the update will not fail because of lack of space */ - ulint n_extents = cursor->tree_height / 16 + 3; + uint32_t n_extents = uint32_t(cursor->tree_height / 16 + 3); if (!fsp_reserve_free_extents( &n_reserved, index->table->space, n_extents, @@ -5643,7 +5639,7 @@ btr_cur_pessimistic_delete( page_zip_des_t* page_zip; dict_index_t* index; rec_t* rec; - ulint n_reserved = 0; + uint32_t n_reserved = 0; bool success; ibool ret = FALSE; mem_heap_t* heap; @@ -5672,7 +5668,7 @@ btr_cur_pessimistic_delete( of the index tree, so that the node pointer updates will not fail because of lack of space */ - ulint n_extents = cursor->tree_height / 32 + 1; + uint32_t n_extents = uint32_t(cursor->tree_height / 32 + 1); success = fsp_reserve_free_extents(&n_reserved, index->table->space, @@ -7315,7 +7311,7 @@ btr_store_big_rec_extern_fields( for (ulint blob_npages = 0;; ++blob_npages) { buf_block_t* block; const ulint commit_freq = 4; - ulint r_extents; + uint32_t r_extents; ut_ad(page_align(field_ref) == page_align(rec)); @@ -7588,7 +7584,7 @@ static void btr_check_blob_fil_page_type(const buf_block_t& block, bool read) if (UNIV_LIKELY(type == FIL_PAGE_TYPE_BLOB)) return; /* FIXME: take the tablespace as a parameter */ - if (fil_space_t *space= fil_space_acquire_silent(block.page.id().space())) + if (fil_space_t *space= fil_space_t::get(block.page.id().space())) { /* Old versions of InnoDB did not initialize FIL_PAGE_TYPE on BLOB pages. Do not print anything about the type mismatch when reading diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 2046ffd4273..2cdd36a8b60 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -415,7 +415,7 @@ static bool buf_tmp_page_decrypt(byte* tmp_frame, byte* src_frame) static bool buf_page_decrypt_after_read(buf_page_t *bpage, const fil_node_t &node) { - ut_ad(node.space->pending_io()); + ut_ad(node.space->referenced()); ut_ad(node.space->id == bpage->id().space()); const auto flags = node.space->flags; @@ -475,7 +475,7 @@ decompress_with_slot: slot->release(); ut_ad(!write_size || fil_page_type_validate(node.space, dst_frame)); - ut_ad(node.space->pending_io()); + ut_ad(node.space->referenced()); return write_size != 0; } @@ -516,7 +516,7 @@ decrypt_failed: goto decompress; } - ut_ad(node.space->pending_io()); + ut_ad(node.space->referenced()); return true; } #endif /* !UNIV_INNOCHECKSUM */ @@ -2768,7 +2768,7 @@ buf_zip_decompress( ulint size = page_zip_get_size(&block->page.zip); /* The tablespace will not be found if this function is called during IMPORT. */ - fil_space_t* space= fil_space_t::get_for_io(block->page.id().space()); + fil_space_t* space= fil_space_t::get(block->page.id().space()); const unsigned key_version = mach_read_from_4( frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION); fil_space_crypt_t* crypt_data = space ? space->crypt_data : NULL; @@ -2805,7 +2805,7 @@ buf_zip_decompress( if (page_zip_decompress(&block->page.zip, block->frame, TRUE)) { if (space) { - space->release_for_io(); + space->release(); } return(TRUE); } @@ -2824,7 +2824,7 @@ buf_zip_decompress( /* Copy to uncompressed storage. */ memcpy(block->frame, frame, block->zip_size()); if (space) { - space->release_for_io(); + space->release(); } return(TRUE); @@ -2848,7 +2848,7 @@ err_exit: dict_set_corrupted_by_space(space); } - space->release_for_io(); + space->release(); } return(FALSE); @@ -3160,10 +3160,10 @@ lookup: asserting. */ if (page_id.space() == TRX_SYS_SPACE) { } else if (page_id.space() == SRV_TMP_SPACE_ID) { - } else if (fil_space_t* space= fil_space_t::get_for_io( + } else if (fil_space_t* space= fil_space_t::get( page_id.space())) { bool set = dict_set_corrupted_by_space(space); - space->release_for_io(); + space->release(); if (set) { return NULL; } @@ -3374,8 +3374,7 @@ re_evict: if (mode != BUF_GET_IF_IN_POOL && mode != BUF_GET_IF_IN_POOL_OR_WATCH) { } else if (!ibuf_debug) { - } else if (fil_space_t* space - = fil_space_t::get_for_io(page_id.space())) { + } else if (fil_space_t* space = fil_space_t::get(page_id.space())) { /* Try to evict the block from the buffer pool, to use the insert buffer (change buffer) as much as possible. */ @@ -3386,7 +3385,7 @@ re_evict: /* Blocks cannot be relocated or enter or exit the buf_pool while we are holding the buf_pool.mutex. */ const bool evicted = buf_LRU_free_page(&fix_block->page, true); - space->release_for_io(); + space->release(); if (evicted) { hash_lock = buf_pool.page_hash.lock_get(fold); @@ -4108,7 +4107,7 @@ after decryption normal page checksum does not match. static dberr_t buf_page_check_corrupt(buf_page_t *bpage, const fil_node_t &node) { - ut_ad(node.space->pending_io()); + ut_ad(node.space->referenced()); byte* dst_frame = (bpage->zip.data) ? bpage->zip.data : ((buf_block_t*) bpage)->frame; diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index 6b1a32d8930..eb460af2de2 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -363,7 +363,7 @@ void buf_dblwr_t::recover() continue; } - fil_space_t *space= fil_space_t::get_for_io(space_id); + fil_space_t *space= fil_space_t::get(space_id); if (!space) /* The tablespace that this page once belonged to does not exist */ @@ -379,7 +379,7 @@ void buf_dblwr_t::recover() << " is beyond the end of tablespace " << space->name << " (" << space->size << " pages)"; next_page: - space->release_for_io(); + space->release(); continue; } @@ -420,7 +420,7 @@ next_page: /* Write the good page from the doublewrite buffer to the intended position. */ - space->reacquire_for_io(); + space->reacquire(); fio= space->io(IORequestWrite, os_offset_t{page_id.page_no()} * physical_size, physical_size, page); @@ -506,10 +506,10 @@ static void buf_dblwr_check_page_lsn(const page_t* page, const fil_space_t& s) static void buf_dblwr_check_page_lsn(const buf_page_t &b, const byte *page) { - if (fil_space_t *space= fil_space_t::get_for_io(b.id().space())) + if (fil_space_t *space= fil_space_t::get(b.id().space())) { buf_dblwr_check_page_lsn(page, *space); - space->release_for_io(); + space->release(); } } @@ -583,7 +583,7 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size) } #endif /* UNIV_DEBUG */ /* Write out the first block of the doublewrite buffer */ - ut_a(fil_system.sys_space->acquire_for_io()); + ut_a(fil_system.sys_space->acquire()); fil_system.sys_space->io(IORequestWrite, os_offset_t{block1.page_no()} << srv_page_size_shift, @@ -593,7 +593,7 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size) if (old_first_free > size) { /* Write out the second block of the doublewrite buffer. */ - ut_a(fil_system.sys_space->acquire_for_io()); + ut_a(fil_system.sys_space->acquire()); fil_system.sys_space->io(IORequestWrite, os_offset_t{block2.page_no()} << srv_page_size_shift, @@ -687,7 +687,7 @@ void buf_dblwr_t::add_to_batch(fil_space_t *space, const IORequest &request, ut_ad(request.bpage); ut_ad(request.bpage->in_file()); ut_ad(space->id == request.bpage->id().space()); - ut_ad(space->pending_io()); + ut_ad(space->referenced()); ut_ad(!srv_read_only_mode); const ulint buf_size= 2 * block_size(); diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc index 19a9e09e4a1..c62c0112e92 100644 --- a/storage/innobase/buf/buf0dump.cc +++ b/storage/innobase/buf/buf0dump.cc @@ -621,19 +621,11 @@ buf_load() ulint last_check_time = 0; ulint last_activity_cnt = 0; - /* Avoid calling the expensive fil_space_acquire_silent() for each + /* Avoid calling the expensive fil_space_t::get() for each page within the same tablespace. dump[] is sorted by (space, page), so all pages from a given tablespace are consecutive. */ ulint cur_space_id = dump[0].space(); - fil_space_t* space = fil_space_acquire_silent(cur_space_id); - if (space) { - bool ok = space->acquire_for_io(); - space->release(); - if (!ok) { - space = nullptr; - } - } - + fil_space_t* space = fil_space_t::get(cur_space_id); ulint zip_size = space ? space->zip_size() : 0; PSI_stage_progress* pfs_stage_progress __attribute__((unused)) @@ -653,24 +645,16 @@ buf_load() if (this_space_id != cur_space_id) { if (space) { - space->release_for_io(); + space->release(); } cur_space_id = this_space_id; - space = fil_space_acquire_silent(cur_space_id); + space = fil_space_t::get(cur_space_id); if (!space) { continue; } - bool ok = space->acquire_for_io(); - space->release(); - - if (!ok) { - space = nullptr; - continue; - } - zip_size = space->zip_size(); } @@ -684,17 +668,17 @@ buf_load() } if (space->is_stopping()) { - space->release_for_io(); + space->release(); space = nullptr; continue; } - space->reacquire_for_io(); + space->reacquire(); buf_read_page_background(space, dump[i], zip_size, true); if (buf_load_abort_flag) { if (space) { - space->release_for_io(); + space->release(); } buf_load_abort_flag = false; ut_free(dump); @@ -722,7 +706,7 @@ buf_load() } if (space) { - space->release_for_io(); + space->release(); } ut_free(dump); diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 25523ab53f1..f671aadeb4e 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -786,7 +786,7 @@ static bool buf_flush_page(buf_page_t *bpage, bool lru, fil_space_t *space) (space == fil_system.temp_space)); ut_ad(space->purpose == FIL_TYPE_TABLESPACE || space->atomic_write_supported); - ut_ad(space->pending_io()); + ut_ad(space->referenced()); rw_lock_t *rw_lock; @@ -854,7 +854,7 @@ static bool buf_flush_page(buf_page_t *bpage, bool lru, fil_space_t *space) buf_release_freed_page(&block->page); else { - space->reacquire_for_io(); + space->reacquire(); ut_ad(status == buf_page_t::NORMAL || status == buf_page_t::INIT_ON_FLUSH); size_t size, orig_size; IORequest::Type type= lru ? IORequest::WRITE_LRU : IORequest::WRITE_ASYNC; @@ -1029,7 +1029,7 @@ static void buf_flush_freed_pages(fil_space_t *space) if (punch_hole) { - space->reacquire_for_io(); + space->reacquire(); space->io(IORequest(IORequest::PUNCH_RANGE), os_offset_t{range.first} * physical_size, (range.last - range.first + 1) * physical_size, @@ -1039,7 +1039,7 @@ static void buf_flush_freed_pages(fil_space_t *space) { for (os_offset_t i= range.first; i <= range.last; i++) { - space->reacquire_for_io(); + space->reacquire(); space->io(IORequest(IORequest::WRITE_ASYNC), i * physical_size, physical_size, const_cast(field_ref_zero)); @@ -1170,7 +1170,7 @@ static ulint buf_free_from_unzip_LRU_list_batch(ulint max) @retval nullptr if the pages for this tablespace should be discarded */ static fil_space_t *buf_flush_space(const uint32_t id) { - fil_space_t *space= fil_space_t::get_for_io(id); + fil_space_t *space= fil_space_t::get(id); if (space) buf_flush_freed_pages(space); return space; @@ -1261,7 +1261,7 @@ static void buf_flush_LRU_list_batch(ulint max, flush_counters_t *n) if (last_space_id != space_id) { if (space) - space->release_for_io(); + space->release(); space= buf_flush_space(space_id); last_space_id= space_id; } @@ -1270,7 +1270,7 @@ static void buf_flush_LRU_list_batch(ulint max, flush_counters_t *n) } else if (space->is_stopping()) { - space->release_for_io(); + space->release(); space= nullptr; } @@ -1298,7 +1298,7 @@ reacquire_mutex: buf_pool.lru_hp.set(nullptr); if (space) - space->release_for_io(); + space->release(); /* We keep track of all flushes happening as part of LRU flush. When estimating the desired rate at which flush_list should be flushed, @@ -1393,7 +1393,7 @@ static ulint buf_do_flush_list_batch(ulint max_n, lsn_t lsn) if (last_space_id != space_id) { if (space) - space->release_for_io(); + space->release(); space= buf_flush_space(space_id); last_space_id= space_id; } @@ -1402,7 +1402,7 @@ static ulint buf_do_flush_list_batch(ulint max_n, lsn_t lsn) } else if (space->is_stopping()) { - space->release_for_io(); + space->release(); space= nullptr; } @@ -1431,7 +1431,7 @@ reacquire_mutex: mysql_mutex_unlock(&buf_pool.flush_list_mutex); if (space) - space->release_for_io(); + space->release(); if (scanned) MONITOR_INC_VALUE_CUMULATIVE(MONITOR_FLUSH_BATCH_SCANNED, diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index daea53ec130..2f59f1ae4d5 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -288,7 +288,7 @@ buf_read_page_low( << page_id; ut_ad(0); nothing_read: - space->release_for_io(); + space->release(); return false; } @@ -358,7 +358,7 @@ nothing_read: /* The i/o was already completed in space->io() */ *err = buf_page_read_complete(bpage, *fio.node); - space->release_for_io(); + space->release(); if (*err != DB_SUCCESS) { return false; @@ -402,7 +402,7 @@ buf_read_ahead_random(const page_id_t page_id, ulint zip_size, bool ibuf) if (buf_pool.n_pend_reads > buf_pool.curr_size / BUF_READ_AHEAD_PEND_LIMIT) return 0; - fil_space_t* space= fil_space_acquire(page_id.space()); + fil_space_t* space= fil_space_t::get(page_id.space()); if (!space) return 0; @@ -431,7 +431,7 @@ no_read_ahead: return 0; read_ahead: - if (!space->acquire_for_io()) + if (!space->acquire_if_not_stopped()) goto no_read_ahead; /* Read all the suitable blocks within the area */ @@ -444,7 +444,7 @@ read_ahead: if (space->is_stopping()) break; dberr_t err; - space->reacquire_for_io(); + space->reacquire(); if (buf_read_page_low(&err, space, false, ibuf_mode, i, zip_size, false)) count++; } @@ -453,7 +453,6 @@ read_ahead: DBUG_PRINT("ib_buf", ("random read-ahead %zu pages from %s: %u", count, space->chain.start->name, low.page_no())); - space->release_for_io(); space->release(); /* Read ahead is considered one I/O operation for the purpose of @@ -478,22 +477,13 @@ after decryption normal page checksum does not match. @retval DB_TABLESPACE_DELETED if tablespace .ibd file is missing */ dberr_t buf_read_page(const page_id_t page_id, ulint zip_size) { - fil_space_t *space= fil_space_acquire(page_id.space()); + fil_space_t *space= fil_space_t::get(page_id.space()); if (!space) { ib::info() << "trying to read page " << page_id << " in nonexisting or being-dropped tablespace"; return DB_TABLESPACE_DELETED; } - else if (!space->acquire_for_io()) - { - ib::warn() << "unable to read " << page_id << " from tablespace " - << space->name; - space->release(); - return DB_PAGE_CORRUPTED; - } - - space->release(); dberr_t err; if (buf_read_page_low(&err, space, true, BUF_READ_ANY_PAGE, @@ -607,22 +597,15 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf) read-ahead, as that could break the ibuf page access order */ return 0; - fil_space_t *space= fil_space_acquire(page_id.space()); + fil_space_t *space= fil_space_t::get(page_id.space()); if (!space) return 0; - else - { - bool ok= space->acquire_for_io(); - space->release(); - if (!ok) - return 0; - } if (high_1.page_no() > space->last_page_number()) { /* The area is not whole. */ fail: - space->release_for_io(); + space->release(); return 0; } @@ -721,7 +704,7 @@ failed: if (space->is_stopping()) break; dberr_t err; - space->reacquire_for_io(); + space->reacquire(); count+= buf_read_page_low(&err, space, false, ibuf_mode, new_low, zip_size, false); } @@ -730,7 +713,7 @@ failed: DBUG_PRINT("ib_buf", ("random read-ahead %zu pages from %s: %u", count, space->chain.start->name, new_low.page_no())); - space->release_for_io(); + space->release(); /* Read ahead is considered one I/O operation for the purpose of LRU policy decision. */ @@ -747,7 +730,7 @@ highest page number the last in the array @param[in] n number of page numbers in the array */ void buf_read_recv_pages(ulint space_id, const uint32_t* page_nos, ulint n) { - fil_space_t* space = fil_space_t::get_for_io(space_id); + fil_space_t* space = fil_space_t::get(space_id); if (!space) { /* The tablespace is missing or unreadable: do nothing */ @@ -784,7 +767,7 @@ void buf_read_recv_pages(ulint space_id, const uint32_t* page_nos, ulint n) } dberr_t err; - space->reacquire_for_io(); + space->reacquire(); buf_read_page_low(&err, space, false, BUF_READ_ANY_PAGE, cur_page_id, zip_size, true); @@ -798,5 +781,5 @@ void buf_read_recv_pages(ulint space_id, const uint32_t* page_nos, ulint n) DBUG_PRINT("ib_buf", ("recovery read (%u pages) for %s", n, space->chain.start->name)); - space->release_for_io(); + space->release(); } diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index fb3247ecdcf..55e3191c228 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -948,7 +948,7 @@ void dict_drop_index_tree(btr_pcur_t* pcur, trx_t* trx, mtr_t* mtr) ut_ad(len == 8); - if (fil_space_t* s = fil_space_acquire_silent(space_id)) { + if (fil_space_t* s = fil_space_t::get(space_id)) { /* Ensure that the tablespace file exists in order to avoid a crash in buf_page_get_gen(). */ if (root_page_no < s->get_size()) { diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 52b77fd93a5..a4a660be584 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -884,7 +884,7 @@ is_unaccessible: return nullptr; } - if (!fil_table_accessible(table)) + if (!table->is_accessible()) goto is_unaccessible; size_t db1_len, tbl1_len; diff --git a/storage/innobase/dict/dict0stats_bg.cc b/storage/innobase/dict/dict0stats_bg.cc index 0b2e28b6476..bd7ae83b53a 100644 --- a/storage/innobase/dict/dict0stats_bg.cc +++ b/storage/innobase/dict/dict0stats_bg.cc @@ -358,7 +358,7 @@ next_table_id: ut_ad(!table->is_temporary()); - if (!fil_table_accessible(table)) { + if (!table->is_accessible()) { dict_table_close(table, TRUE, FALSE); mutex_exit(&dict_sys.mutex); goto next_table_id; diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index e73337a3bdd..73f87173485 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -633,7 +633,7 @@ byte* fil_space_encrypt( return (src_frame); } - ut_ad(space->pending_io()); + ut_ad(space->referenced()); return fil_encrypt_buf(space->crypt_data, space->id, offset, src_frame, space->zip_size(), @@ -846,7 +846,7 @@ fil_space_decrypt( const ulint physical_size = space->physical_size(); ut_ad(space->crypt_data != NULL && space->crypt_data->is_encrypted()); - ut_ad(space->pending_io()); + ut_ad(space->referenced()); bool encrypted = fil_space_decrypt(space->id, space->crypt_data, tmp_frame, physical_size, @@ -1008,8 +1008,6 @@ fil_crypt_read_crypt_data(fil_space_t* space) @return true if a recheck of tablespace is needed by encryption thread. */ static bool fil_crypt_start_encrypting_space(fil_space_t* space) { - bool recheck = false; - mutex_enter(&fil_crypt_threads_mutex); fil_space_crypt_t *crypt_data = space->crypt_data; @@ -1021,12 +1019,9 @@ static bool fil_crypt_start_encrypting_space(fil_space_t* space) return false; } - if (crypt_data != NULL || fil_crypt_start_converting) { - /* someone beat us to it */ - if (fil_crypt_start_converting) { - recheck = true; - } + const bool recheck = fil_crypt_start_converting; + if (recheck || crypt_data || space->is_stopping()) { mutex_exit(&fil_crypt_threads_mutex); return recheck; } @@ -1045,36 +1040,38 @@ static bool fil_crypt_start_encrypting_space(fil_space_t* space) return false; } - crypt_data->type = CRYPT_SCHEME_UNENCRYPTED; - crypt_data->min_key_version = 0; // all pages are unencrypted - crypt_data->rotate_state.start_time = time(0); - crypt_data->rotate_state.starting = true; - crypt_data->rotate_state.active_threads = 1; - - mutex_enter(&fil_system.mutex); - space->crypt_data = crypt_data; - mutex_exit(&fil_system.mutex); - fil_crypt_start_converting = true; mutex_exit(&fil_crypt_threads_mutex); - do - { - mtr_t mtr; - mtr.start(); - mtr.set_named_space(space); + mtr_t mtr; + mtr.start(); - /* 2 - get page 0 */ - dberr_t err = DB_SUCCESS; - buf_block_t* block = buf_page_get_gen( - page_id_t(space->id, 0), space->zip_size(), - RW_X_LATCH, NULL, BUF_GET, - __FILE__, __LINE__, - &mtr, &err); + /* 2 - get page 0 */ + dberr_t err = DB_SUCCESS; + if (buf_block_t* block = buf_page_get_gen( + page_id_t(space->id, 0), space->zip_size(), + RW_X_LATCH, NULL, BUF_GET_POSSIBLY_FREED, + __FILE__, __LINE__, &mtr, &err)) { + crypt_data->type = CRYPT_SCHEME_1; + crypt_data->min_key_version = 0; // all pages are unencrypted + crypt_data->rotate_state.start_time = time(0); + crypt_data->rotate_state.starting = true; + crypt_data->rotate_state.active_threads = 1; + + mutex_enter(&fil_system.mutex); + const bool stopping = space->is_stopping(); + if (!stopping) { + space->crypt_data = crypt_data; + } + mutex_exit(&fil_system.mutex); + + if (stopping) { + goto abort; + } /* 3 - write crypt data to page 0 */ - crypt_data->type = CRYPT_SCHEME_1; + mtr.set_named_space(space); crypt_data->write_page0(block, &mtr); mtr.commit(); @@ -1094,19 +1091,18 @@ static bool fil_crypt_start_encrypting_space(fil_space_t* space) mutex_exit(&crypt_data->mutex); mutex_exit(&fil_crypt_threads_mutex); - return recheck; - } while (0); - - mutex_enter(&crypt_data->mutex); - ut_a(crypt_data->rotate_state.active_threads == 1); - crypt_data->rotate_state.active_threads = 0; - mutex_exit(&crypt_data->mutex); + return false; + } +abort: + mtr.commit(); mutex_enter(&fil_crypt_threads_mutex); fil_crypt_start_converting = false; mutex_exit(&fil_crypt_threads_mutex); - return recheck; + crypt_data->~fil_space_crypt_t(); + ut_free(crypt_data); + return false; } /** State of a rotation thread */ @@ -1479,7 +1475,7 @@ inline fil_space_t *fil_system_t::keyrotate_next(fil_space_t *space, while (it != end) { space= &*it; - if (space->acquire()) + if (space->acquire_if_not_stopped(true)) return space; while (++it != end && (!UT_LIST_GET_LEN(it->chain) || it->is_stopping())); } @@ -1487,44 +1483,41 @@ inline fil_space_t *fil_system_t::keyrotate_next(fil_space_t *space, return NULL; } -/** Return the next tablespace. -@param space previous tablespace (NULL to start from the beginning) +/** Determine the next tablespace for encryption key rotation. +@param space current tablespace (nullptr to start from the beginning) @param recheck whether the removal condition needs to be rechecked after -the encryption parameters were changed +encryption parameters were changed @param encrypt expected state of innodb_encrypt_tables -@return pointer to the next tablespace (with n_pending_ops incremented) -@retval NULL if this was the last */ -static fil_space_t *fil_space_next(fil_space_t *space, bool recheck, - bool encrypt) +@return the next tablespace +@retval nullptr upon reaching the end of the iteration */ +inline fil_space_t *fil_space_t::next(fil_space_t *space, bool recheck, + bool encrypt) { mutex_enter(&fil_system.mutex); if (!srv_fil_crypt_rotate_key_age) space= fil_system.keyrotate_next(space, recheck, encrypt); - else if (!space) - { - space= UT_LIST_GET_FIRST(fil_system.space_list); - /* We can trust that space is not NULL because at least the - system tablespace is always present and loaded first. */ - if (!space->acquire()) - goto next; - } else { - /* Move on to the next fil_space_t */ - space->release(); -next: - space= UT_LIST_GET_NEXT(space_list, space); - - /* Skip abnormal tablespaces or those that are being created by - fil_ibd_create(), or being dropped. */ - while (space && - (UT_LIST_GET_LEN(space->chain) == 0 || - space->is_stopping() || space->purpose != FIL_TYPE_TABLESPACE)) + if (!space) + space= UT_LIST_GET_FIRST(fil_system.space_list); + else + { + /* Move on to the next fil_space_t */ + space->release(); space= UT_LIST_GET_NEXT(space_list, space); + } - if (space && !space->acquire()) - goto next; + for (; space; space= UT_LIST_GET_NEXT(space_list, space)) + { + if (space->purpose != FIL_TYPE_TABLESPACE) + continue; + const uint32_t n= space->acquire_low(); + if (UNIV_LIKELY(!(n & (STOPPING | CLOSING)))) + break; + if (!(n & STOPPING) && space->prepare(true)) + break; + } } mutex_exit(&fil_system.mutex); @@ -1568,8 +1561,8 @@ static bool fil_crypt_find_space_to_rotate( state->space = NULL; } - state->space = fil_space_next(state->space, *recheck, - key_state->key_version != 0); + state->space = fil_space_t::next(state->space, *recheck, + key_state->key_version != 0); while (!state->should_shutdown() && state->space) { /* If there is no crypt data and we have not yet read @@ -1587,8 +1580,8 @@ static bool fil_crypt_find_space_to_rotate( return true; } - state->space = fil_space_next(state->space, *recheck, - key_state->key_version != 0); + state->space = fil_space_t::next(state->space, *recheck, + key_state->key_version != 0); } if (state->space) { @@ -2000,7 +1993,7 @@ fil_crypt_flush_space( if (buf_block_t* block = buf_page_get_gen( page_id_t(space->id, 0), space->zip_size(), - RW_X_LATCH, NULL, BUF_GET, + RW_X_LATCH, NULL, BUF_GET_POSSIBLY_FREED, __FILE__, __LINE__, &mtr, &err)) { mtr.set_named_space(space); crypt_data->write_page0(block, &mtr); @@ -2240,15 +2233,12 @@ static void fil_crypt_rotation_list_fill() if (space->purpose != FIL_TYPE_TABLESPACE || space->is_in_rotation_list || UT_LIST_GET_LEN(space->chain) == 0 - || !space->acquire()) { + || !space->acquire_if_not_stopped(true)) { continue; } /* Ensure that crypt_data has been initialized. */ - if (!space->get_size()) { - /* Page 0 was not loaded. Skip this tablespace. */ - goto next; - } + ut_ad(space->size); /* Skip ENCRYPTION!=DEFAULT tablespaces. */ if (space->crypt_data diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index ad9d2828467..1829bec8a73 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -64,10 +64,10 @@ inline bool fil_is_user_tablespace_id(ulint space_id) !srv_is_undo_tablespace(space_id); } -/** Try to close a file. -@return true if success, false if should retry later -@param print_info if true, prints information why it cannot close a file */ -static bool fil_try_to_close_file(bool print_info) +/** Try to close a file to adhere to the innodb_open_files limit. +@param print_info whether to diagnose why a file cannot be closed +@return whether a file was closed */ +bool fil_space_t::try_to_close(bool print_info) { ut_ad(mutex_own(&fil_system.mutex)); for (fil_space_t *space= UT_LIST_GET_FIRST(fil_system.space_list); space; @@ -94,27 +94,15 @@ static bool fil_try_to_close_file(bool print_info) if (!node->is_open()) continue; - if (auto n= space->set_closing()) + if (const auto n= space->set_closing()) { if (print_info) ib::info() << "Cannot close file " << node->name - << " because of " << n << " pending operations"; - continue; - } - - if (auto n= node->n_pending_flushes) - { - if (print_info) - ib::info() << "Cannot close file " << node->name - << ", because n_pending_flushes " << n; - continue; - } - - if (node->needs_flush) - { - if (print_info) - ib::info() << "Cannot close file " << node->name - << ", because is should be flushed first"; + << " because of " + << (n & PENDING) + << ((n & NEEDS_FSYNC) + ? " pending operations and pending fsync" + : " pending operations"); continue; } @@ -210,7 +198,7 @@ const char* fil_path_to_mysql_datadir; const char* dot_ext[] = { "", ".ibd", ".isl", ".cfg" }; /** Number of pending tablespace flushes */ -ulint fil_n_pending_tablespace_flushes = 0; +Atomic_counter fil_n_pending_tablespace_flushes; /** The tablespace memory cache. This variable is NULL before the module is initialized. */ @@ -267,8 +255,7 @@ The caller should hold an InnoDB table lock or a MDL that prevents the tablespace from being dropped during the operation, or the caller should be in single-threaded crash recovery mode (no user connections that could drop tablespaces). -If this is not the case, fil_space_acquire() and fil_space_t::release() -should be used instead. +Normally, fil_space_t::get() should be used instead. @param[in] id tablespace ID @return tablespace, or NULL if not found */ fil_space_t* @@ -281,30 +268,6 @@ fil_space_get( return(space); } -/**********************************************************************//** -Checks if all the file nodes in a space are flushed. -@return true if all are flushed */ -static -bool -fil_space_is_flushed( -/*=================*/ - fil_space_t* space) /*!< in: space */ -{ - ut_ad(mutex_own(&fil_system.mutex)); - - for (const fil_node_t* node = UT_LIST_GET_FIRST(space->chain); - node != NULL; - node = UT_LIST_GET_NEXT(chain, node)) { - - if (node->needs_flush) { - ut_ad(srv_file_flush_method != SRV_O_DIRECT_NO_FSYNC); - return(false); - } - } - - return(true); -} - /** Validate the compression algorithm for full crc32 format. @param[in] space tablespace object @return whether the compression algorithm support */ @@ -385,7 +348,12 @@ fil_node_t* fil_space_t::add(const char* name, pfs_os_file_t handle, this->size += size; UT_LIST_ADD_LAST(chain, node); if (node->is_open()) { - ++fil_system.n_open; + n_pending.fetch_and(~CLOSING, std::memory_order_relaxed); + if (++fil_system.n_open >= srv_max_n_open_files) { + reacquire(); + try_to_close(true); + release(); + } } mutex_exit(&fil_system.mutex); @@ -422,7 +390,7 @@ static bool fil_node_open_file_low(fil_node_t *node) /* The following call prints an error message */ if (os_file_get_last_error(true) == EMFILE + 100 && - fil_try_to_close_file(true)) + fil_space_t::try_to_close(true)) continue; ib::warn() << "Cannot open '" << node->name << "'."; @@ -442,7 +410,7 @@ static bool fil_node_open_file_low(fil_node_t *node) if (UNIV_LIKELY(!fil_system.freeze_space_list)) { /* Move the file last in fil_system.space_list, so that - fil_try_to_close_file() should close it as a last resort. */ + fil_space_t::try_to_close() should close it as a last resort. */ UT_LIST_REMOVE(fil_system.space_list, node->space); UT_LIST_ADD_LAST(fil_system.space_list, node->space); } @@ -463,11 +431,11 @@ static bool fil_node_open_file(fil_node_t *node) srv_operation == SRV_OPERATION_RESTORE || srv_operation == SRV_OPERATION_RESTORE_DELTA); ut_ad(node->space->purpose != FIL_TYPE_TEMPORARY); - ut_ad(node->space->pending_io()); + ut_ad(node->space->referenced()); for (ulint count= 0; fil_system.n_open >= srv_max_n_open_files; count++) { - if (fil_try_to_close_file(count > 1)) + if (fil_space_t::try_to_close(count > 1)) count= 0; else if (count >= 2) { @@ -512,98 +480,59 @@ pfs_os_file_t fil_node_t::detach() void fil_node_t::prepare_to_close_or_detach() { ut_ad(mutex_own(&fil_system.mutex)); - ut_ad(space->is_closing()); - ut_ad(!space->pending_io()); + ut_ad(space->is_ready_to_close() || srv_operation == SRV_OPERATION_BACKUP || + srv_operation == SRV_OPERATION_RESTORE_DELTA); ut_a(is_open()); - ut_a(n_pending_flushes == 0); ut_a(!being_extended); - ut_a(!needs_flush || space->purpose == FIL_TYPE_TEMPORARY || + ut_a(space->is_ready_to_close() || space->purpose == FIL_TYPE_TEMPORARY || srv_fast_shutdown == 2 || !srv_was_started); ut_a(fil_system.n_open > 0); fil_system.n_open--; } -/** Flush any writes cached by the file system. -@param[in,out] space tablespace -@param[in] metadata whether to update file system metadata -@return whether fil_system.mutex was released and reacquired */ -static bool fil_flush_low(fil_space_t* space, bool metadata = false) +/** Flush any writes cached by the file system. */ +inline void fil_space_t::flush_low() { - ut_ad(mutex_own(&fil_system.mutex)); - ut_ad(!space->is_stopping()); + ut_ad(!mutex_own(&fil_system.mutex)); - if (srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC) { - /* No need to flush. User has explicitly disabled - buffering. */ - ut_ad(!space->is_in_unflushed_spaces); - ut_ad(fil_space_is_flushed(space)); - ut_ad(space->n_pending_flushes == 0); + uint32_t n= 0; + while (!n_pending.compare_exchange_strong(n, (n + 1) | NEEDS_FSYNC, + std::memory_order_acquire, + std::memory_order_relaxed)) + { + if (n & STOPPING) + return; + if (!(n & NEEDS_FSYNC)) + continue; + if (acquire_low() & STOPPING) + return; + break; + } -#ifdef UNIV_DEBUG - for (fil_node_t* node = UT_LIST_GET_FIRST(space->chain); - node != NULL; - node = UT_LIST_GET_NEXT(chain, node)) { - ut_ad(!node->needs_flush); - ut_ad(node->n_pending_flushes == 0); - } -#endif /* UNIV_DEBUG */ + fil_n_pending_tablespace_flushes++; + for (fil_node_t *node= UT_LIST_GET_FIRST(chain); node; + node= UT_LIST_GET_NEXT(chain, node)) + { + ut_a(node->is_open()); + IF_WIN(if (node->is_raw_disk) continue,); + os_file_flush(node->handle); + } - if (!metadata) return false; - } + if (is_in_unflushed_spaces) + { + mutex_enter(&fil_system.mutex); + if (is_in_unflushed_spaces) + { + is_in_unflushed_spaces= false; + fil_system.unflushed_spaces.remove(*this); + } + mutex_exit(&fil_system.mutex); + } - bool reacquired = false; - /* Prevent dropping of the space while we are flushing */ - space->n_pending_flushes++; - - for (fil_node_t* node = UT_LIST_GET_FIRST(space->chain); - node != NULL; - node = UT_LIST_GET_NEXT(chain, node)) { - - if (!node->needs_flush) { - continue; - } - - ut_a(node->is_open()); - - fil_n_pending_tablespace_flushes++; - -#ifdef _WIN32 - if (node->is_raw_disk) { - - goto skip_flush; - } -#endif /* _WIN32 */ - - ut_a(node->is_open()); - node->n_pending_flushes++; - node->needs_flush = false; - - mutex_exit(&fil_system.mutex); - - os_file_flush(node->handle); - reacquired = true; - - mutex_enter(&fil_system.mutex); - - node->n_pending_flushes--; -#ifdef _WIN32 -skip_flush: -#endif /* _WIN32 */ - if (!node->needs_flush) { - if (space->is_in_unflushed_spaces - && fil_space_is_flushed(space)) { - - fil_system.unflushed_spaces.remove(*space); - space->is_in_unflushed_spaces = false; - } - } - - fil_n_pending_tablespace_flushes--; - } - - space->n_pending_flushes--; - return reacquired; + clear_flush(); + release(); + fil_n_pending_tablespace_flushes--; } /** Try to extend a tablespace. @@ -624,7 +553,7 @@ fil_space_extend_must_retry( ut_ad(UT_LIST_GET_LAST(space->chain) == node); ut_ad(size >= FIL_IBD_FILE_INITIAL_SIZE); ut_ad(node->space == space); - ut_ad(space->pending_io()); + ut_ad(space->referenced() || space->is_being_truncated); *success = space->size >= size; @@ -698,28 +627,35 @@ fil_space_extend_must_retry( switch (space->id) { case TRX_SYS_SPACE: srv_sys_space.set_last_file_size(pages_in_MiB); - fil_flush_low(space, true); - return(false); + do_flush: + mutex_exit(&fil_system.mutex); + space->flush_low(); + mutex_enter(&fil_system.mutex); + break; default: ut_ad(space->purpose == FIL_TYPE_TABLESPACE || space->purpose == FIL_TYPE_IMPORT); if (space->purpose == FIL_TYPE_TABLESPACE && !space->is_being_truncated) { - fil_flush_low(space, true); + goto do_flush; } - return(false); + break; case SRV_TMP_SPACE_ID: ut_ad(space->purpose == FIL_TYPE_TEMPORARY); srv_tmp_space.set_last_file_size(pages_in_MiB); - return(false); + break; } + + return false; } /** @return whether the file is usable for io() */ -ATTRIBUTE_COLD bool fil_space_t::prepare_for_io() +ATTRIBUTE_COLD bool fil_space_t::prepare(bool have_mutex) { - ut_ad(pending_io()); - mutex_enter(&fil_system.mutex); + ut_ad(referenced()); + if (!have_mutex) + mutex_enter(&fil_system.mutex); + ut_ad(mutex_own(&fil_system.mutex)); fil_node_t *node= UT_LIST_GET_LAST(chain); ut_ad(!id || purpose == FIL_TYPE_TEMPORARY || node == UT_LIST_GET_FIRST(chain)); @@ -727,7 +663,7 @@ ATTRIBUTE_COLD bool fil_space_t::prepare_for_io() const bool is_open= node && (node->is_open() || fil_node_open_file(node)); if (!is_open) - release_for_io(); + release(); else if (auto desired_size= recv_size) { bool success; @@ -761,9 +697,10 @@ ATTRIBUTE_COLD bool fil_space_t::prepare_for_io() } else clear: - n_pending_ios.fetch_and(NOT_CLOSING); + n_pending.fetch_and(~CLOSING, std::memory_order_relaxed); - mutex_exit(&fil_system.mutex); + if (!have_mutex) + mutex_exit(&fil_system.mutex); return is_open; } @@ -774,28 +711,39 @@ clear: bool fil_space_extend(fil_space_t *space, uint32_t size) { ut_ad(!srv_read_only_mode || space->purpose == FIL_TYPE_TEMPORARY); - if (!space->acquire_for_io()) - return false; - - bool success; - - do - mutex_enter(&fil_system.mutex); - while (fil_space_extend_must_retry(space, UT_LIST_GET_LAST(space->chain), - size, &success)); - + bool success= false; + const bool acquired= space->acquire(); + mutex_enter(&fil_system.mutex); + if (acquired || space->is_being_truncated) + { + while (fil_space_extend_must_retry(space, UT_LIST_GET_LAST(space->chain), + size, &success)) + mutex_enter(&fil_system.mutex); + } mutex_exit(&fil_system.mutex); - space->release_for_io(); + if (acquired) + space->release(); return success; } /** Prepare to free a file from fil_system. */ -pfs_os_file_t fil_node_t::close_to_free(bool detach_handle) +inline pfs_os_file_t fil_node_t::close_to_free(bool detach_handle) { ut_ad(mutex_own(&fil_system.mutex)); ut_a(magic_n == FIL_NODE_MAGIC_N); ut_a(!being_extended); + if (is_open() && + (space->n_pending.fetch_or(fil_space_t::CLOSING, + std::memory_order_acquire) & + fil_space_t::PENDING)) + { + mutex_exit(&fil_system.mutex); + while (space->referenced()) + os_thread_sleep(100); + mutex_enter(&fil_system.mutex); + } + while (is_open()) { if (space->is_in_unflushed_spaces) @@ -805,14 +753,6 @@ pfs_os_file_t fil_node_t::close_to_free(bool detach_handle) fil_system.unflushed_spaces.remove(*space); } - if (n_pending_flushes || space->set_closing()) - { - mutex_exit(&fil_system.mutex); - os_thread_sleep(100); - mutex_enter(&fil_system.mutex); - continue; - } - ut_a(!being_extended); if (detach_handle) { @@ -875,7 +815,7 @@ std::vector fil_system_t::detach(fil_space_t *space, handles.push_back(handle); } - ut_ad(space->n_pending_flushes == 0); + ut_ad(!space->referenced()); return handles; } @@ -891,10 +831,10 @@ fil_space_free_low( ut_ad(srv_fast_shutdown == 2 || !srv_was_started || space->max_lsn == 0); - /* Wait for fil_space_t::release_for_io(); after + /* Wait for fil_space_t::release() after fil_system_t::detach(), the tablespace cannot be found, so - fil_space_t::get_for_io() would return NULL */ - while (space->pending_io()) { + fil_space_t::get() would return NULL */ + while (space->referenced()) { os_thread_sleep(100); } @@ -1001,7 +941,7 @@ fil_space_t *fil_space_t::create(const char *name, ulint id, ulint flags, space->magic_n = FIL_SPACE_MAGIC_N; space->crypt_data = crypt_data; - space->n_pending_ios.store(CLOSING, std::memory_order_relaxed); + space->n_pending.store(CLOSING, std::memory_order_relaxed); DBUG_LOG("tablespace", "Created metadata for " << id << " name " << name); @@ -1041,28 +981,10 @@ fil_space_t *fil_space_t::create(const char *name, ulint id, ulint flags, return(NULL); } - if ((purpose == FIL_TYPE_TABLESPACE || purpose == FIL_TYPE_IMPORT) - && id > fil_system.max_assigned_id) { - if (!fil_system.space_id_reuse_warned) { - fil_system.space_id_reuse_warned = true; - - ib::warn() << "Allocated tablespace ID " << id - << " for " << name << ", old maximum was " - << fil_system.max_assigned_id; - } - - fil_system.max_assigned_id = id; - } - HASH_INSERT(fil_space_t, hash, &fil_system.spaces, id, space); UT_LIST_ADD_LAST(fil_system.space_list, space); - if (id < SRV_SPACE_ID_UPPER_BOUND && id > fil_system.max_assigned_id) { - - fil_system.max_assigned_id = id; - } - switch (id) { case 0: ut_ad(!fil_system.sys_space); @@ -1072,6 +994,18 @@ fil_space_t *fil_space_t::create(const char *name, ulint id, ulint flags, ut_ad(!fil_system.temp_space); fil_system.temp_space = space; break; + default: + ut_ad(purpose != FIL_TYPE_TEMPORARY); + if (UNIV_LIKELY(id <= fil_system.max_assigned_id)) { + break; + } + if (!fil_system.space_id_reuse_warned) { + ib::warn() << "Allocated tablespace ID " << id + << " for " << name << ", old maximum was " + << fil_system.max_assigned_id; + } + + fil_system.max_assigned_id = id; } /* Inform key rotation that there could be something @@ -1157,9 +1091,13 @@ bool fil_space_t::read_page0() return false; ut_ad(!UT_LIST_GET_NEXT(chain, node)); - n_pending_ios.fetch_add(1, std::memory_order_acquire); + if (UNIV_UNLIKELY(acquire_low() & STOPPING)) + { + ut_ad("this should not happen" == 0); + return false; + } const bool ok= node->is_open() || fil_node_open_file(node); - release_for_io(); + release(); return ok; } @@ -1365,7 +1303,7 @@ void fil_system_t::close() } /** Close all tablespace files at shutdown */ -void fil_close_all_files() +void fil_space_t::close_all() { if (!fil_system.is_initialised()) { return; @@ -1395,8 +1333,7 @@ next: } for (ulint count = 10000; count--; ) { - if (!space->set_closing() - && !node->n_pending_flushes) { + if (!space->set_closing()) { node->close(); goto next; } @@ -1409,10 +1346,8 @@ next: } ib::error() << "File '" << node->name - << "' has " << space->pending_io() - << " operations and " - << node->n_pending_flushes - << " flushes"; + << "' has " << space->referenced() + << " operations"; } space = UT_LIST_GET_NEXT(space_list, space); @@ -1460,7 +1395,7 @@ fil_write_flushed_lsn( byte* buf; ut_ad(!srv_read_only_mode); - if (!fil_system.sys_space->acquire_for_io()) { + if (!fil_system.sys_space->acquire()) { return DB_ERROR; } @@ -1484,64 +1419,29 @@ fil_write_flushed_lsn( 0, srv_page_size, buf); fil_flush_file_spaces(); } else { - fil_system.sys_space->release_for_io(); + fil_system.sys_space->release(); } aligned_free(buf); return fio.err; } -/** Acquire a tablespace when it could be dropped concurrently. -Used by background threads that do not necessarily hold proper locks -for concurrency control. -@param[in] id tablespace ID -@param[in] silent whether to silently ignore missing tablespaces -@return the tablespace -@retval NULL if missing or being deleted */ -fil_space_t* fil_space_acquire_low(ulint id, bool silent) -{ - fil_space_t* space; - - mutex_enter(&fil_system.mutex); - - space = fil_space_get_by_id(id); - - if (space == NULL) { - if (!silent) { - ib::warn() << "Trying to access missing" - " tablespace " << id; - } - } else if (!space->acquire()) { - space = NULL; - } - - mutex_exit(&fil_system.mutex); - - return(space); -} - -/** Acquire a tablespace for reading or writing a block, -when it could be dropped concurrently. -@param[in] id tablespace ID -@return the tablespace -@retval NULL if missing */ -fil_space_t *fil_space_t::get_for_io(ulint id) +/** Acquire a tablespace reference. +@param id tablespace identifier +@return tablespace +@retval nullptr if the tablespace is missing or inaccessible */ +fil_space_t *fil_space_t::get(ulint id) { mutex_enter(&fil_system.mutex); - fil_space_t *space= fil_space_get_by_id(id); - - uint32_t f= space - ? space->n_pending_ios.fetch_add(1, std::memory_order_relaxed) - : 0; - + const uint32_t n= space ? space->acquire_low() : 0; mutex_exit(&fil_system.mutex); - if ((f & CLOSING) && !space->prepare_for_io()) - { - // FIXME: issue an error message! + if (n & STOPPING) + space= nullptr; + + if ((n & CLOSING) && !space->prepare()) space= nullptr; - } return space; } @@ -1777,7 +1677,6 @@ fil_check_pending_io( ulint count) /*!< in: number of attempts so far */ { ut_ad(mutex_own(&fil_system.mutex)); - ut_ad(!space->referenced()); /* The following code must change when InnoDB supports multiple datafiles per tablespace. */ @@ -1785,18 +1684,14 @@ fil_check_pending_io( *node = UT_LIST_GET_FIRST(space->chain); - const auto f = space->n_pending_flushes; - const auto p = space->pending_io(); - - if (f || p) { + if (const uint32_t p = space->referenced()) { ut_a(!(*node)->being_extended); /* Give a warning every 10 second, starting after 1 second */ if ((count % 500) == 50) { ib::info() << "Trying to delete" " tablespace '" << space->name - << "' but there are " << f - << " flushes and " << p + << "' but there are " << p << " pending i/o's on it."; } @@ -1824,13 +1719,14 @@ fil_check_pending_operations( fil_space_t* sp = fil_space_get_by_id(id); if (sp) { - if (sp->crypt_data && sp->acquire()) { + sp->set_stopping(true); + if (sp->crypt_data) { + sp->reacquire(); mutex_exit(&fil_system.mutex); fil_space_crypt_close_tablespace(sp); mutex_enter(&fil_system.mutex); sp->release(); } - sp->set_stopping(true); } /* Check for pending operations. */ @@ -1927,27 +1823,6 @@ void fil_close_tablespace(ulint id) ut_free(path); } -/** Determine whether a table can be accessed in operations that are -not (necessarily) protected by meta-data locks. -(Rollback would generally be protected, but rollback of -FOREIGN KEY CASCADE/SET NULL is not protected by meta-data locks -but only by InnoDB table locks, which may be broken by -lock_remove_all_on_table().) -@param[in] table persistent table -checked @return whether the table is accessible */ -bool fil_table_accessible(const dict_table_t* table) -{ - if (UNIV_UNLIKELY(!table->is_readable() || table->corrupted)) { - return(false); - } - - mutex_enter(&fil_system.mutex); - bool accessible = table->space && !table->space->is_stopping(); - mutex_exit(&fil_system.mutex); - ut_ad(accessible || dict_table_is_file_per_table(table)); - return accessible; -} - /** Delete a tablespace and associated .ibd file. @param[in] id tablespace identifier @param[in] if_exists whether to ignore missing tablespace @@ -2313,7 +2188,7 @@ fil_rename_tablespace( multiple datafiles per tablespace. */ ut_a(UT_LIST_GET_LEN(space->chain) == 1); node = UT_LIST_GET_FIRST(space->chain); - ut_a(space->acquire()); + space->reacquire(); mutex_exit(&fil_system.mutex); @@ -2423,10 +2298,7 @@ fil_ibd_create( file = os_file_create( innodb_data_file_key, path, OS_FILE_CREATE | OS_FILE_ON_ERROR_NO_EXIT, - OS_FILE_NORMAL, - OS_DATA_FILE, - srv_read_only_mode, - &success); + OS_FILE_AIO, OS_DATA_FILE, srv_read_only_mode, &success); if (!success) { /* The following call will print an error message */ @@ -2452,7 +2324,7 @@ fil_ibd_create( const bool is_compressed = fil_space_t::is_compressed(flags); bool punch_hole = is_compressed; - + fil_space_crypt_t* crypt_data = nullptr; #ifdef _WIN32 if (is_compressed) { os_file_set_sparse_win32(file); @@ -2466,6 +2338,7 @@ fil_ibd_create( err_exit: os_file_close(file); os_file_delete(innodb_data_file_key, path); + free(crypt_data); return NULL; } @@ -2498,8 +2371,7 @@ err_exit: /* Create crypt data if the tablespace is either encrypted or user has requested it to remain unencrypted. */ - fil_space_crypt_t *crypt_data = (mode != FIL_ENCRYPTION_DEFAULT - || srv_encrypt_tables) + crypt_data = (mode != FIL_ENCRYPTION_DEFAULT || srv_encrypt_tables) ? fil_space_create_crypt_data(mode, key_id) : NULL; @@ -2557,17 +2429,11 @@ err_exit: } } - fil_space_t* space = fil_space_t::create(name, space_id, flags, - FIL_TYPE_TABLESPACE, - crypt_data, mode); - if (!space) { - free(crypt_data); - *err = DB_ERROR; - } else { + if (fil_space_t* space = fil_space_t::create(name, space_id, flags, + FIL_TYPE_TABLESPACE, + crypt_data, mode)) { space->punch_hole = punch_hole; - /* FIXME: Keep the file open! */ - fil_node_t* node = space->add(path, OS_FILE_CLOSED, size, - false, true); + fil_node_t* node = space->add(path, file, size, false, true); mtr_t mtr; mtr.start(); mtr.log_file_op(FILE_CREATE, space_id, node->name); @@ -2575,19 +2441,15 @@ err_exit: node->find_metadata(file); *err = DB_SUCCESS; + return space; } - os_file_close(file); - - if (*err != DB_SUCCESS) { - if (has_data_dir) { - RemoteDatafile::delete_link_file(name); - } - - os_file_delete(innodb_data_file_key, path); + if (has_data_dir) { + RemoteDatafile::delete_link_file(name); } - return space; + *err = DB_ERROR; + goto err_exit; } /** Try to open a single-table tablespace and optionally check that the @@ -2955,12 +2817,12 @@ skip_validate: df_remote.close(); df_dict.close(); df_default.close(); - if (space->acquire_for_io()) { + if (space->acquire()) { if (purpose != FIL_TYPE_IMPORT) { fsp_flags_try_adjust(space, flags & ~FSP_FLAGS_MEM_MASK); } - space->release_for_io(); + space->release(); } } @@ -3464,36 +3326,19 @@ fil_report_invalid_page_access(const char *name, inline void fil_node_t::complete_write() { ut_ad(!mutex_own(&fil_system.mutex)); - ut_ad(space->pending_io()); - if (space->purpose != FIL_TYPE_TEMPORARY && !space->is_stopping() && - srv_file_flush_method != SRV_O_DIRECT_NO_FSYNC) + if (space->purpose != FIL_TYPE_TEMPORARY && + srv_file_flush_method != SRV_O_DIRECT_NO_FSYNC && + space->set_needs_flush()) { mutex_enter(&fil_system.mutex); - if (!space->is_stopping()) + if (!space->is_in_unflushed_spaces) { - needs_flush= true; - - if (!space->is_in_unflushed_spaces) - { - space->is_in_unflushed_spaces= true; - fil_system.unflushed_spaces.push_front(*space); - } + space->is_in_unflushed_spaces= true; + fil_system.unflushed_spaces.push_front(*space); } mutex_exit(&fil_system.mutex); } -#ifdef UNIV_DEBUG - else - { - mutex_enter(&fil_system.mutex); - if (!space->is_stopping()) - { - ut_ad(!space->is_in_unflushed_spaces); - ut_ad(!needs_flush); - } - mutex_exit(&fil_system.mutex); - } -#endif /* UNIV_DEBUG */ } /** Read or write data. @@ -3506,7 +3351,7 @@ inline void fil_node_t::complete_write() fil_io_t fil_space_t::io(const IORequest &type, os_offset_t offset, size_t len, void *buf, buf_page_t *bpage) { - ut_ad(pending_io()); + ut_ad(referenced()); ut_ad(offset % OS_FILE_LOG_BLOCK_SIZE == 0); ut_ad((len % OS_FILE_LOG_BLOCK_SIZE) == 0); ut_ad(fil_validate_skip()); @@ -3524,7 +3369,7 @@ fil_io_t fil_space_t::io(const IORequest &type, os_offset_t offset, size_t len, if (type.type == IORequest::READ_ASYNC && is_stopping() && !is_being_truncated) { - release_for_io(); + release(); return {DB_TABLESPACE_DELETED, nullptr}; } @@ -3540,7 +3385,7 @@ fil_io_t fil_space_t::io(const IORequest &type, os_offset_t offset, size_t len, node = UT_LIST_GET_NEXT(chain, node); if (!node) { if (type.type == IORequest::READ_ASYNC) { - release_for_io(); + release(); return {DB_ERROR, nullptr}; } fil_report_invalid_page_access(name, offset, @@ -3554,7 +3399,7 @@ fil_io_t fil_space_t::io(const IORequest &type, os_offset_t offset, size_t len, if (UNIV_UNLIKELY(node->size <= p)) { if (type.type == IORequest::READ_ASYNC) { - release_for_io(); + release(); /* If we can tolerate the non-existent pages, we should return with DB_ERROR and let caller decide what to do. */ @@ -3594,7 +3439,7 @@ fil_io_t fil_space_t::io(const IORequest &type, os_offset_t offset, size_t len, release_sync_write: node->complete_write(); release: - release_for_io(); + release(); } ut_ad(fil_validate_skip()); } @@ -3662,47 +3507,35 @@ write_completed: } } - node->space->release_for_io(); -} - -/** Flush pending writes from the file system cache to the file */ -void fil_space_t::flush() -{ - ut_ad(purpose == FIL_TYPE_TABLESPACE || purpose == FIL_TYPE_IMPORT); - if (!is_stopping()) - { - mutex_enter(&fil_system.mutex); - if (!is_stopping()) - fil_flush_low(this); - mutex_exit(&fil_system.mutex); - } + node->space->release(); } /** Flush to disk the writes in file spaces of the given type possibly cached by the OS. */ void fil_flush_file_spaces() { - if (srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC) { - ut_d(mutex_enter(&fil_system.mutex)); - ut_ad(fil_system.unflushed_spaces.empty()); - ut_d(mutex_exit(&fil_system.mutex)); - return; - } + if (srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC) + { + ut_d(mutex_enter(&fil_system.mutex)); + ut_ad(fil_system.unflushed_spaces.empty()); + ut_d(mutex_exit(&fil_system.mutex)); + return; + } rescan: - mutex_enter(&fil_system.mutex); + mutex_enter(&fil_system.mutex); - for (sized_ilist::iterator it - = fil_system.unflushed_spaces.begin(), - end = fil_system.unflushed_spaces.end(); - it != end; ++it) { - if (!it->is_stopping() && fil_flush_low(&*it)) { - mutex_exit(&fil_system.mutex); - goto rescan; - } - } + for (fil_space_t &space : fil_system.unflushed_spaces) + { + if (space.needs_flush_not_stopping()) + { + mutex_exit(&fil_system.mutex); + space.flush_low(); + goto rescan; + } + } - mutex_exit(&fil_system.mutex); + mutex_exit(&fil_system.mutex); } /** Functor to validate the file node list of a tablespace. */ diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index 7af8ee56893..ae8c557b24c 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -1641,7 +1641,7 @@ fseg_create(fil_space_t *space, ulint byte_offset, mtr_t *mtr, { fseg_inode_t* inode; ib_id_t seg_id; - ulint n_reserved; + uint32_t n_reserved; DBUG_ENTER("fseg_create"); @@ -2196,7 +2196,7 @@ fseg_alloc_free_page_general( fil_space_t* space; buf_block_t* iblock; buf_block_t* block; - ulint n_reserved; + uint32_t n_reserved; space_id = page_get_space_id(page_align(seg_header)); space = mtr_x_lock_space(space_id, mtr); @@ -2308,64 +2308,64 @@ free pages available. @return true if we were able to make the reservation */ bool fsp_reserve_free_extents( - ulint* n_reserved, + uint32_t* n_reserved, fil_space_t* space, - ulint n_ext, + uint32_t n_ext, fsp_reserve_t alloc_type, mtr_t* mtr, uint32_t n_pages) { - ulint n_free_list_ext; - ulint free_limit; - ulint size; - ulint n_free; - ulint n_free_up; ulint reserve; size_t total_reserved = 0; ut_ad(mtr); *n_reserved = n_ext; + const uint32_t extent_size = FSP_EXTENT_SIZE; + mtr_x_lock_space(space, mtr); - const ulint physical_size = space->physical_size(); + const unsigned physical_size = space->physical_size(); buf_block_t* header = fsp_get_header(space, mtr); try_again: - size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE + header->frame); + uint32_t size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE + + header->frame); ut_ad(size == space->size_in_header); - if (size < FSP_EXTENT_SIZE && n_pages < FSP_EXTENT_SIZE / 2) { + if (size < extent_size && n_pages < extent_size / 2) { /* Use different rules for small single-table tablespaces */ *n_reserved = 0; return(fsp_reserve_free_pages(space, header, size, mtr, n_pages)); } - n_free_list_ext = flst_get_len(FSP_HEADER_OFFSET + FSP_FREE - + header->frame); + uint32_t n_free_list_ext = flst_get_len(FSP_HEADER_OFFSET + FSP_FREE + + header->frame); ut_ad(space->free_len == n_free_list_ext); - free_limit = mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT - + header->frame); + uint32_t free_limit = mach_read_from_4(FSP_HEADER_OFFSET + + FSP_FREE_LIMIT + + header->frame); ut_ad(space->free_limit == free_limit); /* Below we play safe when counting free extents above the free limit: some of them will contain extent descriptor pages, and therefore will not be free extents */ + uint32_t n_free_up; + if (size >= free_limit) { - n_free_up = (size - free_limit) / FSP_EXTENT_SIZE; + n_free_up = (size - free_limit) / extent_size; + if (n_free_up) { + n_free_up--; + n_free_up -= n_free_up / (physical_size / extent_size); + } } else { ut_ad(alloc_type == FSP_BLOB); n_free_up = 0; } - if (n_free_up > 0) { - n_free_up--; - n_free_up -= n_free_up / (physical_size / FSP_EXTENT_SIZE); - } - - n_free = n_free_list_ext + n_free_up; + uint32_t n_free = n_free_list_ext + n_free_up; switch (alloc_type) { case FSP_NORMAL: @@ -2373,7 +2373,7 @@ try_again: and 1 extent + 0.5 % to cleaning operations; NOTE: this source code is duplicated in the function below! */ - reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200; + reserve = 2 + ((size / extent_size) * 2) / 200; if (n_free <= reserve + n_ext) { @@ -2383,7 +2383,7 @@ try_again: case FSP_UNDO: /* We reserve 0.5 % of the space size to cleaning operations */ - reserve = 1 + ((size / FSP_EXTENT_SIZE) * 1) / 200; + reserve = 1 + ((size / extent_size) * 1) / 200; if (n_free <= reserve + n_ext) { @@ -2435,10 +2435,12 @@ fseg_free_page_low( ut_ad(iblock->frame == page_align(seg_inode)); ut_d(space->modify_check(*mtr)); + const uint32_t extent_size = FSP_EXTENT_SIZE; + ut_ad(ut_is_2pow(extent_size)); buf_block_t* xdes; xdes_t* descr = xdes_get_descriptor(space, offset, &xdes, mtr); - if (xdes_is_free(descr, offset % FSP_EXTENT_SIZE)) { + if (xdes_is_free(descr, offset & (extent_size - 1))) { ib::fatal() << "InnoDB is trying to free page " << page_id_t(space->id, offset) << " though it is already marked as free in the" @@ -2499,7 +2501,7 @@ fseg_free_page_low( flst_add_last(iblock, static_cast(FSEG_NOT_FULL + ioffset), xdes, xoffset, mtr); - not_full_n_used += FSP_EXTENT_SIZE - 1; + not_full_n_used += extent_size - 1; } else { ut_a(not_full_n_used > 0); not_full_n_used--; @@ -2507,7 +2509,7 @@ fseg_free_page_low( mtr->write<4>(*iblock, p_not_full, not_full_n_used); - const ulint bit = offset % FSP_EXTENT_SIZE; + const ulint bit = offset & (extent_size - 1); xdes_set_free(*xdes, descr, bit, mtr); diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index 20ba44a8d73..b0324bf7667 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -2389,7 +2389,7 @@ fts_optimize_table_bk( dict_table_t* table = slot->table; dberr_t error; - if (fil_table_accessible(table) + if (table->is_accessible() && table->fts && table->fts->cache && table->fts->cache->deleted >= FTS_OPTIMIZE_THRESHOLD) { error = fts_optimize_table(table); @@ -2799,8 +2799,7 @@ static void fts_optimize_sync_table(dict_table_t *table, if (!sync_table) return; - if (sync_table->fts && sync_table->fts->cache && - fil_table_accessible(sync_table)) + if (sync_table->fts && sync_table->fts->cache && sync_table->is_accessible()) { fts_sync_table(sync_table, false); if (process_message) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 97cce77135b..b636592bb87 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -17481,7 +17481,7 @@ innodb_make_page_dirty(THD*, st_mysql_sys_var*, void*, const void* save) mtr_t mtr; uint space_id = *static_cast(save); mysql_mutex_unlock(&LOCK_global_system_variables); - fil_space_t* space = fil_space_acquire_silent(space_id); + fil_space_t* space = fil_space_t::get(space_id); if (space == NULL) { func_exit_no_space: diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index e7e66bb0e8d..b0dc115977e 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -6551,7 +6551,7 @@ i_s_dict_fill_sys_tablespaces( memset(&file, 0xff, sizeof(file)); memset(&stat, 0x0, sizeof(stat)); - if (fil_space_t* s = fil_space_acquire_silent(space)) { + if (fil_space_t* s = fil_space_t::get(space)) { const char *filepath = s->chain.start ? s->chain.start->name : NULL; if (!filepath) { @@ -7049,7 +7049,8 @@ i_s_tablespaces_encryption_fill_table( for (fil_space_t* space = UT_LIST_GET_FIRST(fil_system.space_list); space; space = UT_LIST_GET_NEXT(space_list, space)) { if (space->purpose == FIL_TYPE_TABLESPACE - && space->acquire()) { + && !space->is_stopping()) { + space->reacquire(); mutex_exit(&fil_system.mutex); if (int err = i_s_dict_fill_tablespaces_encryption( thd, space, tables->table)) { diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index 9e9bc241828..5c9d7955c90 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -2300,7 +2300,7 @@ static void ibuf_read_merge_pages(const uint32_t* space_ids, for (ulint i = 0; i < n_stored; i++) { const ulint space_id = space_ids[i]; - fil_space_t* s = fil_space_t::get_for_io(space_id); + fil_space_t* s = fil_space_t::get(space_id); if (!s) { tablespace_deleted: /* The tablespace was not found: remove all @@ -2314,7 +2314,7 @@ tablespace_deleted: } const ulint zip_size = s->zip_size(), size = s->size; - s->release_for_io(); + s->release(); mtr_t mtr; if (UNIV_LIKELY(page_nos[i] < size)) { @@ -4028,7 +4028,7 @@ ibuf_restore_pos( return true; } - if (fil_space_t* s = fil_space_acquire_silent(page_id.space())) { + if (fil_space_t* s = fil_space_t::get(page_id.space())) { ib::error() << "ibuf cursor restoration fails!" " ibuf record inserted to page " << page_id @@ -4214,7 +4214,7 @@ ibuf_merge_or_delete_for_page( fil_space_t* space; if (update_ibuf_bitmap) { - space = fil_space_acquire_silent(page_id.space()); + space = fil_space_t::get(page_id.space()); if (UNIV_UNLIKELY(!space)) { /* Do not try to read the bitmap page from the diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 1ae52dfbf5d..68eb417e531 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -1806,6 +1806,13 @@ struct dict_table_t { return(UNIV_LIKELY(!file_unreadable)); } + /** @return whether the table is accessible */ + bool is_accessible() const + { + return UNIV_LIKELY(is_readable() && !corrupted && space) + && !space->is_stopping(); + } + /** Check if a table name contains the string "/#sql" which denotes temporary or intermediate tables in MariaDB. */ static bool is_temporary_name(const char* name) diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 57e5c43199b..a980c21ead0 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -317,7 +317,7 @@ struct fil_io_t { /** error code */ dberr_t err; - /** file; node->space->release_for_io() must follow IORequestRead call */ + /** file; node->space->release() must follow IORequestRead call */ fil_node_t *node; }; @@ -332,13 +332,14 @@ enum fil_encryption_t FIL_ENCRYPTION_OFF }; -struct fil_space_t : ilist_node, - ilist_node +struct fil_space_t final : + ilist_node, ilist_node #else -struct fil_space_t +struct fil_space_t final #endif { #ifndef UNIV_INNOCHECKSUM + friend fil_node_t; ulint id; /*!< space id */ hash_node_t hash; /*!< hash chain node */ char* name; /*!< Tablespace name */ @@ -367,39 +368,27 @@ struct fil_space_t /*!< recovered tablespace size in pages; 0 if no size change was read from the redo log, or if the size change was implemented */ - ulint n_reserved_extents; + uint32_t n_reserved_extents; /*!< number of reserved free extents for ongoing operations like B-tree page split */ - ulint n_pending_flushes; /*!< this is positive when flushing - the tablespace to disk; dropping of the - tablespace is forbidden if this is positive */ private: /** the committed size of the tablespace in pages */ Atomic_relaxed committed_size; - /** Number of pending buffer pool operations accessing the - tablespace without holding a table lock or dict_operation_lock - S-latch that would prevent the table (and tablespace) from being - dropped. An example is encryption key rotation. - - The tablespace cannot be dropped while this is nonzero. - - The most significant bit contains the STOP_NEW_OPS flag. */ - Atomic_relaxed n_pending_ops; - /** Number of pending block read or write operations - The tablespace object cannot be freed while this is nonzero, - but it can be detached from fil_system. - - The most significant bit contains the CLOSING flag. */ - std::atomic n_pending_ios; - - /** Flag in n_pending_ops that indicates that the tablespace is being + /** Number of pending operations on the file. + The tablespace cannot be freed while (n_pending & PENDING) != 0. */ + std::atomic n_pending; + /** Flag in n_pending that indicates that the tablespace is being deleted, and no further operations should be performed */ - static constexpr uint32_t STOP_NEW_OPS= ~(~uint32_t(0) >> 1); - /** Flag in n_pending_ios that indicates that the tablespace is a candidate + static constexpr uint32_t STOPPING= 1U << 31; + /** Flag in n_pending that indicates that the tablespace is a candidate for being closed, and fil_node_t::is_open() can only be trusted after acquiring fil_system.mutex and resetting the flag */ - static constexpr uint32_t CLOSING= STOP_NEW_OPS; - static constexpr uint32_t NOT_CLOSING= ~CLOSING; + static constexpr uint32_t CLOSING= 1U << 30; + /** Flag in n_pending that indicates that the tablespace needs fsync(). + This must be the least significant flag bit; @see release_flush() */ + static constexpr uint32_t NEEDS_FSYNC= 1U << 29; + /** The reference count */ + static constexpr uint32_t PENDING= ~(STOPPING | CLOSING | NEEDS_FSYNC); public: rw_lock_t latch; /*!< latch protecting the file space storage allocation */ @@ -467,7 +456,7 @@ public: @param[in] n_free_now current number of free extents @param[in] n_to_reserve number of extents to reserve @return whether the reservation succeeded */ - bool reserve_free_extents(ulint n_free_now, ulint n_to_reserve) + bool reserve_free_extents(uint32_t n_free_now, uint32_t n_to_reserve) { ut_ad(rw_lock_own(&latch, RW_LOCK_X)); if (n_reserved_extents + n_to_reserve > n_free_now) { @@ -480,7 +469,7 @@ public: /** Release the reserved free extents. @param[in] n_reserved number of reserved extents */ - void release_free_extents(ulint n_reserved) + void release_free_extents(uint32_t n_reserved) { if (!n_reserved) return; ut_ad(rw_lock_own(&latch, RW_LOCK_X)); @@ -513,70 +502,91 @@ public: /** Close each file. Only invoked on fil_system.temp_space. */ void close(); - /** @return whether the tablespace is about to be dropped */ - bool is_stopping() const { return n_pending_ops & STOP_NEW_OPS; } - - /** @return number of references being held */ - size_t referenced() const { return n_pending_ops & ~STOP_NEW_OPS; } - /** Note that operations on the tablespace must stop or can resume */ inline void set_stopping(bool stopping); +private: MY_ATTRIBUTE((warn_unused_result)) - /** @return whether a tablespace reference was successfully acquired */ - bool acquire() + /** Try to acquire a tablespace reference. + @return the old reference count (if STOPPING is set, it was not acquired) */ + uint32_t acquire_low() { uint32_t n= 0; - while (!n_pending_ops.compare_exchange_strong(n, n + 1, - std::memory_order_acquire, - std::memory_order_relaxed)) - if (UNIV_UNLIKELY(n & STOP_NEW_OPS)) - return false; - return true; - } - /** Release a tablespace reference. - @return whether this was the last reference */ - bool release() - { - auto n= n_pending_ops.fetch_sub(1); - ut_ad(n & ~STOP_NEW_OPS); - return (n & ~STOP_NEW_OPS) == 1; + while (!n_pending.compare_exchange_strong(n, n + 1, + std::memory_order_acquire, + std::memory_order_relaxed) && + !(n & STOPPING)); + return n; } +public: + MY_ATTRIBUTE((warn_unused_result)) + /** @return whether a tablespace reference was successfully acquired */ + inline bool acquire_if_not_stopped(bool have_mutex= false); MY_ATTRIBUTE((warn_unused_result)) /** Acquire a tablespace reference for I/O. @return whether the file is usable */ - bool acquire_for_io() + bool acquire() { - return UNIV_LIKELY(!(n_pending_ios.fetch_add(1, std::memory_order_acquire)& - CLOSING)) || - prepare_for_io(); + uint32_t n= acquire_low(); + if (UNIV_LIKELY(!(n & (STOPPING | CLOSING)))) + return true; + return UNIV_LIKELY(!(n & STOPPING)) && prepare(); } /** Acquire another tablespace reference for I/O. */ - inline void reacquire_for_io(); + inline void reacquire(); - /** Release a tablespace reference for I/O. */ - void release_for_io() + /** Release a tablespace reference. + @return whether this was the last reference */ + bool release() { - ut_d(uint32_t n=) n_pending_ios.fetch_sub(1, std::memory_order_release); - ut_ad(n & NOT_CLOSING); + uint32_t n= n_pending.fetch_sub(1, std::memory_order_release); + ut_ad(n & PENDING); + return (n & PENDING) == 1; } - /** @return number of pending reads or writes */ - uint32_t pending_io() const - { return n_pending_ios.load(std::memory_order_acquire) & NOT_CLOSING; } + /** Clear the NEEDS_FSYNC flag */ + void clear_flush() + { n_pending.fetch_and(~NEEDS_FSYNC, std::memory_order_release); } + +private: + /** @return pending operations (and flags) */ + uint32_t pending()const { return n_pending.load(std::memory_order_acquire); } +public: + /** @return whether close() of the file handle has been requested */ + bool is_closing() const { return pending() & CLOSING; } + /** @return whether the tablespace is going to be dropped */ + bool is_stopping() const { return pending() & STOPPING; } + /** @return number of pending operations */ + bool is_ready_to_close() const + { return (pending() & (PENDING | CLOSING)) == CLOSING; } + /** @return whether fsync() or similar is needed */ + bool needs_flush() const { return pending() & NEEDS_FSYNC; } + /** @return whether fsync() or similar is needed, and the tablespace is + not being dropped */ + bool needs_flush_not_stopping() const + { return (pending() & (NEEDS_FSYNC | STOPPING)) == NEEDS_FSYNC; } + + uint32_t referenced() const { return pending() & PENDING; } +private: MY_ATTRIBUTE((warn_unused_result)) /** Prepare to close the file handle. - @return number of pending operations */ + @return number of pending operations, possibly with NEEDS_FSYNC flag */ uint32_t set_closing() { - return n_pending_ios.fetch_or(CLOSING, std::memory_order_acquire) & - NOT_CLOSING; + return n_pending.fetch_or(CLOSING, std::memory_order_acquire) & + (PENDING | NEEDS_FSYNC); } - /** @return whether close() of the file handle has been requested */ - bool is_closing() const - { return n_pending_ios.load(std::memory_order_acquire) & CLOSING; } + +public: + /** Try to close a file to adhere to the innodb_open_files limit. + @param print_info whether to diagnose why a file cannot be closed + @return whether a file was closed */ + static bool try_to_close(bool print_info); + + /** Close all tablespace files at shutdown */ + static void close_all(); /** @return last_freed_lsn */ lsn_t get_last_freed_lsn() { return last_freed_lsn; } @@ -587,6 +597,23 @@ public: last_freed_lsn= lsn; } + /** Note that the file will need fsync(). + @return whether this needs to be added to fil_system.unflushed_spaces */ + bool set_needs_flush() + { + uint32_t n= 1; + while (!n_pending.compare_exchange_strong(n, n | NEEDS_FSYNC, + std::memory_order_acquire, + std::memory_order_relaxed)) + { + ut_ad(n & PENDING); + if (n & (NEEDS_FSYNC | STOPPING)) + return false; + } + + return true; + } + /** Clear all freed ranges for undo tablespace when InnoDB encounters TRIM redo log record */ void clear_freed_ranges() @@ -879,17 +906,19 @@ public: fil_type_t purpose, fil_space_crypt_t *crypt_data, fil_encryption_t mode= FIL_ENCRYPTION_DEFAULT); - /** Acquire a tablespace for reading or writing a block. - @param id tablespace ID - @return the tablespace, or nullptr if missing or inaccessible */ - static fil_space_t *get_for_io(ulint id); + MY_ATTRIBUTE((warn_unused_result)) + /** Acquire a tablespace reference. + @param id tablespace identifier + @return tablespace + @retval nullptr if the tablespace is missing or inaccessible */ + static fil_space_t *get(ulint id); /** Add/remove the free page in the freed ranges list. @param[in] offset page number to be added @param[in] free true if page to be freed */ void free_page(uint32_t offset, bool add=true) { - std::lock_guard freed_lock(freed_range_mutex); + std::lock_guard freed_lock(freed_range_mutex); if (add) return freed_ranges.add_value(offset); @@ -902,7 +931,7 @@ public: /** Add the range of freed pages */ void add_free_ranges(range_set ranges) { - std::lock_guard freed_lock(freed_range_mutex); + std::lock_guard freed_lock(freed_range_mutex); freed_ranges= std::move(ranges); } @@ -942,16 +971,28 @@ public: @return status and file descriptor */ fil_io_t io(const IORequest &type, os_offset_t offset, size_t len, void *buf, buf_page_t *bpage= nullptr); - /** Flush pending writes from the file system cache to the file */ - void flush(); + /** Flush pending writes from the file system cache to the file. */ + inline void flush(); + /** Flush pending writes from the file system cache to the file. */ + void flush_low(); /** Read the first page of a data file. @return whether the page was found valid */ bool read_page0(); + /** Determine the next tablespace for encryption key rotation. + @param space current tablespace (nullptr to start from the beginning) + @param recheck whether the removal condition needs to be rechecked after + encryption parameters were changed + @param encrypt expected state of innodb_encrypt_tables + @return the next tablespace + @retval nullptr upon reaching the end of the iteration */ + static inline fil_space_t *next(fil_space_t *space, bool recheck, + bool encrypt); + private: /** @return whether the file is usable for io() */ - ATTRIBUTE_COLD bool prepare_for_io(); + ATTRIBUTE_COLD bool prepare(bool have_mutex= false); #endif /*!UNIV_INNOCHECKSUM */ }; @@ -960,7 +1001,8 @@ private: #define FIL_SPACE_MAGIC_N 89472 /** File node of a tablespace or the log data space */ -struct fil_node_t { +struct fil_node_t final +{ /** tablespace containing this file */ fil_space_t* space; /** file name; protected by fil_system.mutex and log_sys.mutex. */ @@ -980,12 +1022,8 @@ struct fil_node_t { uint32_t init_size; /** maximum size of the file in database pages (0 if unlimited) */ uint32_t max_size; - /** count of pending flushes; is_open must be true if nonzero */ - ulint n_pending_flushes; /** whether the file is currently being extended */ Atomic_relaxed being_extended; - /** whether this file had writes after lasy fsync() */ - bool needs_flush; /** link to other files in this tablespace */ UT_LIST_NODE_T(fil_node_t) chain; @@ -1023,7 +1061,7 @@ struct fil_node_t { /** Prepare to free a file from fil_system. @param detach_handle whether to detach instead of closing a handle @return detached handle or OS_FILE_CLOSED */ - pfs_os_file_t close_to_free(bool detach_handle= false); + inline pfs_os_file_t close_to_free(bool detach_handle= false); /** Update the data structures on write completion */ inline void complete_write(); @@ -1036,13 +1074,6 @@ private: /** Value of fil_node_t::magic_n */ #define FIL_NODE_MAGIC_N 89389 -inline void fil_space_t::reacquire_for_io() -{ - ut_d(uint32_t n=) n_pending_ios.fetch_add(1, std::memory_order_relaxed); - ut_ad(n & NOT_CLOSING); - ut_ad(UT_LIST_GET_FIRST(chain)->is_open()); -} - inline void fil_space_t::set_imported() { ut_ad(purpose == FIL_TYPE_IMPORT); @@ -1278,15 +1309,14 @@ inline uint16_t fil_page_get_type(const byte *page) #ifndef UNIV_INNOCHECKSUM /** Number of pending tablespace flushes */ -extern ulint fil_n_pending_tablespace_flushes; +extern Atomic_counter fil_n_pending_tablespace_flushes; /** Look up a tablespace. The caller should hold an InnoDB table lock or a MDL that prevents the tablespace from being dropped during the operation, or the caller should be in single-threaded crash recovery mode (no user connections that could drop tablespaces). -If this is not the case, fil_space_acquire() and fil_space_t::release() -should be used instead. +Normally, fil_space_t::get() should be used instead. @param[in] id tablespace ID @return tablespace, or NULL if not found */ fil_space_t* @@ -1352,12 +1382,8 @@ public: fil_space_t* temp_space; /*!< The innodb_temporary tablespace */ /** Map of fil_space_t::id to fil_space_t* */ hash_table_t spaces; - sized_ilist unflushed_spaces; - /*!< list of those - tablespaces whose files contain - unflushed writes; those spaces have - at least one file node where - needs_flush == true */ + /** tablespaces for which fil_space_t::needs_flush() holds */ + sized_ilist unflushed_spaces; /** number of currently open files; protected by mutex */ ulint n_open; ulint max_assigned_id;/*!< maximum space id in the existing @@ -1400,12 +1426,44 @@ public: /** The tablespace memory cache. */ extern fil_system_t fil_system; +inline void fil_space_t::reacquire() +{ + ut_d(uint32_t n=) n_pending.fetch_add(1, std::memory_order_relaxed); + ut_d(if (mutex_own(&fil_system.mutex)) return); + ut_ad(n & PENDING); + ut_ad(UT_LIST_GET_FIRST(chain)->is_open()); +} + +inline bool fil_space_t::acquire_if_not_stopped(bool have_mutex) +{ + ut_ad(mutex_own(&fil_system.mutex) == have_mutex); + const uint32_t n= acquire_low(); + if (UNIV_LIKELY(!(n & (STOPPING | CLOSING)))) + return true; + return UNIV_LIKELY(!(n & CLOSING)) || prepare(have_mutex); +} + /** Note that operations on the tablespace must stop or can resume */ inline void fil_space_t::set_stopping(bool stopping) { ut_ad(mutex_own(&fil_system.mutex)); - ut_d(auto n=) n_pending_ops.fetch_xor(STOP_NEW_OPS); - ut_ad(!(n & STOP_NEW_OPS) == stopping); + ut_d(auto n=) n_pending.fetch_xor(STOPPING, std::memory_order_relaxed); + ut_ad(!(n & STOPPING) == stopping); +} + +/** Flush pending writes from the file system cache to the file. */ +inline void fil_space_t::flush() +{ + ut_ad(!mutex_own(&fil_system.mutex)); + + ut_ad(purpose == FIL_TYPE_TABLESPACE || purpose == FIL_TYPE_IMPORT); + if (srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC) + { + ut_ad(!is_in_unflushed_spaces); + ut_ad(!needs_flush()); + } + else + flush_low(); } /** @return the size in pages (0 if unreadable) */ @@ -1450,8 +1508,6 @@ fil_space_free( void fil_space_set_recv_size_and_flags(ulint id, uint32_t size, uint32_t flags); -/** Close all tablespace files at shutdown */ -void fil_close_all_files(); /*******************************************************************//** Sets the max tablespace id counter if the given number is bigger than the previous value. */ @@ -1469,42 +1525,6 @@ fil_write_flushed_lsn( lsn_t lsn) MY_ATTRIBUTE((warn_unused_result)); -/** Acquire a tablespace when it could be dropped concurrently. -Used by background threads that do not necessarily hold proper locks -for concurrency control. -@param[in] id tablespace ID -@param[in] silent whether to silently ignore missing tablespaces -@return the tablespace -@retval NULL if missing or being deleted */ -fil_space_t* fil_space_acquire_low(ulint id, bool silent) - MY_ATTRIBUTE((warn_unused_result)); - -/** Acquire a tablespace when it could be dropped concurrently. -Used by background threads that do not necessarily hold proper locks -for concurrency control. -@param[in] id tablespace ID -@return the tablespace -@retval NULL if missing or being deleted or truncated */ -inline -fil_space_t* -fil_space_acquire(ulint id) -{ - return (fil_space_acquire_low(id, false)); -} - -/** Acquire a tablespace that may not exist. -Used by background threads that do not necessarily hold proper locks -for concurrency control. -@param[in] id tablespace ID -@return the tablespace -@retval NULL if missing or being deleted */ -inline -fil_space_t* -fil_space_acquire_silent(ulint id) -{ - return (fil_space_acquire_low(id, true)); -} - /** Replay a file rename operation if possible. @param[in] space_id tablespace identifier @param[in] name old file name @@ -1519,17 +1539,6 @@ fil_op_replay_rename( const char* new_name) MY_ATTRIBUTE((warn_unused_result)); -/** Determine whether a table can be accessed in operations that are -not (necessarily) protected by meta-data locks. -(Rollback would generally be protected, but rollback of -FOREIGN KEY CASCADE/SET NULL is not protected by meta-data locks -but only by InnoDB table locks, which may be broken by -lock_remove_all_on_table().) -@param[in] table persistent table -checked @return whether the table is accessible */ -bool fil_table_accessible(const dict_table_t* table) - MY_ATTRIBUTE((warn_unused_result, nonnull)); - /** Delete a tablespace and associated .ibd file. @param[in] id tablespace identifier @param[in] if_exists whether to ignore missing tablespace diff --git a/storage/innobase/include/fsp0file.h b/storage/innobase/include/fsp0file.h index 7a0687d4960..7db85e87ed0 100644 --- a/storage/innobase/include/fsp0file.h +++ b/storage/innobase/include/fsp0file.h @@ -268,6 +268,14 @@ public: return(m_handle); } + /** @return detached file handle */ + pfs_os_file_t detach() + { + pfs_os_file_t detached = m_handle; + m_handle = OS_FILE_CLOSED; + return detached; + } + /** Get Datafile::m_order. @return m_order */ ulint order() const diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index 308b0916284..7245db39273 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/include/fsp0fsp.h @@ -466,9 +466,9 @@ free pages available. @return true if we were able to make the reservation */ bool fsp_reserve_free_extents( - ulint* n_reserved, + uint32_t* n_reserved, fil_space_t* space, - ulint n_ext, + uint32_t n_ext, fsp_reserve_t alloc_type, mtr_t* mtr, uint32_t n_pages = 2); diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 71077e3f9fb..42ab5d061af 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -4949,7 +4949,7 @@ static void lock_rec_block_validate(const page_id_t page_id) discard or rebuild a tablespace do hold an exclusive table lock, which would conflict with any locks referring to the tablespace from other transactions. */ - if (fil_space_t* space = fil_space_acquire(page_id.space())) { + if (fil_space_t* space = fil_space_t::get(page_id.space())) { dberr_t err = DB_SUCCESS; mtr_start(&mtr); diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 1fe5c70bcf7..8eeadc8e805 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -2060,14 +2060,14 @@ same_page: const bool is_init= (b & 0x70) <= INIT_PAGE; switch (*store) { case STORE_IF_EXISTS: - if (fil_space_t *space= fil_space_acquire_silent(space_id)) + if (fil_space_t *space= fil_space_t::get(space_id)) { const auto size= space->get_size(); - space->release(); - if (!size) + space->release(); + if (!size) continue; - } - else + } + else continue; /* fall through */ case STORE_YES: @@ -2312,7 +2312,7 @@ static void recv_recover_page(buf_block_t* block, mtr_t& mtr, if (fil_space_t* s = space ? space - : fil_space_acquire(block->page.id().space())) { + : fil_space_t::get(block->page.id().space())) { switch (a) { case log_phys_t::APPLIED_TO_FSP_HEADER: s->flags = mach_read_from_4( @@ -2351,7 +2351,7 @@ static void recv_recover_page(buf_block_t* block, mtr_t& mtr, fil_crypt_parse(s, b); } - if (s != space) { + if (!space) { s->release(); } } @@ -2520,7 +2520,7 @@ inline buf_block_t *recv_sys_t::recover_low(const page_id_t page_id, if (end_lsn < i.lsn) DBUG_LOG("ib_log", "skip log for page " << page_id << " LSN " << end_lsn << " < " << i.lsn); - else if (fil_space_t *space= fil_space_t::get_for_io(page_id.space())) + else if (fil_space_t *space= fil_space_t::get(page_id.space())) { mtr.start(); mtr.set_log_mode(MTR_LOG_NO_REDO); @@ -2547,7 +2547,7 @@ inline buf_block_t *recv_sys_t::recover_low(const page_id_t page_id, map::iterator r= p++; recv_sys.pages.erase(r); } - space->release_for_io(); + space->release(); } return block; diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index cdf61f12ce4..0b9438d2a08 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -4170,7 +4170,7 @@ os_aio_print(FILE* file) ULINTPF " OS file writes, " ULINTPF " OS fsyncs\n", log_sys.get_pending_flushes(), - fil_n_pending_tablespace_flushes, + ulint{fil_n_pending_tablespace_flushes}, os_n_file_reads, os_n_file_writes, os_n_fsyncs); diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc index 987c5b60f21..1529d8050db 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -401,7 +401,7 @@ static bool row_undo_ins_parse_undo_rec(undo_node_t* node, bool dict_locked) goto close_table; } - if (UNIV_UNLIKELY(!fil_table_accessible(node->table))) { + if (UNIV_UNLIKELY(!node->table->is_accessible())) { close_table: /* Normally, tables should not disappear or become unaccessible during ROLLBACK, because they should be diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index af35dc1af7f..f710f54d0c1 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -1235,7 +1235,7 @@ static bool row_undo_mod_parse_undo_rec(undo_node_t* node, bool dict_locked) ut_ad(!node->table->skip_alter_undo); - if (UNIV_UNLIKELY(!fil_table_accessible(node->table))) { + if (UNIV_UNLIKELY(!node->table->is_accessible())) { close_table: /* Normally, tables should not disappear or become unaccessible during ROLLBACK, because they should be diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 44d33126e48..030acc72e63 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -697,7 +697,6 @@ static bool need_srv_free; static void srv_init() { mutex_create(LATCH_ID_SRV_INNODB_MONITOR, &srv_innodb_monitor_mutex); - srv_thread_pool_init(); if (!srv_read_only_mode) { mutex_create(LATCH_ID_SRV_SYS_TASKS, &srv_sys.tasks_mutex); @@ -761,6 +760,7 @@ void srv_boot(void) /*==========*/ { + srv_thread_pool_init(); sync_check_init(); trx_pool_init(); row_mysql_init(); diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index d4ee4dc3c4b..78b7cbb635b 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -2028,7 +2028,7 @@ void innodb_shutdown() } os_aio_free(); - fil_close_all_files(); + fil_space_t::close_all(); /* Exit any remaining threads. */ ut_ad(!buf_page_cleaner_is_active); srv_shutdown_threads(); diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index e6ec441bdeb..1f3ce121c28 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -359,7 +359,7 @@ trx_undo_seg_create(fil_space_t *space, buf_block_t *rseg_hdr, ulint *id, dberr_t *err, mtr_t *mtr) { buf_block_t* block; - ulint n_reserved; + uint32_t n_reserved; bool success; const ulint slot_no = trx_rsegf_undo_find_free(rseg_hdr); @@ -551,7 +551,7 @@ buf_block_t* trx_undo_add_page(trx_undo_t* undo, mtr_t* mtr) { trx_rseg_t* rseg = undo->rseg; buf_block_t* new_block = NULL; - ulint n_reserved; + uint32_t n_reserved; /* When we add a page to an undo log, this is analogous to a pessimistic insert in a B-tree, and we must reserve the From 8cb01c51fbd3bfebfbcadea78a30a6f18df46598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 23 Oct 2020 10:49:03 +0300 Subject: [PATCH 242/323] MDEV-16264 fixup: Clean up asynchronous I/O os_aio_userdata_t: Remove. It was basically duplicating IORequest. buf_page_write_complete(): Take only IORequest as a parameter. os_aio_func(), pfs_os_aio_func(): Replaced with os_aio() that has no redundant parameters. There is only one caller, so there is no point to pass __FILE__, __LINE__ as a parameter. --- storage/innobase/buf/buf0flu.cc | 22 +++-- storage/innobase/fil/fil0fil.cc | 53 ++++-------- storage/innobase/include/buf0flu.h | 7 +- storage/innobase/include/os0file.h | 105 +++--------------------- storage/innobase/include/os0file.ic | 55 +------------ storage/innobase/os/os0file.cc | 121 +++++++++++++--------------- tpool/tpool.h | 2 +- 7 files changed, 107 insertions(+), 258 deletions(-) diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index f671aadeb4e..7910ca68357 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -302,16 +302,28 @@ buf_flush_relocate_on_flush_list( } /** Complete write of a file page from buf_pool. -@param bpage written page -@param request write request -@param dblwr whether the doublewrite buffer was used */ -void buf_page_write_complete(buf_page_t *bpage, const IORequest &request, - bool dblwr) +@param request write request */ +void buf_page_write_complete(const IORequest &request) { ut_ad(request.is_write()); + ut_ad(!srv_read_only_mode/* || + request.node->space->purpose == FIL_TYPE_TEMPORARY*/); + buf_page_t *bpage= request.bpage; + ut_ad(bpage); ut_ad(bpage->in_file()); ut_ad(bpage->io_fix() == BUF_IO_WRITE); ut_ad(!buf_dblwr.is_inside(bpage->id())); + bool dblwr; + if (bpage->status == buf_page_t::INIT_ON_FLUSH) + { + bpage->status= buf_page_t::NORMAL; + dblwr= false; + } + else + { + ut_ad(bpage->status == buf_page_t::NORMAL); + dblwr= request.node->space->use_doublewrite(); + } /* We do not need protect io_fix here by mutex to read it because this and buf_page_read_complete() are the only functions where we can diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 1829bec8a73..1d170117a12 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -3423,11 +3423,8 @@ fil_io_t fil_space_t::io(const IORequest &type, os_offset_t offset, size_t len, goto release_sync_write; } else { /* Queue the aio request */ - err = os_aio( - IORequest(type, node), - node->name, node->handle, buf, offset, len, - purpose != FIL_TYPE_TEMPORARY && srv_read_only_mode, - node, bpage); + err = os_aio(IORequest(bpage, node, type.type), + buf, offset, len); } /* We an try to recover the page from the double write buffer if @@ -3452,62 +3449,44 @@ release: #include /** Callback for AIO completion */ -void fil_aio_callback(os_aio_userdata_t *data) +void fil_aio_callback(const IORequest &request) { ut_ad(fil_validate_skip()); + ut_ad(request.node); - fil_node_t *node= data->node; - - if (UNIV_UNLIKELY(!node)) + if (!request.bpage) { - ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS); - return; - } - - buf_page_t *bpage= static_cast(data->message); - if (!bpage) - { - /* Asynchronous single page writes from the doublewrite buffer, - or calls from buf_flush_freed_page() don't have access to the page. */ - ut_ad(data->type.is_write()); ut_ad(!srv_read_only_mode); + ut_ad(request.type == IORequest::WRITE_ASYNC); write_completed: - node->complete_write(); + request.node->complete_write(); } - else if (data->type.is_write()) + else if (request.is_write()) { - ut_ad(!srv_read_only_mode || node->space->purpose == FIL_TYPE_TEMPORARY); - bool dblwr= node->space->use_doublewrite(); - if (dblwr && bpage->status == buf_page_t::INIT_ON_FLUSH) - { - bpage->status= buf_page_t::NORMAL; - dblwr= false; - } - buf_page_write_complete(bpage, data->type, dblwr); + buf_page_write_complete(request); goto write_completed; } else { - ut_ad(data->type.is_read()); + ut_ad(request.is_read()); /* IMPORTANT: since i/o handling for reads will read also the insert buffer in fil_system.sys_space, we have to be very careful not to - introduce deadlocks. We never close the system tablespace (0) data - files via fil_system.LRU and we never issue asynchronous reads of - change buffer pages. */ - const page_id_t id(bpage->id()); + introduce deadlocks. We never close fil_system.sys_space data + files and never issue asynchronous reads of change buffer pages. */ + const page_id_t id(request.bpage->id()); - if (dberr_t err= buf_page_read_complete(bpage, *node)) + if (dberr_t err= buf_page_read_complete(request.bpage, *request.node)) { if (recv_recovery_is_on() && !srv_force_recovery) recv_sys.found_corrupt_fs= true; ib::error() << "Failed to read page " << id.page_no() - << " from file '" << node->name << "': " << err; + << " from file '" << request.node->name << "': " << err; } } - node->space->release(); + request.node->space->release(); } /** Flush to disk the writes in file spaces of the given type diff --git a/storage/innobase/include/buf0flu.h b/storage/innobase/include/buf0flu.h index 148db809077..1dd0d35793b 100644 --- a/storage/innobase/include/buf0flu.h +++ b/storage/innobase/include/buf0flu.h @@ -72,11 +72,8 @@ buf_flush_relocate_on_flush_list( buf_page_t* dpage); /*!< in/out: destination block */ /** Complete write of a file page from buf_pool. -@param bpage written page -@param request write request -@param dblwr whether the doublewrite buffer was used */ -void buf_page_write_complete(buf_page_t *bpage, const IORequest &request, - bool dblwr); +@param request write request */ +void buf_page_write_complete(const IORequest &request); /** Assign the full crc32 checksum for non-compressed page. @param[in,out] page page to be updated */ diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index 0db22abfb19..dfc6d7568fc 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -208,12 +208,12 @@ public: PUNCH_RANGE= WRITE_SYNC | 128, }; + constexpr IORequest(buf_page_t *bpage, fil_node_t *node, Type type) : + bpage(bpage), node(node), type(type) {} + constexpr IORequest(Type type= READ_SYNC, buf_page_t *bpage= nullptr) : bpage(bpage), type(type) {} - constexpr IORequest(const IORequest &old, fil_node_t *node= nullptr) : - bpage(old.bpage), node(node), type(old.type) {} - bool is_read() const { return (type & READ_SYNC) != 0; } bool is_write() const { return (type & WRITE_SYNC) != 0; } bool is_LRU() const { return (type & (WRITE_LRU ^ WRITE_ASYNC)) != 0; } @@ -243,7 +243,7 @@ public: buf_page_t* const bpage= nullptr; /** File descriptor */ - const fil_node_t *const node= nullptr; + fil_node_t *const node= nullptr; /** Request type bit flags */ const Type type; @@ -608,12 +608,6 @@ The wrapper functions have the prefix of "innodb_". */ # define os_file_close(file) \ pfs_os_file_close_func(file, __FILE__, __LINE__) -# define os_aio(type, name, file, buf, offset, \ - n, read_only, message1, message2) \ - pfs_os_aio_func(type, name, file, buf, offset, \ - n, read_only, message1, message2, \ - __FILE__, __LINE__) - # define os_file_read(type, file, buf, offset, n) \ pfs_os_file_read_func(type, file, buf, offset, n, __FILE__, __LINE__) @@ -793,42 +787,6 @@ pfs_os_file_read_no_error_handling_func( const char* src_file, uint src_line); -/** NOTE! Please use the corresponding macro os_aio(), not directly this -function! -Performance schema wrapper function of os_aio() which requests -an asynchronous I/O operation. -@param[in,out] type IO request context -@param[in] name Name of the file or path as NUL terminated - string -@param[in] file Open file handle -@param[out] buf buffer where to read -@param[in] offset file offset where to read -@param[in] n number of bytes to read -@param[in] read_only if true read only mode checks are enforced -@param[in,out] m1 Message for the AIO handler, (can be used to - identify a completed AIO operation); ignored - if mode is OS_AIO_SYNC -@param[in,out] m2 message for the AIO handler (can be used to - identify a completed AIO operation); ignored - if mode is OS_AIO_SYNC -@param[in] src_file file name where func invoked -@param[in] src_line line where the func invoked -@return DB_SUCCESS if request was queued successfully, FALSE if fail */ -UNIV_INLINE -dberr_t -pfs_os_aio_func( - const IORequest&type, - const char* name, - pfs_os_file_t file, - void* buf, - os_offset_t offset, - ulint n, - bool read_only, - fil_node_t* m1, - void* m2, - const char* src_file, - uint src_line); - /** NOTE! Please use the corresponding macro os_file_write(), not directly this function! This is the performance schema instrumented wrapper function for @@ -950,11 +908,6 @@ to original un-instrumented file I/O APIs */ # define os_file_close(file) os_file_close_func(file) -# define os_aio(type, name, file, buf, offset, \ - n, read_only, message1, message2) \ - os_aio_func(type, name, file, buf, offset, \ - n, read_only, message1, message2) - # define os_file_read(type, file, buf, offset, n) \ os_file_read_func(type, file, buf, offset, n) @@ -1202,48 +1155,14 @@ os_aio_init( Frees the asynchronous io system. */ void os_aio_free(); -struct os_aio_userdata_t -{ - fil_node_t* node; - IORequest type; - void* message; - - os_aio_userdata_t(fil_node_t*node, IORequest type, void*message) : - node(node), type(type), message(message) {} - - /** Construct from tpool::aiocb::m_userdata[] */ - os_aio_userdata_t(const char *buf) { memcpy((void*)this, buf, sizeof*this); } -}; -/** -NOTE! Use the corresponding macro os_aio(), not directly this function! -Requests an asynchronous i/o operation. -@param[in,out] type IO request context -@param[in] name Name of the file or path as NUL terminated - string -@param[in] file Open file handle -@param[out] buf buffer where to read -@param[in] offset file offset where to read -@param[in] n number of bytes to read -@param[in] read_only if true read only mode checks are enforced -@param[in,out] m1 Message for the AIO handler, (can be used to - identify a completed AIO operation); ignored - if mode is OS_AIO_SYNC -@param[in,out] m2 message for the AIO handler (can be used to - identify a completed AIO operation); ignored - if mode is OS_AIO_SYNC -@return DB_SUCCESS or error code */ -dberr_t -os_aio_func( - const IORequest&type, - const char* name, - pfs_os_file_t file, - void* buf, - os_offset_t offset, - ulint n, - bool read_only, - fil_node_t* m1, - void* m2); - +/** Request a read or write. +@param type I/O request +@param buf buffer +@param offset file offset +@param n number of bytes +@retval DB_SUCCESS if request was queued successfully +@retval DB_IO_ERROR on I/O error */ +dberr_t os_aio(const IORequest &type, void *buf, os_offset_t offset, size_t n); /** Waits until there are no pending writes in os_aio_write_array. There can be other, synchronous, pending writes. */ diff --git a/storage/innobase/include/os0file.ic b/storage/innobase/include/os0file.ic index 1382b79bc12..e88f94b8ff3 100644 --- a/storage/innobase/include/os0file.ic +++ b/storage/innobase/include/os0file.ic @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2010, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2019, MariaDB Corporation. +Copyright (c) 2013, 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 @@ -201,59 +201,6 @@ pfs_os_file_close_func( return(result); } -/** NOTE! Please use the corresponding macro os_aio(), not directly this -function! -Performance schema wrapper function of os_aio() which requests -an asynchronous i/o operation. -@param[in,type] type IO request context -@param[in] name Name of the file or path as NUL terminated - string -@param[in] file Open file handle -@param[out] buf buffer where to read -@param[in] offset file offset where to read -@param[in] n number of bytes to read -@param[in] read_only if true read only mode checks are enforced -@param[in,out] m1 Message for the AIO handler, (can be used to - identify a completed AIO operation); ignored - if mode is OS_AIO_SYNC -@param[in,out] m2 message for the AIO handler (can be used to - identify a completed AIO operation); ignored - if mode is OS_AIO_SYNC -@param[in] src_file file name where func invoked -@param[in] src_line line where the func invoked -@return DB_SUCCESS if request was queued successfully, FALSE if fail */ -UNIV_INLINE -dberr_t -pfs_os_aio_func( - const IORequest&type, - const char* name, - pfs_os_file_t file, - void* buf, - os_offset_t offset, - ulint n, - bool read_only, - fil_node_t* m1, - void* m2, - const char* src_file, - uint src_line) -{ - PSI_file_locker_state state; - struct PSI_file_locker* locker = NULL; - - /* Register the read or write I/O depending on "type" */ - register_pfs_file_io_begin( - &state, locker, file, n, - type.is_write() ? PSI_FILE_WRITE : PSI_FILE_READ, - src_file, src_line); - - dberr_t result = os_aio_func( - type, name, file, buf, offset, n, read_only, m1, m2); - - register_pfs_file_io_end(locker, n); - - return(result); -} - /** NOTE! Please use the corresponding macro os_file_read(), not directly this function! This is the performance schema instrumented wrapper function for diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 0b9438d2a08..6f428150291 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -3854,22 +3854,26 @@ os_file_get_status( } -extern void fil_aio_callback(os_aio_userdata_t *data); +extern void fil_aio_callback(const IORequest &request); static void io_callback(tpool::aiocb* cb) { - ut_a(cb->m_err == DB_SUCCESS); - os_aio_userdata_t data(cb->m_userdata); - /* Return cb back to cache*/ - if (cb->m_opcode == tpool::aio_opcode::AIO_PREAD) { - ut_ad(read_slots->contains(cb)); - read_slots->release(cb); - } else { - ut_ad(write_slots->contains(cb)); - write_slots->release(cb); - } + ut_a(cb->m_err == DB_SUCCESS); + const IORequest request(*static_cast + (static_cast(cb->m_userdata))); + /* Return cb back to cache*/ + if (cb->m_opcode == tpool::aio_opcode::AIO_PREAD) + { + ut_ad(read_slots->contains(cb)); + read_slots->release(cb); + } + else + { + ut_ad(write_slots->contains(cb)); + write_slots->release(cb); + } - fil_aio_callback(&data); + fil_aio_callback(request); } #ifdef LINUX_NATIVE_AIO @@ -4052,91 +4056,82 @@ void os_aio_wait_until_no_pending_writes() tpool::tpool_wait_end(); } - -/** -NOTE! Use the corresponding macro os_aio(), not directly this function! -Requests an asynchronous i/o operation. -@param[in,out] type IO request context -@param[in] name Name of the file or path as NUL terminated - string -@param[in] file Open file handle -@param[out] buf buffer where to read -@param[in] offset file offset where to read -@param[in] n number of bytes to read -@param[in] read_only if true read only mode checks are enforced -@param[in,out] m1 Message for the AIO handler, (can be used to - identify a completed AIO operation); ignored - if mode is OS_AIO_SYNC -@param[in,out] m2 message for the AIO handler (can be used to - identify a completed AIO operation); ignored - if mode is OS_AIO_SYNC - -@return DB_SUCCESS or error code */ -dberr_t -os_aio_func( - const IORequest&type, - const char* name, - pfs_os_file_t file, - void* buf, - os_offset_t offset, - ulint n, - bool read_only, - fil_node_t* m1, - void* m2) +/** Request a read or write. +@param type I/O request +@param buf buffer +@param offset file offset +@param n number of bytes +@retval DB_SUCCESS if request was queued successfully +@retval DB_IO_ERROR on I/O error */ +dberr_t os_aio(const IORequest &type, void *buf, os_offset_t offset, size_t n) { - ut_ad(n > 0); ut_ad((n % OS_FILE_LOG_BLOCK_SIZE) == 0); ut_ad((offset % OS_FILE_LOG_BLOCK_SIZE) == 0); + ut_ad(type.is_read() || type.is_write()); + ut_ad(type.node); + ut_ad(type.node->is_open()); #ifdef WIN_ASYNC_IO ut_ad((n & 0xFFFFFFFFUL) == n); #endif /* WIN_ASYNC_IO */ +#ifdef UNIV_PFS_IO + PSI_file_locker_state state; + PSI_file_locker* locker= nullptr; + register_pfs_file_io_begin(&state, locker, type.node->handle, n, + type.is_write() + ? PSI_FILE_WRITE : PSI_FILE_READ, + __FILE__, __LINE__); +#endif /* UNIV_PFS_IO */ + dberr_t err = DB_SUCCESS; + if (!type.is_async()) { - if (type.is_read()) { - return(os_file_read_func(type, file, buf, offset, n)); - } - - ut_ad(type.is_write()); - - return(os_file_write_func(type, name, file, buf, offset, n)); + err = type.is_read() + ? os_file_read_func(type, type.node->handle, + buf, offset, n) + : os_file_write_func(type, type.node->name, + type.node->handle, + buf, offset, n); +func_exit: +#ifdef UNIV_PFS_IO + register_pfs_file_io_end(locker, n); +#endif /* UNIV_PFS_IO */ + return err; } if (type.is_read()) { ++os_n_file_reads; } else { - ut_ad(type.is_write()); ++os_n_file_writes; } - compile_time_assert(sizeof(os_aio_userdata_t) <= tpool::MAX_AIO_USERDATA_LEN); - os_aio_userdata_t userdata{m1,type,m2}; + compile_time_assert(sizeof(IORequest) <= tpool::MAX_AIO_USERDATA_LEN); io_slots* slots= type.is_read() ? read_slots : write_slots; tpool::aiocb* cb = slots->acquire(); cb->m_buffer = buf; cb->m_callback = (tpool::callback_func)io_callback; cb->m_group = slots->get_task_group(); - cb->m_fh = file.m_file; + cb->m_fh = type.node->handle.m_file; cb->m_len = (int)n; cb->m_offset = offset; cb->m_opcode = type.is_read() ? tpool::aio_opcode::AIO_PREAD : tpool::aio_opcode::AIO_PWRITE; - memcpy(cb->m_userdata, &userdata, sizeof(userdata)); + new (cb->m_userdata) IORequest{type}; ut_a(reinterpret_cast(cb->m_buffer) % OS_FILE_LOG_BLOCK_SIZE == 0); ut_a(cb->m_len % OS_FILE_LOG_BLOCK_SIZE == 0); ut_a(cb->m_offset % OS_FILE_LOG_BLOCK_SIZE == 0); - if (!srv_thread_pool->submit_io(cb)) - return DB_SUCCESS; + if (srv_thread_pool->submit_io(cb)) { + slots->release(cb); + os_file_handle_error(type.node->name, type.is_read() + ? "aio read" : "aio write"); + err = DB_IO_ERROR; + } - slots->release(cb); - - os_file_handle_error(name, type.is_read() ? "aio read" : "aio write"); - - return(DB_IO_ERROR); + goto func_exit; } /** Prints info of the aio arrays. diff --git a/tpool/tpool.h b/tpool/tpool.h index 239be53c27e..0d83af5bd74 100644 --- a/tpool/tpool.h +++ b/tpool/tpool.h @@ -114,7 +114,7 @@ enum class aio_opcode AIO_PREAD, AIO_PWRITE }; -const int MAX_AIO_USERDATA_LEN= 40; +constexpr size_t MAX_AIO_USERDATA_LEN= 3 * sizeof(void*); /** IO control block, includes parameters for the IO, and the callback*/ From ef3f71fa7435f092dfce36d606cf22332218dd8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 23 Oct 2020 12:29:11 +0300 Subject: [PATCH 243/323] MDEV-23399 fixup: Interleaved doublewrite batches Author: Vladislav Vaintroub --- storage/innobase/buf/buf0dblwr.cc | 95 +++++++++++++++------------- storage/innobase/include/buf0dblwr.h | 42 +++++++----- 2 files changed, 76 insertions(+), 61 deletions(-) diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index eb460af2de2..81c934faf4f 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -53,8 +53,8 @@ inline buf_block_t *buf_dblwr_trx_sys_get(mtr_t *mtr) @param header doublewrite page header in the TRX_SYS page */ inline void buf_dblwr_t::init(const byte *header) { - ut_ad(!first_free); - ut_ad(!reserved); + ut_ad(!active_slot->first_free); + ut_ad(!active_slot->reserved); ut_ad(!batch_running); mysql_mutex_init(buf_dblwr_mutex_key, &mutex, nullptr); @@ -63,10 +63,14 @@ inline void buf_dblwr_t::init(const byte *header) block2= page_id_t(0, mach_read_from_4(header + TRX_SYS_DOUBLEWRITE_BLOCK2)); const uint32_t buf_size= 2 * block_size(); - write_buf= static_cast(aligned_malloc(buf_size << srv_page_size_shift, - srv_page_size)); - buf_block_arr= static_cast - (ut_zalloc_nokey(buf_size * sizeof(element))); + for (int i= 0; i < 2; i++) + { + slots[i].write_buf= static_cast + (aligned_malloc(buf_size << srv_page_size_shift, srv_page_size)); + slots[i].buf_block_arr= static_cast + (ut_zalloc_nokey(buf_size * sizeof(element))); + } + active_slot= &slots[0]; } /** Create or restore the doublewrite buffer in the TRX_SYS page. @@ -272,6 +276,7 @@ func_exit: TRX_SYS_DOUBLEWRITE + read_buf) != TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N; + auto write_buf= active_slot->write_buf; /* Read the pages from the doublewrite buffer to memory */ err= os_file_read(IORequestRead, file, write_buf, block1.page_no() << srv_page_size_shift, @@ -443,16 +448,20 @@ void buf_dblwr_t::close() return; /* Free the double write data structures. */ - ut_ad(!reserved); - ut_ad(!first_free); + ut_ad(!active_slot->reserved); + ut_ad(!active_slot->first_free); ut_ad(!batch_running); mysql_cond_destroy(&cond); - aligned_free(write_buf); - ut_free(buf_block_arr); + for (int i= 0; i < 2; i++) + { + aligned_free(slots[i].write_buf); + ut_free(slots[i].buf_block_arr); + } mysql_mutex_destroy(&mutex); memset((void*) this, 0, sizeof *this); + active_slot= &slots[0]; } /** Update the doublewrite buffer on write completion. */ @@ -466,10 +475,11 @@ void buf_dblwr_t::write_completed() mysql_mutex_lock(&mutex); ut_ad(batch_running); - ut_ad(reserved); - ut_ad(reserved <= first_free); + slot *flush_slot= active_slot == &slots[0] ? &slots[1] : &slots[0]; + ut_ad(flush_slot->reserved); + ut_ad(flush_slot->reserved <= flush_slot->first_free); - if (!--reserved) + if (!--flush_slot->reserved) { mysql_mutex_unlock(&mutex); /* This will finish the batch. Sync data files to the disk. */ @@ -477,7 +487,7 @@ void buf_dblwr_t::write_completed() mysql_mutex_lock(&mutex); /* We can now reuse the doublewrite memory buffer: */ - first_free= 0; + flush_slot->first_free= 0; batch_running= false; mysql_cond_broadcast(&cond); } @@ -552,25 +562,30 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size) for (;;) { - if (!first_free) + if (!active_slot->first_free) return false; if (!batch_running) break; mysql_cond_wait(&cond, &mutex); } - ut_ad(reserved == first_free); - /* Disallow anyone else to post to doublewrite buffer or to - start another batch of flushing. */ + ut_ad(active_slot->reserved == active_slot->first_free); + + /* Disallow anyone else to start another batch of flushing. */ + slot *flush_slot= active_slot; + /* Switch the active slot */ + active_slot= active_slot == &slots[0] ? &slots[1] : &slots[0]; + ut_a(active_slot->first_free == 0); batch_running= true; - const ulint old_first_free= first_free; + const ulint old_first_free= flush_slot->first_free; + auto write_buf= flush_slot->write_buf; /* Now safe to release the mutex. */ mysql_mutex_unlock(&mutex); #ifdef UNIV_DEBUG for (ulint len2= 0, i= 0; i < old_first_free; len2 += srv_page_size, i++) { - buf_page_t *bpage= buf_block_arr[i].request.bpage; + buf_page_t *bpage= flush_slot->buf_block_arr[i].request.bpage; if (bpage->zip.data) /* No simple validate for ROW_FORMAT=COMPRESSED pages exists. */ @@ -602,7 +617,7 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size) } /* increment the doublewrite flushed pages counter */ - srv_stats.dblwr_pages_written.add(first_free); + srv_stats.dblwr_pages_written.add(flush_slot->first_free); srv_stats.dblwr_writes.inc(); /* Now flush the doublewrite buffer data to disk */ @@ -612,20 +627,13 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size) and in recovery we will find them in the doublewrite buffer blocks. Next do the writes to the intended positions. */ - /* Up to this point old_first_free == first_free because we have set - the batch_running flag disallowing any other thread to post any - request but we can't safely access first_free in the loop below. - This is so because it is possible that after we are done with the - last iteration and before we terminate the loop, the batch gets - finished in the IO helper thread and another thread posts a new - batch setting first_free to a higher value. If this happens and we - are using first_free in the loop termination condition then we'll - end up dispatching the same block twice from two different - threads. */ - ut_ad(old_first_free == first_free); + + ut_ad(active_slot != flush_slot); + ut_ad(flush_slot->first_free == old_first_free); + for (ulint i= 0; i < old_first_free; i++) { - auto e= buf_block_arr[i]; + auto e= flush_slot->buf_block_arr[i]; buf_page_t* bpage= e.request.bpage; ut_ad(bpage->in_file()); @@ -696,18 +704,15 @@ void buf_dblwr_t::add_to_batch(fil_space_t *space, const IORequest &request, for (;;) { - while (batch_running) - mysql_cond_wait(&cond, &mutex); - - ut_ad(first_free <= buf_size); - if (first_free != buf_size) + ut_ad(active_slot->first_free <= buf_size); + if (active_slot->first_free != buf_size) break; if (flush_buffered_writes(buf_size / 2)) mysql_mutex_lock(&mutex); } - byte *p= write_buf + srv_page_size * first_free; + byte *p= active_slot->write_buf + srv_page_size * active_slot->first_free; /* We request frame here to get correct buffer in case of encryption and/or page compression */ @@ -715,11 +720,13 @@ void buf_dblwr_t::add_to_batch(fil_space_t *space, const IORequest &request, memcpy_aligned(p, frame, size); ut_ad(!request.bpage->zip_size() || request.bpage->zip_size() == size); - ut_ad(reserved == first_free); - ut_ad(reserved < buf_size); - new (buf_block_arr + first_free++) element{space, request, size}; - reserved= first_free; + ut_ad(active_slot->reserved == active_slot->first_free); + ut_ad(active_slot->reserved < buf_size); + new (active_slot->buf_block_arr + active_slot->first_free++) + element{space, request, size}; + active_slot->reserved= active_slot->first_free; - if (first_free != buf_size || !flush_buffered_writes(buf_size / 2)) + if (active_slot->first_free != buf_size || + !flush_buffered_writes(buf_size / 2)) mysql_mutex_unlock(&mutex); } diff --git a/storage/innobase/include/buf0dblwr.h b/storage/innobase/include/buf0dblwr.h index aac4715250d..0216c3025c2 100644 --- a/storage/innobase/include/buf0dblwr.h +++ b/storage/innobase/include/buf0dblwr.h @@ -32,6 +32,29 @@ Created 2011/12/19 Inaam Rana /** Doublewrite control struct */ class buf_dblwr_t { + struct element + { + /** tablespace */ + fil_space_t *space; + /** asynchronous write request */ + IORequest request; + /** payload size in bytes */ + size_t size; + }; + + struct slot + { + /** first free position in write_buf measured in units of + * srv_page_size */ + ulint first_free; + /** number of slots reserved for the current write batch */ + ulint reserved; + /** the doublewrite buffer, aligned to srv_page_size */ + byte* write_buf; + /** buffer blocks to be written via write_buf */ + element* buf_block_arr; + }; + /** the page number of the first doublewrite block (block_size() pages) */ page_id_t block1= page_id_t(0, 0); /** the page number of the second doublewrite block (block_size() pages) */ @@ -43,25 +66,10 @@ class buf_dblwr_t mysql_cond_t cond; /** whether a batch is being written from the doublewrite buffer */ bool batch_running; - /** first free position in write_buf measured in units of srv_page_size */ - ulint first_free; - /** number of slots reserved for the current write batch */ - ulint reserved; - /** the doublewrite buffer, aligned to srv_page_size */ - byte *write_buf; - struct element - { - /** tablespace */ - fil_space_t *space; - /** asynchronous write request */ - IORequest request; - /** payload size in bytes */ - size_t size; - }; + slot slots[2]; + slot *active_slot=&slots[0]; - /** buffer blocks to be written via write_buf */ - element *buf_block_arr; /** Initialize the doublewrite buffer data structure. @param header doublewrite page header in the TRX_SYS page */ From a5a2ef079cec378340d8b575aef05974b0b3442e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 23 Oct 2020 12:53:40 +0300 Subject: [PATCH 244/323] MDEV-23855: Implement asynchronous doublewrite Synchronous writes and calls to fdatasync(), fsync() or FlushFileBuffers() would ruin performance. So, let us submit asynchronous writes for the doublewrite buffer. We submit a single request for the likely case that the two doublewrite buffers are contiquous in the system tablespace. buf_dblwr_t::flush_buffered_writes_completed(): The completion callback of buf_dblwr_t::flush_buffered_writes(). os_aio_wait_until_no_pending_writes(): Also wait for doublewrite batches. buf_dblwr_t::element::space: Remove. We can simply use element::request.node->space instead. Reviewed by: Vladislav Vaintroub --- storage/innobase/buf/buf0dblwr.cc | 86 +++++++++++++++++----------- storage/innobase/buf/buf0flu.cc | 2 +- storage/innobase/fil/fil0fil.cc | 8 ++- storage/innobase/include/buf0dblwr.h | 28 ++++++--- storage/innobase/include/os0file.h | 2 + storage/innobase/os/os0file.cc | 15 ++++- 6 files changed, 93 insertions(+), 48 deletions(-) diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index 81c934faf4f..a8ae3e2782a 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -570,6 +570,7 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size) } ut_ad(active_slot->reserved == active_slot->first_free); + ut_ad(!flushing_buffered_writes); /* Disallow anyone else to start another batch of flushing. */ slot *flush_slot= active_slot; @@ -579,7 +580,9 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size) batch_running= true; const ulint old_first_free= flush_slot->first_free; auto write_buf= flush_slot->write_buf; - + const bool multi_batch= block1 + static_cast(size) != block2 && + old_first_free > size; + flushing_buffered_writes= 1 + multi_batch; /* Now safe to release the mutex. */ mysql_mutex_unlock(&mutex); #ifdef UNIV_DEBUG @@ -597,25 +600,48 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size) ut_d(buf_dblwr_check_page_lsn(*bpage, write_buf + len2)); } #endif /* UNIV_DEBUG */ - /* Write out the first block of the doublewrite buffer */ + const IORequest request(nullptr, fil_system.sys_space->chain.start, + IORequest::DBLWR_BATCH); ut_a(fil_system.sys_space->acquire()); - fil_system.sys_space->io(IORequestWrite, - os_offset_t{block1.page_no()} << - srv_page_size_shift, - std::min(size, old_first_free) << - srv_page_size_shift, write_buf); - - if (old_first_free > size) + if (multi_batch) { - /* Write out the second block of the doublewrite buffer. */ - ut_a(fil_system.sys_space->acquire()); - fil_system.sys_space->io(IORequestWrite, - os_offset_t{block2.page_no()} << - srv_page_size_shift, - (old_first_free - size) << srv_page_size_shift, - write_buf + (size << srv_page_size_shift)); + fil_system.sys_space->reacquire(); + os_aio(request, write_buf, + os_offset_t{block1.page_no()} << srv_page_size_shift, + size << srv_page_size_shift); + os_aio(request, write_buf + (size << srv_page_size_shift), + os_offset_t{block2.page_no()} << srv_page_size_shift, + (old_first_free - size) << srv_page_size_shift); } + else + os_aio(request, write_buf, + os_offset_t{block1.page_no()} << srv_page_size_shift, + old_first_free << srv_page_size_shift); + srv_stats.data_written.add(old_first_free); + return true; +} +void buf_dblwr_t::flush_buffered_writes_completed(const IORequest &request) +{ + ut_ad(this == &buf_dblwr); + ut_ad(srv_use_doublewrite_buf); + ut_ad(is_initialised()); + ut_ad(!srv_read_only_mode); + ut_ad(!request.bpage); + ut_ad(request.node == fil_system.sys_space->chain.start); + ut_ad(request.type == IORequest::DBLWR_BATCH); + mysql_mutex_lock(&mutex); + ut_ad(batch_running); + ut_ad(flushing_buffered_writes); + ut_ad(flushing_buffered_writes <= 2); + const bool completed= !--flushing_buffered_writes; + mysql_mutex_unlock(&mutex); + + if (!completed) + return; + + slot *const flush_slot= active_slot == &slots[0] ? &slots[1] : &slots[0]; + ut_ad(flush_slot->reserved == flush_slot->first_free); /* increment the doublewrite flushed pages counter */ srv_stats.dblwr_pages_written.add(flush_slot->first_free); srv_stats.dblwr_writes.inc(); @@ -623,15 +649,9 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size) /* Now flush the doublewrite buffer data to disk */ fil_system.sys_space->flush(); - /* We know that the writes have been flushed to disk now - and in recovery we will find them in the doublewrite buffer - blocks. Next do the writes to the intended positions. */ - - - ut_ad(active_slot != flush_slot); - ut_ad(flush_slot->first_free == old_first_free); - - for (ulint i= 0; i < old_first_free; i++) + /* The writes have been flushed to disk now and in recovery we will + find them in the doublewrite buffer blocks. Next, write the data pages. */ + for (ulint i= 0, first_free= flush_slot->first_free; i < first_free; i++) { auto e= flush_slot->buf_block_arr[i]; buf_page_t* bpage= e.request.bpage; @@ -655,10 +675,9 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size) ut_d(buf_dblwr_check_page_lsn(*bpage, static_cast(frame))); } - e.space->io(e.request, bpage->physical_offset(), e_size, frame, bpage); + e.request.node->space->io(e.request, bpage->physical_offset(), e_size, + frame, bpage); } - - return true; } /** Flush possible buffered writes to persistent storage. @@ -684,18 +703,17 @@ void buf_dblwr_t::flush_buffered_writes() /** Schedule a page write. If the doublewrite memory buffer is full, flush_buffered_writes() will be invoked to make space. -@param space tablespace @param request asynchronous write request @param size payload size in bytes */ -void buf_dblwr_t::add_to_batch(fil_space_t *space, const IORequest &request, - size_t size) +void buf_dblwr_t::add_to_batch(const IORequest &request, size_t size) { ut_ad(request.is_async()); ut_ad(request.is_write()); ut_ad(request.bpage); ut_ad(request.bpage->in_file()); - ut_ad(space->id == request.bpage->id().space()); - ut_ad(space->referenced()); + ut_ad(request.node); + ut_ad(request.node->space->id == request.bpage->id().space()); + ut_ad(request.node->space->referenced()); ut_ad(!srv_read_only_mode); const ulint buf_size= 2 * block_size(); @@ -723,7 +741,7 @@ void buf_dblwr_t::add_to_batch(fil_space_t *space, const IORequest &request, ut_ad(active_slot->reserved == active_slot->first_free); ut_ad(active_slot->reserved < buf_size); new (active_slot->buf_block_arr + active_slot->first_free++) - element{space, request, size}; + element{request, size}; active_slot->reserved= active_slot->first_free; if (active_slot->first_free != buf_size || diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 7910ca68357..22b5bec0520 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -921,7 +921,7 @@ static bool buf_flush_page(buf_page_t *bpage, bool lru, fil_space_t *space) space->io(IORequest(type, bpage), bpage->physical_offset(), size, frame, bpage); else - buf_dblwr.add_to_batch(space, IORequest(type, bpage), size); + buf_dblwr.add_to_batch(IORequest(bpage, space->chain.start, type), size); } /* Increment the I/O operation count used for selecting LRU policy. */ diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 1d170117a12..97595909f24 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -3355,11 +3355,12 @@ fil_io_t fil_space_t::io(const IORequest &type, os_offset_t offset, size_t len, ut_ad(offset % OS_FILE_LOG_BLOCK_SIZE == 0); ut_ad((len % OS_FILE_LOG_BLOCK_SIZE) == 0); ut_ad(fil_validate_skip()); + ut_ad(type.is_read() || type.is_write()); + ut_ad(type.type != IORequest::DBLWR_BATCH); if (type.is_read()) { srv_stats.data_read.add(len); } else { - ut_ad(type.is_write() || type.type == IORequest::PUNCH_RANGE); ut_ad(!srv_read_only_mode || this == fil_system.temp_space); srv_stats.data_written.add(len); } @@ -3457,7 +3458,10 @@ void fil_aio_callback(const IORequest &request) if (!request.bpage) { ut_ad(!srv_read_only_mode); - ut_ad(request.type == IORequest::WRITE_ASYNC); + if (request.type == IORequest::DBLWR_BATCH) + buf_dblwr.flush_buffered_writes_completed(request); + else + ut_ad(request.type == IORequest::WRITE_ASYNC); write_completed: request.node->complete_write(); } diff --git a/storage/innobase/include/buf0dblwr.h b/storage/innobase/include/buf0dblwr.h index 0216c3025c2..47517adc40b 100644 --- a/storage/innobase/include/buf0dblwr.h +++ b/storage/innobase/include/buf0dblwr.h @@ -34,8 +34,6 @@ class buf_dblwr_t { struct element { - /** tablespace */ - fil_space_t *space; /** asynchronous write request */ IORequest request; /** payload size in bytes */ @@ -66,10 +64,11 @@ class buf_dblwr_t mysql_cond_t cond; /** whether a batch is being written from the doublewrite buffer */ bool batch_running; + /** number of expected flush_buffered_writes_completed() calls */ + unsigned flushing_buffered_writes; slot slots[2]; - slot *active_slot=&slots[0]; - + slot *active_slot= &slots[0]; /** Initialize the doublewrite buffer data structure. @param header doublewrite page header in the TRX_SYS page */ @@ -98,24 +97,25 @@ public: /** Process and remove the double write buffer pages for all tablespaces. */ void recover(); - /** Update the doublewrite buffer on write completion. */ + /** Update the doublewrite buffer on data page write completion. */ void write_completed(); /** Flush possible buffered writes to persistent storage. It is very important to call this function after a batch of writes has been posted, and also when we may have to wait for a page latch! Otherwise a deadlock of threads can occur. */ void flush_buffered_writes(); + /** Update the doublewrite buffer on write batch completion + @param request the completed batch write request */ + void flush_buffered_writes_completed(const IORequest &request); /** Size of the doublewrite block in pages */ uint32_t block_size() const { return FSP_EXTENT_SIZE; } /** Schedule a page write. If the doublewrite memory buffer is full, flush_buffered_writes() will be invoked to make space. - @param space tablespace @param request asynchronous write request @param size payload size in bytes */ - void add_to_batch(fil_space_t *space, const IORequest &request, - size_t size) MY_ATTRIBUTE((nonnull)); + void add_to_batch(const IORequest &request, size_t size); /** Determine whether the doublewrite buffer is initialized */ bool is_initialised() const @@ -132,6 +132,18 @@ public: const uint32_t size= block_size(); return id < block1 + size || (id >= block2 && id < block2 + size); } + + /** Wait for flush_buffered_writes() to be fully completed */ + void wait_flush_buffered_writes() + { + if (is_initialised()) + { + mysql_mutex_lock(&mutex); + while (batch_running) + mysql_cond_wait(&cond, &mutex); + mysql_mutex_unlock(&mutex); + } + } }; /** The doublewrite buffer */ diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index dfc6d7568fc..5e0039304b0 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -198,6 +198,8 @@ public: WRITE_SYNC= 16, /** Asynchronous write */ WRITE_ASYNC= WRITE_SYNC | 1, + /** A doublewrite batch */ + DBLWR_BATCH= WRITE_ASYNC | 8, /** Write data; evict the block on write completion */ WRITE_LRU= WRITE_ASYNC | 32, /** Write data and punch hole for the rest */ diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 6f428150291..3afb68d26a1 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -78,6 +78,8 @@ Created 10/21/1995 Heikki Tuuri #include #endif +#include "buf0dblwr.h" + #include #include @@ -4041,9 +4043,8 @@ void os_aio_free() write_slots= nullptr; } -/** Waits until there are no pending writes. There can -be other, synchronous, pending writes. */ -void os_aio_wait_until_no_pending_writes() +/** Wait until there are no pending asynchronous writes. */ +static void os_aio_wait_until_no_pending_writes_low() { bool notify_wait = write_slots->pending_io_count() > 0; @@ -4056,6 +4057,14 @@ void os_aio_wait_until_no_pending_writes() tpool::tpool_wait_end(); } +/** Waits until there are no pending writes. There can +be other, synchronous, pending writes. */ +void os_aio_wait_until_no_pending_writes() +{ + os_aio_wait_until_no_pending_writes_low(); + buf_dblwr.wait_flush_buffered_writes(); +} + /** Request a read or write. @param type I/O request @param buf buffer From c27e53f45992d0b0b5eb5ff6242cfe1a78eba8b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 26 Oct 2020 16:43:52 +0200 Subject: [PATCH 245/323] MDEV-23855: Use normal mutex for log_sys.mutex, log_sys.flush_order_mutex With an unreasonably small innodb_log_file_size, the page cleaner thread would frequently acquire log_sys.flush_order_mutex and spend a significant portion of CPU time spinning on that mutex when determining the checkpoint LSN. --- extra/mariabackup/xtrabackup.cc | 24 +++++----- storage/innobase/buf/buf0flu.cc | 36 +++++++-------- storage/innobase/fil/fil0fil.cc | 22 ++++----- storage/innobase/include/fil0fil.h | 2 +- storage/innobase/include/log0log.h | 63 +++++++++----------------- storage/innobase/include/log0log.ic | 2 +- storage/innobase/include/mtr0mtr.h | 2 +- storage/innobase/include/sync0types.h | 4 -- storage/innobase/log/log0log.cc | 64 +++++++++++++-------------- storage/innobase/log/log0recv.cc | 48 ++++++++++---------- storage/innobase/mtr/mtr0mtr.cc | 28 ++++++------ storage/innobase/srv/srv0mon.cc | 12 ++--- storage/innobase/srv/srv0srv.cc | 4 +- storage/innobase/srv/srv0start.cc | 12 ++--- storage/innobase/sync/sync0debug.cc | 9 ---- 15 files changed, 149 insertions(+), 183 deletions(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index c05677b8810..b63e50474ca 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -2711,7 +2711,7 @@ static bool xtrabackup_copy_logfile(bool last = false) xtrabackup_io_throttling(); - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); lsn_t lsn= start_lsn; for (int retries= 0; retries < 100; retries++) { if (log_sys.log.read_log_seg(&lsn, end_lsn) @@ -2735,7 +2735,7 @@ static bool xtrabackup_copy_logfile(bool last = false) mutex_exit(&recv_sys.mutex); } - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); if (!start_lsn) { const char *reason = recv_sys.found_corrupt_log @@ -2795,10 +2795,10 @@ static os_thread_ret_t DECLARE_THREAD(log_copying_thread)(void*) break; } - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); bool completed = metadata_to_lsn && metadata_to_lsn <= log_copy_scanned_lsn; - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); if (completed) { break; } @@ -3848,7 +3848,7 @@ static bool xtrabackup_backup_low() { ulint max_cp_field; - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); if (recv_find_max_checkpoint(&max_cp_field) == DB_SUCCESS && log_sys.log.format != 0) { @@ -3865,7 +3865,7 @@ static bool xtrabackup_backup_low() } else { msg("Error: recv_find_max_checkpoint() failed."); } - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); } stop_backup_threads(); @@ -4037,20 +4037,20 @@ fail: /* get current checkpoint_lsn */ /* Look for the latest checkpoint from any of the log groups */ - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); reread_log_header: dberr_t err = recv_find_max_checkpoint(&max_cp_field); if (err != DB_SUCCESS) { msg("Error: cannot read redo log header"); - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); goto fail; } if (log_sys.log.format == 0) { msg("Error: cannot process redo log before MariaDB 10.2.2"); - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); goto fail; } @@ -4067,7 +4067,7 @@ reread_log_header: != mach_read_from_8(buf + LOG_CHECKPOINT_OFFSET)) goto reread_log_header; - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); xtrabackup_init_datasinks(); @@ -4603,7 +4603,7 @@ xb_delta_open_matching_space( return OS_FILE_CLOSED; } - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); if (!fil_is_user_tablespace_id(info.space_id)) { found: /* open the file and return its handle */ @@ -4616,7 +4616,7 @@ found: msg("mariabackup: Cannot open file %s\n", real_name); } exit: - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return file; } diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 22b5bec0520..cc2f4c36fa4 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -132,7 +132,7 @@ static void buf_flush_validate_skip() void buf_flush_insert_into_flush_list(buf_block_t* block, lsn_t lsn) { mysql_mutex_assert_not_owner(&buf_pool.mutex); - ut_ad(log_flush_order_mutex_own()); + mysql_mutex_assert_owner(&log_sys.flush_order_mutex); ut_ad(lsn); mysql_mutex_lock(&buf_pool.flush_list_mutex); @@ -1564,7 +1564,7 @@ ulint buf_flush_lists(ulint max_n, lsn_t lsn) static bool log_checkpoint_low(lsn_t oldest_lsn, lsn_t end_lsn) { ut_ad(!srv_read_only_mode); - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); ut_ad(oldest_lsn <= end_lsn); ut_ad(end_lsn == log_sys.get_lsn()); ut_ad(!recv_no_log_write); @@ -1581,7 +1581,7 @@ static bool log_checkpoint_low(lsn_t oldest_lsn, lsn_t end_lsn) { /* Do nothing, because nothing was logged (other than a FILE_CHECKPOINT record) since the previous checkpoint. */ - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return true; } @@ -1602,12 +1602,12 @@ static bool log_checkpoint_low(lsn_t oldest_lsn, lsn_t end_lsn) { flush_lsn= log_sys.get_lsn(); ut_ad(flush_lsn >= end_lsn + SIZE_OF_FILE_CHECKPOINT); - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); log_write_up_to(flush_lsn, true, true); - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); if (log_sys.last_checkpoint_lsn >= oldest_lsn) { - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return true; } } @@ -1619,13 +1619,13 @@ static bool log_checkpoint_low(lsn_t oldest_lsn, lsn_t end_lsn) if (log_sys.n_pending_checkpoint_writes) { /* A checkpoint write is running */ - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return false; } log_sys.next_checkpoint_lsn= oldest_lsn; log_write_checkpoint_info(end_lsn); - ut_ad(!log_mutex_own()); + mysql_mutex_assert_not_owner(&log_sys.mutex); return true; } @@ -1649,13 +1649,13 @@ static bool log_checkpoint() fil_flush_file_spaces(); } - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); const lsn_t end_lsn= log_sys.get_lsn(); - log_flush_order_mutex_enter(); + mysql_mutex_lock(&log_sys.flush_order_mutex); mysql_mutex_lock(&buf_pool.flush_list_mutex); const lsn_t oldest_lsn= buf_pool.get_oldest_modification(end_lsn); mysql_mutex_unlock(&buf_pool.flush_list_mutex); - log_flush_order_mutex_exit(); + mysql_mutex_unlock(&log_sys.flush_order_mutex); return log_checkpoint_low(oldest_lsn, end_lsn); } @@ -1672,7 +1672,7 @@ ATTRIBUTE_COLD void buf_flush_wait_flushed(lsn_t sync_lsn) { ut_ad(sync_lsn); ut_ad(sync_lsn < LSN_MAX); - ut_ad(!log_mutex_own()); + mysql_mutex_assert_not_owner(&log_sys.mutex); ut_ad(!srv_read_only_mode); if (recv_recovery_is_on()) @@ -1732,7 +1732,7 @@ ATTRIBUTE_COLD void buf_flush_wait_flushed(lsn_t sync_lsn) @param lsn buf_pool.get_oldest_modification(LSN_MAX) target */ void buf_flush_ahead(lsn_t lsn) { - ut_ad(!log_mutex_own()); + mysql_mutex_assert_not_owner(&log_sys.mutex); ut_ad(!srv_read_only_mode); if (recv_recovery_is_on()) @@ -1792,12 +1792,12 @@ ATTRIBUTE_COLD static void buf_flush_sync_for_checkpoint(lsn_t lsn) fil_flush_file_spaces(); } - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); const lsn_t newest_lsn= log_sys.get_lsn(); - log_flush_order_mutex_enter(); + mysql_mutex_lock(&log_sys.flush_order_mutex); mysql_mutex_lock(&buf_pool.flush_list_mutex); lsn_t measure= buf_pool.get_oldest_modification(0); - log_flush_order_mutex_exit(); + mysql_mutex_unlock(&log_sys.flush_order_mutex); const lsn_t checkpoint_lsn= measure ? measure : newest_lsn; if (checkpoint_lsn > log_sys.last_checkpoint_lsn + SIZE_OF_FILE_CHECKPOINT) @@ -1809,12 +1809,12 @@ ATTRIBUTE_COLD static void buf_flush_sync_for_checkpoint(lsn_t lsn) } else { - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); if (!measure) measure= LSN_MAX; } - ut_ad(!log_mutex_own()); + mysql_mutex_assert_not_owner(&log_sys.mutex); /* After attempting log checkpoint, check if we have reached our target. */ const lsn_t target= buf_flush_sync_lsn; diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 97595909f24..d234fed4e89 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -885,10 +885,10 @@ fil_space_free( } if (!recv_recovery_is_on()) { - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); } - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); if (space->max_lsn != 0) { ut_d(space->max_lsn = 0); @@ -896,7 +896,7 @@ fil_space_free( } if (!recv_recovery_is_on()) { - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); } fil_space_free_low(space); @@ -1916,14 +1916,14 @@ dberr_t fil_delete_tablespace(ulint id, bool if_exists, } mutex_exit(&fil_system.mutex); - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); if (space->max_lsn != 0) { ut_d(space->max_lsn = 0); UT_LIST_REMOVE(fil_system.named_spaces, space); } - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); fil_space_free_low(space); if (!os_file_delete(innodb_data_file_key, path) @@ -2204,11 +2204,11 @@ fil_rename_tablespace( if (!recv_recovery_is_on()) { fil_name_write_rename(id, old_file_name, new_file_name); - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); } /* log_sys.mutex is above fil_system.mutex in the latching order */ - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); mutex_enter(&fil_system.mutex); space->release(); ut_ad(space->name == old_space_name); @@ -2230,7 +2230,7 @@ skip_second_rename: } if (!recv_recovery_is_on()) { - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); } ut_ad(space->name == old_space_name); @@ -3667,7 +3667,7 @@ void fil_names_dirty( fil_space_t* space) { - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); ut_ad(recv_recovery_is_on()); ut_ad(log_sys.get_lsn() != 0); ut_ad(space->max_lsn == 0); @@ -3683,7 +3683,7 @@ fil_names_clear(). @param[in,out] space tablespace */ void fil_names_dirty_and_write(fil_space_t* space) { - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); ut_d(fil_space_validate_for_mtr_commit(space)); ut_ad(space->max_lsn == log_sys.get_lsn()); @@ -3724,7 +3724,7 @@ fil_names_clear( mtr_checkpoint_size = 75 * 1024; ); - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); ut_ad(lsn); mtr.start(); diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index a980c21ead0..e645ce31232 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -1780,7 +1780,7 @@ for the first time since the latest fil_names_clear(). @return whether any FILE_MODIFY record was written */ inline bool fil_names_write_if_was_clean(fil_space_t* space) { - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); if (space == NULL) { return(false); diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index b82857a8e0f..5a26b4baf7d 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -35,7 +35,6 @@ Created 12/9/1995 Heikki Tuuri #define log0log_h #include "log0types.h" -#include "ut0mutex.h" #include "os0file.h" #include "span.h" #include @@ -127,7 +126,7 @@ ATTRIBUTE_COLD void log_make_checkpoint(); /** Make a checkpoint at the latest lsn on shutdown. */ ATTRIBUTE_COLD void logs_empty_and_mark_files_at_shutdown(); -/** Write checkpoint info to the log header and invoke log_mutex_exit(). +/** Write checkpoint info to the log header and release log_sys.mutex. @param[in] end_lsn start LSN of the FILE_CHECKPOINT mini-transaction */ ATTRIBUTE_COLD void log_write_checkpoint_info(lsn_t end_lsn); @@ -349,9 +348,6 @@ or the MySQL version that created the redo log file. */ header */ #define LOG_FILE_HDR_SIZE (4 * OS_FILE_LOG_BLOCK_SIZE) -typedef ib_mutex_t LogSysMutex; -typedef ib_mutex_t FlushOrderMutex; - /** Memory mapped file */ class mapped_file_t { @@ -471,7 +467,7 @@ struct log_t{ private: /** The log sequence number of the last change of durable InnoDB files */ - MY_ALIGNED(CACHE_LINE_SIZE) + MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) std::atomic lsn; /** the first guaranteed-durable log sequence number */ std::atomic flushed_to_disk_lsn; @@ -480,10 +476,8 @@ private: This must hold if lsn - last_checkpoint_lsn > max_checkpoint_age. */ std::atomic check_flush_or_checkpoint_; public: - /** mutex protecting the log */ - MY_ALIGNED(CACHE_LINE_SIZE) - LogSysMutex mutex; + MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) mysql_mutex_t mutex; /** first free offset within the log buffer in use */ size_t buf_free; /** recommended maximum size of buf, after which the buffer is flushed */ @@ -492,8 +486,7 @@ public: dirty blocks in the list. The idea behind this mutex is to be able to release log_sys.mutex during mtr_commit and still ensure that insertions in the flush_list happen in the LSN order. */ - MY_ALIGNED(CACHE_LINE_SIZE) FlushOrderMutex - log_flush_order_mutex; + MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) mysql_mutex_t flush_order_mutex; /** log_buffer, append data here */ byte *buf; /** log_buffer, writing data to file from this buffer. @@ -736,7 +729,9 @@ inline lsn_t log_t::file::calc_lsn_offset(lsn_t lsn) const ut_ad(this == &log_sys.log); /* The lsn parameters are updated while holding both the mutexes and it is ok to have either of them while reading */ - ut_ad(log_sys.mutex.is_owned() || log_write_lock_own()); +#ifdef SAFE_MUTEX + ut_ad(mysql_mutex_is_owner(&log_sys.mutex) || log_write_lock_own()); +#endif /* SAFE_MUTEX */ const lsn_t size = capacity(); lsn_t l= lsn - this->lsn; if (longlong(l) < 0) { @@ -749,41 +744,23 @@ inline lsn_t log_t::file::calc_lsn_offset(lsn_t lsn) const return l + LOG_FILE_HDR_SIZE * (1 + l / (file_size - LOG_FILE_HDR_SIZE)); } -inline void log_t::file::set_lsn(lsn_t a_lsn) { - ut_ad(log_sys.mutex.is_owned() || log_write_lock_own()); - lsn = a_lsn; +inline void log_t::file::set_lsn(lsn_t a_lsn) +{ +#ifdef SAFE_MUTEX + ut_ad(mysql_mutex_is_owner(&log_sys.mutex) || log_write_lock_own()); +#endif /* SAFE_MUTEX */ + lsn= a_lsn; } -inline void log_t::file::set_lsn_offset(lsn_t a_lsn) { - ut_ad(log_sys.mutex.is_owned() || log_write_lock_own()); - ut_ad((lsn % OS_FILE_LOG_BLOCK_SIZE) == (a_lsn % OS_FILE_LOG_BLOCK_SIZE)); - lsn_offset = a_lsn; +inline void log_t::file::set_lsn_offset(lsn_t a_lsn) +{ +#ifdef SAFE_MUTEX + ut_ad(mysql_mutex_is_owner(&log_sys.mutex) || log_write_lock_own()); +#endif /* SAFE_MUTEX */ + ut_ad((lsn % OS_FILE_LOG_BLOCK_SIZE) == (a_lsn % OS_FILE_LOG_BLOCK_SIZE)); + lsn_offset= a_lsn; } -/** Test if flush order mutex is owned. */ -#define log_flush_order_mutex_own() \ - mutex_own(&log_sys.log_flush_order_mutex) - -/** Acquire the flush order mutex. */ -#define log_flush_order_mutex_enter() do { \ - mutex_enter(&log_sys.log_flush_order_mutex); \ -} while (0) -/** Release the flush order mutex. */ -# define log_flush_order_mutex_exit() do { \ - mutex_exit(&log_sys.log_flush_order_mutex); \ -} while (0) - -/** Test if log sys mutex is owned. */ -#define log_mutex_own() mutex_own(&log_sys.mutex) - - -/** Acquire the log sys mutex. */ -#define log_mutex_enter() mutex_enter(&log_sys.mutex) - - -/** Release the log sys mutex. */ -#define log_mutex_exit() mutex_exit(&log_sys.mutex) - #include "log0log.ic" #endif diff --git a/storage/innobase/include/log0log.ic b/storage/innobase/include/log0log.ic index d7232bc5944..d503e3ffec9 100644 --- a/storage/innobase/include/log0log.ic +++ b/storage/innobase/include/log0log.ic @@ -255,7 +255,7 @@ log_reserve_and_write_fast( ulint len, lsn_t* start_lsn) { - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); ut_ad(len > 0); const ulint data_len = len diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 72eadc60ae8..cf8f37c3fa5 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -106,7 +106,7 @@ struct mtr_t { /** Commit a mini-transaction that did not modify any pages, but generated some redo log on a higher level, such as FILE_MODIFY records and an optional FILE_CHECKPOINT marker. - The caller must invoke log_mutex_enter() and log_mutex_exit(). + The caller must hold log_sys.mutex. This is to be used at log_checkpoint(). @param checkpoint_lsn the log sequence number of a checkpoint, or 0 */ void commit_files(lsn_t checkpoint_lsn= 0); diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h index f0168bd1c27..feb1e3b45ef 100644 --- a/storage/innobase/include/sync0types.h +++ b/storage/innobase/include/sync0types.h @@ -199,8 +199,6 @@ enum latch_level_t { SYNC_FTS_OPTIMIZE, SYNC_FTS_CACHE_INIT, SYNC_RECV, - SYNC_LOG_FLUSH_ORDER, - SYNC_LOG, SYNC_PURGE_QUEUE, SYNC_TRX_SYS_HEADER, SYNC_TRX, @@ -271,8 +269,6 @@ enum latch_id_t { LATCH_ID_IBUF_BITMAP, LATCH_ID_IBUF, LATCH_ID_IBUF_PESSIMISTIC_INSERT, - LATCH_ID_LOG_SYS, - LATCH_ID_LOG_FLUSH_ORDER, LATCH_ID_PURGE_SYS_PQ, LATCH_ID_RECALC_POOL, LATCH_ID_RECV_SYS, diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 472e39130c3..e65498321e4 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -50,6 +50,7 @@ Created 12/9/1995 Heikki Tuuri #include "trx0trx.h" #include "trx0roll.h" #include "srv0mon.h" +#include "sync0sync.h" #include "buf0dump.h" #include "log0sync.h" @@ -83,11 +84,11 @@ void log_buffer_extend(ulong len) (ut_malloc_dontdump(new_buf_size, PSI_INSTRUMENT_ME)); TRASH_ALLOC(new_flush_buf, new_buf_size); - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); if (len <= srv_log_buffer_size) { /* Already extended enough by the others */ - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); ut_free_dodump(new_buf, new_buf_size); ut_free_dodump(new_flush_buf, new_buf_size); return; @@ -109,7 +110,7 @@ void log_buffer_extend(ulong len) log_sys.max_buf_free = new_buf_size / LOG_BUF_FLUSH_RATIO - LOG_BUF_FLUSH_MARGIN; - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); ut_free_dodump(old_buf, old_buf_size); ut_free_dodump(old_flush_buf, old_buf_size); @@ -158,14 +159,14 @@ log_set_capacity(ulonglong file_size) margin = smallest_capacity - free; margin = margin - margin / 10; /* Add still some extra safety */ - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); log_sys.log_capacity = smallest_capacity; log_sys.max_modified_age_async = margin - margin / 8; log_sys.max_checkpoint_age = margin; - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return(true); } @@ -177,8 +178,8 @@ void log_t::create() ut_ad(!is_initialised()); m_initialised= true; - mutex_create(LATCH_ID_LOG_SYS, &mutex); - mutex_create(LATCH_ID_LOG_FLUSH_ORDER, &log_flush_order_mutex); + mysql_mutex_init(log_sys_mutex_key, &mutex, nullptr); + mysql_mutex_init(log_flush_order_mutex_key, &flush_order_mutex, nullptr); /* Start the lsn from one log block from zero: this way every log record has a non-zero start lsn, a fact which we will use */ @@ -622,7 +623,7 @@ loop: } /** Flush the recently written changes to the log file. -and invoke log_mutex_enter(). */ +and invoke mysql_mutex_lock(&log_sys.mutex). */ static void log_write_flush_to_disk_low(lsn_t lsn) { if (!log_sys.log.writes_are_durable()) @@ -638,7 +639,7 @@ static inline void log_buffer_switch() { - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); ut_ad(log_write_lock_own()); size_t area_end = ut_calc_align( @@ -662,18 +663,18 @@ which is the "write" part of log_write_up_to(). This function does not flush anything. -Note : the caller must have log_mutex locked, and this +Note : the caller must have log_sys.mutex locked, and this mutex is released in the function. */ static void log_write(bool rotate_key) { - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); ut_ad(!recv_no_log_write); lsn_t write_lsn; if (log_sys.buf_free == log_sys.buf_next_to_write) { /* Nothing to write */ - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return; } @@ -710,7 +711,7 @@ static void log_write(bool rotate_key) log_sys.log.set_fields(log_sys.write_lsn); - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); /* Erase the end of the last log block. */ memset(write_buf + end_offset, 0, ~end_offset & (OS_FILE_LOG_BLOCK_SIZE - 1)); @@ -801,7 +802,7 @@ void log_write_up_to(lsn_t lsn, bool flush_to_disk, bool rotate_key) if (write_lock.acquire(lsn) == group_commit_lock::ACQUIRED) { - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); lsn_t write_lsn= log_sys.get_lsn(); write_lock.set_pending(write_lsn); @@ -844,25 +845,24 @@ ATTRIBUTE_COLD static void log_flush_margin() { lsn_t lsn = 0; - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); if (log_sys.buf_free > log_sys.max_buf_free) { /* We can write during flush */ lsn = log_sys.get_lsn(); } - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); if (lsn) { log_write_up_to(lsn, false); } } -/** Write checkpoint info to the log header and invoke log_mutex_exit(). +/** Write checkpoint info to the log header and release log_sys.mutex. @param[in] end_lsn start LSN of the FILE_CHECKPOINT mini-transaction */ ATTRIBUTE_COLD void log_write_checkpoint_info(lsn_t end_lsn) { - ut_ad(log_mutex_own()); ut_ad(!srv_read_only_mode); ut_ad(end_lsn == 0 || end_lsn >= log_sys.next_checkpoint_lsn); ut_ad(end_lsn <= log_sys.get_lsn()); @@ -898,7 +898,7 @@ ATTRIBUTE_COLD void log_write_checkpoint_info(lsn_t end_lsn) ++log_sys.n_pending_checkpoint_writes; - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); /* Note: We alternate the physical place of the checkpoint info. See the (next_checkpoint_no & 1) below. */ @@ -909,7 +909,7 @@ ATTRIBUTE_COLD void log_write_checkpoint_info(lsn_t end_lsn) log_sys.log.flush(); - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); --log_sys.n_pending_checkpoint_writes; ut_ad(log_sys.n_pending_checkpoint_writes == 0); @@ -927,7 +927,7 @@ ATTRIBUTE_COLD void log_write_checkpoint_info(lsn_t end_lsn) DBUG_EXECUTE_IF("crash_after_checkpoint", DBUG_SUICIDE();); - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); } /****************************************************************//** @@ -939,13 +939,13 @@ ATTRIBUTE_COLD static void log_checkpoint_margin() { while (log_sys.check_flush_or_checkpoint()) { - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); ut_ad(!recv_no_log_write); if (!log_sys.check_flush_or_checkpoint()) { func_exit: - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return; } @@ -958,7 +958,7 @@ func_exit: goto func_exit; } - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); /* We must wait to prevent the tail of the log overwriting the head. */ buf_flush_wait_flushed(std::min(sync_lsn, checkpoint + (1U << 20))); @@ -1108,10 +1108,10 @@ wait_suspend_loop: } if (log_sys.is_initialised()) { - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); const ulint n_write = log_sys.n_pending_checkpoint_writes; const ulint n_flush = log_sys.pending_flushes; - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); if (n_write || n_flush) { if (srv_print_verbose_log && count > 600) { @@ -1154,7 +1154,7 @@ wait_suspend_loop: "ensuring dirty buffer pool are written to log"); log_make_checkpoint(); - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); lsn = log_sys.get_lsn(); @@ -1163,7 +1163,7 @@ wait_suspend_loop: + SIZE_OF_FILE_CHECKPOINT; ut_ad(lsn >= log_sys.last_checkpoint_lsn); - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); if (lsn_changed) { goto loop; @@ -1220,7 +1220,7 @@ log_print( double time_elapsed; time_t current_time; - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); const lsn_t lsn= log_sys.get_lsn(); mysql_mutex_lock(&buf_pool.flush_list_mutex); @@ -1260,7 +1260,7 @@ log_print( log_sys.n_log_ios_old = log_sys.n_log_ios; log_sys.last_printout_time = current_time; - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); } /**********************************************************************//** @@ -1286,8 +1286,8 @@ void log_t::close() ut_free_dodump(flush_buf, srv_log_buffer_size); flush_buf = NULL; - mutex_free(&mutex); - mutex_free(&log_flush_order_mutex); + mysql_mutex_destroy(&mutex); + mysql_mutex_destroy(&flush_order_mutex); recv_sys.close(); } diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 8eeadc8e805..c5cf21bf59a 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -1086,7 +1086,7 @@ bool log_t::file::read_log_seg(lsn_t* start_lsn, lsn_t end_lsn) { ulint len; bool success = true; - ut_ad(log_sys.mutex.is_owned()); + mysql_mutex_assert_owner(&log_sys.mutex); ut_ad(!(*start_lsn % OS_FILE_LOG_BLOCK_SIZE)); ut_ad(!(end_lsn % OS_FILE_LOG_BLOCK_SIZE)); byte* buf = log_sys.buf; @@ -1209,7 +1209,7 @@ recv_synchronize_groups() if (!srv_read_only_mode) { log_write_checkpoint_info(0); - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); } } @@ -1739,7 +1739,7 @@ static void store_freed_or_init_rec(page_id_t page_id, bool freed) or corruption was noticed */ bool recv_sys_t::parse(lsn_t checkpoint_lsn, store_t *store, bool apply) { - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); ut_ad(mutex_own(&mutex)); ut_ad(parse_start_lsn); ut_ad(log_sys.is_physical()); @@ -2378,9 +2378,9 @@ set_start_lsn: } buf_block_modify_clock_inc(block); - log_flush_order_mutex_enter(); + mysql_mutex_lock(&log_sys.flush_order_mutex); buf_flush_note_modification(block, start_lsn, end_lsn); - log_flush_order_mutex_exit(); + mysql_mutex_unlock(&log_sys.flush_order_mutex); } else if (free_page && init) { /* There have been no operations that modify the page. Any buffered changes must not be merged. A subsequent @@ -2599,7 +2599,9 @@ void recv_sys_t::apply(bool last_batch) mutex_enter(&mutex); } - ut_ad(!last_batch == log_mutex_own()); +#ifdef SAFE_MUTEX + DBUG_ASSERT(!last_batch == mysql_mutex_is_owner(&log_sys.mutex)); +#endif /* SAFE_MUTEX */ recv_no_ibuf_operations = !last_batch || srv_operation == SRV_OPERATION_RESTORE || @@ -2703,10 +2705,10 @@ next_page: else { mlog_init.reset(); - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); } - ut_ad(!log_mutex_own()); + mysql_mutex_assert_not_owner(&log_sys.mutex); mutex_exit(&mutex); /* Instead of flushing, last_batch could sort the buf_pool.flush_list @@ -2716,7 +2718,7 @@ next_page: if (!last_batch) { buf_pool_invalidate(); - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); } mutex_enter(&mutex); @@ -3305,14 +3307,14 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) recv_sys.recovery_on = true; - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); err = recv_find_max_checkpoint(&max_cp_field); if (err != DB_SUCCESS) { recv_sys.recovered_lsn = log_sys.get_lsn(); - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return(err); } @@ -3336,7 +3338,7 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) contiguous_lsn = checkpoint_lsn; switch (log_sys.log.format) { case 0: - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return DB_SUCCESS; default: if (end_lsn == 0) { @@ -3347,7 +3349,7 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) break; } recv_sys.found_corrupt_log = true; - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return(DB_ERROR); } @@ -3365,12 +3367,12 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) ut_ad(!recv_sys.found_corrupt_fs); if (srv_read_only_mode && recv_needed_recovery) { - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return(DB_READ_ONLY); } if (recv_sys.found_corrupt_log && !srv_force_recovery) { - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); ib::warn() << "Log scan aborted at LSN " << contiguous_lsn; return(DB_ERROR); } @@ -3378,7 +3380,7 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) if (recv_sys.mlog_checkpoint_lsn == 0) { lsn_t scan_lsn = log_sys.log.scanned_lsn; if (!srv_read_only_mode && scan_lsn != checkpoint_lsn) { - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); ib::error err; err << "Missing FILE_CHECKPOINT"; if (end_lsn) { @@ -3397,7 +3399,7 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) if ((recv_sys.found_corrupt_log && !srv_force_recovery) || recv_sys.found_corrupt_fs) { - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return(DB_ERROR); } } @@ -3438,7 +3440,7 @@ completed: if (srv_read_only_mode) { ib::error() << "innodb_read_only" " prevents crash recovery"; - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return(DB_READ_ONLY); } @@ -3460,7 +3462,7 @@ completed: rescan, missing_tablespace); if (err != DB_SUCCESS) { - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return(err); } @@ -3490,7 +3492,7 @@ completed: rescan, missing_tablespace); if (err != DB_SUCCESS) { - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return err; } @@ -3514,7 +3516,7 @@ completed: if ((recv_sys.found_corrupt_log && !srv_force_recovery) || recv_sys.found_corrupt_fs) { - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); return(DB_ERROR); } } @@ -3535,7 +3537,7 @@ completed: } if (recv_sys.recovered_lsn < checkpoint_lsn) { - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); ib::error() << "Recovered only to lsn:" << recv_sys.recovered_lsn << " checkpoint_lsn: " << checkpoint_lsn; @@ -3573,7 +3575,7 @@ completed: mutex_exit(&recv_sys.mutex); - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); recv_lsn_checks_on = true; diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index e04a2af92c8..dede92ad755 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -408,12 +408,12 @@ void mtr_t::commit() lsns= { m_commit_lsn, false }; if (m_made_dirty) - log_flush_order_mutex_enter(); + mysql_mutex_lock(&log_sys.flush_order_mutex); /* It is now safe to release the log mutex because the flush_order mutex will ensure that we are the first one to insert into the flush list. */ - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); if (m_freed_pages) { @@ -445,7 +445,7 @@ void mtr_t::commit() (ReleaseBlocks(lsns.first, m_commit_lsn, m_memo))); if (m_made_dirty) - log_flush_order_mutex_exit(); + mysql_mutex_unlock(&log_sys.flush_order_mutex); m_memo.for_each_block_in_reverse(CIterate()); @@ -464,12 +464,12 @@ void mtr_t::commit() /** Commit a mini-transaction that did not modify any pages, but generated some redo log on a higher level, such as FILE_MODIFY records and an optional FILE_CHECKPOINT marker. -The caller must invoke log_mutex_enter() and log_mutex_exit(). +The caller must hold log_sys.mutex. This is to be used at log_checkpoint(). @param[in] checkpoint_lsn log checkpoint LSN, or 0 */ void mtr_t::commit_files(lsn_t checkpoint_lsn) { - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); ut_ad(is_active()); ut_ad(!is_inside_ibuf()); ut_ad(m_log_mode == MTR_LOG_ALL); @@ -643,7 +643,7 @@ static void log_margin_checkpoint_age(ulint len) const ulint margin= len + extra_len; - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); const lsn_t lsn= log_sys.get_lsn(); @@ -676,7 +676,7 @@ static lsn_t log_reserve_and_open(size_t len) { for (ut_d(ulint count= 0);;) { - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); /* Calculate an upper limit for the space the string may take in the log buffer */ @@ -687,7 +687,7 @@ static lsn_t log_reserve_and_open(size_t len) if (log_sys.buf_free + len_upper_limit <= srv_log_buffer_size) break; - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); DEBUG_SYNC_C("log_buf_size_exceeded"); /* Not enough free space, do a write of the log buffer */ @@ -697,7 +697,7 @@ static lsn_t log_reserve_and_open(size_t len) ut_ad(++count < 50); - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); } return log_sys.get_lsn(); @@ -706,7 +706,7 @@ static lsn_t log_reserve_and_open(size_t len) /** Append data to the log buffer. */ static void log_write_low(const void *str, size_t size) { - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); const ulint trailer_offset= log_sys.trailer_offset(); do @@ -758,7 +758,7 @@ static void log_write_low(const void *str, size_t size) @return whether buffer pool flushing is needed */ static bool log_close(lsn_t lsn) { - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); ut_ad(lsn == log_sys.get_lsn()); byte *log_block= static_cast(ut_align_down(log_sys.buf + @@ -820,7 +820,7 @@ inline ulint mtr_t::prepare_write() if (UNIV_UNLIKELY(m_log_mode != MTR_LOG_ALL)) { ut_ad(m_log_mode == MTR_LOG_NO_REDO); ut_ad(m_log.size() == 0); - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); m_commit_lsn = log_sys.get_lsn(); return 0; } @@ -839,7 +839,7 @@ inline ulint mtr_t::prepare_write() space = NULL; } - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); if (fil_names_write_if_was_clean(space)) { len = m_log.size(); @@ -864,7 +864,7 @@ inline ulint mtr_t::prepare_write() inline std::pair mtr_t::finish_write(ulint len) { ut_ad(m_log_mode == MTR_LOG_ALL); - ut_ad(log_mutex_own()); + mysql_mutex_assert_owner(&log_sys.mutex); ut_ad(m_log.size() == len); ut_ad(len > 0); diff --git a/storage/innobase/srv/srv0mon.cc b/storage/innobase/srv/srv0mon.cc index 2af29fded26..174355f992a 100644 --- a/storage/innobase/srv/srv0mon.cc +++ b/storage/innobase/srv/srv0mon.cc @@ -1905,23 +1905,23 @@ srv_mon_process_existing_counter( break; case MONITOR_PENDING_CHECKPOINT_WRITE: - mutex_enter(&log_sys.mutex); + mysql_mutex_lock(&log_sys.mutex); value = static_cast( log_sys.n_pending_checkpoint_writes); - mutex_exit(&log_sys.mutex); + mysql_mutex_unlock(&log_sys.mutex); break; case MONITOR_LOG_IO: - mutex_enter(&log_sys.mutex); + mysql_mutex_lock(&log_sys.mutex); value = static_cast(log_sys.n_log_ios); - mutex_exit(&log_sys.mutex); + mysql_mutex_unlock(&log_sys.mutex); break; case MONITOR_LSN_CHECKPOINT_AGE: - mutex_enter(&log_sys.mutex); + mysql_mutex_lock(&log_sys.mutex); value = static_cast(log_sys.get_lsn() - log_sys.last_checkpoint_lsn); - mutex_exit(&log_sys.mutex); + mysql_mutex_unlock(&log_sys.mutex); break; case MONITOR_OVLD_BUF_OLDEST_LSN: diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 030acc72e63..554e2043ad1 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -1281,13 +1281,13 @@ srv_export_innodb_status(void) mutex_exit(&srv_innodb_monitor_mutex); - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); export_vars.innodb_lsn_current = log_sys.get_lsn(); export_vars.innodb_lsn_flushed = log_sys.get_flushed_lsn(); export_vars.innodb_lsn_last_checkpoint = log_sys.last_checkpoint_lsn; export_vars.innodb_checkpoint_max_age = static_cast( log_sys.max_checkpoint_age); - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); export_vars.innodb_checkpoint_age = static_cast( export_vars.innodb_lsn_current diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 78b7cbb635b..b53c7888509 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -303,7 +303,7 @@ static dberr_t create_log_file(bool create_new_db, lsn_t lsn, } /* Create a log checkpoint. */ - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); if (log_sys.is_encrypted() && !log_crypt_init()) { return DB_ERROR; } @@ -328,7 +328,7 @@ static dberr_t create_log_file(bool create_new_db, lsn_t lsn, log_sys.log.write_header_durable(lsn); - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); log_make_checkpoint(); log_write_up_to(LSN_MAX, true); @@ -355,12 +355,12 @@ static dberr_t create_log_file_rename(lsn_t lsn, std::string &logfile0) ib::info() << "Renaming log file " << logfile0 << " to " << new_name; - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); ut_ad(logfile0.size() == 2 + new_name.size()); logfile0= new_name; dberr_t err= log_sys.log.rename(std::move(new_name)); - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); DBUG_EXECUTE_IF("innodb_log_abort_10", err= DB_ERROR;); @@ -910,7 +910,7 @@ static lsn_t srv_prepare_to_delete_redo_log_file(bool old_exists) DBUG_EXECUTE_IF("innodb_log_abort_1", DBUG_RETURN(0);); DBUG_PRINT("ib_log", ("After innodb_log_abort_1")); - log_mutex_enter(); + mysql_mutex_lock(&log_sys.mutex); fil_names_clear(log_sys.get_lsn(), false); @@ -949,7 +949,7 @@ static lsn_t srv_prepare_to_delete_redo_log_file(bool old_exists) << " bytes; LSN=" << flushed_lsn; } - log_mutex_exit(); + mysql_mutex_unlock(&log_sys.mutex); if (flushed_lsn != log_sys.get_flushed_lsn()) { log_write_up_to(flushed_lsn, false); diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc index b809e5cb42a..a41d8a0d4f9 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -461,8 +461,6 @@ LatchDebug::LatchDebug() LEVEL_MAP_INSERT(SYNC_FTS_OPTIMIZE); LEVEL_MAP_INSERT(SYNC_FTS_CACHE_INIT); LEVEL_MAP_INSERT(SYNC_RECV); - LEVEL_MAP_INSERT(SYNC_LOG_FLUSH_ORDER); - LEVEL_MAP_INSERT(SYNC_LOG); LEVEL_MAP_INSERT(SYNC_PURGE_QUEUE); LEVEL_MAP_INSERT(SYNC_TRX_SYS_HEADER); LEVEL_MAP_INSERT(SYNC_TRX); @@ -734,8 +732,6 @@ LatchDebug::check_order( case SYNC_FTS_OPTIMIZE: case SYNC_FTS_CACHE: case SYNC_FTS_CACHE_INIT: - case SYNC_LOG: - case SYNC_LOG_FLUSH_ORDER: case SYNC_SEARCH_SYS: case SYNC_LOCK_SYS: case SYNC_LOCK_WAIT_SYS: @@ -1237,11 +1233,6 @@ sync_latch_meta_init() LATCH_ADD_MUTEX(IBUF_PESSIMISTIC_INSERT, SYNC_IBUF_PESS_INSERT_MUTEX, ibuf_pessimistic_insert_mutex_key); - LATCH_ADD_MUTEX(LOG_SYS, SYNC_LOG, log_sys_mutex_key); - - LATCH_ADD_MUTEX(LOG_FLUSH_ORDER, SYNC_LOG_FLUSH_ORDER, - log_flush_order_mutex_key); - LATCH_ADD_MUTEX(PURGE_SYS_PQ, SYNC_PURGE_QUEUE, purge_sys_pq_mutex_key); From 858434910835117215890f8368b91b2905e74815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Fri, 23 Oct 2020 18:09:01 +0300 Subject: [PATCH 246/323] MDEV-14945 possible buffer overflow in stack resolver According to https://stackoverflow.com/questions/22827510/how-to-avoid-bad-fd-set-buffer-overflow-crash it seems that using select instead of poll can cause additional memory allocations. As we are in a crashed state, we must prevent allocating any memory (if possible). Thus, switch select call to poll. Also move some bigger datastructures to global space. The code is not run in a multithreaded context so best we don't use up stack space if it's not needed. --- mysys/my_addr_resolve.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/mysys/my_addr_resolve.c b/mysys/my_addr_resolve.c index ecb512572b1..e0ebbe699be 100644 --- a/mysys/my_addr_resolve.c +++ b/mysys/my_addr_resolve.c @@ -147,10 +147,18 @@ err: #include +#if defined(HAVE_POLL_H) +#include +#elif defined(HAVE_SYS_POLL_H) +#include +#endif /* defined(HAVE_POLL_H) */ + static int in[2], out[2]; static pid_t pid; static char addr2line_binary[1024]; static char output[1024]; +static struct pollfd poll_fds; +Dl_info info; int start_addr2line_fork(const char *binary_path) { @@ -200,15 +208,16 @@ int my_addr_resolve(void *ptr, my_addr_loc *loc) ssize_t extra_bytes_read = 0; ssize_t parsed = 0; - fd_set set; - struct timeval timeout; + int ret; int filename_start = -1; int line_number_start = -1; - Dl_info info; void *offset; + poll_fds.fd = out[0]; + poll_fds.events = POLLIN | POLLRDBAND; + if (!dladdr(ptr, &info)) return 1; @@ -230,16 +239,16 @@ int my_addr_resolve(void *ptr, my_addr_loc *loc) if (write(in[1], input, len) <= 0) return 1; - FD_ZERO(&set); - FD_SET(out[0], &set); - /* 100 ms should be plenty of time for addr2line to issue a response. */ - timeout.tv_sec = 0; - timeout.tv_usec = 100000; + /* 500 ms should be plenty of time for addr2line to issue a response. */ /* Read in a loop till all the output from addr2line is complete. */ while (parsed == total_bytes_read && - select(out[0] + 1, &set, NULL, NULL, &timeout) > 0) + (ret= poll(&poll_fds, 1, 500))) { + /* error during poll */ + if (ret < 0) + return 1; + extra_bytes_read= read(out[0], output + total_bytes_read, sizeof(output) - total_bytes_read); if (extra_bytes_read < 0) From 00ddea4f2f7d20e09a28655b2f30a4c014e9344a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 27 Oct 2020 09:52:42 +0200 Subject: [PATCH 247/323] MDEV-24024 innodb.ibuf_not_empty failed in buildbot Probably due to the changes to page flushing in MDEV-23399 (commit 7cffb5f6e8a231a041152447be8980ce35d2c9b8) the command CHECK TABLE would occasionally report a different number of rows for the corrupted secondary index. (The reported number was 991 instead of 990 on one occasion.) Let us map all numbers to 990 in the output. We only care that the injected corruption will be detected. --- mysql-test/suite/innodb/t/ibuf_not_empty.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/innodb/t/ibuf_not_empty.test b/mysql-test/suite/innodb/t/ibuf_not_empty.test index 3b254177497..545a78c887e 100644 --- a/mysql-test/suite/innodb/t/ibuf_not_empty.test +++ b/mysql-test/suite/innodb/t/ibuf_not_empty.test @@ -68,6 +68,7 @@ EOF --let $restart_parameters= --innodb-force-recovery=6 --innodb-change-buffer-dump --source include/start_mysqld.inc +--replace_regex /contains \d+ entries/contains 990 entries/ check table t1; --source include/shutdown_mysqld.inc From 320a73f6a29c6d6adf8576651263812d42796235 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 25 Oct 2020 18:16:24 +0100 Subject: [PATCH 248/323] cleanup: PRIV_LOCK_TABLES (10.5 style) --- sql/sql_parse.cc | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 14ac657862f..fb7552e5929 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -100,6 +100,8 @@ #include "my_json_writer.h" +#define PRIV_LOCK_TABLES (SELECT_ACL | LOCK_TABLES_ACL) + #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") #ifdef WITH_ARIA_STORAGE_ENGINE @@ -4560,7 +4562,7 @@ mysql_execute_command(THD *thd) if (first_table && lex->type & (REFRESH_READ_LOCK|REFRESH_FOR_EXPORT)) { /* Check table-level privileges. */ - if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, + if (check_table_access(thd, PRIV_LOCK_TABLES, all_tables, FALSE, UINT_MAX, FALSE)) goto error; @@ -6065,7 +6067,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, @param thd Thread handler @param privilege requested privilege - @param all_tables global table list of query + @param tables global table list of query @param no_errors FALSE/TRUE - report/don't report error to the client (using my_error() call). @@ -6075,32 +6077,29 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, 1 access denied, error is sent to client */ -bool check_single_table_access(THD *thd, ulong privilege, - TABLE_LIST *all_tables, bool no_errors) +bool check_single_table_access(THD *thd, ulong privilege, TABLE_LIST *tables, + bool no_errors) { Security_context * backup_ctx= thd->security_ctx; /* we need to switch to the saved context (if any) */ - if (all_tables->security_ctx) - thd->security_ctx= all_tables->security_ctx; + if (tables->security_ctx) + thd->security_ctx= tables->security_ctx; const char *db_name; - if ((all_tables->view || all_tables->field_translation) && - !all_tables->schema_table) - db_name= all_tables->view_db.str; + if ((tables->view || tables->field_translation) && !tables->schema_table) + db_name= tables->view_db.str; else - db_name= all_tables->db; + db_name= tables->db; - if (check_access(thd, privilege, db_name, - &all_tables->grant.privilege, - &all_tables->grant.m_internal, - 0, no_errors)) + if (check_access(thd, privilege, db_name, &tables->grant.privilege, + &tables->grant.m_internal, 0, no_errors)) goto deny; /* Show only 1 table for check_grant */ - if (!(all_tables->belong_to_view && - (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) && - check_grant(thd, privilege, all_tables, FALSE, 1, no_errors)) + if (!(tables->belong_to_view && + (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) && + check_grant(thd, privilege, tables, FALSE, 1, no_errors)) goto deny; thd->security_ctx= backup_ctx; @@ -9060,7 +9059,7 @@ static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables) if (is_temporary_table(table)) continue; - if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, table, + if (check_table_access(thd, PRIV_LOCK_TABLES, table, FALSE, 1, FALSE)) return TRUE; } From 0c3723e1d50e61303b63f6264c2c193397ee4475 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 25 Oct 2020 18:17:34 +0100 Subject: [PATCH 249/323] Bug#31304432 "INSUFFICIENT PRIVILEGE CHECK BY LOCK TABLES" `LOCK TABLES view_name` should require * invoker to have SELECT and LOCK TABLES privileges on the view * either invoker or definer (only if sql security definer) to have SELECT and LOCK TABLES privileges on the used tables/views. --- mysql-test/r/lock_view.result | 216 ++++++++++++++++++++++++++++++++++ mysql-test/t/lock_view.test | 76 ++++++++++++ sql/sql_parse.cc | 30 +++++ 3 files changed, 322 insertions(+) create mode 100644 mysql-test/r/lock_view.result create mode 100644 mysql-test/t/lock_view.test diff --git a/mysql-test/r/lock_view.result b/mysql-test/r/lock_view.result new file mode 100644 index 00000000000..aa76dd73609 --- /dev/null +++ b/mysql-test/r/lock_view.result @@ -0,0 +1,216 @@ +create database mysqltest1; +create database mysqltest2; +create database mysqltest3; +create user invoker@localhost; +create user definer@localhost; +grant select,show view on mysqltest1.* to invoker@localhost; +grant select,show view on mysqltest1.* to definer@localhost; +grant select,show view on mysqltest2.* to invoker@localhost; +grant select,show view on mysqltest2.* to definer@localhost; +grant select,show view on mysqltest3.* to invoker@localhost; +grant select on performance_schema.* to definer@localhost; +create table mysqltest1.t1 (a int); +create definer=definer@localhost view mysqltest2.v2 as select * from mysqltest1.t1; +create definer=definer@localhost view mysqltest3.v3 as select * from mysqltest2.v2; +create definer=definer@localhost view mysqltest3.v3is as select schema_name from information_schema.schemata order by schema_name; +create definer=definer@localhost view mysqltest3.v3ps as select user from performance_schema.users where current_connections>0 order by user; +create definer=definer@localhost view mysqltest3.v3nt as select 1; +create definer=definer@localhost sql security invoker view mysqltest3.v3i as select * from mysqltest1.t1; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqltest1` /*!40100 DEFAULT CHARACTER SET latin1 */; + +USE `mysqltest1`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqltest2` /*!40100 DEFAULT CHARACTER SET latin1 */; + +USE `mysqltest2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +/*!50001 CREATE TABLE `v2` ( + `a` tinyint NOT NULL +) ENGINE=MyISAM */; +SET character_set_client = @saved_cs_client; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqltest3` /*!40100 DEFAULT CHARACTER SET latin1 */; + +USE `mysqltest3`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +/*!50001 CREATE TABLE `v3` ( + `a` tinyint NOT NULL +) ENGINE=MyISAM */; +SET character_set_client = @saved_cs_client; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +/*!50001 CREATE TABLE `v3i` ( + `a` tinyint NOT NULL +) ENGINE=MyISAM */; +SET character_set_client = @saved_cs_client; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +/*!50001 CREATE TABLE `v3is` ( + `schema_name` tinyint NOT NULL +) ENGINE=MyISAM */; +SET character_set_client = @saved_cs_client; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +/*!50001 CREATE TABLE `v3nt` ( + `1` tinyint NOT NULL +) ENGINE=MyISAM */; +SET character_set_client = @saved_cs_client; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +/*!50001 CREATE TABLE `v3ps` ( + `user` tinyint NOT NULL +) ENGINE=MyISAM */; +SET character_set_client = @saved_cs_client; + +USE `mysqltest1`; + +USE `mysqltest2`; +/*!50001 DROP TABLE IF EXISTS `v2`*/; +/*!50001 SET @saved_cs_client = @@character_set_client */; +/*!50001 SET @saved_cs_results = @@character_set_results */; +/*!50001 SET @saved_col_connection = @@collation_connection */; +/*!50001 SET character_set_client = latin1 */; +/*!50001 SET character_set_results = latin1 */; +/*!50001 SET collation_connection = latin1_swedish_ci */; +/*!50001 CREATE ALGORITHM=UNDEFINED */ +/*!50013 DEFINER=`definer`@`localhost` SQL SECURITY DEFINER */ +/*!50001 VIEW `v2` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` */; +/*!50001 SET character_set_client = @saved_cs_client */; +/*!50001 SET character_set_results = @saved_cs_results */; +/*!50001 SET collation_connection = @saved_col_connection */; + +USE `mysqltest3`; +/*!50001 DROP TABLE IF EXISTS `v3`*/; +/*!50001 SET @saved_cs_client = @@character_set_client */; +/*!50001 SET @saved_cs_results = @@character_set_results */; +/*!50001 SET @saved_col_connection = @@collation_connection */; +/*!50001 SET character_set_client = latin1 */; +/*!50001 SET character_set_results = latin1 */; +/*!50001 SET collation_connection = latin1_swedish_ci */; +/*!50001 CREATE ALGORITHM=UNDEFINED */ +/*!50013 DEFINER=`definer`@`localhost` SQL SECURITY DEFINER */ +/*!50001 VIEW `v3` AS select `v2`.`a` AS `a` from `mysqltest2`.`v2` */; +/*!50001 SET character_set_client = @saved_cs_client */; +/*!50001 SET character_set_results = @saved_cs_results */; +/*!50001 SET collation_connection = @saved_col_connection */; +/*!50001 DROP TABLE IF EXISTS `v3i`*/; +/*!50001 SET @saved_cs_client = @@character_set_client */; +/*!50001 SET @saved_cs_results = @@character_set_results */; +/*!50001 SET @saved_col_connection = @@collation_connection */; +/*!50001 SET character_set_client = latin1 */; +/*!50001 SET character_set_results = latin1 */; +/*!50001 SET collation_connection = latin1_swedish_ci */; +/*!50001 CREATE ALGORITHM=UNDEFINED */ +/*!50013 DEFINER=`definer`@`localhost` SQL SECURITY INVOKER */ +/*!50001 VIEW `v3i` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` */; +/*!50001 SET character_set_client = @saved_cs_client */; +/*!50001 SET character_set_results = @saved_cs_results */; +/*!50001 SET collation_connection = @saved_col_connection */; +/*!50001 DROP TABLE IF EXISTS `v3is`*/; +/*!50001 SET @saved_cs_client = @@character_set_client */; +/*!50001 SET @saved_cs_results = @@character_set_results */; +/*!50001 SET @saved_col_connection = @@collation_connection */; +/*!50001 SET character_set_client = latin1 */; +/*!50001 SET character_set_results = latin1 */; +/*!50001 SET collation_connection = latin1_swedish_ci */; +/*!50001 CREATE ALGORITHM=UNDEFINED */ +/*!50013 DEFINER=`definer`@`localhost` SQL SECURITY DEFINER */ +/*!50001 VIEW `v3is` AS select `information_schema`.`schemata`.`SCHEMA_NAME` AS `schema_name` from `information_schema`.`schemata` order by `information_schema`.`schemata`.`SCHEMA_NAME` */; +/*!50001 SET character_set_client = @saved_cs_client */; +/*!50001 SET character_set_results = @saved_cs_results */; +/*!50001 SET collation_connection = @saved_col_connection */; +/*!50001 DROP TABLE IF EXISTS `v3nt`*/; +/*!50001 SET @saved_cs_client = @@character_set_client */; +/*!50001 SET @saved_cs_results = @@character_set_results */; +/*!50001 SET @saved_col_connection = @@collation_connection */; +/*!50001 SET character_set_client = latin1 */; +/*!50001 SET character_set_results = latin1 */; +/*!50001 SET collation_connection = latin1_swedish_ci */; +/*!50001 CREATE ALGORITHM=UNDEFINED */ +/*!50013 DEFINER=`definer`@`localhost` SQL SECURITY DEFINER */ +/*!50001 VIEW `v3nt` AS select 1 AS `1` */; +/*!50001 SET character_set_client = @saved_cs_client */; +/*!50001 SET character_set_results = @saved_cs_results */; +/*!50001 SET collation_connection = @saved_col_connection */; +/*!50001 DROP TABLE IF EXISTS `v3ps`*/; +/*!50001 SET @saved_cs_client = @@character_set_client */; +/*!50001 SET @saved_cs_results = @@character_set_results */; +/*!50001 SET @saved_col_connection = @@collation_connection */; +/*!50001 SET character_set_client = latin1 */; +/*!50001 SET character_set_results = latin1 */; +/*!50001 SET collation_connection = latin1_swedish_ci */; +/*!50001 CREATE ALGORITHM=UNDEFINED */ +/*!50013 DEFINER=`definer`@`localhost` SQL SECURITY DEFINER */ +/*!50001 VIEW `v3ps` AS select `performance_schema`.`users`.`USER` AS `user` from `performance_schema`.`users` where (`performance_schema`.`users`.`CURRENT_CONNECTIONS` > 0) order by `performance_schema`.`users`.`USER` */; +/*!50001 SET character_set_client = @saved_cs_client */; +/*!50001 SET character_set_results = @saved_cs_results */; +/*!50001 SET collation_connection = @saved_col_connection */; +lock table mysqltest3.v3 write; +ERROR 42000: Access denied for user 'invoker'@'localhost' to database 'mysqltest3' +grant lock tables on mysqltest3.* to invoker@localhost; +show create view mysqltest3.v3; +View Create View character_set_client collation_connection +v3 CREATE ALGORITHM=UNDEFINED DEFINER=`definer`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest3`.`v3` AS select `v2`.`a` AS `a` from `mysqltest2`.`v2` latin1 latin1_swedish_ci +show create view mysqltest3.v3is; +View Create View character_set_client collation_connection +v3is CREATE ALGORITHM=UNDEFINED DEFINER=`definer`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest3`.`v3is` AS select `information_schema`.`schemata`.`SCHEMA_NAME` AS `schema_name` from `information_schema`.`schemata` order by `information_schema`.`schemata`.`SCHEMA_NAME` latin1 latin1_swedish_ci +show create view mysqltest3.v3ps; +View Create View character_set_client collation_connection +v3ps CREATE ALGORITHM=UNDEFINED DEFINER=`definer`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest3`.`v3ps` AS select `performance_schema`.`users`.`USER` AS `user` from `performance_schema`.`users` where (`performance_schema`.`users`.`CURRENT_CONNECTIONS` > 0) order by `performance_schema`.`users`.`USER` latin1 latin1_swedish_ci +show create view mysqltest3.v3nt; +View Create View character_set_client collation_connection +v3nt CREATE ALGORITHM=UNDEFINED DEFINER=`definer`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest3`.`v3nt` AS select 1 AS `1` latin1 latin1_swedish_ci +show create view mysqltest3.v3i; +View Create View character_set_client collation_connection +v3i CREATE ALGORITHM=UNDEFINED DEFINER=`definer`@`localhost` SQL SECURITY INVOKER VIEW `mysqltest3`.`v3i` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +lock table mysqltest3.v3 write; +ERROR HY000: View 'mysqltest3.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +lock table mysqltest3.v3i write; +ERROR HY000: View 'mysqltest3.v3i' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +lock table mysqltest3.v3is write; +select * from mysqltest3.v3is; +schema_name +information_schema +mysqltest1 +mysqltest2 +mysqltest3 +test +lock table mysqltest3.v3ps write; +select * from mysqltest3.v3ps; +user +NULL +invoker +root +lock table mysqltest3.v3nt write; +select * from mysqltest3.v3nt; +1 +1 +grant lock tables on mysqltest2.* to invoker@localhost; +lock table mysqltest3.v3 write; +ERROR HY000: View 'mysqltest3.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +lock table mysqltest3.v3i write; +ERROR HY000: View 'mysqltest3.v3i' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +grant lock tables on mysqltest1.* to definer@localhost; +lock table mysqltest3.v3 write; +select * from mysqltest3.v3; +a +lock table mysqltest3.v3i write; +ERROR HY000: View 'mysqltest3.v3i' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +grant lock tables on mysqltest1.* to invoker@localhost; +lock table mysqltest3.v3i write; +select * from mysqltest3.v3i; +a +drop user invoker@localhost; +drop user definer@localhost; +drop database mysqltest1; +drop database mysqltest2; +drop database mysqltest3; diff --git a/mysql-test/t/lock_view.test b/mysql-test/t/lock_view.test new file mode 100644 index 00000000000..dd8809ab89d --- /dev/null +++ b/mysql-test/t/lock_view.test @@ -0,0 +1,76 @@ +source include/not_embedded.inc; +# +# LOCK TABLES and privileges on views +# +create database mysqltest1; +create database mysqltest2; +create database mysqltest3; +create user invoker@localhost; +create user definer@localhost; +grant select,show view on mysqltest1.* to invoker@localhost; +grant select,show view on mysqltest1.* to definer@localhost; +grant select,show view on mysqltest2.* to invoker@localhost; +grant select,show view on mysqltest2.* to definer@localhost; +grant select,show view on mysqltest3.* to invoker@localhost; +grant select on performance_schema.* to definer@localhost; +create table mysqltest1.t1 (a int); +create definer=definer@localhost view mysqltest2.v2 as select * from mysqltest1.t1; +create definer=definer@localhost view mysqltest3.v3 as select * from mysqltest2.v2; +create definer=definer@localhost view mysqltest3.v3is as select schema_name from information_schema.schemata order by schema_name; +create definer=definer@localhost view mysqltest3.v3ps as select user from performance_schema.users where current_connections>0 order by user; +create definer=definer@localhost view mysqltest3.v3nt as select 1; +create definer=definer@localhost sql security invoker view mysqltest3.v3i as select * from mysqltest1.t1; + +exec $MYSQL_DUMP --compact -B mysqltest1 mysqltest2 mysqltest3; + +connect inv,localhost,invoker; +error ER_DBACCESS_DENIED_ERROR; +lock table mysqltest3.v3 write; +disconnect inv; +connection default; + +grant lock tables on mysqltest3.* to invoker@localhost; +connect inv,localhost,invoker; +show create view mysqltest3.v3; +show create view mysqltest3.v3is; +show create view mysqltest3.v3ps; +show create view mysqltest3.v3nt; +show create view mysqltest3.v3i; +error ER_VIEW_INVALID; +lock table mysqltest3.v3 write; +error ER_VIEW_INVALID; +lock table mysqltest3.v3i write; +lock table mysqltest3.v3is write; select * from mysqltest3.v3is; +lock table mysqltest3.v3ps write; select * from mysqltest3.v3ps; +lock table mysqltest3.v3nt write; select * from mysqltest3.v3nt; +disconnect inv; +connection default; + +grant lock tables on mysqltest2.* to invoker@localhost; +connect inv,localhost,invoker; +error ER_VIEW_INVALID; +lock table mysqltest3.v3 write; +error ER_VIEW_INVALID; +lock table mysqltest3.v3i write; +disconnect inv; +connection default; + +grant lock tables on mysqltest1.* to definer@localhost; +connect inv,localhost,invoker; +lock table mysqltest3.v3 write; select * from mysqltest3.v3; +error ER_VIEW_INVALID; +lock table mysqltest3.v3i write; +disconnect inv; +connection default; + +grant lock tables on mysqltest1.* to invoker@localhost; +connect inv,localhost,invoker; +lock table mysqltest3.v3i write; select * from mysqltest3.v3i; +disconnect inv; +connection default; + +drop user invoker@localhost; +drop user definer@localhost; +drop database mysqltest1; +drop database mysqltest2; +drop database mysqltest3; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fb7552e5929..bf1dad804e3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2392,10 +2392,40 @@ static bool lock_tables_open_and_lock_tables(THD *thd, TABLE_LIST *tables) We don't set TABLE_LIST::lock_type in this case as this might result in extra warnings from THD::decide_logging_format() even though binary logging is totally irrelevant for LOCK TABLES. + + Check privileges of view tables here, after views were opened. + Either definer or invoker has to have PRIV_LOCK_TABLES to be able to + lock view and its tables. For mysqldump (that locks views before dumping + their structures) compatibility we allow locking views that select + from I_S or P_S tables, but downrade the lock to TL_READ */ for (table= tables; table; table= table->next_global) + { if (!table->placeholder() && table->table->s->tmp_table) table->table->reginfo.lock_type= TL_WRITE; + else if (table->belong_to_view && + check_single_table_access(thd, PRIV_LOCK_TABLES, table, 1)) + { + if (table->grant.m_internal.m_schema_access) + table->lock_type= TL_READ; + else + { + bool error= true; + if (Security_context *sctx= table->security_ctx) + { + table->security_ctx= 0; + error= check_single_table_access(thd, PRIV_LOCK_TABLES, table, 1); + table->security_ctx= sctx; + } + if (error) + { + my_error(ER_VIEW_INVALID, MYF(0), table->belong_to_view->view_db.str, + table->belong_to_view->view_name.str); + goto err; + } + } + } + } if (lock_tables(thd, tables, counter, 0) || thd->locked_tables_list.init_locked_tables(thd)) From 1269fd420dbcac2cedb345944a35aebe3562ddc1 Mon Sep 17 00:00:00 2001 From: Karthik Kamath Date: Mon, 31 Aug 2020 12:21:07 +0530 Subject: [PATCH 250/323] BUG#31650096: MYSQL SERVER HEAP-USE-AFTER-FREE IN TRANS_SAVEPOINT ANALYSIS: ========= During Bootstrap, while executing the statements from sql file passed to the init-file server option, transaction mem_root was being freed for every statement. This creates an issue with multi statement transactions especially when a statement in the transaction has to access the memory used by the previous statement in the transaction. FIX: ==== Transaction mem_root is freed whenever a transaction is committed or rolled-back. Hence explicitly freeing it is not necessary in the bootstrap implementation. Change-Id: I40f71d49781bf7ad32d474bb176bd6060c9377dc --- sql/sql_parse.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index bf1dad804e3..64b9f35d664 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -811,7 +811,6 @@ static void handle_bootstrap_impl(THD *thd) thd->reset_kill_query(); /* Ensure that killed_errmsg is released */ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); - free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC)); thd->lex->restore_set_statement_var(); } From a7d5e85c4935080458fea21c718f56c7bf6f02bd Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 26 Oct 2020 17:20:59 +0100 Subject: [PATCH 251/323] cleanup: have_static_innodb.inc and remove unused files --- mysql-test/include/have_not_innodb_plugin.inc | 4 ---- mysql-test/include/have_static_innodb.inc | 7 +++++++ mysql-test/r/not_true.require | 2 -- mysql-test/t/plugin_innodb.test | 9 +-------- 4 files changed, 8 insertions(+), 14 deletions(-) delete mode 100644 mysql-test/include/have_not_innodb_plugin.inc create mode 100644 mysql-test/include/have_static_innodb.inc delete mode 100644 mysql-test/r/not_true.require diff --git a/mysql-test/include/have_not_innodb_plugin.inc b/mysql-test/include/have_not_innodb_plugin.inc deleted file mode 100644 index e40fd811021..00000000000 --- a/mysql-test/include/have_not_innodb_plugin.inc +++ /dev/null @@ -1,4 +0,0 @@ -disable_query_log; ---require r/not_true.require -select (PLUGIN_LIBRARY LIKE 'ha_innodb_plugin%' OR PLUGIN_DESCRIPTION LIKE '%xtradb%') as `TRUE` from information_schema.plugins where PLUGIN_NAME='InnoDB'; -enable_query_log; diff --git a/mysql-test/include/have_static_innodb.inc b/mysql-test/include/have_static_innodb.inc new file mode 100644 index 00000000000..0d7bb856f4f --- /dev/null +++ b/mysql-test/include/have_static_innodb.inc @@ -0,0 +1,7 @@ +source include/have_innodb.inc; + +if (!`select count(*) from information_schema.plugins + where plugin_name = 'innodb' and plugin_status = 'active' and + plugin_library is null`) { + skip Need compiled-in InnoDB; +} diff --git a/mysql-test/r/not_true.require b/mysql-test/r/not_true.require deleted file mode 100644 index 0032832f3d1..00000000000 --- a/mysql-test/r/not_true.require +++ /dev/null @@ -1,2 +0,0 @@ -TRUE -NULL diff --git a/mysql-test/t/plugin_innodb.test b/mysql-test/t/plugin_innodb.test index fb5dd84b997..03afa190400 100644 --- a/mysql-test/t/plugin_innodb.test +++ b/mysql-test/t/plugin_innodb.test @@ -1,13 +1,6 @@ --source include/not_embedded.inc --source include/have_example_plugin.inc ---source include/have_innodb.inc - -if (!`select count(*) from information_schema.plugins - where plugin_name = 'innodb' and plugin_status = 'active' and - plugin_library is null`) { - skip Need compiled-in InnoDB; -} - +--source include/have_static_innodb.inc --replace_regex /\.dll/.so/ eval install plugin example soname '$HA_EXAMPLE_SO'; From d03ea82759aef7734f162c3137b10aa2476b35e9 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 26 Oct 2020 17:21:26 +0100 Subject: [PATCH 252/323] test case for BUG#31650096 --- mysql-test/r/bootstrap_innodb.result | 7 +++++++ mysql-test/t/bootstrap_innodb.test | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 mysql-test/r/bootstrap_innodb.result create mode 100644 mysql-test/t/bootstrap_innodb.test diff --git a/mysql-test/r/bootstrap_innodb.result b/mysql-test/r/bootstrap_innodb.result new file mode 100644 index 00000000000..2fc7800843b --- /dev/null +++ b/mysql-test/r/bootstrap_innodb.result @@ -0,0 +1,7 @@ +create table t1(a int) engine=innodb; +select * from t1; +a +1 +2 +5 +drop table t1; diff --git a/mysql-test/t/bootstrap_innodb.test b/mysql-test/t/bootstrap_innodb.test new file mode 100644 index 00000000000..ddaefb32155 --- /dev/null +++ b/mysql-test/t/bootstrap_innodb.test @@ -0,0 +1,27 @@ +source include/have_static_innodb.inc; +source include/not_embedded.inc; + +let $datadir= `select @@datadir`; + +create table t1(a int) engine=innodb; +source include/shutdown_mysqld.inc; + +write_file $MYSQLTEST_VARDIR/tmp/bootstrap_test.sql; +use test; +insert t1 values (1); +start transaction; +insert t1 values (2); +savepoint s1; +insert t1 values (3); +savepoint s2; +insert t1 values (4); +rollback to savepoint s1; +insert t1 values (5); +commit; +EOF +exec $MYSQLD_BOOTSTRAP_CMD --datadir=$datadir --innodb < $MYSQLTEST_VARDIR/tmp/bootstrap_test.sql >> $MYSQLTEST_VARDIR/tmp/bootstrap.log 2>&1; +remove_file $MYSQLTEST_VARDIR/tmp/bootstrap_test.sql; + +source include/start_mysqld.inc; +select * from t1; +drop table t1; From 6a614d6934a85e8228957fe1d7242928a00dc5ff Mon Sep 17 00:00:00 2001 From: mkaruza Date: Wed, 21 Oct 2020 09:48:52 +0200 Subject: [PATCH 253/323] MDEV-22707: galera got stuck after flush tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deadlock is possible between applier thread and local committing thread with active FLUSH TABLE. Applier thread should skip table share checks and locks when opening table. Reviewed-by: Jan Lindström --- mysql-test/suite/galera/r/MDEV-22707.result | 26 +++++++++++ mysql-test/suite/galera/t/MDEV-22707.test | 51 +++++++++++++++++++++ sql/sql_base.cc | 5 ++ 3 files changed, 82 insertions(+) create mode 100644 mysql-test/suite/galera/r/MDEV-22707.result create mode 100644 mysql-test/suite/galera/t/MDEV-22707.test diff --git a/mysql-test/suite/galera/r/MDEV-22707.result b/mysql-test/suite/galera/r/MDEV-22707.result new file mode 100644 index 00000000000..a74844d7e12 --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-22707.result @@ -0,0 +1,26 @@ +CREATE TABLE t1(f2 INT) ENGINE=InnoDB; +connect node_1_applier_thd, 127.0.0.1, root, , test, $NODE_MYPORT_1; +SET GLOBAL debug_dbug = "+d,sync.wsrep_apply_cb"; +connection node_2; +SET SESSION wsrep_sync_wait = 0; +INSERT INTO t1 (f2) VALUES (2); +connection node_1_applier_thd; +SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached"; +connection node_1; +SET SESSION wsrep_sync_wait = 0; +SET DEBUG_SYNC = 'wsrep_before_replication SIGNAL wsrep_before_replication_reached WAIT_FOR continue'; +INSERT INTO t1 (f2) VALUES (1); +connect node_1_flush_thd, 127.0.0.1, root, , test, $NODE_MYPORT_1; +SET DEBUG_SYNC="now WAIT_FOR wsrep_before_replication_reached"; +SET GLOBAL debug_dbug = "+d,sync.wsrep_before_mdl_wait"; +FLUSH TABLES; +connect node_1_sync_release_thd, 127.0.0.1, root, , test, $NODE_MYPORT_1; +SET GLOBAL debug_dbug = ""; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_before_mdl_wait"; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb"; +SET DEBUG_SYNC = "now SIGNAL continue"; +SET DEBUG_SYNC = "RESET"; +connection node_1; +connection node_1_flush_thd; +connection node_2; +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/MDEV-22707.test b/mysql-test/suite/galera/t/MDEV-22707.test new file mode 100644 index 00000000000..19755f7c5ac --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-22707.test @@ -0,0 +1,51 @@ +# +# MDEV-22707 galera got stuck after flush tables +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +CREATE TABLE t1(f2 INT) ENGINE=InnoDB; + +--connect node_1_applier_thd, 127.0.0.1, root, , test, $NODE_MYPORT_1 +SET GLOBAL debug_dbug = "+d,sync.wsrep_apply_cb"; + +--connection node_2 +SET SESSION wsrep_sync_wait = 0; +--send INSERT INTO t1 (f2) VALUES (2) + +--connection node_1_applier_thd +# Wait for `sync.wsrep_apply_cb_reached` signal +SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached"; + +--connection node_1 +SET SESSION wsrep_sync_wait = 0; +SET DEBUG_SYNC = 'wsrep_before_replication SIGNAL wsrep_before_replication_reached WAIT_FOR continue'; +--send INSERT INTO t1 (f2) VALUES (1) + +--connect node_1_flush_thd, 127.0.0.1, root, , test, $NODE_MYPORT_1 +SET DEBUG_SYNC="now WAIT_FOR wsrep_before_replication_reached"; +SET GLOBAL debug_dbug = "+d,sync.wsrep_before_mdl_wait"; +--send FLUSH TABLES + +--connect node_1_sync_release_thd, 127.0.0.1, root, , test, $NODE_MYPORT_1 +# First clear all DBUG points +SET GLOBAL debug_dbug = ""; +# Now signal threads to continue execution +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_before_mdl_wait"; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb"; +SET DEBUG_SYNC = "now SIGNAL continue"; +SET DEBUG_SYNC = "RESET"; + +--connection node_1 +--reap + +--connection node_1_flush_thd +--reap + +--connection node_2 +--reap + +DROP TABLE t1; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index cc77b58cb3e..497c6a0322f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1859,7 +1859,12 @@ retry_share: DBUG_RETURN(FALSE); } +#ifdef WITH_WSREP + if (!((flags & MYSQL_OPEN_IGNORE_FLUSH) || + (wsrep_on(thd) && thd->wsrep_applier))) +#else if (!(flags & MYSQL_OPEN_IGNORE_FLUSH)) +#endif { if (share->tdc->flushed) { From 97b10b7fdc268c25dc52d1e960b1f89b1c7db38c Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Tue, 27 Oct 2020 18:55:22 +0700 Subject: [PATCH 254/323] MDEV-22805: SIGSEGV in check_fields on UPDATE For debug build of MariaDB server running of the following test case will hit the assert `thd->lex->sql_command == SQLCOM_UPDATE' in the function check_fields() on attempt to execute the UPDATE statement. CREATE TABLE t1 (a INT); UPDATE t1 FOR PORTION OF APPTIME FROM (SELECT 1 FROM t1) TO 2 SET a = 1; Stack trace to the fired assert statement DBUG_ASSERT(thd->lex->sql_command == SQLCOM_UPDATE) listed below: mysql_execute_command() -> mysql_multi_update_prepare() --> Multiupdate_prelocking_strategy::handle_end() --> check_fiels() It's worth to note that this stack trace looks like a multi update statement is being executed. The fired assert is checked inside the function check_fields() in case table->has_period() returns the value true that in turns happens when temporal period specified in the UPDATE statement. Condition specified in the DEBUG_ASSERT statement returns the false value since the data member thd->lex->sql_command have the value SQLCOM_UPDATE_MULTI. So, the main question is why a program control flow go to the path prescribed for handling MULTI update statement despite of the fact that the ordinary UPDATE statement being executed. The answer is a way that SQL grammar rules written. When the statement UPDATE t1 FOR PORTION OF APPTIME FROM (SELECT 1 FROM t1) TO 2 SET a = 1; being parsed an action for the rule 'table_primary_ident' (part of this action is listed below to simplify description) is invoked to handle the table name 't1' specified in the clause 'SELECT 1 FROM t1'. table_primary_ident: table_ident opt_use_partition opt_for_system_time_clause opt_table_alias_clause opt_key_definition { SELECT_LEX *sel= Select; sel->table_join_options= 0; if (!($$= Select->add_table_to_list(thd, $1, $4, This action calls the method st_select_lex::add_table_to_list() to add the table name 't1' to the list of tables being used by the statement. Later, an action for the following grammar rule update_table_list: table_ident opt_use_partition for_portion_of_time_clause opt_table_alias_clause opt_key_definition { SELECT_LEX *sel= Select; sel->table_join_options= 0; if (!($$= Select->add_table_to_list(thd, $1, $4, is invoked to handle the clause 't1 FOR PORTION OF APPTIME FROM ... TO 2'. This action also calls the method st_select_lex::add_table_to_list() to add the table name 't1' to the list of tables being used by the statement. In result the table name 't1' contained twice in this list. Presence of duplicate names for the table 't1' in a list of table used by a statement leads to the fact that the function unique_table() called from the function mysql_update() returns the value true that forces implementation of the function mysql_update() to return the value 2 as a signal to fall through the case boundary of the switch statement placed in the function mysql_execute_statement() and start handling of the case for sql_command SQLCOM_UPDATE_MULTI. The compound statement block for the case SQLCOM_UPDATE_MULTI invokes the function mysql_multi_update_prepare() that executes the statement set thd->lex->sql_command= SQLCOM_UPDATE_MULTI; and after that calls the method Multiupdate_prelocking_strategy::handle_end(). Finally, this method invokes the check_field() function and assert is fired. The above analysis shows that update for a table that simultaneously specified both as a destination table of UPDATE statement and as a table taking part in subquery is actually treated by MariaDB server as multi-update statement. Taking into account that multi-update statement for temporal period table is not supported yet by MariaDB, correct way to fix the bug is to return the error ER_NOT_SUPPORTED_YET for this case. --- mysql-test/suite/period/r/update.result | 12 ++++++++++++ mysql-test/suite/period/t/update.test | 18 ++++++++++++++++++ sql/sql_parse.cc | 5 +++++ sql/sql_update.cc | 8 ++++++++ 4 files changed, 43 insertions(+) diff --git a/mysql-test/suite/period/r/update.result b/mysql-test/suite/period/r/update.result index b02c075560e..b61d8a73b83 100644 --- a/mysql-test/suite/period/r/update.result +++ b/mysql-test/suite/period/r/update.result @@ -292,3 +292,15 @@ Warning 1264 Out of range value for column 'id' at row 1 Warning 1264 Out of range value for column 'id' at row 2 update ignore t1 for portion of p from '1995-07-06' to '2009-01-12' set f = 1; drop table t1; +# +# MDEV-22805 SIGSEGV in check_fields on UPDATE (optimized builds) | Assertion `thd->lex->sql_command == SQLCOM_UPDATE' failed. +# +CREATE TABLE t1 (a INT, b DATE, c DATE, PERIOD FOR APPTIME(b, c)); +INSERT INTO t1 VALUES(1, '1999-01-01', '2018-12-12'); +UPDATE t1 FOR PORTION OF APPTIME FROM (SELECT '1999-01-01' FROM t1 WHERE a=2) TO '2018-01-01' SET a = 100; +ERROR 42000: This version of MariaDB doesn't yet support 'updating and querying the same temporal periods table' +CREATE VIEW v1 AS SELECT * FROM t1; +UPDATE v1 FOR PORTION OF APPTIME FROM (SELECT '1999-01-01' FROM t1 WHERE a=2) TO '2018-01-01' SET a = 100; +ERROR 42S02: 'v1' is a view +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/suite/period/t/update.test b/mysql-test/suite/period/t/update.test index d4a2080ea0a..66d3bc1e9bf 100644 --- a/mysql-test/suite/period/t/update.test +++ b/mysql-test/suite/period/t/update.test @@ -183,3 +183,21 @@ update ignore t1 set id = 2429681664; update ignore t1 for portion of p from '1995-07-06' to '2009-01-12' set f = 1; drop table t1; + +--echo # +--echo # MDEV-22805 SIGSEGV in check_fields on UPDATE (optimized builds) | Assertion `thd->lex->sql_command == SQLCOM_UPDATE' failed. +--echo # +CREATE TABLE t1 (a INT, b DATE, c DATE, PERIOD FOR APPTIME(b, c)); + +INSERT INTO t1 VALUES(1, '1999-01-01', '2018-12-12'); + +# Without a patch the following statement crashs a server built in debug mode +--error ER_NOT_SUPPORTED_YET +UPDATE t1 FOR PORTION OF APPTIME FROM (SELECT '1999-01-01' FROM t1 WHERE a=2) TO '2018-01-01' SET a = 100; + +CREATE VIEW v1 AS SELECT * FROM t1; +--error ER_IT_IS_A_VIEW +UPDATE v1 FOR PORTION OF APPTIME FROM (SELECT '1999-01-01' FROM t1 WHERE a=2) TO '2018-01-01' SET a = 100; + +DROP VIEW v1; +DROP TABLE t1; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7504863f394..e8c94c6b363 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4373,6 +4373,11 @@ mysql_execute_command(THD *thd) /* mysql_update return 2 if we need to switch to multi-update */ if (up_result != 2) break; + if (thd->lex->period_conditions.is_set()) + { + DBUG_ASSERT(0); // Should never happen + goto error; + } } /* fall through */ case SQLCOM_UPDATE_MULTI: diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 31a015dd0e2..c687b6ca2f5 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -420,6 +420,14 @@ int mysql_update(THD *thd, DBUG_PRINT("info", ("Switch to multi-update")); /* pass counter value */ thd->lex->table_count= table_count; + if (thd->lex->period_conditions.is_set()) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), + "updating and querying the same temporal periods table"); + + DBUG_RETURN(1); + } + /* convert to multiupdate */ DBUG_RETURN(2); } From bc540b8706a404c8aec81a599c7e7ec1a46b5ad1 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 27 Oct 2020 17:56:49 +0530 Subject: [PATCH 255/323] MDEV-23693 Failing assertion: my_atomic_load32_explicit(&lock->lock_word, MY_MEMORY_ORDER_RELAXED) == X_LOCK_DECR InnoDB frees the block lock during buffer pool shrinking when other thread is yet to release the block lock. While shrinking the buffer pool, InnoDB allows the page to be freed unless it is buffer fixed. In some cases, InnoDB releases the latch after unfixing the block. Fix: ==== - InnoDB should unfix the block after releases the latch. - Add more assertion to check buffer fix while accessing the page. - Introduced block_hint structure to store buf_block_t pointer and allow accessing the buf_block_t pointer only by passing a functor. It returns original buf_block_t* pointer if it is valid or nullptr if the pointer become stale. - Replace buf_block_is_uncompressed() with buf_pool_t::is_block_pointer() This change is motivated by a change in mysql-5.7.32: mysql/mysql-server@46e60de444a8fbd876cc6778a7e64a1d3426a48d Bug #31036301 ASSERTION FAILURE: SYNC0RW.IC:429:LOCK->LOCK_WORD --- storage/innobase/CMakeLists.txt | 1 + storage/innobase/btr/btr0bulk.cc | 4 ++ storage/innobase/btr/btr0cur.cc | 43 +++++-------- storage/innobase/btr/btr0pcur.cc | 39 ++++++++---- storage/innobase/buf/buf0block_hint.cc | 78 +++++++++++++++++++++++ storage/innobase/buf/buf0buf.cc | 76 +--------------------- storage/innobase/gis/gis0sea.cc | 25 ++++++-- storage/innobase/include/btr0pcur.h | 11 ++-- storage/innobase/include/buf0block_hint.h | 77 ++++++++++++++++++++++ storage/innobase/include/buf0buf.h | 17 ++--- storage/innobase/include/buf0buf.ic | 35 ++++++---- storage/innobase/include/mtr0mtr.ic | 4 +- storage/innobase/include/trx0undo.h | 2 - storage/innobase/mtr/mtr0mtr.cc | 4 +- storage/innobase/trx/trx0rec.cc | 10 +-- storage/innobase/trx/trx0undo.cc | 1 - 16 files changed, 262 insertions(+), 165 deletions(-) create mode 100644 storage/innobase/buf/buf0block_hint.cc create mode 100644 storage/innobase/include/buf0block_hint.h diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index 1b5345cbddc..08e8e3ff5ab 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -28,6 +28,7 @@ SET(INNOBASE_SOURCES btr/btr0scrub.cc btr/btr0sea.cc btr/btr0defragment.cc + buf/buf0block_hint.cc buf/buf0buddy.cc buf/buf0buf.cc buf/buf0dblwr.cc diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc index 96ff81c9fab..100e48cf537 100644 --- a/storage/innobase/btr/btr0bulk.cc +++ b/storage/innobase/btr/btr0bulk.cc @@ -695,6 +695,8 @@ PageBulk::latch() m_mtr.set_named_space(m_index->space); } + ut_ad(m_block->page.buf_fix_count); + /* In case the block is S-latched by page_cleaner. */ if (!buf_page_optimistic_get(RW_X_LATCH, m_block, m_modify_clock, __FILE__, __LINE__, &m_mtr)) { @@ -713,6 +715,8 @@ PageBulk::latch() buf_block_buf_fix_dec(m_block); + ut_ad(m_block->page.buf_fix_count); + ut_ad(m_cur_rec > m_page && m_cur_rec < m_heap_top); return (m_err); diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 770c6d73585..6ae6bad10c8 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -416,6 +416,8 @@ btr_cur_optimistic_latch_leaves( ulint mode; ulint left_page_no; ulint curr_page_no; + ut_ad(block->page.buf_fix_count); + ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); switch (*latch_mode) { case BTR_SEARCH_LEAF: @@ -427,20 +429,10 @@ btr_cur_optimistic_latch_leaves( mode = *latch_mode == BTR_SEARCH_PREV ? RW_S_LATCH : RW_X_LATCH; - buf_page_mutex_enter(block); - if (buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) { - buf_page_mutex_exit(block); - return(false); - } - /* pin the block not to be relocated */ - buf_block_buf_fix_inc(block, file, line); - buf_page_mutex_exit(block); - rw_lock_s_lock(&block->lock); if (block->modify_clock != modify_clock) { rw_lock_s_unlock(&block->lock); - - goto unpin_failed; + return false; } curr_page_no = block->page.id.page_no(); @@ -470,7 +462,7 @@ btr_cur_optimistic_latch_leaves( /* release the left block */ btr_leaf_page_release( cursor->left_block, mode, mtr); - goto unpin_failed; + return false; } } else { cursor->left_block = NULL; @@ -480,23 +472,28 @@ btr_cur_optimistic_latch_leaves( file, line, mtr)) { if (btr_page_get_prev(buf_block_get_frame(block)) == left_page_no) { - buf_block_buf_fix_dec(block); + /* block was already buffer-fixed while + entering the function and + buf_page_optimistic_get() buffer-fixes + it again. */ + ut_ad(2 <= block->page.buf_fix_count); *latch_mode = mode; return(true); } else { - /* release the block */ + /* release the block and decrement of + buf_fix_count which was incremented + in buf_page_optimistic_get() */ btr_leaf_page_release(block, mode, mtr); } } + ut_ad(block->page.buf_fix_count); /* release the left block */ if (cursor->left_block != NULL) { btr_leaf_page_release(cursor->left_block, mode, mtr); } -unpin_failed: - /* unpin the block */ - buf_block_buf_fix_dec(block); + return(false); default: @@ -1066,12 +1063,7 @@ btr_cur_search_to_nth_level_func( guess = NULL; #else info = btr_search_get_info(index); - - if (!buf_pool_is_obsolete(info->withdraw_clock)) { - guess = info->root_guess; - } else { - guess = NULL; - } + guess = info->root_guess; #ifdef BTR_CUR_HASH_ADAPT rw_lock_t* const search_latch = btr_get_search_latch(index); @@ -1509,10 +1501,7 @@ retry_page_get: } #ifdef BTR_CUR_ADAPT - if (block != guess) { - info->root_guess = block; - info->withdraw_clock = buf_withdraw_clock; - } + info->root_guess = block; #endif } diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc index 4340c2f32b0..560774c715e 100644 --- a/storage/innobase/btr/btr0pcur.cc +++ b/storage/innobase/btr/btr0pcur.cc @@ -165,11 +165,10 @@ btr_pcur_store_position( index, rec, &cursor->old_n_fields, &cursor->old_rec_buf, &cursor->buf_size); - cursor->block_when_stored = block; + cursor->block_when_stored.store(block); /* Function try to check if block is S/X latch. */ cursor->modify_clock = buf_block_get_modify_clock(block); - cursor->withdraw_clock = buf_withdraw_clock; } /**************************************************************//** @@ -199,6 +198,26 @@ btr_pcur_copy_stored_position( pcur_receive->old_n_fields = pcur_donate->old_n_fields; } +/** Structure acts as functor to do the latching of leaf pages. +It returns true if latching of leaf pages succeeded and false +otherwise. */ +struct optimistic_latch_leaves +{ + btr_pcur_t *const cursor; + ulint *latch_mode; + mtr_t *const mtr; + + optimistic_latch_leaves(btr_pcur_t *cursor, ulint *latch_mode, mtr_t *mtr) + :cursor(cursor), latch_mode(latch_mode), mtr(mtr) {} + + bool operator() (buf_block_t *hint) const + { + return hint && btr_cur_optimistic_latch_leaves( + hint, cursor->modify_clock, latch_mode, + btr_pcur_get_btr_cur(cursor), __FILE__, __LINE__, mtr); + } +}; + /**************************************************************//** Restores the stored position of a persistent cursor bufferfixing the page and obtaining the specified latches. If the cursor position was saved when the @@ -261,7 +280,7 @@ btr_pcur_restore_position_func( cursor->latch_mode = BTR_LATCH_MODE_WITHOUT_INTENTION(latch_mode); cursor->pos_state = BTR_PCUR_IS_POSITIONED; - cursor->block_when_stored = btr_pcur_get_block(cursor); + cursor->block_when_stored.clear(); return(FALSE); } @@ -276,12 +295,9 @@ btr_pcur_restore_position_func( case BTR_MODIFY_PREV: /* Try optimistic restoration. */ - if (!buf_pool_is_obsolete(cursor->withdraw_clock) - && btr_cur_optimistic_latch_leaves( - cursor->block_when_stored, cursor->modify_clock, - &latch_mode, btr_pcur_get_btr_cur(cursor), - file, line, mtr)) { - + if (cursor->block_when_stored.run_with_hint( + optimistic_latch_leaves(cursor, &latch_mode, + mtr))) { cursor->pos_state = BTR_PCUR_IS_POSITIONED; cursor->latch_mode = latch_mode; @@ -378,11 +394,10 @@ btr_pcur_restore_position_func( since the cursor can now be on a different page! But we can retain the value of old_rec */ - cursor->block_when_stored = btr_pcur_get_block(cursor); + cursor->block_when_stored.store(btr_pcur_get_block(cursor)); cursor->modify_clock = buf_block_get_modify_clock( - cursor->block_when_stored); + cursor->block_when_stored.block()); cursor->old_stored = true; - cursor->withdraw_clock = buf_withdraw_clock; mem_heap_free(heap); diff --git a/storage/innobase/buf/buf0block_hint.cc b/storage/innobase/buf/buf0block_hint.cc new file mode 100644 index 00000000000..9f974e8304d --- /dev/null +++ b/storage/innobase/buf/buf0block_hint.cc @@ -0,0 +1,78 @@ +/***************************************************************************** + +Copyright (c) 2020, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 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, version 2.0, as published by the +Free Software Foundation. + +This program is also distributed with certain software (including but not +limited to OpenSSL) that is licensed under separate terms, as designated in a +particular file or component or in included license documentation. The authors +of MySQL hereby grant you an additional permission to link the program and +your derivative works with the separately licensed software that they have +included with MySQL. + +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, version 2.0, +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 + +*****************************************************************************/ + +#include "buf0block_hint.h" +namespace buf { + +void Block_hint::buffer_fix_block_if_still_valid() +{ + /* We need to check if m_block points to one of chunks. For this to be + meaningful we need to prevent freeing memory while we check, and until we + buffer-fix the block. For this purpose it is enough to latch any of the many + latches taken by buf_resize(). + However, for buffer-fixing to be meaningful, the block has to contain a page + (as opposed to being already empty, which might mean that buf_pool_resize() + can proceed and free it once we free the s-latch), so we confirm that the + block contains a page. However, it is not sufficient to check that this is + just any page, because just after we check it could get freed, unless we + have a latch which prevents this. This is tricky because page_hash latches + are sharded by page_id and we don't know the page_id until we look into the + block. To solve this chicken-and-egg problem somewhat, we latch the shard + for the m_page_id and compare block->page.id to it - so if is equal then we + can be reasonably sure that we have the correct latch. + There is still a theoretical problem here, where other threads might try + to modify the m_block->page.id while we are comparing it, but the chance of + accidentally causing the old space_id == m_page_id.m_space and the new + page_no == m_page_id.m_page_no is minimal as compilers emit a single 8-byte + comparison instruction to compare both at the same time atomically, and f() + will probably double-check the block->page.id again, anyway. + Finally, assuming that we have correct hash bucket latched, we should check if + the state of the block is BUF_BLOCK_FILE_PAGE before buffer-fixing the block, + as otherwise we risk buffer-fixing and operating on a block, which is already + meant to be freed. In particular, buf_LRU_free_page() first calls + buf_LRU_block_remove_hashed() under hash bucket latch protection to change the + state to BUF_BLOCK_REMOVE_HASH and then releases the latch. Later it calls + buf_LRU_block_free_hashed_page() without any latch to change the state to + BUF_BLOCK_MEMORY and reset the page's id, which means buf_resize() can free it + regardless of our buffer-fixing. */ + if (m_block) + { + const buf_pool_t *const buf_pool= buf_pool_get(m_page_id); + rw_lock_t *latch= buf_page_hash_lock_get(buf_pool, m_page_id); + rw_lock_s_lock(latch); + /* If not own buf_pool_mutex, page_hash can be changed. */ + latch= buf_page_hash_lock_s_confirm(latch, buf_pool, m_page_id); + if (buf_pool->is_block_field(m_block) && + m_page_id == m_block->page.id && + buf_block_get_state(m_block) == BUF_BLOCK_FILE_PAGE) + buf_block_buf_fix_inc(m_block, __FILE__, __LINE__); + else + clear(); + rw_lock_s_unlock(latch); + } +} +} // namespace buf diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index cfc79868482..e2b68011077 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -339,14 +339,6 @@ buf_pool_t* buf_pool_ptr; /** true when resizing buffer pool is in the critical path. */ volatile bool buf_pool_resizing; -/** true when withdrawing buffer pool pages might cause page relocation */ -volatile bool buf_pool_withdrawing; - -/** the clock is incremented every time a pointer to a page may become obsolete; -if the withdrwa clock has not changed, the pointer is still valid in buffer -pool. if changed, the pointer might not be in buffer pool any more. */ -volatile ulint buf_withdraw_clock; - /** Map of buffer pool chunks by its first frame address This is newly made by initialization of buffer pool and buf_resize_thread. Currently, no need mutex protection for update. */ @@ -2068,8 +2060,6 @@ buf_pool_init( NUMA_MEMPOLICY_INTERLEAVE_IN_SCOPE; buf_pool_resizing = false; - buf_pool_withdrawing = false; - buf_withdraw_clock = 0; buf_pool_ptr = (buf_pool_t*) ut_zalloc_nokey( n_instances * sizeof *buf_pool_ptr); @@ -2129,7 +2119,6 @@ buf_page_realloc( { buf_block_t* new_block; - ut_ad(buf_pool_withdrawing); ut_ad(buf_pool_mutex_own(buf_pool)); ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); @@ -2551,9 +2540,6 @@ buf_pool_withdraw_blocks( ib::info() << "buffer pool " << i << " : withdrawn target " << UT_LIST_GET_LEN(buf_pool->withdraw) << " blocks."; - /* retry is not needed */ - ++buf_withdraw_clock; - return(false); } @@ -2650,7 +2636,6 @@ buf_pool_resize() NUMA_MEMPOLICY_INTERLEAVE_IN_SCOPE; ut_ad(!buf_pool_resizing); - ut_ad(!buf_pool_withdrawing); ut_ad(srv_buf_pool_chunk_unit > 0); new_instance_size = srv_buf_pool_size / srv_buf_pool_instances; @@ -2717,7 +2702,6 @@ buf_pool_resize() ut_ad(buf_pool->withdraw_target == 0); buf_pool->withdraw_target = withdraw_target; - buf_pool_withdrawing = true; } } @@ -2742,7 +2726,6 @@ withdraw_retry: if (srv_shutdown_state != SRV_SHUTDOWN_NONE) { /* abort to resize for shutdown. */ - buf_pool_withdrawing = false; return; } @@ -2804,7 +2787,6 @@ withdraw_retry: goto withdraw_retry; } - buf_pool_withdrawing = false; buf_resize_status("Latching whole of buffer pool."); @@ -3981,37 +3963,6 @@ buf_block_from_ahi(const byte* ptr) } #endif /* BTR_CUR_HASH_ADAPT */ -/********************************************************************//** -Find out if a pointer belongs to a buf_block_t. It can be a pointer to -the buf_block_t itself or a member of it. This functions checks one of -the buffer pool instances. -@return TRUE if ptr belongs to a buf_block_t struct */ -static -ibool -buf_pointer_is_block_field_instance( -/*================================*/ - buf_pool_t* buf_pool, /*!< in: buffer pool instance */ - const void* ptr) /*!< in: pointer not dereferenced */ -{ - const buf_chunk_t* chunk = buf_pool->chunks; - const buf_chunk_t* const echunk = chunk + ut_min( - buf_pool->n_chunks, buf_pool->n_chunks_new); - - /* TODO: protect buf_pool->chunks with a mutex (the older pointer will - currently remain while during buf_pool_resize()) */ - while (chunk < echunk) { - if (ptr >= (void*) chunk->blocks - && ptr < (void*) (chunk->blocks + chunk->size)) { - - return(TRUE); - } - - chunk++; - } - - return(FALSE); -} - /********************************************************************//** Find out if a pointer belongs to a buf_block_t. It can be a pointer to the buf_block_t itself or a member of it @@ -4024,11 +3975,7 @@ buf_pointer_is_block_field( ulint i; for (i = 0; i < srv_buf_pool_instances; i++) { - ibool found; - - found = buf_pointer_is_block_field_instance( - buf_pool_from_array(i), ptr); - if (found) { + if (buf_pool_from_array(i)->is_block_field(ptr)) { return(TRUE); } } @@ -4036,25 +3983,6 @@ buf_pointer_is_block_field( return(FALSE); } -/********************************************************************//** -Find out if a buffer block was created by buf_chunk_init(). -@return TRUE if "block" has been added to buf_pool->free by buf_chunk_init() */ -static -ibool -buf_block_is_uncompressed( -/*======================*/ - buf_pool_t* buf_pool, /*!< in: buffer pool instance */ - const buf_block_t* block) /*!< in: pointer to block, - not dereferenced */ -{ - if ((((ulint) block) % sizeof *block) != 0) { - /* The pointer should be aligned. */ - return(FALSE); - } - - return(buf_pointer_is_block_field_instance(buf_pool, (void*) block)); -} - #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG /********************************************************************//** Return true if probe is enabled. @@ -4293,7 +4221,7 @@ loop: has been allocated by buf_page_alloc_descriptor(), it may have been freed by buf_relocate(). */ - if (!buf_block_is_uncompressed(buf_pool, block) + if (!buf_pool->is_block_field(block) || page_id != block->page.id || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) { diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc index c372a3f1cd4..5ea3f328d5c 100644 --- a/storage/innobase/gis/gis0sea.cc +++ b/storage/innobase/gis/gis0sea.cc @@ -1257,6 +1257,24 @@ rtr_check_discard_page( lock_mutex_exit(); } +/** Structure acts as functor to get the optimistic access of the page. +It returns true if it successfully gets the page. */ +struct optimistic_get +{ + btr_pcur_t *const r_cursor; + mtr_t *const mtr; + + optimistic_get(btr_pcur_t *r_cursor,mtr_t *mtr) + :r_cursor(r_cursor), mtr(mtr) {} + + bool operator()(buf_block_t *hint) const + { + return hint && buf_page_optimistic_get( + RW_X_LATCH, hint, r_cursor->modify_clock, __FILE__, + __LINE__, mtr); + } +}; + /** Restore the stored position of a persistent cursor bufferfixing the page */ static bool @@ -1290,11 +1308,8 @@ rtr_cur_restore_position( ut_ad(latch_mode == BTR_CONT_MODIFY_TREE); - if (!buf_pool_is_obsolete(r_cursor->withdraw_clock) - && buf_page_optimistic_get(RW_X_LATCH, - r_cursor->block_when_stored, - r_cursor->modify_clock, - __FILE__, __LINE__, mtr)) { + if (r_cursor->block_when_stored.run_with_hint( + optimistic_get(r_cursor, mtr))) { ut_ad(r_cursor->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(r_cursor->rel_pos == BTR_PCUR_ON); diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h index 26c7ebcee6d..9e3b4fc20a6 100644 --- a/storage/innobase/include/btr0pcur.h +++ b/storage/innobase/include/btr0pcur.h @@ -29,6 +29,7 @@ Created 2/23/1996 Heikki Tuuri #include "dict0dict.h" #include "btr0cur.h" +#include "buf0block_hint.h" #include "btr0btr.h" #include "gis0rtree.h" @@ -514,13 +515,10 @@ struct btr_pcur_t{ whether cursor was on, before, or after the old_rec record */ enum btr_pcur_pos_t rel_pos; /** buffer block when the position was stored */ - buf_block_t* block_when_stored; + buf::Block_hint block_when_stored; /** the modify clock value of the buffer block when the cursor position was stored */ ib_uint64_t modify_clock; - /** the withdraw clock value of the buffer pool when the cursor - position was stored */ - ulint withdraw_clock; /** btr_pcur_store_position() and btr_pcur_restore_position() state. */ enum pcur_pos_t pos_state; /** PAGE_CUR_G, ... */ @@ -540,9 +538,8 @@ struct btr_pcur_t{ btr_pcur_t() : btr_cur(), latch_mode(0), old_stored(false), old_rec(NULL), old_n_fields(0), rel_pos(btr_pcur_pos_t(0)), - block_when_stored(NULL), - modify_clock(0), withdraw_clock(0), - pos_state(BTR_PCUR_NOT_POSITIONED), + block_when_stored(), + modify_clock(0), pos_state(BTR_PCUR_NOT_POSITIONED), search_mode(PAGE_CUR_UNSUPP), trx_if_known(NULL), old_rec_buf(NULL), buf_size(0) { diff --git a/storage/innobase/include/buf0block_hint.h b/storage/innobase/include/buf0block_hint.h new file mode 100644 index 00000000000..2d681175b25 --- /dev/null +++ b/storage/innobase/include/buf0block_hint.h @@ -0,0 +1,77 @@ +/***************************************************************************** + +Copyright (c) 2020, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 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, version 2.0, as published by the +Free Software Foundation. + +This program is also distributed with certain software (including but not +limited to OpenSSL) that is licensed under separate terms, as designated in a +particular file or component or in included license documentation. The authors +of MySQL hereby grant you an additional permission to link the program and +your derivative works with the separately licensed software that they have +included with MySQL. + +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, version 2.0, +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 + +*****************************************************************************/ +#pragma once +#include "buf0buf.h" + +namespace buf { +class Block_hint { + public: + Block_hint():m_block(NULL),m_page_id(0,0) {} + /** Stores the pointer to the block, which is currently buffer-fixed. + @param block a pointer to a buffer-fixed block to be stored */ + inline void store(buf_block_t *block) + { + ut_ad(block->page.buf_fix_count); + m_block= block; + m_page_id= block->page.id; + } + + /** Clears currently stored pointer. */ + inline void clear() { m_block= NULL; } + + /** Invoke f on m_block(which may be null) + @param f The function to be executed. It will be passed the pointer. + If you wish to use the block pointer subsequently, + you need to ensure you buffer-fix it before returning from f. + @return the return value of f + */ + template + bool run_with_hint(const F &f) + { + buffer_fix_block_if_still_valid(); + /* m_block could be changed during f() call, so we use local + variable to remember which block we need to unfix */ + buf_block_t *block= m_block; + bool res= f(block); + if (block) + buf_block_buf_fix_dec(block); + return res; + } + + buf_block_t *block() const { return m_block; } + + private: + /** The block pointer stored by store(). */ + buf_block_t *m_block; + /** If m_block is non-null, the m_block->page.id at time it was stored. */ + page_id_t m_page_id; + + /** A helper function which checks if m_block is not a dangling pointer and + still points to block with page with m_page_id and if so, buffer-fixes it, + otherwise clear()s it */ + void buffer_fix_block_if_still_valid(); +}; +} // namespace buf diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 5f390d2761d..40d2e6b2023 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -101,10 +101,6 @@ extern buf_pool_t* buf_pool_ptr; /*!< The buffer pools extern volatile bool buf_pool_withdrawing; /*!< true when withdrawing buffer pool pages might cause page relocation */ -extern volatile ulint buf_withdraw_clock; /*!< the clock is incremented - every time a pointer to a page may - become obsolete */ - # ifdef UNIV_DEBUG extern my_bool buf_disable_resize_buffer_pool_debug; /*!< if TRUE, resizing buffer pool is not allowed. */ @@ -1373,14 +1369,6 @@ buf_get_nth_chunk_block( ulint n, /*!< in: nth chunk in the buffer pool */ ulint* chunk_size); /*!< in: chunk size */ -/** Verify the possibility that a stored page is not in buffer pool. -@param[in] withdraw_clock withdraw clock when stored the page -@retval true if the page might be relocated */ -UNIV_INLINE -bool -buf_pool_is_obsolete( - ulint withdraw_clock); - /** Calculate aligned buffer pool size based on srv_buf_pool_chunk_unit, if needed. @param[in] size size in bytes @@ -2207,6 +2195,11 @@ struct buf_pool_t{ buf_tmp_array_t* tmp_arr; /*!< Array for temporal memory used in compression and encryption */ + /** Determine if a pointer belongs to a buf_block_t. + It can be a pointer to the buf_block_t itself or a member of it. + @param ptr a pointer that will not be dereferenced + @return whether the ptr belongs to a buf_block_t struct */ + inline bool is_block_field(const void *ptr) const; #if BUF_BUDDY_LOW > UNIV_ZIP_SIZE_MIN # error "BUF_BUDDY_LOW > UNIV_ZIP_SIZE_MIN" diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic index 3df17e8a978..49b741ab5c8 100644 --- a/storage/innobase/include/buf0buf.ic +++ b/storage/innobase/include/buf0buf.ic @@ -54,6 +54,25 @@ struct buf_chunk_t{ } }; +bool buf_pool_t::is_block_field(const void *ptr) const +{ + const buf_chunk_t* chunk= chunks; + const buf_chunk_t *const echunk= chunk + ut_min(n_chunks, + n_chunks_new); + /* TODO: protect chunks with a mutex (the older pointer will + currently remain during resize()) */ + while (chunk < echunk) + { + if (ptr >= reinterpret_cast(chunk->blocks) && + ptr < reinterpret_cast( + chunk->blocks + chunk->size)) + return true; + chunk++; + } + + return false; +} + /*********************************************************************//** Gets the current size of buffer buf_pool in bytes. @return size in bytes */ @@ -1056,8 +1075,6 @@ buf_block_buf_fix_dec( /*==================*/ buf_block_t* block) /*!< in/out: block to bufferunfix */ { - buf_block_unfix(block); - #ifdef UNIV_DEBUG /* No debug latch is acquired if block belongs to system temporary. Debug latch is not of much help if access to block is single @@ -1066,6 +1083,8 @@ buf_block_buf_fix_dec( rw_lock_s_unlock(&block->debug_latch); } #endif /* UNIV_DEBUG */ + + buf_block_unfix(block); } /** Returns the buffer pool instance given a page id. @@ -1439,18 +1458,6 @@ buf_page_get_frame( } } -/** Verify the possibility that a stored page is not in buffer pool. -@param[in] withdraw_clock withdraw clock when stored the page -@retval true if the page might be relocated */ -UNIV_INLINE -bool -buf_pool_is_obsolete( - ulint withdraw_clock) -{ - return(buf_pool_withdrawing - || buf_withdraw_clock != withdraw_clock); -} - /** Calculate aligned buffer pool size based on srv_buf_pool_chunk_unit, if needed. @param[in] size size in bytes diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic index 8d68affb1cb..a45d088d5d7 100644 --- a/storage/innobase/include/mtr0mtr.ic +++ b/storage/innobase/include/mtr0mtr.ic @@ -170,10 +170,10 @@ mtr_t::release_block_at_savepoint( ut_a(slot->object == block); - buf_block_unfix(reinterpret_cast(block)); - buf_page_release_latch(block, slot->type); + buf_block_unfix(reinterpret_cast(block)); + slot->object = NULL; } diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h index bf2d3c7f7f7..99330453c33 100644 --- a/storage/innobase/include/trx0undo.h +++ b/storage/innobase/include/trx0undo.h @@ -424,8 +424,6 @@ struct trx_undo_t { undo_no_t top_undo_no; /*!< undo number of the latest record */ buf_block_t* guess_block; /*!< guess for the buffer block where the top page might reside */ - ulint withdraw_clock; /*!< the withdraw clock value of the - buffer pool when guess_block was stored */ /*-----------------------------*/ UT_LIST_NODE_T(trx_undo_t) undo_list; /*!< undo log objects in the rollback diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index 424ac0b53f0..bc30d6efd55 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -233,8 +233,8 @@ static void memo_slot_release(mtr_memo_slot_t *slot) case MTR_MEMO_PAGE_SX_FIX: case MTR_MEMO_PAGE_X_FIX: buf_block_t *block= reinterpret_cast(slot->object); - buf_block_unfix(block); buf_page_release_latch(block, slot->type); + buf_block_unfix(block); break; } slot->object= NULL; @@ -276,8 +276,8 @@ struct ReleaseLatches { case MTR_MEMO_PAGE_SX_FIX: case MTR_MEMO_PAGE_X_FIX: buf_block_t *block= reinterpret_cast(slot->object); - buf_block_unfix(block); buf_page_release_latch(block, slot->type); + buf_block_unfix(block); break; } slot->object= NULL; diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index 623d8990381..4aecc8ae610 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -1950,8 +1950,7 @@ dberr_t trx_undo_report_rename(trx_t* trx, const dict_table_t* table) buf_block_t* block = buf_page_get_gen( page_id_t(undo->space, undo->last_page_no), univ_page_size, RW_X_LATCH, - buf_pool_is_obsolete(undo->withdraw_clock) - ? NULL : undo->guess_block, + undo->guess_block, BUF_GET, __FILE__, __LINE__, &mtr, &err); ut_ad((err == DB_SUCCESS) == !!block); @@ -1962,7 +1961,6 @@ dberr_t trx_undo_report_rename(trx_t* trx, const dict_table_t* table) if (ulint offset = trx_undo_page_report_rename( trx, table, block, &mtr)) { - undo->withdraw_clock = buf_withdraw_clock; undo->empty = FALSE; undo->top_page_no = undo->last_page_no; undo->top_offset = offset; @@ -2084,8 +2082,7 @@ trx_undo_report_row_operation( undo_block = buf_page_get_gen( page_id_t(undo->space, page_no), univ_page_size, RW_X_LATCH, - buf_pool_is_obsolete(undo->withdraw_clock) - ? NULL : undo->guess_block, BUF_GET, __FILE__, __LINE__, + undo->guess_block, BUF_GET, __FILE__, __LINE__, &mtr, &err); buf_block_dbg_add_level(undo_block, SYNC_TRX_UNDO_PAGE); @@ -2138,14 +2135,13 @@ trx_undo_report_row_operation( mtr_commit(&mtr); } else { /* Success */ - undo->withdraw_clock = buf_withdraw_clock; + undo->guess_block = undo_block; mtr_commit(&mtr); undo->empty = FALSE; undo->top_page_no = page_no; undo->top_offset = offset; undo->top_undo_no = trx->undo_no++; - undo->guess_block = undo_block; trx->undo_rseg_space = rseg->space; diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index 5d4fcdcf53f..5e8467af298 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -1338,7 +1338,6 @@ trx_undo_mem_create( undo->empty = TRUE; undo->top_page_no = page_no; undo->guess_block = NULL; - undo->withdraw_clock = 0; return(undo); } From 8761571a71f0d628c5a82abed115e170d63e34c0 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 27 Oct 2020 00:30:39 +0400 Subject: [PATCH 256/323] MDEV-22524 SIGABRT in safe_mutex_unlock with session_track_system_variables and max_relay_log_size. lock LOCK_global_system_variables around the get_one_variable() call in the Session_sysvars_tracker::store_variable(). --- .../sys_vars/r/session_track_system_variables_basic.result | 2 ++ .../suite/sys_vars/t/session_track_system_variables_basic.test | 2 ++ sql/session_tracker.cc | 3 +++ 3 files changed, 7 insertions(+) diff --git a/mysql-test/suite/sys_vars/r/session_track_system_variables_basic.result b/mysql-test/suite/sys_vars/r/session_track_system_variables_basic.result index 7162e40ef6b..c9e4a0f7dca 100644 --- a/mysql-test/suite/sys_vars/r/session_track_system_variables_basic.result +++ b/mysql-test/suite/sys_vars/r/session_track_system_variables_basic.result @@ -159,6 +159,8 @@ SELECT @@session.session_track_system_variables; @@session.session_track_system_variables +# MDEV-22524 SIGABRT in safe_mutex_unlock with session_track_system_variables and max_relay_log_size. +SET SESSION session_track_system_variables="sql_slave_skip_counter", sql_slave_skip_counter= 0; # Restoring the original values. SET @@global.session_track_system_variables = @global_saved_tmp; # End of tests. diff --git a/mysql-test/suite/sys_vars/t/session_track_system_variables_basic.test b/mysql-test/suite/sys_vars/t/session_track_system_variables_basic.test index 90e6052947c..13423f4404d 100644 --- a/mysql-test/suite/sys_vars/t/session_track_system_variables_basic.test +++ b/mysql-test/suite/sys_vars/t/session_track_system_variables_basic.test @@ -122,6 +122,8 @@ SELECT @@global.session_track_system_variables; SELECT @@session.session_track_system_variables; --echo +--echo # MDEV-22524 SIGABRT in safe_mutex_unlock with session_track_system_variables and max_relay_log_size. +SET SESSION session_track_system_variables="sql_slave_skip_counter", sql_slave_skip_counter= 0; --echo # Restoring the original values. SET @@global.session_track_system_variables = @global_saved_tmp; diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index b73bd1d1d4a..4ef8cbfd706 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -772,8 +772,11 @@ my_bool Session_sysvars_tracker::store_variable(void *ptr, void *data_ptr) show.name= svar->name.str; show.value= (char *) svar; + mysql_mutex_lock(&LOCK_global_system_variables); const char *value= get_one_variable(thd, &show, OPT_SESSION, SHOW_SYS, NULL, &charset, val_buf, &val_length); + mysql_mutex_unlock(&LOCK_global_system_variables); + if (is_plugin) mysql_mutex_unlock(&LOCK_plugin); From 42e1815ad850384fad292534665ff61b78dd96f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 27 Oct 2020 15:35:04 +0200 Subject: [PATCH 257/323] MDEV-16952 Introduce SET GLOBAL innodb_max_purge_lag_wait Let us introduce a dummy variable innodb_max_purge_lag_wait for waiting that the InnoDB history list length is below the user-specified limit. Specifically, SET GLOBAL innodb_max_purge_lag_wait=0; should wait for all history to be purged. This could be useful when upgrading from an older version to MariaDB 10.3 or later, to avoid hitting MDEV-15912. Note: the history cannot be purged if there exist transactions that may see old versions. Reviewed by: Vladislav Vaintroub --- .../suite/innodb/include/wait_all_purged.inc | 24 ++++++----------- .../suite/sys_vars/r/sysvars_innodb.result | 12 +++++++++ storage/innobase/handler/ha_innodb.cc | 27 +++++++++++++++++++ 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/mysql-test/suite/innodb/include/wait_all_purged.inc b/mysql-test/suite/innodb/include/wait_all_purged.inc index 992e14f0843..e3a506c7622 100644 --- a/mysql-test/suite/innodb/include/wait_all_purged.inc +++ b/mysql-test/suite/innodb/include/wait_all_purged.inc @@ -1,25 +1,17 @@ # Wait for everything to be purged. # The user should have set innodb_purge_rseg_truncate_frequency=1. +--disable_query_log if (!$wait_all_purged) { - let $wait_all_purged= 0; + SET GLOBAL innodb_max_purge_lag_wait= 0; } -let $remaining_expect= `select concat('InnoDB ',$wait_all_purged)`; - -let $wait_counter= 600; -while ($wait_counter) +if ($wait_all_purged) { - --replace_regex /.*History list length ([0-9]+).*/\1/ - let $remaining= `SHOW ENGINE INNODB STATUS`; - if ($remaining == $remaining_expect) - { - let $wait_counter= 0; - } - if ($wait_counter) - { - real_sleep 0.1; - dec $wait_counter; - } + eval SET GLOBAL innodb_max_purge_lag_wait= $wait_all_purged; } +--enable_query_log + +--replace_regex /.*History list length ([0-9]+).*/\1/ +let $remaining= `SHOW ENGINE INNODB STATUS`; echo $remaining transactions not purged; diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result index d3d30f8f53f..89138c2fedd 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result @@ -1686,6 +1686,18 @@ NUMERIC_BLOCK_SIZE 0 ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME INNODB_MAX_PURGE_LAG_WAIT +SESSION_VALUE NULL +DEFAULT_VALUE 4294967295 +VARIABLE_SCOPE GLOBAL +VARIABLE_TYPE INT UNSIGNED +VARIABLE_COMMENT Wait until History list length is below the specified limit +NUMERIC_MIN_VALUE 0 +NUMERIC_MAX_VALUE 4294967295 +NUMERIC_BLOCK_SIZE 0 +ENUM_VALUE_LIST NULL +READ_ONLY NO +COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME INNODB_MAX_UNDO_LOG_SIZE SESSION_VALUE NULL DEFAULT_VALUE 10485760 diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index e36dcbad8ff..3db462ee92d 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -271,6 +271,27 @@ enum default_row_format_enum { DEFAULT_ROW_FORMAT_DYNAMIC = 2, }; +/** A dummy variable */ +static uint innodb_max_purge_lag_wait; + +/** Wait for trx_sys_t::rseg_history_len to be below a limit. */ +static void innodb_max_purge_lag_wait_update(THD *thd, st_mysql_sys_var *, + void *, const void *limit) +{ + const uint l= *static_cast(limit); + if (trx_sys->rseg_history_len <= l) + return; + mysql_mutex_unlock(&LOCK_global_system_variables); + while (trx_sys->rseg_history_len > l) + { + if (thd_kill_level(thd)) + break; + srv_wake_purge_thread_if_not_active(); + os_thread_sleep(100000); + } + mysql_mutex_lock(&LOCK_global_system_variables); +} + static void set_my_errno(int err) { @@ -20147,6 +20168,11 @@ static MYSQL_SYSVAR_ULONG(max_purge_lag_delay, srv_max_purge_lag_delay, 0L, /* Minimum value */ 10000000UL, 0); /* Maximum value */ +static MYSQL_SYSVAR_UINT(max_purge_lag_wait, innodb_max_purge_lag_wait, + PLUGIN_VAR_RQCMDARG, + "Wait until History list length is below the specified limit", + NULL, innodb_max_purge_lag_wait_update, UINT_MAX, 0, UINT_MAX, 0); + static MYSQL_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, "Roll back the complete transaction on lock wait timeout, for 4.x compatibility (disabled by default)", @@ -21195,6 +21221,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(flushing_avg_loops), MYSQL_SYSVAR(max_purge_lag), MYSQL_SYSVAR(max_purge_lag_delay), + MYSQL_SYSVAR(max_purge_lag_wait), MYSQL_SYSVAR(old_blocks_pct), MYSQL_SYSVAR(old_blocks_time), MYSQL_SYSVAR(open_files), From e183aec1d75ea7b424ebe237e6b1643961903f2d Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Tue, 27 Oct 2020 12:16:53 +0100 Subject: [PATCH 258/323] MDEV-24018: SIGSEGV in Item_func_nextval::update_table on SELECT SETVAL Reviewed-by: wlad@mariadb.com --- mysql-test/suite/sql_sequence/next.result | 5 +++++ mysql-test/suite/sql_sequence/next.test | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/mysql-test/suite/sql_sequence/next.result b/mysql-test/suite/sql_sequence/next.result index fe761baa032..76991fbe68c 100644 --- a/mysql-test/suite/sql_sequence/next.result +++ b/mysql-test/suite/sql_sequence/next.result @@ -541,5 +541,10 @@ CREATE VIEW v AS SELECT 1; LOCK TABLE v READ; SELECT NEXT VALUE FOR v; ERROR 42S02: 'test.v' is not a SEQUENCE +# +# MDEV-24018: SIGSEGV in Item_func_nextval::update_table on SELECT SETVAL +# +SELECT SETVAL (v,0); +ERROR 42S02: 'test.v' is not a SEQUENCE UNLOCK TABLES; DROP VIEW v; diff --git a/mysql-test/suite/sql_sequence/next.test b/mysql-test/suite/sql_sequence/next.test index 5eac3b668ba..9f0eebdf774 100644 --- a/mysql-test/suite/sql_sequence/next.test +++ b/mysql-test/suite/sql_sequence/next.test @@ -288,5 +288,12 @@ CREATE VIEW v AS SELECT 1; LOCK TABLE v READ; --error ER_NOT_SEQUENCE SELECT NEXT VALUE FOR v; + +--echo # +--echo # MDEV-24018: SIGSEGV in Item_func_nextval::update_table on SELECT SETVAL +--echo # +--error ER_NOT_SEQUENCE +SELECT SETVAL (v,0); + UNLOCK TABLES; DROP VIEW v; From 2cec0523eb3abd888b810e6046a8dfb6ea606c4c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 27 Oct 2020 16:45:35 +0100 Subject: [PATCH 259/323] INET6 type plugin -> Beta --- plugin/type_inet/mysql-test/type_inet/type_inet6_plugin.result | 2 +- plugin/type_inet/plugin.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_plugin.result b/plugin/type_inet/mysql-test/type_inet/type_inet6_plugin.result index d8287363dc5..931c66fd9d2 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6_plugin.result +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_plugin.result @@ -24,7 +24,7 @@ PLUGIN_TYPE DATA TYPE PLUGIN_AUTHOR MariaDB Corporation PLUGIN_DESCRIPTION Data type INET6 PLUGIN_LICENSE GPL -PLUGIN_MATURITY Alpha +PLUGIN_MATURITY Beta PLUGIN_AUTH_VERSION 1.0 # # End of 10.5 tests diff --git a/plugin/type_inet/plugin.cc b/plugin/type_inet/plugin.cc index d7990b2bc5a..55052df80dd 100644 --- a/plugin/type_inet/plugin.cc +++ b/plugin/type_inet/plugin.cc @@ -186,7 +186,7 @@ maria_declare_plugin(type_inet) NULL, // Status variables NULL, // System variables "1.0", // String version representation - MariaDB_PLUGIN_MATURITY_ALPHA // Maturity(see include/mysql/plugin.h)*/ + MariaDB_PLUGIN_MATURITY_BETA // Maturity(see include/mysql/plugin.h)*/ }, { MariaDB_FUNCTION_PLUGIN, // the plugin type (see include/mysql/plugin.h) From afc9d00c66db946c8240fe1fa6b345a3a8b6fec1 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 27 Oct 2020 12:24:55 +0300 Subject: [PATCH 260/323] MDEV-23991 dict_table_stats_lock() has unnecessarily long scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patch removes dict_index_t::stats_latch. Table/index statistics now protected with dict_sys->mutex. That way statistics computation can happen in parallel in several threads and dict_sys->mutex will be locked only for a short period of time. This patch is a joint work with Marko Mäkelä dict_index_t::lock: make mutable which allows to pass const pointer when only lock is touched in an object btr_height_get() btr_get_size(): make index argument const for better type safety btr_estimate_number_of_different_key_vals(): now returns computed values instead of setting fields in dict_index_t directly remove everything related to dict_index_t::stats_latch dict_stats_index_set_n_diff(): now returns computed values instead of setting fields in dict_index_t directly dict_stats_analyze_index(): now returns computed values instead of setting fields in dict_index_t directly Reviewed by: Marko Mäkelä --- .../suite/innodb/r/stats_persistent.result | 18 ++ .../suite/innodb/t/stats_persistent.test | 27 +++ storage/innobase/btr/btr0btr.cc | 4 +- storage/innobase/btr/btr0cur.cc | 46 ++-- storage/innobase/dict/dict0dict.cc | 50 ----- storage/innobase/dict/dict0mem.cc | 13 +- storage/innobase/dict/dict0stats.cc | 212 +++++++++++------- storage/innobase/handler/ha_innodb.cc | 52 ++--- storage/innobase/handler/i_s.cc | 47 ++-- storage/innobase/ibuf/ibuf0ibuf.cc | 2 +- storage/innobase/include/btr0btr.h | 4 +- storage/innobase/include/btr0cur.h | 31 ++- storage/innobase/include/dict0dict.h | 18 +- storage/innobase/include/dict0dict.ic | 2 +- storage/innobase/include/dict0mem.h | 25 +-- storage/innobase/include/dict0stats.ic | 7 +- storage/innobase/include/sync0sync.h | 1 - storage/innobase/row/row0mysql.cc | 6 +- storage/innobase/row/row0uins.cc | 2 +- storage/innobase/sync/sync0debug.cc | 3 - storage/innobase/sync/sync0sync.cc | 1 - 21 files changed, 290 insertions(+), 281 deletions(-) create mode 100644 mysql-test/suite/innodb/r/stats_persistent.result create mode 100644 mysql-test/suite/innodb/t/stats_persistent.test diff --git a/mysql-test/suite/innodb/r/stats_persistent.result b/mysql-test/suite/innodb/r/stats_persistent.result new file mode 100644 index 00000000000..c96afb41af2 --- /dev/null +++ b/mysql-test/suite/innodb/r/stats_persistent.result @@ -0,0 +1,18 @@ +# +# MDEV-23991 dict_table_stats_lock() has unnecessarily long scope +# +CREATE TABLE t1(a INT) ENGINE=INNODB STATS_PERSISTENT=1; +SET DEBUG_SYNC='dict_stats_update_persistent SIGNAL stop WAIT_FOR go'; +ANALYZE TABLE t1; +connect con1, localhost, root; +SET DEBUG_SYNC='now WAIT_FOR stop'; +SELECT ENGINE,SUM(DATA_LENGTH+INDEX_LENGTH),COUNT(ENGINE),SUM(DATA_LENGTH),SUM(INDEX_LENGTH) FROM information_schema.TABLES WHERE ENGINE='InnoDB'; +ENGINE SUM(DATA_LENGTH+INDEX_LENGTH) COUNT(ENGINE) SUM(DATA_LENGTH) SUM(INDEX_LENGTH) +InnoDB 49152 3 49152 0 +SET DEBUG_SYNC='now SIGNAL go'; +disconnect con1; +connection default; +Table Op Msg_type Msg_text +test.t1 analyze status OK +SET DEBUG_SYNC= 'RESET'; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/stats_persistent.test b/mysql-test/suite/innodb/t/stats_persistent.test new file mode 100644 index 00000000000..ac412d56d0d --- /dev/null +++ b/mysql-test/suite/innodb/t/stats_persistent.test @@ -0,0 +1,27 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/count_sessions.inc + +--echo # +--echo # MDEV-23991 dict_table_stats_lock() has unnecessarily long scope +--echo # +CREATE TABLE t1(a INT) ENGINE=INNODB STATS_PERSISTENT=1; + +SET DEBUG_SYNC='dict_stats_update_persistent SIGNAL stop WAIT_FOR go'; +--send ANALYZE TABLE t1 + +--connect(con1, localhost, root) +SET DEBUG_SYNC='now WAIT_FOR stop'; + +SELECT ENGINE,SUM(DATA_LENGTH+INDEX_LENGTH),COUNT(ENGINE),SUM(DATA_LENGTH),SUM(INDEX_LENGTH) FROM information_schema.TABLES WHERE ENGINE='InnoDB'; + +SET DEBUG_SYNC='now SIGNAL go'; +--disconnect con1 + +--connection default +--reap +SET DEBUG_SYNC= 'RESET'; +DROP TABLE t1; + +--source include/wait_until_count_sessions.inc diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 3b0e755bc91..511ac66d58c 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -283,7 +283,7 @@ the index. ulint btr_height_get( /*===========*/ - dict_index_t* index, /*!< in: index tree */ + const dict_index_t* index, /*!< in: index tree */ mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint height=0; @@ -592,7 +592,7 @@ Gets the number of pages in a B-tree. ulint btr_get_size( /*=========*/ - dict_index_t* index, /*!< in: index */ + const dict_index_t* index, /*!< in: index */ ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */ mtr_t* mtr) /*!< in/out: mini-transaction where index is s-latched */ diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 6ae6bad10c8..7fd34c5d652 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -6133,21 +6133,19 @@ btr_record_not_null_field_in_rec( } } -/*******************************************************************//** -Estimates the number of different key values in a given index, for +/** Estimates the number of different key values in a given index, for each n-column prefix of the index where 1 <= n <= dict_index_get_n_unique(index). The estimates are stored in the array index->stat_n_diff_key_vals[] (indexed 0..n_uniq-1) and the number of pages that were sampled is saved in -index->stat_n_sample_sizes[]. +result.n_sample_sizes[]. If innodb_stats_method is nulls_ignored, we also record the number of non-null values for each prefix and stored the estimates in -array index->stat_n_non_null_key_vals. -@return true if the index is available and we get the estimated numbers, -false if the index is unavailable. */ -bool -btr_estimate_number_of_different_key_vals( -/*======================================*/ - dict_index_t* index) /*!< in: index */ +array result.n_non_null_key_vals. +@param[in] index index +@return vector with statistics information +empty vector if the index is unavailable. */ +std::vector +btr_estimate_number_of_different_key_vals(dict_index_t* index) { btr_cur_t cursor; page_t* page; @@ -6167,11 +6165,11 @@ btr_estimate_number_of_different_key_vals( rec_offs* offsets_rec = NULL; rec_offs* offsets_next_rec = NULL; + std::vector result; + /* For spatial index, there is no such stats can be fetched. */ - if (dict_index_is_spatial(index)) { - return(false); - } + ut_ad(!dict_index_is_spatial(index)); n_cols = dict_index_get_n_unique(index); @@ -6280,7 +6278,7 @@ btr_estimate_number_of_different_key_vals( mtr_commit(&mtr); mem_heap_free(heap); - return(false); + return result; } /* Count the number of different key values for each prefix of @@ -6386,8 +6384,12 @@ exit_loop: also the pages used for external storage of fields (those pages are included in index->stat_n_leaf_pages) */ + result.reserve(n_cols); + for (j = 0; j < n_cols; j++) { - index->stat_n_diff_key_vals[j] + index_field_stats_t stat; + + stat.n_diff_key_vals = BTR_TABLE_STATS_FROM_SAMPLE( n_diff[j], index, n_sample_pages, total_external_size, not_empty_flag); @@ -6408,25 +6410,23 @@ exit_loop: add_on = n_sample_pages; } - index->stat_n_diff_key_vals[j] += add_on; + stat.n_diff_key_vals += add_on; - index->stat_n_sample_sizes[j] = n_sample_pages; + stat.n_sample_sizes = n_sample_pages; - /* Update the stat_n_non_null_key_vals[] with our - sampled result. stat_n_non_null_key_vals[] is created - and initialized to zero in dict_index_add_to_cache(), - along with stat_n_diff_key_vals[] array */ if (n_not_null != NULL) { - index->stat_n_non_null_key_vals[j] = + stat.n_non_null_key_vals = BTR_TABLE_STATS_FROM_SAMPLE( n_not_null[j], index, n_sample_pages, total_external_size, not_empty_flag); } + + result.push_back(stat); } mem_heap_free(heap); - return(true); + return result; } /*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/ diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 37a8a4387d1..e3ce13b5b27 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -267,56 +267,6 @@ dict_mutex_exit_for_mysql(void) mutex_exit(&dict_sys->mutex); } -/** Lock the appropriate latch to protect a given table's statistics. -@param[in] table table whose stats to lock -@param[in] latch_mode RW_S_LATCH or RW_X_LATCH */ -void -dict_table_stats_lock( - dict_table_t* table, - ulint latch_mode) -{ - ut_ad(table != NULL); - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - - switch (latch_mode) { - case RW_S_LATCH: - rw_lock_s_lock(&table->stats_latch); - break; - case RW_X_LATCH: - rw_lock_x_lock(&table->stats_latch); - break; - case RW_NO_LATCH: - /* fall through */ - default: - ut_error; - } -} - -/** Unlock the latch that has been locked by dict_table_stats_lock(). -@param[in] table table whose stats to unlock -@param[in] latch_mode RW_S_LATCH or RW_X_LATCH */ -void -dict_table_stats_unlock( - dict_table_t* table, - ulint latch_mode) -{ - ut_ad(table != NULL); - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - - switch (latch_mode) { - case RW_S_LATCH: - rw_lock_s_unlock(&table->stats_latch); - break; - case RW_X_LATCH: - rw_lock_x_unlock(&table->stats_latch); - break; - case RW_NO_LATCH: - /* fall through */ - default: - ut_error; - } -} - /**********************************************************************//** Try to drop any indexes after an aborted index creation. This can also be after a server kill during DROP INDEX. */ diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index 11d362d32c6..efefa40e69f 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -125,8 +125,7 @@ dict_mem_table_create( ulint n_cols, ulint n_v_cols, ulint flags, - ulint flags2, - bool init_stats_latch) + ulint flags2) { dict_table_t* table; mem_heap_t* heap; @@ -182,12 +181,6 @@ dict_mem_table_create( new(&table->foreign_set) dict_foreign_set(); new(&table->referenced_set) dict_foreign_set(); - if (init_stats_latch) { - rw_lock_create(dict_table_stats_key, &table->stats_latch, - SYNC_INDEX_TREE); - table->stats_latch_inited = true; - } - return(table); } @@ -237,10 +230,6 @@ dict_mem_table_free( UT_DELETE(table->s_cols); } - if (table->stats_latch_inited) { - rw_lock_free(&table->stats_latch); - } - mem_heap_free(table->heap); } diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index 5083fda48ee..bf2645fd65c 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -486,8 +486,6 @@ dict_stats_table_clone_create( ut_d(t->magic_n = DICT_TABLE_MAGIC_N); - rw_lock_create(dict_table_stats_key, &t->stats_latch, SYNC_INDEX_TREE); - return(t); } @@ -500,15 +498,12 @@ dict_stats_table_clone_free( /*========================*/ dict_table_t* t) /*!< in: dummy table object to free */ { - rw_lock_free(&t->stats_latch); mem_heap_free(t->heap); } /*********************************************************************//** Write all zeros (or 1 where it makes sense) into an index -statistics members. The resulting stats correspond to an empty index. -The caller must own index's table stats latch in X mode -(dict_table_stats_lock(table, RW_X_LATCH)) */ +statistics members. The resulting stats correspond to an empty index. */ static void dict_stats_empty_index( @@ -519,6 +514,7 @@ dict_stats_empty_index( { ut_ad(!(index->type & DICT_FTS)); ut_ad(!dict_index_is_ibuf(index)); + ut_ad(mutex_own(&dict_sys->mutex)); ulint n_uniq = index->n_uniq; @@ -548,10 +544,9 @@ dict_stats_empty_table( bool empty_defrag_stats) /*!< in: whether to empty defrag stats */ { + mutex_enter(&dict_sys->mutex); + /* Zero the stats members */ - - dict_table_stats_lock(table, RW_X_LATCH); - table->stat_n_rows = 0; table->stat_clustered_index_size = 1; /* 1 page for each index, not counting the clustered */ @@ -575,8 +570,7 @@ dict_stats_empty_table( } table->stat_initialized = TRUE; - - dict_table_stats_unlock(table, RW_X_LATCH); + mutex_exit(&dict_sys->mutex); } /*********************************************************************//** @@ -675,6 +669,8 @@ dict_stats_copy( to have the same statistics as if the table was empty */ { + ut_ad(mutex_own(&dict_sys->mutex)); + dst->stats_last_recalc = src->stats_last_recalc; dst->stat_n_rows = src->stat_n_rows; dst->stat_clustered_index_size = src->stat_clustered_index_size; @@ -792,8 +788,6 @@ dict_stats_snapshot_create( { mutex_enter(&dict_sys->mutex); - dict_table_stats_lock(table, RW_S_LATCH); - dict_stats_assert_initialized(table); dict_table_t* t; @@ -807,8 +801,6 @@ dict_stats_snapshot_create( t->stats_sample_pages = table->stats_sample_pages; t->stats_bg_flag = table->stats_bg_flag; - dict_table_stats_unlock(table, RW_S_LATCH); - mutex_exit(&dict_sys->mutex); return(t); @@ -848,10 +840,14 @@ dict_stats_update_transient_for_index( Initialize some bogus index cardinality statistics, so that the data can be queried in various means, also via secondary indexes. */ + mutex_enter(&dict_sys->mutex); dict_stats_empty_index(index, false); + mutex_exit(&dict_sys->mutex); #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG } else if (ibuf_debug && !dict_index_is_clust(index)) { + mutex_enter(&dict_sys->mutex); dict_stats_empty_index(index, false); + mutex_exit(&dict_sys->mutex); #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ } else { mtr_t mtr; @@ -874,7 +870,9 @@ dict_stats_update_transient_for_index( switch (size) { case ULINT_UNDEFINED: + mutex_enter(&dict_sys->mutex); dict_stats_empty_index(index, false); + mutex_exit(&dict_sys->mutex); return; case 0: /* The root node of the tree is a leaf */ @@ -886,11 +884,23 @@ dict_stats_update_transient_for_index( /* Do not continue if table decryption has failed or table is already marked as corrupted. */ if (index->is_readable()) { - /* We don't handle the return value since it - will be false only when some thread is - dropping the table and we don't have to empty - the statistics of the to be dropped index */ - btr_estimate_number_of_different_key_vals(index); + std::vector stats + = btr_estimate_number_of_different_key_vals( + index); + + if (!stats.empty()) { + ut_ad(!mutex_own(&dict_sys->mutex)); + mutex_enter(&dict_sys->mutex); + for (size_t i = 0; i < stats.size(); ++i) { + index->stat_n_diff_key_vals[i] + = stats[i].n_diff_key_vals; + index->stat_n_sample_sizes[i] + = stats[i].n_sample_sizes; + index->stat_n_non_null_key_vals[i] + = stats[i].n_non_null_key_vals; + } + mutex_exit(&dict_sys->mutex); + } } } } @@ -907,6 +917,8 @@ dict_stats_update_transient( /*========================*/ dict_table_t* table) /*!< in/out: table */ { + ut_ad(!mutex_own(&dict_sys->mutex)); + dict_index_t* index; ulint sum_of_index_sizes = 0; @@ -932,27 +944,25 @@ dict_stats_update_transient( ut_ad(!dict_index_is_ibuf(index)); - if (index->type & DICT_FTS || dict_index_is_spatial(index)) { + if (index->type & (DICT_FTS | DICT_SPATIAL)) { continue; } - dict_stats_empty_index(index, false); - - if (dict_stats_should_ignore_index(index)) { + if (dict_stats_should_ignore_index(index) + || !index->is_readable()) { + mutex_enter(&dict_sys->mutex); + dict_stats_empty_index(index, false); + mutex_exit(&dict_sys->mutex); continue; } - /* Do not continue if table decryption has failed or - table is already marked as corrupted. */ - if (!index->is_readable()) { - break; - } - dict_stats_update_transient_for_index(index); sum_of_index_sizes += index->stat_index_size; } + mutex_enter(&dict_sys->mutex); + index = dict_table_get_first_index(table); table->stat_n_rows = index->stat_n_diff_key_vals[ @@ -968,6 +978,8 @@ dict_stats_update_transient( table->stat_modified_counter = 0; table->stat_initialized = TRUE; + + mutex_exit(&dict_sys->mutex); } /* @{ Pseudo code about the relation between the following functions @@ -1808,16 +1820,31 @@ dict_stats_analyze_index_for_n_prefix( btr_pcur_close(&pcur); } +/** statistics for an index */ +struct index_stats_t +{ + std::vector stats; + ulint index_size; + ulint n_leaf_pages; + + index_stats_t(ulint n_uniq) : index_size(1), n_leaf_pages(1) + { + stats.reserve(n_uniq); + for (ulint i= 0; i < n_uniq; ++i) + stats.push_back(index_field_stats_t(0, 1, 0)); + } +}; + /** Set dict_index_t::stat_n_diff_key_vals[] and stat_n_sample_sizes[]. @param[in] n_diff_data input data to use to derive the results -@param[in,out] index index whose stat_n_diff_key_vals[] to set */ +@param[in,out] index_stats index stats to set */ UNIV_INLINE void dict_stats_index_set_n_diff( const n_diff_data_t* n_diff_data, - dict_index_t* index) + index_stats_t& index_stats) { - for (ulint n_prefix = dict_index_get_n_unique(index); + for (ulint n_prefix = index_stats.stats.size(); n_prefix >= 1; n_prefix--) { /* n_diff_all_analyzed_pages can be 0 here if @@ -1848,14 +1875,14 @@ dict_stats_index_set_n_diff( that the total number of ordinary leaf pages is T * D / (D + E). */ n_ordinary_leaf_pages - = index->stat_n_leaf_pages + = index_stats.n_leaf_pages * data->n_leaf_pages_to_analyze / (data->n_leaf_pages_to_analyze + data->n_external_pages_sum); } /* See REF01 for an explanation of the algorithm */ - index->stat_n_diff_key_vals[n_prefix - 1] + index_stats.stats[n_prefix - 1].n_diff_key_vals = n_ordinary_leaf_pages * data->n_diff_on_level @@ -1864,7 +1891,7 @@ dict_stats_index_set_n_diff( * data->n_diff_all_analyzed_pages / data->n_leaf_pages_to_analyze; - index->stat_n_sample_sizes[n_prefix - 1] + index_stats.stats[n_prefix - 1].n_sample_sizes = data->n_leaf_pages_to_analyze; DEBUG_PRINTF(" %s(): n_diff=" UINT64PF @@ -1873,9 +1900,9 @@ dict_stats_index_set_n_diff( " * " UINT64PF " / " UINT64PF " * " UINT64PF " / " UINT64PF ")\n", __func__, - index->stat_n_diff_key_vals[n_prefix - 1], + index_stats.stats[n_prefix - 1].n_diff_key_vals, n_prefix, - index->stat_n_leaf_pages, + index_stats.n_leaf_pages, data->n_diff_on_level, data->n_recs_on_level, data->n_diff_all_analyzed_pages, @@ -1883,15 +1910,12 @@ dict_stats_index_set_n_diff( } } -/*********************************************************************//** -Calculates new statistics for a given index and saves them to the index +/** Calculates new statistics for a given index and saves them to the index members stat_n_diff_key_vals[], stat_n_sample_sizes[], stat_index_size and -stat_n_leaf_pages. This function could be slow. */ -static -void -dict_stats_analyze_index( -/*=====================*/ - dict_index_t* index) /*!< in/out: index to analyze */ +stat_n_leaf_pages. This function can be slow. +@param[in] index index to analyze +@return index stats */ +static index_stats_t dict_stats_analyze_index(dict_index_t* index) { ulint root_level; ulint level; @@ -1902,20 +1926,22 @@ dict_stats_analyze_index( ib_uint64_t total_pages; mtr_t mtr; ulint size; + index_stats_t result(index->n_uniq); DBUG_ENTER("dict_stats_analyze_index"); DBUG_PRINT("info", ("index: %s, online status: %d", index->name(), dict_index_get_online_status(index))); + ut_ad(!mutex_own(&dict_sys->mutex)); // because this function is slow + ut_ad(index->table->get_ref_count()); + /* Disable update statistic for Rtree */ if (dict_index_is_spatial(index)) { - DBUG_VOID_RETURN; + DBUG_RETURN(result); } DEBUG_PRINTF(" %s(index=%s)\n", __func__, index->name()); - dict_stats_empty_index(index, false); - mtr_start(&mtr); mtr_s_lock(dict_index_get_lock(index), &mtr); @@ -1923,7 +1949,7 @@ dict_stats_analyze_index( size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr); if (size != ULINT_UNDEFINED) { - index->stat_index_size = size; + result.index_size = size; size = btr_get_size(index, BTR_N_LEAF_PAGES, &mtr); } @@ -1933,13 +1959,13 @@ dict_stats_analyze_index( switch (size) { case ULINT_UNDEFINED: dict_stats_assert_initialized_index(index); - DBUG_VOID_RETURN; + DBUG_RETURN(result); case 0: /* The root node of the tree is a leaf */ size = 1; } - index->stat_n_leaf_pages = size; + result.n_leaf_pages = size; mtr_start(&mtr); @@ -1980,14 +2006,18 @@ dict_stats_analyze_index( NULL /* boundaries not needed */, &mtr); - for (ulint i = 0; i < n_uniq; i++) { - index->stat_n_sample_sizes[i] = total_pages; - } - mtr_commit(&mtr); - dict_stats_assert_initialized_index(index); - DBUG_VOID_RETURN; + mutex_enter(&dict_sys->mutex); + for (ulint i = 0; i < n_uniq; i++) { + result.stats[i].n_diff_key_vals = index->stat_n_diff_key_vals[i]; + result.stats[i].n_sample_sizes = total_pages; + result.stats[i].n_non_null_key_vals = index->stat_n_non_null_key_vals[i]; + } + result.n_leaf_pages = index->stat_n_leaf_pages; + mutex_exit(&dict_sys->mutex); + + DBUG_RETURN(result); } /* For each level that is being scanned in the btree, this contains the @@ -2179,13 +2209,12 @@ found_level: /* n_prefix == 0 means that the above loop did not end up prematurely due to tree being changed and so n_diff_data[] is set up. */ if (n_prefix == 0) { - dict_stats_index_set_n_diff(n_diff_data, index); + dict_stats_index_set_n_diff(n_diff_data, result); } UT_DELETE_ARRAY(n_diff_data); - dict_stats_assert_initialized_index(index); - DBUG_VOID_RETURN; + DBUG_RETURN(result); } /*********************************************************************//** @@ -2203,7 +2232,7 @@ dict_stats_update_persistent( DEBUG_PRINTF("%s(table=%s)\n", __func__, table->name); - dict_table_stats_lock(table, RW_X_LATCH); + DEBUG_SYNC_C("dict_stats_update_persistent"); /* analyze the clustered index first */ @@ -2214,7 +2243,6 @@ dict_stats_update_persistent( || (index->type | DICT_UNIQUE) != (DICT_CLUSTERED | DICT_UNIQUE)) { /* Table definition is corrupt */ - dict_table_stats_unlock(table, RW_X_LATCH); dict_stats_empty_table(table, true); return(DB_CORRUPTION); @@ -2222,7 +2250,16 @@ dict_stats_update_persistent( ut_ad(!dict_index_is_ibuf(index)); - dict_stats_analyze_index(index); + index_stats_t stats = dict_stats_analyze_index(index); + + mutex_enter(&dict_sys->mutex); + index->stat_index_size = stats.index_size; + index->stat_n_leaf_pages = stats.n_leaf_pages; + for (size_t i = 0; i < stats.stats.size(); ++i) { + index->stat_n_diff_key_vals[i] = stats.stats[i].n_diff_key_vals; + index->stat_n_sample_sizes[i] = stats.stats[i].n_sample_sizes; + index->stat_n_non_null_key_vals[i] = stats.stats[i].n_non_null_key_vals; + } ulint n_unique = dict_index_get_n_unique(index); @@ -2240,7 +2277,7 @@ dict_stats_update_persistent( ut_ad(!dict_index_is_ibuf(index)); - if (index->type & DICT_FTS || dict_index_is_spatial(index)) { + if (index->type & (DICT_FTS | DICT_SPATIAL)) { continue; } @@ -2251,7 +2288,20 @@ dict_stats_update_persistent( } if (!(table->stats_bg_flag & BG_STAT_SHOULD_QUIT)) { - dict_stats_analyze_index(index); + mutex_exit(&dict_sys->mutex); + stats = dict_stats_analyze_index(index); + mutex_enter(&dict_sys->mutex); + + index->stat_index_size = stats.index_size; + index->stat_n_leaf_pages = stats.n_leaf_pages; + for (size_t i = 0; i < stats.stats.size(); ++i) { + index->stat_n_diff_key_vals[i] + = stats.stats[i].n_diff_key_vals; + index->stat_n_sample_sizes[i] + = stats.stats[i].n_sample_sizes; + index->stat_n_non_null_key_vals[i] + = stats.stats[i].n_non_null_key_vals; + } } table->stat_sum_of_other_index_sizes @@ -2266,7 +2316,7 @@ dict_stats_update_persistent( dict_stats_assert_initialized(table); - dict_table_stats_unlock(table, RW_X_LATCH); + mutex_exit(&dict_sys->mutex); return(DB_SUCCESS); } @@ -3094,11 +3144,22 @@ dict_stats_update_for_index( if (dict_stats_is_persistent_enabled(index->table)) { if (dict_stats_persistent_storage_check(false)) { - dict_table_stats_lock(index->table, RW_X_LATCH); - dict_stats_analyze_index(index); + index_stats_t stats = dict_stats_analyze_index(index); + mutex_enter(&dict_sys->mutex); + index->stat_index_size = stats.index_size; + index->stat_n_leaf_pages = stats.n_leaf_pages; + for (size_t i = 0; i < stats.stats.size(); ++i) { + index->stat_n_diff_key_vals[i] + = stats.stats[i].n_diff_key_vals; + index->stat_n_sample_sizes[i] + = stats.stats[i].n_sample_sizes; + index->stat_n_non_null_key_vals[i] + = stats.stats[i].n_non_null_key_vals; + } index->table->stat_sum_of_other_index_sizes += index->stat_index_size; - dict_table_stats_unlock(index->table, RW_X_LATCH); + mutex_exit(&dict_sys->mutex); + dict_stats_save(index->table, &index->id); DBUG_VOID_RETURN; } @@ -3119,9 +3180,7 @@ dict_stats_update_for_index( } } - dict_table_stats_lock(index->table, RW_X_LATCH); dict_stats_update_transient_for_index(index); - dict_table_stats_unlock(index->table, RW_X_LATCH); DBUG_VOID_RETURN; } @@ -3275,7 +3334,7 @@ dict_stats_update( switch (err) { case DB_SUCCESS: - dict_table_stats_lock(table, RW_X_LATCH); + mutex_enter(&dict_sys->mutex); /* Pass reset_ignored_indexes=true as parameter to dict_stats_copy. This will cause statictics @@ -3284,7 +3343,7 @@ dict_stats_update( dict_stats_assert_initialized(table); - dict_table_stats_unlock(table, RW_X_LATCH); + mutex_exit(&dict_sys->mutex); dict_stats_table_clone_free(t); @@ -3338,13 +3397,8 @@ dict_stats_update( } transient: - - dict_table_stats_lock(table, RW_X_LATCH); - dict_stats_update_transient(table); - dict_table_stats_unlock(table, RW_X_LATCH); - return(DB_SUCCESS); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 3db462ee92d..0617005a213 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -672,7 +672,6 @@ static PSI_rwlock_info all_innodb_rwlocks[] = { PSI_RWLOCK_KEY(trx_purge_latch), PSI_RWLOCK_KEY(index_tree_rw_lock), PSI_RWLOCK_KEY(index_online_log), - PSI_RWLOCK_KEY(dict_table_stats), PSI_RWLOCK_KEY(hash_table_locks) }; # endif /* UNIV_PFS_RWLOCK */ @@ -14341,6 +14340,8 @@ ha_innobase::info_low( DEBUG_SYNC_C("ha_innobase_info_low"); + ut_ad(!mutex_own(&dict_sys->mutex)); + /* If we are forcing recovery at a high level, we will suppress statistics calculation on tables, because that may crash the server if an index is badly corrupted. */ @@ -14377,7 +14378,6 @@ ha_innobase::info_low( opt = DICT_STATS_RECALC_TRANSIENT; } - ut_ad(!mutex_own(&dict_sys->mutex)); ret = dict_stats_update(ib_table, opt); if (ret != DB_SUCCESS) { @@ -14398,9 +14398,7 @@ ha_innobase::info_low( ulint stat_clustered_index_size; ulint stat_sum_of_other_index_sizes; - if (!(flag & HA_STATUS_NO_LOCK)) { - dict_table_stats_lock(ib_table, RW_S_LATCH); - } + mutex_enter(&dict_sys->mutex); ut_a(ib_table->stat_initialized); @@ -14412,9 +14410,7 @@ ha_innobase::info_low( stat_sum_of_other_index_sizes = ib_table->stat_sum_of_other_index_sizes; - if (!(flag & HA_STATUS_NO_LOCK)) { - dict_table_stats_unlock(ib_table, RW_S_LATCH); - } + mutex_exit(&dict_sys->mutex); /* The MySQL optimizer seems to assume in a left join that n_rows @@ -14563,10 +14559,27 @@ ha_innobase::info_low( ib_push_frm_error(m_user_thd, ib_table, table, num_innodb_index, true); } - if (!(flag & HA_STATUS_NO_LOCK)) { - dict_table_stats_lock(ib_table, RW_S_LATCH); + + snprintf(path, sizeof(path), "%s/%s%s", + mysql_data_home, table->s->normalized_path.str, + reg_ext); + + unpack_filename(path,path); + + /* Note that we do not know the access time of the table, + nor the CHECK TABLE time, nor the UPDATE or INSERT time. */ + + if (os_file_get_status( + path, &stat_info, false, + srv_read_only_mode) == DB_SUCCESS) { + stats.create_time = (ulong) stat_info.ctime; } + struct Locking { + Locking() { mutex_enter(&dict_sys->mutex); } + ~Locking() { mutex_exit(&dict_sys->mutex); } + } locking; + ut_a(ib_table->stat_initialized); for (i = 0; i < table->s->keys; i++) { @@ -14644,25 +14657,6 @@ ha_innobase::info_low( key->rec_per_key[j] = rec_per_key_int; } } - - if (!(flag & HA_STATUS_NO_LOCK)) { - dict_table_stats_unlock(ib_table, RW_S_LATCH); - } - - snprintf(path, sizeof(path), "%s/%s%s", - mysql_data_home, table->s->normalized_path.str, - reg_ext); - - unpack_filename(path,path); - - /* Note that we do not know the access time of the table, - nor the CHECK TABLE time, nor the UPDATE or INSERT time. */ - - if (os_file_get_status( - path, &stat_info, false, - srv_read_only_mode) == DB_SUCCESS) { - stats.create_time = (ulong) stat_info.ctime; - } } if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 1140b8b252a..003760f80b1 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -6317,38 +6317,43 @@ i_s_dict_fill_sys_tablestats( OK(field_store_string(fields[SYS_TABLESTATS_NAME], table->name.m_name)); - dict_table_stats_lock(table, RW_S_LATCH); + { + struct Locking + { + Locking() { mutex_enter(&dict_sys->mutex); } + ~Locking() { mutex_exit(&dict_sys->mutex); } + } locking; - if (table->stat_initialized) { - OK(field_store_string(fields[SYS_TABLESTATS_INIT], - "Initialized")); + if (table->stat_initialized) { + OK(field_store_string(fields[SYS_TABLESTATS_INIT], + "Initialized")); - OK(fields[SYS_TABLESTATS_NROW]->store(table->stat_n_rows, - true)); + OK(fields[SYS_TABLESTATS_NROW]->store( + table->stat_n_rows, true)); - OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store( - table->stat_clustered_index_size, true)); + OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store( + table->stat_clustered_index_size, true)); - OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store( - table->stat_sum_of_other_index_sizes, true)); + OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store( + table->stat_sum_of_other_index_sizes, + true)); - OK(fields[SYS_TABLESTATS_MODIFIED]->store( - table->stat_modified_counter, true)); - } else { - OK(field_store_string(fields[SYS_TABLESTATS_INIT], - "Uninitialized")); + OK(fields[SYS_TABLESTATS_MODIFIED]->store( + table->stat_modified_counter, true)); + } else { + OK(field_store_string(fields[SYS_TABLESTATS_INIT], + "Uninitialized")); - OK(fields[SYS_TABLESTATS_NROW]->store(0, true)); + OK(fields[SYS_TABLESTATS_NROW]->store(0, true)); - OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(0, true)); + OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(0, true)); - OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(0, true)); + OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(0, true)); - OK(fields[SYS_TABLESTATS_MODIFIED]->store(0, true)); + OK(fields[SYS_TABLESTATS_MODIFIED]->store(0, true)); + } } - dict_table_stats_unlock(table, RW_S_LATCH); - OK(fields[SYS_TABLESTATS_AUTONINC]->store(table->autoinc, true)); OK(fields[SYS_TABLESTATS_TABLE_REF_COUNT]->store(ref_count, true)); diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index 37666cdf372..7068dab77a4 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -1447,7 +1447,7 @@ ibuf_dummy_index_create( table = dict_mem_table_create("IBUF_DUMMY", DICT_HDR_SPACE, n, 0, - comp ? DICT_TF_COMPACT : 0, 0, false); + comp ? DICT_TF_COMPACT : 0, 0); index = dict_mem_index_create("IBUF_DUMMY", "IBUF_DUMMY", DICT_HDR_SPACE, 0, n); diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index 5bc0b70714c..29ece955702 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -213,7 +213,7 @@ the index. ulint btr_height_get( /*===========*/ - dict_index_t* index, /*!< in: index tree */ + const dict_index_t* index, /*!< in: index tree */ mtr_t* mtr) /*!< in/out: mini-transaction */ MY_ATTRIBUTE((warn_unused_result)); @@ -585,7 +585,7 @@ Gets the number of pages in a B-tree. ulint btr_get_size( /*=========*/ - dict_index_t* index, /*!< in: index */ + const dict_index_t* index, /*!< in: index */ ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */ mtr_t* mtr) /*!< in/out: mini-transaction where index is s-latched */ diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index f70fe687182..2f49ac6d12f 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -592,8 +592,24 @@ btr_estimate_n_rows_in_range( const dtuple_t* tuple2, page_cur_mode_t mode2); -/*******************************************************************//** -Estimates the number of different key values in a given index, for + +/** Statistics for one field of an index. */ +struct index_field_stats_t +{ + ib_uint64_t n_diff_key_vals; + ib_uint64_t n_sample_sizes; + ib_uint64_t n_non_null_key_vals; + + index_field_stats_t(ib_uint64_t n_diff_key_vals= 0, + ib_uint64_t n_sample_sizes= 0, + ib_uint64_t n_non_null_key_vals= 0) + : n_diff_key_vals(n_diff_key_vals), n_sample_sizes(n_sample_sizes), + n_non_null_key_vals(n_non_null_key_vals) + { + } +}; + +/** Estimates the number of different key values in a given index, for each n-column prefix of the index where 1 <= n <= dict_index_get_n_unique(index). The estimates are stored in the array index->stat_n_diff_key_vals[] (indexed 0..n_uniq-1) and the number of pages that were sampled is saved in @@ -601,12 +617,11 @@ index->stat_n_sample_sizes[]. If innodb_stats_method is nulls_ignored, we also record the number of non-null values for each prefix and stored the estimates in array index->stat_n_non_null_key_vals. -@return true if the index is available and we get the estimated numbers, -false if the index is unavailable. */ -bool -btr_estimate_number_of_different_key_vals( -/*======================================*/ - dict_index_t* index); /*!< in: index */ +@param[in] index index +@return stat vector if the index is available and we get the estimated numbers, +empty vector if the index is unavailable. */ +std::vector +btr_estimate_number_of_different_key_vals(dict_index_t* index); /** Gets the externally stored size of a record, in units of a database page. @param[in] rec record diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 49e884d064d..7351b5fb682 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -1459,7 +1459,7 @@ UNIV_INLINE rw_lock_t* dict_index_get_lock( /*================*/ - dict_index_t* index) /*!< in: index */ + const dict_index_t* index) /*!< in: index */ MY_ATTRIBUTE((nonnull, warn_unused_result)); /********************************************************************//** Returns free space reserved for future updates of records. This is @@ -1524,22 +1524,6 @@ void dict_mutex_exit_for_mysql(void); /*===========================*/ -/** Lock the appropriate latch to protect a given table's statistics. -@param[in] table table whose stats to lock -@param[in] latch_mode RW_S_LATCH or RW_X_LATCH */ -void -dict_table_stats_lock( - dict_table_t* table, - ulint latch_mode); - -/** Unlock the latch that has been locked by dict_table_stats_lock(). -@param[in] table table whose stats to unlock -@param[in] latch_mode RW_S_LATCH or RW_X_LATCH */ -void -dict_table_stats_unlock( - dict_table_t* table, - ulint latch_mode); - /********************************************************************//** Checks if the database name in two table names is the same. @return TRUE if same db name */ diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index 3b68e113aa5..554bfdd50ac 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -1181,7 +1181,7 @@ UNIV_INLINE rw_lock_t* dict_index_get_lock( /*================*/ - dict_index_t* index) /*!< in: index */ + const dict_index_t* index) /*!< in: index */ { ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 3c7913d7f39..a4defe4d92a 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -307,7 +307,6 @@ before proceeds. */ @param[in] n_v_cols number of virtual columns @param[in] flags table flags @param[in] flags2 table flags2 -@param[in] init_stats_latch whether to init the stats latch @return own: table object */ dict_table_t* dict_mem_table_create( @@ -316,8 +315,7 @@ dict_mem_table_create( ulint n_cols, ulint n_v_cols, ulint flags, - ulint flags2, - bool init_stats_latch=true); + ulint flags2); /****************************************************************//** Free a table memory object. */ @@ -970,7 +968,7 @@ struct dict_index_t{ when InnoDB was started up */ zip_pad_info_t zip_pad;/*!< Information about state of compression failures and successes */ - rw_lock_t lock; /*!< read-write lock protecting the + mutable rw_lock_t lock; /*!< read-write lock protecting the upper levels of the index tree */ /** Determine if the index has been committed to the @@ -1691,23 +1689,8 @@ struct dict_table_t { /*!< set of foreign key constraints which refer to this table */ dict_foreign_set referenced_set; - /** Statistics for query optimization. @{ */ - - /** Creation state of 'stats_latch'. */ - bool stats_latch_inited; - - /** This latch protects: - dict_table_t::stat_initialized, - dict_table_t::stat_n_rows (*), - dict_table_t::stat_clustered_index_size, - dict_table_t::stat_sum_of_other_index_sizes, - dict_table_t::stat_modified_counter (*), - dict_table_t::indexes*::stat_n_diff_key_vals[], - dict_table_t::indexes*::stat_index_size, - dict_table_t::indexes*::stat_n_leaf_pages. - (*) Those are not always protected for - performance reasons. */ - rw_lock_t stats_latch; + /** Statistics for query optimization. Mostly protected by + dict_sys->mutex. @{ */ /** TRUE if statistics have been calculated the first time after database startup or table creation. */ diff --git a/storage/innobase/include/dict0stats.ic b/storage/innobase/include/dict0stats.ic index 98024935e16..c467ee1f3ac 100644 --- a/storage/innobase/include/dict0stats.ic +++ b/storage/innobase/include/dict0stats.ic @@ -75,7 +75,7 @@ dict_stats_is_persistent_enabled(const dict_table_t* table) + dict_stats_update(DICT_STATS_RECALC_TRANSIENT) on a table that has just been PS-enabled. This is acceptable. Avoiding this would mean that we would have to - protect the ::stat_persistent with dict_table_stats_lock() like the + protect the ::stat_persistent with dict_sys->mutex like the other ::stat_ members which would be too big performance penalty, especially when this function is called from dict_stats_update_if_needed(). */ @@ -178,10 +178,7 @@ dict_stats_deinit( ut_a(table->get_ref_count() == 0); - dict_table_stats_lock(table, RW_X_LATCH); - if (!table->stat_initialized) { - dict_table_stats_unlock(table, RW_X_LATCH); return; } @@ -221,6 +218,4 @@ dict_stats_deinit( sizeof(index->stat_n_leaf_pages)); } #endif /* HAVE_valgrind_or_MSAN */ - - dict_table_stats_unlock(table, RW_X_LATCH); } diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index 0438d9d0c92..037bf8047cd 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -126,7 +126,6 @@ extern mysql_pfs_key_t trx_i_s_cache_lock_key; extern mysql_pfs_key_t trx_purge_latch_key; extern mysql_pfs_key_t index_tree_rw_lock_key; extern mysql_pfs_key_t index_online_log_key; -extern mysql_pfs_key_t dict_table_stats_key; extern mysql_pfs_key_t trx_sys_rw_lock_key; extern mysql_pfs_key_t hash_table_locks_key; #endif /* UNIV_PFS_RWLOCK */ diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 6704c5cff00..312c35c58a3 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1512,7 +1512,7 @@ error_exit: srv_stats.n_rows_inserted.inc(size_t(trx->id)); } - /* Not protected by dict_table_stats_lock() for performance + /* Not protected by dict_sys->mutex for performance reasons, we would rather get garbage in stat_n_rows (which is just an estimate anyway) than protecting the following code with a latch. */ @@ -1870,7 +1870,7 @@ row_update_for_mysql(row_prebuilt_t* prebuilt) ut_ad(node->is_delete == is_delete); if (/*node->*/is_delete) { - /* Not protected by dict_table_stats_lock() for performance + /* Not protected by dict_sys->mutex for performance reasons, we would rather get garbage in stat_n_rows (which is just an estimate anyway) than protecting the following code with a latch. */ @@ -2131,7 +2131,7 @@ row_update_cascade_for_mysql( if (node->is_delete) { /* Not protected by - dict_table_stats_lock() for + dict_sys->mutex for performance reasons, we would rather get garbage in stat_n_rows (which is just an estimate anyway) than diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc index 54fa244fca6..915d4b99d16 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -524,7 +524,7 @@ row_undo_ins( } if (err == DB_SUCCESS && node->table->stat_initialized) { - /* Not protected by dict_table_stats_lock() for + /* Not protected by dict_sys->mutex for performance reasons, we would rather get garbage in stat_n_rows (which is just an estimate anyway) than protecting the following code with a latch. */ diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc index edcb886fe5c..89db512da2a 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -1473,9 +1473,6 @@ sync_latch_meta_init() LATCH_ADD_RWLOCK(INDEX_TREE, SYNC_INDEX_TREE, index_tree_rw_lock_key); - LATCH_ADD_RWLOCK(DICT_TABLE_STATS, SYNC_INDEX_TREE, - dict_table_stats_key); - LATCH_ADD_RWLOCK(HASH_TABLE_RW_LOCK, SYNC_BUF_PAGE_HASH, hash_table_locks_key); diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc index 2e5558a3294..81bce39df33 100644 --- a/storage/innobase/sync/sync0sync.cc +++ b/storage/innobase/sync/sync0sync.cc @@ -102,7 +102,6 @@ mysql_pfs_key_t buf_block_debug_latch_key; # endif /* UNIV_DEBUG */ mysql_pfs_key_t checkpoint_lock_key; mysql_pfs_key_t dict_operation_lock_key; -mysql_pfs_key_t dict_table_stats_key; mysql_pfs_key_t hash_table_locks_key; mysql_pfs_key_t index_tree_rw_lock_key; mysql_pfs_key_t index_online_log_key; From 3829b408d689182f05804ec045c9705da8de4e34 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 27 Oct 2020 20:31:16 +0100 Subject: [PATCH 261/323] MDEV-24040 Named pipe permission issue Tighten access control - deny FILE_CREATE_PIPE_INSTANCE permission to everyone except current user (the one that runs mysqld) --- sql/mysqld.cc | 70 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8d00b5af948..3a5222d32de 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2582,6 +2582,62 @@ static MYSQL_SOCKET activate_tcp_port(uint port) DBUG_RETURN(ip_sock); } +#ifdef _WIN32 +/* + Create a security descriptor for pipe. + - Use low integrity level, so that it is possible to connect + from any process. + - Give current user read/write access to pipe. + - Give Everyone read/write access to pipe minus FILE_CREATE_PIPE_INSTANCE +*/ +static void init_pipe_security_descriptor() +{ +#define SDDL_FMT "S:(ML;; NW;;; LW) D:(A;; 0x%08x;;; WD)(A;; FRFW;;; %s)" +#define EVERYONE_PIPE_ACCESS_MASK \ + (FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | READ_CONTROL | \ + SYNCHRONIZE | FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) + + /* + Figure out SID of the user that runs the server, then create SDDL string + for pipe permissions, and convert it to the security descriptor. + */ + char sddl_string[sizeof(SDDL_FMT) + 8 + SECURITY_MAX_SID_STRING_CHARACTERS]; + struct + { + TOKEN_USER token_user; + BYTE buffer[SECURITY_MAX_SID_SIZE]; + } token_buffer; + HANDLE token; + DWORD tmp; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) + goto fail; + + if (!GetTokenInformation(token, TokenUser, &token_buffer, + (DWORD) sizeof(token_buffer), &tmp)) + goto fail; + + CloseHandle(token); + + char *current_user_string_sid; + if (!ConvertSidToStringSid(token_buffer.token_user.User.Sid, + ¤t_user_string_sid)) + goto fail; + + snprintf(sddl_string, sizeof(sddl_string), SDDL_FMT, + EVERYONE_PIPE_ACCESS_MASK, current_user_string_sid); + LocalFree(current_user_string_sid); + + if (ConvertStringSecurityDescriptorToSecurityDescriptor(sddl_string, + SDDL_REVISION_1, &saPipeSecurity.lpSecurityDescriptor, 0)) + return; + +fail: + sql_perror("Can't start server : Initialize security descriptor"); + unireg_abort(1); +} +#endif + static void network_init(void) { #ifdef HAVE_SYS_UN_H @@ -2619,19 +2675,7 @@ static void network_init(void) strxnmov(pipe_name, sizeof(pipe_name)-1, "\\\\.\\pipe\\", mysqld_unix_port, NullS); - /* - Create a security descriptor for pipe. - - Use low integrity level, so that it is possible to connect - from any process. - - Give Everyone read/write access to pipe. - */ - if (!ConvertStringSecurityDescriptorToSecurityDescriptor( - "S:(ML;; NW;;; LW) D:(A;; FRFW;;; WD)", - SDDL_REVISION_1, &saPipeSecurity.lpSecurityDescriptor, NULL)) - { - sql_perror("Can't start server : Initialize security descriptor"); - unireg_abort(1); - } + init_pipe_security_descriptor(); saPipeSecurity.nLength = sizeof(SECURITY_ATTRIBUTES); saPipeSecurity.bInheritHandle = FALSE; if ((hPipe= CreateNamedPipe(pipe_name, From 46c273892eb56d3ebd1fbfcdd06e5ce337ce30e7 Mon Sep 17 00:00:00 2001 From: Daniele Sciascia Date: Thu, 8 Oct 2020 13:15:18 +0200 Subject: [PATCH 262/323] MDEV-23623 - Fix assertion in MTR test galera_sr.GCF-1051 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix assertion `thd->in_active_multi_stmt_transaction() || thd->m_transaction_psi == __null' failed on MTR test galera_sr.GCF-1051. Add a new MTR test MDEV-23623 that reproduces the issue deterministically and update wsrep-lib submodule, containing the actual fix. Reviewed-by: Jan Lindström --- .../suite/galera_sr/r/MDEV-23623.result | 26 ++++++++++ mysql-test/suite/galera_sr/t/MDEV-23623.test | 50 +++++++++++++++++++ wsrep-lib | 2 +- 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/galera_sr/r/MDEV-23623.result create mode 100644 mysql-test/suite/galera_sr/t/MDEV-23623.test diff --git a/mysql-test/suite/galera_sr/r/MDEV-23623.result b/mysql-test/suite/galera_sr/r/MDEV-23623.result new file mode 100644 index 00000000000..edba2a16bcb --- /dev/null +++ b/mysql-test/suite/galera_sr/r/MDEV-23623.result @@ -0,0 +1,26 @@ +connection node_2; +connection node_1; +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB; +INSERT INTO t1 (f2) VALUES ('a'); +INSERT INTO t1 (f2) VALUES ('b'); +INSERT INTO t1 (f2) VALUES ('c'); +connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; +connection node_2a; +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_provider_options = 'dbug=d,after_certify_apply_monitor_enter'; +connection node_2; +SET SESSION wsrep_retry_autocommit = 0; +SET SESSION wsrep_trx_fragment_size = 64; +DELETE FROM t1 ORDER BY f1 DESC LIMIT 2;; +connection node_2a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +connection node_1; +INSERT INTO t1 (f2) VALUES ('d'),('e'); +connection node_2a; +SET GLOBAL wsrep_provider_options = 'signal=after_certify_apply_monitor_enter'; +SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_2; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +connection node_1; +DROP TABLE t1; diff --git a/mysql-test/suite/galera_sr/t/MDEV-23623.test b/mysql-test/suite/galera_sr/t/MDEV-23623.test new file mode 100644 index 00000000000..2fe728f42bb --- /dev/null +++ b/mysql-test/suite/galera_sr/t/MDEV-23623.test @@ -0,0 +1,50 @@ +# +# MDEV-23623 - trans_commit_stmt(THD*): Assertion +# `thd->in_active_multi_stmt_transaction() || +# thd->m_transaction_psi == __null' failed +# + +--source include/galera_cluster.inc +--source include/have_debug_sync.inc +--source include/galera_have_debug_sync.inc + +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB; +INSERT INTO t1 (f2) VALUES ('a'); +INSERT INTO t1 (f2) VALUES ('b'); +INSERT INTO t1 (f2) VALUES ('c'); + +--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2 +--connection node_2a +SET SESSION wsrep_sync_wait = 0; +--let $galera_sync_point = after_certify_apply_monitor_enter +--source include/galera_set_sync_point.inc + +--connection node_2 +SET SESSION wsrep_retry_autocommit = 0; +SET SESSION wsrep_trx_fragment_size = 64; +--send DELETE FROM t1 ORDER BY f1 DESC LIMIT 2; + +--connection node_2a +--source include/galera_wait_sync_point.inc + +# +# This is going to cause a certification +# failure on node_2 +# +--connection node_1 +INSERT INTO t1 (f2) VALUES ('d'),('e'); + +--connection node_2a +--source include/galera_signal_sync_point.inc +--source include/galera_clear_sync_point.inc + +--connection node_2 +--error ER_LOCK_DEADLOCK +--reap + +# +# Assertion would happen when the following +# DROP TABLE is applied on node_2 +# +--connection node_1 +DROP TABLE t1; diff --git a/wsrep-lib b/wsrep-lib index ae4e58ba031..2da6e4894e1 160000 --- a/wsrep-lib +++ b/wsrep-lib @@ -1 +1 @@ -Subproject commit ae4e58ba031587039c8830f2f8ca51fa9fb7d6eb +Subproject commit 2da6e4894e1df5d1db51db2bbc49255e02251b9d From db56f9b8521077c119d700927510c7a0e54bd820 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Mon, 26 Oct 2020 12:05:47 +0530 Subject: [PATCH 263/323] MDEV-24015: SQL Error (1038): Out of sort memory when enough memory for the sort buffer is provided For a correlated subquery filesort is executed multiple times. During each execution, sortlength() computed total sort key length in Sort_keys::sort_length, without resetting it first. Eventually Sort_keys::sort_length got larger than @@sort_buffer_size, which caused filesort() to be aborted with error. Fixed by making sortlength() to compute lengths only during the first invocation. Subsequent invocations return pre-computed values. --- mysql-test/main/order_by.result | 121 ++++++++++++++++++++++++++++++++ mysql-test/main/order_by.test | 20 ++++++ sql/filesort.cc | 10 ++- sql/sql_sort.h | 50 +++++++++---- 4 files changed, 188 insertions(+), 13 deletions(-) diff --git a/mysql-test/main/order_by.result b/mysql-test/main/order_by.result index a3811ca61e2..806b7b9eea6 100644 --- a/mysql-test/main/order_by.result +++ b/mysql-test/main/order_by.result @@ -4123,4 +4123,125 @@ f baz foo DROP TABLE t1; +# +# MDEV-24015: SQL Error (1038): Out of sort memory when enough memory for the +# sort buffer is provided +# +CREATE TABLE t1 (a VARCHAR(100), b INT); +CREATE TABLE t2 (a VARCHAR(100), b INT); +INSERT INTO t1 SELECT 'abc', seq FROM seq_1_to_50; +INSERT INTO t2 SELECT seq, seq FROM seq_1_to_50; +set @save_sort_buffer_size= @@sort_buffer_size; +set sort_buffer_size=2000; +ANALYZE FORMAT=JSON +SELECT (SELECT sum(t2.b) FROM t2 WHERE t1.b=t2.b GROUP BY t2.a) FROM t1; +ANALYZE +{ + "query_block": { + "select_id": 1, + "r_loops": 1, + "r_total_time_ms": "REPLACED", + "table": { + "table_name": "t1", + "access_type": "ALL", + "r_loops": 1, + "rows": 50, + "r_rows": 50, + "r_table_time_ms": "REPLACED", + "r_other_time_ms": "REPLACED", + "filtered": 100, + "r_filtered": 100 + }, + "subqueries": [ + { + "expression_cache": { + "r_loops": 50, + "r_hit_ratio": 0, + "query_block": { + "select_id": 2, + "r_loops": 50, + "r_total_time_ms": "REPLACED", + "filesort": { + "sort_key": "t2.a", + "r_loops": 50, + "r_total_time_ms": "REPLACED", + "r_used_priority_queue": false, + "r_output_rows": 1, + "r_buffer_size": "REPLACED" across executions)", + "r_sort_mode": "sort_key,rowid", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "r_loops": 50, + "rows": 50, + "r_rows": 50, + "r_table_time_ms": "REPLACED", + "r_other_time_ms": "REPLACED", + "filtered": 100, + "r_filtered": 2, + "attached_condition": "t1.b = t2.b" + } + } + } + } + } + } + ] + } +} +SELECT (SELECT sum(t2.b) FROM t2 WHERE t1.b=t2.b GROUP BY t2.a) FROM t1; +(SELECT sum(t2.b) FROM t2 WHERE t1.b=t2.b GROUP BY t2.a) +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +set sort_buffer_size= @save_sort_buffer_size; +DROP TABLE t1,t2; # End of 10.5 tests diff --git a/mysql-test/main/order_by.test b/mysql-test/main/order_by.test index 8e0b479e02d..88d5250bb4c 100644 --- a/mysql-test/main/order_by.test +++ b/mysql-test/main/order_by.test @@ -2556,4 +2556,24 @@ INSERT t1 VALUES ('foo','bar'),('baz','qux'); SELECT COALESCE(a, b) AS f FROM t1 ORDER BY f; DROP TABLE t1; +--echo # +--echo # MDEV-24015: SQL Error (1038): Out of sort memory when enough memory for the +--echo # sort buffer is provided +--echo # + +CREATE TABLE t1 (a VARCHAR(100), b INT); +CREATE TABLE t2 (a VARCHAR(100), b INT); + +INSERT INTO t1 SELECT 'abc', seq FROM seq_1_to_50; +INSERT INTO t2 SELECT seq, seq FROM seq_1_to_50; + +set @save_sort_buffer_size= @@sort_buffer_size; +set sort_buffer_size=2000; +--source include/analyze-format.inc +ANALYZE FORMAT=JSON +SELECT (SELECT sum(t2.b) FROM t2 WHERE t1.b=t2.b GROUP BY t2.a) FROM t1; +SELECT (SELECT sum(t2.b) FROM t2 WHERE t1.b=t2.b GROUP BY t2.a) FROM t1; + +set sort_buffer_size= @save_sort_buffer_size; +DROP TABLE t1,t2; --echo # End of 10.5 tests diff --git a/sql/filesort.cc b/sql/filesort.cc index 2ce532308a2..b261f089313 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -2199,6 +2199,12 @@ sortlength(THD *thd, Sort_keys *sort_keys, bool *allow_packing_for_sortkeys) length=0; uint nullable_cols=0; + if (sort_keys->is_parameters_computed()) + { + *allow_packing_for_sortkeys= sort_keys->using_packed_sortkeys(); + return sort_keys->get_sort_length_with_memcmp_values(); + } + for (SORT_FIELD *sortorder= sort_keys->begin(); sortorder != sort_keys->end(); sortorder++) @@ -2260,6 +2266,8 @@ sortlength(THD *thd, Sort_keys *sort_keys, bool *allow_packing_for_sortkeys) // add bytes for nullable_cols sort_keys->increment_original_sort_length(nullable_cols); *allow_packing_for_sortkeys= allow_packing_for_keys; + sort_keys->set_sort_length_with_memcmp_values(length + nullable_cols); + sort_keys->set_parameters_computed(true); DBUG_PRINT("info",("sort_length: %d",length)); return length + nullable_cols; } @@ -2518,7 +2526,7 @@ void Sort_param::try_to_pack_sortkeys() return; const uint sz= Sort_keys::size_of_length_field; - uint sort_len= sort_keys->get_sort_length(); + uint sort_len= sort_keys->get_sort_length_with_original_values(); /* Heuristic introduced, skip packing sort keys if saving less than 128 bytes diff --git a/sql/sql_sort.h b/sql/sql_sort.h index 40f0c5ede5f..a474d7c25e9 100644 --- a/sql/sql_sort.h +++ b/sql/sql_sort.h @@ -255,10 +255,12 @@ class Sort_keys :public Sql_alloc, { public: Sort_keys(SORT_FIELD* arr, size_t count): - Sort_keys_array(arr, count), - m_using_packed_sortkeys(false), - size_of_packable_fields(0), - sort_length(0) + Sort_keys_array(arr, count), + m_using_packed_sortkeys(false), + size_of_packable_fields(0), + sort_length_with_original_values(0), + sort_length_with_memcmp_values(0), + parameters_computed(false) { DBUG_ASSERT(!is_null()); } @@ -280,14 +282,24 @@ public: return size_of_packable_fields; } - void set_sort_length(uint len) + void set_sort_length_with_original_values(uint len) { - sort_length= len; + sort_length_with_original_values= len; } - uint get_sort_length() + uint get_sort_length_with_original_values() { - return sort_length; + return sort_length_with_original_values; + } + + void set_sort_length_with_memcmp_values(uint len) + { + sort_length_with_memcmp_values= len; + } + + uint get_sort_length_with_memcmp_values() + { + return sort_length_with_memcmp_values; } static void store_sortkey_length(uchar *p, uint sz) @@ -307,9 +319,12 @@ public: void increment_original_sort_length(uint len) { - sort_length+= len; + sort_length_with_original_values+= len; } + bool is_parameters_computed() { return parameters_computed; } + void set_parameters_computed(bool val) { parameters_computed= val; } + static const uint size_of_length_field= 4; private: @@ -317,10 +332,21 @@ private: uint size_of_packable_fields; // Total length bytes for packable columns /* - The length that would be needed if we stored non-packed mem-comparable - images of fields? + The sort length for all the keyparts storing the original values */ - uint sort_length; + uint sort_length_with_original_values; + + /* + The sort length for all the keyparts storing the mem-comparable images + */ + uint sort_length_with_memcmp_values; + + /* + TRUE parameters(like sort_length_* , size_of_packable_field) + are computed + FALSE otherwise. + */ + bool parameters_computed; }; From 527ade25909bf63655ba1f8965096d105ff55368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 28 Oct 2020 07:27:18 +0200 Subject: [PATCH 264/323] MDEV-23163 Merge new release of InnoDB 5.7.32 to 10.2 All relevant InnoDB changes from MySQL 5.7.32 have been applied in preceding commits. --- storage/innobase/include/univ.i | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index c7474cff4ea..7819b0ae92b 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -41,7 +41,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 5 #define INNODB_VERSION_MINOR 7 -#define INNODB_VERSION_BUGFIX 31 +#define INNODB_VERSION_BUGFIX 32 /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; From cc5f4428b8b568f98e967a57178efcaf78702168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 28 Oct 2020 08:13:06 +0200 Subject: [PATCH 265/323] MDEV-23693 fixup: Remove unused btr_search_t::withdraw_clock --- storage/innobase/include/btr0sea.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h index f2e208df6eb..a9781c65491 100644 --- a/storage/innobase/include/btr0sea.h +++ b/storage/innobase/include/btr0sea.h @@ -230,8 +230,6 @@ struct btr_search_t{ the machine word, i.e., they cannot be turned into bit-fields. */ buf_block_t* root_guess;/*!< the root page frame when it was last time fetched, or NULL */ - ulint withdraw_clock; /*!< the withdraw clock value of the buffer - pool when root_guess was stored */ #ifdef BTR_CUR_HASH_ADAPT ulint hash_analysis; /*!< when this exceeds BTR_SEARCH_HASH_ANALYSIS, the hash From 9478368d8193a7ccc14a1b336ef767aed500909c Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 27 Oct 2020 20:54:03 +0100 Subject: [PATCH 266/323] MDEV-24037 Use NtFlushBuffersFileEx(FLUSH_FLAGS_FILE_DATA_SYNC_ONLY) on Windows This avoids flushing file metadata on NTFS , and writing to :\$Log file. With heavy write workload this can consume up to 1/3 of the server's IO bandwidth. Reviewed by : Marko --- storage/innobase/os/os0file.cc | 59 ++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 3afb68d26a1..24134479d8e 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -1891,39 +1891,56 @@ os_file_status_win32( return(true); } +/* Dynamically load NtFlushBuffersFileEx, used in os_file_flush_func */ +#include +typedef NTSTATUS(WINAPI* pNtFlushBuffersFileEx)( + HANDLE FileHandle, ULONG Flags, PVOID Parameters, ULONG ParametersSize, + PIO_STATUS_BLOCK IoStatusBlock); + +static pNtFlushBuffersFileEx my_NtFlushBuffersFileEx + = (pNtFlushBuffersFileEx)GetProcAddress(GetModuleHandle("ntdll"), + "NtFlushBuffersFileEx"); + /** NOTE! Use the corresponding macro os_file_flush(), not directly this function! Flushes the write buffers of a given file to the disk. @param[in] file handle to a file @return true if success */ -bool -os_file_flush_func( - os_file_t file) +bool os_file_flush_func(os_file_t file) { - ++os_n_fsyncs; + ++os_n_fsyncs; + static bool disable_datasync; - BOOL ret = FlushFileBuffers(file); + if (my_NtFlushBuffersFileEx && !disable_datasync) + { + IO_STATUS_BLOCK iosb{}; + NTSTATUS status= my_NtFlushBuffersFileEx( + file, FLUSH_FLAGS_FILE_DATA_SYNC_ONLY, nullptr, 0, &iosb); + if (!status) + return true; + /* + NtFlushBuffersFileEx(FLUSH_FLAGS_FILE_DATA_SYNC_ONLY) might fail + unless on Win10+, and maybe non-NTFS. Switch to using FlushFileBuffers(). + */ + disable_datasync= true; + } - if (ret) { - return(true); - } + if (FlushFileBuffers(file)) + return true; - /* Since Windows returns ERROR_INVALID_FUNCTION if the 'file' is - actually a raw device, we choose to ignore that error if we are using - raw disks */ + /* Since Windows returns ERROR_INVALID_FUNCTION if the 'file' is + actually a raw device, we choose to ignore that error if we are using + raw disks */ + if (srv_start_raw_disk_in_use && GetLastError() == ERROR_INVALID_FUNCTION) + return true; - if (srv_start_raw_disk_in_use && GetLastError() - == ERROR_INVALID_FUNCTION) { - return(true); - } + os_file_handle_error(nullptr, "flush"); - os_file_handle_error(NULL, "flush"); + /* It is a fatal error if a file flush does not succeed, because then + the database can get corrupt on disk */ + ut_error; - /* It is a fatal error if a file flush does not succeed, because then - the database can get corrupt on disk */ - ut_error; - - return(false); + return false; } /** Retrieves the last error number if an error occurs in a file io function. From ec0e9d6f76b1715bb7e229f8361b42476c016734 Mon Sep 17 00:00:00 2001 From: Teemu Ollakka Date: Sun, 25 Oct 2020 11:17:27 +0200 Subject: [PATCH 267/323] MDEV-22681 EXECUTE IMMEDIATE crashes server if wsrep is on. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A wsrep transaction was started for EXECUTE IMMEDIATE, which caused assertion failure when the executed statement was CREATE TABLE which should be executed in TOI mode. As a fix, don't start wsrep transaction for EXECUTE IMMEDIATE to let the wsrep state logic to be handled from inside stored procedure codepath. Reviewed-by: Jan Lindström --- .../r/galera_var_replicate_myisam_on.result | 133 +++++++++++++++++- .../t/galera_var_replicate_myisam_on.test | 82 ++++++++++- mysql-test/suite/wsrep/r/mdev_22681.result | 3 + mysql-test/suite/wsrep/t/mdev_22681.cnf | 10 ++ mysql-test/suite/wsrep/t/mdev_22681.test | 15 ++ sql/sql_parse.cc | 1 + 6 files changed, 241 insertions(+), 3 deletions(-) create mode 100644 mysql-test/suite/wsrep/r/mdev_22681.result create mode 100644 mysql-test/suite/wsrep/t/mdev_22681.cnf create mode 100644 mysql-test/suite/wsrep/t/mdev_22681.test diff --git a/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result b/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result index 716af033e7a..ad28f5a426e 100644 --- a/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result +++ b/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result @@ -107,6 +107,135 @@ i 1 DROP TABLE t1; connection node_1; -SET GLOBAL wsrep_replicate_myisam = 0; +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, b INT) ENGINE=MyISAM; +INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10); +PREPARE upd from 'update t1 set b = 100 where id = 5'; +PREPARE ins from 'insert into t1 values (11,11)'; +PREPARE del from 'delete from t1 where id = 4'; +PREPARE rep from 'replace into t1 values (12,12),(6,600)'; +EXECUTE upd; +EXECUTE ins; +EXECUTE del; +EXECUTE rep; +SELECT * FROM t1 ORDER BY id; +id b +1 1 +2 2 +3 3 +5 100 +6 600 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +connection node_2; +SELECT * FROM t1 ORDER BY id; +id b +1 1 +2 2 +3 3 +5 100 +6 600 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +DROP TABLE t1; +connection node_1; +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, b INT) ENGINE=MyISAM; +INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10); +CREATE PROCEDURE proc() +BEGIN +UPDATE t1 set b = 100 WHERE id = 5; +INSERT INTO t1 VALUES (11,11); +DELETE FROM t1 WHERE id = 4; +REPLACE INTO t1 VALUES (12,12),(6,600); +COMMIT; +END| +CALL proc(); +SELECT * FROM t1 ORDER BY id; +id b +1 1 +2 2 +3 3 +5 100 +6 600 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +connection node_2; +SELECT * FROM t1 ORDER BY id; +id b +1 1 +2 2 +3 3 +5 100 +6 600 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +DROP PROCEDURE proc; +DROP TABLE t1; +connection node_1; +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, b INT) ENGINE=MyISAM; +CREATE TABLE t2 (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b INT) ENGINE=MyISAM; +INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10); +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES (NULL, NEW.b); +CREATE TRIGGER tr2 BEFORE UPDATE ON t1 FOR EACH ROW INSERT INTO t2 VALUES (NULL, OLD.b),(NULL, NEW.b); +CREATE TRIGGER tr3 BEFORE DELETE ON t1 FOR EACH ROW INSERT INTO t2 VALUES (NULL, OLD.b); +INSERT INTO t1 VALUES (11,11); +UPDATE t1 SET b = 200 WHERE id = 2; +DELETE FROM t1 where id = 5; +SELECT * FROM t1 ORDER BY id; +id b +1 1 +2 200 +3 3 +4 4 +6 6 +7 7 +8 8 +9 9 +10 10 +11 11 +SELECT * FROM t2 ORDER BY id; +id b +1 11 +2 2 +3 200 +4 5 +connection node_2; +SELECT * FROM t1 ORDER BY id; +id b +1 1 +2 200 +3 3 +4 4 +6 6 +7 7 +8 8 +9 9 +10 10 +11 11 +SELECT * FROM t2 ORDER BY id; +id b +1 11 +2 2 +3 200 +4 5 +DROP TRIGGER tr1; +DROP TRIGGER tr2; +DROP TRIGGER tr3; +DROP TABLE t1,t2; +connection node_1; connection node_2; -SET GLOBAL wsrep_replicate_myisam = 0; diff --git a/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test b/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test index 90c786f0af0..adb5cb04273 100644 --- a/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test +++ b/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test @@ -142,8 +142,88 @@ INSERT INTO t1 VALUES(1); SELECT * FROM t1; DROP TABLE t1; +# +# Test prepared staments +# --connection node_1 ---eval SET GLOBAL wsrep_replicate_myisam = $wsrep_replicate_myisam_orig +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, b INT) ENGINE=MyISAM; +INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10); + +PREPARE upd from 'update t1 set b = 100 where id = 5'; +PREPARE ins from 'insert into t1 values (11,11)'; +PREPARE del from 'delete from t1 where id = 4'; +PREPARE rep from 'replace into t1 values (12,12),(6,600)'; + +EXECUTE upd; +EXECUTE ins; +EXECUTE del; +EXECUTE rep; + +SELECT * FROM t1 ORDER BY id; --connection node_2 +SELECT * FROM t1 ORDER BY id; + +DROP TABLE t1; + +# +# Test procedure +# +--connection node_1 +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, b INT) ENGINE=MyISAM; +INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10); + +DELIMITER |; +CREATE PROCEDURE proc() +BEGIN + UPDATE t1 set b = 100 WHERE id = 5; + INSERT INTO t1 VALUES (11,11); + DELETE FROM t1 WHERE id = 4; + REPLACE INTO t1 VALUES (12,12),(6,600); + COMMIT; +END| +DELIMITER ;| + +CALL proc(); +SELECT * FROM t1 ORDER BY id; + +--connection node_2 +SELECT * FROM t1 ORDER BY id; + +DROP PROCEDURE proc; +DROP TABLE t1; + +# +# Test trigger +# +--connection node_1 +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, b INT) ENGINE=MyISAM; +CREATE TABLE t2 (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b INT) ENGINE=MyISAM; +INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10); +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES (NULL, NEW.b); +CREATE TRIGGER tr2 BEFORE UPDATE ON t1 FOR EACH ROW INSERT INTO t2 VALUES (NULL, OLD.b),(NULL, NEW.b); +CREATE TRIGGER tr3 BEFORE DELETE ON t1 FOR EACH ROW INSERT INTO t2 VALUES (NULL, OLD.b); + +INSERT INTO t1 VALUES (11,11); +UPDATE t1 SET b = 200 WHERE id = 2; +DELETE FROM t1 where id = 5; +SELECT * FROM t1 ORDER BY id; +SELECT * FROM t2 ORDER BY id; + +--connection node_2 +SELECT * FROM t1 ORDER BY id; +SELECT * FROM t2 ORDER BY id; +DROP TRIGGER tr1; +DROP TRIGGER tr2; +DROP TRIGGER tr3; +DROP TABLE t1,t2; + +--connection node_1 +--disable_query_log --eval SET GLOBAL wsrep_replicate_myisam = $wsrep_replicate_myisam_orig +--enable_query_log + +--connection node_2 +--disable_query_log +--eval SET GLOBAL wsrep_replicate_myisam = $wsrep_replicate_myisam_orig +--enable_query_log diff --git a/mysql-test/suite/wsrep/r/mdev_22681.result b/mysql-test/suite/wsrep/r/mdev_22681.result new file mode 100644 index 00000000000..ecce324ead6 --- /dev/null +++ b/mysql-test/suite/wsrep/r/mdev_22681.result @@ -0,0 +1,3 @@ +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 ENGINE=InnoDB AS SELECT 1 AS b'; +DROP TABLE t1; diff --git a/mysql-test/suite/wsrep/t/mdev_22681.cnf b/mysql-test/suite/wsrep/t/mdev_22681.cnf new file mode 100644 index 00000000000..2f310476733 --- /dev/null +++ b/mysql-test/suite/wsrep/t/mdev_22681.cnf @@ -0,0 +1,10 @@ +!include ../my.cnf + +[mysqld.1] +wsrep-on=ON +log-bin +binlog-format=ROW +innodb-flush-log-at-trx-commit=1 +wsrep-cluster-address=gcomm:// +wsrep-provider=@ENV.WSREP_PROVIDER +innodb-autoinc-lock-mode=2 diff --git a/mysql-test/suite/wsrep/t/mdev_22681.test b/mysql-test/suite/wsrep/t/mdev_22681.test new file mode 100644 index 00000000000..ce1129c7485 --- /dev/null +++ b/mysql-test/suite/wsrep/t/mdev_22681.test @@ -0,0 +1,15 @@ +# +# MDEV-22681: Server crashes in galera::ReplicatorSMM::CommitOrder::CommitOrder +# or assertion failed in wsrep::transaction::before_prepare. +# +# EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 ENGINE=InnoDB AS SELECT 1 AS b' +# crashes the server if binlog is on (see mdev_22681.cnf for configuration). +# +--source include/have_wsrep.inc +--source include/have_wsrep_provider.inc +--source include/have_innodb.inc + +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 ENGINE=InnoDB AS SELECT 1 AS b'; + +DROP TABLE t1; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e8c94c6b363..05a1ee57d63 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3792,6 +3792,7 @@ mysql_execute_command(THD *thd) lex->sql_command != SQLCOM_BEGIN && lex->sql_command != SQLCOM_CALL && lex->sql_command != SQLCOM_EXECUTE && + lex->sql_command != SQLCOM_EXECUTE_IMMEDIATE && !(sql_command_flags[lex->sql_command] & CF_AUTO_COMMIT_TRANS)) { wsrep_start_trx_if_not_started(thd); From 85c686e2d1576b0be6daf11849167bb1c38e3603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Thu, 15 Oct 2020 17:37:31 +0300 Subject: [PATCH 268/323] cleanup: Static_binary_string need not take non-const double parameter Convert the parameter to const as the function won't modify the pointer value. --- sql/sql_string.cc | 4 ++-- sql/sql_string.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 0e62b5b9c2e..94f2e6fc8c6 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -767,10 +767,10 @@ void Static_binary_string::qs_append(double d) NULL); } -void Static_binary_string::qs_append(double *d) +void Static_binary_string::qs_append(const double *d) { double ld; - float8get(ld, (char*) d); + float8get(ld, (const char*) d); qs_append(ld); } diff --git a/sql/sql_string.h b/sql/sql_string.h index 2ef817ea0ad..d1378e62a97 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -345,7 +345,7 @@ public: void qs_append(const char *str, size_t len); void qs_append_hex(const char *str, uint32 len); void qs_append(double d); - void qs_append(double *d); + void qs_append(const double *d); inline void qs_append(const char c) { Ptr[str_length]= c; From f6549e95448e5cce52336361f5a59d1edcdac46a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Thu, 15 Oct 2020 18:02:24 +0300 Subject: [PATCH 269/323] MDEV-18323 Convert MySQL JSON type to MariaDB TEXT in mysql_upgrade This patch solves two key problems. 1. There is a type number clash between MySQL and MariaDB. The number 245, used for MariaDB Virtual Fields is the same as MySQL's JSON. This leads to corrupt FRM errors if unhandled. The code properly checks frm table version number and if it matches 5.7+ (until 10.0+) it will assume it is dealing with a MySQL table with the JSON datatype. 2. MySQL JSON datatype uses a proprietary format to pack JSON data. The patch introduces a datatype plugin which parses the format and convers it to its string representation. The intended conversion path is to only use the JSON datatype within ALTER TABLE FORCE, to force a table recreate. This happens during mysql_upgrade or via a direct ALTER TABLE
FORCE. --- mysql-test/main/mysql_json_table_recreate.opt | 1 + .../main/mysql_json_table_recreate.result | 171 ++++++ .../main/mysql_json_table_recreate.test | 89 +++ .../mysql_upgrade_mysql_json_datatype.result | 106 ++++ .../mysql_upgrade_mysql_json_datatype.test | 63 +++ .../std_data/mysql_json/mysql_json_test.MYD | Bin 0 -> 1905700 bytes .../std_data/mysql_json/mysql_json_test.MYI | Bin 0 -> 1024 bytes .../std_data/mysql_json/mysql_json_test.frm | Bin 0 -> 8646 bytes .../mysql_json/mysql_json_test_big.MYD | Bin 0 -> 1898044 bytes .../mysql_json/mysql_json_test_big.MYI | Bin 0 -> 1024 bytes .../mysql_json/mysql_json_test_big.frm | Bin 0 -> 8646 bytes mysql-test/std_data/mysql_json/tempty.MYD | Bin 0 -> 40 bytes mysql-test/std_data/mysql_json/tempty.MYI | Bin 0 -> 1024 bytes mysql-test/std_data/mysql_json/tempty.frm | Bin 0 -> 8554 bytes plugin/type_mysql_json/CMakeLists.txt | 18 + plugin/type_mysql_json/mysql_json.cc | 515 ++++++++++++++++++ plugin/type_mysql_json/mysql_json.h | 44 ++ plugin/type_mysql_json/type.cc | 203 +++++++ sql/table.cc | 16 +- 19 files changed, 1224 insertions(+), 2 deletions(-) create mode 100644 mysql-test/main/mysql_json_table_recreate.opt create mode 100644 mysql-test/main/mysql_json_table_recreate.result create mode 100644 mysql-test/main/mysql_json_table_recreate.test create mode 100644 mysql-test/main/mysql_upgrade_mysql_json_datatype.result create mode 100644 mysql-test/main/mysql_upgrade_mysql_json_datatype.test create mode 100644 mysql-test/std_data/mysql_json/mysql_json_test.MYD create mode 100644 mysql-test/std_data/mysql_json/mysql_json_test.MYI create mode 100644 mysql-test/std_data/mysql_json/mysql_json_test.frm create mode 100644 mysql-test/std_data/mysql_json/mysql_json_test_big.MYD create mode 100644 mysql-test/std_data/mysql_json/mysql_json_test_big.MYI create mode 100644 mysql-test/std_data/mysql_json/mysql_json_test_big.frm create mode 100644 mysql-test/std_data/mysql_json/tempty.MYD create mode 100644 mysql-test/std_data/mysql_json/tempty.MYI create mode 100644 mysql-test/std_data/mysql_json/tempty.frm create mode 100644 plugin/type_mysql_json/CMakeLists.txt create mode 100644 plugin/type_mysql_json/mysql_json.cc create mode 100644 plugin/type_mysql_json/mysql_json.h create mode 100644 plugin/type_mysql_json/type.cc diff --git a/mysql-test/main/mysql_json_table_recreate.opt b/mysql-test/main/mysql_json_table_recreate.opt new file mode 100644 index 00000000000..135fd2b77b8 --- /dev/null +++ b/mysql-test/main/mysql_json_table_recreate.opt @@ -0,0 +1 @@ +--plugin-load=$TYPE_MYSQL_JSON_SO diff --git a/mysql-test/main/mysql_json_table_recreate.result b/mysql-test/main/mysql_json_table_recreate.result new file mode 100644 index 00000000000..3dfc6d7a259 --- /dev/null +++ b/mysql-test/main/mysql_json_table_recreate.result @@ -0,0 +1,171 @@ +# +# The following test takes 2 tables containing a JSON column and attempts +# to repair them. +# +# The tables header is (Description, Expected, Actual), where description +# shows a brief description what the JSON value is testing in the MariaDB +# implementation. Expected is the longtext string and actual is the JSON +# column that needs to be converted to MariaDB's representation of +# LONGTEXT. +# +call mtr.add_suppression("Table rebuild required"); +call mtr.add_suppression("is marked as crashed"); +call mtr.add_suppression("Checking"); +SET NAMES utf8; +# +# Check that only ALTER TABLE ... FORCE is allowed on a MySQL 5.7 table +# with a JSON column. +# +show create table tempty; +ERROR HY000: Table rebuild required. Please do "ALTER TABLE `test.tempty` FORCE" or dump/reload to fix it! +select * from tempty; +ERROR HY000: Table rebuild required. Please do "ALTER TABLE `test.tempty` FORCE" or dump/reload to fix it! +alter table tempty force; +show create table tempty; +Table Create Table +tempty CREATE TABLE `tempty` ( + `t` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show create table mysql_json_test; +ERROR HY000: Table rebuild required. Please do "ALTER TABLE `test.mysql_json_test` FORCE" or dump/reload to fix it! +select * from mysql_json_test; +ERROR HY000: Table rebuild required. Please do "ALTER TABLE `test.mysql_json_test` FORCE" or dump/reload to fix it! +LOCK TABLES mysql_json_test WRITE; +ERROR HY000: Table rebuild required. Please do "ALTER TABLE `test.mysql_json_test` FORCE" or dump/reload to fix it! +alter table mysql_json_test force; +select description, expected, actual, expected = actual from mysql_json_test; +description expected actual expected = actual +Array LITERALS: ["prefix", false, "suffix", 1] ["prefix", false, "suffix", 1] 1 +Array LITERALS: ["prefix", null, "suffix", 1] ["prefix", null, "suffix", 1] 1 +Array LITERALS: ["prefix", true, "suffix", 1] ["prefix", true, "suffix", 1] 1 +DateTime as Raw Value: "2015-01-15 23:24:25.000000" "2015-01-15 23:24:25.000000" 1 +DateTime as Raw Value: "2015-01-15 23:24:25.000000" "2015-01-15 23:24:25.000000" 1 +DateTime as Raw Value: "2015-01-15" "2015-01-15" 1 +DateTime as Raw Value: "23:24:25.000000" "23:24:25.000000" 1 +Empty JSON Object/Array: [] [] 1 +Empty JSON Object/Array: {} {} 1 +GeoJSON {"type": "GeometryCollection", "geometries": []} {"type": "GeometryCollection", "geometries": []} 1 +GeoJSON {"type": "LineString", "coordinates": [[0, 5], [5, 10], [10, 15]]} {"type": "LineString", "coordinates": [[0, 5], [5, 10], [10, 15]]} 1 +GeoJSON {"type": "MultiPoint", "coordinates": [[1, 1], [2, 2], [3, 3]]} {"type": "MultiPoint", "coordinates": [[1, 1], [2, 2], [3, 3]]} 1 +GeoJSON {"type": "Point", "coordinates": [11.1111, 12.22222]} {"type": "Point", "coordinates": [11.1111, 12.22222]} 1 +JSON LITERALS: {"val": false} {"val": false} 1 +JSON LITERALS: {"val": null} {"val": null} 1 +JSON LITERALS: {"val": true} {"val": true} 1 +Opaque Types: opaque_mysql_type_binary "base64:type254:YWJjAAAAAAAAAA==" "base64:type254:YWJjAAAAAAAAAA==" 1 +Opaque Types: opaque_mysql_type_bit "base64:type16:yv4=" "base64:type16:yv4=" 1 +Opaque Types: opaque_mysql_type_blob "base64:type252:yv66vg==" "base64:type252:yv66vg==" 1 +Opaque Types: opaque_mysql_type_date "2015-01-15" "2015-01-15" 1 +Opaque Types: opaque_mysql_type_datetime "2015-01-15 23:24:25.000000" "2015-01-15 23:24:25.000000" 1 +Opaque Types: opaque_mysql_type_enum "b" "b" 1 +Opaque Types: opaque_mysql_type_geom {"type": "Point", "coordinates": [1, 1]} {"type": "Point", "coordinates": [1, 1]} 1 +Opaque Types: opaque_mysql_type_longblob "base64:type251:yv66vg==" "base64:type251:yv66vg==" 1 +Opaque Types: opaque_mysql_type_mediumblob "base64:type250:yv66vg==" "base64:type250:yv66vg==" 1 +Opaque Types: opaque_mysql_type_set "b,c" "b,c" 1 +Opaque Types: opaque_mysql_type_time "23:24:25.000000" "23:24:25.000000" 1 +Opaque Types: opaque_mysql_type_tinyblob "base64:type249:yv66vg==" "base64:type249:yv66vg==" 1 +Opaque Types: opaque_mysql_type_varbinary "base64:type15:YWJj" "base64:type15:YWJj" 1 +Opaque Types: opaque_mysql_type_varchar "base64:type15:Zm9v" "base64:type15:Zm9v" 1 +Opaque Types: opaque_mysql_type_year "base64:type13:MjAxOQ==" "base64:type13:MjAxOQ==" 1 +Raw LITERALS: false false 1 +Raw LITERALS: null null 1 +Raw LITERALS: true true 1 +Raw doubles as JSON -2.2250738585072014e-308 -2.2250738585072014e-308 1 +Raw doubles as JSON -5678.987 -5678.987 1 +Raw doubles as JSON 0.0 0.0 1 +Raw doubles as JSON 2.2250738585072014e-308 2.2250738585072014e-308 1 +Raw doubles as JSON 3.14 3.14 1 +Raw integers as JSON -127 -127 1 +Raw integers as JSON -2147483648 -2147483648 1 +Raw integers as JSON -32768 -32768 1 +Raw integers as JSON -9223372036854775807 -9223372036854775807 1 +Raw integers as JSON 0 0 1 +Raw integers as JSON 128 128 1 +Raw integers as JSON 18446744073709551615 18446744073709551615 1 +Raw integers as JSON 2147483647 2147483647 1 +Raw integers as JSON 32767 32767 1 +Raw integers as JSON 4294967295 4294967295 1 +Raw integers as JSON 65535 65535 1 +Raw integers as JSON 65536 65536 1 +Raw integers as JSON 9223372036854775807 9223372036854775807 1 +Simple Array as Base Key [1, 2, 3, 4, 5, [], "a", "b", "c"] [1, 2, 3, 4, 5, [], "a", "b", "c"] 1 +Simple Array as Value {"a": [1, 2], "b": ["x", "y"]} {"a": [1, 2], "b": ["x", "y"]} 1 +Simple JSON test {"key1": "val1", "key2": "val2"} {"key1": "val1", "key2": "val2"} 1 +Special Characters: "" "" 1 +Special Characters: "'" "'" 1 +Special Characters: "'" "'" 1 +Special Characters: "'" "'" 1 +Special Characters: "''" "''" 1 +Special Characters: "\"" "\"" 1 +Special Characters: "\\" "\\" 1 +Special Characters: "\\b" "\\b" 1 +Special Characters: "\b" "\b" 1 +Special Characters: "\f" "\f" 1 +Special Characters: "\n" "\n" 1 +Special Characters: "\r" "\r" 1 +Special Characters: "\t" "\t" 1 +Special Characters: "f" "f" 1 +Special Characters: "key1 - with \" val " "key1 - with \" val " 1 +Special Characters: "q" "q" 1 +Special Characters: "some_string" "some_string" 1 +Special Characters: ["a ' b", "c ' d"] ["a ' b", "c ' d"] 1 +Special Characters: ["a \" b", "c \" d"] ["a \" b", "c \" d"] 1 +Special Characters: ["a \\ b", "c \\ d"] ["a \\ b", "c \\ d"] 1 +Special Characters: ["a \b b", "c \b d"] ["a \b b", "c \b d"] 1 +Special Characters: ["a \f b", "c \f d"] ["a \f b", "c \f d"] 1 +Special Characters: ["a \r b", "c \r d"] ["a \r b", "c \r d"] 1 +Special Characters: ["a \t b", "c \t d"] ["a \t b", "c \t d"] 1 +Special Characters: {"[": "]"} {"[": "]"} 1 +Special Characters: {"key ' key": "val ' val"} {"key ' key": "val ' val"} 1 +Special Characters: {"key \" key": "val \" val"} {"key \" key": "val \" val"} 1 +Special Characters: {"key \\ key": "val \\ val"} {"key \\ key": "val \\ val"} 1 +Special Characters: {"key \\0 key": "val \n val"} {"key \\0 key": "val \n val"} 1 +Special Characters: {"key \\Z key": "val ' val"} {"key \\Z key": "val ' val"} 1 +Special Characters: {"key \b key": "val \b val"} {"key \b key": "val \b val"} 1 +Special Characters: {"key \f key": "val \f val"} {"key \f key": "val \f val"} 1 +Special Characters: {"key \n key": "val \n val"} {"key \n key": "val \n val"} 1 +Special Characters: {"key \r key": "val \r val"} {"key \r key": "val \r val"} 1 +Special Characters: {"key \t key": "val \t val"} {"key \t key": "val \t val"} 1 +Special Characters: {"key1 and \n\"key2\"": "val1\t val2"} {"key1 and \n\"key2\"": "val1\t val2"} 1 +Special Characters: {"{": "}"} {"{": "}"} 1 +Special Characters: {"{": "}"} {"{": "}"} 1 +Special String Cases: [""] [""] 1 +Special String Cases: {"": ""} {"": ""} 1 +Timestamp as RawValue "2019-12-26 19:56:03.000000" "2019-12-26 19:56:03.000000" 1 +UTF8 Characters: "Anel Husaković - test: đžšćč" "Anel Husaković - test: đžšćč" 1 +UTF8 Characters: {"Name": "Anel Husaković - test: đžšćč"} {"Name": "Anel Husaković - test: đžšćč"} 1 +UTF8 Characters: {"Person": "EMP", "details": {"Name": "Anel Husaković - test: đžšćč"}} {"Person": "EMP", "details": {"Name": "Anel Husaković - test: đžšćč"}} 1 +UTF8 Characters: {"details": {"Name": "Anel Husaković - test: đžšćč"}, "\"Anel Husaković - test: đžšćč\"": "EMP"} {"details": {"Name": "Anel Husaković - test: đžšćč"}, "\"Anel Husaković - test: đžšćč\"": "EMP"} 1 +# +# A quick check that all rows match from the original MySQL Table. +# +select count(*) as 'Total_Number_of_Tests', +sum(expected = actual) as 'Succesful_Tests' +from mysql_json_test; +Total_Number_of_Tests Succesful_Tests +100 100 +show create table mysql_json_test; +Table Create Table +mysql_json_test CREATE TABLE `mysql_json_test` ( + `description` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `expected` longtext COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `actual` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci +show create table mysql_json_test_big; +ERROR HY000: Table rebuild required. Please do "ALTER TABLE `test.mysql_json_test_big` FORCE" or dump/reload to fix it! +select * from mysql_json_test_big; +ERROR HY000: Table rebuild required. Please do "ALTER TABLE `test.mysql_json_test_big` FORCE" or dump/reload to fix it! +# +# This test checks the long format implementation of MySQL's JSON +# Not printing the actual contents as they are not readable by a human, +# just compare the strings, make sure they match. +# +alter table mysql_json_test_big force; +select count(*) as 'Total_Number_of_Tests', +sum(expected = actual) as 'Succesful_Tests', +sum(JSON_VALID(actual)) as 'String_is_valid_JSON' +from mysql_json_test_big; +Total_Number_of_Tests Succesful_Tests String_is_valid_JSON +1 1 1 +drop table tempty; +drop table mysql_json_test; +drop table mysql_json_test_big; diff --git a/mysql-test/main/mysql_json_table_recreate.test b/mysql-test/main/mysql_json_table_recreate.test new file mode 100644 index 00000000000..1762a452cc8 --- /dev/null +++ b/mysql-test/main/mysql_json_table_recreate.test @@ -0,0 +1,89 @@ +--source include/have_utf8.inc + +--echo # +--echo # The following test takes 2 tables containing a JSON column and attempts +--echo # to repair them. +--echo # +--echo # The tables header is (Description, Expected, Actual), where description +--echo # shows a brief description what the JSON value is testing in the MariaDB +--echo # implementation. Expected is the longtext string and actual is the JSON +--echo # column that needs to be converted to MariaDB's representation of +--echo # LONGTEXT. +--echo # + + +call mtr.add_suppression("Table rebuild required"); +call mtr.add_suppression("is marked as crashed"); +call mtr.add_suppression("Checking"); + +let $MYSQLD_DATADIR= `select @@datadir`; + +SET NAMES utf8; + +--copy_file std_data/mysql_json/tempty.frm $MYSQLD_DATADIR/test/tempty.frm +--copy_file std_data/mysql_json/tempty.MYI $MYSQLD_DATADIR/test/tempty.MYI +--copy_file std_data/mysql_json/tempty.MYD $MYSQLD_DATADIR/test/tempty.MYD + +--copy_file std_data/mysql_json/mysql_json_test.frm $MYSQLD_DATADIR/test/mysql_json_test.frm +--copy_file std_data/mysql_json/mysql_json_test.MYI $MYSQLD_DATADIR/test/mysql_json_test.MYI +--copy_file std_data/mysql_json/mysql_json_test.MYD $MYSQLD_DATADIR/test/mysql_json_test.MYD + +--copy_file std_data/mysql_json/mysql_json_test_big.frm $MYSQLD_DATADIR/test/mysql_json_test_big.frm +--copy_file std_data/mysql_json/mysql_json_test_big.MYI $MYSQLD_DATADIR/test/mysql_json_test_big.MYI +--copy_file std_data/mysql_json/mysql_json_test_big.MYD $MYSQLD_DATADIR/test/mysql_json_test_big.MYD + +--echo # +--echo # Check that only ALTER TABLE ... FORCE is allowed on a MySQL 5.7 table +--echo # with a JSON column. +--echo # + +--error ER_TABLE_NEEDS_REBUILD +show create table tempty; +--error ER_TABLE_NEEDS_REBUILD +select * from tempty; + +alter table tempty force; +show create table tempty; + +--error ER_TABLE_NEEDS_REBUILD +show create table mysql_json_test; +--error ER_TABLE_NEEDS_REBUILD +select * from mysql_json_test; + +--error ER_TABLE_NEEDS_REBUILD +LOCK TABLES mysql_json_test WRITE; + +alter table mysql_json_test force; + +--sorted_result +select description, expected, actual, expected = actual from mysql_json_test; + +--echo # +--echo # A quick check that all rows match from the original MySQL Table. +--echo # +select count(*) as 'Total_Number_of_Tests', + sum(expected = actual) as 'Succesful_Tests' +from mysql_json_test; + +show create table mysql_json_test; + +--error ER_TABLE_NEEDS_REBUILD +show create table mysql_json_test_big; +--error ER_TABLE_NEEDS_REBUILD +select * from mysql_json_test_big; + +--echo # +--echo # This test checks the long format implementation of MySQL's JSON +--echo # Not printing the actual contents as they are not readable by a human, +--echo # just compare the strings, make sure they match. +--echo # +alter table mysql_json_test_big force; + +select count(*) as 'Total_Number_of_Tests', + sum(expected = actual) as 'Succesful_Tests', + sum(JSON_VALID(actual)) as 'String_is_valid_JSON' +from mysql_json_test_big; + +drop table tempty; +drop table mysql_json_test; +drop table mysql_json_test_big; diff --git a/mysql-test/main/mysql_upgrade_mysql_json_datatype.result b/mysql-test/main/mysql_upgrade_mysql_json_datatype.result new file mode 100644 index 00000000000..d4028b6db3d --- /dev/null +++ b/mysql-test/main/mysql_upgrade_mysql_json_datatype.result @@ -0,0 +1,106 @@ +call mtr.add_suppression("Table rebuild required"); +call mtr.add_suppression("is marked as crashed"); +call mtr.add_suppression("Checking"); +SET NAMES utf8; +set sql_mode=""; +install soname 'type_mysql_json.so'; +show create table tempty; +ERROR HY000: Table rebuild required. Please do "ALTER TABLE `test.tempty` FORCE" or dump/reload to fix it! +show create table mysql_json_test; +ERROR HY000: Table rebuild required. Please do "ALTER TABLE `test.mysql_json_test` FORCE" or dump/reload to fix it! +show create table mysql_json_test_big; +ERROR HY000: Table rebuild required. Please do "ALTER TABLE `test.mysql_json_test_big` FORCE" or dump/reload to fix it! +# Run mysql_upgrade to fix the tables containing JSON. +Phase 1/7: Checking and upgrading mysql database +Processing databases +mysql +mysql.column_stats OK +mysql.columns_priv OK +mysql.db OK +mysql.event OK +mysql.func OK +mysql.global_priv OK +mysql.gtid_slave_pos OK +mysql.help_category OK +mysql.help_keyword OK +mysql.help_relation OK +mysql.help_topic OK +mysql.index_stats OK +mysql.innodb_index_stats OK +mysql.innodb_table_stats OK +mysql.plugin OK +mysql.proc OK +mysql.procs_priv OK +mysql.proxies_priv OK +mysql.roles_mapping OK +mysql.servers OK +mysql.table_stats OK +mysql.tables_priv OK +mysql.time_zone OK +mysql.time_zone_leap_second OK +mysql.time_zone_name OK +mysql.time_zone_transition OK +mysql.time_zone_transition_type OK +mysql.transaction_registry OK +Phase 2/7: Installing used storage engines... Skipped +Phase 3/7: Fixing views +mysql.user OK +Phase 4/7: Running 'mysql_fix_privilege_tables' +Phase 5/7: Fixing table and database names +Phase 6/7: Checking and upgrading tables +Processing databases +information_schema +mtr +mtr.global_suppressions OK +mtr.test_suppressions OK +performance_schema +test +test.mysql_json_test Needs upgrade +test.mysql_json_test_big Needs upgrade +test.tempty Needs upgrade + +Repairing tables +test.mysql_json_test OK +test.mysql_json_test_big OK +test.tempty OK +Phase 7/7: Running 'FLUSH PRIVILEGES' +OK +# +# Now check if the table structure is correct and that the data +# is still present. +# +show create table tempty; +Table Create Table +tempty CREATE TABLE `tempty` ( + `t` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show create table mysql_json_test; +Table Create Table +mysql_json_test CREATE TABLE `mysql_json_test` ( + `description` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `expected` longtext COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `actual` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci +show create table mysql_json_test_big; +Table Create Table +mysql_json_test_big CREATE TABLE `mysql_json_test_big` ( + `description` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `expected` longtext COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `actual` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci +select count(*) as 'Total_Number_of_Tests', +sum(expected = actual) as 'Succesful_Tests', +sum(JSON_VALID(actual)) as 'String_is_valid_JSON' +from mysql_json_test; +Total_Number_of_Tests Succesful_Tests String_is_valid_JSON +100 100 100 +select count(*) as 'Total_Number_of_Tests', +sum(expected = actual) as 'Succesful_Tests', +sum(JSON_VALID(actual)) as 'String_is_valid_JSON' +from mysql_json_test_big; +Total_Number_of_Tests Succesful_Tests String_is_valid_JSON +1 1 1 +drop table tempty; +drop table mysql_json_test; +drop table mysql_json_test_big; +uninstall soname 'type_mysql_json.so'; diff --git a/mysql-test/main/mysql_upgrade_mysql_json_datatype.test b/mysql-test/main/mysql_upgrade_mysql_json_datatype.test new file mode 100644 index 00000000000..0b5b07f233a --- /dev/null +++ b/mysql-test/main/mysql_upgrade_mysql_json_datatype.test @@ -0,0 +1,63 @@ +-- source include/mysql_upgrade_preparation.inc +-- source include/have_working_dns.inc +-- source include/have_innodb.inc + +call mtr.add_suppression("Table rebuild required"); +call mtr.add_suppression("is marked as crashed"); +call mtr.add_suppression("Checking"); + +let $MYSQLD_DATADIR= `select @@datadir`; +SET NAMES utf8; + +--copy_file std_data/mysql_json/tempty.frm $MYSQLD_DATADIR/test/tempty.frm +--copy_file std_data/mysql_json/tempty.MYI $MYSQLD_DATADIR/test/tempty.MYI +--copy_file std_data/mysql_json/tempty.MYD $MYSQLD_DATADIR/test/tempty.MYD + +--copy_file std_data/mysql_json/mysql_json_test.frm $MYSQLD_DATADIR/test/mysql_json_test.frm +--copy_file std_data/mysql_json/mysql_json_test.MYI $MYSQLD_DATADIR/test/mysql_json_test.MYI +--copy_file std_data/mysql_json/mysql_json_test.MYD $MYSQLD_DATADIR/test/mysql_json_test.MYD + +--copy_file std_data/mysql_json/mysql_json_test_big.frm $MYSQLD_DATADIR/test/mysql_json_test_big.frm +--copy_file std_data/mysql_json/mysql_json_test_big.MYI $MYSQLD_DATADIR/test/mysql_json_test_big.MYI +--copy_file std_data/mysql_json/mysql_json_test_big.MYD $MYSQLD_DATADIR/test/mysql_json_test_big.MYD + + +set sql_mode=""; + +--eval install soname '$TYPE_MYSQL_JSON_SO' + +--error ER_TABLE_NEEDS_REBUILD +show create table tempty; +--error ER_TABLE_NEEDS_REBUILD +show create table mysql_json_test; +--error ER_TABLE_NEEDS_REBUILD +show create table mysql_json_test_big; + +--echo # Run mysql_upgrade to fix the tables containing JSON. +--exec $MYSQL_UPGRADE --force 2>&1 + +--echo # +--echo # Now check if the table structure is correct and that the data +--echo # is still present. +--echo # + +show create table tempty; +show create table mysql_json_test; +show create table mysql_json_test_big; + +select count(*) as 'Total_Number_of_Tests', +sum(expected = actual) as 'Succesful_Tests', +sum(JSON_VALID(actual)) as 'String_is_valid_JSON' +from mysql_json_test; + +select count(*) as 'Total_Number_of_Tests', +sum(expected = actual) as 'Succesful_Tests', +sum(JSON_VALID(actual)) as 'String_is_valid_JSON' +from mysql_json_test_big; + +drop table tempty; +drop table mysql_json_test; +drop table mysql_json_test_big; + +--eval uninstall soname '$TYPE_MYSQL_JSON_SO' +--remove_file $MYSQLD_DATADIR/mysql_upgrade_info diff --git a/mysql-test/std_data/mysql_json/mysql_json_test.MYD b/mysql-test/std_data/mysql_json/mysql_json_test.MYD new file mode 100644 index 0000000000000000000000000000000000000000..0be8c5968b4d89b5b925e393be8e91e2a33968cf GIT binary patch literal 1905700 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 z

@Z?LgJ(B=$B6I0-(l@807p!IQ>c9B>jmyE5i@@aJg|^y4EFan*Mp<_?BlY8%yhCrx=NPlG#!^IkG)4F<(X>j0zZX8M!E+#CyIl>QqVebXvGS8^M0nKAreQ_+Y$Z>t)Zp(R zClS7T(er6rMHoA!RfLCAI@=q9G37MNYVZib)mWy%lk8p%&1&eGDY%^6IU`8H5~@~f zd`0-n!W_bXwz$WPlN)-Pds-IFecPPKR`&XBd7cK}9pZV+LwFX!G^*9m^JW@rc18HV zcYv4(|HC}9HT1Y}5lQ=gG7V8w{yuv#Pa|*pC@WLLtd&RRxf*j3zDL2Pebq{+xUmS6 z|H1v(-e&!ZHS~l^+a$z&@_9C1O_LnL*TeLAMflqcaR|@yo2IP>|7wV*!Dp;C9%}F* zsNF9M0f%rJsR$1PZHul5k0!pF-y!@MGS4T%Uzv;=JffyG4kA1~(B-fidY;|`K~_W0 zc_?9w-miX=ZaCym`^X>=DYs^M2v1OPE;mb+jcVCM-ruMHIH>V7SP}l-M5+eQ;?(tu z@QB{l&1HN!kSaNi+)soD$u=I-;2B;KNDZDe@&rf`zS-^mzU@OKpAS}pPb{|a7{Yf4 zcgJHj^cY%e2+FCSPj1CR_%W2KPJ0xQ$2)#2a*lpiNVy+ zS3^$_J9jL?zZljn@Px2)$kx!aVCRvkdCuR%=S&K-h8_SW_)dRJgJ%MWymb$R207EZ zpJ#nw@vf#~8ay{t^B%(Ev*(!I0^iuF&s!fsiOkh}*GWX(n{O83`8i7}e{ULm5)d1Y z)zB9VcE9u=W9RNF53ozc+1AH2cpTO|v>H5BRddmY@QLPnziIF(*PFdkgJ&!A*2gq> zkjXs-LwJa3e%c!PRxIv*Z6C&Rp860TUo?e$8axUy0Y{!!g#V>@huPx!0D%*)DDK%m zaK_z6q^<+IoroqL?J@j2mPCdRZ*Gws!(aaVRCt&kPuF{7m|=LDJ-ej}|6aQO7@p{@ zBZI-}Pa68>(I3O#exEzV?#mYTOh%&PPfdJ-%^*ATulI<#f!9CCp8n(t$)N*u43E8^ zL&pyG8-yKm=`uXX?g2WF;S-g&r7}GEQ8ndbc>K;}SGU2li00f+h5r|tn96DyeRmt~ zrfn(JBLA#>=Bg5o;lb^$sAG6W$vn|9JiCiF zP<1@GW0q}K6b2{#ku|x};A8ke`&QI3dRGpA_=6?zslH8#0Ih?UW^eOpJsH;Ff(R@E1qR@O`ZbfA<(Z2cGA$lYl5?=q1Bnl46N5eDKVY zb@abdS&-kRt60OBJ(!YNS=X>RkCl=_|r@3+H9{I|OJ9-zAz>$?!z`?e;M|(bd8m8J>kw z=PScsL8c6Ul_IU9$Cm4vWcVveli^7;bhgXzcM!J>e@d1Nk5n^g&l=1rXA7!j_}e!r z!&hnNiN^4B#w@c8&#t?6`xu^+M3)AX;hA&o_AxxEgGJvmd^ezR=P^9N`(jNQzM0;9 z8p{x@SV$$q2?_&Th(rt;m;Au@YHX$+hurC31dDPKGrk$I);CYvwiT$ z?u#mTR$4}g>jA4WJRVbKmf@dF_fO2$PoP*vl;H~r{d<{Ul>8qP$?%9ui{V#e^(Xec z?bE)qQM5yF4A1!>V-RI{C}T`1!{6DUpelb4mG)#n8J;rhnfft&2ztyg86Mv_S1iL* z;$q#j3?C2E_Ko2|%mshP@b`iQ;3R*a-ZZBn!xJsZ;B8+LJsXe4S5zrn-R>BkSW{+| z;pw17^fEjyPiBre!`_}OS=&$1_U*Hk;m^e%!{6=?8J^bZY-|4+%#$%E!+)uhk6(f> z@(#X?Z(TsviwrXv{(rBIcnn`J-2R&kPyL~;cMP8`sv8ew__yzO4A1e;=2&F-cSzS5 z9#>{gL55G|cH38HfDiTLmScG8t~VYs{MA405PCdv1gJcp439q?9*yCNea%70@OZ?H zM}0!htX~e?I(qhDnA56PpjPP^Q-&uCQnz3oJ?ZJW<74a|3N&?NAB{8xql;}8eSIGtXG;6 zAECwMiqKc5Da2n=;voL^Rm?QBk}o~9Nqigi4&u#W2=SS|ooY1+7(bJCHC^QN=8T1S zoWs^f%@%%Vi&BVB_vcnZ{3VkI@#K=1ArazF^%LTWk&6gI{FPn{@s#v8<`&`!(Yw@z zc$R7Hix7{-F-$KmcOIlwLOcOX!yO@>BDwau5Kk!BZWrR&^-`lN#ODO1-YR`Xy3X^< z2JuK2OI`}`?_|aF74_d%d?>^>jHXpW{M-GW5lk|6F{u!bX>GR)@i>c3?apm_W~l`s zp2EpV?VaCv`&lp{p5pSQ2hu7QxCwh9{*p{WeBTUCBM0%+4jt>AcJfn{*I(jh)1&$vW0l2!_57Jc%nmtav}cJ zjtlX`enNRY5Kd5qONhS{oUEm1ud)y~A-)<(pLY;Xo@`FlT6#1BgZ@E0nX=6nb7*=xM<5aN4CWZE}~Z(Ts2SBPih z;>KeT&(?|)=CeH5+-}-gi2qB@bL&HhPh8OZ)gNSfibFy?c5CZHi2rPE&-%dqTYIMv zPpl<9Z8JPcA%$Hbo{&puPy5Jw-n$zn#IrAK?pTO#q|)}SmY(He(q#}&kv?M}ZL{62RXC_SIep$XF zKS-n3)SpcO9>hoDSrSNyXSr=WCd8*VHXb|74r$XufNh2+-Y{t-#Irl1u0kOmLpm3& z5Z`F7&pU|6oT%+gh^Oqp!ix#_d&{GEBDN)lr1%uxZIK+s6Q^ucq(b~ly827_J+b=p*?FRwedh-{1DZVt*mP+w>Lem^d@$~V8sw=05IF%xg;t2w~oQ~q(_Qgl>Y>aITc2Yd) z2ldN(oNNcTboeM9b#O5NsF}g0I7~^5JVXD1aa*eO%IVn#YZZYMpDj3DQMVx;hFu__ z6i<&cU;6ly;@R$-6lO+WipP+dvXSDM;udpA@e~j*8aRqC1NNp$@q`~jwiM5-TtM(B zzT4~aXQg<4aNysyzhl*;_}HB96mOf-GdRaSLV5L08yv-F(;CZza#;p9>Ly~!?Jg>CTVu~IzSzv>sdm|_=1@AMVPNDqIJ;_vL=Q9KsG3_#}) zC&?~28O67dIS;5552&`=rFhc)D*d8EKUie+Pz0 z@q|R3=TbcCVkf#3pX~)%a8ms3A(rAX6rJl*JkrgeK7Ez?`58bdp7(ckwoCC@qG^>B zPb#e4F2!TC+U=uwmfNhp6wlPJKW}u#RNzj%Rc1TZJ+D~JowEW-9b_k1F4HQ8-kN_Y z{z_7%_}GfvN{YWz^)08rGpeO{V#>~TDgLjoFPGw@v-MVO6_#BYzpbL6Y%$6xp1S-6 zHBvk~yU zQ%{P=lU{j#I*+=9)Ys?vmEtdPZ8<$bztkzkbH>*wbrj#1>$H7RJS8Nf;F^4V?j5l% z#oxKZNAXOkjfWJ^$ZkBO_&dbtDE_kbte3Q(33yqB_@kTzX%<3?zx|K|hkTBE%08An zZ;e0Y@^_?It$#K^&(oe1|I6(}QatlicPqtTS)~*YE}Y9v`?6_Grz^$Zu}xV2d|ofy z{+kq^(cXAS@nn7Ge5H6M;IcBKc#N}Bs}vt4efP`w!f=6rJg*dgx(ww>`5eV*KKLlU zX@Gpc?ttA1mY$vz|K2V;il-ZeA1VHiQjt62i6jLqrTE+Qsua(OB+Iy3PXELxnoax2 zncb0bqjkf-nlLGz%^D}kWd1FhYx|^lYBRPzM)5GWvXB&y^_#t#6pyxI zse}}tN{`(y^N-gV=E#clUo*c+M;nGejK9eJ#CUMq#NT23oxE}t^~6f177yc*yyW`E z+bm(hWv_)NxZr(Mvs+?3Zo%~EVLSu5l_JKIZkhka`SK{B;&Izm)U%g(KKwAg(Qlsq zVLa%+s8x)Auf%v5|FE?VCGO=&w;mS`8m(EW0G2%flJ7rpVu$f1t={x7o}i*`=P;fs^<|UY6^~mp z{Vc}wu;!}|}F?stmC8z%t0= z?8A6enp(WWcsz#rg~RyU(s*J#iC`e7VtkjwcZ@e1krss{(ow_s1nFE9!EQtUFg{@m zpJX!e49hzu;G_Kp<6KnX$k&GPnS)%2@zSng9!{>G4dZ#9UZoYhQ)J?C2Lmxl3CWAjzT_=7-~+?|8=@@C_@!+1Pwf13s|!wIl@ zIgIDNTWMWr?B=p}(zC826uMaVo>noZC5VafJ(n_H7US>4EHOTX zyZy9th?%->7vu43ZIu`w@6s=)uP`@68of+kk?}6Zkqvvxe#$OyQ#wT6SPcxx7 zf|8)Lm+33)JXWcfZ58M0F2)t(6T$S;&Ti7~o8Dr4RF!_3R_&#Vy-cf87r99;#$Plk z#%IrXzAVPy!DnLp9hM}Y1h+)< z+hII6TDObwce0xpAKvPh(^pJq;~gM%*%l$Ncg@A4dBF3j^G@lOR zW7T>qF`ml5KHxCE*xoN^1XJ|3**=VCRju2__&iX*+*a|T%5}S9{JktrjF0HwFJ}ak z09dz+@#i?j_&Y39jK8z_#P~bjOELZwykUGmrma$pkG_$=JB-I5ZMKW?SCBc3$Hp3F zD#pip=EsNepBKAl!sB*g@%wrDE8@G+pBUe5!~Hz7t2-{dU%HGvY(zTyedgCs?BixV zPA}K3-`MBrHOdU|e7&A^@9B@bPG~^6I8pPiYvI}PsEHTj-@$FecpT40ftZTl@9@F> zKJDA9M|Yj}u?d32^{&%Cj00iUuG79>-BjCaF+Lt<*J&S+h#TH@+lMN&(ICpn=a}NH zg2VW$M)P31jI8%-`#AY~_D75-tLAu!@!9jZzt{HlD285(@$q@P9>yo7x9hZz1+AM^ zjK?U8!4u;b@MU}_#-~2n`=xz*z02;G{$p^S%T51n-`YM;`?96q@fgO}3-@y|J{t~p z-S$yA<9LYi?;t`k{vBK<#>Y_X_ibO}*Il=L_*ln7j86ghK2Q7j>pJ1Xcv`#rO^heo z<9LYicPuK>LVlm%cK2%x#c)Bkz5g)2@U-i+j{+3NbwCx$jS9{-e+eZ}Qc+^4Q@$}2se%ix+ z&!or z2zqG6cow|lv5NXebN&7>zI$1Bo%x5C(o6ehIR?!2A;zcjc;9dP`r4OWXMEWguBUz& ze>K8~@rdzr8xP~7A@vqwd_&CrL-8n?4;P6Tj{xSVsK#>=&PA!|Mg*XD;NoF?*myTh zLy1jNRkD9bPlnp#XR`Fgcrv!G71el*yAi8ue52p|!eBBoTD{XfgdsxAN>8S?Tz* z=!*S^!}yre{X^#|l&|xD7=Q0-I*iBsZ#g}Tzk^i|<5N26O*{I`eItOw_!fxn&#tAP zbK;viW~{R-tKU$KFKO)`)>7=mR+Jcz88Qxd7=KmBhw*rVA;`mc@`Y=uYJ8D=f2Dnj z;%_i;7>_sDih39yfwey=jYKsv9=PM_e?-yQH@c!QkVXWD@wkM!pi|?2-C??i@jHEU z7@z0=hVjbmF4$%DyI6^pn-b3SPmNU*ADK{nJ4PCnA>x^sUR>m%scl*nP=*FmO4Ilx z6NoV};hYso&PbD%29f@;ge;9U*wmE<1}z z^URQm@kq**^i<<1QmZ=M$SoyXOI@qR6G$`*J&b<|WikG$pr*#-!zbRV#uF5EVo!}v z`QfH^TeZV#X=K&-6#6VBD#qXI4prmXRoyAB8qYz$O%99kcR;%sf0e6ZJU4E)595gh zm!A{ke=_qk)2GJw4aQw^U2|;QTUE-`coK+HyTo|Hns&Pw|L@hs599CPTQUB235fCJ zblUA=JSBOZ?W*y3$#%OKe>k+7dV+|FCSp8e*4aKap3Q3XB~K*AGf~>@Vti~x9#D*D z>^s}V_5Fgvi2^mLV?R$Ve;Fw3i;g>o*2(w&(3x+ zo|H$sU5qCZZnul^82xE3!}wayH0v;)yp8I5mLU!xoY&9WGAebjs=aR05=FP~8L@ny zvzd$^r^d5WS~X2I9#v>Hw_-f`=Jr1UU4GBb3)L$z{?ceDD)}6FOI4|AJiF96eX8vn z#;00zYMdB<@8uNZiP|nrkm;Xu0jH>_##0QiI*3!_(UUt8Zj7hE#%cvI{+&Nwi_a^P zeDjbS<2e#$%D`d#z2)^Vp5|{nrpCWOm>QY1FKLdAN9{iL#iB#zcs@tFQvF^{Jrcsa z>khY@&+GWA#uEc{HL!&EJ<{$K+p5Ojt8G=|Q8;wAV*I6_SQz;|YO)S@HT6Ut=W^3N z0`9A6pBhgntlJgia3wRR##4UN=kDJx2JV>}B4PR{3I{7cJ-@th_%)m4ngx^I09<9R@< z2gG=4+7|{56hrk>gsHR7r9t^eBn(ms@_I~;IoJi*BvwCB@fb?2cER*tLD6_diJH6;8Bhz;b@_U zay&DA4*YRES&}UlIi6ygIdS-f(SXvEgi1>v$5Vf`uvIypqSCo?II%xr!p@n?@i?L@ zUp|h1$H&X@q%`N!J>U*oeU<2PJP>&Le3_GJ`Na0N6!Z45y(CAz>11&C#^-f3T{^cn zo~1Mg|2Y1s&4mb*rgB#v|2Y2F>A)@a!pZR4I{K62aqTL!R@HOT$(;Sk@kE@<+}_@J zKyD8Io7aB@5a)g+v9)8qJ{R$E%P6EEnYn~&q~gqGuY^6b_;)blXmetQPYaXino zWZKE`*g{JSl;hc#VV!_-Jh9q|{+*|oKM%gSs(R*v370w`vgthA21+@eT+vYbaXhDEN3~P98bi!BA_&il0S?0%JHeoNvt5p<60XE$?;73p?OUJb$v6l z$MFiIay($uCDbU6>0%Tq$5+41A4*>lLc9G+j&D|oPvv+LPVIE%_}j#%9FNtlf0g6! zebaLMr5ok=d#!*R4+u3@9>=rCU`|kuC-82!%ki0z>2^6D$gka%8(1usaKu{ljEzL&>)ww z0NENoWR&Bt%De$u_z~xtFK7L+Eh6?RmuXc_qFxq9jwk2Q*)GS!-nA!k{2g{G#~=F1 z@r*%dyBtsHTW9+?9y7VPS2-SAT@yHtZ^d6)CC3wkcD9e>6QQ)*<@kGftQ^mJZg?ig z$7tnNa{T3%hl6&e0kIel!KI}M2jwk1BResvXoJ(S^zfa#`$eDG!U)slu zNN=mvs_Lm$na7vop=7ytRrMV3C-;rx>tT97IX-XJE{E0RlekRcAb(#up0KUiN;#h4 zFpnX}N6^{*+CHdKj+Nutk~fZ%!VF{-DyfyvvdA;8_K1Hg_%gFJ>P2=Ek zJmKYWdHRoPT@%F0@!d+j`=x#OnWGXp9>=N6jRB!J;#K9x2k`WlXOZLY#YygsC#XNp z&iGPNdR6CgJe)Sp8ppF)MYNb4-}GnOH;%{Tnm4L1NNurslRATN$K?&uK0*Ro(Eh7C zSX|Ki$?*i)TOV>f^2o+xa{T8-?s7bNq>aZop6RFTu)Xo0z3$_9B6c}=RrRbsF>rD` z6L#+SIR1is%xT)6D)5>p52@$Eyp9~tdquZC#_=rY*;P&N;6Adf=75jl`2fZY(I-{#=a2F^ll z^1QGz<{r$6CGVfqW}%^Z4Zt zF#UF8K9Hwsrmp7%dA@l%Y-}f)@vApJkVlJMG;rJF-+93p@%{wcuz27Ed6Gv92p-52 zt#3sM@&xE|_JREEY&(#T__l$n6XK3NvLg>C$aCZgm@|+M$$STSK{QS5dyDyLk(I+R zMpAr|P@(1`4^NAh|IK6~2AfkZ$kUW|TOOFC`OH)nB|GZO;SS{aqZyGCY{c`1d4vtK zkZDD@aR#&@N-OsAyE?F>bb6OG1lM4ypn^O(AycY+_LtCMkxvc8=RCq0veTKn*`{DAbJ|B3i6kr6y$F&kRVSr zT=S}eJkQ#mK9F}$i-J7ow$){9S>P}FW8$R~TDOh=|kUx!YAfFAC?RG()ugJveTN3W9mv;c7v!wnD@}T&@av%@KE5!-*`vTK>HJYToq(`S`q!uONSAF(=65 z+BP17JZD-=3|w73sY#t}?LTJb5+QW})HJGn5H0Zhh$Yz~n)y%{z;ExQc?EeSieb$_ zzFxTPs~2FUUY34>JVh-!UqL=+gEuiE$V0vxkAXY~uUn@s$g?4JAYEU;%DI9QLH@lt zq23^`gcx_6AfLFP?HkA=x|nzozXJ*o_ZtI3qc-xw)G*%qug#h6yy(YSVpvu zaOMt?tA9Y$y#fqD{@zVvT|Go22n+Iwo!Y*EJe5=?{seiJOPz#*Jj=<%$OL&_hIgPI z`$C?9P<;1m`_QvYObYTG+PXy9K%V7e;zp3albQtiMsvNNAkT3S8;^lJX%iE96XaRm zbJGkX?Ew$&2q5g_{^9NXkmP~AIqNH}2b@hd9?3t!NlBi)w{zK#r@fvh|Vto#Ct`Pl7|m=t%w*FrFk&{mxN%`!oWS_&1#paK{w1PbGOWSQarH z$=_Q+j^vp>moF&%#I_5n1C0?)Z#vY#xSZmwB)^?!8A?f>6>4TpobDredazLe1JZBcXBHM5$zvLb3r6z!%6F2NCiCMv9j;5DJL~yN z`3*g~*eef@elmj2gENmtYl#UsA!k-)ByapVlE=_38033>=S!Z`NbltHJR{Musm-(k z<6uyiW-!u*2x&*(sL;ElA=qN=Ra%l`BNj}hDKLeh(ny{^patQ>J#~BijDxwNb~!81 z$)+W9ZB;5%8&65{J=lOgI+C{> zQIhAiN)2|lv~meKYLB!BxtBzY1F4g4heZk5QFNAk!!T|SaLRr-VTn9|LI z^pzw}k!GF5NIrX1+Ut`1Pmh!v$uo5a1d@Dol-??R#RRvMM3TopEk`ht$K-eYN%Dk_ z?RH5%6Ee4wnl6-Ax?wnR7 z)4v5Q$)8jt$!BGxRg(N2ohr$b3LMyHUQvu`P1r~ttG}FxB!3&KNAiSt}T}hsmQ1dCtv!SltF3Df=MM=JUVtAsFeB$kPyOR9n{wB$j{ad^% z$rBydDNFK{JGa{<`Pho|l_XCgTDx76r^2SQT}dAF=xiU!6Lkz+CHds!d#lVVj$ZWC zHc1|}aA2Piq`pRVQj+I=I-Tv3e2i9ZCCR5~Hbf%HlkDznm*m+x(QcRInd|NLkvtiA z)%~=JT!f{FBYBEDCK5^VIPA{$k$keqi_MheG1=|+BY6T-Nj(!Dhj7P-OY+16BMC|V zbNqa)*4G{IZQK_LK6Z;jUMfmUE+cuYnB=4+Pc~@Az3~oF@zqLMtv)hsj}$rHCrYLYyX!ANY9Jhe}Y7+Kjo&pb@qH`24BjPqKxLU8N&bR_ljM^)*!?oTXmoel_DKFk!$q=VQS5~zPo3ZF)kvN^hMA^1i$!z2-$k**l*-w-wg*@MW zD9

IL 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 VKw91B5_}Hy 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

*()svHdF+V47 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%0Dt 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 m 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%0A5C*l7?6>M)x^ZHjB4(BIF_C5E0 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


U?_eP`p|a9`g2Wc(5Mzp5{BO&Sxr^j8(pe_{=8B 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 ($?3whI`mZQ)#P)pD>vxh})Hq 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

*CnD!PHA`iLQVj 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 nw#vfuLo&xsFu{?c<|L!Ofy_I$*1 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 b=r?9|I^t2`R4xtBFn=- literal 0 HcmV?d00001 diff --git a/mysql-test/std_data/mysql_json/mysql_json_test_big.MYI b/mysql-test/std_data/mysql_json/mysql_json_test_big.MYI new file mode 100644 index 0000000000000000000000000000000000000000..79a1d9ebd896270dfb404501e093c288d03e56ef GIT binary patch literal 1024 zcmezOkDZZ$knpj?n!k#6X+@6NnY5?rdWmx54gFUjzuIN0D}V%l)-3J zJCq^c6rcbFC_n)UP=Epypa2CZKmiK0PQZY!I{odch?}+w*qE-LU&hmGKfkRt*^2@c zpa2CZKmiI+fC3bt00o*CIH=!$`pp+4{<&bm zkK$$ck)&Dj{wB94ym*zyVHQWQ;Vi=JbMXqxpXADr=^J^vN4aF-xh}pG?zVm4M*`cC VKw91B5_}HJawD=Fdba@5_xShz#u(5f8f*{OP4|Fq-76Gw=n30VcL;@iL c1H`*P1`+_fjfH^+?nWfJQRZj}44V)D08TU+)c^nh literal 0 HcmV?d00001 diff --git a/mysql-test/std_data/mysql_json/tempty.frm b/mysql-test/std_data/mysql_json/tempty.frm new file mode 100644 index 0000000000000000000000000000000000000000..15e6955dfb3ffe11a7b2193da8c80fe706d4792e GIT binary patch literal 8554 zcmeI&y$ZrG6o%n1$115%=uiX~>8Mj(I*X%2LGUh|yLcB~m3QQ7O)HJ7qvCs(^OF$5 zvnCIhrV}Z5(l#VzieX-0K7yS=MnG*fdqoc7IYeIB<_Abtime_type= MYSQL_TIMESTAMP_DATE; +} + + +/* + Json values in MySQL comprises the standard set of JSON values plus a MySQL + specific set. A JSON number type is subdivided into int, uint, double and + decimal. + + MySQL also adds four built-in date/time values: date, time, datetime and + timestamp. An additional opaque value can store any other MySQL type. +*/ + +enum JSONB_LITERAL_TYPES { + JSONB_NULL_LITERAL= 0x0, + JSONB_TRUE_LITERAL= 0x1, + JSONB_FALSE_LITERAL= 0x2, +}; + +/* + The size of offset or size fields in the small and the large storage + format for JSON objects and JSON arrays. +*/ +static const uchar SMALL_OFFSET_SIZE= 2; +static const uchar LARGE_OFFSET_SIZE= 4; + +/* + The size of key entries for objects when using the small storage + format or the large storage format. In the small format it is 4 + bytes (2 bytes for key length and 2 bytes for key offset). In the + large format it is 6 (2 bytes for length, 4 bytes for offset). +*/ +static const uchar KEY_ENTRY_SIZE_SMALL= (2 + SMALL_OFFSET_SIZE); +static const uchar KEY_ENTRY_SIZE_LARGE= (2 + LARGE_OFFSET_SIZE); + +/* + The size of value entries for objects or arrays. When using the + small storage format, the entry size is 3 (1 byte for type, 2 bytes + for offset). When using the large storage format, it is 5 (1 byte + for type, 4 bytes for offset). +*/ +static const uchar VALUE_ENTRY_SIZE_SMALL= (1 + SMALL_OFFSET_SIZE); +static const uchar VALUE_ENTRY_SIZE_LARGE= (1 + LARGE_OFFSET_SIZE); + +/* The maximum number of nesting levels allowed in a JSON document. */ +static const uchar JSON_DOCUMENT_MAX_DEPTH= 150; + +/** + Read an offset or size field from a buffer. The offset could be either + a two byte unsigned integer or a four byte unsigned integer. + + @param data the buffer to read from + @param large tells if the large or small storage format is used; true + means read four bytes, false means read two bytes +*/ +static inline size_t read_offset_or_size(const uchar *data, bool large) +{ + return large ? uint4korr(data) : uint2korr(data); +} + +static inline size_t key_size(bool large) +{ + return large ? KEY_ENTRY_SIZE_LARGE : KEY_ENTRY_SIZE_SMALL; +} + +static inline size_t value_size(bool large) +{ + return large ? VALUE_ENTRY_SIZE_LARGE : VALUE_ENTRY_SIZE_SMALL; +} + +/** + Inlined values are a space optimization. The actual value is stored + instead of the offset pointer to the location where a non-inlined + value would be located. + + @param[in] type The type to check. + @param[in] large tells if the large or small storage format is used; +*/ +static inline bool type_is_stored_inline(JSONB_TYPES type, bool large) +{ + return (type == JSONB_TYPE_INT16 || + type == JSONB_TYPE_UINT16 || + type == JSONB_TYPE_LITERAL || + (large && (type == JSONB_TYPE_INT32 || + type == JSONB_TYPE_UINT32))); +} + +/** + Read a variable length integer. A variable length integer uses the 8th bit in + each byte to mark if there are more bytes needed to store the integer. The + other 7 bits in the byte are used to store the actual integer's bits. + + @param[in] data the buffer to read from + @param[in] data_length the maximum number of bytes to read from data + @param[out] length the length that was read + @param[out] num the number of bytes needed to represent the length + @return false on success, true on error +*/ +static inline bool read_variable_length(const uchar *data, size_t data_length, + size_t *length, size_t *num) +{ + /* + It takes five bytes to represent UINT_MAX32, which is the largest + supported length, so don't look any further. + + Use data_length as max value to prevent segfault when reading a corrupted + JSON document. + */ + const size_t MAX_BYTES= MY_MIN(data_length, 5); + size_t len= 0; + for (size_t i= 0; i < MAX_BYTES; i++) + { + /* Get the next 7 bits of the length. */ + len|= (data[i] & 0x7f) << (7 * i); + if ((data[i] & 0x80) == 0) + { + /* The length shouldn't exceed 32 bits. */ + if (len > UINT_MAX32) + return true; + + /* This was the last byte. Return successfully. */ + *num= i + 1; + *length= len; + return false; + } + } + + /* No more available bytes. Return true to signal error. This implies a + corrupted JSON document. */ + return true; +} + +/** + JSON formatting in MySQL escapes a few special characters to prevent + ambiguity. +*/ +static bool append_string_json(String *buffer, const uchar *data, size_t len) +{ + const uchar *last= data + len; + for (; data < last; data++) + { + const uchar c= *data; + switch (c) { + case '\\': + buffer->append("\\\\"); + break; + case '\n': + buffer->append("\\n"); + break; + case '\r': + buffer->append("\\r"); + break; + case '"': + buffer->append("\\\""); + break; + case '\b': + buffer->append("\\b"); + break; + case '\f': + buffer->append("\\f"); + break; + case '\t': + buffer->append("\\t"); + break; + default: + buffer->append(c); + break; + } + } + return false; +} + +/* + Function used for JSON_OPAQUE type. +*/ +static bool print_mysql_datetime_value(String *buffer, enum_field_types type, + const uchar *data, size_t len) +{ + if (len < 8) + return true; + + MYSQL_TIME t; + switch (type) + { + case MYSQL_TYPE_TIME: + TIME_from_longlong_time_packed(&t, sint8korr(data)); + break; + case MYSQL_TYPE_DATE: + TIME_from_longlong_date_packed(&t, sint8korr(data)); + break; + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + TIME_from_longlong_datetime_packed(&t, sint8korr(data)); + break; + default: + DBUG_ASSERT(0); + return true; + } + /* Wrap all datetime strings within double quotes. */ + buffer->append('\"'); + buffer->reserve(MAX_DATE_STRING_REP_LENGTH); + buffer->length(buffer->length() + + my_TIME_to_str(&t, const_cast(buffer->end()), 6)); + buffer->append('\"'); + return false; +} + +static bool parse_mysql_scalar(String *buffer, size_t value_json_type, + const uchar *data, size_t len) +{ + switch (value_json_type) { + case JSONB_TYPE_LITERAL: + { + if (len < 1) + return true; + switch (static_cast(*data)) { + case JSONB_NULL_LITERAL: + return buffer->append("null"); + case JSONB_TRUE_LITERAL: + return buffer->append("true"); + case JSONB_FALSE_LITERAL: + return buffer->append("false"); + default: /* Invalid literal constant, malformed JSON. */ + return true; + } + } + case JSONB_TYPE_INT16: + return len < 2 || buffer->append_longlong(sint2korr(data)); + case JSONB_TYPE_INT32: + return len < 4 || buffer->append_longlong(sint4korr(data)); + case JSONB_TYPE_INT64: + return len < 8 || buffer->append_longlong(sint8korr(data)); + case JSONB_TYPE_UINT16: + return len < 2 || buffer->append_ulonglong(uint2korr(data)); + case JSONB_TYPE_UINT32: + return len < 4 || buffer->append_ulonglong(uint4korr(data)); + case JSONB_TYPE_UINT64: + return len < 8 || buffer->append_ulonglong(uint8korr(data)); + case JSONB_TYPE_DOUBLE: + if (len < 8) + return true; + buffer->reserve(FLOATING_POINT_BUFFER, 2 * FLOATING_POINT_BUFFER); + buffer->qs_append(reinterpret_cast(data)); + return false; + case JSONB_TYPE_STRING: + { + size_t string_length, store_bytes; + + return read_variable_length(data, len, &string_length, &store_bytes) || + len < store_bytes + string_length || + buffer->append('"') || + append_string_json(buffer, data + store_bytes, string_length) || + buffer->append('"'); + } + case JSONB_TYPE_OPAQUE: + { + /* The field_type maps directly to enum_field_types. */ + const uchar type_value= *data; + const enum_field_types field_type= static_cast(type_value); + + size_t blob_length, length_bytes; + const uchar *blob_start; + + if (read_variable_length(data + 1, len, &blob_length, &length_bytes) || + len < length_bytes + blob_length) + return true; + blob_start= data + length_bytes + 1; + + switch (field_type) { + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + return print_mysql_datetime_value(buffer, field_type, + blob_start, blob_length); + case MYSQL_TYPE_NEWDECIMAL: + { + /* Expect at least two bytes, which contain precision and scale. */ + if (blob_length < 2) + return true; + + const int precision= blob_start[0]; + const int scale= blob_start[1]; + + my_decimal d; + + /* The decimal value is encoded after the two prec/scale bytes. */ + const size_t dec_size= my_decimal_get_binary_size(precision, scale); + if (dec_size != blob_length - 2 || + binary2my_decimal(E_DEC_ERROR, + reinterpret_cast(blob_start + 2), + &d, precision, scale) != E_DEC_OK) + return true; + + if (d.to_string_native(buffer, 0, 0, ' ', E_DEC_ERROR) != E_DEC_OK) + return true; + return false; + } + default: + { + /* Any other MySQL type is presented as a base64 encoded string. */ + if (buffer->append("\"base64:type") || + buffer->append_longlong(field_type) || + buffer->append(':')) + return true; + + const size_t needed= my_base64_needed_encoded_length( + static_cast(blob_length)); + if (buffer->reserve(needed) || + my_base64_encode(blob_start, blob_length, + const_cast(buffer->end()))) + return true; + /* -1 to override the null terminator from my_base64_encode */ + DBUG_ASSERT(*(buffer->end() + needed) == '\0'); + buffer->length(buffer->length() + needed - 1); + return buffer->append('"'); + } + } + } + default: + return true; + } +} + + +/** + Read a value from a JSON Object or Array, given the position of it. + This function handles both inlined values as well as values stored at + an offset. + + @param[out] buffer Where to print the results. + @param[in] data The raw binary data of the Object or Array. + @param[in] len The length of the binary data. + @param[in] value_type_offset Where the type of the value is stored. + @param[in] large true if the large storage format is used; + @param[in] depth How deep the JSON object is in the hierarchy. +*/ +static bool parse_mysql_scalar_or_value(String *buffer, const uchar *data, + size_t len, size_t value_type_offset, + bool large, size_t depth) +{ + /* Get the type of the value stored at the key. */ + const JSONB_TYPES value_type= + static_cast(data[value_type_offset]); + + if (type_is_stored_inline(value_type, large)) + { + const size_t value_start = value_type_offset + 1; + if (parse_mysql_scalar(buffer, value_type, data + value_start, + len - value_start)) + return true; + } + else + { + /* The offset to where the value is stored is relative to the start + of the Object / Array */ + const size_t value_start= read_offset_or_size( + data + value_type_offset + 1, large); + if (parse_mysql_json_value(buffer, value_type, data + value_start, + len - value_start, depth)) + return true; + } + return false; +} + +static bool parse_array_or_object(String *buffer, const uchar *data, size_t len, + bool handle_as_object, bool large, + size_t depth) +{ + if (++depth > JSON_DOCUMENT_MAX_DEPTH) + return true; + + /* + Make sure the document is long enough to contain the two length fields + (both number of elements or members, and number of bytes). + */ + const size_t offset_size= large ? LARGE_OFFSET_SIZE : SMALL_OFFSET_SIZE; + /* The length has to be at least double offset size (header). */ + if (len < 2 * offset_size) + return true; + + + /* + Every JSON Object or Array contains two numbers in the header: + - The number of elements in the Object / Array (Keys) + - The total number of bytes occupied by the JSON Object / Array, including + the two numbers in the header. + Depending on the Object / Array type (small / large) the numbers are stored + in 2 bytes or 4 bytes each. + */ + const size_t element_count= read_offset_or_size(data, large); + const size_t bytes= read_offset_or_size(data + offset_size, large); + + /* The value can't have more bytes than what's available in the buffer. */ + if (bytes > len) + return true; + + if (buffer->append(handle_as_object ? '{' : '[')) + return true; + + + for (size_t i= 0; i < element_count; i++) + { + if (handle_as_object) + { + /* + The JSON Object is stored as a header part and a data part. + Header consists of: + - two length fields, + - an array of pointers to keys. + - an array of tuples (type, pointer to values) + * For certain types, the pointer to values is replaced by the actual + value. (see type_is_stored_inline) + Data consists of: + - All Key data, in order + - All Value data, in order + */ + const size_t key_offset= 2 * offset_size + i * key_size(large); + const size_t key_start= read_offset_or_size(data + key_offset, large); + /* The length of keys is always stored in 2 bytes (large == false) */ + const size_t key_len= read_offset_or_size( + data + key_offset + offset_size, false); + + const size_t value_type_offset=(2 * offset_size + + element_count * key_size(large) + + i * value_size(large)); + + /* First print the key. */ + if (buffer->append('"') || + append_string_json(buffer, data + key_start, key_len) || + buffer->append("\": ")) + { + return true; + } + + /* Then print the value. */ + if (parse_mysql_scalar_or_value(buffer, data, bytes, value_type_offset, + large, depth)) + return true; + } + else + { + /* + Arrays do not have the keys vector and its associated data. + We jump straight to reading values. + */ + const size_t value_type_offset= 2 * offset_size + value_size(large) * i; + + if (parse_mysql_scalar_or_value(buffer, data, bytes, value_type_offset, + large, depth)) + return true; + } + + if (i != element_count - 1 && buffer->append(", ")) + return true; + } + + return buffer->append(handle_as_object ? '}' : ']'); +} + +/** + Check the first byte of data which is the enum structure and based on it + perform parsing of object or array where each can have small or large + representation. + + @param[out] buffer Where to print the results. + @param[in] type Type of value {object, array, scalar}. + @param[in] data Raw data for parsing. + @param[in] length Length of data. + @param[in] depth Depth size. +*/ +bool parse_mysql_json_value(String *buffer, JSONB_TYPES type, const uchar *data, + size_t len, size_t depth) +{ + const bool IS_OBJECT=true, IS_LARGE=true; + switch (type) { + case JSONB_TYPE_SMALL_OBJECT: + return parse_array_or_object(buffer, data, len, IS_OBJECT, !IS_LARGE, depth); + case JSONB_TYPE_LARGE_OBJECT: + return parse_array_or_object(buffer, data, len, IS_OBJECT, IS_LARGE, depth); + case JSONB_TYPE_SMALL_ARRAY: + return parse_array_or_object(buffer, data, len, !IS_OBJECT, !IS_LARGE, depth); + case JSONB_TYPE_LARGE_ARRAY: + return parse_array_or_object(buffer, data, len, !IS_OBJECT, IS_LARGE, depth); + default: + return parse_mysql_scalar(buffer, type, data, len); + } +} diff --git a/plugin/type_mysql_json/mysql_json.h b/plugin/type_mysql_json/mysql_json.h new file mode 100644 index 00000000000..79a784cbb6e --- /dev/null +++ b/plugin/type_mysql_json/mysql_json.h @@ -0,0 +1,44 @@ +/* + Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020 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-1335 USA */ + +#ifndef MYSQL_JSON_INCLUDED +#define MYSQL_JSON_INCLUDED + +#include "my_global.h" +#include "sql_string.h" // String + +enum JSONB_TYPES { + JSONB_TYPE_SMALL_OBJECT= 0x0, + JSONB_TYPE_LARGE_OBJECT= 0x1, + JSONB_TYPE_SMALL_ARRAY= 0x2, + JSONB_TYPE_LARGE_ARRAY= 0x3, + JSONB_TYPE_LITERAL= 0x4, + JSONB_TYPE_INT16= 0x5, + JSONB_TYPE_UINT16= 0x6, + JSONB_TYPE_INT32= 0x7, + JSONB_TYPE_UINT32= 0x8, + JSONB_TYPE_INT64= 0x9, + JSONB_TYPE_UINT64= 0xA, + JSONB_TYPE_DOUBLE= 0xB, + JSONB_TYPE_STRING= 0xC, + JSONB_TYPE_OPAQUE= 0xF +}; + +bool parse_mysql_json_value(String *buffer, JSONB_TYPES type, const uchar *data, + size_t len, size_t depth); +#endif /* MYSQL_JSON_INCLUDED */ diff --git a/plugin/type_mysql_json/type.cc b/plugin/type_mysql_json/type.cc new file mode 100644 index 00000000000..b267745a998 --- /dev/null +++ b/plugin/type_mysql_json/type.cc @@ -0,0 +1,203 @@ +/* + Copyright (c) 2020 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-1335 USA */ + +#include +#include +#include +#include +#include +#include "mysql_json.h" + +static const LEX_CSTRING empty_clex_str= {"", 0}; + +class Type_handler_mysql_json: public Type_handler_blob +{ +public: + Field *make_conversion_table_field(MEM_ROOT *, TABLE *, uint, const Field *) + const override; + const Type_collection *type_collection() const override; + Field *make_table_field_from_def(TABLE_SHARE *, MEM_ROOT *, + const LEX_CSTRING *, const Record_addr &, + const Bit_addr &, + const Column_definition_attributes *, + uint32) const override; + Field *make_table_field(MEM_ROOT *, const LEX_CSTRING *, + const Record_addr &, const Type_all_attributes &, + TABLE_SHARE *) const override; +}; + +Type_handler_mysql_json type_handler_mysql_json; + + +class Field_mysql_json: public Field_blob +{ +public: + Field_mysql_json(uchar *ptr_arg, uchar *null_ptr_arg, + uchar null_bit_arg, enum utype unireg_check_arg, + const LEX_CSTRING *field_name_arg, TABLE_SHARE *share, + uint blob_pack_length, const DTCollation &collation) + : Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, share, blob_pack_length, + &my_charset_utf8mb4_bin) + {} + + String *val_str(String *val_buffer, String *val_str); + const Type_handler *type_handler() const { return &type_handler_mysql_json; } + bool parse_mysql(String *dest, const char *data, size_t length) const; + bool send(Protocol *protocol) { return Field::send(protocol); } + void sql_type(String &s) const + { s.set_ascii(STRING_WITH_LEN("json /* MySQL 5.7 */")); } + /* this will make ALTER TABLE to consider it different from built-in field */ + Compression_method *compression_method() const { return (Compression_method*)1; } +}; + +Field *Type_handler_mysql_json::make_conversion_table_field(MEM_ROOT *root, + TABLE *table, uint metadata, const Field *target) const +{ + uint pack_length= metadata & 0x00ff; + if (pack_length < 1 || pack_length > 4) + return NULL; // Broken binary log? + return new (root) + Field_mysql_json(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str, + table->s, pack_length, target->charset()); +} + +Field *Type_handler_mysql_json::make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *root, const LEX_CSTRING *name, + const Record_addr &addr, const Bit_addr &bit, + const Column_definition_attributes *attr, uint32 flags) const +{ + return new (root) Field_mysql_json(addr.ptr(), addr.null_ptr(), + addr.null_bit(), attr->unireg_check, name, share, + attr->pack_flag_to_pack_length(), attr->charset); +} + + +Field *Type_handler_mysql_json::make_table_field(MEM_ROOT *root, + const LEX_CSTRING *name, const Record_addr &addr, + const Type_all_attributes &attr, TABLE_SHARE *share) const +{ + return new (root) Field_mysql_json(addr.ptr(), addr.null_ptr(), + addr.null_bit(), Field::NONE, name, share, 2, attr.collation); +} + + +String *Field_mysql_json::val_str(String *val_buffer, String *val_ptr) +{ + String *raw_value= Field_blob::val_str(val_buffer, val_ptr); + String data; + + data.copy(*raw_value); + + val_ptr->length(0); + if (parse_mysql(val_ptr, data.ptr(), data.length())) + { + val_ptr->length(0); + my_printf_error(ER_UNKNOWN_ERROR, + "Error parsing MySQL JSON format, please dump this table from MySQL " + "and then restore it to be able to use it in MariaDB.", MYF(0)); + } + return val_ptr; +} + +bool Field_mysql_json::parse_mysql(String *dest, + const char *data, size_t length) const +{ + if (!data) + return false; + + /* Each JSON blob must start with a type specifier. */ + if (length < 2) + return true; + + if (parse_mysql_json_value(dest, static_cast(data[0]), + reinterpret_cast(data) + 1, + length - 1, 0)) + return true; + + return false; +} + +class Type_collection_mysql_json: public Type_collection +{ +public: + const Type_handler *aggregate_for_result(const Type_handler *a, + const Type_handler *b) + const override + { + if (a == b) + return a; + return NULL; + } + + const Type_handler *aggregate_for_min_max(const Type_handler *a, + const Type_handler *b) + const override + { + return aggregate_for_result(a, b); + } + + const Type_handler *aggregate_for_comparison(const Type_handler *a, + const Type_handler *b) + const override + { + return aggregate_for_result(a, b); + } + + const Type_handler *aggregate_for_num_op(const Type_handler *a, + const Type_handler *b) + const override + { + return NULL; + } + + const Type_handler *handler_by_name(const LEX_CSTRING &name) const override + { + if (type_handler_mysql_json.name().eq(name)) + return &type_handler_mysql_json; + return NULL; + } +}; + +const Type_collection *Type_handler_mysql_json::type_collection() const +{ + static Type_collection_mysql_json type_collection_mysql_json; + return &type_collection_mysql_json; +} + +static struct st_mariadb_data_type plugin_descriptor_type_mysql_json= +{ + MariaDB_DATA_TYPE_INTERFACE_VERSION, + &type_handler_mysql_json +}; + +maria_declare_plugin(type_mysql_json) +{ + MariaDB_DATA_TYPE_PLUGIN, + &plugin_descriptor_type_mysql_json, + "MYSQL_JSON", + "Anel Husaković, Vicențiu Ciorbaru", + "Data type MYSQL_JSON", + PLUGIN_LICENSE_GPL, + 0, + 0, + 0x0001, + NULL, + NULL, + "0.1", + MariaDB_PLUGIN_MATURITY_ALPHA +} +maria_declare_plugin_end; diff --git a/sql/table.cc b/sql/table.cc index 3cccc376bdf..c48a6fed89a 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2367,7 +2367,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, comment_pos+= comment_length; } - if ((uchar) strpos[13] == (uchar) MYSQL_TYPE_VIRTUAL) + if ((uchar) strpos[13] == (uchar) MYSQL_TYPE_VIRTUAL + && likely(share->mysql_version >= 100000)) { /* MariaDB version 10.0 version. @@ -2417,7 +2418,18 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, interval_nr= (uint) strpos[12]; enum_field_types field_type= (enum_field_types) strpos[13]; if (!(handler= Type_handler::get_handler_by_real_type(field_type))) - goto err; // Not supported field type + { + if (field_type == 245 && + share->mysql_version >= 50700) // a.k.a MySQL 5.7 JSON + { + share->incompatible_version|= HA_CREATE_USED_ENGINE; + const LEX_CSTRING mysql_json{STRING_WITH_LEN("MYSQL_JSON")}; + handler= Type_handler::handler_by_name_or_error(thd, mysql_json); + } + + if (!handler) + goto err; // Not supported field type + } handler= handler->type_handler_frm_unpack(strpos); if (handler->Column_definition_attributes_frm_unpack(&attr, share, strpos, From d5c9f84dfc72787c94ca773f83cceee9d93b2014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 28 Oct 2020 14:00:37 +0200 Subject: [PATCH 270/323] MDEV-22707 : galera got stuck after flush tables Remove unnecessary condition and add necessary include for non debug Galera library. --- mysql-test/suite/galera/t/MDEV-22707.test | 1 + sql/sql_base.cc | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/galera/t/MDEV-22707.test b/mysql-test/suite/galera/t/MDEV-22707.test index 19755f7c5ac..feb44e5e44f 100644 --- a/mysql-test/suite/galera/t/MDEV-22707.test +++ b/mysql-test/suite/galera/t/MDEV-22707.test @@ -6,6 +6,7 @@ --source include/have_innodb.inc --source include/have_debug.inc --source include/have_debug_sync.inc +--source include/galera_have_debug_sync.inc CREATE TABLE t1(f2 INT) ENGINE=InnoDB; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 497c6a0322f..635e17d1865 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1861,7 +1861,7 @@ retry_share: #ifdef WITH_WSREP if (!((flags & MYSQL_OPEN_IGNORE_FLUSH) || - (wsrep_on(thd) && thd->wsrep_applier))) + (thd->wsrep_applier))) #else if (!(flags & MYSQL_OPEN_IGNORE_FLUSH)) #endif From cb04c1bc64031c7a2e5e0af16c97766b2a331c4a Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 28 Oct 2020 13:35:43 +0100 Subject: [PATCH 271/323] MDEV-24040 - fix appveyor build Old SDK is missing #define SECURITY_MAX_SID_STRING_CHARACTERS --- sql/mysqld.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3a5222d32de..433a6dacc01 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2597,6 +2597,11 @@ static void init_pipe_security_descriptor() (FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | READ_CONTROL | \ SYNCHRONIZE | FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) +#ifndef SECURITY_MAX_SID_STRING_CHARACTERS +/* Old SDK does not have this constant */ +#define SECURITY_MAX_SID_STRING_CHARACTERS 187 +#endif + /* Figure out SID of the user that runs the server, then create SDDL string for pipe permissions, and convert it to the security descriptor. From e451145aa981f3442977975687087183a05cda88 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 28 Oct 2020 14:24:10 +0100 Subject: [PATCH 272/323] MDEV-24040 Named pipe permission issue Tighten access control - deny FILE_CREATE_PIPE_INSTANCE permission to everyone except current user (the one that runs mysqld) --- sql/handle_connections_win.cc | 66 +++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/sql/handle_connections_win.cc b/sql/handle_connections_win.cc index 0046dcdfd8c..50fd9090e0a 100644 --- a/sql/handle_connections_win.cc +++ b/sql/handle_connections_win.cc @@ -310,6 +310,64 @@ retry : } }; +/* + Create a security descriptor for pipe. + - Use low integrity level, so that it is possible to connect + from any process. + - Give current user read/write access to pipe. + - Give Everyone read/write access to pipe minus FILE_CREATE_PIPE_INSTANCE +*/ +static void init_pipe_security_descriptor() +{ +#define SDDL_FMT "S:(ML;; NW;;; LW) D:(A;; 0x%08x;;; WD)(A;; FRFW;;; %s)" +#define EVERYONE_PIPE_ACCESS_MASK \ + (FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | READ_CONTROL | \ + SYNCHRONIZE | FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) + +#ifndef SECURITY_MAX_SID_STRING_CHARACTERS +/* Old SDK does not have this constant */ +#define SECURITY_MAX_SID_STRING_CHARACTERS 187 +#endif + + /* + Figure out SID of the user that runs the server, then create SDDL string + for pipe permissions, and convert it to the security descriptor. + */ + char sddl_string[sizeof(SDDL_FMT) + 8 + SECURITY_MAX_SID_STRING_CHARACTERS]; + struct + { + TOKEN_USER token_user; + BYTE buffer[SECURITY_MAX_SID_SIZE]; + } token_buffer; + HANDLE token; + DWORD tmp; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) + goto fail; + + if (!GetTokenInformation(token, TokenUser, &token_buffer, + (DWORD) sizeof(token_buffer), &tmp)) + goto fail; + + CloseHandle(token); + + char *current_user_string_sid; + if (!ConvertSidToStringSid(token_buffer.token_user.User.Sid, + ¤t_user_string_sid)) + goto fail; + + snprintf(sddl_string, sizeof(sddl_string), SDDL_FMT, + EVERYONE_PIPE_ACCESS_MASK, current_user_string_sid); + LocalFree(current_user_string_sid); + + if (ConvertStringSecurityDescriptorToSecurityDescriptor(sddl_string, + SDDL_REVISION_1, &pipe_security.lpSecurityDescriptor, 0)) + return; + +fail: + sql_perror("Can't start server : Initialize security descriptor"); + unireg_abort(1); +} /** Pipe Listener. @@ -338,13 +396,7 @@ struct Pipe_Listener : public Listener { snprintf(pipe_name, sizeof(pipe_name), "\\\\.\\pipe\\%s", mysqld_unix_port); open_mode |= FILE_FLAG_FIRST_PIPE_INSTANCE; - if (!ConvertStringSecurityDescriptorToSecurityDescriptorA( - "S:(ML;; NW;;; LW) D:(A;; FRFW;;; WD)", - 1, &pipe_security.lpSecurityDescriptor, NULL)) - { - sql_perror("Can't start server : Initialize security descriptor"); - unireg_abort(1); - } + init_pipe_security_descriptor(); pipe_security.nLength= sizeof(SECURITY_ATTRIBUTES); pipe_security.bInheritHandle= FALSE; } From dee690292228ff240707826db9d4847e32981fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 28 Oct 2020 18:48:14 +0200 Subject: [PATCH 273/323] After-merge fix: sys_vars.sysvars_innodb,32bit --- .../sys_vars/r/sysvars_innodb,32bit.rdiff | 822 ++++++++++++------ 1 file changed, 550 insertions(+), 272 deletions(-) diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff b/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff index 16cda279c3e..50a1d1f197a 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff @@ -1,272 +1,550 @@ -52c52 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -64c64 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -76c76 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -88c88 -< VARIABLE_TYPE BIGINT ---- -> VARIABLE_TYPE INT -160c160 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -163c163 -< NUMERIC_MAX_VALUE 9223372036854775807 ---- -> NUMERIC_MAX_VALUE 2147483647 -196c196 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -232c232 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -292c292 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -388c388 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -424c424 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -448c448 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -460c460 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -463c463 -< NUMERIC_MAX_VALUE 18446744073709551615 ---- -> NUMERIC_MAX_VALUE 4294967295 -688c688 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -784c784 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -832c832 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -844c844 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -868c868 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -892c892 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -940c940 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -964c964 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1000c1000 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1012c1012 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1024c1024 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1036c1036 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1039c1039 -< NUMERIC_MAX_VALUE 18446744073709551615 ---- -> NUMERIC_MAX_VALUE 4294967295 -1060c1060 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1072c1072 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1096c1096 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1120c1120 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1123c1123 -< NUMERIC_MAX_VALUE 18446744073709551615 ---- -> NUMERIC_MAX_VALUE 4294967295 -1130c1130 -< DEFAULT_VALUE 18446744073709551615 ---- -> DEFAULT_VALUE 4294967295 -1132c1132 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1135c1135 -< NUMERIC_MAX_VALUE 18446744073709551615 ---- -> NUMERIC_MAX_VALUE 4294967295 -1192c1192 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1204c1204 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1207c1207 -< NUMERIC_MAX_VALUE 9223372036854775807 ---- -> NUMERIC_MAX_VALUE 2147483647 -1252c1252 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1300c1300 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1312c1312 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1315c1315 -< NUMERIC_MAX_VALUE 18446744073709551615 ---- -> NUMERIC_MAX_VALUE 4294967295 -1360c1360 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1363c1363 -< NUMERIC_MAX_VALUE 18446744073709551615 ---- -> NUMERIC_MAX_VALUE 4294967295 -1372c1372 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1492c1492 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1495c1495 -< NUMERIC_MAX_VALUE 9223372036854775807 ---- -> NUMERIC_MAX_VALUE 2147483647 -1516c1516 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1540c1540 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1552c1552 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1588c1588 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1600c1600 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1612c1612 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1636c1636 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1648c1648 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1672c1672 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1675c1675 -< NUMERIC_MAX_VALUE 18446744073709551615 ---- -> NUMERIC_MAX_VALUE 4294967295 -1696c1696 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1708c1708 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1756c1756 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1936c1936 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1960c1960 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -1963c1963 -< NUMERIC_MAX_VALUE 18446744073709551615 ---- -> NUMERIC_MAX_VALUE 4294967295 -1996c1996 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -2008c2008 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -2068c2068 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -2092c2092 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED -2116c2116 -< VARIABLE_TYPE BIGINT UNSIGNED ---- -> VARIABLE_TYPE INT UNSIGNED +@@ -49,7 +49,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 8 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Number of InnoDB Adaptive Hash Index Partitions (default 8) + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 512 +@@ -61,7 +61,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 150000 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT The upper limit of the sleep delay in usec. Value of 0 disables it. + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 1000000 +@@ -73,7 +73,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 64 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Data file autoextend increment in megabytes + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 1000 +@@ -85,7 +85,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 1 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT ++VARIABLE_TYPE INT + VARIABLE_COMMENT The AUTOINC lock modes supported by InnoDB: 0 => Old style AUTOINC locking (for backward compatibility); 1 => New style AUTOINC locking; 2 => No AUTOINC locking (unsafe for SBR) + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 2 +@@ -157,10 +157,10 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 134217728 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Size of a single memory chunk within each buffer pool instance for resizing buffer pool. Online buffer pool resizing happens at this granularity. 0 means disable resizing buffer pool. + NUMERIC_MIN_VALUE 1048576 +-NUMERIC_MAX_VALUE 9223372036854775807 ++NUMERIC_MAX_VALUE 2147483647 + NUMERIC_BLOCK_SIZE 1048576 + ENUM_VALUE_LIST NULL + READ_ONLY YES +@@ -193,7 +193,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 25 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Dump only the hottest N% of each buffer pool, defaults to 25 + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 100 +@@ -229,7 +229,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 0 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Number of buffer pool instances, set to higher value on high-end machines to increase scalability + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 64 +@@ -289,7 +289,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 0 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT A number between [0, 100] that tells how oftern buffer pool dump status in percentages should be printed. E.g. 10 means that buffer pool dump status is printed when every 10% of number of buffer pool pages are dumped. Default is 0 (only start and end status is printed). + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 100 +@@ -397,7 +397,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 0 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Helps in performance tuning in heavily concurrent environments. + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 1000 +@@ -433,7 +433,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 5 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT If the compression failure rate of a table is greater than this number more padding is added to the pages to reduce the failures. A value of zero implies no padding + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 100 +@@ -457,7 +457,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 50 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Percentage of empty space on a data page that can be reserved to make the page compressible. + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 75 +@@ -469,10 +469,10 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 5000 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket + NUMERIC_MIN_VALUE 1 +-NUMERIC_MAX_VALUE 18446744073709551615 ++NUMERIC_MAX_VALUE 4294967295 + NUMERIC_BLOCK_SIZE 0 + ENUM_VALUE_LIST NULL + READ_ONLY NO +@@ -697,7 +697,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 120 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Number of pages reserved in doublewrite buffer for batch flushing + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 127 +@@ -793,7 +793,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 600 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Maximum number of seconds that semaphore times out in InnoDB. + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 4294967295 +@@ -841,7 +841,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 0 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Make the first page of the given tablespace dirty. + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 4294967295 +@@ -853,7 +853,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 30 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Number of iterations over which the background flushing is averaged. + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 1000 +@@ -877,7 +877,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 1 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Controls the durability/speed trade-off for commits. Set to 0 (write and flush redo log to disk only once per second), 1 (flush to disk at each commit), 2 (write to log at commit but flush to disk only once per second) or 3 (flush to disk at prepare and at commit, slower and usually redundant). 1 and 3 guarantees that after a crash, committed transactions will not be lost and will be consistent with the binlog and other transactional engines. 2 can get inconsistent and lose transactions if there is a power failure or kernel crash but not if mysqld crashes. 0 has no guarantees in case of crash. 0 and 2 can be faster than 1 or 3. + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 3 +@@ -901,7 +901,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 1 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Set to 0 (don't flush neighbors from buffer pool), 1 (flush contiguous neighbors from buffer pool) or 2 (flush neighbors from buffer pool), when flushing a block + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 2 +@@ -949,7 +949,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 0 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Helps to save your data in case the disk image of the database becomes corrupt. + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 6 +@@ -973,7 +973,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 8000000 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT InnoDB Fulltext search cache size in bytes + NUMERIC_MIN_VALUE 1600000 + NUMERIC_MAX_VALUE 80000000 +@@ -1009,7 +1009,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 84 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT InnoDB Fulltext search maximum token size in characters + NUMERIC_MIN_VALUE 10 + NUMERIC_MAX_VALUE 84 +@@ -1021,7 +1021,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 3 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT InnoDB Fulltext search minimum token size in characters + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 16 +@@ -1033,7 +1033,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 2000 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT InnoDB Fulltext search number of words to optimize for each optimize table call + NUMERIC_MIN_VALUE 1000 + NUMERIC_MAX_VALUE 10000 +@@ -1045,10 +1045,10 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 2000000000 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT InnoDB Fulltext search query result cache limit in bytes + NUMERIC_MIN_VALUE 1000000 +-NUMERIC_MAX_VALUE 18446744073709551615 ++NUMERIC_MAX_VALUE 4294967295 + NUMERIC_BLOCK_SIZE 0 + ENUM_VALUE_LIST NULL + READ_ONLY NO +@@ -1069,7 +1069,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 2 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT InnoDB Fulltext search parallel sort degree, will round up to nearest power of 2 number + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 16 +@@ -1081,7 +1081,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 640000000 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Total memory allocated for InnoDB Fulltext Search cache + NUMERIC_MIN_VALUE 32000000 + NUMERIC_MAX_VALUE 1600000000 +@@ -1105,7 +1105,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 100 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Up to what percentage of dirty pages should be flushed when innodb finds it has spare resources to do so. + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 100 +@@ -1141,22 +1141,22 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 200 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Number of IOPs the server can do. Tunes the background IO rate + NUMERIC_MIN_VALUE 100 +-NUMERIC_MAX_VALUE 18446744073709551615 ++NUMERIC_MAX_VALUE 4294967295 + NUMERIC_BLOCK_SIZE 0 + ENUM_VALUE_LIST NULL + READ_ONLY NO + COMMAND_LINE_ARGUMENT REQUIRED + VARIABLE_NAME INNODB_IO_CAPACITY_MAX + SESSION_VALUE NULL +-DEFAULT_VALUE 18446744073709551615 ++DEFAULT_VALUE 4294967295 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Limit to which innodb_io_capacity can be inflated. + NUMERIC_MIN_VALUE 100 +-NUMERIC_MAX_VALUE 18446744073709551615 ++NUMERIC_MAX_VALUE 4294967295 + NUMERIC_BLOCK_SIZE 0 + ENUM_VALUE_LIST NULL + READ_ONLY NO +@@ -1213,7 +1213,7 @@ + SESSION_VALUE 50 + DEFAULT_VALUE 50 + VARIABLE_SCOPE SESSION +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout. + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 1073741824 +@@ -1225,10 +1225,10 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 16777216 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT The size of the buffer which InnoDB uses to write log to the log files on disk. + NUMERIC_MIN_VALUE 262144 +-NUMERIC_MAX_VALUE 9223372036854775807 ++NUMERIC_MAX_VALUE 2147483647 + NUMERIC_BLOCK_SIZE 1024 + ENUM_VALUE_LIST NULL + READ_ONLY YES +@@ -1273,7 +1273,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 2 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Number of log files in the log group. InnoDB writes to the files in a circular fashion. + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 100 +@@ -1321,7 +1321,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 8192 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Redo log write ahead unit size to avoid read-on-write, it should match the OS cache block IO size + NUMERIC_MIN_VALUE 512 + NUMERIC_MAX_VALUE 16384 +@@ -1333,10 +1333,10 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 1024 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT How deep to scan LRU to keep it clean + NUMERIC_MIN_VALUE 100 +-NUMERIC_MAX_VALUE 18446744073709551615 ++NUMERIC_MAX_VALUE 4294967295 + NUMERIC_BLOCK_SIZE 0 + ENUM_VALUE_LIST NULL + READ_ONLY NO +@@ -1381,10 +1381,10 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 0 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Desired maximum length of the purge queue (0 = no limit) + NUMERIC_MIN_VALUE 0 +-NUMERIC_MAX_VALUE 18446744073709551615 ++NUMERIC_MAX_VALUE 4294967295 + NUMERIC_BLOCK_SIZE 0 + ENUM_VALUE_LIST NULL + READ_ONLY NO +@@ -1393,7 +1393,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 0 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Maximum delay of user threads in micro-seconds + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 10000000 +@@ -1525,10 +1525,10 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 0 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT How many files at the maximum InnoDB keeps open at the same time. + NUMERIC_MIN_VALUE 0 +-NUMERIC_MAX_VALUE 9223372036854775807 ++NUMERIC_MAX_VALUE 2147483647 + NUMERIC_BLOCK_SIZE 0 + ENUM_VALUE_LIST NULL + READ_ONLY YES +@@ -1549,7 +1549,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 4 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Page cleaner threads can be from 1 to 64. Default is 4. + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 64 +@@ -1573,7 +1573,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 16 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Number of rw_locks protecting buffer pool page_hash. Rounded up to the next power of 2 + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 1024 +@@ -1585,7 +1585,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 16384 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Page size to use for all InnoDB tablespaces. + NUMERIC_MIN_VALUE 4096 + NUMERIC_MAX_VALUE 65536 +@@ -1621,7 +1621,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 300 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Number of UNDO log pages to purge in one batch from the history list. + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 5000 +@@ -1633,7 +1633,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 128 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Dictates rate at which UNDO records are purged. Value N means purge rollback segment(s) on every Nth iteration of purge invocation + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 128 +@@ -1645,7 +1645,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 4 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Purge threads can be from 1 to 32. Default is 4. + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 32 +@@ -1669,7 +1669,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 56 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Number of pages that must be accessed sequentially for InnoDB to trigger a readahead. + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 64 +@@ -1681,7 +1681,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 4 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Number of background read I/O threads in InnoDB. + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 64 +@@ -1705,10 +1705,10 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 0 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Replication thread delay (ms) on the slave server if innodb_thread_concurrency is reached (0 by default) + NUMERIC_MIN_VALUE 0 +-NUMERIC_MAX_VALUE 18446744073709551615 ++NUMERIC_MAX_VALUE 4294967295 + NUMERIC_BLOCK_SIZE 0 + ENUM_VALUE_LIST NULL + READ_ONLY NO +@@ -1729,7 +1729,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 128 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Number of undo logs to use (deprecated). + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 128 +@@ -1741,7 +1741,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 0 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT An InnoDB page number. + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 4294967295 +@@ -1789,7 +1789,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 1048576 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Memory buffer size for index creation + NUMERIC_MIN_VALUE 65536 + NUMERIC_MAX_VALUE 67108864 +@@ -1969,7 +1969,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 1 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Size of the mutex/lock wait array. + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 1024 +@@ -1993,10 +1993,10 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 30 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Count of spin-loop rounds in InnoDB mutexes (30 by default) + NUMERIC_MIN_VALUE 0 +-NUMERIC_MAX_VALUE 18446744073709551615 ++NUMERIC_MAX_VALUE 4294967295 + NUMERIC_BLOCK_SIZE 0 + ENUM_VALUE_LIST NULL + READ_ONLY NO +@@ -2029,7 +2029,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 0 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling. + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 1000 +@@ -2041,7 +2041,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 10000 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 1000000 +@@ -2101,7 +2101,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 128 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Number of undo logs to use. + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 128 +@@ -2125,7 +2125,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 0 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Number of undo tablespaces to use. + NUMERIC_MIN_VALUE 0 + NUMERIC_MAX_VALUE 127 +@@ -2149,7 +2149,7 @@ + SESSION_VALUE NULL + DEFAULT_VALUE 4 + VARIABLE_SCOPE GLOBAL +-VARIABLE_TYPE BIGINT UNSIGNED ++VARIABLE_TYPE INT UNSIGNED + VARIABLE_COMMENT Number of background write I/O threads in InnoDB. + NUMERIC_MIN_VALUE 1 + NUMERIC_MAX_VALUE 64 From 1e778a3b5624f97fdf44a15fd6cee3d615891cff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 29 Oct 2020 08:02:33 +0200 Subject: [PATCH 274/323] MDEV-21201 fixup: GCC 10.2.0 -Wparentheses An assertion inadvertently contained an assignment and an implicit comparison to zero. The intention was to test equality. --- sql/sql_show.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 6bd8c9b5c27..20e34269752 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -8688,7 +8688,8 @@ static int optimize_schema_tables_memory_usage(TABLE_LIST *table_list) { Field *field= table->field[i]; DBUG_ASSERT(field->vcol_info == 0); - DBUG_ASSERT(from_recinfo->length= field->pack_length_in_rec()); + DBUG_ASSERT(from_recinfo->length); + DBUG_ASSERT(from_recinfo->length == field->pack_length_in_rec()); if (bitmap_is_set(table->read_set, i)) { field->move_field(cur); From e33d452b4d60ec650bb5963b1b6775d0956ebcf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 29 Oct 2020 08:16:44 +0200 Subject: [PATCH 275/323] Fix bogus -Wmaybe-uninitialized in GCC 10.2.0 -Og If and only if read_variable_length() returns true, the variable blob_length will be uninitialized and not used. For some reason, GCC 10.2.0 -Og debug builds would issue a warning. --- plugin/type_mysql_json/mysql_json.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/type_mysql_json/mysql_json.cc b/plugin/type_mysql_json/mysql_json.cc index 0c939cfb81c..4a75cae3909 100644 --- a/plugin/type_mysql_json/mysql_json.cc +++ b/plugin/type_mysql_json/mysql_json.cc @@ -285,7 +285,7 @@ static bool parse_mysql_scalar(String *buffer, size_t value_json_type, const uchar type_value= *data; const enum_field_types field_type= static_cast(type_value); - size_t blob_length, length_bytes; + size_t UNINIT_VAR(blob_length), length_bytes; const uchar *blob_start; if (read_variable_length(data + 1, len, &blob_length, &length_bytes) || From 9e3e4c0e04509ebdac9017c334927fe7e2fbda5e Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 28 Oct 2020 20:54:29 +0100 Subject: [PATCH 276/323] new CC --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index 0cdc1656a70..8e5be108991 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit 0cdc1656a70c52103b4329debf9ed02ccacfb3c2 +Subproject commit 8e5be108991ffc29887660fd6540ed0fd3428d1b From 6cb88685c46e74e7b4644b0bc64d283c969468fe Mon Sep 17 00:00:00 2001 From: Vlad Lesin Date: Tue, 27 Oct 2020 20:03:41 +0300 Subject: [PATCH 277/323] MDEV-24026: InnoDB: Failing assertion: os_total_large_mem_allocated >= size upon incremental backup mariabackup deallocated uninitialized write_filt_ctxt.u.wf_incremental_ctxt in xtrabackup_copy_datafile() when some table should be skipped due to parsed DDL redo log record. --- extra/mariabackup/backup_copy.cc | 2 +- extra/mariabackup/backup_copy.h | 4 ++++ extra/mariabackup/xtrabackup.cc | 11 ++++++++++- .../mariabackup/incremental_ddl_during_backup.result | 1 + .../mariabackup/incremental_ddl_during_backup.test | 6 +++++- 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index 1cde4a4cf13..0ba220364e2 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -1448,7 +1448,7 @@ out: void backup_fix_ddl(void); -static lsn_t get_current_lsn(MYSQL *connection) +lsn_t get_current_lsn(MYSQL *connection) { static const char lsn_prefix[] = "\nLog sequence number "; lsn_t lsn = 0; diff --git a/extra/mariabackup/backup_copy.h b/extra/mariabackup/backup_copy.h index fbc09eaded3..7c886719f37 100644 --- a/extra/mariabackup/backup_copy.h +++ b/extra/mariabackup/backup_copy.h @@ -3,6 +3,7 @@ #define XTRABACKUP_BACKUP_COPY_H #include +#include #include "datasink.h" /* special files */ @@ -48,4 +49,7 @@ is_path_separator(char); bool directory_exists(const char *dir, bool create); +lsn_t +get_current_lsn(MYSQL *connection); + #endif diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 668a355f0fa..364d1242b29 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -2578,6 +2578,8 @@ static my_bool xtrabackup_copy_datafile(fil_node_t *node, uint thread_n, return(FALSE); } + memset(&write_filt_ctxt, 0, sizeof(xb_write_filt_ctxt_t)); + bool was_dropped; pthread_mutex_lock(&backup_mutex); was_dropped = (ddl_tracker.drops.find(node->space->id) != ddl_tracker.drops.end()); @@ -2605,7 +2607,6 @@ static my_bool xtrabackup_copy_datafile(fil_node_t *node, uint thread_n, sizeof dst_name - 1); dst_name[sizeof dst_name - 1] = '\0'; - memset(&write_filt_ctxt, 0, sizeof(xb_write_filt_ctxt_t)); ut_a(write_filter.process != NULL); if (write_filter.init != NULL && @@ -2947,8 +2948,14 @@ static void dbug_mariabackup_event(const char *event,const char *key) } #define DBUG_MARIABACKUP_EVENT(A, B) DBUG_EXECUTE_IF("mariabackup_events", dbug_mariabackup_event(A,B);); +#define DBUG_MB_INJECT_CODE(EVENT, KEY, CODE) \ + DBUG_EXECUTE_IF("mariabackup_inject_code", {\ + char *env = getenv(EVENT); \ + if (env && !strcmp(env, KEY)) { CODE } \ + }) #else #define DBUG_MARIABACKUP_EVENT(A,B) +#define DBUG_MB_INJECT_CODE(EVENT, KEY, CODE) #endif /************************************************************************** @@ -2973,6 +2980,8 @@ data_copy_thread_func( while ((node = datafiles_iter_next(ctxt->it)) != NULL) { DBUG_MARIABACKUP_EVENT("before_copy", node->space->name); + DBUG_MB_INJECT_CODE("wait_innodb_redo_before_copy", node->space->name, + backup_wait_for_lsn(get_current_lsn(mysql_connection));); /* copy the datafile */ if (xtrabackup_copy_datafile(node, num, NULL, xtrabackup_incremental ? wf_incremental : wf_write_through)) diff --git a/mysql-test/suite/mariabackup/incremental_ddl_during_backup.result b/mysql-test/suite/mariabackup/incremental_ddl_during_backup.result index ffca1ef0e1f..e9746083178 100644 --- a/mysql-test/suite/mariabackup/incremental_ddl_during_backup.result +++ b/mysql-test/suite/mariabackup/incremental_ddl_during_backup.result @@ -2,6 +2,7 @@ call mtr.add_suppression("InnoDB: New log files created"); CREATE TABLE t1(i INT PRIMARY KEY) ENGINE INNODB; CREATE TABLE t2(i INT PRIMARY KEY) ENGINE INNODB; CREATE TABLE t3(i INT) ENGINE INNODB; +CREATE TABLE t10(i INT PRIMARY KEY) ENGINE INNODB; # Create full backup , modify table, then create incremental/differential backup INSERT into t1 values(1); # Prepare full backup, apply incremental one diff --git a/mysql-test/suite/mariabackup/incremental_ddl_during_backup.test b/mysql-test/suite/mariabackup/incremental_ddl_during_backup.test index 60780b13920..49e952eefea 100644 --- a/mysql-test/suite/mariabackup/incremental_ddl_during_backup.test +++ b/mysql-test/suite/mariabackup/incremental_ddl_during_backup.test @@ -8,6 +8,7 @@ let $incremental_dir=$MYSQLTEST_VARDIR/tmp/backup_inc1; CREATE TABLE t1(i INT PRIMARY KEY) ENGINE INNODB; CREATE TABLE t2(i INT PRIMARY KEY) ENGINE INNODB; CREATE TABLE t3(i INT) ENGINE INNODB; +CREATE TABLE t10(i INT PRIMARY KEY) ENGINE INNODB; echo # Create full backup , modify table, then create incremental/differential backup; --disable_result_log @@ -20,8 +21,11 @@ INSERT into t1 values(1); --let after_copy_test_t1=RENAME TABLE test.t1 TO test.t1_renamed --let after_copy_test_t2=DROP TABLE test.t2 --let after_copy_test_t3=CREATE INDEX a_i ON test.t3(i); +--let before_copy_test_t10=DROP TABLE test.t10 +--let wait_innodb_redo_before_copy=test/t10 -exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$incremental_dir --incremental-basedir=$basedir --dbug=+d,mariabackup_events; +# mariabackup should crash with assertion if MDEV-24026 is not fixed +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$incremental_dir --incremental-basedir=$basedir --dbug=+d,mariabackup_events,mariabackup_inject_code; --let after_load_tablespaces= --disable_result_log echo # Prepare full backup, apply incremental one; From 4b854d47957173317294ed129690e11defdc8a8d Mon Sep 17 00:00:00 2001 From: Lawrin Novitsky Date: Tue, 27 Oct 2020 22:26:41 +0100 Subject: [PATCH 278/323] MDEV-19838 Wrong direxec param data caused crash In case of direct execution(stmtid=-1, mariadb_stmt_execute_direct in C API) application is in control of how many parameters client sends to the server. In case this number is not equal to actual query parameters number, the server may start to interprete packet data incorrectly, e.g. starting from the size of null bitmap. And that could cause it to crash at some point. The commit introduces some additional COM_STMT_EXECUTE packet sanity checks: - checking that "types sent" byte is set, and the value is equal to 1. if it's not direct execution, then that value is 0 or 1. - checking that parameter type value is a valid type, and parameter flags value is 0 or only "unsigned" bit is set - added more checks that read does not go beyond the end of the packet --- sql/sql_prepare.cc | 199 +++++++++++++++++++++++++++++++++++--- tests/mysql_client_test.c | 149 ++++++++++++++++++++++++++++ 2 files changed, 336 insertions(+), 12 deletions(-) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 1efb9d713bc..0df2617bb9a 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -123,6 +123,9 @@ When one supplies long data for a placeholder: #include "transaction.h" // trans_rollback_implicit #include "wsrep_mysqld.h" +/* Constants defining bits in parameter type flags. Flags are read from high byte of short value */ +static const uint PARAMETER_FLAG_UNSIGNED = 128U << 8; + /** A result class used to send cursor rows using the binary protocol. */ @@ -1003,11 +1006,73 @@ static bool insert_bulk_params(Prepared_statement *stmt, DBUG_RETURN(0); } -static bool set_conversion_functions(Prepared_statement *stmt, - uchar **data, uchar *data_end) + +/** + Checking if parameter type and flags are valid + + @param typecode ushort value with type in low byte, and flags in high byte + + @retval true this parameter is wrong + @retval false this parameter is OK +*/ + +static bool +parameter_type_sanity_check(ushort typecode) +{ + /* Checking if type in lower byte is valid */ + switch (typecode & 0xff) { + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_NULL: + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_GEOMETRY: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_NEWDATE: + break; + /* + This types normally cannot be sent by client, so maybe it'd be + better to treat them like an error here. + */ + case MYSQL_TYPE_TIMESTAMP2: + case MYSQL_TYPE_TIME2: + case MYSQL_TYPE_DATETIME2: + default: + return true; + }; + + // In Flags in high byte only unsigned bit may be set + if (typecode & ((~PARAMETER_FLAG_UNSIGNED) & 0x0000ff00)) + { + return true; + } + return false; +} + +static bool +set_conversion_functions(Prepared_statement *stmt, uchar **data) { uchar *read_pos= *data; - const uint signed_bit= 1 << 15; + DBUG_ENTER("set_conversion_functions"); /* First execute or types altered by the client, setup the @@ -1020,12 +1085,17 @@ static bool set_conversion_functions(Prepared_statement *stmt, { ushort typecode; - if (read_pos >= data_end) - DBUG_RETURN(1); - + /* + stmt_execute_packet_sanity_check has already verified, that there + are enough data in the packet for data types + */ typecode= sint2korr(read_pos); read_pos+= 2; - (**it).unsigned_flag= MY_TEST(typecode & signed_bit); + if (parameter_type_sanity_check(typecode)) + { + DBUG_RETURN(1); + } + (**it).unsigned_flag= MY_TEST(typecode & PARAMETER_FLAG_UNSIGNED); setup_one_conversion_function(thd, *it, (uchar) (typecode & 0xff)); (*it)->sync_clones(); } @@ -1035,7 +1105,7 @@ static bool set_conversion_functions(Prepared_statement *stmt, static bool setup_conversion_functions(Prepared_statement *stmt, - uchar **data, uchar *data_end, + uchar **data, bool bulk_protocol= 0) { /* skip null bits */ @@ -1048,7 +1118,7 @@ static bool setup_conversion_functions(Prepared_statement *stmt, if (*read_pos++) //types supplied / first execute { *data= read_pos; - bool res= set_conversion_functions(stmt, data, data_end); + bool res= set_conversion_functions(stmt, data); DBUG_RETURN(res); } *data= read_pos; @@ -3159,11 +3229,20 @@ static void mysql_stmt_execute_common(THD *thd, void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length) { + const uint packet_min_lenght= 9; uchar *packet= (uchar*)packet_arg; // GCC 4.0.1 workaround + + DBUG_ENTER("mysqld_stmt_execute"); + + if (packet_length < packet_min_lenght) + { + my_error(ER_MALFORMED_PACKET, MYF(0), 0, + "", "mysqld_stmt_execute"); + DBUG_VOID_RETURN; + } ulong stmt_id= uint4korr(packet); ulong flags= (ulong) packet[4]; uchar *packet_end= packet + packet_length; - DBUG_ENTER("mysqld_stmt_execute"); packet+= 9; /* stmt_id + 5 bytes of flags */ @@ -3219,6 +3298,84 @@ void mysqld_stmt_bulk_execute(THD *thd, char *packet_arg, uint packet_length) DBUG_VOID_RETURN; } +/** + Additional packet checks for direct execution + + @param thd THD handle + @param stmt prepared statement being directly executed + @param paket packet with parameters to bind + @param packet_end pointer to the byte after parameters end + @param bulk_op is it bulk operation + @param direct_exec is it direct execution + @param read_bytes need to read types (only with bulk_op) + + @retval true this parameter is wrong + @retval false this parameter is OK +*/ + +static bool +stmt_execute_packet_sanity_check(Prepared_statement *stmt, + uchar *packet, uchar *packet_end, + bool bulk_op, bool direct_exec, + bool read_types) +{ + + DBUG_ASSERT((!read_types) || (read_types && bulk_op)); + if (stmt->param_count > 0) + { + uint packet_length= static_cast(packet_end - packet); + uint null_bitmap_bytes= (bulk_op ? 0 : (stmt->param_count + 7)/8); + uint min_len_for_param_count = null_bitmap_bytes + + (bulk_op ? 0 : 1); /* sent types byte */ + + if (!bulk_op && packet_length >= min_len_for_param_count) + { + if ((read_types= packet[null_bitmap_bytes])) + { + /* + Should be 0 or 1. If the byte is not 1, that could mean, + e.g. that we read incorrect byte due to incorrect number + of sent parameters for direct execution (i.e. null bitmap + is shorter or longer, than it should be) + */ + if (packet[null_bitmap_bytes] != '\1') + { + return true; + } + } + } + + if (read_types) + { + /* 2 bytes per parameter of the type and flags */ + min_len_for_param_count+= 2*stmt->param_count; + } + else + { + /* + If types are not sent, there is nothing to do here. + But for direct execution types should always be sent + */ + return direct_exec; + } + + /* + If true, the packet is guaranteed too short for the number of + parameters in the PS + */ + return (packet_length < min_len_for_param_count); + } + else + { + /* + If there is no parameters, this should be normally already end + of the packet. If it's not - then error + */ + return (packet_end > packet); + } + return false; +} + /** Common part of prepared statement execution @@ -3258,6 +3415,24 @@ static void mysql_stmt_execute_common(THD *thd, llstr(stmt_id, llbuf), "mysqld_stmt_execute"); DBUG_VOID_RETURN; } + + /* + In case of direct execution application decides how many parameters + to send. + + Thus extra checks are required to prevent crashes caused by incorrect + interpretation of the packet data. Plus there can be always a broken + evil client. + */ + if (stmt_execute_packet_sanity_check(stmt, packet, packet_end, bulk_op, + stmt_id == LAST_STMT_ID, read_types)) + { + char llbuf[22]; + my_error(ER_MALFORMED_PACKET, MYF(0), static_cast(sizeof(llbuf)), + llstr(stmt_id, llbuf), "mysqld_stmt_execute"); + DBUG_VOID_RETURN; + } + stmt->read_types= read_types; #if defined(ENABLED_PROFILING) @@ -4168,7 +4343,7 @@ Prepared_statement::set_parameters(String *expanded_query, { #ifndef EMBEDDED_LIBRARY uchar *null_array= packet; - res= (setup_conversion_functions(this, &packet, packet_end) || + res= (setup_conversion_functions(this, &packet) || set_params(this, null_array, packet, packet_end, expanded_query)); #else /* @@ -4400,7 +4575,7 @@ Prepared_statement::execute_bulk_loop(String *expanded_query, #ifndef EMBEDDED_LIBRARY if (read_types && - set_conversion_functions(this, &packet, packet_end)) + set_conversion_functions(this, &packet)) #else // bulk parameters are not supported for embedded, so it will an error #endif diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 9a90862e93f..058168eedd5 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -19897,6 +19897,152 @@ static void test_ps_params_in_ctes() } +#ifndef EMBEDDED_LIBRARY +#define MDEV19838_MAX_PARAM_COUNT 32 +#define MDEV19838_FIELDS_COUNT 17 +static void test_mdev19838() +{ + int rc; + MYSQL_BIND bind[MDEV19838_MAX_PARAM_COUNT]; + unsigned int i, paramCount = 1; + char charvalue[] = "012345678901234567890123456789012345"; + MYSQL_STMT *stmt; + + myheader("test_mdev19838"); + + rc = mysql_query(mysql, "CREATE TABLE mdev19838(" + "f1 char(36)," + "f2 char(36)," + "f3 char(36)," + "f4 char(36)," + "f5 char(36)," + "f6 char(36)," + "f7 char(36)," + "f8 char(36)," + "f9 char(36)," + "f10 char(36)," + "f11 char(36)," + "f12 char(36)," + "f13 char(36)," + "f14 char(36)," + "f15 char(36)," + "f16 char(36)," + "f17 char(36)" + ")"); + myquery(rc); + + stmt = mysql_stmt_init(mysql); + check_stmt(stmt); + + memset(bind, 0, sizeof(bind)); + + for (i = 0; i < MDEV19838_MAX_PARAM_COUNT; ++i) + { + bind[i].buffer = charvalue; + bind[i].buffer_type = MYSQL_TYPE_STRING; + bind[i].buffer_length = strlen(charvalue) + 1; + bind[i].length = &bind[i].length_value; + bind[i].length_value = bind[i].buffer_length - 1; + } + + for (paramCount = 1; paramCount < MDEV19838_FIELDS_COUNT; ++paramCount) + { + mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mCount); + + rc = mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838" + "(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17)" + " VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", -1); + + /* Expecting an error */ + DIE_UNLESS(rc != 0); + + mysql_stmt_close(stmt); + stmt = mysql_stmt_init(mysql); + check_stmt(stmt); + } + + paramCount = 0; + mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mCount); + rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838(f1)" + " VALUES (?)", -1); + /* Expecting an error */ + DIE_UNLESS(rc != 0); + mysql_stmt_close(stmt); + + stmt = mysql_stmt_init(mysql); + check_stmt(stmt); + /* Correct number of parameters */ + paramCount = MDEV19838_FIELDS_COUNT; + mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mCount); + mysql_stmt_bind_param(stmt, bind); + + rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838" + "(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17)" + " VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", -1); + check_execute(stmt, rc); + + /* MYSQL_TYPE_TINY = 1. This parameter byte can be read as "parameters send" flag byte. + Checking that wrong packet is still detected */ + bind[0].buffer_type = MYSQL_TYPE_TINY; + bind[0].length_value = 1; + bind[0].buffer_length = 1; + + for (paramCount = 8; paramCount > 0; --paramCount) + { + mysql_stmt_close(stmt); + stmt = mysql_stmt_init(mysql); + check_stmt(stmt); + + mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mCount); + + rc = mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838" + "(f1, f2, f3, f4, f5, f6, f7, f8, f9)" + " VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?, ?)", -1); + + /* Expecting an error */ + DIE_UNLESS(rc != 0); + } + + /* Test of query w/out parameters, with parameter sent and not sent */ + for (paramCount = MDEV19838_MAX_PARAM_COUNT; paramCount != (unsigned int)-1; --paramCount) + { + mysql_stmt_close(stmt); + stmt = mysql_stmt_init(mysql); + check_stmt(stmt); + + mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mCount); + + if (paramCount > 0) + { + rc = mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + } + + rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838" + "(f1)" + " VALUES " + "(0x1111111111111111)", -1); + + /* Expecting an error if parameters are sent */ + DIE_UNLESS(rc != 0 || paramCount == 0); + } + + mysql_stmt_close(stmt); + + rc = mysql_query(mysql, "drop table mdev19838"); + myquery(rc); +} +#endif // EMBEDDED_LIBRARY + static struct my_tests_st my_tests[]= { { "disable_query_logs", disable_query_logs }, { "test_view_sp_list_fields", test_view_sp_list_fields }, @@ -20182,6 +20328,9 @@ static struct my_tests_st my_tests[]= { { "test_bulk_replace", test_bulk_replace }, #endif { "test_ps_params_in_ctes", test_ps_params_in_ctes }, +#ifndef EMBEDDED_LIBRARY + { "test_mdev19838", test_mdev19838 }, +#endif { 0, 0 } }; From 7f04686a2a50be00e25f2073266dd341664155f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 29 Oct 2020 09:15:35 +0200 Subject: [PATCH 279/323] MDEV-24049 InnoDB: Failing assertion: node->is_open() in fil_space_t::flush_low As part of MDEV-23855, we eliminated fil_system.LRU and changed the way how InnoDB data files are opened. We are also enforcing the innodb_open_files limit when new data files are created. The function fil_space_t::flush() would be invoked by row_quiesce_table_start(). If the table was already in clean state, it is possible that the data file is not open. fil_space_t::flush_low(): If the data file is not open, check with a debug assertion that there are no unflushed changes, and carry on. Reviewed by: Eugene Kosov and Thirunarayanan Balathandayuthapani --- mysql-test/suite/innodb/r/flush.result | 16 ++++++++++++++++ mysql-test/suite/innodb/t/flush.opt | 1 + mysql-test/suite/innodb/t/flush.test | 19 +++++++++++++++++++ storage/innobase/fil/fil0fil.cc | 6 +++++- 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/innodb/r/flush.result create mode 100644 mysql-test/suite/innodb/t/flush.opt create mode 100644 mysql-test/suite/innodb/t/flush.test diff --git a/mysql-test/suite/innodb/r/flush.result b/mysql-test/suite/innodb/r/flush.result new file mode 100644 index 00000000000..cd6bec48d4e --- /dev/null +++ b/mysql-test/suite/innodb/r/flush.result @@ -0,0 +1,16 @@ +SELECT @@GLOBAL.innodb_open_files; +@@GLOBAL.innodb_open_files +10 +CREATE TABLE t0 (a INT) ENGINE=InnoDB; +FLUSH TABLE t0 WITH READ LOCK; +UNLOCK TABLES; +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +CREATE TABLE t2 (a INT) ENGINE=InnoDB; +CREATE TABLE t3 (a INT) ENGINE=InnoDB; +CREATE TABLE t4 (a INT) ENGINE=InnoDB; +CREATE TABLE t5 (a INT) ENGINE=InnoDB; +CREATE TABLE t6 (a INT) ENGINE=InnoDB; +CREATE TABLE t7 (a INT) ENGINE=InnoDB; +FLUSH TABLE t0 WITH READ LOCK; +UNLOCK TABLES; +DROP TABLE t0, t1, t2, t3, t4, t5, t6, t7; diff --git a/mysql-test/suite/innodb/t/flush.opt b/mysql-test/suite/innodb/t/flush.opt new file mode 100644 index 00000000000..99dbd8f47c3 --- /dev/null +++ b/mysql-test/suite/innodb/t/flush.opt @@ -0,0 +1 @@ +--innodb-open-files=10 diff --git a/mysql-test/suite/innodb/t/flush.test b/mysql-test/suite/innodb/t/flush.test new file mode 100644 index 00000000000..e03728825cf --- /dev/null +++ b/mysql-test/suite/innodb/t/flush.test @@ -0,0 +1,19 @@ +--source include/have_innodb.inc + +SELECT @@GLOBAL.innodb_open_files; + +CREATE TABLE t0 (a INT) ENGINE=InnoDB; +# Ensure that the created table t0 is clean. +FLUSH TABLE t0 WITH READ LOCK; +UNLOCK TABLES; +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +CREATE TABLE t2 (a INT) ENGINE=InnoDB; +CREATE TABLE t3 (a INT) ENGINE=InnoDB; +CREATE TABLE t4 (a INT) ENGINE=InnoDB; +CREATE TABLE t5 (a INT) ENGINE=InnoDB; +CREATE TABLE t6 (a INT) ENGINE=InnoDB; +CREATE TABLE t7 (a INT) ENGINE=InnoDB; +# Now, the data file for t0 should not be open anymore. +FLUSH TABLE t0 WITH READ LOCK; +UNLOCK TABLES; +DROP TABLE t0, t1, t2, t3, t4, t5, t6, t7; diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index d234fed4e89..c515cd82c48 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -514,7 +514,11 @@ inline void fil_space_t::flush_low() for (fil_node_t *node= UT_LIST_GET_FIRST(chain); node; node= UT_LIST_GET_NEXT(chain, node)) { - ut_a(node->is_open()); + if (!node->is_open()) + { + ut_ad(!is_in_unflushed_spaces); + continue; + } IF_WIN(if (node->is_raw_disk) continue,); os_file_flush(node->handle); } From eae10a87ff60d1b419f103533d739caa8c5e467c Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Thu, 29 Oct 2020 08:29:03 +0100 Subject: [PATCH 280/323] Move result files at the correct place. --- mysql-test/{t => r}/aria_icp_debug.result | 0 mysql-test/{t => r}/innodb_icp_debug.result | 0 mysql-test/{t => r}/myisam_icp_debug.result | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename mysql-test/{t => r}/aria_icp_debug.result (100%) rename mysql-test/{t => r}/innodb_icp_debug.result (100%) rename mysql-test/{t => r}/myisam_icp_debug.result (100%) diff --git a/mysql-test/t/aria_icp_debug.result b/mysql-test/r/aria_icp_debug.result similarity index 100% rename from mysql-test/t/aria_icp_debug.result rename to mysql-test/r/aria_icp_debug.result diff --git a/mysql-test/t/innodb_icp_debug.result b/mysql-test/r/innodb_icp_debug.result similarity index 100% rename from mysql-test/t/innodb_icp_debug.result rename to mysql-test/r/innodb_icp_debug.result diff --git a/mysql-test/t/myisam_icp_debug.result b/mysql-test/r/myisam_icp_debug.result similarity index 100% rename from mysql-test/t/myisam_icp_debug.result rename to mysql-test/r/myisam_icp_debug.result From 313cf9de2c9036e5acd5fef3be6afebbad471998 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 29 Oct 2020 01:42:07 +0100 Subject: [PATCH 281/323] update result files after backport followup for 3e807d255e0e and eae10a87ff60 --- mysql-test/r/aria_icp_debug.result | 4 ---- mysql-test/r/innodb_icp_debug.result | 4 ---- mysql-test/r/myisam_icp_debug.result | 4 ---- 3 files changed, 12 deletions(-) diff --git a/mysql-test/r/aria_icp_debug.result b/mysql-test/r/aria_icp_debug.result index fc01ee4fb3b..26881d5a4cc 100644 --- a/mysql-test/r/aria_icp_debug.result +++ b/mysql-test/r/aria_icp_debug.result @@ -21,14 +21,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range kp1 kp1 5 NULL 10 Using index condition set debug_sync='handler_index_cond_check SIGNAL at_icp_check WAIT_FOR go'; select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; -connect con1, localhost, root,,; -connection con1; set debug_sync='now WAIT_FOR at_icp_check'; kill query $target_id; set debug_sync='now SIGNAL go'; -connection default; ERROR 70100: Query execution was interrupted set debug_sync='RESET'; -disconnect con1; drop table t0,t1,t2; set default_storage_engine=default; diff --git a/mysql-test/r/innodb_icp_debug.result b/mysql-test/r/innodb_icp_debug.result index 5a169650c8e..f9f5dcc794c 100644 --- a/mysql-test/r/innodb_icp_debug.result +++ b/mysql-test/r/innodb_icp_debug.result @@ -21,14 +21,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range kp1 kp1 5 NULL 11 Using index condition set debug_sync='handler_index_cond_check SIGNAL at_icp_check WAIT_FOR go'; select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; -connect con1, localhost, root,,; -connection con1; set debug_sync='now WAIT_FOR at_icp_check'; kill query $target_id; set debug_sync='now SIGNAL go'; -connection default; ERROR 70100: Query execution was interrupted set debug_sync='RESET'; -disconnect con1; drop table t0,t1,t2; set default_storage_engine=default; diff --git a/mysql-test/r/myisam_icp_debug.result b/mysql-test/r/myisam_icp_debug.result index cb45a0e2274..8c5caef7874 100644 --- a/mysql-test/r/myisam_icp_debug.result +++ b/mysql-test/r/myisam_icp_debug.result @@ -20,13 +20,9 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range kp1 kp1 5 NULL 11 Using index condition set debug_sync='handler_index_cond_check SIGNAL at_icp_check WAIT_FOR go'; select * from t2 where kp1 between 10 and 20 and kp2 +1 >100; -connect con1, localhost, root,,; -connection con1; set debug_sync='now WAIT_FOR at_icp_check'; kill query $target_id; set debug_sync='now SIGNAL go'; -connection default; ERROR 70100: Query execution was interrupted set debug_sync='RESET'; -disconnect con1; drop table t0,t1,t2; From d6302c9a47615019a3bca5304d3f61c587d826b8 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 28 Oct 2020 20:44:03 +0100 Subject: [PATCH 282/323] MDEV-23702 calculating(auto rounding) issue Implement a different fix for "MDEV-19232: Floating point precision / value comparison problem" Instead of truncating decimal values after every division, truncate them for comparison purposes. This reverts commit 62d73df6b270 but keeps the test. --- mysql-test/r/func_group.result | 4 ++-- mysql-test/r/parser_precedence.result | 2 +- mysql-test/r/subselect4.result | 2 +- mysql-test/r/type_newdecimal.result | 7 +++++-- mysql-test/r/type_ranges.result | 6 ++++-- .../r/div_precision_increment_func.result | 16 ++++++++-------- mysql-test/suite/vcol/r/not_supported.result | 2 +- sql/item_cmpfunc.cc | 6 +++++- sql/item_func.cc | 2 -- sql/my_decimal.h | 11 +++++++++++ .../mysql-test/tokudb/r/type_newdecimal.result | 7 +++++-- .../mysql-test/tokudb/r/type_ranges.result | 6 ++++-- 12 files changed, 47 insertions(+), 24 deletions(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index d0d413331df..06323f5b3bb 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1186,13 +1186,13 @@ i count(*) std(e1/e2) 3 4 0.00000000 select std(s1/s2) from bug22555; std(s1/s2) -0.21328517 +0.21325764 select std(o1/o2) from bug22555; std(o1/o2) 0.2132576358664934 select std(e1/e2) from bug22555; std(e1/e2) -0.21328517 +0.21325764 set @saved_div_precision_increment=@@div_precision_increment; set div_precision_increment=19; select i, count(*), std(s1/s2) from bug22555 group by i order by i; diff --git a/mysql-test/r/parser_precedence.result b/mysql-test/r/parser_precedence.result index f23295bd61b..4330c8a2045 100644 --- a/mysql-test/r/parser_precedence.result +++ b/mysql-test/r/parser_precedence.result @@ -619,7 +619,7 @@ select 4 - 3 * 2, (4 - 3) * 2, 4 - (3 * 2); Testing that / is left associative select 15 / 5 / 3, (15 / 5) / 3, 15 / (5 / 3); 15 / 5 / 3 (15 / 5) / 3 15 / (5 / 3) -1.00000000 1.00000000 8.9998 +1.00000000 1.00000000 9.0000 Testing that / has precedence over | select 105 / 5 | 2, (105 / 5) | 2, 105 / (5 | 2); 105 / 5 | 2 (105 / 5) | 2 105 / (5 | 2) diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index e7655131fcf..b7161151928 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -2596,7 +2596,7 @@ SELECT population, area, population/area, cast(population/area as DECIMAL(20,9)) FROM t1 LIMIT 1; population area population/area cast(population/area as DECIMAL(20,9)) -11797 91 129.6374 129.637400000 +11797 91 129.6374 129.637362637 SELECT * FROM t1 A WHERE population/area = (SELECT MAX(population/area) from t1 B where A.region = B.region); region area population diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index 0c8f4f55442..6c9f3467b97 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -1530,8 +1530,11 @@ select (1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 * 1.01500000 * 1.01500000 * 0.99500000) 0.812988073953673124592306939480 create table t1 as select 5.05 / 0.014; +Warnings: +Note 1265 Data truncated for column '5.05 / 0.014' at row 1 show warnings; Level Code Message +Note 1265 Data truncated for column '5.05 / 0.014' at row 1 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -1646,6 +1649,8 @@ my_col 0.123456789123456789123456789123 DROP TABLE t1; CREATE TABLE t1 SELECT 1 / .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col; +Warnings: +Note 1265 Data truncated for column 'my_col' at row 1 DESCRIBE t1; Field Type Null Key Default Extra my_col decimal(65,4) YES NULL @@ -1831,8 +1836,6 @@ DROP TABLE t1; CREATE TABLE t1 (a DECIMAL(30,30)); INSERT INTO t1 VALUES (0.1),(0.2),(0.3); CREATE TABLE t2 SELECT MIN(a + 0.0000000000000000000000000000001) AS c1 FROM t1; -Warnings: -Note 1265 Data truncated for column 'c1' at row 4 DESC t2; Field Type Null Key Default Extra c1 decimal(33,30) YES NULL diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result index a10d2a56eae..101bf0cfb2c 100644 --- a/mysql-test/r/type_ranges.result +++ b/mysql-test/r/type_ranges.result @@ -94,6 +94,8 @@ DROP INDEX test ON t1; insert into t1 values (10, 1,1,1,1,1,1,1,1,1,1,1,1,1,NULL,0,0,0,1,1,1,1,'one','one'); insert into t1 values (NULL,2,2,2,2,2,2,2,2,2,2,2,2,2,NULL,NULL,NULL,NULL,NULL,NULL,2,2,'two','two,one'); insert into t1 values (0,1/3,3,3,3,3,3,3,3,3,3,3,3,3,NULL,'19970303','10:10:10','19970303101010','','','','3',3,3); +Warnings: +Warning 1265 Data truncated for column 'string' at row 1 insert into t1 values (0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,NULL,19970807,080706,19970403090807,-1,-1,-1,'-1',-1,-1); Warnings: Warning 1264 Out of range value for column 'utiny' at row 1 @@ -134,7 +136,7 @@ select auto,string,tiny,short,medium,long_int,longlong,real_float,real_double,ut auto string tiny short medium long_int longlong real_float real_double utiny ushort umedium ulong ulonglong mod(floor(time_stamp/1000000),1000000)-mod(curdate(),1000000) date_field time_field date_time blob_col tinyblob_col mediumblob_col longblob_col 10 1 1 1 1 1 1 1.0 1.0000 1 00001 1 1 1 0 0000-00-00 00:00:00 0000-00-00 00:00:00 1 1 1 1 11 2 2 2 2 2 2 2.0 2.0000 2 00002 2 2 2 0 NULL NULL NULL NULL NULL 2 2 -12 0.3333 3 3 3 3 3 3.0 3.0000 3 00003 3 3 3 0 1997-03-03 10:10:10 1997-03-03 10:10:10 3 +12 0.33333333 3 3 3 3 3 3.0 3.0000 3 00003 3 3 3 0 1997-03-03 10:10:10 1997-03-03 10:10:10 3 13 -1 -1 -1 -1 -1 -1 -1.0 -1.0000 0 00000 0 0 0 0 1997-08-07 08:07:06 1997-04-03 09:08:07 -1 -1 -1 -1 14 -429496729 -128 -32768 -8388608 -2147483648 -4294967295 -4294967296.0 -4294967295.0000 0 00000 0 0 0 0 0000-00-00 00:00:00 0000-00-00 00:00:00 -4294967295 -4294967295 -4294967295 -4294967295 15 4294967295 127 32767 8388607 2147483647 4294967295 4294967296.0 4294967295.0000 255 65535 16777215 4294967295 4294967295 0 0000-00-00 00:00:00 0000-00-00 00:00:00 4294967295 4294967295 4294967295 4294967295 @@ -186,7 +188,7 @@ Warning 1265 Data truncated for column 'new_field' at row 7 select * from t2; auto string mediumblob_col new_field 1 2 2 ne -2 0.3333 ne +2 0.33333333 ne 3 -1 -1 ne 4 -429496729 -4294967295 ne 5 4294967295 4294967295 ne diff --git a/mysql-test/suite/sys_vars/r/div_precision_increment_func.result b/mysql-test/suite/sys_vars/r/div_precision_increment_func.result index ffe23eb3cef..ee8b7c5691d 100644 --- a/mysql-test/suite/sys_vars/r/div_precision_increment_func.result +++ b/mysql-test/suite/sys_vars/r/div_precision_increment_func.result @@ -50,9 +50,9 @@ INSERT into t1(name, salary, income_tax) values('Record_2', 501, 501*2.5/1000); INSERT into t1(name, salary, income_tax) values('Record_3', 210, 210*2.5/1000); SELECT * from t1; id name salary income_tax -1 Record_1 100011 250.03 -2 Record_2 501 1.25 -3 Record_3 210 0.53 +1 Record_1 100011 250.027 +2 Record_2 501 1.2525 +3 Record_3 210 0.525 ## Creating new connection ## ## Verifying session & global value of variable ## SELECT @@global.div_precision_increment = 2; @@ -67,11 +67,11 @@ INSERT into t1(name, salary, income_tax) values('Record_5', 501, 501*2.5/1000); INSERT into t1(name, salary, income_tax) values('Record_6', 210, 210*2.5/1000); SELECT * from t1; id name salary income_tax -1 Record_1 100011 250.03 -2 Record_2 501 1.25 -3 Record_3 210 0.53 -4 Record_4 100011 250.028 -5 Record_5 501 1.253 +1 Record_1 100011 250.027 +2 Record_2 501 1.2525 +3 Record_3 210 0.525 +4 Record_4 100011 250.027 +5 Record_5 501 1.2525 6 Record_6 210 0.525 ## Dropping table t1 ## drop table t1; diff --git a/mysql-test/suite/vcol/r/not_supported.result b/mysql-test/suite/vcol/r/not_supported.result index a3b73d3444f..06627fccf8b 100644 --- a/mysql-test/suite/vcol/r/not_supported.result +++ b/mysql-test/suite/vcol/r/not_supported.result @@ -51,7 +51,7 @@ a b v flush tables; select * from t1; a b v -1 2 0.3333000000000000000 +1 2 0.3333333330000000000 select * from t5; a b v 20141010 2 October diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 61c6b980551..7e99230723a 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -914,6 +914,8 @@ int Arg_comparator::compare_decimal() { if (set_null) owner->null_value= 0; + my_decimal_round_if_needed(E_DEC_FATAL_ERROR, val1, (*a)->decimals, 0); + my_decimal_round_if_needed(E_DEC_FATAL_ERROR, val2, (*b)->decimals, 0); return my_decimal_cmp(val1, val2); } } @@ -938,7 +940,9 @@ int Arg_comparator::compare_e_decimal() my_decimal *val2= (*b)->val_decimal(&decimal2); if ((*a)->null_value || (*b)->null_value) return MY_TEST((*a)->null_value && (*b)->null_value); - return MY_TEST(my_decimal_cmp(val1, val2) == 0); + my_decimal_round_if_needed(E_DEC_FATAL_ERROR, val1, (*a)->decimals, 0); + my_decimal_round_if_needed(E_DEC_FATAL_ERROR, val2, (*b)->decimals, 0); + return my_decimal_cmp(val1, val2) == 0; } diff --git a/sql/item_func.cc b/sql/item_func.cc index b4cffc84b80..034fb385f05 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1719,8 +1719,6 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value) null_value= 1; return 0; } - my_decimal_round(E_DEC_FATAL_ERROR, decimal_value, - decimals, FALSE, decimal_value); return decimal_value; } diff --git a/sql/my_decimal.h b/sql/my_decimal.h index f318bcd1cd3..6a73cd54d50 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -303,6 +303,17 @@ bool my_decimal_is_zero(const my_decimal *decimal_value) } +inline +int my_decimal_round_if_needed(uint mask, my_decimal *dec, int scale, + bool truncate) +{ + if (scale >= dec->frac) + return E_DEC_OK; + return check_result(mask, decimal_round(dec, dec, scale, + (truncate ? TRUNCATE : HALF_UP))); +} + + inline int my_decimal_round(uint mask, const my_decimal *from, int scale, bool truncate, my_decimal *to) diff --git a/storage/tokudb/mysql-test/tokudb/r/type_newdecimal.result b/storage/tokudb/mysql-test/tokudb/r/type_newdecimal.result index dd47b8a1a5c..1f173bbb796 100644 --- a/storage/tokudb/mysql-test/tokudb/r/type_newdecimal.result +++ b/storage/tokudb/mysql-test/tokudb/r/type_newdecimal.result @@ -1531,8 +1531,11 @@ select (1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 * 1.01500000 * 1.01500000 * 0.99500000) 0.812988073953673124592306939480 create table t1 as select 5.05 / 0.014; +Warnings: +Note 1265 Data truncated for column '5.05 / 0.014' at row 1 show warnings; Level Code Message +Note 1265 Data truncated for column '5.05 / 0.014' at row 1 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -1647,6 +1650,8 @@ my_col 0.123456789123456789123456789123 DROP TABLE t1; CREATE TABLE t1 SELECT 1 / .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col; +Warnings: +Note 1265 Data truncated for column 'my_col' at row 1 DESCRIBE t1; Field Type Null Key Default Extra my_col decimal(65,4) YES NULL @@ -1832,8 +1837,6 @@ DROP TABLE t1; CREATE TABLE t1 (a DECIMAL(30,30)); INSERT INTO t1 VALUES (0.1),(0.2),(0.3); CREATE TABLE t2 SELECT MIN(a + 0.0000000000000000000000000000001) AS c1 FROM t1; -Warnings: -Note 1265 Data truncated for column 'c1' at row 4 DESC t2; Field Type Null Key Default Extra c1 decimal(33,30) YES NULL diff --git a/storage/tokudb/mysql-test/tokudb/r/type_ranges.result b/storage/tokudb/mysql-test/tokudb/r/type_ranges.result index 395f21a8a8f..bd8491336b3 100644 --- a/storage/tokudb/mysql-test/tokudb/r/type_ranges.result +++ b/storage/tokudb/mysql-test/tokudb/r/type_ranges.result @@ -95,6 +95,8 @@ DROP INDEX test ON t1; insert into t1 values (10, 1,1,1,1,1,1,1,1,1,1,1,1,1,NULL,0,0,0,1,1,1,1,'one','one'); insert into t1 values (NULL,2,2,2,2,2,2,2,2,2,2,2,2,2,NULL,NULL,NULL,NULL,NULL,NULL,2,2,'two','two,one'); insert into t1 values (0,1/3,3,3,3,3,3,3,3,3,3,3,3,3,NULL,'19970303','10:10:10','19970303101010','','','','3',3,3); +Warnings: +Warning 1265 Data truncated for column 'string' at row 1 insert into t1 values (0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,NULL,19970807,080706,19970403090807,-1,-1,-1,'-1',-1,-1); Warnings: Warning 1264 Out of range value for column 'utiny' at row 1 @@ -135,7 +137,7 @@ select auto,string,tiny,short,medium,long_int,longlong,real_float,real_double,ut auto string tiny short medium long_int longlong real_float real_double utiny ushort umedium ulong ulonglong mod(floor(time_stamp/1000000),1000000)-mod(curdate(),1000000) date_field time_field date_time blob_col tinyblob_col mediumblob_col longblob_col 10 1 1 1 1 1 1 1.0 1.0000 1 00001 1 1 1 0 0000-00-00 00:00:00 0000-00-00 00:00:00 1 1 1 1 11 2 2 2 2 2 2 2.0 2.0000 2 00002 2 2 2 0 NULL NULL NULL NULL NULL 2 2 -12 0.3333 3 3 3 3 3 3.0 3.0000 3 00003 3 3 3 0 1997-03-03 10:10:10 1997-03-03 10:10:10 3 +12 0.33333333 3 3 3 3 3 3.0 3.0000 3 00003 3 3 3 0 1997-03-03 10:10:10 1997-03-03 10:10:10 3 13 -1 -1 -1 -1 -1 -1 -1.0 -1.0000 0 00000 0 0 0 0 1997-08-07 08:07:06 1997-04-03 09:08:07 -1 -1 -1 -1 14 -429496729 -128 -32768 -8388608 -2147483648 -4294967295 -4294967296.0 -4294967295.0000 0 00000 0 0 0 0 0000-00-00 00:00:00 0000-00-00 00:00:00 -4294967295 -4294967295 -4294967295 -4294967295 15 4294967295 127 32767 8388607 2147483647 4294967295 4294967296.0 4294967295.0000 255 65535 16777215 4294967295 4294967295 0 0000-00-00 00:00:00 0000-00-00 00:00:00 4294967295 4294967295 4294967295 4294967295 @@ -187,7 +189,7 @@ Warning 1265 Data truncated for column 'new_field' at row 7 select * from t2; auto string mediumblob_col new_field 1 2 2 ne -2 0.3333 ne +2 0.33333333 ne 3 -1 -1 ne 4 -429496729 -4294967295 ne 5 4294967295 4294967295 ne From 17cf27f5b61aace463c3ae52df54c2363d2d4ca8 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 26 Oct 2020 18:08:58 +0100 Subject: [PATCH 283/323] remove non-working debug assert and restore the test modified in the same commit (the non-replication related deadlock will be reported separately) --- mysql-test/suite/rpl/t/rpl_slave_grp_exec.test | 3 +-- mysys/my_error.c | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/mysql-test/suite/rpl/t/rpl_slave_grp_exec.test b/mysql-test/suite/rpl/t/rpl_slave_grp_exec.test index 84f4438dd76..e69c28500ae 100644 --- a/mysql-test/suite/rpl/t/rpl_slave_grp_exec.test +++ b/mysql-test/suite/rpl/t/rpl_slave_grp_exec.test @@ -101,8 +101,7 @@ ALTER TABLE t1 ADD PRIMARY KEY (a); ALTER TABLE t2 ADD PRIMARY KEY (a); ALTER TABLE t3 ADD PRIMARY KEY (a); -#--sync_slave_with_master ---connection slave +--sync_slave_with_master RENAME TABLE t3 TO t3_bak; --connection master diff --git a/mysys/my_error.c b/mysys/my_error.c index 20836269939..2bb9305b2fb 100644 --- a/mysys/my_error.c +++ b/mysys/my_error.c @@ -112,9 +112,6 @@ void my_error(uint nr, myf MyFlags, ...) char ebuff[ERRMSGSIZE]; DBUG_ENTER("my_error"); DBUG_PRINT("my", ("nr: %d MyFlags: %lu errno: %d", nr, MyFlags, errno)); - - if (errno == 1213) - DBUG_ASSERT(0); if (!(format = my_get_err_msg(nr))) (void) my_snprintf(ebuff, sizeof(ebuff), "Unknown error %d", nr); From 05bd2816978104f477a861ebc95fff5d3cbab9a4 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 28 Oct 2020 21:53:35 +0100 Subject: [PATCH 284/323] SPIDER storage engine plugin -> Stable --- storage/spider/spd_param.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/spider/spd_param.cc b/storage/spider/spd_param.cc index 3657cc9120d..ec0949b579f 100644 --- a/storage/spider/spd_param.cc +++ b/storage/spider/spd_param.cc @@ -3673,7 +3673,7 @@ maria_declare_plugin(spider) spider_status_variables, spider_system_variables, SPIDER_DETAIL_VERSION, - MariaDB_PLUGIN_MATURITY_GAMMA + MariaDB_PLUGIN_MATURITY_STABLE }, spider_i_s_alloc_mem_maria, spider_i_s_wrapper_protocols_maria From 9a4398b048d3a5f3d2ef052681c7b36e9f5ba87f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 28 Oct 2020 00:58:38 +0100 Subject: [PATCH 285/323] update columnstore --- storage/columnstore/columnstore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/columnstore/columnstore b/storage/columnstore/columnstore index 86dcaa57d1c..86347532abf 160000 --- a/storage/columnstore/columnstore +++ b/storage/columnstore/columnstore @@ -1 +1 @@ -Subproject commit 86dcaa57d1c0284dc8ea1edfaeff9e748afb3963 +Subproject commit 86347532abf1f7dae8896a96d5b7251233fca229 From 27b762e23d8305bbc65dc61d283fe192e2dbd00a Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 29 Oct 2020 12:14:19 +0300 Subject: [PATCH 286/323] MDEV-22805 SIGSEGV in check_fields on UPDATE Additional case for PS protocol: UPDATE is converted to multi-update in mysql_multi_update_prepare(). --- mysql-test/suite/period/r/update.result | 3 +++ mysql-test/suite/period/t/update.test | 6 +++++- sql/sql_update.cc | 7 +++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/period/r/update.result b/mysql-test/suite/period/r/update.result index b61d8a73b83..f726b4c07cf 100644 --- a/mysql-test/suite/period/r/update.result +++ b/mysql-test/suite/period/r/update.result @@ -299,6 +299,9 @@ CREATE TABLE t1 (a INT, b DATE, c DATE, PERIOD FOR APPTIME(b, c)); INSERT INTO t1 VALUES(1, '1999-01-01', '2018-12-12'); UPDATE t1 FOR PORTION OF APPTIME FROM (SELECT '1999-01-01' FROM t1 WHERE a=2) TO '2018-01-01' SET a = 100; ERROR 42000: This version of MariaDB doesn't yet support 'updating and querying the same temporal periods table' +set @tmp= "UPDATE t1 FOR PORTION OF APPTIME FROM (SELECT '1999-01-01' FROM t1 WHERE a=2) TO '2018-01-01' SET a = 100"; +execute immediate @tmp; +ERROR 42000: This version of MariaDB doesn't yet support 'updating and querying the same temporal periods table' CREATE VIEW v1 AS SELECT * FROM t1; UPDATE v1 FOR PORTION OF APPTIME FROM (SELECT '1999-01-01' FROM t1 WHERE a=2) TO '2018-01-01' SET a = 100; ERROR 42S02: 'v1' is a view diff --git a/mysql-test/suite/period/t/update.test b/mysql-test/suite/period/t/update.test index 66d3bc1e9bf..3f4dd2bdc68 100644 --- a/mysql-test/suite/period/t/update.test +++ b/mysql-test/suite/period/t/update.test @@ -192,8 +192,12 @@ CREATE TABLE t1 (a INT, b DATE, c DATE, PERIOD FOR APPTIME(b, c)); INSERT INTO t1 VALUES(1, '1999-01-01', '2018-12-12'); # Without a patch the following statement crashs a server built in debug mode +let $stmt= UPDATE t1 FOR PORTION OF APPTIME FROM (SELECT '1999-01-01' FROM t1 WHERE a=2) TO '2018-01-01' SET a = 100; --error ER_NOT_SUPPORTED_YET -UPDATE t1 FOR PORTION OF APPTIME FROM (SELECT '1999-01-01' FROM t1 WHERE a=2) TO '2018-01-01' SET a = 100; +eval $stmt; +eval set @tmp= "$stmt"; +--error ER_NOT_SUPPORTED_YET +execute immediate @tmp; CREATE VIEW v1 AS SELECT * FROM t1; --error ER_IT_IS_A_VIEW diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c687b6ca2f5..9514b193407 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -190,6 +190,13 @@ static bool check_fields(THD *thd, TABLE_LIST *table, List &items, my_error(ER_IT_IS_A_VIEW, MYF(0), table->table_name.str); return TRUE; } + if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), + "updating and querying the same temporal periods table"); + + return true; + } DBUG_ASSERT(thd->lex->sql_command == SQLCOM_UPDATE); for (List_iterator_fast it(items); (item=it++);) { From 17ec6d6ce1620c927430ccc3b0d34dad78db983b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Wed, 28 Oct 2020 21:21:15 +0200 Subject: [PATCH 287/323] Skip MYSQL_JSON related tests if the plugin is not compiled --- mysql-test/main/mysql_json_table_recreate.test | 4 ++++ mysql-test/main/mysql_upgrade_mysql_json_datatype.test | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/mysql-test/main/mysql_json_table_recreate.test b/mysql-test/main/mysql_json_table_recreate.test index 1762a452cc8..de1e9202985 100644 --- a/mysql-test/main/mysql_json_table_recreate.test +++ b/mysql-test/main/mysql_json_table_recreate.test @@ -1,5 +1,9 @@ --source include/have_utf8.inc +if (!$TYPE_MYSQL_JSON_SO) { + skip Need MYSQL_JSON plugin; +} + --echo # --echo # The following test takes 2 tables containing a JSON column and attempts --echo # to repair them. diff --git a/mysql-test/main/mysql_upgrade_mysql_json_datatype.test b/mysql-test/main/mysql_upgrade_mysql_json_datatype.test index 0b5b07f233a..6de1e31cf03 100644 --- a/mysql-test/main/mysql_upgrade_mysql_json_datatype.test +++ b/mysql-test/main/mysql_upgrade_mysql_json_datatype.test @@ -2,6 +2,10 @@ -- source include/have_working_dns.inc -- source include/have_innodb.inc +if (!$TYPE_MYSQL_JSON_SO) { + skip Need MYSQL_JSON plugin; +} + call mtr.add_suppression("Table rebuild required"); call mtr.add_suppression("is marked as crashed"); call mtr.add_suppression("Checking"); From 76fabe816f6beb1698d9bc5e88c059608b8bcd8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Wed, 28 Oct 2020 21:33:20 +0200 Subject: [PATCH 288/323] Expose utf8mb4_bin charset for plugins Cleanup other linker errors --- include/m_ctype.h | 2 +- plugin/type_mysql_json/mysql_json.h | 1 + plugin/type_mysql_json/type.cc | 2 +- sql/sql_type.h | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/m_ctype.h b/include/m_ctype.h index 59ac7814aee..5fa8f28ff7a 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -1175,7 +1175,7 @@ extern struct charset_info_st my_charset_utf8mb3_general_nopad_ci; extern struct charset_info_st my_charset_utf8mb3_general_mysql500_ci; extern struct charset_info_st my_charset_utf8mb3_unicode_ci; extern struct charset_info_st my_charset_utf8mb3_unicode_nopad_ci; -extern struct charset_info_st my_charset_utf8mb4_bin; +extern MYSQL_PLUGIN_IMPORT struct charset_info_st my_charset_utf8mb4_bin; extern struct charset_info_st my_charset_utf8mb4_general_ci; extern struct charset_info_st my_charset_utf8mb4_nopad_bin; extern struct charset_info_st my_charset_utf8mb4_general_nopad_ci; diff --git a/plugin/type_mysql_json/mysql_json.h b/plugin/type_mysql_json/mysql_json.h index 79a784cbb6e..afbacafc9c8 100644 --- a/plugin/type_mysql_json/mysql_json.h +++ b/plugin/type_mysql_json/mysql_json.h @@ -41,4 +41,5 @@ enum JSONB_TYPES { bool parse_mysql_json_value(String *buffer, JSONB_TYPES type, const uchar *data, size_t len, size_t depth); + #endif /* MYSQL_JSON_INCLUDED */ diff --git a/plugin/type_mysql_json/type.cc b/plugin/type_mysql_json/type.cc index b267745a998..ec827a2182a 100644 --- a/plugin/type_mysql_json/type.cc +++ b/plugin/type_mysql_json/type.cc @@ -21,7 +21,7 @@ #include #include "mysql_json.h" -static const LEX_CSTRING empty_clex_str= {"", 0}; +const LEX_CSTRING empty_clex_str= {"", 0}; class Type_handler_mysql_json: public Type_handler_blob { diff --git a/sql/sql_type.h b/sql/sql_type.h index 41e840d9ed7..c5d5dc7facc 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -3498,7 +3498,7 @@ public: const Column_definition *row_start, const Column_definition *row_end) const; }; -extern Vers_type_timestamp vers_type_timestamp; +extern MYSQL_PLUGIN_IMPORT Vers_type_timestamp vers_type_timestamp; class Vers_type_trx: public Vers_type_handler From a041b940328d8b3ec86923d234fb31c30c89d69b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Wed, 28 Oct 2020 23:00:21 +0200 Subject: [PATCH 289/323] Move vers_type_timestamp within the CC file It's a virtual method and it can't be inlined anyway. This allows type plugins (mysql_json in particular) to use Type_handler_blob and / or subclass it, without needing to explicitly expose the vers_type_timestamp object. --- sql/sql_type.cc | 18 ++++++++++++++++++ sql/sql_type.h | 8 ++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/sql/sql_type.cc b/sql/sql_type.cc index b7ad8c04af5..32bb7c4cbf7 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -6958,6 +6958,24 @@ bool Type_handler_string_result:: /***************************************************************************/ +const Vers_type_handler* Type_handler_temporal_result::vers() const +{ + return &vers_type_timestamp; +} + +const Vers_type_handler* Type_handler_string_result::vers() const +{ + return &vers_type_timestamp; +} + +const Vers_type_handler* Type_handler_blob_common::vers() const + +{ + return &vers_type_timestamp; +} + +/***************************************************************************/ + uint Type_handler::Item_time_precision(THD *thd, Item *item) const { return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS); diff --git a/sql/sql_type.h b/sql/sql_type.h index c5d5dc7facc..7b541962bac 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -3498,7 +3498,7 @@ public: const Column_definition *row_start, const Column_definition *row_end) const; }; -extern MYSQL_PLUGIN_IMPORT Vers_type_timestamp vers_type_timestamp; +extern Vers_type_timestamp vers_type_timestamp; class Vers_type_trx: public Vers_type_handler @@ -5249,7 +5249,7 @@ public: bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override; bool Item_func_div_fix_length_and_dec(Item_func_div *) const override; bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override; - const Vers_type_handler *vers() const override { return &vers_type_timestamp; } + const Vers_type_handler *vers() const override; }; @@ -5416,7 +5416,7 @@ public: bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override; bool Item_func_div_fix_length_and_dec(Item_func_div *) const override; bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override; - const Vers_type_handler *vers() const override { return &vers_type_timestamp; } + const Vers_type_handler *vers() const override; }; @@ -7039,7 +7039,7 @@ public: const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; - const Vers_type_handler *vers() const override { return &vers_type_timestamp; } + const Vers_type_handler *vers() const override; }; From f3c5a9249072d9193cedf6b9c691de3dfe581cd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Wed, 28 Oct 2020 23:04:55 +0200 Subject: [PATCH 290/323] Add type_mysql_json.so to debian packages --- debian/mariadb-server-10.5.install | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/mariadb-server-10.5.install b/debian/mariadb-server-10.5.install index a33b3267254..67842703af4 100644 --- a/debian/mariadb-server-10.5.install +++ b/debian/mariadb-server-10.5.install @@ -61,6 +61,7 @@ usr/lib/mysql/plugin/query_response_time.so usr/lib/mysql/plugin/server_audit.so usr/lib/mysql/plugin/simple_password_check.so usr/lib/mysql/plugin/sql_errlog.so +usr/lib/mysql/plugin/type_mysql_json.so usr/lib/mysql/plugin/wsrep_info.so usr/share/doc/mariadb-server-10.5/mariadbd.sym.gz usr/share/man/man1/aria_chk.1 From 8b2800d076dd393af2ae332cc692cbdc8b3314c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Thu, 29 Oct 2020 08:37:27 +0200 Subject: [PATCH 291/323] Fix decimals to 0 for MySQL JSON This prevents the clash between NOT_FIXED_DEC differing between server and plugins if MYSQL_SERVER is not defined during plugin compilation. --- plugin/type_mysql_json/type.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/plugin/type_mysql_json/type.cc b/plugin/type_mysql_json/type.cc index ec827a2182a..61507a24d92 100644 --- a/plugin/type_mysql_json/type.cc +++ b/plugin/type_mysql_json/type.cc @@ -37,6 +37,9 @@ public: Field *make_table_field(MEM_ROOT *, const LEX_CSTRING *, const Record_addr &, const Type_all_attributes &, TABLE_SHARE *) const override; + void Column_definition_reuse_fix_attributes(THD *thd, + Column_definition *def, + const Field *field) const override; }; Type_handler_mysql_json type_handler_mysql_json; @@ -85,6 +88,16 @@ Field *Type_handler_mysql_json::make_table_field_from_def(TABLE_SHARE *share, attr->pack_flag_to_pack_length(), attr->charset); } +void Type_handler_mysql_json:: + Column_definition_reuse_fix_attributes(THD *thd, + Column_definition *def, + const Field *field) const +{ + Type_handler_blob::Column_definition_reuse_fix_attributes(thd, def, field); + def->decimals= 0; +} + + Field *Type_handler_mysql_json::make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, From 8cfdddac71eb9451435281c9a9348b4fe224cb89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Thu, 29 Oct 2020 08:49:03 +0200 Subject: [PATCH 292/323] MYSQL_JSON: Update test case to omit .so or .dll extension --- mysql-test/main/mysql_upgrade_mysql_json_datatype.result | 4 ++-- mysql-test/main/mysql_upgrade_mysql_json_datatype.test | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/main/mysql_upgrade_mysql_json_datatype.result b/mysql-test/main/mysql_upgrade_mysql_json_datatype.result index d4028b6db3d..604ef2bc0df 100644 --- a/mysql-test/main/mysql_upgrade_mysql_json_datatype.result +++ b/mysql-test/main/mysql_upgrade_mysql_json_datatype.result @@ -3,7 +3,7 @@ call mtr.add_suppression("is marked as crashed"); call mtr.add_suppression("Checking"); SET NAMES utf8; set sql_mode=""; -install soname 'type_mysql_json.so'; +install soname 'type_mysql_json'; show create table tempty; ERROR HY000: Table rebuild required. Please do "ALTER TABLE `test.tempty` FORCE" or dump/reload to fix it! show create table mysql_json_test; @@ -103,4 +103,4 @@ Total_Number_of_Tests Succesful_Tests String_is_valid_JSON drop table tempty; drop table mysql_json_test; drop table mysql_json_test_big; -uninstall soname 'type_mysql_json.so'; +uninstall soname 'type_mysql_json'; diff --git a/mysql-test/main/mysql_upgrade_mysql_json_datatype.test b/mysql-test/main/mysql_upgrade_mysql_json_datatype.test index 6de1e31cf03..0363b2d0dc1 100644 --- a/mysql-test/main/mysql_upgrade_mysql_json_datatype.test +++ b/mysql-test/main/mysql_upgrade_mysql_json_datatype.test @@ -28,7 +28,7 @@ SET NAMES utf8; set sql_mode=""; ---eval install soname '$TYPE_MYSQL_JSON_SO' +install soname 'type_mysql_json'; --error ER_TABLE_NEEDS_REBUILD show create table tempty; @@ -63,5 +63,5 @@ drop table tempty; drop table mysql_json_test; drop table mysql_json_test_big; ---eval uninstall soname '$TYPE_MYSQL_JSON_SO' +uninstall soname 'type_mysql_json'; --remove_file $MYSQLD_DATADIR/mysql_upgrade_info From 6d3356c12e06f72f5c9e381b9e6d5e1fbb1a1bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 29 Oct 2020 15:51:09 +0200 Subject: [PATCH 293/323] MDEV-24053 MSAN use-of-uninitialized-value in tpool::simulated_aio::simulated_aio_callback() Starting with commit ef3f71fa7435f092dfce36d606cf22332218dd8b MemorySanitizer would complain that we are writing uninitialized data via the doublewrite buffer. buf_dblwr_t::add_to_batch(): Zero out any unused part of the doublewrite buffer, for PAGE_COMPRESSED and ROW_FORMAT=COMPRESSED tables. Reviewed by: Eugene Kosov --- storage/innobase/buf/buf0dblwr.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index a8ae3e2782a..f17cf6cc128 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -736,7 +736,15 @@ void buf_dblwr_t::add_to_batch(const IORequest &request, size_t size) encryption and/or page compression */ void *frame= buf_page_get_frame(request.bpage); - memcpy_aligned(p, frame, size); + /* "frame" is at least 1024-byte aligned for ROW_FORMAT=COMPRESSED pages, + and at least srv_page_size (4096-byte) for everything else. */ + memcpy_aligned(p, frame, size); + /* fil_page_compress() for page_compressed guarantees 256-byte alignment */ + memset_aligned<256>(p + size, 0, srv_page_size - size); + /* FIXME: Inform the compiler that "size" and "srv_page_size - size" + are integer multiples of 256, so the above can translate into simple + SIMD instructions. Currently, we make no such assumptions about the + non-pointer parameters that are passed to the _aligned templates. */ ut_ad(!request.bpage->zip_size() || request.bpage->zip_size() == size); ut_ad(active_slot->reserved == active_slot->first_free); ut_ad(active_slot->reserved < buf_size); From 14798d3cd139430c1d23f14d810a27c5410f7161 Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 29 Oct 2020 16:20:57 +0200 Subject: [PATCH 294/323] MDEV-23159 Assertion `table_share->tmp_table != NO_TMP_TABLE || m_lock_type != 2'... The problem was that opt_sum_query() was, as part of MIN/MAX optimization, doing read operations on constant tables that where already closed Fixed by ensuring we don't try to read from tables that are closed. --- mysql-test/suite/maria/create.result | 33 ++++++++++++++++++++++++++++ mysql-test/suite/maria/create.test | 33 ++++++++++++++++++++++++++++ sql/opt_sum.cc | 24 +++++++++++++------- 3 files changed, 82 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/maria/create.result b/mysql-test/suite/maria/create.result index 82c6b8c9871..462c148df8e 100644 --- a/mysql-test/suite/maria/create.result +++ b/mysql-test/suite/maria/create.result @@ -31,3 +31,36 @@ select * from t2; f1 f2 3 qux DROP TABLE t1, t2; +# +# MDEV-23159 Assertion `table_share->tmp_table != NO_TMP_TABLE || +# m_lock_type != 2' + SIGSEGV in trnman_can_read_from +# (on optimized builds) +# +SET @org_sql_mode=@@SQL_MODE; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=Aria ROW_FORMAT=COMPRESSED; +INSERT INTO t1 VALUES(1); +CREATE TEMPORARY TABLE t2(b INT); +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT MAX(a) FROM t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 Using index +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +DROP TABLE t1,t2; +SET SQL_MODE=''; +CREATE TABLE t1 (c INT PRIMARY KEY) ENGINE=Aria; +CREATE TABLE t2 (d INT); +INSERT INTO t1 VALUES (1); +SELECT c FROM t1 WHERE (c) IN (SELECT MIN(c) FROM t2); +c +DROP TABLE t1,t2; +USE test; +SET SQL_MODE='ONLY_FULL_GROUP_BY'; +CREATE TABLE t3 (c1 DECIMAL(1,1) PRIMARY KEY,c2 DATE,c3 NUMERIC(10) UNSIGNED) ENGINE=Aria; +CREATE TABLE t2 (f1 INTEGER ) ENGINE=Aria; +INSERT INTO t3 VALUES (0,0,0); +SELECT c1 FROM t3 WHERE (c1) IN (SELECT MIN(DISTINCT c1) FROM t2); +c1 +DROP TABLE t2,t3; +SET @@SQL_MODE=@org_sql_mode; +# +# End of 10.3 tests +# diff --git a/mysql-test/suite/maria/create.test b/mysql-test/suite/maria/create.test index 8f2ffd7492f..0efae8cac1b 100644 --- a/mysql-test/suite/maria/create.test +++ b/mysql-test/suite/maria/create.test @@ -40,3 +40,36 @@ INSERT IGNORE INTO t1 VALUES (1),(2); CREATE OR REPLACE TABLE t2 ENGINE=Aria AS SELECT SUM(a) AS f1, IFNULL( 'qux', ExtractValue( 'foo', 'bar' ) ) AS f2 FROM t1; select * from t2; DROP TABLE t1, t2; + +--echo # +--echo # MDEV-23159 Assertion `table_share->tmp_table != NO_TMP_TABLE || +--echo # m_lock_type != 2' + SIGSEGV in trnman_can_read_from +--echo # (on optimized builds) +--echo # + +SET @org_sql_mode=@@SQL_MODE; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=Aria ROW_FORMAT=COMPRESSED; +INSERT INTO t1 VALUES(1); +CREATE TEMPORARY TABLE t2(b INT); +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT MAX(a) FROM t2); +DROP TABLE t1,t2; + +SET SQL_MODE=''; +CREATE TABLE t1 (c INT PRIMARY KEY) ENGINE=Aria; +CREATE TABLE t2 (d INT); +INSERT INTO t1 VALUES (1); +SELECT c FROM t1 WHERE (c) IN (SELECT MIN(c) FROM t2); +DROP TABLE t1,t2; + +USE test; +SET SQL_MODE='ONLY_FULL_GROUP_BY'; +CREATE TABLE t3 (c1 DECIMAL(1,1) PRIMARY KEY,c2 DATE,c3 NUMERIC(10) UNSIGNED) ENGINE=Aria; +CREATE TABLE t2 (f1 INTEGER ) ENGINE=Aria; +INSERT INTO t3 VALUES (0,0,0); +SELECT c1 FROM t3 WHERE (c1) IN (SELECT MIN(DISTINCT c1) FROM t2); +DROP TABLE t2,t3; +SET @@SQL_MODE=@org_sql_mode; + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index adfad29bb34..525d7390a26 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -399,20 +399,28 @@ int opt_sum_query(THD *thd, break; } longlong info_limit= 1; - table->file->info_push(INFO_KIND_FORCE_LIMIT_BEGIN, &info_limit); - if (likely(!(error= table->file->ha_index_init((uint) ref.key, 1)))) - error= (is_max ? - get_index_max_value(table, &ref, range_fl) : - get_index_min_value(table, &ref, item_field, range_fl, - prefix_len)); + error= 0; + table->file->info_push(INFO_KIND_FORCE_LIMIT_BEGIN, &info_limit); + if (!table->const_table) + { + if (likely(!(error= table->file->ha_index_init((uint) ref.key, + 1)))) + error= (is_max ? + get_index_max_value(table, &ref, range_fl) : + get_index_min_value(table, &ref, item_field, range_fl, + prefix_len)); + } /* Verify that the read tuple indeed matches the search key */ if (!error && reckey_in_range(is_max, &ref, item_field->field, conds, range_fl, prefix_len)) error= HA_ERR_KEY_NOT_FOUND; - table->file->ha_end_keyread(); - table->file->ha_index_end(); + if (!table->const_table) + { + table->file->ha_end_keyread(); + table->file->ha_index_end(); + } table->file->info_push(INFO_KIND_FORCE_LIMIT_END, NULL); if (error) { From 85613a32477ef4b8fb9aefba5f61689028f3ff87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 29 Oct 2020 16:27:04 +0200 Subject: [PATCH 295/323] After-merge fix: main,innodb_ext_key,off For some reason, in the test main,innodb_ext_key,off we frequently get unexpected EXPLAIN output, in particular on Microsoft Windows debug builders. Let us comment out that EXPLAIN statement for now. --- mysql-test/main/innodb_ext_key,off.rdiff | 9 --------- mysql-test/main/innodb_ext_key.result | 6 ------ mysql-test/main/innodb_ext_key.test | 10 +++++----- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/mysql-test/main/innodb_ext_key,off.rdiff b/mysql-test/main/innodb_ext_key,off.rdiff index 2164c56c5b5..1e0f5d6fbd5 100644 --- a/mysql-test/main/innodb_ext_key,off.rdiff +++ b/mysql-test/main/innodb_ext_key,off.rdiff @@ -150,15 +150,6 @@ Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 explain -@@ -209,7 +209,7 @@ - where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 - or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; - id select_type table type possible_keys key key_len ref rows Extra --1 SIMPLE lineitem index_merge PRIMARY,i_l_shipdate,i_l_receiptdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate,i_l_receiptdate # NULL # Using -+1 SIMPLE lineitem index_merge PRIMARY,i_l_shipdate,i_l_receiptdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate,PRIMARY,i_l_receiptdate,PRIMARY # NULL # Using - flush status; - select l_orderkey, l_linenumber from lineitem - where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 @@ -220,12 +220,12 @@ 5959 3 show status like 'handler_read_next'; diff --git a/mysql-test/main/innodb_ext_key.result b/mysql-test/main/innodb_ext_key.result index dbc201be669..6725e91a137 100644 --- a/mysql-test/main/innodb_ext_key.result +++ b/mysql-test/main/innodb_ext_key.result @@ -204,12 +204,6 @@ Handler_read_retry 0 Handler_read_rnd 3 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 -explain -select l_orderkey, l_linenumber from lineitem -where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 -or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE lineitem index_merge PRIMARY,i_l_shipdate,i_l_receiptdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate,i_l_receiptdate # NULL # Using flush status; select l_orderkey, l_linenumber from lineitem where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 diff --git a/mysql-test/main/innodb_ext_key.test b/mysql-test/main/innodb_ext_key.test index 9ca9bbd608f..2fed1c35a41 100644 --- a/mysql-test/main/innodb_ext_key.test +++ b/mysql-test/main/innodb_ext_key.test @@ -98,11 +98,11 @@ select l_orderkey, l_linenumber or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; show status like 'handler_read%'; ---replace_column 7 # 9 # 10 Using -explain -select l_orderkey, l_linenumber from lineitem - where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 - or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; +# FIXME: optimizer_switch=extended_keys=off occasionally gets wrong plan +#explain +#select l_orderkey, l_linenumber from lineitem +# where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 +# or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; flush status; select l_orderkey, l_linenumber from lineitem where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 From 4c99e3e948dd14cfee9209e1a6274d94ecb5e22f Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 29 Oct 2020 17:36:49 +0200 Subject: [PATCH 296/323] Fixed bug in detection of getgrouplist parameters. On my system, OpenSuse, I got a compilation error that some arguments to getgrouplist() where not initialized --- plugin/auth_pam/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/auth_pam/CMakeLists.txt b/plugin/auth_pam/CMakeLists.txt index ff7ba4a4f68..740aedeb7d9 100644 --- a/plugin/auth_pam/CMakeLists.txt +++ b/plugin/auth_pam/CMakeLists.txt @@ -14,8 +14,8 @@ CHECK_C_SOURCE_COMPILES( #include #include int main() { - char *arg_1; - gid_t arg_2, arg_3; + char *arg_1= 0; + gid_t arg_2=0, arg_3; int arg_4; (void)getgrouplist(arg_1,arg_2,&arg_3,&arg_4); return 0; From 14d43f4fa691e3af113195a3608f1fc401b85090 Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 29 Oct 2020 18:34:26 +0200 Subject: [PATCH 297/323] MDEV-23222 SIGSEG in maria_create() because of double free The crash happens because a double free in the case CREATE TABLE fails because there is a conflicting tables on disk. Fixed by ensuring that the double free can't happen. --- mysql-test/suite/maria/create.result | 11 +++++++++++ mysql-test/suite/maria/create.test | 22 ++++++++++++++++++++++ storage/maria/ma_create.c | 1 + 3 files changed, 34 insertions(+) diff --git a/mysql-test/suite/maria/create.result b/mysql-test/suite/maria/create.result index 462c148df8e..f1da0d7105b 100644 --- a/mysql-test/suite/maria/create.result +++ b/mysql-test/suite/maria/create.result @@ -62,5 +62,16 @@ c1 DROP TABLE t2,t3; SET @@SQL_MODE=@org_sql_mode; # +# MDEV-23222 SIGSEGV in maria_status | Assertion `(longlong) +# thd->status_var.local_memory_used >= 0 +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +CREATE TABLE MDEV_23222 (i INT) DATA DIRECTORY = 'MYSQL_TMP_DIR', ENGINE=Aria TRANSACTIONAL=1;; +flush tables; +CREATE TABLE MDEV_23222 (i INT) DATA DIRECTORY = 'MYSQL_TMP_DIR', ENGINE=Aria TRANSACTIONAL=1;; +Got one of the listed errors +DROP TABLE t1; +# # End of 10.3 tests # diff --git a/mysql-test/suite/maria/create.test b/mysql-test/suite/maria/create.test index 0efae8cac1b..cac1f8bd7e1 100644 --- a/mysql-test/suite/maria/create.test +++ b/mysql-test/suite/maria/create.test @@ -70,6 +70,28 @@ SELECT c1 FROM t3 WHERE (c1) IN (SELECT MIN(DISTINCT c1) FROM t2); DROP TABLE t2,t3; SET @@SQL_MODE=@org_sql_mode; +--echo # +--echo # MDEV-23222 SIGSEGV in maria_status | Assertion `(longlong) +--echo # thd->status_var.local_memory_used >= 0 +--echo # + +let $mysqld_datadir= `select @@datadir`; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +--eval CREATE TABLE MDEV_23222 (i INT) DATA DIRECTORY = '$MYSQL_TMP_DIR', ENGINE=Aria TRANSACTIONAL=1; +flush tables; +--remove_file $mysqld_datadir/test/MDEV_23222.frm +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +--error 1,ER_TABLE_EXISTS_ERROR +--eval CREATE TABLE MDEV_23222 (i INT) DATA DIRECTORY = '$MYSQL_TMP_DIR', ENGINE=Aria TRANSACTIONAL=1; +DROP TABLE t1; +--disable_warnings +--remove_file $mysqld_datadir/test/MDEV_23222.MAD +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +--remove_file $MYSQL_TMP_DIR/MDEV_23222.MAD +--enable_warnings + --echo # --echo # End of 10.3 tests --echo # diff --git a/storage/maria/ma_create.c b/storage/maria/ma_create.c index 98c33f896ac..8d6eb6edc48 100644 --- a/storage/maria/ma_create.c +++ b/storage/maria/ma_create.c @@ -1163,6 +1163,7 @@ int maria_create(const char *name, enum data_file_type datafile_type, FALSE, TRUE)) goto err; my_free(log_data); + log_data= 0; } if (!(flags & HA_DONT_TOUCH_DATA)) From eb38e7ef607146ca307ab15e2d5cdb49209d3c7e Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 29 Oct 2020 17:06:56 +0200 Subject: [PATCH 298/323] MDEV-22879 SIGSEGV (or hang) in free/my_free This bug was already fixed in a previous commit. Added test case from the MDEV to prove it's fixed. --- mysql-test/main/backup_locks.result | 19 +++++++++++++++++++ mysql-test/main/backup_locks.test | 23 +++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/mysql-test/main/backup_locks.result b/mysql-test/main/backup_locks.result index f1c02677b7a..1505c39f166 100644 --- a/mysql-test/main/backup_locks.result +++ b/mysql-test/main/backup_locks.result @@ -146,3 +146,22 @@ connection default; disconnect con1; show tables; Tables_in_test +# +# MDEV-22879 SIGSEGV (or hang) in free/my_free from +# _ma_end_block_record (on optimized builds) +# +SET STATEMENT max_statement_time=20 FOR BACKUP LOCK test.t1; +CREATE TABLE IF NOT EXISTS t3 (c1 CHAR(1) BINARY,c2 SMALLINT(10),c3 NUMERIC(1,0), PRIMARY KEY(c1(1))) ENGINE=InnoDB; +ERROR HY000: Can't execute the query because you have a conflicting read lock +BACKUP UNLOCK; +CREATE TABLE IF NOT EXISTS t3 (c1 CHAR(1) BINARY,c2 SMALLINT(10),c3 NUMERIC(1,0), PRIMARY KEY(c1(1))) ENGINE=InnoDB; +SET STATEMENT max_statement_time=20 FOR BACKUP LOCK test.t1; +LOCK TABLES t3 AS a2 WRITE, t3 AS a1 READ LOCAL; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +DROP TABLE t3; +ERROR HY000: Can't execute the query because you have a conflicting read lock +BACKUP UNLOCK; +DROP TABLE t3; +# +# End of MariaDB 10.4 tests +# diff --git a/mysql-test/main/backup_locks.test b/mysql-test/main/backup_locks.test index ed7d3875d1d..d2f3d95d703 100644 --- a/mysql-test/main/backup_locks.test +++ b/mysql-test/main/backup_locks.test @@ -167,3 +167,26 @@ connection con1; connection default; disconnect con1; show tables; + +--echo # +--echo # MDEV-22879 SIGSEGV (or hang) in free/my_free from +--echo # _ma_end_block_record (on optimized builds) +--echo # + +SET STATEMENT max_statement_time=20 FOR BACKUP LOCK test.t1; +--error ER_CANT_UPDATE_WITH_READLOCK +CREATE TABLE IF NOT EXISTS t3 (c1 CHAR(1) BINARY,c2 SMALLINT(10),c3 NUMERIC(1,0), PRIMARY KEY(c1(1))) ENGINE=InnoDB; +BACKUP UNLOCK; + +CREATE TABLE IF NOT EXISTS t3 (c1 CHAR(1) BINARY,c2 SMALLINT(10),c3 NUMERIC(1,0), PRIMARY KEY(c1(1))) ENGINE=InnoDB; +SET STATEMENT max_statement_time=20 FOR BACKUP LOCK test.t1; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +LOCK TABLES t3 AS a2 WRITE, t3 AS a1 READ LOCAL; +--error ER_CANT_UPDATE_WITH_READLOCK +DROP TABLE t3; +BACKUP UNLOCK; +DROP TABLE t3; + +--echo # +--echo # End of MariaDB 10.4 tests +--echo # From f9b0ee07ef066625403ef64bf3486c2db7baed10 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Thu, 29 Oct 2020 22:19:32 +0100 Subject: [PATCH 299/323] MDEV-19838: followup, fix for PS & embedded Use 9 byte (min length packet) --- libmysqld/lib_sql.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index d278bd39834..229e4e69e6a 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -330,7 +330,7 @@ static my_bool emb_read_query_result(MYSQL *mysql) static int emb_stmt_execute(MYSQL_STMT *stmt) { DBUG_ENTER("emb_stmt_execute"); - uchar header[5]; + uchar header[9]; THD *thd; my_bool res; @@ -342,6 +342,7 @@ static int emb_stmt_execute(MYSQL_STMT *stmt) int4store(header, stmt->stmt_id); header[4]= (uchar) stmt->flags; + header[5]= header[6]= header[7]= header[8]= 0; // safety thd= (THD*)stmt->mysql->thd; thd->client_param_count= stmt->param_count; thd->client_params= stmt->params; From a90b15837cb1a2138a07266cb8df42fcaa905229 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Thu, 29 Oct 2020 22:20:21 +0100 Subject: [PATCH 300/323] MDEV-19838: fix of error messages --- sql/sql_prepare.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 0df2617bb9a..11edd577309 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -3236,8 +3236,7 @@ void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length) if (packet_length < packet_min_lenght) { - my_error(ER_MALFORMED_PACKET, MYF(0), 0, - "", "mysqld_stmt_execute"); + my_error(ER_MALFORMED_PACKET, MYF(0)); DBUG_VOID_RETURN; } ulong stmt_id= uint4korr(packet); @@ -3427,9 +3426,7 @@ static void mysql_stmt_execute_common(THD *thd, if (stmt_execute_packet_sanity_check(stmt, packet, packet_end, bulk_op, stmt_id == LAST_STMT_ID, read_types)) { - char llbuf[22]; - my_error(ER_MALFORMED_PACKET, MYF(0), static_cast(sizeof(llbuf)), - llstr(stmt_id, llbuf), "mysqld_stmt_execute"); + my_error(ER_MALFORMED_PACKET, MYF(0)); DBUG_VOID_RETURN; } From 571bcf9aaaf59b84e24bbfb809738dea25495d78 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 30 Oct 2020 15:09:18 +1100 Subject: [PATCH 301/323] deb: logrotate - fix my_print_defaults arg Corrects: 7803601dcb8e40746a10a4012b0c8eb08274db3e --- debian/mariadb-server-10.5.mysql-server.logrotate | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/mariadb-server-10.5.mysql-server.logrotate b/debian/mariadb-server-10.5.mysql-server.logrotate index eed6fc5e88d..4111a276dc3 100644 --- a/debian/mariadb-server-10.5.mysql-server.logrotate +++ b/debian/mariadb-server-10.5.mysql-server.logrotate @@ -11,7 +11,7 @@ sharedscripts postrotate test -x /usr/bin/mysqladmin || exit 0 - if [ -f `my_print_defaults --mariadbd | grep -oP "pid-file=\K[^$]+"` ]; then + if [ -f `my_print_defaults --mysqld | grep -oP "pid-file=\K[^$]+"` ]; then # If this fails, check debian.conf! mysqladmin --defaults-file=/etc/mysql/debian.cnf --local flush-error-log \ flush-engine-log flush-general-log flush-slow-log From 54856714748082284f43efe15adf846c63854e8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 30 Oct 2020 08:52:10 +0200 Subject: [PATCH 302/323] Remove test that does not apply for 10.4. --- mysql-test/suite/galera/r/MDEV-22707.result | 26 ----------- mysql-test/suite/galera/t/MDEV-22707.test | 51 --------------------- 2 files changed, 77 deletions(-) delete mode 100644 mysql-test/suite/galera/r/MDEV-22707.result delete mode 100644 mysql-test/suite/galera/t/MDEV-22707.test diff --git a/mysql-test/suite/galera/r/MDEV-22707.result b/mysql-test/suite/galera/r/MDEV-22707.result deleted file mode 100644 index a74844d7e12..00000000000 --- a/mysql-test/suite/galera/r/MDEV-22707.result +++ /dev/null @@ -1,26 +0,0 @@ -CREATE TABLE t1(f2 INT) ENGINE=InnoDB; -connect node_1_applier_thd, 127.0.0.1, root, , test, $NODE_MYPORT_1; -SET GLOBAL debug_dbug = "+d,sync.wsrep_apply_cb"; -connection node_2; -SET SESSION wsrep_sync_wait = 0; -INSERT INTO t1 (f2) VALUES (2); -connection node_1_applier_thd; -SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached"; -connection node_1; -SET SESSION wsrep_sync_wait = 0; -SET DEBUG_SYNC = 'wsrep_before_replication SIGNAL wsrep_before_replication_reached WAIT_FOR continue'; -INSERT INTO t1 (f2) VALUES (1); -connect node_1_flush_thd, 127.0.0.1, root, , test, $NODE_MYPORT_1; -SET DEBUG_SYNC="now WAIT_FOR wsrep_before_replication_reached"; -SET GLOBAL debug_dbug = "+d,sync.wsrep_before_mdl_wait"; -FLUSH TABLES; -connect node_1_sync_release_thd, 127.0.0.1, root, , test, $NODE_MYPORT_1; -SET GLOBAL debug_dbug = ""; -SET DEBUG_SYNC = "now SIGNAL signal.wsrep_before_mdl_wait"; -SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb"; -SET DEBUG_SYNC = "now SIGNAL continue"; -SET DEBUG_SYNC = "RESET"; -connection node_1; -connection node_1_flush_thd; -connection node_2; -DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/MDEV-22707.test b/mysql-test/suite/galera/t/MDEV-22707.test deleted file mode 100644 index 19755f7c5ac..00000000000 --- a/mysql-test/suite/galera/t/MDEV-22707.test +++ /dev/null @@ -1,51 +0,0 @@ -# -# MDEV-22707 galera got stuck after flush tables -# - ---source include/galera_cluster.inc ---source include/have_innodb.inc ---source include/have_debug.inc ---source include/have_debug_sync.inc - -CREATE TABLE t1(f2 INT) ENGINE=InnoDB; - ---connect node_1_applier_thd, 127.0.0.1, root, , test, $NODE_MYPORT_1 -SET GLOBAL debug_dbug = "+d,sync.wsrep_apply_cb"; - ---connection node_2 -SET SESSION wsrep_sync_wait = 0; ---send INSERT INTO t1 (f2) VALUES (2) - ---connection node_1_applier_thd -# Wait for `sync.wsrep_apply_cb_reached` signal -SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached"; - ---connection node_1 -SET SESSION wsrep_sync_wait = 0; -SET DEBUG_SYNC = 'wsrep_before_replication SIGNAL wsrep_before_replication_reached WAIT_FOR continue'; ---send INSERT INTO t1 (f2) VALUES (1) - ---connect node_1_flush_thd, 127.0.0.1, root, , test, $NODE_MYPORT_1 -SET DEBUG_SYNC="now WAIT_FOR wsrep_before_replication_reached"; -SET GLOBAL debug_dbug = "+d,sync.wsrep_before_mdl_wait"; ---send FLUSH TABLES - ---connect node_1_sync_release_thd, 127.0.0.1, root, , test, $NODE_MYPORT_1 -# First clear all DBUG points -SET GLOBAL debug_dbug = ""; -# Now signal threads to continue execution -SET DEBUG_SYNC = "now SIGNAL signal.wsrep_before_mdl_wait"; -SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb"; -SET DEBUG_SYNC = "now SIGNAL continue"; -SET DEBUG_SYNC = "RESET"; - ---connection node_1 ---reap - ---connection node_1_flush_thd ---reap - ---connection node_2 ---reap - -DROP TABLE t1; From 99362359850d3cece6e465788827aef7e8c33ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 30 Oct 2020 08:54:05 +0200 Subject: [PATCH 303/323] MDEV-23659: Update Galera disabled.def file Disable galera_var_replicate_myisam until fixed on 10.4 --- mysql-test/suite/galera/disabled.def | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def index e986a0c8951..d940c702d54 100644 --- a/mysql-test/suite/galera/disabled.def +++ b/mysql-test/suite/galera/disabled.def @@ -16,6 +16,7 @@ MDEV-16509 : MDEV-21523 galera.MDEV-16509 MDEV-20225 : MDEV-20886 galera.MDEV-20225 MW-286 : MDEV-18464 Killing thread can cause mutex deadlock if done concurrently with Galera/replication victim kill MW-328A : MDEV-22666 galera.MW-328A MTR failed: "Semaphore wait has lasted > 600 seconds" and do not release port 16002 +MW-328A : MDEV-22666? MW-328B : MDEV-22666 galera.MW-328A MTR failed: "Semaphore wait has lasted > 600 seconds" and do not release port 16002 MW-329 : MDEV-19962 Galera test failure on MW-329 galera.galera_defaults : MDEV-21494 Galera test sporadic failure on galera.galera_defaults @@ -40,6 +41,7 @@ galera_toi_truncate : MDEV-22996 Hang on galera_toi_truncate test case galera_var_node_address : MDEV-20485 Galera test failure galera_var_notify_cmd : MDEV-21905 Galera test galera_var_notify_cmd causes hang galera_var_reject_queries : assertion in inline_mysql_socket_send +galera_var_replicate_myisam_on : MDEV-24062 Galera test failure on galera_var_replicate_myisam_on galera_var_retry_autocommit: MDEV-18181 Galera test failure on galera.galera_var_retry_autocommit galera_wan : MDEV-17259 Test failure on galera.galera_wan lp1376747-4 : MDEV-21911 Galera test failure on lp1376747-4 @@ -47,4 +49,3 @@ partition : MDEV-19958 Galera test failure on galera.partition query_cache: MDEV-15805 Test failure on galera.query_cache sql_log_bin : MDEV-21491 galera.sql_log_bin versioning_trx_id : MDEV-18590 galera.versioning_trx_id -MW-328A : MDEV-22666? From 5482d62760bcbdcf44f1340fb5846c3942419dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 30 Oct 2020 09:19:29 +0200 Subject: [PATCH 304/323] Fix sporadic test failure on galera_parallel_apply_3nodes. Test itself is not deterministic. --- .../r/galera_parallel_apply_3nodes.result | 16 +++++++++++----- .../t/galera_parallel_apply_3nodes.test | 16 ++++++++++++++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/galera_3nodes/r/galera_parallel_apply_3nodes.result b/mysql-test/suite/galera_3nodes/r/galera_parallel_apply_3nodes.result index 4f9951c382f..4742fc1af9c 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_parallel_apply_3nodes.result +++ b/mysql-test/suite/galera_3nodes/r/galera_parallel_apply_3nodes.result @@ -7,12 +7,18 @@ UPDATE t1 SET f1 = f1 + 10;; connection node_2; UPDATE t1 SET f1 = f1 + 100;; connection node_1; -connection node_2; -connection node_3; -SELECT f1 = 111 FROM t1; -f1 = 111 +SELECT COUNT(*) FROM t1; +COUNT(*) 1 -SELECT COUNT(*) IN (1, 2) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE 'committed%'; +connection node_2; +SELECT COUNT(*) FROM t1; +COUNT(*) +1 +connection node_3; +SELECT COUNT(*) FROM t1; +COUNT(*) +1 +SELECT COUNT(*) IN (1, 2) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%committed%'; COUNT(*) IN (1, 2) 1 SET GLOBAL wsrep_slave_threads = 1;; diff --git a/mysql-test/suite/galera_3nodes/t/galera_parallel_apply_3nodes.test b/mysql-test/suite/galera_3nodes/t/galera_parallel_apply_3nodes.test index 7d80d8036a1..f1168e59193 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_parallel_apply_3nodes.test +++ b/mysql-test/suite/galera_3nodes/t/galera_parallel_apply_3nodes.test @@ -24,14 +24,26 @@ SET GLOBAL wsrep_slave_threads = 2; --send UPDATE t1 SET f1 = f1 + 100; --connection node_1 +# +# Note that test is not deterministic. We have following cases possible +# (1) Both updates are certified locally and then executed by the applier +# (2) Certification of update in node_1 fails because applier has started +# update from node_2 +# (3) Certification of update in node_2 fails because applier has started +# update from node_1 +# +--error 0,ER_LOCK_DEADLOCK --reap +SELECT COUNT(*) FROM t1; --connection node_2 +--error 0,ER_LOCK_DEADLOCK --reap +SELECT COUNT(*) FROM t1; --connection node_3 -SELECT f1 = 111 FROM t1; -SELECT COUNT(*) IN (1, 2) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE 'committed%'; +SELECT COUNT(*) FROM t1; +SELECT COUNT(*) IN (1, 2) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%committed%'; --eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig; From 199863d72b7cccaa4c75641c50c45a83b568ab8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 30 Oct 2020 11:04:16 +0200 Subject: [PATCH 305/323] MDEV-23991 fixup: Initialize the memory Also, revert the work-around for the test that was attempted in commit 85613a32477ef4b8fb9aefba5f61689028f3ff87. This issue was caught by MemorySanitizer as well as on the Microsoft Windows debug builds, thanks to /MD being used starting with 10.4. The code fix will also be applied to 10.2 because the regression was introduced in commit afc9d00c66db946c8240fe1fa6b345a3a8b6fec1. --- mysql-test/main/innodb_ext_key,off.rdiff | 9 +++++++++ mysql-test/main/innodb_ext_key.result | 6 ++++++ mysql-test/main/innodb_ext_key.test | 10 +++++----- storage/innobase/dict/dict0stats.cc | 3 +++ 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/mysql-test/main/innodb_ext_key,off.rdiff b/mysql-test/main/innodb_ext_key,off.rdiff index 1e0f5d6fbd5..2164c56c5b5 100644 --- a/mysql-test/main/innodb_ext_key,off.rdiff +++ b/mysql-test/main/innodb_ext_key,off.rdiff @@ -150,6 +150,15 @@ Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 explain +@@ -209,7 +209,7 @@ + where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 + or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE lineitem index_merge PRIMARY,i_l_shipdate,i_l_receiptdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate,i_l_receiptdate # NULL # Using ++1 SIMPLE lineitem index_merge PRIMARY,i_l_shipdate,i_l_receiptdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate,PRIMARY,i_l_receiptdate,PRIMARY # NULL # Using + flush status; + select l_orderkey, l_linenumber from lineitem + where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 @@ -220,12 +220,12 @@ 5959 3 show status like 'handler_read_next'; diff --git a/mysql-test/main/innodb_ext_key.result b/mysql-test/main/innodb_ext_key.result index 6725e91a137..dbc201be669 100644 --- a/mysql-test/main/innodb_ext_key.result +++ b/mysql-test/main/innodb_ext_key.result @@ -204,6 +204,12 @@ Handler_read_retry 0 Handler_read_rnd 3 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 +explain +select l_orderkey, l_linenumber from lineitem +where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 +or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE lineitem index_merge PRIMARY,i_l_shipdate,i_l_receiptdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate,i_l_receiptdate # NULL # Using flush status; select l_orderkey, l_linenumber from lineitem where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 diff --git a/mysql-test/main/innodb_ext_key.test b/mysql-test/main/innodb_ext_key.test index 2fed1c35a41..9ca9bbd608f 100644 --- a/mysql-test/main/innodb_ext_key.test +++ b/mysql-test/main/innodb_ext_key.test @@ -98,11 +98,11 @@ select l_orderkey, l_linenumber or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; show status like 'handler_read%'; -# FIXME: optimizer_switch=extended_keys=off occasionally gets wrong plan -#explain -#select l_orderkey, l_linenumber from lineitem -# where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 -# or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; +--replace_column 7 # 9 # 10 Using +explain +select l_orderkey, l_linenumber from lineitem + where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 + or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; flush status; select l_orderkey, l_linenumber from lineitem where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index 950e33c090b..ba724703221 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -2244,6 +2244,9 @@ dict_stats_update_persistent( } ut_ad(!dict_index_is_ibuf(index)); + mutex_enter(&dict_sys.mutex); + dict_stats_empty_index(index, false); + mutex_exit(&dict_sys.mutex); index_stats_t stats = dict_stats_analyze_index(index); From 5a0c34e4c2fd951119efb432eedcaa65a1d36606 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Fri, 30 Oct 2020 14:56:57 +0530 Subject: [PATCH 306/323] MDEV-24033: SIGSEGV in __memcmp_avx2_movbe from queue_insert | SIGSEGV in __memcmp_avx2_movbe from native_compare The issue here was the system variable max_sort_length was being applied to decimals and it was truncating the value for decimals to the number of bytes set by max_sort_length. This was leading to a buffer overflow as the values were written to the buffer without truncation and then we moved the offset to the number of bytes(set by max_sort_length), that are needed for comparison. The fix is to not apply max_sort_length for fixed size types like INT, DECIMALS and only apply max_sort_length for CHAR, VARCHARS, TEXT and BLOBS. --- mysql-test/r/order_by.result | 20 ++++++++++++++++++++ mysql-test/t/order_by.test | 21 +++++++++++++++++++++ sql/field.h | 3 +++ sql/filesort.cc | 14 +++++++++++++- sql/sql_class.h | 2 ++ sql/sql_type.h | 2 ++ 6 files changed, 61 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 1daf523e052..7bc8f562f1b 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -3432,4 +3432,24 @@ NULLIF(GROUP_CONCAT(v1), null) C B DROP TABLE t1; +# +# MDEV-24033: SIGSEGV in __memcmp_avx2_movbe from queue_insert | SIGSEGV in __memcmp_avx2_movbe from native_compare +# +SET @save_max_length_for_sort_data=@@max_length_for_sort_data; +SET @save_max_sort_length= @@max_sort_length; +SET @save_sql_select_limit= @@sql_select_limit; +CREATE TABLE t1 (a DECIMAL(64,0), b INT); +INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4); +SET max_length_for_sort_data= 30; +SET sql_select_limit = 3; +SET max_sort_length=8; +SELECT * FROM t1 ORDER BY a+1; +a b +1 1 +2 2 +3 3 +SET max_length_for_sort_data=@save_max_length_for_sort_data; +SET max_sort_length= @save_max_sort_length; +SET sql_select_limit= @save_sql_select_limit; +DROP TABLE t1; # End of 10.2 tests diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index f6886d6d45c..e9802f95721 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -2272,4 +2272,25 @@ ORDER BY id+1 DESC; DROP TABLE t1; +--echo # +--echo # MDEV-24033: SIGSEGV in __memcmp_avx2_movbe from queue_insert | SIGSEGV in __memcmp_avx2_movbe from native_compare +--echo # + +SET @save_max_length_for_sort_data=@@max_length_for_sort_data; +SET @save_max_sort_length= @@max_sort_length; +SET @save_sql_select_limit= @@sql_select_limit; + +CREATE TABLE t1 (a DECIMAL(64,0), b INT); +INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4); + +SET max_length_for_sort_data= 30; +SET sql_select_limit = 3; +SET max_sort_length=8; +SELECT * FROM t1 ORDER BY a+1; + +SET max_length_for_sort_data=@save_max_length_for_sort_data; +SET max_sort_length= @save_max_sort_length; +SET sql_select_limit= @save_sql_select_limit; +DROP TABLE t1; + --echo # End of 10.2 tests diff --git a/sql/field.h b/sql/field.h index 18e44f1d9d4..fea40251587 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1339,6 +1339,8 @@ public: virtual uint max_packed_col_length(uint max_length) { return max_length;} + virtual bool is_packable() const { return false; } + uint offset(uchar *record) const { return (uint) (ptr - record); @@ -1827,6 +1829,7 @@ public: bool can_optimize_range(const Item_bool_func *cond, const Item *item, bool is_eq_func) const; + bool is_packable() const { return true; } }; /* base class for float and double and decimal (old one) */ diff --git a/sql/filesort.cc b/sql/filesort.cc index d76c39c3bd4..96f9aa874da 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -1971,7 +1971,14 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length, if (sortorder->field) { CHARSET_INFO *cs= sortorder->field->sort_charset(); + sortorder->type= sortorder->field->is_packable() ? + SORT_FIELD_ATTR::VARIABLE_SIZE : + SORT_FIELD_ATTR::FIXED_SIZE; + sortorder->length= sortorder->field->sort_length(); + if (sortorder->is_variable_sized()) + set_if_smaller(sortorder->length, thd->variables.max_sort_length); + if (use_strnxfrm((cs=sortorder->field->sort_charset()))) { *multi_byte_charset= true; @@ -1982,6 +1989,10 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length, } else { + sortorder->type= sortorder->item->type_handler()->is_packable() ? + SORT_FIELD_ATTR::VARIABLE_SIZE : + SORT_FIELD_ATTR::FIXED_SIZE; + sortorder->item->sortlength(thd, sortorder->item, sortorder); if (use_strnxfrm(sortorder->item->collation.collation)) { @@ -1990,7 +2001,8 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length, if (sortorder->item->maybe_null) length++; // Place for NULL marker } - set_if_smaller(sortorder->length, thd->variables.max_sort_length); + if (sortorder->is_variable_sized()) + set_if_smaller(sortorder->length, thd->variables.max_sort_length); length+=sortorder->length; } sortorder->field= (Field*) 0; // end marker diff --git a/sql/sql_class.h b/sql/sql_class.h index d693cfa2727..2727b4c84d5 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -5449,6 +5449,8 @@ struct SORT_FIELD_ATTR { uint length; /* Length of sort field */ uint suffix_length; /* Length suffix (0-4) */ + enum Type { FIXED_SIZE, VARIABLE_SIZE } type; + bool is_variable_sized() { return type == VARIABLE_SIZE; } }; diff --git a/sql/sql_type.h b/sql/sql_type.h index 42090037ead..046b42e4a83 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -92,6 +92,7 @@ public: virtual void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const= 0; + virtual bool is_packable() const { return false; } }; @@ -169,6 +170,7 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + bool is_packable()const { return true; } }; From fbcd7c0c0659108624422bc845272fab775bdce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 30 Oct 2020 12:22:23 +0200 Subject: [PATCH 307/323] Update Connector/C --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index 8e5be108991..62427520a5b 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit 8e5be108991ffc29887660fd6540ed0fd3428d1b +Subproject commit 62427520a5ba20e42fe51f5045062a7a9cadb466 From 066773e2f0fec428713fff25091ecb27922b9d52 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 30 Oct 2020 11:46:12 +0100 Subject: [PATCH 308/323] after-merge fix: update the test to pass in --ps --- mysql-test/main/temp_table_symlink.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/main/temp_table_symlink.test b/mysql-test/main/temp_table_symlink.test index 35f956e8890..ea5f1dfa4de 100644 --- a/mysql-test/main/temp_table_symlink.test +++ b/mysql-test/main/temp_table_symlink.test @@ -12,9 +12,9 @@ chdir "$ENV{MYSQL_TMP_DIR}/mysqld.1/"; for (<#sql*.MYI>) { /^(#sql-temptable-[0-9a-f]+)(-[0-9a-f]+-)([0-9a-f]+)\.MYI$/ or die $_; symlink "$ENV{datadir}/test/d1.MYI", sprintf "$1$2%x.MYI", hex($3)+1; - symlink "$ENV{datadir}/test/d1.MYI", sprintf "$1$2%x.MAI", hex($3)+1; symlink "$ENV{datadir}/test/d1.MYI", sprintf "$1$2%x.MAI", hex($3)+2; symlink "$ENV{datadir}/test/d1.MYI", sprintf "$1$2%x.MAI", hex($3)+3; + symlink "$ENV{datadir}/test/d1.MYI", sprintf "$1$2%x.MAI", hex($3)+4; symlink "$ENV{datadir}/test/d1.MYI", "$1-0.MAI"; } EOF From 72eea39d4c4a8bcadccfdac457e61abc7b618ff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 30 Oct 2020 12:58:16 +0200 Subject: [PATCH 309/323] MDEV-23991 fixup: Initialize the memory This regression was introduced in commit afc9d00c66db946c8240fe1fa6b345a3a8b6fec1. This is a partial backport of commit 199863d72b7cccaa4c75641c50c45a83b568ab8c from 10.4. --- storage/innobase/dict/dict0stats.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index bf2645fd65c..f8a4cebfb16 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -2249,6 +2249,9 @@ dict_stats_update_persistent( } ut_ad(!dict_index_is_ibuf(index)); + mutex_enter(&dict_sys->mutex); + dict_stats_empty_index(index, false); + mutex_exit(&dict_sys->mutex); index_stats_t stats = dict_stats_analyze_index(index); From cb253b8687092960287c333962d56771f6ad9db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 30 Oct 2020 13:07:42 +0200 Subject: [PATCH 310/323] MDEV-22387: Static_binary_string::q_append() invokes memcpy on NULL Invoking memcpy() on a NULL pointer is undefined behaviour (even if the length is 0) and gives the compiler permission to assume that the pointer is nonnull. Recent versions of GCC (starting with version 8) are more aggressively optimizing away checks for NULL pointers. This undefined behaviour would cause a SIGSEGV in the test main.func_encrypt on an optimized debug build on GCC 10.2.0. --- sql/sql_string.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/sql_string.h b/sql/sql_string.h index 85c3bbd6044..0098ad15cb6 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -313,7 +313,8 @@ public: } void q_append(const char *data, size_t data_len) { - memcpy(Ptr + str_length, data, data_len); + if (data_len) + memcpy(Ptr + str_length, data, data_len); DBUG_ASSERT(str_length <= UINT_MAX32 - data_len); str_length += (uint)data_len; } From 5b3be9e1c657c3e44377d3c236ff2c31a04adeee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 30 Oct 2020 13:18:41 +0200 Subject: [PATCH 311/323] Try to stabilize main.innodb_ext_key,off Thanks to Varun Gupta for suggesting this. This seems to make main.innodb_ext_key,off more stable. --- mysql-test/main/innodb_ext_key,off.rdiff | 2 ++ mysql-test/main/innodb_ext_key.result | 6 +++--- mysql-test/main/innodb_ext_key.test | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/mysql-test/main/innodb_ext_key,off.rdiff b/mysql-test/main/innodb_ext_key,off.rdiff index 2164c56c5b5..f4eaa4b112c 100644 --- a/mysql-test/main/innodb_ext_key,off.rdiff +++ b/mysql-test/main/innodb_ext_key,off.rdiff @@ -1,3 +1,5 @@ +--- innodb_ext_key.result ++++ innodb_ext_key,off.result @@ -9,7 +9,7 @@ explain select count(*) from lineitem where l_orderkey=130 and l_shipdate='1992-07-01'; diff --git a/mysql-test/main/innodb_ext_key.result b/mysql-test/main/innodb_ext_key.result index dbc201be669..7cc03bee546 100644 --- a/mysql-test/main/innodb_ext_key.result +++ b/mysql-test/main/innodb_ext_key.result @@ -26,12 +26,12 @@ Handler_read_rnd 0 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 explain -select count(*) from lineitem +select count(*) from lineitem use index(primary) where l_orderkey=130 and l_linenumber=2 and l_shipdate='1992-07-01'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE lineitem const PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity PRIMARY 8 const,const 1 +1 SIMPLE lineitem const PRIMARY PRIMARY 8 const,const 1 flush status; -select count(*) from lineitem +select count(*) from lineitem use index(primary) where l_orderkey=130 and l_linenumber=2 and l_shipdate='1992-07-01'; count(*) 1 diff --git a/mysql-test/main/innodb_ext_key.test b/mysql-test/main/innodb_ext_key.test index 9ca9bbd608f..413d5570be5 100644 --- a/mysql-test/main/innodb_ext_key.test +++ b/mysql-test/main/innodb_ext_key.test @@ -17,6 +17,7 @@ use dbt3_s001; --disable_result_log --disable_warnings --source include/dbt3_s001.inc +ANALYZE TABLE lineitem PERSISTENT FOR COLUMNS() INDEXES(); --enable_warnings --enable_result_log --enable_query_log @@ -28,10 +29,10 @@ select count(*) from lineitem where l_orderkey=130 and l_shipdate='1992-07-01'; show status like 'handler_read%'; explain -select count(*) from lineitem +select count(*) from lineitem use index(primary) where l_orderkey=130 and l_linenumber=2 and l_shipdate='1992-07-01'; flush status; -select count(*) from lineitem +select count(*) from lineitem use index(primary) where l_orderkey=130 and l_linenumber=2 and l_shipdate='1992-07-01'; show status like 'handler_read%'; From 1fddccf676e213f94923f5efaaa76d9793b19a89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 30 Oct 2020 13:26:58 +0200 Subject: [PATCH 312/323] Update Connector/C --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index 0cdc1656a70..62427520a5b 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit 0cdc1656a70c52103b4329debf9ed02ccacfb3c2 +Subproject commit 62427520a5ba20e42fe51f5045062a7a9cadb466 From b0ff791618d97487fb7515d3f785b37f46eba132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 30 Oct 2020 19:06:50 +0200 Subject: [PATCH 313/323] MDEV-24054 Assertion in_LRU_list failed in buf_flush_try_neighbors() buf_flush_try_neighbors(): Before invoking buf_page_t::ready_for_flush(), check that the freshly looked up buf_pool.page_hash entry actually is a buffer page and not a buf_pool.watch[] sentinel for purge buffering. This race condition was introduced in MDEV-15053 (commit b1ab211dee599eabd9a5b886fafa3adea29ae041). It is rather hard to hit this bug, because buf_flush_check_neighbors() already checked the condition. The problem exists if buf_pool.watch_set() was invoked for a page in the range after the check in buf_flush_check_neighbor() had been finished. --- storage/innobase/buf/buf0flu.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index cc2f4c36fa4..ac6c45deeab 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -1106,7 +1106,8 @@ static ulint buf_flush_try_neighbors(fil_space_t *space, because the flushed blocks are soon freed */ if (!lru || id == page_id || bpage->is_old()) { - if (bpage->ready_for_flush() && buf_flush_page(bpage, lru, space)) + if (!buf_pool.watch_is_sentinel(*bpage) && + bpage->ready_for_flush() && buf_flush_page(bpage, lru, space)) { ++count; continue; From 95fcd567bdc4f9cdbe6b75ea6047982500b45c2f Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Mon, 2 Nov 2020 04:15:13 +0200 Subject: [PATCH 314/323] List of unstable tests for 10.5.7 release --- mysql-test/unstable-tests | 872 +++++++++++++++++--------------------- 1 file changed, 387 insertions(+), 485 deletions(-) diff --git a/mysql-test/unstable-tests b/mysql-test/unstable-tests index 67d4c2ae736..8536f7fba3f 100644 --- a/mysql-test/unstable-tests +++ b/mysql-test/unstable-tests @@ -23,238 +23,199 @@ # ############################################################################## # -# Based on bb-10.5-release 91c3c9efc192ac0ec2ec32fa801bdc0cb236ab5e -# Thu Aug 6 17:55:22 2020 +0200 - Merge branch '10.4' into 10.5 +# Based on 10.5 8e1e2856f2523c225a81840059e93fa9f61fbacf -main.alter_table : Modified in 10.5.4 +main.alter_table : Modified in 10.5.7 +main.alter_table_mdev539_maria : MDEV-23922 - Timeout or crash main.alter_table_trans : MDEV-12084 - timeout main.analyze_stmt_slow_query_log : MDEV-12237 - Wrong result +main.aria_icp_debug : Added in 10.5.7 main.auth_named_pipe : MDEV-14724 - System error 2 -main.backup_lock : Modified in 10.5.4 -main.backup_stages : MDEV-23401 - Bad file descriptor; modified in 10.5.4 +main.backup_locks : Modified in 10.5.7 +main.backup_stages : MDEV-23401 - Bad file descriptor main.binary_to_hex : MDEV-20211 - Wrong result -main.comment_table : Modified in 10.5.4 -main.commit_1innodb : Include file modified in 10.5.4 +main.blackhole : Modified in 10.5.7 +main.bootstrap_innodb : Added in 10.5.7 +main.client_xml : MDEV-24085 - Wrong result +main.column_compression : MDEV-23954 - Wrong result main.connect : MDEV-17282 - Wrong result main.connect-abstract : MDEV-20162 - Could not execute 'check-testcase' main.connect2 : MDEV-13885 - Server crash main.count_distinct2 : MDEV-11768 - timeout -main.create : Modified in 10.5.5 main.create_delayed : MDEV-10605 - failed with timeout main.create_drop_event : MDEV-16271 - Wrong result -main.create_drop_function : Modified in 10.5.5 -main.create_drop_view : Modified in 10.5.4 main.create_or_replace : MDEV-22954 - Wrong result -main.cte_recursive : Modified in 10.5.4 -main.ctype_big5 : Modified in 10.5.4 -main.ctype_binary : Modified in 10.5.4 -main.ctype_cp932 : Modified in 10.5.4 +main.ctype_binary : MDEV-24080 - Data too long for column; include file modified in 10.5.7 +main.ctype_cp1251 : Include file modified in 10.5.7 main.ctype_cp932_binlog_row : MDEV-20540 - Wrong result main.ctype_cp932_binlog_stm : MDEV-20534 - Wrong result -main.ctype_dec8 : Added in 10.5.4 -main.ctype_eucjpms : Modified in 10.5.4 -main.ctype_euckr : Modified in 10.5.4 -main.ctype_filename : Modified in 10.5.4 -main.ctype_gb2312 : Modified in 10.5.4 -main.ctype_gbk : Modified in 10.5.4 -main.ctype_ldml : Modified in 10.5.5 -main.ctype_sjis : Modified in 10.5.4 -main.ctype_swe7 : Modified in 10.5.4 -main.ctype_ucs : MDEV-17681 - Data too long for column +main.ctype_filename : Modified in 10.5.7 +main.ctype_latin1 : Include file modified in 10.5.7 +main.ctype_ucs : MDEV-17681 - Data too long for column; include file modified in 10.5.7 main.ctype_upgrade : MDEV-16945 - Error upon mysql_upgrade -main.ctype_utf16 : MDEV-10675 - Timeout or extra warnings; modified in 10.5.4 -main.ctype_utf16_uca : Modified in 10.5.4 -main.ctype_utf16le : MDEV-10675 - Timeout or extra warnings; modified in 10.5.4 -main.ctype_utf32 : Modified in 10.5.4 -main.ctype_utf32_uca : Modified in 10.5.4 -main.ctype_utf8 : Modified in 10.5.4 -main.ctype_utf8mb4 : Modified in 10.5.4 -main.ctype_utf8mb4_heap : Include file modified in 10.5.4 -main.ctype_utf8mb4_innodb : MDEV-17744 - Timeout; MDEV-18567 - ASAN use-after-poison; include file modified in 10.5.4 -main.ctype_utf8mb4_myisam : Include file modified in 10.5.4 -main.custom_aggregate_functions : Modified in 10.5.4 +main.ctype_utf16 : MDEV-10675 - Timeout or extra warnings +main.ctype_utf16le : MDEV-10675 - Timeout or extra warnings +main.ctype_utf8 : Modified in 10.5.7 +main.ctype_utf8mb4_innodb : MDEV-17744 - Timeout; MDEV-18567 - ASAN use-after-poison main.debug_sync : MDEV-10607 - internal error main.delayed : MDEV-20961 - Assertion failure -main.delete_innodb : Added in 10.5.5 main.derived_cond_pushdown : MDEV-20532 - Floating point differences main.derived_opt : MDEV-11768 - timeout main.dirty_close : MDEV-19368 - mysqltest failed but provided no output main.distinct : MDEV-14194 - Crash -main.drop : Modified in 10.5.5 main.drop_bad_db_type : MDEV-15676 - Wrong result -main.drop_combinations : Added in 10.5.4 -main.drop_table_force : Modified in 10.5.5 +main.drop_table_force : Modified in 10.5.7 main.dyncol : MDEV-19455 - Extra warning +main.errors : Modified in 10.5.7 main.events_2 : MDEV-13277 - Crash main.events_bugs : MDEV-12892 - Crash main.events_restart : MDEV-12236 - Server shutdown problem main.events_slowlog : MDEV-12821 - Wrong result +main.failed_auth_unixsocket : MDEV-23933 - Access denied +main.fast_prefix_index_fetch_innodb : Modified in 10.5.7 main.flush : MDEV-19368 - mysqltest failed but provided no output -main.flush_read_lock : MDEV-22953 - Unknown XID; modified in 10.5.4 +main.flush_block_commit_notembedded : MDEV-23974 - InnoDB error +main.flush_read_lock : MDEV-22953 - Unknown XID main.flush_ssl : MDEV-21276 - Aria recovery failure -main.func_bit : Added in 10.5.4 -main.func_des_encrypt : Modified in 10.5.5 -main.func_gconcat : Modified in 10.5.4 -main.func_json : Modified in 10.5.5 -main.func_math : MDEV-20966 - Wrong error code; modified in 10.5.4 -main.gis : MDEV-13411 - wrong result on P8; modified in 10.5.4 +main.func_gconcat : MDEV-21379 - Valgrind warnings +main.func_json : Modified in 10.5.7 +main.func_math : MDEV-20966 - Wrong error code; modified in 10.5.7 +main.func_test : Modified in 10.5.7 +main.gis : MDEV-13411 - wrong result on P8 main.gis_notembedded : MDEV-21264 - Wrong result with non-default charset -main.grant : Modified in 10.5.4 -main.grant5 : Modified in 10.5.5 +main.grant : Modified in 10.5.7 +main.grant5 : Modified in 10.5.7 +main.grant_kill : MDEV-23915 - Wrong result main.having : MDEV-23420 - Server crash main.host_cache_size_functionality : MDEV-10606 - sporadic failure on shutdown -main.index_intersect_innodb : MDEV-10643 - failed with timeout -main.index_merge_innodb : MDEV-7142 - Plan mismatch; modified in 10.5.4 -main.information_schema : Modified in 10.5.5 -main.information_schema_all_engines : MDEV-23421 - Wrong result; configuration modified in 10.5.5 -main.information_schema_db : Modified in 10.5.4 -main.innodb_ext_key : Modified in 10.5.4 +main.implicit_commit : Modified in 10.5.7 +main.index_intersect : MDEV-23921 - Wrong result +main.index_intersect_innodb : MDEV-23921 - Wrong result; MDEV-10643 - failed with timeout +main.index_merge_innodb : MDEV-7142 - Plan mismatch +main.information_schema : Modified in 10.5.7 +main.information_schema_all_engines : MDEV-23421 - Wrong result +main.innodb_ext_key : Modified in 10.5.7 main.innodb_icp : MDEV-20168 - Wrong execution plans -main.innodb_mrr_cpk : MDEV-23370 - Server crash +main.innodb_icp_debug : Added in 10.5.7 +main.invisible_field : Modified in 10.5.7 main.invisible_field_grant_completely : MDEV-22254 - Syscall param write points to uninitialised bytes main.ipv4_and_ipv6 : MDEV-20964 - Wrong result main.ipv6 : MDEV-20964 - Wrong result main.join_cache : MDEV-17743 - Bad address from storage engine MyISAM -main.join_outer : Modified in 10.5.5 -main.kill : Modified in 10.5.4 -main.kill-2 : MDEV-13257 - Wrong result; modified in 10.5.4 +main.kill : Modified in 10.5.7 +main.kill-2 : MDEV-13257 - Wrong result main.kill_processlist-6619 : MDEV-10793 - Wrong result +main.limit_rows_examined : Modified in 10.5.7 main.loaddata : MDEV-19368 - mysqltest failed but provided no output main.locale : MDEV-20521 - Missing warning -main.lock : Modified in 10.5.4 +main.lock_view : Added in 10.5.7 main.log_slow : MDEV-13263 - Wrong result -main.log_tables : Modified in 10.5.5 +main.log_tables : Modified in 10.5.7 main.log_tables-big : MDEV-13408 - wrong result main.log_tables_upgrade : MDEV-20962 - Wrong result -main.long_unique_bugs : Modified in 10.5.4 -main.long_unique_bugs_replication : Added in 10.5.4 -main.lowercase_fs_off : Modified in 10.5.5 -main.mdev-21101 : Added in 10.5.5 main.mdev-504 : MDEV-15171 - warning main.mdev375 : MDEV-10607 - sporadic "can't connect" -main.mdev_22370 : Added in 10.5.4 -main.mdl : MDEV-22954 - Wrong result; modified in 10.5.5 +main.mdl : MDEV-22954 - Wrong result main.merge : MDEV-10607 - sporadic "can't connect" -main.myisampack : Modified in 10.5.4 +main.multi_update_big : Modified in 10.5.7 +main.myisam_icp_debug : Added in 10.5.7 +main.myisam_icp_notembedded : MDEV-23420 - Server crash main.mysql : MDEV-20156 - Wrong result main.mysql_client_test : MDEV-19369 - error: 5888, status: 23, errno: 2; MDEV-19511 - Big endian issue main.mysql_client_test_comp : MDEV-16641 - Error in exec main.mysql_client_test_nonblock : CONC-208 - Error on Power; MDEV-15096 - exec failed main.mysql_cp932 : MDEV-21275 - Wrong result -main.mysql_install_db_win : Modified in 10.5.5 -main.mysql_upgrade : MDEV-20161 - Wrong result; MDEV-20166 - FATAL ERROR: Upgrade failed; modified in 10.5.5 +main.mysql_json_table_recreate : Added in 10.5.7 +main.mysql_upgrade : MDEV-20161 - Wrong result; MDEV-20166 - FATAL ERROR: Upgrade failed; modified in 10.5.7 main.mysql_upgrade-6984 : MDEV-22514 - Wrong result +main.mysql_upgrade_mysql_json_datatype : Added in 10.5.7 main.mysql_upgrade_no_innodb : MDEV-20537 - Wrong result main.mysql_upgrade_noengine : MDEV-14355 - Wrong result main.mysql_upgrade_view : MDEV-23392 - Wrong result; MDEV-20161 - Wrong result main.mysqladmin : MDEV-20535 - Wrong result main.mysqlbinlog_row_compressed : MDEV-22964 - Wrong result +main.mysqlbinlog_row_minimal : Modified in 10.5.7 main.mysqlcheck : MDEV-20164 - Wrong result -main.mysqld--help-aria : Modified in 10.5.5 +main.mysqld--help : Modified in 10.5.7 main.mysqld_option_err : MDEV-21236 - Wrong error; MDEV-21571 - Crash on bootstrap -main.mysqldump : MDEV-14800 - Stack smashing detected +main.mysqldump : MDEV-14800 - Stack smashing detected; modified in 10.5.7 main.mysqldump-max : MDEV-21272 - Wrong result main.mysqlhotcopy_myisam : MDEV-10995 - Hang on debug -main.mysqlshow : MDEV-20965 - Wrong result; modified in 10.5.4 +main.mysqlshow : MDEV-20965 - Wrong result main.mysqlslap : MDEV-11801 - timeout main.mysqltest : MDEV-13887 - Wrong result -main.mysqltest_tracking_info : Modified in 10.5.5 -main.named_pipe : MDEV-23279 - Test timeouts; modified in 10.5.4 -main.nested_profiling : Added in 10.5.5 +main.named_pipe : Modified in 10.5.7 main.old-mode : MDEV-19373 - Wrong result main.openssl_6975 : MDEV-17184 - Failures with OpenSSL 1.1.1 -main.opt_trace : Modified in 10.5.5 -main.order_by : Modified in 10.5.5 +main.opt_trace : Modified in 10.5.7 +main.order_by : Modified in 10.5.7 main.order_by_optimizer_innodb : MDEV-10683 - Wrong result -main.parser : Modified in 10.5.5 -main.partition : Modified in 10.5.5 -main.partition_alter : Modified in 10.5.4 +main.parser : Modified in 10.5.7 +main.partition : Modified in 10.5.7 main.partition_debug_sync : MDEV-15669 - Deadlock found when trying to get lock -main.partition_explicit_prune : Modified in 10.5.5 -main.partition_innodb : MDEV-20169 - Wrong result +main.partition_innodb : MDEV-20169 - Wrong result; MDEV-23427 - Server crash main.partition_innodb_plugin : MDEV-12901 - Valgrind warnings main.partition_innodb_semi_consistent : MDEV-19411 - Failed to start mysqld.1 -main.percona_nonflushing_analyze_debug : Added in 10.5.4 -main.plugin : Modified in 10.5.5 main.plugin_auth : MDEV-20957 - Upgrade file was not properly created main.plugin_auth_qa_2 : MDEV-20165 - Wrong result -main.pool_of_threads : MDEV-18135 - SSL error: key too small -main.processlist_notembedded : Modified in 10.5.4 -main.ps : MDEV-11017 - sporadic wrong Prepared_stmt_count; modified in 10.5.4 -main.query_cache : MDEV-16180 - Wrong result; modified in 10.5.4 +main.plugin_innodb : Modified in 10.5.7 +main.pool_of_threads : MDEV-18135 - SSL error: key too small; modified in 10.5.7 +main.precedence : Added in 10.5.7 +main.precedence_bugs : Added in 10.5.7 +main.processlist_notembedded : Modified in 10.5.7 +main.ps : MDEV-11017 - sporadic wrong Prepared_stmt_count +main.ps_error : MDEV-24079 - Memory not freed +main.query_cache : MDEV-16180 - Wrong result main.query_cache_debug : MDEV-15281 - Query cache is disabled +main.range : Modified in 10.5.7 main.range_innodb : MDEV-23371 - Server crash main.range_vs_index_merge_innodb : MDEV-15283 - Server has gone away -main.repair : Modified in 10.5.4 -main.row : Modified in 10.5.4 +main.repair_symlink-5543 : MDEV-23920 - Wrong result +main.rowid_filter : Modified in 10.5.7 main.rowid_filter_innodb : MDEV-20538 - Wrong result main.rowid_filter_innodb_debug : Added in 10.5.7 -main.rowid_filter_myisam : Added in 10.5.5 +main.rowid_filter_myisam_debug : Added in 10.5.7 main.select : MDEV-20532 - Floating point differences main.select_jcl6 : MDEV-20532 - Floating point differences main.select_pkeycache : MDEV-20532 - Floating point differences -main.selectivity : Modified in 10.5.4 main.set_statement : MDEV-13183 - Wrong result -main.set_statement_notembedded : MDEV-19414 - Wrong result +main.set_statement_notembedded : MDEV-19414 - Wrong result; modified in 10.5.7 main.shm : MDEV-12727 - Mismatch, ERROR 2013 main.show_explain : MDEV-10674 - Wrong result code -main.signal : Modified in 10.5.5 -main.sp : MDEV-7866 - Mismatch; modified in 10.5.5 -main.sp-error : Modified in 10.5.5 -main.sp-security : MDEV-10607 - sporadic "can't connect"; modified in 10.5.4 -main.sp-vars : Modified in 10.5.4 -main.sp2 : Added in 10.5.4 +main.sp : MDEV-7866 - Mismatch; modified in 10.5.7 +main.sp-destruct : Modified in 10.5.7 +main.sp-security : MDEV-10607 - sporadic "can't connect" main.sp_notembedded : MDEV-10607 - internal error main.ssl : MDEV-17184 - Failures with OpenSSL 1.1.1 main.ssl_7937 : MDEV-20958 - Wrong result main.ssl_ca : MDEV-10895 - SSL connection error on Power main.ssl_cipher : MDEV-17184 - Failures with OpenSSL 1.1.1 main.ssl_timeout : MDEV-11244 - Crash -main.stat_tables_innodb : Modified in 10.5.5 main.stat_tables_par_innodb : MDEV-14155 - Wrong rounding -main.stat_tables_partition : Modified in 10.5.5 main.status : MDEV-13255 - Wrong result -main.status_bug17954 : Modified in 10.5.4 main.subselect : MDEV-20551 - Valgrind failure -main.subselect4 : Modified in 10.5.5 -main.subselect_exists2in : Modified in 10.5.5 -main.subselect_innodb : MDEV-10614 - Wrong result -main.table_value_constr : Modified in 10.5.4 +main.subselect4 : Modified in 10.5.7 +main.subselect_innodb : MDEV-10614 - Wrong result; modified in 10.5.7 +main.sum_distinct-big : Modified in 10.5.7 main.tc_heuristic_recover : MDEV-14189 - Wrong result -main.temp_table : Modified in 10.5.5 +main.temp_table_symlink : MDEV-24058 - Wrong error code; added in 10.5.7 main.tls_version : MDEV-23417 - Wrong result -main.type_bit : Modified in 10.5.5 -main.type_blob : MDEV-15195 - Wrong result -main.type_date : Modified in 10.5.5 -main.type_datetime : Modified in 10.5.4 -main.type_datetime_hires : MDEV-10687 - Timeout; modified in 10.5.5 -main.type_enum : Modified in 10.5.5 -main.type_float : MDEV-20532 - Floating point differences; modified in 10.5.5 -main.type_hex_hybrid : Modified in 10.5.5 -main.type_int : Modified in 10.5.5 -main.type_newdecimal : MDEV-20532 - Floating point differences +main.type_blob : MDEV-15195 - Wrong result; modified in 10.5.7 +main.type_date : Modified in 10.5.7 +main.type_datetime : Modified in 10.5.7 +main.type_datetime_hires : MDEV-10687 - Timeout +main.type_float : MDEV-20532 - Floating point differences; modified in 10.5.7 +main.type_newdecimal : MDEV-20532 - Floating point differences; modified in 10.5.7 main.type_ranges : MDEV-20532 - Floating point differences -main.type_set : Modified in 10.5.5 -main.type_temporal_innodb : Modified in 10.5.5 -main.type_time : Modified in 10.5.4 -main.type_time_hires : Modified in 10.5.5 -main.type_timestamp : Modified in 10.5.4 -main.type_timestamp_hires : Modified in 10.5.5 -main.type_year : Modified in 10.5.5 -main.udf : Modified in 10.5.4 -main.union : Modified in 10.5.5 -main.upgrade_MDEV-19650 : Modified in 10.5.5 -main.upgrade_MDEV-23102-1 : Added in 10.5.5 -main.upgrade_MDEV-23102-2 : Added in 10.5.5 +main.type_temporal_innodb : MDEV-24025 - Wrong result +main.type_time : Modified in 10.5.7 +main.udf : Modified in 10.5.7 main.userstat : MDEV-12904 - SSL errors -main.view : Modified in 10.5.4 +main.view : Modified in 10.5.7 main.wait_timeout : MDEV-19023 - Lost connection to MySQL server during query -main.warnings_debug : Modified in 10.5.4 -main.win : Modified in 10.5.5 -main.win_ntile : Modified in 10.5.5 -main.win_percentile : Modified in 10.5.4 -main.xa : MDEV-11769 - lock wait timeout; modified in 10.5.4 -main.xa_binlog : Modified in 10.5.4 +main.win : Modified in 10.5.7 +main.windows_debug : Added in 10.5.7 +main.xa : MDEV-11769 - lock wait timeout main.xml : MDEV-21968 - Crash on armhf #----------------------------------------------------------------------- @@ -271,34 +232,30 @@ archive-test_sql_discovery.discover : MDEV-16817 - Table marked as crashed #----------------------------------------------------------------------- -binlog.binlog_base64_flag : Modified in 10.5.4 -binlog.binlog_commit_wait : MDEV-10150 - Mismatch -binlog.binlog_drop_if_exists : Modified in 10.5.4 -binlog.binlog_empty_xa_prepared : Added in 10.5.5 -binlog.binlog_innodb : MDEV-22516 - Wrong result -binlog.binlog_invalid_read_in_rotate : MDEV-22455 - Server crash -binlog.binlog_ioerr : MDEV-20159 - Assertion failure -binlog.binlog_killed : MDEV-12925 - Wrong result -binlog.binlog_max_extension : MDEV-19762 - Crash on shutdown -binlog.binlog_mixed : Added in 10.5.4 -binlog.binlog_mysqlbinlog_row_frag : Modified in 10.5.4 -binlog.binlog_mysqlbinlog_row_innodb : MDEV-20530 - Binary files differ -binlog.binlog_mysqlbinlog_row_myisam : MDEV-20530 - Binary files differ -binlog.binlog_no_uniqfile_crash : Added in 10.5.4 -binlog.binlog_parallel_replication_marks_row : Include file modified in 10.5.5 -binlog.binlog_parallel_replication_marks_stm_mix : Include file modified in 10.5.5 -binlog.binlog_row_binlog : MDEV-23402 - Wrong result; include file modified in 10.5.4 -binlog.binlog_show_binlog_event_random_pos : MDEV-22473 - Server crash -binlog.binlog_stm_binlog : MDEV-20412 - Wrong result; include file modified in 10.5.4 -binlog.binlog_xa_recover : MDEV-8517 - Extra checkpoint -binlog.flashback-largebinlog : MDEV-19764 - Out of memory -binlog.load_data_stm_view : MDEV-16948 - Wrong result -binlog.show_concurrent_rotate : MDEV-20215 - Wrong result +binlog.binlog_commit_wait : MDEV-10150 - Mismatch +binlog.binlog_innodb : MDEV-22516 - Wrong result +binlog.binlog_ioerr : MDEV-20159 - Assertion failure +binlog.binlog_killed : MDEV-12925 - Wrong result +binlog.binlog_max_extension : MDEV-19762 - Crash on shutdown +binlog.binlog_mysqlbinlog_row : Modified in 10.5.7 +binlog.binlog_mysqlbinlog_row_frag : Modified in 10.5.7 +binlog.binlog_mysqlbinlog_row_innodb : MDEV-20530 - Binary files differ +binlog.binlog_mysqlbinlog_row_myisam : MDEV-20530 - Binary files differ +binlog.binlog_no_uniqfile_crash : MDEV-24078 - Server crash upon shutdown +binlog.binlog_recover_checksum_error : Added in 10.5.7 +binlog.binlog_row_binlog : MDEV-23402 - Wrong result +binlog.binlog_show_binlog_event_random_pos : Modified in 10.5.7 +binlog.binlog_stm_binlog : MDEV-20412 - Wrong result +binlog.binlog_stm_mix_innodb_myisam : MDEV-24057 - Wrong result +binlog.binlog_xa_recover : MDEV-8517 - Extra checkpoint +binlog.flashback-largebinlog : MDEV-19764 - Out of memory +binlog.load_data_stm_view : MDEV-16948 - Wrong result +binlog.show_concurrent_rotate : MDEV-20215 - Wrong result #----------------------------------------------------------------------- binlog_encryption.binlog_xa_recover : MDEV-12908 - Extra checkpoint -binlog_encryption.encrypted_master : MDEV-14201 - Extra warnings +binlog_encryption.encrypted_master : MDEV-23905 - Failure upon post-check; MDEV-23637 - Assertion failure; MDEV-14201 - Extra warnings binlog_encryption.encrypted_master_switch_to_unencrypted : MDEV-14190 - Can't init tc log binlog_encryption.encrypted_slave : MDEV-18135 - SSL error: key too small binlog_encryption.encryption_combo : MDEV-14199 - Table is marked as crashed @@ -312,6 +269,7 @@ binlog_encryption.rpl_loadfile : MDEV-16645 - Timeou binlog_encryption.rpl_mixed_binlog_max_cache_size : MDEV-20956 - Incorrect checksum for freed object binlog_encryption.rpl_parallel : MDEV-10653 - Timeout in include binlog_encryption.rpl_parallel_ignored_errors : MDEV-22471 - Slave crash +binlog_encryption.rpl_parallel_stop_on_con_kill : MDEV-24086 - Timeout binlog_encryption.rpl_relayrotate : MDEV-15194 - Timeout binlog_encryption.rpl_semi_sync : MDEV-11673 - Valgrind binlog_encryption.rpl_skip_replication : MDEV-13571 - Unexpected warning; MDEV-20573 - Wrong result @@ -323,21 +281,8 @@ binlog_encryption.rpl_typeconv : MDEV-14362 - Lost c #----------------------------------------------------------------------- -columnstore.* : Engine enabled in 10.5.4 - -#----------------------------------------------------------------------- - -compat/maxdb.rpl_mariadb_timestamp : Added in 10.5.5 -compat/maxdb.type_timestamp : Added in 10.5.5 - -#----------------------------------------------------------------------- - -compat/oracle.binlog_ptr_mysqlbinlog : Added in 10.5.5 -compat/oracle.parser : Modified in 10.5.4 -compat/oracle.rpl_mariadb_date : Added in 10.5.5 -compat/oracle.sp : Modified in 10.5.5 -compat/oracle.sp-cursor-rowtype : Modified in 10.5.5 -compat/oracle.type_date : Modified in 10.5.5 +compat/oracle.parser : Modified in 10.5.7 +compat/oracle.sp-package : Modified in 10.5.7 #----------------------------------------------------------------------- @@ -348,7 +293,7 @@ connect.part_file : MDEV-18135 - SSL error: key too small connect.part_table : MDEV-18135 - SSL error: key too small connect.pivot : MDEV-14803 - Failed to discover table connect.secure_file_priv : MDEV-18135 - SSL error: key too small -connect.type_inet6 : Added in 10.5.4 +connect.updelx : Modified in 10.5.7 connect.vcol : MDEV-12374 - Fails on Windows connect.zip : MDEV-13884 - Wrong result @@ -358,8 +303,9 @@ disks.disks_notembedded : MDEV-21587 - Wrong result #----------------------------------------------------------------------- -encryption.corrupted_during_recovery : MDEV-20159 - Assertion failure; modified in 10.5.4 -encryption.create_or_replace : MDEV-16115 - Trying to access tablespace +encryption.corrupted_during_recovery : MDEV-20159 - Assertion failure +encryption.create_or_replace : MDEV-24081 - Lock wait timeout exceeded; modified in 10.5.7 +encryption.create_or_replace_big : Added in 10.5.7 encryption.debug_key_management : MDEV-13841 - Timeout encryption.encrypt_and_grep : MDEV-13765 - Wrong result encryption.innochecksum : MDEV-13644 - Assertion failure @@ -371,26 +317,27 @@ encryption.innodb-first-page-read : MDEV-14356 - Timeout in wait encryption.innodb-force-corrupt : MDEV-17286 - SSL error encryption.innodb-missing-key : MDEV-14728 - SSL error encryption.innodb-page_encryption : MDEV-10641 - mutex problem -encryption.innodb-page_encryption_log_encryption : MDEV-17339 - Crash on restart +encryption.innodb-page_encryption_compression : Modified in 10.5.7 +encryption.innodb-page_encryption_log_encryption : MDEV-17339 - Crash on restart; modified in 10.5.7 encryption.innodb-read-only : MDEV-16563 - Crash on startup -encryption.innodb-redo-badkey : Modified in 10.5.4 +encryption.innodb-redo-badkey : MDEV-12898 - Server hang on startup encryption.innodb-redo-nokeys : MDEV-20159 - Assertion failure -encryption.innodb-remove-encryption : MDEV-16493 - Timeout in wait condition +encryption.innodb-remove-encryption : MDEV-16493 - Timeout in wait condition; modified in 10.5.7 encryption.innodb-spatial-index : MDEV-13746 - Wrong result -encryption.innodb_encrypt_key_rotation_age : MDEV-19763 - Timeout +encryption.innodb_encrypt_key_rotation_age : MDEV-19763 - Timeout; modified in 10.5.7 encryption.innodb_encrypt_log : MDEV-13725 - Wrong result encryption.innodb_encrypt_log_corruption : MDEV-14379 - Server crash -encryption.innodb_encrypt_temporary_tables : MDEV-20142 - Wrong result; modified in 10.5.5 +encryption.innodb_encrypt_temporary_tables : MDEV-20142 - Wrong result encryption.innodb_encryption : MDEV-14728 - Unable to get certificate; MDEV-15675 - Timeout encryption.innodb_encryption-page-compression : MDEV-12630 - Crash or assertion failure; MDEV-21843 - Assertion failure -encryption.innodb_encryption_discard_import : MDEV-16116 - Wrong result +encryption.innodb_encryption_discard_import : MDEV-16116 - Wrong result; configuration modified in 10.5.7 encryption.innodb_encryption_filekeys : MDEV-15673 - Timeout encryption.innodb_encryption_is : MDEV-12898 - Server hang on startup encryption.innodb_encryption_row_compressed : MDEV-16113 - Crash encryption.innodb_encryption_tables : MDEV-17339 - Crash on restart encryption.innodb_first_page : MDEV-10689 - Crash encryption.innodb_onlinealter_encryption : MDEV-17287 - SIGABRT on server restart -encryption.tempfiles_encrypted : Added in 10.5.4 +encryption.tempfiles_encrypted : Modified in 10.5.7 #----------------------------------------------------------------------- @@ -413,8 +360,7 @@ federated.federated_innodb : MDEV-10617 - Wrong checksum federated.federated_partition : MDEV-10417 - Fails on Mips federated.federated_transactions : MDEV-10617 - Wrong checksum federated.federatedx : MDEV-10617 - Wrong checksum -federated.federatedx_create_handlers : Modified in 10.5.5 -federated.federatedx_versioning : Modified in 10.5.4 +federated.federatedx_create_handlers : Modified in 10.5.7 #----------------------------------------------------------------------- @@ -441,57 +387,53 @@ galera_3nodes.* : Suite is not stable yet #----------------------------------------------------------------------- -gcol.gcol_bugfixes : Modified in 10.5.5 -gcol.gcol_purge : Added in 10.5.4 +gcol.gcol_keys_innodb : Include file modified in 10.5.7 +gcol.gcol_keys_myisam : Include file modified in 10.5.7 +gcol.gcol_partition_innodb : Include file modified in 10.5.7 +gcol.gcol_purge : Include file modified in 10.5.7 +gcol.gcol_update : Include file modified in 10.5.7 gcol.innodb_virtual_basic : MDEV-16950 - Failing assertion gcol.innodb_virtual_debug : MDEV-23404 - Server crash; MDEV-23112 - Server crash -gcol.innodb_virtual_debug_purge : MDEV-16952 - Wrong result +gcol.innodb_virtual_debug_purge : Include file modified in 10.5.7 +gcol.innodb_virtual_fk : MDEV-20640 - Assertion failure; modified in 10.5.7 gcol.innodb_virtual_fk_restart : MDEV-17466 - Assertion failure -gcol.innodb_virtual_purge : MDEV-22952 - Lock wait timeout +gcol.innodb_virtual_index : Modified in 10.5.7 +gcol.innodb_virtual_purge : MDEV-22952 - Lock wait timeout; include file modified in 10.5.7 gcol.main_alter_table : MDEV-23403 - Wrong result #----------------------------------------------------------------------- -handler.aria : Include file modified in 10.5.4 -handler.heap : Include file modified in 10.5.4 -handler.innodb : Modified in 10.5.4 -handler.myisam : Include file modified in 10.5.4 - -#----------------------------------------------------------------------- - -heap.drop : Added in 10.5.5 - -#----------------------------------------------------------------------- - innodb.101_compatibility : MDEV-13891 - Wrong result innodb.alter_copy : MDEV-16181 - Assertion failure -innodb.alter_crash : MDEV-16944 - The process cannot access the file; modified in 10.5.4 +innodb.alter_crash : MDEV-16944 - The process cannot access the file innodb.alter_large_dml : MDEV-20148 - Debug sync point wait timed out -innodb.alter_primary_key : Added in 10.5.5 -innodb.analyze_table : Modified in 10.5.4 +innodb.alter_table : Modified in 10.5.7 innodb.binlog_consistent : MDEV-10618 - Server fails to start innodb.blob-crash : MDEV-20481 - Crash during recovery -innodb.corrupted_during_recovery : Modified in 10.5.4 innodb.create-index : MDEV-20159 - Assertion failure -innodb.default_row_format_alter : Modified in 10.5.5 innodb.default_row_format_compatibility : MDEV-20159 - Assertion failure innodb.doublewrite : MDEV-12905 - Server crash -innodb.foreign_key : MDEV-21283 - Extra warning; modified in 10.5.4 +innodb.flush : Added in 10.5.7 +innodb.foreign-keys : Modified in 10.5.7 +innodb.foreign_key : MDEV-21283 - Extra warning; modified in 10.5.7 innodb.group_commit_crash : MDEV-14191 - InnoDB registration failed innodb.group_commit_crash_no_optimize_thread : MDEV-11770 - Checksum mismatch -innodb.ibuf_not_empty : MDEV-19021 - Wrong result -innodb.innodb : Modified in 10.5.5 +innodb.ibuf_not_empty : MDEV-19021 - Wrong result; modified in 10.5.7 +innodb.innodb : Modified in 10.5.7 innodb.innodb-32k-crash : MDEV-20194 - Extra warnings +innodb.innodb-64k : Modified in 10.5.7 innodb.innodb-64k-crash : MDEV-13872 - Failure and crash on startup -innodb.innodb-alter : MDEV-22955 - Extra warning; modified in 10.5.5 -innodb.innodb-alter-debug : MDEV-13182 - InnoDB: adjusting FSP_SPACE_FLAGS; modified in 10.5.4 +innodb.innodb-alter : MDEV-22955 - Extra warning +innodb.innodb-alter-debug : MDEV-13182 - InnoDB: adjusting FSP_SPACE_FLAGS innodb.innodb-alter-table : MDEV-10619 - Testcase timeout innodb.innodb-bigblob : MDEV-18655 - ASAN unknown crash innodb.innodb-blob : MDEV-12053 - Client crash -innodb.innodb-change-buffer-recovery : MDEV-19115 - Lost connection to MySQL server during query +innodb.innodb-change-buffer-recovery : MDEV-19115 - Lost connection to MySQL server during query; modified in 10.5.7 innodb.innodb-dict : MDEV-20159 - Assertion failure -innodb.innodb-fk : MDEV-13832 - Assertion failure on shutdown; modified in 10.5.4 +innodb.innodb-fk : MDEV-13832 - Assertion failure on shutdown innodb.innodb-get-fk : MDEV-13276 - Server crash +innodb.innodb-index : Include file modified in 10.5.7 +innodb.innodb-index-debug : Include file modified in 10.5.7 innodb.innodb-index-online : MDEV-14809 - Cannot save statistics innodb.innodb-page_compression_default : MDEV-13644 - Assertion failure innodb.innodb-page_compression_lzma : MDEV-14353 - Wrong result @@ -500,73 +442,73 @@ innodb.innodb-page_compression_tables : MDEV-13644 - Assertion failure innodb.innodb-page_compression_zip : MDEV-10641 - mutex problem innodb.innodb-table-online : MDEV-13894 - Wrong result innodb.innodb-timeout : MDEV-20159 - Assertion failure -innodb.innodb-ucs2 : MDEV-23370 - Server crash +innodb.innodb-trim : Modified in 10.5.7 innodb.innodb-wl5522 : MDEV-13644 - Assertion failure innodb.innodb-wl5522-1 : MDEV-22945 - Server crash -innodb.innodb-wl5522-debug : MDEV-14200 - Wrong errno +innodb.innodb-wl5522-debug : MDEV-14200 - Wrong errno; modified in 10.5.7 innodb.innodb_buffer_pool_dump_pct : MDEV-20139 - Timeout in wait_condition.inc innodb.innodb_buffer_pool_resize : MDEV-16964 - Assertion failure -innodb.innodb_buffer_pool_resize_debug : MDEV-22515 - Timeout in wait_condition; modified in 10.5.5 +innodb.innodb_buffer_pool_resize_debug : MDEV-22515 - Timeout in wait_condition innodb.innodb_buffer_pool_resize_with_chunks : MDEV-16964 - Assertion failure -innodb.innodb_bug14147491 : MDEV-11808 - Index is corrupt; modified in 10.5.4 +innodb.innodb_bug14147491 : MDEV-11808 - Index is corrupt innodb.innodb_bug30423 : MDEV-7311 - Wrong result innodb.innodb_bug47167 : MDEV-20524 - Table 'user' is marked as crashed and should be repaired innodb.innodb_bug48024 : MDEV-14352 - Assertion failure innodb.innodb_bulk_create_index_replication : MDEV-15273 - Slave failed to start -innodb.innodb_ctype_ldml : Modified in 10.5.5 innodb.innodb_defrag_stats_many_tables : MDEV-14198 - Table is full -innodb.innodb_force_recovery : Modified in 10.5.4 -innodb.innodb_force_recovery_rollback : MDEV-22889 - Wrong result; modified in 10.5.5 +innodb.innodb_force_recovery_rollback : MDEV-22889 - Wrong result innodb.innodb_information_schema : MDEV-8851 - Wrong result -innodb.innodb_information_schema_buffer : MDEV-23418 - Wrong result; modified in 10.5.4 +innodb.innodb_information_schema_buffer : MDEV-23418 - Wrong result innodb.innodb_max_recordsize_32k : MDEV-14801 - Operation failed innodb.innodb_max_recordsize_64k : MDEV-15203 - Wrong result innodb.innodb_monitor : MDEV-10939 - Testcase timeout innodb.innodb_mutexes : MDEV-23416 - Extra warning -innodb.innodb_mysql : MDEV-19873 - Wrong result; include file modified in 10.5.5 -innodb.innodb_scrub : Added in 10.5.4 +innodb.innodb_mysql : MDEV-19873 - Wrong result +innodb.innodb_scrub : Modified in 10.5.7 innodb.innodb_simulate_comp_failures_small : MDEV-20526 - ASAN use-after-poison -innodb.innodb_skip_innodb_is_tables : Configuration modified in 10.5.5 innodb.innodb_stats : MDEV-10682 - wrong result -innodb.innodb_stats_persistent : MDEV-17745 - Wrong result; MDEV-21567 - Wrong result in execution plan +innodb.innodb_stats_drop_locked : Modified in 10.5.7 +innodb.innodb_stats_persistent : MDEV-21567 - Wrong result in execution plan innodb.innodb_stats_persistent_debug : MDEV-14801 - Operation failed innodb.innodb_sys_semaphore_waits : MDEV-10331 - Semaphore wait +innodb.innodb_trx_weight : Configuration deleted in 10.5.7 innodb.innodb_zip_innochecksum2 : MDEV-13882 - Warning: difficult to find free blocks -innodb.instant_alter_bugs : Modified in 10.5.5 -innodb.instant_alter_charset : Modified in 10.5.5 -innodb.instant_alter_debug : MDEV-22958 - Wrong result; modified in 10.5.5 -innodb.instant_alter_extend : MDEV-20963 - Binary files differ; modified in 10.5.5 -innodb.instant_alter_limit : Modified in 10.5.4 -innodb.leaf_page_corrupted_during_recovery : Modified in 10.5.4 +innodb.instant_alter_bugs : Modified in 10.5.7 +innodb.instant_alter_crash : Modified in 10.5.7 +innodb.instant_alter_extend : MDEV-20963 - Binary files differ +innodb.instant_alter_index_rename : Modified in 10.5.7 innodb.log_corruption : MDEV-13251 - Wrong result innodb.log_data_file_size : MDEV-14204 - Server failed to start; MDEV-20648 - Assertion failure innodb.log_file : MDEV-20159 - Assertion failure innodb.log_file_name : MDEV-14193 - Exception innodb.log_file_size : MDEV-15668 - Not found pattern +innodb.max_record_size : MDEV-23420 - Server crash innodb.monitor : MDEV-16179 - Wrong result -innodb.mvcc : Modified in 10.5.5 innodb.page_id_innochecksum : MDEV-20159 - Assertion failure -innodb.purge_secondary : MDEV-15681 - Wrong result +innodb.purge_secondary : MDEV-15681 - Wrong result; modified in 10.5.7 innodb.purge_thread_shutdown : MDEV-13792 - Wrong result -innodb.read_only_recover_committed : Modified in 10.5.5 innodb.read_only_recovery : MDEV-13886 - Server crash innodb.recovery_shutdown : MDEV-15671 - Checksum mismatch in datafile -innodb.row_format_redundant : MDEV-15192 - Trying to access missing tablespace -innodb.table_definition_cache_debug : MDEV-14206 - Extra warning -innodb.table_flags : MDEV-13572 - Wrong result; MDEV-19374 - Server failed to start -innodb.temp_table_savepoint : Modified in 10.5.4 -innodb.temporary_table : MDEV-13265 - Wrong result -innodb.truncate_foreign : Modified in 10.5.5 -innodb.undo_truncate : MDEV-17340 - Server hung; MDEV-20840 - Sporadic timeout +innodb.redo_log_during_checkpoint : Modified in 10.5.7 +innodb.row_format_redundant : MDEV-15192 - Trying to access missing tablespace; modified in 10.5.7 +innodb.stats_persistent : Added in 10.5.7 +innodb.table_definition_cache_debug : MDEV-14206 - Extra warning; modified in 10.5.7 +innodb.table_flags : MDEV-13572 - Wrong result; MDEV-19374 - Server failed to start; modified in 10.5.7 +innodb.temp_table_savepoint : MDEV-24077 - Assertion failure +innodb.temporary_table : MDEV-13265 - Wrong result; modified in 10.5.7 +innodb.truncate : Modified in 10.5.7 +innodb.undo_truncate : MDEV-17340 - Server hung; MDEV-20840 - Sporadic timeout; modified in 10.5.7 innodb.undo_truncate_recover : MDEV-17679 - Server has gone away; MDEV-19200 - Shutdown fails +innodb.update-cascade : Combinations added in 10.5.7 innodb.update_time : MDEV-14804 - Wrong result -innodb.xa_recovery : MDEV-15279 - mysqld got exception; modified in 10.5.4 -innodb.xa_recovery_debug : Modified in 10.5.4 +innodb.xa_recovery : MDEV-15279 - mysqld got exception #----------------------------------------------------------------------- -innodb_fts.innodb-fts-ddl : Modified in 10.5.5 +innodb_fts.basic : Modified in 10.5.7 +innodb_fts.fulltext2 : MDEV-24074 - Server crash innodb_fts.innodb_fts_misc : MDEV-22955 - Extra warning +innodb_fts.innodb_fts_misc_1 : Modified in 10.5.7 innodb_fts.innodb_fts_misc_debug : MDEV-14156 - Unexpected warning innodb_fts.innodb_fts_plugin : MDEV-13888 - Errors in server log innodb_fts.innodb_fts_stopword_charset : MDEV-13259 - Table crashed @@ -576,23 +518,25 @@ innodb_fts.sync_ddl : MDEV-21568 - Errno: 2000; MDEV-18654 - innodb_gis.alter_spatial_index : MDEV-13745 - Server crash innodb_gis.gis_split_nan : MDEV-21678 - Cannot get geometry object +innodb_gis.rtree_add_index : Include file modified in 10.5.7 +innodb_gis.rtree_compress : Include file modified in 10.5.7 innodb_gis.rtree_compress2 : MDEV-16269 - Wrong result innodb_gis.rtree_concurrent_srch : MDEV-15284 - Wrong result with embedded -innodb_gis.rtree_purge : MDEV-15275 - Timeout +innodb_gis.rtree_purge : MDEV-15275 - Timeout; include file modified in 10.5.7 innodb_gis.rtree_recovery : MDEV-15274 - Error on check innodb_gis.rtree_split : MDEV-14208 - Too many arguments -innodb_gis.rtree_undo : MDEV-14456 - Timeout in include file +innodb_gis.rtree_undo : MDEV-14456 - Timeout in include file; include file modified in 10.5.7 innodb_gis.types : MDEV-15679 - Table is marked as crashed #----------------------------------------------------------------------- +innodb_zip.blob : Include file modified in 10.5.7 innodb_zip.cmp_per_index : MDEV-14490 - Table is marked as crashed -innodb_zip.create_options : MDEV-21329 - Assertion failure +innodb_zip.create_options : MDEV-21329 - Assertion failure; MDEV-24076 - Assertion failure innodb_zip.index_large_prefix_4k : MDEV-21679 - Row size too large innodb_zip.innochecksum : MDEV-14486 - Server failed to shut down innodb_zip.innochecksum_3 : MDEV-13279 - Extra warnings -innodb_zip.recover : MDEV-22512 - Server failed to restart -innodb_zip.restart : MDEV-23422 - Wrong result +innodb_zip.restart : Modified in 10.5.7 innodb_zip.wl5522_debug_zip : MDEV-11600 - Operating system error number 2 innodb_zip.wl6470_1 : MDEV-14240 - Assertion failure innodb_zip.wl6501_1 : MDEV-10891 - Can't create UNIX socket @@ -600,39 +544,37 @@ innodb_zip.wl6501_scale_1 : MDEV-13254 - Timeout, MDEV-14104 - Error 192 #----------------------------------------------------------------------- -maria.bulk_insert_crash : Added in 10.5.4 -maria.create : Modified in 10.5.4 -maria.encrypt-no-key : Added in 10.5.5 +maria.alter : Modified in 10.5.7 +maria.create : Modified in 10.5.7 maria.insert_select : MDEV-12757 - Timeout maria.insert_select-7314 : MDEV-16492 - Timeout -maria.lock : Modified in 10.5.4 maria.maria : MDEV-14430 - Extra warning -maria.maria-connect : Modified in 10.5.4 -maria.maria-no-logging : MDEV-20196 - Crash on shutdown or server can't start -maria.rollback : Added in 10.5.4 -maria.transaction : Added in 10.5.4 +maria.maria-no-logging : MDEV-20196 - Crash on shutdown or server can't start; modified in 10.5.7 #----------------------------------------------------------------------- mariabackup.absolute_ibdata_paths : MDEV-16571 - Wrong result mariabackup.apply-log-only : MDEV-20135 - Timeout +mariabackup.backup_ssl : MDEV-24073 - Server crash upon shutdown mariabackup.create_with_data_directory_during_backup : MDEV-20159 - Assertion failure mariabackup.data_directory : MDEV-15270 - Error on exec mariabackup.full_backup : MDEV-16571 - Wrong result -mariabackup.huge_lsn : MDEV-18569 - Table doesn't exist; modified in 10.5.5 +mariabackup.huge_lsn : MDEV-18569 - Table doesn't exist mariabackup.incremental_backup : MDEV-21222 - Memory allocation failure +mariabackup.incremental_ddl_during_backup : Modified in 10.5.7 mariabackup.incremental_encrypted : MDEV-15667 - timeout mariabackup.incremental_rocksdb : MDEV-20954 - Cannot access the file +mariabackup.innodb_redo_overwrite : MDEV-24023 - Wrong result; added in 10.5.7 mariabackup.log_checksum_mismatch : MDEV-16571 - Wrong result mariabackup.mdev-14447 : MDEV-15201 - Timeout -mariabackup.options_check : Modified in 10.5.5 mariabackup.partial_exclude : MDEV-15270 - Error on exec -mariabackup.unencrypted_page_compressed : MDEV-18653 - Wrong error +mariabackup.rpl_slave_info : Added in 10.5.7 +mariabackup.undo_space_id : MDEV-24022 - InnoDB error +mariabackup.unencrypted_page_compressed : MDEV-18653 - Wrong error; include file modified in 10.5.7 mariabackup.xb_compressed_encrypted : MDEV-14812 - Segmentation fault mariabackup.xb_file_key_management : MDEV-16571 - Wrong result -mariabackup.xb_fulltext_encrypted : Modified in 10.5.4 mariabackup.xb_page_compress : MDEV-14810 - status: 1, errno: 11 -mariabackup.xb_partition : MDEV-17584 - Crash upon shutdown; modified in 10.5.4 +mariabackup.xb_partition : MDEV-17584 - Crash upon shutdown mariabackup.xb_rocksdb : MDEV-17338 - Server hung on shutdown #----------------------------------------------------------------------- @@ -669,44 +611,27 @@ oqgraph.social : MDEV-22280 - Timeout #----------------------------------------------------------------------- -parts.alter_table : Modified in 10.5.5 -parts.debug_innodb_crash : Added in 10.5.4 -parts.debug_innodb_fail : Added in 10.5.4 -parts.debug_myisam_crash : Include file modified in 10.5.4 -parts.debug_myisam_fail : Added in 10.5.4 -parts.longname : Modified in 10.5.4 -parts.partition_alter1_1_2_innodb : MDEV-18655 - ASAN unknown crash -parts.partition_alter1_1_innodb : MDEV-18655 - ASAN unknown crash -parts.partition_alter1_2_innodb : MDEV-18655 - ASAN unknown crash -parts.partition_alter2_2_maria : MDEV-14364 - Lost connection to MySQL server during query -parts.partition_auto_increment_archive : MDEV-16491 - Marked as crashed and should be repaired; include file modified in 10.5.4 -parts.partition_auto_increment_blackhole : Include file modified in 10.5.4 -parts.partition_auto_increment_innodb : Include file modified in 10.5.4 -parts.partition_auto_increment_maria : MDEV-14430 - Extra warning; include file modified in 10.5.4 -parts.partition_auto_increment_memory : Include file modified in 10.5.4 -parts.partition_auto_increment_myisam : Include file modified in 10.5.4 -parts.partition_basic_innodb : MDEV-20214 - ASAN error -parts.partition_debug : Modified in 10.5.5 -parts.partition_debug_innodb : MDEV-10891 - Can't create UNIX socket; MDEV-15095 - Table doesn't exist; modified in 10.5.4 -parts.partition_debug_myisam : Modified in 10.5.4 -parts.partition_exch_qa_10 : MDEV-11765 - wrong result -parts.partition_innodb_status_file : MDEV-12901 - Valgrind -parts.partition_special_innodb : MDEV-16942 - Timeout -parts.percona_nonflushing_analyze_debug : Added in 10.5.4 - -#----------------------------------------------------------------------- - -percona.* : MDEV-10997 - Not maintained +parts.partition_alter1_1_2_innodb : MDEV-18655 - ASAN unknown crash +parts.partition_alter1_1_innodb : MDEV-18655 - ASAN unknown crash +parts.partition_alter1_2_innodb : MDEV-18655 - ASAN unknown crash +parts.partition_alter2_2_maria : MDEV-14364 - Lost connection to MySQL server during query +parts.partition_auto_increment_archive : MDEV-16491 - Marked as crashed and should be repaired +parts.partition_auto_increment_maria : MDEV-14430 - Extra warning +parts.partition_basic_innodb : MDEV-20214 - ASAN error +parts.partition_debug_innodb : MDEV-10891 - Can't create UNIX socket; MDEV-15095 - Table doesn't exist +parts.partition_exch_qa_10 : MDEV-11765 - wrong result +parts.partition_innodb_status_file : MDEV-12901 - Valgrind +parts.partition_special_innodb : MDEV-16942 - Timeout +parts.reorganize : Added in 10.5.7 #----------------------------------------------------------------------- perfschema.bad_option_1 : MDEV-21571 - Crash on bootstrap perfschema.connect_attrs : MDEV-17283 - Wrong result -perfschema.dml_file_instances : MDEV-15179 - Wrong result +perfschema.dml_file_instances : MDEV-15179 - Wrong result; modified in 10.5.7 perfschema.dml_threads : MDEV-17746 - Wrong errno perfschema.func_file_io : MDEV-5708 - fails for s390x perfschema.func_mutex : MDEV-5708 - fails for s390x -perfschema.grant : Added in 10.5.4 perfschema.hostcache_ipv4_addrinfo_again_allow : MDEV-12759 - Crash perfschema.hostcache_ipv6_addrinfo_again_allow : MDEV-12752 - Crash perfschema.hostcache_ipv6_addrinfo_bad_allow : MDEV-13260 - Crash @@ -714,18 +639,18 @@ perfschema.hostcache_ipv6_ssl : MDEV-10696 - Crash perfschema.memory_aggregate_no_a : MDEV-22949 - Wrong result perfschema.memory_aggregate_no_a_no_h : MDEV-22949 - Wrong result perfschema.memory_aggregate_no_a_no_u : MDEV-22949 - Wrong result -perfschema.no_threads : Modified in 10.5.4 -perfschema.one_thread_per_con : Modified in 10.5.4 +perfschema.memory_aggregate_no_a_no_u_no_h : MDEV-22949 - Wrong result +perfschema.nesting : MDEV-23458 - Wrong result perfschema.pfs_upgrade_event : MDEV-20957 - Wrong result perfschema.pfs_upgrade_func : MDEV-20957 - Upgrade file was not properly created perfschema.pfs_upgrade_proc : MDEV-20533 - Upgrade file was not properly created perfschema.pfs_upgrade_table : MDEV-20533 - Exec failed perfschema.pfs_upgrade_view : MDEV-20533 - Upgrade file was not properly created perfschema.privilege_table_io : MDEV-13184 - Extra lines -perfschema.relaylog : MDEV-18134 - Wrong result +perfschema.relaylog : MDEV-18134 - Wrong result; MDEV-24075 - Extra warning perfschema.rpl_gtid_func : MDEV-16897 - Wrong result perfschema.show_aggregate : MDEV-22962 - Wrong results -perfschema.show_sanity : Modified in 10.5.4 +perfschema.show_sanity : Modified in 10.5.7 perfschema.socket_instances_func : MDEV-20140 - Wrong result perfschema.socket_summary_by_event_name_func : MDEV-10622 - Wrong result perfschema.socket_summary_by_instance_func : MDEV-19413 - Wrong result @@ -734,10 +659,8 @@ perfschema.stage_mdl_global : MDEV-11803 - wrong result on sl perfschema.stage_mdl_procedure : MDEV-11545 - Missing row perfschema.stage_mdl_table : MDEV-12638 - Wrong result perfschema.start_server_low_digest : MDEV-21221 - Wrong result -perfschema.thread_cache : Modified in 10.5.4 perfschema.threads_history : MDEV-22948 - Wrong result perfschema.threads_mysql : MDEV-10677 - Wrong result -perfschema.transaction_nested_events : Modified in 10.5.4 #----------------------------------------------------------------------- @@ -745,17 +668,17 @@ perfschema_stress.* : MDEV-10996 - Not maintained #----------------------------------------------------------------------- -period.engines : Combinations modified in 10.5.4 -period.overlaps : Modified in 10.5.4 -period.versioning : MDEV-20159 - Assertion failure; include file modified in 10.5.4 +period.delete : Modified in 10.5.7 +period.update : Modified in 10.5.7 +period.versioning : MDEV-20159 - Assertion failure #----------------------------------------------------------------------- -plugins.audit_null_debug : Modified in 10.5.5 plugins.feedback_plugin_send : MDEV-7932, MDEV-11118 - Connection problems and such plugins.multiauth : MDEV-20163 - Plugin could not be loaded plugins.processlist : MDEV-16574 - Wrong result -plugins.server_audit : MDEV-14295 - Wrong result +plugins.server_audit : MDEV-14295 - Wrong result; modified in 10.5.7 +plugins.test_sql_service : Added in 10.5.7 plugins.thread_pool_server_audit : MDEV-14295 - Wrong result #----------------------------------------------------------------------- @@ -795,133 +718,131 @@ rocksdb_sys_vars.rocksdb_rate_limiter_bytes_per_sec_basic : MDEV-16639 - Crash #----------------------------------------------------------------------- -roles.create_and_grant_role : MDEV-11772 - wrong result -roles.drop_current_role : Added in 10.5.5 -roles.set_default_role_invalid : Modified in 10.5.4 +roles.create_and_grant_role : MDEV-11772 - wrong result #----------------------------------------------------------------------- -rpl.circular_serverid0 : MDEV-19372 - ASAN heap-use-after-free -rpl.create_or_replace2 : MDEV-19412 - Lost connection to MySQL server -rpl.create_or_replace_mix : MDEV-20523 - Wrong result -rpl.create_or_replace_statement : MDEV-20523 - Wrong result -rpl.create_select : MDEV-14121 - Assertion failure -rpl.last_insert_id : MDEV-10625 - warnings in error log -rpl.parallel_backup : Added in 10.5.5 -rpl.rpl_auto_increment : MDEV-10417 - Fails on Mips -rpl.rpl_auto_increment_bug45679 : MDEV-10417 - Fails on Mips -rpl.rpl_auto_increment_update_failure : MDEV-10625 - warnings in error log -rpl.rpl_binlog_dump_slave_gtid_state_info : Added in 10.5.5 -rpl.rpl_binlog_errors : MDEV-12742 - Crash -rpl.rpl_binlog_grant : MDEV-21274 - Lost connection at handshake -rpl.rpl_binlog_index : MDEV-9501 - Failed registering on master -rpl.rpl_cant_read_event_incident : MDEV-20960 - Abort on shutdown -rpl.rpl_checksum_cache : MDEV-22510 - Server crash -rpl.rpl_circular_for_4_hosts : MDEV-20536 - Server crash -rpl.rpl_colSize : MDEV-16112 - Server crash -rpl.rpl_corruption : MDEV-20527 - Slave stopped with wrong error code -rpl.rpl_create_tmp_table_if_not_exists : MDEV-20159 - Assertion failure -rpl.rpl_ctype_latin1 : MDEV-14813 - Wrong result on Mac -rpl.rpl_ddl : MDEV-10417 - Fails on Mips -rpl.rpl_domain_id_filter_io_crash : MDEV-12729 - Timeout in include file, MDEV-13677 - Server crash -rpl.rpl_domain_id_filter_master_crash : MDEV-19043 - Table marked as crashed -rpl.rpl_domain_id_filter_restart : MDEV-10684 - Wrong result; MDEV-19043 - Table marked as crashed -rpl.rpl_drop_db_fail : MDEV-16898 - Slave fails to start -rpl.rpl_dump_request_retry_warning : Added in 10.5.5 -rpl.rpl_extra_col_master_innodb : MDEV-16570 - Extra warning -rpl.rpl_fail_register : Modified in 10.5.4 -rpl.rpl_flushlog_loop : MDEV-21570 - Server crash -rpl.rpl_get_lock : MDEV-19368 - mysqltest failed but provided no output -rpl.rpl_gtid_basic : MDEV-10681 - server startup problem -rpl.rpl_gtid_crash : MDEV-9501 - Failed registering on master, MDEV-13643 - Lost connection -rpl.rpl_gtid_delete_domain : MDEV-23103 - Could not delete gtid domain; MDEV-14463 - Timeout -rpl.rpl_gtid_errorhandling : MDEV-13261 - Crash -rpl.rpl_gtid_mdev9033 : MDEV-10680 - warnings -rpl.rpl_gtid_reconnect : MDEV-14497 - Crash -rpl.rpl_gtid_startpos : MDEV-20141 - mysqltest failed but provided no output -rpl.rpl_gtid_stop_start : MDEV-10629 - Crash on shutdown, MDEV-12629 - Valgrind warnings -rpl.rpl_gtid_until : MDEV-10625 - warnings in error log -rpl.rpl_ignore_grant : MDEV-20159 - Assertion failure -rpl.rpl_ignore_table_update : MDEV-20159 - Assertion failure -rpl.rpl_innodb_bug30888 : MDEV-10417 - Fails on Mips -rpl.rpl_insert : MDEV-9329 - Fails on Ubuntu/s390x -rpl.rpl_insert_delayed : MDEV-9329 - Fails on Ubuntu/s390x -rpl.rpl_insert_id : MDEV-15197 - Wrong result -rpl.rpl_insert_id_pk : MDEV-16567 - Assertion failure -rpl.rpl_insert_ignore : MDEV-14365 - Lost connection to MySQL server during query -rpl.rpl_invoked_features : MDEV-10417 - Fails on Mips -rpl.rpl_ipv4_as_ipv6 : MDEV-20147 - Incorrect checksum for freed object -rpl.rpl_mariadb_slave_capability : MDEV-11018 - Extra lines in binlog -rpl.rpl_mdev12179 : MDEV-19043 - Table marked as crashed -rpl.rpl_mdev6020 : MDEV-15272 - Server crash -rpl.rpl_mixed_mixing_engines : MDEV-21266 - Timeout -rpl.rpl_multi_engine : MDEV-23419 - Server crash -rpl.rpl_non_direct_row_mixing_engines : MDEV-16561 - Timeout in master_pos_wait -rpl.rpl_old_master : MDEV-22956 - Assertion failure -rpl.rpl_parallel : MDEV-10653 - Timeouts -rpl.rpl_parallel2 : MDEV-17390 - Operation cannot be performed; modified in 10.5.5 -rpl.rpl_parallel_conflicts : MDEV-15272 - Server crash -rpl.rpl_parallel_mdev6589 : MDEV-12979 - Assertion failure -rpl.rpl_parallel_multilevel : MDEV-20160 - Server crash -rpl.rpl_parallel_multilevel2 : MDEV-14723 - Timeout -rpl.rpl_parallel_optimistic : MDEV-15278 - Failed to sync with master -rpl.rpl_parallel_optimistic_nobinlog : MDEV-15278 - Failed to sync with master -rpl.rpl_parallel_optimistic_until : MDEV-23021 - Query didn't return a result set; added in 10.5.4 -rpl.rpl_parallel_retry : MDEV-11119 - Crash; MDEV-17109 - Timeout -rpl.rpl_parallel_temptable : MDEV-10356 - Crash; MDEV-19076 - Wrong result -rpl.rpl_partition_innodb : MDEV-10417 - Fails on Mips -rpl.rpl_password_boundaries : MDEV-11534 - Slave IO warnings -rpl.rpl_read_only : MDEV-20159 - Assertion failure -rpl.rpl_row_001 : MDEV-16653 - MTR's internal check fails -rpl.rpl_row_basic_11bugs : MDEV-12171 - Server failed to start -rpl.rpl_row_basic_2myisam : MDEV-13875 - command "diff_files" failed -rpl.rpl_row_corruption : MDEV-21569 - mutex: LOCK_global_system_variables unlocking -rpl.rpl_row_drop_create_temp_table : MDEV-14487 - Wrong result -rpl.rpl_row_end_of_statement_loss : MDEV-21237 - Server crash -rpl.rpl_row_img_blobs : MDEV-13875 - command "diff_files" failed -rpl.rpl_row_img_eng_min : MDEV-13875 - diff_files failed -rpl.rpl_row_img_eng_noblob : MDEV-13875 - command "diff_files" failed -rpl.rpl_row_index_choice : MDEV-15196 - Slave crash -rpl.rpl_row_sp001 : MDEV-9329 - Fails on Ubuntu/s390x -rpl.rpl_row_until : MDEV-14052 - Master will not send events with checksum -rpl.rpl_row_virt : Added in 10.5.5 -rpl.rpl_semi_sync : MDEV-11220 - Wrong result -rpl.rpl_semi_sync_after_sync : MDEV-14366 - Wrong result -rpl.rpl_semi_sync_after_sync_row : MDEV-14366 - Wrong result -rpl.rpl_semi_sync_event_after_sync : MDEV-11806 - warnings -rpl.rpl_semi_sync_skip_repl : MDEV-23371 - Server crash -rpl.rpl_semi_sync_uninstall_plugin : MDEV-7140 - Assorted failures -rpl.rpl_semi_sync_wait_no_slave : MDEV-20159 - Assertion failure -rpl.rpl_semi_sync_wait_point : MDEV-11807 - timeout in wait condition -rpl.rpl_semisync_ali_issues : MDEV-16272 - Wrong result -rpl.rpl_show_slave_hosts : MDEV-10681 - Crash -rpl.rpl_shutdown_wait_slaves : MDEV-22517 - Timeout on sync_with_master -rpl.rpl_skip_replication : MDEV-23372 - Extra warning -rpl.rpl_slave_alias_replica : Modified in 10.5.5 -rpl.rpl_slave_grp_exec : MDEV-10514 - Deadlock -rpl.rpl_slave_load_in : MDEV-20159 - Assertion failure -rpl.rpl_slow_query_log : MDEV-13250 - Test abort -rpl.rpl_sp_effects : MDEV-13249 - Crash -rpl.rpl_start_stop_slave : MDEV-13567 - Sync slave timeout -rpl.rpl_stm_multi_query : MDEV-9501 - Failed registering on master -rpl.rpl_stm_relay_ign_space : MDEV-14360 - Test assertion -rpl.rpl_stm_start_stop_slave : MDEV-23180 - ASAN heap-use-after-free -rpl.rpl_stm_stop_middle_group : MDEV-13791 - Server crash -rpl.rpl_sync : MDEV-10633 - Database page corruption -rpl.rpl_temporal_mysql56_to_mariadb53 : MDEV-9501 - Failed registering on master -rpl.rpl_temporary_error2 : MDEV-10634 - Wrong number of retries -rpl.rpl_test_framework : MDEV-19368 - mysqltest failed but provided no output -rpl.rpl_trigger : MDEV-18055 - Wrong result -rpl.rpl_truncate_3innodb : MDEV-19454 - Syntax error -rpl.rpl_upgrade_master_info : MDEV-16567 - Assertion failure -rpl.rpl_user_variables : MDEV-20522 - Wrong result -rpl.rpl_variables : MDEV-20150 - Server crash -rpl.sec_behind_master-5114 : MDEV-13878 - Wrong result -rpl.show_status_stop_slave_race-7126 : MDEV-17438 - Timeout +rpl.circular_serverid0 : MDEV-19372 - ASAN heap-use-after-free +rpl.create_or_replace2 : MDEV-19412 - Lost connection to MySQL server +rpl.create_or_replace_mix : MDEV-20523 - Wrong result +rpl.create_or_replace_statement : MDEV-20523 - Wrong result +rpl.create_select : MDEV-14121 - Assertion failure +rpl.last_insert_id : MDEV-10625 - warnings in error log +rpl.rpl_auto_increment : MDEV-10417 - Fails on Mips +rpl.rpl_auto_increment_bug45679 : MDEV-10417 - Fails on Mips +rpl.rpl_auto_increment_update_failure : MDEV-10625 - warnings in error log +rpl.rpl_binlog_errors : MDEV-12742 - Crash +rpl.rpl_binlog_grant : MDEV-21274 - Lost connection at handshake +rpl.rpl_binlog_index : Modified in 10.5.7 +rpl.rpl_cant_read_event_incident : MDEV-20960 - Abort on shutdown +rpl.rpl_checksum_cache : MDEV-22510 - Server crash +rpl.rpl_circular_for_4_hosts : MDEV-20536 - Server crash +rpl.rpl_colSize : MDEV-16112 - Server crash +rpl.rpl_corruption : MDEV-20527 - Slave stopped with wrong error code +rpl.rpl_create_drop_view : Modified in 10.5.7 +rpl.rpl_create_tmp_table_if_not_exists : MDEV-20159 - Assertion failure +rpl.rpl_ctype_latin1 : MDEV-14813 - Wrong result on Mac +rpl.rpl_ddl : MDEV-10417 - Fails on Mips +rpl.rpl_domain_id_filter_io_crash : MDEV-12729 - Timeout in include file, MDEV-13677 - Server crash +rpl.rpl_domain_id_filter_master_crash : MDEV-19043 - Table marked as crashed +rpl.rpl_domain_id_filter_restart : MDEV-10684 - Wrong result; MDEV-19043 - Table marked as crashed +rpl.rpl_drop_db_fail : MDEV-16898 - Slave fails to start +rpl.rpl_extra_col_master_innodb : MDEV-16570 - Extra warning +rpl.rpl_extra_col_master_myisam : MDEV-23372 - Extra warning +rpl.rpl_filter_tables_dynamic : Modified in 10.5.7 +rpl.rpl_flushlog_loop : MDEV-21570 - Server crash +rpl.rpl_get_lock : MDEV-19368 - mysqltest failed but provided no output +rpl.rpl_gtid_basic : MDEV-10681 - server startup problem +rpl.rpl_gtid_crash : MDEV-13643 - Lost connection; modified in 10.5.7 +rpl.rpl_gtid_delete_domain : MDEV-23103 - Could not delete gtid domain; MDEV-14463 - Timeout; modified in 10.5.7 +rpl.rpl_gtid_errorhandling : MDEV-13261 - Crash +rpl.rpl_gtid_mdev9033 : MDEV-10680 - warnings +rpl.rpl_gtid_reconnect : MDEV-14497 - Crash +rpl.rpl_gtid_startpos : MDEV-20141 - mysqltest failed but provided no output +rpl.rpl_gtid_stop_start : MDEV-10629 - Crash on shutdown, MDEV-12629 - Valgrind warnings +rpl.rpl_gtid_until : MDEV-10625 - warnings in error log +rpl.rpl_ignore_grant : MDEV-20159 - Assertion failure +rpl.rpl_ignore_table_update : MDEV-20159 - Assertion failure +rpl.rpl_innodb_bug30888 : MDEV-10417 - Fails on Mips +rpl.rpl_insert : MDEV-9329 - Fails on Ubuntu/s390x +rpl.rpl_insert_delayed : MDEV-9329 - Fails on Ubuntu/s390x +rpl.rpl_insert_id : MDEV-15197 - Wrong result +rpl.rpl_insert_id_pk : MDEV-16567 - Assertion failure +rpl.rpl_insert_ignore : MDEV-14365 - Lost connection to MySQL server during query +rpl.rpl_invoked_features : MDEV-10417 - Fails on Mips +rpl.rpl_ipv4_as_ipv6 : MDEV-20147 - Incorrect checksum for freed object +rpl.rpl_mariadb_slave_capability : MDEV-11018 - Extra lines in binlog +rpl.rpl_mdev12179 : MDEV-19043 - Table marked as crashed +rpl.rpl_mdev6020 : MDEV-23426 - Server crash, ASAN failures; MDEV-15272 - Server crash +rpl.rpl_mixed_mixing_engines : MDEV-21266 - Timeout +rpl.rpl_multi_engine : MDEV-23419 - Server crash +rpl.rpl_mysql_upgrade : Modified in 10.5.7 +rpl.rpl_non_direct_row_mixing_engines : MDEV-16561 - Timeout in master_pos_wait +rpl.rpl_old_master : MDEV-22956 - Assertion failure +rpl.rpl_parallel : MDEV-10653 - Timeouts +rpl.rpl_parallel2 : MDEV-17390 - Operation cannot be performed +rpl.rpl_parallel_conflicts : MDEV-15272 - Server crash +rpl.rpl_parallel_mdev6589 : MDEV-12979 - Assertion failure +rpl.rpl_parallel_multilevel : MDEV-20160 - Server crash +rpl.rpl_parallel_multilevel2 : MDEV-14723 - Timeout +rpl.rpl_parallel_optimistic : MDEV-15278 - Failed to sync with master +rpl.rpl_parallel_optimistic_nobinlog : MDEV-15278 - Failed to sync with master +rpl.rpl_parallel_optimistic_until : MDEV-23021 - Query didn't return a result set +rpl.rpl_parallel_retry : MDEV-11119 - Crash; MDEV-17109 - Timeout; modified in 10.5.7 +rpl.rpl_parallel_temptable : MDEV-10356 - Crash; MDEV-19076 - Wrong result +rpl.rpl_partition_innodb : MDEV-10417 - Fails on Mips +rpl.rpl_password_boundaries : MDEV-11534 - Slave IO warnings +rpl.rpl_read_only : MDEV-20159 - Assertion failure +rpl.rpl_rewrt_db : MDEV-24060 - Server did not start +rpl.rpl_row_001 : MDEV-16653 - MTR's internal check fails +rpl.rpl_row_basic_11bugs : MDEV-12171 - Server failed to start +rpl.rpl_row_basic_2myisam : MDEV-13875 - command "diff_files" failed +rpl.rpl_row_corruption : MDEV-21569 - mutex: LOCK_global_system_variables unlocking +rpl.rpl_row_drop_create_temp_table : MDEV-14487 - Wrong result +rpl.rpl_row_end_of_statement_loss : MDEV-21237 - Server crash +rpl.rpl_row_img_blobs : MDEV-13875 - command "diff_files" failed +rpl.rpl_row_img_eng_min : MDEV-13875 - diff_files failed +rpl.rpl_row_img_eng_noblob : MDEV-13875 - command "diff_files" failed +rpl.rpl_row_index_choice : MDEV-15196 - Slave crash +rpl.rpl_row_sp001 : MDEV-9329 - Fails on Ubuntu/s390x +rpl.rpl_row_until : MDEV-14052 - Master will not send events with checksum +rpl.rpl_semi_sync : MDEV-11220 - Wrong result +rpl.rpl_semi_sync_after_sync : MDEV-14366 - Wrong result +rpl.rpl_semi_sync_after_sync_row : MDEV-14366 - Wrong result +rpl.rpl_semi_sync_event_after_sync : MDEV-11806 - warnings +rpl.rpl_semi_sync_skip_repl : MDEV-23371 - Server crash +rpl.rpl_semi_sync_uninstall_plugin : MDEV-7140 - Assorted failures +rpl.rpl_semi_sync_wait_no_slave : MDEV-20159 - Assertion failure +rpl.rpl_semi_sync_wait_point : MDEV-11807 - timeout in wait condition +rpl.rpl_semisync_ali_issues : MDEV-16272 - Wrong result +rpl.rpl_show_slave_hosts : MDEV-10681 - Crash +rpl.rpl_shutdown_wait_slaves : MDEV-22517 - Timeout on sync_with_master +rpl.rpl_skip_replication : MDEV-23372 - Extra warning +rpl.rpl_slave_grp_exec : MDEV-10514 - Deadlock; re-enabled in 10.5.7; modified in 10.5.7 +rpl.rpl_slave_load_in : MDEV-20159 - Assertion failure +rpl.rpl_slave_load_tmpdir_not_exist : MDEV-23372 - Extra warning +rpl.rpl_slow_query_log : MDEV-13250 - Test abort +rpl.rpl_sp_effects : MDEV-13249 - Crash +rpl.rpl_start_stop_slave : MDEV-13567 - Sync slave timeout; modified in 10.5.7 +rpl.rpl_stm_relay_ign_space : MDEV-14360 - Test assertion +rpl.rpl_stm_start_stop_slave : MDEV-23180 - ASAN heap-use-after-free +rpl.rpl_stm_stop_middle_group : MDEV-13791 - Server crash +rpl.rpl_sync : MDEV-10633 - Database page corruption +rpl.rpl_temporary_error2 : MDEV-10634 - Wrong number of retries +rpl.rpl_test_framework : MDEV-19368 - mysqltest failed but provided no output +rpl.rpl_trigger : MDEV-18055 - Wrong result +rpl.rpl_truncate_3innodb : MDEV-19454 - Syntax error +rpl.rpl_upgrade_master_info : MDEV-16567 - Assertion failure +rpl.rpl_user_variables : MDEV-20522 - Wrong result +rpl.rpl_variables : MDEV-20150 - Server crash +rpl.sec_behind_master-5114 : MDEV-13878 - Wrong result +rpl.show_status_stop_slave_race-7126 : Modified in 10.5.7 #----------------------------------------------------------------------- -rpl-tokudb.* : TokuDB is deprecated and not maintained anymore +rpl-tokudb.* : TokuDB is deprecated and not maintained anymore +rpl-tokudb.rpl_deadlock_tokudb : MDEV-20529 - mysqltest failed but provided no output +rpl-tokudb.rpl_tokudb_commit_after_flush : MDEV-16966 - Server crash #----------------------------------------------------------------------- @@ -929,11 +850,10 @@ rpl/extra/rpl_tests.* : MDEV-10994 - Not maintained #----------------------------------------------------------------------- -s3.* : Engine enabled in 10.5.4 -s3.alter2 : Modified in 10.5.4 -s3.replication_mixed : Include file modified in 10.5.4 -s3.replication_partition : Modified in 10.5.4 -s3.replication_stmt : Include file modified in 10.5.4 +s3.* : Configuration files modified in 10.5.7 +s3.alter : Modified in 10.5.7 +s3.replication_delayed : Added in 10.5.7 +s3.replication_partition : MDEV-24087 - Replication failure; modified in 10.5.7 #----------------------------------------------------------------------- @@ -943,31 +863,24 @@ sphinx.union-5539 : MDEV-10986 - Sporadic failures #----------------------------------------------------------------------- -spider.* : MDEV-9329, MDEV-18737 - tests are too memory-consuming; include files modified in 10.5.4 -spider.basic_sql : MDEV-11186 - Internal check fails -spider.slave_trx_isolation : Modified in 10.5.4 -spider.spider_wrapper_protocols : Added in 10.5.4 +spider.* : MDEV-9329, MDEV-18737 - tests are too memory-consuming +spider.basic_sql : MDEV-11186 - Internal check fails #----------------------------------------------------------------------- -spider/bg.* : Include fieles modified in 10.5.4 -spider/bg.direct_aggregate : MDEV-7098 - Packets out of order -spider/bg.direct_aggregate_part : MDEV-7098 - Trying to unlock mutex that wasn't locked -spider/bg.ha : MDEV-9329 - failures on s390x -spider/bg.ha_part : MDEV-9329 - Fails on Ubuntu/s390x -spider/bg.spider3_fixes : MDEV-12639 - Syntax error -spider/bg.spider3_fixes_part : MDEV-7098 - Trying to unlock mutex -spider/bg.spider_fixes : MDEV-7098 -Mutex problem, MDEV-9329 - failures on s390x -spider/bg.spider_fixes_part : MDEV-7098 - Trying to unlock mutex that wasn't locked -spider/bg.vp_fixes : MDEV-9329 - Fails on Ubuntu/s390x +spider/bg.* : MDEV-24059 - Timeout +spider/bg.ha : MDEV-9329 - failures on s390x +spider/bg.ha_part : MDEV-9329 - Fails on Ubuntu/s390x +spider/bg.spider3_fixes : MDEV-12639 - Syntax error +spider/bg.spider_fixes : MDEV-9329 - failures on s390x +spider/bg.vp_fixes : MDEV-9329 - Fails on Ubuntu/s390x #----------------------------------------------------------------------- -spider/bugfix.* : Include fieles modified in 10.5.4 -spider/bugfix.insert_select : Added in 10.5.4 -spider/bugfix.self_reference : Added in 10.5.4 -spider/bugfix.slave_trx_isolation : Modified in 10.5.4 -spider/bugfix.strict_group_by : Added in 10.5.4 +spider/bugfix.direct_sql_with_comma_pwd : Added in 10.5.7 +spider/bugfix.mdev_20100 : Added in 10.5.7 +spider/bugfix.mdev_22246 : Added in 10.5.7 +spider/bugfix.xa_cmd : Added in 10.5.7 #----------------------------------------------------------------------- @@ -975,10 +888,9 @@ spider/handler.* : MDEV-10987, MDEV-10990 - Tests have not been maintained #----------------------------------------------------------------------- -sql_sequence.alter : Modified in 10.5.4 sql_sequence.concurrent_create : MDEV-16635 - Server crash -sql_sequence.create : Modified in 10.5.4 -sql_sequence.kill : MDEV-23393 - Server crash; added in 10.5.5 +sql_sequence.kill : MDEV-23393 - Server crash +sql_sequence.next : Modified in 10.5.7 sql_sequence.read_only : MDEV-22956 - Failing assertion #----------------------------------------------------------------------- @@ -987,29 +899,27 @@ storage_engine.* : Tests are not always timely maintained #----------------------------------------------------------------------- -stress.* : Added to the main set in 10.5.4 stress.ddl_innodb : MDEV-10635 - Testcase timeout -stress.misc : Added in 10.5.4 +stress.misc : MDEV-23420 - Server crash #----------------------------------------------------------------------- -sys_vars.all_vars : Modified in 10.5.4 sys_vars.autocommit_func2 : MDEV-9329 - Fails on Ubuntu/s390x sys_vars.host_cache_size_auto : MDEV-20112 - Wrong result sys_vars.innodb_buffer_pool_dump_at_shutdown_basic : MDEV-14280 - Unexpected error sys_vars.innodb_checksum_algorithm_basic : MDEV-21568 - Errno: 2000 -sys_vars.innodb_commit_concurrency_basic : Modified in 10.5.5 sys_vars.innodb_fatal_semaphore_wait_threshold : MDEV-22961 - Server failed to dissapear +sys_vars.innodb_max_dirty_pages_pct_func : Modified in 10.5.7 sys_vars.keep_files_on_create_basic : MDEV-10676 - timeout sys_vars.log_slow_admin_statements_func : MDEV-12235 - Server crash -sys_vars.max_sort_length_basic : Modified in 10.5.4 -sys_vars.optimizer_switch_basic : Modified in 10.5.5 -sys_vars.rpl_init_slave_func : MDEV-10149 - Test assertion -sys_vars.session_track_system_variables_basic : Modified in 10.5.5 +sys_vars.replicate_do_db_basic : Modified in 10.5.7 +sys_vars.rpl_init_slave_func : Modified in 10.5.7 +sys_vars.session_track_system_variables_basic : Modified in 10.5.7 sys_vars.slow_query_log_func : MDEV-14273 - Wrong result sys_vars.thread_cache_size_func : MDEV-11775 - Wrong result -sys_vars.thread_pool_size_basic : Modified in 10.5.4 -sys_vars.wait_timeout_func : MDEV-12896 - Wrong result; modified in 10.5.4 +sys_vars.wait_timeout_func : MDEV-12896 - Wrong result +sys_vars.wsrep_cluster_address_basic : Modified in 10.5.7 +sys_vars.wsrep_on_basic : Configuration deleted in 10.5.7 #----------------------------------------------------------------------- @@ -1017,8 +927,7 @@ tokudb.* : TokuDB is deprecated and not maintained anymore #----------------------------------------------------------------------- -type_inet.type_inet6 : Modified in 10.5.4 -type_inet.type_inet6_stat_tables : Modified in 10.5.4 +type_inet.type_inet6 : Modified in 10.5.7 #----------------------------------------------------------------------- @@ -1036,36 +945,29 @@ unit.mf_iocache : MDEV-20952 - ASAN stack-buffer-overflow vcol.not_supported : MDEV-10639 - Testcase timeout vcol.vcol_keys_innodb : MDEV-10639 - Testcase timeout -vcol.vcol_keys_myisam : Modified in 10.5.4 -vcol.vcol_misc : MDEV-16651 - Wrong error message; modified in 10.5.4 +vcol.vcol_misc : MDEV-16651 - Wrong error message; modified in 10.5.7 #----------------------------------------------------------------------- -versioning.alter : Include file modified in 10.5.4 -versioning.auto_increment : Include file modified in 10.5.4 -versioning.commit_id : Include file modified in 10.5.4 -versioning.create : Include file modified in 10.5.4 -versioning.delete : Include file modified in 10.5.4 -versioning.delete_history : Include file modified in 10.5.4 -versioning.engines : Combinations modified in 10.5.4 -versioning.foreign : Include file modified in 10.5.4 -versioning.insert : Include file modified in 10.5.4 -versioning.online : Include file modified in 10.5.4 -versioning.partition : Modified in 10.5.5 -versioning.replace : MDEV-22960 - OS errors, crash; include file modified in 10.5.4 -versioning.select : Modified in 10.5.4 -versioning.select2 : Modified in 10.5.4 -versioning.sysvars : Modified in 10.5.5 -versioning.update : MDEV-22475 - Wrong result code; modified in 10.5.5 -versioning.update-big : Include file modified in 10.5.4 -versioning.view : Modified in 10.5.4 +versioning.create : Modified in 10.5.7 +versioning.replace : MDEV-22960 - OS errors, crash +versioning.select : Modified in 10.5.7 +versioning.sysvars : Modified in 10.5.7 +versioning.update : MDEV-22475 - Wrong result code +versioning.view : Modified in 10.5.7 #----------------------------------------------------------------------- +wsrep.MDEV-22443 : Added in 10.5.7 +wsrep.MDEV-23081 : Added in 10.5.7 +wsrep.MDEV-23092 : Added in 10.5.7 +wsrep.MDEV-23466 : Added in 10.5.7 wsrep.foreign_key : MDEV-14725 - WSREP has not yet prepared node +wsrep.mdev_22681 : Added in 10.5.7 wsrep.mdev_6832 : MDEV-14195 - Check testcase failed wsrep.pool_of_threads : MDEV-17345 - WSREP has not yet prepared node for application use -wsrep.variables : MDEV-17585 - Deadlock +wsrep.variables : Modified in 10.5.7 +wsrep.variables_debug : Added in 10.5.7 #----------------------------------------------------------------------- From 30894fe9a9024d4dfe85f7fc93cf702040a9ef67 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Tue, 22 Sep 2020 20:17:02 +1000 Subject: [PATCH 315/323] Add DBUG_ASSERT in Field::ptr_in_record 1. Subtracting table->record[0] from record is UB (non-contiguous buffers) 2. It is very popular to use move_field_offset, which changes Field::ptr, but leaves table->record[0] unchanged. This makes a ptr_in_record result incorrect, since it relies on table->record[0] value. The check ensures the result is within the queried record boundaries. --- sql/field.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sql/field.h b/sql/field.h index be4d279ce61..dfc02149f9d 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1151,8 +1151,9 @@ public: virtual void reset_fields() {} const uchar *ptr_in_record(const uchar *record) const { - my_ptrdiff_t l_offset= (my_ptrdiff_t) (record - table->record[0]); - return ptr + l_offset; + my_ptrdiff_t l_offset= (my_ptrdiff_t) (ptr - table->record[0]); + DBUG_ASSERT(l_offset >= 0 && table->s->rec_buff_length - l_offset > 0); + return record + l_offset; } virtual int set_default(); From d543363f25f96a6cf1779904ea483c59effa1796 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Thu, 24 Sep 2020 21:59:28 +1000 Subject: [PATCH 316/323] MDEV-22714 Assertion failed upon multi-update on table WITHOUT OVERLAPS The problem here was that ha_check_overlaps internally uses ha_index_read, which in case of fail overwrites table->status. Even though the handlers are different, they share a common table, so the value is anyway spoiled. This is bad, and table->status is badly designed and overweighted by functionality, but nothing can be done with it, since the code related to this logic is ancient and it's impossible to extract it with normal effort. So let's just save and restore the value in ha_update_row before and after the checks. Other operations like INSERT and simple UPDATE are not in risk, since they don't use this table->status approach. DELETE does not do any unique checks, so it's also safe. --- mysql-test/suite/period/r/overlaps.result | 9 +++++++++ mysql-test/suite/period/t/overlaps.test | 14 ++++++++++++++ sql/handler.cc | 15 +++++++++------ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/period/r/overlaps.result b/mysql-test/suite/period/r/overlaps.result index fcd54a0a942..f5839a84e4b 100644 --- a/mysql-test/suite/period/r/overlaps.result +++ b/mysql-test/suite/period/r/overlaps.result @@ -320,4 +320,13 @@ t1 CREATE TABLE `t1` ( PARTITION `pn` CURRENT ENGINE = InnoDB) insert into t1 values (1,'2013-01-12','2015-11-04'), (2,'2016-03-15','2024-11-09'); +# MDEV-22714 Assertion `index->table->is_instant()' failed upon +# multi-update on table with WITHOUT OVERLAPS +create or replace table t (a int); +insert into t values (0),(null),(0); +create or replace table t1 (f int, s date, e date, period for p(s,e), +unique(f, p without overlaps)); +insert into t1 values (0,'2026-02-12','2036-09-16'), +(null,'2025-03-09','2032-12-05'); +update ignore t join t1 set f = a; drop table t, t1; diff --git a/mysql-test/suite/period/t/overlaps.test b/mysql-test/suite/period/t/overlaps.test index 30032f9898c..ef2161d27a2 100644 --- a/mysql-test/suite/period/t/overlaps.test +++ b/mysql-test/suite/period/t/overlaps.test @@ -299,5 +299,19 @@ insert into t1 values (1,'2013-01-12','2015-11-04'), (2,'2016-03-15','2024-11-09'); +--echo # MDEV-22714 Assertion `index->table->is_instant()' failed upon +--echo # multi-update on table with WITHOUT OVERLAPS + +create or replace table t (a int); +insert into t values (0),(null),(0); + +create or replace table t1 (f int, s date, e date, period for p(s,e), + unique(f, p without overlaps)); + +insert into t1 values (0,'2026-02-12','2036-09-16'), + (null,'2025-03-09','2032-12-05'); + +update ignore t join t1 set f = a; + drop table t, t1; diff --git a/sql/handler.cc b/sql/handler.cc index c33dcb192d8..aa04b0bce1c 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -7182,17 +7182,20 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data) DBUG_ASSERT(new_data == table->record[0]); DBUG_ASSERT(old_data == table->record[1]); - if ((error= ha_check_overlaps(old_data, new_data))) - return error; + uint saved_status= table->status; + error= ha_check_overlaps(old_data, new_data); MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str); mark_trx_read_write(); increment_statistics(&SSV::ha_update_count); - if (table->s->long_unique_table && this == table->file && - (error= check_duplicate_long_entries_update(new_data))) - { + + if (!error && table->s->long_unique_table && this == table->file) + error= check_duplicate_long_entries_update(new_data); + table->status= saved_status; + + if (error) return error; - } + TABLE_IO_WAIT(tracker, PSI_TABLE_UPDATE_ROW, active_index, 0, { error= update_row(old_data, new_data);}) From afca976885ca03556a4f0b18b3a2b8c91155f779 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Tue, 20 Oct 2020 19:19:36 +1000 Subject: [PATCH 317/323] MDEV-22639 Assertion failed in ha_check_overlaps upon multi-table update After Sergei's cleanup this assertion is not actual anymore -- we can't predict if the handler was used for lookup, especially in multi-update scenario. `position(old_data)` is made earlier in `ha_check_overlaps`, therefore it is guaranteed that we compare right refs. --- mysql-test/suite/period/r/overlaps.result | 8 ++++++++ mysql-test/suite/period/t/overlaps.test | 10 ++++++++++ sql/handler.cc | 6 +----- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/period/r/overlaps.result b/mysql-test/suite/period/r/overlaps.result index f5839a84e4b..40d38fc5a56 100644 --- a/mysql-test/suite/period/r/overlaps.result +++ b/mysql-test/suite/period/r/overlaps.result @@ -329,4 +329,12 @@ unique(f, p without overlaps)); insert into t1 values (0,'2026-02-12','2036-09-16'), (null,'2025-03-09','2032-12-05'); update ignore t join t1 set f = a; +# MDEV-22639 Assertion `inited != NONE' failed in +# handler::ha_check_overlaps upon multi-table update +create or replace table t (f int, s date, e date, period for p(s,e), +unique(f, p without overlaps)) engine=myisam; +insert into t values (1,'1988-08-25','2024-03-06'); +create or replace table t1 (a int) engine=myisam; +insert into t1 values (1),(2); +update t join t1 set s = '2020-01-01'; drop table t, t1; diff --git a/mysql-test/suite/period/t/overlaps.test b/mysql-test/suite/period/t/overlaps.test index ef2161d27a2..17005878385 100644 --- a/mysql-test/suite/period/t/overlaps.test +++ b/mysql-test/suite/period/t/overlaps.test @@ -313,5 +313,15 @@ insert into t1 values (0,'2026-02-12','2036-09-16'), update ignore t join t1 set f = a; +--echo # MDEV-22639 Assertion `inited != NONE' failed in +--echo # handler::ha_check_overlaps upon multi-table update + +create or replace table t (f int, s date, e date, period for p(s,e), + unique(f, p without overlaps)) engine=myisam; +insert into t values (1,'1988-08-25','2024-03-06'); +create or replace table t1 (a int) engine=myisam; +insert into t1 values (1),(2); + +update t join t1 set s = '2020-01-01'; drop table t, t1; diff --git a/sql/handler.cc b/sql/handler.cc index aa04b0bce1c..038effc3e5b 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6947,7 +6947,7 @@ int handler::ha_check_overlaps(const uchar *old_data, const uchar* new_data) uchar *record_buffer= lookup_buffer + table_share->max_unique_length + table_share->null_fields; - // Needs to compare record refs later is old_row_found() + // Needed to compare record refs later if (is_update) position(old_data); @@ -7003,12 +7003,8 @@ int handler::ha_check_overlaps(const uchar *old_data, const uchar* new_data) /* In case of update it could happen that the nearest neighbour is a record we are updating. It means, that there are no overlaps from this side. - - An assumption is made that during update we always have the last - fetched row in old_data. Therefore, comparing ref's is enough */ DBUG_ASSERT(lookup_handler != this); - DBUG_ASSERT(inited != NONE); DBUG_ASSERT(ref_length == lookup_handler->ref_length); lookup_handler->position(record_buffer); From d9e00770a31892588fe6293a70e81312eaf329a6 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Wed, 21 Oct 2020 02:04:37 +1000 Subject: [PATCH 318/323] MDEV-22608 ASAN use-after-poison in TABLE::check_period_overlaps The bug was fixed by MDEV-22599 bugfix, which changed `Field::cmp` call to `Field::cmp_prefix` in `TABLE::check_period_overlaps`. The trick is that `Field_bit::cmp` apparently calls `Field_bit::cmp_key`, which condiders an argument an actual pointer to data, which isn't correct for `Field_bit`, since it stores data by `bit_ptr`. which is in the beginning of the record, and using `ptr` is incorrect (we use it through `ptr_in_record` call) --- mysql-test/suite/period/r/overlaps.result | 7 +++++++ mysql-test/suite/period/t/overlaps.test | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/mysql-test/suite/period/r/overlaps.result b/mysql-test/suite/period/r/overlaps.result index 40d38fc5a56..d7eb1a92b2b 100644 --- a/mysql-test/suite/period/r/overlaps.result +++ b/mysql-test/suite/period/r/overlaps.result @@ -337,4 +337,11 @@ insert into t values (1,'1988-08-25','2024-03-06'); create or replace table t1 (a int) engine=myisam; insert into t1 values (1),(2); update t join t1 set s = '2020-01-01'; +# MDEV-22608 ASAN use-after-poison in TABLE::check_period_overlaps +create or replace table t1 (s date, e date, b bit, period for p(s,e), +unique(b, p without overlaps)) engine=myisam; +insert into t1 values ('2024-12-21','2034-06-29',0), +('2024-12-21','2034-06-29',1); +update t1 set b = 1; +ERROR 23000: Duplicate entry '\x01-2034-06-29-2024-12-21' for key 'b' drop table t, t1; diff --git a/mysql-test/suite/period/t/overlaps.test b/mysql-test/suite/period/t/overlaps.test index 17005878385..adf004ad405 100644 --- a/mysql-test/suite/period/t/overlaps.test +++ b/mysql-test/suite/period/t/overlaps.test @@ -324,4 +324,15 @@ insert into t1 values (1),(2); update t join t1 set s = '2020-01-01'; + +--echo # MDEV-22608 ASAN use-after-poison in TABLE::check_period_overlaps + +create or replace table t1 (s date, e date, b bit, period for p(s,e), + unique(b, p without overlaps)) engine=myisam; +insert into t1 values ('2024-12-21','2034-06-29',0), + ('2024-12-21','2034-06-29',1); +--error ER_DUP_ENTRY +update t1 set b = 1; + + drop table t, t1; From a79c6e369e8d07786395a04493f2142f41f7befc Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Thu, 22 Oct 2020 01:32:44 +1000 Subject: [PATCH 319/323] MDEV-22677 UPDATE crashes on partitioned HEAP table WITHOUT OVERLAPS `ha_heap::clone` was creating a handler by share's handlerton, which is partition handlerton. handler's handlerton should be used instead. Here in particular, HEAP handlerton will be used and it will create ha_heap handler. --- mysql-test/suite/period/r/overlaps.result | 6 ++++++ mysql-test/suite/period/t/overlaps.test | 8 ++++++++ storage/heap/ha_heap.cc | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/period/r/overlaps.result b/mysql-test/suite/period/r/overlaps.result index d7eb1a92b2b..efbbe7cf15b 100644 --- a/mysql-test/suite/period/r/overlaps.result +++ b/mysql-test/suite/period/r/overlaps.result @@ -344,4 +344,10 @@ insert into t1 values ('2024-12-21','2034-06-29',0), ('2024-12-21','2034-06-29',1); update t1 set b = 1; ERROR 23000: Duplicate entry '\x01-2034-06-29-2024-12-21' for key 'b' +# MDEV-22677 Server crashes in ha_partition::open upon update on +# partitioned HEAP table with WITHOUT OVERLAPS +create or replace table t (id int, s date, e date, period for p(s,e), +primary key(id, p without overlaps) +) engine=heap partition by hash(id); +update t set id = 1; drop table t, t1; diff --git a/mysql-test/suite/period/t/overlaps.test b/mysql-test/suite/period/t/overlaps.test index adf004ad405..6cd78769d4a 100644 --- a/mysql-test/suite/period/t/overlaps.test +++ b/mysql-test/suite/period/t/overlaps.test @@ -335,4 +335,12 @@ insert into t1 values ('2024-12-21','2034-06-29',0), update t1 set b = 1; +--echo # MDEV-22677 Server crashes in ha_partition::open upon update on +--echo # partitioned HEAP table with WITHOUT OVERLAPS + +create or replace table t (id int, s date, e date, period for p(s,e), + primary key(id, p without overlaps) + ) engine=heap partition by hash(id); +update t set id = 1; + drop table t, t1; diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc index f8c2e72ba4a..96f4f4dc53a 100644 --- a/storage/heap/ha_heap.cc +++ b/storage/heap/ha_heap.cc @@ -153,7 +153,7 @@ int ha_heap::close(void) handler *ha_heap::clone(const char *name, MEM_ROOT *mem_root) { - handler *new_handler= get_new_handler(table->s, mem_root, table->s->db_type()); + handler *new_handler= get_new_handler(table->s, mem_root, ht); if (new_handler && !new_handler->ha_open(table, file->s->name, table->db_stat, HA_OPEN_IGNORE_IF_LOCKED)) return new_handler; From e618f7e9f60acb89e6990d9f705f90220fda0252 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Tue, 20 Oct 2020 15:21:28 +1000 Subject: [PATCH 320/323] MDEV-22506 Malformed error message for ER_KEY_CONTAINS_PERIOD_FIELDS Though this is an error message task, the problem was deep in the `mysql_prepare_create_table` implementation. The problem is described as follows: 1. `append_system_key_parts` was called before `mysql_prepare_create_table`, though key name generation was done close to the latest stage of the latter. 2. We can't move `append_system_key_parts` in the end, because system keys should be appended before some checks done. 3. If the checks from `append_system_key_parts` are moved to the end of `mysql_prepare_create_table`, then some other inappropriate errors are issued. like `ER_DUP_FIELDNAME`. To have key name specified in error message, name generation should be done before the checks, which consequenced in more changes. The final design for key initialization in `mysql_prepare_create_table` follows. The initialization is done in three phases: 1. Calculate a total number of keys created with respect to keys ignored. Allocate KEY* buffer. 2. Generate unique names; calculate a total number of key parts. Make early checks. Allocate KEY_PART_INFO* buffer. 3. Initialize key parts, make the rest of the checks. --- mysql-test/suite/period/r/overlaps.result | 2 +- sql/sql_table.cc | 200 ++++++++++++---------- 2 files changed, 110 insertions(+), 92 deletions(-) diff --git a/mysql-test/suite/period/r/overlaps.result b/mysql-test/suite/period/r/overlaps.result index efbbe7cf15b..b8f23ce413c 100644 --- a/mysql-test/suite/period/r/overlaps.result +++ b/mysql-test/suite/period/r/overlaps.result @@ -127,7 +127,7 @@ ERROR HY000: Period `p` is not found in table create or replace table t(id int, s date, e date, period for p(s,e), primary key(id, s, p without overlaps)); -ERROR HY000: Key `(null)` cannot explicitly include column `s` +ERROR HY000: Key `PRIMARY` cannot explicitly include column `s` create or replace table t(id int, s date, e date, period for p(s,e), primary key(id)); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 67a505d78bc..c2ba9bcadfb 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -75,9 +75,8 @@ static int copy_data_between_tables(THD *, TABLE *,TABLE *, ha_rows *, ha_rows *, Alter_info::enum_enable_or_disable, Alter_table_ctx *); -static bool append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info, - Alter_info *alter_info, KEY **key_info, - uint key_count); +static int append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info, + Key *key); static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *, uint *, handler *, KEY **, uint *, int); static uint blob_length_by_type(enum_field_types type); @@ -1823,10 +1822,6 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) strxmov(shadow_frm_name, shadow_path, reg_ext, NullS); if (flags & WFRM_WRITE_SHADOW) { - if (append_system_key_parts(lpt->thd, lpt->create_info, lpt->alter_info, - &lpt->key_info_buffer, 0)) - DBUG_RETURN(true); - if (mysql_prepare_create_table(lpt->thd, lpt->create_info, lpt->alter_info, &lpt->db_options, lpt->table->file, &lpt->key_info_buffer, &lpt->key_count, @@ -3557,7 +3552,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, Create_field *sql_field,*dup_field; uint field,null_fields,max_key_length; ulong record_offset= 0; - KEY *key_info; KEY_PART_INFO *key_part_info; int field_no,dup_no; int select_field_pos,auto_increment=0; @@ -3875,6 +3869,57 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, thd->abort_on_warning= sav_abort_on_warning; } } + + KEY *key_info= *key_info_buffer= (KEY*)thd->calloc(sizeof(KEY) * (*key_count)); + if (!*key_info_buffer) + DBUG_RETURN(true); // Out of memory + + key_iterator.rewind(); + while ((key=key_iterator++)) + { + if (key->name.str == ignore_key || key->type == Key::FOREIGN_KEY) + continue; + /* Create the key->ame based on the first column (if not given) */ + if (key->type == Key::PRIMARY) + { + if (primary_key) + { + my_message(ER_MULTIPLE_PRI_KEY, ER_THD(thd, ER_MULTIPLE_PRI_KEY), + MYF(0)); + DBUG_RETURN(true); + } + key_name=primary_key_name; + primary_key=1; + } + else if (!(key_name= key->name.str)) + { + auto field_name= key->columns.elem(0)->field_name; + it.rewind(); + while ((sql_field=it++) && + lex_string_cmp(system_charset_info, + &field_name, + &sql_field->field_name)); + if (sql_field) + field_name= sql_field->field_name; + key_name=make_unique_key_name(thd, field_name.str, + *key_info_buffer, key_info); + } + if (check_if_keyname_exists(key_name, *key_info_buffer, key_info)) + { + my_error(ER_DUP_KEYNAME, MYF(0), key_name); + DBUG_RETURN(true); + } + + key_info->name.str= (char*) key_name; + key_info->name.length= strlen(key_name); + key->name= key_info->name; + + int parts_added= append_system_key_parts(thd, create_info, key); + if (parts_added < 0) + DBUG_RETURN(true); + key_parts += parts_added; + key_info++; + } tmp=file->max_keys(); if (*key_count > tmp) { @@ -3882,11 +3927,11 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, DBUG_RETURN(TRUE); } - (*key_info_buffer)= key_info= (KEY*) thd->calloc(sizeof(KEY) * (*key_count)); key_part_info=(KEY_PART_INFO*) thd->calloc(sizeof(KEY_PART_INFO)*key_parts); - if (!*key_info_buffer || ! key_part_info) - DBUG_RETURN(TRUE); // Out of memory + if (!key_part_info) + DBUG_RETURN(true); // Out of memory + key_info= *key_info_buffer; key_iterator.rewind(); key_number=0; for (; (key=key_iterator++) ; key_number++) @@ -4257,32 +4302,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, key_length+= key_part_length; key_part_info++; - - /* Create the key name based on the first column (if not given) */ - if (column_nr == 0) - { - if (key->type == Key::PRIMARY) - { - if (primary_key) - { - my_message(ER_MULTIPLE_PRI_KEY, ER_THD(thd, ER_MULTIPLE_PRI_KEY), - MYF(0)); - DBUG_RETURN(TRUE); - } - key_name=primary_key_name; - primary_key=1; - } - else if (!(key_name= key->name.str)) - key_name=make_unique_key_name(thd, sql_field->field_name.str, - *key_info_buffer, key_info); - if (check_if_keyname_exists(key_name, *key_info_buffer, key_info)) - { - my_error(ER_DUP_KEYNAME, MYF(0), key_name); - DBUG_RETURN(TRUE); - } - key_info->name.str= (char*) key_name; - key_info->name.length= strlen(key_name); - } } if (!key_info->name.str || check_column_name(key_info->name.str)) { @@ -4715,72 +4734,75 @@ bool Column_definition::sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root) } -static bool append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info, - Alter_info *alter_info, KEY **key_info, - uint key_count) +/** + Appends key parts generated by mariadb server. + Adds row_end in UNIQUE keys for system versioning, + and period fields for WITHOUT OVERLAPS. + @param thd Thread data + @param create_info Table create info + @param key Parsed key + @return a number of key parts added to key. + */ +static int append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info, + Key *key) { const Lex_ident &row_start_field= create_info->vers_info.as_row.start; const Lex_ident &row_end_field= create_info->vers_info.as_row.end; DBUG_ASSERT(!create_info->versioned() || (row_start_field && row_end_field)); - List_iterator key_it(alter_info->key_list); - Key *key= NULL; - - if (create_info->versioned()) + int result = 0; + if (create_info->versioned() && (key->type == Key::PRIMARY + || key->type == Key::UNIQUE)) { - while ((key=key_it++)) + Key_part_spec *key_part=NULL; + List_iterator part_it(key->columns); + while ((key_part=part_it++)) { - if (key->type != Key::PRIMARY && key->type != Key::UNIQUE) - continue; - - Key_part_spec *key_part=NULL; - List_iterator part_it(key->columns); - while ((key_part=part_it++)) - { - if (row_start_field.streq(key_part->field_name) || - row_end_field.streq(key_part->field_name)) - break; - } - if (!key_part) - key->columns.push_back(new (thd->mem_root) + if (row_start_field.streq(key_part->field_name) || + row_end_field.streq(key_part->field_name)) + break; + } + if (!key_part) + { + key->columns.push_back(new (thd->mem_root) Key_part_spec(&row_end_field, 0, true)); + result++; } - key_it.rewind(); + } - while ((key=key_it++)) + if (key->without_overlaps) { - if (key->without_overlaps) + DBUG_ASSERT(key->type == Key::PRIMARY || key->type == Key::UNIQUE); + if (!create_info->period_info.is_set() + || !key->period.streq(create_info->period_info.name)) { - DBUG_ASSERT(key->type == Key::PRIMARY || key->type == Key::UNIQUE); - if (!create_info->period_info.is_set() - || !key->period.streq(create_info->period_info.name)) - { - my_error(ER_PERIOD_NOT_FOUND, MYF(0), key->period.str); - return true; - } - - const auto &period_start= create_info->period_info.period.start; - const auto &period_end= create_info->period_info.period.end; - List_iterator part_it(key->columns); - while (Key_part_spec *key_part= part_it++) - { - if (period_start.streq(key_part->field_name) - || period_end.streq(key_part->field_name)) - { - my_error(ER_KEY_CONTAINS_PERIOD_FIELDS, MYF(0), key->name.str, - key_part->field_name); - return true; - } - } - key->columns.push_back(new (thd->mem_root) - Key_part_spec(&period_end, 0)); - key->columns.push_back(new (thd->mem_root) - Key_part_spec(&period_start, 0)); + my_error(ER_PERIOD_NOT_FOUND, MYF(0), key->period.str); + return -1; } + + const auto &period_start= create_info->period_info.period.start; + const auto &period_end= create_info->period_info.period.end; + List_iterator part_it(key->columns); + while (Key_part_spec *key_part= part_it++) + { + if (period_start.streq(key_part->field_name) + || period_end.streq(key_part->field_name)) + { + my_error(ER_KEY_CONTAINS_PERIOD_FIELDS, MYF(0), key->name.str, + key_part->field_name.str); + return -1; + } + } + const auto &period= create_info->period_info.period; + key->columns.push_back(new (thd->mem_root) + Key_part_spec(&period.end, 0, true)); + key->columns.push_back(new (thd->mem_root) + Key_part_spec(&period.start, 0, true)); + result += 2; } - return false; + return result; } handler *mysql_create_frm_image(THD *thd, const LEX_CSTRING &db, @@ -5018,10 +5040,6 @@ handler *mysql_create_frm_image(THD *thd, const LEX_CSTRING &db, } #endif - if (append_system_key_parts(thd, create_info, alter_info, key_info, - *key_count)) - goto err; - if (mysql_prepare_create_table(thd, create_info, alter_info, &db_options, file, key_info, key_count, create_table_mode)) goto err; From f244b499e736ac55ce5f31eee726096658b5cc6b Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Wed, 14 Oct 2020 15:40:46 +1000 Subject: [PATCH 321/323] handler: move row change start signal down after the checks --- sql/handler.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index 038effc3e5b..01825c13da6 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -7129,16 +7129,17 @@ int handler::ha_write_row(const uchar *buf) if ((error= ha_check_overlaps(NULL, buf))) DBUG_RETURN(error); - MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str); - mark_trx_read_write(); - increment_statistics(&SSV::ha_write_count); - if (table->s->long_unique_table && this == table->file) { DBUG_ASSERT(inited == NONE || lookup_handler != this); if ((error= check_duplicate_long_entries(buf))) DBUG_RETURN(error); } + + MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str); + mark_trx_read_write(); + increment_statistics(&SSV::ha_write_count); + TABLE_IO_WAIT(tracker, PSI_TABLE_WRITE_ROW, MAX_KEY, error, { error= write_row(buf); }) @@ -7181,10 +7182,6 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data) uint saved_status= table->status; error= ha_check_overlaps(old_data, new_data); - MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str); - mark_trx_read_write(); - increment_statistics(&SSV::ha_update_count); - if (!error && table->s->long_unique_table && this == table->file) error= check_duplicate_long_entries_update(new_data); table->status= saved_status; @@ -7192,6 +7189,9 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data) if (error) return error; + MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str); + mark_trx_read_write(); + increment_statistics(&SSV::ha_update_count); TABLE_IO_WAIT(tracker, PSI_TABLE_UPDATE_ROW, active_index, 0, { error= update_row(old_data, new_data);}) From 504d4c1ff6e0cecde9adfea320abd616d28b21a1 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 2 Nov 2020 10:07:05 +0100 Subject: [PATCH 322/323] Windows : require at least VS2019 for MSVC. This will avoid some errors on appveyor, due to outdated SDKs. --- appveyor.yml | 4 ++-- cmake/os/Windows.cmake | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 4a6a49fd8b5..4c83cb100b0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,7 +3,7 @@ version: build-{build}~branch-{branch} before_build: - md %APPVEYOR_BUILD_FOLDER%\win_build - cd %APPVEYOR_BUILD_FOLDER%\win_build - - cmake .. -G "Visual Studio 15 2017 Win64" -DWITH_UNIT_TESTS=0 -DWITH_MARIABACKUP=0 -DMYSQL_MAINTAINER_MODE=ERR -DPLUGIN_ROCKSDB=NO -DPLUGIN_CONNECT=NO -DBISON_EXECUTABLE=C:\cygwin64\bin\bison + - cmake .. -DWITH_UNIT_TESTS=0 -DWITH_MARIABACKUP=0 -DMYSQL_MAINTAINER_MODE=ERR -DPLUGIN_ROCKSDB=NO -DPLUGIN_CONNECT=NO -DBISON_EXECUTABLE=C:\cygwin64\bin\bison build: project: win_build\MySQL.sln @@ -18,4 +18,4 @@ test_script: - cd %APPVEYOR_BUILD_FOLDER%\win_build\mysql-test - perl mysql-test-run.pl --force --max-test-fail=10 --parallel=4 --testcase-timeout=10 --skip-test-list=unstable-tests --suite=main -image: Visual Studio 2017 +image: Visual Studio 2019 diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake index 1383a717bdc..29bd637250d 100644 --- a/cmake/os/Windows.cmake +++ b/cmake/os/Windows.cmake @@ -110,6 +110,9 @@ ENDMACRO() IF(MSVC) + IF(MSVC_VERSION LESS 1920) + MESSAGE(FATAL_ERROR "Visual Studio q2019 or later is required") + ENDIF() # Disable mingw based pkg-config found in Strawberry perl SET(PKG_CONFIG_EXECUTABLE 0 CACHE INTERNAL "") From 440d4b282dd4992d64abdd6289859598db7e5f75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 2 Nov 2020 10:53:37 +0200 Subject: [PATCH 323/323] Fix clang -Winconsistent-missing-override --- storage/maria/ha_s3.h | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/storage/maria/ha_s3.h b/storage/maria/ha_s3.h index 8fc607e6717..e16353b2a32 100644 --- a/storage/maria/ha_s3.h +++ b/storage/maria/ha_s3.h @@ -1,6 +1,6 @@ #ifndef HA_S3_INCLUDED #define HA_S3_INCLUDED -/* Copyright (C) 2019 MariaDB Corppration AB +/* Copyright (C) 2019, 2020, MariaDB Corporation 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 @@ -31,52 +31,50 @@ public: ~ha_s3() {} int create(const char *name, TABLE *table_arg, - HA_CREATE_INFO *ha_create_info); - int open(const char *name, int mode, uint open_flags); - int write_row(const uchar *buf); - int update_row(const uchar * old_data, const uchar * new_data) + HA_CREATE_INFO *ha_create_info) override; + int open(const char *name, int mode, uint open_flags) override; + int write_row(const uchar *buf) override; + int update_row(const uchar *, const uchar *) override { DBUG_ENTER("update_row"); DBUG_RETURN(HA_ERR_TABLE_READONLY); } - int delete_row(const uchar * buf) + int delete_row(const uchar *) override { DBUG_ENTER("delete_row"); DBUG_RETURN(HA_ERR_TABLE_READONLY); } - int check(THD * thd, HA_CHECK_OPT * check_opt) + int check(THD *, HA_CHECK_OPT *) override { DBUG_ENTER("delete_row"); DBUG_RETURN(HA_ERR_TABLE_READONLY); } - int analyze(THD * thd, HA_CHECK_OPT * check_opt) + int analyze(THD *, HA_CHECK_OPT *) override { DBUG_ENTER("analyze"); DBUG_RETURN(HA_ERR_TABLE_READONLY); } - int repair(THD * thd, HA_CHECK_OPT * check_opt) + int repair(THD *, HA_CHECK_OPT *) override { DBUG_ENTER("repair"); DBUG_RETURN(HA_ERR_TABLE_READONLY); } - int preload_keys(THD * thd, HA_CHECK_OPT * check_opt) + int preload_keys(THD *, HA_CHECK_OPT *) override { DBUG_ENTER("preload_keys"); DBUG_RETURN(HA_ERR_TABLE_READONLY); } - int external_lock(THD * thd, int lock_type); + int external_lock(THD * thd, int lock_type) override; /* drop_table() is only used for internal temporary tables, not applicable for s3 */ - void drop_table(const char *name) - { - } - int delete_table(const char *name); - int rename_table(const char *from, const char *to); + void drop_table(const char *) override {} + int delete_table(const char *name) override; + int rename_table(const char *from, const char *to) override; int discover_check_version() override; int rebind(); - S3_INFO *s3_open_args() { return open_args; } - void register_handler(MARIA_HA *file); + S3_INFO *s3_open_args() override { return open_args; } + void register_handler(MARIA_HA *file) override; }; #endif /* HA_S3_INCLUDED */

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 z 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