mirror of
https://github.com/MariaDB/server.git
synced 2026-05-07 23:54:31 +02:00
Fix and Enhance remote indexing:
- Apply to ODBC tables as well as MYSQL tables - Fix and enhance the CheckCond routine Make ReadKey and MakeKeyWhere handle all conditions modified: storage/connect/.gitattributes modified: storage/connect/.gitignore modified: storage/connect/connect.cc modified: storage/connect/connect.h modified: storage/connect/ha_connect.cc modified: storage/connect/ha_connect.h modified: storage/connect/mycat.cc modified: storage/connect/tabmysql.cpp modified: storage/connect/tabmysql.h modified: storage/connect/tabodbc.cpp modified: storage/connect/tabodbc.h modified: storage/connect/xobject.cpp modified: storage/connect/xobject.h modified: storage/connect/xtable.h Add some new tests: storage/connect/mysql-test/connect/r/endian.result storage/connect/mysql-test/connect/r/mysql_index.result storage/connect/mysql-test/connect/t/endian.test storage/connect/mysql-test/connect/t/mysql_index.test
This commit is contained in:
parent
3a9a3b98b7
commit
a392c79552
18 changed files with 917 additions and 342 deletions
|
|
@ -169,9 +169,9 @@
|
|||
#define JSONMAX 10 // JSON Default max grp size
|
||||
|
||||
extern "C" {
|
||||
char version[]= "Version 1.03.0007 June 03, 2015";
|
||||
char version[]= "Version 1.04.0001 June 29, 2015";
|
||||
#if defined(__WIN__)
|
||||
char compver[]= "Version 1.03.0007 " __DATE__ " " __TIME__;
|
||||
char compver[]= "Version 1.04.0001 " __DATE__ " " __TIME__;
|
||||
char slash= '\\';
|
||||
#else // !__WIN__
|
||||
char slash= '/';
|
||||
|
|
@ -2188,97 +2188,157 @@ int ha_connect::ScanRecord(PGLOBAL g, uchar *)
|
|||
/***********************************************************************/
|
||||
int ha_connect::CheckRecord(PGLOBAL g, const uchar *, uchar *newbuf)
|
||||
{
|
||||
return ScanRecord(g, 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)
|
||||
return true;
|
||||
|
||||
} // endif active_index
|
||||
|
||||
return false;
|
||||
} // end of IsIndexed
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
/* Return the where clause for remote indexed read. */
|
||||
/***********************************************************************/
|
||||
bool ha_connect::MakeKeyWhere(PGLOBAL g, PSTRG qry, OPVAL op, char q,
|
||||
const void *key, int klen)
|
||||
bool ha_connect::MakeKeyWhere(PGLOBAL g, PSTRG qry, OPVAL vop, char q,
|
||||
const key_range *kr)
|
||||
{
|
||||
const uchar *ptr;
|
||||
uint rem, len, stlen; //, prtlen;
|
||||
bool nq, oom, b= false;
|
||||
Field *fp;
|
||||
KEY *kfp;
|
||||
KEY_PART_INFO *kpart;
|
||||
const uchar *ptr;
|
||||
uint i, rem, len, klen, stlen;
|
||||
bool nq, both, oom= false;
|
||||
OPVAL op;
|
||||
Field *fp;
|
||||
const key_range *ranges[2];
|
||||
my_bitmap_map *old_map;
|
||||
KEY *kfp;
|
||||
KEY_PART_INFO *kpart;
|
||||
|
||||
if (active_index == MAX_KEY)
|
||||
return false;
|
||||
else if (!key) {
|
||||
strcpy(g->Message, "MakeKeyWhere: No key");
|
||||
return true;
|
||||
} // endif key
|
||||
|
||||
oom= qry->Append(" WHERE (");
|
||||
kfp= &table->key_info[active_index];
|
||||
rem= kfp->user_defined_key_parts,
|
||||
len= klen,
|
||||
ptr= (const uchar *)key;
|
||||
ranges[0]= kr;
|
||||
ranges[1]= (end_range && !eq_range) ? &save_end_range : NULL;
|
||||
|
||||
for (kpart= kfp->key_part; rem; rem--, kpart++) {
|
||||
fp= kpart->field;
|
||||
stlen= kpart->store_length;
|
||||
// prtlen= MY_MIN(stlen, len);
|
||||
nq= fp->str_needs_quotes();
|
||||
if (!ranges[0] && !ranges[1]) {
|
||||
strcpy(g->Message, "MakeKeyWhere: No key");
|
||||
return true;
|
||||
} else
|
||||
both= ranges[0] && ranges[1];
|
||||
|
||||
if (b)
|
||||
oom|= qry->Append(" AND ");
|
||||
else
|
||||
b= true;
|
||||
kfp= &table->key_info[active_index];
|
||||
old_map= dbug_tmp_use_all_columns(table, table->write_set);
|
||||
|
||||
oom|= qry->Append(q);
|
||||
oom|= qry->Append((PSZ)fp->field_name);
|
||||
oom|= qry->Append(q);
|
||||
for (i = 0; i <= 1; i++) {
|
||||
if (ranges[i] == NULL)
|
||||
continue;
|
||||
|
||||
switch (op) {
|
||||
case OP_EQ:
|
||||
case OP_GT:
|
||||
case OP_GE:
|
||||
oom|= qry->Append((PSZ)GetValStr(op, false));
|
||||
break;
|
||||
default:
|
||||
oom|= qry->Append(" ??? ");
|
||||
} // endwitch op
|
||||
if (both && i > 0)
|
||||
oom|= qry->Append(") AND (");
|
||||
else
|
||||
oom|= qry->Append(" WHERE (");
|
||||
|
||||
if (nq)
|
||||
oom|= qry->Append('\'');
|
||||
klen= len= ranges[i]->length;
|
||||
rem= kfp->user_defined_key_parts;
|
||||
ptr= ranges[i]->key;
|
||||
|
||||
if (kpart->key_part_flag & HA_VAR_LENGTH_PART) {
|
||||
String varchar;
|
||||
uint var_length= uint2korr(ptr);
|
||||
for (kpart= kfp->key_part; rem; rem--, kpart++) {
|
||||
fp= kpart->field;
|
||||
stlen= kpart->store_length;
|
||||
nq= fp->str_needs_quotes();
|
||||
|
||||
varchar.set_quick((char*) ptr+HA_KEY_BLOB_LENGTH,
|
||||
var_length, &my_charset_bin);
|
||||
oom|= qry->Append(varchar.ptr(), varchar.length());
|
||||
} else {
|
||||
char strbuff[MAX_FIELD_WIDTH];
|
||||
String str(strbuff, sizeof(strbuff), kpart->field->charset()), *res;
|
||||
if (kpart != kfp->key_part)
|
||||
oom|= qry->Append(" AND ");
|
||||
|
||||
res= fp->val_str(&str, ptr);
|
||||
oom|= qry->Append(res->ptr(), res->length());
|
||||
} // endif flag
|
||||
if (q) {
|
||||
oom|= qry->Append(q);
|
||||
oom|= qry->Append((PSZ)fp->field_name);
|
||||
oom|= qry->Append(q);
|
||||
} else
|
||||
oom|= qry->Append((PSZ)fp->field_name);
|
||||
|
||||
if (nq)
|
||||
oom|= qry->Append('\'');
|
||||
switch (ranges[i]->flag) {
|
||||
case HA_READ_KEY_EXACT:
|
||||
// op= (stlen >= len || !nq || fp->result_type() != STRING_RESULT)
|
||||
// ? OP_EQ : OP_LIKE;
|
||||
op= OP_EQ;
|
||||
break;
|
||||
case HA_READ_AFTER_KEY:
|
||||
op= (stlen >= len) ? (!i ? OP_GT : OP_LE) : OP_GE;
|
||||
break;
|
||||
case HA_READ_KEY_OR_NEXT:
|
||||
op= OP_GE;
|
||||
break;
|
||||
case HA_READ_BEFORE_KEY:
|
||||
op= (stlen >= len) ? OP_LT : OP_LE;
|
||||
break;
|
||||
case HA_READ_KEY_OR_PREV:
|
||||
op= OP_LE;
|
||||
break;
|
||||
default:
|
||||
sprintf(g->Message, "cannot handle flag %d", ranges[i]->flag);
|
||||
goto err;
|
||||
} // endswitch flag
|
||||
|
||||
if (stlen >= len)
|
||||
break;
|
||||
oom|= qry->Append((PSZ)GetValStr(op, false));
|
||||
|
||||
len-= stlen;
|
||||
if (nq)
|
||||
oom|= qry->Append('\'');
|
||||
|
||||
/* For nullable columns, null-byte is already skipped before, that is
|
||||
ptr was incremented by 1. Since store_length still counts null-byte,
|
||||
we need to subtract 1 from store_length. */
|
||||
ptr+= stlen - MY_TEST(kpart->null_bit);
|
||||
} // endfor kpart
|
||||
if (kpart->key_part_flag & HA_VAR_LENGTH_PART) {
|
||||
String varchar;
|
||||
uint var_length= uint2korr(ptr);
|
||||
|
||||
varchar.set_quick((char*)ptr + HA_KEY_BLOB_LENGTH,
|
||||
var_length, &my_charset_bin);
|
||||
oom|= qry->Append(varchar.ptr(), varchar.length(), nq);
|
||||
} else {
|
||||
char strbuff[MAX_FIELD_WIDTH];
|
||||
String str(strbuff, sizeof(strbuff), kpart->field->charset()), *res;
|
||||
|
||||
res= fp->val_str(&str, ptr);
|
||||
oom|= qry->Append(res->ptr(), res->length(), nq);
|
||||
} // endif flag
|
||||
|
||||
if (nq)
|
||||
oom |= qry->Append('\'');
|
||||
|
||||
if (stlen >= len)
|
||||
break;
|
||||
|
||||
len-= stlen;
|
||||
|
||||
/* For nullable columns, null-byte is already skipped before, that is
|
||||
ptr was incremented by 1. Since store_length still counts null-byte,
|
||||
we need to subtract 1 from store_length. */
|
||||
ptr+= stlen - MY_TEST(kpart->null_bit);
|
||||
} // endfor kpart
|
||||
|
||||
} // endfor i
|
||||
|
||||
if ((oom|= qry->Append(")")))
|
||||
strcpy(g->Message, "Out of memory");
|
||||
|
||||
return oom;
|
||||
dbug_tmp_restore_column_map(table->write_set, old_map);
|
||||
return oom;
|
||||
|
||||
err:
|
||||
dbug_tmp_restore_column_map(table->write_set, old_map);
|
||||
return true;
|
||||
} // end of MakeKeyWhere
|
||||
|
||||
|
||||
|
|
@ -2548,8 +2608,9 @@ PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond)
|
|||
/***********************************************************************/
|
||||
/* Check the WHERE condition and return a MYSQL/ODBC/WQL filter. */
|
||||
/***********************************************************************/
|
||||
PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
|
||||
PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
|
||||
{
|
||||
AMT tty = filp->Type;
|
||||
char *body= filp->Body;
|
||||
unsigned int i;
|
||||
bool ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
|
||||
|
|
@ -2582,7 +2643,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
|
|||
|
||||
List<Item>* arglist= cond_item->argument_list();
|
||||
List_iterator<Item> li(*arglist);
|
||||
Item *subitem;
|
||||
const Item *subitem;
|
||||
|
||||
p1= body + strlen(body);
|
||||
strcpy(p1, "(");
|
||||
|
|
@ -2590,7 +2651,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 (!CheckCond(g, filp, subitem)) {
|
||||
if (vop == OP_OR || nonul)
|
||||
return NULL;
|
||||
else
|
||||
|
|
@ -2612,26 +2673,27 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
|
|||
|
||||
} else if (cond->type() == COND::FUNC_ITEM) {
|
||||
unsigned int i;
|
||||
// int n;
|
||||
bool iscol, neg= FALSE;
|
||||
Item_func *condf= (Item_func *)cond;
|
||||
Item* *args= condf->arguments();
|
||||
|
||||
if (trace)
|
||||
htrc("Func type=%d argnum=%d\n", condf->functype(),
|
||||
condf->argument_count());
|
||||
|
||||
// neg= condf->
|
||||
condf->argument_count());
|
||||
|
||||
switch (condf->functype()) {
|
||||
case Item_func::EQUAL_FUNC:
|
||||
case Item_func::EQ_FUNC: vop= OP_EQ; break;
|
||||
case Item_func::NE_FUNC: vop= OP_NE; break;
|
||||
case Item_func::LT_FUNC: vop= OP_LT; break;
|
||||
case Item_func::LE_FUNC: vop= OP_LE; break;
|
||||
case Item_func::GE_FUNC: vop= OP_GE; break;
|
||||
case Item_func::GT_FUNC: vop= OP_GT; break;
|
||||
case Item_func::IN_FUNC: vop= OP_IN;
|
||||
case Item_func::EQ_FUNC: vop= OP_EQ; break;
|
||||
case Item_func::NE_FUNC: vop= OP_NE; break;
|
||||
case Item_func::LT_FUNC: vop= OP_LT; break;
|
||||
case Item_func::LE_FUNC: vop= OP_LE; break;
|
||||
case Item_func::GE_FUNC: vop= OP_GE; break;
|
||||
case Item_func::GT_FUNC: vop= OP_GT; break;
|
||||
case Item_func::LIKE_FUNC: vop= OP_LIKE; break;
|
||||
case Item_func::ISNOTNULL_FUNC:
|
||||
neg = true;
|
||||
case Item_func::ISNULL_FUNC: vop= OP_NULL; break;
|
||||
case Item_func::IN_FUNC: vop= OP_IN;
|
||||
case Item_func::BETWEEN:
|
||||
ismul= true;
|
||||
neg= ((Item_func_opt_neg *)condf)->negated;
|
||||
|
|
@ -2644,7 +2706,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
|
|||
else if (ismul && tty == TYPE_AM_WMI)
|
||||
return NULL; // Not supported by WQL
|
||||
|
||||
if (x && (neg || !(vop == OP_EQ || vop == OP_IN)))
|
||||
if (x && (neg || !(vop == OP_EQ || vop == OP_IN || vop == OP_NULL)))
|
||||
return NULL;
|
||||
|
||||
for (i= 0; i < condf->argument_count(); i++) {
|
||||
|
|
@ -2665,9 +2727,10 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
|
|||
|
||||
if (x && i)
|
||||
return NULL;
|
||||
|
||||
if (pField->field->table != table)
|
||||
return NULL; // Field does not belong to this table
|
||||
else if (pField->field->table != table)
|
||||
return NULL; // Field does not belong to this table
|
||||
else if (tty != TYPE_AM_WMI && IsIndexed(pField->field))
|
||||
return NULL; // Will be handled by ReadKey
|
||||
else
|
||||
fop= GetFieldOptionStruct(pField->field);
|
||||
|
||||
|
|
@ -2698,7 +2761,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
|
|||
strcat(body, fnm);
|
||||
} else if (args[i]->type() == COND::FUNC_ITEM) {
|
||||
if (tty == TYPE_AM_MYSQL) {
|
||||
if (!CheckCond(g, filp, tty, args[i]))
|
||||
if (!CheckCond(g, filp, args[i]))
|
||||
return NULL;
|
||||
|
||||
} else
|
||||
|
|
@ -2887,14 +2950,17 @@ const COND *ha_connect::cond_push(const COND *cond)
|
|||
goto fin;
|
||||
|
||||
if (b) {
|
||||
PCFIL filp= (PCFIL)PlugSubAlloc(g, NULL, sizeof(CONDFIL));
|
||||
PCFIL filp;
|
||||
|
||||
if ((filp= tdbp->GetCondFil()) && filp->Cond == cond &&
|
||||
filp->Idx == active_index && filp->Type == tty)
|
||||
goto fin; // Already done
|
||||
|
||||
filp= new(g) CONDFIL(cond, active_index, tty);
|
||||
filp->Body= (char*)PlugSubAlloc(g, NULL, (x) ? 128 : 0);
|
||||
*filp->Body= 0;
|
||||
filp->Op= OP_XX;
|
||||
filp->Cmds= NULL;
|
||||
|
||||
if (CheckCond(g, filp, tty, (Item *)cond)) {
|
||||
if (CheckCond(g, filp, cond)) {
|
||||
if (trace)
|
||||
htrc("cond_push: %s\n", filp->Body);
|
||||
|
||||
|
|
@ -3358,13 +3424,13 @@ int ha_connect::index_end()
|
|||
/****************************************************************************/
|
||||
/* This is internally called by all indexed reading functions. */
|
||||
/****************************************************************************/
|
||||
int ha_connect::ReadIndexed(uchar *buf, OPVAL op, const uchar *key, uint key_len)
|
||||
int ha_connect::ReadIndexed(uchar *buf, OPVAL op, const key_range *kr)
|
||||
{
|
||||
int rc;
|
||||
|
||||
//statistic_increment(ha_read_key_count, &LOCK_status);
|
||||
|
||||
switch (CntIndexRead(xp->g, tdbp, op, key, (int)key_len, mrr)) {
|
||||
switch (CntIndexRead(xp->g, tdbp, op, kr, mrr)) {
|
||||
case RC_OK:
|
||||
xp->fnd++;
|
||||
rc= MakeRecord((char*)buf);
|
||||
|
|
@ -3430,7 +3496,12 @@ int ha_connect::index_read(uchar * buf, const uchar * key, uint key_len,
|
|||
htrc("%p index_read: op=%d\n", this, op);
|
||||
|
||||
if (indexing > 0) {
|
||||
rc= ReadIndexed(buf, op, key, key_len);
|
||||
start_key.key= key;
|
||||
start_key.length= key_len;
|
||||
start_key.flag= find_flag;
|
||||
start_key.keypart_map= 0;
|
||||
|
||||
rc= ReadIndexed(buf, op, &start_key);
|
||||
|
||||
if (rc == HA_ERR_INTERNAL_ERROR) {
|
||||
nox= true; // To block making indexes
|
||||
|
|
@ -3736,7 +3807,7 @@ void ha_connect::position(const uchar *)
|
|||
//if (((PTDBASE)tdbp)->GetDef()->Indexable())
|
||||
my_store_ptr(ref, ref_length, (my_off_t)((PTDBASE)tdbp)->GetRecpos());
|
||||
|
||||
if (trace)
|
||||
if (trace > 1)
|
||||
htrc("position: pos=%d\n", ((PTDBASE)tdbp)->GetRecpos());
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
|
|
@ -6648,10 +6719,10 @@ maria_declare_plugin(connect)
|
|||
PLUGIN_LICENSE_GPL,
|
||||
connect_init_func, /* Plugin Init */
|
||||
connect_done_func, /* Plugin Deinit */
|
||||
0x0103, /* version number (1.03) */
|
||||
0x0104, /* version number (1.04) */
|
||||
NULL, /* status variables */
|
||||
connect_system_variables, /* system variables */
|
||||
"1.03.0007", /* string version */
|
||||
"1.04.0001", /* string version */
|
||||
MariaDB_PLUGIN_MATURITY_BETA /* maturity */
|
||||
}
|
||||
maria_declare_plugin_end;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue