Commit 6c09a72a authored by Sergei Golubchik's avatar Sergei Golubchik

Merge remote-tracking branch 'origin/10.0' into 10.0

parents 126523d1 723be516
...@@ -235,7 +235,7 @@ typedef struct _global { /* Global structure */ ...@@ -235,7 +235,7 @@ typedef struct _global { /* Global structure */
void *Xchk; /* indexes in create/alter */ void *Xchk; /* indexes in create/alter */
short Alchecked; /* Checked for ALTER */ short Alchecked; /* Checked for ALTER */
short Mrr; /* True when doing mrr */ short Mrr; /* True when doing mrr */
short Trace; int N; /* Utility */
int jump_level; int jump_level;
jmp_buf jumper[MAX_JUMP + 2]; jmp_buf jumper[MAX_JUMP + 2];
} GLOBAL; } GLOBAL;
......
...@@ -168,6 +168,7 @@ ...@@ -168,6 +168,7 @@
#define SZCONV 8192 #define SZCONV 8192
#define SZWORK 67108864 // Default work area size 64M #define SZWORK 67108864 // Default work area size 64M
#define SZWMIN 4194304 // Minimum work area size 4M #define SZWMIN 4194304 // Minimum work area size 4M
#define JSONMAX 10 // JSON Default max grp size
extern "C" { extern "C" {
char version[]= "Version 1.03.0006 February 06, 2015"; char version[]= "Version 1.03.0006 February 06, 2015";
...@@ -217,6 +218,7 @@ bool ExactInfo(void); ...@@ -217,6 +218,7 @@ bool ExactInfo(void);
USETEMP UseTemp(void); USETEMP UseTemp(void);
int GetConvSize(void); int GetConvSize(void);
TYPCONV GetTypeConv(void); TYPCONV GetTypeConv(void);
uint GetJsonGrpSize(void);
uint GetWorkSize(void); uint GetWorkSize(void);
void SetWorkSize(uint); void SetWorkSize(uint);
extern "C" const char *msglang(void); extern "C" const char *msglang(void);
...@@ -323,6 +325,12 @@ static MYSQL_THDVAR_ENUM( ...@@ -323,6 +325,12 @@ static MYSQL_THDVAR_ENUM(
0, // def (no) 0, // def (no)
&xconv_typelib); // typelib &xconv_typelib); // typelib
// Estimate max number of rows for JSON aggregate functions
static MYSQL_THDVAR_UINT(json_grp_size,
PLUGIN_VAR_RQCMDARG, // opt
"max number of rows for JSON aggregate functions.",
NULL, NULL, JSONMAX, 1, INT_MAX, 1);
#if defined(XMSG) || defined(NEWMSG) #if defined(XMSG) || defined(NEWMSG)
const char *language_names[]= const char *language_names[]=
{ {
...@@ -353,6 +361,7 @@ bool ExactInfo(void) {return THDVAR(current_thd, exact_info);} ...@@ -353,6 +361,7 @@ bool ExactInfo(void) {return THDVAR(current_thd, exact_info);}
USETEMP UseTemp(void) {return (USETEMP)THDVAR(current_thd, use_tempfile);} USETEMP UseTemp(void) {return (USETEMP)THDVAR(current_thd, use_tempfile);}
int GetConvSize(void) {return THDVAR(current_thd, conv_size);} int GetConvSize(void) {return THDVAR(current_thd, conv_size);}
TYPCONV GetTypeConv(void) {return (TYPCONV)THDVAR(current_thd, type_conv);} TYPCONV GetTypeConv(void) {return (TYPCONV)THDVAR(current_thd, type_conv);}
uint GetJsonGrpSize(void) {return THDVAR(current_thd, json_grp_size);}
uint GetWorkSize(void) {return THDVAR(current_thd, work_size);} uint GetWorkSize(void) {return THDVAR(current_thd, work_size);}
void SetWorkSize(uint n) void SetWorkSize(uint n)
{ {
...@@ -6516,6 +6525,7 @@ static struct st_mysql_sys_var* connect_system_variables[]= { ...@@ -6516,6 +6525,7 @@ static struct st_mysql_sys_var* connect_system_variables[]= {
#if defined(XMSG) #if defined(XMSG)
MYSQL_SYSVAR(errmsg_dir_path), MYSQL_SYSVAR(errmsg_dir_path),
#endif // XMSG #endif // XMSG
MYSQL_SYSVAR(json_grp_size),
NULL NULL
}; };
......
...@@ -74,6 +74,7 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma) ...@@ -74,6 +74,7 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
goto err; goto err;
} else if (!(jsp = ParseObject(g, ++i, src))) } else if (!(jsp = ParseObject(g, ++i, src)))
goto err; goto err;
break; break;
case ' ': case ' ':
case '\t': case '\t':
...@@ -90,6 +91,11 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma) ...@@ -90,6 +91,11 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty); sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty);
goto err; goto err;
case '"':
if (!(jsp = ParseValue(g, i, src)))
goto err;
break;
case '(': case '(':
b = true; b = true;
break; break;
......
...@@ -8,12 +8,18 @@ ...@@ -8,12 +8,18 @@
/* Include relevant sections of the MariaDB header file. */ /* Include relevant sections of the MariaDB header file. */
/***********************************************************************/ /***********************************************************************/
#include <my_global.h> #include <my_global.h>
#include <mysqld.h>
#include <mysql.h> #include <mysql.h>
#include <sql_error.h>
#include "global.h" #include "global.h"
#include "plgdbsem.h" #include "plgdbsem.h"
#include "json.h" #include "json.h"
#define MEMFIX 512
uint GetJsonGrpSize(void);
extern "C" { extern "C" {
DllExport my_bool Json_Value_init(UDF_INIT*, UDF_ARGS*, char*); DllExport my_bool Json_Value_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Value(UDF_INIT*, UDF_ARGS*, char*, DllExport char *Json_Value(UDF_INIT*, UDF_ARGS*, char*,
...@@ -23,6 +29,10 @@ DllExport my_bool Json_Array_init(UDF_INIT*, UDF_ARGS*, char*); ...@@ -23,6 +29,10 @@ DllExport my_bool Json_Array_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Array(UDF_INIT*, UDF_ARGS*, char*, DllExport char *Json_Array(UDF_INIT*, UDF_ARGS*, char*,
unsigned long*, char *, char *); unsigned long*, char *, char *);
DllExport void Json_Array_deinit(UDF_INIT*); DllExport void Json_Array_deinit(UDF_INIT*);
DllExport my_bool Json_Array_Add_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Array_Add(UDF_INIT*, UDF_ARGS*, char*,
unsigned long*, char *, char *);
DllExport void Json_Array_Add_deinit(UDF_INIT*);
DllExport my_bool Json_Object_init(UDF_INIT*, UDF_ARGS*, char*); DllExport my_bool Json_Object_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Object(UDF_INIT*, UDF_ARGS*, char*, DllExport char *Json_Object(UDF_INIT*, UDF_ARGS*, char*,
unsigned long*, char *, char *); unsigned long*, char *, char *);
...@@ -44,8 +54,8 @@ DllExport void Json_Object_Grp_deinit(UDF_INIT*); ...@@ -44,8 +54,8 @@ DllExport void Json_Object_Grp_deinit(UDF_INIT*);
/***********************************************************************/ /***********************************************************************/
/* Allocate and initialise the memory area. */ /* Allocate and initialise the memory area. */
/***********************************************************************/ /***********************************************************************/
static my_bool JsonInit(UDF_INIT *initid, char *message, unsigned long reslen, static my_bool JsonInit(UDF_INIT *initid, char *message,
unsigned long memlen) unsigned long reslen, unsigned long memlen)
{ {
PGLOBAL g = PlugInit(NULL, memlen); PGLOBAL g = PlugInit(NULL, memlen);
...@@ -119,7 +129,7 @@ static my_bool CalcLen(UDF_ARGS *args, my_bool obj, ...@@ -119,7 +129,7 @@ static my_bool CalcLen(UDF_ARGS *args, my_bool obj,
} // endfor i } // endfor i
// Calculate the amount of memory needed // Calculate the amount of memory needed
memlen = 1024 + sizeof(JOUTSTR) + reslen; memlen = MEMFIX + sizeof(JOUTSTR) + reslen;
for (i = 0; i < args->arg_count; i++) { for (i = 0; i < args->arg_count; i++) {
memlen += (args->lengths[i] + sizeof(JVALUE)); memlen += (args->lengths[i] + sizeof(JVALUE));
...@@ -219,14 +229,23 @@ static PSZ MakeKey(PGLOBAL g, UDF_ARGS *args, int i) ...@@ -219,14 +229,23 @@ static PSZ MakeKey(PGLOBAL g, UDF_ARGS *args, int i)
static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, int i) static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, int i)
{ {
char *sap = args->args[i]; char *sap = args->args[i];
PJSON jsp;
PJVAL jvp = new(g) JVALUE; PJVAL jvp = new(g) JVALUE;
if (sap) switch (args->arg_type[i]) { if (sap) switch (args->arg_type[i]) {
case STRING_RESULT: case STRING_RESULT:
if (args->lengths[i]) { if (args->lengths[i]) {
if (IsJson(args, i)) if (IsJson(args, i)) {
jvp->SetValue(ParseJson(g, sap, args->lengths[i], 0)); if (!(jsp = ParseJson(g, sap, args->lengths[i], 0)))
push_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, 0,
g->Message);
if (jsp && jsp->GetType() == TYPE_JVAL)
jvp = (PJVAL)jsp;
else else
jvp->SetValue(jsp);
} else
jvp->SetString(g, MakePSZ(g, args, i)); jvp->SetString(g, MakePSZ(g, args, i));
} // endif str } // endif str
...@@ -328,6 +347,59 @@ void Json_Array_deinit(UDF_INIT* initid) ...@@ -328,6 +347,59 @@ void Json_Array_deinit(UDF_INIT* initid)
PlugExit((PGLOBAL)initid->ptr); PlugExit((PGLOBAL)initid->ptr);
} // end of Json_Array_deinit } // end of Json_Array_deinit
/***********************************************************************/
/* Add values to a Json array. */
/***********************************************************************/
my_bool Json_Array_Add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "Json_Value_Add must have at least 2 arguments");
return true;
} else if (!IsJson(args, 0)) {
strcpy(message, "Json_Value_Add first argument must be a json array");
return true;
} else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, message, reslen, memlen);
} // end of Json_Array_Add_init
char *Json_Array_Add(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str;
PJVAL jvp;
PJAR arp;
PGLOBAL g = (PGLOBAL)initid->ptr;
PlugSubSet(g, g->Sarea, g->Sarea_Size);
jvp = MakeValue(g, args, 0);
if (jvp->GetValType() != TYPE_JAR) {
arp = new(g) JARRAY;
arp->AddValue(g, jvp);
} else
arp = jvp->GetArray();
for (uint i = 1; i < args->arg_count; i++)
arp->AddValue(g, MakeValue(g, args, i));
arp->InitArray(g);
if (!(str = Serialize(g, arp, NULL, 0)))
str = strcpy(result, g->Message);
*res_length = strlen(str);
return str;
} // end of Json_Array_Add
void Json_Array_Add_deinit(UDF_INIT* initid)
{
PlugExit((PGLOBAL)initid->ptr);
} // end of Json_Array_Add_deinit
/***********************************************************************/ /***********************************************************************/
/* Make a Json Oject containing all the parameters. */ /* Make a Json Oject containing all the parameters. */
/***********************************************************************/ /***********************************************************************/
...@@ -370,7 +442,7 @@ void Json_Object_deinit(UDF_INIT* initid) ...@@ -370,7 +442,7 @@ void Json_Object_deinit(UDF_INIT* initid)
/***********************************************************************/ /***********************************************************************/
my_bool Json_Array_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message) my_bool Json_Array_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ {
unsigned long reslen, memlen, n = 10; unsigned long reslen, memlen, n = GetJsonGrpSize();
if (args->arg_count != 1) { if (args->arg_count != 1) {
strcpy(message, "Json_Array_Grp can only accept 1 argument"); strcpy(message, "Json_Array_Grp can only accept 1 argument");
...@@ -379,7 +451,7 @@ my_bool Json_Array_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message) ...@@ -379,7 +451,7 @@ my_bool Json_Array_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
CalcLen(args, false, reslen, memlen); CalcLen(args, false, reslen, memlen);
reslen *= n; reslen *= n;
memlen *= n; memlen += ((memlen - MEMFIX) * (n - 1));
if (JsonInit(initid, message, reslen, memlen)) if (JsonInit(initid, message, reslen, memlen))
return true; return true;
...@@ -388,6 +460,7 @@ my_bool Json_Array_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message) ...@@ -388,6 +460,7 @@ my_bool Json_Array_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
PlugSubSet(g, g->Sarea, g->Sarea_Size); PlugSubSet(g, g->Sarea, g->Sarea_Size);
g->Activityp = (PACTIVITY)new(g) JARRAY; g->Activityp = (PACTIVITY)new(g) JARRAY;
g->N = (int)n;
return false; return false;
} // end of Json_Array_Grp_init } // end of Json_Array_Grp_init
...@@ -397,7 +470,9 @@ void Json_Array_Grp_add(UDF_INIT *initid, UDF_ARGS *args, ...@@ -397,7 +470,9 @@ void Json_Array_Grp_add(UDF_INIT *initid, UDF_ARGS *args,
PGLOBAL g = (PGLOBAL)initid->ptr; PGLOBAL g = (PGLOBAL)initid->ptr;
PJAR arp = (PJAR)g->Activityp; PJAR arp = (PJAR)g->Activityp;
if (g->N-- > 0)
arp->AddValue(g, MakeValue(g, args, 0)); arp->AddValue(g, MakeValue(g, args, 0));
} // end of Json_Array_Grp_add } // end of Json_Array_Grp_add
char *Json_Array_Grp(UDF_INIT *initid, UDF_ARGS *args, char *result, char *Json_Array_Grp(UDF_INIT *initid, UDF_ARGS *args, char *result,
...@@ -407,6 +482,10 @@ char *Json_Array_Grp(UDF_INIT *initid, UDF_ARGS *args, char *result, ...@@ -407,6 +482,10 @@ char *Json_Array_Grp(UDF_INIT *initid, UDF_ARGS *args, char *result,
PGLOBAL g = (PGLOBAL)initid->ptr; PGLOBAL g = (PGLOBAL)initid->ptr;
PJAR arp = (PJAR)g->Activityp; PJAR arp = (PJAR)g->Activityp;
if (g->N < 0)
push_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, 0,
"Result truncated to json_grp_size values");
arp->InitArray(g); arp->InitArray(g);
if (!(str = Serialize(g, arp, NULL, 0))) if (!(str = Serialize(g, arp, NULL, 0)))
...@@ -422,6 +501,7 @@ void Json_Array_Grp_clear(UDF_INIT *initid, char *is_null, char *error) ...@@ -422,6 +501,7 @@ void Json_Array_Grp_clear(UDF_INIT *initid, char *is_null, char *error)
PlugSubSet(g, g->Sarea, g->Sarea_Size); PlugSubSet(g, g->Sarea, g->Sarea_Size);
g->Activityp = (PACTIVITY)new(g) JARRAY; g->Activityp = (PACTIVITY)new(g) JARRAY;
g->N = GetJsonGrpSize();
} // end of Json_Array_Grp_clear } // end of Json_Array_Grp_clear
void Json_Array_Grp_deinit(UDF_INIT* initid) void Json_Array_Grp_deinit(UDF_INIT* initid)
...@@ -434,7 +514,7 @@ void Json_Array_Grp_deinit(UDF_INIT* initid) ...@@ -434,7 +514,7 @@ void Json_Array_Grp_deinit(UDF_INIT* initid)
/***********************************************************************/ /***********************************************************************/
my_bool Json_Object_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message) my_bool Json_Object_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ {
unsigned long reslen, memlen, n = 10; unsigned long reslen, memlen, n = GetJsonGrpSize();
if (args->arg_count != 2) { if (args->arg_count != 2) {
strcpy(message, "Json_Array_Grp can only accept 2 argument"); strcpy(message, "Json_Array_Grp can only accept 2 argument");
...@@ -443,7 +523,7 @@ my_bool Json_Object_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message) ...@@ -443,7 +523,7 @@ my_bool Json_Object_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
CalcLen(args, true, reslen, memlen); CalcLen(args, true, reslen, memlen);
reslen *= n; reslen *= n;
memlen *= n; memlen += ((memlen - MEMFIX) * (n - 1));
if (JsonInit(initid, message, reslen, memlen)) if (JsonInit(initid, message, reslen, memlen))
return true; return true;
...@@ -452,6 +532,7 @@ my_bool Json_Object_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message) ...@@ -452,6 +532,7 @@ my_bool Json_Object_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
PlugSubSet(g, g->Sarea, g->Sarea_Size); PlugSubSet(g, g->Sarea, g->Sarea_Size);
g->Activityp = (PACTIVITY)new(g) JOBJECT; g->Activityp = (PACTIVITY)new(g) JOBJECT;
g->N = (int)n;
return false; return false;
} // end of Json_Object_Grp_init } // end of Json_Object_Grp_init
...@@ -461,7 +542,9 @@ void Json_Object_Grp_add(UDF_INIT *initid, UDF_ARGS *args, ...@@ -461,7 +542,9 @@ void Json_Object_Grp_add(UDF_INIT *initid, UDF_ARGS *args,
PGLOBAL g = (PGLOBAL)initid->ptr; PGLOBAL g = (PGLOBAL)initid->ptr;
PJOB objp = (PJOB)g->Activityp; PJOB objp = (PJOB)g->Activityp;
if (g->N-- > 0)
objp->SetValue(g, MakeValue(g, args, 0), MakePSZ(g, args, 1)); objp->SetValue(g, MakeValue(g, args, 0), MakePSZ(g, args, 1));
} // end of Json_Object_Grp_add } // end of Json_Object_Grp_add
char *Json_Object_Grp(UDF_INIT *initid, UDF_ARGS *args, char *result, char *Json_Object_Grp(UDF_INIT *initid, UDF_ARGS *args, char *result,
...@@ -471,6 +554,10 @@ char *Json_Object_Grp(UDF_INIT *initid, UDF_ARGS *args, char *result, ...@@ -471,6 +554,10 @@ char *Json_Object_Grp(UDF_INIT *initid, UDF_ARGS *args, char *result,
PGLOBAL g = (PGLOBAL)initid->ptr; PGLOBAL g = (PGLOBAL)initid->ptr;
PJOB objp = (PJOB)g->Activityp; PJOB objp = (PJOB)g->Activityp;
if (g->N < 0)
push_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, 0,
"Result truncated to json_grp_size values");
if (!(str = Serialize(g, objp, NULL, 0))) if (!(str = Serialize(g, objp, NULL, 0)))
str = strcpy(result, g->Message); str = strcpy(result, g->Message);
...@@ -484,6 +571,7 @@ void Json_Object_Grp_clear(UDF_INIT *initid, char *is_null, char *error) ...@@ -484,6 +571,7 @@ void Json_Object_Grp_clear(UDF_INIT *initid, char *is_null, char *error)
PlugSubSet(g, g->Sarea, g->Sarea_Size); PlugSubSet(g, g->Sarea, g->Sarea_Size);
g->Activityp = (PACTIVITY)new(g) JOBJECT; g->Activityp = (PACTIVITY)new(g) JOBJECT;
g->N = GetJsonGrpSize();
} // end of Json_Object_Grp_clear } // end of Json_Object_Grp_clear
void Json_Object_Grp_deinit(UDF_INIT* initid) void Json_Object_Grp_deinit(UDF_INIT* initid)
......
...@@ -311,7 +311,7 @@ PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids, ...@@ -311,7 +311,7 @@ PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
else else
crp->Kdata = NULL; crp->Kdata = NULL;
if (g->Trace) if (trace)
htrc("Column(%d) %s type=%d len=%d value=%p\n", htrc("Column(%d) %s type=%d len=%d value=%p\n",
crp->Ncol, crp->Name, crp->Type, crp->Length, crp->Kdata); crp->Ncol, crp->Name, crp->Type, crp->Length, crp->Kdata);
......
...@@ -144,12 +144,12 @@ PGLOBAL PlugInit(LPCSTR Language, uint worksize) ...@@ -144,12 +144,12 @@ PGLOBAL PlugInit(LPCSTR Language, uint worksize)
return NULL; return NULL;
} else { } else {
g->Sarea_Size = worksize; g->Sarea_Size = worksize;
g->Trace = 0;
g->Createas = 0; g->Createas = 0;
g->Alchecked = 0; g->Alchecked = 0;
g->Mrr = 0; g->Mrr = 0;
g->Activityp = g->ActivityStart = NULL; g->Activityp = g->ActivityStart = NULL;
g->Xchk = NULL; g->Xchk = NULL;
g->N = 0;
strcpy(g->Message, ""); strcpy(g->Message, "");
/*******************************************************************/ /*******************************************************************/
......
...@@ -931,7 +931,11 @@ void JSONCOL::WriteColumn(PGLOBAL g) ...@@ -931,7 +931,11 @@ void JSONCOL::WriteColumn(PGLOBAL g)
case TYPE_STRING: case TYPE_STRING:
if (Nodes[Nod-1].Op == OP_XX) { if (Nodes[Nod-1].Op == OP_XX) {
s = Value->GetCharValue(); s = Value->GetCharValue();
jsp = ParseJson(g, s, (int)strlen(s), 0);
if (!(jsp = ParseJson(g, s, (int)strlen(s), 0))) {
strcpy(g->Message, s);
longjmp(g->jumper[g->jump_level], 666);
} // endif jsp
if (arp) { if (arp) {
if (Nod > 1 && Nodes[Nod-2].Rank) if (Nod > 1 && Nodes[Nod-2].Rank)
......
...@@ -787,7 +787,7 @@ bool TDBODBC::OpenDB(PGLOBAL g) ...@@ -787,7 +787,7 @@ bool TDBODBC::OpenDB(PGLOBAL g)
{ {
bool rc = true; bool rc = true;
if (g->Trace) if (trace)
htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n", htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n",
this, Tdb_No, Use, Mode); this, Tdb_No, Use, Mode);
...@@ -1185,12 +1185,12 @@ void ODBCCOL::ReadColumn(PGLOBAL g) ...@@ -1185,12 +1185,12 @@ void ODBCCOL::ReadColumn(PGLOBAL g)
} // endif Buf_Type } // endif Buf_Type
if (g->Trace) { if (trace) {
char buf[64]; char buf[64];
htrc("ODBC Column %s: rows=%d buf=%p type=%d value=%s\n", htrc("ODBC Column %s: rows=%d buf=%p type=%d value=%s\n",
Name, tdbp->Rows, Bufp, Buf_Type, Value->GetCharString(buf)); Name, tdbp->Rows, Bufp, Buf_Type, Value->GetCharString(buf));
} // endif Trace } // endif trace
put: put:
if (tdbp->Memory != 2) if (tdbp->Memory != 2)
...@@ -1424,7 +1424,7 @@ bool TDBXDBC::OpenDB(PGLOBAL g) ...@@ -1424,7 +1424,7 @@ bool TDBXDBC::OpenDB(PGLOBAL g)
{ {
bool rc = false; bool rc = false;
if (g->Trace) if (trace)
htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n", htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n",
this, Tdb_No, Use, Mode); this, Tdb_No, Use, Mode);
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
...@@ -72,6 +73,12 @@ struct lock_t { ...@@ -72,6 +73,12 @@ struct lock_t {
hash_node_t hash; /*!< hash chain node for a record hash_node_t hash; /*!< hash chain node for a record
lock */ lock */
dict_index_t* index; /*!< index for a record lock */ dict_index_t* index; /*!< index for a record lock */
/* Statistics for how long lock has been held and time
how long this lock had to be waited before it was granted */
time_t requested_time; /*!< Lock request time */
ulint wait_time; /*!< Time waited this lock or 0 */
union { union {
lock_table_t tab_lock;/*!< table lock */ lock_table_t tab_lock;/*!< table lock */
lock_rec_t rec_lock;/*!< record lock */ lock_rec_t rec_lock;/*!< record lock */
......
...@@ -1009,6 +1009,19 @@ struct trx_t{ ...@@ -1009,6 +1009,19 @@ struct trx_t{
/*------------------------------*/ /*------------------------------*/
char detailed_error[256]; /*!< detailed error message for last char detailed_error[256]; /*!< detailed error message for last
error, or empty. */ error, or empty. */
/* Lock wait statistics */
ulint n_rec_lock_waits;
/*!< Number of record lock waits,
might not be exactly correct. */
ulint n_table_lock_waits;
/*!< Number of table lock waits,
might not be exactly correct. */
ulint total_rec_lock_wait_time;
/*!< Total rec lock wait time up
to this moment. */
ulint total_table_lock_wait_time;
/*!< Total table lock wait time
up to this moment. */
}; };
/* Transaction isolation levels (trx->isolation_level) */ /* Transaction isolation levels (trx->isolation_level) */
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2014, 2015, MariaDB Corporation
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
...@@ -1886,6 +1887,9 @@ lock_rec_create( ...@@ -1886,6 +1887,9 @@ lock_rec_create(
/* Set the bit corresponding to rec */ /* Set the bit corresponding to rec */
lock_rec_set_nth_bit(lock, heap_no); lock_rec_set_nth_bit(lock, heap_no);
lock->requested_time = ut_time();
lock->wait_time = 0;
index->table->n_rec_locks++; index->table->n_rec_locks++;
ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted); ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted);
...@@ -2034,6 +2038,8 @@ lock_rec_enqueue_waiting( ...@@ -2034,6 +2038,8 @@ lock_rec_enqueue_waiting(
MONITOR_INC(MONITOR_LOCKREC_WAIT); MONITOR_INC(MONITOR_LOCKREC_WAIT);
trx->n_rec_lock_waits++;
return(DB_LOCK_WAIT); return(DB_LOCK_WAIT);
} }
...@@ -2454,6 +2460,17 @@ lock_grant( ...@@ -2454,6 +2460,17 @@ lock_grant(
} }
} }
/* Cumulate total lock wait time for statistics */
if (lock_get_type_low(lock) & LOCK_TABLE) {
lock->trx->total_table_lock_wait_time +=
(ulint)difftime(ut_time(), lock->trx->lock.wait_started);
} else {
lock->trx->total_rec_lock_wait_time +=
(ulint)difftime(ut_time(), lock->trx->lock.wait_started);
}
lock->wait_time = (ulint)difftime(ut_time(), lock->requested_time);
trx_mutex_exit(lock->trx); trx_mutex_exit(lock->trx);
} }
...@@ -4215,6 +4232,8 @@ lock_table_create( ...@@ -4215,6 +4232,8 @@ lock_table_create(
lock->type_mode = type_mode | LOCK_TABLE; lock->type_mode = type_mode | LOCK_TABLE;
lock->trx = trx; lock->trx = trx;
lock->requested_time = ut_time();
lock->wait_time = 0;
lock->un_member.tab_lock.table = table; lock->un_member.tab_lock.table = table;
...@@ -4458,6 +4477,7 @@ lock_table_enqueue_waiting( ...@@ -4458,6 +4477,7 @@ lock_table_enqueue_waiting(
trx->lock.wait_started = ut_time(); trx->lock.wait_started = ut_time();
trx->lock.was_chosen_as_deadlock_victim = FALSE; trx->lock.was_chosen_as_deadlock_victim = FALSE;
trx->n_table_lock_waits++;
ut_a(que_thr_stop(thr)); ut_a(que_thr_stop(thr));
...@@ -5133,6 +5153,10 @@ lock_table_print( ...@@ -5133,6 +5153,10 @@ lock_table_print(
fputs(" waiting", file); fputs(" waiting", file);
} }
fprintf(file, " lock hold time %lu wait time before grant %lu ",
(ulint)difftime(ut_time(), lock->requested_time),
lock->wait_time);
putc('\n', file); putc('\n', file);
} }
...@@ -5200,6 +5224,10 @@ lock_rec_print( ...@@ -5200,6 +5224,10 @@ lock_rec_print(
mtr_start(&mtr); mtr_start(&mtr);
fprintf(file, " lock hold time %lu wait time before grant %lu ",
(ulint)difftime(ut_time(), lock->requested_time),
lock->wait_time);
putc('\n', file); putc('\n', file);
block = buf_page_try_get(space, page_no, &mtr); block = buf_page_try_get(space, page_no, &mtr);
...@@ -5458,6 +5486,14 @@ lock_print_info_all_transactions( ...@@ -5458,6 +5486,14 @@ lock_print_info_all_transactions(
trx->read_view->up_limit_id); trx->read_view->up_limit_id);
} }
/* Total trx lock waits and times */
fprintf(file, "Trx #rec lock waits %lu #table lock waits %lu\n",
trx->n_rec_lock_waits, trx->n_table_lock_waits);
fprintf(file, "Trx total rec lock wait time %lu SEC\n",
trx->total_rec_lock_wait_time);
fprintf(file, "Trx total table lock wait time %lu SEC\n",
trx->total_table_lock_wait_time);
if (trx->lock.que_state == TRX_QUE_LOCK_WAIT) { if (trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
fprintf(file, fprintf(file,
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
...@@ -72,6 +73,12 @@ struct lock_t { ...@@ -72,6 +73,12 @@ struct lock_t {
hash_node_t hash; /*!< hash chain node for a record hash_node_t hash; /*!< hash chain node for a record
lock */ lock */
dict_index_t* index; /*!< index for a record lock */ dict_index_t* index; /*!< index for a record lock */
/* Statistics for how long lock has been held and time
how long this lock had to be waited before it was granted */
time_t requested_time; /*!< Lock request time */
ulint wait_time; /*!< Time waited this lock or 0 */
union { union {
lock_table_t tab_lock;/*!< table lock */ lock_table_t tab_lock;/*!< table lock */
lock_rec_t rec_lock;/*!< record lock */ lock_rec_t rec_lock;/*!< record lock */
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
...@@ -1058,6 +1059,20 @@ struct trx_t{ ...@@ -1058,6 +1059,20 @@ struct trx_t{
#define DPAH_SIZE 8192 #define DPAH_SIZE 8192
byte* distinct_page_access_hash; byte* distinct_page_access_hash;
ibool take_stats; ibool take_stats;
/* Lock wait statistics */
ulint n_rec_lock_waits;
/*!< Number of record lock waits,
might not be exactly correct. */
ulint n_table_lock_waits;
/*!< Number of table lock waits,
might not be exactly correct. */
ulint total_rec_lock_wait_time;
/*!< Total rec lock wait time up
to this moment. */
ulint total_table_lock_wait_time;
/*!< Total table lock wait time
up to this moment. */
}; };
/* Transaction isolation levels (trx->isolation_level) */ /* Transaction isolation levels (trx->isolation_level) */
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2014, 2015, MariaDB Corporation
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
...@@ -1897,6 +1898,9 @@ lock_rec_create( ...@@ -1897,6 +1898,9 @@ lock_rec_create(
/* Set the bit corresponding to rec */ /* Set the bit corresponding to rec */
lock_rec_set_nth_bit(lock, heap_no); lock_rec_set_nth_bit(lock, heap_no);
lock->requested_time = ut_time();
lock->wait_time = 0;
index->table->n_rec_locks++; index->table->n_rec_locks++;
ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted); ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted);
...@@ -2055,6 +2059,8 @@ lock_rec_enqueue_waiting( ...@@ -2055,6 +2059,8 @@ lock_rec_enqueue_waiting(
MONITOR_INC(MONITOR_LOCKREC_WAIT); MONITOR_INC(MONITOR_LOCKREC_WAIT);
trx->n_rec_lock_waits++;
return(DB_LOCK_WAIT); return(DB_LOCK_WAIT);
} }
...@@ -2474,6 +2480,17 @@ lock_grant( ...@@ -2474,6 +2480,17 @@ lock_grant(
} }
} }
/* Cumulate total lock wait time for statistics */
if (lock_get_type_low(lock) & LOCK_TABLE) {
lock->trx->total_table_lock_wait_time +=
(ulint)difftime(ut_time(), lock->trx->lock.wait_started);
} else {
lock->trx->total_rec_lock_wait_time +=
(ulint)difftime(ut_time(), lock->trx->lock.wait_started);
}
lock->wait_time = (ulint)difftime(ut_time(), lock->requested_time);
trx_mutex_exit(lock->trx); trx_mutex_exit(lock->trx);
} }
...@@ -4239,6 +4256,8 @@ lock_table_create( ...@@ -4239,6 +4256,8 @@ lock_table_create(
lock->type_mode = type_mode | LOCK_TABLE; lock->type_mode = type_mode | LOCK_TABLE;
lock->trx = trx; lock->trx = trx;
lock->requested_time = ut_time();
lock->wait_time = 0;
lock->un_member.tab_lock.table = table; lock->un_member.tab_lock.table = table;
...@@ -4484,6 +4503,7 @@ lock_table_enqueue_waiting( ...@@ -4484,6 +4503,7 @@ lock_table_enqueue_waiting(
trx->lock.wait_started = ut_time(); trx->lock.wait_started = ut_time();
trx->lock.was_chosen_as_deadlock_victim = FALSE; trx->lock.was_chosen_as_deadlock_victim = FALSE;
trx->n_table_lock_waits++;
if (UNIV_UNLIKELY(trx->take_stats)) { if (UNIV_UNLIKELY(trx->take_stats)) {
ut_usectime(&sec, &ms); ut_usectime(&sec, &ms);
...@@ -5168,6 +5188,10 @@ lock_table_print( ...@@ -5168,6 +5188,10 @@ lock_table_print(
fputs(" waiting", file); fputs(" waiting", file);
} }
fprintf(file, " lock hold time %lu wait time before grant %lu ",
(ulint)difftime(ut_time(), lock->requested_time),
lock->wait_time);
putc('\n', file); putc('\n', file);
} }
...@@ -5235,6 +5259,10 @@ lock_rec_print( ...@@ -5235,6 +5259,10 @@ lock_rec_print(
mtr_start(&mtr); mtr_start(&mtr);
fprintf(file, " lock hold time %lu wait time before grant %lu ",
(ulint)difftime(ut_time(), lock->requested_time),
lock->wait_time);
putc('\n', file); putc('\n', file);
if ( srv_show_verbose_locks ) { if ( srv_show_verbose_locks ) {
...@@ -5495,6 +5523,14 @@ lock_print_info_all_transactions( ...@@ -5495,6 +5523,14 @@ lock_print_info_all_transactions(
trx->read_view->up_limit_id); trx->read_view->up_limit_id);
} }
/* Total trx lock waits and times */
fprintf(file, "Trx #rec lock waits %lu #table lock waits %lu\n",
trx->n_rec_lock_waits, trx->n_table_lock_waits);
fprintf(file, "Trx total rec lock wait time %lu SEC\n",
trx->total_rec_lock_wait_time);
fprintf(file, "Trx total table lock wait time %lu SEC\n",
trx->total_table_lock_wait_time);
if (trx->lock.que_state == TRX_QUE_LOCK_WAIT) { if (trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
fprintf(file, fprintf(file,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment