mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01: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 896 additions and 321 deletions
6
storage/connect/.gitattributes
vendored
6
storage/connect/.gitattributes
vendored
|
@ -11,8 +11,10 @@
|
|||
|
||||
# Declare files that will always have LF line endings on checkout.
|
||||
*.result text eol=lf
|
||||
mysql-test/connect/std_data/*.txt text eol=lf
|
||||
mysql-test/connect/std_data/*.dat text eol=lf
|
||||
|
||||
# Denote files that should not be modified.
|
||||
mysql-test/connect/std_data/*.txt binary
|
||||
mysql-test/connect/std_data/*.dat binary
|
||||
|
||||
# Denote all files that are truly binary and should not be modified.
|
||||
*.png binary
|
||||
|
|
4
storage/connect/.gitignore
vendored
4
storage/connect/.gitignore
vendored
|
@ -82,6 +82,10 @@ RelWithDebInfo/
|
|||
*.vcproj.*
|
||||
*.vcproj.*.*
|
||||
*.vcproj.*.*.*
|
||||
*.vcxproj
|
||||
*.vcxproj.*
|
||||
*.vcxproj.*.*
|
||||
*.vcxproj.*.*.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
|
|
|
@ -735,17 +735,12 @@ static void SetSwapValue(PVAL valp, char *kp)
|
|||
/* IndexRead: fetch a record having the index value. */
|
||||
/***********************************************************************/
|
||||
RCODE CntIndexRead(PGLOBAL g, PTDB ptdb, OPVAL op,
|
||||
const void *key, int len, bool mrr)
|
||||
const key_range *kr, bool mrr)
|
||||
{
|
||||
char *kp= (char*)key;
|
||||
int n, x;
|
||||
short lg;
|
||||
bool rcb;
|
||||
RCODE rc;
|
||||
PVAL valp;
|
||||
PCOL colp;
|
||||
XXBASE *xbp;
|
||||
PTDBDOX tdbp;
|
||||
PTDBDOX tdbp;
|
||||
|
||||
if (!ptdb)
|
||||
return RC_FX;
|
||||
|
@ -757,13 +752,13 @@ RCODE CntIndexRead(PGLOBAL g, PTDB ptdb, OPVAL op,
|
|||
return RC_FX;
|
||||
} else if (x == 2) {
|
||||
// Remote index
|
||||
if (ptdb->ReadKey(g, op, key, len))
|
||||
if (ptdb->ReadKey(g, op, kr))
|
||||
return RC_FX;
|
||||
|
||||
goto rnd;
|
||||
} else if (x == 3) {
|
||||
if (key)
|
||||
((PTDBASE)ptdb)->SetRecpos(g, *(int*)key);
|
||||
if (kr)
|
||||
((PTDBASE)ptdb)->SetRecpos(g, *(int*)kr->key);
|
||||
|
||||
if (op == OP_SAME)
|
||||
return RC_NF;
|
||||
|
@ -790,7 +785,14 @@ RCODE CntIndexRead(PGLOBAL g, PTDB ptdb, OPVAL op,
|
|||
|
||||
xbp= (XXBASE*)tdbp->To_Kindex;
|
||||
|
||||
if (key) {
|
||||
if (kr) {
|
||||
char *kp= (char*)kr->key;
|
||||
int len= kr->length;
|
||||
short lg;
|
||||
bool rcb;
|
||||
PVAL valp;
|
||||
PCOL colp;
|
||||
|
||||
for (n= 0; n < tdbp->Knum; n++) {
|
||||
colp= (PCOL)tdbp->To_Key_Col[n];
|
||||
|
||||
|
@ -832,10 +834,10 @@ RCODE CntIndexRead(PGLOBAL g, PTDB ptdb, OPVAL op,
|
|||
|
||||
kp+= valp->GetClen();
|
||||
|
||||
if (len == kp - (char*)key) {
|
||||
if (len == kp - (char*)kr->key) {
|
||||
n++;
|
||||
break;
|
||||
} else if (len < kp - (char*)key) {
|
||||
} else if (len < kp - (char*)kr->key) {
|
||||
strcpy(g->Message, "Key buffer is too small");
|
||||
return RC_FX;
|
||||
} // endif len
|
||||
|
|
|
@ -36,7 +36,7 @@ bool CntRewindTable(PGLOBAL g, PTDB tdbp);
|
|||
int CntCloseTable(PGLOBAL g, PTDB tdbp, bool nox, bool abort);
|
||||
int CntIndexInit(PGLOBAL g, PTDB tdbp, int id, bool sorted);
|
||||
RCODE CntReadNext(PGLOBAL g, PTDB tdbp);
|
||||
RCODE CntIndexRead(PGLOBAL g, PTDB, OPVAL op, const void *k, int n, bool mrr);
|
||||
RCODE CntIndexRead(PGLOBAL g, PTDB, OPVAL op, const key_range *kr, bool mrr);
|
||||
RCODE CntWriteRow(PGLOBAL g, PTDB tdbp);
|
||||
RCODE CntUpdateRow(PGLOBAL g, PTDB tdbp);
|
||||
RCODE CntDeleteRow(PGLOBAL g, PTDB tdbp, bool all);
|
||||
|
@ -60,7 +60,7 @@ class TDBDOX: public TDBDOS {
|
|||
friend int MakeIndex(PGLOBAL, PTDB, PIXDEF);
|
||||
friend int CntCloseTable(PGLOBAL, PTDB, bool, bool);
|
||||
friend int CntIndexInit(PGLOBAL, PTDB, int, bool);
|
||||
friend RCODE CntIndexRead(PGLOBAL, PTDB, OPVAL, const void*, int, bool);
|
||||
friend RCODE CntIndexRead(PGLOBAL, PTDB, OPVAL, const key_range*, bool);
|
||||
friend RCODE CntDeleteRow(PGLOBAL, PTDB, bool);
|
||||
friend int CntIndexRange(PGLOBAL, PTDB, const uchar**, uint*,
|
||||
bool*, key_part_map*);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -241,11 +241,12 @@ public:
|
|||
int MakeRecord(char *buf);
|
||||
int ScanRecord(PGLOBAL g, uchar *buf);
|
||||
int CheckRecord(PGLOBAL g, const uchar *oldbuf, uchar *newbuf);
|
||||
int ReadIndexed(uchar *buf, OPVAL op, const uchar* key= NULL,
|
||||
uint key_len= 0);
|
||||
int ReadIndexed(uchar *buf, OPVAL op, const key_range *kr= NULL);
|
||||
bool IsIndexed(Field *fp);
|
||||
bool MakeKeyWhere(PGLOBAL g, PSTRG qry, OPVAL op, char q,
|
||||
const void *key, int klen);
|
||||
inline char *Strz(LEX_STRING &ls);
|
||||
const key_range *kr);
|
||||
inline char *Strz(LEX_STRING &ls);
|
||||
key_range start_key;
|
||||
|
||||
|
||||
/** @brief
|
||||
|
@ -374,7 +375,7 @@ public:
|
|||
condition stack.
|
||||
*/
|
||||
virtual const COND *cond_push(const COND *cond);
|
||||
PCFIL CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond);
|
||||
PCFIL CheckCond(PGLOBAL g, PCFIL filp, const Item *cond);
|
||||
const char *GetValStr(OPVAL vop, bool neg);
|
||||
PFIL CondFilter(PGLOBAL g, Item *cond);
|
||||
//PFIL CheckFilter(PGLOBAL g);
|
||||
|
|
|
@ -299,13 +299,13 @@ int GetIndexType(TABTYPE type)
|
|||
xtyp= 1;
|
||||
break;
|
||||
case TAB_MYSQL:
|
||||
// case TAB_ODBC:
|
||||
case TAB_ODBC:
|
||||
xtyp= 2;
|
||||
break;
|
||||
case TAB_VIR:
|
||||
xtyp= 3;
|
||||
break;
|
||||
case TAB_ODBC:
|
||||
// case TAB_ODBC:
|
||||
default:
|
||||
xtyp= 0;
|
||||
break;
|
||||
|
|
105
storage/connect/mysql-test/connect/r/endian.result
Normal file
105
storage/connect/mysql-test/connect/r/endian.result
Normal file
|
@ -0,0 +1,105 @@
|
|||
SET time_zone='+00:00';
|
||||
#
|
||||
# Testing little endian table
|
||||
#
|
||||
CREATE TABLE t1
|
||||
(
|
||||
fig INT(4) NOT NULL FIELD_FORMAT='C',
|
||||
name CHAR(10) NOT NULL,
|
||||
birth DATE NOT NULL FIELD_FORMAT='L',
|
||||
id CHAR(5) NOT NULL FIELD_FORMAT='L2',
|
||||
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='LF',
|
||||
dept INT(4) NOT NULL FIELD_FORMAT='L2'
|
||||
) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat';
|
||||
SELECT * FROM t1;
|
||||
fig name birth id salary dept
|
||||
5500 ARCHIBALD 1980-01-25 3789 4380.50 318
|
||||
123 OLIVER 1953-08-10 23456 3400.68 2158
|
||||
3123 FOO 2002-07-23 888 0.00 318
|
||||
INSERT INTO t1 VALUES (5555,'RONALD','1980-02-26','3333',4444.44,555);
|
||||
SELECT * FROM t1;
|
||||
fig name birth id salary dept
|
||||
5500 ARCHIBALD 1980-01-25 3789 4380.50 318
|
||||
123 OLIVER 1953-08-10 23456 3400.68 2158
|
||||
3123 FOO 2002-07-23 888 0.00 318
|
||||
5555 RONALD 1980-02-26 3333 4444.44 555
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1
|
||||
(
|
||||
fig INT(4) NOT NULL FIELD_FORMAT='C',
|
||||
name CHAR(10) NOT NULL,
|
||||
birth DATE NOT NULL,
|
||||
id CHAR(5) NOT NULL FIELD_FORMAT='S',
|
||||
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
|
||||
dept INT(4) NOT NULL FIELD_FORMAT='S'
|
||||
) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat' OPTION_LIST='Endian=Little';
|
||||
SELECT * FROM t1;
|
||||
fig name birth id salary dept
|
||||
5500 ARCHIBALD 1980-01-25 3789 4380.50 318
|
||||
123 OLIVER 1953-08-10 23456 3400.68 2158
|
||||
3123 FOO 2002-07-23 888 0.00 318
|
||||
5555 RONALD 1980-02-26 3333 4444.44 555
|
||||
#
|
||||
# Testing big endian table
|
||||
#
|
||||
CREATE TABLE t2 (
|
||||
fig INT(4) NOT NULL FIELD_FORMAT='C',
|
||||
name CHAR(10) NOT NULL,
|
||||
birth DATE NOT NULL FIELD_FORMAT='B',
|
||||
id CHAR(5) NOT NULL FIELD_FORMAT='BS',
|
||||
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='BF',
|
||||
dept INT(4) NOT NULL FIELD_FORMAT='B2'
|
||||
) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin';
|
||||
INSERT INTO t2 SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
fig name birth id salary dept
|
||||
5500 ARCHIBALD 1980-01-25 3789 4380.50 318
|
||||
123 OLIVER 1953-08-10 23456 3400.68 2158
|
||||
3123 FOO 2002-07-23 888 0.00 318
|
||||
5555 RONALD 1980-02-26 3333 4444.44 555
|
||||
DROP TABLE t2;
|
||||
CREATE TABLE t2 (
|
||||
fig INT(4) NOT NULL FIELD_FORMAT='C',
|
||||
name CHAR(10) NOT NULL,
|
||||
birth DATE NOT NULL,
|
||||
id CHAR(5) NOT NULL FIELD_FORMAT='S',
|
||||
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
|
||||
dept INT(4) NOT NULL FIELD_FORMAT='2'
|
||||
) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin' OPTION_LIST='Endian=Big';
|
||||
SELECT * FROM t2;
|
||||
fig name birth id salary dept
|
||||
5500 ARCHIBALD 1980-01-25 3789 4380.50 318
|
||||
123 OLIVER 1953-08-10 23456 3400.68 2158
|
||||
3123 FOO 2002-07-23 888 0.00 318
|
||||
5555 RONALD 1980-02-26 3333 4444.44 555
|
||||
DROP TABLE t2;
|
||||
CREATE TABLE t2 (
|
||||
fig CHAR(4) NOT NULL,
|
||||
name CHAR(10) NOT NULL,
|
||||
birth DATE NOT NULL,
|
||||
id SMALLINT(5) NOT NULL,
|
||||
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
|
||||
dept SMALLINT(4) NOT NULL
|
||||
) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin' OPTION_LIST='Endian=Big';
|
||||
SELECT * FROM t2;
|
||||
fig name birth id salary dept
|
||||
5500 ARCHIBALD 1980-01-25 3789 4380.50 318
|
||||
123 OLIVER 1953-08-10 23456 3400.68 2158
|
||||
3123 FOO 2002-07-23 888 0.00 318
|
||||
5555 RONALD 1980-02-26 3333 4444.44 555
|
||||
DROP TABLE t2;
|
||||
CREATE TABLE t2 (
|
||||
fig INT(4) NOT NULL FIELD_FORMAT='C',
|
||||
name CHAR(10) NOT NULL,
|
||||
birth DATE NOT NULL FIELD_FORMAT='B',
|
||||
id CHAR(5) NOT NULL FIELD_FORMAT='BS',
|
||||
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='BF',
|
||||
dept SMALLINT(4) NOT NULL FIELD_FORMAT='B'
|
||||
) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin';
|
||||
SELECT * FROM t2;
|
||||
fig name birth id salary dept
|
||||
5500 ARCHIBALD 1980-01-25 3789 4380.50 318
|
||||
123 OLIVER 1953-08-10 23456 3400.68 2158
|
||||
3123 FOO 2002-07-23 888 0.00 318
|
||||
5555 RONALD 1980-02-26 3333 4444.44 555
|
||||
DROP TABLE t1, t2;
|
114
storage/connect/mysql-test/connect/r/mysql_index.result
Normal file
114
storage/connect/mysql-test/connect/r/mysql_index.result
Normal file
|
@ -0,0 +1,114 @@
|
|||
#
|
||||
# Make remote table
|
||||
#
|
||||
CREATE TABLE t1 (
|
||||
id int(11) NOT NULL,
|
||||
msg char(100) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
|
||||
INSERT INTO t1 VALUES(1,'Un'),(3,'Trois'),(5,'Cinq');
|
||||
INSERT INTO t1 VALUES(2,'Two'),(4,'Four'),(6,'Six');
|
||||
SELECT * FROM t1;
|
||||
id msg
|
||||
1 Un
|
||||
3 Trois
|
||||
5 Cinq
|
||||
2 Two
|
||||
4 Four
|
||||
6 Six
|
||||
#
|
||||
# Make local MYSQL table with indexed id column
|
||||
#
|
||||
CREATE TABLE t2 (
|
||||
id int(11) NOT NULL,
|
||||
msg char(100) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=CONNECT DEFAULT CHARSET=latin1 TABLE_TYPE=MYSQL TABNAME=t1;
|
||||
#
|
||||
# Testing SELECT, etc.
|
||||
#
|
||||
SELECT * FROM t2;
|
||||
id msg
|
||||
1 Un
|
||||
3 Trois
|
||||
5 Cinq
|
||||
2 Two
|
||||
4 Four
|
||||
6 Six
|
||||
SELECT * FROM t2 WHERE id = 3;
|
||||
id msg
|
||||
3 Trois
|
||||
SELECT * FROM t2 WHERE id IN (2,4);
|
||||
id msg
|
||||
2 Two
|
||||
4 Four
|
||||
SELECT * FROM t2 WHERE id IN (2,4) AND msg = 'Two';
|
||||
id msg
|
||||
2 Two
|
||||
SELECT * FROM t2 WHERE id > 3;
|
||||
id msg
|
||||
5 Cinq
|
||||
4 Four
|
||||
6 Six
|
||||
SELECT * FROM t2 WHERE id >= 3;
|
||||
id msg
|
||||
3 Trois
|
||||
5 Cinq
|
||||
4 Four
|
||||
6 Six
|
||||
SELECT * FROM t2 WHERE id < 3;
|
||||
id msg
|
||||
1 Un
|
||||
2 Two
|
||||
SELECT * FROM t2 WHERE id < 3 OR id > 4;
|
||||
id msg
|
||||
1 Un
|
||||
2 Two
|
||||
5 Cinq
|
||||
6 Six
|
||||
SELECT * FROM t2 WHERE id <= 3;
|
||||
id msg
|
||||
1 Un
|
||||
2 Two
|
||||
3 Trois
|
||||
SELECT * FROM t2 WHERE id BETWEEN 3 AND 5;
|
||||
id msg
|
||||
3 Trois
|
||||
4 Four
|
||||
5 Cinq
|
||||
SELECT * FROM t2 WHERE id > 2 AND id < 6;
|
||||
id msg
|
||||
3 Trois
|
||||
4 Four
|
||||
5 Cinq
|
||||
SELECT * FROM t2 ORDER BY id;
|
||||
id msg
|
||||
1 Un
|
||||
2 Two
|
||||
3 Trois
|
||||
4 Four
|
||||
5 Cinq
|
||||
6 Six
|
||||
UPDATE t2 SET msg = 'Five' WHERE id = 5;
|
||||
Warnings:
|
||||
Note 1105 t1: 1 affected rows
|
||||
SELECT * FROM t2;
|
||||
id msg
|
||||
1 Un
|
||||
3 Trois
|
||||
5 Five
|
||||
2 Two
|
||||
4 Four
|
||||
6 Six
|
||||
DELETE FROM t2 WHERE id = 4;
|
||||
Warnings:
|
||||
Note 1105 t1: 1 affected rows
|
||||
SELECT * FROM t2;
|
||||
id msg
|
||||
1 Un
|
||||
3 Trois
|
||||
5 Five
|
||||
2 Two
|
||||
6 Six
|
||||
DROP TABLE t2;
|
||||
DROP TABLE t1;
|
88
storage/connect/mysql-test/connect/t/endian.test
Normal file
88
storage/connect/mysql-test/connect/t/endian.test
Normal file
|
@ -0,0 +1,88 @@
|
|||
let $MYSQLD_DATADIR= `select @@datadir`;
|
||||
|
||||
--copy_file $MTR_SUITE_DIR/std_data/Testbal.dat $MYSQLD_DATADIR/test/Testbal.dat
|
||||
|
||||
SET time_zone='+00:00';
|
||||
|
||||
--echo #
|
||||
--echo # Testing little endian table
|
||||
--echo #
|
||||
CREATE TABLE t1
|
||||
(
|
||||
fig INT(4) NOT NULL FIELD_FORMAT='C',
|
||||
name CHAR(10) NOT NULL,
|
||||
birth DATE NOT NULL FIELD_FORMAT='L',
|
||||
id CHAR(5) NOT NULL FIELD_FORMAT='L2',
|
||||
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='LF',
|
||||
dept INT(4) NOT NULL FIELD_FORMAT='L2'
|
||||
) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat';
|
||||
SELECT * FROM t1;
|
||||
INSERT INTO t1 VALUES (5555,'RONALD','1980-02-26','3333',4444.44,555);
|
||||
SELECT * FROM t1;
|
||||
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1
|
||||
(
|
||||
fig INT(4) NOT NULL FIELD_FORMAT='C',
|
||||
name CHAR(10) NOT NULL,
|
||||
birth DATE NOT NULL,
|
||||
id CHAR(5) NOT NULL FIELD_FORMAT='S',
|
||||
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
|
||||
dept INT(4) NOT NULL FIELD_FORMAT='S'
|
||||
) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat' OPTION_LIST='Endian=Little';
|
||||
SELECT * FROM t1;
|
||||
|
||||
--echo #
|
||||
--echo # Testing big endian table
|
||||
--echo #
|
||||
CREATE TABLE t2 (
|
||||
fig INT(4) NOT NULL FIELD_FORMAT='C',
|
||||
name CHAR(10) NOT NULL,
|
||||
birth DATE NOT NULL FIELD_FORMAT='B',
|
||||
id CHAR(5) NOT NULL FIELD_FORMAT='BS',
|
||||
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='BF',
|
||||
dept INT(4) NOT NULL FIELD_FORMAT='B2'
|
||||
) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin';
|
||||
INSERT INTO t2 SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
|
||||
DROP TABLE t2;
|
||||
CREATE TABLE t2 (
|
||||
fig INT(4) NOT NULL FIELD_FORMAT='C',
|
||||
name CHAR(10) NOT NULL,
|
||||
birth DATE NOT NULL,
|
||||
id CHAR(5) NOT NULL FIELD_FORMAT='S',
|
||||
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
|
||||
dept INT(4) NOT NULL FIELD_FORMAT='2'
|
||||
) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin' OPTION_LIST='Endian=Big';
|
||||
SELECT * FROM t2;
|
||||
|
||||
DROP TABLE t2;
|
||||
CREATE TABLE t2 (
|
||||
fig CHAR(4) NOT NULL,
|
||||
name CHAR(10) NOT NULL,
|
||||
birth DATE NOT NULL,
|
||||
id SMALLINT(5) NOT NULL,
|
||||
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
|
||||
dept SMALLINT(4) NOT NULL
|
||||
) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin' OPTION_LIST='Endian=Big';
|
||||
SELECT * FROM t2;
|
||||
|
||||
DROP TABLE t2;
|
||||
CREATE TABLE t2 (
|
||||
fig INT(4) NOT NULL FIELD_FORMAT='C',
|
||||
name CHAR(10) NOT NULL,
|
||||
birth DATE NOT NULL FIELD_FORMAT='B',
|
||||
id CHAR(5) NOT NULL FIELD_FORMAT='BS',
|
||||
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='BF',
|
||||
dept SMALLINT(4) NOT NULL FIELD_FORMAT='B'
|
||||
) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin';
|
||||
SELECT * FROM t2;
|
||||
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
#
|
||||
# Clean up
|
||||
#
|
||||
--remove_file $MYSQLD_DATADIR/test/Testbal.dat
|
||||
--remove_file $MYSQLD_DATADIR/test/Testbal.bin
|
66
storage/connect/mysql-test/connect/t/mysql_index.test
Normal file
66
storage/connect/mysql-test/connect/t/mysql_index.test
Normal file
|
@ -0,0 +1,66 @@
|
|||
-- source include/not_embedded.inc
|
||||
|
||||
#
|
||||
# TODO: consider a possibility to run this test
|
||||
# against some remote MySQL server
|
||||
#
|
||||
|
||||
let $PORT= `select @@port`;
|
||||
|
||||
--disable_query_log
|
||||
--replace_result $PORT PORT
|
||||
--error 0,ER_UNKNOWN_ERROR
|
||||
--eval CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='tx1' OPTION_LIST='host=localhost,user=root,port=$PORT'
|
||||
if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'
|
||||
AND ENGINE='CONNECT'
|
||||
AND CREATE_OPTIONS LIKE '%`table_type`=MySQL%'`)
|
||||
{
|
||||
Skip Need MySQL support;
|
||||
}
|
||||
DROP TABLE t1;
|
||||
--enable_query_log
|
||||
|
||||
--echo #
|
||||
--echo # Make remote table
|
||||
--echo #
|
||||
CREATE TABLE t1 (
|
||||
id int(11) NOT NULL,
|
||||
msg char(100) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
|
||||
INSERT INTO t1 VALUES(1,'Un'),(3,'Trois'),(5,'Cinq');
|
||||
INSERT INTO t1 VALUES(2,'Two'),(4,'Four'),(6,'Six');
|
||||
SELECT * FROM t1;
|
||||
|
||||
--echo #
|
||||
--echo # Make local MYSQL table with indexed id column
|
||||
--echo #
|
||||
CREATE TABLE t2 (
|
||||
id int(11) NOT NULL,
|
||||
msg char(100) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=CONNECT DEFAULT CHARSET=latin1 TABLE_TYPE=MYSQL TABNAME=t1;
|
||||
|
||||
--echo #
|
||||
--echo # Testing SELECT, etc.
|
||||
--echo #
|
||||
SELECT * FROM t2;
|
||||
SELECT * FROM t2 WHERE id = 3;
|
||||
SELECT * FROM t2 WHERE id IN (2,4);
|
||||
SELECT * FROM t2 WHERE id IN (2,4) AND msg = 'Two';
|
||||
SELECT * FROM t2 WHERE id > 3;
|
||||
SELECT * FROM t2 WHERE id >= 3;
|
||||
SELECT * FROM t2 WHERE id < 3;
|
||||
SELECT * FROM t2 WHERE id < 3 OR id > 4;
|
||||
SELECT * FROM t2 WHERE id <= 3;
|
||||
SELECT * FROM t2 WHERE id BETWEEN 3 AND 5;
|
||||
SELECT * FROM t2 WHERE id > 2 AND id < 6;
|
||||
SELECT * FROM t2 ORDER BY id;
|
||||
UPDATE t2 SET msg = 'Five' WHERE id = 5;
|
||||
SELECT * FROM t2;
|
||||
DELETE FROM t2 WHERE id = 4;
|
||||
SELECT * FROM t2;
|
||||
|
||||
DROP TABLE t2;
|
||||
DROP TABLE t1;
|
|
@ -1054,14 +1054,14 @@ int TDBMYSQL::SendCommand(PGLOBAL g)
|
|||
/***********************************************************************/
|
||||
/* Data Base indexed read routine for MYSQL access method. */
|
||||
/***********************************************************************/
|
||||
bool TDBMYSQL::ReadKey(PGLOBAL g, OPVAL op, const void *key, int len)
|
||||
bool TDBMYSQL::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
|
||||
{
|
||||
bool oom;
|
||||
int oldlen = Query->GetLength();
|
||||
PHC hc = To_Def->GetHandler();
|
||||
|
||||
if (!key || op == OP_NEXT ||
|
||||
Mode == MODE_UPDATE || Mode == MODE_DELETE) {
|
||||
if (!key && Mode == MODE_READX) {
|
||||
if (!(kr || hc->end_range) || op == OP_NEXT ||
|
||||
Mode == MODE_UPDATE || Mode == MODE_DELETE) {
|
||||
if (!kr && Mode == MODE_READX) {
|
||||
// This is a false indexed read
|
||||
m_Rc = Myc.ExecSQL(g, Query->GetStr());
|
||||
Mode = MODE_READ;
|
||||
|
@ -1069,37 +1069,39 @@ bool TDBMYSQL::ReadKey(PGLOBAL g, OPVAL op, const void *key, int len)
|
|||
} // endif key
|
||||
|
||||
return false;
|
||||
} else if (op == OP_FIRST) {
|
||||
if (To_CondFil) {
|
||||
oom = Query->Append(" WHERE ");
|
||||
|
||||
if ((oom |= Query->Append(To_CondFil->Body))) {
|
||||
strcpy(g->Message, "Readkey: Out of memory");
|
||||
return true;
|
||||
} // endif oom
|
||||
|
||||
} // endif To_Condfil
|
||||
|
||||
} else {
|
||||
if (Myc.m_Res)
|
||||
Myc.FreeResult();
|
||||
|
||||
To_Def->GetHandler()->MakeKeyWhere(g, Query, op, '`', key, len);
|
||||
if (hc->MakeKeyWhere(g, Query, op, '`', kr))
|
||||
return true;
|
||||
|
||||
if (To_CondFil) {
|
||||
oom = Query->Append(" AND (");
|
||||
oom |= Query->Append(To_CondFil->Body);
|
||||
if (To_CondFil->Idx != hc->active_index) {
|
||||
To_CondFil->Idx = hc->active_index;
|
||||
To_CondFil->Body= (char*)PlugSubAlloc(g, NULL, 0);
|
||||
*To_CondFil->Body= 0;
|
||||
|
||||
if ((oom |= Query->Append(')'))) {
|
||||
strcpy(g->Message, "Readkey: Out of memory");
|
||||
return true;
|
||||
} // endif oom
|
||||
if ((To_CondFil = hc->CheckCond(g, To_CondFil, To_CondFil->Cond)))
|
||||
PlugSubAlloc(g, NULL, strlen(To_CondFil->Body) + 1);
|
||||
|
||||
} // endif To_Condfil
|
||||
} // endif active_index
|
||||
|
||||
} // endif's op
|
||||
if (To_CondFil)
|
||||
if (Query->Append(" AND ") || Query->Append(To_CondFil->Body)) {
|
||||
strcpy(g->Message, "Readkey: Out of memory");
|
||||
return true;
|
||||
} // endif Append
|
||||
|
||||
m_Rc = Myc.ExecSQL(g, Query->GetStr());
|
||||
} // endif To_Condfil
|
||||
|
||||
Mode = MODE_READ;
|
||||
} // endif's op
|
||||
|
||||
if (trace)
|
||||
htrc("MYSQL ReadKey: Query=%s\n", Query->GetStr());
|
||||
|
||||
m_Rc = Myc.ExecSQL(g, Query->GetStr());
|
||||
Query->Truncate(oldlen);
|
||||
return (m_Rc == RC_FX) ? true : false;
|
||||
} // end of ReadKey
|
||||
|
|
|
@ -99,7 +99,7 @@ class TDBMYSQL : public TDBASE {
|
|||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
virtual void CloseDB(PGLOBAL g);
|
||||
virtual bool ReadKey(PGLOBAL g, OPVAL op, const void *key, int len);
|
||||
virtual bool ReadKey(PGLOBAL g, OPVAL op, const key_range *kr);
|
||||
|
||||
// Specific routines
|
||||
bool SetColumnRanks(PGLOBAL g);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/************* Tabodbc C++ Program Source Code File (.CPP) *************/
|
||||
/* PROGRAM NAME: TABODBC */
|
||||
/* ------------- */
|
||||
/* Version 2.9 */
|
||||
/* Version 3.0 */
|
||||
/* */
|
||||
/* COPYRIGHT: */
|
||||
/* ---------- */
|
||||
|
@ -35,6 +35,7 @@
|
|||
/* Include relevant MariaDB header file. */
|
||||
/***********************************************************************/
|
||||
#include "my_global.h"
|
||||
#include "sql_class.h"
|
||||
#if defined(__WIN__)
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -72,6 +73,7 @@
|
|||
#include "reldef.h"
|
||||
#include "tabcol.h"
|
||||
#include "valblk.h"
|
||||
#include "ha_connect.h"
|
||||
|
||||
#include "sql_string.h"
|
||||
|
||||
|
@ -386,176 +388,209 @@ int TDBODBC::Decode(char *txt, char *buf, size_t n)
|
|||
/* Note: when implementing EOM filtering, column only used in local */
|
||||
/* filter should be removed from column list. */
|
||||
/***********************************************************************/
|
||||
char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
|
||||
bool TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
|
||||
{
|
||||
char *colist, *tabname, *sql, buf[NAM_LEN * 3];
|
||||
LPCSTR schmp = NULL, catp = NULL;
|
||||
int len, ncol = 0;
|
||||
bool first = true;
|
||||
PTABLE tablep = To_Table;
|
||||
PCOL colp;
|
||||
char *schmp = NULL, *catp = NULL, buf[NAM_LEN * 3];
|
||||
int len;
|
||||
bool oom = false, first = true;
|
||||
PTABLE tablep = To_Table;
|
||||
PCOL colp;
|
||||
|
||||
if (Srcdef)
|
||||
return Srcdef;
|
||||
if (Srcdef) {
|
||||
Query = new(g)STRING(g, 0, Srcdef);
|
||||
return false;
|
||||
} // endif Srcdef
|
||||
|
||||
if (!cnt) {
|
||||
// Normal SQL statement to retrieve results
|
||||
for (colp = Columns; colp; colp = colp->GetNext())
|
||||
if (!colp->IsSpecial())
|
||||
ncol++;
|
||||
// Allocate the string used to contain the Query
|
||||
Query = new(g)STRING(g, 1023, "SELECT ");
|
||||
|
||||
if (ncol) {
|
||||
colist = (char*)PlugSubAlloc(g, NULL, (NAM_LEN + 4) * ncol);
|
||||
if (!cnt) {
|
||||
if (Columns) {
|
||||
// Normal SQL statement to retrieve results
|
||||
for (colp = Columns; colp; colp = colp->GetNext())
|
||||
if (!colp->IsSpecial()) {
|
||||
if (!first)
|
||||
oom |= Query->Append(", ");
|
||||
else
|
||||
first = false;
|
||||
|
||||
for (colp = Columns; colp; colp = colp->GetNext())
|
||||
if (!colp->IsSpecial()) {
|
||||
// Column name can be in UTF-8 encoding
|
||||
/*rc=*/ Decode(colp->GetName(), buf, sizeof(buf));
|
||||
// Column name can be encoded in UTF-8
|
||||
Decode(colp->GetName(), buf, sizeof(buf));
|
||||
|
||||
if (Quote) {
|
||||
if (first) {
|
||||
strcat(strcat(strcpy(colist, Quote), buf), Quote);
|
||||
first = false;
|
||||
} else
|
||||
strcat(strcat(strcat(strcat(colist, ", "),
|
||||
Quote), buf), Quote);
|
||||
if (Quote) {
|
||||
// Put column name between identifier quotes in case in contains blanks
|
||||
oom |= Query->Append(Quote);
|
||||
oom |= Query->Append(buf);
|
||||
oom |= Query->Append(Quote);
|
||||
} else
|
||||
oom |= Query->Append(buf);
|
||||
|
||||
} else {
|
||||
if (first) {
|
||||
strcpy(colist, buf);
|
||||
first = false;
|
||||
} else
|
||||
strcat(strcat(colist, ", "), buf);
|
||||
} // endif colp
|
||||
|
||||
} // endif Quote
|
||||
|
||||
} // endif !Special
|
||||
|
||||
} else {
|
||||
// ncol == 0 can occur for queries such that sql count(*) from...
|
||||
} else
|
||||
// !Columns can occur for queries such that sql count(*) from...
|
||||
// for which we will count the rows from sql * from...
|
||||
colist = (char*)PlugSubAlloc(g, NULL, 2);
|
||||
strcpy(colist, "*");
|
||||
} // endif ncol
|
||||
oom |= Query->Append('*');
|
||||
|
||||
} else {
|
||||
} else
|
||||
// SQL statement used to retrieve the size of the result
|
||||
colist = (char*)PlugSubAlloc(g, NULL, 9);
|
||||
strcpy(colist, "count(*)");
|
||||
} // endif cnt
|
||||
oom |= Query->Append("count(*)");
|
||||
|
||||
// Table name can be encoded in UTF-8
|
||||
/*rc = */Decode(TableName, buf, sizeof(buf));
|
||||
|
||||
// Put table name between identifier quotes in case in contains blanks
|
||||
tabname = (char*)PlugSubAlloc(g, NULL, strlen(buf) + 3);
|
||||
|
||||
if (Quote)
|
||||
strcat(strcat(strcpy(tabname, Quote), buf), Quote);
|
||||
else
|
||||
strcpy(tabname, buf);
|
||||
|
||||
// Below 14 is length of 'select ' + length of ' from ' + 1
|
||||
len = (strlen(colist) + strlen(buf) + 14);
|
||||
len += (To_CondFil ? strlen(To_CondFil->Body) + 7 : 0);
|
||||
oom |= Query->Append(" FROM ");
|
||||
|
||||
if (Catalog && *Catalog)
|
||||
catp = Catalog;
|
||||
|
||||
if (catp)
|
||||
len += (strlen(catp) + 2);
|
||||
|
||||
if (tablep->GetSchema())
|
||||
schmp = tablep->GetSchema();
|
||||
schmp = (char*)tablep->GetSchema();
|
||||
else if (Schema && *Schema)
|
||||
schmp = Schema;
|
||||
|
||||
if (schmp)
|
||||
len += (strlen(schmp) + 1);
|
||||
|
||||
sql = (char*)PlugSubAlloc(g, NULL, len);
|
||||
strcat(strcat(strcpy(sql, "SELECT "), colist), " FROM ");
|
||||
|
||||
if (catp) {
|
||||
strcat(sql, catp);
|
||||
oom |= Query->Append(catp);
|
||||
|
||||
if (schmp)
|
||||
strcat(strcat(sql, "."), schmp);
|
||||
else
|
||||
strcat(sql, ".");
|
||||
if (schmp) {
|
||||
oom |= Query->Append('.');
|
||||
oom |= Query->Append(schmp);
|
||||
} // endif schmp
|
||||
|
||||
strcat(sql, ".");
|
||||
} else if (schmp)
|
||||
strcat(strcat(sql, schmp), ".");
|
||||
oom |= Query->Append('.');
|
||||
} else if (schmp) {
|
||||
oom |= Query->Append(schmp);
|
||||
oom |= Query->Append('.');
|
||||
} // endif schmp
|
||||
|
||||
strcat(sql, tabname);
|
||||
// Table name can be encoded in UTF-8
|
||||
Decode(TableName, buf, sizeof(buf));
|
||||
|
||||
if (To_CondFil)
|
||||
strcat(strcat(sql, " WHERE "), To_CondFil->Body);
|
||||
|
||||
if (trace)
|
||||
htrc("sql: '%s'\n", sql);
|
||||
if (Quote) {
|
||||
// Put table name between identifier quotes in case in contains blanks
|
||||
oom |= Query->Append(Quote);
|
||||
oom |= Query->Append(buf);
|
||||
oom |= Query->Append(Quote);
|
||||
} else
|
||||
oom |= Query->Append(buf);
|
||||
|
||||
return sql;
|
||||
len = Query->GetLength();
|
||||
|
||||
if (To_CondFil) {
|
||||
if (Mode == MODE_READ) {
|
||||
oom |= Query->Append(" WHERE ");
|
||||
oom |= Query->Append(To_CondFil->Body);
|
||||
len = Query->GetLength() + 1;
|
||||
} else
|
||||
len += (strlen(To_CondFil->Body) + 256);
|
||||
|
||||
} else
|
||||
len += ((Mode == MODE_READX) ? 256 : 1);
|
||||
|
||||
if (oom || Query->Resize(len)) {
|
||||
strcpy(g->Message, "MakeSQL: Out of memory");
|
||||
return true;
|
||||
} // endif oom
|
||||
|
||||
if (trace)
|
||||
htrc("Query=%s\n", Query->GetStr());
|
||||
|
||||
return false;
|
||||
} // end of MakeSQL
|
||||
|
||||
/***********************************************************************/
|
||||
/* MakeInsert: make the Insert statement used with ODBC connection. */
|
||||
/***********************************************************************/
|
||||
char *TDBODBC::MakeInsert(PGLOBAL g)
|
||||
bool TDBODBC::MakeInsert(PGLOBAL g)
|
||||
{
|
||||
char *stmt, *colist, *valist, buf[NAM_LEN * 3];
|
||||
// char *tk = "`";
|
||||
int len = 0;
|
||||
bool b = FALSE;
|
||||
PCOL colp;
|
||||
char *schmp = NULL, *catp = NULL, buf[NAM_LEN * 3];
|
||||
int len = 0;
|
||||
bool b = false, oom;
|
||||
PTABLE tablep = To_Table;
|
||||
PCOL colp;
|
||||
|
||||
for (colp = Columns; colp; colp = colp->GetNext())
|
||||
if (colp->IsSpecial()) {
|
||||
strcpy(g->Message, MSG(NO_ODBC_SPECOL));
|
||||
return NULL;
|
||||
return true;
|
||||
} else {
|
||||
len += (strlen(colp->GetName()) + 4);
|
||||
// Column name can be encoded in UTF-8
|
||||
Decode(colp->GetName(), buf, sizeof(buf));
|
||||
len += (strlen(buf) + 6); // comma + quotes + valist
|
||||
((PODBCCOL)colp)->Rank = ++Nparm;
|
||||
} // endif colp
|
||||
|
||||
colist = (char*)PlugSubAlloc(g, NULL, len);
|
||||
*colist = '\0';
|
||||
valist = (char*)PlugSubAlloc(g, NULL, 2 * Nparm);
|
||||
*valist = '\0';
|
||||
// Below 32 is enough to contain the fixed part of the query
|
||||
if (Catalog && *Catalog)
|
||||
catp = Catalog;
|
||||
|
||||
for (colp = Columns; colp; colp = colp->GetNext()) {
|
||||
if (b) {
|
||||
strcat(colist, ", ");
|
||||
strcat(valist, ",");
|
||||
} else
|
||||
b = true;
|
||||
if (catp)
|
||||
len += strlen(catp) + 1;
|
||||
|
||||
// Column name can be in UTF-8 encoding
|
||||
Decode(colp->GetName(), buf, sizeof(buf));
|
||||
if (tablep->GetSchema())
|
||||
schmp = (char*)tablep->GetSchema();
|
||||
else if (Schema && *Schema)
|
||||
schmp = Schema;
|
||||
|
||||
if (Quote)
|
||||
strcat(strcat(strcat(colist, Quote), buf), Quote);
|
||||
else
|
||||
strcat(colist, buf);
|
||||
if (schmp)
|
||||
len += strlen(schmp) + 1;
|
||||
|
||||
strcat(valist, "?"); // Parameter marker
|
||||
} // endfor colp
|
||||
// Column name can be encoded in UTF-8
|
||||
Decode(TableName, buf, sizeof(buf));
|
||||
len += (strlen(buf) + 32);
|
||||
Query = new(g) STRING(g, len, "INSERT INTO ");
|
||||
|
||||
// Below 32 is enough to contain the fixed part of the query
|
||||
len = (strlen(TableName) + strlen(colist) + strlen(valist) + 32);
|
||||
stmt = (char*)PlugSubAlloc(g, NULL, len);
|
||||
strcpy(stmt, "INSERT INTO ");
|
||||
if (catp) {
|
||||
oom |= Query->Append(catp);
|
||||
|
||||
if (Quote)
|
||||
strcat(strcat(strcat(stmt, Quote), TableName), Quote);
|
||||
else
|
||||
strcat(stmt, TableName);
|
||||
if (schmp) {
|
||||
oom |= Query->Append('.');
|
||||
oom |= Query->Append(schmp);
|
||||
} // endif schmp
|
||||
|
||||
strcat(strcat(strcat(stmt, " ("), colist), ") VALUES (");
|
||||
strcat(strcat(stmt, valist), ")");
|
||||
oom |= Query->Append('.');
|
||||
} else if (schmp) {
|
||||
oom |= Query->Append(schmp);
|
||||
oom |= Query->Append('.');
|
||||
} // endif schmp
|
||||
|
||||
return stmt;
|
||||
if (Quote) {
|
||||
// Put table name between identifier quotes in case in contains blanks
|
||||
oom |= Query->Append(Quote);
|
||||
oom |= Query->Append(buf);
|
||||
oom |= Query->Append(Quote);
|
||||
} else
|
||||
oom |= Query->Append(buf);
|
||||
|
||||
oom |= Query->Append('(');
|
||||
|
||||
for (colp = Columns; colp; colp = colp->GetNext()) {
|
||||
if (b)
|
||||
oom |= Query->Append(", ");
|
||||
else
|
||||
b = true;
|
||||
|
||||
// Column name can be in UTF-8 encoding
|
||||
Decode(colp->GetName(), buf, sizeof(buf));
|
||||
|
||||
if (Quote) {
|
||||
// Put column name between identifier quotes in case in contains blanks
|
||||
oom |= Query->Append(Quote);
|
||||
oom |= Query->Append(buf);
|
||||
oom |= Query->Append(Quote);
|
||||
} else
|
||||
oom |= Query->Append(buf);
|
||||
|
||||
} // endfor colp
|
||||
|
||||
oom |= Query->Append(") VALUES (");
|
||||
|
||||
for (int i = 0; i < Nparm; i++)
|
||||
oom |= Query->Append("?,");
|
||||
|
||||
if (oom)
|
||||
strcpy(g->Message, "MakeInsert: Out of memory");
|
||||
else
|
||||
Query->RepLast(')');
|
||||
|
||||
return oom;
|
||||
} // end of MakeInsert
|
||||
|
||||
/***********************************************************************/
|
||||
|
@ -580,7 +615,7 @@ bool TDBODBC::BindParameters(PGLOBAL g)
|
|||
/* MakeCommand: make the Update or Delete statement to send to the */
|
||||
/* MySQL server. Limited to remote values and filtering. */
|
||||
/***********************************************************************/
|
||||
char *TDBODBC::MakeCommand(PGLOBAL g)
|
||||
bool TDBODBC::MakeCommand(PGLOBAL g)
|
||||
{
|
||||
char *p, *stmt, name[68], *body = NULL, *qc = Ocp->GetQuoteChar();
|
||||
char *qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 1);
|
||||
|
@ -638,7 +673,8 @@ char *TDBODBC::MakeCommand(PGLOBAL g)
|
|||
return NULL;
|
||||
} // endif p
|
||||
|
||||
return stmt;
|
||||
Query = new(g) STRING(g, 0, stmt);
|
||||
return (!Query->GetSize());
|
||||
} // end of MakeCommand
|
||||
|
||||
#if 0
|
||||
|
@ -815,10 +851,12 @@ bool TDBODBC::OpenDB(PGLOBAL g)
|
|||
|
||||
if (Memory < 3) {
|
||||
// Method will depend on cursor type
|
||||
if ((Rbuf = Ocp->Rewind(Query, (PODBCCOL)Columns)) < 0) {
|
||||
Ocp->Close();
|
||||
return true;
|
||||
} // endif Rewind
|
||||
if ((Rbuf = Ocp->Rewind(Query->GetStr(), (PODBCCOL)Columns)) < 0)
|
||||
if (Mode != MODE_READX) {
|
||||
Ocp->Close();
|
||||
return true;
|
||||
} else
|
||||
Rbuf = 0;
|
||||
|
||||
} else
|
||||
Rbuf = Qrp->Nblin;
|
||||
|
@ -853,15 +891,14 @@ bool TDBODBC::OpenDB(PGLOBAL g)
|
|||
/*********************************************************************/
|
||||
if (Mode == MODE_READ || Mode == MODE_READX) {
|
||||
if (Memory > 1 && !Srcdef) {
|
||||
char *Sql;
|
||||
int n;
|
||||
int n;
|
||||
|
||||
if ((Sql = MakeSQL(g, true))) {
|
||||
if (!MakeSQL(g, true)) {
|
||||
// Allocate a Count(*) column
|
||||
Cnp = new(g) ODBCCOL;
|
||||
Cnp->InitValue(g);
|
||||
|
||||
if ((n = Ocp->GetResultSize(Sql, Cnp)) < 0) {
|
||||
if ((n = Ocp->GetResultSize(Query->GetStr(), Cnp)) < 0) {
|
||||
strcpy(g->Message, "Cannot get result size");
|
||||
return true;
|
||||
} // endif n
|
||||
|
@ -871,36 +908,36 @@ bool TDBODBC::OpenDB(PGLOBAL g)
|
|||
if ((Qrp = Ocp->AllocateResult(g)))
|
||||
Memory = 2; // Must be filled
|
||||
else {
|
||||
strcpy(g->Message, "Memory allocation failed");
|
||||
strcpy(g->Message, "Result set memory allocation failed");
|
||||
return true;
|
||||
} // endif n
|
||||
|
||||
Ocp->m_Rows = 0;
|
||||
} else {
|
||||
strcpy(g->Message, "MakeSQL failed");
|
||||
} else
|
||||
return true;
|
||||
} // endif Sql
|
||||
|
||||
} // endif Memory
|
||||
|
||||
if ((Query = MakeSQL(g, false))) {
|
||||
if (!(rc = MakeSQL(g, false))) {
|
||||
for (PODBCCOL colp = (PODBCCOL)Columns; colp;
|
||||
colp = (PODBCCOL)colp->GetNext())
|
||||
if (!colp->IsSpecial())
|
||||
colp->AllocateBuffers(g, Rows);
|
||||
|
||||
rc = ((Rows = Ocp->ExecDirectSQL(Query, (PODBCCOL)Columns)) < 0);
|
||||
} // endif Query
|
||||
rc = (Mode == MODE_READ)
|
||||
? ((Rows = Ocp->ExecDirectSQL(Query->GetStr(), (PODBCCOL)Columns)) < 0)
|
||||
: false;
|
||||
} // endif rc
|
||||
|
||||
} else if (Mode == MODE_INSERT) {
|
||||
if ((Query = MakeInsert(g))) {
|
||||
if (Nparm != Ocp->PrepareSQL(Query)) {
|
||||
if (!(rc = MakeInsert(g))) {
|
||||
if (Nparm != Ocp->PrepareSQL(Query->GetStr())) {
|
||||
strcpy(g->Message, MSG(PARM_CNT_MISS));
|
||||
rc = true;
|
||||
} else
|
||||
rc = BindParameters(g);
|
||||
|
||||
} // endif Query
|
||||
} // endif rc
|
||||
|
||||
} else if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
|
||||
rc = false; // wait for CheckCond before calling MakeCommand(g);
|
||||
|
@ -958,6 +995,59 @@ bool TDBODBC::SetRecpos(PGLOBAL g, int recpos)
|
|||
return false;
|
||||
} // end of SetRecpos
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base indexed read routine for MYSQL access method. */
|
||||
/***********************************************************************/
|
||||
bool TDBODBC::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
|
||||
{
|
||||
char c = Quote ? *Quote : 0;
|
||||
int oldlen = Query->GetLength();
|
||||
PHC hc = To_Def->GetHandler();
|
||||
|
||||
if (!(kr || hc->end_range) || op == OP_NEXT ||
|
||||
Mode == MODE_UPDATE || Mode == MODE_DELETE) {
|
||||
if (!kr && Mode == MODE_READX) {
|
||||
// This is a false indexed read
|
||||
Rows = Ocp->ExecDirectSQL((char*)Query->GetStr(), (PODBCCOL)Columns);
|
||||
Mode = MODE_READ;
|
||||
return (Rows < 0);
|
||||
} // endif key
|
||||
|
||||
return false;
|
||||
} else {
|
||||
if (To_Def->GetHandler()->MakeKeyWhere(g, Query, op, c, kr))
|
||||
return true;
|
||||
|
||||
if (To_CondFil) {
|
||||
if (To_CondFil->Idx != hc->active_index) {
|
||||
To_CondFil->Idx = hc->active_index;
|
||||
To_CondFil->Body= (char*)PlugSubAlloc(g, NULL, 0);
|
||||
*To_CondFil->Body= 0;
|
||||
|
||||
if ((To_CondFil = hc->CheckCond(g, To_CondFil, To_CondFil->Cond)))
|
||||
PlugSubAlloc(g, NULL, strlen(To_CondFil->Body) + 1);
|
||||
|
||||
} // endif active_index
|
||||
|
||||
if (To_CondFil)
|
||||
if (Query->Append(" AND ") || Query->Append(To_CondFil->Body)) {
|
||||
strcpy(g->Message, "Readkey: Out of memory");
|
||||
return true;
|
||||
} // endif Append
|
||||
|
||||
} // endif To_Condfil
|
||||
|
||||
Mode = MODE_READ;
|
||||
} // endif's op
|
||||
|
||||
if (trace)
|
||||
htrc("ODBC ReadKey: Query=%s\n", Query->GetStr());
|
||||
|
||||
Rows = Ocp->ExecDirectSQL((char*)Query->GetStr(), (PODBCCOL)Columns);
|
||||
Query->Truncate(oldlen);
|
||||
return (Rows < 0);
|
||||
} // end of ReadKey
|
||||
|
||||
/***********************************************************************/
|
||||
/* VRDNDOS: Data Base read routine for odbc access method. */
|
||||
/***********************************************************************/
|
||||
|
@ -970,11 +1060,11 @@ int TDBODBC::ReadDB(PGLOBAL g)
|
|||
GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex);
|
||||
|
||||
if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
|
||||
if (!Query && !(Query = MakeCommand(g)))
|
||||
if (!Query && MakeCommand(g))
|
||||
return RC_FX;
|
||||
|
||||
// Send the UPDATE/DELETE command to the remote table
|
||||
if (!Ocp->ExecSQLcommand(Query)) {
|
||||
if (!Ocp->ExecSQLcommand(Query->GetStr())) {
|
||||
sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
|
||||
|
||||
if (trace)
|
||||
|
@ -1052,11 +1142,11 @@ int TDBODBC::WriteDB(PGLOBAL g)
|
|||
int TDBODBC::DeleteDB(PGLOBAL g, int irc)
|
||||
{
|
||||
if (irc == RC_FX) {
|
||||
if (!Query && !(Query = MakeCommand(g)))
|
||||
if (!Query && MakeCommand(g))
|
||||
return RC_FX;
|
||||
|
||||
// Send the DELETE (all) command to the remote table
|
||||
if (!Ocp->ExecSQLcommand(Query)) {
|
||||
if (!Ocp->ExecSQLcommand(Query->GetStr())) {
|
||||
sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
|
||||
|
||||
if (trace)
|
||||
|
@ -1272,7 +1362,7 @@ void ODBCCOL::ReadColumn(PGLOBAL g)
|
|||
if (Value->IsZero())
|
||||
Value->SetNull(Nullable);
|
||||
|
||||
if (trace) {
|
||||
if (trace > 1) {
|
||||
char buf[64];
|
||||
|
||||
htrc("ODBC Column %s: rows=%d buf=%p type=%d value=%s\n",
|
||||
|
@ -1560,9 +1650,12 @@ bool TDBXDBC::OpenDB(PGLOBAL g)
|
|||
int TDBXDBC::ReadDB(PGLOBAL g)
|
||||
{
|
||||
if (Cmdlist) {
|
||||
Query = Cmdlist->Cmd;
|
||||
if (!Query)
|
||||
Query = new(g)STRING(g, 0, Cmdlist->Cmd);
|
||||
else
|
||||
Query->Set(Cmdlist->Cmd);
|
||||
|
||||
if (Ocp->ExecSQLcommand(Query))
|
||||
if (Ocp->ExecSQLcommand(Query->GetStr()))
|
||||
Nerr++;
|
||||
|
||||
Fpos++; // Used for progress info
|
||||
|
@ -1620,10 +1713,10 @@ void XSRCCOL::ReadColumn(PGLOBAL g)
|
|||
PTDBXDBC tdbp = (PTDBXDBC)To_Tdb;
|
||||
|
||||
switch (Flag) {
|
||||
case 0: Value->SetValue_psz(tdbp->Query); break;
|
||||
case 1: Value->SetValue(tdbp->AftRows); break;
|
||||
case 2: Value->SetValue_psz(g->Message); break;
|
||||
default: Value->SetValue_psz("Invalid Flag"); break;
|
||||
case 0: Value->SetValue_psz(tdbp->Query->GetStr()); break;
|
||||
case 1: Value->SetValue(tdbp->AftRows); break;
|
||||
case 2: Value->SetValue_psz(g->Message); break;
|
||||
default: Value->SetValue_psz("Invalid Flag"); break;
|
||||
} // endswitch Flag
|
||||
|
||||
} // end of ReadColumn
|
||||
|
|
|
@ -42,7 +42,8 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
|
|||
int GetOptions(void) {return Options;}
|
||||
|
||||
// Methods
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
virtual int Indexable(void) {return 2;}
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
virtual PTDB GetTable(PGLOBAL g, MODE m);
|
||||
|
||||
protected:
|
||||
|
@ -111,15 +112,14 @@ class TDBODBC : public TDBASE {
|
|||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
virtual void CloseDB(PGLOBAL g);
|
||||
virtual bool ReadKey(PGLOBAL g, OPVAL op, const void *key, int len)
|
||||
{return true;}
|
||||
virtual bool ReadKey(PGLOBAL g, OPVAL op, const key_range *kr);
|
||||
|
||||
protected:
|
||||
// Internal functions
|
||||
int Decode(char *utf, char *buf, size_t n);
|
||||
char *MakeSQL(PGLOBAL g, bool cnt);
|
||||
char *MakeInsert(PGLOBAL g);
|
||||
char *MakeCommand(PGLOBAL g);
|
||||
bool MakeSQL(PGLOBAL g, bool cnt);
|
||||
bool MakeInsert(PGLOBAL g);
|
||||
bool MakeCommand(PGLOBAL g);
|
||||
//bool MakeFilter(PGLOBAL g, bool c);
|
||||
bool BindParameters(PGLOBAL g);
|
||||
//char *MakeUpdate(PGLOBAL g);
|
||||
|
@ -129,14 +129,14 @@ class TDBODBC : public TDBASE {
|
|||
ODBConn *Ocp; // Points to an ODBC connection class
|
||||
ODBCCOL *Cnp; // Points to count(*) column
|
||||
ODBCPARM Ops; // Additional parameters
|
||||
char *Connect; // Points to connection string
|
||||
PSTRG Query; // Constructed SQL query
|
||||
char *Connect; // Points to connection string
|
||||
char *TableName; // Points to ODBC table name
|
||||
char *Schema; // Points to ODBC table Schema
|
||||
char *User; // User connect info
|
||||
char *Pwd; // Password connect info
|
||||
char *Catalog; // Points to ODBC table Catalog
|
||||
char *Srcdef; // The source table SQL definition
|
||||
char *Query; // Points to SQL statement
|
||||
char *Count; // Points to count(*) SQL statement
|
||||
//char *Where; // Points to local where clause
|
||||
char *Quote; // The identifier quoting character
|
||||
|
|
|
@ -290,14 +290,14 @@ bool STRING::Set(char *s, uint n)
|
|||
} // end of Set
|
||||
|
||||
/***********************************************************************/
|
||||
/* Append a char* to a STRING. */
|
||||
/* Append a char* to a STRING. */
|
||||
/***********************************************************************/
|
||||
bool STRING::Append(const char *s, uint ln)
|
||||
bool STRING::Append(const char *s, uint ln, bool nq)
|
||||
{
|
||||
if (!s)
|
||||
return false;
|
||||
|
||||
uint len = Length + ln + 1;
|
||||
uint i, len = Length + ln + 1;
|
||||
|
||||
if (len > Size) {
|
||||
char *p = Realloc(len);
|
||||
|
@ -311,8 +311,22 @@ bool STRING::Append(const char *s, uint ln)
|
|||
|
||||
} // endif n
|
||||
|
||||
strncpy(Strp + Length, s, ln);
|
||||
Length = len - 1;
|
||||
if (nq) {
|
||||
for (i = 0; i < ln; i++)
|
||||
switch (s[i]) {
|
||||
case '\\': Strp[Length++] = '\\'; Strp[Length++] = '\\'; break;
|
||||
case '\0': Strp[Length++] = '\\'; Strp[Length++] = '0'; break;
|
||||
case '\'': Strp[Length++] = '\\'; Strp[Length++] = '\''; break;
|
||||
case '\n': Strp[Length++] = '\\'; Strp[Length++] = 'n'; break;
|
||||
case '\r': Strp[Length++] = '\\'; Strp[Length++] = 'r'; break;
|
||||
case '\032': Strp[Length++] = '\\'; Strp[Length++] = 'Z'; break;
|
||||
default: Strp[Length++] = s[i];
|
||||
} // endswitch s[i]
|
||||
|
||||
} else
|
||||
for (i = 0; i < ln && s[i]; i++)
|
||||
Strp[Length++] = s[i];
|
||||
|
||||
Strp[Length] = 0;
|
||||
return false;
|
||||
} // end of Append
|
||||
|
|
|
@ -134,7 +134,7 @@ class DllExport STRING : public BLOCK {
|
|||
inline void Reset(void) {*Strp = 0;}
|
||||
bool Set(PSZ s);
|
||||
bool Set(char *s, uint n);
|
||||
bool Append(const char *s, uint ln);
|
||||
bool Append(const char *s, uint ln, bool nq = false);
|
||||
bool Append(PSZ s);
|
||||
bool Append(STRING &str);
|
||||
bool Append(char c);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "m_ctype.h"
|
||||
|
||||
typedef class CMD *PCMD;
|
||||
typedef struct st_key_range key_range;
|
||||
|
||||
// Commands executed by XDBC and MYX tables
|
||||
class CMD : public BLOCK {
|
||||
|
@ -32,12 +33,24 @@ class CMD : public BLOCK {
|
|||
}; // end of class CMD
|
||||
|
||||
// Condition filter structure
|
||||
typedef struct _cond_filter {
|
||||
char *Body;
|
||||
OPVAL Op;
|
||||
PCMD Cmds;
|
||||
} CONDFIL, *PCFIL;
|
||||
class CONDFIL : public BLOCK {
|
||||
public:
|
||||
// Constructor
|
||||
CONDFIL(const Item *cond, uint idx, AMT type)
|
||||
{
|
||||
Cond = cond; Idx = idx; Type = type; Body = NULL; Op = OP_XX; Cmds = NULL;
|
||||
}
|
||||
|
||||
// Members
|
||||
const Item *Cond;
|
||||
AMT Type;
|
||||
uint Idx;
|
||||
char *Body;
|
||||
OPVAL Op;
|
||||
PCMD Cmds;
|
||||
}; // end of class CONDFIL
|
||||
|
||||
typedef class CONDFIL *PCFIL;
|
||||
typedef class TDBCAT *PTDBCAT;
|
||||
typedef class CATCOL *PCATCOL;
|
||||
|
||||
|
@ -109,7 +122,7 @@ class DllExport TDB: public BLOCK { // Table Descriptor Block.
|
|||
virtual int DeleteDB(PGLOBAL, int) = 0;
|
||||
virtual void CloseDB(PGLOBAL) = 0;
|
||||
virtual int CheckWrite(PGLOBAL) {return 0;}
|
||||
virtual bool ReadKey(PGLOBAL, OPVAL, const void *, int) = 0;
|
||||
virtual bool ReadKey(PGLOBAL, OPVAL, const key_range *) = 0;
|
||||
|
||||
protected:
|
||||
// Members
|
||||
|
@ -188,7 +201,7 @@ class DllExport TDBASE : public TDB {
|
|||
virtual void MarkDB(PGLOBAL g, PTDB tdb2);
|
||||
virtual int MakeIndex(PGLOBAL g, PIXDEF, bool)
|
||||
{strcpy(g->Message, "Remote index"); return RC_INFO;}
|
||||
virtual bool ReadKey(PGLOBAL, OPVAL, const void *, int)
|
||||
virtual bool ReadKey(PGLOBAL, OPVAL, const key_range *)
|
||||
{assert(false); return true;}
|
||||
|
||||
protected:
|
||||
|
|
Loading…
Reference in a new issue