diff options
Diffstat (limited to 'storage/connect/ha_connect.cc')
-rw-r--r-- | storage/connect/ha_connect.cc | 790 |
1 files changed, 500 insertions, 290 deletions
diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index a0ac4668eba..c2fb6481cb0 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -130,24 +130,21 @@ #if defined(ODBC_SUPPORT) #include "odbccat.h" #endif // ODBC_SUPPORT -#if defined(MYSQL_SUPPORT) #include "xtable.h" #include "tabmysql.h" -#endif // MYSQL_SUPPORT #include "filamdbf.h" #include "tabxcl.h" #include "tabfmt.h" #include "reldef.h" #include "tabcol.h" #include "xindex.h" -#if defined(WIN32) +#if defined(__WIN__) #include <io.h> #include "tabwmi.h" -#endif // WIN32 +#endif // __WIN__ #include "connect.h" #include "user_connect.h" #include "ha_connect.h" -#include "mycat.h" #include "myutil.h" #include "preparse.h" #include "inihandl.h" @@ -156,6 +153,7 @@ #endif // LIBXML2_SUPPORT #include "taboccur.h" #include "tabpivot.h" +#include "tabfix.h" #define my_strupr(p) my_caseup_str(default_charset_info, (p)); #define my_strlwr(p) my_casedn_str(default_charset_info, (p)); @@ -165,40 +163,27 @@ /***********************************************************************/ /* Initialize the ha_connect static members. */ /***********************************************************************/ -#define SZCONV 8192 -#define SZWORK 67108864 // Default work area size 64M -#define SZWMIN 4194304 // Minimum work area size 4M +#define SZCONV 8192 +#define SZWORK 67108864 // Default work area size 64M +#define SZWMIN 4194304 // Minimum work area size 4M +#define JSONMAX 10 // JSON Default max grp size extern "C" { - char version[]= "Version 1.03.0006 January 13, 2015"; - char compver[]= "Version 1.03.0006 " __DATE__ " " __TIME__; - -#if defined(WIN32) + char version[]= "Version 1.03.0007 June 03, 2015"; +#if defined(__WIN__) + char compver[]= "Version 1.03.0007 " __DATE__ " " __TIME__; char slash= '\\'; -#else // !WIN32 +#else // !__WIN__ char slash= '/'; -#endif // !WIN32 - -// int trace= 0; // The general trace value - ulong xconv= 0; // The type conversion option - int zconv= 0; // The text conversion size +#endif // !__WIN__ } // extern "C" #if defined(XMAP) my_bool xmap= false; #endif // XMAP -// uint worksize= 0; ulong ha_connect::num= 0; -//int DTVAL::Shift= 0; -/* CONNECT system variables */ -//atic int conv_size= 0; -//atic uint work_size= 0; -//atic ulong type_conv= 0; -#if defined(XMAP) -//atic my_bool indx_map= 0; -#endif // XMAP #if defined(XMSG) extern "C" { char *msg_path; @@ -209,12 +194,17 @@ extern "C" { /* Utility functions. */ /***********************************************************************/ PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info); -PQRYRES VirColumns(PGLOBAL g, char *tab, char *db, bool info); +PQRYRES VirColumns(PGLOBAL g, bool info); +PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info); +PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info); void PushWarning(PGLOBAL g, THD *thd, int level); bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host, const char *db, char *tab, const char *src, int port); bool ExactInfo(void); USETEMP UseTemp(void); +int GetConvSize(void); +TYPCONV GetTypeConv(void); +uint GetJsonGrpSize(void); uint GetWorkSize(void); void SetWorkSize(uint); extern "C" const char *msglang(void); @@ -289,6 +279,44 @@ static MYSQL_THDVAR_UINT(work_size, "Size of the CONNECT work area.", NULL, NULL, SZWORK, SZWMIN, UINT_MAX, 1); +// Size used when converting TEXT columns to VARCHAR +static MYSQL_THDVAR_INT(conv_size, + PLUGIN_VAR_RQCMDARG, // opt + "Size used when converting TEXT columns.", + NULL, NULL, SZCONV, 0, 65500, 1); + +/** + Type conversion: + no: Unsupported types -> TYPE_ERROR + yes: TEXT -> VARCHAR + skip: skip unsupported type columns in Discovery +*/ +const char *xconv_names[]= +{ + "NO", "YES", "SKIP", NullS +}; + +TYPELIB xconv_typelib= +{ + array_elements(xconv_names) - 1, "xconv_typelib", + xconv_names, NULL +}; + +static MYSQL_THDVAR_ENUM( + type_conv, // name + PLUGIN_VAR_RQCMDARG, // opt + "Unsupported types conversion.", // comment + NULL, // check + NULL, // update function + 0, // def (no) + &xconv_typelib); // typelib + +// Estimate max number of rows for JSON aggregate functions +static MYSQL_THDVAR_UINT(json_grp_size, + PLUGIN_VAR_RQCMDARG, // opt + "max number of rows for JSON aggregate functions.", + NULL, NULL, JSONMAX, 1, INT_MAX, 1); + #if defined(XMSG) || defined(NEWMSG) const char *language_names[]= { @@ -317,8 +345,11 @@ static MYSQL_THDVAR_ENUM( extern "C" int GetTraceValue(void) {return THDVAR(current_thd, xtrace);} bool ExactInfo(void) {return THDVAR(current_thd, exact_info);} 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);} +uint GetJsonGrpSize(void) {return THDVAR(current_thd, json_grp_size);} uint GetWorkSize(void) {return THDVAR(current_thd, work_size);} -void SetWorkSize(uint n) +void SetWorkSize(uint) { // Changing the session variable value seems to be impossible here // and should be done in a check function @@ -568,9 +599,9 @@ DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir) delete_table method in handler.cc */ static const char *ha_connect_exts[]= { - ".dos", ".fix", ".csv", ".bin", ".fmt", ".dbf", ".xml", ".ini", ".vec", - ".dnx", ".fnx", ".bnx", ".vnx", ".dbx", ".dop", ".fop", ".bop", ".vop", - NULL}; + ".dos", ".fix", ".csv", ".bin", ".fmt", ".dbf", ".xml", ".json", ".ini", + ".vec", ".dnx", ".fnx", ".bnx", ".vnx", ".dbx", ".dop", ".fop", ".bop", + ".vop", NULL}; /** @brief @@ -598,7 +629,11 @@ static int connect_init_func(void *p) } #endif // 0 (LINUX) +#if defined(__WIN__) sql_print_information("CONNECT: %s", compver); +#else // !__WIN__ + sql_print_information("CONNECT: %s", version); +#endif // !__WIN__ #ifdef LIBXML2_SUPPORT XmlInitParserLib(); @@ -621,6 +656,7 @@ static int connect_init_func(void *p) sql_print_information("connect_init: hton=%p", p); DTVAL::SetTimeShift(); // Initialize time zone shift once for all + BINCOL::SetEndian(); // Initialize host endian setting DBUG_RETURN(0); } // end of connect_init_func @@ -629,7 +665,7 @@ static int connect_init_func(void *p) @brief Plugin clean up */ -static int connect_done_func(void *p) +static int connect_done_func(void *) { int error= 0; PCONNECT pc, pn; @@ -639,9 +675,9 @@ static int connect_done_func(void *p) XmlCleanupParserLib(); #endif // LIBXML2_SUPPORT -#if !defined(WIN32) +#if !defined(__WIN__) //PROFILE_End(); Causes signal 11 -#endif // !WIN32 +#endif // !__WIN__ for (pc= user_connect::to_users; pc; pc= pn) { if (pc->g) @@ -708,11 +744,11 @@ ha_connect::ha_connect(handlerton *hton, TABLE_SHARE *table_arg) xp= (table) ? GetUser(ha_thd(), NULL) : NULL; if (xp) xp->SetHandler(this); -#if defined(WIN32) +#if defined(__WIN__) datapath= ".\\"; -#else // !WIN32 +#else // !__WIN__ datapath= "./"; -#endif // !WIN32 +#endif // !__WIN__ tdbp= NULL; sdvalin1= sdvalin2= sdvalin3= sdvalin4= NULL; sdvalout= NULL; @@ -787,8 +823,6 @@ ha_connect::~ha_connect(void) /****************************************************************************/ static PCONNECT GetUser(THD *thd, PCONNECT xp) { - const char *dbn= NULL; - if (!thd) return NULL; @@ -800,7 +834,7 @@ static PCONNECT GetUser(THD *thd, PCONNECT xp) break; if (!xp) { - xp= new user_connect(thd, dbn); + xp= new user_connect(thd); if (xp->user_init()) { delete xp; @@ -873,7 +907,8 @@ const char *ha_connect::index_type(uint inx) If all_parts is set, MySQL wants to know the flags for the combined index, up to and including 'part'. */ -ulong ha_connect::index_flags(uint inx, uint part, bool all_parts) const +//ong ha_connect::index_flags(uint inx, uint part, bool all_parts) const +ulong ha_connect::index_flags(uint, uint, bool) const { ulong flags= HA_READ_NEXT | HA_READ_RANGE | HA_KEYREAD_ONLY | HA_KEY_SCAN_NOT_ROR; @@ -934,6 +969,9 @@ ulonglong ha_connect::table_flags() const char *GetListOption(PGLOBAL g, const char *opname, const char *oplist, const char *def) { + if (!oplist) + return (char*)def; + char key[16], val[256]; char *pk, *pv, *pn; char *opval= (char*) def; @@ -968,8 +1006,7 @@ char *GetListOption(PGLOBAL g, const char *opname, } // endif pv if (!stricmp(opname, key)) { - opval= (char*)PlugSubAlloc(g, NULL, strlen(val) + 1); - strcpy(opval, val); + opval= PlugDup(g, val); break; } else if (!pn) break; @@ -980,6 +1017,117 @@ char *GetListOption(PGLOBAL g, const char *opname, } // end of GetListOption /****************************************************************************/ +/* Return the value of a string option or NULL if not specified. */ +/****************************************************************************/ +char *GetStringTableOption(PGLOBAL g, PTOS options, char *opname, char *sdef) +{ + const char *opval= NULL; + + if (!options) + return sdef; + else if (!stricmp(opname, "Type")) + opval= options->type; + else if (!stricmp(opname, "Filename")) + opval= options->filename; + else if (!stricmp(opname, "Optname")) + opval= options->optname; + else if (!stricmp(opname, "Tabname")) + opval= options->tabname; + else if (!stricmp(opname, "Tablist")) + opval= options->tablist; + else if (!stricmp(opname, "Database") || + !stricmp(opname, "DBname")) + opval= options->dbname; + else if (!stricmp(opname, "Separator")) + opval= options->separator; + else if (!stricmp(opname, "Qchar")) + opval= options->qchar; + else if (!stricmp(opname, "Module")) + opval= options->module; + else if (!stricmp(opname, "Subtype")) + opval= options->subtype; + else if (!stricmp(opname, "Catfunc")) + opval= options->catfunc; + else if (!stricmp(opname, "Srcdef")) + opval= options->srcdef; + else if (!stricmp(opname, "Colist")) + opval= options->colist; + else if (!stricmp(opname, "Data_charset")) + opval= options->data_charset; + + if (!opval && options && options->oplist) + opval= GetListOption(g, opname, options->oplist); + + return opval ? (char*)opval : sdef; +} // end of GetStringTableOption + +/****************************************************************************/ +/* Return the value of a Boolean option or bdef if not specified. */ +/****************************************************************************/ +bool GetBooleanTableOption(PGLOBAL g, PTOS options, char *opname, bool bdef) +{ + bool opval= bdef; + char *pv; + + if (!options) + return bdef; + else if (!stricmp(opname, "Mapped")) + opval= options->mapped; + else if (!stricmp(opname, "Huge")) + opval= options->huge; + else if (!stricmp(opname, "Split")) + opval= options->split; + else if (!stricmp(opname, "Readonly")) + opval= options->readonly; + else if (!stricmp(opname, "SepIndex")) + opval= options->sepindex; + else if (!stricmp(opname, "Header")) + opval= (options->header != 0); // Is Boolean for some table types + else if (options->oplist) + if ((pv= GetListOption(g, opname, options->oplist))) + opval= (!*pv || *pv == 'y' || *pv == 'Y' || atoi(pv) != 0); + + return opval; +} // end of GetBooleanTableOption + +/****************************************************************************/ +/* Return the value of an integer option or NO_IVAL if not specified. */ +/****************************************************************************/ +int GetIntegerTableOption(PGLOBAL g, PTOS options, char *opname, int idef) +{ + ulonglong opval= NO_IVAL; + + if (!options) + return idef; + else if (!stricmp(opname, "Lrecl")) + opval= options->lrecl; + else if (!stricmp(opname, "Elements")) + opval= options->elements; + else if (!stricmp(opname, "Multiple")) + opval= options->multiple; + else if (!stricmp(opname, "Header")) + opval= options->header; + else if (!stricmp(opname, "Quoted")) + opval= options->quoted; + else if (!stricmp(opname, "Ending")) + opval= options->ending; + else if (!stricmp(opname, "Compressed")) + opval= (options->compressed); + + if (opval == NO_IVAL) { + char *pv; + + if ((pv= GetListOption(g, opname, options->oplist))) + opval= CharToNumber(pv, strlen(pv), ULONGLONG_MAX, true); + else + return idef; + + } // endif opval + + return (int)opval; +} // end of GetIntegerTableOption + +/****************************************************************************/ /* Return the table option structure. */ /****************************************************************************/ PTOS ha_connect::GetTableOptionStruct(TABLE_SHARE *s) @@ -997,8 +1145,9 @@ char *ha_connect::GetRealString(const char *s) char *sv; if (IsPartitioned() && s) { - sv= (char*)PlugSubAlloc(xp->g, NULL, strlen(s) + strlen(partname)); + sv= (char*)PlugSubAlloc(xp->g, NULL, 0); sprintf(sv, s, partname); + PlugSubAlloc(xp->g, NULL, strlen(sv) + 1); } else sv= (char*)s; @@ -1006,7 +1155,7 @@ char *ha_connect::GetRealString(const char *s) } // end of GetRealString /****************************************************************************/ -/* Return the value of a string option or NULL if not specified. */ +/* Return the value of a string option or sdef if not specified. */ /****************************************************************************/ char *ha_connect::GetStringOption(char *opname, char *sdef) { @@ -1024,37 +1173,6 @@ char *ha_connect::GetStringOption(char *opname, char *sdef) opval= thd_query_string(table->in_use)->str; else if (!stricmp(opname, "Partname")) opval= partname; - else if (!options) - ; - else if (!stricmp(opname, "Type")) - opval= (char*)options->type; - else if (!stricmp(opname, "Filename")) - opval= GetRealString(options->filename); - else if (!stricmp(opname, "Optname")) - opval= (char*)options->optname; - else if (!stricmp(opname, "Tabname")) - opval= GetRealString(options->tabname); - else if (!stricmp(opname, "Tablist")) - opval= (char*)options->tablist; - else if (!stricmp(opname, "Database") || - !stricmp(opname, "DBname")) - opval= (char*)options->dbname; - else if (!stricmp(opname, "Separator")) - opval= (char*)options->separator; - else if (!stricmp(opname, "Qchar")) - opval= (char*)options->qchar; - else if (!stricmp(opname, "Module")) - opval= (char*)options->module; - else if (!stricmp(opname, "Subtype")) - opval= (char*)options->subtype; - else if (!stricmp(opname, "Catfunc")) - opval= (char*)options->catfunc; - else if (!stricmp(opname, "Srcdef")) - opval= (char*)options->srcdef; - else if (!stricmp(opname, "Colist")) - opval= (char*)options->colist; - else if (!stricmp(opname, "Data_charset")) - opval= (char*)options->data_charset; else if (!stricmp(opname, "Table_charset")) { const CHARSET_INFO *chif= (tshp) ? tshp->table_charset : table->s->table_charset; @@ -1062,10 +1180,13 @@ char *ha_connect::GetStringOption(char *opname, char *sdef) if (chif) opval= (char*)chif->csname; - } // endif Table_charset + } else + opval= GetStringTableOption(xp->g, options, opname, NULL); - if (!opval && options && options->oplist) - opval= GetListOption(xp->g, opname, options->oplist); + if (opval && (!stricmp(opname, "connect") + || !stricmp(opname, "tabname") + || !stricmp(opname, "filename"))) + opval = GetRealString(opval); if (!opval) { if (sdef && !strcmp(sdef, "*")) { @@ -1096,31 +1217,13 @@ char *ha_connect::GetStringOption(char *opname, char *sdef) /****************************************************************************/ bool ha_connect::GetBooleanOption(char *opname, bool bdef) { - bool opval= bdef; - char *pv; + bool opval; PTOS options= GetTableOptionStruct(); if (!stricmp(opname, "View")) opval= (tshp) ? tshp->is_view : table_share->is_view; - else if (!options) - ; - else if (!stricmp(opname, "Mapped")) - opval= options->mapped; - else if (!stricmp(opname, "Huge")) - opval= options->huge; -//else if (!stricmp(opname, "Compressed")) -// opval= options->compressed; - else if (!stricmp(opname, "Split")) - opval= options->split; - else if (!stricmp(opname, "Readonly")) - opval= options->readonly; - else if (!stricmp(opname, "SepIndex")) - opval= options->sepindex; - else if (!stricmp(opname, "Header")) - opval= (options->header != 0); // Is Boolean for some table types - else if (options->oplist) - if ((pv= GetListOption(xp->g, opname, options->oplist))) - opval= (!*pv || *pv == 'y' || *pv == 'Y' || atoi(pv) != 0); + else + opval= GetBooleanTableOption(xp->g, options, opname, bdef); return opval; } // end of GetBooleanOption @@ -1149,37 +1252,18 @@ bool ha_connect::SetBooleanOption(char *opname, bool b) /****************************************************************************/ int ha_connect::GetIntegerOption(char *opname) { - ulonglong opval= NO_IVAL; - char *pv; + int opval; PTOS options= GetTableOptionStruct(); TABLE_SHARE *tsp= (tshp) ? tshp : table_share; if (!stricmp(opname, "Avglen")) - opval= (ulonglong)tsp->avg_row_length; + opval= (int)tsp->avg_row_length; else if (!stricmp(opname, "Estimate")) - opval= (ulonglong)tsp->max_rows; - else if (!options) - ; - else if (!stricmp(opname, "Lrecl")) - opval= options->lrecl; - else if (!stricmp(opname, "Elements")) - opval= options->elements; - else if (!stricmp(opname, "Multiple")) - opval= options->multiple; - else if (!stricmp(opname, "Header")) - opval= options->header; - else if (!stricmp(opname, "Quoted")) - opval= options->quoted; - else if (!stricmp(opname, "Ending")) - opval= options->ending; - else if (!stricmp(opname, "Compressed")) - opval= (options->compressed); - - if (opval == (ulonglong)NO_IVAL && options && options->oplist) - if ((pv= GetListOption(xp->g, opname, options->oplist))) - opval= CharToNumber(pv, strlen(pv), ULONGLONG_MAX, true); + opval= (int)tsp->max_rows; + else + opval= GetIntegerTableOption(xp->g, options, opname, NO_IVAL); - return (int)opval; + return opval; } // end of GetIntegerOption /****************************************************************************/ @@ -1443,8 +1527,7 @@ PIXDEF ha_connect::GetIndexInfo(TABLE_SHARE *s) // Now get index information pn= (char*)s->keynames.type_names[n]; - name= (char*)PlugSubAlloc(g, NULL, strlen(pn) + 1); - strcpy(name, pn); // This is probably unuseful + name= PlugDup(g, pn); unique= (kp.flags & 1) != 0; pkp= NULL; @@ -1454,8 +1537,7 @@ PIXDEF ha_connect::GetIndexInfo(TABLE_SHARE *s) // Get the the key parts info for (int k= 0; (unsigned)k < kp.user_defined_key_parts; k++) { pn= (char*)kp.key_part[k].field->field_name; - name= (char*)PlugSubAlloc(g, NULL, strlen(pn) + 1); - strcpy(name, pn); // This is probably unuseful + name= PlugDup(g, pn); // Allocate the key part description block kpp= new(g) KPARTDEF(name, k + 1); @@ -1962,7 +2044,7 @@ int ha_connect::MakeRecord(char *buf) /***********************************************************************/ /* Set row values from a MySQL pseudo record. Specific to MySQL. */ /***********************************************************************/ -int ha_connect::ScanRecord(PGLOBAL g, uchar *buf) +int ha_connect::ScanRecord(PGLOBAL g, uchar *) { char attr_buffer[1024]; char data_buffer[1024]; @@ -2104,7 +2186,7 @@ int ha_connect::ScanRecord(PGLOBAL g, uchar *buf) /* Check change in index column. Specific to MySQL. */ /* Should be elaborated to check for real changes. */ /***********************************************************************/ -int ha_connect::CheckRecord(PGLOBAL g, const uchar *oldbuf, uchar *newbuf) +int ha_connect::CheckRecord(PGLOBAL g, const uchar *, uchar *newbuf) { return ScanRecord(g, newbuf); } // end of dummy CheckRecord @@ -2113,12 +2195,12 @@ int ha_connect::CheckRecord(PGLOBAL g, const uchar *oldbuf, uchar *newbuf) /***********************************************************************/ /* Return the where clause for remote indexed read. */ /***********************************************************************/ -bool ha_connect::MakeKeyWhere(PGLOBAL g, char *qry, OPVAL op, char *q, +bool ha_connect::MakeKeyWhere(PGLOBAL g, PSTRG qry, OPVAL op, char q, const void *key, int klen) { const uchar *ptr; uint rem, len, stlen; //, prtlen; - bool nq, b= false; + bool nq, oom, b= false; Field *fp; KEY *kfp; KEY_PART_INFO *kpart; @@ -2130,7 +2212,7 @@ bool ha_connect::MakeKeyWhere(PGLOBAL g, char *qry, OPVAL op, char *q, return true; } // endif key - strcat(qry, " WHERE ("); + oom= qry->Append(" WHERE ("); kfp= &table->key_info[active_index]; rem= kfp->user_defined_key_parts, len= klen, @@ -2143,24 +2225,26 @@ bool ha_connect::MakeKeyWhere(PGLOBAL g, char *qry, OPVAL op, char *q, nq= fp->str_needs_quotes(); if (b) - strcat(qry, " AND "); + oom|= qry->Append(" AND "); else b= true; - strcat(strncat(strcat(qry, q), fp->field_name, strlen(fp->field_name)), q); + oom|= qry->Append(q); + oom|= qry->Append((PSZ)fp->field_name); + oom|= qry->Append(q); switch (op) { case OP_EQ: case OP_GT: case OP_GE: - strcat(qry, GetValStr(op, false)); + oom|= qry->Append((PSZ)GetValStr(op, false)); break; default: - strcat(qry, " ??? "); + oom|= qry->Append(" ??? "); } // endwitch op if (nq) - strcat(qry, "'"); + oom|= qry->Append('\''); if (kpart->key_part_flag & HA_VAR_LENGTH_PART) { String varchar; @@ -2168,17 +2252,17 @@ bool ha_connect::MakeKeyWhere(PGLOBAL g, char *qry, OPVAL op, char *q, varchar.set_quick((char*) ptr+HA_KEY_BLOB_LENGTH, var_length, &my_charset_bin); - strncat(qry, varchar.ptr(), varchar.length()); + oom|= qry->Append(varchar.ptr(), varchar.length()); } else { char strbuff[MAX_FIELD_WIDTH]; String str(strbuff, sizeof(strbuff), kpart->field->charset()), *res; res= fp->val_str(&str, ptr); - strncat(qry, res->ptr(), res->length()); + oom|= qry->Append(res->ptr(), res->length()); } // endif flag if (nq) - strcat(qry, "'"); + oom|= qry->Append('\''); if (stlen >= len) break; @@ -2191,8 +2275,10 @@ bool ha_connect::MakeKeyWhere(PGLOBAL g, char *qry, OPVAL op, char *q, ptr+= stlen - MY_TEST(kpart->null_bit); } // endfor kpart - strcat(qry, ")"); - return false; + if ((oom|= qry->Append(")"))) + strcpy(g->Message, "Out of memory"); + + return oom; } // end of MakeKeyWhere @@ -2467,6 +2553,8 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond) char *body= filp->Body; unsigned int i; bool ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC); + bool nonul= (tty == TYPE_AM_ODBC && (tdbp->GetMode() == MODE_INSERT || + tdbp->GetMode() == MODE_DELETE)); OPVAL vop= OP_XX; if (!cond) @@ -2484,7 +2572,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond) if (trace) htrc("Cond: Ftype=%d name=%s\n", cond_item->functype(), - cond_item->func_name()); + cond_item->func_name()); switch (cond_item->functype()) { case Item_func::COND_AND_FUNC: vop= OP_AND; break; @@ -2503,7 +2591,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond) for (i= 0; i < arglist->elements; i++) if ((subitem= li++)) { if (!CheckCond(g, filp, tty, subitem)) { - if (vop == OP_OR) + if (vop == OP_OR || nonul) return NULL; else *p2= 0; @@ -2599,6 +2687,8 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond) if (trace) { htrc("Field index=%d\n", pField->field->field_index); htrc("Field name=%s\n", pField->field->field_name); + htrc("Field type=%d\n", pField->field->type()); + htrc("Field_type=%d\n", args[i]->field_type()); } // endif trace // IN and BETWEEN clauses should be col VOP list @@ -2618,8 +2708,9 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond) char buff[256]; String *res, tmp(buff, sizeof(buff), &my_charset_bin); Item_basic_constant *pval= (Item_basic_constant *)args[i]; + Item::Type type= args[i]->real_type(); - switch (args[i]->real_type()) { + switch (type) { case COND::STRING_ITEM: case COND::INT_ITEM: case COND::REAL_ITEM: @@ -2644,10 +2735,73 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond) if (!x) { // Append the value to the filter - if (args[i]->field_type() == MYSQL_TYPE_VARCHAR) - strcat(strncat(strcat(body, "'"), res->ptr(), res->length()), "'"); - else - strncat(body, res->ptr(), res->length()); + switch (args[i]->field_type()) { + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: + if (tty == TYPE_AM_ODBC) { + strcat(body, "{ts '"); + strncat(body, res->ptr(), res->length()); + + if (res->length() < 19) + strcat(body, "1970-01-01 00:00:00" + res->length()); + + strcat(body, "'}"); + break; + } // endif ODBC + + case MYSQL_TYPE_DATE: + if (tty == TYPE_AM_ODBC) { + strcat(body, "{d '"); + strcat(strncat(body, res->ptr(), res->length()), "'}"); + break; + } // endif ODBC + + case MYSQL_TYPE_TIME: + if (tty == TYPE_AM_ODBC) { + strcat(body, "{t '"); + strcat(strncat(body, res->ptr(), res->length()), "'}"); + break; + } // endif ODBC + + case MYSQL_TYPE_VARCHAR: + if (tty == TYPE_AM_ODBC && i) { + switch (args[0]->field_type()) { + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: + strcat(body, "{ts '"); + strncat(body, res->ptr(), res->length()); + + if (res->length() < 19) + strcat(body, "1970-01-01 00:00:00" + res->length()); + + strcat(body, "'}"); + break; + case MYSQL_TYPE_DATE: + strcat(body, "{d '"); + strncat(body, res->ptr(), res->length()); + strcat(body, "'}"); + break; + case MYSQL_TYPE_TIME: + strcat(body, "{t '"); + strncat(body, res->ptr(), res->length()); + strcat(body, "'}"); + break; + default: + strcat(body, "'"); + strncat(body, res->ptr(), res->length()); + strcat(body, "'"); + } // endswitch field type + + } else { + strcat(body, "'"); + strncat(body, res->ptr(), res->length()); + strcat(body, "'"); + } // endif tty + + break; + default: + strncat(body, res->ptr(), res->length()); + } // endswitch field type } else { if (args[i]->field_type() == MYSQL_TYPE_VARCHAR) { @@ -2753,7 +2907,7 @@ const COND *ha_connect::cond_push(const COND *cond) } else if (x && cond) tdbp->SetCondFil(filp); // Wrong filter - } else + } else if (tty != TYPE_AM_JSN && tty != TYPE_AM_JSON) tdbp->SetFilter(CondFilter(g, (Item *)cond)); fin: @@ -2805,7 +2959,7 @@ bool ha_connect::get_error_message(int error, String* buf) &dummy_errors); if (trace) - htrc("GEM(%u): %s\n", len, g->Message); + htrc("GEM(%d): len=%u %s\n", error, len, g->Message); msg[len]= '\0'; buf->copy(msg, (uint)strlen(msg), system_charset_info); @@ -2901,7 +3055,7 @@ int ha_connect::open(const char *name, int mode, uint test_if_locked) @brief Make the indexes for this table */ -int ha_connect::optimize(THD* thd, HA_CHECK_OPT* check_opt) +int ha_connect::optimize(THD* thd, HA_CHECK_OPT*) { int rc= 0; PGLOBAL& g= xp->g; @@ -3105,7 +3259,7 @@ int ha_connect::update_row(const uchar *old_data, uchar *new_data) @see sql_acl.cc, sql_udf.cc, sql_delete.cc, sql_insert.cc and sql_select.cc */ -int ha_connect::delete_row(const uchar *buf) +int ha_connect::delete_row(const uchar *) { int rc= 0; DBUG_ENTER("ha_connect::delete_row"); @@ -3385,7 +3539,8 @@ int ha_connect::index_last(uchar *buf) /****************************************************************************/ /* This is called to get more rows having the same index value. */ /****************************************************************************/ -int ha_connect::index_next_same(uchar *buf, const uchar *key, uint keylen) +//t ha_connect::index_next_same(uchar *buf, const uchar *key, uint keylen) +int ha_connect::index_next_same(uchar *buf, const uchar *, uint) { int rc; DBUG_ENTER("ha_connect::index_next_same"); @@ -3575,7 +3730,7 @@ int ha_connect::rnd_next(uchar *buf) @see filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc */ -void ha_connect::position(const uchar *record) +void ha_connect::position(const uchar *) { DBUG_ENTER("ha_connect::position"); //if (((PTDBASE)tdbp)->GetDef()->Indexable()) @@ -3758,7 +3913,7 @@ int ha_connect::info(uint flag) @see ha_innodb.cc */ -int ha_connect::extra(enum ha_extra_function operation) +int ha_connect::extra(enum ha_extra_function /*operation*/) { DBUG_ENTER("ha_connect::extra"); DBUG_RETURN(0); @@ -3837,11 +3992,11 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn) case TAB_JSON: if (options->filename && *options->filename) { char *s, path[FN_REFLEN], dbpath[FN_REFLEN]; -#if defined(WIN32) +#if defined(__WIN__) s= "\\"; -#else // !WIN32 +#else // !__WIN__ s= "/"; -#endif // !WIN32 +#endif // !__WIN__ strcpy(dbpath, mysql_real_data_home); if (db) @@ -3990,6 +4145,7 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, case SQLCOM_UPDATE_MULTI: case SQLCOM_SELECT: case SQLCOM_OPTIMIZE: + case SQLCOM_SET_OPTION: break; case SQLCOM_LOCK_TABLES: locked= 1; @@ -4014,6 +4170,10 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, break; // } // endif partitioned + case SQLCOM_END: + // Met in procedures: IF(EXISTS(SELECT... + newmode= MODE_READ; + break; default: htrc("Unsupported sql_command=%d\n", thd_sql_command(thd)); strcpy(g->Message, "CONNECT Unsupported command"); @@ -4361,7 +4521,7 @@ int ha_connect::external_lock(THD *thd, int lock_type) @see get_lock_data() in lock.cc */ -THR_LOCK_DATA **ha_connect::store_lock(THD *thd, +THR_LOCK_DATA **ha_connect::store_lock(THD *, THR_LOCK_DATA **to, enum thr_lock_type lock_type) { @@ -4509,8 +4669,13 @@ int ha_connect::delete_or_rename_table(const char *name, const char *to) } // endif pos - } else // Avoid infamous DBUG_ASSERT - thd->get_stmt_da()->reset_diagnostics_area(); + } // endif open_table_def + +// This below was done to avoid DBUG_ASSERT in some case that +// we don't know anymore what they were. It was suppressed because +// it did cause assertion in other cases (see MDEV-7935) +// } else // Avoid infamous DBUG_ASSERT +// thd->get_stmt_da()->reset_diagnostics_area(); free_table_share(share); } else // Temporary file @@ -4590,9 +4755,31 @@ ha_rows ha_connect::records_in_range(uint inx, key_range *min_key, else rows= HA_POS_ERROR; + if (trace) + htrc("records_in_range: rows=%llu\n", rows); + DBUG_RETURN(rows); } // end of records_in_range +// Used to check whether a MYSQL table is created on itself +bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host, + const char *db, char *tab, const char *src, int port) +{ + if (src) + return false; + else if (host && stricmp(host, "localhost") && strcmp(host, "127.0.0.1")) + return false; + else if (db && stricmp(db, s->db.str)) + return false; + else if (tab && stricmp(tab, s->table_name.str)) + return false; + else if (port && port != (signed)GetDefaultPort()) + return false; + + strcpy(g->Message, "This MySQL table is defined on itself"); + return true; +} // end of CheckSelf + /** Convert an ISO-8859-1 column name to UTF-8 */ @@ -4615,12 +4802,12 @@ 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, int flag, bool dbf, char v) +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 error= false; + bool q, error= false; const char *type= PLGtoMYSQLtype(typ, dbf, var); error|= sql->append('`'); @@ -4661,7 +4848,12 @@ static bool add_field(String *sql, const char *field_name, int typ, if (dft && *dft) { error|= sql->append(" DEFAULT "); - if (!IsTypeNum(typ)) { + 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("'"); @@ -4681,6 +4873,12 @@ static bool add_field(String *sql, const char *field_name, int typ, 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); @@ -4743,7 +4941,7 @@ static int init_table_share(THD* thd, oom|= sql->append(' '); oom|= sql->append(opt->name); oom|= sql->append('='); - oom|= sql->append(vull ? "ON" : "OFF"); + oom|= sql->append(vull ? "YES" : "NO"); } // endif vull break; @@ -4785,25 +4983,6 @@ static int init_table_share(THD* thd, sql->ptr(), sql->length()); } // end of init_table_share -// Used to check whether a MYSQL table is created on itself -bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host, - const char *db, char *tab, const char *src, int port) -{ - if (src) - return false; - else if (host && stricmp(host, "localhost") && strcmp(host, "127.0.0.1")) - return false; - else if (db && stricmp(db, s->db.str)) - return false; - else if (tab && stricmp(tab, s->table_name.str)) - return false; - else if (port && port != (signed)GetDefaultPort()) - return false; - - strcpy(g->Message, "This MySQL table is defined on itself"); - return true; -} // end of CheckSelf - /** @brief connect_assisted_discovery() is called when creating a table with no columns. @@ -4816,7 +4995,7 @@ bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host, @note this function is no more called in case of CREATE .. SELECT */ -static int connect_assisted_discovery(handlerton *hton, THD* thd, +static int connect_assisted_discovery(handlerton *, THD* thd, TABLE_SHARE *table_s, HA_CREATE_INFO *create_info) { @@ -4825,12 +5004,15 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, const char *user, *fn, *db, *host, *pwd, *sep, *tbl, *src; const char *col, *ocl, *rnk, *pic, *fcl, *skc; char *tab, *dsn, *shm, *dpath; -#if defined(WIN32) +#if defined(__WIN__) char *nsp= NULL, *cls= NULL; -#endif // WIN32 - int port= 0, hdr= 0, mxr __attribute__((unused))= 0, mxe= 0, rc= 0; - int cop __attribute__((unused)) = 0; +#endif // __WIN__ + int port= 0, hdr= 0, mxr= 0, mxe= 0, rc= 0; + int cop __attribute__((unused))= 0, lrecl= 0; #if defined(ODBC_SUPPORT) + POPARM sop = NULL; + char *ucnc = NULL; + bool cnc= false; int cto= -1, qto= -1; #endif // ODBC_SUPPORT uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL); @@ -4872,10 +5054,12 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, hdr= (int)topt->header; tbl= topt->tablist; col= topt->colist; + lrecl= (int)topt->lrecl; if (topt->oplist) { host= GetListOption(g, "host", topt->oplist, "localhost"); - user= GetListOption(g, "user", topt->oplist, "root"); + user= GetListOption(g, "user", topt->oplist, + (ttp == TAB_ODBC ? NULL : "root")); // Default value db can come from the DBNAME=xxx option. db= GetListOption(g, "database", topt->oplist, db); col= GetListOption(g, "colist", topt->oplist, col); @@ -4885,15 +5069,18 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, skc= GetListOption(g, "skipcol", topt->oplist, NULL); rnk= GetListOption(g, "rankcol", topt->oplist, NULL); pwd= GetListOption(g, "password", topt->oplist); -#if defined(WIN32) +#if defined(__WIN__) nsp= GetListOption(g, "namespace", topt->oplist); cls= GetListOption(g, "class", topt->oplist); -#endif // WIN32 +#endif // __WIN__ port= atoi(GetListOption(g, "port", topt->oplist, "0")); #if defined(ODBC_SUPPORT) mxr= atoi(GetListOption(g,"maxres", topt->oplist, "0")); cto= atoi(GetListOption(g,"ConnectTimeout", topt->oplist, "-1")); qto= atoi(GetListOption(g,"QueryTimeout", topt->oplist, "-1")); + + if ((ucnc= GetListOption(g, "UseDSN", topt->oplist))) + cnc= (!*ucnc || *ucnc == 'y' || *ucnc == 'Y' || atoi(ucnc) != 0); #endif mxe= atoi(GetListOption(g,"maxerr", topt->oplist, "0")); #if defined(PROMPT_OK) @@ -4901,7 +5088,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, #endif // PROMPT_OK } else { host= "localhost"; - user= "root"; + user= (ttp == TAB_ODBC ? NULL : "root"); } // endif option_list if (!(shm= (char*)db)) @@ -4942,8 +5129,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, goto err; } // endif tbl - tab= (char*)PlugSubAlloc(g, NULL, strlen(tbl) + 1); - strcpy(tab, tbl); + tab= PlugDup(g, tbl); if ((p= strchr(tab, ','))) *p= 0; @@ -4978,10 +5164,18 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, } // endif dsn #endif // PROMPT_OK - } else if (!dsn) + } else if (!dsn) { sprintf(g->Message, "Missing %s connection string", topt->type); - else + } else { + // Store ODBC additional parameters + sop= (POPARM)PlugSubAlloc(g, NULL, sizeof(ODBCPARM)); + sop->User= (char*)user; + sop->Pwd= (char*)pwd; + sop->Cto= cto; + sop->Qto= qto; + sop->UseCnc= cnc; ok= true; + } // endif's supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER); break; @@ -4996,7 +5190,6 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ok= true; break; -#if defined(MYSQL_SUPPORT) case TAB_MYSQL: ok= true; @@ -5036,14 +5229,15 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ok= false; break; -#endif // MYSQL_SUPPORT -#if defined(WIN32) +#if defined(__WIN__) case TAB_WMI: ok= true; break; -#endif // WIN32 +#endif // __WIN__ +#if defined(PIVOT_SUPPORT) case TAB_PIVOT: supfnc= FNC_NO; +#endif // PIVOT_SUPPORT case TAB_PRX: case TAB_TBL: case TAB_XCL: @@ -5062,6 +5256,16 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, strcpy(g->Message, "Missing OEM module or subtype"); break; +#if defined(LIBXML2_SUPPORT) || defined(DOMDOC_SUPPORT) + case TAB_XML: +#endif // LIBXML2_SUPPORT || DOMDOC_SUPPORT + case TAB_JSON: + if (!fn) + sprintf(g->Message, "Missing %s file name", topt->type); + else + ok= true; + + break; case TAB_VIR: ok= true; break; @@ -5083,7 +5287,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, } // endif src if (ok) { - char *cnm, *rem, *dft, *xtra, *key; + char *cnm, *rem, *dft, *xtra, *key, *fmt; int i, len, prec, dec, typ, flg; // if (cat) @@ -5112,15 +5316,15 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, case FNC_NO: case FNC_COL: if (src) { - qrp= ODBCSrcCols(g, dsn, (char*)src, cto, qto); + qrp= ODBCSrcCols(g, dsn, (char*)src, sop); src= NULL; // for next tests } else - qrp= ODBCColumns(g, dsn, shm, tab, NULL, - mxr, cto, qto, fnc == FNC_COL); + qrp= ODBCColumns(g, dsn, shm, tab, NULL, + mxr, fnc == FNC_COL, sop); break; case FNC_TABLE: - qrp= ODBCTables(g, dsn, shm, tab, mxr, cto, qto, true); + qrp= ODBCTables(g, dsn, shm, tab, mxr, true, sop); break; case FNC_DSN: qrp= ODBCDataSources(g, mxr, true); @@ -5135,20 +5339,18 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, break; #endif // ODBC_SUPPORT -#if defined(MYSQL_SUPPORT) case TAB_MYSQL: qrp= MyColumns(g, thd, host, db, user, pwd, tab, NULL, port, fnc == FNC_COL); break; -#endif // MYSQL_SUPPORT case TAB_CSV: qrp= CSVColumns(g, dpath, fn, spc, qch, hdr, mxe, fnc == FNC_COL); break; -#if defined(WIN32) +#if defined(__WIN__) case TAB_WMI: qrp= WMIColumns(g, nsp, cls, fnc == FNC_COL); break; -#endif // WIN32 +#endif // __WIN__ case TAB_PRX: case TAB_TBL: case TAB_XCL: @@ -5166,12 +5368,22 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, } // endif OcrColumns break; +#if defined(PIVOT_SUPPORT) case TAB_PIVOT: qrp= PivotColumns(g, tab, src, pic, fcl, skc, host, db, user, pwd, port); break; +#endif // PIVOT_SUPPORT case TAB_VIR: - qrp= VirColumns(g, tab, (char*)db, fnc == FNC_COL); + qrp= VirColumns(g, fnc == FNC_COL); + break; + case TAB_JSON: + qrp= JSONColumns(g, (char*)db, topt, fnc == FNC_COL); + break; +#if defined(LIBXML2_SUPPORT) || defined(DOMDOC_SUPPORT) + case TAB_XML: + qrp= XMLColumns(g, (char*)db, tab, topt, fnc == FNC_COL); break; +#endif // LIBXML2_SUPPORT || DOMDOC_SUPPORT case TAB_OEM: qrp= OEMColumns(g, topt, tab, (char*)db, fnc == FNC_COL); break; @@ -5188,7 +5400,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, if (fnc != FNC_NO || src || ttp == TAB_PIVOT) { // Catalog like table for (crp= qrp->Colresp; !rc && crp; crp= crp->Next) { - cnm= encode(g, crp->Name); + cnm= (ttp == TAB_PIVOT) ? crp->Name : encode(g, crp->Name); typ= crp->Type; len= crp->Length; dec= crp->Prec; @@ -5204,12 +5416,14 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, NOT_NULL_FLAG, "", flg, dbf, v); #else // !NEW_WAY if (add_field(&sql, cnm, typ, len, dec, NULL, NOT_NULL_FLAG, - NULL, NULL, NULL, flg, dbf, v)) + NULL, NULL, NULL, NULL, flg, dbf, v)) rc= HA_ERR_OUT_OF_MEM; #endif // !NEW_WAY } // endfor crp - } else { + } else { + char *schem= NULL; + // Not a catalog table if (!qrp->Nblin) { if (tab) @@ -5225,7 +5439,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, typ= len= prec= dec= 0; tm= NOT_NULL_FLAG; cnm= (char*)"noname"; - dft= xtra= key= NULL; + dft= xtra= key= fmt= NULL; v= ' '; #if defined(NEW_WAY) rem= ""; @@ -5237,9 +5451,10 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, for (crp= qrp->Colresp; crp; crp= crp->Next) switch (crp->Fld) { case FLD_NAME: - if (ttp == TAB_CSV && topt->data_charset && + if (ttp == TAB_PRX || + (ttp == TAB_CSV && topt->data_charset && (!stricmp(topt->data_charset, "UTF8") || - !stricmp(topt->data_charset, "UTF-8"))) + !stricmp(topt->data_charset, "UTF-8")))) cnm= crp->Kdata->GetCharValue(i); else cnm= encode(g, crp->Kdata->GetCharValue(i)); @@ -5264,6 +5479,9 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, tm= 0; // Nullable break; + case FLD_FORMAT: + fmt= (crp->Kdata) ? crp->Kdata->GetCharValue(i) : NULL; + break; case FLD_REM: rem= crp->Kdata->GetCharValue(i); break; @@ -5289,27 +5507,59 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, key= crp->Kdata->GetCharValue(i); break; + case FLD_SCHEM: +#if defined(ODBC_SUPPORT) + if (ttp == TAB_ODBC && crp->Kdata) { + if (schem && stricmp(schem, crp->Kdata->GetCharValue(i))) { + sprintf(g->Message, + "Several %s tables found, specify DBNAME", tab); + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + goto err; + } else if (!schem) + schem= crp->Kdata->GetCharValue(i); + + } // endif ttp +#endif // ODBC_SUPPORT default: break; // Ignore } // endswitch Fld #if defined(ODBC_SUPPORT) if (ttp == TAB_ODBC) { - int plgtyp; + int plgtyp; + bool w= false; // Wide character type // typ must be PLG type, not SQL type - if (!(plgtyp= TranslateSQLType(typ, dec, prec, v))) { - sprintf(g->Message, "Unsupported SQL type %d", typ); - my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); - goto err; + if (!(plgtyp= TranslateSQLType(typ, dec, prec, v, w))) { + if (GetTypeConv() == TPC_SKIP) { + // Skip this column + sprintf(g->Message, "Column %s skipped (unsupported type %d)", + cnm, typ); + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); + continue; + } else { + sprintf(g->Message, "Unsupported SQL type %d", typ); + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + goto err; + } // endif type_conv + } else typ= plgtyp; switch (typ) { + case TYPE_STRING: + if (w) { + sprintf(g->Message, "Column %s is wide characters", cnm); + push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, 0, g->Message); + } // endif w + + break; case TYPE_DOUBLE: // Some data sources do not count dec in length (prec) prec += (dec + 2); // To be safe + break; case TYPE_DECIM: + prec= len; break; default: dec= 0; @@ -5330,7 +5580,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, tm, rem, 0, dbf, v); #else // !NEW_WAY if (add_field(&sql, cnm, typ, prec, dec, key, tm, rem, dft, xtra, - 0, dbf, v)) + fmt, 0, dbf, v)) rc= HA_ERR_OUT_OF_MEM; #endif // !NEW_WAY } // endfor i @@ -5562,11 +5812,11 @@ int ha_connect::create(const char *name, TABLE *table_arg, // on Windows and libxml2 otherwise switch (*xsup) { case '*': -#if defined(WIN32) +#if defined(__WIN__) dom= true; -#else // !WIN32 +#else // !__WIN__ dom= false; -#endif // !WIN32 +#endif // !__WIN__ break; case 'M': case 'D': @@ -5599,6 +5849,18 @@ int ha_connect::create(const char *name, TABLE *table_arg, } // endif type + if (type == TAB_JSON) { + int pretty= atoi(GetListOption(g, "Pretty", options->oplist, "2")); + + if (!options->lrecl && pretty != 2) { + sprintf(g->Message, "LRECL must be specified for pretty=%d", pretty); + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + rc= HA_ERR_INTERNAL_ERROR; + DBUG_RETURN(rc); + } // endif lrecl + + } // endif type + // Check column types for (field= table_arg->field; *field; field++) { fp= *field; @@ -5901,11 +6163,11 @@ bool ha_connect::FileExists(const char *fn, bool bf) NULL, NULL, 0, 0)) return true; -#if defined(WIN32) +#if defined(__WIN__) s= "\\"; -#else // !WIN32 +#else // !__WIN__ s= "/"; -#endif // !WIN32 +#endif // !__WIN__ if (IsPartitioned()) { sprintf(tfn, fn, GetPartName()); @@ -6247,8 +6509,7 @@ fin: @note: This function is no more called by check_if_supported_inplace_alter */ -bool ha_connect::check_if_incompatible_data(HA_CREATE_INFO *info, - uint table_changes) +bool ha_connect::check_if_incompatible_data(HA_CREATE_INFO *, uint) { DBUG_ENTER("ha_connect::check_if_incompatible_data"); // TO DO: really implement and check it. @@ -6341,58 +6602,6 @@ struct st_mysql_storage_engine connect_storage_engine= /***********************************************************************/ /* CONNECT global variables definitions. */ /***********************************************************************/ -// Size used when converting TEXT columns to VARCHAR -#if defined(_DEBUG) -static MYSQL_SYSVAR_INT(conv_size, zconv, - PLUGIN_VAR_RQCMDARG, // opt - "Size used when converting TEXT columns.", - NULL, NULL, SZCONV, 0, 65500, 1); -#else -static MYSQL_SYSVAR_INT(conv_size, zconv, - PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, // opt - "Size used when converting TEXT columns.", - NULL, NULL, SZCONV, 0, 65500, 1); -#endif - -/** - Type conversion: - no: Unsupported types -> TYPE_ERROR - yes: TEXT -> VARCHAR - skip: skip unsupported type columns in Discovery -*/ -const char *xconv_names[]= -{ - "NO", "YES", "SKIP", NullS -}; - -TYPELIB xconv_typelib= -{ - array_elements(xconv_names) - 1, "xconv_typelib", - xconv_names, NULL -}; - -#if defined(_DEBUG) -static MYSQL_SYSVAR_ENUM( - type_conv, // name - xconv, // varname - PLUGIN_VAR_RQCMDARG, // opt - "Unsupported types conversion.", // comment - NULL, // check - NULL, // update function - 0, // def (no) - &xconv_typelib); // typelib -#else -static MYSQL_SYSVAR_ENUM( - type_conv, // name - xconv, // varname - PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, - "Unsupported types conversion.", // comment - NULL, // check - NULL, // update function - 0, // def (no) - &xconv_typelib); // typelib -#endif - #if defined(XMAP) // Using file mapping for indexes if true static MYSQL_SYSVAR_BOOL(indx_map, xmap, PLUGIN_VAR_RQCMDARG, @@ -6425,6 +6634,7 @@ static struct st_mysql_sys_var* connect_system_variables[]= { #if defined(XMSG) MYSQL_SYSVAR(errmsg_dir_path), #endif // XMSG + MYSQL_SYSVAR(json_grp_size), NULL }; @@ -6441,7 +6651,7 @@ maria_declare_plugin(connect) 0x0103, /* version number (1.03) */ NULL, /* status variables */ connect_system_variables, /* system variables */ - "1.03.0005", /* string version */ + "1.03.0007", /* string version */ MariaDB_PLUGIN_MATURITY_BETA /* maturity */ } maria_declare_plugin_end; |