diff options
author | Nikita Malyavin <nikitamalyavin@gmail.com> | 2021-05-04 14:49:31 +0300 |
---|---|---|
committer | Nikita Malyavin <nikitamalyavin@gmail.com> | 2021-05-04 14:49:31 +0300 |
commit | a8a925dd22ae00494cc9ffdc1ff68906106a408c (patch) | |
tree | a857c565a22ec7f6f41d3efa72053a726a346af2 /storage | |
parent | 2820f30dde3148df71e1d748ac705d98d60e0787 (diff) | |
parent | 72fa9dabadb4b0011f483ccbf1ef59e62d0ef1e0 (diff) | |
download | mariadb-git-a8a925dd22ae00494cc9ffdc1ff68906106a408c.tar.gz |
Merge branch bb-10.2-release into bb-10.3-release
Diffstat (limited to 'storage')
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} |