summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2020-10-28 10:01:50 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2020-10-28 10:01:50 +0200
commita8de8f261d1b7621b8e16396e87dfaac14891162 (patch)
tree9b8ec45858c2757305e0bdecf237fcb59251020c /storage
parente183aec1d75ea7b424ebe237e6b1643961903f2d (diff)
parent42e1815ad850384fad292534665ff61b78dd96f6 (diff)
downloadmariadb-git-a8de8f261d1b7621b8e16396e87dfaac14891162.tar.gz
Merge 10.2 into 10.3
Diffstat (limited to 'storage')
-rw-r--r--storage/connect/global.h56
-rw-r--r--storage/connect/ha_connect.cc256
-rw-r--r--storage/connect/ha_connect.h4
-rw-r--r--storage/connect/json.cpp164
-rw-r--r--storage/connect/json.h57
-rw-r--r--storage/connect/jsonudf.cpp550
-rw-r--r--storage/connect/jsonudf.h39
-rw-r--r--storage/connect/mongo.cpp10
-rw-r--r--storage/connect/mysql-test/connect/r/json_java_2.result36
-rw-r--r--storage/connect/mysql-test/connect/r/json_java_3.result36
-rw-r--r--storage/connect/mysql-test/connect/r/json_mongo_c.result36
-rw-r--r--storage/connect/mysql-test/connect/r/updelx.result4
-rw-r--r--storage/connect/mysql-test/connect/t/updelx.test4
-rw-r--r--storage/connect/myutil.h4
-rw-r--r--storage/connect/plgdbutl.cpp20
-rw-r--r--storage/connect/plugutil.cpp67
-rw-r--r--storage/connect/tabjson.cpp141
-rw-r--r--storage/connect/tabjson.h4
-rw-r--r--storage/connect/tabrest.cpp28
-rw-r--r--storage/connect/tabxml.cpp9
-rw-r--r--storage/connect/user_connect.cc20
-rw-r--r--storage/connect/value.cpp9
-rw-r--r--storage/connect/value.h7
-rw-r--r--storage/innobase/CMakeLists.txt1
-rw-r--r--storage/innobase/btr/btr0bulk.cc4
-rw-r--r--storage/innobase/btr/btr0cur.cc43
-rw-r--r--storage/innobase/btr/btr0pcur.cc39
-rw-r--r--storage/innobase/buf/buf0block_hint.cc78
-rw-r--r--storage/innobase/buf/buf0buf.cc76
-rw-r--r--storage/innobase/dict/dict0dict.cc149
-rw-r--r--storage/innobase/dict/dict0mem.cc48
-rw-r--r--storage/innobase/dict/dict0stats.cc10
-rw-r--r--storage/innobase/fil/fil0crypt.cc2
-rw-r--r--storage/innobase/fts/fts0ast.cc8
-rw-r--r--storage/innobase/fts/fts0que.cc31
-rw-r--r--storage/innobase/gis/gis0sea.cc25
-rw-r--r--storage/innobase/handler/ha_innodb.cc35
-rw-r--r--storage/innobase/ibuf/ibuf0ibuf.cc2
-rw-r--r--storage/innobase/include/btr0pcur.h11
-rw-r--r--storage/innobase/include/buf0block_hint.h77
-rw-r--r--storage/innobase/include/buf0buf.h17
-rw-r--r--storage/innobase/include/buf0buf.ic37
-rw-r--r--storage/innobase/include/dict0dict.h25
-rw-r--r--storage/innobase/include/dict0mem.h115
-rw-r--r--storage/innobase/include/mtr0mtr.ic4
-rw-r--r--storage/innobase/include/os0once.h120
-rw-r--r--storage/innobase/include/trx0sys.h4
-rw-r--r--storage/innobase/include/trx0undo.h4
-rw-r--r--storage/innobase/lock/lock0lock.cc2
-rw-r--r--storage/innobase/mtr/mtr0mtr.cc4
-rw-r--r--storage/innobase/page/page0zip.cc2
-rw-r--r--storage/innobase/trx/trx0rec.cc2
-rw-r--r--storage/innobase/trx/trx0undo.cc9
53 files changed, 1465 insertions, 1080 deletions
diff --git a/storage/connect/global.h b/storage/connect/global.h
index fd26c87b800..d17620861fa 100644
--- a/storage/connect/global.h
+++ b/storage/connect/global.h
@@ -1,7 +1,7 @@
/***********************************************************************/
/* GLOBAL.H: Declaration file used by all CONNECT implementations. */
/* (C) Copyright MariaDB Corporation Ab */
-/* Author Olivier Bertrand 1993-2018 */
+/* Author Olivier Bertrand 1993-2020 */
/***********************************************************************/
/***********************************************************************/
@@ -89,14 +89,10 @@ extern "C" {
#define PAT_LOG "log"
#if defined(UNIX) || defined(LINUX) || defined(UNIV_LINUX)
- /*********************************************************************/
- /* printf does not accept null pointer for %s target. */
- /*********************************************************************/
+ // printf does not accept null pointer for %s target
#define SVP(S) ((S) ? S : "<null>")
#else
- /*********************************************************************/
- /* printf accepts null pointer for %s target. */
- /*********************************************************************/
+ // printf accepts null pointer for %s target
#define SVP(S) S
#endif
@@ -112,9 +108,6 @@ extern "C" {
/***********************************************************************/
#include "os.h"
-typedef uint OFFSET;
-typedef char NAME[9];
-
typedef struct {
ushort Length;
char String[2];
@@ -127,6 +120,7 @@ typedef struct _global *PGLOBAL;
typedef struct _globplg *PGS;
typedef struct _activity *PACTIVITY;
typedef struct _parm *PPARM;
+typedef char NAME[9];
/***********************************************************************/
/* Segment Sub-Allocation block structure declares. */
@@ -135,8 +129,8 @@ typedef struct _parm *PPARM;
/* restore them if needed. This scheme implies that no SubFree be used */
/***********************************************************************/
typedef struct { /* Plug Area SubAlloc header */
- OFFSET To_Free; /* Offset of next free block */
- uint FreeBlk; /* Size of remaining free memory */
+ size_t To_Free; /* Offset of next free block */
+ size_t FreeBlk; /* Size of remaining free memory */
} POOLHEADER, *PPOOLHEADER;
/***********************************************************************/
@@ -188,11 +182,12 @@ typedef struct _parm {
/***********************************************************************/
typedef struct _global { /* Global structure */
void *Sarea; /* Points to work area */
- uint Sarea_Size; /* Work area size */
+ size_t Sarea_Size; /* Work area size */
PACTIVITY Activityp;
- char Message[MAX_STR];
+ char Message[MAX_STR]; /* Message (result, error, trace) */
ulong More; /* Used by jsonudf */
- int Createas; /* To pass multi to ext tables */
+ size_t Saved_Size; /* Saved work area to_free */
+ bool Createas; /* To pass multi to ext tables */
void *Xchk; /* indexes in create/alter */
short Alchecked; /* Checked for ALTER */
short Mrr; /* True when doing mrr */
@@ -210,19 +205,18 @@ DllExport char *PlugReadMessage(PGLOBAL, int, char *);
DllExport char *PlugGetMessage(PGLOBAL, int);
#endif // XMSG || NEWMSG
#if defined(__WIN__)
-DllExport short GetLineLength(PGLOBAL); // Console line length
+DllExport short GetLineLength(PGLOBAL); // Console line length
#endif // __WIN__
-DllExport PGLOBAL PlugInit(LPCSTR, uint); // Plug global initialization
-DllExport int PlugExit(PGLOBAL); // Plug global termination
+DllExport PGLOBAL PlugInit(LPCSTR, size_t); // Plug global initialization
+DllExport int PlugExit(PGLOBAL); // Plug global termination
DllExport LPSTR PlugRemoveType(LPSTR, LPCSTR);
DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR prefix, LPCSTR name, LPCSTR dir);
DllExport BOOL PlugIsAbsolutePath(LPCSTR path);
-DllExport bool AllocSarea(PGLOBAL, uint);
+DllExport bool AllocSarea(PGLOBAL, size_t);
DllExport void FreeSarea(PGLOBAL);
-DllExport BOOL PlugSubSet(void *, uint);
+DllExport BOOL PlugSubSet(void *, size_t);
DllExport void *PlugSubAlloc(PGLOBAL, void *, size_t);
DllExport char *PlugDup(PGLOBAL g, const char *str);
-DllExport void *MakePtr(void *, OFFSET);
DllExport void htrc(char const *fmt, ...);
DllExport void xtrc(uint, char const* fmt, ...);
DllExport uint GetTraceValue(void);
@@ -232,8 +226,24 @@ DllExport uint GetTraceValue(void);
#endif
/***********************************************************************/
-/* Non exported routine declarations. */
+/* Inline routine definitions. */
+/***********************************************************************/
+/***********************************************************************/
+/* This routine makes a pointer from an offset to a memory pointer. */
+/***********************************************************************/
+inline void* MakePtr(void* memp, size_t offset) {
+ // return ((offset == 0) ? NULL : &((char*)memp)[offset]);
+ return (!offset) ? NULL : (char *)memp + offset;
+} /* end of MakePtr */
+
+/***********************************************************************/
+/* This routine makes an offset from a pointer new format. */
/***********************************************************************/
-//void *PlugSubAlloc(PGLOBAL, void *, size_t); // Does throw
+inline size_t MakeOff(void* memp, void* ptr) {
+#if defined(_DEBUG)
+ assert(ptr > memp);
+#endif // _DEBUG
+ return ((!ptr) ? 0 : (size_t)((char*)ptr - (size_t)memp));
+} /* end of MakeOff */
/*-------------------------- End of Global.H --------------------------*/
diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc
index 53e9c112ab8..8894a16c2a9 100644
--- a/storage/connect/ha_connect.cc
+++ b/storage/connect/ha_connect.cc
@@ -170,9 +170,9 @@
#define JSONMAX 10 // JSON Default max grp size
extern "C" {
- char version[]= "Version 1.07.0001 November 12, 2019";
+ char version[]= "Version 1.07.0002 October 18, 2020";
#if defined(__WIN__)
- char compver[]= "Version 1.07.0001 " __DATE__ " " __TIME__;
+ char compver[]= "Version 1.07.0002 " __DATE__ " " __TIME__;
char slash= '\\';
#else // !__WIN__
char slash= '/';
@@ -251,11 +251,13 @@ bool ExactInfo(void);
USETEMP UseTemp(void);
int GetConvSize(void);
TYPCONV GetTypeConv(void);
+bool JsonAllPath(void);
char *GetJsonNull(void);
+int GetDefaultDepth(void);
uint GetJsonGrpSize(void);
char *GetJavaWrapper(void);
-uint GetWorkSize(void);
-void SetWorkSize(uint);
+size_t GetWorkSize(void);
+void SetWorkSize(size_t);
extern "C" const char *msglang(void);
static void PopUser(PCONNECT xp);
@@ -345,11 +347,19 @@ static MYSQL_THDVAR_ENUM(
1, // def (AUTO)
&usetemp_typelib); // typelib
+#ifdef _WIN64
// Size used for g->Sarea_Size
-static MYSQL_THDVAR_UINT(work_size,
- PLUGIN_VAR_RQCMDARG,
- "Size of the CONNECT work area.",
- NULL, NULL, SZWORK, SZWMIN, UINT_MAX, 1);
+static MYSQL_THDVAR_ULONGLONG(work_size,
+ PLUGIN_VAR_RQCMDARG,
+ "Size of the CONNECT work area.",
+ NULL, NULL, SZWORK, SZWMIN, ULONGLONG_MAX, 1);
+#else
+// Size used for g->Sarea_Size
+static MYSQL_THDVAR_ULONG(work_size,
+ PLUGIN_VAR_RQCMDARG,
+ "Size of the CONNECT work area.",
+ NULL, NULL, SZWORK, SZWMIN, ULONG_MAX, 1);
+#endif
// Size used when converting TEXT columns to VARCHAR
static MYSQL_THDVAR_INT(conv_size,
@@ -384,6 +394,11 @@ static MYSQL_THDVAR_ENUM(
1, // def (yes)
&xconv_typelib); // typelib
+// Adding JPATH to all Json table columns
+static MYSQL_THDVAR_BOOL(json_all_path, PLUGIN_VAR_RQCMDARG,
+ "Adding JPATH to all Json table columns",
+ NULL, NULL, 0); // NO by default
+
// Null representation for JSON values
static MYSQL_THDVAR_STR(json_null,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
@@ -391,6 +406,12 @@ static MYSQL_THDVAR_STR(json_null,
// check_json_null, update_json_null,
NULL, NULL, "<null>");
+// Default Json, XML or Mongo depth
+static MYSQL_THDVAR_INT(default_depth,
+ PLUGIN_VAR_RQCMDARG,
+ "Default depth used by Json, XML and Mongo discovery",
+ NULL, NULL, 0, -1, 16, 1);
+
// Estimate max number of rows for JSON aggregate functions
static MYSQL_THDVAR_UINT(json_grp_size,
PLUGIN_VAR_RQCMDARG, // opt
@@ -452,15 +473,17 @@ uint GetTraceValue(void)
{return (uint)(connect_hton ? THDVAR(current_thd, xtrace) : 0);}
bool ExactInfo(void) {return THDVAR(current_thd, exact_info);}
static bool CondPushEnabled(void) {return THDVAR(current_thd, cond_push);}
+bool JsonAllPath(void) {return THDVAR(current_thd, json_all_path);}
USETEMP UseTemp(void) {return (USETEMP)THDVAR(current_thd, use_tempfile);}
int GetConvSize(void) {return THDVAR(current_thd, conv_size);}
TYPCONV GetTypeConv(void) {return (TYPCONV)THDVAR(current_thd, type_conv);}
char *GetJsonNull(void)
{return connect_hton ? THDVAR(current_thd, json_null) : NULL;}
+int GetDefaultDepth(void) {return THDVAR(current_thd, default_depth);}
uint GetJsonGrpSize(void)
{return connect_hton ? THDVAR(current_thd, json_grp_size) : 10;}
-uint GetWorkSize(void) {return THDVAR(current_thd, work_size);}
-void SetWorkSize(uint)
+size_t GetWorkSize(void) {return (size_t)THDVAR(current_thd, work_size);}
+void SetWorkSize(size_t)
{
// Changing the session variable value seems to be impossible here
// and should be done in a check function
@@ -470,7 +493,8 @@ void SetWorkSize(uint)
#if defined(JAVA_SUPPORT)
char *GetJavaWrapper(void)
-{return connect_hton ? THDVAR(current_thd, java_wrapper) : (char*)"wrappers/JdbcInterface";}
+{return connect_hton ? THDVAR(current_thd, java_wrapper)
+ : (char*)"wrappers/JdbcInterface";}
#endif // JAVA_SUPPORT
#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
@@ -619,8 +643,10 @@ ha_create_table_option connect_field_option_list[]=
HA_FOPTION_NUMBER("FIELD_LENGTH", fldlen, 0, 0, INT_MAX32, 1),
HA_FOPTION_STRING("DATE_FORMAT", dateformat),
HA_FOPTION_STRING("FIELD_FORMAT", fieldformat),
- HA_FOPTION_STRING("SPECIAL", special),
- HA_FOPTION_ENUM("DISTRIB", opt, "scattered,clustered,sorted", 0),
+ HA_FOPTION_STRING("JPATH", jsonpath),
+ HA_FOPTION_STRING("XPATH", xmlpath),
+ HA_FOPTION_STRING("SPECIAL", special),
+ HA_FOPTION_ENUM("DISTRIB", opt, "scattered,clustered,sorted", 0),
HA_FOPTION_END
};
@@ -1311,9 +1337,10 @@ int GetIntegerTableOption(PGLOBAL g, PTOS options, PCSZ opname, int idef)
if ((ulonglong) opval == (ulonglong)NO_IVAL) {
PCSZ pv;
- if ((pv= GetListOption(g, opname, options->oplist)))
- opval= CharToNumber((char*)pv, strlen(pv), ULONGLONG_MAX, true);
- else
+ if ((pv = GetListOption(g, opname, options->oplist))) {
+ // opval = CharToNumber((char*)pv, strlen(pv), ULONGLONG_MAX, false);
+ return atoi(pv);
+ } else
return idef;
} // endif opval
@@ -1565,8 +1592,9 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf)
pcf->Offset= (int)fop->offset;
pcf->Freq= (int)fop->freq;
pcf->Datefmt= (char*)fop->dateformat;
- pcf->Fieldfmt= (char*)fop->fieldformat;
- } else {
+ pcf->Fieldfmt = fop->fieldformat ? (char*)fop->fieldformat
+ : fop->jsonpath ? (char*)fop->jsonpath : (char*)fop->xmlpath;
+ } else {
pcf->Offset= -1;
pcf->Freq= 0;
pcf->Datefmt= NULL;
@@ -1575,6 +1603,9 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf)
chset= (char *)fp->charset()->name;
+ if (!strcmp(chset, "binary"))
+ v = 'B'; // Binary string
+
switch (fp->type()) {
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VARCHAR:
@@ -1584,7 +1615,7 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf)
default:
pcf->Type= MYSQLtoPLG(fp->type(), &v);
break;
- } // endswitch SQL type
+ } // endswitch SQL type
switch (pcf->Type) {
case TYPE_STRING:
@@ -1638,7 +1669,7 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf)
break;
default:
break;
- } // endswitch type
+ } // endswitch type
if (fp->flags & UNSIGNED_FLAG)
pcf->Flags |= U_UNSIGNED;
@@ -2211,7 +2242,7 @@ int ha_connect::MakeRecord(char *buf)
case TYPE_BIN:
p= value->GetCharValue();
charset= &my_charset_bin;
- rc= fp->store(p, strlen(p), charset, CHECK_FIELD_WARN);
+ rc= fp->store(p, value->GetSize(), charset, CHECK_FIELD_WARN);
break;
case TYPE_DOUBLE:
rc= fp->store(value->GetFloatValue());
@@ -4970,7 +5001,7 @@ int ha_connect::check_stmt(PGLOBAL g, MODE newmode, bool cras)
} // endif CheckCleanup
if (cras)
- g->Createas= 1; // To tell external tables of a multi-table command
+ g->Createas= true; // To tell external tables of a multi-table command
if (trace(1))
htrc("Calling CntCheckDB db=%s cras=%d\n", GetDBName(NULL), cras);
@@ -5320,91 +5351,100 @@ static char *encode(PGLOBAL g, const char *cnm)
@return
Return 0 if ok
*/
-static bool add_field(String *sql, const char *field_name, int typ, int len,
- int dec, char *key, uint tm, const char *rem, char *dft,
- char *xtra, char *fmt, int flag, bool dbf, char v)
-{
- char var= (len > 255) ? 'V' : v;
- bool q, error= false;
- const char *type= PLGtoMYSQLtype(typ, dbf, var);
+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);
- error|= sql->append('`');
- error|= sql->append(field_name);
- error|= sql->append("` ");
- error|= sql->append(type);
+ error |= sql->append('`');
+ error |= sql->append(field_name);
+ error |= sql->append("` ");
+ error |= sql->append(type);
- if (typ == TYPE_STRING ||
- (len && typ != TYPE_DATE && (typ != TYPE_DOUBLE || dec >= 0))) {
- error|= sql->append('(');
- error|= sql->append_ulonglong(len);
+ if (typ == TYPE_STRING ||
+ (len && typ != TYPE_DATE && (typ != TYPE_DOUBLE || dec >= 0))) {
+ error |= sql->append('(');
+ error |= sql->append_ulonglong(len);
if (typ == TYPE_DOUBLE) {
- error|= sql->append(',');
- // dec must be < len and < 31
- error|= sql->append_ulonglong(MY_MIN(dec, (MY_MIN(len, 31) - 1)));
- } else if (dec > 0 && !strcmp(type, "DECIMAL")) {
- error|= sql->append(',');
- // dec must be < len
- error|= sql->append_ulonglong(MY_MIN(dec, len - 1));
- } // endif dec
-
- error|= sql->append(')');
- } // endif len
-
- if (v == 'U')
- error|= sql->append(" UNSIGNED");
- else if (v == 'Z')
- error|= sql->append(" ZEROFILL");
-
- if (key && *key) {
- error|= sql->append(" ");
- error|= sql->append(key);
- } // endif key
-
- if (tm)
- error|= sql->append(STRING_WITH_LEN(" NOT NULL"), system_charset_info);
-
- if (dft && *dft) {
- error|= sql->append(" DEFAULT ");
-
- if (typ == TYPE_DATE)
- q= (strspn(dft, "0123456789 -:/") == strlen(dft));
- else
- q= !IsTypeNum(typ);
+ error |= sql->append(',');
+ // dec must be < len and < 31
+ error |= sql->append_ulonglong(MY_MIN(dec, (MY_MIN(len, 31) - 1)));
+ } else if (dec > 0 && !strcmp(type, "DECIMAL")) {
+ error |= sql->append(',');
+ // dec must be < len
+ error |= sql->append_ulonglong(MY_MIN(dec, len - 1));
+ } // endif dec
+
+ error |= sql->append(')');
+ } // endif len
+
+ if (v == 'U')
+ error |= sql->append(" UNSIGNED");
+ else if (v == 'Z')
+ error |= sql->append(" ZEROFILL");
+
+ if (key && *key) {
+ error |= sql->append(" ");
+ error |= sql->append(key);
+ } // endif key
+
+ if (tm)
+ error |= sql->append(STRING_WITH_LEN(" NOT NULL"), system_charset_info);
+
+ if (dft && *dft) {
+ error |= sql->append(" DEFAULT ");
+
+ if (typ == TYPE_DATE)
+ q = (strspn(dft, "0123456789 -:/") == strlen(dft));
+ else
+ q = !IsTypeNum(typ);
- if (q) {
- error|= sql->append("'");
- error|= sql->append_for_single_quote(dft, strlen(dft));
- error|= sql->append("'");
- } else
- error|= sql->append(dft);
-
- } // endif dft
-
- if (xtra && *xtra) {
- error|= sql->append(" ");
- error|= sql->append(xtra);
- } // endif rem
-
- if (rem && *rem) {
- error|= sql->append(" COMMENT '");
- error|= sql->append_for_single_quote(rem, strlen(rem));
- error|= sql->append("'");
- } // endif rem
-
- if (fmt && *fmt) {
- error|= sql->append(" FIELD_FORMAT='");
- error|= sql->append_for_single_quote(fmt, strlen(fmt));
- error|= sql->append("'");
- } // endif flag
-
- if (flag) {
- error|= sql->append(" FLAG=");
- error|= sql->append_ulonglong(flag);
- } // endif flag
-
- error|= sql->append(',');
- return error;
+ if (q) {
+ error |= sql->append("'");
+ error |= sql->append_for_single_quote(dft, strlen(dft));
+ error |= sql->append("'");
+ } else
+ error |= sql->append(dft);
+
+ } // endif dft
+
+ if (xtra && *xtra) {
+ error |= sql->append(" ");
+ error |= sql->append(xtra);
+ } // endif rem
+
+ if (rem && *rem) {
+ error |= sql->append(" COMMENT '");
+ error |= sql->append_for_single_quote(rem, strlen(rem));
+ error |= sql->append("'");
+ } // endif rem
+
+ if (fmt && *fmt) {
+ switch (ttp) {
+ case TAB_JSON: error |= sql->append(" JPATH='"); break;
+ case TAB_XML: error |= sql->append(" XPATH='"); break;
+ default: error |= sql->append(" FIELD_FORMAT='");
+ } // endswitch ttp
+
+ error |= sql->append_for_single_quote(fmt, strlen(fmt));
+ error |= sql->append("'");
+ } // endif flag
+
+ if (flag) {
+ error |= sql->append(" FLAG=");
+ error |= sql->append_ulonglong(flag);
+ } // endif flag
+
+ error |= sql->append(',');
+ return error;
} // end of add_field
/**
@@ -6026,7 +6066,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
len= 256; // STRBLK's have 0 length
// Now add the field
- if (add_field(&sql, cnm, typ, len, dec, NULL, tm,
+ if (add_field(&sql, ttp, cnm, typ, len, dec, NULL, tm,
NULL, NULL, NULL, NULL, flg, dbf, v))
rc= HA_ERR_OUT_OF_MEM;
} // endfor crp
@@ -6220,7 +6260,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
prec= 0;
// Now add the field
- if (add_field(&sql, cnm, typ, prec, dec, key, tm, rem, dft, xtra,
+ if (add_field(&sql, ttp, cnm, typ, prec, dec, key, tm, rem, dft, xtra,
fmt, flg, dbf, v))
rc= HA_ERR_OUT_OF_MEM;
} // endfor i
@@ -6973,7 +7013,7 @@ bool ha_connect::NoFieldOptionChange(TABLE *tab)
fop1->fldlen == fop2->fldlen &&
CheckString(fop1->dateformat, fop2->dateformat) &&
CheckString(fop1->fieldformat, fop2->fieldformat) &&
- CheckString(fop1->special, fop2->special));
+ CheckString(fop1->special, fop2->special));
} // endfor fld
return rc;
@@ -7345,7 +7385,9 @@ static struct st_mysql_sys_var* connect_system_variables[]= {
MYSQL_SYSVAR(errmsg_dir_path),
#endif // XMSG
MYSQL_SYSVAR(json_null),
- MYSQL_SYSVAR(json_grp_size),
+ MYSQL_SYSVAR(json_all_path),
+ MYSQL_SYSVAR(default_depth),
+ MYSQL_SYSVAR(json_grp_size),
#if defined(JAVA_SUPPORT)
MYSQL_SYSVAR(jvm_path),
MYSQL_SYSVAR(class_path),
@@ -7371,7 +7413,7 @@ maria_declare_plugin(connect)
0x0107, /* version number (1.07) */
NULL, /* status variables */
connect_system_variables, /* system variables */
- "1.07.0001", /* string version */
+ "1.07.0002", /* string version */
MariaDB_PLUGIN_MATURITY_STABLE /* maturity */
}
maria_declare_plugin_end;
diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h
index 3e4474d140e..b7090be8b27 100644
--- a/storage/connect/ha_connect.h
+++ b/storage/connect/ha_connect.h
@@ -104,7 +104,9 @@ struct ha_field_option_struct
uint opt;
const char *dateformat;
const char *fieldformat;
- char *special;
+ const char* jsonpath;
+ const char* xmlpath;
+ char *special;
};
/*
diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp
index 98a4659cea8..ea3ea18da0b 100644
--- a/storage/connect/json.cpp
+++ b/storage/connect/json.cpp
@@ -93,9 +93,8 @@ char *NextChr(PSZ s, char sep)
PJSON ParseJson(PGLOBAL g, char *s, int len, int *ptyp, bool *comma)
{
int i, pretty = (ptyp) ? *ptyp : 3;
- bool b = false, pty[3] = {true, true, true};
- PJSON jsp = NULL;
- STRG src;
+ bool b = false, pty[3] = {true,true,true};
+ PJSON jsp = NULL, jp = NULL;
if (trace(1))
htrc("ParseJson: s=%.10s len=%d\n", s, len);
@@ -106,27 +105,29 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int *ptyp, bool *comma)
} else if (comma)
*comma = false;
- src.str = s;
- src.len = len;
-
// Trying to guess the pretty format
if (s[0] == '[' && (s[1] == '\n' || (s[1] == '\r' && s[2] == '\n')))
pty[0] = false;
try {
- for (i = 0; i < len; i++)
+ jp = new(g) JSON();
+ jp->s = s;
+ jp->len = len;
+ jp->pty = pty;
+
+ for (i = 0; i < jp->len; i++)
switch (s[i]) {
case '[':
if (jsp)
- goto tryit;
- else if (!(jsp = ParseArray(g, ++i, src, pty)))
- throw 1;
+ jsp = jp->ParseAsArray(g, i, pretty, ptyp);
+ else
+ jsp = jp->ParseArray(g, ++i);
break;
case '{':
if (jsp)
- goto tryit;
- else if (!(jsp = ParseObject(g, ++i, src, pty)))
+ jsp = jp->ParseAsArray(g, i, pretty, ptyp);
+ else if (!(jsp = jp->ParseObject(g, ++i)))
throw 2;
break;
@@ -157,8 +158,8 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int *ptyp, bool *comma)
default:
if (jsp)
- goto tryit;
- else if (!(jsp = ParseValue(g, i, src, pty)))
+ jsp = jp->ParseAsArray(g, i, pretty, ptyp);
+ else if (!(jsp = jp->ParseValue(g, i)))
throw 4;
break;
@@ -187,10 +188,17 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int *ptyp, bool *comma)
} // end catch
return jsp;
+} // end of ParseJson
-tryit:
+/***********************************************************************/
+/* Parse several items as being in an array. */
+/***********************************************************************/
+PJAR JSON::ParseAsArray(PGLOBAL g, int& i, int pretty, int *ptyp)
+{
if (pty[0] && (!pretty || pretty > 2)) {
- if ((jsp = ParseArray(g, (i = 0), src, pty)) && ptyp && pretty == 3)
+ PJAR jsp;
+
+ if ((jsp = ParseArray(g, (i = 0))) && ptyp && pretty == 3)
*ptyp = (pty[0]) ? 0 : 3;
return jsp;
@@ -198,26 +206,23 @@ tryit:
strcpy(g->Message, "More than one item in file");
return NULL;
-} // end of ParseJson
+} // end of ParseAsArray
/***********************************************************************/
/* Parse a JSON Array. */
/***********************************************************************/
-PJAR ParseArray(PGLOBAL g, int& i, STRG& src, bool *pty)
+PJAR JSON::ParseArray(PGLOBAL g, int& i)
{
- char *s = src.str;
- int len = src.len;
- int level = 0;
- bool b = (!i);
- PJAR jarp = new(g) JARRAY;
- PJVAL jvp = NULL;
+ int level = 0;
+ bool b = (!i);
+ PJAR jarp = new(g) JARRAY;
for (; i < len; i++)
switch (s[i]) {
case ',':
if (level < 2) {
sprintf(g->Message, "Unexpected ',' near %.*s",ARGS);
- return NULL;
+ throw 1;
} else
level = 1;
@@ -225,8 +230,8 @@ PJAR ParseArray(PGLOBAL g, int& i, STRG& src, bool *pty)
case ']':
if (level == 1) {
sprintf(g->Message, "Unexpected ',]' near %.*s", ARGS);
- return NULL;
- } // endif level
+ throw 1;
+ } // endif level
jarp->InitArray(g);
return jarp;
@@ -240,11 +245,9 @@ PJAR ParseArray(PGLOBAL g, int& i, STRG& src, bool *pty)
default:
if (level == 2) {
sprintf(g->Message, "Unexpected value near %.*s", ARGS);
- return NULL;
- } else if ((jvp = ParseValue(g, i, src, pty)))
- jarp->AddValue(g, jvp);
- else
- return NULL;
+ throw 1;
+ } else
+ jarp->AddValue(g, ParseValue(g, i));
level = (b) ? 1 : 2;
break;
@@ -256,18 +259,15 @@ PJAR ParseArray(PGLOBAL g, int& i, STRG& src, bool *pty)
return jarp;
} // endif b
- strcpy(g->Message, "Unexpected EOF in array");
- return NULL;
+ throw ("Unexpected EOF in array");
} // end of ParseArray
/***********************************************************************/
/* Parse a JSON Object. */
/***********************************************************************/
-PJOB ParseObject(PGLOBAL g, int& i, STRG& src, bool *pty)
+PJOB JSON::ParseObject(PGLOBAL g, int& i)
{
PSZ key;
- char *s = src.str;
- int len = src.len;
int level = 0;
PJOB jobp = new(g) JOBJECT;
PJPR jpp = NULL;
@@ -276,42 +276,37 @@ PJOB ParseObject(PGLOBAL g, int& i, STRG& src, bool *pty)
switch (s[i]) {
case '"':
if (level < 2) {
- if ((key = ParseString(g, ++i, src))) {
- jpp = jobp->AddPair(g, key);
- level = 1;
- } else
- return NULL;
-
+ key = ParseString(g, ++i);
+ jpp = jobp->AddPair(g, key);
+ level = 1;
} else {
sprintf(g->Message, "misplaced string near %.*s", ARGS);
- return NULL;
+ throw 2;
} // endif level
break;
case ':':
if (level == 1) {
- if (!(jpp->Val = ParseValue(g, ++i, src, pty)))
- return NULL;
-
+ jpp->Val = ParseValue(g, ++i);
level = 2;
} else {
sprintf(g->Message, "Unexpected ':' near %.*s", ARGS);
- return NULL;
+ throw 2;
} // endif level
break;
case ',':
if (level < 2) {
sprintf(g->Message, "Unexpected ',' near %.*s", ARGS);
- return NULL;
+ throw 2;
} else
- level = 1;
+ level = 0;
break;
case '}':
- if (level == 1) {
+ if (level < 2) {
sprintf(g->Message, "Unexpected '}' near %.*s", ARGS);
- return NULL;
+ throw 2;
} // endif level
return jobp;
@@ -324,20 +319,19 @@ PJOB ParseObject(PGLOBAL g, int& i, STRG& src, bool *pty)
default:
sprintf(g->Message, "Unexpected character '%c' near %.*s",
s[i], ARGS);
- return NULL;
+ throw 2;
}; // endswitch s[i]
strcpy(g->Message, "Unexpected EOF in Object");
- return NULL;
+ throw 2;
} // end of ParseObject
/***********************************************************************/
/* Parse a JSON Value. */
/***********************************************************************/
-PJVAL ParseValue(PGLOBAL g, int& i, STRG& src, bool *pty)
+PJVAL JSON::ParseValue(PGLOBAL g, int& i)
{
- char *strval, *s = src.str;
- int n, len = src.len;
+ int n;
PJVAL jvp = new(g) JVALUE;
for (; i < len; i++)
@@ -355,21 +349,13 @@ PJVAL ParseValue(PGLOBAL g, int& i, STRG& src, bool *pty)
suite:
switch (s[i]) {
case '[':
- if (!(jvp->Jsp = ParseArray(g, ++i, src, pty)))
- return NULL;
-
+ jvp->Jsp = ParseArray(g, ++i);
break;
case '{':
- if (!(jvp->Jsp = ParseObject(g, ++i, src, pty)))
- return NULL;
-
+ jvp->Jsp = ParseObject(g, ++i);
break;
case '"':
- if ((strval = ParseString(g, ++i, src)))
- jvp->Value = AllocateValue(g, strval, TYPE_STRING);
- else
- return NULL;
-
+ jvp->Value = AllocateValue(g, ParseString(g, ++i), TYPE_STRING);
break;
case 't':
if (!strncmp(s + i, "true", 4)) {
@@ -398,11 +384,9 @@ PJVAL ParseValue(PGLOBAL g, int& i, STRG& src, bool *pty)
break;
case '-':
default:
- if (s[i] == '-' || isdigit(s[i])) {
- if (!(jvp->Value = ParseNumeric(g, i, src)))
- goto err;
-
- } else
+ if (s[i] == '-' || isdigit(s[i]))
+ jvp->Value = ParseNumeric(g, i);
+ else
goto err;
}; // endswitch s[i]
@@ -410,25 +394,21 @@ PJVAL ParseValue(PGLOBAL g, int& i, STRG& src, bool *pty)
return jvp;
err:
- sprintf(g->Message, "Unexpected character '%c' near %.*s",
- s[i], ARGS);
- return NULL;
+ sprintf(g->Message, "Unexpected character '%c' near %.*s", s[i], ARGS);
+ throw 3;
} // end of ParseValue
/***********************************************************************/
/* Unescape and parse a JSON string. */
/***********************************************************************/
-char *ParseString(PGLOBAL g, int& i, STRG& src)
+char *JSON::ParseString(PGLOBAL g, int& i)
{
- char *s = src.str;
uchar *p;
- int n = 0, len = src.len;
+ int n = 0;
// Be sure of memory availability
- if (len + 1 - i > (signed)((PPOOLHEADER)g->Sarea)->FreeBlk) {
- strcpy(g->Message, "ParseString: Out of memory");
- return NULL;
- } // endif len
+ if (((size_t)len + 1 - i) > ((PPOOLHEADER)g->Sarea)->FreeBlk)
+ throw("ParseString: Out of memory");
// The size to allocate is not known yet
p = (uchar*)PlugSubAlloc(g, NULL, 0);
@@ -502,17 +482,16 @@ char *ParseString(PGLOBAL g, int& i, STRG& src)
}; // endswitch s[i]
err:
- strcpy(g->Message, "Unexpected EOF in String");
- return NULL;
+ throw("Unexpected EOF in String");
} // end of ParseString
/***********************************************************************/
/* Parse a JSON numeric value. */
/***********************************************************************/
-PVAL ParseNumeric(PGLOBAL g, int& i, STRG& src)
+PVAL JSON::ParseNumeric(PGLOBAL g, int& i)
{
- char *s = src.str, buf[50];
- int n = 0, len = src.len;
+ char buf[50];
+ int n = 0;
short nd = 0;
bool has_dot = false;
bool has_e = false;
@@ -575,14 +554,11 @@ PVAL ParseNumeric(PGLOBAL g, int& i, STRG& src)
i--; // Unstack following character
return valp;
- } else {
- strcpy(g->Message, "No digit found");
- return NULL;
- } // endif found_digit
+ } else
+ throw("No digit found");
err:
- strcpy(g->Message, "Unexpected EOF in number");
- return NULL;
+ throw("Unexpected EOF in number");
} // end of ParseNumeric
/***********************************************************************/
diff --git a/storage/connect/json.h b/storage/connect/json.h
index 1d058ad575f..bc94b372133 100644
--- a/storage/connect/json.h
+++ b/storage/connect/json.h
@@ -1,10 +1,11 @@
/**************** json H Declares Source Code File (.H) ****************/
/* Name: json.h Version 1.2 */
/* */
-/* (C) Copyright to the author Olivier BERTRAND 2014 - 2017 */
+/* (C) Copyright to the author Olivier BERTRAND 2014 - 2020 */
/* */
/* This file contains the JSON classes declares. */
/***********************************************************************/
+#include <mysql_com.h>
#include "value.h"
#if defined(_DEBUG)
@@ -44,15 +45,31 @@ typedef struct {
int len;
} STRG, *PSG;
+// BSON size should be equal on Linux and Windows
+#define BMX 255
+typedef struct BSON* PBSON;
+
+/***********************************************************************/
+/* Structure used to return binary json to Json UDF functions. */
+/***********************************************************************/
+struct BSON {
+ char Msg[BMX + 1];
+ char *Filename;
+ PGLOBAL G;
+ int Pretty;
+ ulong Reslen;
+ my_bool Changed;
+ PJSON Top;
+ PJSON Jsp;
+ PBSON Bsp;
+}; // end of struct BSON
+
+PBSON JbinAlloc(PGLOBAL g, UDF_ARGS* args, ulong len, PJSON jsp);
+
char *NextChr(PSZ s, char sep);
char *GetJsonNull(void);
-PJSON ParseJson(PGLOBAL g, char *s, int n, int *prty = NULL, bool *b = NULL);
-PJAR ParseArray(PGLOBAL g, int& i, STRG& src, bool *pty);
-PJOB ParseObject(PGLOBAL g, int& i, STRG& src, bool *pty);
-PJVAL ParseValue(PGLOBAL g, int& i, STRG& src, bool *pty);
-char *ParseString(PGLOBAL g, int& i, STRG& src);
-PVAL ParseNumeric(PGLOBAL g, int& i, STRG& src);
+PJSON ParseJson(PGLOBAL g, char* s, int n, int* prty = NULL, bool* b = NULL);
PSZ Serialize(PGLOBAL g, PJSON jsp, char *fn, int pretty);
bool SerializeArray(JOUT *js, PJAR jarp, bool b);
bool SerializeObject(JOUT *js, PJOB jobp);
@@ -130,7 +147,7 @@ class JOUTPRT : public JOUTFILE {
class JPAIR : public BLOCK {
friend class JOBJECT;
friend class JSNX;
- friend PJOB ParseObject(PGLOBAL, int&, STRG&, bool*);
+ friend class JSON;
friend bool SerializeObject(JOUT *, PJOB);
public:
JPAIR(PCSZ key) : BLOCK() {Key = key; Val = NULL; Next = NULL;}
@@ -149,8 +166,9 @@ class JPAIR : public BLOCK {
/* Class JSON. The base class for all other json classes. */
/***********************************************************************/
class JSON : public BLOCK {
+ friend PJSON ParseJson(PGLOBAL, char*, int, int*, bool*);
public:
- JSON(void) {Size = 0;}
+ JSON(void) : s(NULL), len(0), pty(NULL) {Size = 0;}
int size(void) {return Size;}
virtual int GetSize(bool b) {return Size;}
@@ -187,14 +205,27 @@ class JSON : public BLOCK {
virtual bool IsNull(void) {X return true;}
protected:
- int Size;
+ PJAR ParseArray(PGLOBAL g, int& i);
+ PJOB ParseObject(PGLOBAL g, int& i);
+ PJVAL ParseValue(PGLOBAL g, int& i);
+ char *ParseString(PGLOBAL g, int& i);
+ PVAL ParseNumeric(PGLOBAL g, int& i);
+ PJAR ParseAsArray(PGLOBAL g, int& i, int pretty, int *ptyp);
+
+ // Members
+ int Size;
+
+ // Only used when parsing
+ private:
+ char *s;
+ int len;
+ bool *pty;
}; // end of class JSON
/***********************************************************************/
/* Class JOBJECT: contains a list of value pairs. */
/***********************************************************************/
class JOBJECT : public JSON {
- friend PJOB ParseObject(PGLOBAL, int&, STRG&, bool*);
friend bool SerializeObject(JOUT *, PJOB);
friend class JSNX;
public:
@@ -260,8 +291,8 @@ class JVALUE : public JSON {
friend class JARRAY;
friend class JSNX;
friend class JSONCOL;
- friend PJVAL ParseValue(PGLOBAL, int&, STRG&, bool*);
- friend bool SerializeValue(JOUT *, PJVAL);
+ friend class JSON;
+ friend bool SerializeValue(JOUT*, PJVAL);
public:
JVALUE(void) : JSON() {Clear();}
JVALUE(PJSON jsp);
diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp
index d5bd1215e77..f16aaa80803 100644
--- a/storage/connect/jsonudf.cpp
+++ b/storage/connect/jsonudf.cpp
@@ -25,7 +25,7 @@
#else
#define PUSH_WARNING(M) htrc(M)
#endif
-#define M 7
+#define M 9
bool IsNum(PSZ s);
char *NextChr(PSZ s, char sep);
@@ -1076,29 +1076,10 @@ my_bool JSNX::AddPath(void)
/* --------------------------------- JSON UDF ---------------------------------- */
-// BSON size should be equal on Linux and Windows
-#define BMX 255
-typedef struct BSON *PBSON;
-
-/*********************************************************************************/
-/* Structure used to return binary json. */
-/*********************************************************************************/
-struct BSON {
- char Msg[BMX + 1];
- char *Filename;
- PGLOBAL G;
- int Pretty;
- ulong Reslen;
- my_bool Changed;
- PJSON Top;
- PJSON Jsp;
- PBSON Bsp;
-}; // end of struct BSON
-
/*********************************************************************************/
/* Allocate and initialize a BSON structure. */
/*********************************************************************************/
-static PBSON JbinAlloc(PGLOBAL g, UDF_ARGS *args, ulong len, PJSON jsp)
+PBSON JbinAlloc(PGLOBAL g, UDF_ARGS *args, ulong len, PJSON jsp)
{
PBSON bsp = (PBSON)PlgDBSubAlloc(g, NULL, sizeof(BSON));
@@ -1111,7 +1092,7 @@ static PBSON JbinAlloc(PGLOBAL g, UDF_ARGS *args, ulong len, PJSON jsp)
bsp->Reslen = len;
bsp->Changed = false;
bsp->Top = bsp->Jsp = jsp;
- bsp->Bsp = (IsJson(args, 0) == 3) ? (PBSON)args->args[0] : NULL;
+ bsp->Bsp = (args && IsJson(args, 0) == 3) ? (PBSON)args->args[0] : NULL;
} else
PUSH_WARNING(g->Message);
@@ -1144,7 +1125,7 @@ static my_bool JsonSubSet(PGLOBAL g)
{
PPOOLHEADER pph = (PPOOLHEADER)g->Sarea;
- pph->To_Free = (OFFSET)((g->Createas) ? g->Createas : sizeof(POOLHEADER));
+ pph->To_Free = (g->Saved_Size) ? g->Saved_Size : (size_t)sizeof(POOLHEADER);
pph->FreeBlk = g->Sarea_Size - pph->To_Free;
return FALSE;
} /* end of JsonSubSet */
@@ -1154,7 +1135,7 @@ static my_bool JsonSubSet(PGLOBAL g)
/*********************************************************************************/
inline void JsonMemSave(PGLOBAL g)
{
- g->Createas = (int)((PPOOLHEADER)g->Sarea)->To_Free;
+ g->Saved_Size = ((PPOOLHEADER)g->Sarea)->To_Free;
} /* end of JsonMemSave */
/*********************************************************************************/
@@ -1422,7 +1403,7 @@ static int IsJson(UDF_ARGS *args, uint i, bool b)
n = 2; // arg is a json file name
} else if (b) {
char *sap;
- PGLOBAL g = PlugInit(NULL, args->lengths[i] * M + 1024);
+ PGLOBAL g = PlugInit(NULL, (size_t)args->lengths[i] * M + 1024);
JsonSubSet(g);
sap = MakePSZ(g, args, i);
@@ -1625,7 +1606,7 @@ static my_bool CheckMemory(PGLOBAL g, UDF_INIT *initid, UDF_ARGS *args, uint n,
return true;
} // endif SareaAlloc
- g->Createas = 0;
+ g->Saved_Size = 0;
g->Xchk = NULL;
initid->max_length = rl;
} // endif Size
@@ -4423,13 +4404,15 @@ char *json_file(UDF_INIT *initid, UDF_ARGS *args, char *result,
fn = MakePSZ(g, args, 0);
if (args->arg_count > 1) {
- int len, pretty, pty = 3;
+ int len, pretty = 3, pty = 3;
PJSON jsp;
PJVAL jvp = NULL;
- pretty = (args->arg_type[1] == INT_RESULT) ? (int)*(longlong*)args->args[1]
- : (args->arg_count > 2 && args->arg_type[2] == INT_RESULT)
- ? (int)*(longlong*)args->args[2] : 3;
+ for (unsigned int i = 1; i < args->arg_count; i++)
+ if (args->arg_type[i] == INT_RESULT && *(longlong*)args->args[i] < 4) {
+ pretty = (int) * (longlong*)args->args[i];
+ break;
+ } // endif type
/*******************************************************************************/
/* Parse the json file and allocate its tree structure. */
@@ -4497,6 +4480,7 @@ my_bool jfile_make_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
} // endif
CalcLen(args, false, reslen, memlen);
+ memlen = memlen + 5000; // To take care of not pretty files
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of jfile_make_init
@@ -5626,20 +5610,19 @@ my_bool jbin_file_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
} else if (args->arg_type[0] != STRING_RESULT || !args->args[0]) {
strcpy(message, "First argument must be a constant string (file name)");
return true;
- } else if (args->arg_count > 1 && args->arg_type[1] != STRING_RESULT) {
- strcpy(message, "Second argument is not a string (path)");
- return true;
- } else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
- strcpy(message, "Third argument is not an integer (pretty)");
- return true;
- } else if (args->arg_count > 3) {
- if (args->arg_type[3] != INT_RESULT) {
- strcpy(message, "Fourth argument is not an integer (memory)");
+ } // endifs
+
+ for (unsigned int i = 1; i < args->arg_count; i++) {
+ if (!(args->arg_type[i] == INT_RESULT || args->arg_type[i] == STRING_RESULT)) {
+ sprintf(message, "Argument %d is not an integer or a string (pretty or path)", i);
return true;
- } else
- more += (ulong)*(longlong*)args->args[3];
+ } // endif arg_type
- } // endifs
+ // Take care of eventual memory argument
+ if (args->arg_type[i] == INT_RESULT && args->args[i])
+ more += (ulong) * (longlong*)args->args[i];
+
+ } // endfor i
initid->maybe_null = 1;
CalcLen(args, false, reslen, memlen);
@@ -5654,7 +5637,7 @@ char *jbin_file(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *fn;
- int pretty, len = 0, pty = 3;
+ int pretty = 3, len = 0, pty = 3;
PJSON jsp;
PJVAL jvp = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
@@ -5666,7 +5649,12 @@ char *jbin_file(UDF_INIT *initid, UDF_ARGS *args, char *result,
PlugSubSet(g->Sarea, g->Sarea_Size);
g->Xchk = NULL;
fn = MakePSZ(g, args, 0);
- pretty = (args->arg_count > 2 && args->args[2]) ? (int)*(longlong*)args->args[2] : 3;
+
+ for (unsigned int i = 1; i < args->arg_count; i++)
+ if (args->arg_type[i] == INT_RESULT && *(longlong*)args->args[i] < 4) {
+ pretty = (int) * (longlong*)args->args[i];
+ break;
+ } // endif type
/*********************************************************************************/
/* Parse the json file and allocate its tree structure. */
@@ -5757,7 +5745,7 @@ char *json_serialize(UDF_INIT *initid, UDF_ARGS *args, char *result,
// Keep result of constant function
g->Xchk = (initid->const_item) ? str : NULL;
} else {
- *error = 1;
+ // *error = 1;
str = strcpy(result, "Argument is not a Jbin tree");
} // endif
@@ -5774,6 +5762,478 @@ void json_serialize_deinit(UDF_INIT* initid)
} // end of json_serialize_deinit
/*********************************************************************************/
+/* Convert a prettiest Json file to Pretty=0. */
+/*********************************************************************************/
+my_bool jfile_convert_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
+ unsigned long reslen, memlen;
+
+ if (args->arg_count != 3) {
+ strcpy(message, "This function must have 3 arguments");
+ return true;
+ } else if (args->arg_type[2] != INT_RESULT) {
+ strcpy(message, "Third Argument must be an integer (LRECL)");
+ return true;
+ } else for (int i = 0; i < 2; i++)
+ if (args->arg_type[i] != STRING_RESULT) {
+ sprintf(message, "Arguments %d must be a string (file name)", i+1);
+ return true;
+ } // endif args
+
+ CalcLen(args, false, reslen, memlen);
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of jfile_convert_init
+
+char *jfile_convert(UDF_INIT* initid, UDF_ARGS* args, char* result,
+ unsigned long *res_length, char *, char *error) {
+ char *str, *fn, *ofn;
+ int lrecl = (int)*(longlong*)args->args[2];
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ PlugSubSet(g->Sarea, g->Sarea_Size);
+ fn = MakePSZ(g, args, 0);
+ ofn = MakePSZ(g, args, 1);
+
+ if (!g->Xchk) {
+ JUP* jup = new(g) JUP(g);
+
+ str = jup->UnprettyJsonFile(g, fn, ofn, lrecl);
+ g->Xchk = str;
+ } else
+ str = (char*)g->Xchk;
+
+ if (!str) {
+ if (g->Message)
+ str = PlugDup(g, g->Message);
+ else
+ str = PlugDup(g, "Unexpected error");
+
+ } // endif str
+
+ *res_length = strlen(str);
+ return str;
+} // end of jfile_convert
+
+void jfile_convert_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jfile_convert_deinit
+
+/* --------------------------------- Class JUP --------------------------------- */
+
+#define ARGS MY_MIN(24,len-i),s+MY_MAX(i-3,0)
+
+/*********************************************************************************/
+/* JUP public constructor. */
+/*********************************************************************************/
+JUP::JUP(PGLOBAL g) {
+ fs = NULL;
+ s = buff = NULL;
+ i = k = len = recl = 0;
+} // end of JUP constructor
+
+/*********************************************************************************/
+/* Copy a json file to another with pretty = 0. */
+/*********************************************************************************/
+char* JUP::UnprettyJsonFile(PGLOBAL g, char *fn, char *outfn, int lrecl) {
+ char *ret = NULL;
+ HANDLE hFile;
+ MEMMAP mm;
+
+ /*******************************************************************************/
+ /* Create the mapping file object. */
+ /*******************************************************************************/
+ hFile = CreateFileMap(g, fn, &mm, MODE_READ, false);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ DWORD rc = GetLastError();
+
+ if (!(*g->Message))
+ sprintf(g->Message, MSG(OPEN_MODE_ERROR), "map", (int)rc, fn);
+
+ return NULL;
+ } // endif hFile
+
+ /*******************************************************************************/
+ /* Get the file size (assuming file is smaller than 4 GB) */
+ /*******************************************************************************/
+ if (!mm.lenL) { // Empty or deleted file
+ CloseFileHandle(hFile);
+ return NULL;
+ } else
+ len = (int)mm.lenL;
+
+ if (!mm.memory) {
+ CloseFileHandle(hFile);
+ sprintf(g->Message, MSG(MAP_VIEW_ERROR), fn, GetLastError());
+ return NULL;
+ } else
+ s = (char*)mm.memory;
+
+ CloseFileHandle(hFile); // Not used anymore
+
+ /*********************************************************************************/
+ /* Parse the json file and allocate its tree structure. */
+ /*********************************************************************************/
+ if (!(fs = fopen(outfn, "wb"))) {
+ sprintf(g->Message, MSG(OPEN_MODE_ERROR),
+ "w", (int)errno, outfn);
+ strcat(strcat(g->Message, ": "), strerror(errno));
+ CloseMemMap(mm.memory, (size_t)mm.lenL);
+ return NULL;
+ } // endif fs
+
+ g->Message[0] = 0;
+
+ if (!unPretty(g, lrecl))
+ ret = outfn;
+
+ CloseMemMap(mm.memory, (size_t)mm.lenL);
+ fclose(fs);
+ return ret;
+} // end of UnprettyJsonFile
+
+/***********************************************************************/
+/* Translate a json file to pretty = 0. */
+/***********************************************************************/
+bool JUP::unPretty(PGLOBAL g, int lrecl) {
+ bool go, next, rc = false;
+
+ if (trace(1))
+ htrc("UnPretty: s=%.10s len=%zd lrecl=%d\n", s, len, lrecl);
+
+ if (!s || !len) {
+ strcpy(g->Message, "Void JSON file");
+ return true;
+ } else if (*s != '[') {
+ // strcpy(g->Message, "JSON file is not an array");
+ s = strchr(s, '[');
+ // return true;
+ } // endif s
+
+ i = 1;
+ go = next = true;
+
+ try {
+ // Allocate the record
+ buff = (char*)PlugSubAlloc(g, NULL, (size_t)lrecl + 3);
+ recl = lrecl;
+
+ do {
+ for (k = 0; go && i < len; i++)
+ switch (s[i]) {
+ case '{':
+ buff[k++] = s[i++];
+ CopyObject(g);
+ break;
+ case '[':
+ throw "JSON file is not an array of objects";
+ break;
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ break;
+ case ',':
+ go = false;
+ break;
+ case ']':
+ go = next = false;
+ break;
+ default:
+ sprintf(g->Message, "Unexpected '%c' near %.*s", s[i], ARGS);
+ throw 4;
+ break;
+ }; // endswitch s[i]
+
+ // Write the record
+#ifdef __win_
+ buff[k++] = '\r';
+#endif
+ buff[k++] = '\n';
+ buff[k] = 0;
+
+ if ((fputs(buff, fs)) == EOF) {
+ sprintf(g->Message, MSG(FPUTS_ERROR), strerror(errno));
+ throw 5;
+ } // endif EOF
+
+ go = true;
+ } while (next);
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ rc = true;
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ rc = true;
+ } // end catch
+
+ return rc;
+} // end of unPretty
+
+/***********************************************************************/
+/* Copy a JSON Object. */
+/***********************************************************************/
+void JUP::CopyObject(PGLOBAL g) {
+ int level = 0;
+
+ for (; i < len; i++)
+ switch (s[i]) {
+ case '"':
+ AddBuff(s[i++]);
+
+ if (level < 2) {
+ CopyString(g);
+ level = 1;
+ } else {
+ sprintf(g->Message, "misplaced string near %.*s", ARGS);
+ throw 3;
+ } // endif level
+
+ break;
+ case ':':
+ AddBuff(s[i++]);
+
+ if (level == 1) {
+ CopyValue(g);
+ level = 2;
+ } else {
+ sprintf(g->Message, "Unexpected ':' near %.*s", ARGS);
+ throw 3;
+ } // endif level
+
+ break;
+ case ',':
+ AddBuff(s[i]);
+
+ if (level < 2) {
+ sprintf(g->Message, "Unexpected ',' near %.*s", ARGS);
+ throw 3;
+ } else
+ level = 0;
+
+ break;
+ case '}':
+ AddBuff(s[i]);
+
+ if (level == 1) {
+ sprintf(g->Message, "Unexpected '}' near %.*s", ARGS);
+ throw 3;
+ } // endif level
+
+ return;
+ case '\n':
+ case '\r':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ sprintf(g->Message, "Unexpected character '%c' near %.*s", s[i], ARGS);
+ throw 3;
+ }; // endswitch s[i]
+
+ throw "Unexpected EOF in Object";
+} // end of CopyObject
+
+/***********************************************************************/
+/* Copy a JSON Array. */
+/***********************************************************************/
+void JUP::CopyArray(PGLOBAL g) {
+ int level = 0;
+
+ for (; i < len; i++)
+ switch (s[i]) {
+ case ',':
+ if (level < 2) {
+ sprintf(g->Message, "Unexpected ',' near %.*s", ARGS);
+ throw 2;
+ } else
+ level = 1;
+
+ AddBuff(s[i]);
+ break;
+ case ']':
+ if (level == 1) {
+ sprintf(g->Message, "Unexpected ',]' near %.*s", ARGS);
+ throw 2;
+ } // endif level
+
+ AddBuff(s[i]);
+ return;
+ case '\n':
+ case '\r':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ if (level == 2) {
+ sprintf(g->Message, "Unexpected value near %.*s", ARGS);
+ throw 2;
+ } // endif level
+
+ CopyValue(g);
+ level = 2;
+ break;
+ }; // endswitch s[i]
+
+ throw "Unexpected EOF in array";
+} // end of CopyArray
+
+/***********************************************************************/
+/* Copy a JSON Value. */
+/***********************************************************************/
+void JUP::CopyValue(PGLOBAL g) {
+ for (; i < len; i++)
+ switch (s[i]) {
+ case '\n':
+ case '\r':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ goto suite;
+ } // endswitch
+
+suite:
+ switch (s[i]) {
+ case '[':
+ AddBuff(s[i++]);
+ CopyArray(g);
+ break;
+ case '{':
+ AddBuff(s[i++]);
+ CopyObject(g);
+ break;
+ case '"':
+ AddBuff(s[i++]);
+ CopyString(g);
+ break;
+ case 't':
+ if (!strncmp(s + i, "true", 4)) {
+ AddBuff(s[i++]);
+ AddBuff(s[i++]);
+ AddBuff(s[i++]);
+ AddBuff(s[i]);
+ } else
+ goto err;
+
+ break;
+ case 'f':
+ if (!strncmp(s + i, "false", 5)) {
+ AddBuff(s[i++]);
+ AddBuff(s[i++]);
+ AddBuff(s[i++]);
+ AddBuff(s[i++]);
+ AddBuff(s[i]);
+ } else
+ goto err;
+
+ break;
+ case 'n':
+ if (!strncmp(s + i, "null", 4)) {
+ AddBuff(s[i++]);
+ AddBuff(s[i++]);
+ AddBuff(s[i++]);
+ AddBuff(s[i]);
+ } else
+ goto err;
+
+ break;
+ default:
+ if (s[i] == '-' || isdigit(s[i]))
+ CopyNumeric(g);
+ else
+ goto err;
+
+ }; // endswitch s[i]
+
+ return;
+
+err:
+ sprintf(g->Message, "Unexpected character '%c' near %.*s", s[i], ARGS);
+ throw 1;
+} // end of CopyValue
+
+/***********************************************************************/
+/* Unescape and parse a JSON string. */
+/***********************************************************************/
+void JUP::CopyString(PGLOBAL g) {
+ for (; i < len; i++) {
+ AddBuff(s[i]);
+
+ switch (s[i]) {
+ case '"':
+ return;
+ case '\\':
+ AddBuff(s[++i]);
+ break;
+ default:
+ break;
+ }; // endswitch s[i]
+
+ } // endfor i
+
+ throw "Unexpected EOF in String";
+} // end of CopyString
+
+/***********************************************************************/
+/* Copy a JSON numeric value. */
+/***********************************************************************/
+void JUP::CopyNumeric(PGLOBAL g) {
+ bool has_dot = false;
+ bool has_e = false;
+ bool found_digit = false;
+
+ for (; i < len; i++) {
+ switch (s[i]) {
+ case '.':
+ if (!found_digit || has_dot || has_e)
+ goto err;
+
+ has_dot = true;
+ break;
+ case 'e':
+ case 'E':
+ if (!found_digit || has_e)
+ goto err;
+
+ has_e = true;
+ found_digit = false;
+ break;
+ case '+':
+ if (!has_e)
+ goto err;
+
+ // fall through
+ case '-':
+ if (found_digit)
+ goto err;
+
+ break;
+ default:
+ if (isdigit(s[i])) {
+ found_digit = true;
+ } else
+ goto fin;
+
+ }; // endswitch s[i]
+
+ AddBuff(s[i]);
+ } // endfor i
+
+fin:
+ if (!found_digit)
+ throw "No digit found";
+ else
+ i--;
+
+ return;
+
+err:
+ throw "Unexpected EOF in number";
+} // end of CopyNumeric
+
+/*********************************************************************************/
/* Utility function returning an environment variable value. */
/*********************************************************************************/
my_bool envar_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
diff --git a/storage/connect/jsonudf.h b/storage/connect/jsonudf.h
index ee56869a111..897b0fe9919 100644
--- a/storage/connect/jsonudf.h
+++ b/storage/connect/jsonudf.h
@@ -235,6 +235,10 @@ extern "C" {
DllExport char *json_serialize(UDF_EXEC_ARGS);
DllExport void json_serialize_deinit(UDF_INIT*);
+ DllExport my_bool jfile_convert_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* jfile_convert(UDF_EXEC_ARGS);
+ DllExport void jfile_convert_deinit(UDF_INIT*);
+
DllExport my_bool envar_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *envar(UDF_EXEC_ARGS);
@@ -324,3 +328,38 @@ protected:
my_bool Wr; // Write mode
my_bool Jb; // Must return json item
}; // end of class JSNX
+
+/*********************************************************************************/
+/* Class JUP: used by jfile_convert to make a json file pretty = 0. */
+/*********************************************************************************/
+class JUP : public BLOCK {
+public:
+ // Constructor
+ JUP(PGLOBAL g);
+
+ // Implementation
+ void AddBuff(char c) {
+ if (k < recl)
+ buff[k++] = c;
+ else
+ throw "Record size is too small";
+ } // end of AddBuff
+
+ // Methods
+ char *UnprettyJsonFile(PGLOBAL g, char* fn, char* outfn, int lrecl);
+ bool unPretty(PGLOBAL g, int lrecl);
+ void CopyObject(PGLOBAL g);
+ void CopyArray(PGLOBAL g);
+ void CopyValue(PGLOBAL g);
+ void CopyString(PGLOBAL g);
+ void CopyNumeric(PGLOBAL g);
+
+ // Members
+ FILE* fs;
+ char* s;
+ char* buff;
+ int len;
+ int recl;
+ int i, k;
+}; // end of class JUP
+
diff --git a/storage/connect/mongo.cpp b/storage/connect/mongo.cpp
index bd3d3b893c1..5f10a89ee67 100644
--- a/storage/connect/mongo.cpp
+++ b/storage/connect/mongo.cpp
@@ -35,6 +35,7 @@
bool MakeSelector(PGLOBAL g, PFIL fp, PSTRG s);
bool IsNum(PSZ s);
+int GetDefaultDepth(void);
/***********************************************************************/
/* Make selector json representation for Mongo tables. */
@@ -248,15 +249,10 @@ MGODISC::MGODISC(PGLOBAL g, int *lg) {
/***********************************************************************/
int MGODISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt)
{
- PCSZ level = GetStringTableOption(g, topt, "Level", NULL);
PMGODEF tdp;
- if (level) {
- lvl = atoi(level);
- lvl = (lvl > 16) ? 16 : lvl;
- } else
- lvl = 0;
-
+ lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth());
+ lvl = GetIntegerTableOption(g, topt, "Depth", lvl);
all = GetBooleanTableOption(g, topt, "Fullarray", false);
/*********************************************************************/
diff --git a/storage/connect/mysql-test/connect/r/json_java_2.result b/storage/connect/mysql-test/connect/r/json_java_2.result
index 4bbac236200..47fc4abbd28 100644
--- a/storage/connect/mysql-test/connect/r/json_java_2.result
+++ b/storage/connect/mysql-test/connect/r/json_java_2.result
@@ -20,12 +20,12 @@ SELECT * from t1;
Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Nullable Jpath
_id 1 CHAR 24 24 0 0 _id
address_building 1 CHAR 10 10 0 0 address.building
-address_coord 1 CHAR 256 256 0 1 address.coord
+address_coord 1 CHAR 1024 1024 0 1 address.coord
address_street 1 CHAR 38 38 0 0 address.street
address_zipcode 1 CHAR 5 5 0 0 address.zipcode
borough 1 CHAR 13 13 0 0
cuisine 1 CHAR 64 64 0 0
-grades_date 1 CHAR 256 256 0 1 grades.0.date
+grades_date 1 CHAR 1024 1024 0 1 grades.0.date
grades_grade 1 CHAR 14 14 0 1 grades.0.grade
grades_score 5 BIGINT 2 2 0 1 grades.0.score
name 1 CHAR 98 98 0 0
@@ -64,16 +64,16 @@ OPTION_LIST='Level=1,Driver=Java,Version=2' CONNECTION='mongodb://localhost:2701
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `_id` char(24) NOT NULL `FIELD_FORMAT`='_id',
- `address_building` char(10) NOT NULL `FIELD_FORMAT`='address.building',
- `address_coord` varchar(256) DEFAULT NULL `FIELD_FORMAT`='address.coord',
- `address_street` char(38) NOT NULL `FIELD_FORMAT`='address.street',
- `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode',
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` varchar(1024) DEFAULT NULL `JPATH`='address.coord',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
`borough` char(13) NOT NULL,
`cuisine` char(64) NOT NULL,
- `grades_date` varchar(256) DEFAULT NULL `FIELD_FORMAT`='grades.0.date',
- `grades_grade` char(14) DEFAULT NULL `FIELD_FORMAT`='grades.0.grade',
- `grades_score` bigint(2) DEFAULT NULL `FIELD_FORMAT`='grades.0.score',
+ `grades_date` varchar(1024) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` bigint(2) DEFAULT NULL `JPATH`='grades.0.score',
`name` char(98) NOT NULL,
`restaurant_id` char(8) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `OPTION_LIST`='Level=1,Driver=Java,Version=2' `DATA_CHARSET`='utf8' `LRECL`=4096
@@ -251,15 +251,15 @@ OPTION_LIST='Driver=Java,level=2,version=2';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `_id` char(24) NOT NULL `FIELD_FORMAT`='_id',
- `address_building` char(10) NOT NULL `FIELD_FORMAT`='address.building',
- `address_coord` double(18,16) DEFAULT NULL `FIELD_FORMAT`='address.coord.0',
- `address_street` char(38) NOT NULL `FIELD_FORMAT`='address.street',
- `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode',
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` double(18,16) DEFAULT NULL `JPATH`='address.coord.0',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
`borough` char(13) NOT NULL,
- `grades_date` char(24) DEFAULT NULL `FIELD_FORMAT`='grades.0.date',
- `grades_grade` char(14) DEFAULT NULL `FIELD_FORMAT`='grades.0.grade',
- `grades_score` bigint(2) DEFAULT NULL `FIELD_FORMAT`='grades.0.score',
+ `grades_date` char(24) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` bigint(2) DEFAULT NULL `JPATH`='grades.0.score',
`name` char(98) NOT NULL,
`restaurant_id` char(8) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `COLIST`='{"cuisine":0}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=Java,level=2,version=2' `LRECL`=4096
diff --git a/storage/connect/mysql-test/connect/r/json_java_3.result b/storage/connect/mysql-test/connect/r/json_java_3.result
index eb8bfc022d6..720c82cd7f9 100644
--- a/storage/connect/mysql-test/connect/r/json_java_3.result
+++ b/storage/connect/mysql-test/connect/r/json_java_3.result
@@ -20,12 +20,12 @@ SELECT * from t1;
Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Nullable Jpath
_id 1 CHAR 24 24 0 0 _id
address_building 1 CHAR 10 10 0 0 address.building
-address_coord 1 CHAR 256 256 0 1 address.coord
+address_coord 1 CHAR 1024 1024 0 1 address.coord
address_street 1 CHAR 38 38 0 0 address.street
address_zipcode 1 CHAR 5 5 0 0 address.zipcode
borough 1 CHAR 13 13 0 0
cuisine 1 CHAR 64 64 0 0
-grades_date 1 CHAR 256 256 0 1 grades.0.date
+grades_date 1 CHAR 1024 1024 0 1 grades.0.date
grades_grade 1 CHAR 14 14 0 1 grades.0.grade
grades_score 5 BIGINT 2 2 0 1 grades.0.score
name 1 CHAR 98 98 0 0
@@ -64,16 +64,16 @@ OPTION_LIST='Level=1,Driver=Java,Version=3' CONNECTION='mongodb://localhost:2701
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `_id` char(24) NOT NULL `FIELD_FORMAT`='_id',
- `address_building` char(10) NOT NULL `FIELD_FORMAT`='address.building',
- `address_coord` varchar(256) DEFAULT NULL `FIELD_FORMAT`='address.coord',
- `address_street` char(38) NOT NULL `FIELD_FORMAT`='address.street',
- `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode',
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` varchar(1024) DEFAULT NULL `JPATH`='address.coord',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
`borough` char(13) NOT NULL,
`cuisine` char(64) NOT NULL,
- `grades_date` varchar(256) DEFAULT NULL `FIELD_FORMAT`='grades.0.date',
- `grades_grade` char(14) DEFAULT NULL `FIELD_FORMAT`='grades.0.grade',
- `grades_score` bigint(2) DEFAULT NULL `FIELD_FORMAT`='grades.0.score',
+ `grades_date` varchar(1024) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` bigint(2) DEFAULT NULL `JPATH`='grades.0.score',
`name` char(98) NOT NULL,
`restaurant_id` char(8) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `OPTION_LIST`='Level=1,Driver=Java,Version=3' `DATA_CHARSET`='utf8' `LRECL`=4096
@@ -251,15 +251,15 @@ OPTION_LIST='Driver=Java,level=2,version=3';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `_id` char(24) NOT NULL `FIELD_FORMAT`='_id',
- `address_building` char(10) NOT NULL `FIELD_FORMAT`='address.building',
- `address_coord` double(18,16) DEFAULT NULL `FIELD_FORMAT`='address.coord.0',
- `address_street` char(38) NOT NULL `FIELD_FORMAT`='address.street',
- `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode',
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` double(18,16) DEFAULT NULL `JPATH`='address.coord.0',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
`borough` char(13) NOT NULL,
- `grades_date` bigint(13) DEFAULT NULL `FIELD_FORMAT`='grades.0.date',
- `grades_grade` char(14) DEFAULT NULL `FIELD_FORMAT`='grades.0.grade',
- `grades_score` bigint(2) DEFAULT NULL `FIELD_FORMAT`='grades.0.score',
+ `grades_date` bigint(13) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` bigint(2) DEFAULT NULL `JPATH`='grades.0.score',
`name` char(98) NOT NULL,
`restaurant_id` char(8) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `COLIST`='{"cuisine":0}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=Java,level=2,version=3' `LRECL`=4096
diff --git a/storage/connect/mysql-test/connect/r/json_mongo_c.result b/storage/connect/mysql-test/connect/r/json_mongo_c.result
index 550e94f286e..f9bfc01763e 100644
--- a/storage/connect/mysql-test/connect/r/json_mongo_c.result
+++ b/storage/connect/mysql-test/connect/r/json_mongo_c.result
@@ -20,12 +20,12 @@ SELECT * from t1;
Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Nullable Jpath
_id 1 CHAR 24 24 0 0 _id
address_building 1 CHAR 10 10 0 0 address.building
-address_coord 1 CHAR 256 256 0 1 address.coord
+address_coord 1 CHAR 1024 1024 0 1 address.coord
address_street 1 CHAR 38 38 0 0 address.street
address_zipcode 1 CHAR 5 5 0 0 address.zipcode
borough 1 CHAR 13 13 0 0
cuisine 1 CHAR 64 64 0 0
-grades_date 1 CHAR 256 256 0 1 grades.0.date
+grades_date 1 CHAR 1024 1024 0 1 grades.0.date
grades_grade 1 CHAR 14 14 0 1 grades.0.grade
grades_score 5 BIGINT 2 2 0 1 grades.0.score
name 1 CHAR 98 98 0 0
@@ -64,16 +64,16 @@ OPTION_LIST='Level=1,Driver=C,Version=0' CONNECTION='mongodb://localhost:27017'
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `_id` char(24) NOT NULL `FIELD_FORMAT`='_id',
- `address_building` char(10) NOT NULL `FIELD_FORMAT`='address.building',
- `address_coord` varchar(256) DEFAULT NULL `FIELD_FORMAT`='address.coord',
- `address_street` char(38) NOT NULL `FIELD_FORMAT`='address.street',
- `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode',
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` varchar(1024) DEFAULT NULL `JPATH`='address.coord',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
`borough` char(13) NOT NULL,
`cuisine` char(64) NOT NULL,
- `grades_date` varchar(256) DEFAULT NULL `FIELD_FORMAT`='grades.0.date',
- `grades_grade` char(14) DEFAULT NULL `FIELD_FORMAT`='grades.0.grade',
- `grades_score` bigint(2) DEFAULT NULL `FIELD_FORMAT`='grades.0.score',
+ `grades_date` varchar(1024) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` bigint(2) DEFAULT NULL `JPATH`='grades.0.score',
`name` char(98) NOT NULL,
`restaurant_id` char(8) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `OPTION_LIST`='Level=1,Driver=C,Version=0' `DATA_CHARSET`='utf8' `LRECL`=1024
@@ -251,15 +251,15 @@ OPTION_LIST='Driver=C,level=2,version=0';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `_id` char(24) NOT NULL `FIELD_FORMAT`='_id',
- `address_building` char(10) NOT NULL `FIELD_FORMAT`='address.building',
- `address_coord` double(23,20) DEFAULT NULL `FIELD_FORMAT`='address.coord.0',
- `address_street` char(38) NOT NULL `FIELD_FORMAT`='address.street',
- `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode',
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` double(23,20) DEFAULT NULL `JPATH`='address.coord.0',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
`borough` char(13) NOT NULL,
- `grades_date` bigint(13) DEFAULT NULL `FIELD_FORMAT`='grades.0.date',
- `grades_grade` char(14) DEFAULT NULL `FIELD_FORMAT`='grades.0.grade',
- `grades_score` bigint(2) DEFAULT NULL `FIELD_FORMAT`='grades.0.score',
+ `grades_date` bigint(13) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` bigint(2) DEFAULT NULL `JPATH`='grades.0.score',
`name` char(98) NOT NULL,
`restaurant_id` char(8) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `COLIST`='{"projection":{"cuisine":0}}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=C,level=2,version=0' `LRECL`=1024
diff --git a/storage/connect/mysql-test/connect/r/updelx.result b/storage/connect/mysql-test/connect/r/updelx.result
index 2aed1e06928..bb82afcc1a8 100644
--- a/storage/connect/mysql-test/connect/r/updelx.result
+++ b/storage/connect/mysql-test/connect/r/updelx.result
@@ -978,7 +978,7 @@ DROP TABLE t1;
# FIX table
CREATE TABLE t1 (
id INT(4) KEY NOT NULL,
-msg VARCHAR(16) CHARSET BINARY DISTRIB=CLUSTERED)
+msg VARCHAR(16) DISTRIB=CLUSTERED)
ENGINE=CONNECT TABLE_TYPE=FIX BLOCK_SIZE=4;
Warnings:
Warning 1105 No file name. Table will use t1.fix
@@ -1345,7 +1345,7 @@ DROP TABLE t1;
# BIN table
CREATE TABLE t1 (
id INT(4) KEY NOT NULL,
-msg VARCHAR(16) CHARSET BINARY DISTRIB=CLUSTERED)
+msg VARCHAR(16) DISTRIB=CLUSTERED)
ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=8;
Warnings:
Warning 1105 No file name. Table will use t1.bin
diff --git a/storage/connect/mysql-test/connect/t/updelx.test b/storage/connect/mysql-test/connect/t/updelx.test
index 19d0d790a30..f6291432e48 100644
--- a/storage/connect/mysql-test/connect/t/updelx.test
+++ b/storage/connect/mysql-test/connect/t/updelx.test
@@ -36,7 +36,7 @@ DROP TABLE t1;
--echo # FIX table
CREATE TABLE t1 (
id INT(4) KEY NOT NULL,
-msg VARCHAR(16) CHARSET BINARY DISTRIB=CLUSTERED)
+msg VARCHAR(16) DISTRIB=CLUSTERED)
ENGINE=CONNECT TABLE_TYPE=FIX BLOCK_SIZE=4;
-- source updelx.inc
ALTER TABLE t1 MAPPED=YES;
@@ -48,7 +48,7 @@ DROP TABLE t1;
--echo # BIN table
CREATE TABLE t1 (
id INT(4) KEY NOT NULL,
-msg VARCHAR(16) CHARSET BINARY DISTRIB=CLUSTERED)
+msg VARCHAR(16) DISTRIB=CLUSTERED)
ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=8;
-- source updelx.inc
ALTER TABLE t1 MAPPED=YES;
diff --git a/storage/connect/myutil.h b/storage/connect/myutil.h
index 6991172b39e..fa41fa47d61 100644
--- a/storage/connect/myutil.h
+++ b/storage/connect/myutil.h
@@ -6,8 +6,8 @@
enum enum_field_types PLGtoMYSQL(int type, bool dbf, char var = 0);
const char *PLGtoMYSQLtype(int type, bool dbf, char var = 0);
-int MYSQLtoPLG(char *typname, char *var = NULL);
-int MYSQLtoPLG(int mytype, char *var = NULL);
+int MYSQLtoPLG(char *typname, char *var);
+int MYSQLtoPLG(int mytype, char *var);
PCSZ MyDateFmt(int mytype);
PCSZ MyDateFmt(char *typname);
diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp
index e296553d8e2..7bc7c5f592b 100644
--- a/storage/connect/plgdbutl.cpp
+++ b/storage/connect/plgdbutl.cpp
@@ -5,7 +5,7 @@
/* */
/* COPYRIGHT: */
/* ---------- */
-/* (C) Copyright to the author Olivier BERTRAND 1998-2018 */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2020 */
/* */
/* WHAT THIS PROGRAM DOES: */
/* ----------------------- */
@@ -1242,7 +1242,7 @@ void *PlgDBalloc(PGLOBAL g, void *area, MBLOCK& mp)
mp.Sub = mp.Size <= ((mp.Sub) ? maxsub : (maxsub >> 2));
if (trace(2))
- htrc("PlgDBalloc: in %p size=%d used=%d free=%d sub=%d\n",
+ htrc("PlgDBalloc: in %p size=%zd used=%zd free=%zd sub=%d\n",
arp, mp.Size, pph->To_Free, pph->FreeBlk, mp.Sub);
if (!mp.Sub) {
@@ -1258,7 +1258,7 @@ void *PlgDBalloc(PGLOBAL g, void *area, MBLOCK& mp)
mp.Memp = malloc(mp.Size);
if (trace(8))
- htrc("PlgDBalloc: %s(%d) at %p\n", v, mp.Size, mp.Memp);
+ htrc("PlgDBalloc: %s(%zd) at %p\n", v, mp.Size, mp.Memp);
if (!mp.Inlist && mp.Memp) {
// New allocated block, put it in the memory block chain.
@@ -1290,7 +1290,7 @@ void *PlgDBrealloc(PGLOBAL g, void *area, MBLOCK& mp, size_t newsize)
#endif
if (trace(2))
- htrc("PlgDBrealloc: %p size=%d sub=%d\n", mp.Memp, mp.Size, mp.Sub);
+ htrc("PlgDBrealloc: %p size=%zd sub=%d\n", mp.Memp, mp.Size, mp.Sub);
if (newsize == mp.Size)
return mp.Memp; // Nothing to do
@@ -1340,7 +1340,7 @@ void *PlgDBrealloc(PGLOBAL g, void *area, MBLOCK& mp, size_t newsize)
} // endif's
if (trace(8))
- htrc(" newsize=%d newp=%p sub=%d\n", mp.Size, mp.Memp, mp.Sub);
+ htrc(" newsize=%zd newp=%p sub=%d\n", mp.Size, mp.Memp, mp.Sub);
return mp.Memp;
} // end of PlgDBrealloc
@@ -1392,13 +1392,13 @@ void *PlgDBSubAlloc(PGLOBAL g, void *memp, size_t size)
pph = (PPOOLHEADER)memp;
if (trace(16))
- htrc("PlgDBSubAlloc: memp=%p size=%d used=%d free=%d\n",
+ htrc("PlgDBSubAlloc: memp=%p size=%zd used=%zd free=%zd\n",
memp, size, pph->To_Free, pph->FreeBlk);
- if ((uint)size > pph->FreeBlk) { /* Not enough memory left in pool */
+ if (size > pph->FreeBlk) { /* Not enough memory left in pool */
sprintf(g->Message,
- "Not enough memory in Work area for request of %d (used=%d free=%d)",
- (int) size, pph->To_Free, pph->FreeBlk);
+ "Not enough memory in Work area for request of %zd (used=%zd free=%zd)",
+ size, pph->To_Free, pph->FreeBlk);
if (trace(1))
htrc("%s\n", g->Message);
@@ -1414,7 +1414,7 @@ void *PlgDBSubAlloc(PGLOBAL g, void *memp, size_t size)
pph->FreeBlk -= size; // New size of pool free block
if (trace(16))
- htrc("Done memp=%p used=%d free=%d\n",
+ htrc("Done memp=%p used=%zd free=%zd\n",
memp, pph->To_Free, pph->FreeBlk);
return (memp);
diff --git a/storage/connect/plugutil.cpp b/storage/connect/plugutil.cpp
index e74937b942a..0ab594f5533 100644
--- a/storage/connect/plugutil.cpp
+++ b/storage/connect/plugutil.cpp
@@ -6,7 +6,7 @@
/* */
/* COPYRIGHT: */
/* ---------- */
-/* (C) Copyright to the author Olivier BERTRAND 1993-2019 */
+/* (C) Copyright to the author Olivier BERTRAND 1993-2020 */
/* */
/* WHAT THIS PROGRAM DOES: */
/* ----------------------- */
@@ -142,7 +142,7 @@ void htrc(char const* fmt, ...)
/* Language points on initial language name and eventual path. */
/* Return value is the pointer to the Global structure. */
/***********************************************************************/
-PGLOBAL PlugInit(LPCSTR Language, uint worksize)
+PGLOBAL PlugInit(LPCSTR Language, size_t worksize)
{
PGLOBAL g;
@@ -158,13 +158,14 @@ PGLOBAL PlugInit(LPCSTR Language, uint worksize)
} // end try/catch
g->Sarea = NULL;
- g->Createas = 0;
+ g->Createas = false;
g->Alchecked = 0;
g->Mrr = 0;
g->Activityp = NULL;
g->Xchk = NULL;
g->N = 0;
g->More = 0;
+ g->Saved_Size = 0;
strcpy(g->Message, "");
/*******************************************************************/
@@ -459,7 +460,7 @@ short GetLineLength(PGLOBAL g)
/***********************************************************************/
/* Program for memory allocation of work and language areas. */
/***********************************************************************/
-bool AllocSarea(PGLOBAL g, uint size)
+bool AllocSarea(PGLOBAL g, size_t size)
{
/*********************************************************************/
/* This is the allocation routine for the WIN32/UNIX/AIX version. */
@@ -483,7 +484,7 @@ bool AllocSarea(PGLOBAL g, uint size)
if (trace(8)) {
#endif
if (g->Sarea)
- htrc("Work area of %u allocated at %p\n", size, g->Sarea);
+ htrc("Work area of %zd allocated at %p\n", size, g->Sarea);
else
htrc("SareaAlloc: %s\n", g->Message);
@@ -510,7 +511,7 @@ void FreeSarea(PGLOBAL g)
#else
if (trace(8))
#endif
- htrc("Freeing Sarea at %p size = %d\n", g->Sarea, g->Sarea_Size);
+ htrc("Freeing Sarea at %p size = %zd\n", g->Sarea, g->Sarea_Size);
g->Sarea = NULL;
g->Sarea_Size = 0;
@@ -524,11 +525,11 @@ void FreeSarea(PGLOBAL g)
/* Here there should be some verification done such as validity of */
/* the address and size not larger than memory size. */
/***********************************************************************/
-BOOL PlugSubSet(void *memp, uint size)
+BOOL PlugSubSet(void *memp, size_t size)
{
PPOOLHEADER pph = (PPOOLHEADER)memp;
- pph->To_Free = (OFFSET)sizeof(POOLHEADER);
+ pph->To_Free = (size_t)sizeof(POOLHEADER);
pph->FreeBlk = size - pph->To_Free;
return FALSE;
} /* end of PlugSubSet */
@@ -560,15 +561,15 @@ void *PlugSubAlloc(PGLOBAL g, void *memp, size_t size)
pph = (PPOOLHEADER)memp;
if (trace(16))
- htrc("SubAlloc in %p size=%d used=%d free=%d\n",
+ htrc("SubAlloc in %p size=%zd used=%zd free=%zd\n",
memp, size, pph->To_Free, pph->FreeBlk);
- if ((uint)size > pph->FreeBlk) { /* Not enough memory left in pool */
+ if (size > pph->FreeBlk) { /* Not enough memory left in pool */
PCSZ pname = "Work";
sprintf(g->Message,
- "Not enough memory in %s area for request of %u (used=%d free=%d)",
- pname, (uint)size, pph->To_Free, pph->FreeBlk);
+ "Not enough memory in %s area for request of %zd (used=%zd free=%zd)",
+ pname, size, pph->To_Free, pph->FreeBlk);
if (trace(1))
htrc("PlugSubAlloc: %s\n", g->Message);
@@ -580,11 +581,11 @@ void *PlugSubAlloc(PGLOBAL g, void *memp, size_t size)
/* Do the suballocation the simplest way. */
/*********************************************************************/
memp = MakePtr(memp, pph->To_Free); /* Points to suballocated block */
- pph->To_Free += (OFFSET)size; /* New offset of pool free block */
- pph->FreeBlk -= (uint)size; /* New size of pool free block */
+ pph->To_Free += size; /* New offset of pool free block */
+ pph->FreeBlk -= size; /* New size of pool free block */
if (trace(16))
- htrc("Done memp=%p used=%d free=%d\n",
+ htrc("Done memp=%p used=%zd free=%zd\n",
memp, pph->To_Free, pph->FreeBlk);
return (memp);
@@ -605,40 +606,4 @@ char *PlugDup(PGLOBAL g, const char *str)
} // end of PlugDup
-#if 0
-/***********************************************************************/
-/* This routine suballocate a copy of the passed string. */
-/***********************************************************************/
-char *PlugDup(PGLOBAL g, const char *str)
- {
- char *buf;
- size_t len;
-
- if (str && (len = strlen(str))) {
- buf = (char*)PlugSubAlloc(g, NULL, len + 1);
- strcpy(buf, str);
- } else
- buf = NULL;
-
- return(buf);
- } /* end of PlugDup */
-#endif // 0
-
-/***********************************************************************/
-/* This routine makes a pointer from an offset to a memory pointer. */
-/***********************************************************************/
-void *MakePtr(void *memp, OFFSET offset)
- {
- return ((offset == 0) ? NULL : &((char *)memp)[offset]);
- } /* end of MakePtr */
-
-/***********************************************************************/
-/* This routine makes an offset from a pointer new format. */
-/***********************************************************************/
-#if 0
-OFFSET MakeOff(void *memp, void *ptr)
- {
- return ((!ptr) ? 0 : (OFFSET)((char *)ptr - (char *)memp));
- } /* end of MakeOff */
-#endif
/*--------------------- End of PLUGUTIL program -----------------------*/
diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp
index 3b0d458a7a6..cdf9e40f97c 100644
--- a/storage/connect/tabjson.cpp
+++ b/storage/connect/tabjson.cpp
@@ -52,19 +52,10 @@
/* External functions. */
/***********************************************************************/
USETEMP UseTemp(void);
+bool JsonAllPath(void);
+int GetDefaultDepth(void);
char *GetJsonNull(void);
-//typedef struct _jncol {
-// struct _jncol *Next;
-// char *Name;
-// char *Fmt;
-// int Type;
-// int Len;
-// int Scale;
-// bool Cbn;
-// bool Found;
-//} JCOL, *PJCL;
-
/***********************************************************************/
/* JSONColumns: construct the result blocks containing the description */
/* of all the columns of a table contained inside a JSON file. */
@@ -167,23 +158,20 @@ JSONDISC::JSONDISC(PGLOBAL g, uint *lg)
jsp = NULL;
row = NULL;
sep = NULL;
- i = n = bf = ncol = lvl = 0;
- all = false;
+ i = n = bf = ncol = lvl = sz = 0;
+ all = strfy = false;
} // end of JSONDISC constructor
int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
{
char filename[_MAX_PATH];
bool mgo = (GetTypeID(topt->type) == TAB_MONGO);
- PCSZ level = GetStringTableOption(g, topt, "Level", NULL);
-
- if (level) {
- lvl = atoi(level);
- lvl = (lvl > 16) ? 16 : lvl;
- } else
- lvl = 0;
- sep = GetStringTableOption(g, topt, "Separator", ".");
+ lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth());
+ lvl = GetIntegerTableOption(g, topt, "Depth", lvl);
+ sep = GetStringTableOption(g, topt, "Separator", ".");
+ sz = GetIntegerTableOption(g, topt, "Jsize", 1024);
+ strfy = GetBooleanTableOption(g, topt, "Stringify", false);
/*********************************************************************/
/* Open the input file. */
@@ -254,12 +242,14 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
jsp = (tjsp->GetDoc()) ? tjsp->GetDoc()->GetValue(0) : NULL;
} else {
- if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0)))
- if (!mgo) {
- sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty);
- return 0;
- } else
- tdp->Lrecl = 8192; // Should be enough
+ if (!((tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0)))) {
+ if (!mgo) {
+ sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty);
+ return 0;
+ } else
+ tdp->Lrecl = 8192; // Should be enough
+
+ } // endif Lrecl
tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF);
@@ -304,7 +294,7 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
// Allocate the parse work memory
PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL));
memset(G, 0, sizeof(GLOBAL));
- G->Sarea_Size = tdp->Lrecl * 10;
+ G->Sarea_Size = (size_t)tdp->Lrecl * 10;
G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size);
PlugSubSet(G->Sarea, G->Sarea_Size);
G->jump_level = 0;
@@ -401,7 +391,10 @@ bool JSONDISC::Find(PGLOBAL g, PJVAL jvp, PCSZ key, int j)
PJAR jar;
if ((valp = jvp ? jvp->GetValue() : NULL)) {
- jcol.Type = valp->GetType();
+ if (JsonAllPath() && !fmt[bf])
+ strcat(fmt, colname);
+
+ jcol.Type = valp->GetType();
jcol.Len = valp->GetValLen();
jcol.Scale = valp->GetValPrec();
jcol.Cbn = valp->IsNull();
@@ -480,8 +473,16 @@ bool JSONDISC::Find(PGLOBAL g, PJVAL jvp, PCSZ key, int j)
} // endswitch Type
} else if (lvl >= 0) {
- jcol.Type = TYPE_STRING;
- jcol.Len = 256;
+ if (strfy) {
+ if (!fmt[bf])
+ strcat(fmt, colname);
+
+ strcat(fmt, ".*");
+ } else if (JsonAllPath() && !fmt[bf])
+ strcat(fmt, colname);
+
+ jcol.Type = TYPE_STRING;
+ jcol.Len = sz;
jcol.Scale = 0;
jcol.Cbn = true;
} else
@@ -1329,7 +1330,7 @@ bool JSONCOL::ParseJpath(PGLOBAL g)
{
char *p, *p1 = NULL, *p2 = NULL, *pbuf = NULL;
int i;
- bool a, mul = false;
+ bool a;
if (Parsed)
return false; // Already done
@@ -1486,7 +1487,18 @@ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp)
if (Value->IsTypeNum()) {
strcpy(g->Message, "Cannot make Json for a numeric column");
Value->Reset();
- } else
+ } else if (Value->GetType() == TYPE_BIN) {
+ if ((unsigned)Value->GetClen() >= sizeof(BSON)) {
+ ulong len = Tjp->Lrecl ? Tjp->Lrecl : 500;
+ PBSON bsp = JbinAlloc(g, NULL, len, jsp);
+
+ strcat(bsp->Msg, " column");
+ ((BINVAL*)Value)->SetBinValue(bsp, sizeof(BSON));
+ } else {
+ strcpy(g->Message, "Column size too small");
+ Value->SetValue_char(NULL, 0);
+ } // endif Clen
+ } else
Value->SetValue_psz(Serialize(g, jsp, NULL, 0));
return Value;
@@ -1559,7 +1571,6 @@ void JSONCOL::ReadColumn(PGLOBAL g)
PVAL JSONCOL::GetColumnValue(PGLOBAL g, PJSON row, int i)
{
int n = Nod - 1;
- bool expd = false;
PJAR arp;
PJVAL val = NULL;
@@ -1983,8 +1994,9 @@ int TDBJSON::MakeNewDoc(PGLOBAL g)
/***********************************************************************/
int TDBJSON::MakeDocument(PGLOBAL g)
{
- char *p, *memory, *objpath, *key = NULL;
+ char *p, *p1, *p2, *memory, *objpath, *key = NULL;
int len, i = 0;
+ my_bool a;
MODE mode = Mode;
PJSON jsp;
PJOB objp = NULL;
@@ -2027,22 +2039,39 @@ int TDBJSON::MakeDocument(PGLOBAL g)
if ((objpath = PlugDup(g, Objname))) {
if (*objpath == '$') objpath++;
if (*objpath == '.') objpath++;
+ p1 = (*objpath == '[') ? objpath++ : NULL;
/*********************************************************************/
/* Find the table in the tree structure. */
/*********************************************************************/
- for (; jsp && objpath; objpath = p) {
- if ((p = strchr(objpath, Sep)))
- *p++ = 0;
-
- if (*objpath != '[' && !IsNum(objpath)) {
- // objpass is a key
+ for (p = objpath; jsp && p; p = (p2 ? p2 : NULL)) {
+ a = (p1 != NULL);
+ p1 = strchr(p, '[');
+ p2 = strchr(p, '.');
+
+ if (!p2)
+ p2 = p1;
+ else if (p1) {
+ if (p1 < p2)
+ p2 = p1;
+ else if (p1 == p2 + 1)
+ *p2++ = 0; // Old syntax .[
+ else
+ p1 = NULL;
+
+ } // endif p1
+
+ if (p2)
+ *p2++ = 0;
+
+ if (!a && *p && *p != '[' && !IsNum(p)) {
+ // obj is a key
if (jsp->GetType() != TYPE_JOB) {
strcpy(g->Message, "Table path does not match the json file");
return RC_FX;
} // endif Type
- key = objpath;
+ key = p;
objp = jsp->GetObject();
arp = NULL;
val = objp->GetValue(key);
@@ -2053,15 +2082,15 @@ int TDBJSON::MakeDocument(PGLOBAL g)
} // endif val
} else {
- if (*objpath == '[') {
+ if (*p == '[') {
// Old style
- if (objpath[strlen(objpath) - 1] != ']') {
- sprintf(g->Message, "Invalid Table path %s", Objname);
+ if (p[strlen(p) - 1] != ']') {
+ sprintf(g->Message, "Invalid Table path near %s", p);
return RC_FX;
} else
- objpath++;
+ p++;
- } // endif objpath
+ } // endif p
if (jsp->GetType() != TYPE_JAR) {
strcpy(g->Message, "Table path does not match the json file");
@@ -2070,7 +2099,7 @@ int TDBJSON::MakeDocument(PGLOBAL g)
arp = jsp->GetArray();
objp = NULL;
- i = atoi(objpath) - B;
+ i = atoi(p) - B;
val = arp->GetValue(i);
if (!val) {
@@ -2081,7 +2110,7 @@ int TDBJSON::MakeDocument(PGLOBAL g)
} // endif
jsp = val->GetJson();
- } // endfor objpath
+ } // endfor p
} // endif objpath
@@ -2119,13 +2148,15 @@ int TDBJSON::Cardinality(PGLOBAL g)
{
if (!g)
return (Xcol || Multiple) ? 0 : 1;
- else if (Cardinal < 0)
- if (!Multiple) {
- if (MakeDocument(g) == RC_OK)
- Cardinal = Doc->size();
+ else if (Cardinal < 0) {
+ if (!Multiple) {
+ if (MakeDocument(g) == RC_OK)
+ Cardinal = Doc->size();
- } else
- return 10;
+ } else
+ return 10;
+
+ } // endif Cardinal
return Cardinal;
} // end of Cardinality
diff --git a/storage/connect/tabjson.h b/storage/connect/tabjson.h
index 8c3f1013919..88aa5e2ee8b 100644
--- a/storage/connect/tabjson.h
+++ b/storage/connect/tabjson.h
@@ -68,8 +68,8 @@ public:
PCSZ sep;
char colname[65], fmt[129], buf[16];
uint *length;
- int i, n, bf, ncol, lvl;
- bool all;
+ int i, n, bf, ncol, lvl, sz;
+ bool all, strfy;
}; // end of JSONDISC
/***********************************************************************/
diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp
index 3ef2a460b9d..b1bdeffc880 100644
--- a/storage/connect/tabrest.cpp
+++ b/storage/connect/tabrest.cpp
@@ -158,16 +158,32 @@ PQRYRES __stdcall ColREST(PGLOBAL g, PTOS tp, char *tab, char *db, bool info)
http = GetStringTableOption(g, tp, "Http", NULL);
uri = GetStringTableOption(g, tp, "Uri", NULL);
- fn = GetStringTableOption(g, tp, "Filename", "rest.json");
#if defined(MARIADB)
ftype = GetStringTableOption(g, tp, "Type", "JSON");
#else // !MARIADB
// OEM tables must specify the file type
ftype = GetStringTableOption(g, tp, "Ftype", "JSON");
#endif // !MARIADB
+ fn = GetStringTableOption(g, tp, "Filename", NULL);
+
+ if (!fn) {
+ int n, m = strlen(ftype) + 1;
+
+ strcat(strcpy(filename, tab), ".");
+ n = strlen(filename);
+
+ // Fold ftype to lower case
+ for (int i = 0; i < m; i++)
+ filename[n + i] = tolower(ftype[i]);
+
+ fn = filename;
+ tp->filename = PlugDup(g, fn);
+ } // endif fn
// We used the file name relative to recorded datapath
- snprintf(filename, sizeof filename, IF_WIN(".\\%s\\%s","./%s/%s"), db, fn);
+ PlugSetPath(filename, fn, db);
+ //strcat(strcat(strcat(strcpy(filename, "."), slash), db), slash);
+ //strncat(filename, fn, _MAX_PATH - strlen(filename));
// Retrieve the file from the web and copy it locally
if (http && grf(g->Message, trace(515), http, uri, filename)) {
@@ -226,12 +242,10 @@ bool RESTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
Http = GetStringCatInfo(g, "Http", NULL);
Uri = GetStringCatInfo(g, "Uri", NULL);
- Fn = GetStringCatInfo(g, "Filename", "rest.json");
+ Fn = GetStringCatInfo(g, "Filename", NULL);
// We used the file name relative to recorded datapath
- //PlugSetPath(filename, Fn, GetPath());
- strcpy(filename, GetPath());
- strncat(filename, Fn, _MAX_PATH - strlen(filename));
+ PlugSetPath(filename, Fn, GetPath());
// Retrieve the file from the web and copy it locally
rc = grf(g->Message, xt, Http, Uri, filename);
@@ -269,7 +283,7 @@ PTDB RESTDEF::GetTable(PGLOBAL g, MODE m)
if (trace(515))
htrc("REST GetTable mode=%d\n", m);
- if (m != MODE_READ && m != MODE_READX) {
+ if (m != MODE_READ && m != MODE_READX && m != MODE_ANY) {
strcpy(g->Message, "REST tables are currently read only");
return NULL;
} // endif m
diff --git a/storage/connect/tabxml.cpp b/storage/connect/tabxml.cpp
index 68941c67be8..6c9e9597cec 100644
--- a/storage/connect/tabxml.cpp
+++ b/storage/connect/tabxml.cpp
@@ -3,7 +3,7 @@
/* ------------- */
/* Version 3.0 */
/* */
-/* Author Olivier BERTRAND 2007 - 2017 */
+/* Author Olivier BERTRAND 2007 - 2020 */
/* */
/* This program are the XML tables classes using MS-DOM or libxml2. */
/***********************************************************************/
@@ -62,6 +62,8 @@ extern "C" char version[];
#define TYPE_UNKNOWN 12 /* Must be greater than other types */
#define XLEN(M) sizeof(M) - strlen(M) - 1 /* To avoid overflow*/
+int GetDefaultDepth(void);
+
/***********************************************************************/
/* Class and structure used by XMLColumns. */
/***********************************************************************/
@@ -149,8 +151,9 @@ PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info)
strcpy(g->Message, MSG(MISSING_FNAME));
return NULL;
} else {
- lvl = GetIntegerTableOption(g, topt, "Level", 0);
- lvl = (lvl < 0) ? 0 : (lvl > 16) ? 16 : lvl;
+ lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth());
+ lvl = GetIntegerTableOption(g, topt, "Depth", lvl);
+ lvl = (lvl < 0) ? 0 : (lvl > 16) ? 16 : lvl;
} // endif fn
if (trace(1))
diff --git a/storage/connect/user_connect.cc b/storage/connect/user_connect.cc
index c25443ef7ef..09d6db1ad27 100644
--- a/storage/connect/user_connect.cc
+++ b/storage/connect/user_connect.cc
@@ -28,7 +28,7 @@
*/
/****************************************************************************/
-/* Author: Olivier Bertrand -- bertrandop@gmail.com -- 2004-2015 */
+/* Author: Olivier Bertrand -- bertrandop@gmail.com -- 2004-2020 */
/****************************************************************************/
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
@@ -58,8 +58,8 @@ PCONNECT user_connect::to_users= NULL;
/****************************************************************************/
/* Get the work_size SESSION variable value . */
/****************************************************************************/
-uint GetWorkSize(void);
-void SetWorkSize(uint);
+size_t GetWorkSize(void);
+void SetWorkSize(size_t);
/* -------------------------- class user_connect -------------------------- */
@@ -97,14 +97,14 @@ user_connect::~user_connect()
bool user_connect::user_init()
{
// Initialize Plug-like environment
- uint worksize= GetWorkSize();
+ size_t worksize= GetWorkSize();
PACTIVITY ap= NULL;
PDBUSER dup= NULL;
// Areasize= 64M because of VEC tables. Should be parameterisable
//g= PlugInit(NULL, 67108864);
//g= PlugInit(NULL, 134217728); // 128M was because of old embedded tests
- g= PlugInit(NULL, worksize);
+ g= PlugInit(NULL, (size_t)worksize);
// Check whether the initialization is complete
if (!g || !g->Sarea || PlugSubSet(g->Sarea, g->Sarea_Size)
@@ -157,16 +157,17 @@ void user_connect::SetHandler(ha_connect *hc)
bool user_connect::CheckCleanup(bool force)
{
if (thdp->query_id > last_query_id || force) {
- uint worksize= GetWorkSize(), size = g->Sarea_Size;
+ size_t worksize = GetWorkSize();
PlugCleanup(g, true);
- if (size != worksize) {
+ if (worksize != g->Sarea_Size) {
FreeSarea(g);
+ g->Saved_Size = g->Sarea_Size;
// Check whether the work area could be allocated
if (AllocSarea(g, worksize)) {
- AllocSarea(g, size);
+ AllocSarea(g, g->Saved_Size);
SetWorkSize(g->Sarea_Size); // Was too big
} // endif sarea
@@ -174,10 +175,11 @@ bool user_connect::CheckCleanup(bool force)
PlugSubSet(g->Sarea, g->Sarea_Size);
g->Xchk = NULL;
- g->Createas = 0;
+ g->Createas = false;
g->Alchecked = 0;
g->Mrr = 0;
g->More = 0;
+ g->Saved_Size = 0;
last_query_id= thdp->query_id;
if (trace(65) && !force)
diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp
index df75722d0e8..de04f7678f9 100644
--- a/storage/connect/value.cpp
+++ b/storage/connect/value.cpp
@@ -2251,6 +2251,15 @@ void BINVAL::SetBinValue(void *p)
} // end of SetBinValue
/***********************************************************************/
+/* BINVAL SetBinValue: fill string with len bytes. */
+/***********************************************************************/
+void BINVAL::SetBinValue(void* p, ulong len)
+{
+ memcpy(Binp, p, len);
+ Len = len;
+} // end of SetBinValue
+
+/***********************************************************************/
/* GetBinValue: fill a buffer with the internal binary value. */
/* This function checks whether the buffer length is enough and */
/* returns true if not. Actual filling occurs only if go is true. */
diff --git a/storage/connect/value.h b/storage/connect/value.h
index 4f7d9a440fa..ee7a1c8032f 100644
--- a/storage/connect/value.h
+++ b/storage/connect/value.h
@@ -115,8 +115,8 @@ class DllExport VALUE : public BLOCK {
virtual void SetValue(ulonglong) {assert(false);}
virtual void SetValue(double) {assert(false);}
virtual void SetValue_pvblk(PVBLK blk, int n) = 0;
- virtual void SetBinValue(void *p) = 0;
- virtual bool GetBinValue(void *buf, int buflen, bool go) = 0;
+ virtual void SetBinValue(void* p) = 0;
+ virtual bool GetBinValue(void *buf, int buflen, bool go) = 0;
virtual int ShowValue(char *buf, int len) = 0;
virtual char *GetCharString(char *p) = 0;
virtual bool IsEqual(PVAL vp, bool chktype) = 0;
@@ -385,7 +385,8 @@ class DllExport BINVAL: public VALUE {
virtual void SetValue(ulonglong n);
virtual void SetValue(double f);
virtual void SetBinValue(void *p);
- virtual bool GetBinValue(void *buf, int buflen, bool go);
+ virtual void SetBinValue(void* p, ulong len);
+ virtual bool GetBinValue(void *buf, int buflen, bool go);
virtual int CompareValue(PVAL) {assert(false); return 0;}
virtual int ShowValue(char *buf, int len);
virtual char *GetCharString(char *p);
diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt
index 4513a63049d..10be3187072 100644
--- a/storage/innobase/CMakeLists.txt
+++ b/storage/innobase/CMakeLists.txt
@@ -28,6 +28,7 @@ SET(INNOBASE_SOURCES
btr/btr0scrub.cc
btr/btr0sea.cc
btr/btr0defragment.cc
+ buf/buf0block_hint.cc
buf/buf0buddy.cc
buf/buf0buf.cc
buf/buf0dblwr.cc
diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc
index 3de8ee5c1c2..69f605dc905 100644
--- a/storage/innobase/btr/btr0bulk.cc
+++ b/storage/innobase/btr/btr0bulk.cc
@@ -698,6 +698,8 @@ PageBulk::latch()
m_index->set_modified(m_mtr);
}
+ ut_ad(m_block->page.buf_fix_count);
+
/* In case the block is S-latched by page_cleaner. */
if (!buf_page_optimistic_get(RW_X_LATCH, m_block, m_modify_clock,
__FILE__, __LINE__, &m_mtr)) {
@@ -716,6 +718,8 @@ PageBulk::latch()
buf_block_buf_fix_dec(m_block);
+ ut_ad(m_block->page.buf_fix_count);
+
ut_ad(m_cur_rec > m_page && m_cur_rec < m_heap_top);
return (m_err);
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index a682148a482..d300c01fe90 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -639,6 +639,8 @@ btr_cur_optimistic_latch_leaves(
ulint mode;
ulint left_page_no;
ulint curr_page_no;
+ ut_ad(block->page.buf_fix_count);
+ ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
switch (*latch_mode) {
case BTR_SEARCH_LEAF:
@@ -650,20 +652,10 @@ btr_cur_optimistic_latch_leaves(
mode = *latch_mode == BTR_SEARCH_PREV
? RW_S_LATCH : RW_X_LATCH;
- buf_page_mutex_enter(block);
- if (buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) {
- buf_page_mutex_exit(block);
- return(false);
- }
- /* pin the block not to be relocated */
- buf_block_buf_fix_inc(block, file, line);
- buf_page_mutex_exit(block);
-
rw_lock_s_lock(&block->lock);
if (block->modify_clock != modify_clock) {
rw_lock_s_unlock(&block->lock);
-
- goto unpin_failed;
+ return false;
}
curr_page_no = block->page.id.page_no();
@@ -690,7 +682,7 @@ btr_cur_optimistic_latch_leaves(
/* release the left block */
btr_leaf_page_release(
cursor->left_block, mode, mtr);
- goto unpin_failed;
+ return false;
}
} else {
cursor->left_block = NULL;
@@ -700,23 +692,28 @@ btr_cur_optimistic_latch_leaves(
file, line, mtr)) {
if (btr_page_get_prev(buf_block_get_frame(block))
== left_page_no) {
- buf_block_buf_fix_dec(block);
+ /* block was already buffer-fixed while
+ entering the function and
+ buf_page_optimistic_get() buffer-fixes
+ it again. */
+ ut_ad(2 <= block->page.buf_fix_count);
*latch_mode = mode;
return(true);
} else {
- /* release the block */
+ /* release the block and decrement of
+ buf_fix_count which was incremented
+ in buf_page_optimistic_get() */
btr_leaf_page_release(block, mode, mtr);
}
}
+ ut_ad(block->page.buf_fix_count);
/* release the left block */
if (cursor->left_block != NULL) {
btr_leaf_page_release(cursor->left_block,
mode, mtr);
}
-unpin_failed:
- /* unpin the block */
- buf_block_buf_fix_dec(block);
+
return(false);
default:
@@ -1281,12 +1278,7 @@ btr_cur_search_to_nth_level_func(
guess = NULL;
#else
info = btr_search_get_info(index);
-
- if (!buf_pool_is_obsolete(info->withdraw_clock)) {
- guess = info->root_guess;
- } else {
- guess = NULL;
- }
+ guess = info->root_guess;
#ifdef BTR_CUR_HASH_ADAPT
@@ -1722,10 +1714,7 @@ retry_page_get:
}
#ifdef BTR_CUR_ADAPT
- if (block != guess) {
- info->root_guess = block;
- info->withdraw_clock = buf_withdraw_clock;
- }
+ info->root_guess = block;
#endif
}
diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc
index 4f06251d0bf..019369d997d 100644
--- a/storage/innobase/btr/btr0pcur.cc
+++ b/storage/innobase/btr/btr0pcur.cc
@@ -174,11 +174,10 @@ before_first:
index, rec, &cursor->old_n_fields,
&cursor->old_rec_buf, &cursor->buf_size);
- cursor->block_when_stored = block;
+ cursor->block_when_stored.store(block);
/* Function try to check if block is S/X latch. */
cursor->modify_clock = buf_block_get_modify_clock(block);
- cursor->withdraw_clock = buf_withdraw_clock;
}
/**************************************************************//**
@@ -208,6 +207,26 @@ btr_pcur_copy_stored_position(
pcur_receive->old_n_fields = pcur_donate->old_n_fields;
}
+/** Structure acts as functor to do the latching of leaf pages.
+It returns true if latching of leaf pages succeeded and false
+otherwise. */
+struct optimistic_latch_leaves
+{
+ btr_pcur_t *const cursor;
+ ulint *latch_mode;
+ mtr_t *const mtr;
+
+ optimistic_latch_leaves(btr_pcur_t *cursor, ulint *latch_mode, mtr_t *mtr)
+ :cursor(cursor), latch_mode(latch_mode), mtr(mtr) {}
+
+ bool operator() (buf_block_t *hint) const
+ {
+ return hint && btr_cur_optimistic_latch_leaves(
+ hint, cursor->modify_clock, latch_mode,
+ btr_pcur_get_btr_cur(cursor), __FILE__, __LINE__, mtr);
+ }
+};
+
/**************************************************************//**
Restores the stored position of a persistent cursor bufferfixing the page and
obtaining the specified latches. If the cursor position was saved when the
@@ -270,7 +289,7 @@ btr_pcur_restore_position_func(
cursor->latch_mode =
BTR_LATCH_MODE_WITHOUT_INTENTION(latch_mode);
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
- cursor->block_when_stored = btr_pcur_get_block(cursor);
+ cursor->block_when_stored.clear();
return(FALSE);
}
@@ -285,12 +304,9 @@ btr_pcur_restore_position_func(
case BTR_MODIFY_PREV:
/* Try optimistic restoration. */
- if (!buf_pool_is_obsolete(cursor->withdraw_clock)
- && btr_cur_optimistic_latch_leaves(
- cursor->block_when_stored, cursor->modify_clock,
- &latch_mode, btr_pcur_get_btr_cur(cursor),
- file, line, mtr)) {
-
+ if (cursor->block_when_stored.run_with_hint(
+ optimistic_latch_leaves(cursor, &latch_mode,
+ mtr))) {
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
cursor->latch_mode = latch_mode;
@@ -388,11 +404,10 @@ btr_pcur_restore_position_func(
since the cursor can now be on a different page!
But we can retain the value of old_rec */
- cursor->block_when_stored = btr_pcur_get_block(cursor);
+ cursor->block_when_stored.store(btr_pcur_get_block(cursor));
cursor->modify_clock = buf_block_get_modify_clock(
- cursor->block_when_stored);
+ cursor->block_when_stored.block());
cursor->old_stored = true;
- cursor->withdraw_clock = buf_withdraw_clock;
mem_heap_free(heap);
diff --git a/storage/innobase/buf/buf0block_hint.cc b/storage/innobase/buf/buf0block_hint.cc
new file mode 100644
index 00000000000..9f974e8304d
--- /dev/null
+++ b/storage/innobase/buf/buf0block_hint.cc
@@ -0,0 +1,78 @@
+/*****************************************************************************
+
+Copyright (c) 2020, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2020, MariaDB Corporation.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License, version 2.0, as published by the
+Free Software Foundation.
+
+This program is also distributed with certain software (including but not
+limited to OpenSSL) that is licensed under separate terms, as designated in a
+particular file or component or in included license documentation. The authors
+of MySQL hereby grant you an additional permission to link the program and
+your derivative works with the separately licensed software that they have
+included with MySQL.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
+for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+*****************************************************************************/
+
+#include "buf0block_hint.h"
+namespace buf {
+
+void Block_hint::buffer_fix_block_if_still_valid()
+{
+ /* We need to check if m_block points to one of chunks. For this to be
+ meaningful we need to prevent freeing memory while we check, and until we
+ buffer-fix the block. For this purpose it is enough to latch any of the many
+ latches taken by buf_resize().
+ However, for buffer-fixing to be meaningful, the block has to contain a page
+ (as opposed to being already empty, which might mean that buf_pool_resize()
+ can proceed and free it once we free the s-latch), so we confirm that the
+ block contains a page. However, it is not sufficient to check that this is
+ just any page, because just after we check it could get freed, unless we
+ have a latch which prevents this. This is tricky because page_hash latches
+ are sharded by page_id and we don't know the page_id until we look into the
+ block. To solve this chicken-and-egg problem somewhat, we latch the shard
+ for the m_page_id and compare block->page.id to it - so if is equal then we
+ can be reasonably sure that we have the correct latch.
+ There is still a theoretical problem here, where other threads might try
+ to modify the m_block->page.id while we are comparing it, but the chance of
+ accidentally causing the old space_id == m_page_id.m_space and the new
+ page_no == m_page_id.m_page_no is minimal as compilers emit a single 8-byte
+ comparison instruction to compare both at the same time atomically, and f()
+ will probably double-check the block->page.id again, anyway.
+ Finally, assuming that we have correct hash bucket latched, we should check if
+ the state of the block is BUF_BLOCK_FILE_PAGE before buffer-fixing the block,
+ as otherwise we risk buffer-fixing and operating on a block, which is already
+ meant to be freed. In particular, buf_LRU_free_page() first calls
+ buf_LRU_block_remove_hashed() under hash bucket latch protection to change the
+ state to BUF_BLOCK_REMOVE_HASH and then releases the latch. Later it calls
+ buf_LRU_block_free_hashed_page() without any latch to change the state to
+ BUF_BLOCK_MEMORY and reset the page's id, which means buf_resize() can free it
+ regardless of our buffer-fixing. */
+ if (m_block)
+ {
+ const buf_pool_t *const buf_pool= buf_pool_get(m_page_id);
+ rw_lock_t *latch= buf_page_hash_lock_get(buf_pool, m_page_id);
+ rw_lock_s_lock(latch);
+ /* If not own buf_pool_mutex, page_hash can be changed. */
+ latch= buf_page_hash_lock_s_confirm(latch, buf_pool, m_page_id);
+ if (buf_pool->is_block_field(m_block) &&
+ m_page_id == m_block->page.id &&
+ buf_block_get_state(m_block) == BUF_BLOCK_FILE_PAGE)
+ buf_block_buf_fix_inc(m_block, __FILE__, __LINE__);
+ else
+ clear();
+ rw_lock_s_unlock(latch);
+ }
+}
+} // namespace buf
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index 5e7c49becc2..6867d15ee57 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -339,14 +339,6 @@ buf_pool_t* buf_pool_ptr;
/** true when resizing buffer pool is in the critical path. */
volatile bool buf_pool_resizing;
-/** true when withdrawing buffer pool pages might cause page relocation */
-volatile bool buf_pool_withdrawing;
-
-/** the clock is incremented every time a pointer to a page may become obsolete;
-if the withdrwa clock has not changed, the pointer is still valid in buffer
-pool. if changed, the pointer might not be in buffer pool any more. */
-volatile ulint buf_withdraw_clock;
-
/** Map of buffer pool chunks by its first frame address
This is newly made by initialization of buffer pool and buf_resize_thread.
Currently, no need mutex protection for update. */
@@ -2110,8 +2102,6 @@ buf_pool_init(
NUMA_MEMPOLICY_INTERLEAVE_IN_SCOPE;
buf_pool_resizing = false;
- buf_pool_withdrawing = false;
- buf_withdraw_clock = 0;
buf_pool_ptr = (buf_pool_t*) ut_zalloc_nokey(
n_instances * sizeof *buf_pool_ptr);
@@ -2171,7 +2161,6 @@ buf_page_realloc(
{
buf_block_t* new_block;
- ut_ad(buf_pool_withdrawing);
ut_ad(buf_pool_mutex_own(buf_pool));
ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
@@ -2593,9 +2582,6 @@ buf_pool_withdraw_blocks(
ib::info() << "buffer pool " << i << " : withdrawn target "
<< UT_LIST_GET_LEN(buf_pool->withdraw) << " blocks.";
- /* retry is not needed */
- ++buf_withdraw_clock;
-
return(false);
}
@@ -2692,7 +2678,6 @@ buf_pool_resize()
NUMA_MEMPOLICY_INTERLEAVE_IN_SCOPE;
ut_ad(!buf_pool_resizing);
- ut_ad(!buf_pool_withdrawing);
ut_ad(srv_buf_pool_chunk_unit > 0);
new_instance_size = srv_buf_pool_size / srv_buf_pool_instances;
@@ -2760,7 +2745,6 @@ buf_pool_resize()
ut_ad(buf_pool->withdraw_target == 0);
buf_pool->withdraw_target = withdraw_target;
- buf_pool_withdrawing = true;
}
}
@@ -2785,7 +2769,6 @@ withdraw_retry:
if (srv_shutdown_state != SRV_SHUTDOWN_NONE) {
/* abort to resize for shutdown. */
- buf_pool_withdrawing = false;
return;
}
@@ -2847,7 +2830,6 @@ withdraw_retry:
goto withdraw_retry;
}
- buf_pool_withdrawing = false;
buf_resize_status("Latching whole of buffer pool.");
@@ -4046,37 +4028,6 @@ buf_block_from_ahi(const byte* ptr)
/********************************************************************//**
Find out if a pointer belongs to a buf_block_t. It can be a pointer to
-the buf_block_t itself or a member of it. This functions checks one of
-the buffer pool instances.
-@return TRUE if ptr belongs to a buf_block_t struct */
-static
-ibool
-buf_pointer_is_block_field_instance(
-/*================================*/
- buf_pool_t* buf_pool, /*!< in: buffer pool instance */
- const void* ptr) /*!< in: pointer not dereferenced */
-{
- const buf_chunk_t* chunk = buf_pool->chunks;
- const buf_chunk_t* const echunk = chunk + ut_min(
- buf_pool->n_chunks, buf_pool->n_chunks_new);
-
- /* TODO: protect buf_pool->chunks with a mutex (the older pointer will
- currently remain while during buf_pool_resize()) */
- while (chunk < echunk) {
- if (ptr >= (void*) chunk->blocks
- && ptr < (void*) (chunk->blocks + chunk->size)) {
-
- return(TRUE);
- }
-
- chunk++;
- }
-
- return(FALSE);
-}
-
-/********************************************************************//**
-Find out if a pointer belongs to a buf_block_t. It can be a pointer to
the buf_block_t itself or a member of it
@return TRUE if ptr belongs to a buf_block_t struct */
ibool
@@ -4087,11 +4038,7 @@ buf_pointer_is_block_field(
ulint i;
for (i = 0; i < srv_buf_pool_instances; i++) {
- ibool found;
-
- found = buf_pointer_is_block_field_instance(
- buf_pool_from_array(i), ptr);
- if (found) {
+ if (buf_pool_from_array(i)->is_block_field(ptr)) {
return(TRUE);
}
}
@@ -4099,25 +4046,6 @@ buf_pointer_is_block_field(
return(FALSE);
}
-/********************************************************************//**
-Find out if a buffer block was created by buf_chunk_init().
-@return TRUE if "block" has been added to buf_pool->free by buf_chunk_init() */
-static
-ibool
-buf_block_is_uncompressed(
-/*======================*/
- buf_pool_t* buf_pool, /*!< in: buffer pool instance */
- const buf_block_t* block) /*!< in: pointer to block,
- not dereferenced */
-{
- if ((((ulint) block) % sizeof *block) != 0) {
- /* The pointer should be aligned. */
- return(FALSE);
- }
-
- return(buf_pointer_is_block_field_instance(buf_pool, (void*) block));
-}
-
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
/********************************************************************//**
Return true if probe is enabled.
@@ -4356,7 +4284,7 @@ loop:
has been allocated by buf_page_alloc_descriptor(),
it may have been freed by buf_relocate(). */
- if (!buf_block_is_uncompressed(buf_pool, block)
+ if (!buf_pool->is_block_field(block)
|| page_id != block->page.id
|| buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) {
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index a6d6e9e6b3c..2e165a3a7bc 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -60,7 +60,6 @@ extern uint ibuf_debug;
#include "lock0lock.h"
#include "mach0data.h"
#include "mem0mem.h"
-#include "os0once.h"
#include "page0page.h"
#include "page0zip.h"
#include "pars0pars.h"
@@ -263,76 +262,6 @@ dict_mutex_exit_for_mysql(void)
mutex_exit(&dict_sys->mutex);
}
-/** Allocate and init a dict_table_t's stats latch.
-This function must not be called concurrently on the same table object.
-@param[in,out] table_void table whose stats latch to create */
-static
-void
-dict_table_stats_latch_alloc(
- void* table_void)
-{
- dict_table_t* table = static_cast<dict_table_t*>(table_void);
-
- /* Note: rw_lock_create() will call the constructor */
-
- table->stats_latch = static_cast<rw_lock_t*>(
- ut_malloc_nokey(sizeof(rw_lock_t)));
-
- ut_a(table->stats_latch != NULL);
-
- rw_lock_create(dict_table_stats_key, table->stats_latch,
- SYNC_INDEX_TREE);
-}
-
-/** Deinit and free a dict_table_t's stats latch.
-This function must not be called concurrently on the same table object.
-@param[in,out] table table whose stats latch to free */
-static
-void
-dict_table_stats_latch_free(
- dict_table_t* table)
-{
- rw_lock_free(table->stats_latch);
- ut_free(table->stats_latch);
-}
-
-/** Create a dict_table_t's stats latch or delay for lazy creation.
-This function is only called from either single threaded environment
-or from a thread that has not shared the table object with other threads.
-@param[in,out] table table whose stats latch to create
-@param[in] enabled if false then the latch is disabled
-and dict_table_stats_lock()/unlock() become noop on this table. */
-void
-dict_table_stats_latch_create(
- dict_table_t* table,
- bool enabled)
-{
- if (!enabled) {
- table->stats_latch = NULL;
- table->stats_latch_created = os_once::DONE;
- return;
- }
-
- /* We create this lazily the first time it is used. */
- table->stats_latch = NULL;
- table->stats_latch_created = os_once::NEVER_DONE;
-}
-
-/** Destroy a dict_table_t's stats latch.
-This function is only called from either single threaded environment
-or from a thread that has not shared the table object with other threads.
-@param[in,out] table table whose stats latch to destroy */
-void
-dict_table_stats_latch_destroy(
- dict_table_t* table)
-{
- if (table->stats_latch_created == os_once::DONE
- && table->stats_latch != NULL) {
-
- dict_table_stats_latch_free(table);
- }
-}
-
/** Lock the appropriate latch to protect a given table's statistics.
@param[in] table table whose stats to lock
@param[in] latch_mode RW_S_LATCH or RW_X_LATCH */
@@ -344,23 +273,12 @@ dict_table_stats_lock(
ut_ad(table != NULL);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
- os_once::do_or_wait_for_done(
- &table->stats_latch_created,
- dict_table_stats_latch_alloc, table);
-
- if (table->stats_latch == NULL) {
- /* This is a dummy table object that is private in the current
- thread and is not shared between multiple threads, thus we
- skip any locking. */
- return;
- }
-
switch (latch_mode) {
case RW_S_LATCH:
- rw_lock_s_lock(table->stats_latch);
+ rw_lock_s_lock(&table->stats_latch);
break;
case RW_X_LATCH:
- rw_lock_x_lock(table->stats_latch);
+ rw_lock_x_lock(&table->stats_latch);
break;
case RW_NO_LATCH:
/* fall through */
@@ -380,19 +298,12 @@ dict_table_stats_unlock(
ut_ad(table != NULL);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
- if (table->stats_latch == NULL) {
- /* This is a dummy table object that is private in the current
- thread and is not shared between multiple threads, thus we
- skip any locking. */
- return;
- }
-
switch (latch_mode) {
case RW_S_LATCH:
- rw_lock_s_unlock(table->stats_latch);
+ rw_lock_s_unlock(&table->stats_latch);
break;
case RW_X_LATCH:
- rw_lock_x_unlock(table->stats_latch);
+ rw_lock_x_unlock(&table->stats_latch);
break;
case RW_NO_LATCH:
/* fall through */
@@ -734,34 +645,6 @@ dict_table_get_nth_v_col_mysql(
return(dict_table_get_nth_v_col(table, i));
}
-/** Allocate and init the autoinc latch of a given table.
-This function must not be called concurrently on the same table object.
-@param[in,out] table_void table whose autoinc latch to create */
-static
-void
-dict_table_autoinc_alloc(
- void* table_void)
-{
- dict_table_t* table = static_cast<dict_table_t*>(table_void);
- table->autoinc_mutex = UT_NEW_NOKEY(ib_mutex_t());
- ut_a(table->autoinc_mutex != NULL);
- mutex_create(LATCH_ID_AUTOINC, table->autoinc_mutex);
-}
-
-/** Allocate and init the zip_pad_mutex of a given index.
-This function must not be called concurrently on the same index object.
-@param[in,out] index_void index whose zip_pad_mutex to create */
-static
-void
-dict_index_zip_pad_alloc(
- void* index_void)
-{
- dict_index_t* index = static_cast<dict_index_t*>(index_void);
- index->zip_pad.mutex = UT_NEW_NOKEY(SysMutex());
- ut_a(index->zip_pad.mutex != NULL);
- mutex_create(LATCH_ID_ZIP_PAD_MUTEX, index->zip_pad.mutex);
-}
-
/********************************************************************//**
Acquire the autoinc lock. */
void
@@ -769,11 +652,7 @@ dict_table_autoinc_lock(
/*====================*/
dict_table_t* table) /*!< in/out: table */
{
- os_once::do_or_wait_for_done(
- &table->autoinc_mutex_created,
- dict_table_autoinc_alloc, table);
-
- mutex_enter(table->autoinc_mutex);
+ mysql_mutex_lock(&table->autoinc_mutex);
}
/** Acquire the zip_pad_mutex latch.
@@ -783,11 +662,7 @@ void
dict_index_zip_pad_lock(
dict_index_t* index)
{
- os_once::do_or_wait_for_done(
- &index->zip_pad.mutex_created,
- dict_index_zip_pad_alloc, index);
-
- mutex_enter(index->zip_pad.mutex);
+ mysql_mutex_lock(&index->zip_pad.mutex);
}
/** Get all the FTS indexes on a table.
@@ -822,7 +697,7 @@ dict_table_autoinc_unlock(
/*======================*/
dict_table_t* table) /*!< in/out: table */
{
- mutex_exit(table->autoinc_mutex);
+ mysql_mutex_unlock(&table->autoinc_mutex);
}
/** Looks for column n in an index.
@@ -1254,6 +1129,7 @@ dict_table_t::add_to_cache()
ut_ad(dict_lru_validate());
ut_ad(mutex_own(&dict_sys->mutex));
+ mysql_mutex_init(0, &autoinc_mutex, NULL);
cached = TRUE;
ulint fold = ut_fold_string(name.m_name);
@@ -1395,7 +1271,7 @@ dict_index_t *dict_index_t::clone() const
(mem_heap_zalloc(heap, n_uniq * sizeof *stat_n_sample_sizes));
index->stat_n_non_null_key_vals= static_cast<ib_uint64_t*>
(mem_heap_zalloc(heap, n_uniq * sizeof *stat_n_non_null_key_vals));
- memset(&index->zip_pad, 0, sizeof index->zip_pad);
+ mysql_mutex_init(0, &index->zip_pad.mutex, NULL);
return index;
}
@@ -2086,8 +1962,15 @@ dict_table_remove_from_cache_low(
UT_DELETE(table->vc_templ);
}
+ mysql_mutex_destroy(&table->autoinc_mutex);
#ifdef BTR_CUR_HASH_ADAPT
if (UNIV_UNLIKELY(UT_LIST_GET_LEN(table->freed_indexes) != 0)) {
+ if (table->fts) {
+ fts_optimize_remove_table(table);
+ fts_free(table);
+ table->fts = NULL;
+ }
+
table->vc_templ = NULL;
table->id = 0;
return;
diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
index 78ed717156c..a7201f165c0 100644
--- a/storage/innobase/dict/dict0mem.cc
+++ b/storage/innobase/dict/dict0mem.cc
@@ -115,19 +115,24 @@ operator<<(
return(s << ut_get_name(NULL, table_name.m_name));
}
-/**********************************************************************//**
-Creates a table memory object.
+/** Create a table memory object.
+@param name table name
+@param space tablespace
+@param n_cols total number of columns (both virtual and non-virtual)
+@param n_v_cols number of virtual columns
+@param flags table flags
+@param flags2 table flags2
+@param init_stats_latch whether to init the stats latch
@return own: table object */
dict_table_t*
dict_mem_table_create(
-/*==================*/
- const char* name, /*!< in: table name */
- fil_space_t* space, /*!< in: tablespace */
- ulint n_cols, /*!< in: total number of columns including
- virtual and non-virtual columns */
- ulint n_v_cols,/*!< in: number of virtual columns */
- ulint flags, /*!< in: table flags */
- ulint flags2) /*!< in: table flags2 */
+ const char* name,
+ fil_space_t* space,
+ ulint n_cols,
+ ulint n_v_cols,
+ ulint flags,
+ ulint flags2,
+ bool init_stats_latch)
{
dict_table_t* table;
mem_heap_t* heap;
@@ -171,16 +176,9 @@ dict_mem_table_create(
table->v_cols = static_cast<dict_v_col_t*>(
mem_heap_alloc(heap, n_v_cols * sizeof(*table->v_cols)));
- /* true means that the stats latch will be enabled -
- dict_table_stats_lock() will not be noop. */
- dict_table_stats_latch_create(table, true);
-
table->autoinc_lock = static_cast<ib_lock_t*>(
mem_heap_alloc(heap, lock_get_size()));
- /* lazy creation of table autoinc latch */
- dict_table_autoinc_create_lazy(table);
-
/* If the table has an FTS index or we are in the process
of building one, create the table->fts */
if (dict_table_has_fts_index(table)
@@ -195,6 +193,12 @@ dict_mem_table_create(
new(&table->foreign_set) dict_foreign_set();
new(&table->referenced_set) dict_foreign_set();
+ if (init_stats_latch) {
+ rw_lock_create(dict_table_stats_key, &table->stats_latch,
+ SYNC_INDEX_TREE);
+ table->stats_latch_inited = true;
+ }
+
return(table);
}
@@ -223,9 +227,7 @@ dict_mem_table_free(
}
}
- dict_table_autoinc_destroy(table);
dict_mem_table_free_foreign_vcol_set(table);
- dict_table_stats_latch_destroy(table);
table->foreign_set.~dict_foreign_set();
table->referenced_set.~dict_foreign_set();
@@ -246,6 +248,10 @@ dict_mem_table_free(
UT_DELETE(table->s_cols);
}
+ if (table->stats_latch_inited) {
+ rw_lock_free(&table->stats_latch);
+ }
+
mem_heap_free(table->heap);
}
@@ -778,7 +784,7 @@ dict_mem_index_create(
dict_mem_fill_index_struct(index, heap, index_name, type, n_fields);
- dict_index_zip_pad_mutex_create_lazy(index);
+ mysql_mutex_init(0, &index->zip_pad.mutex, NULL);
if (type & DICT_SPATIAL) {
index->rtr_track = static_cast<rtr_info_track_t*>(
@@ -1093,7 +1099,7 @@ dict_mem_index_free(
ut_ad(index);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
- dict_index_zip_pad_mutex_destroy(index);
+ mysql_mutex_destroy(&index->zip_pad.mutex);
if (dict_index_is_spatial(index)) {
rtr_info_active::iterator it;
diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc
index 758a95017c9..2c0ba38886f 100644
--- a/storage/innobase/dict/dict0stats.cc
+++ b/storage/innobase/dict/dict0stats.cc
@@ -33,6 +33,7 @@ Created Jan 06, 2010 Vasil Dimov
#include "pars0pars.h"
#include <mysql_com.h>
#include "btr0btr.h"
+#include "sync0sync.h"
#include <algorithm>
#include <map>
@@ -418,11 +419,6 @@ dict_stats_table_clone_create(
t->corrupted = table->corrupted;
- /* This private object "t" is not shared with other threads, so
- we do not need the stats_latch (thus we pass false below). The
- dict_table_stats_lock()/unlock() routines will do nothing. */
- dict_table_stats_latch_create(t, false);
-
UT_LIST_INIT(t->indexes, &dict_index_t::indexes);
#ifdef BTR_CUR_HASH_ADAPT
UT_LIST_INIT(t->freed_indexes, &dict_index_t::indexes);
@@ -488,6 +484,8 @@ dict_stats_table_clone_create(
ut_d(t->magic_n = DICT_TABLE_MAGIC_N);
+ rw_lock_create(dict_table_stats_key, &t->stats_latch, SYNC_INDEX_TREE);
+
return(t);
}
@@ -500,7 +498,7 @@ dict_stats_table_clone_free(
/*========================*/
dict_table_t* t) /*!< in: dummy table object to free */
{
- dict_table_stats_latch_destroy(t);
+ rw_lock_free(&t->stats_latch);
mem_heap_free(t->heap);
}
diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc
index 2ba13709016..f0f0351e20a 100644
--- a/storage/innobase/fil/fil0crypt.cc
+++ b/storage/innobase/fil/fil0crypt.cc
@@ -407,6 +407,8 @@ fil_space_crypt_t::write_page0(
mlog_write_ulint(page + offset + MAGIC_SZ + 2 + len + 8, encryption,
MLOG_1BYTE, mtr);
+ DBUG_EXECUTE_IF("ib_do_not_log_crypt_data", return;);
+
byte* log_ptr = mlog_open(mtr, 11 + 17 + len);
if (log_ptr != NULL) {
diff --git a/storage/innobase/fts/fts0ast.cc b/storage/innobase/fts/fts0ast.cc
index e22613a265b..6be4fb0d52b 100644
--- a/storage/innobase/fts/fts0ast.cc
+++ b/storage/innobase/fts/fts0ast.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2007, 2020, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2018, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
@@ -557,8 +557,7 @@ fts_ast_node_check_union(
fts_ast_node_t* node)
{
if (node->type == FTS_AST_LIST
- || node->type == FTS_AST_SUBEXP_LIST
- || node->type == FTS_AST_PARSER_PHRASE_LIST) {
+ || node->type == FTS_AST_SUBEXP_LIST) {
for (node = node->list.head; node; node = node->next) {
if (!fts_ast_node_check_union(node)) {
@@ -566,6 +565,9 @@ fts_ast_node_check_union(
}
}
+ } else if (node->type == FTS_AST_PARSER_PHRASE_LIST) {
+ /* Phrase search for plugin parser */
+ return(false);
} else if (node->type == FTS_AST_OPER
&& (node->oper == FTS_IGNORE
|| node->oper == FTS_EXIST)) {
diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc
index 2d8f040d788..b3ef795a463 100644
--- a/storage/innobase/fts/fts0que.cc
+++ b/storage/innobase/fts/fts0que.cc
@@ -4421,24 +4421,27 @@ fts_phrase_or_proximity_search(
if (k == ib_vector_size(query->match_array[j])) {
end_list = TRUE;
- if (match[j]->doc_id != match[0]->doc_id) {
- /* no match */
- if (query->flags & FTS_PHRASE) {
- ulint s;
+ if (query->flags & FTS_PHRASE) {
+ ulint s;
+ /* Since i is the last doc id in the
+ match_array[j], remove all doc ids > i
+ from the match_array[0]. */
+ fts_match_t* match_temp;
+ for (s = i + 1; s < n_matched; s++) {
+ match_temp = static_cast<
+ fts_match_t*>(ib_vector_get(
+ query->match_array[0], s));
+ match_temp->doc_id = 0;
+ }
+ if (match[j]->doc_id !=
+ match[0]->doc_id) {
+ /* no match */
match[0]->doc_id = 0;
-
- for (s = i + 1; s < n_matched;
- s++) {
- match[0] = static_cast<
- fts_match_t*>(
- ib_vector_get(
- query->match_array[0],
- s));
- match[0]->doc_id = 0;
- }
}
+ }
+ if (match[j]->doc_id != match[0]->doc_id) {
goto func_exit;
}
}
diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc
index 65079260aae..ff5cbcfa9aa 100644
--- a/storage/innobase/gis/gis0sea.cc
+++ b/storage/innobase/gis/gis0sea.cc
@@ -1256,6 +1256,24 @@ rtr_check_discard_page(
lock_mutex_exit();
}
+/** Structure acts as functor to get the optimistic access of the page.
+It returns true if it successfully gets the page. */
+struct optimistic_get
+{
+ btr_pcur_t *const r_cursor;
+ mtr_t *const mtr;
+
+ optimistic_get(btr_pcur_t *r_cursor,mtr_t *mtr)
+ :r_cursor(r_cursor), mtr(mtr) {}
+
+ bool operator()(buf_block_t *hint) const
+ {
+ return hint && buf_page_optimistic_get(
+ RW_X_LATCH, hint, r_cursor->modify_clock, __FILE__,
+ __LINE__, mtr);
+ }
+};
+
/** Restore the stored position of a persistent cursor bufferfixing the page */
static
bool
@@ -1289,11 +1307,8 @@ rtr_cur_restore_position(
ut_ad(latch_mode == BTR_CONT_MODIFY_TREE);
- if (!buf_pool_is_obsolete(r_cursor->withdraw_clock)
- && buf_page_optimistic_get(RW_X_LATCH,
- r_cursor->block_when_stored,
- r_cursor->modify_clock,
- __FILE__, __LINE__, mtr)) {
+ if (r_cursor->block_when_stored.run_with_hint(
+ optimistic_get(r_cursor, mtr))) {
ut_ad(r_cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(r_cursor->rel_pos == BTR_PCUR_ON);
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index d6dc48dad7c..0be3a532e69 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -248,6 +248,27 @@ enum default_row_format_enum {
DEFAULT_ROW_FORMAT_DYNAMIC = 2,
};
+/** A dummy variable */
+static uint innodb_max_purge_lag_wait;
+
+/** Wait for trx_sys_t::rseg_history_len to be below a limit. */
+static void innodb_max_purge_lag_wait_update(THD *thd, st_mysql_sys_var *,
+ void *, const void *limit)
+{
+ const uint l= *static_cast<const uint*>(limit);
+ if (trx_sys.history_size() <= l)
+ return;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ while (trx_sys.history_size() > l)
+ {
+ if (thd_kill_level(thd))
+ break;
+ srv_wake_purge_thread_if_not_active();
+ os_thread_sleep(100000);
+ }
+ mysql_mutex_lock(&LOCK_global_system_variables);
+}
+
static
void set_my_errno(int err)
{
@@ -19308,6 +19329,11 @@ static MYSQL_SYSVAR_ULONG(max_purge_lag_delay, srv_max_purge_lag_delay,
0L, /* Minimum value */
10000000UL, 0); /* Maximum value */
+static MYSQL_SYSVAR_UINT(max_purge_lag_wait, innodb_max_purge_lag_wait,
+ PLUGIN_VAR_RQCMDARG,
+ "Wait until History list length is below the specified limit",
+ NULL, innodb_max_purge_lag_wait_update, UINT_MAX, 0, UINT_MAX, 0);
+
static MYSQL_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout,
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
"Roll back the complete transaction on lock wait timeout, for 4.x compatibility (disabled by default)",
@@ -19406,10 +19432,10 @@ static MYSQL_SYSVAR_BOOL(log_compressed_pages, page_zip_log_pages,
static MYSQL_SYSVAR_BOOL(log_optimize_ddl, innodb_log_optimize_ddl,
PLUGIN_VAR_OPCMDARG,
- "Reduce redo logging when natively creating indexes or rebuilding tables."
- " Setting this OFF avoids delay due to page flushing and"
- " allows concurrent backup.",
- NULL, NULL, TRUE);
+ "DEPRECATED. Ignored in MariaDB 10.5."
+ " Reduce redo logging when natively creating indexes or rebuilding tables."
+ " Enabling this may slow down backup and cause delay due to page flushing.",
+ NULL, NULL, FALSE);
static MYSQL_SYSVAR_ULONG(autoextend_increment,
sys_tablespace_auto_extend_increment,
@@ -20328,6 +20354,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(flushing_avg_loops),
MYSQL_SYSVAR(max_purge_lag),
MYSQL_SYSVAR(max_purge_lag_delay),
+ MYSQL_SYSVAR(max_purge_lag_wait),
MYSQL_SYSVAR(old_blocks_pct),
MYSQL_SYSVAR(old_blocks_time),
MYSQL_SYSVAR(open_files),
diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc
index c6c934c76c4..5c94c005e4e 100644
--- a/storage/innobase/ibuf/ibuf0ibuf.cc
+++ b/storage/innobase/ibuf/ibuf0ibuf.cc
@@ -1447,7 +1447,7 @@ ibuf_dummy_index_create(
dict_index_t* index;
table = dict_mem_table_create("IBUF_DUMMY", NULL, n, 0,
- comp ? DICT_TF_COMPACT : 0, 0);
+ comp ? DICT_TF_COMPACT : 0, 0, false);
index = dict_mem_index_create(table, "IBUF_DUMMY", 0, n);
diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h
index c20b971de98..38960b1d15c 100644
--- a/storage/innobase/include/btr0pcur.h
+++ b/storage/innobase/include/btr0pcur.h
@@ -29,6 +29,7 @@ Created 2/23/1996 Heikki Tuuri
#include "dict0dict.h"
#include "btr0cur.h"
+#include "buf0block_hint.h"
#include "btr0btr.h"
#include "gis0rtree.h"
@@ -502,13 +503,10 @@ struct btr_pcur_t{
whether cursor was on, before, or after the old_rec record */
enum btr_pcur_pos_t rel_pos;
/** buffer block when the position was stored */
- buf_block_t* block_when_stored;
+ buf::Block_hint block_when_stored;
/** the modify clock value of the buffer block when the cursor position
was stored */
ib_uint64_t modify_clock;
- /** the withdraw clock value of the buffer pool when the cursor
- position was stored */
- ulint withdraw_clock;
/** btr_pcur_store_position() and btr_pcur_restore_position() state. */
enum pcur_pos_t pos_state;
/** PAGE_CUR_G, ... */
@@ -528,9 +526,8 @@ struct btr_pcur_t{
btr_pcur_t() :
btr_cur(), latch_mode(0), old_stored(false), old_rec(NULL),
old_n_fields(0), rel_pos(btr_pcur_pos_t(0)),
- block_when_stored(NULL),
- modify_clock(0), withdraw_clock(0),
- pos_state(BTR_PCUR_NOT_POSITIONED),
+ block_when_stored(),
+ modify_clock(0), pos_state(BTR_PCUR_NOT_POSITIONED),
search_mode(PAGE_CUR_UNSUPP), trx_if_known(NULL),
old_rec_buf(NULL), buf_size(0)
{
diff --git a/storage/innobase/include/buf0block_hint.h b/storage/innobase/include/buf0block_hint.h
new file mode 100644
index 00000000000..2d681175b25
--- /dev/null
+++ b/storage/innobase/include/buf0block_hint.h
@@ -0,0 +1,77 @@
+/*****************************************************************************
+
+Copyright (c) 2020, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2020, MariaDB Corporation.
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License, version 2.0, as published by the
+Free Software Foundation.
+
+This program is also distributed with certain software (including but not
+limited to OpenSSL) that is licensed under separate terms, as designated in a
+particular file or component or in included license documentation. The authors
+of MySQL hereby grant you an additional permission to link the program and
+your derivative works with the separately licensed software that they have
+included with MySQL.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
+for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+*****************************************************************************/
+#pragma once
+#include "buf0buf.h"
+
+namespace buf {
+class Block_hint {
+ public:
+ Block_hint():m_block(NULL),m_page_id(0,0) {}
+ /** Stores the pointer to the block, which is currently buffer-fixed.
+ @param block a pointer to a buffer-fixed block to be stored */
+ inline void store(buf_block_t *block)
+ {
+ ut_ad(block->page.buf_fix_count);
+ m_block= block;
+ m_page_id= block->page.id;
+ }
+
+ /** Clears currently stored pointer. */
+ inline void clear() { m_block= NULL; }
+
+ /** Invoke f on m_block(which may be null)
+ @param f The function to be executed. It will be passed the pointer.
+ If you wish to use the block pointer subsequently,
+ you need to ensure you buffer-fix it before returning from f.
+ @return the return value of f
+ */
+ template <typename F>
+ bool run_with_hint(const F &f)
+ {
+ buffer_fix_block_if_still_valid();
+ /* m_block could be changed during f() call, so we use local
+ variable to remember which block we need to unfix */
+ buf_block_t *block= m_block;
+ bool res= f(block);
+ if (block)
+ buf_block_buf_fix_dec(block);
+ return res;
+ }
+
+ buf_block_t *block() const { return m_block; }
+
+ private:
+ /** The block pointer stored by store(). */
+ buf_block_t *m_block;
+ /** If m_block is non-null, the m_block->page.id at time it was stored. */
+ page_id_t m_page_id;
+
+ /** A helper function which checks if m_block is not a dangling pointer and
+ still points to block with page with m_page_id and if so, buffer-fixes it,
+ otherwise clear()s it */
+ void buffer_fix_block_if_still_valid();
+};
+} // namespace buf
diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h
index bc14be6a3c5..1c9383aff80 100644
--- a/storage/innobase/include/buf0buf.h
+++ b/storage/innobase/include/buf0buf.h
@@ -101,10 +101,6 @@ extern buf_pool_t* buf_pool_ptr; /*!< The buffer pools
extern volatile bool buf_pool_withdrawing; /*!< true when withdrawing buffer
pool pages might cause page relocation */
-extern volatile ulint buf_withdraw_clock; /*!< the clock is incremented
- every time a pointer to a page may
- become obsolete */
-
# ifdef UNIV_DEBUG
extern my_bool buf_disable_resize_buffer_pool_debug; /*!< if TRUE, resizing
buffer pool is not allowed. */
@@ -1373,14 +1369,6 @@ buf_get_nth_chunk_block(
ulint n, /*!< in: nth chunk in the buffer pool */
ulint* chunk_size); /*!< in: chunk size */
-/** Verify the possibility that a stored page is not in buffer pool.
-@param[in] withdraw_clock withdraw clock when stored the page
-@retval true if the page might be relocated */
-UNIV_INLINE
-bool
-buf_pool_is_obsolete(
- ulint withdraw_clock);
-
/** Calculate aligned buffer pool size based on srv_buf_pool_chunk_unit,
if needed.
@param[in] size size in bytes
@@ -2207,6 +2195,11 @@ struct buf_pool_t{
buf_tmp_array_t* tmp_arr;
/*!< Array for temporal memory
used in compression and encryption */
+ /** Determine if a pointer belongs to a buf_block_t.
+ It can be a pointer to the buf_block_t itself or a member of it.
+ @param ptr a pointer that will not be dereferenced
+ @return whether the ptr belongs to a buf_block_t struct */
+ inline bool is_block_field(const void *ptr) const;
#if BUF_BUDDY_LOW > UNIV_ZIP_SIZE_MIN
# error "BUF_BUDDY_LOW > UNIV_ZIP_SIZE_MIN"
diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic
index f331091a1d7..3f8ad25bdfe 100644
--- a/storage/innobase/include/buf0buf.ic
+++ b/storage/innobase/include/buf0buf.ic
@@ -2,7 +2,7 @@
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
-Copyright (c) 2014, 2019, MariaDB Corporation.
+Copyright (c) 2014, 2020, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -54,6 +54,25 @@ struct buf_chunk_t{
}
};
+bool buf_pool_t::is_block_field(const void *ptr) const
+{
+ const buf_chunk_t* chunk= chunks;
+ const buf_chunk_t *const echunk= chunk + ut_min(n_chunks,
+ n_chunks_new);
+ /* TODO: protect chunks with a mutex (the older pointer will
+ currently remain during resize()) */
+ while (chunk < echunk)
+ {
+ if (ptr >= reinterpret_cast<const void*>(chunk->blocks) &&
+ ptr < reinterpret_cast<const void*>(
+ chunk->blocks + chunk->size))
+ return true;
+ chunk++;
+ }
+
+ return false;
+}
+
/*********************************************************************//**
Gets the current size of buffer buf_pool in bytes.
@return size in bytes */
@@ -1056,8 +1075,6 @@ buf_block_buf_fix_dec(
/*==================*/
buf_block_t* block) /*!< in/out: block to bufferunfix */
{
- buf_block_unfix(block);
-
#ifdef UNIV_DEBUG
/* No debug latch is acquired if block belongs to system temporary.
Debug latch is not of much help if access to block is single
@@ -1066,6 +1083,8 @@ buf_block_buf_fix_dec(
rw_lock_s_unlock(&block->debug_latch);
}
#endif /* UNIV_DEBUG */
+
+ buf_block_unfix(block);
}
/** Returns the buffer pool instance given a page id.
@@ -1439,18 +1458,6 @@ buf_page_get_frame(
}
}
-/** Verify the possibility that a stored page is not in buffer pool.
-@param[in] withdraw_clock withdraw clock when stored the page
-@retval true if the page might be relocated */
-UNIV_INLINE
-bool
-buf_pool_is_obsolete(
- ulint withdraw_clock)
-{
- return(UNIV_UNLIKELY(buf_pool_withdrawing
- || buf_withdraw_clock != withdraw_clock));
-}
-
/** Calculate aligned buffer pool size based on srv_buf_pool_chunk_unit,
if needed.
@param[in] size size in bytes
diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
index 9f5485bb15c..1c34e69bbf7 100644
--- a/storage/innobase/include/dict0dict.h
+++ b/storage/innobase/include/dict0dict.h
@@ -302,7 +302,7 @@ UNIV_INLINE
void
dict_table_autoinc_initialize(dict_table_t* table, ib_uint64_t value)
{
- ut_ad(dict_table_autoinc_own(table));
+ mysql_mutex_assert_owner(&table->autoinc_mutex);
table->autoinc = value;
}
@@ -315,7 +315,7 @@ UNIV_INLINE
ib_uint64_t
dict_table_autoinc_read(const dict_table_t* table)
{
- ut_ad(dict_table_autoinc_own(table));
+ mysql_mutex_assert_owner(&table->autoinc_mutex);
return(table->autoinc);
}
@@ -329,7 +329,7 @@ UNIV_INLINE
bool
dict_table_autoinc_update_if_greater(dict_table_t* table, ib_uint64_t value)
{
- ut_ad(dict_table_autoinc_own(table));
+ mysql_mutex_assert_owner(&table->autoinc_mutex);
if (value > table->autoinc) {
@@ -1468,25 +1468,6 @@ void
dict_mutex_exit_for_mysql(void);
/*===========================*/
-/** Create a dict_table_t's stats latch or delay for lazy creation.
-This function is only called from either single threaded environment
-or from a thread that has not shared the table object with other threads.
-@param[in,out] table table whose stats latch to create
-@param[in] enabled if false then the latch is disabled
-and dict_table_stats_lock()/unlock() become noop on this table. */
-void
-dict_table_stats_latch_create(
- dict_table_t* table,
- bool enabled);
-
-/** Destroy a dict_table_t's stats latch.
-This function is only called from either single threaded environment
-or from a thread that has not shared the table object with other threads.
-@param[in,out] table table whose stats latch to destroy */
-void
-dict_table_stats_latch_destroy(
- dict_table_t* table);
-
/** Lock the appropriate latch to protect a given table's statistics.
@param[in] table table whose stats to lock
@param[in] latch_mode RW_S_LATCH or RW_X_LATCH */
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index dfe8f9747f7..1c4292a2d38 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -44,7 +44,6 @@ Created 1/8/1996 Heikki Tuuri
#include "fts0fts.h"
#include "buf0buf.h"
#include "gis0type.h"
-#include "os0once.h"
#include "fil0fil.h"
#include "fil0crypt.h"
#include <set>
@@ -296,20 +295,25 @@ parent table will fail, and user has to drop excessive foreign constraint
before proceeds. */
#define FK_MAX_CASCADE_DEL 15
-/**********************************************************************//**
-Creates a table memory object.
+/** Create a table memory object.
+@param name table name
+@param space tablespace
+@param n_cols total number of columns (both virtual and non-virtual)
+@param n_v_cols number of virtual columns
+@param flags table flags
+@param flags2 table flags2
+@param init_stats_latch whether to init the stats latch
@return own: table object */
dict_table_t*
dict_mem_table_create(
-/*==================*/
- const char* name, /*!< in: table name */
- fil_space_t* space, /*!< in: tablespace */
- ulint n_cols, /*!< in: total number of columns
- including virtual and non-virtual
- columns */
- ulint n_v_cols, /*!< in: number of virtual columns */
- ulint flags, /*!< in: table flags */
- ulint flags2); /*!< in: table flags2 */
+ const char* name,
+ fil_space_t* space,
+ ulint n_cols,
+ ulint n_v_cols,
+ ulint flags,
+ ulint flags2,
+ bool init_stats_latch=true);
+
/****************************************************************//**
Free a table memory object. */
void
@@ -812,7 +816,7 @@ extern ulong zip_pad_max;
an uncompressed page should be left as padding to avoid compression
failures. This estimate is based on a self-adapting heuristic. */
struct zip_pad_info_t {
- SysMutex* mutex; /*!< mutex protecting the info */
+ mysql_mutex_t mutex; /*!< mutex protecting the info */
ulint pad; /*!< number of bytes used as pad */
ulint success;/*!< successful compression ops during
current round */
@@ -820,9 +824,6 @@ struct zip_pad_info_t {
current round */
ulint n_rounds;/*!< number of currently successful
rounds */
- volatile os_once::state_t
- mutex_created;
- /*!< Creation state of mutex member */
};
/** Number of samples of data size kept when page compression fails for
@@ -1864,7 +1865,7 @@ struct dict_table_t {
/** Statistics for query optimization. @{ */
/** Creation state of 'stats_latch'. */
- volatile os_once::state_t stats_latch_created;
+ bool stats_latch_inited;
/** This latch protects:
dict_table_t::stat_initialized,
@@ -1877,7 +1878,7 @@ struct dict_table_t {
dict_table_t::indexes*::stat_n_leaf_pages.
(*) Those are not always protected for
performance reasons. */
- rw_lock_t* stats_latch;
+ rw_lock_t stats_latch;
/** TRUE if statistics have been calculated the first time after
database startup or table creation. */
@@ -2001,11 +2002,8 @@ struct dict_table_t {
from a select. */
lock_t* autoinc_lock;
- /** Creation state of autoinc_mutex member */
- volatile os_once::state_t autoinc_mutex_created;
-
/** Mutex protecting the autoincrement counter. */
- ib_mutex_t* autoinc_mutex;
+ mysql_mutex_t autoinc_mutex;
/** Autoinc counter value to give to the next inserted row. */
ib_uint64_t autoinc;
@@ -2112,64 +2110,6 @@ struct dict_foreign_add_to_referenced_table {
}
};
-/** Destroy the autoinc latch of the given table.
-This function is only called from either single threaded environment
-or from a thread that has not shared the table object with other threads.
-@param[in,out] table table whose stats latch to destroy */
-inline
-void
-dict_table_autoinc_destroy(
- dict_table_t* table)
-{
- if (table->autoinc_mutex_created == os_once::DONE
- && table->autoinc_mutex != NULL) {
- mutex_free(table->autoinc_mutex);
- UT_DELETE(table->autoinc_mutex);
- }
-}
-
-/** Request for lazy creation of the autoinc latch of a given table.
-This function is only called from either single threaded environment
-or from a thread that has not shared the table object with other threads.
-@param[in,out] table table whose autoinc latch is to be created. */
-inline
-void
-dict_table_autoinc_create_lazy(
- dict_table_t* table)
-{
- table->autoinc_mutex = NULL;
- table->autoinc_mutex_created = os_once::NEVER_DONE;
-}
-
-/** Request a lazy creation of dict_index_t::zip_pad::mutex.
-This function is only called from either single threaded environment
-or from a thread that has not shared the table object with other threads.
-@param[in,out] index index whose zip_pad mutex is to be created */
-inline
-void
-dict_index_zip_pad_mutex_create_lazy(
- dict_index_t* index)
-{
- index->zip_pad.mutex = NULL;
- index->zip_pad.mutex_created = os_once::NEVER_DONE;
-}
-
-/** Destroy the zip_pad_mutex of the given index.
-This function is only called from either single threaded environment
-or from a thread that has not shared the table object with other threads.
-@param[in,out] table table whose stats latch to destroy */
-inline
-void
-dict_index_zip_pad_mutex_destroy(
- dict_index_t* index)
-{
- if (index->zip_pad.mutex_created == os_once::DONE
- && index->zip_pad.mutex != NULL) {
- mutex_free(index->zip_pad.mutex);
- UT_DELETE(index->zip_pad.mutex);
- }
-}
-
/** Release the zip_pad_mutex of a given index.
@param[in,out] index index whose zip_pad_mutex is to be released */
inline
@@ -2177,22 +2117,9 @@ void
dict_index_zip_pad_unlock(
dict_index_t* index)
{
- mutex_exit(index->zip_pad.mutex);
+ mysql_mutex_unlock(&index->zip_pad.mutex);
}
-#ifdef UNIV_DEBUG
-/** Check if the current thread owns the autoinc_mutex of a given table.
-@param[in] table the autoinc_mutex belongs to this table
-@return true, if the current thread owns the autoinc_mutex, false otherwise.*/
-inline
-bool
-dict_table_autoinc_own(
- const dict_table_t* table)
-{
- return(mutex_own(table->autoinc_mutex));
-}
-#endif /* UNIV_DEBUG */
-
/** Check whether the col is used in spatial index or regular index.
@param[in] col column to check
@return spatial status */
diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic
index 845b2ff625f..17b7f04a29d 100644
--- a/storage/innobase/include/mtr0mtr.ic
+++ b/storage/innobase/include/mtr0mtr.ic
@@ -170,10 +170,10 @@ mtr_t::release_block_at_savepoint(
ut_a(slot->object == block);
- buf_block_unfix(reinterpret_cast<buf_block_t*>(block));
-
buf_page_release_latch(block, slot->type);
+ buf_block_unfix(reinterpret_cast<buf_block_t*>(block));
+
slot->object = NULL;
}
diff --git a/storage/innobase/include/os0once.h b/storage/innobase/include/os0once.h
deleted file mode 100644
index a818b451830..00000000000
--- a/storage/innobase/include/os0once.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*****************************************************************************
-
-Copyright (c) 2014, Oracle and/or its affiliates. All Rights Reserved.
-
-This program is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free Software
-Foundation; version 2 of the License.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along with
-this program; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
-
-*****************************************************************************/
-
-/**************************************************//**
-@file include/os0once.h
-A class that aids executing a given function exactly once in a multi-threaded
-environment.
-
-Created Feb 20, 2014 Vasil Dimov
-*******************************************************/
-
-#ifndef os0once_h
-#define os0once_h
-
-#include "univ.i"
-
-#include "ut0ut.h"
-#include "my_cpu.h"
-
-/** Execute a given function exactly once in a multi-threaded environment
-or wait for the function to be executed by another thread.
-
-Example usage:
-First the user must create a control variable of type os_once::state_t and
-assign it os_once::NEVER_DONE.
-Then the user must pass this variable, together with a function to be
-executed to os_once::do_or_wait_for_done().
-
-Multiple threads can call os_once::do_or_wait_for_done() simultaneously with
-the same (os_once::state_t) control variable. The provided function will be
-called exactly once and when os_once::do_or_wait_for_done() returns then this
-function has completed execution, by this or another thread. In other words
-os_once::do_or_wait_for_done() will either execute the provided function or
-will wait for its execution to complete if it is already called by another
-thread or will do nothing if the function has already completed its execution
-earlier.
-
-This mimics pthread_once(3), but unfortunatelly pthread_once(3) does not
-support passing arguments to the init_routine() function. We should use
-std::call_once() when we start compiling with C++11 enabled. */
-class os_once {
-public:
- /** Control variables' state type */
- typedef ib_uint32_t state_t;
-
- /** Not yet executed. */
- static const state_t NEVER_DONE = 0;
-
- /** Currently being executed by this or another thread. */
- static const state_t IN_PROGRESS = 1;
-
- /** Finished execution. */
- static const state_t DONE = 2;
-
- /** Call a given function or wait its execution to complete if it is
- already called by another thread.
- @param[in,out] state control variable
- @param[in] do_func function to call
- @param[in,out] do_func_arg an argument to pass to do_func(). */
- static
- void
- do_or_wait_for_done(
- volatile state_t* state,
- void (*do_func)(void*),
- void* do_func_arg)
- {
- int32 oldval = NEVER_DONE;
-
- /* Avoid calling my_atomic_cas32() in the most common case. */
- if (*state == DONE) {
- return;
- }
-
- if (my_atomic_cas32((int32*) state, &oldval, IN_PROGRESS)) {
- /* We are the first. Call the function. */
-
- do_func(do_func_arg);
-
- my_atomic_store32((int32*) state, DONE);
- } else {
- /* The state is not NEVER_DONE, so either it is
- IN_PROGRESS (somebody is calling the function right
- now or DONE (it has already been called and completed).
- Wait for it to become DONE. */
- for (;;) {
- const state_t s = *state;
-
- switch (s) {
- case DONE:
- return;
- case IN_PROGRESS:
- break;
- case NEVER_DONE:
- /* fall through */
- default:
- ut_error;
- }
-
- MY_RELAX_CPU();
- }
- }
- }
-};
-
-#endif /* os0once_h */
diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h
index 786b5fe2386..b8ccb2726b2 100644
--- a/storage/innobase/include/trx0sys.h
+++ b/storage/innobase/include/trx0sys.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -1119,7 +1119,7 @@ public:
}
/** @return number of committed transactions waiting for purge */
- ulint history_size() const
+ uint32 history_size() const
{
return uint32(my_atomic_load32(&const_cast<trx_sys_t*>(this)
->rseg_history_len));
diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h
index 7be4314ecbc..22420f111b5 100644
--- a/storage/innobase/include/trx0undo.h
+++ b/storage/innobase/include/trx0undo.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2018, MariaDB Corporation.
+Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -366,8 +366,6 @@ struct trx_undo_t {
(IB_ID_MAX if the undo log is empty) */
buf_block_t* guess_block; /*!< guess for the buffer block where
the top page might reside */
- ulint withdraw_clock; /*!< the withdraw clock value of the
- buffer pool when guess_block was stored */
/** @return whether the undo log is empty */
bool empty() const { return top_undo_no == IB_ID_MAX; }
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index c8c8e66d0b2..1a25cff5961 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -4551,7 +4551,7 @@ lock_print_info_summary(
fprintf(file,
"Purge done for trx's n:o < " TRX_ID_FMT
" undo n:o < " TRX_ID_FMT " state: %s\n"
- "History list length " ULINTPF "\n",
+ "History list length %u\n",
purge_sys.tail.trx_no(),
purge_sys.tail.undo_no,
purge_sys.enabled()
diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc
index 1749c582f2c..ef6dc58e749 100644
--- a/storage/innobase/mtr/mtr0mtr.cc
+++ b/storage/innobase/mtr/mtr0mtr.cc
@@ -233,8 +233,8 @@ static void memo_slot_release(mtr_memo_slot_t *slot)
case MTR_MEMO_PAGE_SX_FIX:
case MTR_MEMO_PAGE_X_FIX:
buf_block_t *block= reinterpret_cast<buf_block_t*>(slot->object);
- buf_block_unfix(block);
buf_page_release_latch(block, slot->type);
+ buf_block_unfix(block);
break;
}
slot->object= NULL;
@@ -276,8 +276,8 @@ struct ReleaseLatches {
case MTR_MEMO_PAGE_SX_FIX:
case MTR_MEMO_PAGE_X_FIX:
buf_block_t *block= reinterpret_cast<buf_block_t*>(slot->object);
- buf_block_unfix(block);
buf_page_release_latch(block, slot->type);
+ buf_block_unfix(block);
break;
}
slot->object= NULL;
diff --git a/storage/innobase/page/page0zip.cc b/storage/innobase/page/page0zip.cc
index f1f10bcd58d..50b2a56a941 100644
--- a/storage/innobase/page/page0zip.cc
+++ b/storage/innobase/page/page0zip.cc
@@ -1654,7 +1654,7 @@ page_zip_fields_free(
{
if (index) {
dict_table_t* table = index->table;
- dict_index_zip_pad_mutex_destroy(index);
+ mysql_mutex_destroy(&index->zip_pad.mutex);
mem_heap_free(index->heap);
dict_mem_table_free(table);
diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc
index c7be4f44ee0..aaab2e1b5ec 100644
--- a/storage/innobase/trx/trx0rec.cc
+++ b/storage/innobase/trx/trx0rec.cc
@@ -1915,7 +1915,6 @@ dberr_t trx_undo_report_rename(trx_t* trx, const dict_table_t* table)
if (ulint offset = trx_undo_page_report_rename(
trx, table, block, &mtr)) {
- undo->withdraw_clock = buf_withdraw_clock;
undo->top_page_no = undo->last_page_no;
undo->top_offset = offset;
undo->top_undo_no = trx->undo_no++;
@@ -2055,7 +2054,6 @@ trx_undo_report_row_operation(
mtr_commit(&mtr);
} else {
/* Success */
- undo->withdraw_clock = buf_withdraw_clock;
mtr_commit(&mtr);
undo->top_page_no = undo_block->page.id.page_no();
diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc
index e43902006d0..7254c830cde 100644
--- a/storage/innobase/trx/trx0undo.cc
+++ b/storage/innobase/trx/trx0undo.cc
@@ -1213,7 +1213,6 @@ trx_undo_mem_create(
undo->top_undo_no = IB_ID_MAX;
undo->top_page_no = page_no;
undo->guess_block = NULL;
- undo->withdraw_clock = 0;
ut_ad(undo->empty());
return(undo);
@@ -1402,9 +1401,7 @@ trx_undo_assign(trx_t* trx, dberr_t* err, mtr_t* mtr)
if (undo) {
return buf_page_get_gen(
page_id_t(undo->rseg->space->id, undo->last_page_no),
- univ_page_size, RW_X_LATCH,
- buf_pool_is_obsolete(undo->withdraw_clock)
- ? NULL : undo->guess_block,
+ univ_page_size, RW_X_LATCH, undo->guess_block,
BUF_GET, __FILE__, __LINE__, mtr, err);
}
@@ -1458,9 +1455,7 @@ trx_undo_assign_low(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo,
if (*undo) {
return buf_page_get_gen(
page_id_t(rseg->space->id, (*undo)->last_page_no),
- univ_page_size, RW_X_LATCH,
- buf_pool_is_obsolete((*undo)->withdraw_clock)
- ? NULL : (*undo)->guess_block,
+ univ_page_size, RW_X_LATCH, (*undo)->guess_block,
BUF_GET, __FILE__, __LINE__, mtr, err);
}