summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorNikita Malyavin <nikitamalyavin@gmail.com>2021-05-04 14:49:31 +0300
committerNikita Malyavin <nikitamalyavin@gmail.com>2021-05-04 14:49:31 +0300
commita8a925dd22ae00494cc9ffdc1ff68906106a408c (patch)
treea857c565a22ec7f6f41d3efa72053a726a346af2 /storage
parent2820f30dde3148df71e1d748ac705d98d60e0787 (diff)
parent72fa9dabadb4b0011f483ccbf1ef59e62d0ef1e0 (diff)
downloadmariadb-git-a8a925dd22ae00494cc9ffdc1ff68906106a408c.tar.gz
Merge branch bb-10.2-release into bb-10.3-release
Diffstat (limited to 'storage')
-rw-r--r--storage/connect/CMakeLists.txt3
-rw-r--r--storage/connect/bson.cpp18
-rw-r--r--storage/connect/bsonudf.cpp46
-rw-r--r--storage/connect/bsonudf.h3
-rw-r--r--storage/connect/cmgoconn.cpp6
-rw-r--r--storage/connect/ha_connect.cc62
-rw-r--r--storage/connect/javaconn.cpp21
-rw-r--r--storage/connect/jmgoconn.cpp9
-rw-r--r--storage/connect/json.cpp19
-rw-r--r--storage/connect/jsonudf.cpp206
-rw-r--r--storage/connect/jsonudf.h6
-rw-r--r--storage/connect/mysql-test/connect/r/json_udf.result10
-rw-r--r--storage/connect/tabbson.cpp32
-rw-r--r--storage/connect/tabbson.h3
-rw-r--r--storage/connect/tabjson.cpp120
-rw-r--r--storage/connect/tabjson.h10
-rw-r--r--storage/connect/tabrest.cpp208
-rw-r--r--storage/connect/tabxml.cpp19
-rw-r--r--storage/connect/valblk.h2
-rw-r--r--storage/innobase/dict/dict0dict.cc6
-rw-r--r--storage/innobase/fil/fil0fil.cc17
-rw-r--r--storage/innobase/handler/ha_innodb.cc52
-rw-r--r--storage/innobase/handler/i_s.cc3
-rw-r--r--storage/innobase/include/dict0mem.h5
-rw-r--r--storage/innobase/include/srv0srv.h10
-rw-r--r--storage/innobase/include/trx0trx.h4
-rw-r--r--storage/innobase/lock/lock0wait.cc33
-rw-r--r--storage/innobase/row/row0purge.cc20
-rw-r--r--storage/innobase/row/row0vers.cc1
-rw-r--r--storage/innobase/srv/srv0srv.cc17
-rw-r--r--storage/innobase/trx/trx0roll.cc3
-rw-r--r--storage/innobase/trx/trx0trx.cc13
-rw-r--r--storage/mroonga/CMakeLists.txt2
-rw-r--r--storage/myisam/ha_myisam.cc3
-rw-r--r--storage/perfschema/CMakeLists.txt3
35 files changed, 661 insertions, 334 deletions
diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt
index b69d1a04f54..4df76095f02 100644
--- a/storage/connect/CMakeLists.txt
+++ b/storage/connect/CMakeLists.txt
@@ -274,9 +274,6 @@ IF(CONNECT_WITH_JDBC)
Mongo2Interface.java Mongo3Interface.java
JavaWrappers.jar)
add_definitions(-DJAVA_SUPPORT)
- IF(CONNECT_WITH_MONGO)
- add_definitions(-DMONGO_SUPPORT)
- ENDIF()
ELSE()
SET(JDBC_LIBRARY "")
ENDIF()
diff --git a/storage/connect/bson.cpp b/storage/connect/bson.cpp
index 3c33551cb68..a0a421657bd 100644
--- a/storage/connect/bson.cpp
+++ b/storage/connect/bson.cpp
@@ -1138,6 +1138,9 @@ PBVAL BJSON::GetArrayValue(PBVAL bap, int n)
CheckType(bap, TYPE_JAR);
int i = 0;
+ if (n < 0)
+ n += GetArraySize(bap);
+
for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp), i++)
if (i == n)
return bvp;
@@ -1348,12 +1351,17 @@ PBVAL BJSON::NewVal(PVAL valp)
/***********************************************************************/
/* Sub-allocate and initialize a BVAL from another BVAL. */
/***********************************************************************/
-PBVAL BJSON::DupVal(PBVAL bvlp) {
- PBVAL bvp = NewVal();
+PBVAL BJSON::DupVal(PBVAL bvlp)
+{
+ if (bvlp) {
+ PBVAL bvp = NewVal();
+
+ *bvp = *bvlp;
+ bvp->Next = 0;
+ return bvp;
+ } else
+ return NULL;
- *bvp = *bvlp;
- bvp->Next = 0;
- return bvp;
} // end of DupVal
/***********************************************************************/
diff --git a/storage/connect/bsonudf.cpp b/storage/connect/bsonudf.cpp
index 29fe0a6bf22..a56db4d731b 100644
--- a/storage/connect/bsonudf.cpp
+++ b/storage/connect/bsonudf.cpp
@@ -117,7 +117,7 @@ BJNX::BJNX(PGLOBAL g) : BDOC(g)
Jp = NULL;
Nodes = NULL;
Value = NULL;
- MulVal = NULL;
+ //MulVal = NULL;
Jpath = NULL;
Buf_Type = TYPE_STRING;
Long = len;
@@ -148,7 +148,7 @@ BJNX::BJNX(PGLOBAL g, PBVAL row, int type, int len, int prec, my_bool wr) : BDOC
Jp = NULL;
Nodes = NULL;
Value = AllocateValue(g, type, len, prec);
- MulVal = NULL;
+ //MulVal = NULL;
Jpath = NULL;
Buf_Type = type;
Long = len;
@@ -273,40 +273,6 @@ my_bool BJNX::SetArrayOptions(PGLOBAL g, char* p, int i, PSZ nm)
return true;
} // endif's
-#if 0
- // For calculated arrays, a local Value must be used
- switch (jnp->Op) {
- case OP_NUM:
- jnp->Valp = AllocateValue(g, TYPE_INT);
- break;
- case OP_ADD:
- case OP_MULT:
- case OP_SEP:
- if (!IsTypeChar(Buf_Type))
- jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision());
- else
- jnp->Valp = AllocateValue(g, TYPE_DOUBLE, 0, 2);
-
- break;
- case OP_MIN:
- case OP_MAX:
- jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision());
- break;
- case OP_CNC:
- if (IsTypeChar(Buf_Type))
- jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision());
- else
- jnp->Valp = AllocateValue(g, TYPE_STRING, 512);
-
- break;
- default:
- break;
- } // endswitch Op
-
- if (jnp->Valp)
- MulVal = AllocateValue(g, jnp->Valp);
-#endif // 0
-
return false;
} // end of SetArrayOptions
@@ -452,6 +418,8 @@ PBVAL BJNX::MakeJson(PGLOBAL g, PBVAL bvp, int n)
{
PBVAL vlp, jvp = bvp;
+ Jb = false;
+
if (n < Nod -1) {
if (bvp->Type == TYPE_JAR) {
int ars = GetArraySize(bvp);
@@ -3022,7 +2990,7 @@ void bson_object_grp_add(UDF_INIT *initid, UDF_ARGS *args, char*, char*)
PBVAL bop = (PBVAL)g->Activityp;
if (g->N-- > 0)
- bxp->SetKeyValue(bop, bxp->MakeValue(args, 1), MakePSZ(g, args, 0));
+ bxp->SetKeyValue(bop, bxp->MakeValue(args, 1), MakePSZ(g, args, 0));
} // end of bson_object_grp_add
@@ -3710,7 +3678,7 @@ char *bson_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
PUSH_WARNING("CheckMemory error");
goto fin;
} else {
- bnx.Reset();
+ bnx.Reset();
jvp = bnx.MakeValue(args, 0, true);
if (g->Mrr) { // First argument is a constant
@@ -4056,7 +4024,7 @@ double bsonget_real(UDF_INIT *initid, UDF_ARGS *args,
*is_null = 1;
return 0.0;
} else {
- bnx.Reset();
+ bnx.Reset();
jvp = bnx.MakeValue(args, 0);
if ((p = bnx.GetString(jvp))) {
diff --git a/storage/connect/bsonudf.h b/storage/connect/bsonudf.h
index bbfd1ceed80..0fe3715617e 100644
--- a/storage/connect/bsonudf.h
+++ b/storage/connect/bsonudf.h
@@ -41,7 +41,6 @@ typedef struct _jnode {
PSZ Key; // The key used for object
OPVAL Op; // Operator used for this node
PVAL CncVal; // To cont value used for OP_CNC
- PVAL Valp; // The internal array VALUE
int Rank; // The rank in array
int Rx; // Read row number
int Nx; // Next to read row number
@@ -153,7 +152,7 @@ protected:
JOUTSTR *Jp;
JNODE *Nodes; // The intermediate objects
PVAL Value;
- PVAL MulVal; // To value used by multiple column
+ //PVAL MulVal; // To value used by multiple column
char *Jpath; // The json path
int Buf_Type;
int Long;
diff --git a/storage/connect/cmgoconn.cpp b/storage/connect/cmgoconn.cpp
index edee1874b97..474f940a8cf 100644
--- a/storage/connect/cmgoconn.cpp
+++ b/storage/connect/cmgoconn.cpp
@@ -150,6 +150,12 @@ void CMgoConn::mongo_init(bool init)
/***********************************************************************/
bool CMgoConn::Connect(PGLOBAL g)
{
+ if (!Pcg->Db_name || !Pcg->Coll_name) {
+ // This would crash in mongoc_client_get_collection
+ strcpy(g->Message, "Missing DB or collection name");
+ return true;
+ } // endif name
+
if (!IsInit)
#if defined(__WIN__)
__try {
diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc
index c470529db86..06c68c846c9 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 January 27, 2021";
+ char version[]= "Version 1.07.0002 March 22, 2021";
#if defined(__WIN__)
char compver[]= "Version 1.07.0002 " __DATE__ " " __TIME__;
char slash= '\\';
@@ -275,6 +275,10 @@ static handler *connect_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root);
+static bool checkPrivileges(THD* thd, TABTYPE type, PTOS options,
+ const char* db, TABLE* table = NULL,
+ bool quick = false);
+
static int connect_assisted_discovery(handlerton *hton, THD* thd,
TABLE_SHARE *table_s,
HA_CREATE_INFO *info);
@@ -757,8 +761,8 @@ DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir)
For engines that have two file name extensions (separate meta/index file
and data file), the order of elements is relevant. First element of engine
- file name extensions array should be meta/index file extention. Second
- element - data file extention. This order is assumed by
+ file name extensions array should be meta/index file extension. Second
+ element - data file extension. This order is assumed by
prepare_for_repair() when REPAIR TABLE ... USE_FRM is issued.
@see
@@ -1294,9 +1298,9 @@ PCSZ GetStringTableOption(PGLOBAL g, PTOS options, PCSZ opname, PCSZ sdef)
else if (!stricmp(opname, "Data_charset"))
opval= options->data_charset;
else if (!stricmp(opname, "Http") || !stricmp(opname, "URL"))
- opval = options->http;
+ opval= options->http;
else if (!stricmp(opname, "Uri"))
- opval = options->uri;
+ opval= options->uri;
if (!opval && options->oplist)
opval= GetListOption(g, opname, options->oplist);
@@ -1610,7 +1614,7 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf)
pcf->Opt= (fop) ? (int)fop->opt : 0;
if (fp->field_length >= 0) {
- pcf->Length = fp->field_length;
+ pcf->Length= fp->field_length;
// length is bytes for Connect, not characters
if (!strnicmp(chset, "utf8", 4))
@@ -1625,7 +1629,7 @@ 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 = fop->fieldformat ? (char*)fop->fieldformat
+ pcf->Fieldfmt= fop->fieldformat ? (char*)fop->fieldformat
: fop->jsonpath ? (char*)fop->jsonpath : (char*)fop->xmlpath;
} else {
pcf->Offset= -1;
@@ -4508,11 +4512,9 @@ int ha_connect::delete_all_rows()
} // end of delete_all_rows
-bool ha_connect::check_privileges(THD *thd, PTOS options, const char *dbn, bool quick)
+static bool checkPrivileges(THD *thd, TABTYPE type, PTOS options,
+ const char *db, TABLE *table, bool quick)
{
- const char *db= (dbn && *dbn) ? dbn : NULL;
- TABTYPE type=GetRealType(options);
-
switch (type) {
case TAB_UNDEF:
// case TAB_CATLG:
@@ -4595,6 +4597,16 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, const char *dbn, bool
my_printf_error(ER_UNKNOWN_ERROR, "check_privileges failed", MYF(0));
return true;
+} // end of checkPrivileges
+
+// Check whether the user has required (file) privileges
+bool ha_connect::check_privileges(THD *thd, PTOS options, const char *dbn,
+ bool quick)
+{
+ const char *db= (dbn && *dbn) ? dbn : NULL;
+ TABTYPE type=GetRealType(options);
+
+ return checkPrivileges(thd, type, options, db, table, quick);
} // end of check_privileges
// Check that two indexes are equivalent
@@ -5388,12 +5400,7 @@ 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;
-#else
char var = (len > 255) ? 'V' : v;
-#endif
bool q, error = false;
const char* type = PLGtoMYSQLtype(typ, dbf, var);
@@ -5729,6 +5736,29 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
#endif // REST_SUPPORT
} // endif ttp
+ if (fn && *fn)
+ switch (ttp) {
+ case TAB_FMT:
+ case TAB_DBF:
+ case TAB_XML:
+ case TAB_INI:
+ case TAB_VEC:
+ case TAB_REST:
+ case TAB_JSON:
+#if defined(BSON_SUPPORT)
+ case TAB_BSON:
+#endif // BSON_SUPPORT
+ if (checkPrivileges(thd, ttp, topt, db)) {
+ strcpy(g->Message, "This operation requires the FILE privilege");
+ rc= HA_ERR_INTERNAL_ERROR;
+ goto err;
+ } // endif check_privileges
+
+ break;
+ default:
+ break;
+ } // endswitch ttp
+
if (!tab) {
if (ttp == TAB_TBL) {
// Make tab the first table of the list
diff --git a/storage/connect/javaconn.cpp b/storage/connect/javaconn.cpp
index e3f64d17064..cdf925d63a7 100644
--- a/storage/connect/javaconn.cpp
+++ b/storage/connect/javaconn.cpp
@@ -1,7 +1,7 @@
/************ Javaconn C++ Functions Source Code File (.CPP) ***********/
-/* Name: JAVAConn.CPP Version 1.0 */
+/* Name: JAVAConn.CPP Version 1.1 */
/* */
-/* (C) Copyright to the author Olivier BERTRAND 2017 */
+/* (C) Copyright to the author Olivier BERTRAND 2017 - 2021 */
/* */
/* This file contains the JAVA connection classes functions. */
/***********************************************************************/
@@ -400,24 +400,35 @@ bool JAVAConn::Open(PGLOBAL g)
jpop->Append(ClassPath);
} // endif ClassPath
- // Java source will be compiled as a jar file installed in the plugin dir
+#if 0
+ // Java source will be compiled as a jar file installed in the plugin dir
jpop->Append(sep);
jpop->Append(GetPluginDir());
jpop->Append("JdbcInterface.jar");
+#endif // 0
// All wrappers are pre-compiled in JavaWrappers.jar in the plugin dir
jpop->Append(sep);
jpop->Append(GetPluginDir());
jpop->Append("JavaWrappers.jar");
+#if defined(MONGO_SUPPORT)
+ jpop->Append(sep);
+ jpop->Append(GetPluginDir());
+ jpop->Append("Mongo3.jar");
+ jpop->Append(sep);
+ jpop->Append(GetPluginDir());
+ jpop->Append("Mongo2.jar");
+#endif // MONGO_SUPPORT
+
if ((cp = getenv("CLASSPATH"))) {
jpop->Append(sep);
jpop->Append(cp);
} // endif cp
if (trace(1)) {
- htrc("ClassPath=%s\n", ClassPath);
- htrc("CLASSPATH=%s\n", cp);
+ htrc("ClassPath=%s\n", ClassPath ? ClassPath : "null");
+ htrc("CLASSPATH=%s\n", cp ? cp : "null");
htrc("%s\n", jpop->GetStr());
} // endif trace
diff --git a/storage/connect/jmgoconn.cpp b/storage/connect/jmgoconn.cpp
index 8a12fffbd05..0af91bc78cd 100644
--- a/storage/connect/jmgoconn.cpp
+++ b/storage/connect/jmgoconn.cpp
@@ -121,20 +121,21 @@ JMgoConn::JMgoConn(PGLOBAL g, PCSZ collname, PCSZ wrapper)
/***********************************************************************/
void JMgoConn::AddJars(PSTRG jpop, char sep)
{
-#if defined(BSON_SUPPORT)
+#if defined(DEVELOPMENT)
if (m_Version == 2) {
jpop->Append(sep);
// jpop->Append("C:/Eclipse/workspace/MongoWrap2/bin");
- jpop->Append(sep);
+// jpop->Append(sep);
jpop->Append("C:/mongo-java-driver/mongo-java-driver-2.13.3.jar");
} else {
jpop->Append(sep);
// jpop->Append("C:/Eclipse/workspace/MongoWrap3/bin");
+// jpop->Append(sep);
// jpop->Append("C:/Program Files/MariaDB 10.1/lib/plugin/JavaWrappers.jar");
- jpop->Append(sep);
+// jpop->Append(sep);
jpop->Append("C:/mongo-java-driver/mongo-java-driver-3.4.2.jar");
} // endif m_Version
-#endif // BSON_SUPPORT
+#endif // DEVELOPMENT
} // end of AddJars
/***********************************************************************/
diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp
index 0152a44fffa..f65294429db 100644
--- a/storage/connect/json.cpp
+++ b/storage/connect/json.cpp
@@ -54,15 +54,24 @@ char *GetExceptionDesc(PGLOBAL g, unsigned int e);
#endif // SE_CATCH
char *GetJsonNull(void);
+int GetDefaultPrec(void);
/***********************************************************************/
/* IsNum: check whether this string is all digits. */
/***********************************************************************/
-bool IsNum(PSZ s) {
- for (char* p = s; *p; p++)
+bool IsNum(PSZ s)
+{
+ char* p = s;
+
+ if (*p == '-')
+ p++;
+
+ if (*p == ']')
+ return false;
+ else for (; *p; p++)
if (*p == ']')
break;
- else if (!isdigit(*p) || *p == '-')
+ else if (!isdigit(*p))
return false;
return true;
@@ -1257,6 +1266,8 @@ PJVAL JARRAY::GetArrayValue(int i)
{
if (Mvals && i >= 0 && i < Size)
return Mvals[i];
+ else if (Mvals && i < 0 && i >= -Size)
+ return Mvals[Size + i];
else
return NULL;
} // end of GetValue
@@ -1752,7 +1763,7 @@ void JVALUE::SetBigint(PGLOBAL g, long long ll)
void JVALUE::SetFloat(PGLOBAL g, double f)
{
F = f;
- Nd = 6;
+ Nd = GetDefaultPrec();
DataType = TYPE_DBL;
} // end of SetFloat
diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp
index 1891560357b..c1eb81d3486 100644
--- a/storage/connect/jsonudf.cpp
+++ b/storage/connect/jsonudf.cpp
@@ -72,7 +72,7 @@ JSNX::JSNX(PGLOBAL g, PJSON row, int type, int len, int prec, my_bool wr)
Jp = NULL;
Nodes = NULL;
Value = AllocateValue(g, type, len, prec);
- MulVal = NULL;
+ //MulVal = NULL;
Jpath = NULL;
Buf_Type = type;
Long = len;
@@ -198,38 +198,6 @@ my_bool JSNX::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
return true;
} // endif's
- // For calculated arrays, a local Value must be used
- switch (jnp->Op) {
- case OP_NUM:
- jnp->Valp = AllocateValue(g, TYPE_INT);
- break;
- case OP_ADD:
- case OP_MULT:
- case OP_SEP:
- if (!IsTypeChar(Buf_Type))
- jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision());
- else
- jnp->Valp = AllocateValue(g, TYPE_DOUBLE, 0, 2);
-
- break;
- case OP_MIN:
- case OP_MAX:
- jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision());
- break;
- case OP_CNC:
- if (IsTypeChar(Buf_Type))
- jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision());
- else
- jnp->Valp = AllocateValue(g, TYPE_STRING, 512);
-
- break;
- default:
- break;
- } // endswitch Op
-
- if (jnp->Valp)
- MulVal = AllocateValue(g, jnp->Valp);
-
return false;
} // end of SetArrayOptions
@@ -312,7 +280,7 @@ my_bool JSNX::ParseJpath(PGLOBAL g)
} // endfor i, p
Nod = i;
- MulVal = AllocateValue(g, Value);
+ //MulVal = AllocateValue(g, Value);
if (trace(1))
for (i = 0; i < Nod; i++)
@@ -324,23 +292,6 @@ my_bool JSNX::ParseJpath(PGLOBAL g)
} // end of ParseJpath
/*********************************************************************************/
-/* MakeJson: Serialize the json item and set value to it. */
-/*********************************************************************************/
-PVAL JSNX::MakeJson(PGLOBAL g, PJSON jsp)
-{
- if (Value->IsTypeNum()) {
- strcpy(g->Message, "Cannot make Json for a numeric value");
- Value->Reset();
- } else if (jsp->GetType() != TYPE_JAR && jsp->GetType() != TYPE_JOB) {
- strcpy(g->Message, "Target is not an array or object");
- Value->Reset();
- } else
- Value->SetValue_psz(Serialize(g, jsp, NULL, 0));
-
- return Value;
-} // end of MakeJson
-
-/*********************************************************************************/
/* SetValue: Set a value from a JVALUE contains. */
/*********************************************************************************/
void JSNX::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val)
@@ -350,6 +301,7 @@ void JSNX::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val)
if (Jb) {
vp->SetValue_psz(Serialize(g, val->GetJsp(), NULL, 0));
+ Jb = false;
} else switch (val->GetValType()) {
case TYPE_DTM:
case TYPE_STRG:
@@ -395,6 +347,52 @@ void JSNX::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val)
} // end of SetJsonValue
/*********************************************************************************/
+/* MakeJson: Serialize the json item and set value to it. */
+/*********************************************************************************/
+PJVAL JSNX::MakeJson(PGLOBAL g, PJSON jsp, int n)
+{
+ Jb = false;
+
+ if (Value->IsTypeNum()) {
+ strcpy(g->Message, "Cannot make Json for a numeric value");
+ return NULL;
+ } else if (jsp->GetType() != TYPE_JAR && jsp->GetType() != TYPE_JOB) {
+ strcpy(g->Message, "Target is not an array or object");
+ return NULL;
+ } else if (n < Nod -1) {
+ if (jsp->GetType() == TYPE_JAR) {
+ int ars = jsp->GetSize(false);
+ PJNODE jnp = &Nodes[n];
+ PJAR jarp = new(g) JARRAY;
+
+ jnp->Op = OP_EQ;
+
+ for (jnp->Rank = 0; jnp->Rank < ars; jnp->Rank++)
+ jarp->AddArrayValue(g, GetRowValue(g, jsp, n));
+
+ jarp->InitArray(g);
+ jnp->Op = OP_XX;
+ jnp->Rank = 0;
+ jsp = jarp;
+ } else if(jsp->GetType() == TYPE_JOB) {
+ PJSON jp;
+ PJOB jobp = new(g) JOBJECT;
+
+ for (PJPR prp = ((PJOB)jsp)->GetFirst(); prp; prp = prp->Next) {
+ jp = (prp->Val->DataType == TYPE_JSON) ? prp->Val->Jsp : prp->Val;
+ jobp->SetKeyValue(g, GetRowValue(g, jp, n + 1), prp->Key);
+ } // endfor prp
+
+ jsp = jobp;
+ } // endif Type
+
+ } // endif
+
+ Jb = true;
+ return new(g) JVALUE(jsp);
+} // end of MakeJson
+
+/*********************************************************************************/
/* GetJson: */
/*********************************************************************************/
PJVAL JSNX::GetJson(PGLOBAL g)
@@ -437,8 +435,7 @@ PJVAL JSNX::GetRowValue(PGLOBAL g, PJSON row, int i, my_bool b)
val = new(g) JVALUE(g, Value);
return val;
} else if (Nodes[i].Op == OP_XX) {
- Jb = b;
- return new(g)JVALUE(row);
+ return MakeJson(g, row, i);
} else switch (row->GetType()) {
case TYPE_JOB:
if (!Nodes[i].Key) {
@@ -505,6 +502,88 @@ PVAL JSNX::ExpandArray(PGLOBAL g, PJAR arp, int n)
} // end of ExpandArray
/*********************************************************************************/
+/* Get the value used for calculating the array. */
+/*********************************************************************************/
+PVAL JSNX::GetCalcValue(PGLOBAL g, PJAR jap, int n)
+{
+ // For calculated arrays, a local Value must be used
+ int lng = 0;
+ short type, prec = 0;
+ bool b = n < Nod - 1;
+ PVAL valp;
+ PJVAL vlp, vp;
+ OPVAL op = Nodes[n].Op;
+
+ switch (op) {
+ case OP_NUM:
+ type = TYPE_INT;
+ break;
+ case OP_ADD:
+ case OP_MULT:
+ if (!IsTypeNum(Buf_Type)) {
+ type = TYPE_INT;
+ prec = 0;
+
+ for (vlp = jap->GetArrayValue(0); vlp; vlp = vlp->Next) {
+ vp = (b && vlp->GetJsp()) ? GetRowValue(g, vlp, n + 1) : vlp;
+
+ switch (vp->DataType) {
+ case TYPE_BINT:
+ if (type == TYPE_INT)
+ type = TYPE_BIGINT;
+
+ break;
+ case TYPE_DBL:
+ case TYPE_FLOAT:
+ type = TYPE_DOUBLE;
+ prec = MY_MAX(prec, vp->Nd);
+ break;
+ default:
+ break;
+ } // endswitch Type
+
+ } // endfor vlp
+
+ } else {
+ type = Buf_Type;
+ prec = GetPrecision();
+ } // endif Buf_Type
+
+ break;
+ case OP_SEP:
+ if (IsTypeChar(Buf_Type)) {
+ type = TYPE_DOUBLE;
+ prec = 2;
+ } else {
+ type = Buf_Type;
+ prec = GetPrecision();
+ } // endif Buf_Type
+
+ break;
+ case OP_MIN:
+ case OP_MAX:
+ type = Buf_Type;
+ lng = Long;
+ prec = GetPrecision();
+ break;
+ case OP_CNC:
+ type = TYPE_STRING;
+
+ if (IsTypeChar(Buf_Type)) {
+ lng = (Long) ? Long : 512;
+ prec = GetPrecision();
+ } else
+ lng = 512;
+
+ break;
+ default:
+ break;
+ } // endswitch Op
+
+ return valp = AllocateValue(g, type, lng, prec);
+} // end of GetCalcValue
+
+/*********************************************************************************/
/* CalculateArray: */
/*********************************************************************************/
PVAL JSNX::CalculateArray(PGLOBAL g, PJAR arp, int n)
@@ -512,7 +591,8 @@ PVAL JSNX::CalculateArray(PGLOBAL g, PJAR arp, int n)
int i, ars = arp->size(), nv = 0;
bool err;
OPVAL op = Nodes[n].Op;
- PVAL val[2], vp = Nodes[n].Valp;
+ PVAL val[2], vp = GetCalcValue(g, arp, n);
+ PVAL mulval = AllocateValue(g, vp);
PJVAL jvrp, jvp;
JVALUE jval;
@@ -545,9 +625,9 @@ PVAL JSNX::CalculateArray(PGLOBAL g, PJAR arp, int n)
SetJsonValue(g, vp, jvp);
continue;
} else
- SetJsonValue(g, MulVal, jvp);
+ SetJsonValue(g, mulval, jvp);
- if (!MulVal->IsNull()) {
+ if (!mulval->IsNull()) {
switch (op) {
case OP_CNC:
if (Nodes[n].CncVal) {
@@ -555,18 +635,18 @@ PVAL JSNX::CalculateArray(PGLOBAL g, PJAR arp, int n)
err = vp->Compute(g, val, 1, op);
} // endif CncVal
- val[0] = MulVal;
+ val[0] = mulval;
err = vp->Compute(g, val, 1, op);
break;
// case OP_NUM:
case OP_SEP:
- val[0] = Nodes[n].Valp;
- val[1] = MulVal;
+ val[0] = vp;
+ val[1] = mulval;
err = vp->Compute(g, val, 2, OP_ADD);
break;
default:
- val[0] = Nodes[n].Valp;
- val[1] = MulVal;
+ val[0] = vp;
+ val[1] = mulval;
err = vp->Compute(g, val, 2, op);
} // endswitch Op
@@ -588,9 +668,9 @@ PVAL JSNX::CalculateArray(PGLOBAL g, PJAR arp, int n)
if (op == OP_SEP) {
// Calculate average
- MulVal->SetValue(nv);
+ mulval->SetValue(nv);
val[0] = vp;
- val[1] = MulVal;
+ val[1] = mulval;
if (vp->Compute(g, val, 2, OP_DIV))
vp->Reset();
diff --git a/storage/connect/jsonudf.h b/storage/connect/jsonudf.h
index 689a02ebbc5..ada0dbcd96b 100644
--- a/storage/connect/jsonudf.h
+++ b/storage/connect/jsonudf.h
@@ -44,7 +44,6 @@ typedef struct _jnode {
PSZ Key; // The key used for object
OPVAL Op; // Operator used for this node
PVAL CncVal; // To cont value used for OP_CNC
- PVAL Valp; // The internal array VALUE
int Rank; // The rank in array
int Rx; // Read row number
int Nx; // Next to read row number
@@ -334,8 +333,9 @@ protected:
my_bool SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm);
PVAL GetColumnValue(PGLOBAL g, PJSON row, int i);
PVAL ExpandArray(PGLOBAL g, PJAR arp, int n);
+ PVAL GetCalcValue(PGLOBAL g, PJAR bap, int n);
PVAL CalculateArray(PGLOBAL g, PJAR arp, int n);
- PVAL MakeJson(PGLOBAL g, PJSON jsp);
+ PJVAL MakeJson(PGLOBAL g, PJSON jsp, int i);
void SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val);
PJSON GetRow(PGLOBAL g);
my_bool CompareValues(PJVAL v1, PJVAL v2);
@@ -358,7 +358,7 @@ protected:
JOUTSTR *Jp;
JNODE *Nodes; // The intermediate objects
PVAL Value;
- PVAL MulVal; // To value used by multiple column
+ //PVAL MulVal; // To value used by multiple column
char *Jpath; // The json path
int Buf_Type;
int Long;
diff --git a/storage/connect/mysql-test/connect/r/json_udf.result b/storage/connect/mysql-test/connect/r/json_udf.result
index 8315fc3f3bf..e3ee84d9084 100644
--- a/storage/connect/mysql-test/connect/r/json_udf.result
+++ b/storage/connect/mysql-test/connect/r/json_udf.result
@@ -322,7 +322,7 @@ JsonGet_String(Json_Make_Array(45,28,36,45,89),'3')
45
SELECT JsonGet_String(Json_Make_Array(45,28,36,45,89),'["+"]') "list",'=' as "egal",JsonGet_String(Json_Make_Array(45,28,36,45,89),'[+]') "sum";
list egal sum
-45+28+36+45+89 = 243.00
+45+28+36+45+89 = 243
SELECT JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)),'1.0');
JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)),'1.0')
36
@@ -349,10 +349,10 @@ Warnings:
Warning 1105
SELECT department, JsonGet_String(Json_Make_Object(department, Json_Array_Grp(salary) "Json_salaries"),'salaries.[+]') Sumsal FROM t3 GROUP BY department;
department Sumsal
-0021 28500.00
-0318 72230.00
-0319 89800.95
-2452 45900.00
+0021 28500.000000
+0318 72230.000000
+0319 89800.950000
+2452 45900.000000
SELECT JsonGet_Int(@j1, '4');
JsonGet_Int(@j1, '4')
89
diff --git a/storage/connect/tabbson.cpp b/storage/connect/tabbson.cpp
index db63b8e78db..8477d22d364 100644
--- a/storage/connect/tabbson.cpp
+++ b/storage/connect/tabbson.cpp
@@ -1,6 +1,6 @@
/************* tabbson C++ Program Source Code File (.CPP) *************/
-/* PROGRAM NAME: tabbson Version 1.0 */
-/* (C) Copyright to the author Olivier BERTRAND 2020 */
+/* PROGRAM NAME: tabbson Version 1.1 */
+/* (C) Copyright to the author Olivier BERTRAND 2020 - 2021 */
/* This program are the BSON class DB execution routines. */
/***********************************************************************/
@@ -158,8 +158,9 @@ BSONDISC::BSONDISC(PGLOBAL g, uint* lg)
bp = NULL;
row = NULL;
sep = NULL;
+ strfy = NULL;
i = n = bf = ncol = lvl = sz = limit = 0;
- all = strfy = false;
+ all = false;
} // end of BSONDISC constructor
int BSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
@@ -173,7 +174,7 @@ int BSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
sep = GetStringTableOption(g, topt, "Separator", ".");
sz = GetIntegerTableOption(g, topt, "Jsize", 1024);
limit = GetIntegerTableOption(g, topt, "Limit", 10);
- strfy = GetBooleanTableOption(g, topt, "Stringify", false);
+ strfy = GetStringTableOption(g, topt, "Stringify", NULL);
/*********************************************************************/
/* Open the input file. */
@@ -186,6 +187,9 @@ int BSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
#endif // ZIP_SUPPORT
tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL);
+ if (!tdp->Fn && topt->http)
+ tdp->Fn = GetStringTableOption(g, topt, "Subtype", NULL);
+
if (!(tdp->Database = SetPath(g, db)))
return 0;
@@ -199,7 +203,8 @@ int BSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
if (!tdp->Fn && !tdp->Uri) {
strcpy(g->Message, MSG(MISSING_FNAME));
return 0;
- } // endif Fn
+ } else
+ topt->subtype = NULL;
if (tdp->Fn) {
// We used the file name relative to recorded datapath
@@ -428,7 +433,7 @@ bool BSONDISC::Find(PGLOBAL g, PBVAL jvp, PCSZ key, int j)
jcol.Type = TYPE_UNKNOWN;
jcol.Len = jcol.Scale = 0;
jcol.Cbn = true;
- } else if (j < lvl) {
+ } else if (j < lvl && !(strfy && !stricmp(strfy, colname))) {
if (!fmt[bf])
strcat(fmt, colname);
@@ -499,7 +504,7 @@ bool BSONDISC::Find(PGLOBAL g, PBVAL jvp, PCSZ key, int j)
} // endswitch Type
} else if (lvl >= 0) {
- if (strfy) {
+ if (strfy && !stricmp(strfy, colname)) {
if (!fmt[bf])
strcat(fmt, colname);
@@ -731,7 +736,6 @@ void BCUTIL::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL jvp)
case TYPE_FLOAT:
switch (vp->GetType()) {
case TYPE_STRING:
- case TYPE_DATE:
case TYPE_DECIM:
vp->SetValue_psz(GetString(jvp));
break;
@@ -750,6 +754,16 @@ void BCUTIL::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL jvp)
vp->SetPrec(jvp->Nd);
break;
+ case TYPE_DATE:
+ if (jvp->Type == TYPE_STRG) {
+ if (!((DTVAL*)vp)->IsFormatted())
+ ((DTVAL*)vp)->SetFormat(g, "YYYY-MM-DDThh:mm:ssZ", 20, 0);
+
+ vp->SetValue_psz(GetString(jvp));
+ } else
+ vp->SetValue(GetInteger(jvp));
+
+ break;
default:
sprintf(G->Message, "Unsupported column type %d", vp->GetType());
throw 888;
@@ -881,7 +895,7 @@ PBVAL BCUTIL::GetRowValue(PGLOBAL g, PBVAL row, int i)
} // endfor i
return bvp;
-} // end of GetColumnValue
+} // end of GetRowValue
/***********************************************************************/
/* GetColumnValue: */
diff --git a/storage/connect/tabbson.h b/storage/connect/tabbson.h
index adb02dd28e4..e9c5cc6477f 100644
--- a/storage/connect/tabbson.h
+++ b/storage/connect/tabbson.h
@@ -44,10 +44,11 @@ public:
PBPR row;
PBTUT bp;
PCSZ sep;
+ PCSZ strfy;
char colname[65], fmt[129], buf[16];
uint *length;
int i, n, bf, ncol, lvl, sz, limit;
- bool all, strfy;
+ bool all;
}; // end of BSONDISC
/***********************************************************************/
diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp
index fb5a64c7d55..dee4b737a89 100644
--- a/storage/connect/tabjson.cpp
+++ b/storage/connect/tabjson.cpp
@@ -1,6 +1,6 @@
/************* tabjson C++ Program Source Code File (.CPP) *************/
/* PROGRAM NAME: tabjson Version 1.8 */
-/* (C) Copyright to the author Olivier BERTRAND 2014 - 2020 */
+/* (C) Copyright to the author Olivier BERTRAND 2014 - 2021 */
/* This program are the JSON class DB execution routines. */
/***********************************************************************/
#undef BSON_SUPPORT
@@ -9,6 +9,8 @@
/* Include relevant sections of the MariaDB header file. */
/***********************************************************************/
#include <my_global.h>
+#include <mysqld.h>
+#include <sql_error.h>
/***********************************************************************/
/* Include application header files: */
@@ -160,22 +162,24 @@ JSONDISC::JSONDISC(PGLOBAL g, uint *lg)
jsp = NULL;
row = NULL;
sep = NULL;
+ strfy = NULL;
i = n = bf = ncol = lvl = sz = limit = 0;
- all = strfy = false;
+ all = false;
} // end of JSONDISC constructor
int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
{
char filename[_MAX_PATH];
+ size_t reclg = 0;
bool mgo = (GetTypeID(topt->type) == TAB_MONGO);
PGLOBAL G = NULL;
lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth());
lvl = GetIntegerTableOption(g, topt, "Depth", lvl);
sep = GetStringTableOption(g, topt, "Separator", ".");
- sz = GetIntegerTableOption(g, topt, "Jsize", 1024);
+ strfy = GetStringTableOption(g, topt, "Stringify", NULL);
+ sz = GetIntegerTableOption(g, topt, "Jsize", 250);
limit = GetIntegerTableOption(g, topt, "Limit", 10);
- strfy = GetBooleanTableOption(g, topt, "Stringify", false);
/*********************************************************************/
/* Open the input file. */
@@ -187,6 +191,9 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
#endif // ZIP_SUPPORT
tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL);
+ if (!tdp->Fn && topt->http)
+ tdp->Fn = GetStringTableOption(g, topt, "Subtype", NULL);
+
if (!(tdp->Database = SetPath(g, db)))
return 0;
@@ -200,7 +207,8 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
if (!tdp->Fn && !tdp->Uri) {
strcpy(g->Message, MSG(MISSING_FNAME));
return 0;
- } // endif Fn
+ } else
+ topt->subtype = NULL;
if (tdp->Fn) {
// We used the file name relative to recorded datapath
@@ -247,11 +255,11 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
jsp = (tjsp->GetDoc()) ? tjsp->GetDoc()->GetArrayValue(0) : NULL;
} else {
if (!((tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0)))) {
- if (!mgo) {
+ if (!mgo && !tdp->Uri) {
sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty);
return 0;
- } else
- tdp->Lrecl = 8192; // Should be enough
+ } else
+ tdp->Lrecl = 8192; // Should be enough
} // endif Lrecl
@@ -310,7 +318,9 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
case RC_FX:
goto err;
default:
-// jsp = tjnp->FindRow(g); // FindRow was done in ReadDB
+ if (tdp->Pretty != 2)
+ reclg = strlen(tjnp->To_Line);
+
jsp = tjnp->Row;
} // endswitch ReadDB
@@ -361,7 +371,9 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
case RC_FX:
goto err;
default:
-// jsp = tjnp->FindRow(g);
+ if (tdp->Pretty != 2 && reclg < strlen(tjnp->To_Line))
+ reclg = strlen(tjnp->To_Line);
+
jsp = tjnp->Row;
} // endswitch ReadDB
@@ -373,8 +385,12 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
} // endfor i
- if (tdp->Pretty != 2)
+ if (tdp->Pretty != 2) {
+ if (!topt->lrecl)
+ topt->lrecl = reclg + 10;
+
tjnp->CloseDB(g);
+ } // endif Pretty
return n;
@@ -426,7 +442,7 @@ bool JSONDISC::Find(PGLOBAL g, PJVAL jvp, PCSZ key, int j)
jcol.Type = TYPE_UNKNOWN;
jcol.Len = jcol.Scale = 0;
jcol.Cbn = true;
- } else if (j < lvl) {
+ } else if (j < lvl && !(strfy && !stricmp(strfy, colname))) {
if (!fmt[bf])
strcat(fmt, colname);
@@ -480,9 +496,8 @@ bool JSONDISC::Find(PGLOBAL g, PJVAL jvp, PCSZ key, int j)
strncat(strncat(colname, "_", n), buf, n - 1);
} // endif all
- } else {
+ } else
strncat(fmt, (tdp->Uri ? sep : "[*]"), n);
- }
if (Find(g, jar->GetArrayValue(k), "", j))
return true;
@@ -497,7 +512,7 @@ bool JSONDISC::Find(PGLOBAL g, PJVAL jvp, PCSZ key, int j)
} // endswitch Type
} else if (lvl >= 0) {
- if (strfy) {
+ if (strfy && !stricmp(strfy, colname)) {
if (!fmt[bf])
strcat(fmt, colname);
@@ -1610,7 +1625,7 @@ PSZ JSONCOL::GetJpath(PGLOBAL g, bool proj)
/***********************************************************************/
/* MakeJson: Serialize the json item and set value to it. */
/***********************************************************************/
-PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp)
+PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp, int n)
{
if (Value->IsTypeNum()) {
strcpy(g->Message, "Cannot make Json for a numeric column");
@@ -1621,6 +1636,7 @@ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp)
} // endif Warned
Value->Reset();
+ return Value;
#if 0
} else if (Value->GetType() == TYPE_BIN) {
if ((unsigned)Value->GetClen() >= sizeof(BSON)) {
@@ -1634,13 +1650,66 @@ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp)
Value->SetValue_char(NULL, 0);
} // endif Clen
#endif // 0
- } else
- Value->SetValue_psz(Serialize(g, jsp, NULL, 0));
+ } else if (n < Nod - 1) {
+ if (jsp->GetType() == TYPE_JAR) {
+ int ars = jsp->GetSize(false);
+ PJNODE jnp = &Nodes[n];
+ PJAR jvp = new(g) JARRAY;
+
+ for (jnp->Rank = 0; jnp->Rank < ars; jnp->Rank++)
+ jvp->AddArrayValue(g, GetRowValue(g, jsp, n));
+ jnp->Rank = 0;
+ jvp->InitArray(g);
+ jsp = jvp;
+ } else if (jsp->Type == TYPE_JOB) {
+ PJOB jvp = new(g) JOBJECT;
+
+ for (PJPR prp = ((PJOB)jsp)->GetFirst(); prp; prp = prp->Next)
+ jvp->SetKeyValue(g, GetRowValue(g, prp->Val, n + 1), prp->Key);
+
+ jsp = jvp;
+ } // endif Type
+
+ } // endif
+
+ Value->SetValue_psz(Serialize(g, jsp, NULL, 0));
return Value;
} // end of MakeJson
/***********************************************************************/
+/* GetRowValue: */
+/***********************************************************************/
+PJVAL JSONCOL::GetRowValue(PGLOBAL g, PJSON row, int i)
+{
+ int n = Nod - 1;
+ PJVAL val = NULL;
+
+ for (; i < Nod && row; i++) {
+ switch (row->GetType()) {
+ case TYPE_JOB:
+ val = (Nodes[i].Key) ? ((PJOB)row)->GetKeyValue(Nodes[i].Key) : NULL;
+ break;
+ case TYPE_JAR:
+ val = ((PJAR)row)->GetArrayValue(Nodes[i].Rank);
+ break;
+ case TYPE_JVAL:
+ val = (PJVAL)row;
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->GetType());
+ val = NULL;
+ } // endswitch Type
+
+ if (i < Nod-1)
+ row = (val) ? val->GetJson() : NULL;
+
+ } // endfor i
+
+ return val;
+} // end of GetRowValue
+
+/***********************************************************************/
/* SetValue: Set a value from a JVALUE contains. */
/***********************************************************************/
void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL jvp)
@@ -1656,7 +1725,6 @@ void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL jvp)
case TYPE_DTM:
switch (vp->GetType()) {
case TYPE_STRING:
- case TYPE_DATE:
vp->SetValue_psz(jvp->GetString(g));
break;
case TYPE_INT:
@@ -1674,7 +1742,17 @@ void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL jvp)
vp->SetPrec(jvp->Nd);
break;
- default:
+ case TYPE_DATE:
+ if (jvp->GetValType() == TYPE_STRG) {
+ if (!((DTVAL*)vp)->IsFormatted())
+ ((DTVAL*)vp)->SetFormat(g, "YYYY-MM-DDThh:mm:ssZ", 20, 0);
+
+ vp->SetValue_psz(jvp->GetString(g));
+ } else
+ vp->SetValue(jvp->GetInteger());
+
+ break;
+ default:
sprintf(g->Message, "Unsupported column type %d\n", vp->GetType());
throw 888;
} // endswitch Type
@@ -1740,7 +1818,7 @@ PVAL JSONCOL::GetColumnValue(PGLOBAL g, PJSON row, int i)
Value->SetValue(row->GetType() == TYPE_JAR ? ((PJAR)row)->size() : 1);
return(Value);
} else if (Nodes[i].Op == OP_XX) {
- return MakeJson(G, row);
+ return MakeJson(G, row, i);
} else switch (row->GetType()) {
case TYPE_JOB:
if (!Nodes[i].Key) {
diff --git a/storage/connect/tabjson.h b/storage/connect/tabjson.h
index b47dc9b0665..1062928d410 100644
--- a/storage/connect/tabjson.h
+++ b/storage/connect/tabjson.h
@@ -1,7 +1,7 @@
/*************** tabjson H Declares Source Code File (.H) **************/
/* Name: tabjson.h Version 1.3 */
/* */
-/* (C) Copyright to the author Olivier BERTRAND 2014 - 2018 */
+/* (C) Copyright to the author Olivier BERTRAND 2014 - 2021 */
/* */
/* This file contains the JSON classes declares. */
/***********************************************************************/
@@ -67,10 +67,11 @@ public:
PJSON jsp;
PJOB row;
PCSZ sep;
+ PCSZ strfy;
char colname[65], fmt[129], buf[16];
uint *length;
int i, n, bf, ncol, lvl, sz, limit;
- bool all, strfy;
+ bool all;
}; // end of JSONDISC
/***********************************************************************/
@@ -230,8 +231,9 @@ public:
PVAL GetColumnValue(PGLOBAL g, PJSON row, int i);
PVAL ExpandArray(PGLOBAL g, PJAR arp, int n);
PVAL CalculateArray(PGLOBAL g, PJAR arp, int n);
- PVAL MakeJson(PGLOBAL g, PJSON jsp);
- void SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val);
+ PVAL MakeJson(PGLOBAL g, PJSON jsp, int n);
+ PJVAL GetRowValue(PGLOBAL g, PJSON row, int i);
+ void SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val);
PJSON GetRow(PGLOBAL g);
// Default constructor not to be used
diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp
index 1efda6e3bca..4b6bb6a9e62 100644
--- a/storage/connect/tabrest.cpp
+++ b/storage/connect/tabrest.cpp
@@ -1,8 +1,7 @@
/************** tabrest C++ Program Source Code File (.CPP) ************/
-/* PROGRAM NAME: tabrest Version 1.8 */
-/* (C) Copyright to the author Olivier BERTRAND 2018 - 2020 */
+/* PROGRAM NAME: tabrest Version 2.0 */
+/* (C) Copyright to the author Olivier BERTRAND 2018 - 2021 */
/* This program is the REST Web API support for MariaDB. */
-/* When compiled without MARIADB defined, it is the EOM module code. */
/* The way Connect handles NOSQL data returned by REST queries is */
/* just by retrieving it as a file and then leave the existing data */
/* type tables (JSON, XML or CSV) process it as usual. */
@@ -11,23 +10,13 @@
/***********************************************************************/
/* Definitions needed by the included files. */
/***********************************************************************/
-#if defined(MARIADB)
#include <my_global.h> // All MariaDB stuff
#include <mysqld.h>
#include <sql_error.h>
-#else // !MARIADB OEM module
-#include "mini-global.h"
-#define _MAX_PATH 260
-#if !defined(REST_SOURCE)
-#if defined(__WIN__) || defined(_WINDOWS)
-#include <windows.h>
-#else // !__WIN__
-#define __stdcall
-#include <dlfcn.h> // dlopen(), dlclose(), dlsym() ...
-#endif // !__WIN__
-#endif // !REST_SOURCE
-#define _OS_H_INCLUDED // Prevent os.h to be called
-#endif // !MARIADB
+#if !defined(__WIN__) && !defined(_WINDOWS)
+#include <sys/types.h>
+#include <sys/wait.h>
+#endif // !__WIN__ && !_WINDOWS
/***********************************************************************/
/* Include application header files: */
@@ -53,74 +42,98 @@
#define PUSH_WARNING(M) htrc(M)
#endif
-#if defined(__WIN__) || defined(_WINDOWS)
-#define popen _popen
-#define pclose _pclose
-#endif
-
static XGETREST getRestFnc = NULL;
static int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename);
-#if !defined(MARIADB)
-/***********************************************************************/
-/* DB static variables. */
-/***********************************************************************/
-int TDB::Tnum;
-int DTVAL::Shift;
-int CSORT::Limit = 0;
-double CSORT::Lg2 = log(2.0);
-size_t CSORT::Cpn[1000] = { 0 };
-
-/***********************************************************************/
-/* These functions are exported from the REST library. */
-/***********************************************************************/
-extern "C" {
- PTABDEF __stdcall GetREST(PGLOBAL, void*);
- PQRYRES __stdcall ColREST(PGLOBAL, PTOS, char*, char*, bool);
-} // extern "C"
-
-/***********************************************************************/
-/* This function returns a table definition class. */
-/***********************************************************************/
-PTABDEF __stdcall GetREST(PGLOBAL g, void *memp)
-{
- return new(g, memp) RESTDEF;
-} // end of GetREST
-#endif // !MARIADB
-
/***********************************************************************/
/* Xcurl: retrieve the REST answer by executing cURL. */
/***********************************************************************/
int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename)
{
- char buf[1024];
- int rc;
- FILE *pipe;
+ char buf[512];
+ int rc = 0;
+
+ if (strchr(filename, '"')) {
+ strcpy(g->Message, "Invalid file name");
+ return 1;
+ } // endif filename
if (Uri) {
if (*Uri == '/' || Http[strlen(Http) - 1] == '/')
- sprintf(buf, "curl %s%s -o %s", Http, Uri, filename);
+ sprintf(buf, "%s%s", Http, Uri);
else
- sprintf(buf, "curl %s/%s -o %s", Http, Uri, filename);
+ sprintf(buf, "%s/%s", Http, Uri);
} else
- sprintf(buf, "curl %s -o %s", Http, filename);
+ strcpy(buf, Http);
+
+#if defined(__WIN__)
+ char cmd[1024];
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ sprintf(cmd, "curl \"%s\" -o \"%s\"", buf, filename);
+
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ ZeroMemory(&pi, sizeof(pi));
+
+ // Start the child process.
+ if (CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
+ // Wait until child process exits.
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ // Close process and thread handles.
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ } else {
+ sprintf(g->Message, "CreateProcess curl failed (%d)", GetLastError());
+ rc = 1;
+ } // endif CreateProcess
+#else // !__WIN__
+ char fn[600];
+ pid_t pID;
- if ((pipe = popen(buf, "rt"))) {
- if (trace(515))
- while (fgets(buf, sizeof(buf), pipe)) {
- htrc("%s", buf);
- } // endwhile
+ // Check if curl package is availabe by executing subprocess
+ FILE *f= popen("command -v curl", "r");
- pclose(pipe);
- rc = 0;
+ if (!f) {
+ strcpy(g->Message, "Problem in allocating memory.");
+ return 1;
} else {
- sprintf(g->Message, "curl failed, errno =%d", errno);
+ char temp_buff[50];
+ size_t len = fread(temp_buff,1, 50, f);
+
+ if(!len) {
+ strcpy(g->Message, "Curl not installed.");
+ return 1;
+ } else
+ pclose(f);
+
+ } // endif f
+
+ pID = vfork();
+ sprintf(fn, "-o%s", filename);
+
+ if (pID == 0) {
+ // Code executed by child process
+ execlp("curl", "curl", buf, fn, (char*)NULL);
+
+ // If execlp() is successful, we should not reach this next line.
+ strcpy(g->Message, "Unsuccessful execlp from vfork()");
+ exit(1);
+ } else if (pID < 0) {
+ // failed to fork
+ strcpy(g->Message, "Failed to fork");
rc = 1;
- } // endif pipe
+ } else {
+ // Parent process
+ wait(NULL); // Wait for the child to terminate
+ } // endif pID
+#endif // !__WIN__
return rc;
-} // end od Xcurl
+} // end of Xcurl
/***********************************************************************/
/* GetREST: load the Rest lib and get the Rest function. */
@@ -130,7 +143,7 @@ XGETREST GetRestFunction(PGLOBAL g)
if (getRestFnc)
return getRestFnc;
-#if !defined(MARIADB) || !defined(REST_SOURCE)
+#if !defined(REST_SOURCE)
if (trace(515))
htrc("Looking for GetRest library\n");
@@ -183,9 +196,9 @@ XGETREST GetRestFunction(PGLOBAL g)
return NULL;
} // endif getdef
#endif // !__WIN__
-#else
+#else // REST_SOURCE
getRestFnc = restGetFile;
-#endif
+#endif // REST_SOURCE
return getRestFnc;
} // end of GetRestFunction
@@ -193,30 +206,21 @@ XGETREST GetRestFunction(PGLOBAL g)
/***********************************************************************/
/* Return the columns definition to MariaDB. */
/***********************************************************************/
-#if defined(MARIADB)
PQRYRES RESTColumns(PGLOBAL g, PTOS tp, char *tab, char *db, bool info)
-#else // !MARIADB
-PQRYRES __stdcall ColREST(PGLOBAL g, PTOS tp, char *tab, char *db, bool info)
-#endif // !MARIADB
{
PQRYRES qrp= NULL;
char filename[_MAX_PATH + 1]; // MAX PATH ???
int rc;
- bool curl = false;
PCSZ http, uri, fn, ftype;
- XGETREST grf = GetRestFunction(g);
+ XGETREST grf = NULL;
+ bool curl = GetBooleanTableOption(g, tp, "Curl", false);
- if (!grf)
+ if (!curl && !(grf = GetRestFunction(g)))
curl = true;
http = GetStringTableOption(g, tp, "Http", NULL);
uri = GetStringTableOption(g, tp, "Uri", NULL);
-#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) {
@@ -230,28 +234,25 @@ PQRYRES __stdcall ColREST(PGLOBAL g, PTOS tp, char *tab, char *db, bool info)
filename[n + i] = tolower(ftype[i]);
fn = filename;
- tp->filename = PlugDup(g, fn);
+ tp->subtype = PlugDup(g, fn);
sprintf(g->Message, "No file name. Table will use %s", fn);
PUSH_WARNING(g->Message);
} // endif fn
// We used the file name relative to recorded datapath
PlugSetPath(filename, fn, db);
- curl = GetBooleanTableOption(g, tp, "Curl", curl);
+ remove(filename);
// Retrieve the file from the web and copy it locally
if (curl)
rc = Xcurl(g, http, uri, filename);
- else if (grf)
+ else
rc = grf(g->Message, trace(515), http, uri, filename);
- else {
- strcpy(g->Message, "Cannot access to curl nor casablanca");
- rc = 1;
- } // endif !grf
- if (rc)
+ if (rc) {
+ strcpy(g->Message, "Cannot access to curl nor casablanca");
return NULL;
- else if (!stricmp(ftype, "JSON"))
+ } else if (!stricmp(ftype, "JSON"))
qrp = JSONColumns(g, db, NULL, tp, info);
else if (!stricmp(ftype, "CSV"))
qrp = CSVColumns(g, NULL, tp, info);
@@ -274,19 +275,15 @@ bool RESTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
{
char filename[_MAX_PATH + 1];
int rc = 0, n;
- bool curl = false, xt = trace(515);
+ bool xt = trace(515);
LPCSTR ftype;
- XGETREST grf = GetRestFunction(g);
+ XGETREST grf = NULL;
+ bool curl = GetBoolCatInfo("Curl", false);
- if (!grf)
+ if (!curl && !(grf = GetRestFunction(g)))
curl = true;
-#if defined(MARIADB)
ftype = GetStringCatInfo(g, "Type", "JSON");
-#else // !MARIADB
- // OEM tables must specify the file type
- ftype = GetStringCatInfo(g, "Ftype", "JSON");
-#endif // !MARIADB
if (xt)
htrc("ftype = %s am = %s\n", ftype, SVP(am));
@@ -309,24 +306,21 @@ bool RESTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
// We used the file name relative to recorded datapath
PlugSetPath(filename, Fn, GetPath());
-
- curl = GetBoolCatInfo("Curl", curl);
+ remove(filename);
// Retrieve the file from the web and copy it locally
if (curl) {
rc = Xcurl(g, Http, Uri, filename);
xtrc(515, "Return from Xcurl: rc=%d\n", rc);
- } else if (grf) {
+ } else {
rc = grf(g->Message, xt, Http, Uri, filename);
xtrc(515, "Return from restGetFile: rc=%d\n", rc);
- } else {
- strcpy(g->Message, "Cannot access to curl nor casablanca");
- rc = 1;
- } // endif !grf
+ } // endelse
- if (rc)
- return true;
- else switch (n) {
+ if (rc) {
+ // strcpy(g->Message, "Cannot access to curl nor casablanca");
+ return true;
+ } else switch (n) {
case 1: Tdp = new (g) JSONDEF; break;
#if defined(XML_SUPPORT)
case 2: Tdp = new (g) XMLDEF; break;
diff --git a/storage/connect/tabxml.cpp b/storage/connect/tabxml.cpp
index 6c9e9597cec..6065bb1b5d2 100644
--- a/storage/connect/tabxml.cpp
+++ b/storage/connect/tabxml.cpp
@@ -148,14 +148,21 @@ PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info)
/* Open the input file. */
/*********************************************************************/
if (!(fn = GetStringTableOption(g, topt, "Filename", NULL))) {
- strcpy(g->Message, MSG(MISSING_FNAME));
- return NULL;
- } else {
- lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth());
- lvl = GetIntegerTableOption(g, topt, "Depth", lvl);
- lvl = (lvl < 0) ? 0 : (lvl > 16) ? 16 : lvl;
+ if (topt->http) // REST table can have default filename
+ fn = GetStringTableOption(g, topt, "Subtype", NULL);
+
+ if (!fn) {
+ strcpy(g->Message, MSG(MISSING_FNAME));
+ return NULL;
+ } else
+ topt->subtype = NULL;
+
} // endif fn
+ lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth());
+ lvl = GetIntegerTableOption(g, topt, "Depth", lvl);
+ lvl = (lvl < 0) ? 0 : (lvl > 16) ? 16 : lvl;
+
if (trace(1))
htrc("File %s lvl=%d\n", topt->filename, lvl);
diff --git a/storage/connect/valblk.h b/storage/connect/valblk.h
index ad970105868..568fc172c6a 100644
--- a/storage/connect/valblk.h
+++ b/storage/connect/valblk.h
@@ -69,7 +69,7 @@ class VALBLK : public BLOCK {
int GetPrec(void) {return Prec;}
void SetCheck(bool b) {Check = b;}
void MoveNull(int i, int j)
- {if (To_Nulls) To_Nulls[j] = To_Nulls[j];}
+ {if (To_Nulls) To_Nulls[j] = To_Nulls[i];}
virtual void SetNull(int n, bool b)
{if (To_Nulls) {To_Nulls[n] = (b) ? '*' : 0;}}
virtual bool IsNull(int n) {return To_Nulls && To_Nulls[n];}
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 1f05eb80e5d..10b878c0e49 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -6587,3 +6587,9 @@ dict_table_t::get_overflow_field_local_len() const
/* up to MySQL 5.1: store a 768-byte prefix locally */
return BTR_EXTERN_FIELD_REF_SIZE + DICT_ANTELOPE_MAX_INDEX_COL_LEN;
}
+
+bool dict_table_t::is_stats_table() const
+{
+ return !strcmp(name.m_name, TABLE_STATS_NAME) ||
+ !strcmp(name.m_name, INDEX_STATS_NAME);
+}
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index 9b91fdd879f..3d4d65eccfd 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
-Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2014, 2020, MariaDB Corporation.
+Copyright (c) 1995, 2021, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2021, 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
@@ -3777,7 +3777,7 @@ fil_ibd_load(
space = fil_space_get_by_id(space_id);
mutex_exit(&fil_system.mutex);
- if (space != NULL) {
+ if (space) {
/* Compare the filename we are trying to open with the
filename from the first node of the tablespace we opened
previously. Fail if it is different. */
@@ -3789,8 +3789,8 @@ fil_ibd_load(
<< "' with space ID " << space->id
<< ". Another data file called " << node->name
<< " exists with the same space ID.";
- space = NULL;
- return(FIL_LOAD_ID_CHANGED);
+ space = NULL;
+ return(FIL_LOAD_ID_CHANGED);
}
return(FIL_LOAD_OK);
}
@@ -3827,13 +3827,6 @@ fil_ibd_load(
os_offset_t minimum_size;
case DB_SUCCESS:
if (file.space_id() != space_id) {
- ib::info()
- << "Ignoring data file '"
- << file.filepath()
- << "' with space ID " << file.space_id()
- << ", since the redo log references "
- << file.filepath() << " with space ID "
- << space_id << ".";
return(FIL_LOAD_ID_CHANGED);
}
/* Get and test the file size. */
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index c5b65160827..2f02fa31c98 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -5270,13 +5270,19 @@ ha_innobase::index_type(
{
dict_index_t* index = innobase_get_index(keynr);
- if (index && index->type & DICT_FTS) {
+ if (!index) {
+ return "Corrupted";
+ }
+
+ if (index->type & DICT_FTS) {
return("FULLTEXT");
- } else if (dict_index_is_spatial(index)) {
+ }
+
+ if (dict_index_is_spatial(index)) {
return("SPATIAL");
- } else {
- return("BTREE");
}
+
+ return("BTREE");
}
/****************************************************************//**
@@ -18835,6 +18841,33 @@ innodb_log_checksums_update(THD* thd, st_mysql_sys_var*, void* var_ptr,
thd, *static_cast<const my_bool*>(save));
}
+#ifdef UNIV_DEBUG
+static
+void
+innobase_debug_sync_callback(srv_slot_t *slot, const void *value)
+{
+ const char *value_str = *static_cast<const char* const*>(value);
+ size_t len = strlen(value_str) + 1;
+
+
+ // One allocation for list node object and value.
+ void *buf = ut_malloc_nokey(sizeof(srv_slot_t::debug_sync_t) + len-1);
+ srv_slot_t::debug_sync_t *sync = new(buf) srv_slot_t::debug_sync_t();
+ strcpy(sync->str, value_str);
+
+ rw_lock_x_lock(&slot->debug_sync_lock);
+ UT_LIST_ADD_LAST(slot->debug_sync, sync);
+ rw_lock_x_unlock(&slot->debug_sync_lock);
+}
+static
+void
+innobase_debug_sync_set(THD *thd, st_mysql_sys_var*, void *, const void *value)
+{
+ srv_for_each_thread(SRV_WORKER, innobase_debug_sync_callback, value);
+ srv_for_each_thread(SRV_PURGE, innobase_debug_sync_callback, value);
+}
+#endif
+
static SHOW_VAR innodb_status_variables_export[]= {
{"Innodb", (char*) &show_innodb_vars, SHOW_FUNC},
{NullS, NullS, SHOW_LONG}
@@ -20399,6 +20432,16 @@ static MYSQL_SYSVAR_BOOL(debug_force_scrubbing,
0,
"Perform extra scrubbing to increase test exposure",
NULL, NULL, FALSE);
+
+char *innobase_debug_sync;
+static MYSQL_SYSVAR_STR(debug_sync, innobase_debug_sync,
+ PLUGIN_VAR_NOCMDARG,
+ "debug_sync for innodb purge threads. "
+ "Use it to set up sync points for all purge threads "
+ "at once. The commands will be applied sequentially at"
+ " the beginning of purging the next undo record.",
+ NULL,
+ innobase_debug_sync_set, NULL);
#endif /* UNIV_DEBUG */
static MYSQL_SYSVAR_BOOL(encrypt_temporary_tables, innodb_encrypt_temporary_tables,
@@ -20612,6 +20655,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(background_scrub_data_check_interval),
#ifdef UNIV_DEBUG
MYSQL_SYSVAR(debug_force_scrubbing),
+ MYSQL_SYSVAR(debug_sync),
#endif
MYSQL_SYSVAR(buf_dump_status_frequency),
MYSQL_SYSVAR(background_thread),
diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
index d8cb0b67ab5..206756ec09b 100644
--- a/storage/innobase/handler/i_s.cc
+++ b/storage/innobase/handler/i_s.cc
@@ -2880,7 +2880,8 @@ i_s_fts_deleted_generic_fill(
if (!user_table) {
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(0);
- } else if (!dict_table_has_fts_index(user_table)) {
+ } else if (!dict_table_has_fts_index(user_table)
+ || !user_table->is_readable()) {
dict_table_close(user_table, FALSE, FALSE);
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(0);
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 40c343652fb..a4ac79a0d6d 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -2115,6 +2115,11 @@ public:
return true;
return false;
}
+
+ /** Check whether the table name is same as mysql/innodb_stats_table
+ or mysql/innodb_index_stats.
+ @return true if the table name is same as stats table */
+ bool is_stats_table() const;
};
inline void dict_index_t::set_modified(mtr_t& mtr) const
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
index 6aa079676a0..ae05d45e257 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -1119,6 +1119,16 @@ struct srv_slot_t{
to do */
que_thr_t* thr; /*!< suspended query thread
(only used for user threads) */
+#ifdef UNIV_DEBUG
+ struct debug_sync_t {
+ UT_LIST_NODE_T(debug_sync_t)
+ debug_sync_list;
+ char str[1];
+ };
+ UT_LIST_BASE_NODE_T(debug_sync_t)
+ debug_sync;
+ rw_lock_t debug_sync_lock;
+#endif
};
#ifdef UNIV_DEBUG
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index c1572a0d07f..7cd11bf5496 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -1119,6 +1119,10 @@ public:
ut_ad(old_n_ref > 0);
}
+ /** @return whether the table has lock on
+ mysql.innodb_table_stats and mysql.innodb_index_stats */
+ bool has_stats_table_lock() const;
+
/** Free the memory to trx_pools */
void free();
diff --git a/storage/innobase/lock/lock0wait.cc b/storage/innobase/lock/lock0wait.cc
index 90fe1ccd626..3291198e376 100644
--- a/storage/innobase/lock/lock0wait.cc
+++ b/storage/innobase/lock/lock0wait.cc
@@ -192,28 +192,33 @@ wsrep_is_BF_lock_timeout(
const trx_t* trx,
bool locked = true)
{
- if (trx->is_wsrep() && wsrep_thd_is_BF(trx->mysql_thd, FALSE)
- && trx->error_state != DB_DEADLOCK) {
- ib::info() << "WSREP: BF lock wait long for trx:" << ib::hex(trx->id)
+ bool long_wait= (trx->error_state != DB_DEADLOCK &&
+ trx->is_wsrep() &&
+ wsrep_thd_is_BF(trx->mysql_thd, false));
+ bool was_wait= true;
+
+ DBUG_EXECUTE_IF("wsrep_instrument_BF_lock_wait",
+ was_wait=false; long_wait=true;);
+
+ if (long_wait) {
+ ib::info() << "WSREP: BF lock wait long for trx:" << trx->id
<< " query: " << wsrep_thd_query(trx->mysql_thd);
- if (!locked) {
+
+ if (!locked)
lock_mutex_enter();
- }
ut_ad(lock_mutex_own());
trx_print_latched(stderr, trx, 3000);
+ /* Note this will release lock_sys mutex */
+ lock_print_info_all_transactions(stderr);
- if (!locked) {
- lock_mutex_exit();
- }
+ if (locked)
+ lock_mutex_enter();
- srv_print_innodb_monitor = TRUE;
- srv_print_innodb_lock_monitor = TRUE;
- os_event_set(srv_monitor_event);
- return true;
- }
- return false;
+ return was_wait;
+ } else
+ return false;
}
#endif /* WITH_WSREP */
diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc
index 6a7f5921aa3..e57a63bc8e2 100644
--- a/storage/innobase/row/row0purge.cc
+++ b/storage/innobase/row/row0purge.cc
@@ -46,6 +46,7 @@ Created 3/14/1997 Heikki Tuuri
#include "handler.h"
#include "ha_innodb.h"
#include "fil0fil.h"
+#include "debug_sync.h"
/*************************************************************************
IMPORTANT NOTE: Any operation that generates redo MUST check that there
@@ -1306,6 +1307,25 @@ row_purge_step(
node->start();
+#ifdef UNIV_DEBUG
+ srv_slot_t *slot = thr->thread_slot;
+ ut_ad(slot);
+
+ rw_lock_x_lock(&slot->debug_sync_lock);
+ while (UT_LIST_GET_LEN(slot->debug_sync)) {
+ srv_slot_t::debug_sync_t *sync =
+ UT_LIST_GET_FIRST(slot->debug_sync);
+ bool result = debug_sync_set_action(current_thd,
+ sync->str,
+ strlen(sync->str));
+ ut_a(!result);
+
+ UT_LIST_REMOVE(slot->debug_sync, sync);
+ ut_free(sync);
+ }
+ rw_lock_x_unlock(&slot->debug_sync_lock);
+#endif
+
if (!(node->undo_recs == NULL || ib_vector_is_empty(node->undo_recs))) {
trx_purge_rec_t*purge_rec;
diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc
index cde4e9e7b89..a5ef82405d4 100644
--- a/storage/innobase/row/row0vers.cc
+++ b/storage/innobase/row/row0vers.cc
@@ -466,6 +466,7 @@ row_vers_build_clust_v_col(
vcol_info->set_used();
maria_table = vcol_info->table();
}
+ DEBUG_SYNC(current_thd, "ib_clust_v_col_before_row_allocated");
ib_vcol_row vc(NULL);
byte *record = vc.record(thd, index, &maria_table);
diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
index 3da92d48feb..9d19a14cb66 100644
--- a/storage/innobase/srv/srv0srv.cc
+++ b/storage/innobase/srv/srv0srv.cc
@@ -2518,6 +2518,13 @@ DECLARE_THREAD(srv_worker_thread)(
slot = srv_reserve_slot(SRV_WORKER);
+#ifdef UNIV_DEBUG
+ UT_LIST_INIT(slot->debug_sync,
+ &srv_slot_t::debug_sync_t::debug_sync_list);
+ rw_lock_create(PFS_NOT_INSTRUMENTED, &slot->debug_sync_lock,
+ SYNC_NO_ORDER_CHECK);
+#endif
+
ut_a(srv_n_purge_threads > 1);
ut_a(ulong(my_atomic_loadlint(&srv_sys.n_threads_active[SRV_WORKER]))
< srv_n_purge_threads);
@@ -2539,6 +2546,8 @@ DECLARE_THREAD(srv_worker_thread)(
}
} while (purge_sys.enabled());
+ ut_d(rw_lock_free(&slot->debug_sync_lock));
+
srv_free_slot(slot);
ut_ad(!purge_sys.enabled());
@@ -2739,6 +2748,12 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
slot = srv_reserve_slot(SRV_PURGE);
+#ifdef UNIV_DEBUG
+ UT_LIST_INIT(slot->debug_sync,
+ &srv_slot_t::debug_sync_t::debug_sync_list);
+ rw_lock_create(PFS_NOT_INSTRUMENTED, &slot->debug_sync_lock,
+ SYNC_NO_ORDER_CHECK);
+#endif
ulint rseg_history_len = trx_sys.history_size();
do {
@@ -2767,6 +2782,8 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
shutdown state. */
ut_a(srv_get_task_queue_length() == 0);
+ ut_d(rw_lock_free(&slot->debug_sync_lock));
+
srv_free_slot(slot);
/* Note that we are shutting down. */
diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc
index d519265dc8a..88ff251548c 100644
--- a/storage/innobase/trx/trx0roll.cc
+++ b/storage/innobase/trx/trx0roll.cc
@@ -805,7 +805,8 @@ void trx_rollback_recovered(bool all)
srv_fast_shutdown)
goto discard;
- if (all || trx_get_dict_operation(trx) != TRX_DICT_OP_NONE)
+ if (all || trx_get_dict_operation(trx) != TRX_DICT_OP_NONE
+ || trx->has_stats_table_lock())
{
trx_rollback_active(trx);
if (trx->error_state != DB_SUCCESS)
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index 90ed4141633..2620005269c 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -2404,3 +2404,16 @@ trx_set_rw_mode(
trx->read_view.set_creator_trx_id(trx->id);
}
}
+
+bool trx_t::has_stats_table_lock() const
+{
+ for (lock_list::const_iterator it= lock.table_locks.begin(),
+ end= lock.table_locks.end(); it != end; ++it)
+ {
+ const lock_t *lock= *it;
+ if (lock && lock->un_member.tab_lock.table->is_stats_table())
+ return true;
+ }
+
+ return false;
+}
diff --git a/storage/mroonga/CMakeLists.txt b/storage/mroonga/CMakeLists.txt
index af95c13d275..c57a524ff1e 100644
--- a/storage/mroonga/CMakeLists.txt
+++ b/storage/mroonga/CMakeLists.txt
@@ -17,7 +17,7 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
-cmake_minimum_required(VERSION 2.6)
+cmake_minimum_required(VERSION 2.8.12)
project(mroonga)
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc
index 0d9a2c6c18e..d43ba828957 100644
--- a/storage/myisam/ha_myisam.cc
+++ b/storage/myisam/ha_myisam.cc
@@ -949,7 +949,8 @@ void ha_myisam::setup_vcols_for_repair(HA_CHECK *param)
return;
file->s->vreclength= new_vreclength;
}
- DBUG_ASSERT(file->s->base.reclength < file->s->vreclength);
+ DBUG_ASSERT(file->s->base.reclength < file->s->vreclength ||
+ !table->s->stored_fields);
param->fix_record= compute_vcols;
table->use_all_columns();
table->vcol_set= &table->s->all_set;
diff --git a/storage/perfschema/CMakeLists.txt b/storage/perfschema/CMakeLists.txt
index e1839bc5b00..56083f24223 100644
--- a/storage/perfschema/CMakeLists.txt
+++ b/storage/perfschema/CMakeLists.txt
@@ -20,8 +20,7 @@
# along with this program; if not, write to the Free Software Foundation,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}
- ${CMAKE_SOURCE_DIR}/include
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/sql
${CMAKE_BINARY_DIR}/sql
${PCRE_INCLUDES}