YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense alongwiththisprogram;ifnot,writetotheFreeSoftware
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
#ifdef _WIN64 // Size used for g->Sarea_Size 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,
PLUGIN_VAR_RQCMDARG, // opt "Size used when converting TEXT columns",
NULL, NULL, SZCONV, 0, 65500, 1);
// 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, 1); // YES by default
// 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, 5, -1, 16, 1); // Defaults to 5
// Default precision for doubles static MYSQL_THDVAR_INT(default_prec,
PLUGIN_VAR_RQCMDARG, "Default precision used for doubles",
NULL, NULL, 6, 0, 16, 1); // Defaults to 6
// 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);
#ifdefined(JAVA_SUPPORT) // Default java wrapper to use with JDBC tables static MYSQL_THDVAR_STR(java_wrapper,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC, "Java wrapper class name", // check_java_wrapper, update_java_wrapper,
NULL, NULL, "wrappers/JdbcInterface"); #endif// JAVA_SUPPORT
// This is apparently not acceptable for a plugin so it is undocumented #ifdefined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) // Enabling MONGO table type #ifdefined(MONGO_SUPPORT) || (MYSQL_VERSION_ID > 100200) static MYSQL_THDVAR_BOOL(enable_mongo, PLUGIN_VAR_RQCMDARG, "Enabling the MongoDB access", NULL, NULL, 1); #else// !version 2,3 static MYSQL_THDVAR_BOOL(enable_mongo, PLUGIN_VAR_RQCMDARG, "Enabling the MongoDB access", NULL, NULL, 0); #endif// !version 2,3 #endif// JAVA_SUPPORT || CMGO_SUPPORT
#ifdefined(BSON_SUPPORT) // Force using BSON for JSON tables static MYSQL_THDVAR_BOOL(force_bson, PLUGIN_VAR_RQCMDARG, "Force using BSON for JSON tables",
NULL, NULL, 0); // NO by default #endif// BSON_SUPPORT
if (path && *path != '*') { /* Save a pointer to the name in the
'file_format_name_map' constant array. */
*(char**)save= my_strdup(path, MYF(0)); return(0);
} else {
push_warning_printf(thd,
Sql_condition::WARN_LEVEL_WARN,
ER_WRONG_ARGUMENTS, "CONNECT: invalid message path");
} // endif path
*(char**)save= NULL; return(1);
} // end of check_msg_path #endif// 0
// added from Sergei mail #if0// (defined(LINUX))
Dl_info dl_info; if (dladdr(&connect_hton, &dl_info))
{ if (dlopen(dl_info.dli_fname, RTLD_NOLOAD | RTLD_NOW | RTLD_GLOBAL) == 0)
{
sql_print_information("CONNECT: dlopen() failed, OEM table type is not supported");
sql_print_information("CONNECT: %s", dlerror());
}
} else
{
sql_print_information("CONNECT: dladdr() failed, OEM table type is not supported");
sql_print_information("CONNECT: %s", dlerror());
} #endif// 0 (LINUX)
if (trace(128))
sql_print_information("connect_init: hton=%p", p);
DTVAL::SetTimeShift(); // Initialize time zone shift once for all #ifdefined(JAVA_SUPPORT)
JAVAConn::SetJVM(); #endif// JAVA_SUPPORT
DBUG_RETURN(0);
} // end of connect_init_func
/** @brief Plugincleanup
*/ int connect_done_func(void *)
{ int error= 0;
PCONNECT pc, pn;
DBUG_ENTER("connect_done_func");
/****************************************************************************/ /* Check whether this user can be removed. */ /****************************************************************************/ staticvoid PopUser(PCONNECT xp)
{ if (xp) {
pthread_mutex_lock(&usrmut);
xp->count--;
if (!xp->count) {
PCONNECT p;
for (p= user_connect::to_users; p; p= p->next) if (p == xp) break;
if (p) { if (p->next)
p->next->previous= p->previous;
if (p->previous)
p->previous->next= p->next; else
user_connect::to_users= p->next;
/****************************************************************************/ /* Get a pointer to the user of this handler. */ /****************************************************************************/ static PCONNECT GetUser(THD *thd, PCONNECT xp)
{ if (!thd) return NULL;
if (xp) { if (thd == xp->thdp) return xp;
PopUser(xp); // Avoid memory leak
} // endif xp
pthread_mutex_lock(&usrmut);
for (xp= user_connect::to_users; xp; xp= xp->next) if (thd == xp->thdp) break;
/****************************************************************************/ /* Get the global pointer of the user of this handler. */ /****************************************************************************/ static PGLOBAL GetPlug(THD *thd, PCONNECT& lxp)
{
lxp= GetUser(thd, lxp); return (lxp) ? lxp->g : NULL;
} // end of GetPlug
/****************************************************************************/ /* Get the implied table type. */ /****************************************************************************/
TABTYPE ha_connect::GetRealType(PTOS pos)
{
TABTYPE type= TAB_UNDEF;
if (pos || (pos= GetTableOptionStruct())) {
type= GetTypeID(pos->type);
if (type == TAB_UNDEF && !pos->http)
type= pos->srcdef ? TAB_MYSQL : pos->tabname ? TAB_PRX : TAB_DOS; #ifdefined(REST_SUPPORT) elseif (pos->http) switch (type) { case TAB_JSON: case TAB_XML: case TAB_CSV: case TAB_UNDEF:
type = TAB_REST; break; case TAB_REST:
type = TAB_NIY; break; default: break;
} // endswitch type #endif// REST_SUPPORT
if (IsExactType(type))
flags|= (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT);
// No data change on ALTER for outward tables if (!IsFileType(type) || hp->FileExists(pos->filename, true))
flags|= HA_NO_COPY_ON_ALTER;
} // endif pos
return flags;
} // end of table_flags
/****************************************************************************/ /* Return the value of an option specified in an option list. */ /****************************************************************************/
PCSZ GetListOption(PGLOBAL g, PCSZ opname, PCSZ oplist, PCSZ def)
{ if (!oplist) return (char*)def;
/****************************************************************************/ /* Return the value of a string option or NULL if not specified. */ /****************************************************************************/
PCSZ GetStringTableOption(PGLOBAL g, PTOS options, PCSZ opname, PCSZ sdef)
{
PCSZ opval= NULL;
if (!opval && 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, PCSZ opname, bool bdef)
{ bool opval= bdef;
PCSZ pv;
/****************************************************************************/ /* Return the value of an integer option or NO_IVAL if not specified. */ /****************************************************************************/ int GetIntegerTableOption(PGLOBAL g, PTOS options, PCSZ opname, int idef)
{
ulonglong opval= (ulonglong) NO_IVAL;
/****************************************************************************/ /* Return the value of a string option or sdef if not specified. */ /****************************************************************************/
PCSZ ha_connect::GetStringOption(PCSZ opname, PCSZ sdef)
{
PCSZ opval= NULL;
PTOS options= GetTableOptionStruct();
if (!stricmp(opname, "Connect")) { constchar *cnc= options->connect;
if (!opval) { if (sdef && !strcmp(sdef, "*")) { // Return the handler default value if (!stricmp(opname, "Dbname") || !stricmp(opname, "Database"))
opval= (char*)GetDBName(NULL); // Current database elseif (!stricmp(opname, "Type")) // Default type
opval= (!options) ? NULL :
(options->srcdef) ? (char*)"MYSQL" :
(options->tabname) ? (char*)"PROXY" : (char*)"DOS"; elseif (!stricmp(opname, "User")) // Connected user
opval= (char *) "root"; elseif (!stricmp(opname, "Host")) // Connected user host
opval= (char *) "localhost"; else
opval= sdef; // Caller default
} else
opval= sdef; // Caller default
} // endif !opval
return opval;
} // end of GetStringOption
/****************************************************************************/ /* Return the value of a Boolean option or bdef if not specified. */ /****************************************************************************/ bool ha_connect::GetBooleanOption(PCSZ opname, bool bdef)
{ bool opval;
PTOS options= GetTableOptionStruct();
/****************************************************************************/ /* Set the value of the opname option (does not work for oplist options) */ /* Currently used only to set the Sepindex value. */ /****************************************************************************/ bool ha_connect::SetBooleanOption(PCSZ opname, bool b)
{
PTOS options= GetTableOptionStruct();
if (!options) returntrue;
if (!stricmp(opname, "SepIndex"))
options->sepindex= b; else returntrue;
returnfalse;
} // end of SetBooleanOption
/****************************************************************************/ /* Return the value of an integer option or NO_IVAL if not specified. */ /****************************************************************************/ int ha_connect::GetIntegerOption(PCSZ opname)
{ int opval;
PTOS options= GetTableOptionStruct();
TABLE_SHARE *tsp= (tshp) ? tshp : table_share;
/****************************************************************************/ /* Set the value of the opname option (does not work for oplist options) */ /* Currently used only to set the Lrecl value. */ /****************************************************************************/ bool ha_connect::SetIntegerOption(PCSZ opname, int n)
{
PTOS options= GetTableOptionStruct();
/****************************************************************************/ /* Return a field option structure. */ /****************************************************************************/
PFOS ha_connect::GetFieldOptionStruct(Field *fdp)
{ return fdp->option_struct;
} // end of GetFildOptionStruct
/****************************************************************************/ /* Returns the column description structure used to make the column. */ /****************************************************************************/ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf)
{ constchar *cp; char *chset, v= 0;
ha_field_option_struct *fop;
Field* fp;
Field* *fldp;
// Double test to be on the safe side if (!table) return NULL;
// Find the column to describe if (field) {
fldp= (Field**)field;
fldp++;
} else
fldp= (tshp) ? tshp->field : table->field;
if (!fldp || !(fp= *fldp)) return NULL;
// Get the CONNECT field options structure
fop= GetFieldOptionStruct(fp);
pcf->Flags= 0;
// Now get column information
pcf->Name= (char*)fp->field_name.str;
chset= (char*)fp->charset()->coll_name.str;
if (fop && fop->special) {
pcf->Fieldfmt= (char*)fop->special;
pcf->Flags= U_SPECIAL; return fldp;
} // endif special
if (!strcmp(chset, "binary"))
v = 'B'; // Binary string
switch (fp->type()) { case MYSQL_TYPE_BLOB: case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_VAR_STRING:
pcf->Flags |= U_VAR; // fall through default:
pcf->Type= MYSQLtoPLG(fp->type(), &v); break;
} // endswitch SQL type
switch (pcf->Type) { case TYPE_STRING: case TYPE_BIN: // Do something for case
cp= chset;
// Find if collation name ends by _ci if (!strcmp(cp + strlen(cp) - 3, "_ci")) {
pcf->Scale= 1; // Case insensitive
pcf->Opt= 0; // Prevent index opt until it is safe
} // endif ci
break; case TYPE_DOUBLE:
pcf->Scale= MY_MAX(MY_MIN(fp->decimals(), ((unsigned)pcf->Length - 2)), 0); break; case TYPE_DECIM:
pcf->Precision= ((Field_new_decimal*)fp)->precision;
pcf->Length= pcf->Precision;
pcf->Scale= fp->decimals(); break; case TYPE_DATE: // Field_length is only used for DATE columns if (fop && fop->fldlen)
pcf->Length= (int)fop->fldlen; else { int len;
if (pcf->Datefmt) { // Find the (max) length produced by the date format char buf[256];
PGLOBAL g= GetPlug(table->in_use, xp);
PDTP pdtp= MakeDateFormat(g, pcf->Datefmt, false, true, 0); struct tm datm;
bzero(&datm, sizeof(datm));
datm.tm_mday= 12;
datm.tm_mon= 11;
datm.tm_year= 112;
mktime(&datm); // set other fields get proper day name
len= strftime(buf, 256, pdtp->OutFmt, &datm);
} else
len= 0;
// 11 is for signed numeric representation of the date
pcf->Length= (len) ? len : 11;
} // endelse
// For Value setting
pcf->Precision= MY_MAX(pcf->Precision, pcf->Length); break; default: break;
} // endswitch type
if (fp->flags & UNSIGNED_FLAG)
pcf->Flags |= U_UNSIGNED;
if (fp->flags & ZEROFILL_FLAG)
pcf->Flags |= U_ZEROFILL;
// This is used to skip null bit if (fp->real_maybe_null())
pcf->Flags |= U_NULLS;
// Mark virtual columns as such if (fp->vcol_info && !fp->stored_in_db)
pcf->Flags |= U_VIRTUAL;
pcf->Key= 0; // Not used when called from MySQL
// Get the comment if any if (fp->comment.str && fp->comment.length)
pcf->Remark= strz(g, fp->comment); else
pcf->Remark= NULL;
return fldp;
} // end of GetColumnOption
/****************************************************************************/ /* Return an index option structure. */ /****************************************************************************/
PXOS ha_connect::GetIndexOptionStruct(KEY *kp)
{ return kp->option_struct;
} // end of GetIndexOptionStruct
/****************************************************************************/ /* Return a Boolean index option or false if not specified. */ /****************************************************************************/ bool ha_connect::GetIndexOption(KEY *kp, PCSZ opname)
{ bool opval= false;
PXOS options= GetIndexOptionStruct(kp);
if (options) { if (!stricmp(opname, "Dynamic"))
opval= options->dynamic; elseif (!stricmp(opname, "Mapped"))
opval= options->mapped;
/****************************************************************************/ /* Returns the index description structure used to make the index. */ /****************************************************************************/ bool ha_connect::IsUnique(uint n)
{ return (table->key_info[n].flags & HA_NOSAME) != 0;
} // end of IsUnique
/****************************************************************************/ /* Returns the index description structure used to make the index. */ /****************************************************************************/
PIXDEF ha_connect::GetIndexInfo(TABLE_SHARE *s)
{ char *name, *pn; bool unique;
PIXDEF xdp, pxd=NULL, toidx= NULL;
PKPDEF kpp, pkp;
KEY kp;
PGLOBAL& g= xp->g;
if (!s)
s= table->s;
for (int n= 0; (unsigned)n < s->keynames.count; n++) { if (trace(1))
htrc("Getting created index %d info\n", n + 1);
// Find the index to describe
kp= s->key_info[n];
// Now get index information
pn= (char*)s->keynames.type_names[n];
name= PlugDup(g, pn);
unique= (kp.flags & 1) != 0;
pkp= NULL;
// Allocate the index description block
xdp= new(g) INDEXDEF(name, unique, n);
// 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.str;
name= PlugDup(g, pn);
if (kp.key_part[k].key_part_flag & HA_REVERSE_SORT)
{
strcpy(g->Message, "Descending indexes are not supported");
xdp->Invalid= true;
}
// Allocate the key part description block
kpp= new(g) KPARTDEF(name, k + 1);
kpp->SetKlen(kp.key_part[k].length);
#if0// NIY // Index on auto increment column can be an XXROW index if (kp.key_part[k].field->flags & AUTO_INCREMENT_FLAG &&
kp.uder_defined_key_parts == 1) { char *type= GetStringOption("Type", "DOS");
TABTYPE typ= GetTypeID(type);
/****************************************************************************/ /* Returns the index description structure used to make the index. */ /****************************************************************************/ bool ha_connect::CheckVirtualIndex(TABLE_SHARE *s)
{
// Get the the key parts info for (int k= 0; (unsigned)k < kp.user_defined_key_parts; k++) {
fp= kp.key_part[k].field;
rid= (fp->option_struct) ? fp->option_struct->special : NULL;
PCSZ ha_connect::GetDBName(PCSZ name)
{ return (name) ? name : table->s->db.str;
} // end of GetDBName
constchar *ha_connect::GetTableName(void)
{ constchar *path= tshp ? tshp->path.str : table_share->path.str; constchar *name= strrchr(path, slash); return name ? name + 1 : path;
} // end of GetTableName
char *ha_connect::GetPartName(void)
{ return (IsPartitioned()) ? partname : (char*)GetTableName();
} // end of GetTableName
#if0 /****************************************************************************/ /* Returns the column real or special name length of a field. */ /****************************************************************************/ int ha_connect::GetColNameLen(Field *fp)
{ int n;
PFOS fop= GetFieldOptionStruct(fp);
// Now get the column name length if (fop && fop->special)
n= strlen(fop->special) + 1; else
n= fp->field_name.length;
return n;
} // end of GetColNameLen
/****************************************************************************/ /* Returns the column real or special name of a field. */ /****************************************************************************/ char *ha_connect::GetColName(Field *fp)
{
PFOS fop= GetFieldOptionStruct(fp);
return (fop && fop->special) ? fop->special : (char*)fp->field_name.str;
} // end of GetColName
/****************************************************************************/ /* Adds the column real or special name of a field to a string. */ /****************************************************************************/ void ha_connect::AddColName(char *cp, Field *fp)
{
PFOS fop= GetFieldOptionStruct(fp);
// Now add the column name if (fop && fop->special) // The prefix * mark the column as "special"
strcat(strcpy(cp, "*"), strupr(fop->special)); else
strcpy(cp, fp->field_name.str);
} // end of AddColName #endif// 0
/***********************************************************************/ /* This function sets the current database path. */ /***********************************************************************/ bool ha_connect::SetDataPath(PGLOBAL g, PCSZ path)
{ return (!(datapath= SetPath(g, path)));
} // end of SetDataPath
/****************************************************************************/ /* Get the table description block of a CONNECT table. */ /****************************************************************************/
PTDB ha_connect::GetTDB(PGLOBAL g)
{ constchar *table_name;
PTDB tp;
// Double test to be on the safe side if (!g || !table) return NULL;
/****************************************************************************/ /* Open a CONNECT table, restricting column list if cols is true. */ /****************************************************************************/ int ha_connect::OpenTable(PGLOBAL g, bool del)
{ bool rc= false; char *c1= NULL, *c2=NULL;
// Double test to be on the safe side if (!g || !table) {
htrc("OpenTable logical error; g=%p table=%p\n", g, table); return HA_ERR_INITIALIZATION;
} // endif g
if (!(tdbp= GetTDB(g))) return RC_FX; elseif (tdbp->IsReadOnly()) switch (xmod) { case MODE_WRITE: case MODE_INSERT: case MODE_UPDATE: case MODE_DELETE:
snprintf(g->Message, sizeof(g->Message), MSG(READ_ONLY)); return HA_ERR_TABLE_READONLY; default: break;
} // endswitch xmode
// g->More is 1 when executing commands from triggers if (!g->More && (xmod != MODE_INSERT
|| tdbp->GetAmType() == TYPE_AM_MYSQL
|| tdbp->GetAmType() == TYPE_AM_ODBC
|| tdbp->GetAmType() == TYPE_AM_JDBC)) { // Get the list of used fields (columns) char *p; unsignedint k1, k2, n1, n2;
Field* *field;
Field* fp;
MY_BITMAP *map= (xmod == MODE_INSERT) ? table->write_set : table->read_set;
MY_BITMAP *ump= (xmod == MODE_UPDATE) ? table->write_set : NULL;
k1= k2= 0;
n1= n2= 1; // 1 is space for final null character
for (field= table->field; (fp= *field); field++) { if (bitmap_is_set(map, fp->field_index)) {
n1+= (fp->field_name.length + 1);
k1++;
} // endif
if (k1) {
p= c1= (char*)PlugSubAlloc(g, NULL, n1);
for (field= table->field; (fp= *field); field++) if (bitmap_is_set(map, fp->field_index)) {
strcpy(p, fp->field_name.str);
p+= (fp->field_name.length + 1);
} // endif used field
*p= '\0'; // mark end of list
} // endif k1
if (k2) {
p= c2= (char*)PlugSubAlloc(g, NULL, n2);
for (field= table->field; (fp= *field); field++) if (bitmap_is_set(ump, fp->field_index)) {
strcpy(p, fp->field_name.str);
if (part_id && bitmap_is_set(part_id, fp->field_index)) { // Trying to update a column used for partitioning // This cannot be currently done because it may require // a row to be moved in another partition.
snprintf(g->Message, sizeof(g->Message), "Cannot update column %s because it is used for partitioning",
p); return HA_ERR_INTERNAL_ERROR;
} // endif part_id
p+= (strlen(p) + 1);
} // endif used field
*p= '\0'; // mark end of list
} // endif k2
} // endif xmod
// Open the table if (!(rc= CntOpenTable(g, tdbp, xmod, c1, c2, del, this))) {
istable= true; // strmake(tname, table_name, sizeof(tname)-1);
#ifdef NOT_USED_VARIABLE // We may be in a create index query if (xmod == MODE_ANY && *tdbp->GetName() != '#') { // The current indexes
PIXDEF oldpix= GetIndexInfo();
} // endif xmod #endif
return (rc) ? HA_ERR_INITIALIZATION : 0;
} // end of OpenTable
/****************************************************************************/ /* CheckColumnList: check that all bitmap columns do exist. */ /****************************************************************************/ bool ha_connect::CheckColumnList(PGLOBAL g)
{ // Check the list of used fields (columns) bool brc= false;
PCOL colp;
Field* *field;
Field* fp;
MY_BITMAP *map= table->read_set;
try { for (field= table->field; (fp= *field); field++) if (bitmap_is_set(map, fp->field_index)) { if (!(colp= tdbp->ColDB(g, (PSZ)fp->field_name.str, 0))) {
snprintf(g->Message, sizeof(g->Message), "Column %s not found in %s",
fp->field_name.str, tdbp->GetName()); throw1;
} // endif colp
if ((brc= colp->InitValue(g))) throw2;
colp->AddColUse(U_P); // For PLG tables
} // endif
} catch (int n) { if (trace(1))
htrc("Exception %d: %s\n", n, g->Message);
brc= true;
} catch (constchar *msg) {
snprintf(g->Message, sizeof(g->Message), "%s", msg);
brc= true;
} // end catch
return brc;
} // end of CheckColumnList
/****************************************************************************/ /* IsOpened: returns true if the table is already opened. */ /****************************************************************************/ bool ha_connect::IsOpened(void)
{ return (!xp->CheckQuery(valid_query_id) && tdbp
&& tdbp->GetUse() == USE_OPEN);
} // end of IsOpened
/****************************************************************************/ /* Close a CONNECT table. */ /****************************************************************************/ int ha_connect::CloseTable(PGLOBAL g)
{ int rc= CntCloseTable(g, tdbp, nox, abort);
tdbp= NULL;
sdvalin1= sdvalin2= sdvalin3= sdvalin4= NULL;
sdvalout=NULL;
valid_info= false;
indexing= -1;
nox= true;
abort= false; return rc;
} // end of CloseTable
/***********************************************************************/ /* Make a pseudo record from current row values. Specific to MySQL. */ /***********************************************************************/ int ha_connect::MakeRecord(char *buf)
{
PCSZ fmt; char *p, val[32]; int rc= 0;
Field* *field;
Field *fp;
CHARSET_INFO *charset= tdbp->data_charset(); //MY_BITMAP readmap;
MY_BITMAP *map;
PVAL value;
PCOL colp= NULL;
DBUG_ENTER("ha_connect::MakeRecord");
// Avoid asserts in field::store() for columns that are not updated
MY_BITMAP *org_bitmap= dbug_tmp_use_all_columns(table, &table->write_set);
// This is for variable_length rows
memset(buf, 0, table->s->null_bytes);
// When sorting read_set selects all columns, so we use def_read_set
map= (MY_BITMAP *)&table->def_read_set;
// Make the pseudo record from field values for (field= table->field; *field && !rc; field++) {
fp= *field;
if (fp->vcol_info && !fp->stored_in_db) continue; // This is a virtual column
if (bitmap_is_set(map, fp->field_index) || alter) { // This is a used field, fill the buffer with value for (colp= tdbp->GetColumns(); colp; colp= colp->GetNext()) if ((!mrr || colp->GetKcol()) &&
!stricmp(colp->GetName(), fp->field_name.str)) break;
// All this was better optimized if (!value->IsNull()) { switch (value->GetType()) { case TYPE_DATE: if (!sdvalout)
sdvalout= AllocateValue(xp->g, TYPE_STRING, 20);
switch (fp->type()) { case MYSQL_TYPE_DATE:
fmt= "%Y-%m-%d"; break; case MYSQL_TYPE_TIME:
fmt= "%H:%M:%S"; break; case MYSQL_TYPE_YEAR:
fmt= "%Y"; break; default:
fmt= "%Y-%m-%d %H:%M:%S"; break;
} // endswitch type
// Get date in the format required by MySQL fields
value->FormatValue(sdvalout, fmt);
p= sdvalout->GetCharValue();
rc= fp->store(p, strlen(p), charset, CHECK_FIELD_WARN); break; case TYPE_STRING: case TYPE_DECIM:
p= value->GetCharString(val);
charset= tdbp->data_charset();
rc= fp->store_text(p, strlen(p), charset, CHECK_FIELD_WARN); break; case TYPE_BIN:
p= value->GetCharValue();
charset= &my_charset_bin;
rc= fp->store(p, value->GetSize(), charset, CHECK_FIELD_WARN); break; case TYPE_DOUBLE:
rc= fp->store(value->GetFloatValue()); break; default:
rc= fp->store(value->GetBigintValue(), value->IsUnsigned()); break;
} // endswitch Type
// Store functions returns 1 on overflow and -1 on fatal error if (rc > 0) { char buf[256];
THD *thd= ha_thd();
snprintf(buf, sizeof(buf), "Out of range value %.140s for column '%s' at row %ld",
value->GetCharString(val),
fp->field_name.str,
thd->get_stmt_da()->current_row_for_warning());
// This is sometimes required for partition tables because the buf // can be different from the table->record[0] buffer if (buf != (char*)table->record[0])
memcpy(buf, table->record[0], table->s->stored_rec_length);
// This is copied from ha_tina and is necessary to avoid asserts
dbug_tmp_restore_column_map(&table->write_set, org_bitmap);
DBUG_RETURN(rc);
} // end of MakeRecord
/***********************************************************************/ /* Set row values from a MySQL pseudo record. Specific to MySQL. */ /***********************************************************************/ int ha_connect::ScanRecord(PGLOBAL g, const uchar *)
{ char attr_buffer[1024]; char data_buffer[1024];
PCSZ fmt; int rc= 0;
PCOL colp;
PVAL value, sdvalin;
Field *fp; //PTDBASE tp= (PTDBASE)tdbp;
String attribute(attr_buffer, sizeof(attr_buffer),
table->s->table_charset);
MY_BITMAP *bmap= dbug_tmp_use_all_columns(table, &table->read_set); const CHARSET_INFO *charset= tdbp->data_charset();
String data_charset_value(data_buffer, sizeof(data_buffer), charset);
// Scan the pseudo record for field values and set column values for (Field **field=table->field ; *field ; field++) {
fp= *field;
if ((fp->vcol_info && !fp->stored_in_db) ||
fp->option_struct->special) continue; // Is a virtual column possible here ???
if ((xmod == MODE_INSERT && tdbp->GetAmType() != TYPE_AM_MYSQL
&& tdbp->GetAmType() != TYPE_AM_ODBC
&& tdbp->GetAmType() != TYPE_AM_JDBC) ||
bitmap_is_set(table->write_set, fp->field_index)) { for (colp= tdbp->GetSetCols(); colp; colp= colp->GetNext()) if (!stricmp(colp->GetName(), fp->field_name.str)) break;
if (!colp) {
htrc("Column %s not found\n", fp->field_name.str);
rc= HA_ERR_WRONG_IN_RECORD; goto err;
} else
value= colp->GetValue();
// This is a used field, fill the value from the row buffer // All this could be better optimized if (fp->is_null()) { if (colp->IsNullable())
value->SetNull(true);
value->Reset();
} elseswitch (value->GetType()) { case TYPE_DOUBLE:
value->SetValue(fp->val_real()); break; case TYPE_DATE: // Get date in the format produced by MySQL fields switch (fp->type()) { case MYSQL_TYPE_DATE: if (!sdvalin2) {
sdvalin2= (DTVAL*)AllocateValue(xp->g, TYPE_DATE, 19);
fmt= "YYYY-MM-DD";
((DTVAL*)sdvalin2)->SetFormat(g, fmt, strlen(fmt));
} // endif sdvalin1
err:
dbug_tmp_restore_column_map(&table->read_set, bmap); return rc;
} // end of ScanRecord
/***********************************************************************/ /* Check change in index column. Specific to MySQL. */ /* Should be elaborated to check for real changes. */ /***********************************************************************/ int ha_connect::CheckRecord(PGLOBAL g, const uchar *, const uchar *newbuf)
{ return ScanRecord(g, newbuf);
} // end of dummy CheckRecord
/***********************************************************************/ /* Return true if this field is used in current indexing. */ /***********************************************************************/ bool ha_connect::IsIndexed(Field *fp)
{ if (active_index < MAX_KEY) {
KEY_PART_INFO *kpart;
KEY *kfp= &table->key_info[active_index];
uint rem= kfp->user_defined_key_parts;
for (kpart= kfp->key_part; rem; rem--, kpart++) if (kpart->field == fp) returntrue;
} // endif active_index
returnfalse;
} // end of IsIndexed
/***********************************************************************/ /* Return the where clause for remote indexed read. */ /***********************************************************************/ bool ha_connect::MakeKeyWhere(PGLOBAL g, PSTRG qry, OPVAL vop, char q, const key_range *kr)
{ const uchar *ptr; //uint i, rem, len, klen, stlen;
uint i, rem, len, stlen; bool nq, both, oom;
OPVAL op;
Field *fp; const key_range *ranges[2];
MY_BITMAP *old_map;
KEY *kfp;
KEY_PART_INFO *kpart;
res= fp->val_str(&str, ptr);
qry->Append(res->ptr(), res->length(), nq);
} // endif flag
if (nq)
qry->Append('\'');
if (stlen >= len) break;
len-= stlen;
/* For nullable columns, null-byte is already skipped before, that is ptrwasincrementedby1.Sincestore_lengthstillcountsnull-byte,
we need to subtract 1 from store_length. */
ptr+= stlen - MY_TEST(kpart->null_bit);
} // endfor kpart
} // endfor i
qry->Append(')');
if ((oom= qry->IsTruncated()))
snprintf(g->Message, sizeof(g->Message), "Out of memory");
err:
dbug_tmp_restore_column_map(&table->write_set, old_map); returntrue;
} // end of MakeKeyWhere
/***********************************************************************/ /* Return the string representing an operator. */ /***********************************************************************/ constchar *ha_connect::GetValStr(OPVAL vop, bool neg)
{ constchar *val;
switch (vop) { case OP_EQ:
val= "= "; break; case OP_NE:
val= " <> "; break; case OP_GT:
val= " > "; break; case OP_GE:
val= " >= "; break; case OP_LT:
val= " < "; break; case OP_LE:
val= " <= "; break; case OP_IN:
val= (neg) ? " NOT IN (" : " IN ("; break; case OP_NULL:
val= (neg) ? " IS NOT NULL" : " IS NULL"; break; case OP_LIKE:
val= (neg) ? " NOT LIKE " : " LIKE "; break; case OP_XX:
val= (neg) ? " NOT BETWEEN " : " BETWEEN "; break; case OP_EXIST:
val= (neg) ? " NOT EXISTS " : " EXISTS "; break; case OP_AND:
val= " AND "; break; case OP_OR:
val= " OR "; break; case OP_NOT:
val= " NOT "; break; case OP_CNC:
val= " || "; break; case OP_ADD:
val= " + "; break; case OP_SUB:
val= " - "; break; case OP_MULT:
val= " * "; break; case OP_DIV:
val= " / "; break; default:
val= " ? "; break;
} /* endswitch */
return val;
} // end of GetValStr
#if0 /***********************************************************************/ /* Check the WHERE condition and return a CONNECT filter. */ /***********************************************************************/
PFIL ha_connect::CheckFilter(PGLOBAL g)
{ return CondFilter(g, (Item *)pushed_cond);
} // end of CheckFilter #endif// 0
/***********************************************************************/ /* Check the WHERE condition and return a CONNECT filter. */ /***********************************************************************/
PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond)
{ unsignedint i; bool ismul= false;
OPVAL vop= OP_XX;
PFIL filp= NULL;
if (!cond) return NULL;
if (trace(1))
htrc("Cond type=%d\n", cond->type());
for (i= 0; i < condf->argument_count(); i++) { if (trace(1))
htrc("Argtype(%d)=%d\n", i, args[i]->type());
if (i >= 2 && !ismul) { if (trace(1))
htrc("Unexpected arg for vop=%d\n", vop);
continue;
} // endif i
if ((iscol= args[i]->type() == COND::FIELD_ITEM)) {
Item_field *pField= (Item_field *)args[i];
// IN and BETWEEN clauses should be col VOP list if (i && ismul) return NULL;
if (pField->field->table != table ||
!(colp[i]= tdbp->ColDB(g, (PSZ)pField->field->field_name.str, 0))) return NULL; // Column does not belong to this table
// These types are not yet implemented (buggy) switch (pField->field->type()) { case MYSQL_TYPE_TIMESTAMP: case MYSQL_TYPE_DATE: case MYSQL_TYPE_TIME: case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_YEAR: case MYSQL_TYPE_NEWDATE: return NULL; default: break;
} // endswitch type
// IN and BETWEEN clauses should be col VOP list if (i && (x || ismul)) return NULL; // IN and BETWEEN clauses should be col VOP list elseif (pField->field->table != table) return NULL; // Field does not belong to this table elseif (tty != TYPE_AM_WMI && IsIndexed(pField->field)) return NULL; // Will be handled by ReadKey else
fop= GetFieldOptionStruct(pField->field);
// Append the value to the filter switch (args[i]->field_type()) { case MYSQL_TYPE_TIMESTAMP: case MYSQL_TYPE_DATETIME: if (tty == TYPE_AM_ODBC) {
strcat(s, "{ts '");
strncat(s, res->ptr(), res->length());
if (res->length() < 19)
strcat(s, &"1970-01-01 00:00:00"[res->length()]);
strcat(s, "'}"); break;
} // endif ODBC // fall through case MYSQL_TYPE_DATE: if (tty == TYPE_AM_ODBC) {
strcat(s, "{d '");
strcat(strncat(s, res->ptr(), res->length()), "'}"); break;
} // endif ODBC // fall through
case MYSQL_TYPE_TIME: if (tty == TYPE_AM_ODBC) {
strcat(s, "{t '");
strcat(strncat(s, res->ptr(), res->length()), "'}"); break;
} // endif ODBC // fall through
case MYSQL_TYPE_VARCHAR: if (tty == TYPE_AM_ODBC && i) { switch (args[0]->field_type()) { case MYSQL_TYPE_TIMESTAMP: case MYSQL_TYPE_DATETIME:
strcat(s, "{ts '");
strncat(s, res->ptr(), res->length());
if (res->length() < 19)
strcat(s, &"1970-01-01 00:00:00"[res->length()]);
if (!g || !table || xmod != MODE_READ)
DBUG_RETURN(HA_ADMIN_INTERNAL_ERROR);
// Do not close the table if it was opened yet (possible?) if (IsOpened()) { if (IsPartitioned() && CheckColumnList(g)) // map can have been changed
rc= HA_ADMIN_CORRUPT; elseif (tdbp->OpenDB(g)) // Rewind table
rc= HA_ADMIN_CORRUPT;
} elseif (xp->CheckQuery(valid_query_id)) {
tdbp= NULL; // Not valid anymore
@see handler::ha_open()inhandler.cc
*/ int ha_connect::open(constchar *name, int mode, uint test_if_locked)
{ int rc= 0;
DBUG_ENTER("ha_connect::open");
if (trace(1))
htrc("open: name=%s mode=%d test=%u\n", name, mode, test_if_locked);
if (!(share= get_share()))
DBUG_RETURN(1);
thr_lock_data_init(&share->lock,&lock,NULL);
// Try to get the user if possible
xp= GetUser(ha_thd(), xp);
PGLOBAL g= (xp) ? xp->g : NULL;
// Try to set the database environment if (g) {
rc= (CntCheckDB(g, this, name)) ? (-2) : 0;
if (g->Mrr) { // This should only happen for the mrr secondary handler
mrr= true;
g->Mrr= false;
} else
mrr= false;
@see sql_base.cc,sql_select.ccandtable.cc
*/ int ha_connect::close(void)
{ int rc= 0;
DBUG_ENTER("ha_connect::close");
// If this is called by a later query, the table may have // been already closed and the tdbp is not valid anymore. if (tdbp && xp->last_query_id == valid_query_id)
rc= CloseTable(xp->g);
@see item_sum.cc,item_sum.cc,sql_acl.cc,sql_insert.cc, sql_insert.cc,sql_select.cc,sql_table.cc,sql_udf.ccandsql_update.cc
*/ int ha_connect::write_row(const uchar *buf)
{ int rc= 0;
PGLOBAL& g= xp->g;
DBUG_ENTER("ha_connect::write_row");
// This is not tested yet if (xmod == MODE_ALTER) { if (IsPartitioned() && GetStringOption("Filename", NULL)) // Why does this happen now that check_if_supported_inplace_alter is called?
DBUG_RETURN(0); // Alter table on an outward partition table
xmod= MODE_INSERT;
} elseif (xmod == MODE_ANY)
DBUG_RETURN(0); // Probably never met
// Open the table if it was not opened yet (locked) if (!IsOpened() || xmod != tdbp->GetMode()) { if (IsOpened())
CloseTable(g);
if ((rc= OpenTable(g)))
DBUG_RETURN(rc);
} // endif isopened
#if0// AUTO_INCREMENT NIY if (table->next_number_field && buf == table->record[0]) { int error;
if ((error= update_auto_increment())) return error;
} // endif nex_number_field #endif// 0
// Set column values from the passed pseudo record if ((rc= ScanRecord(g, buf)))
DBUG_RETURN(rc);
// Return result code from write operation if (CntWriteRow(g, tdbp)) {
DBUG_PRINT("write_row", ("%s", g->Message));
htrc("write_row: %s\n", g->Message);
rc= HA_ERR_INTERNAL_ERROR;
} else// Table is modified
nox= false; // Indexes to be remade
@see sql_acl.cc,sql_udf.cc,sql_delete.cc,sql_insert.ccandsql_select.cc
*/ int ha_connect::delete_row(const uchar *)
{ int rc= 0;
DBUG_ENTER("ha_connect::delete_row");
if (CntDeleteRow(xp->g, tdbp, false)) {
rc= HA_ERR_INTERNAL_ERROR;
htrc("delete_row CONNECT: %s\n", xp->g->Message);
} else
nox= false; // To remake indexes
DBUG_RETURN(rc);
} // end of delete_row
/****************************************************************************/ /* We seem to come here at the begining of an index use. */ /****************************************************************************/ int ha_connect::index_init(uint idx, bool sorted)
{ int rc;
PGLOBAL& g= xp->g;
DBUG_ENTER("index_init");
if (trace(1))
htrc("index_init: this=%p idx=%u sorted=%d\n", this, idx, sorted);
if (GetIndexType(GetRealType()) == 2) { if (xmod == MODE_READ) // This is a remote index
xmod= MODE_READX;
if (trace(1))
htrc("index_init: rc=%d indexing=%d active_index=%d\n",
rc, indexing, active_index);
DBUG_RETURN(rc);
} // end of index_init
/****************************************************************************/ /* We seem to come here at the end of an index use. */ /****************************************************************************/ int ha_connect::index_end()
{
DBUG_ENTER("index_end");
active_index= MAX_KEY;
ds_mrr.dsmrr_close();
DBUG_RETURN(rnd_end());
} // end of index_end
/****************************************************************************/ /* This is internally called by all indexed reading functions. */ /****************************************************************************/ int ha_connect::ReadIndexed(uchar *buf, OPVAL op, const key_range *kr)
{ int rc;
/****************************************************************************/ /* This is called by handler::index_read_map. */ /****************************************************************************/ int ha_connect::index_read(uchar * buf, const uchar * key, uint key_len, enum ha_rkey_function find_flag)
{ int rc;
OPVAL op= OP_XX;
DBUG_ENTER("ha_connect::index_read");
switch(find_flag) { case HA_READ_KEY_EXACT: op= OP_EQ; break; case HA_READ_AFTER_KEY: op= OP_GT; break; case HA_READ_KEY_OR_NEXT: op= OP_GE; break; default: DBUG_RETURN(-1); break;
} // endswitch find_flag
if (trace(2))
htrc("%p index_read: op=%d\n", this, op);
@see opt_range.cc,opt_sum.cc,sql_handler.ccandsql_select.cc
*/ int ha_connect::index_first(uchar *buf)
{ int rc;
DBUG_ENTER("ha_connect::index_first");
/****************************************************************************/ /* This is called to get more rows having the same index value. */ /****************************************************************************/ //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"); //statistic_increment(ha_read_next_count, &LOCK_status);
if (!g || !table || xmod == MODE_INSERT)
DBUG_RETURN(HA_ERR_INITIALIZATION);
// Do not close the table if it was opened yet (locked?) if (IsOpened()) { if (IsPartitioned() && xmod != MODE_INSERT) if (CheckColumnList(g)) // map can have been changed
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
if (tdbp->OpenDB(g)) // Rewind table
DBUG_RETURN(HA_ERR_INTERNAL_ERROR); else
DBUG_RETURN(0);
} elseif (xp->CheckQuery(valid_query_id))
tdbp= NULL; // Not valid anymore
// When updating, to avoid skipped update, force the table // handler to retrieve write-only fields to be able to compare // records and detect data change. if (xmod == MODE_UPDATE)
bitmap_union(table->read_set, table->write_set);
if (OpenTable(g, xmod == MODE_DELETE))
DBUG_RETURN(HA_ERR_INITIALIZATION);
xp->nrd= xp->fnd= xp->nfd= 0;
xp->tb1= my_interval_timer();
DBUG_RETURN(0);
} // end of rnd_init
/** @brief Notdescribed.
@note Thepreviousversionsaid: Stopscanningoftable.Notethatthismaybecalledseveraltimesduring executionofasubselect. =====>Thishasbeenmovedtoexternallocktoavoidclosingsubselecttables.
*/ int ha_connect::rnd_end()
{ int rc= 0;
DBUG_ENTER("ha_connect::rnd_end");
// If this is called by a later query, the table may have // been already closed and the tdbp is not valid anymore. // if (tdbp && xp->last_query_id == valid_query_id) // rc= CloseTable(xp->g);
ds_mrr.dsmrr_close();
DBUG_RETURN(rc);
} // end of rnd_end
if (!g) {
my_message(ER_UNKNOWN_ERROR, "Cannot get g pointer", MYF(0));
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
} // endif g
if (trace(1))
htrc("%p In info: flag=%u valid_info=%d\n", this, flag, valid_info);
// tdbp must be available to get updated info if (xp->CheckQuery(valid_query_id) || !tdbp) {
if (xmod == MODE_ANY || xmod == MODE_ALTER) { // Pure info, not a query
pure= true;
xp->CheckCleanup(xmod == MODE_ANY && valid_query_id == 0);
} // endif xmod
// This is necessary for getting file length if (table) { if (SetDataPath(g, table->s->db.str)) {
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
} // endif SetDataPath
} else
DBUG_RETURN(HA_ERR_INTERNAL_ERROR); // Should never happen
@see Item_func_group_concat::clear(),Item_sum_count_distinct::clear()and Item_func_group_concat::clear()initem_sum.cc; mysql_delete()insql_delete.cc; JOIN::reinit()insql_select.ccand st_select_lex_unit::exec()insql_union.cc.
*/ int ha_connect::delete_all_rows()
{ int rc= 0;
PGLOBAL g= xp->g;
DBUG_ENTER("ha_connect::delete_all_rows");
if (tdbp && tdbp->GetUse() == USE_OPEN &&
tdbp->GetAmType() != TYPE_AM_XML &&
tdbp->GetFtype() != RECFM_NAF) // Close and reopen the table so it will be deleted
rc= CloseTable(g);
if (!(rc= OpenTable(g))) { if (CntDeleteRow(g, tdbp, true)) {
htrc("%s\n", g->Message);
rc= HA_ERR_INTERNAL_ERROR;
} else
nox= false;
} // endif rc
DBUG_RETURN(rc);
} // end of delete_all_rows
staticbool checkPrivileges(THD *thd, TABTYPE type, PTOS options, constchar *db, TABLE *table, bool quick)
{ switch (type) { case TAB_UNDEF: // case TAB_CATLG: case TAB_PLG: case TAB_JCT: case TAB_DMY: case TAB_NIY:
my_printf_error(ER_UNKNOWN_ERROR, "Unsupported table type %s", MYF(0), options->type); returntrue;
case TAB_DOS: case TAB_FIX: case TAB_BIN: case TAB_CSV: case TAB_FMT: case TAB_DBF: case TAB_XML: case TAB_INI: case TAB_VEC: case TAB_REST: case TAB_JSON: #ifdefined(BSON_SUPPORT) case TAB_BSON: #endif// BSON_SUPPORT if (options->filename && *options->filename) { if (!quick) { char path[FN_REFLEN], dbpath[FN_REFLEN];
// Fall through case TAB_MYSQL: case TAB_DIR: case TAB_ZIP: case TAB_OEM: if (table && table->pos_in_table_list) { // if SELECT #if MYSQL_VERSION_ID > 100200
Switch_to_definer_security_ctx backup_ctx(thd, table->pos_in_table_list); #endif// VERSION_ID > 100200 return check_global_access(thd, FILE_ACL);
} else return check_global_access(thd, FILE_ACL); case TAB_ODBC: case TAB_JDBC: case TAB_MONGO: case TAB_MAC: case TAB_WMI: returnfalse; case TAB_TBL: case TAB_XCL: case TAB_PRX: case TAB_OCCUR: case TAB_PIVOT: case TAB_VIR: default: // This is temporary until a solution is found returnfalse;
} // endswitch type
my_printf_error(ER_UNKNOWN_ERROR, "check_privileges failed", MYF(0)); returntrue;
} // end of checkPrivileges
// Check whether the user has required (file) privileges bool ha_connect::check_privileges(THD *thd, PTOS options, constchar *dbn, bool quick)
{ constchar *db= (dbn && *dbn) ? dbn : NULL;
TABTYPE type=GetRealType(options);
return checkPrivileges(thd, type, options, db, table, quick);
} // end of check_privileges
// Check that two indexes are equivalent bool ha_connect::IsSameIndex(PIXDEF xp1, PIXDEF xp2)
{ bool b= true;
PKPDEF kp1, kp2;
// Next code is temporarily replaced until sql_command is set
stop= false;
if (newmode == MODE_WRITE) { switch (thd_sql_command(thd)) { case SQLCOM_LOCK_TABLES:
locked= 2; // fall through case SQLCOM_CREATE_TABLE: case SQLCOM_INSERT: case SQLCOM_LOAD: case SQLCOM_INSERT_SELECT:
newmode= MODE_INSERT; break; // case SQLCOM_REPLACE: // case SQLCOM_REPLACE_SELECT: // newmode= MODE_UPDATE; // To be checked // break; case SQLCOM_DELETE_MULTI:
*cras= true; // fall through case SQLCOM_DELETE: case SQLCOM_TRUNCATE:
newmode= MODE_DELETE; break; case SQLCOM_UPDATE_MULTI:
*cras= true; // fall through case SQLCOM_UPDATE:
newmode= MODE_UPDATE; break; case SQLCOM_SELECT: case SQLCOM_OPTIMIZE:
newmode= MODE_READ; break; case SQLCOM_FLUSH:
locked= 0; // fall through case SQLCOM_DROP_TABLE: case SQLCOM_RENAME_TABLE:
newmode= MODE_ANY; break; case SQLCOM_CREATE_VIEW: case SQLCOM_DROP_VIEW:
newmode= MODE_ANY; break; case SQLCOM_ALTER_TABLE:
newmode= MODE_ALTER; break; case SQLCOM_DROP_INDEX: case SQLCOM_CREATE_INDEX: // if (!IsPartitioned()) {
newmode= MODE_ANY; break; // } // endif partitioned case SQLCOM_REPAIR: // TODO implement it
newmode= MODE_UPDATE; break; default:
htrc("Unsupported sql_command=%d\n", thd_sql_command(thd));
snprintf(g->Message, sizeof(g->Message), "CONNECT Unsupported command");
my_message(ER_NOT_ALLOWED_COMMAND, g->Message, MYF(0));
newmode= MODE_ERROR; break;
} // endswitch newmode
} elseif (newmode == MODE_READ) { switch (thd_sql_command(thd)) { case SQLCOM_CREATE_TABLE:
*chk= true; break; case SQLCOM_UPDATE_MULTI: case SQLCOM_DELETE_MULTI:
*cras= true; case SQLCOM_INSERT: case SQLCOM_LOAD: case SQLCOM_INSERT_SELECT: // case SQLCOM_REPLACE: // case SQLCOM_REPLACE_SELECT: case SQLCOM_DELETE: case SQLCOM_TRUNCATE: case SQLCOM_UPDATE: case SQLCOM_SELECT: case SQLCOM_OPTIMIZE: case SQLCOM_SET_OPTION: break; case SQLCOM_LOCK_TABLES:
locked= 1; break; case SQLCOM_DROP_TABLE: case SQLCOM_RENAME_TABLE:
newmode= MODE_ANY; break; case SQLCOM_CREATE_VIEW: case SQLCOM_DROP_VIEW: case SQLCOM_CREATE_TRIGGER: case SQLCOM_DROP_TRIGGER:
newmode= MODE_ANY; break; case SQLCOM_ALTER_TABLE:
*chk= true;
newmode= MODE_ALTER; break; case SQLCOM_DROP_INDEX: case SQLCOM_CREATE_INDEX: // if (!IsPartitioned()) {
*chk= true;
newmode= MODE_ANY; break; // } // endif partitioned
case SQLCOM_CHECK: // TODO implement it case SQLCOM_ANALYZE: // TODO implement it case SQLCOM_END: // Met in procedures: IF(EXISTS(SELECT...
newmode= MODE_READ; break; default:
htrc("Unsupported sql_command=%d\n", thd_sql_command(thd));
snprintf(g->Message, sizeof(g->Message), "CONNECT Unsupported command");
my_message(ER_NOT_ALLOWED_COMMAND, g->Message, MYF(0));
newmode= MODE_ERROR; break;
} // endswitch newmode
} // endif's newmode
if (trace(1))
htrc("New mode=%d\n", newmode);
return newmode;
} // end of check_mode
int ha_connect::start_stmt(THD *thd, thr_lock_type lock_type)
{ int rc= 0; bool chk=false, cras= false;
MODE newmode;
PGLOBAL g= GetPlug(thd, xp);
DBUG_ENTER("ha_connect::start_stmt");
if (check_privileges(thd, GetTableOptionStruct(), table->s->db.str, true))
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
// Action will depend on lock_type switch (lock_type) { case TL_WRITE_ALLOW_WRITE: case TL_WRITE_CONCURRENT_INSERT: case TL_WRITE_DELAYED: case TL_WRITE_DEFAULT: case TL_WRITE_LOW_PRIORITY: case TL_WRITE: case TL_WRITE_ONLY:
newmode= MODE_WRITE; break; case TL_READ: case TL_READ_WITH_SHARED_LOCKS: case TL_READ_HIGH_PRIORITY: case TL_READ_NO_INSERT: case TL_READ_DEFAULT:
newmode= MODE_READ; break; case TL_UNLOCK: default:
newmode= MODE_ANY; break;
} // endswitch mode
if (newmode == MODE_ANY) { if (CloseTable(g)) { // Make error a warning to avoid crash
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, g->Message);
rc= 0;
} // endif Close
locked= 0;
xmod= MODE_ANY; // For info commands
DBUG_RETURN(rc);
} // endif MODE_ANY
newmode= CheckMode(g, thd, newmode, &chk, &cras);
if (newmode == MODE_ERROR)
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
DBUG_RETURN(check_stmt(g, newmode, cras));
} // end of start_stmt
if (oldsep != newsep) { // All indexes have to be remade
ddp->DeleteIndexFile(g, NULL);
oldpix= NULL;
ddp->SetIndx(NULL);
SetBooleanOption("Sepindex", newsep);
} elseif (newsep) { // Make the list of dropped indexes
xlst= &drp; xprc= &oldpix;
for (xp2= oldpix; xp2; xp2= xp) { for (xp1= newpix; xp1; xp1= xp1->Next) if (IsSameIndex(xp1, xp2)) break; // Index not to drop
if (adp) // Here we do make the new indexes if (tdp->MakeIndex(g, adp, true) == RC_FX) { // Make it a warning to avoid crash //push_warning(thd, Sql_condition::WARN_LEVEL_WARN, // ER_UNKNOWN_ERROR, g->Message); //rc= 0;
my_message(ER_TOO_MANY_KEYS, g->Message, MYF(0));
rc= HA_ERR_INDEX_CORRUPT;
} // endif MakeIndex
} elseif (tdbp->GetDef()->Indexable() == 3) { if (CheckVirtualIndex(NULL)) { // Make it a warning to avoid crash
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
ER_UNKNOWN_ERROR, g->Message);
rc= 0;
} // endif Check
} // endif indexable
} // endif Tdbp
} // endelse Xchk
if (CloseTable(g)) { // This is an error while building index // Make it a warning to avoid crash
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, g->Message);
rc= 0;
} // endif Close
locked= 0;
xmod= MODE_ANY; // For info commands
DBUG_RETURN(rc);
} elseif (check_privileges(thd, options, table->s->db.str)) {
snprintf(g->Message, sizeof(g->Message), "This operation requires the FILE privilege");
htrc("%s\n", g->Message);
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
} // endif check_privileges
DBUG_ASSERT(table && table->s);
// Table mode depends on the query type
newmode= CheckMode(g, thd, newmode, &xcheck, &cras);
if (newmode == MODE_ERROR)
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
DBUG_RETURN(check_stmt(g, newmode, cras));
} // end of external_lock
int ha_connect::check_stmt(PGLOBAL g, MODE newmode, bool cras)
{ int rc= 0;
DBUG_ENTER("ha_connect::check_stmt");
// If this is the start of a new query, cleanup the previous one if (xp->CheckCleanup()) {
tdbp= NULL;
valid_info= false;
} // endif CheckCleanup
if (cras)
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);
// Set or reset the good database environment if (CntCheckDB(g, this, GetDBName(NULL))) {
htrc("%p check_stmt: %s\n", this, g->Message);
rc= HA_ERR_INTERNAL_ERROR; // This can NOT be called without open called first, but // the table can have been closed since then
} elseif (!tdbp || xp->CheckQuery(valid_query_id) || xmod != newmode) { if (tdbp) { // If this is called by a later query, the table may have // been already closed and the tdbp is not valid anymore. if (xp->last_query_id == valid_query_id)
rc= CloseTable(g); else
tdbp= NULL;
} // endif tdbp
xmod= newmode;
// Delay open until used fields are known
} // endif tdbp
/* Find filename - the rightmost directory part */ if (strnrchr(&t, filename, length, slash) || t.length + 1 > table_size) returntrue;
memcpy(table, t.str, t.length);
table[t.length]= '\0'; if (!(length-= t.length)) returntrue;
length--; /* Skip slash */
/* Find database name - the second rightmost directory part */ if (strnrchr(&d, filename, length, slash) || d.length + 1 > database_size) returntrue;
memcpy(database, d.str, d.length);
database[d.length]= '\0'; returnfalse;
} // end of filename_to_dbname_and_tablename
// If a temporary file exists, all the tests below were passed // successfully when making it, so they are not needed anymore // in particular because they sometimes cause DBUG_ASSERT crash. // Also, for partitioned tables, no test can be done because when // this function is called, the .par file is already deleted and // this causes the open_table_def function to fail. // Not having any other clues (table and table_share are NULL) // the only mean we have to test for partitioning is this: if (*tabname != '#' && !strstr(tabname, "#P#")) { // We have to retrieve the information about this table options.
ha_table_option_struct *pos; char key[MAX_DBKEY_LENGTH];
uint key_length;
TABLE_SHARE *share;
// if ((p= strstr(tabname, "#P#"))) won't work, see above // *p= 0; // Get the main the table name
key_length= tdc_create_key(key, db, tabname);
// share contains the option struct that we need if (!(share= alloc_table_share(db, tabname, key, key_length)))
DBUG_RETURN(rc);
// Get the share info from the .frm file
Dummy_error_handler error_handler;
thd->push_internal_handler(&error_handler); bool got_error= open_table_def(thd, share);
thd->pop_internal_handler(); if (!got_error && share->db_type() != connect_hton)
{ /* The .frm file is not for the connect engine. Something is wrong! */
got_error= 1;
rc= HA_ERR_INTERNAL_ERROR;
my_error(HA_ERR_INTERNAL_ERROR, MYF(0), "TABLE_SHARE is not for the CONNECT engine");
} if (!got_error) { // Now we can work if ((pos= share->option_struct_table)) { if (check_privileges(thd, pos, db))
rc= HA_ERR_INTERNAL_ERROR; // ??? else if (IsFileType(GetRealType(pos)) && !pos->filename)
ok= true;
if (ok) { // Let the base handler do the job if (to)
rc= handler::rename_table(name, to); elseif ((rc= handler::delete_table(name)) == ENOENT)
rc= 0; // No files is not an error for CONNECT
} // endif ok
DBUG_RETURN(rc);
} // end of delete_or_rename_table
int ha_connect::delete_table(constchar *name)
{ return delete_or_rename_table(name, NULL);
} // end of delete_table
int ha_connect::rename_table(constchar *from, constchar *to)
{ return delete_or_rename_table(from, to);
} // end of rename_table
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)));
} elseif (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(STRING_WITH_LEN(" UNSIGNED")); elseif (v == 'Z')
error |= sql->append(STRING_WITH_LEN(" ZEROFILL"));
if (!(shm= (char*)db))
db= table_s->db.str; // Default value
try { // Check table type if (ttp == TAB_UNDEF && !topt->http) {
topt->type= (src) ? "MYSQL" : (tab) ? "PROXY" : "DOS";
ttp= GetTypeID(topt->type);
snprintf(g->Message, sizeof(g->Message), "No table_type. Was set to %s", topt->type);
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR, g->Message);
} elseif (ttp == TAB_NIY) {
snprintf(g->Message, sizeof(g->Message), "Unsupported table type %s", topt->type);
rc= HA_ERR_INTERNAL_ERROR; goto err; #ifdefined(REST_SUPPORT)
} elseif (topt->http) { if (ttp == TAB_UNDEF) {
ttr= TAB_JSON;
snprintf(g->Message, sizeof(g->Message), "No table_type. Was set to JSON");
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR, g->Message);
} else
ttr= ttp;
switch (ttr) { case TAB_JSON: #ifdefined(BSON_SUPPORT) case TAB_BSON: #endif// BSON_SUPPORT case TAB_XML: case TAB_CSV:
ttp = TAB_REST; break; default: break;
} // endswitch type #endif// REST_SUPPORT
} // endif ttp
if (fn && *fn) switch (ttp) { case TAB_FMT: case TAB_DBF: case TAB_XML: case TAB_INI: case TAB_VEC: case TAB_REST: case TAB_JSON: #ifdefined(BSON_SUPPORT) case TAB_BSON: #endif// BSON_SUPPORT if (checkPrivileges(thd, ttp, topt, db)) {
snprintf(g->Message, sizeof(g->Message), "This operation requires the FILE privilege");
rc= HA_ERR_INTERNAL_ERROR; goto err;
} // endif check_privileges
break; default: break;
} // endswitch ttp
if (!tab) { if (ttp == TAB_TBL) { // Make tab the first table of the list char *p;
break; #ifdefined(_WIN32) case TAB_WMI:
ok= true; break; #endif// _WIN32 case TAB_PIVOT:
supfnc= FNC_NO; // fall through case TAB_PRX: case TAB_TBL: case TAB_XCL: case TAB_OCCUR: if (!src && !stricmp(tab, create_info->alias.str) &&
(!db || !stricmp(db, table_s->db.str)))
snprintf(g->Message, sizeof(g->Message), "A %s table cannot refer to itself", topt->type); else
ok= true;
break; case TAB_OEM: if (topt->module && topt->subtype)
ok= true; else
snprintf(g->Message, sizeof(g->Message), "Missing OEM module or subtype");
break; #ifdefined(LIBXML2_SUPPORT) || defined(DOMDOC_SUPPORT) case TAB_XML: #endif// LIBXML2_SUPPORT || DOMDOC_SUPPORT case TAB_JSON: #ifdefined(BSON_SUPPORT) case TAB_BSON: #endif// BSON_SUPPORT
dsn= (char*)create_info->option_struct->connect;
ok= true; break; #ifdefined(JAVA_SUPPORT) case TAB_MONGO: if (!topt->tabname)
topt->tabname= tab;
ok= true; break; #endif// JAVA_SUPPORT #ifdefined(REST_SUPPORT) case TAB_REST: if (!topt->http)
snprintf(g->Message, sizeof(g->Message), "Missing %s HTTP address", topt->type); else
ok= true;
break; #endif// REST_SUPPORT case TAB_VIR:
ok= true; break; default:
snprintf(g->Message, sizeof(g->Message), "Cannot get column info for table type %s", topt->type); break;
} // endif ttp
// Check for supported catalog function if (ok && !(supfnc & fnc)) {
snprintf(g->Message, sizeof(g->Message), "Unsupported catalog function %s for table type %s",
fncn, topt->type);
ok= false;
} // endif supfnc
if (src && fnc != FNC_NO) {
snprintf(g->Message, sizeof(g->Message), "Cannot make catalog table from srcdef");
ok= false;
} // endif src
if (ok) { constchar *cnm, *rem; char *dft, *xtra, *key, *fmt; int i, len, prec, dec, typ, flg;
// Not a catalog table if (!qrp->Nblin) { if (tab)
snprintf(g->Message, sizeof(g->Message), "Cannot get columns from %s", tab); else
strncpy(g->Message, "Fail to retrieve columns", sizeof(g->Message));
break; case FLD_TYPE:
typ= crp->Kdata->GetIntValue(i);
v= (crp->Nulls) ? crp->Nulls[i] : 0; break; case FLD_TYPENAME:
tn= crp->Kdata->GetCharValue(i); break; case FLD_PREC: // PREC must be always before LENGTH
len= prec= crp->Kdata->GetIntValue(i); break; case FLD_LENGTH:
len= crp->Kdata->GetIntValue(i); break; case FLD_SCALE:
dec= (!crp->Kdata->IsNull(i)) ? crp->Kdata->GetIntValue(i) : -1; break; case FLD_NULL: if (crp->Kdata->GetIntValue(i))
tm= 0; // Nullable
break; case FLD_FLAG:
flg = crp->Kdata->GetIntValue(i); break; case FLD_FORMAT:
fmt= (crp->Kdata) ? crp->Kdata->GetCharValue(i) : NULL; break; case FLD_REM:
rem= crp->Kdata->GetCharValue(i); break; // case FLD_CHARSET: // No good because remote table is already translated // if (*(csn= crp->Kdata->GetCharValue(i))) // cs= get_charset_by_name(csn, 0);
// break; case FLD_DEFAULT:
dft= crp->Kdata->GetCharValue(i); break; case FLD_EXTRA:
xtra= crp->Kdata->GetCharValue(i);
// Auto_increment is not supported yet if (!stricmp(xtra, "AUTO_INCREMENT"))
xtra= NULL;
break; case FLD_KEY: if (ttp == TAB_VIR)
key= crp->Kdata->GetCharValue(i);
#ifdefined(ODBC_SUPPORT) if (ttp == TAB_ODBC) { int plgtyp; bool w= false; // Wide character type
// typ must be PLG type, not SQL type if (!(plgtyp= TranslateSQLType(typ, dec, prec, v, w))) { if (GetTypeConv() == TPC_SKIP) { // Skip this column
snprintf(g->Message, sizeof(g->Message), "Column %s skipped (unsupported type %d)",
cnm, typ);
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, g->Message); continue;
} else {
snprintf(g->Message, sizeof(g->Message), "Unsupported SQL type %d", typ);
rc= HA_ERR_INTERNAL_ERROR; goto err;
} // endif type_conv
} else
typ= plgtyp;
switch (typ) { case TYPE_STRING: if (w) {
snprintf(g->Message, sizeof(g->Message), "Column %s is wide characters", cnm);
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR, 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;
} // endswitch typ
} else #endif// ODBC_SUPPORT #ifdefined(JAVA_SUPPORT) if (ttp == TAB_JDBC) { int plgtyp;
// typ must be PLG type, not SQL type if (!(plgtyp= TranslateJDBCType(typ, tn, dec, prec, v))) { if (GetTypeConv() == TPC_SKIP) { // Skip this column
snprintf(g->Message, sizeof(g->Message), "Column %s skipped (unsupported type %d)",
cnm, typ);
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, g->Message); continue;
} else {
snprintf(g->Message, sizeof(g->Message), "Unsupported SQL type %d", typ);
rc= HA_ERR_INTERNAL_ERROR; goto err;
} // endif type_conv
} else
typ= plgtyp;
switch (typ) { case TYPE_DOUBLE: case TYPE_DECIM: // Some data sources do not count dec in length (prec)
prec += (dec + 2); // To be safe break; default:
dec= 0;
} // endswitch typ
} else #endif// ODBC_SUPPORT // Make the arguments as required by add_fields if (typ == TYPE_DOUBLE)
prec= len;
if (typ == TYPE_DATE)
prec= 0;
// Now add the field 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
} // endif fnc
if (!rc)
rc= init_table_share(thd, table_s, create_info, &sql);
if (table_arg->versioned())
{ /* Due to microseconds not supported by CONNECT (MDEV-15967) system versioning
cannot work as expected (MDEV-15968, MDEV-28288) */
my_error(ER_VERS_NOT_SUPPORTED, MYF(0), "CONNECT storage engine");
DBUG_RETURN(HA_ERR_UNSUPPORTED);
}
// Can be null in ALTER TABLE if (create_info->alias.str) // Check whether a table is defined on itself switch (type) { case TAB_PRX: case TAB_XCL: case TAB_PIVOT: case TAB_OCCUR: if (options->srcdef) {
snprintf(g->Message, sizeof(g->Message), "Cannot check looping reference");
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, g->Message);
} elseif (options->tabname) { if (!stricmp(options->tabname, create_info->alias.str) &&
(!options->dbname ||
!stricmp(options->dbname, table_arg->s->db.str))) {
snprintf(g->Message, sizeof(g->Message), "A %s table cannot refer to itself",
options->type);
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
} // endif tab
} else {
snprintf(g->Message, sizeof(g->Message), "Missing object table name or definition");
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
} // endif tabname
// fall through case TAB_MYSQL: if (!part_info)
{constchar *src= options->srcdef;
PCSZ host, db, tab= options->tabname; int port;
// Note that if no support is specified, the default is MS-DOM // on Windows and libxml2 otherwise switch (toupper(*xsup)) { case'*': #ifdefined(_WIN32)
dom= true; #else// !_WIN32
dom= false; #endif// !_WIN32 break; case'M': case'D':
dom= true; break; default:
dom= false; break;
} // endswitch xsup
#if !defined(DOMDOC_SUPPORT) if (dom) {
snprintf(g->Message, sizeof(g->Message), "MS-DOM not supported by this version");
xsup= NULL;
} // endif DomDoc #endif// !DOMDOC_SUPPORT
#if !defined(LIBXML2_SUPPORT) if (!dom) {
snprintf(g->Message, sizeof(g->Message), "libxml2 not supported by this version");
xsup= NULL;
} // endif Libxml2 #endif// !LIBXML2_SUPPORT
if (fp->vcol_info && !fp->stored_in_db) continue; // This is a virtual column
if (fp->flags & AUTO_INCREMENT_FLAG) {
snprintf(g->Message, sizeof(g->Message), "Auto_increment is not supported yet");
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
rc= HA_ERR_INTERNAL_ERROR;
DBUG_RETURN(rc);
} // endif flags
if (fp->flags & (BLOB_FLAG | ENUM_FLAG | SET_FLAG)) {
snprintf(g->Message, sizeof(g->Message), "Unsupported type for column %s",
fp->field_name.str);
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
rc= HA_ERR_INTERNAL_ERROR;
DBUG_RETURN(rc);
} // endif flags
if (type == TAB_VIR) if (!fp->option_struct || !fp->option_struct->special) {
snprintf(g->Message, sizeof(g->Message), "Virtual tables accept only special or virtual columns");
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
rc= HA_ERR_INTERNAL_ERROR;
DBUG_RETURN(rc);
} // endif special
switch (fp->type()) { case MYSQL_TYPE_SHORT: case MYSQL_TYPE_LONG: case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: case MYSQL_TYPE_TIMESTAMP: case MYSQL_TYPE_DATE: case MYSQL_TYPE_TIME: case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_YEAR: case MYSQL_TYPE_NEWDATE: case MYSQL_TYPE_LONGLONG: case MYSQL_TYPE_TINY: case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_NEWDECIMAL: case MYSQL_TYPE_INT24: break; // Ok case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: #if0 if (!fp->field_length) {
snprintf(g->Message, sizeof(g->Message), "Unsupported 0 length for column %s",
fp->field_name.str);
rc= HA_ERR_INTERNAL_ERROR;
my_printf_error(ER_UNKNOWN_ERROR, "Unsupported 0 length for column %s",
MYF(0), fp->field_name.str);
DBUG_RETURN(rc);
} // endif fp #endif// 0 break; // To be checked case MYSQL_TYPE_BIT: case MYSQL_TYPE_NULL: case MYSQL_TYPE_ENUM: case MYSQL_TYPE_SET: case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: case MYSQL_TYPE_GEOMETRY: default: // fprintf(stderr, "Unsupported type column %s\n", fp->field_name.str);
snprintf(g->Message, sizeof(g->Message), "Unsupported type for column %s",
fp->field_name.str);
rc= HA_ERR_INTERNAL_ERROR;
my_printf_error(ER_UNKNOWN_ERROR, "Unsupported type for column %s",
MYF(0), fp->field_name.str);
DBUG_RETURN(rc); break;
} // endswitch type
if ((fp)->real_maybe_null() && !IsTypeNullable(type)) {
my_printf_error(ER_UNKNOWN_ERROR, "Table type %s does not support nullable columns",
MYF(0), options->type);
DBUG_RETURN(HA_ERR_UNSUPPORTED);
} // endif !nullable
if (dbf) { bool b= false;
if ((b= fp->field_name.length > 10))
snprintf(g->Message, sizeof(g->Message), "DBF: Column name '%s' is too long (max=10)",
fp->field_name.str); elseif ((b= fp->field_length > 255))
snprintf(g->Message, sizeof(g->Message), "DBF: Column length too big for '%s' (max=255)",
fp->field_name.str);
if (b) {
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
rc= HA_ERR_INTERNAL_ERROR;
DBUG_RETURN(rc);
} // endif b
} // endif dbf
} // endfor field
if ((sqlcom == SQLCOM_CREATE_TABLE || *GetTableName() == '#') && inward) { // The file name is not specified, create a default file in // the database directory named table_name.table_type. // (temporarily not done for XML because a void file causes // the XML parsers to report an error on the first Insert) char buf[_MAX_PATH], fn[_MAX_PATH], dbpath[_MAX_PATH], lwt[12]; int h;
// Check for incompatible options if (options->sepindex) {
my_message(ER_UNKNOWN_ERROR, "SEPINDEX is incompatible with unspecified file name", MYF(0));
DBUG_RETURN(HA_ERR_UNSUPPORTED);
} elseif (GetTypeID(options->type) == TAB_VEC) { if (!table->s->max_rows || options->split) {
my_printf_error(ER_UNKNOWN_ERROR, "%s tables whose file name is unspecified cannot be split",
MYF(0), options->type);
DBUG_RETURN(HA_ERR_UNSUPPORTED);
} elseif (options->header == 2) {
my_printf_error(ER_UNKNOWN_ERROR, "header=2 is not allowed for %s tables whose file name is unspecified",
MYF(0), options->type);
DBUG_RETURN(HA_ERR_UNSUPPORTED);
} // endif's
} elseif (options->zipped) {
my_message(ER_UNKNOWN_ERROR, "ZIPPED is incompatible with unspecified file name", MYF(0));
DBUG_RETURN(HA_ERR_UNSUPPORTED);
} // endif's options
// Fold type to lower case for (int i= 0; i < 12; i++) if (!options->type[i]) {
lwt[i]= 0; break;
} else
lwt[i]= tolower(options->type[i]);
if ((type == TAB_FMT || options->readonly) && sqlcom == SQLCOM_CREATE_TABLE)
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, "Congratulation, you just created a read-only void table!");
} // endif sqlcom
if (trace(1))
htrc("xchk=%p createas=%d\n", g->Xchk, g->Createas);
if (options->zipped) { #ifdefined(ZIP_SUPPORT) // Check whether the zip entry must be made from a file
PCSZ fn= GetListOption(g, "Load", options->oplist, NULL);
if (g->Alchecked == 0 &&
(!IsFileType(type) || FileExists(options->filename, false))) { if (part_info) {
snprintf(g->Message, sizeof(g->Message), "Data repartition in %s is unchecked", partname);
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, g->Message);
} elseif (sqlcom == SQLCOM_ALTER_TABLE) { // This is an ALTER to CONNECT from another engine. // It cannot be accepted because the table data would be modified // except when the target file does not exist.
snprintf(g->Message, sizeof(g->Message), "Operation denied. Table data would be modified.");
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
} // endif part_info
} // endif outward
// Get the index definitions if ((xdp= GetIndexInfo()) || sqlcom == SQLCOM_DROP_INDEX) { if (options->multiple) {
snprintf(g->Message, sizeof(g->Message), "Multiple tables are not indexable");
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
rc= HA_ERR_UNSUPPORTED;
} elseif (options->compressed) {
snprintf(g->Message, sizeof(g->Message), "Compressed tables are not indexable");
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
rc= HA_ERR_UNSUPPORTED;
} elseif (xdp->Invalid) {
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
rc= HA_ERR_UNSUPPORTED;
} elseif (GetIndexType(type) == 1) {
PDBUSER dup= PlgGetUser(g);
PCATLG cat= (dup) ? dup->Catalog : NULL;
} elseif (!GetIndexType(type)) {
snprintf(g->Message, sizeof(g->Message), "Table type %s is not indexable", options->type);
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
rc= HA_ERR_UNSUPPORTED;
} // endif index type
} // endif xdp
} else { // This should not happen anymore with indexing new way
my_message(ER_UNKNOWN_ERROR, "CONNECT index modification should be in-place", MYF(0));
DBUG_RETURN(HA_ERR_UNSUPPORTED);
} // endif Xchk
table= st;
DBUG_RETURN(rc);
} // end of create
PRAGMA_REENABLE_CHECK_STACK_FRAME
// This is to avoid an initialization error raised by the // test on check_table_flags made in ha_partition::open // that can fail if some partition files are empty.
b= true;
} else
strcpy(tfn, fn);
} elseif (!GetIndexType(type)) {
snprintf(g->Message, sizeof(g->Message), "Table type %s is not indexable", oldopt->type);
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
DBUG_RETURN(HA_ALTER_ERROR);
} // endif index type
} // endif index operation
if (!SameString(altered_table, "filename")) { if (!outward) { // Conversion to outward table is only allowed for file based // tables whose file does not exist.
tshp= altered_table->s;
PCSZ fn= GetStringOption("filename");
tshp= NULL;
if (FileExists(fn, false)) {
snprintf(g->Message, sizeof(g->Message), "Operation denied. Table data would be lost.");
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
DBUG_RETURN(HA_ALTER_ERROR);
} else goto fin;
} else goto fin;
} // endif filename
/* Is there at least one operation that requires copy algorithm? */ if (ha_alter_info->handler_flags & ~inplace_offline_operations) goto fin;
if (table->file->check_if_incompatible_data(create_info, table_changes)
== COMPATIBLE_DATA_YES)
DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK); #endif// 0
// This was in check_if_incompatible_data if (NoFieldOptionChange(altered_table) &&
type == newtyp &&
SameInt(altered_table, "lrecl") &&
SameInt(altered_table, "elements") &&
SameInt(altered_table, "header") &&
SameInt(altered_table, "quoted") &&
SameInt(altered_table, "ending") &&
SameInt(altered_table, "compressed"))
DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK);
fin: if (idx) { // Indexing is only supported inplace
my_message(ER_ALTER_OPERATION_NOT_SUPPORTED, "Alter operations not supported together by CONNECT", MYF(0));
DBUG_RETURN(HA_ALTER_ERROR);
} elseif (outward) { if (IsFileType(type))
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, "This is an outward table, table data were not modified.");
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.
push_warning(ha_thd(), Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, "Unexpected call to check_if_incompatible_data.");
DBUG_RETURN(COMPATIBLE_DATA_NO);
} // end of check_if_incompatible_data
/***********************************************************************/ /* CONNECT global variables definitions. */ /***********************************************************************/ #ifdefined(XMAP) // Using file mapping for indexes if true static MYSQL_SYSVAR_BOOL(indx_map, xmap, PLUGIN_VAR_RQCMDARG, "Using file mapping for indexes", NULL, NULL, 0); #endif// XMAP
#ifdefined(XMSG) static MYSQL_SYSVAR_STR(errmsg_dir_path, msg_path, // PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Path to the directory where are the message files", // check_msg_path, update_msg_path,
NULL, NULL, "../../../../storage/connect/"); // for testing #endif// XMSG
#ifdefined(JAVA_SUPPORT) static MYSQL_SYSVAR_STR(jvm_path, JvmPath,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC, "Path to the directory where is the JVM lib", // check_jvm_path, update_jvm_path,
NULL, NULL, NULL);
maria_declare_plugin(connect)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
&connect_storage_engine, "CONNECT", "Olivier Bertrand", "Management of External Data (SQL/NOSQL/MED), including Rest query results",
PLUGIN_LICENSE_GPL,
connect_init_func, /* Plugin Init */
connect_done_func, /* Plugin Deinit */ 0x0107, /* version number (1.07) */
NULL, /* status variables */
connect_system_variables, /* system variables */ "1.07.0003", /* string version */
MariaDB_PLUGIN_MATURITY_STABLE /* maturity */
}
maria_declare_plugin_end;
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.444Bemerkung:
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.