From ca63004190a7c5d449c88e91f55f32a09f04ec7e Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Fri, 5 Feb 2021 11:55:47 +0100 Subject: - Fix bug causing bnx base wrong after CheckMemory Add negative array indexes starting from the last modified: storage/connect/bson.cpp modified: storage/connect/bsonudf.cpp modified: storage/connect/json.cpp --- storage/connect/bson.cpp | 3 +++ storage/connect/bsonudf.cpp | 2 ++ storage/connect/json.cpp | 16 +++++++++++++--- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/storage/connect/bson.cpp b/storage/connect/bson.cpp index a494cf3166b..7b948164cfb 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; diff --git a/storage/connect/bsonudf.cpp b/storage/connect/bsonudf.cpp index 0a9d3813aeb..d85bc7042d3 100644 --- a/storage/connect/bsonudf.cpp +++ b/storage/connect/bsonudf.cpp @@ -3707,6 +3707,7 @@ char *bson_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result, PUSH_WARNING("CheckMemory error"); goto fin; } else { + bnx.Reset(); jvp = bnx.MakeValue(args, 0, true); if (g->Mrr) { // First argument is a constant @@ -4052,6 +4053,7 @@ double bsonget_real(UDF_INIT *initid, UDF_ARGS *args, *is_null = 1; return 0.0; } else { + bnx.Reset(); jvp = bnx.MakeValue(args, 0); if ((p = bnx.GetString(jvp))) { diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index 0152a44fffa..ac5f5a122cc 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -58,11 +58,19 @@ char *GetJsonNull(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 +1265,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 -- cgit v1.2.1 From d788225b66ba74c6e246b558e37dbcae27261f65 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Fri, 5 Feb 2021 18:07:43 +0100 Subject: Fix bson_object_grp inverted args. Modified: storage/connect/bsonudf.cpp and bson_udf.result --- storage/connect/bsonudf.cpp | 2 +- storage/connect/mysql-test/connect/r/bson_udf.result | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/storage/connect/bsonudf.cpp b/storage/connect/bsonudf.cpp index d85bc7042d3..ebaca1b3cd3 100644 --- a/storage/connect/bsonudf.cpp +++ b/storage/connect/bsonudf.cpp @@ -3019,7 +3019,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, 0), MakePSZ(g, args, 1)); + bxp->SetKeyValue(bop, bxp->MakeValue(args, 1), MakePSZ(g, args, 0)); } // end of bson_object_grp_add diff --git a/storage/connect/mysql-test/connect/r/bson_udf.result b/storage/connect/mysql-test/connect/r/bson_udf.result index 4ec1f0c87fd..fef55f7d3d9 100644 --- a/storage/connect/mysql-test/connect/r/bson_udf.result +++ b/storage/connect/mysql-test/connect/r/bson_udf.result @@ -280,13 +280,13 @@ SELECT Bson_Object_Grp(SALARY) FROM t3; ERROR HY000: Can't initialize function 'bson_object_grp'; This function requires 2 arguments (key, value) SELECT Bson_Object_Grp(NAME, SALARY) FROM t3; Bson_Object_Grp(NAME, SALARY) -{"":"MARTIN","ffffęp§@":"KITTY"} +{"BANCROFT":9600.00,"SMITH":9000.00,"MERCHANT":8700.00,"FUNNIGUY":8500.00,"BUGHAPPY":8500.00,"BIGHEAD":8000.00,"SHRINKY":7500.00,"WALTER":7400.00,"FODDERMAN":7000.00,"TONGHO":6800.00,"SHORTSIGHT":5500.00,"MESSIFUL":5000.50,"HONEY":4900.00,"GOOSEPEN":4700.00,"CHERRY":4500.00,"MONAPENNY":3800.00,"KITTY":3000.45,"PLUMHEAD":2800.00,"STRONG":23000.00,"BULLOZER":14800.00,"WERTHER":14500.00,"QUINN":14000.00,"ORELLY":13400.00,"BIGHORN":11000.00,"BROWNY":10500.00,"WHEELFOR":10030.00,"MARTIN":10000.00} SELECT Bson_Make_Object(DEPARTMENT, Bson_Object_Grp(NAME, SALARY) "Json_SALARIES") FROM t3 GROUP BY DEPARTMENT; Bson_Make_Object(DEPARTMENT, Bson_Object_Grp(NAME, SALARY) "Json_SALARIES") -{"DEPARTMENT":"0021","SALARIES":{"":"SHORTSIGHT"}} -{"DEPARTMENT":"0318","SALARIES":{"":"WHEELFOR"}} -{"DEPARTMENT":"0319","SALARIES":{"":"GOOSEPEN","ffffęp§@":"KITTY"}} -{"DEPARTMENT":"2452","SALARIES":{"":"CHERRY"}} +{"DEPARTMENT":"0021","SALARIES":{"STRONG":23000.00,"SHORTSIGHT":5500.00}} +{"DEPARTMENT":"0318","SALARIES":{"BANCROFT":9600.00,"PLUMHEAD":2800.00,"HONEY":4900.00,"TONGHO":6800.00,"WALTER":7400.00,"SHRINKY":7500.00,"WERTHER":14500.00,"MERCHANT":8700.00,"WHEELFOR":10030.00}} +{"DEPARTMENT":"0319","SALARIES":{"BULLOZER":14800.00,"QUINN":14000.00,"BROWNY":10500.00,"KITTY":3000.45,"MONAPENNY":3800.00,"MARTIN":10000.00,"FUNNIGUY":8500.00,"BUGHAPPY":8500.00,"FODDERMAN":7000.00,"MESSIFUL":5000.50,"GOOSEPEN":4700.00}} +{"DEPARTMENT":"2452","SALARIES":{"BIGHEAD":8000.00,"ORELLY":13400.00,"BIGHORN":11000.00,"SMITH":9000.00,"CHERRY":4500.00}} SELECT Bson_Array_Grp(NAME) FROM t3; Bson_Array_Grp(NAME) ["BANCROFT","SMITH","MERCHANT","FUNNIGUY","BUGHAPPY","BIGHEAD","SHRINKY","WALTER","FODDERMAN","TONGHO","SHORTSIGHT","MESSIFUL","HONEY","GOOSEPEN","CHERRY","MONAPENNY","KITTY","PLUMHEAD","STRONG","BULLOZER","WERTHER","QUINN","ORELLY","BIGHORN","BROWNY","WHEELFOR","MARTIN"] @@ -303,7 +303,7 @@ Bson_Object_Key(name, title) {"WHEELFOR":"SALESMAN"} SELECT Bson_Object_Grp(name, title) FROM t3 WHERE DEPARTMENT = 318; Bson_Object_Grp(name, title) -{"SALESMAN":"WHEELFOR","ADMINISTRATOR":"SHRINKY","ENGINEER":"TONGHO","SECRETARY":"HONEY","TYPIST":"PLUMHEAD","DIRECTOR":"WERTHER"} +{"BANCROFT":"SALESMAN","MERCHANT":"SALESMAN","SHRINKY":"ADMINISTRATOR","WALTER":"ENGINEER","TONGHO":"ENGINEER","HONEY":"SECRETARY","PLUMHEAD":"TYPIST","WERTHER":"DIRECTOR","WHEELFOR":"SALESMAN"} # # Test value getting UDF's # -- cgit v1.2.1 From 801a6d500f364e55fc548ac1532839c38a4b4226 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Tue, 16 Feb 2021 00:31:27 +0100 Subject: - Add new JPATH features modified: storage/connect/bson.cpp modified: storage/connect/bsonudf.cpp modified: storage/connect/bsonudf.h modified: storage/connect/json.cpp modified: storage/connect/jsonudf.cpp modified: storage/connect/jsonudf.h modified: storage/connect/mysql-test/connect/r/json_udf.result modified: storage/connect/tabbson.cpp modified: storage/connect/tabjson.cpp modified: storage/connect/tabjson.h --- storage/connect/bson.cpp | 15 +- storage/connect/bsonudf.cpp | 40 +--- storage/connect/bsonudf.h | 3 +- storage/connect/json.cpp | 3 +- storage/connect/jsonudf.cpp | 206 ++++++++++++++------- storage/connect/jsonudf.h | 6 +- .../connect/mysql-test/connect/r/json_udf.result | 10 +- storage/connect/tabbson.cpp | 2 +- storage/connect/tabjson.cpp | 62 ++++++- storage/connect/tabjson.h | 5 +- 10 files changed, 230 insertions(+), 122 deletions(-) diff --git a/storage/connect/bson.cpp b/storage/connect/bson.cpp index 7b948164cfb..92f36a4cdf2 100644 --- a/storage/connect/bson.cpp +++ b/storage/connect/bson.cpp @@ -1352,12 +1352,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 ebaca1b3cd3..dcf072242c8 100644 --- a/storage/connect/bsonudf.cpp +++ b/storage/connect/bsonudf.cpp @@ -114,7 +114,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; @@ -145,7 +145,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; @@ -270,40 +270,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 @@ -449,6 +415,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); 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/json.cpp b/storage/connect/json.cpp index ac5f5a122cc..f65294429db 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -54,6 +54,7 @@ char *GetExceptionDesc(PGLOBAL g, unsigned int e); #endif // SE_CATCH char *GetJsonNull(void); +int GetDefaultPrec(void); /***********************************************************************/ /* IsNum: check whether this string is all digits. */ @@ -1762,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 49a36407cec..bf6c9991800 100644 --- a/storage/connect/jsonudf.cpp +++ b/storage/connect/jsonudf.cpp @@ -70,7 +70,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; @@ -196,38 +196,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 @@ -310,7 +278,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++) @@ -321,23 +289,6 @@ my_bool JSNX::ParseJpath(PGLOBAL g) return false; } // 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. */ /*********************************************************************************/ @@ -348,6 +299,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: @@ -392,6 +344,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: */ /*********************************************************************************/ @@ -435,8 +433,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) { @@ -502,6 +499,88 @@ PVAL JSNX::ExpandArray(PGLOBAL g, PJAR arp, int n) return NULL; } // 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: */ /*********************************************************************************/ @@ -510,7 +589,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; @@ -543,9 +623,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) { @@ -553,18 +633,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 @@ -586,9 +666,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..bbc2c54c80f 100644 --- a/storage/connect/tabbson.cpp +++ b/storage/connect/tabbson.cpp @@ -881,7 +881,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/tabjson.cpp b/storage/connect/tabjson.cpp index fb5a64c7d55..96aa5db683a 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -1610,7 +1610,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 +1621,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,12 +1635,65 @@ 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. */ /***********************************************************************/ @@ -1740,7 +1794,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..147bef484a6 100644 --- a/storage/connect/tabjson.h +++ b/storage/connect/tabjson.h @@ -230,8 +230,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 -- cgit v1.2.1 From e85006e6708800b3b3cdc6a40b43acc43880e075 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Tue, 16 Mar 2021 23:32:58 +0100 Subject: - Fix bug making REST table fail using CURL This when the HTTP contains & characters modified: storage/connect/tabbson.cpp modified: storage/connect/tabjson.cpp - Make stringfy option work on only one Json item modified: storage/connect/tabbson.cpp modified: storage/connect/tabbson.h modified: storage/connect/tabjson.cpp modified: storage/connect/tabjson.h - Make Json/Bson DATE columns accept JSON date syntax modified: storage/connect/tabbson.cpp modified: storage/connect/tabjson.cpp - Fix bug making REST table default file not being erased when dropping the table modified: storage/connect/tabbson.cpp modified: storage/connect/tabjson.cpp modified: storage/connect/tabrest.cpp modified: storage/connect/tabxml.cpp - Suppress CHAR(36) --> VARCHAR(36) when DEVELOPMENT This was fixed in MyClient modified: storage/connect/ha_connect.cc --- storage/connect/ha_connect.cc | 5 ----- storage/connect/tabbson.cpp | 30 ++++++++++++++++++------- storage/connect/tabbson.h | 3 ++- storage/connect/tabjson.cpp | 35 +++++++++++++++++++---------- storage/connect/tabjson.h | 5 +++-- storage/connect/tabrest.cpp | 51 +++++++++++++++++++------------------------ storage/connect/tabxml.cpp | 19 +++++++++++----- 7 files changed, 87 insertions(+), 61 deletions(-) diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 69646e22e30..7682063c410 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -5391,12 +5391,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); diff --git a/storage/connect/tabbson.cpp b/storage/connect/tabbson.cpp index bbc2c54c80f..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; @@ -749,6 +753,16 @@ void BCUTIL::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL jvp) if (jvp->Type == TYPE_DBL || jvp->Type == TYPE_FLOAT) 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()); 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 96aa5db683a..185ad3ebc8b 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 @@ -160,8 +160,9 @@ 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) @@ -173,9 +174,9 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt) 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 +188,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 +204,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 @@ -426,7 +431,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 +485,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 +501,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); @@ -1710,7 +1714,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: @@ -1728,7 +1731,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 diff --git a/storage/connect/tabjson.h b/storage/connect/tabjson.h index 147bef484a6..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 /***********************************************************************/ diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp index 1efda6e3bca..f0230ef7229 100644 --- a/storage/connect/tabrest.cpp +++ b/storage/connect/tabrest.cpp @@ -99,12 +99,12 @@ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename) if (Uri) { if (*Uri == '/' || Http[strlen(Http) - 1] == '/') - sprintf(buf, "curl %s%s -o %s", Http, Uri, filename); + sprintf(buf, "curl \"%s%s\" -o %s", Http, Uri, filename); else - sprintf(buf, "curl %s/%s -o %s", Http, Uri, filename); + sprintf(buf, "curl \"%s/%s\" -o %s", Http, Uri, filename); } else - sprintf(buf, "curl %s -o %s", Http, filename); + sprintf(buf, "curl \"%s\" -o %s", Http, filename); if ((pipe = popen(buf, "rt"))) { if (trace(515)) @@ -202,11 +202,11 @@ PQRYRES __stdcall ColREST(PGLOBAL g, PTOS tp, char *tab, char *db, bool info) 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); @@ -230,28 +230,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,11 +271,12 @@ 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) @@ -309,24 +307,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); -- cgit v1.2.1 From caff19ada53f7414b646d0b46a927e1b8a22fd8e Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Mon, 5 Apr 2021 17:01:43 +0200 Subject: - Copy Mongo2.jar and Mongo3.jar in plugin directory modified: storage/connect/CMakeLists.txt modified: storage/connect/javaconn.cpp - Check privileges while creating tables with Discovery modified: storage/connect/ha_connect.cc - Calculate LRECL for JSON tables created with Discovery modified: storage/connect/tabjson.cpp - Use CreateProcess (Windows) or fork/exec (linux) to retrieve the result from REST queries modified: storage/connect/tabrest.cpp - Typo modified: storage/connect/jmgoconn.cpp --- storage/connect/CMakeLists.txt | 4 ++ storage/connect/Mongo2.jar | Bin 0 -> 623907 bytes storage/connect/Mongo3.jar | Bin 0 -> 1705776 bytes storage/connect/ha_connect.cc | 58 +++++++++++++++++++------ storage/connect/javaconn.cpp | 21 +++++++--- storage/connect/jmgoconn.cpp | 9 ++-- storage/connect/tabjson.cpp | 23 +++++++--- storage/connect/tabrest.cpp | 93 ++++++++++++++++++++++++++++++++--------- 8 files changed, 161 insertions(+), 47 deletions(-) create mode 100644 storage/connect/Mongo2.jar create mode 100644 storage/connect/Mongo3.jar diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index 77e77227e21..72934aa953c 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -409,6 +409,10 @@ IF(CONNECT_WITH_JDBC AND JAVA_FOUND AND JNI_FOUND) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/JavaWrappers.jar ${CMAKE_CURRENT_BINARY_DIR}/JdbcInterface.jar + IF(CONNECT_WITH_MONGO) + ${CMAKE_CURRENT_SOURCE_DIR}/Mongo2.jar + ${CMAKE_CURRENT_SOURCE_DIR}/Mongo3.jar + ENDIF() DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) ENDIF() diff --git a/storage/connect/Mongo2.jar b/storage/connect/Mongo2.jar new file mode 100644 index 00000000000..9be654bd4c8 Binary files /dev/null and b/storage/connect/Mongo2.jar differ diff --git a/storage/connect/Mongo3.jar b/storage/connect/Mongo3.jar new file mode 100644 index 00000000000..2850177a668 Binary files /dev/null and b/storage/connect/Mongo3.jar differ diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 7682063c410..2686bb4338e 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= '\\'; @@ -277,6 +277,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,10 +761,10 @@ DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir) used by the default rename_table and delete_table method in handler.cc. - For engines that have two file name extentions (separate meta/index file + 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 extentions 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 @@ -1296,9 +1300,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); @@ -1612,7 +1616,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)) @@ -1627,7 +1631,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; @@ -4511,11 +4515,9 @@ int ha_connect::delete_all_rows() } // end of delete_all_rows -bool ha_connect::check_privileges(THD *thd, PTOS options, 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: @@ -4598,6 +4600,15 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn, bool quick) 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, 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 @@ -5727,6 +5738,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 f919344f20b..3737c82a02e 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/tabjson.cpp b/storage/connect/tabjson.cpp index 185ad3ebc8b..dee4b737a89 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -9,6 +9,8 @@ /* Include relevant sections of the MariaDB header file. */ /***********************************************************************/ #include +#include +#include /***********************************************************************/ /* Include application header files: */ @@ -168,6 +170,7 @@ JSONDISC::JSONDISC(PGLOBAL g, uint *lg) 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; @@ -252,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 @@ -315,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 @@ -366,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 @@ -378,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; diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp index f0230ef7229..3ac86388ab2 100644 --- a/storage/connect/tabrest.cpp +++ b/storage/connect/tabrest.cpp @@ -1,6 +1,6 @@ /************** 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 1.9 */ +/* (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 */ @@ -53,10 +53,10 @@ #define PUSH_WARNING(M) htrc(M) #endif -#if defined(__WIN__) || defined(_WINDOWS) +#if 0 #define popen _popen #define pclose _pclose -#endif +#endif // 0 static XGETREST getRestFnc = NULL; static int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename); @@ -93,34 +93,87 @@ PTABDEF __stdcall GetREST(PGLOBAL g, void *memp) /***********************************************************************/ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename) { - char buf[1024]; - int rc; + char buf[512]; + int rc = 0; FILE *pipe; + if ((pipe = popen("curl --version", "r"))) { + if (trace(515)) + while (fgets(buf, sizeof(buf), pipe)) { + htrc("%s", buf); + } // endwhile + + pclose(pipe); + } else { + sprintf(g->Message, "curl not available, errno=%d", errno); + return 1; + } // endif pipe + + 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 ((pipe = popen(buf, "rt"))) { - if (trace(515)) - while (fgets(buf, sizeof(buf), pipe)) { - htrc("%s", buf); - } // endwhile +#if defined(__WIN__) + char cmd[1024]; + STARTUPINFO si; + PROCESS_INFORMATION pi; - pclose(pipe); - rc = 0; + 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, "curl failed, errno =%d", errno); + sprintf(g->Message, "CreateProcess curl failed (%d)", GetLastError()); rc = 1; - } // endif pipe + } // endif CreateProcess +#else // !__WIN__ + char fn[600]; + int rcd; + pid_t 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, explain_execlp()); + rc = 1; + exit(rc); + } // endif execlp + + } else if (pID < 0) { + // failed to fork + strcpy(g->Message, "Failed to fork"); + rc = 1; + } else { + // Parent process + wait(0); // 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. */ @@ -319,7 +372,7 @@ bool RESTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) } // endelse if (rc) { - strcpy(g->Message, "Cannot access to curl nor casablanca"); + // strcpy(g->Message, "Cannot access to curl nor casablanca"); return true; } else switch (n) { case 1: Tdp = new (g) JSONDEF; break; -- cgit v1.2.1 From 2aefe0bee1fc1bb74f1e02448825917183c305e5 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Mon, 5 Apr 2021 18:33:37 +0200 Subject: - Fix crash when not specifying the collection for MongoDB modified: storage/connect/cmgoconn.cpp - Fix(?) Linux compile errors modified: storage/connect/tabrest.cpp --- storage/connect/cmgoconn.cpp | 6 ++++++ storage/connect/tabrest.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) 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/tabrest.cpp b/storage/connect/tabrest.cpp index 3ac86388ab2..9204043da62 100644 --- a/storage/connect/tabrest.cpp +++ b/storage/connect/tabrest.cpp @@ -24,6 +24,7 @@ #else // !__WIN__ #define __stdcall #include // dlopen(), dlclose(), dlsym() ... +#include #endif // !__WIN__ #endif // !REST_SOURCE #define _OS_H_INCLUDED // Prevent os.h to be called @@ -148,7 +149,6 @@ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename) } // endif CreateProcess #else // !__WIN__ char fn[600]; - int rcd; pid_t pID = vfork(); sprintf(fn, "-o%s", filename); -- cgit v1.2.1 From 28b76afceac1eb2c35e77439142daac53908cdc3 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Tue, 6 Apr 2021 00:10:07 +0200 Subject: - Fix(?) Linux compile errors modified: storage/connect/tabrest.cpp modified: storage/connect/CMakeLists.txt -fix MDEV-24794 modified: storage/connect/valblk.h --- storage/connect/CMakeLists.txt | 3 +++ storage/connect/tabrest.cpp | 30 ++++++++++++++++-------------- storage/connect/valblk.h | 2 +- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index 72934aa953c..028376d510b 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -354,6 +354,9 @@ IF(CONNECT_WITH_REST) ##ELSE(NOT cpprestsdk_FOUND) ## MESSAGE(STATUS "=====> cpprestsdk package not found") # ENDIF (cpprestsdk_FOUND) +IF(UNIX) + SET(REST_LIBRARY -lexplain) +ENDIF(UNIX) ENDIF(CONNECT_WITH_REST) # diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp index 9204043da62..af1961c8314 100644 --- a/storage/connect/tabrest.cpp +++ b/storage/connect/tabrest.cpp @@ -24,6 +24,10 @@ #else // !__WIN__ #define __stdcall #include // dlopen(), dlclose(), dlsym() ... +#include +#include +#include "stdio.h" +#include #include #endif // !__WIN__ #endif // !REST_SOURCE @@ -98,18 +102,6 @@ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename) int rc = 0; FILE *pipe; - if ((pipe = popen("curl --version", "r"))) { - if (trace(515)) - while (fgets(buf, sizeof(buf), pipe)) { - htrc("%s", buf); - } // endwhile - - pclose(pipe); - } else { - sprintf(g->Message, "curl not available, errno=%d", errno); - return 1; - } // endif pipe - if (strchr(filename, '"')) { strcpy(g->Message, "Invalid file name"); return 1; @@ -149,15 +141,25 @@ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename) } // endif CreateProcess #else // !__WIN__ char fn[600]; - pid_t pID = vfork(); + pid_t pID; + // Check if curl package is availabe by executing subprocess + FILE *f= popen("command -v curl", "r"); + + if (!f) { + strcpy(g->Message, "curl CLI not installed"); + return 1; + } else + close(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, explain_execlp()); + strcpy(g->Message, explain_execlp("curl", "curl", buf, fn, (char*)NULL))); rc = 1; exit(rc); } // endif execlp 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];} -- cgit v1.2.1 From d1b6cad0287a27e63d9ee57eb1862a70ba98f091 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Tue, 6 Apr 2021 14:16:38 +0200 Subject: Test tabrest.cpp fix --- storage/connect/tabrest.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp index af1961c8314..d2b12ca1eb3 100644 --- a/storage/connect/tabrest.cpp +++ b/storage/connect/tabrest.cpp @@ -100,7 +100,6 @@ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename) { char buf[512]; int rc = 0; - FILE *pipe; if (strchr(filename, '"')) { strcpy(g->Message, "Invalid file name"); @@ -150,7 +149,7 @@ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename) strcpy(g->Message, "curl CLI not installed"); return 1; } else - close(f); + pclose(f); pID = vfork(); sprintf(fn, "-o%s", filename); -- cgit v1.2.1 From 26e5ba4b5139f79002b2d8cf43a9164a4a4e7838 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Wed, 7 Apr 2021 15:53:46 +0200 Subject: - Fix Linux compile errors modified: storage/connect/tabrest.cpp modified: storage/connect/CMakeLists.txt - Fix cmake error modified: libmariadb/cmake/ConnectorName.cmake --- storage/connect/CMakeLists.txt | 3 --- storage/connect/tabrest.cpp | 37 +++++++++++++++++-------------------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index 028376d510b..72934aa953c 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -354,9 +354,6 @@ IF(CONNECT_WITH_REST) ##ELSE(NOT cpprestsdk_FOUND) ## MESSAGE(STATUS "=====> cpprestsdk package not found") # ENDIF (cpprestsdk_FOUND) -IF(UNIX) - SET(REST_LIBRARY -lexplain) -ENDIF(UNIX) ENDIF(CONNECT_WITH_REST) # diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp index d2b12ca1eb3..4ecf3edcc2e 100644 --- a/storage/connect/tabrest.cpp +++ b/storage/connect/tabrest.cpp @@ -24,11 +24,6 @@ #else // !__WIN__ #define __stdcall #include // dlopen(), dlclose(), dlsym() ... -#include -#include -#include "stdio.h" -#include -#include #endif // !__WIN__ #endif // !REST_SOURCE #define _OS_H_INCLUDED // Prevent os.h to be called @@ -58,11 +53,6 @@ #define PUSH_WARNING(M) htrc(M) #endif -#if 0 -#define popen _popen -#define pclose _pclose -#endif // 0 - static XGETREST getRestFnc = NULL; static int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename); @@ -146,10 +136,19 @@ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename) FILE *f= popen("command -v curl", "r"); if (!f) { - strcpy(g->Message, "curl CLI not installed"); - return 1; - } else - pclose(f); + strcpy(g->Message, "Problem in allocating memory."); + return 1; + } else { + 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); @@ -157,19 +156,17 @@ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ 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, explain_execlp("curl", "curl", buf, fn, (char*)NULL))); - rc = 1; - exit(rc); - } // endif execlp + // If execlp() is successful, we should not reach this next line. + strcpy(g->Message, "I shouldn't be called after execlp from vfork()"); + exit(1); } else if (pID < 0) { // failed to fork strcpy(g->Message, "Failed to fork"); rc = 1; } else { // Parent process - wait(0); // Wait for the child to terminate + wait(NULL); // Wait for the child to terminate } // endif pID #endif // !__WIN__ -- cgit v1.2.1 From 953c84657b009271028d548e850ecbffbd61bd18 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Wed, 7 Apr 2021 16:48:14 +0200 Subject: try to fix tabrest.cpp compile error --- storage/connect/tabrest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp index 4ecf3edcc2e..4e73930a267 100644 --- a/storage/connect/tabrest.cpp +++ b/storage/connect/tabrest.cpp @@ -166,7 +166,7 @@ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename) rc = 1; } else { // Parent process - wait(NULL); // Wait for the child to terminate + wait(0); // Wait for the child to terminate } // endif pID #endif // !__WIN__ -- cgit v1.2.1 From e4c23fe2d0a29fa738e5883d172a9b625ec59b62 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Wed, 7 Apr 2021 17:40:24 +0200 Subject: tabrest.cpp --- storage/connect/tabrest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp index 4e73930a267..d4e7b766635 100644 --- a/storage/connect/tabrest.cpp +++ b/storage/connect/tabrest.cpp @@ -166,7 +166,7 @@ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename) rc = 1; } else { // Parent process - wait(0); // Wait for the child to terminate + wait(); // Wait for the child to terminate } // endif pID #endif // !__WIN__ -- cgit v1.2.1 From 757aaa3bcc7698fff934bad167b7a751bb6c4ddb Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Wed, 7 Apr 2021 19:15:31 +0200 Subject: tabrest.cpp --- storage/connect/tabrest.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp index d4e7b766635..5733ee7ad56 100644 --- a/storage/connect/tabrest.cpp +++ b/storage/connect/tabrest.cpp @@ -129,6 +129,9 @@ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename) rc = 1; } // endif CreateProcess #else // !__WIN__ +#include +#include + char fn[600]; pid_t pID; @@ -166,7 +169,7 @@ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename) rc = 1; } else { // Parent process - wait(); // Wait for the child to terminate + wait(NULL); // Wait for the child to terminate } // endif pID #endif // !__WIN__ -- cgit v1.2.1 From 710e1bac5a74b4dc647dfc50a5e693b92c1cc9bc Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Wed, 7 Apr 2021 23:43:08 +0200 Subject: tabrest.cpp --- storage/connect/tabrest.cpp | 71 +++++---------------------------------------- 1 file changed, 8 insertions(+), 63 deletions(-) diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp index 5733ee7ad56..d96c57ae948 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.9 */ +/* 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 // All MariaDB stuff #include #include -#else // !MARIADB OEM module -#include "mini-global.h" -#define _MAX_PATH 260 -#if !defined(REST_SOURCE) -#if defined(__WIN__) || defined(_WINDOWS) -#include -#else // !__WIN__ -#define __stdcall -#include // 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 +#include +#endif // !__WIN__ && !_WINDOWS /***********************************************************************/ /* Include application header files: */ @@ -56,33 +45,6 @@ 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. */ /***********************************************************************/ @@ -129,9 +91,6 @@ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename) rc = 1; } // endif CreateProcess #else // !__WIN__ -#include -#include - char fn[600]; pid_t pID; @@ -184,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"); @@ -237,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 @@ -247,11 +206,7 @@ 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 ??? @@ -265,12 +220,7 @@ PQRYRES __stdcall ColREST(PGLOBAL g, PTOS tp, char *tab, char *db, bool info) http = GetStringTableOption(g, tp, "Http", NULL); uri = GetStringTableOption(g, tp, "Uri", NULL); -#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) { @@ -333,12 +283,7 @@ bool RESTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) 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)); -- cgit v1.2.1 From bbec4aafda377a5510a61b1042a23c1a7363cb7c Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Thu, 8 Apr 2021 19:04:07 +0200 Subject: typo tabrest.cpp --- storage/connect/tabrest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp index d96c57ae948..4b6bb6a9e62 100644 --- a/storage/connect/tabrest.cpp +++ b/storage/connect/tabrest.cpp @@ -120,7 +120,7 @@ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename) execlp("curl", "curl", buf, fn, (char*)NULL); // If execlp() is successful, we should not reach this next line. - strcpy(g->Message, "I shouldn't be called after execlp from vfork()"); + strcpy(g->Message, "Unsuccessful execlp from vfork()"); exit(1); } else if (pID < 0) { // failed to fork -- cgit v1.2.1 From 03f929aea84b1a48bd528d66f52ed2e645b83e26 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Fri, 9 Apr 2021 11:58:13 +0200 Subject: Fix install modified: CMakeLists.txt --- storage/connect/CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index 72934aa953c..a1a90e8a043 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -409,10 +409,12 @@ IF(CONNECT_WITH_JDBC AND JAVA_FOUND AND JNI_FOUND) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/JavaWrappers.jar ${CMAKE_CURRENT_BINARY_DIR}/JdbcInterface.jar - IF(CONNECT_WITH_MONGO) + DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) + IF(CONNECT_WITH_MONGO) + INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/Mongo2.jar ${CMAKE_CURRENT_SOURCE_DIR}/Mongo3.jar - ENDIF() - DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) + DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) + ENDIF() ENDIF() -- cgit v1.2.1 From 46340ad8d126891c18d7efece2b484ebe1b9c9a6 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Fri, 9 Apr 2021 14:41:50 +0200 Subject: Fix add_jar modified: CMakeLists.txt --- storage/connect/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index a1a90e8a043..80f20bca378 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -411,6 +411,8 @@ IF(CONNECT_WITH_JDBC AND JAVA_FOUND AND JNI_FOUND) ${CMAKE_CURRENT_BINARY_DIR}/JdbcInterface.jar DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) IF(CONNECT_WITH_MONGO) + add_jar(Mongo2 Mongo2Interface.java) + add_jar(Mongo3 Mongo3Interface.java) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/Mongo2.jar ${CMAKE_CURRENT_SOURCE_DIR}/Mongo3.jar -- cgit v1.2.1 From 36fd94aa5c129e8b3b6b6233cc9d830ef5551e0a Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Fri, 9 Apr 2021 15:24:34 +0200 Subject: Remove add_jar modified: CMakeLists.txt --- storage/connect/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index 80f20bca378..be206e583f9 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -275,6 +275,7 @@ IF(CONNECT_WITH_JDBC) JavaWrappers.jar) add_definitions(-DJAVA_SUPPORT) IF(CONNECT_WITH_MONGO) + SET(CONNECT_SOURCES ${CONNECT_SOURCES} Mongo2.jar Mono3.jar) add_definitions(-DMONGO_SUPPORT) ENDIF() ELSE() @@ -411,8 +412,6 @@ IF(CONNECT_WITH_JDBC AND JAVA_FOUND AND JNI_FOUND) ${CMAKE_CURRENT_BINARY_DIR}/JdbcInterface.jar DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) IF(CONNECT_WITH_MONGO) - add_jar(Mongo2 Mongo2Interface.java) - add_jar(Mongo3 Mongo3Interface.java) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/Mongo2.jar ${CMAKE_CURRENT_SOURCE_DIR}/Mongo3.jar -- cgit v1.2.1 From 4df6952ce3e778c8f4d1d638350d4155281c1618 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Fri, 9 Apr 2021 16:10:37 +0200 Subject: Typo modified: CMakeLists.txt --- storage/connect/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index be206e583f9..96b8d877ee0 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -275,7 +275,7 @@ IF(CONNECT_WITH_JDBC) JavaWrappers.jar) add_definitions(-DJAVA_SUPPORT) IF(CONNECT_WITH_MONGO) - SET(CONNECT_SOURCES ${CONNECT_SOURCES} Mongo2.jar Mono3.jar) + SET(CONNECT_SOURCES ${CONNECT_SOURCES} Mongo2.jar Mongo3.jar) add_definitions(-DMONGO_SUPPORT) ENDIF() ELSE() -- cgit v1.2.1 From 6d73282b136058deb992fdb758d8992fa186e73e Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 21 Apr 2021 22:14:08 +0300 Subject: MDEV-25468 DELETE HISTORY may delete current data on system-versioned table Item_func_history (is_history()) is a bool function that checks if the row is the history row by checking row_end->is_max(). The argument to this function must be row_end system field. Added the above function to conjunction with SYSTEM_TIME_BEFORE versioning condition. --- .../suite/versioning/r/delete_history.result | 33 ++++++++++++++++++++++ mysql-test/suite/versioning/t/delete_history.test | 22 +++++++++++++++ sql/item_vers.cc | 16 +++++++++++ sql/item_vers.h | 30 ++++++++++++++++++++ sql/sql_select.cc | 6 ++-- 5 files changed, 105 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/versioning/r/delete_history.result b/mysql-test/suite/versioning/r/delete_history.result index 93f240272c1..95d7304c3dd 100644 --- a/mysql-test/suite/versioning/r/delete_history.result +++ b/mysql-test/suite/versioning/r/delete_history.result @@ -129,3 +129,36 @@ select * from t1; a 1 drop table t1; +# +# MDEV-25468 DELETE HISTORY may delete current data on system-versioned table +# +create or replace table t1 (x int) with system versioning; +insert into t1 values (1); +delete history from t1 before system_time '2039-01-01 23:00'; +select * from t1; +x +1 +explain extended delete history from t1 before system_time '2039-01-01 23:00'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00 Using where +create or replace procedure p() delete history from t1 before system_time '2039-01-01 23:00'; +call p; +select * from t1; +x +1 +call p; +select * from t1; +x +1 +drop procedure p; +prepare stmt from "delete history from t1 before system_time '2039-01-01 23:00'"; +execute stmt; +select * from t1; +x +1 +execute stmt; +select * from t1; +x +1 +drop prepare stmt; +drop table t1; diff --git a/mysql-test/suite/versioning/t/delete_history.test b/mysql-test/suite/versioning/t/delete_history.test index 8a7f8e84a76..bd605c689ad 100644 --- a/mysql-test/suite/versioning/t/delete_history.test +++ b/mysql-test/suite/versioning/t/delete_history.test @@ -141,4 +141,26 @@ insert into t1 values (1); select * from t1; drop table t1; +--echo # +--echo # MDEV-25468 DELETE HISTORY may delete current data on system-versioned table +--echo # +create or replace table t1 (x int) with system versioning; +insert into t1 values (1); +delete history from t1 before system_time '2039-01-01 23:00'; +select * from t1; +explain extended delete history from t1 before system_time '2039-01-01 23:00'; +create or replace procedure p() delete history from t1 before system_time '2039-01-01 23:00'; +call p; +select * from t1; +call p; +select * from t1; +drop procedure p; +prepare stmt from "delete history from t1 before system_time '2039-01-01 23:00'"; +execute stmt; +select * from t1; +execute stmt; +select * from t1; +drop prepare stmt; +drop table t1; + --source suite/versioning/common_finish.inc diff --git a/sql/item_vers.cc b/sql/item_vers.cc index cfedc6b0f81..76cda6a5ea2 100644 --- a/sql/item_vers.cc +++ b/sql/item_vers.cc @@ -26,6 +26,22 @@ #include "tztime.h" #include "item.h" +bool Item_func_history::val_bool() +{ + Item_field *f= static_cast(args[0]); + DBUG_ASSERT(f->fixed); + DBUG_ASSERT(f->field->flags & VERS_SYS_END_FLAG); + return !f->field->is_max(); +} + +void Item_func_history::print(String *str, enum_query_type query_type) +{ + str->append(func_name()); + str->append('('); + args[0]->print(str, query_type); + str->append(')'); +} + Item_func_trt_ts::Item_func_trt_ts(THD *thd, Item* a, TR_table::field_id_t _trt_field) : Item_datetimefunc(thd, a), trt_field(_trt_field) diff --git a/sql/item_vers.h b/sql/item_vers.h index 8b9c0e6056c..2be3f683913 100644 --- a/sql/item_vers.h +++ b/sql/item_vers.h @@ -22,6 +22,36 @@ #pragma interface /* gcc class implementation */ #endif +class Item_func_history: public Item_bool_func +{ +public: + /* + @param a Item_field for row_end system field + */ + Item_func_history(THD *thd, Item *a): Item_bool_func(thd, a) + { + DBUG_ASSERT(a->type() == Item::FIELD_ITEM); + } + + virtual bool val_bool(); + virtual longlong val_int() + { + return (val_bool() ? 1 : 0); + } + bool fix_length_and_dec() + { + maybe_null= 0; + null_value= 0; + decimals= 0; + max_length= 1; + return FALSE; + } + virtual const char* func_name() const { return "is_history"; } + virtual void print(String *str, enum_query_type query_type); + Item *get_copy(THD *thd) + { return get_item_copy(thd, this); } +}; + class Item_func_trt_ts: public Item_datetimefunc { TR_table::field_id_t trt_field; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d53c592ff7b..2526866e534 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -928,7 +928,8 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) cond3= newx Item_func_le(thd, point_in_time1, point_in_time2); break; case SYSTEM_TIME_BEFORE: - cond1= newx Item_func_lt(thd, row_end, point_in_time1); + cond1= newx Item_func_history(thd, row_end); + cond2= newx Item_func_lt(thd, row_end, point_in_time1); break; default: DBUG_ASSERT(0); @@ -978,7 +979,8 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) trx_id0= vers_conditions.start.unit == VERS_TIMESTAMP ? newx Item_func_trt_id(thd, point_in_time1, TR_table::FLD_TRX_ID, true) : point_in_time1; - cond1= newx Item_func_trt_trx_sees(thd, trx_id0, row_end); + cond1= newx Item_func_history(thd, row_end); + cond2= newx Item_func_trt_trx_sees(thd, trx_id0, row_end); break; default: DBUG_ASSERT(0); -- cgit v1.2.1 From 23e090626a9138f44905a5a8e681e8952f98aac7 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sat, 24 Apr 2021 09:06:16 +0300 Subject: MDEV-20842 Crash using versioning plugin functions after plugin was removed from server Remove plugin functions via item_create_remove() at deinit time. --- mysql-test/suite/versioning/r/trx_id.result | 6 ++++++ mysql-test/suite/versioning/t/trx_id.test | 8 +++++++- plugin/versioning/versioning.cc | 1 + sql/item_create.cc | 15 +++++++++++++++ sql/item_create.h | 1 + 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/versioning/r/trx_id.result b/mysql-test/suite/versioning/r/trx_id.result index 58d02505fb6..ea06a2e545d 100644 --- a/mysql-test/suite/versioning/r/trx_id.result +++ b/mysql-test/suite/versioning/r/trx_id.result @@ -506,3 +506,9 @@ add period for system_time(`row_start`,`row_end`), modify x int after row_start, with system versioning; create or replace database test; +# +# MDEV-20842 Crash using versioning plugin functions after plugin was removed from server +# +uninstall plugin test_versioning; +select trt_begin_ts(0); +ERROR 42000: FUNCTION trt_begin_ts does not exist diff --git a/mysql-test/suite/versioning/t/trx_id.test b/mysql-test/suite/versioning/t/trx_id.test index 7dfc8acb080..b68d5513dd9 100644 --- a/mysql-test/suite/versioning/t/trx_id.test +++ b/mysql-test/suite/versioning/t/trx_id.test @@ -529,5 +529,11 @@ alter table t add `row_start` bigint unsigned as row start, modify x int after row_start, with system versioning; - create or replace database test; + +--echo # +--echo # MDEV-20842 Crash using versioning plugin functions after plugin was removed from server +--echo # +uninstall plugin test_versioning; +--error ER_SP_DOES_NOT_EXIST +select trt_begin_ts(0); diff --git a/plugin/versioning/versioning.cc b/plugin/versioning/versioning.cc index 7e3c29e1494..56f8f1f5a1d 100644 --- a/plugin/versioning/versioning.cc +++ b/plugin/versioning/versioning.cc @@ -175,6 +175,7 @@ static int versioning_plugin_init(void *p __attribute__ ((unused))) static int versioning_plugin_deinit(void *p __attribute__ ((unused))) { DBUG_ENTER("versioning_plugin_deinit"); + (void) item_create_remove(func_array); DBUG_RETURN(0); } diff --git a/sql/item_create.cc b/sql/item_create.cc index 48e396210a5..70ac2abe959 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -7465,6 +7465,21 @@ int item_create_append(Native_func_registry array[]) DBUG_RETURN(0); } +int item_create_remove(Native_func_registry array[]) +{ + Native_func_registry *func; + + DBUG_ENTER("item_create_remove"); + + for (func= array; func->builder != NULL; func++) + { + if (my_hash_delete(& native_functions_hash, (uchar*) func)) + DBUG_RETURN(1); + } + + DBUG_RETURN(0); +} + /* Empty the hash table for native functions. Note: this code is not thread safe, and is intended to be used at server diff --git a/sql/item_create.h b/sql/item_create.h index b9d5ab9f377..7e92016ab96 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -214,6 +214,7 @@ struct Native_func_registry int item_create_init(); int item_create_append(Native_func_registry array[]); +int item_create_remove(Native_func_registry array[]); void item_create_cleanup(); Item *create_func_dyncol_create(THD *thd, List &list); -- cgit v1.2.1 From 300253acf12bf66fdea8e64abae5d717c289e559 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Thu, 25 Jul 2019 22:17:04 +1000 Subject: revive innodb_debug_sync innodb_debug_sync was introduced in commit b393e2cb0c079b30563dcc87a62002c9c778643c and reverted in commit fc58c1721631fcc6c9414482b3b7e90cd8e7325d due to memory leak reported by valgrind, see MDEV-21336. The leak is now fixed by adding `rw_lock_free(&slot->debug_sync_lock)` after background thread working loop is finished, and the patch is reapplied, with respect to c++98 fixes by Marko. The missing DEBUG_SYNC for MDEV-18546 in row0vers.cc is also reapplied. --- .../suite/gcol/r/innodb_virtual_debug_purge.result | 44 +++++++++++++++ .../suite/gcol/t/innodb_virtual_debug_purge.test | 63 ++++++++++++++++++++++ mysql-test/suite/sys_vars/r/sysvars_innodb.result | 12 +++++ storage/innobase/handler/ha_innodb.cc | 38 +++++++++++++ storage/innobase/include/srv0srv.h | 10 ++++ storage/innobase/row/row0purge.cc | 20 +++++++ storage/innobase/row/row0vers.cc | 1 + storage/innobase/srv/srv0srv.cc | 17 ++++++ 8 files changed, 205 insertions(+) diff --git a/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result b/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result index c9d95dae579..3670f8f1711 100644 --- a/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result +++ b/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result @@ -233,3 +233,47 @@ set global debug_dbug= @saved_dbug; drop table t1; set debug_sync=reset; SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; +# +# MDEV-18546 ASAN heap-use-after-free +# in innobase_get_computed_value / row_purge +# +CREATE TABLE t1 ( +pk INT AUTO_INCREMENT, +b BIT(15), +v BIT(15) AS (b) VIRTUAL, +PRIMARY KEY(pk), +UNIQUE(v) +) ENGINE=InnoDB; +INSERT IGNORE INTO t1 (b) VALUES +(NULL),(b'011'),(b'000110100'), +(b'01101101010'),(b'01111001001011'),(NULL); +SET GLOBAL innodb_debug_sync = "ib_clust_v_col_before_row_allocated " + "SIGNAL before_row_allocated " + "WAIT_FOR flush_unlock"; +SET GLOBAL innodb_debug_sync = "ib_open_after_dict_open " + "SIGNAL purge_open " + "WAIT_FOR select_open"; +set global debug_dbug= "d,ib_purge_virtual_index_callback"; +connect purge_waiter,localhost,root; +SET debug_sync= "now WAIT_FOR before_row_allocated"; +connection default; +REPLACE INTO t1 (pk, b) SELECT pk, b FROM t1; +connection purge_waiter; +connection default; +disconnect purge_waiter; +FLUSH TABLES; +SET GLOBAL innodb_debug_sync = reset; +SET debug_sync= "now SIGNAL flush_unlock WAIT_FOR purge_open"; +SET GLOBAL innodb_debug_sync = reset; +SET debug_sync= "ib_open_after_dict_open SIGNAL select_open"; +SELECT * FROM t1; +pk b v +1 NULL NULL +2   +3 4 4 +4 j j +5 K K +6 NULL NULL +DROP TABLE t1; +SET debug_sync= reset; +set global debug_dbug= @old_dbug; diff --git a/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test b/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test index 238a4937e9f..3716d7e7083 100644 --- a/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test +++ b/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test @@ -323,3 +323,66 @@ drop table t1; --source include/wait_until_count_sessions.inc set debug_sync=reset; SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; + +--echo # +--echo # MDEV-18546 ASAN heap-use-after-free +--echo # in innobase_get_computed_value / row_purge +--echo # + +CREATE TABLE t1 ( + pk INT AUTO_INCREMENT, + b BIT(15), + v BIT(15) AS (b) VIRTUAL, + PRIMARY KEY(pk), + UNIQUE(v) +) ENGINE=InnoDB; +INSERT IGNORE INTO t1 (b) VALUES + (NULL),(b'011'),(b'000110100'), + (b'01101101010'),(b'01111001001011'),(NULL); + +SET GLOBAL innodb_debug_sync = "ib_clust_v_col_before_row_allocated " + "SIGNAL before_row_allocated " + "WAIT_FOR flush_unlock"; +SET GLOBAL innodb_debug_sync = "ib_open_after_dict_open " + "SIGNAL purge_open " + "WAIT_FOR select_open"; + +# In 10.2 trx_undo_roll_ptr_is_insert(t_roll_ptr) condition never pass in purge, +# so this condition is forced to pass in row_vers_old_has_index_entry +set global debug_dbug= "d,ib_purge_virtual_index_callback"; + +# The purge starts from REPLACE command. To avoid possible race, separate +# connection is used. +--connect(purge_waiter,localhost,root) +--send +SET debug_sync= "now WAIT_FOR before_row_allocated"; + +--connection default +REPLACE INTO t1 (pk, b) SELECT pk, b FROM t1; + +--connection purge_waiter +# Now we will definitely catch ib_clust_v_col_before_row_allocated +--reap +--connection default +--disconnect purge_waiter + +# purge hangs on the sync point. table is purged, ref_count is set to 0 +FLUSH TABLES; + +# Avoid hang on repeating purge. +# Reset Will be applied after first record is purged +SET GLOBAL innodb_debug_sync = reset; + +SET debug_sync= "now SIGNAL flush_unlock WAIT_FOR purge_open"; + +# Avoid hang on repeating purge +SET GLOBAL innodb_debug_sync = reset; + +# select unblocks purge thread +SET debug_sync= "ib_open_after_dict_open SIGNAL select_open"; +SELECT * FROM t1; + +# Cleanup +DROP TABLE t1; +SET debug_sync= reset; +set global debug_dbug= @old_dbug; diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result index 440efc6a9cd..ecc5e9b50bb 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result @@ -654,6 +654,18 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST OFF,ON READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME INNODB_DEBUG_SYNC +SESSION_VALUE NULL +DEFAULT_VALUE +VARIABLE_SCOPE GLOBAL +VARIABLE_TYPE VARCHAR +VARIABLE_COMMENT 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. +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST NULL +READ_ONLY NO +COMMAND_LINE_ARGUMENT NONE VARIABLE_NAME INNODB_DEFAULT_ENCRYPTION_KEY_ID SESSION_VALUE 1 DEFAULT_VALUE 1 diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 91d12f64fa5..22fe3b5d9ed 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -19559,6 +19559,33 @@ innodb_log_checksums_update( thd, *static_cast(save)); } +#ifdef UNIV_DEBUG +static +void +innobase_debug_sync_callback(srv_slot_t *slot, const void *value) +{ + const char *value_str = *static_cast(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} @@ -21205,6 +21232,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(instrument_semaphores, innodb_instrument_semaphores, @@ -21428,6 +21465,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(instrument_semaphores), MYSQL_SYSVAR(buf_dump_status_frequency), diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index d196a4d6db6..62d7c139ee2 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -1142,6 +1142,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/row/row0purge.cc b/storage/innobase/row/row0purge.cc index 024625e9e0a..10a0b91f8f8 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 @@ -1208,6 +1209,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 2d8704764d1..b9bc8418366 100644 --- a/storage/innobase/row/row0vers.cc +++ b/storage/innobase/row/row0vers.cc @@ -467,6 +467,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 44e0946f067..56c717e142b 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -2601,6 +2601,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); @@ -2625,6 +2632,8 @@ DECLARE_THREAD(srv_worker_thread)( purge_sys->latch here. */ } while (purge_sys->state != PURGE_STATE_EXIT); + ut_d(rw_lock_free(&slot->debug_sync_lock)); + srv_free_slot(slot); rw_lock_x_lock(&purge_sys->latch); @@ -2848,6 +2857,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->rseg_history_len; do { @@ -2881,6 +2896,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. */ -- cgit v1.2.1 From 6ba5f81c7dcb133d2f4fabb7f24b76286fa868a3 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Tue, 6 Apr 2021 21:31:00 +0300 Subject: MDEV-16962 Assertion failed in open_purge_table upon concurrent ALTER/FLUSH So we are having a race condition of three of threads, resulting in a deadlock backoff in purge, which is unexpected. More precisely, the following happens: T1: NOCOPY ALTER TABLE begins, and eventually it holds MDL_SHARED_NO_WRITE lock; T2: FLUSH TABLES begins. it sets share->tdc->flushed = true T3: purge on a record with virtual column begins. it is going to open a table. MDL_SHARED_READ lock is acquired therefore. Since share->tdc->flushed is set, it waits for a TDC purge end. T1: is going to elevate MDL LOCK to exclusive and therefore has to set other waiters to back off. T3: receives VICTIM status, reports a DEADLOCK, sets OT_BACKOFF_AND_RETRY to Open_table_context::m_action My fix is to allow opening table in purge while flushing. It is already done the same way in other maintainance facilities like REPAIR TABLE. Another way would be making an actual backoff, but Open_table_context does not allow to distinguish it from other failure types, which still seem to be unexpected. Making this would require hacking into Open_table_context interface for no benefit, in comparison to passing MYSQL_OPEN_IGNORE_FLUSH during table open. --- .../suite/gcol/r/innodb_virtual_debug_purge.result | 30 ++++++++++++- .../suite/gcol/t/innodb_virtual_debug_purge.test | 50 +++++++++++++++++++++- sql/sql_class.cc | 2 +- 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result b/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result index 3670f8f1711..724f6167ce1 100644 --- a/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result +++ b/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result @@ -232,7 +232,6 @@ set debug_sync= "now WAIT_FOR got_no_such_table TIMEOUT 1"; set global debug_dbug= @saved_dbug; drop table t1; set debug_sync=reset; -SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; # # MDEV-18546 ASAN heap-use-after-free # in innobase_get_computed_value / row_purge @@ -277,3 +276,32 @@ pk b v DROP TABLE t1; SET debug_sync= reset; set global debug_dbug= @old_dbug; +# MDEV-16962 Assertion '!error || !ot_ctx.can_recover_from_failed_open()' +# failed in open_purge_table upon concurrent ALTER and FLUSH +CREATE TABLE t1 ( +pk SERIAL, +c VARCHAR(128), +d DATE, +vd DATE AS (d) VIRTUAL, +PRIMARY KEY(pk), +KEY(vd,c) +) ENGINE=InnoDB; +INSERT IGNORE INTO t1 (pk,c) VALUES (1,'foo'); +set debug_sync="now WAIT_FOR purge"; +connect con1,localhost,root,,test; +SET GLOBAL innodb_debug_sync="after_open_table_mdl_shared SIGNAL purge WAIT_FOR flush"; +SET global debug_dbug="d,ib_purge_virtual_index_callback"; +REPLACE INTO t1 (pk,c) VALUES (1,'bar'); +connection default; +SET debug_sync="alter_table_before_rename_result_table WAIT_FOR flush"; +ALTER TABLE t1 ADD FULLTEXT KEY(c), ALGORITHM=COPY; +connection con1; +SET debug_sync="after_flush_unlock SIGNAL flush "; +FLUSH TABLES; +disconnect con1; +connection default; +InnoDB 0 transactions not purged +DROP TABLE t1; +SET debug_sync= reset; +SET global debug_dbug=@old_dbug; +SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; diff --git a/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test b/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test index 3716d7e7083..a40e788f9a7 100644 --- a/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test +++ b/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test @@ -322,7 +322,6 @@ drop table t1; --source include/wait_until_count_sessions.inc set debug_sync=reset; -SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; --echo # --echo # MDEV-18546 ASAN heap-use-after-free @@ -386,3 +385,52 @@ SELECT * FROM t1; DROP TABLE t1; SET debug_sync= reset; set global debug_dbug= @old_dbug; + + +--echo # MDEV-16962 Assertion '!error || !ot_ctx.can_recover_from_failed_open()' +--echo # failed in open_purge_table upon concurrent ALTER and FLUSH + +CREATE TABLE t1 ( + pk SERIAL, + c VARCHAR(128), + d DATE, + vd DATE AS (d) VIRTUAL, + PRIMARY KEY(pk), + KEY(vd,c) +) ENGINE=InnoDB; +INSERT IGNORE INTO t1 (pk,c) VALUES (1,'foo'); + +--send +set debug_sync="now WAIT_FOR purge"; +--connect (con1,localhost,root,,test) +# Will break innodb purge thread inside open_purge_table after mdl +# acquired, but before tdc->flushed check +SET GLOBAL innodb_debug_sync="after_open_table_mdl_shared SIGNAL purge WAIT_FOR flush"; + +# Workaround to pass trx_undo_roll_ptr_is_insert() in 10.2 +SET global debug_dbug="d,ib_purge_virtual_index_callback"; + +REPLACE INTO t1 (pk,c) VALUES (1,'bar'); + +--connection default +# wait for MDL acquired by purge +--reap +# MDL_SHARED will be acquired, but will hang before MDL upgrade started. +SET debug_sync="alter_table_before_rename_result_table WAIT_FOR flush"; +--send +ALTER TABLE t1 ADD FULLTEXT KEY(c), ALGORITHM=COPY; +--connection con1 +# Will hang after tdc->flushed is set, but before emptying tdc cache. +SET debug_sync="after_flush_unlock SIGNAL flush "; +FLUSH TABLES; + +# Cleanup +--disconnect con1 +--connection default +--reap +--source ../../innodb/include/wait_all_purged.inc +DROP TABLE t1; +SET debug_sync= reset; +SET global debug_dbug=@old_dbug; + +SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 047d6517a4b..ac9df47dd47 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4424,7 +4424,7 @@ TABLE *open_purge_table(THD *thd, const char *db, size_t dblen, DBUG_ASSERT(thd->open_tables == NULL); DBUG_ASSERT(thd->locked_tables_mode < LTM_PRELOCKED); - Open_table_context ot_ctx(thd, 0); + Open_table_context ot_ctx(thd, MYSQL_OPEN_IGNORE_FLUSH); TABLE_LIST *tl= (TABLE_LIST*)thd->alloc(sizeof(TABLE_LIST)); tl->init_one_table(db, dblen, tb, tblen, tb, TL_READ); -- cgit v1.2.1 From f85afa5124b91d43105d32825a46584047975de7 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Tue, 23 Mar 2021 16:48:02 +0300 Subject: MDEV-19011 Assertion `file->s->base.reclength < file->s->vreclength' failed The assertion is improved: storage engines like myisam always have to store at least one field, so the assertion does not cover tables with no stored columns. --- mysql-test/suite/gcol/inc/gcol_keys.inc | 8 ++++++++ mysql-test/suite/gcol/r/gcol_keys_innodb.result | 5 +++++ mysql-test/suite/gcol/r/gcol_keys_myisam.result | 5 +++++ storage/myisam/ha_myisam.cc | 3 ++- 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/gcol/inc/gcol_keys.inc b/mysql-test/suite/gcol/inc/gcol_keys.inc index 475ab96e56f..e5f7f976120 100644 --- a/mysql-test/suite/gcol/inc/gcol_keys.inc +++ b/mysql-test/suite/gcol/inc/gcol_keys.inc @@ -809,4 +809,12 @@ eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/load.data' REPLACE INTO TABLE t1 (p --remove_file $MYSQLTEST_VARDIR/tmp/load.data DROP TABLE t1; + +--echo # MDEV-19011 Assertion `file->s->base.reclength < file->s->vreclength' +--echo # failed in ha_myisam::setup_vcols_for_repair +CREATE TABLE t1 (a INT GENERATED ALWAYS AS (1) VIRTUAL) ENGINE=MyISAM; +ALTER TABLE t1 ADD KEY (a); + +DROP TABLE t1; + } diff --git a/mysql-test/suite/gcol/r/gcol_keys_innodb.result b/mysql-test/suite/gcol/r/gcol_keys_innodb.result index ae2843dd2ec..5a29c64bc20 100644 --- a/mysql-test/suite/gcol/r/gcol_keys_innodb.result +++ b/mysql-test/suite/gcol/r/gcol_keys_innodb.result @@ -875,6 +875,11 @@ Warning 1264 Out of range value for column 'vi' at row 1 LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/load.data' REPLACE INTO TABLE t1 (pk,i,ts); ERROR 22003: Out of range value for column 'vi' at row 1 DROP TABLE t1; +# MDEV-19011 Assertion `file->s->base.reclength < file->s->vreclength' +# failed in ha_myisam::setup_vcols_for_repair +CREATE TABLE t1 (a INT GENERATED ALWAYS AS (1) VIRTUAL) ENGINE=MyISAM; +ALTER TABLE t1 ADD KEY (a); +DROP TABLE t1; # # BUG#21365158 WL8149:ASSERTION `!TABLE || (!TABLE->WRITE_SET # diff --git a/mysql-test/suite/gcol/r/gcol_keys_myisam.result b/mysql-test/suite/gcol/r/gcol_keys_myisam.result index a91a77aedf3..643c4a304a3 100644 --- a/mysql-test/suite/gcol/r/gcol_keys_myisam.result +++ b/mysql-test/suite/gcol/r/gcol_keys_myisam.result @@ -877,6 +877,11 @@ Warning 1264 Out of range value for column 'vi' at row 1 LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/load.data' REPLACE INTO TABLE t1 (pk,i,ts); ERROR 22003: Out of range value for column 'vi' at row 1 DROP TABLE t1; +# MDEV-19011 Assertion `file->s->base.reclength < file->s->vreclength' +# failed in ha_myisam::setup_vcols_for_repair +CREATE TABLE t1 (a INT GENERATED ALWAYS AS (1) VIRTUAL) ENGINE=MyISAM; +ALTER TABLE t1 ADD KEY (a); +DROP TABLE t1; DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index ce52f1af828..9a11a55ecab 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -945,7 +945,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; -- cgit v1.2.1 From 43e879c717952fa84e2914609a13b8f05da2daba Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Wed, 24 Mar 2021 01:02:26 +0300 Subject: MDEV-24583 SELECT aborts after failed REPLACE into table with vcol table->move_fields wasn't undone in case of error. 1. move_fields is unconditionally undone even when error is occurred 2. cherry-pick an assertion in `ptr_in_record`, which is already in 10.5 --- mysql-test/suite/gcol/r/gcol_bugfixes.result | 74 ++++++++++++++++++++++++ mysql-test/suite/gcol/t/gcol_bugfixes.test | 84 ++++++++++++++++++++++++++++ mysql-test/suite/vcol/r/binlog.result | 13 +++++ mysql-test/suite/vcol/t/binlog.test | 14 +++++ sql/field.h | 5 +- sql/sql_insert.cc | 5 +- 6 files changed, 191 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/gcol/r/gcol_bugfixes.result b/mysql-test/suite/gcol/r/gcol_bugfixes.result index 8eb7a9372b5..4bc424d1b1e 100644 --- a/mysql-test/suite/gcol/r/gcol_bugfixes.result +++ b/mysql-test/suite/gcol/r/gcol_bugfixes.result @@ -669,3 +669,77 @@ PRIMARY KEY (number) REPLACE t2(number) VALUES('1'); REPLACE t2(number) VALUES('1'); DROP TABLE t2; +# MDEV-24583 SELECT aborts after failed REPLACE into table with vcol +CREATE TABLE t1 (pk INT, a VARCHAR(3), v VARCHAR(3) AS (CONCAT('x-',a)), +PRIMARY KEY(pk)) ENGINE=MyISAM; +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (pk, a) VALUES (1,'foo'); +SET sql_mode=CONCAT(@@sql_mode,',STRICT_ALL_TABLES'); +REPLACE INTO t1 (pk,a) VALUES (1,'qux'); +SELECT * FROM v1; +pk a v +1 foo x-f +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 ( +pk INT, +a VARCHAR(1), +v VARCHAR(1) AS (CONCAT('virt-',a)) VIRTUAL, +PRIMARY KEY (pk) +) ENGINE=InnoDB; +INSERT INTO t1 (pk,a) VALUES +(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'),(6,'f'); +REPLACE INTO t1 (pk) VALUES (1); +ERROR 22001: Data too long for column 'v' at row 1 +SELECT * FROM t1 ORDER BY a; +pk a v +1 a v +2 b v +3 c v +4 d v +5 e v +6 f v +SET SQL_MODE=DEFAULT; +DROP TABLE t1; +# (duplicate) MDEV-24656 +# [FATAL] InnoDB: Data field type 0, len 0, ASAN heap-buffer-overflow +# upon LOAD DATA with virtual columns +CREATE TABLE t1 (id INT PRIMARY KEY, a VARCHAR(2333), +va VARCHAR(171) AS (a)) ENGINE=InnoDB; +INSERT INTO t1 (id,a) VALUES (1,REPEAT('x',200)); +SELECT id, va INTO OUTFILE 'load_t1' FROM t1; +LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id,va); +ERROR 22001: Data too long for column 'va' at row 1 +SELECT * FROM t1; +id a va +1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +LOAD DATA INFILE 'load_t1' IGNORE INTO TABLE t1 (id,va); +Warnings: +Warning 1062 Duplicate entry '1' for key 'PRIMARY' +DROP TABLE t1; +CREATE TABLE t1 (id BIGINT PRIMARY KEY, a VARCHAR(2333), +va VARCHAR(171) AS (a)) ENGINE=InnoDB; +INSERT INTO t1 (id,a) VALUES (1,REPEAT('x',200)); +SELECT id, va INTO OUTFILE 'load_t1' FROM t1; +LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id,va); +ERROR 22001: Data too long for column 'va' at row 1 +SELECT * FROM t1; +id a va +1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +LOAD DATA INFILE 'load_t1' IGNORE INTO TABLE t1 (id,va); +Warnings: +Warning 1062 Duplicate entry '1' for key 'PRIMARY' +DROP TABLE t1; +# (duplicate) MDEV-24665 +# ASAN errors, assertion failures, corrupt values after failed +# LOAD DATA into table with virtual/stored column +CREATE TABLE t1 (id INT PRIMARY KEY, +ts TIMESTAMP DEFAULT '1971-01-01 00:00:00', +c VARBINARY(8) DEFAULT '', vc VARCHAR(3) AS (c) STORED); +INSERT IGNORE INTO t1 (id,c) VALUES (1,'foobar'); +Warnings: +Warning 1265 Data truncated for column 'vc' at row 1 +SELECT id, ts, vc INTO OUTFILE 'load_t1' FROM t1; +LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id, ts, vc); +INSERT IGNORE INTO t1 (id) VALUES (2); +DROP TABLE t1; diff --git a/mysql-test/suite/gcol/t/gcol_bugfixes.test b/mysql-test/suite/gcol/t/gcol_bugfixes.test index 033c430853d..a1f277199eb 100644 --- a/mysql-test/suite/gcol/t/gcol_bugfixes.test +++ b/mysql-test/suite/gcol/t/gcol_bugfixes.test @@ -634,3 +634,87 @@ REPLACE t2(number) VALUES('1'); REPLACE t2(number) VALUES('1'); DROP TABLE t2; + +--echo # MDEV-24583 SELECT aborts after failed REPLACE into table with vcol + +CREATE TABLE t1 (pk INT, a VARCHAR(3), v VARCHAR(3) AS (CONCAT('x-',a)), + PRIMARY KEY(pk)) ENGINE=MyISAM; +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (pk, a) VALUES (1,'foo'); +SET sql_mode=CONCAT(@@sql_mode,',STRICT_ALL_TABLES'); +--error 0,ER_DATA_TOO_LONG +REPLACE INTO t1 (pk,a) VALUES (1,'qux'); +SELECT * FROM v1; + +# Cleanup +DROP VIEW v1; +DROP TABLE t1; + +CREATE TABLE t1 ( + pk INT, + a VARCHAR(1), + v VARCHAR(1) AS (CONCAT('virt-',a)) VIRTUAL, + PRIMARY KEY (pk) +) ENGINE=InnoDB; + +INSERT INTO t1 (pk,a) VALUES +(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'),(6,'f'); + + --error ER_DATA_TOO_LONG +REPLACE INTO t1 (pk) VALUES (1); +SELECT * FROM t1 ORDER BY a; + +SET SQL_MODE=DEFAULT; +DROP TABLE t1; + +--echo # (duplicate) MDEV-24656 +--echo # [FATAL] InnoDB: Data field type 0, len 0, ASAN heap-buffer-overflow +--echo # upon LOAD DATA with virtual columns + +CREATE TABLE t1 (id INT PRIMARY KEY, a VARCHAR(2333), + va VARCHAR(171) AS (a)) ENGINE=InnoDB; +INSERT INTO t1 (id,a) VALUES (1,REPEAT('x',200)); +SELECT id, va INTO OUTFILE 'load_t1' FROM t1; +--error ER_DATA_TOO_LONG +LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id,va); +SELECT * FROM t1; +LOAD DATA INFILE 'load_t1' IGNORE INTO TABLE t1 (id,va); + +DROP TABLE t1; +--let $datadir= `select @@datadir` +--remove_file $datadir/test/load_t1 + +CREATE TABLE t1 (id BIGINT PRIMARY KEY, a VARCHAR(2333), + va VARCHAR(171) AS (a)) ENGINE=InnoDB; +INSERT INTO t1 (id,a) VALUES (1,REPEAT('x',200)); +SELECT id, va INTO OUTFILE 'load_t1' FROM t1; +--error ER_DATA_TOO_LONG +LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id,va); +SELECT * FROM t1; +LOAD DATA INFILE 'load_t1' IGNORE INTO TABLE t1 (id,va); + +# Cleanup +DROP TABLE t1; +--let $datadir= `select @@datadir` +--remove_file $datadir/test/load_t1 + + +--echo # (duplicate) MDEV-24665 +--echo # ASAN errors, assertion failures, corrupt values after failed +--echo # LOAD DATA into table with virtual/stored column + +CREATE TABLE t1 (id INT PRIMARY KEY, + ts TIMESTAMP DEFAULT '1971-01-01 00:00:00', + c VARBINARY(8) DEFAULT '', vc VARCHAR(3) AS (c) STORED); +INSERT IGNORE INTO t1 (id,c) VALUES (1,'foobar'); +SELECT id, ts, vc INTO OUTFILE 'load_t1' FROM t1; +--error 0,ER_DATA_TOO_LONG +LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id, ts, vc); +INSERT IGNORE INTO t1 (id) VALUES (2); + +# Cleanup +DROP TABLE t1; +--let $datadir= `select @@datadir` +--remove_file $datadir/test/load_t1 + + diff --git a/mysql-test/suite/vcol/r/binlog.result b/mysql-test/suite/vcol/r/binlog.result index 83382d47511..d4893b7ed3c 100644 --- a/mysql-test/suite/vcol/r/binlog.result +++ b/mysql-test/suite/vcol/r/binlog.result @@ -67,4 +67,17 @@ connection master; DROP VIEW v1; set @@binlog_row_image=default; DROP TABLE t1; +SET SQL_MODE=default; +CREATE TABLE t1 (pk INT, a VARCHAR(3), b VARCHAR(1) AS (a) VIRTUAL, PRIMARY KEY (pk)); +INSERT IGNORE INTO t1 (pk, a) VALUES (1,'foo'),(2,'bar'); +Warnings: +Warning 1265 Data truncated for column 'b' at row 1 +Warning 1265 Data truncated for column 'b' at row 2 +REPLACE INTO t1 (pk) VALUES (2); +ERROR 22001: Data too long for column 'b' at row 1 +UPDATE IGNORE t1 SET a = NULL; +Warnings: +Warning 1265 Data truncated for column 'b' at row 1 +Warning 1265 Data truncated for column 'b' at row 2 +DROP TABLE t1; include/rpl_end.inc diff --git a/mysql-test/suite/vcol/t/binlog.test b/mysql-test/suite/vcol/t/binlog.test index 95bb4df4cc5..aa939086f12 100644 --- a/mysql-test/suite/vcol/t/binlog.test +++ b/mysql-test/suite/vcol/t/binlog.test @@ -51,5 +51,19 @@ DROP VIEW v1; set @@binlog_row_image=default; DROP TABLE t1; +SET SQL_MODE=default; + +# MDEV-24782 +# ASAN use-after-poison in Field::pack_int / THD::binlog_update_row + +CREATE TABLE t1 (pk INT, a VARCHAR(3), b VARCHAR(1) AS (a) VIRTUAL, PRIMARY KEY (pk)); +INSERT IGNORE INTO t1 (pk, a) VALUES (1,'foo'),(2,'bar'); +--error ER_DATA_TOO_LONG +REPLACE INTO t1 (pk) VALUES (2); +UPDATE IGNORE t1 SET a = NULL; + +# Cleanup +DROP TABLE t1; + --source include/rpl_end.inc diff --git a/sql/field.h b/sql/field.h index 18e44f1d9d4..f63fb670211 100644 --- a/sql/field.h +++ b/sql/field.h @@ -972,8 +972,9 @@ public: virtual void reset_fields() {} const uchar *ptr_in_record(const uchar *record) const { - my_ptrdiff_t l_offset= (my_ptrdiff_t) (record - table->record[0]); - return ptr + l_offset; + my_ptrdiff_t l_offset= (my_ptrdiff_t) (ptr - table->record[0]); + DBUG_ASSERT(l_offset >= 0 && table->s->rec_buff_length - l_offset > 0); + return record + l_offset; } virtual int set_default(); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index ec79ff6d688..90cf8782d48 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1753,9 +1753,10 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) in handler methods for the just read row in record[1]. */ table->move_fields(table->field, table->record[1], table->record[0]); - if (table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_REPLACE)) - goto err; + int verr = table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_REPLACE); table->move_fields(table->field, table->record[0], table->record[1]); + if (verr) + goto err; } if (info->handle_duplicates == DUP_UPDATE) { -- cgit v1.2.1 From a312cb28bdc42a9e44ad4989439b9be41c548bd4 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 27 Apr 2021 12:57:17 +0300 Subject: MDEV-20842 fix test internal check failure --- mysql-test/suite/versioning/r/trx_id.result | 5 +++-- mysql-test/suite/versioning/t/trx_id.opt | 1 - mysql-test/suite/versioning/t/trx_id.test | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) delete mode 100644 mysql-test/suite/versioning/t/trx_id.opt diff --git a/mysql-test/suite/versioning/r/trx_id.result b/mysql-test/suite/versioning/r/trx_id.result index ea06a2e545d..c6abadcb076 100644 --- a/mysql-test/suite/versioning/r/trx_id.result +++ b/mysql-test/suite/versioning/r/trx_id.result @@ -1,3 +1,4 @@ +install plugin test_versioning soname 'test_versioning.so'; set default_storage_engine= innodb; create or replace table t1 ( x int, @@ -505,10 +506,10 @@ add `row_end` bigint unsigned as row end, add period for system_time(`row_start`,`row_end`), modify x int after row_start, with system versioning; -create or replace database test; +drop table t; # # MDEV-20842 Crash using versioning plugin functions after plugin was removed from server # uninstall plugin test_versioning; select trt_begin_ts(0); -ERROR 42000: FUNCTION trt_begin_ts does not exist +ERROR 42000: FUNCTION test.trt_begin_ts does not exist diff --git a/mysql-test/suite/versioning/t/trx_id.opt b/mysql-test/suite/versioning/t/trx_id.opt deleted file mode 100644 index b55a187cb13..00000000000 --- a/mysql-test/suite/versioning/t/trx_id.opt +++ /dev/null @@ -1 +0,0 @@ ---plugin-load-add=$TEST_VERSIONING_SO diff --git a/mysql-test/suite/versioning/t/trx_id.test b/mysql-test/suite/versioning/t/trx_id.test index b68d5513dd9..0212c9f759f 100644 --- a/mysql-test/suite/versioning/t/trx_id.test +++ b/mysql-test/suite/versioning/t/trx_id.test @@ -5,6 +5,8 @@ if (!$TEST_VERSIONING_SO) --source include/have_innodb.inc --source include/default_charset.inc +--eval install plugin test_versioning soname '$TEST_VERSIONING_SO' + set default_storage_engine= innodb; create or replace table t1 ( @@ -528,8 +530,7 @@ alter table t add `row_start` bigint unsigned as row start, add period for system_time(`row_start`,`row_end`), modify x int after row_start, with system versioning; - -create or replace database test; +drop table t; --echo # --echo # MDEV-20842 Crash using versioning plugin functions after plugin was removed from server -- cgit v1.2.1 From 2b0d5b78c2bbe2bdd763a8e2ed12be644bd705d2 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 26 Apr 2021 22:20:44 +0530 Subject: MDEV-22928 InnoDB fails to fetch index type when index mismatch happens InnoDB fails to fetch the index type when innodb dictionary doesn't match with frm. InnoDB should return corrupted if it can't find the index in ha_innobase::index_type(). --- .../suite/innodb/r/innodb-alter-tempfile.result | 25 ++++++++++++++++++++ .../suite/innodb/t/innodb-alter-tempfile.test | 27 ++++++++++++++++++++++ sql/sql_table.cc | 1 + storage/innobase/handler/ha_innodb.cc | 14 +++++++---- 4 files changed, 63 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb-alter-tempfile.result b/mysql-test/suite/innodb/r/innodb-alter-tempfile.result index 3b797559603..7441cc23594 100644 --- a/mysql-test/suite/innodb/r/innodb-alter-tempfile.result +++ b/mysql-test/suite/innodb/r/innodb-alter-tempfile.result @@ -1,3 +1,7 @@ +call mtr.add_suppression("Cannot find index f2 in InnoDB index dictionary."); +call mtr.add_suppression("InnoDB indexes are inconsistent with what defined in .frm for table .*"); +call mtr.add_suppression("Table test/t1 contains 1 indexes inside InnoDB, which is different from the number of indexes 2 defined in the MariaDB .*"); +call mtr.add_suppression("InnoDB could not find key no 1 with name f2 from dict cache for table .*"); # # Bug #18734396 INNODB IN-PLACE ALTER FAILURES BLOCK FUTURE ALTERS # @@ -25,3 +29,24 @@ t1 CREATE TABLE `t1` ( PRIMARY KEY (`f2`,`f1`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 drop table t1; +# +# MDEV-22928 InnoDB fails to fetch index type +# when index mismatch +# +CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL, +index(f1), index(f2))ENGINE=InnoDB; +INSERT INTO t1 VALUES(1, 1), (2, 2); +connect con1,localhost,root,,test; +SET DEBUG_SYNC="alter_table_inplace_after_commit SIGNAL default_signal WAIT_FOR default_done"; +ALTER TABLE t1 DROP INDEX f2, ALGORITHM=INPLACE; +connection default; +set DEBUG_SYNC="now WAIT_FOR default_signal"; +disconnect con1; +SHOW KEYS FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 1 f1 1 f1 A 2 NULL NULL BTREE +t1 1 f2 1 f2 A NULL NULL NULL Corrupted +Warnings: +Warning 1082 InnoDB: Table test/t1 contains 1 indexes inside InnoDB, which is different from the number of indexes 2 defined in the MariaDB +Warning 1082 InnoDB: Table test/t1 contains 1 indexes inside InnoDB, which is different from the number of indexes 2 defined in the MariaDB +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/innodb-alter-tempfile.test b/mysql-test/suite/innodb/t/innodb-alter-tempfile.test index de27c7ebf62..e6fafd936c8 100644 --- a/mysql-test/suite/innodb/t/innodb-alter-tempfile.test +++ b/mysql-test/suite/innodb/t/innodb-alter-tempfile.test @@ -12,6 +12,12 @@ --source include/innodb_page_size.inc +call mtr.add_suppression("Cannot find index f2 in InnoDB index dictionary."); +call mtr.add_suppression("InnoDB indexes are inconsistent with what defined in .frm for table .*"); +call mtr.add_suppression("Table test/t1 contains 1 indexes inside InnoDB, which is different from the number of indexes 2 defined in the MariaDB .*"); +call mtr.add_suppression("InnoDB could not find key no 1 with name f2 from dict cache for table .*"); + + --echo # --echo # Bug #18734396 INNODB IN-PLACE ALTER FAILURES BLOCK FUTURE ALTERS --echo # @@ -42,3 +48,24 @@ show create table t1; ALTER TABLE t1 ADD PRIMARY KEY (f2, f1); show create table t1; drop table t1; + +--echo # +--echo # MDEV-22928 InnoDB fails to fetch index type +--echo # when index mismatch +--echo # +CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL, + index(f1), index(f2))ENGINE=InnoDB; +INSERT INTO t1 VALUES(1, 1), (2, 2); + +connect (con1,localhost,root,,test); +SET DEBUG_SYNC="alter_table_inplace_after_commit SIGNAL default_signal WAIT_FOR default_done"; +--send +ALTER TABLE t1 DROP INDEX f2, ALGORITHM=INPLACE; +connection default; +set DEBUG_SYNC="now WAIT_FOR default_signal"; +--let $shutdown_timeout=0 +--source include/restart_mysqld.inc +disconnect con1; +SHOW KEYS FROM t1; +DROP TABLE t1; +remove_files_wildcard $datadir/test #sql-*.frm; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 07762e64259..2b26af6e9ba 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7537,6 +7537,7 @@ static bool mysql_inplace_alter_table(THD *thd, goto rollback; } + DEBUG_SYNC(thd, "alter_table_inplace_after_commit"); close_all_tables_for_name(thd, table->s, alter_ctx->is_table_renamed() ? HA_EXTRA_PREPARE_FOR_RENAME : diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 22fe3b5d9ed..e431b3f3595 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -5338,13 +5338,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"); } /****************************************************************//** -- cgit v1.2.1 From b862377c3e9a6818bc2d5265c19edeee79a293fc Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 27 Apr 2021 16:46:54 +0530 Subject: MDEV-25503 InnoDB hangs on startup during recovery InnoDB startup hangs if a DDL transaction needs to be rolled back and a recovered transaction on statistics tables exists. In that case, InnoDB should rollback the transaction which holds locks on innodb_table_stats or innodb_index_stats during trx_rollback_or_clean_recovered(). --- .../suite/innodb/r/innodb-alter-tempfile.result | 15 +++++++++++++++ .../suite/innodb/t/innodb-alter-tempfile.test | 22 ++++++++++++++++++++++ storage/innobase/dict/dict0dict.cc | 6 ++++++ storage/innobase/include/dict0mem.h | 5 +++++ storage/innobase/include/trx0trx.h | 4 ++++ storage/innobase/trx/trx0roll.cc | 6 ++++-- storage/innobase/trx/trx0trx.cc | 13 +++++++++++++ 7 files changed, 69 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb-alter-tempfile.result b/mysql-test/suite/innodb/r/innodb-alter-tempfile.result index 7441cc23594..ad6e17b920c 100644 --- a/mysql-test/suite/innodb/r/innodb-alter-tempfile.result +++ b/mysql-test/suite/innodb/r/innodb-alter-tempfile.result @@ -50,3 +50,18 @@ Warnings: Warning 1082 InnoDB: Table test/t1 contains 1 indexes inside InnoDB, which is different from the number of indexes 2 defined in the MariaDB Warning 1082 InnoDB: Table test/t1 contains 1 indexes inside InnoDB, which is different from the number of indexes 2 defined in the MariaDB DROP TABLE t1; +# +# MDEV-25503 InnoDB hangs on startup during recovery +# +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1; +connect con1,localhost,root,,; +BEGIN; +DELETE FROM mysql.innodb_table_stats; +connect con2,localhost,root,,; +SET DEBUG_SYNC='inplace_after_index_build SIGNAL blocked WAIT_FOR ever'; +ALTER TABLE t1 FORCE; +connection default; +SET DEBUG_SYNC='now WAIT_FOR blocked'; +SELECT * FROM t1; +a +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/innodb-alter-tempfile.test b/mysql-test/suite/innodb/t/innodb-alter-tempfile.test index e6fafd936c8..7e4244d09f8 100644 --- a/mysql-test/suite/innodb/t/innodb-alter-tempfile.test +++ b/mysql-test/suite/innodb/t/innodb-alter-tempfile.test @@ -12,6 +12,8 @@ --source include/innodb_page_size.inc +--source include/have_debug_sync.inc + call mtr.add_suppression("Cannot find index f2 in InnoDB index dictionary."); call mtr.add_suppression("InnoDB indexes are inconsistent with what defined in .frm for table .*"); call mtr.add_suppression("Table test/t1 contains 1 indexes inside InnoDB, which is different from the number of indexes 2 defined in the MariaDB .*"); @@ -69,3 +71,23 @@ disconnect con1; SHOW KEYS FROM t1; DROP TABLE t1; remove_files_wildcard $datadir/test #sql-*.frm; + +--echo # +--echo # MDEV-25503 InnoDB hangs on startup during recovery +--echo # +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1; +connect (con1,localhost,root,,); +BEGIN; +DELETE FROM mysql.innodb_table_stats; + +connect (con2,localhost,root,,); +SET DEBUG_SYNC='inplace_after_index_build SIGNAL blocked WAIT_FOR ever'; +send ALTER TABLE t1 FORCE; + +connection default; +SET DEBUG_SYNC='now WAIT_FOR blocked'; +--let $shutdown_timeout=0 +--source include/restart_mysqld.inc +SELECT * FROM t1; +DROP TABLE t1; +remove_files_wildcard $datadir/test #sql-*.frm; diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index d6330cb5906..48c37855d3e 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -6719,3 +6719,9 @@ dict_table_t::get_overflow_field_local_len() const /* new-format table: do not store any BLOB prefix locally */ return BTR_EXTERN_FIELD_REF_SIZE; } + +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/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 7ca1ad9ecd3..ae7f00c01bf 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -1935,6 +1935,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 bool table_name_t::is_temporary() const diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 5354c77db25..a7591fa1b19 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -1191,6 +1191,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 */ inline void free(); diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index c5f70452bf2..c986a866fe2 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -677,7 +677,8 @@ ibool trx_rollback_resurrected( /*=====================*/ trx_t* trx, /*!< in: transaction to rollback or clean */ - ibool* all) /*!< in/out: FALSE=roll back dictionary transactions; + ibool* all) /*!< in/out: FALSE=roll back dictionary and + statistics table transactions; TRUE=roll back all non-PREPARED transactions */ { ut_ad(trx_sys_mutex_own()); @@ -713,7 +714,8 @@ fake_prepared: } trx_mutex_exit(trx); - 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_sys_mutex_exit(); 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 42bd67cb24b..e3df3f397a5 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -3072,3 +3072,16 @@ trx_set_rw_mode( mutex_exit(&trx_sys->mutex); } + +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; +} -- cgit v1.2.1 From 883b723d7cc38c04f48395c1cf5512900c7c2705 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 27 Apr 2021 11:19:10 +0200 Subject: MDEV-25326 mysql_install_db help text incomplete encourage the use of mysql_secure_installation, that can always set the root password correctly for all root accounts, no matter how many are there and what the structure of privilege tables is --- scripts/mysql_install_db.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index 0326d4fcd7d..c6129659151 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -556,12 +556,8 @@ then echo echo echo "PLEASE REMEMBER TO SET A PASSWORD FOR THE MariaDB root USER !" - echo "To do so, start the server, then issue the following commands:" + echo "To do so, start the server, then issue the following command:" echo - echo "'$bindir/mysqladmin' -u root password 'new-password'" - echo "'$bindir/mysqladmin' -u root -h $hostname password 'new-password'" - echo - echo "Alternatively you can run:" echo "'$bindir/mysql_secure_installation'" echo echo "which will also give you the option of removing the test" -- cgit v1.2.1 From 4f63b6cf53ce2d9eaf4a8006587ebf3c4d6ddd3c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 26 Apr 2021 16:52:32 +0200 Subject: Bug #31674599: THE UDF_INIT() FUNCTION CAUSE SERVER CRASH --- mysql-test/r/udf.result | 8 ++++++++ mysql-test/t/udf.test | 10 ++++++++++ sql/sql_udf.cc | 6 +++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result index 49768f6c514..367fc187ed2 100644 --- a/mysql-test/r/udf.result +++ b/mysql-test/r/udf.result @@ -492,4 +492,12 @@ select * from mysql.plugin WHERE name='unexisting_udf'; name dl DROP FUNCTION unexisting_udf; ERROR 42000: FUNCTION test.unexisting_udf does not exist +# +# Bug #31674599: THE UDF_INIT() FUNCTION CAUSE SERVER CRASH +# +call mtr.add_suppression('Invalid row in mysql.func table'); +insert mysql.func () values (); +delete from mysql.func where name = ''; +# # End of 10.2 tests +# diff --git a/mysql-test/t/udf.test b/mysql-test/t/udf.test index 07c7f599db7..199c0737dd1 100644 --- a/mysql-test/t/udf.test +++ b/mysql-test/t/udf.test @@ -562,4 +562,14 @@ select * from mysql.plugin WHERE name='unexisting_udf'; --error ER_SP_DOES_NOT_EXIST DROP FUNCTION unexisting_udf; +--echo # +--echo # Bug #31674599: THE UDF_INIT() FUNCTION CAUSE SERVER CRASH +--echo # +call mtr.add_suppression('Invalid row in mysql.func table'); +insert mysql.func () values (); +source include/restart_mysqld.inc; +delete from mysql.func where name = ''; + +--echo # --echo # End of 10.2 tests +--echo # diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 2af12d94228..c026ef6b7ba 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -196,7 +196,7 @@ void udf_init() DBUG_PRINT("info",("init udf record")); LEX_STRING name; name.str=get_field(&mem, table->field[0]); - name.length = (uint) strlen(name.str); + name.length = (uint) safe_strlen(name.str); char *dl_name= get_field(&mem, table->field[2]); bool new_dl=0; Item_udftype udftype=UDFTYPE_FUNCTION; @@ -210,12 +210,12 @@ void udf_init() On windows we must check both FN_LIBCHAR and '/'. */ - if (check_valid_path(dl_name, strlen(dl_name)) || + if (!name.str || !dl_name || check_valid_path(dl_name, strlen(dl_name)) || check_string_char_length(&name, 0, NAME_CHAR_LEN, system_charset_info, 1)) { sql_print_error("Invalid row in mysql.func table for function '%.64s'", - name.str); + safe_str(name.str)); continue; } -- cgit v1.2.1 From 91599701d07a9efb02a2f27d17a8f95bc2b9accf Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 26 Apr 2021 22:32:58 +0200 Subject: Bug#29363867: LOST CONNECTION TO MYSQL SERVER DURING QUERY plugin variables in SET only locked the plugin till the end of the statement. If SET with a plugin variable was prepared, it was possible to uninstall the plugin before EXECUTE. Then EXECUTE would crash, trying to resolve a now-invalid pointer to a disappeared variable. Fix: keep plugins locked until the prepared statement is closed. --- mysql-test/r/plugin_vars.result | 35 +++++++++++++++++++++++++++++++++++ mysql-test/t/plugin_vars.test | 35 +++++++++++++++++++++++++++++++++++ sql/sql_lex.cc | 34 ++++++++++++---------------------- sql/sql_lex.h | 4 ++-- sql/sql_prepare.cc | 8 +++++--- 5 files changed, 89 insertions(+), 27 deletions(-) diff --git a/mysql-test/r/plugin_vars.result b/mysql-test/r/plugin_vars.result index 0e382427b1d..3fadd5e74fd 100644 --- a/mysql-test/r/plugin_vars.result +++ b/mysql-test/r/plugin_vars.result @@ -30,3 +30,38 @@ disconnect con2; USE test; DROP PROCEDURE p_install; DROP PROCEDURE p_show_vars; +# +# Bug#29363867: LOST CONNECTION TO MYSQL SERVER DURING QUERY +# +## prepared SET with a plugin variable prevents uninstall +install plugin query_response_time soname 'query_response_time'; +prepare s from 'set global query_response_time_range_base=16'; +select plugin_status from information_schema.plugins where plugin_name='query_response_time'; +plugin_status +ACTIVE +uninstall plugin query_response_time; +Warnings: +Warning 1620 Plugin is busy and will be uninstalled on shutdown +execute s; +execute s; +select plugin_status from information_schema.plugins where plugin_name='query_response_time'; +plugin_status +DELETED +deallocate prepare s; +select plugin_status from information_schema.plugins where plugin_name='query_response_time'; +plugin_status +## prepared SET mentioning a plugin otherwise does not prevent uninstall +install plugin archive soname 'ha_archive'; +create table t1 (a int) engine=archive; +insert t1 values (1),(2),(3); +prepare s from 'set session auto_increment_increment=(select count(*) from t1)'; +flush tables; +select plugin_status from information_schema.plugins where plugin_name='archive'; +plugin_status +ACTIVE +uninstall plugin archive; +select plugin_status from information_schema.plugins where plugin_name='archive'; +plugin_status +execute s; +ERROR 42000: Unknown storage engine 'ARCHIVE' +drop table t1; diff --git a/mysql-test/t/plugin_vars.test b/mysql-test/t/plugin_vars.test index 8ba8fe2ec0e..797dcbea727 100644 --- a/mysql-test/t/plugin_vars.test +++ b/mysql-test/t/plugin_vars.test @@ -1,3 +1,10 @@ +if (!$QUERY_RESPONSE_TIME_SO) { + skip Needs query_response_time loadable plugin; +} +if (!$HA_ARCHIVE_SO) { + skip Needs Archive loadable plugin; +} + --echo # --echo # MDEV-5345 - Deadlock between mysql_change_user(), SHOW VARIABLES and --echo # INSTALL PLUGIN @@ -54,3 +61,31 @@ disconnect con2; USE test; DROP PROCEDURE p_install; DROP PROCEDURE p_show_vars; + +--echo # +--echo # Bug#29363867: LOST CONNECTION TO MYSQL SERVER DURING QUERY +--echo # + +--echo ## prepared SET with a plugin variable prevents uninstall +install plugin query_response_time soname 'query_response_time'; +prepare s from 'set global query_response_time_range_base=16'; +select plugin_status from information_schema.plugins where plugin_name='query_response_time'; +uninstall plugin query_response_time; +execute s; +execute s; +select plugin_status from information_schema.plugins where plugin_name='query_response_time'; +deallocate prepare s; +select plugin_status from information_schema.plugins where plugin_name='query_response_time'; + +--echo ## prepared SET mentioning a plugin otherwise does not prevent uninstall +install plugin archive soname 'ha_archive'; +create table t1 (a int) engine=archive; +insert t1 values (1),(2),(3); +prepare s from 'set session auto_increment_increment=(select count(*) from t1)'; +flush tables; +select plugin_status from information_schema.plugins where plugin_name='archive'; +uninstall plugin archive; +select plugin_status from information_schema.plugins where plugin_name='archive'; +--error ER_UNKNOWN_STORAGE_ENGINE +execute s; +drop table t1; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 57c6dfad4e5..c534ba76670 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -765,15 +765,15 @@ void lex_end(LEX *lex) DBUG_ENTER("lex_end"); DBUG_PRINT("enter", ("lex: %p", lex)); - lex_end_stage1(lex); - lex_end_stage2(lex); + lex_unlock_plugins(lex); + lex_end_nops(lex); DBUG_VOID_RETURN; } -void lex_end_stage1(LEX *lex) +void lex_unlock_plugins(LEX *lex) { - DBUG_ENTER("lex_end_stage1"); + DBUG_ENTER("lex_unlock_plugins"); /* release used plugins */ if (lex->plugins.elements) /* No function call and no mutex if no plugins. */ @@ -782,33 +782,23 @@ void lex_end_stage1(LEX *lex) lex->plugins.elements); } reset_dynamic(&lex->plugins); - - if (lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_PREPARE) - { - /* - Don't delete lex->sphead, it'll be needed for EXECUTE. - Note that of all statements that populate lex->sphead - only SQLCOM_COMPOUND can be PREPAREd - */ - DBUG_ASSERT(lex->sphead == 0 || lex->sql_command == SQLCOM_COMPOUND); - } - else - { - sp_head::destroy(lex->sphead); - lex->sphead= NULL; - } - DBUG_VOID_RETURN; } /* + Don't delete lex->sphead, it'll be needed for EXECUTE. + Note that of all statements that populate lex->sphead + only SQLCOM_COMPOUND can be PREPAREd + MASTER INFO parameters (or state) is normally cleared towards the end of a statement. But in case of PS, the state needs to be preserved during its lifetime and should only be cleared on PS close or deallocation. */ -void lex_end_stage2(LEX *lex) +void lex_end_nops(LEX *lex) { - DBUG_ENTER("lex_end_stage2"); + DBUG_ENTER("lex_end_nops"); + sp_head::destroy(lex->sphead); + lex->sphead= NULL; /* Reset LEX_MASTER_INFO */ lex->mi.reset(lex->sql_command == SQLCOM_CHANGE_MASTER); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 0dab0f0666d..fbc2bf7f822 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3412,8 +3412,8 @@ extern void lex_init(void); extern void lex_free(void); extern void lex_start(THD *thd); extern void lex_end(LEX *lex); -extern void lex_end_stage1(LEX *lex); -extern void lex_end_stage2(LEX *lex); +extern void lex_end_nops(LEX *lex); +extern void lex_unlock_plugins(LEX *lex); void end_lex_with_single_table(THD *thd, TABLE *table, LEX *old_lex); int init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex); extern int MYSQLlex(union YYSTYPE *yylval, THD *thd); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index fa335465f02..56a38757f28 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -4307,8 +4307,10 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) thd->release_transactional_locks(); } - /* Preserve CHANGE MASTER attributes */ - lex_end_stage1(lex); + /* Preserve locked plugins for SET */ + if (lex->sql_command != SQLCOM_SET_OPTION) + lex_unlock_plugins(lex); + cleanup_stmt(); thd->restore_backup_statement(this, &stmt_backup); thd->stmt_arena= old_stmt_arena; @@ -5189,7 +5191,7 @@ void Prepared_statement::deallocate_immediate() status_var_increment(thd->status_var.com_stmt_close); /* It should now be safe to reset CHANGE MASTER parameters */ - lex_end_stage2(lex); + lex_end(lex); } -- cgit v1.2.1 From 1ca56de8a68075bd189140b1fd953262c3b39002 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 27 Apr 2021 21:30:15 +0300 Subject: MDEV-20842 fix windows result failure --- mysql-test/suite/versioning/r/trx_id.result | 1 - mysql-test/suite/versioning/t/trx_id.test | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/versioning/r/trx_id.result b/mysql-test/suite/versioning/r/trx_id.result index c6abadcb076..bad7272419e 100644 --- a/mysql-test/suite/versioning/r/trx_id.result +++ b/mysql-test/suite/versioning/r/trx_id.result @@ -1,4 +1,3 @@ -install plugin test_versioning soname 'test_versioning.so'; set default_storage_engine= innodb; create or replace table t1 ( x int, diff --git a/mysql-test/suite/versioning/t/trx_id.test b/mysql-test/suite/versioning/t/trx_id.test index 0212c9f759f..08f183536f6 100644 --- a/mysql-test/suite/versioning/t/trx_id.test +++ b/mysql-test/suite/versioning/t/trx_id.test @@ -5,7 +5,9 @@ if (!$TEST_VERSIONING_SO) --source include/have_innodb.inc --source include/default_charset.inc +--disable_query_log --eval install plugin test_versioning soname '$TEST_VERSIONING_SO' +--enable_query_log set default_storage_engine= innodb; -- cgit v1.2.1 From b07a6f45fe78dcc2f40e1e980a8ab712416e08cd Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 26 Apr 2021 12:18:39 +0200 Subject: MDEV-25232 - CMake deprecation warning about CMAKE_MINIMUM_REQUIRED < 2.8.12 --- CMakeLists.txt | 27 +++++++++++++-------------- storage/mroonga/CMakeLists.txt | 2 +- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3decb4bac67..866792967d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA -CMAKE_MINIMUM_REQUIRED(VERSION 2.8.5) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12) +PROJECT(MySQL) # explicitly set the policy to OLD # (cannot use NEW, not everyone is on cmake-2.8.12 yet) @@ -53,8 +54,16 @@ IF(NOT DEFINED MANUFACTURER) MARK_AS_ADVANCED(MANUFACTURER) ENDIF() -SET(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING - "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel") +IF(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + # Setting build type to RelWithDebInfo as none was specified.") + SET(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING + "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel" + FORCE) + # Set the possible values of build type for cmake-gui + SET_PROPERTY(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "None" "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +ENDIF() + # MAX_INDEXES - Set the maximum number of indexes per table, default 64 IF (NOT MAX_INDEXES) @@ -83,18 +92,8 @@ IF(UNIX AND NOT APPLE) MARK_AS_ADVANCED(WITH_PIC) ENDIF() -# Optionally set project name, e.g. -# foo.xcodeproj (mac) or foo.sln (windows) +# This is used by TokuDB only SET(MYSQL_PROJECT_NAME_DOCSTRING "MySQL project name") -IF(DEFINED MYSQL_PROJECT_NAME) - SET(MYSQL_PROJECT_NAME ${MYSQL_PROJECT_NAME} CACHE STRING - ${MYSQL_PROJECT_NAME_DOCSTRING} FORCE) -ELSE() - SET(MYSQL_PROJECT_NAME "MySQL" CACHE STRING - ${MYSQL_PROJECT_NAME_DOCSTRING} FORCE) - MARK_AS_ADVANCED(MYSQL_PROJECT_NAME) -ENDIF() -PROJECT(${MYSQL_PROJECT_NAME}) SET(CPACK_PACKAGE_NAME "MariaDB") SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MariaDB: a very fast and robust SQL database server") diff --git a/storage/mroonga/CMakeLists.txt b/storage/mroonga/CMakeLists.txt index 9af111baf56..317c337e247 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}") -- cgit v1.2.1 From a6e97dad8a333e22d6d757df3afbd348be74347c Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 26 Apr 2021 12:19:01 +0200 Subject: MDEV-25232 update libmariadb --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index d19c7c69269..0bd29ba4fab 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit d19c7c69269fdf4e2af8943dd86c12e4e1664afd +Subproject commit 0bd29ba4fab5a4c75ea93f71983381433b90b35c -- cgit v1.2.1 From b9fbd102dd294eb8247eb22d92c68e933fac4595 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 28 Apr 2021 00:36:19 +0200 Subject: MDEV-19198 - DBUG assert in CREATE IF NOT EXIST under LOCK TABLES WRITE Relax the assert condition. A locked table that did existed prior to CREATE IF NOT EXIST, retains the MDL_NO_SHARED_READ_WRITE MDL lock prio. --- mysql-test/r/mdev19198.result | 15 +++++++++++++++ mysql-test/t/mdev19198.test | 15 +++++++++++++++ sql/sql_table.cc | 9 ++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 mysql-test/r/mdev19198.result create mode 100644 mysql-test/t/mdev19198.test diff --git a/mysql-test/r/mdev19198.result b/mysql-test/r/mdev19198.result new file mode 100644 index 00000000000..77c08ca0fb7 --- /dev/null +++ b/mysql-test/r/mdev19198.result @@ -0,0 +1,15 @@ +CREATE TABLE t1 (c INT); +CREATE TABLE t2 (c INT); +LOCK TABLES t1 WRITE, t2 READ; +CREATE TABLE IF NOT EXISTS t1 LIKE t2; +Warnings: +Note 1050 Table 't1' already exists +UNLOCK TABLES; +LOCK TABLES t1 READ , t2 READ; +CREATE TABLE IF NOT EXISTS t1 LIKE t2; +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +UNLOCK TABLES; +CREATE TABLE IF NOT EXISTS t1 LIKE t2; +Warnings: +Note 1050 Table 't1' already exists +DROP TABLES t1,t2; diff --git a/mysql-test/t/mdev19198.test b/mysql-test/t/mdev19198.test new file mode 100644 index 00000000000..19b45ed7510 --- /dev/null +++ b/mysql-test/t/mdev19198.test @@ -0,0 +1,15 @@ +CREATE TABLE t1 (c INT); +CREATE TABLE t2 (c INT); + +LOCK TABLES t1 WRITE, t2 READ; +CREATE TABLE IF NOT EXISTS t1 LIKE t2; +UNLOCK TABLES; + +LOCK TABLES t1 READ , t2 READ; +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +CREATE TABLE IF NOT EXISTS t1 LIKE t2; +UNLOCK TABLES; + +CREATE TABLE IF NOT EXISTS t1 LIKE t2; + +DROP TABLES t1,t2; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2b26af6e9ba..3a3a903bc35 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5615,11 +5615,18 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, /* Ensure that we have an exclusive lock on target table if we are creating non-temporary table. + If we're creating non-temporary table, then either + - there is an exclusive lock on the table + or + - there was CREATE IF EXIST, and the table was not created + (it existed), and was previously locked */ DBUG_ASSERT((create_info->tmp_table()) || thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db, table->table_name, - MDL_EXCLUSIVE)); + MDL_EXCLUSIVE) || + (thd->locked_tables_mode && pos_in_locked_tables && + create_info->if_not_exists())); } DEBUG_SYNC(thd, "create_table_like_before_binlog"); -- cgit v1.2.1 From 2e279962e97c03db1546d7069256ccc60d41e67e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 27 Apr 2021 13:00:04 +0200 Subject: cleanup: lowercase_table.test --- mysql-test/main/lowercase_table.result | 31 ++++++++++++++----- mysql-test/main/lowercase_table.test | 56 ++++++++++++++++------------------ 2 files changed, 50 insertions(+), 37 deletions(-) diff --git a/mysql-test/main/lowercase_table.result b/mysql-test/main/lowercase_table.result index 823ffa7696f..92dfdfdac96 100644 --- a/mysql-test/main/lowercase_table.result +++ b/mysql-test/main/lowercase_table.result @@ -1,7 +1,3 @@ -drop table if exists t1,t2,t3,t4; -drop table if exists t0,t5,t6,t7,t8,t9; -drop database if exists mysqltest; -drop view if exists v0, v1, v2, v3, v4; create table T1 (id int primary key, Word varchar(40) not null, Index(Word)); create table t4 (id int primary key, Word varchar(40) not null); INSERT INTO T1 VALUES (1, 'a'), (2, 'b'), (3, 'c'); @@ -79,13 +75,21 @@ ERROR 42000: Not unique table/alias: 'C' select C.a, c.a from t1 c, t2 C; ERROR 42000: Not unique table/alias: 'C' drop table t1, t2; +# +# Bug #9761: CREATE TABLE ... LIKE ... not handled correctly when lower_case_table_names is set +# create table t1 (a int); create table t2 like T1; drop table t1, t2; show tables; Tables_in_test +# +# End of 4.1 tests +# +# +# Bug#20404: SHOW CREATE TABLE fails with Turkish I +# set names utf8; -drop table if exists Ä°,Ä°Ä°; create table Ä° (s1 int); show create table Ä°; Table Create Table @@ -107,7 +111,12 @@ Tables_in_test ii drop table Ä°Ä°; set names latin1; -End of 5.0 tests +# +# End of 5.0 tests +# +# +# Bug#21317: SHOW CREATE DATABASE does not obey to lower_case_table_names +# create database mysql_TEST character set latin2; create table mysql_TEST.T1 (a int); show create database mysql_TEST; @@ -126,8 +135,16 @@ show databases like "mysql_TE%"; Database (mysql_TE%) mysql_test drop database mysql_TEST; -End of 10.0 tests +# +# End of 10.0 tests +# +# +# MDEV-17148 DROP DATABASE throw "Directory not empty" after changed lower_case_table_names. +# create database db1; create table t1 (a int); drop database db1; drop table t1; +# +# End of 10.2 tests +# diff --git a/mysql-test/main/lowercase_table.test b/mysql-test/main/lowercase_table.test index e0dcb6c36dd..203203a30c0 100644 --- a/mysql-test/main/lowercase_table.test +++ b/mysql-test/main/lowercase_table.test @@ -2,14 +2,6 @@ # Test of --lower-case-table-names # ---disable_warnings -drop table if exists t1,t2,t3,t4; -# Clear up from other tests (to ensure that SHOW TABLES below is right) -drop table if exists t0,t5,t6,t7,t8,t9; -drop database if exists mysqltest; -drop view if exists v0, v1, v2, v3, v4; ---enable_warnings - create table T1 (id int primary key, Word varchar(40) not null, Index(Word)); create table t4 (id int primary key, Word varchar(40) not null); INSERT INTO T1 VALUES (1, 'a'), (2, 'b'), (3, 'c'); @@ -68,32 +60,29 @@ drop table t1,t2; # create table t1 (a int); create table t2 (a int); --- error 1066 +--error ER_NONUNIQ_TABLE select * from t1 c, t2 C; --- error 1066 +--error ER_NONUNIQ_TABLE select C.a, c.a from t1 c, t2 C; drop table t1, t2; -# -# Bug #9761: CREATE TABLE ... LIKE ... not handled correctly when -# lower_case_table_names is set +--echo # +--echo # Bug #9761: CREATE TABLE ... LIKE ... not handled correctly when lower_case_table_names is set +--echo # create table t1 (a int); create table t2 like T1; drop table t1, t2; show tables; +--echo # +--echo # End of 4.1 tests +--echo # -# End of 4.1 tests - - -# -# Bug#20404: SHOW CREATE TABLE fails with Turkish I -# +--echo # +--echo # Bug#20404: SHOW CREATE TABLE fails with Turkish I +--echo # set names utf8; ---disable_warnings -drop table if exists Ä°,Ä°Ä°; ---enable_warnings create table Ä° (s1 int); show create table Ä°; show tables; @@ -104,11 +93,13 @@ show tables; drop table Ä°Ä°; set names latin1; ---echo End of 5.0 tests +--echo # +--echo # End of 5.0 tests +--echo # -# -# Bug#21317: SHOW CREATE DATABASE does not obey to lower_case_table_names -# +--echo # +--echo # Bug#21317: SHOW CREATE DATABASE does not obey to lower_case_table_names +--echo # create database mysql_TEST character set latin2; create table mysql_TEST.T1 (a int); show create database mysql_TEST; @@ -117,11 +108,13 @@ show databases like "mysql%"; show databases like "mysql_TE%"; drop database mysql_TEST; ---echo End of 10.0 tests +--echo # +--echo # End of 10.0 tests +--echo # -# -# MDEV-17148 DROP DATABASE throw "Directory not empty" after changed lower_case_table_names. -# +--echo # +--echo # MDEV-17148 DROP DATABASE throw "Directory not empty" after changed lower_case_table_names. +--echo # let $datadir=`select @@datadir`; create database db1; @@ -130,3 +123,6 @@ copy_file $datadir/test/t1.frm $datadir/db1/T1.frm; drop database db1; drop table t1; +--echo # +--echo # End of 10.2 tests +--echo # -- cgit v1.2.1 From 64b7433709dc5fb5080861018b13a0e1cf9d5238 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 27 Apr 2021 13:05:13 +0200 Subject: MDEV-25109 Server crashes in sp_name::sp_name upon invalid data in mysql.proc don't try to lowercase a db name if it's zero-length. (empty_lex_str is not writable, even db.str[0]=0 will fail) --- mysql-test/main/lowercase_table.result | 16 ++++++++++++++++ mysql-test/main/lowercase_table.test | 13 +++++++++++++ sql/sp_head.h | 2 +- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/lowercase_table.result b/mysql-test/main/lowercase_table.result index 92dfdfdac96..3d840445bf2 100644 --- a/mysql-test/main/lowercase_table.result +++ b/mysql-test/main/lowercase_table.result @@ -148,3 +148,19 @@ drop table t1; # # End of 10.2 tests # +# +# MDEV-25109 Server crashes in sp_name::sp_name upon invalid data in mysql.proc +# +call mtr.add_suppression("Stored routine ''.'': invalid value in column"); +insert ignore into mysql.proc () values (); +Warnings: +Warning 1364 Field 'param_list' doesn't have a default value +Warning 1364 Field 'returns' doesn't have a default value +Warning 1364 Field 'body' doesn't have a default value +Warning 1364 Field 'comment' doesn't have a default value +show function status; +ERROR 42000: Incorrect routine name '' +delete from mysql.proc where name = ''; +# +# End of 10.3 tests +# diff --git a/mysql-test/main/lowercase_table.test b/mysql-test/main/lowercase_table.test index 203203a30c0..4f92e43f5f7 100644 --- a/mysql-test/main/lowercase_table.test +++ b/mysql-test/main/lowercase_table.test @@ -126,3 +126,16 @@ drop table t1; --echo # --echo # End of 10.2 tests --echo # + +--echo # +--echo # MDEV-25109 Server crashes in sp_name::sp_name upon invalid data in mysql.proc +--echo # +call mtr.add_suppression("Stored routine ''.'': invalid value in column"); +insert ignore into mysql.proc () values (); +--error ER_SP_WRONG_NAME +show function status; +delete from mysql.proc where name = ''; + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/sql/sp_head.h b/sql/sp_head.h index 493bb777bdf..e1cfbb484ad 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -111,7 +111,7 @@ public: bool use_explicit_name) : Database_qualified_name(db, name), m_explicit_name(use_explicit_name) { - if (lower_case_table_names && m_db.str) + if (lower_case_table_names && m_db.length) m_db.length= my_casedn_str(files_charset_info, (char*) m_db.str); } -- cgit v1.2.1 From c6dbabed5659937deb35700635b096fcd488fd94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 21 Oct 2020 11:39:24 +0300 Subject: MDEV-21514 : Galera test failure on galera.galera_wan_restart_sst Replace unnecessary sleeps with real wait_conditions to make sure correct cluster sizes. --- .../suite/galera/r/galera_wan_restart_sst.result | 48 +++++++++++----------- .../suite/galera/t/galera_wan_restart_sst.test | 40 +++++++++++------- 2 files changed, 49 insertions(+), 39 deletions(-) diff --git a/mysql-test/suite/galera/r/galera_wan_restart_sst.result b/mysql-test/suite/galera/r/galera_wan_restart_sst.result index 71786cdd023..1adcbfd1d50 100644 --- a/mysql-test/suite/galera/r/galera_wan_restart_sst.result +++ b/mysql-test/suite/galera/r/galera_wan_restart_sst.result @@ -1,6 +1,6 @@ -SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -VARIABLE_VALUE = 4 -1 +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +EXPECT_4 +4 connection node_1; CREATE TABLE t1 (f1 INTEGER); INSERT INTO t1 VALUES (1); @@ -46,30 +46,30 @@ INSERT INTO t1 VALUES (33); connection node_4; INSERT INTO t1 VALUES (341); connection node_1; -SELECT COUNT(*) = 19 FROM t1; -COUNT(*) = 19 -1 +SELECT COUNT(*) AS EXPECT_19 FROM t1; +EXPECT_19 +19 connection node_2; -SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -VARIABLE_VALUE = 4 -1 -SELECT COUNT(*) = 19 FROM t1; -COUNT(*) = 19 -1 +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +EXPECT_4 +4 +SELECT COUNT(*) AS EXPECT_19 FROM t1; +EXPECT_19 +19 connection node_3; -SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -VARIABLE_VALUE = 4 -1 -SELECT COUNT(*) = 19 FROM t1; -COUNT(*) = 19 -1 +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +EXPECT_4 +4 +SELECT COUNT(*) AS EXPECT_19 FROM t1; +EXPECT_19 +19 connection node_4; -SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -VARIABLE_VALUE = 4 -1 -SELECT COUNT(*) = 19 FROM t1; -COUNT(*) = 19 -1 +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +EXPECT_4 +4 +SELECT COUNT(*) AS EXPECT_19 FROM t1; +EXPECT_19 +19 connection node_1; DROP TABLE t1; CALL mtr.add_suppression("There are no nodes in the same segment that will ever be able to become donors, yet there is a suitable donor outside"); diff --git a/mysql-test/suite/galera/t/galera_wan_restart_sst.test b/mysql-test/suite/galera/t/galera_wan_restart_sst.test index 9b12eeed1ac..4bd7e6e71fb 100644 --- a/mysql-test/suite/galera/t/galera_wan_restart_sst.test +++ b/mysql-test/suite/galera/t/galera_wan_restart_sst.test @@ -10,9 +10,11 @@ --source include/big_test.inc --source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/force_restart.inc -SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--source include/wait_condition.inc +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; --connection node_1 CREATE TABLE t1 (f1 INTEGER); @@ -37,10 +39,11 @@ INSERT INTO t1 VALUES (4); INSERT INTO t1 VALUES (13); --source include/kill_galera.inc ---sleep 5 --connection node_1 --source include/wait_until_connected_again.inc +--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--source include/wait_condition.inc INSERT INTO t1 VALUES (11); --connection node_2 @@ -51,9 +54,11 @@ INSERT INTO t1 VALUES (14); --connection node_3 --source include/start_mysqld.inc ---sleep 5 --source include/wait_until_connected_again.inc +--let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--source include/wait_condition.inc + INSERT INTO t1 VALUES (131); # @@ -64,10 +69,12 @@ INSERT INTO t1 VALUES (131); INSERT INTO t1 VALUES (22); --source include/kill_galera.inc ---sleep 5 --connection node_1 --source include/wait_until_connected_again.inc +--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--source include/wait_condition.inc + INSERT INTO t1 VALUES (21); --connection node_3 @@ -78,8 +85,9 @@ INSERT INTO t1 VALUES (24); --connection node_2 --source include/start_mysqld.inc ---sleep 5 --source include/wait_until_connected_again.inc +--let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--source include/wait_condition.inc INSERT INTO t1 VALUES (221); @@ -91,10 +99,11 @@ INSERT INTO t1 VALUES (221); INSERT INTO t1 VALUES (34); --source include/kill_galera.inc ---sleep 5 --connection node_1 --source include/wait_until_connected_again.inc +--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--source include/wait_condition.inc INSERT INTO t1 VALUES (31); --connection node_2 @@ -105,8 +114,9 @@ INSERT INTO t1 VALUES (33); --connection node_4 --source include/start_mysqld.inc ---sleep 5 --source include/wait_until_connected_again.inc +--let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--source include/wait_condition.inc INSERT INTO t1 VALUES (341); @@ -119,19 +129,19 @@ INSERT INTO t1 VALUES (341); --let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; --source include/wait_condition.inc -SELECT COUNT(*) = 19 FROM t1; +SELECT COUNT(*) AS EXPECT_19 FROM t1; --connection node_2 -SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -SELECT COUNT(*) = 19 FROM t1; +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +SELECT COUNT(*) AS EXPECT_19 FROM t1; --connection node_3 -SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -SELECT COUNT(*) = 19 FROM t1; +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +SELECT COUNT(*) AS EXPECT_19 FROM t1; --connection node_4 -SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -SELECT COUNT(*) = 19 FROM t1; +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +SELECT COUNT(*) AS EXPECT_19 FROM t1; --connection node_1 DROP TABLE t1; -- cgit v1.2.1 From f946192e6f995fe57f30b135313447f062a8c450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 27 Apr 2021 10:41:36 +0300 Subject: MDEV-25258 : SET PASSWORD command fail with wsrep api Problem was that we should skip strict password validation on applier nodes similarly as is done for slave nodes. --- mysql-test/suite/galera/r/galera_password.result | 19 +++++++++++++++++++ mysql-test/suite/galera/t/galera_password.test | 14 ++++++++++++++ sql/sql_acl.cc | 6 +++++- 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/galera/r/galera_password.result create mode 100644 mysql-test/suite/galera/t/galera_password.test diff --git a/mysql-test/suite/galera/r/galera_password.result b/mysql-test/suite/galera/r/galera_password.result new file mode 100644 index 00000000000..7af0c2169a0 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_password.result @@ -0,0 +1,19 @@ +SHOW VARIABLES LIKE '%password%'; +Variable_name Value +old_passwords OFF +report_password +strict_password_validation ON +CREATE USER 'user123456'@'localhost'; +GRANT SELECT, INSERT, UPDATE ON test.* TO 'user123456'@'localhost'; +SET PASSWORD FOR 'user123456'@'localhost' = PASSWORD('A$10abcdDCBA123456%7'); +SHOW GRANTS FOR 'user123456'@'localhost'; +Grants for user123456@localhost +GRANT USAGE ON *.* TO 'user123456'@'localhost' IDENTIFIED BY PASSWORD '*5846CF4D641598B360B3562E581586155C59F65A' +GRANT SELECT, INSERT, UPDATE ON `test`.* TO 'user123456'@'localhost' +connection node_2; +SHOW GRANTS FOR 'user123456'@'localhost'; +Grants for user123456@localhost +GRANT USAGE ON *.* TO 'user123456'@'localhost' IDENTIFIED BY PASSWORD '*5846CF4D641598B360B3562E581586155C59F65A' +GRANT SELECT, INSERT, UPDATE ON `test`.* TO 'user123456'@'localhost' +connection node_1; +DROP USER 'user123456'@'localhost'; diff --git a/mysql-test/suite/galera/t/galera_password.test b/mysql-test/suite/galera/t/galera_password.test new file mode 100644 index 00000000000..7843097c67e --- /dev/null +++ b/mysql-test/suite/galera/t/galera_password.test @@ -0,0 +1,14 @@ +--source include/galera_cluster.inc + +SHOW VARIABLES LIKE '%password%'; + +CREATE USER 'user123456'@'localhost'; +GRANT SELECT, INSERT, UPDATE ON test.* TO 'user123456'@'localhost'; +SET PASSWORD FOR 'user123456'@'localhost' = PASSWORD('A$10abcdDCBA123456%7'); +SHOW GRANTS FOR 'user123456'@'localhost'; + +--connection node_2 +SHOW GRANTS FOR 'user123456'@'localhost'; + +--connection node_1 +DROP USER 'user123456'@'localhost'; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index f1034986f22..2b59a82277e 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1566,7 +1566,11 @@ static bool validate_password(LEX_USER *user, THD *thd) else { if (!thd->slave_thread && - strict_password_validation && has_validation_plugins()) + strict_password_validation && has_validation_plugins() +#ifdef WITH_WSREP + && !thd->wsrep_applier +#endif + ) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--strict-password-validation"); return true; -- cgit v1.2.1 From e85b389b762e038bc2e347421fa39636159b53b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 27 Apr 2021 14:50:21 +0300 Subject: MDEV-25319 : Long BF log wait turns on InnoDB Monitor output without telling, never turns it off Removed explicit InnoDB monitor startup and used just functions to print current lock information. --- .../galera/r/galera_inject_bf_long_wait.result | 22 +++++++++++++++ .../suite/galera/t/galera_inject_bf_long_wait.test | 25 ++++++++++++++++ storage/innobase/lock/lock0wait.cc | 33 +++++++++++++--------- 3 files changed, 66 insertions(+), 14 deletions(-) create mode 100644 mysql-test/suite/galera/r/galera_inject_bf_long_wait.result create mode 100644 mysql-test/suite/galera/t/galera_inject_bf_long_wait.test diff --git a/mysql-test/suite/galera/r/galera_inject_bf_long_wait.result b/mysql-test/suite/galera/r/galera_inject_bf_long_wait.result new file mode 100644 index 00000000000..e9eab5401c4 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_inject_bf_long_wait.result @@ -0,0 +1,22 @@ +CREATE TABLE t1(id int not null primary key, b int) engine=InnoDB; +INSERT INTO t1 VALUES (0,0),(1,1),(2,2),(3,3); +BEGIN; +UPDATE t1 set b = 100 where id between 1 and 2;; +connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1; +connection node_1b; +SET @save_dbug = @@SESSION.debug_dbug; +SET @@SESSION.innodb_lock_wait_timeout=2; +SET @@SESSION.debug_dbug = '+d,wsrep_instrument_BF_lock_wait'; +UPDATE t1 set b = 200 WHERE id = 1; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +SET @@SESSION.debug_dbug = @save_dbug; +connection node_1; +COMMIT; +SELECT * FROM t1; +id b +0 0 +1 100 +2 100 +3 3 +disconnect node_1b; +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_inject_bf_long_wait.test b/mysql-test/suite/galera/t/galera_inject_bf_long_wait.test new file mode 100644 index 00000000000..f4aac7fd795 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_inject_bf_long_wait.test @@ -0,0 +1,25 @@ +--source include/galera_cluster.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +CREATE TABLE t1(id int not null primary key, b int) engine=InnoDB; +INSERT INTO t1 VALUES (0,0),(1,1),(2,2),(3,3); + +BEGIN; +--send UPDATE t1 set b = 100 where id between 1 and 2; + +--connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1 +--connection node_1b +SET @save_dbug = @@SESSION.debug_dbug; +SET @@SESSION.innodb_lock_wait_timeout=2; +SET @@SESSION.debug_dbug = '+d,wsrep_instrument_BF_lock_wait'; +--error ER_LOCK_WAIT_TIMEOUT +UPDATE t1 set b = 200 WHERE id = 1; +SET @@SESSION.debug_dbug = @save_dbug; + +--connection node_1 +--reap +COMMIT; +SELECT * FROM t1; +--disconnect node_1b +DROP TABLE t1; diff --git a/storage/innobase/lock/lock0wait.cc b/storage/innobase/lock/lock0wait.cc index 5d0d41ef494..df1488b9df3 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()); wsrep_trx_print_locking(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 */ -- cgit v1.2.1 From 24693c6fcf041f5ee7d5c9d3215094bde6da4bc8 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Tue, 27 Apr 2021 16:08:33 +0200 Subject: Bug#29363867: LOST CONNECTION TO MYSQL SERVER DURING QUERY The problem is that sharing default expression among set instruction leads to attempt access result field of function created in other instruction runtime MEM_ROOT and already freed (a bit different then MySQL problem). Fix is the same as in MySQL (but no optimisation for constant), turn DECLARE a, b, c type DEFAULT expr; to DECLARE a type DEFAULT expr, b type DEFAULT a, c type DEFAULT a; --- mysql-test/r/sp.result | 15 +++++++++++++++ mysql-test/suite/funcs_1/r/storedproc.result | 26 +++++++++++++------------- mysql-test/t/sp.test | 19 +++++++++++++++++++ sql/sql_yacc.yy | 28 ++++++++++++++++++++++++---- 4 files changed, 71 insertions(+), 17 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index b679f3f54fc..25675a11f4a 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -8486,4 +8486,19 @@ ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function DROP PROCEDURE p1; DROP VIEW v1; DROP TABLE t1; +# +# BUG#30366310: USING A FUNCTION TO ASSIGN DEFAULT VALUES TO +# 2 OR MORE VARIABLES CRASHES SERVER +# +create function f1() returns bigint return now()-1| +create procedure p1() +begin +declare b, c bigint default f1(); +select b-c; +end| +call p1()| +b-c +0 +drop procedure p1| +drop function f1| #End of 10.2 tests diff --git a/mysql-test/suite/funcs_1/r/storedproc.result b/mysql-test/suite/funcs_1/r/storedproc.result index ac48e20eaed..516ea983563 100644 --- a/mysql-test/suite/funcs_1/r/storedproc.result +++ b/mysql-test/suite/funcs_1/r/storedproc.result @@ -7125,7 +7125,7 @@ CALL sp1(); x y z 000 000 000 Warnings: -Warning 1264 Out of range value for column 'z' at row 1 +Warning 1264 Out of range value for column 'x' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN @@ -7163,7 +7163,7 @@ CALL sp1(); x y z 00000 00000 00000 Warnings: -Warning 1264 Out of range value for column 'z' at row 1 +Warning 1264 Out of range value for column 'x' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN @@ -7201,7 +7201,7 @@ CALL sp1(); x y z 00000000 00000000 00000000 Warnings: -Warning 1264 Out of range value for column 'z' at row 1 +Warning 1264 Out of range value for column 'x' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN @@ -7239,7 +7239,7 @@ CALL sp1(); x y z 0000000000 0000000000 0000000000 Warnings: -Warning 1264 Out of range value for column 'z' at row 1 +Warning 1264 Out of range value for column 'x' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN @@ -7277,7 +7277,7 @@ CALL sp1(); x y z 00000000000000000000 00000000000000000000 00000000000000000000 Warnings: -Warning 1264 Out of range value for column 'z' at row 1 +Warning 1264 Out of range value for column 'x' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN @@ -7297,7 +7297,7 @@ CALL sp1(); x y z -9999999999 -9999999999 -9999999999 Warnings: -Warning 1264 Out of range value for column 'z' at row 1 +Warning 1264 Out of range value for column 'x' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN @@ -7308,7 +7308,7 @@ CALL sp1(); x y z 0 0 0 Warnings: -Note 1265 Data truncated for column 'z' at row 1 +Note 1265 Data truncated for column 'x' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN @@ -7319,7 +7319,7 @@ CALL sp1(); x y z 0000000000 0000000000 0000000000 Warnings: -Warning 1264 Out of range value for column 'z' at row 1 +Warning 1264 Out of range value for column 'x' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN @@ -7330,7 +7330,7 @@ CALL sp1(); x y z 0000000000 0000000000 0000000000 Warnings: -Note 1265 Data truncated for column 'z' at row 1 +Note 1265 Data truncated for column 'x' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN @@ -7341,7 +7341,7 @@ CALL sp1(); x y z 0 0 0 Warnings: -Note 1265 Data truncated for column 'z' at row 1 +Note 1265 Data truncated for column 'x' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN @@ -7352,7 +7352,7 @@ CALL sp1(); x y z 0 0 0 Warnings: -Note 1265 Data truncated for column 'z' at row 1 +Note 1265 Data truncated for column 'x' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN @@ -7363,7 +7363,7 @@ CALL sp1(); x y z 0000000000 0000000000 0000000000 Warnings: -Note 1265 Data truncated for column 'z' at row 1 +Note 1265 Data truncated for column 'x' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN @@ -7374,7 +7374,7 @@ CALL sp1(); x y z 0000000000 0000000000 0000000000 Warnings: -Note 1265 Data truncated for column 'z' at row 1 +Note 1265 Data truncated for column 'x' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index f13b3fbc281..0ef5e7d0b6e 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -10025,4 +10025,23 @@ DROP PROCEDURE p1; DROP VIEW v1; DROP TABLE t1; + +--echo # +--echo # BUG#30366310: USING A FUNCTION TO ASSIGN DEFAULT VALUES TO +--echo # 2 OR MORE VARIABLES CRASHES SERVER +--echo # + +delimiter |; +create function f1() returns bigint return now()-1| +create procedure p1() +begin + declare b, c bigint default f1(); + select b-c; +end| +call p1()| +drop procedure p1| +drop function f1| +delimiter ;| + + --echo #End of 10.2 tests diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6eb47f1e49f..387c77a4ef5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3104,17 +3104,22 @@ sp_decl: sp_pcontext *pctx= lex->spcont; uint num_vars= pctx->context_var_count(); Item *dflt_value_item= $5; + const bool has_default_clause = (dflt_value_item != NULL); Lex->set_last_field_type($4); - if (!dflt_value_item) + + if (!has_default_clause) { dflt_value_item= new (thd->mem_root) Item_null(thd); if (dflt_value_item == NULL) MYSQL_YYABORT; /* QQ Set to the var_type with null_value? */ } - - for (uint i = num_vars-$2 ; i < num_vars ; i++) + + sp_variable *first_spvar = NULL; + const uint first_var_num = num_vars - $2; + + for (uint i = first_var_num ; i < num_vars ; i++) { uint var_idx= pctx->var_context2runtime(i); sp_variable *spvar= pctx->find_variable(var_idx); @@ -3126,9 +3131,24 @@ sp_decl: if (!last) spvar->field_def= *lex->last_field; + if (i == first_var_num) { + first_spvar = spvar; + } else if (has_default_clause) { + Item_splocal *item = + new (thd->mem_root) + Item_splocal(thd, first_spvar->name, first_spvar->offset, + first_spvar->sql_type(), 0, 0); + if (item == NULL) + MYSQL_YYABORT; // OOM +#ifndef DBUG_OFF + item->m_sp = lex->sphead; +#endif + dflt_value_item = item; + } + spvar->default_value= dflt_value_item; spvar->field_def.field_name= spvar->name.str; - + if (lex->sphead->fill_field_definition(thd, lex, &spvar->field_def)) { -- cgit v1.2.1 From e788738e18bd5cedb21f75b21f902f1bbcc34719 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Wed, 28 Apr 2021 10:42:20 +0700 Subject: MDEV-25543: Building failure on MacOS in case MariadDB server is compiled with XCode 12.5 Attempt to build MariaDB server on MacOS could result in compilation errors like the following one: In file included from server-10.2/storage/perfschema/cursor_by_account.cc:28: In file included from server-10.2/include/my_global.h:287: In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk/usr/include/c++/v1/math.h:309: In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk/usr/include/c++/v1/type_traits:418: server-10.2/version:1:1: error: expected unqualified-id MYSQL_VERSION_MAJOR=10 ^ server-10.2/build.dir/include/my_config.h:529:29: note: expanded from macro 'MYSQL_VERSION_MAJOR' This kind of compiler errors occur by the reson that compiler's system headers contain the directive '#include ' and a compiler is invoked with -I${CMAKE_SOURCE_DIR}. The MariaDB source code root directory contains the file VERSION that is handled by the compiler during processing the directive #include since file names on MacOS are case insensetive, so version and VERSION is treated as the same file name. To fix the issue the source code root directory should be removed from a list of directories used by the compiler for include search path. --- storage/perfschema/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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} -- cgit v1.2.1 From 8f9a72a1504c73a2d432cb5a521b9ca631d1e455 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 28 Apr 2021 21:27:04 +0200 Subject: MDEV-25501 routine_definition in information_schema.routines loses tablename if it starts with an _ and is not backticked remove code duplication in Lex_input_stream::scan_ident_middle(), make sure identifiers are always use the same code path whether they start form an underscore or not. --- mysql-test/main/sp-bugs.result | 27 ++++++++++++++++++++++++++- mysql-test/main/sp-bugs.test | 23 ++++++++++++++++++++++- sql/sql_lex.cc | 18 ++++++------------ 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/mysql-test/main/sp-bugs.result b/mysql-test/main/sp-bugs.result index 60cb6a89cde..f88b3b137d3 100644 --- a/mysql-test/main/sp-bugs.result +++ b/mysql-test/main/sp-bugs.result @@ -130,7 +130,9 @@ Warnings: Note 1050 Table 't2' already exists DROP DATABASE testdb; USE test; -End of 5.1 tests +# +# End of 5.1 tests +# # # BUG#13489996 valgrind:conditional jump or move depends on # uninitialised values-field_blob @@ -342,3 +344,26 @@ FOR i IN 1..10 DO RETURN 1; END FOR DROP FUNCTION f1; +# +# End of 10.2 tests +# +# +# MDEV-25501 routine_definition in information_schema.routines loses tablename if it starts with an _ and is not backticked +# +create table _t1 (a int); +create procedure p1() select * from _t1; +show create procedure p1; +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +p1 CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`() +select * from _t1 latin1 latin1_swedish_ci latin1_swedish_ci +select routine_definition from information_schema.routines where routine_schema=database() and specific_name='p1'; +routine_definition +select * from _t1 +select body, body_utf8 from mysql.proc where name='p1'; +body body_utf8 +select * from _t1 select * from _t1 +drop procedure p1; +drop table _t1; +# +# End of 10.3 tests +# diff --git a/mysql-test/main/sp-bugs.test b/mysql-test/main/sp-bugs.test index d7b88bbeeec..0693ee5f2fc 100644 --- a/mysql-test/main/sp-bugs.test +++ b/mysql-test/main/sp-bugs.test @@ -164,7 +164,9 @@ CALL p1(); DROP DATABASE testdb; USE test; ---echo End of 5.1 tests +--echo # +--echo # End of 5.1 tests +--echo # --echo # --echo # BUG#13489996 valgrind:conditional jump or move depends on @@ -371,3 +373,22 @@ DELIMITER ;$$ SELECT f1(); SELECT body FROM mysql.proc WHERE db='test' AND specific_name='f1'; DROP FUNCTION f1; + +--echo # +--echo # End of 10.2 tests +--echo # + +--echo # +--echo # MDEV-25501 routine_definition in information_schema.routines loses tablename if it starts with an _ and is not backticked +--echo # +create table _t1 (a int); +create procedure p1() select * from _t1; +show create procedure p1; +select routine_definition from information_schema.routines where routine_schema=database() and specific_name='p1'; +select body, body_utf8 from mysql.proc where name='p1'; +drop procedure p1; +drop table _t1; + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 56046584b8b..b1c5327d10c 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2161,6 +2161,11 @@ int Lex_input_stream::scan_ident_middle(THD *thd, Lex_ident_cli_st *str, yySkip(); // next state does a unget } + yyUnget(); // ptr points now after last token char + str->set_ident(m_tok_start, length, is_8bit); + m_cpp_text_start= m_cpp_tok_start; + m_cpp_text_end= m_cpp_text_start + length; + /* Note: "SELECT _bla AS 'alias'" _bla should be considered as a IDENT if charset haven't been found. @@ -2170,28 +2175,17 @@ int Lex_input_stream::scan_ident_middle(THD *thd, Lex_ident_cli_st *str, DBUG_ASSERT(length > 0); if (resolve_introducer && m_tok_start[0] == '_') { - - yyUnget(); // ptr points now after last token char - str->set_ident(m_tok_start, length, false); - - m_cpp_text_start= m_cpp_tok_start; - m_cpp_text_end= m_cpp_text_start + length; - body_utf8_append(m_cpp_text_start, m_cpp_tok_start + length); ErrConvString csname(str->str + 1, str->length - 1, &my_charset_bin); CHARSET_INFO *cs= get_charset_by_csname(csname.ptr(), MY_CS_PRIMARY, MYF(0)); if (cs) { + body_utf8_append(m_cpp_text_start, m_cpp_tok_start + length); *introducer= cs; return UNDERSCORE_CHARSET; } - return IDENT; } - yyUnget(); // ptr points now after last token char - str->set_ident(m_tok_start, length, is_8bit); - m_cpp_text_start= m_cpp_tok_start; - m_cpp_text_end= m_cpp_text_start + length; body_utf8_append(m_cpp_text_start); body_utf8_append_ident(thd, str, m_cpp_text_end); return is_8bit ? IDENT_QUOTED : IDENT; -- cgit v1.2.1 From b1ac251bf1668d5d2472c2c520d6db71fb835065 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Wed, 28 Apr 2021 17:39:04 -0700 Subject: Another correction of the patch for MDEV-24823. This commits replaces the call of the function setup_tables() with a call of the function setup_tables_and_check_access() in the method Multiupdate_prelocking_strategy::handle_end(). There is no known bug that would require this change. However the change aligns this piece of code with the code existed before the patch for MDEV-24823. --- sql/sql_update.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index e8b973c03bd..ec27ccda778 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1390,8 +1390,9 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd) call in setup_tables()). */ - if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list, - table_list, select_lex->leaf_tables, FALSE, TRUE)) + if (setup_tables_and_check_access(thd, &select_lex->context, + &select_lex->top_join_list, table_list, select_lex->leaf_tables, + FALSE, UPDATE_ACL, SELECT_ACL, TRUE)) DBUG_RETURN(1); List *fields= &lex->select_lex.item_list; -- cgit v1.2.1 From 8880dff2d90ea8a8279cbcb466f90e0b2fdfcff5 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Thu, 29 Apr 2021 13:14:57 +0300 Subject: update CC --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index 0bd29ba4fab..d60bdbeb684 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit 0bd29ba4fab5a4c75ea93f71983381433b90b35c +Subproject commit d60bdbeb684ccf74adb9b69685a516fc68b508ba -- cgit v1.2.1 From 26148e2a67953390fe5190ad39f0dc532712296f Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Fri, 30 Apr 2021 00:22:41 +0300 Subject: Revert "update CC" This reverts commit 8880dff2d90ea8a8279cbcb466f90e0b2fdfcff5. --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index d60bdbeb684..0bd29ba4fab 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit d60bdbeb684ccf74adb9b69685a516fc68b508ba +Subproject commit 0bd29ba4fab5a4c75ea93f71983381433b90b35c -- cgit v1.2.1 From 65d2fbaf77cba4096d7caec93f61bbfcc27a829a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 30 Apr 2021 09:37:50 +0300 Subject: MDEV-25568 RENAME TABLE causes "Ignoring data file" messages fil_ibd_load(): Remove a message that is basically saying that everything works as expected. The other "Ignoring data file" message about the presence of an extraneous file will be retained (and expected by the test innodb.log_file_name). --- mysql-test/suite/innodb/r/log_file_name.result | 1 - mysql-test/suite/innodb/t/log_file_name.test | 3 --- storage/innobase/fil/fil0fil.cc | 15 ++++----------- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/mysql-test/suite/innodb/r/log_file_name.result b/mysql-test/suite/innodb/r/log_file_name.result index 220f5ab6699..6004f05ff98 100644 --- a/mysql-test/suite/innodb/r/log_file_name.result +++ b/mysql-test/suite/innodb/r/log_file_name.result @@ -21,7 +21,6 @@ SELECT * FROM INFORMATION_SCHEMA.ENGINES WHERE engine = 'innodb' AND support IN ('YES', 'DEFAULT', 'ENABLED'); ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS -FOUND 1 /InnoDB: Ignoring data file '.*t1.ibd' with space ID.*/ in mysqld.1.err FOUND 1 /InnoDB: Tablespace \d+ was not found at.*t3.ibd.*/ in mysqld.1.err # Fault 3: Wrong space_id in a dirty file, and no missing file. SELECT * FROM INFORMATION_SCHEMA.ENGINES diff --git a/mysql-test/suite/innodb/t/log_file_name.test b/mysql-test/suite/innodb/t/log_file_name.test index df9f8664a64..b8f6025e617 100644 --- a/mysql-test/suite/innodb/t/log_file_name.test +++ b/mysql-test/suite/innodb/t/log_file_name.test @@ -54,9 +54,6 @@ let SEARCH_PATTERN= InnoDB: Ignoring data file '.*t2.ibd' with space ID \d+. Ano --source include/start_mysqld.inc eval $check_no_innodb; -let SEARCH_PATTERN= InnoDB: Ignoring data file '.*t1.ibd' with space ID.*; ---source include/search_pattern_in_file.inc - let SEARCH_PATTERN= InnoDB: Tablespace \d+ was not found at.*t3.ibd.*; --source include/search_pattern_in_file.inc diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 39e7507373f..2607856bc74 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2021, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2014, 2020, MariaDB Corporation. +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 @@ -4356,7 +4356,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. */ @@ -4368,8 +4368,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); } @@ -4406,13 +4406,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. */ -- cgit v1.2.1 From 0024524d542bffcadc3359543511c9b62d4742d7 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Thu, 29 Apr 2021 12:31:06 +0530 Subject: MDEV-25536 InnoDB: Failing assertion: sym_node->table != NULL in pars_retrieve_table_def InnoDB tries to fetch the deleted doc ids for discarded tablespace. In i_s_fts_deleted_generic_fill(), InnoDB needs to check whether the table is discarded or not before fetching deleted doc ids. --- mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result | 10 ++++++++++ mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test | 10 ++++++++++ storage/innobase/handler/i_s.cc | 3 ++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result b/mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result index e039b7e77d9..8ec0157728c 100644 --- a/mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result +++ b/mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result @@ -962,3 +962,13 @@ UPDATE t1 SET f6='cascade'; ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_3` FOREIGN KEY (`f5`) REFERENCES `t1` (`f6`) ON UPDATE SET NULL) DROP TABLE t1; SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; +# +# MDEV-25536 sym_node->table != NULL in pars_retrieve_table_def +# +CREATE TABLE t1 (f1 TEXT,FULLTEXT (f1)) ENGINE=InnoDB; +ALTER TABLE t1 DISCARD TABLESPACE; +SET GLOBAL innodb_ft_aux_table='test/t1'; +SELECT * FROM information_schema.innodb_ft_deleted; +DOC_ID +DROP TABLE t1; +SET GLOBAL innodb_ft_aux_table=DEFAULT; diff --git a/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test b/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test index 46b65590298..adc10886d66 100644 --- a/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test +++ b/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test @@ -932,3 +932,13 @@ UPDATE t1 SET f6='cascade'; DROP TABLE t1; SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; + +--echo # +--echo # MDEV-25536 sym_node->table != NULL in pars_retrieve_table_def +--echo # +CREATE TABLE t1 (f1 TEXT,FULLTEXT (f1)) ENGINE=InnoDB; +ALTER TABLE t1 DISCARD TABLESPACE; +SET GLOBAL innodb_ft_aux_table='test/t1'; +SELECT * FROM information_schema.innodb_ft_deleted; +DROP TABLE t1; +SET GLOBAL innodb_ft_aux_table=DEFAULT; diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 003760f80b1..bf6717de5ee 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -2901,7 +2901,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); -- cgit v1.2.1 From 13b9af50e42e9de9d8e540b2c59f763cc8041a42 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Fri, 30 Apr 2021 20:05:12 +0530 Subject: MDEV-25536 InnoDB: Failing assertion: sym_node->table != NULL in pars_retrieve_table_def - Fixing post-push failure of innodb_fts_misc_1 test case. --- mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.opt | 1 + 1 file changed, 1 insertion(+) create mode 100644 mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.opt diff --git a/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.opt b/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.opt new file mode 100644 index 00000000000..b38416a0349 --- /dev/null +++ b/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.opt @@ -0,0 +1 @@ +--innodb-ft-deleted -- cgit v1.2.1 From abe6eb10a65d5c28c221d756357b4e7f392ad13d Mon Sep 17 00:00:00 2001 From: Sujatha Date: Fri, 30 Apr 2021 18:12:43 +0530 Subject: MDEV-16146: MariaDB slave stops with following errors. Problem: ======== 180511 11:07:58 [ERROR] Slave I/O: Unexpected master's heartbeat data: heartbeat is not compatible with local info;the event's data: log_file_name mysql-bin.000009 log_pos 1054262041, Error_code: 1623 Analysis: ========= In replication setup when master server doesn't have any events to send to slave server it sends an 'Heartbeat_log_event'. This event carries the current binary log filename and offset details. The offset values is stored within 4 bytes of event header. When the size of binary log is higher than UINT32_MAX the log_pos values will not fit in 4 bytes memory. It overflows and hence slave stops with an error. Fix: === Since we cannot extend the common_header of Log_event class, a greater than 4GB value of Log_event::log_pos is made to be transported with a HeartBeat event's sub-header. Log_event::log_pos in such case is set to zero to indicate that the 8 byte sub-header is allocated in the event. In case of cross version replication following behaviour is expected OLD - Server without fix NEW - Server with fix OLD<->NEW : works bidirectionally as long as the binlog offset is (normally) within 4GB. When log_pos > UINT32_MAX OLD->NEW : The 'log_pos' is bound to overflow and NEW slave may report an invalid event/incompatible heart beat event error. NEW->OLD : Since patched server sets log_pos=0 on overflow, OLD slave will report invalid event error. --- .../suite/rpl/r/rpl_incompatible_heartbeat.result | 17 +++++++++ .../suite/rpl/t/rpl_incompatible_heartbeat.test | 44 ++++++++++++++++++++++ sql/log_event.cc | 17 +++++++-- sql/log_event.h | 13 ++++++- sql/sql_repl.cc | 31 +++++++++++++-- 5 files changed, 112 insertions(+), 10 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_incompatible_heartbeat.result create mode 100644 mysql-test/suite/rpl/t/rpl_incompatible_heartbeat.test diff --git a/mysql-test/suite/rpl/r/rpl_incompatible_heartbeat.result b/mysql-test/suite/rpl/r/rpl_incompatible_heartbeat.result new file mode 100644 index 00000000000..51da761c50d --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_incompatible_heartbeat.result @@ -0,0 +1,17 @@ +include/master-slave.inc +[connection master] +connection master; +SET @saved_dbug = @@GLOBAL.debug_dbug; +SET @@global.debug_dbug= 'd,simulate_pos_4G'; +connection slave; +include/stop_slave.inc +CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD=0.001; +include/start_slave.inc +connection master; +SET @@GLOBAL.debug_dbug = @saved_dbug; +connection slave; +connection master; +CREATE TABLE t (f INT) ENGINE=INNODB; +INSERT INTO t VALUES (10); +DROP TABLE t; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_incompatible_heartbeat.test b/mysql-test/suite/rpl/t/rpl_incompatible_heartbeat.test new file mode 100644 index 00000000000..104debe707f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_incompatible_heartbeat.test @@ -0,0 +1,44 @@ +# ==== Purpose ==== +# +# Test verifies that slave IO thread can process heartbeat events with log_pos +# values higher than UINT32_MAX. +# +# ==== Implementation ==== +# +# Steps: +# 0 - Stop slave threads. Configure a small master_heartbeat_period. +# 1 - Using debug points, simulate a huge binlog offset higher than +# UINT32_MAX on master. +# 2 - Start the slave and observe that slave IO thread is able to process +# the offset received through heartbeat event. +# +# ==== References ==== +# +# MDEV-16146: MariaDB slave stops with incompatible heartbeat +# +--source include/have_debug.inc +--source include/have_innodb.inc +--source include/have_binlog_format_mixed.inc +# Test simulates binarylog offsets higher than UINT32_MAX +--source include/have_64bit.inc +--source include/master-slave.inc + +--connection master +SET @saved_dbug = @@GLOBAL.debug_dbug; +SET @@global.debug_dbug= 'd,simulate_pos_4G'; + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD=0.001; +--source include/start_slave.inc + +--connection master +sleep 1; +SET @@GLOBAL.debug_dbug = @saved_dbug; +--sync_slave_with_master + +--connection master +CREATE TABLE t (f INT) ENGINE=INNODB; +INSERT INTO t VALUES (10); +DROP TABLE t; +--source include/rpl_end.inc diff --git a/sql/log_event.cc b/sql/log_event.cc index c32f31db1f6..94b2af20354 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -14324,14 +14324,23 @@ st_print_event_info::st_print_event_info() #endif #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -Heartbeat_log_event::Heartbeat_log_event(const char* buf, uint event_len, +Heartbeat_log_event::Heartbeat_log_event(const char* buf, ulong event_len, const Format_description_log_event* description_event) :Log_event(buf, description_event) { uint8 header_size= description_event->common_header_len; - ident_len = event_len - header_size; - set_if_smaller(ident_len,FN_REFLEN-1); - log_ident= buf + header_size; + if (log_pos == 0) + { + log_pos= uint8korr(buf + header_size); + log_ident= buf + header_size + HB_SUB_HEADER_LEN; + ident_len= event_len - (header_size + HB_SUB_HEADER_LEN); + } + else + { + log_ident= buf + header_size; + ident_len = event_len - header_size; + } + } #endif diff --git a/sql/log_event.h b/sql/log_event.h index 3fc44a9669f..bd40795a7fb 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -570,6 +570,14 @@ class String; #define MARIA_SLAVE_CAPABILITY_MINE MARIA_SLAVE_CAPABILITY_GTID +/* + When the size of 'log_pos' within Heartbeat_log_event exceeds UINT32_MAX it + cannot be accommodated in common_header, as 'log_pos' is of 4 bytes size. In + such cases, sub_header, of size 8 bytes will hold larger 'log_pos' value. +*/ +#define HB_SUB_HEADER_LEN 8 + + /** @enum Log_event_type @@ -5160,12 +5168,13 @@ static inline bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache, class Heartbeat_log_event: public Log_event { public: - Heartbeat_log_event(const char* buf, uint event_len, + uint8 hb_flags; + Heartbeat_log_event(const char* buf, ulong event_len, const Format_description_log_event* description_event); Log_event_type get_type_code() { return HEARTBEAT_LOG_EVENT; } bool is_valid() const { - return (log_ident != NULL && + return (log_ident != NULL && ident_len <= FN_REFLEN-1 && log_pos >= BIN_LOG_HEADER_SIZE); } const char * get_log_ident() { return log_ident; } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 59a3f686e45..7ff0e27b008 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -32,6 +32,7 @@ #include "debug_sync.h" #include "log.h" // get_gtid_list_event + enum enum_gtid_until_state { GTID_UNTIL_NOT_DONE, GTID_UNTIL_STOP_AFTER_STANDALONE, @@ -781,7 +782,7 @@ get_slave_until_gtid(THD *thd, String *out_str) @param event_coordinates binlog file name and position of the last real event master sent from binlog - @note + @note Among three essential pieces of heartbeat data Log_event::when is computed locally. The error to send is serious and should force terminating @@ -795,6 +796,8 @@ static int send_heartbeat_event(binlog_send_info *info, DBUG_ENTER("send_heartbeat_event"); ulong ev_offset; + char sub_header_buf[HB_SUB_HEADER_LEN]; + bool sub_header_in_use=false; if (reset_transmit_packet(info, info->flags, &ev_offset, &info->errmsg)) DBUG_RETURN(1); @@ -815,18 +818,38 @@ static int send_heartbeat_event(binlog_send_info *info, ulong event_len = ident_len + LOG_EVENT_HEADER_LEN + (do_checksum ? BINLOG_CHECKSUM_LEN : 0); int4store(header + SERVER_ID_OFFSET, global_system_variables.server_id); + DBUG_EXECUTE_IF("simulate_pos_4G", + { + const_cast(coord)->pos= (UINT_MAX32 + (ulong)1); + DBUG_SET("-d, simulate_pos_4G"); + };); + if (coord->pos <= UINT_MAX32) + { + int4store(header + LOG_POS_OFFSET, coord->pos); // log_pos + } + else + { + // Set common_header.log_pos=0 to indicate its overflow + int4store(header + LOG_POS_OFFSET, 0); + sub_header_in_use= true; + int8store(sub_header_buf, coord->pos); + event_len+= HB_SUB_HEADER_LEN; + } + int4store(header + EVENT_LEN_OFFSET, event_len); int2store(header + FLAGS_OFFSET, 0); - int4store(header + LOG_POS_OFFSET, coord->pos); // log_pos - packet->append(header, sizeof(header)); - packet->append(p, ident_len); // log_file_name + if (sub_header_in_use) + packet->append(sub_header_buf, sizeof(sub_header_buf)); + packet->append(p, ident_len); // log_file_name if (do_checksum) { char b[BINLOG_CHECKSUM_LEN]; ha_checksum crc= my_checksum(0, (uchar*) header, sizeof(header)); + if (sub_header_in_use) + crc= my_checksum(crc, (uchar*) sub_header_buf, sizeof(sub_header_buf)); crc= my_checksum(crc, (uchar*) p, ident_len); int4store(b, crc); packet->append(b, sizeof(b)); -- cgit v1.2.1 From 2820f30dde3148df71e1d748ac705d98d60e0787 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 29 Apr 2021 19:30:07 +0300 Subject: MDEV-23723: Crash when test_if_skip_sort_order() is checked for derived ... The problem was caused by the following scenario: Subquery's table has two indexes, KEY a(a), KEY a_b(a,b) - LATERAL DERIVED optimization decides to use index a. = The subquery uses ref access over key a. - test_if_skip_sort_order() sees that KEY a_b satisfies the subquery's GROUP BY clause, and attempts to switch to it. = It fails to do so, because KEYUSE objects for index a_b are switched off. Fixed by disallowing to change the ref access key if it uses KEYUSE objects injected by LATERAL DERIVED optimization. --- mysql-test/main/derived_split_innodb.result | 34 +++++++++++++++++++++++++++++ mysql-test/main/derived_split_innodb.test | 26 ++++++++++++++++++++++ sql/sql_select.cc | 5 ++++- sql/sql_select.h | 6 +++++ 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/derived_split_innodb.result b/mysql-test/main/derived_split_innodb.result index b9ed016429b..0b57e72b821 100644 --- a/mysql-test/main/derived_split_innodb.result +++ b/mysql-test/main/derived_split_innodb.result @@ -140,3 +140,37 @@ id select_type table type possible_keys key key_len ref rows Extra 2 DERIVED t2 index NULL PRIMARY 4 NULL 3 drop view v1; drop table t1,t2; +# +# MDEV-23723: Crash when test_if_skip_sort_order() is checked for derived table subject to split +# +CREATE TABLE t1 (a INT, b INT, KEY (a), KEY (a,b)) ENGINE=InnoDB; +CREATE TABLE t2 (c INT, KEY (c)) ENGINE=InnoDB; +SELECT * FROM t1 t1a JOIN t1 t1b; +a b a b +INSERT INTO t2 VALUES (1),(2); +INSERT INTO t1 VALUES (1,2),(3,4),(5,6),(7,8),(9,10),(11,12); +set statement optimizer_switch='split_materialized=off' for EXPLAIN +SELECT * +FROM +t1 JOIN +(SELECT t1.a, t1.b FROM t1, t2 WHERE t1.b = t2.c GROUP BY t1.a, t1.b) as dt +WHERE +t1.a = dt.a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index a,a_2 a_2 10 NULL 6 Using where; Using index +1 PRIMARY ref key0 key0 5 test.t1.a 2 +2 DERIVED t1 index NULL a_2 10 NULL 6 Using where; Using index +2 DERIVED t2 ref c c 5 test.t1.b 1 Using index +set statement optimizer_switch='split_materialized=on' for EXPLAIN +SELECT * +FROM +t1 JOIN +(SELECT t1.a, t1.b FROM t1, t2 WHERE t1.b = t2.c GROUP BY t1.a, t1.b) as dt +WHERE +t1.a = dt.a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index a,a_2 a_2 10 NULL 6 Using where; Using index +1 PRIMARY ref key0 key0 5 test.t1.a 2 +2 LATERAL DERIVED t1 ref a,a_2 a 5 test.t1.a 1 Using where; Using temporary; Using filesort +2 LATERAL DERIVED t2 ref c c 5 test.t1.b 1 Using index +DROP TABLE t1, t2; diff --git a/mysql-test/main/derived_split_innodb.test b/mysql-test/main/derived_split_innodb.test index 4f9d2e970f7..19a6ecf216f 100644 --- a/mysql-test/main/derived_split_innodb.test +++ b/mysql-test/main/derived_split_innodb.test @@ -124,3 +124,29 @@ eval set statement optimizer_switch='split_materialized=off' for explain $q; drop view v1; drop table t1,t2; + +--echo # +--echo # MDEV-23723: Crash when test_if_skip_sort_order() is checked for derived table subject to split +--echo # +CREATE TABLE t1 (a INT, b INT, KEY (a), KEY (a,b)) ENGINE=InnoDB; +CREATE TABLE t2 (c INT, KEY (c)) ENGINE=InnoDB; + +SELECT * FROM t1 t1a JOIN t1 t1b; + +INSERT INTO t2 VALUES (1),(2); +INSERT INTO t1 VALUES (1,2),(3,4),(5,6),(7,8),(9,10),(11,12); + +let $query= +EXPLAIN +SELECT * +FROM + t1 JOIN + (SELECT t1.a, t1.b FROM t1, t2 WHERE t1.b = t2.c GROUP BY t1.a, t1.b) as dt +WHERE + t1.a = dt.a; + +eval set statement optimizer_switch='split_materialized=off' for $query; +eval set statement optimizer_switch='split_materialized=on' for $query; + +DROP TABLE t1, t2; + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2526866e534..6c090ea5352 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10102,6 +10102,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, j->ref.disable_cache= FALSE; j->ref.null_ref_part= NO_REF_PART; j->ref.const_ref_part_map= 0; + j->ref.uses_splitting= FALSE; keyuse=org_keyuse; store_key **ref_key= j->ref.key_copy; @@ -10150,6 +10151,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, j->ref.null_rejecting|= (key_part_map)1 << i; keyuse_uses_no_tables= keyuse_uses_no_tables && !keyuse->used_tables; + j->ref.uses_splitting |= (keyuse->validity_ref != NULL); /* We don't want to compute heavy expressions in EXPLAIN, an example would select * from t1 where t1.key=(select thats very heavy); @@ -22536,7 +22538,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, todo: why does JT_REF_OR_NULL mean filesort? We could find another index that satisfies the ordering. I would just set ref_key=MAX_KEY here... */ - if (tab->type == JT_REF_OR_NULL || tab->type == JT_FT) + if (tab->type == JT_REF_OR_NULL || tab->type == JT_FT || + tab->ref.uses_splitting) goto use_filesort; } else if (select && select->quick) // Range found by opt_range diff --git a/sql/sql_select.h b/sql/sql_select.h index 06cc86b5710..1efb2471793 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -178,6 +178,12 @@ typedef struct st_table_ref */ bool disable_cache; + /* + If true, this ref access was constructed from equalities generated by + LATERAL DERIVED (aka GROUP BY splitting) optimization + */ + bool uses_splitting; + bool tmp_table_index_lookup_init(THD *thd, KEY *tmp_key, Item_iterator &it, bool value, uint skip= 0); bool is_access_triggered(); -- cgit v1.2.1 From a910e1ee9e6185fbc2c29bca58f02616381d8a36 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 3 May 2021 15:34:52 +0200 Subject: MDEV-25584 Implement posix semantics file deletion for Windows 10 --- mysys/my_delete.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/mysys/my_delete.c b/mysys/my_delete.c index 4201c252715..6cdecef22f1 100644 --- a/mysys/my_delete.c +++ b/mysys/my_delete.c @@ -58,6 +58,7 @@ int my_delete(const char *name, myf MyFlags) #if defined (_WIN32) + /* Delete file. @@ -65,15 +66,14 @@ int my_delete(const char *name, myf MyFlags) where another program (or thread in the current program) has the the same file open. - We're using 2 tricks to prevent the errors. + We're using several tricks to prevent the errors, such as + + - Windows 10 "posix semantics" delete - 1. A usual Win32's DeleteFile() can with ERROR_SHARED_VIOLATION, - because the file is opened in another application (often, antivirus or backup) - - We avoid the error by using CreateFile() with FILE_FLAG_DELETE_ON_CLOSE, instead + - Avoid the error by using CreateFile() with FILE_FLAG_DELETE_ON_CLOSE, instead of DeleteFile() - 2. If file which is deleted (delete on close) but has not entirely gone, + - If file which is deleted (delete on close) but has not entirely gone, because it is still opened by some app, an attempt to trcreate file with the same name would result in yet another error. The workaround here is renaming a file to unique name. @@ -116,6 +116,27 @@ static int my_win_unlink(const char *name) DBUG_RETURN(0); } + /* + Try Windows 10 method, delete with "posix semantics" (file is not visible, and creating + a file with the same name won't fail, even if it the fiile was open) + */ + struct + { + DWORD _Flags; + } disp={0x3}; + /* 0x3 = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS */ + + handle= CreateFile(name, DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, 0, NULL); + if (handle != INVALID_HANDLE_VALUE) + { + BOOL ok= SetFileInformationByHandle(handle, + (FILE_INFO_BY_HANDLE_CLASS) 21, &disp, sizeof(disp)); + CloseHandle(handle); + if (ok) + DBUG_RETURN(0); + } + handle= CreateFile(name, DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL); if (handle != INVALID_HANDLE_VALUE) { -- cgit v1.2.1 From 562c88257f574d297ca0d9c284ed80390a3c927b Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Mon, 3 May 2021 16:30:52 +0300 Subject: MDEV-10674: main.show_explain failed in buildbot Fix a race condition in the testcase. The testcase assumed that State='Sending data' means that the thread is already in an InnoDB lock wait. This is not case, there is a gap between the state changing to Sending data and execution reaching the point where it is waiting for a lock. Use a more precise check instead, through I_S.INNODB_TRX. --- mysql-test/t/show_explain.opt | 1 + mysql-test/t/show_explain.test | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 mysql-test/t/show_explain.opt diff --git a/mysql-test/t/show_explain.opt b/mysql-test/t/show_explain.opt new file mode 100644 index 00000000000..3a3bab51225 --- /dev/null +++ b/mysql-test/t/show_explain.opt @@ -0,0 +1 @@ +--enable-plugin-innodb-lock-waits --enable-plugin-innodb-trx diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 2a87d24cf6d..542701bc42b 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -861,7 +861,14 @@ select * from t1 where pk between 10 and 20 for update; # run SHOW EXPLAIN on a frozen thread connection default; let $save_wait_condition= $wait_condition; -let $wait_condition= select State='Sending data' from information_schema.processlist where id=$thr2; +let $wait_condition= +select 1 +from information_schema.INNODB_LOCK_WAITS +where + requesting_trx_id=(select trx_id + from information_schema.INNODB_TRX + where trx_mysql_thread_id=$thr2); + let $thr_default=`select connection_id()`; --source include/wait_condition.inc --echo # do: send_eval show explain for thr2; -- cgit v1.2.1 From 098e4efd334154f1d7c86cd1b55e47e5748f7065 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Sun, 2 May 2021 14:02:47 +0200 Subject: new CC --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index 0bd29ba4fab..180c543704d 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit 0bd29ba4fab5a4c75ea93f71983381433b90b35c +Subproject commit 180c543704d627a50a52aaf60e24ca14e0ec4686 -- cgit v1.2.1 From 72fa9dabadb4b0011f483ccbf1ef59e62d0ef1e0 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Sun, 2 May 2021 23:24:28 +0300 Subject: Connect: remove Mongo dependencies --- storage/connect/CMakeLists.txt | 10 ---------- storage/connect/Mongo2.jar | Bin 623907 -> 0 bytes storage/connect/Mongo3.jar | Bin 1705776 -> 0 bytes 3 files changed, 10 deletions(-) delete mode 100644 storage/connect/Mongo2.jar delete mode 100644 storage/connect/Mongo3.jar diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index 96b8d877ee0..43902613ce8 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -274,10 +274,6 @@ IF(CONNECT_WITH_JDBC) Mongo2Interface.java Mongo3Interface.java JavaWrappers.jar) add_definitions(-DJAVA_SUPPORT) - IF(CONNECT_WITH_MONGO) - SET(CONNECT_SOURCES ${CONNECT_SOURCES} Mongo2.jar Mongo3.jar) - add_definitions(-DMONGO_SUPPORT) - ENDIF() ELSE() SET(JDBC_LIBRARY "") ENDIF() @@ -411,11 +407,5 @@ IF(CONNECT_WITH_JDBC AND JAVA_FOUND AND JNI_FOUND) ${CMAKE_CURRENT_SOURCE_DIR}/JavaWrappers.jar ${CMAKE_CURRENT_BINARY_DIR}/JdbcInterface.jar DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) - IF(CONNECT_WITH_MONGO) - INSTALL(FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Mongo2.jar - ${CMAKE_CURRENT_SOURCE_DIR}/Mongo3.jar - DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) - ENDIF() ENDIF() diff --git a/storage/connect/Mongo2.jar b/storage/connect/Mongo2.jar deleted file mode 100644 index 9be654bd4c8..00000000000 Binary files a/storage/connect/Mongo2.jar and /dev/null differ diff --git a/storage/connect/Mongo3.jar b/storage/connect/Mongo3.jar deleted file mode 100644 index 2850177a668..00000000000 Binary files a/storage/connect/Mongo3.jar and /dev/null differ -- cgit v1.2.1 From a20195bba5ff695b8c00b8b3f57edced3c1108a6 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 3 May 2021 23:26:30 +0200 Subject: MDEV-21603 Crashing SHOW TABLES with derived table in WHERE condition When you only need view structure, don't call handle_derived with DT_CREATE and rely on its internal hackish check to skip DT_CREATE. Because handle_derived is called from many different places, and this internal hackish check is indiscriminative. Instead, just don't ask handle_derived to do DT_CREATE if you don't want it to do DT_CREATE. --- mysql-test/r/show.result | 32 ++++++++++++++++++++++++++++++++ mysql-test/t/show.test | 34 +++++++++++++++++++++++++++++----- sql/sql_base.cc | 1 - sql/sql_class.h | 4 ---- sql/sql_derived.cc | 7 ------- sql/sql_prepare.cc | 8 ++++---- sql/sql_show.cc | 4 ++-- 7 files changed, 67 insertions(+), 23 deletions(-) diff --git a/mysql-test/r/show.result b/mysql-test/r/show.result index 3dd7af5de05..d1b373d8969 100644 --- a/mysql-test/r/show.result +++ b/mysql-test/r/show.result @@ -1,3 +1,8 @@ +# +# MDEV-9538 Server crashes in check_show_access on SHOW STATISTICS +# MDEV-9539 Server crashes in make_columns_old_format on SHOW GEOMETRY_COLUMNS +# MDEV-9540 SHOW SPATIAL_REF_SYS and SHOW SYSTEM_VARIABLES return empty results with numerous warnings +# show statistics; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'statistics' at line 1 show spatial_ref_sys @@ -10,3 +15,30 @@ show geometry_columns; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'geometry_columns' at line 1 show nonexistent; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'nonexistent' at line 1 +# +# MDEV-21603 Crashing SHOW TABLES with derived table in WHERE condition +# +create table t1 (nm varchar(32), a int); +insert t1 values ('1',1),('2',2),('3',3); +show tables +where tables_in_test in (select * +from (select nm from test.t1 group by nm) dt); +Tables_in_test +show fields from test.t1 +where field in (select * from (select nm from test.t1 group by nm) dt); +Field Type Null Key Default Extra +insert t1 values ('nm',0); +show fields from test.t1 +where field in (select * from (select nm from test.t1 group by nm) dt); +Field Type Null Key Default Extra +nm varchar(32) YES NULL +show fields from test.t1 where field in +(select * from (select column_name from information_schema.columns +where table_name='t1' group by column_name) dt); +Field Type Null Key Default Extra +nm varchar(32) YES NULL +a int(11) YES NULL +drop table t1; +# +# End of 10.2 tests +# diff --git a/mysql-test/t/show.test b/mysql-test/t/show.test index 3101f443264..f2f6efc4e45 100644 --- a/mysql-test/t/show.test +++ b/mysql-test/t/show.test @@ -1,8 +1,8 @@ -# -# MDEV-9538 Server crashes in check_show_access on SHOW STATISTICS -# MDEV-9539 Server crashes in make_columns_old_format on SHOW GEOMETRY_COLUMNS -# MDEV-9540 SHOW SPATIAL_REF_SYS and SHOW SYSTEM_VARIABLES return empty results with numerous warnings -# +--echo # +--echo # MDEV-9538 Server crashes in check_show_access on SHOW STATISTICS +--echo # MDEV-9539 Server crashes in make_columns_old_format on SHOW GEOMETRY_COLUMNS +--echo # MDEV-9540 SHOW SPATIAL_REF_SYS and SHOW SYSTEM_VARIABLES return empty results with numerous warnings +--echo # --error ER_PARSE_ERROR show statistics; --error ER_PARSE_ERROR @@ -13,3 +13,27 @@ show system_variables; show geometry_columns; --error ER_PARSE_ERROR show nonexistent; + +--echo # +--echo # MDEV-21603 Crashing SHOW TABLES with derived table in WHERE condition +--echo # +create table t1 (nm varchar(32), a int); +insert t1 values ('1',1),('2',2),('3',3); + +show tables + where tables_in_test in (select * + from (select nm from test.t1 group by nm) dt); +show fields from test.t1 + where field in (select * from (select nm from test.t1 group by nm) dt); +insert t1 values ('nm',0); +show fields from test.t1 + where field in (select * from (select nm from test.t1 group by nm) dt); + +show fields from test.t1 where field in + (select * from (select column_name from information_schema.columns + where table_name='t1' group by column_name) dt); +drop table t1; + +--echo # +--echo # End of 10.2 tests +--echo # diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 3403f9e03ff..16689f86c4e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4939,7 +4939,6 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags, uint counter; MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); DBUG_ENTER("open_normal_and_derived_tables"); - DBUG_ASSERT(!thd->fill_derived_tables()); if (open_tables(thd, &tables, &counter, flags, &prelocking_strategy) || mysql_handle_derived(thd->lex, dt_phases)) goto end; diff --git a/sql/sql_class.h b/sql/sql_class.h index ce4bf67e745..e08bb3e6358 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3469,10 +3469,6 @@ public: { return server_status & SERVER_STATUS_IN_TRANS; } - inline bool fill_derived_tables() - { - return !stmt_arena->is_stmt_prepare() && !lex->only_view_structure(); - } inline bool fill_information_schema_tables() { return !stmt_arena->is_stmt_prepare(); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 5f90f2f9ab0..3ab93840d80 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -70,7 +70,6 @@ bool mysql_handle_derived(LEX *lex, uint phases) { bool res= FALSE; - THD *thd= lex->thd; DBUG_ENTER("mysql_handle_derived"); DBUG_PRINT("enter", ("phases: 0x%x", phases)); if (!lex->derived_tables) @@ -85,8 +84,6 @@ mysql_handle_derived(LEX *lex, uint phases) break; if (!(phases & phase_flag)) continue; - if (phase_flag >= DT_CREATE && !thd->fill_derived_tables()) - break; for (SELECT_LEX *sl= lex->all_selects_list; sl && !res; @@ -169,7 +166,6 @@ bool mysql_handle_single_derived(LEX *lex, TABLE_LIST *derived, uint phases) { bool res= FALSE; - THD *thd= lex->thd; uint8 allowed_phases= (derived->is_merged_derived() ? DT_PHASES_MERGE : DT_PHASES_MATERIALIZE); DBUG_ENTER("mysql_handle_single_derived"); @@ -192,8 +188,6 @@ mysql_handle_single_derived(LEX *lex, TABLE_LIST *derived, uint phases) if (phase_flag != DT_PREPARE && !(allowed_phases & phase_flag)) continue; - if (phase_flag >= DT_CREATE && !thd->fill_derived_tables()) - break; if ((res= (*processors[phase])(lex->thd, lex, derived))) break; @@ -1376,4 +1370,3 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived) thd->lex->current_select= save_curr_select; DBUG_RETURN(false); } - diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 56a38757f28..a8a671075f9 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1659,7 +1659,7 @@ static int mysql_test_select(Prepared_statement *stmt, } if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL, - DT_INIT | DT_PREPARE | DT_CREATE)) + DT_INIT | DT_PREPARE)) goto error; thd->lex->used_tables= 0; // Updated by setup_fields @@ -1721,7 +1721,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt, DBUG_RETURN(TRUE); if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL, - DT_INIT | DT_PREPARE | DT_CREATE)) + DT_INIT | DT_PREPARE)) DBUG_RETURN(TRUE); DBUG_RETURN(setup_fields(thd, Ref_ptr_array(), *values, MARK_COLUMNS_NONE, 0, NULL, 0)); @@ -1753,7 +1753,7 @@ static bool mysql_test_set_fields(Prepared_statement *stmt, if ((tables && check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)) || open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL, - DT_INIT | DT_PREPARE | DT_CREATE)) + DT_INIT | DT_PREPARE)) goto error; while ((var= it++)) @@ -1918,7 +1918,7 @@ static bool mysql_test_create_table(Prepared_statement *stmt) if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, MYSQL_OPEN_FORCE_SHARED_MDL, - DT_INIT | DT_PREPARE | DT_CREATE)) + DT_INIT | DT_PREPARE)) DBUG_RETURN(TRUE); select_lex->context.resolve_in_select_list= TRUE; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 7023e5fe9ea..b5622497a06 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1528,7 +1528,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) if (open_normal_and_derived_tables(thd, table_list, MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL, - DT_INIT | DT_PREPARE | DT_CREATE)) + DT_INIT | DT_PREPARE)) DBUG_VOID_RETURN; table= table_list->table; @@ -4414,7 +4414,7 @@ fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys, MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL | (can_deadlock ? MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)), - DT_INIT | DT_PREPARE | DT_CREATE)); + DT_INIT | DT_PREPARE)); /* Restore old value of sql_command back as it is being looked at in -- cgit v1.2.1 From 4f143a88bcb36e94e9edba8a3c5b4a350dcd9bf9 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 5 May 2021 15:56:23 +0200 Subject: Fix of ppc64 by Wlad --- cmake/libutils.cmake | 2 +- libmysqld/CMakeLists.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/libutils.cmake b/cmake/libutils.cmake index 002d5a4cabc..4112faa341c 100644 --- a/cmake/libutils.cmake +++ b/cmake/libutils.cmake @@ -166,7 +166,7 @@ MACRO(MERGE_STATIC_LIBS TARGET OUTPUT_NAME LIBS_TO_MERGE) ENDFOREACH() IF(OSLIBS) LIST(REMOVE_DUPLICATES OSLIBS) - TARGET_LINK_LIBRARIES(${TARGET} ${OSLIBS}) + TARGET_LINK_LIBRARIES(${TARGET} LINK_PRIVATE ${OSLIBS}) ENDIF() # Make the generated dummy source file depended on all static input diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 9880653b2a5..8886d69851b 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -446,9 +446,9 @@ IF(NOT DISABLE_SHARED) # Clean direct output flags, as 2 targets have the same base name # libmysqld SET_TARGET_PROPERTIES(libmysqld PROPERTIES CLEAN_DIRECT_OUTPUT 1) - TARGET_LINK_LIBRARIES(libmysqld ${CRC32_LIBRARY}) + TARGET_LINK_LIBRARIES(libmysqld LINK_PRIVATE ${CRC32_LIBRARY}) SET_TARGET_PROPERTIES(mysqlserver PROPERTIES CLEAN_DIRECT_OUTPUT 1) - TARGET_LINK_LIBRARIES(mysqlserver ${CRC32_LIBRARY}) + TARGET_LINK_LIBRARIES(mysqlserver LINK_PRIVATE ${CRC32_LIBRARY}) IF(LIBMYSQLD_SO_EXTRA_LIBS) TARGET_LINK_LIBRARIES(libmysqld ${LIBMYSQLD_SO_EXTRA_LIBS}) ENDIF() -- cgit v1.2.1