summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mnogosearch.org>2013-12-03 14:12:53 +0400
committerAlexander Barkov <bar@mnogosearch.org>2013-12-03 14:12:53 +0400
commitd240a0418cf6d59fba711f0677f164d9ee881b7e (patch)
treefc2dedfcd5437f1c59c1b5bc59ead689f5736246 /storage
parent5bb01fa1ace1dcfe87c9c1eae3cd30a55c9de032 (diff)
parent0d37409fe7fd6cc4b576c62ed5c0a6804e049e8f (diff)
downloadmariadb-git-d240a0418cf6d59fba711f0677f164d9ee881b7e.tar.gz
Merge 10.0-connect -> 10.0
Diffstat (limited to 'storage')
-rw-r--r--storage/connect/CMakeLists.txt13
-rw-r--r--storage/connect/colblk.cpp6
-rw-r--r--storage/connect/connect.cc18
-rw-r--r--storage/connect/filamtxt.h2
-rwxr-xr-xstorage/connect/filamvct.cpp2
-rw-r--r--storage/connect/filamzip.h3
-rw-r--r--storage/connect/ha_connect.cc255
-rw-r--r--storage/connect/ha_connect.h2
-rw-r--r--storage/connect/libdoc.cpp43
-rw-r--r--storage/connect/myconn.cpp56
-rw-r--r--storage/connect/myconn.h5
-rw-r--r--storage/connect/mysql-test/connect/my.cnf15
-rw-r--r--storage/connect/mysql-test/connect/r/bin.result4
-rw-r--r--storage/connect/mysql-test/connect/r/csv.result10
-rw-r--r--storage/connect/mysql-test/connect/r/dbf.result8
-rw-r--r--storage/connect/mysql-test/connect/r/fix.result8
-rw-r--r--storage/connect/mysql-test/connect/r/ini.result8
-rw-r--r--storage/connect/mysql-test/connect/r/mysql.result4
-rw-r--r--storage/connect/mysql-test/connect/r/mysql_discovery.result42
-rw-r--r--storage/connect/mysql-test/connect/r/mysql_exec.result62
-rw-r--r--storage/connect/mysql-test/connect/r/mysql_new.result218
-rw-r--r--storage/connect/mysql-test/connect/r/odbc_sqlite3.result12
-rw-r--r--storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result2
-rw-r--r--storage/connect/mysql-test/connect/r/odbc_xls.result11
-rw-r--r--storage/connect/mysql-test/connect/r/vec.result8
-rw-r--r--storage/connect/mysql-test/connect/r/xml.result2
-rw-r--r--storage/connect/mysql-test/connect/t/bin.test154
-rw-r--r--storage/connect/mysql-test/connect/t/csv.test370
-rw-r--r--storage/connect/mysql-test/connect/t/dbf.test1018
-rw-r--r--storage/connect/mysql-test/connect/t/fix.test216
-rw-r--r--storage/connect/mysql-test/connect/t/ini.test312
-rw-r--r--storage/connect/mysql-test/connect/t/myconn.inc27
-rw-r--r--storage/connect/mysql-test/connect/t/myconn_cleanup.inc9
-rw-r--r--storage/connect/mysql-test/connect/t/mysql_discovery.test33
-rw-r--r--storage/connect/mysql-test/connect/t/mysql_exec.test45
-rw-r--r--storage/connect/mysql-test/connect/t/mysql_new.test325
-rw-r--r--storage/connect/mysql-test/connect/t/odbc_sqlite3.test10
-rw-r--r--storage/connect/mysql-test/connect/t/odbc_xls.test13
-rw-r--r--storage/connect/mysql-test/connect/t/vec.test160
-rw-r--r--storage/connect/myutil.cpp34
-rw-r--r--storage/connect/myutil.h9
-rw-r--r--storage/connect/odbccat.h2
-rw-r--r--storage/connect/odbconn.cpp170
-rw-r--r--storage/connect/odbconn.h7
-rw-r--r--storage/connect/plgdbsem.h12
-rw-r--r--storage/connect/plgdbutl.cpp2
-rw-r--r--storage/connect/tabdos.cpp2
-rw-r--r--storage/connect/table.cpp1
-rw-r--r--storage/connect/tabmysql.cpp404
-rw-r--r--storage/connect/tabmysql.h30
-rw-r--r--storage/connect/taboccur.cpp1
-rw-r--r--storage/connect/taboccur.h2
-rw-r--r--storage/connect/tabodbc.cpp324
-rw-r--r--storage/connect/tabodbc.h31
-rw-r--r--storage/connect/tabpivot.cpp2
-rw-r--r--storage/connect/tabtbl.cpp9
-rw-r--r--storage/connect/tabutil.cpp1
-rw-r--r--storage/connect/tabutil.h2
-rw-r--r--storage/connect/tabvct.cpp2
-rw-r--r--storage/connect/tabwmi.cpp19
-rw-r--r--storage/connect/tabxcl.cpp1
-rw-r--r--storage/connect/tabxcl.h2
-rw-r--r--storage/connect/valblk.cpp123
-rw-r--r--storage/connect/valblk.h42
-rw-r--r--storage/connect/value.cpp259
-rw-r--r--storage/connect/value.h87
-rwxr-xr-xstorage/connect/xindex.cpp10
-rw-r--r--storage/connect/xtable.h34
68 files changed, 3381 insertions, 1754 deletions
diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt
index 327f0035e06..dedcec792a5 100644
--- a/storage/connect/CMakeLists.txt
+++ b/storage/connect/CMakeLists.txt
@@ -264,6 +264,19 @@ int main() {
ENDIF(UNIX)
ENDIF(CONNECT_WITH_ODBC)
+#
+# Installing tests
+#
+IF(INSTALL_MYSQLTESTDIR)
+INSTALL(
+ DIRECTORY mysql-test/connect
+ DESTINATION ${INSTALL_MYSQLTESTDIR}/suite
+ USE_SOURCE_PERMISSIONS
+ COMPONENT Test
+ PATTERN "*~" EXCLUDE
+)
+ENDIF()
+
#
# Plugin definition
diff --git a/storage/connect/colblk.cpp b/storage/connect/colblk.cpp
index 64cccfced7f..2953fa29493 100644
--- a/storage/connect/colblk.cpp
+++ b/storage/connect/colblk.cpp
@@ -164,8 +164,7 @@ bool COLBLK::CheckSort(PTDB tdbp)
/* Now we use Format.Length for the len parameter to avoid strings */
/* to be truncated when converting from string to coded string. */
/* Added in version 1.5 is the arguments GetPrecision() and Domain */
-/* in calling AllocateValue. Domain is used for TYPE_TOKEN only, */
-/* but why was GetPrecision() not specified ? To be checked. */
+/* in calling AllocateValue. Domain is used for TYPE_DATE only. */
/***********************************************************************/
bool COLBLK::InitValue(PGLOBAL g)
{
@@ -174,8 +173,7 @@ bool COLBLK::InitValue(PGLOBAL g)
// Allocate a Value object
if (!(Value = AllocateValue(g, Buf_Type, Format.Length,
- GetPrecision(), GetDomain(),
- (To_Tdb) ? To_Tdb->GetCat() : NULL)))
+ GetPrecision(), GetDomain())))
return true;
AddStatus(BUF_READY);
diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc
index 2f7ec8299df..fd5f6fe6d5d 100644
--- a/storage/connect/connect.cc
+++ b/storage/connect/connect.cc
@@ -251,7 +251,7 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2,
return true;
} // endif tdbp
- tdbp->SetMode(mode);
+//tdbp->SetMode(mode); done in ha_connect::GetTDB
if (!c1) {
if (mode == MODE_INSERT)
@@ -498,8 +498,8 @@ RCODE CntDeleteRow(PGLOBAL g, PTDB tdbp, bool all)
if (!tdbp || tdbp->GetMode() != MODE_DELETE)
return RC_FX;
-// else
-// ((PTDBDOX)tdbp)->SetModified(true);
+ else if (tdbp->IsReadOnly())
+ return RC_NF;
if (((PTDBASE)tdbp)->GetDef()->Indexable() && all)
((PTDBDOS)tdbp)->Cardinal= 0;
@@ -518,17 +518,13 @@ int CntCloseTable(PGLOBAL g, PTDB tdbp)
int rc= RC_OK;
TDBDOX *tbxp= NULL;
- if (!tdbp)
- return rc; // Already done
+ if (!tdbp || tdbp->GetUse() != USE_OPEN)
+ return rc; // Nothing to do
if (xtrace)
printf("CntCloseTable: tdbp=%p mode=%d\n", tdbp, tdbp->GetMode());
- /*********************************************************************/
- /* This will close the table file(s) and also finalize write */
- /* operations such as Insert, Update, or Delete. */
- /*********************************************************************/
- if (tdbp->GetMode() == MODE_DELETE)
+ if (tdbp->GetMode() == MODE_DELETE && tdbp->GetUse() == USE_OPEN)
rc= tdbp->DeleteDB(g, RC_EF); // Specific A.M. delete routine
// Prepare error return
@@ -543,6 +539,8 @@ int CntCloseTable(PGLOBAL g, PTDB tdbp)
goto err;
} // endif
+ // This will close the table file(s) and also finalize write
+ // operations such as Insert, Update, or Delete.
tdbp->CloseDB(g);
g->jump_level--;
diff --git a/storage/connect/filamtxt.h b/storage/connect/filamtxt.h
index 6a1093eaa06..a6105d0fe66 100644
--- a/storage/connect/filamtxt.h
+++ b/storage/connect/filamtxt.h
@@ -17,8 +17,6 @@ typedef class BLKFAM *PBLKFAM;
typedef class DOSDEF *PDOSDEF;
typedef class TDBDOS *PTDBDOS;
-#define TYPE_AM_BLK (AMT)160
-
/***********************************************************************/
/* This is the base class for all file access method classes. */
/***********************************************************************/
diff --git a/storage/connect/filamvct.cpp b/storage/connect/filamvct.cpp
index 2b66437d127..11c9ac69d4d 100755
--- a/storage/connect/filamvct.cpp
+++ b/storage/connect/filamvct.cpp
@@ -91,7 +91,7 @@ typedef struct _vecheader {
/* Conversion of block values allowed conditionally for insert only. */
/***********************************************************************/
PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int,
- bool check = true, bool blank = true);
+ bool check = true, bool blank = true, bool un = false);
/* -------------------------- Class VCTFAM --------------------------- */
diff --git a/storage/connect/filamzip.h b/storage/connect/filamzip.h
index a83af78b19a..f6f28ca5315 100644
--- a/storage/connect/filamzip.h
+++ b/storage/connect/filamzip.h
@@ -10,9 +10,6 @@
#include "zlib.h"
-#define TYPE_AM_ZIP (AMT)150
-#define TYPE_AM_ZLIB (AMT)155
-
typedef class ZIPFAM *PZIPFAM;
typedef class ZBKFAM *PZBKFAM;
typedef class ZIXFAM *PZIXFAM;
diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc
index 9708fd9a521..038fb05839a 100644
--- a/storage/connect/ha_connect.cc
+++ b/storage/connect/ha_connect.cc
@@ -165,7 +165,7 @@ extern "C" char nmfile[];
extern "C" char pdebug[];
extern "C" {
- char version[]= "Version 1.01.0008 August 18, 2013";
+ char version[]= "Version 1.01.0009 October 29, 2013";
#if defined(XMSG)
char msglang[]; // Default message language
@@ -183,7 +183,7 @@ ulong ha_connect::num= 0;
//int DTVAL::Shift= 0;
static PCONNECT GetUser(THD *thd, PCONNECT xp);
-static PGLOBAL GetPlug(THD *thd, PCONNECT lxp);
+static PGLOBAL GetPlug(THD *thd, PCONNECT& lxp);
static handler *connect_create_handler(handlerton *hton,
TABLE_SHARE *table,
@@ -258,17 +258,21 @@ ha_create_table_option connect_field_option_list[]=
/***********************************************************************/
/* Push G->Message as a MySQL warning. */
/***********************************************************************/
-bool PushWarning(PGLOBAL g, PTDBASE tdbp)
+bool PushWarning(PGLOBAL g, PTDBASE tdbp, int level)
{
PHC phc;
THD *thd;
MYCAT *cat= (MYCAT*)tdbp->GetDef()->GetCat();
+ Sql_condition::enum_warning_level wlvl;
+
if (!cat || !(phc= cat->GetHandler()) || !phc->GetTable() ||
!(thd= (phc->GetTable())->in_use))
return true;
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+//push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ wlvl= (Sql_condition::enum_warning_level)level;
+ push_warning(thd, wlvl, 0, g->Message);
return false;
} // end of PushWarning
@@ -552,7 +556,7 @@ static PCONNECT GetUser(THD *thd, PCONNECT xp)
/****************************************************************************/
/* Get the global pointer of the user of this handler. */
/****************************************************************************/
-static PGLOBAL GetPlug(THD *thd, PCONNECT lxp)
+static PGLOBAL GetPlug(THD *thd, PCONNECT& lxp)
{
lxp= GetUser(thd, lxp);
return (lxp) ? lxp->g : NULL;
@@ -659,6 +663,8 @@ char *ha_connect::GetStringOption(char *opname, char *sdef)
opval= (char*)options->colist;
else if (!stricmp(opname, "Data_charset"))
opval= (char*)options->data_charset;
+ else if (!stricmp(opname, "Query_String"))
+ opval= thd_query_string(table->in_use)->str;
if (!opval && options && options->oplist)
opval= GetListOption(xp->g, opname, options->oplist);
@@ -1096,19 +1102,20 @@ PTDB ha_connect::GetTDB(PGLOBAL g)
&& (tdbp->GetMode() == xmod
|| tdbp->GetAmType() == TYPE_AM_XML)) {
tp= tdbp;
- tp->SetMode(xmod);
+// tp->SetMode(xmod);
} else if ((tp= CntGetTDB(g, table_name, xmod, this)))
valid_query_id= xp->last_query_id;
else
printf("GetTDB: %s\n", g->Message);
+ tp->SetMode(xmod);
return tp;
} // end of GetTDB
/****************************************************************************/
/* Open a CONNECT table, restricting column list if cols is true. */
/****************************************************************************/
-bool ha_connect::OpenTable(PGLOBAL g, bool del)
+int ha_connect::OpenTable(PGLOBAL g, bool del)
{
bool rc= false;
char *c1= NULL, *c2=NULL;
@@ -1116,11 +1123,11 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del)
// Double test to be on the safe side
if (!g || !table) {
printf("OpenTable logical error; g=%p table=%p\n", g, table);
- return true;
+ return HA_ERR_INITIALIZATION;
} // endif g
if (!(tdbp= GetTDB(g)))
- return true;
+ return RC_FX;
else if (tdbp->IsReadOnly())
switch (xmod) {
case MODE_WRITE:
@@ -1128,7 +1135,7 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del)
case MODE_UPDATE:
case MODE_DELETE:
strcpy(g->Message, MSG(READ_ONLY));
- return true;
+ return HA_ERR_TABLE_READONLY;
default:
break;
} // endswitch xmode
@@ -1205,7 +1212,7 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del)
valid_info= false;
} // endif rc
- return rc;
+ return (rc) ? HA_ERR_INITIALIZATION : 0;
} // end of OpenTable
@@ -1239,15 +1246,16 @@ int ha_connect::CloseTable(PGLOBAL g)
/***********************************************************************/
int ha_connect::MakeRecord(char *buf)
{
- char *p, *fmt, val[32];
- int rc= 0;
- Field* *field;
- Field *fp;
- my_bitmap_map *org_bitmap;
- CHARSET_INFO *charset= tdbp->data_charset();
- const MY_BITMAP *map;
- PVAL value;
- PCOL colp= NULL;
+ char *p, *fmt, val[32];
+ int rc= 0;
+ Field* *field;
+ Field *fp;
+ my_bitmap_map *org_bitmap;
+ CHARSET_INFO *charset= tdbp->data_charset();
+//MY_BITMAP readmap;
+ MY_BITMAP *map;
+ PVAL value;
+ PCOL colp= NULL;
DBUG_ENTER("ha_connect::MakeRecord");
if (xtrace > 1)
@@ -1263,7 +1271,7 @@ int ha_connect::MakeRecord(char *buf)
memset(buf, 0, table->s->null_bytes);
// When sorting read_set selects all columns, so we use def_read_set
- map= (const MY_BITMAP *)&table->def_read_set;
+ map= (MY_BITMAP *)&table->def_read_set;
// Make the pseudo record from field values
for (field= table->field; *field && !rc; field++) {
@@ -1300,6 +1308,9 @@ int ha_connect::MakeRecord(char *buf)
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;
@@ -1401,24 +1412,25 @@ int ha_connect::ScanRecord(PGLOBAL g, uchar *buf)
value->SetValue(fp->val_real());
break;
case TYPE_DATE:
- if (!sdvalin) {
+ if (!sdvalin)
sdvalin= (DTVAL*)AllocateValue(xp->g, TYPE_DATE, 19);
- // Get date in the format produced by MySQL fields
- switch (fp->type()) {
- case MYSQL_TYPE_DATE:
- fmt= "YYYY-MM-DD";
- break;
- case MYSQL_TYPE_TIME:
- fmt= "hh:mm:ss";
- break;
- default:
- fmt= "YYYY-MM-DD hh:mm:ss";
- } // endswitch type
-
- ((DTVAL*)sdvalin)->SetFormat(g, fmt, strlen(fmt));
- } // endif sdvalin
+ // Get date in the format produced by MySQL fields
+ switch (fp->type()) {
+ case MYSQL_TYPE_DATE:
+ fmt= "YYYY-MM-DD";
+ break;
+ case MYSQL_TYPE_TIME:
+ fmt= "hh:mm:ss";
+ break;
+ case MYSQL_TYPE_YEAR:
+ fmt= "YYYY";
+ break;
+ default:
+ fmt= "YYYY-MM-DD hh:mm:ss";
+ } // endswitch type
+ ((DTVAL*)sdvalin)->SetFormat(g, fmt, strlen(fmt));
fp->val_str(&attribute);
sdvalin->SetValue_psz(attribute.c_ptr_safe());
value->SetValue_pval(sdvalin);
@@ -1557,8 +1569,9 @@ const char *ha_connect::GetValStr(OPVAL vop, bool neg)
/***********************************************************************/
PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
{
+ char *body= filp->Body;
unsigned int i;
- bool ismul= false;
+ bool ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
PPARM pfirst= NULL, pprec= NULL, pp[2]= {NULL, NULL};
OPVAL vop= OP_XX;
@@ -1572,6 +1585,9 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
char *p1, *p2;
Item_cond *cond_item= (Item_cond *)cond;
+ if (x)
+ return NULL;
+
if (xtrace > 1)
printf("Cond: Ftype=%d name=%s\n", cond_item->functype(),
cond_item->func_name());
@@ -1586,7 +1602,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
List_iterator<Item> li(*arglist);
Item *subitem;
- p1= filp + strlen(filp);
+ p1= body + strlen(body);
strcpy(p1, "(");
p2= p1 + 1;
@@ -1615,7 +1631,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
} else if (cond->type() == COND::FUNC_ITEM) {
unsigned int i;
// int n;
- bool iscol, neg= FALSE;
+ bool iscol, neg= FALSE;
Item_func *condf= (Item_func *)cond;
Item* *args= condf->arguments();
@@ -1644,6 +1660,9 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL 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)))
+ return NULL;
+
for (i= 0; i < condf->argument_count(); i++) {
if (xtrace > 1)
printf("Argtype(%d)=%d\n", i, args[i]->type());
@@ -1660,6 +1679,9 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
ha_field_option_struct *fop;
Item_field *pField= (Item_field *)args[i];
+ if (x && i)
+ return NULL;
+
if (pField->field->table != table)
return NULL; // Field does not belong to this table
else
@@ -1685,10 +1707,10 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
if (i && ismul)
return NULL;
- strcat(filp, fnm);
+ strcat(body, fnm);
} else {
- char buff[256];
- String *res, tmp(buff,sizeof(buff), &my_charset_bin);
+ char buff[256];
+ String *res, tmp(buff, sizeof(buff), &my_charset_bin);
Item_basic_constant *pval= (Item_basic_constant *)args[i];
if ((res= pval->val_str(&tmp)) == NULL)
@@ -1698,26 +1720,46 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
printf("Value=%.*s\n", res->length(), res->ptr());
// IN and BETWEEN clauses should be col VOP list
- if (!i && ismul)
+ if (!i && (x || ismul))
return NULL;
- // Append the value to the filter
- if (args[i]->type() == COND::STRING_ITEM)
- strcat(strcat(strcat(filp, "'"), res->ptr()), "'");
- else
- strncat(filp, res->ptr(), res->length());
+ if (!x) {
+ // Append the value to the filter
+ if (args[i]->field_type() == MYSQL_TYPE_VARCHAR)
+ strcat(strcat(strcat(body, "'"), res->ptr()), "'");
+ else
+ strncat(body, res->ptr(), res->length());
+
+ } else {
+ if (args[i]->field_type() == MYSQL_TYPE_VARCHAR) {
+ // Add the command to the list
+ PCMD *ncp, cmdp= new(g) CMD(g, (char*)res->ptr());
+
+ for (ncp= &filp->Cmds; *ncp; ncp= &(*ncp)->Next) ;
+
+ *ncp= cmdp;
+ } else
+ return NULL;
+
+ } // endif x
} // endif
- if (!i)
- strcat(filp, GetValStr(vop, neg));
- else if (vop == OP_XX && i == 1)
- strcat(filp, " AND ");
- else if (vop == OP_IN)
- strcat(filp, (i == condf->argument_count() - 1) ? ")" : ",");
+ if (!x) {
+ if (!i)
+ strcat(body, GetValStr(vop, neg));
+ else if (vop == OP_XX && i == 1)
+ strcat(body, " AND ");
+ else if (vop == OP_IN)
+ strcat(body, (i == condf->argument_count() - 1) ? ")" : ",");
+
+ } // endif x
} // endfor i
+ if (x)
+ filp->Op= vop;
+
} else {
if (xtrace > 1)
printf("Unsupported condition\n");
@@ -1753,23 +1795,31 @@ const COND *ha_connect::cond_push(const COND *cond)
DBUG_ENTER("ha_connect::cond_push");
if (tdbp) {
- AMT tty= tdbp->GetAmType();
+ AMT tty= tdbp->GetAmType();
+ bool x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
if (tty == TYPE_AM_WMI || tty == TYPE_AM_ODBC ||
- tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL) {
+ tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL || x) {
PGLOBAL& g= xp->g;
- PFIL filp= (PFIL)PlugSubAlloc(g, NULL, 0);
+ PFIL filp= (PFIL)PlugSubAlloc(g, NULL, sizeof(FILTER));
- *filp= 0;
+ 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 (xtrace)
- puts(filp);
+ puts(filp->Body);
+
+ if (!x)
+ PlugSubAlloc(g, NULL, strlen(filp->Body) + 1);
+ else
+ cond= NULL; // Does this work?
tdbp->SetFilter(filp);
-// cond= NULL; // This does not work anyway
- PlugSubAlloc(g, NULL, strlen(filp) + 1);
- } // endif filp
+ } else if (x && cond)
+ tdbp->SetFilter(filp); // Wrong filter
} // endif tty
@@ -1965,14 +2015,8 @@ int ha_connect::write_row(uchar *buf)
if (IsOpened())
CloseTable(g);
- if (OpenTable(g)) {
- if (strstr(g->Message, "read only"))
- rc= HA_ERR_TABLE_READONLY;
- else
- rc= HA_ERR_INITIALIZATION;
-
+ if ((rc= OpenTable(g)))
DBUG_RETURN(rc);
- } // endif tdbp
} // endif isopened
@@ -2337,6 +2381,7 @@ int ha_connect::index_next_same(uchar *buf, const uchar *key, uint keylen)
*/
int ha_connect::rnd_init(bool scan)
{
+ int rc;
PGLOBAL g= ((table && table->in_use) ? GetPlug(table->in_use, xp) :
(xp) ? xp->g : NULL);
DBUG_ENTER("ha_connect::rnd_init");
@@ -2344,18 +2389,21 @@ int ha_connect::rnd_init(bool scan)
if (xtrace)
printf("%p in rnd_init: scan=%d\n", this, scan);
- if (g) {
- if (!table || xmod == MODE_INSERT)
- DBUG_RETURN(HA_ERR_INITIALIZATION);
+ if (!g || !table || xmod == MODE_INSERT)
+ DBUG_RETURN(HA_ERR_INITIALIZATION);
- // Close the table if it was opened yet (locked?)
- if (IsOpened())
- CloseTable(g);
+ // Close the table if it was opened yet (locked?)
+ if (IsOpened())
+ CloseTable(g);
- if (OpenTable(g, xmod == MODE_DELETE))
- DBUG_RETURN(HA_ERR_INITIALIZATION);
+ // 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);
- } // endif g
+ if ((rc= OpenTable(g, xmod == MODE_DELETE)))
+ DBUG_RETURN(rc);
xp->nrd= xp->fnd= xp->nfd= 0;
xp->tb1= my_interval_timer();
@@ -2566,7 +2614,6 @@ int ha_connect::info(uint flag)
xp->CheckCleanup();
} // endif xmod
-// tdbp= OpenTable(g, xmod == MODE_DELETE);
tdbp= GetTDB(g);
} // endif tdbp
@@ -2661,18 +2708,19 @@ int ha_connect::delete_all_rows()
PGLOBAL g= xp->g;
DBUG_ENTER("ha_connect::delete_all_rows");
- if (tdbp && tdbp->GetAmType() != TYPE_AM_XML)
+ if (tdbp && tdbp->GetUse() == USE_OPEN &&
+ tdbp->GetAmType() != TYPE_AM_XML &&
+ ((PTDBASE)tdbp)->GetFtype() != RECFM_NAF)
// Close and reopen the table so it will be deleted
rc= CloseTable(g);
- if (!(OpenTable(g))) {
+ if (!(rc= OpenTable(g))) {
if (CntDeleteRow(g, tdbp, true)) {
printf("%s\n", g->Message);
rc= HA_ERR_INTERNAL_ERROR;
} // endif
- } else
- rc= HA_ERR_INITIALIZATION;
+ } // endif rc
DBUG_RETURN(rc);
} // end of delete_all_rows
@@ -3461,12 +3509,13 @@ static bool add_fields(PGLOBAL g,
DBUG_RETURN(0);
} // end of add_fields
#else // !NEW_WAY
-static bool add_field(String *sql, const char *field_name, int typ, int len,
- int dec, uint tm, const char *rem, int flag, bool dbf)
+static bool add_field(String *sql, const char *field_name, int typ,
+ int len, int dec, uint tm, const char *rem,
+ int flag, bool dbf, char v)
{
+ char var = (len > 255) ? 'V' : v;
bool error= false;
- const char *type= PLGtoMYSQLtype(typ, dbf);
-// type= PLGtoMYSQLtype(typ, true); ?????
+ const char *type= PLGtoMYSQLtype(typ, dbf, var);
error|= sql->append('`');
error|= sql->append(field_name);
@@ -3479,7 +3528,8 @@ static bool add_field(String *sql, const char *field_name, int typ, int len,
if (!strcmp(type, "DOUBLE")) {
error|= sql->append(',');
- error|= sql->append_ulonglong(dec);
+ // dec must be <= len and <= 31
+ error|= sql->append_ulonglong(min(dec, (len - 1)));
} // endif dec
error|= sql->append(')');
@@ -3518,6 +3568,8 @@ static int init_table_share(THD *thd,
HA_CREATE_INFO *create_info,
Alter_info *alter_info)
{
+ KEY *not_used_1;
+ uint not_used_2;
int rc= 0;
handler *file;
LEX_CUSTRING frm= {0,0};
@@ -3577,9 +3629,8 @@ static int init_table_share(THD *thd,
tmp_disable_binlog(thd);
file= mysql_create_frm_image(thd, table_s->db.str, table_s->table_name.str,
- create_info, alter_info,
-// &thd->lex->create_info, &thd->lex->alter_info,
- C_ORDINARY_CREATE, &frm);
+ create_info, alter_info, C_ORDINARY_CREATE,
+ &not_used_1, &not_used_2, &frm);
if (file)
delete file;
else
@@ -3772,13 +3823,14 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
TABTYPE ttp= TAB_UNDEF;
PQRYRES qrp= NULL;
PCOLRES crp;
- PGLOBAL g= GetPlug(thd, NULL);
+ PCONNECT xp= NULL;
+ PGLOBAL g= GetPlug(thd, xp);
PTOS topt= table_s->option_struct;
#if defined(NEW_WAY)
//CHARSET_INFO *cs;
Alter_info alter_info;
#else // !NEW_WAY
- char buf[1024];
+ char v, buf[1024];
String sql(buf, sizeof(buf), system_charset_info);
sql.copy(STRING_WITH_LEN("CREATE TABLE whatever ("), system_charset_info);
@@ -3821,7 +3873,9 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
#endif // WIN32
port= atoi(GetListOption(g, "port", topt->oplist, "0"));
mxr= atoi(GetListOption(g,"maxerr", topt->oplist, "0"));
+#if defined(PROMPT_OK)
cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0"));
+#endif // PROMPT_OK
} else {
host= "localhost";
user= "root";
@@ -3879,14 +3933,16 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
case TAB_ODBC:
dsn= create_info->connect_string.str;
- if (fnc & (FNC_DSN | FNC_DRIVER))
+ if (fnc & (FNC_DSN | FNC_DRIVER)) {
ok= true;
- else if (!stricmp(thd->main_security_ctx.host, "localhost")
+#if defined(PROMPT_OK)
+ } else if (!stricmp(thd->main_security_ctx.host, "localhost")
&& cop == 1) {
if ((dsn = ODBCCheckConnection(g, dsn, cop)) != NULL) {
thd->make_lex_string(&create_info->connect_string, dsn, strlen(dsn));
ok= true;
} // endif dsn
+#endif // PROMPT_OK
} else if (!dsn)
sprintf(g->Message, "Missing %s connection string", topt->type);
@@ -4098,7 +4154,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
NOT_NULL_FLAG, "", flg, dbf);
#else // !NEW_WAY
// Now add the field
- if (add_field(&sql, cnm, typ, len, dec, NOT_NULL_FLAG, 0, flg, dbf))
+ if (add_field(&sql, cnm, typ, len, dec, NOT_NULL_FLAG, 0, flg, dbf, 0))
rc= HA_ERR_OUT_OF_MEM;
#endif // !NEW_WAY
} // endfor crp
@@ -4122,6 +4178,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
break;
case FLD_TYPE:
typ= crp->Kdata->GetIntValue(i);
+ v = (crp->Nulls) ? crp->Nulls[i] : 0;
break;
case FLD_PREC:
len= crp->Kdata->GetIntValue(i);
@@ -4152,7 +4209,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
int plgtyp;
// typ must be PLG type, not SQL type
- if (!(plgtyp= TranslateSQLType(typ, dec, len))) {
+ if (!(plgtyp= TranslateSQLType(typ, dec, len, v))) {
sprintf(g->Message, "Unsupported SQL type %d", typ);
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
return HA_ERR_INTERNAL_ERROR;
@@ -4177,7 +4234,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
rc= add_fields(g, thd, &alter_info, cnm, typ, len, dec,
tm, rem, 0, true);
#else // !NEW_WAY
- if (add_field(&sql, cnm, typ, len, dec, tm, rem, 0, true))
+ if (add_field(&sql, cnm, typ, len, dec, tm, rem, 0, dbf, v))
rc= HA_ERR_OUT_OF_MEM;
#endif // !NEW_WAY
} // endfor i
@@ -4671,6 +4728,6 @@ maria_declare_plugin(connect)
NULL, /* status variables */
NULL, /* system variables */
"0.1", /* string version */
- MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */
+ MariaDB_PLUGIN_MATURITY_ALPHA /* maturity */
}
maria_declare_plugin_end;
diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h
index 35daf2e5c19..dd67773efc0 100644
--- a/storage/connect/ha_connect.h
+++ b/storage/connect/ha_connect.h
@@ -174,7 +174,7 @@ public:
bool IsSameIndex(PIXDEF xp1, PIXDEF xp2);
PTDB GetTDB(PGLOBAL g);
- bool OpenTable(PGLOBAL g, bool del= false);
+ int OpenTable(PGLOBAL g, bool del= false);
bool IsOpened(void);
int CloseTable(PGLOBAL g);
int MakeRecord(char *buf);
diff --git a/storage/connect/libdoc.cpp b/storage/connect/libdoc.cpp
index 31aa90da076..e6046a07c5c 100644
--- a/storage/connect/libdoc.cpp
+++ b/storage/connect/libdoc.cpp
@@ -8,6 +8,9 @@
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
+#include <libxml/catalog.h>
+#include <libxml/xmlschemastypes.h>
+#include <libxml/relaxng.h>
//#if defined(WIN32)
//#include <windows.h>
//#else // !WIN32
@@ -290,10 +293,46 @@ if (!rc)
/******************************************************************/
/* XML library cleanup function. */
/******************************************************************/
+/*
+ This is a copy of xmlCleanupParser() from the libxml2 sources
+ with xmlResetLastError() commented.
+
+ xmlResetLastError() called from the original xmlCleanupParser() causes
+ valgrind to report memory leaks. This happens because
+ ha_initialize_handlerton() is called from the main thread in mysqld.cc,
+ while ha_finalize_handlerton() is called from a non-main thread.
+ libxml2 gets confused because of xmlInitParser() and xmlCleanupParser()
+ being called from the different threads.
+
+ Perhaps the code in mysqld.cc should eventually be modified
+ to shutdown plugins from the main thread.
+*/
+static void
+xmlCleanupParser_replacement(void)
+ {
+ xmlCleanupCharEncodingHandlers();
+#ifdef LIBXML_CATALOG_ENABLED
+ xmlCatalogCleanup();
+#endif
+ xmlDictCleanup();
+ xmlCleanupInputCallbacks();
+#ifdef LIBXML_OUTPUT_ENABLED
+ xmlCleanupOutputCallbacks();
+#endif
+#ifdef LIBXML_SCHEMAS_ENABLED
+ xmlSchemaCleanupTypes();
+ xmlRelaxNGCleanupTypes();
+#endif
+ //xmlResetLastError();
+ xmlCleanupGlobals();
+ xmlCleanupThreads(); /* must be last if called not from the main thread */
+ xmlCleanupMemory();
+ }
+
+
void XmlCleanupParserLib(void)
{
- xmlCleanupParser();
- xmlMemoryDump();
+ xmlCleanupParser_replacement();
} // end of XmlCleanupParserLib
/******************************************************************/
diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp
index e2de93e8fc8..f9763f0eb2f 100644
--- a/storage/connect/myconn.cpp
+++ b/storage/connect/myconn.cpp
@@ -87,7 +87,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
FLD_KEY, FLD_SCALE, FLD_RADIX, FLD_NULL,
FLD_REM, FLD_NO, FLD_CHARSET};
static unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 256, 32, 32};
- char *fld, *fmt, cmd[128];
+ char *fld, *fmt, v, cmd[128];
int i, n, nf, ncol = sizeof(buftyp) / sizeof(int);
int len, type, prec, rc, k = 0;
PQRYRES qrp;
@@ -139,6 +139,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
// Some columns must be renamed
for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
switch (++i) {
+ case 2: crp->Nulls = (char*)PlugSubAlloc(g, NULL, n); break;
case 4: crp->Name = "Length"; break;
case 5: crp->Name = "Key"; break;
case 10: crp->Name = "Date_fmt"; break;
@@ -166,7 +167,8 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
// Get type, type name, and precision
fld = myc.GetCharField(1);
prec = 0;
- len = 255; // Default for text or blob
+ len = 0;
+ v = 0;
if ((nf = sscanf(fld, "%[^(](%d,%d", cmd, &len, &prec)) < 1) {
sprintf(g->Message, MSG(BAD_FIELD_TYPE), fld);
@@ -175,14 +177,16 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
} else
qrp->Nblin++;
- if ((type = MYSQLtoPLG(cmd)) == TYPE_ERROR) {
+ if ((type = MYSQLtoPLG(cmd, &v)) == TYPE_ERROR) {
sprintf(g->Message, "Unsupported column type %s", cmd);
myc.Close();
return NULL;
- } // endif type
+ } else if (type == TYPE_STRING)
+ len = min(len, 4096);
crp = crp->Next; // Data_Type
crp->Kdata->SetValue(type, i);
+ crp->Nulls[i] = v;
crp = crp->Next; // Type_Name
crp->Kdata->SetValue(cmd, i);
@@ -253,6 +257,7 @@ PQRYRES SrcColumns(PGLOBAL g, const char *host, const char *db,
const char *user, const char *pwd,
const char *srcdef, int port)
{
+ char *query;
int w;
MYSQLC myc;
PQRYRES qrp = NULL;
@@ -260,12 +265,15 @@ PQRYRES SrcColumns(PGLOBAL g, const char *host, const char *db,
if (!port)
port = mysqld_port;
+ query = (char *)PlugSubAlloc(g, NULL, strlen(srcdef) + 9);
+ strcat(strcpy(query, srcdef), " LIMIT 0");
+
// Open a MySQL connection for this table
if (myc.Open(g, host, db, user, pwd, port))
return NULL;
// Send the source command to MySQL
- if (myc.ExecSQL(g, srcdef, &w) == RC_OK)
+ if (myc.ExecSQL(g, query, &w) == RC_OK)
qrp = myc.GetResult(g);
myc.Close();
@@ -701,7 +709,7 @@ PQRYRES MYSQLC::GetResult(PGLOBAL g, bool pdb)
crp->Clen = GetTypeSize(crp->Type, crp->Length);
if (!(crp->Kdata = AllocValBlock(g, NULL, crp->Type, m_Rows,
- crp->Clen, 0, FALSE, TRUE))) {
+ crp->Clen, 0, FALSE, TRUE, FALSE))) {
sprintf(g->Message, MSG(INV_RESULT_TYPE),
GetFormatType(crp->Type));
return NULL;
@@ -779,6 +787,42 @@ void MYSQLC::Rewind(void)
} // end of Rewind
/***********************************************************************/
+/* Exec the Select SQL command and return ncol or afrws (TDBMYEXC). */
+/***********************************************************************/
+int MYSQLC::ExecSQLcmd(PGLOBAL g, const char *query, int *w)
+ {
+ int rc = RC_OK;
+
+ if (!m_DB) {
+ strcpy(g->Message, "MySQL not connected");
+ return RC_FX;
+ } else
+ *w = 0;
+
+ if (!stricmp(query, "Warning") || !stricmp(query, "Note")
+ || !stricmp(query, "Error"))
+ return RC_INFO;
+ else
+ m_Afrw = 0;
+
+//if (mysql_query(m_DB, query) != 0) {
+ if (mysql_real_query(m_DB, query, strlen(query))) {
+ m_Afrw = (int)mysql_errno(m_DB);
+ sprintf(g->Message, "Remote: %s", mysql_error(m_DB));
+ rc = RC_FX;
+//} else if (!(m_Fields = mysql_field_count(m_DB))) {
+ } else if (!(m_Fields = (int)m_DB->field_count)) {
+// m_Afrw = (int)mysql_affected_rows(m_DB);
+ m_Afrw = (int)m_DB->affected_rows;
+ rc = RC_NF;
+ } // endif's
+
+//*w = mysql_warning_count(m_DB);
+ *w = m_DB->warning_count;
+ return rc;
+ } // end of ExecSQLcmd
+
+/***********************************************************************/
/* Close the connection. */
/***********************************************************************/
void MYSQLC::Close(void)
diff --git a/storage/connect/myconn.h b/storage/connect/myconn.h
index 10ff76c3273..8a49239ec7a 100644
--- a/storage/connect/myconn.h
+++ b/storage/connect/myconn.h
@@ -26,7 +26,6 @@
#define DllItem
#endif // !WIN32
-//#define TYPE_AM_MYSQL (AMT)192
#define MYSQL_ENABLED 0x00000001
#define MYSQL_LOGON 0x00000002
@@ -75,9 +74,12 @@ class DllItem MYSQLC {
//const char *ServerInfo(void);
int KillQuery(ulong id);
int ExecSQL(PGLOBAL g, const char *query, int *w = NULL);
+ int ExecSQLcmd(PGLOBAL g, const char *query, int *w);
+#if defined(MYSQL_PREPARED_STATEMENTS)
int PrepareSQL(PGLOBAL g, const char *query);
int ExecStmt(PGLOBAL g);
int BindParams(PGLOBAL g, MYSQL_BIND *bind);
+#endif // MYSQL_PREPARED_STATEMENTS
PQRYRES GetResult(PGLOBAL g, bool pdb = FALSE);
int Fetch(PGLOBAL g, int pos);
char *GetCharField(int i);
@@ -99,5 +101,6 @@ class DllItem MYSQLC {
int m_Rows; // The number of rows of the result
int N;
int m_Fields; // The number of result fields
+ int m_Afrw; // The number of affected rows
}; // end of class MYSQLC
diff --git a/storage/connect/mysql-test/connect/my.cnf b/storage/connect/mysql-test/connect/my.cnf
new file mode 100644
index 00000000000..124047fb792
--- /dev/null
+++ b/storage/connect/mysql-test/connect/my.cnf
@@ -0,0 +1,15 @@
+# Use default setting for mysqld processes
+!include include/default_mysqld.cnf
+!include include/default_client.cnf
+
+[mysqld.1]
+#log-bin= master-bin
+
+[mysqld.2]
+
+[ENV]
+MASTER_MYPORT= @mysqld.1.port
+MASTER_MYSOCK= @mysqld.1.socket
+
+SLAVE_MYPORT= @mysqld.2.port
+SLAVE_MYSOCK= @mysqld.2.socket
diff --git a/storage/connect/mysql-test/connect/r/bin.result b/storage/connect/mysql-test/connect/r/bin.result
index c64b270b538..10deb54cb2e 100644
--- a/storage/connect/mysql-test/connect/r/bin.result
+++ b/storage/connect/mysql-test/connect/r/bin.result
@@ -48,7 +48,7 @@ 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 READONLY=Yes FILE_NAME='Testbal.dat';
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
ALTER TABLE t1 READONLY=NO;
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk
@@ -84,7 +84,7 @@ t1 CREATE TABLE `t1` (
`dept` int(4) NOT NULL `FIELD_FORMAT`='S'
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=BIN `FILE_NAME`='Testbal.dat' `READONLY`=YES
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
DROP TABLE t1;
#
# Testing that the underlying file is created
diff --git a/storage/connect/mysql-test/connect/r/csv.result b/storage/connect/mysql-test/connect/r/csv.result
index b2498326edb..94fd95a5d83 100644
--- a/storage/connect/mysql-test/connect/r/csv.result
+++ b/storage/connect/mysql-test/connect/r/csv.result
@@ -50,13 +50,13 @@ children SMALLINT(2) NOT NULL
) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='people.csv'
HEADER=1 SEP_CHAR=';' QUOTED=1 READONLY=yes;
INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
UPDATE t1 SET children=6 WHERE name='BILL';
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
DELETE FROM t1 WHERE name='BILL';
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
TRUNCATE TABLE t1;
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
SELECT * FROM t1;
name birth children
Archibald 2001-05-17 3
@@ -90,7 +90,7 @@ t1 CREATE TABLE `t1` (
`children` smallint(2) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=CSV `FILE_NAME`='people.csv' `HEADER`=1 `SEP_CHAR`=';' `QUOTED`=1 `READONLY`=1
INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
SELECT * FROM t1;
name birth children
Archibald 2001-05-17 3
diff --git a/storage/connect/mysql-test/connect/r/dbf.result b/storage/connect/mysql-test/connect/r/dbf.result
index cbe4f4db620..c7bb5739e75 100644
--- a/storage/connect/mysql-test/connect/r/dbf.result
+++ b/storage/connect/mysql-test/connect/r/dbf.result
@@ -77,13 +77,13 @@ t1 CREATE TABLE `t1` (
`a` int(11) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DBF `FILE_NAME`='t1.dbf' `READONLY`=Yes
INSERT INTO t1 VALUES (30);
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
UPDATE t1 SET a=30 WHERE a=10;
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
DELETE FROM t1 WHERE a=10;
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
TRUNCATE TABLE t1;
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
ALTER TABLE t1 READONLY=NO;
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk
diff --git a/storage/connect/mysql-test/connect/r/fix.result b/storage/connect/mysql-test/connect/r/fix.result
index c8f51abe961..c218561c3aa 100644
--- a/storage/connect/mysql-test/connect/r/fix.result
+++ b/storage/connect/mysql-test/connect/r/fix.result
@@ -30,13 +30,13 @@ t1 CREATE TABLE `t1` (
`id` int(11) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=FIX `FILE_NAME`='t1.txt' `READONLY`=1
INSERT INTO t1 VALUES (20);
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
UPDATE t1 SET id=20 WHERE id=10;
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
DELETE FROM t1 WHERE id=10;
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
TRUNCATE TABLE t1;
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
ALTER TABLE t1 READONLY=0;
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk
diff --git a/storage/connect/mysql-test/connect/r/ini.result b/storage/connect/mysql-test/connect/r/ini.result
index 83ba98fbd84..fa03435323e 100644
--- a/storage/connect/mysql-test/connect/r/ini.result
+++ b/storage/connect/mysql-test/connect/r/ini.result
@@ -194,13 +194,13 @@ t1 CREATE TABLE `t1` (
`c2` char(60) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=INI `FILE_NAME`='t1.ini' `READONLY`=1
INSERT INTO t1 VALUES ('US',40);
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
UPDATE t1 SET c2=20 WHERE c2=10;
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
DELETE FROM t1 WHERE c2=10;
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
TRUNCATE TABLE t1;
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
ALTER TABLE t1 READONLY=0;
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk
diff --git a/storage/connect/mysql-test/connect/r/mysql.result b/storage/connect/mysql-test/connect/r/mysql.result
index c0ef487c111..eb45e29c7f1 100644
--- a/storage/connect/mysql-test/connect/r/mysql.result
+++ b/storage/connect/mysql-test/connect/r/mysql.result
@@ -44,7 +44,7 @@ SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` int(11) DEFAULT NULL,
- `b` varchar(10) DEFAULT NULL
+ `b` char(10) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MYSQL' `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
SELECT * FROM t2;
a b
@@ -176,7 +176,7 @@ t1 CREATE TABLE `t1` (
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `a` varchar(10) DEFAULT NULL
+ `a` char(10) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MYSQL' `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
SELECT * FROM t2;
a
diff --git a/storage/connect/mysql-test/connect/r/mysql_discovery.result b/storage/connect/mysql-test/connect/r/mysql_discovery.result
new file mode 100644
index 00000000000..2fc2039e53e
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mysql_discovery.result
@@ -0,0 +1,42 @@
+CREATE DATABASE connect;
+CREATE DATABASE connect;
+CREATE TABLE t1 (
+`id` int(20) primary key,
+`group` int NOT NULL default 1,
+`a\\b` int NOT NULL default 2,
+`a\\` int unsigned,
+`name` varchar(32) default 'name')
+DEFAULT CHARSET=latin1;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `id` int(20) NOT NULL,
+ `group` int(11) NOT NULL,
+ `a\\b` int(11) NOT NULL,
+ `a\\` int(10) DEFAULT NULL,
+ `name` varchar(32) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1' `TABLE_TYPE`='MYSQL'
+INSERT INTO t1 (id, name) VALUES (1, 'foo');
+Warnings:
+Warning 1364 Field 'group' doesn't have a default value
+Warning 1364 Field 'a\\b' doesn't have a default value
+INSERT INTO t1 (id, name) VALUES (2, 'fee');
+Warnings:
+Warning 1364 Field 'group' doesn't have a default value
+Warning 1364 Field 'a\\b' doesn't have a default value
+SELECT * FROM t1;
+id group a\\b a\\ name
+1 1 2 NULL foo
+2 1 2 NULL fee
+DROP TABLE t1;
+SELECT * FROM t1;
+id group a\\b a\\ name
+1 1 2 NULL foo
+2 1 2 NULL fee
+DROP TABLE t1;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
diff --git a/storage/connect/mysql-test/connect/r/mysql_exec.result b/storage/connect/mysql-test/connect/r/mysql_exec.result
new file mode 100644
index 00000000000..778577a1d8a
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mysql_exec.result
@@ -0,0 +1,62 @@
+CREATE DATABASE connect;
+CREATE DATABASE connect;
+#
+# Checking Sending Commands
+#
+CREATE TABLE t1 (
+command VARCHAR(128) NOT NULL,
+warnings INT(4) NOT NULL FLAG=3,
+number INT(5) NOT NULL FLAG=1,
+message VARCHAR(255) FLAG=2)
+ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test' OPTION_LIST='Execsrc=1,maxerr=2';
+SELECT * FROM t1 WHERE command IN ('Warning','Note',
+'drop table if exists t1',
+'create table t1 (id int key auto_increment, msg varchar(32) not null)',
+"insert into t1(msg) values('One'),(NULL),('Three')",
+"insert into t1 values(2,'Deux') on duplicate key update msg = 'Two'",
+"insert into t1(message) values('Four'),('Five'),('Six')",
+'insert into t1(id) values(NULL)',
+"update t1 set msg = 'Four' where id = 4",
+'select * from t1');
+command warnings number message
+drop table if exists t1 1 0 Affected rows
+Note 0 1051 Unknown table 'test.t1'
+create table t1 (id int key auto_increment, msg varchar(32) not null) 0 0 Affected rows
+insert into t1(msg) values('One'),(NULL),('Three') 1 3 Affected rows
+Warning 0 1048 Column 'msg' cannot be null
+insert into t1 values(2,'Deux') on duplicate key update msg = 'Two' 0 2 Affected rows
+insert into t1(message) values('Four'),('Five'),('Six') 0 1054 Remote: Unknown column 'message' in 'field list'
+insert into t1(id) values(NULL) 1 1 Affected rows
+Warning 0 1364 Field 'msg' doesn't have a default value
+update t1 set msg = 'Four' where id = 4 0 1 Affected rows
+select * from t1 0 2 Result set columns
+#
+# Checking Using Procedure
+#
+DROP PROCEDURE IF EXISTS p1;
+Warnings:
+Note 1305 PROCEDURE test.p1 does not exist
+CREATE PROCEDURE p1(cmd varchar(512))
+READS SQL DATA
+SELECT * FROM t1 WHERE command IN ('Warning','Note',cmd);
+CALL p1('insert into t1(id) values(NULL)');
+command warnings number message
+insert into t1(id) values(NULL) 1 1 Affected rows
+Warning 0 1364 Field 'msg' doesn't have a default value
+CALL p1('update t1 set msg = "Five" where id = 5');
+command warnings number message
+update t1 set msg = "Five" where id = 5 0 1 Affected rows
+DROP PROCEDURE p1;
+DROP TABLE t1;
+SELECT * FROM t1;
+id msg
+1 One
+2 Two
+3 Three
+4 Four
+5 Five
+DROP TABLE t1;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
diff --git a/storage/connect/mysql-test/connect/r/mysql_new.result b/storage/connect/mysql-test/connect/r/mysql_new.result
new file mode 100644
index 00000000000..057c09f53fc
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mysql_new.result
@@ -0,0 +1,218 @@
+CREATE DATABASE connect;
+CREATE DATABASE connect;
+CREATE TABLE t1 (a int, b char(10));
+INSERT INTO t1 VALUES (NULL,NULL),(0,'test00'),(1,'test01'),(2,'test02'),(3,'test03');
+SELECT * FROM t1;
+a b
+NULL NULL
+0 test00
+1 test01
+2 test02
+3 test03
+#
+# Testing errors
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://unknown@127.0.0.1:SLAVE_PORT/test/t1';
+ERROR HY000: (1045) Access denied for user 'unknown'@'localhost' (using password: NO)
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/unknown/t1';
+ERROR HY000: (1049) Unknown database 'unknown'
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+OPTION_LIST='host=127.0.0.1,user=root,port=SLAVE_PORT' DBNAME='unknown' TABNAME='t1';
+ERROR HY000: (1049) Unknown database 'unknown'
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/unknown';
+ERROR HY000: (1146) Table 'test.unknown' doesn't exist [SHOW FULL COLUMNS FROM unknown FROM test]
+SHOW CREATE TABLE t1;
+ERROR 42S02: Table 'test.t1' doesn't exist
+CREATE TABLE t1 (x int, y char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x` int(11) DEFAULT NULL,
+ `y` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1' `TABLE_TYPE`=MYSQL
+SELECT * FROM t1;
+ERROR HY000: Got error 174 '(1054) Unknown column 'x' in 'field list' [SELECT `x`, `y` FROM `t1`]' from CONNECT
+DROP TABLE t1;
+CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1';
+ALTER TABLE t1 RENAME t1backup;
+SELECT * FROM t1;
+ERROR HY000: Got error 174 '(1146) Table 'test.t1' doesn't exist [SELECT `a`, `b` FROM `t1`]' from CONNECT
+ALTER TABLE t1backup RENAME t1;
+DROP TABLE t1;
+#
+# Testing SELECT, etc.
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1' `TABLE_TYPE`='MYSQL'
+SELECT * FROM t1;
+a b
+NULL NULL
+0 test00
+1 test01
+2 test02
+3 test03
+DROP TABLE t1;
+CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1'
+ OPTION_LIST='host=127.0.0.1,user=root,port=SLAVE_PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=MYSQL `TABNAME`='t1' `OPTION_LIST`='host=127.0.0.1,user=root,port=SLAVE_PORT'
+SELECT * FROM t1;
+a b
+NULL NULL
+0 test00
+1 test01
+2 test02
+3 test03
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL, b CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=MYSQL
+OPTION_LIST='host=127.0.0.1,user=root,port=SLAVE_PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=MYSQL `OPTION_LIST`='host=127.0.0.1,user=root,port=SLAVE_PORT'
+SELECT * FROM t1;
+a b
+0
+0 test00
+1 test01
+2 test02
+3 test03
+DROP TABLE t1;
+CREATE TABLE t1 (a char(10), b int) ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(10) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1' `TABLE_TYPE`=MYSQL
+SELECT * FROM t1;
+a b
+NULL NULL
+0 0
+1 0
+2 0
+3 0
+DROP TABLE t1;
+DROP TABLE t1;
+#
+# Testing numeric data types
+#
+CREATE TABLE t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float, g double, h decimal(20,5));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` tinyint(4) DEFAULT NULL,
+ `b` smallint(6) DEFAULT NULL,
+ `c` mediumint(9) DEFAULT NULL,
+ `d` int(11) DEFAULT NULL,
+ `e` bigint(20) DEFAULT NULL,
+ `f` float DEFAULT NULL,
+ `g` double DEFAULT NULL,
+ `h` decimal(20,5) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES(100,3333,41235,1234567890,235000000000,3.14159265,3.14159265,3141.59265);
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+OPTION_LIST='host=127.0.0.1,user=root,port=SLAVE_PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` tinyint(4) DEFAULT NULL,
+ `b` smallint(6) DEFAULT NULL,
+ `c` int(9) DEFAULT NULL,
+ `d` int(11) DEFAULT NULL,
+ `e` bigint(20) DEFAULT NULL,
+ `f` double DEFAULT NULL,
+ `g` double DEFAULT NULL,
+ `h` double(20,5) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MYSQL' `OPTION_LIST`='host=127.0.0.1,user=root,port=SLAVE_PORT'
+SELECT * FROM t1;
+a b c d e f g h
+100 3333 41235 1234567890 235000000000 3.14159 3.14159265 3141.59265
+DROP TABLE t1;
+DROP TABLE t1;
+#
+# Testing character data types
+#
+CREATE TABLE t1 (a char(12), b varchar(12));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(12) DEFAULT NULL,
+ `b` varchar(12) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES('Welcome','Hello, World');
+SELECT * FROM t1;
+a b
+Welcome Hello, World
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(12) DEFAULT NULL,
+ `b` varchar(12) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT' `TABLE_TYPE`='MYSQL'
+SELECT * FROM t1;
+a b
+Welcome Hello, World
+DROP TABLE t1;
+DROP TABLE t1;
+#
+# Testing temporal data types
+#
+CREATE TABLE t1 (a date, b datetime, c time, d timestamp, e year);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` date DEFAULT NULL,
+ `b` datetime DEFAULT NULL,
+ `c` time DEFAULT NULL,
+ `d` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `e` year(4) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES('2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23');
+Warnings:
+Note 1265 Data truncated for column 'a' at row 1
+Note 1265 Data truncated for column 'c' at row 1
+Warning 1265 Data truncated for column 'e' at row 1
+SELECT * FROM t1;
+a b c d e
+2003-05-27 2003-05-27 10:45:23 10:45:23 2003-05-27 10:45:23 2003
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` date DEFAULT NULL,
+ `b` datetime DEFAULT NULL,
+ `c` time DEFAULT NULL,
+ `d` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `e` year(4) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT' `TABLE_TYPE`='MYSQL'
+SELECT * FROM t1;
+a b c d e
+2003-05-27 2003-05-27 10:45:23 10:45:23 2003-05-27 10:45:23 2003
+DROP TABLE t1;
+DROP TABLE t1;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
diff --git a/storage/connect/mysql-test/connect/r/odbc_sqlite3.result b/storage/connect/mysql-test/connect/r/odbc_sqlite3.result
index 339dbb6a53d..00ef94c4791 100644
--- a/storage/connect/mysql-test/connect/r/odbc_sqlite3.result
+++ b/storage/connect/mysql-test/connect/r/odbc_sqlite3.result
@@ -1,6 +1,6 @@
Table Create Table
t1 CREATE TABLE `t1` (
- `Description` varchar(128) NOT NULL,
+ `Description` char(128) NOT NULL,
`Attributes` varchar(256) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Drivers'
SET NAMES utf8;
@@ -41,3 +41,13 @@ test2
ÆÇÈÉË
DROP VIEW v1;
DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Columns TABNAME='t1' TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=MTR_SUITE_DIR/std_data/test.sqlite3;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8;
+SELECT * FROM t1;
+Table_Qualif Table_Owner Table_Name Column_Name Data_Type Type_Name Precision Length Scale Radix Nullable Remarks
+ t1 a 12 varchar(64) 64 64 10 0 1
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Tables TABNAME='t1' TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=MTR_SUITE_DIR/std_data/test.sqlite3;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8;
+SELECT * FROM t1;
+Table_Qualifier Table_Owner Table_Name Table_Type Remark
+ t1 TABLE
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result b/storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result
index 87f7803166c..364f340eddf 100644
--- a/storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result
+++ b/storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result
@@ -1,6 +1,6 @@
Table Create Table
t1 CREATE TABLE `t1` (
- `Description` varchar(128) NOT NULL,
+ `Description` char(128) NOT NULL,
`Attributes` varchar(256) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Drivers'
SET NAMES utf8;
diff --git a/storage/connect/mysql-test/connect/r/odbc_xls.result b/storage/connect/mysql-test/connect/r/odbc_xls.result
index 4f080eae986..a0b26fe3569 100644
--- a/storage/connect/mysql-test/connect/r/odbc_xls.result
+++ b/storage/connect/mysql-test/connect/r/odbc_xls.result
@@ -13,3 +13,14 @@ Thomas Dominique NULL
Lemonnier Nathalie Directeur Marketing Client
Menseau Eric NULL
DROP TABLE contact;
+CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Tables TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineXLS;DBQ=DATADIR/test/contacts.xls' CHARSET=utf8 DATA_CHARSET=latin1;;
+SELECT * FROM t1 WHERE Table_name='CONTACT';
+Table_Qualifier Table_Owner Table_Name Table_Type Remark
+DATADIR/test/contacts CONTACT TABLE
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Columns TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineXLS;DBQ=DATADIR/test/contacts.xls' CHARSET=utf8 DATA_CHARSET=latin1;;
+SELECT * FROM t1 WHERE Table_name='CONTACT' AND Column_name IN ('Nom','Fonction');
+Table_Qualif Table_Owner Table_Name Column_Name Data_Type Type_Name Precision Length Scale Radix Nullable Remarks
+DATADIR/test/contacts CONTACT Nom 12 VARCHAR 255 510 0 0 1
+DATADIR/test/contacts CONTACT Fonction 12 VARCHAR 255 510 0 0 1
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/vec.result b/storage/connect/mysql-test/connect/r/vec.result
index 65513dc07db..926c0f2f4c6 100644
--- a/storage/connect/mysql-test/connect/r/vec.result
+++ b/storage/connect/mysql-test/connect/r/vec.result
@@ -103,13 +103,13 @@ t1 CREATE TABLE `t1` (
`b` char(10) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 MAX_ROWS=10 `TABLE_TYPE`=VEC `FILE_NAME`='t1vec' `READONLY`=yes
INSERT INTO t1 VALUES (4,'test04');
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
UPDATE t1 SET b='test04' WHERE a=3;
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
DELETE FROM t1 WHERE a=3;
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
TRUNCATE TABLE t1;
-ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+ERROR HY000: Table 't1' is read only
ALTER TABLE t1 READONLY=no;
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk
diff --git a/storage/connect/mysql-test/connect/r/xml.result b/storage/connect/mysql-test/connect/r/xml.result
index ea915234203..a8d2ded7bcf 100644
--- a/storage/connect/mysql-test/connect/r/xml.result
+++ b/storage/connect/mysql-test/connect/r/xml.result
@@ -413,7 +413,7 @@ DROP TABLE t1;
SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml');
SELECT CAST(@a AS CHAR CHARACTER SET latin1);
CAST(@a AS CHAR CHARACTER SET latin1) <?xml version="1.0" encoding="iso-8859-1"?>
-<!-- Created by CONNECT Version 1.01.0008 August 18, 2013 -->
+<!-- Created by CONNECT Version 1.01.0009 October 29, 2013 -->
<t1>
<line>
<node>ÀÁÂÃ</node>
diff --git a/storage/connect/mysql-test/connect/t/bin.test b/storage/connect/mysql-test/connect/t/bin.test
index a9dab32987e..6ef0ffc75ec 100644
--- a/storage/connect/mysql-test/connect/t/bin.test
+++ b/storage/connect/mysql-test/connect/t/bin.test
@@ -1,77 +1,77 @@
-let $MYSQLD_DATADIR= `select @@datadir`;
-
---copy_file $MTR_SUITE_DIR/std_data/Testbal.dat $MYSQLD_DATADIR/test/Testbal.dat
-
---echo #
---echo # Testing errors
---echo #
-CREATE TABLE t1
-(
- ID INT NOT NULL
-) Engine=CONNECT TABLE_TYPE=BIN FILE_NAME='nonexistent.txt';
---replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
-# TODO: check why this is needed for Windows
---replace_result Open(rt) Open(rb)
-SELECT * FROM t1;
-DROP TABLE t1;
-
-SET time_zone='+00:00';
-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';
-SELECT * FROM t1;
-
---error ER_GET_ERRMSG
-INSERT INTO t1 VALUES (55555,'RONALD','1980-02-26','3333',4444.44,555);
-INSERT INTO t1 VALUES (5555,'RONALD','1980-02-26','3333',4444.44,555);
-SELECT * FROM t1;
-
-DROP TABLE t1;
-
---echo #
---echo # Testing READONLY tables
---echo #
-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 READONLY=Yes FILE_NAME='Testbal.dat';
---error ER_GET_ERRMSG
-INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
-ALTER TABLE t1 READONLY=NO;
-SHOW CREATE TABLE t1;
-INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
-SELECT * FROM t1;
-ALTER TABLE t1 READONLY=YES;
-SHOW CREATE TABLE t1;
---error ER_GET_ERRMSG
-INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
-DROP TABLE t1;
-
-
---echo #
---echo # Testing that the underlying file is created
---echo #
-CREATE TABLE t1
-(
- c CHAR(4) NOT NULL FIELD_FORMAT='C'
-) ENGINE=CONNECT TABLE_TYPE=BIN FILE_NAME='bin2.dat';
-INSERT INTO t1 VALUES (10),(20),(300),(4000);
-SELECT * FROM t1;
-DROP TABLE t1;
-
-#
-# Clean up
-#
---remove_file $MYSQLD_DATADIR/test/Testbal.dat
---remove_file $MYSQLD_DATADIR/test/bin2.dat
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/Testbal.dat $MYSQLD_DATADIR/test/Testbal.dat
+
+--echo #
+--echo # Testing errors
+--echo #
+CREATE TABLE t1
+(
+ ID INT NOT NULL
+) Engine=CONNECT TABLE_TYPE=BIN FILE_NAME='nonexistent.txt';
+--replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
+# TODO: check why this is needed for Windows
+--replace_result Open(rt) Open(rb)
+SELECT * FROM t1;
+DROP TABLE t1;
+
+SET time_zone='+00:00';
+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';
+SELECT * FROM t1;
+
+--error ER_GET_ERRMSG
+INSERT INTO t1 VALUES (55555,'RONALD','1980-02-26','3333',4444.44,555);
+INSERT INTO t1 VALUES (5555,'RONALD','1980-02-26','3333',4444.44,555);
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+--echo #
+--echo # Testing READONLY tables
+--echo #
+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 READONLY=Yes FILE_NAME='Testbal.dat';
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
+ALTER TABLE t1 READONLY=NO;
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
+SELECT * FROM t1;
+ALTER TABLE t1 READONLY=YES;
+SHOW CREATE TABLE t1;
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that the underlying file is created
+--echo #
+CREATE TABLE t1
+(
+ c CHAR(4) NOT NULL FIELD_FORMAT='C'
+) ENGINE=CONNECT TABLE_TYPE=BIN FILE_NAME='bin2.dat';
+INSERT INTO t1 VALUES (10),(20),(300),(4000);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/Testbal.dat
+--remove_file $MYSQLD_DATADIR/test/bin2.dat
diff --git a/storage/connect/mysql-test/connect/t/csv.test b/storage/connect/mysql-test/connect/t/csv.test
index 685ac434df7..a21686d8a08 100644
--- a/storage/connect/mysql-test/connect/t/csv.test
+++ b/storage/connect/mysql-test/connect/t/csv.test
@@ -1,185 +1,185 @@
-let $MYSQLD_DATADIR= `select @@datadir`;
-
---copy_file $MTR_SUITE_DIR/std_data/people.csv $MYSQLD_DATADIR/test/people.csv
-
-SET NAMES utf8;
-
---echo #
---echo # Testing errors
---echo #
-CREATE TABLE t1
-(
- ID INT NOT NULL
-) Engine=CONNECT TABLE_TYPE=CSV FILE_NAME='nonexistent.txt';
---replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
-# TODO: check why this is needed for Windows
---replace_result Open(rt) Open(rb)
-SELECT * FROM t1;
-DROP TABLE t1;
-
---echo #
---echo # Testing examples from the manual
---echo #
-CREATE TABLE t1
-(
- name CHAR(12) NOT NULL,
- birth DATE NOT NULL DATE_FORMAT='DD/MM/YY',
- children SMALLINT(2) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='people.csv'
- HEADER=1 SEP_CHAR=';' QUOTED=1;
-SELECT * FROM t1;
-INSERT INTO t1 VALUES ('RONALD','1980-02-26',4);
-SELECT * FROM t1;
-DROP TABLE t1;
---chmod 0777 $MYSQLD_DATADIR/test/people.csv
---replace_result $MYSQLD_DATADIR DATADIR
---eval SELECT REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/people.csv'),'\r\n','\n');
-
---echo #
---echo # Testing READONLY tables
---echo #
-CREATE TABLE t1
-(
- name CHAR(12) NOT NULL,
- birth DATE NOT NULL DATE_FORMAT='DD/MM/YY',
- children SMALLINT(2) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='people.csv'
- HEADER=1 SEP_CHAR=';' QUOTED=1 READONLY=yes;
---error ER_GET_ERRMSG
-INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
---error ER_GET_ERRMSG
-UPDATE t1 SET children=6 WHERE name='BILL';
---error ER_GET_ERRMSG
-DELETE FROM t1 WHERE name='BILL';
---error ER_GET_ERRMSG
-TRUNCATE TABLE t1;
-SELECT * FROM t1;
-ALTER TABLE t1 READONLY=no;
-SHOW CREATE TABLE t1;
-INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
-SELECT * FROM t1;
-ALTER TABLE t1 READONLY=1;
-SHOW CREATE TABLE t1;
---error ER_GET_ERRMSG
-INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
-SELECT * FROM t1;
-DROP TABLE t1;
-
-
---echo #
---echo # Testing that the underlying file is created
---echo #
-CREATE TABLE t1
-(
- c1 CHAR(12) NOT NULL,
- c2 CHAR(12) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='tmp.csv'
- HEADER=1 SEP_CHAR=',' QUOTED=1;
-INSERT INTO t1 VALUES (10,10),(20,20),(300,300),(4000,4000), ('a b','c d');
-SELECT * FROM t1;
-DROP TABLE t1;
---chmod 0777 $MYSQLD_DATADIR/test/tmp.csv
---replace_result $MYSQLD_DATADIR DATADIR
---eval SELECT REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/tmp.csv'),'\r\n','\n');
-
---echo #
---echo # Creating a CSV table from a MyISAM table
---echo #
-CREATE TABLE t1 (a VARCHAR(10) NOT NULL, b INT NOT NULL) ENGINE=MyISAM;
-INSERT INTO t1 VALUES ('test1',1), ('test2',2);
-CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t2.csv'
- AS SELECT * FROM t1;
-SELECT * FROM t2;
-DROP TABLE t2;
-DROP TABLE t1;
---chmod 0777 $MYSQLD_DATADIR/test/t2.csv
---replace_result $MYSQLD_DATADIR DATADIR
---eval SELECT REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t2.csv'),'\r\n','\n');
---remove_file $MYSQLD_DATADIR/test/t2.csv
-
---echo #
---echo # Testing international data
---echo #
-CREATE TABLE t1
-(
- c1 CHAR(12) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
- CHARSET=utf8;
-INSERT INTO t1 VALUES ('á');
-SELECT * FROM t1;
-DROP TABLE t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.csv
---replace_result $MYSQLD_DATADIR DATADIR
---eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
---remove_file $MYSQLD_DATADIR/test/t1.csv
-
-CREATE TABLE t1
-(
- c1 CHAR(12) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
- CHARSET=utf8 DATA_CHARSET=latin1;
-INSERT INTO t1 VALUES ('á');
-SELECT * FROM t1;
-DROP TABLE t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.csv
---replace_result $MYSQLD_DATADIR DATADIR
---eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
---remove_file $MYSQLD_DATADIR/test/t1.csv
-
-CREATE TABLE t1
-(
- c1 CHAR(12) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv';
-INSERT INTO t1 VALUES ('á');
-SELECT * FROM t1;
-DROP TABLE t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.csv
---replace_result $MYSQLD_DATADIR DATADIR
---eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
---remove_file $MYSQLD_DATADIR/test/t1.csv
-
-CREATE TABLE t1
-(
- c1 CHAR(12) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
- CHARSET=latin1;
-INSERT INTO t1 VALUES ('á');
-SELECT * FROM t1;
-DROP TABLE t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.csv
---replace_result $MYSQLD_DATADIR DATADIR
---eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
---remove_file $MYSQLD_DATADIR/test/t1.csv
-
-CREATE TABLE t1
-(
- c1 CHAR(12) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
- CHARSET=latin1 DATA_CHARSET=utf8;
-INSERT INTO t1 VALUES ('á');
-SELECT * FROM t1;
-DROP TABLE t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.csv
---replace_result $MYSQLD_DATADIR DATADIR
---eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
---remove_file $MYSQLD_DATADIR/test/t1.csv
-
-CREATE TABLE t1
-(
- c1 CHAR(12) CHARACTER SET latin1 NOT NULL,
- c2 CHAR(12) CHARACTER SET utf8 NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv';
-INSERT INTO t1 VALUES ('á','á');
-SELECT * FROM t1;
-DROP TABLE t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.csv
---replace_result $MYSQLD_DATADIR DATADIR
---eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
---remove_file $MYSQLD_DATADIR/test/t1.csv
-
-
-#
-# Clean up
-#
---remove_file $MYSQLD_DATADIR/test/people.csv
---remove_file $MYSQLD_DATADIR/test/tmp.csv
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/people.csv $MYSQLD_DATADIR/test/people.csv
+
+SET NAMES utf8;
+
+--echo #
+--echo # Testing errors
+--echo #
+CREATE TABLE t1
+(
+ ID INT NOT NULL
+) Engine=CONNECT TABLE_TYPE=CSV FILE_NAME='nonexistent.txt';
+--replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
+# TODO: check why this is needed for Windows
+--replace_result Open(rt) Open(rb)
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing examples from the manual
+--echo #
+CREATE TABLE t1
+(
+ name CHAR(12) NOT NULL,
+ birth DATE NOT NULL DATE_FORMAT='DD/MM/YY',
+ children SMALLINT(2) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='people.csv'
+ HEADER=1 SEP_CHAR=';' QUOTED=1;
+SELECT * FROM t1;
+INSERT INTO t1 VALUES ('RONALD','1980-02-26',4);
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/people.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/people.csv'),'\r\n','\n');
+
+--echo #
+--echo # Testing READONLY tables
+--echo #
+CREATE TABLE t1
+(
+ name CHAR(12) NOT NULL,
+ birth DATE NOT NULL DATE_FORMAT='DD/MM/YY',
+ children SMALLINT(2) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='people.csv'
+ HEADER=1 SEP_CHAR=';' QUOTED=1 READONLY=yes;
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
+--error ER_OPEN_AS_READONLY
+UPDATE t1 SET children=6 WHERE name='BILL';
+--error ER_OPEN_AS_READONLY
+DELETE FROM t1 WHERE name='BILL';
+--error ER_OPEN_AS_READONLY
+TRUNCATE TABLE t1;
+SELECT * FROM t1;
+ALTER TABLE t1 READONLY=no;
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
+SELECT * FROM t1;
+ALTER TABLE t1 READONLY=1;
+SHOW CREATE TABLE t1;
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that the underlying file is created
+--echo #
+CREATE TABLE t1
+(
+ c1 CHAR(12) NOT NULL,
+ c2 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='tmp.csv'
+ HEADER=1 SEP_CHAR=',' QUOTED=1;
+INSERT INTO t1 VALUES (10,10),(20,20),(300,300),(4000,4000), ('a b','c d');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/tmp.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/tmp.csv'),'\r\n','\n');
+
+--echo #
+--echo # Creating a CSV table from a MyISAM table
+--echo #
+CREATE TABLE t1 (a VARCHAR(10) NOT NULL, b INT NOT NULL) ENGINE=MyISAM;
+INSERT INTO t1 VALUES ('test1',1), ('test2',2);
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t2.csv'
+ AS SELECT * FROM t1;
+SELECT * FROM t2;
+DROP TABLE t2;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t2.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t2.csv'),'\r\n','\n');
+--remove_file $MYSQLD_DATADIR/test/t2.csv
+
+--echo #
+--echo # Testing international data
+--echo #
+CREATE TABLE t1
+(
+ c1 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
+ CHARSET=utf8;
+INSERT INTO t1 VALUES ('á');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
+--remove_file $MYSQLD_DATADIR/test/t1.csv
+
+CREATE TABLE t1
+(
+ c1 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
+ CHARSET=utf8 DATA_CHARSET=latin1;
+INSERT INTO t1 VALUES ('á');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
+--remove_file $MYSQLD_DATADIR/test/t1.csv
+
+CREATE TABLE t1
+(
+ c1 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv';
+INSERT INTO t1 VALUES ('á');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
+--remove_file $MYSQLD_DATADIR/test/t1.csv
+
+CREATE TABLE t1
+(
+ c1 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
+ CHARSET=latin1;
+INSERT INTO t1 VALUES ('á');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
+--remove_file $MYSQLD_DATADIR/test/t1.csv
+
+CREATE TABLE t1
+(
+ c1 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
+ CHARSET=latin1 DATA_CHARSET=utf8;
+INSERT INTO t1 VALUES ('á');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
+--remove_file $MYSQLD_DATADIR/test/t1.csv
+
+CREATE TABLE t1
+(
+ c1 CHAR(12) CHARACTER SET latin1 NOT NULL,
+ c2 CHAR(12) CHARACTER SET utf8 NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv';
+INSERT INTO t1 VALUES ('á','á');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
+--remove_file $MYSQLD_DATADIR/test/t1.csv
+
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/people.csv
+--remove_file $MYSQLD_DATADIR/test/tmp.csv
diff --git a/storage/connect/mysql-test/connect/t/dbf.test b/storage/connect/mysql-test/connect/t/dbf.test
index b9a1b6e2183..3fd30f98f20 100644
--- a/storage/connect/mysql-test/connect/t/dbf.test
+++ b/storage/connect/mysql-test/connect/t/dbf.test
@@ -1,509 +1,509 @@
-let $MYSQLD_DATADIR= `select @@datadir`;
-
---echo #
---echo # Testing errors
---echo #
-CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-SHOW CREATE TABLE t1;
---replace_regex /on .*test.t1.dbf/on DATADIR\/test\/t1.dbf/
-SELECT * FROM t1;
-DROP TABLE t1;
-
---replace_regex /Cannot open .*test.t1.dbf/Cannot open DATADIR\/test\/t1.dbf/
---error ER_UNKNOWN_ERROR
-CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
---replace_regex /Cannot open .*test.t1.dbf/Cannot open DATADIR\/test\/t1.dbf/
-SHOW WARNINGS;
-
-
-DELIMITER //;
-CREATE PROCEDURE test.dbf_field(in fieldno INT, in content BLOB) DETERMINISTIC
-BEGIN
- SELECT '---';
- SELECT fieldno AS `FieldN`;
- SELECT TRIM(TRAILING 0x00 FROM LEFT(content, 10)) AS `Name`;
- SELECT SUBSTRING(content, 12, 1) AS `Type`;
- SELECT CONV(HEX(REVERSE(SUBSTRING(content,13,4))),16,10) AS `Offset`;
- SELECT CONV(HEX(REVERSE(SUBSTRING(content,17,1))),16,10) AS `Length`;
- SELECT CONV(HEX(REVERSE(SUBSTRING(content,18,1))),16,10) AS `Dec`;
- SELECT HEX(REVERSE(SUBSTRING(content,19,1))) AS `Flags`;
--- SELECT CONV(HEX(REVERSE(SUBSTRING(content,20,4))),16,10) AS `Next`;
--- SELECT CONV(HEX(REVERSE(SUBSTRING(content,24,4))),16,10) AS `Step`;
-END//
-
-CREATE PROCEDURE test.dbf_header(in fname VARCHAR(1024)) DETERMINISTIC
-BEGIN
- DECLARE content BLOB;
- DECLARE offset INT;
- DECLARE fieldno INT;
- SELECT '--------';
- SELECT LOAD_FILE(fname) INTO content;
- SELECT LENGTH(content) AS FileSize;
- SELECT HEX(LEFT(content, 1)) AS DBF_Version;
- SELECT CONV(HEX(REVERSE(SUBSTRING(content,5,4))),16,10) AS NRecords;
- SELECT CONV(HEX(REVERSE(SUBSTRING(content,9,2))),16,10) AS FirstRecPos;
- SELECT CONV(HEX(REVERSE(SUBSTRING(content,11,2))),16,10) AS RecLength;
- SELECT HEX(REVERSE(SUBSTRING(content,29,2))) AS TableFlags;
- SELECT HEX(REVERSE(SUBSTRING(content,30,1))) AS CodePageMark;
- SET offset=33;
- SET fieldno=0;
- WHILE SUBSTR(content, offset, 1) <> 0x0D AND offset + 32 < LENGTH(content) DO
- CALL dbf_field(fieldno, SUBSTRING(content, offset, 32));
- SET offset=offset + 32;
- SET fieldno=fieldno + 1;
- END WHILE;
- SELECT '--------';
-END//
-DELIMITER ;//
-
-
---echo #
---echo # Testing READONLY tables
---echo #
-CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-SHOW CREATE TABLE t1;
-INSERT INTO t1 VALUES (10),(20);
-SELECT * FROM t1;
-ALTER TABLE t1 READONLY=Yes;
-SHOW CREATE TABLE t1;
---error ER_GET_ERRMSG
-INSERT INTO t1 VALUES (30);
---error ER_GET_ERRMSG
-UPDATE t1 SET a=30 WHERE a=10;
---error ER_GET_ERRMSG
-DELETE FROM t1 WHERE a=10;
---error ER_GET_ERRMSG
-TRUNCATE TABLE t1;
-ALTER TABLE t1 READONLY=NO;
-SHOW CREATE TABLE t1;
-INSERT INTO t1 VALUES (30);
-SELECT * FROM t1;
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-
---echo #
---echo # This SQL script crashed (dbf01.sql)
---echo #
-CREATE TABLE t1
-(
- a int(11) NOT NULL,
- b char(10) NOT NULL,
- c varchar(10) NOT NULL
-) ENGINE=CONNECT table_type=DBF file_name='t1.dbf';
-INSERT INTO t1 VALUES (1,'1','1');
-INSERT INTO t1 VALUES (2,'2','2');
-SELECT * FROM t1;
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-
---echo #
---echo # Testing that table options in lower case and mixed case are understood:
---echo #
-CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT table_type=dbf file_name='t1.dbf';
-SHOW CREATE TABLE t1;
-INSERT INTO t1 VALUES (10);
-SELECT * FROM t1;
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1.dbf
-CREATE TABLE t1 (a CHAR(10) NOT NULL) ENGINE=CONNECT Table_Type=dbf File_Name='t1.dbf';
-SHOW CREATE TABLE t1;
-INSERT INTO t1 VALUES ('test');
-SELECT * FROM t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
---vertical_results
---replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
-eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
---horizontal_results
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-
-#
-# TODO: this creates DBF record with length=32, which looks wrong
-#
---echo #
---echo # Testing multiple columns
---echo #
-CREATE TABLE t1
-(
- a INT NOT NULL,
- b CHAR(10) NOT NULL,
- c VARCHAR(10) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-INSERT INTO t1 VALUES (1,'1','1');
-INSERT INTO t1 VALUES (2,'2','2');
-SELECT * FROM t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
---vertical_results
---replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
-eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
---horizontal_results
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-
---echo #
---echo # Testing long column name
---echo #
---error ER_UNKNOWN_ERROR
-CREATE TABLE t1
-(
- a012345678901234567890123456789 INT NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-
---echo #
---echo # Testing 2 columns with long names (12)
---echo #
---error ER_UNKNOWN_ERROR
-CREATE TABLE t1
-(
- a0123456789a INT NOT NULL,
- b0123456789b INT NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t02x11.dbf';
-
---echo #
---echo # Testing 2 columns with long names (11)
---echo #
---error ER_UNKNOWN_ERROR
-CREATE TABLE t1
-(
- a012345678a INT NOT NULL,
- b012345678b INT NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t02x12.dbf';
-
---echo #
---echo # Testing 2 columns name length 10 (maximum possible length)
---echo #
-CREATE TABLE t1
-(
- a01234567a INT NOT NULL,
- b01234567b INT NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t02x13.dbf';
-SHOW CREATE TABLE t1;
-INSERT INTO t1 VALUES (1,2);
-SELECT * FROM t1;
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t02x13.dbf
-
-
---echo #
---echo # Testing BIGINT
---echo #
-CREATE TABLE t1
-(
- a bigint NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-INSERT INTO t1 VALUES (0x7FFFFFFFFFFFFFFF);
-INSERT INTO t1 VALUES (-0x8000000000000000);
-SELECT * FROM t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
---vertical_results
---replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
-eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
---horizontal_results
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-
---echo #
---echo # Testing TINYINT
---echo #
-CREATE TABLE t1
-(
- a TINYINT NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-INSERT INTO t1 VALUES (123);
-SELECT * FROM t1;
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-
---echo #
---echo # Testing SMALLINT
---echo #
-CREATE TABLE t1
-(
- a SMALLINT NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-INSERT INTO t1 VALUES (0x7FFF);
-INSERT INTO t1 VALUES (-0x8000);
-SELECT * FROM t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
---vertical_results
---replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
-eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
---horizontal_results
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-
---echo #
---echo # Testing VARCHAR
---echo #
-CREATE TABLE t1
-(
- a VARCHAR(255) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-INSERT INTO t1 VALUES (REPEAT('a',255));
-SELECT LENGTH(a) FROM t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
---vertical_results
---replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
-eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
---horizontal_results
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-
---echo #
---echo # Testing too long CHAR
---echo # All columns longer than 255 bytes should be rejected
---echo #
---error ER_UNKNOWN_ERROR
-CREATE TABLE t1
-(
- a CHAR(86) CHARACTER SET utf8 NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
---error ER_UNKNOWN_ERROR
-
-
---echo #
---echo # Testing too long VARCHAR
---echo # All columns longer than 255 bytes should be rejected
---echo #
---error ER_UNKNOWN_ERROR
-CREATE TABLE t1
-(
- a VARCHAR(256) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
---error ER_UNKNOWN_ERROR
-CREATE TABLE t1
-(
- a VARCHAR(86) CHARACTER SET utf8 NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
---error ER_UNKNOWN_ERROR
-CREATE TABLE t1
-(
- a VARCHAR(64000) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-
-
---echo #
---echo # Testing BLOB
---echo #
---error ER_UNKNOWN_ERROR
-CREATE TABLE t1
-(
- a BLOB
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
---error ER_UNKNOWN_ERROR
-CREATE TABLE t1
-(
- a TINYBLOB
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
---error ER_UNKNOWN_ERROR
-CREATE TABLE t1
-(
- a MEDIUMBLOB
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
---error ER_UNKNOWN_ERROR
-CREATE TABLE t1
-(
- a LONGBLOB
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-
-
-# TODO: utf8 does not work
-#--echo #
-#--echo # Testing varchar with utf8
-#--echo #
-#SET NAMES utf8;
-#CREATE TABLE t1
-#(
-# a VARCHAR(10) CHARACTER SET utf8
-#) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-#INSERT INTO t1 VALUES (REPEAT(_ucs2 0x00DF,10));
-#SELECT * FROM t1;
-#DROP TABLE IF EXISTS t1;
-#--remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-
---echo #
---echo # Testing DATE
---echo #
-CREATE TABLE t1
-(
- a DATE NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-INSERT INTO t1 VALUES ('2001-01-01');
-SELECT * FROM t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
---vertical_results
---replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
-eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
---horizontal_results
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-
-
---echo #
---echo # Testing FLOAT
---echo #
-CREATE TABLE t1
-(
- a FLOAT(12,4) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-INSERT INTO t1 VALUES (123);
-SELECT * FROM t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
---vertical_results
---replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
-eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
---horizontal_results
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1.dbf
-#
-# TODO: this return error:
-# Got error 122 'Value 123.0000000000 too long for column a of length 12'
-# from CONNECT
-#
-#CREATE TABLE t1
-#(
-# a FLOAT NOT NULL
-#) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-#--error ER_GET_ERRMSG - why this error?
-#INSERT INTO t1 VALUES (123);
-#SELECT * FROM t1;
-#DROP TABLE IF EXISTS t1;
-#--remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-
-#
-# TODO: this creates a column of type 'D' (date), which is wrong
-#
-#--echo #
-#--echo # Testing DATETIME
-#--echo #
-#CREATE TABLE t1
-#(
-# a DATETIME NOT NULL
-#) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-#INSERT INTO t1 VALUES ('2013-02-01');
-#SELECT * FROM t1;
-#DROP TABLE t1;
-#--remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-
-#
-# TODO: this creates a column of type 'D' (date), which is wrong
-#
-#--echo #
-#--echo # Testing TIMESTAMP
-#--echo #
-#CREATE TABLE t1
-#(
-# a TIMESTAMP
-#) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-#INSERT INTO t1 VALUES ('2013-02-01');
-#SELECT * FROM t1;
-#DROP TABLE t1;
-#--remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-
---echo #
---echo # Testing double
---echo #
-CREATE TABLE t1
-(
- a DOUBLE(20,5) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-INSERT INTO t1 VALUES (123);
-INSERT INTO t1 VALUES (123456789.12345);
-SELECT * FROM t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
---vertical_results
---replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
-eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
---horizontal_results
-DROP TABLE IF EXISTS t1;
---remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-
-# TODO:
-# Testing with no FILE_NAME specified
-# Currently it returns:
-# ERROR 1296 (HY000): Got error 174 'Open(a+) error 21
-# on /opt/mariadb-5.5/data/: Is a directory' from CONNECT
-#CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=DBF;
-
---echo #
---echo # Testing ALTER
---echo #
-CREATE TABLE t1
-(
- a VARCHAR(10) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-INSERT INTO t1 VALUES ('10');
-SELECT * FROM t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
---vertical_results
---replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
-eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
---horizontal_results
-ALTER TABLE t1 MODIFY a VARCHAR(10) NOT NULL;
-SHOW CREATE TABLE t1;
-SELECT * FROM t1;
---vertical_results
---replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
-eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
---horizontal_results
-ALTER TABLE t1 MODIFY a INT(10) NOT NULL;
-SHOW CREATE TABLE t1;
-SELECT * FROM t1;
---vertical_results
---replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
-eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
---horizontal_results
-
-# TODO: this does not work on Windows
-#ALTER TABLE t1 MODIFY a INT(8) NOT NULL;
-#SHOW CREATE TABLE t1;
-#--error ER_GET_ERRMSG
-#SELECT * FROM t1;
-#--vertical_results
-#--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
-#eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
-#--horizontal_results
-DROP TABLE IF EXISTS t1;
---remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-
---echo #
---echo # Testing NULL
---echo #
-# TODO: NULLs should probably change to DEFAULT and produce a warning
-CREATE TABLE t1
-(
- c1 VARCHAR(10) NOT NULL,
- c2 VARCHAR(10) NOT NULL DEFAULT 'def',
- i1 INT NOT NULL,
- i2 INT NOT NULL DEFAULT 123
-) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
-INSERT INTO t1 VALUES ('10','10',10,10);
-#INSERT INTO t1 VALUES (NULL,NULL,NULL,NULL);
-INSERT INTO t1(c1,i1) VALUES ('20',20);
-INSERT INTO t1 VALUES ('30',DEFAULT,30,DEFAULT);
-SELECT * FROM t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
---vertical_results
---replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
-eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
---horizontal_results
-DROP TABLE IF EXISTS t1;
---remove_file $MYSQLD_DATADIR/test/t1.dbf
-
-DROP PROCEDURE test.dbf_field;
-DROP PROCEDURE test.dbf_header;
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--echo #
+--echo # Testing errors
+--echo #
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+SHOW CREATE TABLE t1;
+--replace_regex /on .*test.t1.dbf/on DATADIR\/test\/t1.dbf/
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--replace_regex /Cannot open .*test.t1.dbf/Cannot open DATADIR\/test\/t1.dbf/
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+--replace_regex /Cannot open .*test.t1.dbf/Cannot open DATADIR\/test\/t1.dbf/
+SHOW WARNINGS;
+
+
+DELIMITER //;
+CREATE PROCEDURE test.dbf_field(in fieldno INT, in content BLOB) DETERMINISTIC
+BEGIN
+ SELECT '---';
+ SELECT fieldno AS `FieldN`;
+ SELECT TRIM(TRAILING 0x00 FROM LEFT(content, 10)) AS `Name`;
+ SELECT SUBSTRING(content, 12, 1) AS `Type`;
+ SELECT CONV(HEX(REVERSE(SUBSTRING(content,13,4))),16,10) AS `Offset`;
+ SELECT CONV(HEX(REVERSE(SUBSTRING(content,17,1))),16,10) AS `Length`;
+ SELECT CONV(HEX(REVERSE(SUBSTRING(content,18,1))),16,10) AS `Dec`;
+ SELECT HEX(REVERSE(SUBSTRING(content,19,1))) AS `Flags`;
+-- SELECT CONV(HEX(REVERSE(SUBSTRING(content,20,4))),16,10) AS `Next`;
+-- SELECT CONV(HEX(REVERSE(SUBSTRING(content,24,4))),16,10) AS `Step`;
+END//
+
+CREATE PROCEDURE test.dbf_header(in fname VARCHAR(1024)) DETERMINISTIC
+BEGIN
+ DECLARE content BLOB;
+ DECLARE offset INT;
+ DECLARE fieldno INT;
+ SELECT '--------';
+ SELECT LOAD_FILE(fname) INTO content;
+ SELECT LENGTH(content) AS FileSize;
+ SELECT HEX(LEFT(content, 1)) AS DBF_Version;
+ SELECT CONV(HEX(REVERSE(SUBSTRING(content,5,4))),16,10) AS NRecords;
+ SELECT CONV(HEX(REVERSE(SUBSTRING(content,9,2))),16,10) AS FirstRecPos;
+ SELECT CONV(HEX(REVERSE(SUBSTRING(content,11,2))),16,10) AS RecLength;
+ SELECT HEX(REVERSE(SUBSTRING(content,29,2))) AS TableFlags;
+ SELECT HEX(REVERSE(SUBSTRING(content,30,1))) AS CodePageMark;
+ SET offset=33;
+ SET fieldno=0;
+ WHILE SUBSTR(content, offset, 1) <> 0x0D AND offset + 32 < LENGTH(content) DO
+ CALL dbf_field(fieldno, SUBSTRING(content, offset, 32));
+ SET offset=offset + 32;
+ SET fieldno=fieldno + 1;
+ END WHILE;
+ SELECT '--------';
+END//
+DELIMITER ;//
+
+
+--echo #
+--echo # Testing READONLY tables
+--echo #
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES (10),(20);
+SELECT * FROM t1;
+ALTER TABLE t1 READONLY=Yes;
+SHOW CREATE TABLE t1;
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES (30);
+--error ER_OPEN_AS_READONLY
+UPDATE t1 SET a=30 WHERE a=10;
+--error ER_OPEN_AS_READONLY
+DELETE FROM t1 WHERE a=10;
+--error ER_OPEN_AS_READONLY
+TRUNCATE TABLE t1;
+ALTER TABLE t1 READONLY=NO;
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES (30);
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # This SQL script crashed (dbf01.sql)
+--echo #
+CREATE TABLE t1
+(
+ a int(11) NOT NULL,
+ b char(10) NOT NULL,
+ c varchar(10) NOT NULL
+) ENGINE=CONNECT table_type=DBF file_name='t1.dbf';
+INSERT INTO t1 VALUES (1,'1','1');
+INSERT INTO t1 VALUES (2,'2','2');
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing that table options in lower case and mixed case are understood:
+--echo #
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT table_type=dbf file_name='t1.dbf';
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+CREATE TABLE t1 (a CHAR(10) NOT NULL) ENGINE=CONNECT Table_Type=dbf File_Name='t1.dbf';
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES ('test');
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+#
+# TODO: this creates DBF record with length=32, which looks wrong
+#
+--echo #
+--echo # Testing multiple columns
+--echo #
+CREATE TABLE t1
+(
+ a INT NOT NULL,
+ b CHAR(10) NOT NULL,
+ c VARCHAR(10) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (1,'1','1');
+INSERT INTO t1 VALUES (2,'2','2');
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing long column name
+--echo #
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a012345678901234567890123456789 INT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+
+--echo #
+--echo # Testing 2 columns with long names (12)
+--echo #
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a0123456789a INT NOT NULL,
+ b0123456789b INT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t02x11.dbf';
+
+--echo #
+--echo # Testing 2 columns with long names (11)
+--echo #
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a012345678a INT NOT NULL,
+ b012345678b INT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t02x12.dbf';
+
+--echo #
+--echo # Testing 2 columns name length 10 (maximum possible length)
+--echo #
+CREATE TABLE t1
+(
+ a01234567a INT NOT NULL,
+ b01234567b INT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t02x13.dbf';
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES (1,2);
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t02x13.dbf
+
+
+--echo #
+--echo # Testing BIGINT
+--echo #
+CREATE TABLE t1
+(
+ a bigint NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (0x7FFFFFFFFFFFFFFF);
+INSERT INTO t1 VALUES (-0x8000000000000000);
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing TINYINT
+--echo #
+CREATE TABLE t1
+(
+ a TINYINT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (123);
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing SMALLINT
+--echo #
+CREATE TABLE t1
+(
+ a SMALLINT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (0x7FFF);
+INSERT INTO t1 VALUES (-0x8000);
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing VARCHAR
+--echo #
+CREATE TABLE t1
+(
+ a VARCHAR(255) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (REPEAT('a',255));
+SELECT LENGTH(a) FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing too long CHAR
+--echo # All columns longer than 255 bytes should be rejected
+--echo #
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a CHAR(86) CHARACTER SET utf8 NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+--error ER_UNKNOWN_ERROR
+
+
+--echo #
+--echo # Testing too long VARCHAR
+--echo # All columns longer than 255 bytes should be rejected
+--echo #
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a VARCHAR(256) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a VARCHAR(86) CHARACTER SET utf8 NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a VARCHAR(64000) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+
+
+--echo #
+--echo # Testing BLOB
+--echo #
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a BLOB
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a TINYBLOB
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a MEDIUMBLOB
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a LONGBLOB
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+
+
+# TODO: utf8 does not work
+#--echo #
+#--echo # Testing varchar with utf8
+#--echo #
+#SET NAMES utf8;
+#CREATE TABLE t1
+#(
+# a VARCHAR(10) CHARACTER SET utf8
+#) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+#INSERT INTO t1 VALUES (REPEAT(_ucs2 0x00DF,10));
+#SELECT * FROM t1;
+#DROP TABLE IF EXISTS t1;
+#--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing DATE
+--echo #
+CREATE TABLE t1
+(
+ a DATE NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES ('2001-01-01');
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+
+--echo #
+--echo # Testing FLOAT
+--echo #
+CREATE TABLE t1
+(
+ a FLOAT(12,4) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (123);
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+#
+# TODO: this return error:
+# Got error 122 'Value 123.0000000000 too long for column a of length 12'
+# from CONNECT
+#
+#CREATE TABLE t1
+#(
+# a FLOAT NOT NULL
+#) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+#--error ER_GET_ERRMSG - why this error?
+#INSERT INTO t1 VALUES (123);
+#SELECT * FROM t1;
+#DROP TABLE IF EXISTS t1;
+#--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+#
+# TODO: this creates a column of type 'D' (date), which is wrong
+#
+#--echo #
+#--echo # Testing DATETIME
+#--echo #
+#CREATE TABLE t1
+#(
+# a DATETIME NOT NULL
+#) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+#INSERT INTO t1 VALUES ('2013-02-01');
+#SELECT * FROM t1;
+#DROP TABLE t1;
+#--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+#
+# TODO: this creates a column of type 'D' (date), which is wrong
+#
+#--echo #
+#--echo # Testing TIMESTAMP
+#--echo #
+#CREATE TABLE t1
+#(
+# a TIMESTAMP
+#) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+#INSERT INTO t1 VALUES ('2013-02-01');
+#SELECT * FROM t1;
+#DROP TABLE t1;
+#--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing double
+--echo #
+CREATE TABLE t1
+(
+ a DOUBLE(20,5) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (123);
+INSERT INTO t1 VALUES (123456789.12345);
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE IF EXISTS t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+# TODO:
+# Testing with no FILE_NAME specified
+# Currently it returns:
+# ERROR 1296 (HY000): Got error 174 'Open(a+) error 21
+# on /opt/mariadb-5.5/data/: Is a directory' from CONNECT
+#CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=DBF;
+
+--echo #
+--echo # Testing ALTER
+--echo #
+CREATE TABLE t1
+(
+ a VARCHAR(10) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES ('10');
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+ALTER TABLE t1 MODIFY a VARCHAR(10) NOT NULL;
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+ALTER TABLE t1 MODIFY a INT(10) NOT NULL;
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+
+# TODO: this does not work on Windows
+#ALTER TABLE t1 MODIFY a INT(8) NOT NULL;
+#SHOW CREATE TABLE t1;
+#--error ER_GET_ERRMSG
+#SELECT * FROM t1;
+#--vertical_results
+#--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+#eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+#--horizontal_results
+DROP TABLE IF EXISTS t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing NULL
+--echo #
+# TODO: NULLs should probably change to DEFAULT and produce a warning
+CREATE TABLE t1
+(
+ c1 VARCHAR(10) NOT NULL,
+ c2 VARCHAR(10) NOT NULL DEFAULT 'def',
+ i1 INT NOT NULL,
+ i2 INT NOT NULL DEFAULT 123
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES ('10','10',10,10);
+#INSERT INTO t1 VALUES (NULL,NULL,NULL,NULL);
+INSERT INTO t1(c1,i1) VALUES ('20',20);
+INSERT INTO t1 VALUES ('30',DEFAULT,30,DEFAULT);
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE IF EXISTS t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+DROP PROCEDURE test.dbf_field;
+DROP PROCEDURE test.dbf_header;
diff --git a/storage/connect/mysql-test/connect/t/fix.test b/storage/connect/mysql-test/connect/t/fix.test
index c3cec55a217..15e642a85fd 100644
--- a/storage/connect/mysql-test/connect/t/fix.test
+++ b/storage/connect/mysql-test/connect/t/fix.test
@@ -1,108 +1,108 @@
-let $MYSQLD_DATADIR= `select @@datadir`;
-
---copy_file $MTR_SUITE_DIR/std_data/dept.dat $MYSQLD_DATADIR/test/dept.dat
---copy_file $MTR_SUITE_DIR/std_data/boys.txt $MYSQLD_DATADIR/test/boys.txt
---copy_file $MTR_SUITE_DIR/std_data/boyswin.txt $MYSQLD_DATADIR/test/boyswin.txt
-
---echo #
---echo # Testing errors
---echo #
-CREATE TABLE t1
-(
- ID INT NOT NULL
-) Engine=CONNECT TABLE_TYPE=DOS FILE_NAME='nonexistent.txt';
---replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
-# TODO: check why this is needed for Windows
---replace_result Open(rt) Open(rb)
-SELECT * FROM t1;
-DROP TABLE t1;
-
---echo #
---echo # Testing READONLY tables
---echo #
-CREATE TABLE t1
-(
- id INT NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='t1.txt';
-INSERT INTO t1 VALUES (10);
-SELECT * FROM t1;
-ALTER TABLE t1 READONLY=1;
-SHOW CREATE TABLE t1;
---error ER_GET_ERRMSG
-INSERT INTO t1 VALUES (20);
---error ER_GET_ERRMSG
-UPDATE t1 SET id=20 WHERE id=10;
---error ER_GET_ERRMSG
-DELETE FROM t1 WHERE id=10;
---error ER_GET_ERRMSG
-TRUNCATE TABLE t1;
-ALTER TABLE t1 READONLY=0;
-SHOW CREATE TABLE t1;
-INSERT INTO t1 VALUES (20);
-SELECT * FROM t1;
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1.txt
-
-
---echo #
---echo # Testing manual examples
---echo #
-CREATE TABLE t1
-(
- number CHAR(4) not null,
- location CHAR(15) NOT NULL flag=5,
- director CHAR(5) NOT NULL flag=20,
- function CHAR(12) NOT NULL flag=26,
- name CHAR(22) NOT NULL flag=38
-) ENGINE=CONNECT TABLE_TYPE=DOS FILE_NAME='dept.dat';
-SELECT * FROM t1;
-DROP TABLE t1;
-
-CREATE TABLE t1
-(
- name char(12) not null,
- city char(12) not null,
- birth date not null date_format='DD/MM/YYYY',
- hired date not null date_format='DD/MM/YYYY' flag=36
-) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boys.txt' ENDING=1;
-SELECT * FROM t1;
-DROP TABLE t1;
-
-CREATE TABLE t1
-(
- name char(12) not null,
- city char(12) not null,
- birth date not null date_format='DD/MM/YYYY',
- hired date not null date_format='DD/MM/YYYY' flag=36
-) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boys.txt' LRECL=47 ENDING=1;
-SELECT * FROM t1;
-DROP TABLE t1;
-
-
-CREATE TABLE t1
-(
- name char(12) not null,
- city char(12) not null,
- birth date not null date_format='DD/MM/YYYY',
- hired date not null date_format='DD/MM/YYYY' flag=36
-) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boyswin.txt' ENDING=2;
-SELECT * FROM t1;
-DROP TABLE t1;
-
-CREATE TABLE t1
-(
- name char(12) not null,
- city char(12) not null,
- birth date not null date_format='DD/MM/YYYY',
- hired date not null date_format='DD/MM/YYYY' flag=36
-) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boyswin.txt' LRECL=47 ENDING=2;
-SELECT * FROM t1;
-DROP TABLE t1;
-
-
-#
-# Clean up
-#
---remove_file $MYSQLD_DATADIR/test/dept.dat
---remove_file $MYSQLD_DATADIR/test/boys.txt
---remove_file $MYSQLD_DATADIR/test/boyswin.txt
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/dept.dat $MYSQLD_DATADIR/test/dept.dat
+--copy_file $MTR_SUITE_DIR/std_data/boys.txt $MYSQLD_DATADIR/test/boys.txt
+--copy_file $MTR_SUITE_DIR/std_data/boyswin.txt $MYSQLD_DATADIR/test/boyswin.txt
+
+--echo #
+--echo # Testing errors
+--echo #
+CREATE TABLE t1
+(
+ ID INT NOT NULL
+) Engine=CONNECT TABLE_TYPE=DOS FILE_NAME='nonexistent.txt';
+--replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
+# TODO: check why this is needed for Windows
+--replace_result Open(rt) Open(rb)
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing READONLY tables
+--echo #
+CREATE TABLE t1
+(
+ id INT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='t1.txt';
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+ALTER TABLE t1 READONLY=1;
+SHOW CREATE TABLE t1;
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES (20);
+--error ER_OPEN_AS_READONLY
+UPDATE t1 SET id=20 WHERE id=10;
+--error ER_OPEN_AS_READONLY
+DELETE FROM t1 WHERE id=10;
+--error ER_OPEN_AS_READONLY
+TRUNCATE TABLE t1;
+ALTER TABLE t1 READONLY=0;
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES (20);
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.txt
+
+
+--echo #
+--echo # Testing manual examples
+--echo #
+CREATE TABLE t1
+(
+ number CHAR(4) not null,
+ location CHAR(15) NOT NULL flag=5,
+ director CHAR(5) NOT NULL flag=20,
+ function CHAR(12) NOT NULL flag=26,
+ name CHAR(22) NOT NULL flag=38
+) ENGINE=CONNECT TABLE_TYPE=DOS FILE_NAME='dept.dat';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1
+(
+ name char(12) not null,
+ city char(12) not null,
+ birth date not null date_format='DD/MM/YYYY',
+ hired date not null date_format='DD/MM/YYYY' flag=36
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boys.txt' ENDING=1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1
+(
+ name char(12) not null,
+ city char(12) not null,
+ birth date not null date_format='DD/MM/YYYY',
+ hired date not null date_format='DD/MM/YYYY' flag=36
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boys.txt' LRECL=47 ENDING=1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1
+(
+ name char(12) not null,
+ city char(12) not null,
+ birth date not null date_format='DD/MM/YYYY',
+ hired date not null date_format='DD/MM/YYYY' flag=36
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boyswin.txt' ENDING=2;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1
+(
+ name char(12) not null,
+ city char(12) not null,
+ birth date not null date_format='DD/MM/YYYY',
+ hired date not null date_format='DD/MM/YYYY' flag=36
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boyswin.txt' LRECL=47 ENDING=2;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/dept.dat
+--remove_file $MYSQLD_DATADIR/test/boys.txt
+--remove_file $MYSQLD_DATADIR/test/boyswin.txt
diff --git a/storage/connect/mysql-test/connect/t/ini.test b/storage/connect/mysql-test/connect/t/ini.test
index 0d23142ac9e..dd3b84e4699 100644
--- a/storage/connect/mysql-test/connect/t/ini.test
+++ b/storage/connect/mysql-test/connect/t/ini.test
@@ -1,156 +1,156 @@
-let $MYSQLD_DATADIR= `select @@datadir`;
-
---copy_file $MTR_SUITE_DIR/std_data/contact.ini $MYSQLD_DATADIR/test/contact.ini
-
---echo #
---echo # Testing errors
---echo #
-CREATE TABLE t1
-(
- ID INT
-) Engine=CONNECT TABLE_TYPE=INI FILE_NAME='nonexistent.txt';
---replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
-# TODO: check why this is needed for Windows
---replace_result Open(rt) Open(rb)
-SELECT * FROM t1;
-DROP TABLE t1;
-
---echo #
---echo # Testing examples from the manual
---echo #
-
-CREATE TABLE t1
-(
- contact CHAR(16) flag=1,
- name CHAR(20),
- forename CHAR(32),
- hired date date_format='DD/MM/YYYY',
- address CHAR(64),
- city CHAR(20),
- zipcode CHAR(8),
- tel CHAR(16)
-) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='contact.ini';
-SELECT contact, name, hired, city, tel FROM t1;
-
-UPDATE t1 SET forename= 'Harry' where contact='UK1';
-SELECT * FROM t1 WHERE contact='UK1';
-INSERT INTO t1 (contact,forename) VALUES ('UK1','Harrison');
-SELECT * FROM t1 WHERE contact='UK1';
-INSERT INTO t1 (contact,forename) VALUES ('UK2','John');
-SELECT * FROM t1 WHERE contact='UK2';
-DROP TABLE t1;
---chmod 0777 $MYSQLD_DATADIR/test/contact.ini
---replace_result $MYSQLD_DATADIR DATADIR
---eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/contact.ini'),'\r\n','\n'),'\n\n','\n');
-
-CREATE TABLE t1
-(
- section CHAR(16) flag=1,
- keyname CHAR(16) flag=2,
- value CHAR(32)
-) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='contact.ini'
- OPTION_LIST='Layout=Row';
-UPDATE t1 SET value='Paul' WHERE section='UK2' AND keyname='forename';
-SELECT * FROM t1;
-DROP TABLE t1;
---chmod 0777 $MYSQLD_DATADIR/test/contact.ini
---replace_result $MYSQLD_DATADIR DATADIR
---eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/contact.ini'),'\r\n','\n'),'\n\n','\n');
-
-
---echo #
---echo # Testing that the underlying file is created
---echo #
-CREATE TABLE t1
-(
- contact CHAR(12) NOT NULL flag=1,
- c2 CHAR(12) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='tmp.ini';
-INSERT INTO t1 VALUES (10,10),(20,20),(300,300),(4000,4000), ('a b','c d');
-SELECT * FROM t1;
-DROP TABLE t1;
---chmod 0777 $MYSQLD_DATADIR/test/tmp.ini
---replace_result $MYSQLD_DATADIR DATADIR
---eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/tmp.ini'),'\r\n','\n'),'\n\n','\n');
-
-
---echo #
---echo # Testing bad table
---echo #
-CREATE TABLE t1
-(
- id INT
-) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.ini';
---error ER_GET_ERRMSG
-INSERT INTO t1 VALUES (10);
-SELECT * FROM t1;
-DROP TABLE t1;
-
-
---echo #
---echo # Testing READONLY tables
---echo #
-CREATE TABLE t1
-(
- contact CHAR(10) flag=1,
- c2 CHAR(60)
-) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.ini';
-INSERT INTO t1 VALUES ('UK',10),('FR',20),('RU',30);
-SELECT * FROM t1;
-ALTER TABLE t1 READONLY=1;
-SHOW CREATE TABLE t1;
---error ER_GET_ERRMSG
-INSERT INTO t1 VALUES ('US',40);
---error ER_GET_ERRMSG
-UPDATE t1 SET c2=20 WHERE c2=10;
---error ER_GET_ERRMSG
-DELETE FROM t1 WHERE c2=10;
---error ER_GET_ERRMSG
-TRUNCATE TABLE t1;
-ALTER TABLE t1 READONLY=0;
-SHOW CREATE TABLE t1;
-INSERT INTO t1 VALUES ('US',40);
-SELECT * FROM t1;
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1.ini
-
-
-#
-# Clean up
-#
---remove_file $MYSQLD_DATADIR/test/contact.ini
---remove_file $MYSQLD_DATADIR/test/tmp.ini
-
-
---echo #
---echo # Bug: TABLE_TYPE=ini does not clear memory between CREATE TABLEs
---echo #
-CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL)
-ENGINE=CONNECT TABLE_TYPE=INI;
-INSERT INTO t1 VALUES ('sec1','val1'),('sec2','val2');
-SELECT sec AS s, val AS v FROM t1;
-DROP TABLE t1;
-CREATE TABLE t1 (sec2 CHAR(10) NOT NULL FLAG=1, val2 CHAR(10) NOT NULL)
-ENGINE=CONNECT TABLE_TYPE=INI;
-INSERT INTO t1 VALUES ('sec1','val11'),('sec2','val22');
-SELECT sec2 AS s, val2 AS v FROM t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.ini
---replace_result $MYSQLD_DATADIR DATADIR
---eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.ini'),'\r\n','\n'),'\n\n','\n');
-DROP TABLE t1;
-
-CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL)
-ENGINE=CONNECT TABLE_TYPE=INI;
-CREATE TABLE t2 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL)
-ENGINE=CONNECT TABLE_TYPE=INI;
-INSERT INTO t1 VALUES('1sec1','1val1'),('1sec2','1val2');
-INSERT INTO t2 VALUES('2sec1','2val1'),('2sec2','2val2');
-SELECT sec AS s, val AS v FROM t1;
---chmod 0777 $MYSQLD_DATADIR/test/t1.ini
---replace_result $MYSQLD_DATADIR DATADIR
---eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.ini'),'\r\n','\n'),'\n\n','\n');
-SELECT sec AS s, val AS v FROM t2;
---chmod 0777 $MYSQLD_DATADIR/test/t2.ini
---replace_result $MYSQLD_DATADIR DATADIR
---eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t2.ini'),'\r\n','\n'),'\n\n','\n');
-DROP TABLE t1, t2;
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/contact.ini $MYSQLD_DATADIR/test/contact.ini
+
+--echo #
+--echo # Testing errors
+--echo #
+CREATE TABLE t1
+(
+ ID INT
+) Engine=CONNECT TABLE_TYPE=INI FILE_NAME='nonexistent.txt';
+--replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
+# TODO: check why this is needed for Windows
+--replace_result Open(rt) Open(rb)
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing examples from the manual
+--echo #
+
+CREATE TABLE t1
+(
+ contact CHAR(16) flag=1,
+ name CHAR(20),
+ forename CHAR(32),
+ hired date date_format='DD/MM/YYYY',
+ address CHAR(64),
+ city CHAR(20),
+ zipcode CHAR(8),
+ tel CHAR(16)
+) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='contact.ini';
+SELECT contact, name, hired, city, tel FROM t1;
+
+UPDATE t1 SET forename= 'Harry' where contact='UK1';
+SELECT * FROM t1 WHERE contact='UK1';
+INSERT INTO t1 (contact,forename) VALUES ('UK1','Harrison');
+SELECT * FROM t1 WHERE contact='UK1';
+INSERT INTO t1 (contact,forename) VALUES ('UK2','John');
+SELECT * FROM t1 WHERE contact='UK2';
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/contact.ini
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/contact.ini'),'\r\n','\n'),'\n\n','\n');
+
+CREATE TABLE t1
+(
+ section CHAR(16) flag=1,
+ keyname CHAR(16) flag=2,
+ value CHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='contact.ini'
+ OPTION_LIST='Layout=Row';
+UPDATE t1 SET value='Paul' WHERE section='UK2' AND keyname='forename';
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/contact.ini
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/contact.ini'),'\r\n','\n'),'\n\n','\n');
+
+
+--echo #
+--echo # Testing that the underlying file is created
+--echo #
+CREATE TABLE t1
+(
+ contact CHAR(12) NOT NULL flag=1,
+ c2 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='tmp.ini';
+INSERT INTO t1 VALUES (10,10),(20,20),(300,300),(4000,4000), ('a b','c d');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/tmp.ini
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/tmp.ini'),'\r\n','\n'),'\n\n','\n');
+
+
+--echo #
+--echo # Testing bad table
+--echo #
+CREATE TABLE t1
+(
+ id INT
+) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.ini';
+--error ER_GET_ERRMSG
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing READONLY tables
+--echo #
+CREATE TABLE t1
+(
+ contact CHAR(10) flag=1,
+ c2 CHAR(60)
+) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.ini';
+INSERT INTO t1 VALUES ('UK',10),('FR',20),('RU',30);
+SELECT * FROM t1;
+ALTER TABLE t1 READONLY=1;
+SHOW CREATE TABLE t1;
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES ('US',40);
+--error ER_OPEN_AS_READONLY
+UPDATE t1 SET c2=20 WHERE c2=10;
+--error ER_OPEN_AS_READONLY
+DELETE FROM t1 WHERE c2=10;
+--error ER_OPEN_AS_READONLY
+TRUNCATE TABLE t1;
+ALTER TABLE t1 READONLY=0;
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES ('US',40);
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.ini
+
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/contact.ini
+--remove_file $MYSQLD_DATADIR/test/tmp.ini
+
+
+--echo #
+--echo # Bug: TABLE_TYPE=ini does not clear memory between CREATE TABLEs
+--echo #
+CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=INI;
+INSERT INTO t1 VALUES ('sec1','val1'),('sec2','val2');
+SELECT sec AS s, val AS v FROM t1;
+DROP TABLE t1;
+CREATE TABLE t1 (sec2 CHAR(10) NOT NULL FLAG=1, val2 CHAR(10) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=INI;
+INSERT INTO t1 VALUES ('sec1','val11'),('sec2','val22');
+SELECT sec2 AS s, val2 AS v FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.ini
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.ini'),'\r\n','\n'),'\n\n','\n');
+DROP TABLE t1;
+
+CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=INI;
+CREATE TABLE t2 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=INI;
+INSERT INTO t1 VALUES('1sec1','1val1'),('1sec2','1val2');
+INSERT INTO t2 VALUES('2sec1','2val1'),('2sec2','2val2');
+SELECT sec AS s, val AS v FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.ini
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.ini'),'\r\n','\n'),'\n\n','\n');
+SELECT sec AS s, val AS v FROM t2;
+--chmod 0777 $MYSQLD_DATADIR/test/t2.ini
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t2.ini'),'\r\n','\n'),'\n\n','\n');
+DROP TABLE t1, t2;
diff --git a/storage/connect/mysql-test/connect/t/myconn.inc b/storage/connect/mysql-test/connect/t/myconn.inc
new file mode 100644
index 00000000000..bdd60687d87
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/myconn.inc
@@ -0,0 +1,27 @@
+--source include/not_embedded.inc
+
+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
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/tx1';
+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
+
+connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,);
+connect (slave,127.0.0.1,root,,test,$SLAVE_MYPORT,);
+
+connection master;
+CREATE DATABASE connect;
+
+connection slave;
+CREATE DATABASE connect;
diff --git a/storage/connect/mysql-test/connect/t/myconn_cleanup.inc b/storage/connect/mysql-test/connect/t/myconn_cleanup.inc
new file mode 100644
index 00000000000..ba2d99ed8b4
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/myconn_cleanup.inc
@@ -0,0 +1,9 @@
+connection master;
+--disable_warnings
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
+
+connection slave;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
+--enable_warnings
diff --git a/storage/connect/mysql-test/connect/t/mysql_discovery.test b/storage/connect/mysql-test/connect/t/mysql_discovery.test
new file mode 100644
index 00000000000..057244a2a97
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mysql_discovery.test
@@ -0,0 +1,33 @@
+-- source myconn.inc
+
+connection slave;
+
+CREATE TABLE t1 (
+ `id` int(20) primary key,
+ `group` int NOT NULL default 1,
+ `a\\b` int NOT NULL default 2,
+ `a\\` int unsigned,
+ `name` varchar(32) default 'name')
+ DEFAULT CHARSET=latin1;
+
+connection master;
+
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
+
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+INSERT INTO t1 (id, name) VALUES (1, 'foo');
+INSERT INTO t1 (id, name) VALUES (2, 'fee');
+--sorted_result
+SELECT * FROM t1;
+DROP TABLE t1;
+
+connection slave;
+--sorted_result
+SELECT * FROM t1;
+DROP TABLE t1;
+
+-- source myconn_cleanup.inc
+
diff --git a/storage/connect/mysql-test/connect/t/mysql_exec.test b/storage/connect/mysql-test/connect/t/mysql_exec.test
new file mode 100644
index 00000000000..e56072a63e1
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mysql_exec.test
@@ -0,0 +1,45 @@
+-- source myconn.inc
+
+--echo #
+--echo # Checking Sending Commands
+--echo #
+connection master;
+
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (
+ command VARCHAR(128) NOT NULL,
+ warnings INT(4) NOT NULL FLAG=3,
+ number INT(5) NOT NULL FLAG=1,
+ message VARCHAR(255) FLAG=2)
+ ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test' OPTION_LIST='Execsrc=1,maxerr=2';
+
+SELECT * FROM t1 WHERE command IN ('Warning','Note',
+ 'drop table if exists t1',
+ 'create table t1 (id int key auto_increment, msg varchar(32) not null)',
+ "insert into t1(msg) values('One'),(NULL),('Three')",
+ "insert into t1 values(2,'Deux') on duplicate key update msg = 'Two'",
+ "insert into t1(message) values('Four'),('Five'),('Six')",
+ 'insert into t1(id) values(NULL)',
+ "update t1 set msg = 'Four' where id = 4",
+ 'select * from t1');
+
+--echo #
+--echo # Checking Using Procedure
+--echo #
+DROP PROCEDURE IF EXISTS p1;
+CREATE PROCEDURE p1(cmd varchar(512))
+ READS SQL DATA
+ SELECT * FROM t1 WHERE command IN ('Warning','Note',cmd);
+
+CALL p1('insert into t1(id) values(NULL)');
+CALL p1('update t1 set msg = "Five" where id = 5');
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+connection slave;
+--sorted_result
+SELECT * FROM t1;
+DROP TABLE t1;
+
+-- source myconn_cleanup.inc
+
diff --git a/storage/connect/mysql-test/connect/t/mysql_new.test b/storage/connect/mysql-test/connect/t/mysql_new.test
new file mode 100644
index 00000000000..08f27b6b19b
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mysql_new.test
@@ -0,0 +1,325 @@
+-- source myconn.inc
+
+#
+# This test is run against a remote MySQL server
+#
+
+connection slave;
+
+CREATE TABLE t1 (a int, b char(10));
+INSERT INTO t1 VALUES (NULL,NULL),(0,'test00'),(1,'test01'),(2,'test02'),(3,'test03');
+SELECT * FROM t1;
+
+--echo #
+--echo # Testing errors
+--echo #
+connection master;
+
+# Bad user name
+# Suppress "mysql_real_connect failed:" (printed in _DEBUG build)
+--replace_result $SLAVE_MYPORT SLAVE_PORT "mysql_real_connect failed: " ""
+--error ER_UNKNOWN_ERROR
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://unknown@127.0.0.1:$SLAVE_MYPORT/test/t1';
+
+# Bad database name
+--replace_result $SLAVE_MYPORT SLAVE_PORT "mysql_real_connect failed: " ""
+--error ER_UNKNOWN_ERROR
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/unknown/t1';
+
+# Bad database name, with OPTION_LIST going first.
+--replace_result $SLAVE_MYPORT SLAVE_PORT "mysql_real_connect failed: " ""
+--error ER_UNKNOWN_ERROR
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT' DBNAME='unknown' TABNAME='t1';
+
+# Bad table name
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+--error ER_UNKNOWN_ERROR
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/unknown';
+--error ER_NO_SUCH_TABLE
+SHOW CREATE TABLE t1;
+
+# Bad column name
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (x int, y char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+--error ER_GET_ERRMSG
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# The remote table disappeared
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
+
+connection slave;
+ALTER TABLE t1 RENAME t1backup;
+
+connection master;
+--error ER_GET_ERRMSG
+SELECT * FROM t1;
+
+connection slave;
+ALTER TABLE t1backup RENAME t1;
+
+connection master;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing SELECT, etc.
+--echo #
+
+# Automatic table structure
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Explicit table structure
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1'
+ OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Explicit table structure: remote NULL, local NOT NULL
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (a INT NOT NULL, b CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=MYSQL
+ OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Explicit table structure with wrong column types
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (a char(10), b int) ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+connection slave;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing numeric data types
+--echo #
+
+# TODO: mediumint is converted to int, float is converted to double, decimal is converted to double
+CREATE TABLE t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float, g double, h decimal(20,5));
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES(100,3333,41235,1234567890,235000000000,3.14159265,3.14159265,3141.59265);
+
+connection master;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+connection slave;
+DROP TABLE t1;
+
+# TODO: unsigned does not work
+#CREATE TABLE t1 (a tinyint unsigned);
+#SHOW CREATE TABLE t1;
+
+#connection master;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT';
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1;
+
+#connection slave;
+#DROP TABLE t1;
+
+# TODO: add test for BIT
+
+--echo #
+--echo # Testing character data types
+--echo #
+
+CREATE TABLE t1 (a char(12), b varchar(12));
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES('Welcome','Hello, World');
+SELECT * FROM t1;
+
+connection master;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+connection slave;
+DROP TABLE t1;
+
+# TODO: ERROR 1105: Unsupported column type tinytext
+#CREATE TABLE t1 (a tinytext);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: ERROR 1105: Unsupported column type mediumtext
+#CREATE TABLE t1 (a mediumtext);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: text is converted to varchar(256)
+#CREATE TABLE t1 (a text);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: ERROR 1105: Unsupported column type longtext
+#CREATE TABLE t1 (a longtext);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+#TODO: add tests for ENUM
+#TODO: add tests for SET
+
+#--echo #
+#--echo # Testing binary data types
+#--echo #
+
+# TODO: ERROR 1105: Unsupported column type binary
+#CREATE TABLE t1 (a binary(10));
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: ERROR 1105: Unsupported column type varbinary
+#CREATE TABLE t1 (a varbinary(10));
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: ERROR 1105: Unsupported column type tinyblob
+#CREATE TABLE t1 (a tinyblob);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: ERROR 1105: Unsupported column type mediumblob
+#CREATE TABLE t1 (a mediumblob);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: blob is converted to varchar(256)
+#CREATE TABLE t1 (a blob);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: ERROR 1105: Unsupported column type longblob
+#CREATE TABLE t1 (a longblob);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: ERROR 1105: Unsupported column type geometry
+#CREATE TABLE t1 (a geometry);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+--echo #
+--echo # Testing temporal data types
+--echo #
+
+CREATE TABLE t1 (a date, b datetime, c time, d timestamp, e year);
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES('2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23');
+SELECT * FROM t1;
+
+connection master;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+connection slave;
+DROP TABLE t1;
+
+-- source myconn_cleanup.inc
+
diff --git a/storage/connect/mysql-test/connect/t/odbc_sqlite3.test b/storage/connect/mysql-test/connect/t/odbc_sqlite3.test
index 2705b4f47fb..ac28ec5a29b 100644
--- a/storage/connect/mysql-test/connect/t/odbc_sqlite3.test
+++ b/storage/connect/mysql-test/connect/t/odbc_sqlite3.test
@@ -67,3 +67,13 @@ SELECT * FROM v1;
DROP VIEW v1;
DROP TABLE t1;
+
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Columns TABNAME='t1' TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=$Database;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Tables TABNAME='t1' TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=$Database;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8
+SELECT * FROM t1;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/t/odbc_xls.test b/storage/connect/mysql-test/connect/t/odbc_xls.test
index 449d8983d63..1ae1382bae2 100644
--- a/storage/connect/mysql-test/connect/t/odbc_xls.test
+++ b/storage/connect/mysql-test/connect/t/odbc_xls.test
@@ -23,4 +23,17 @@ let $MYSQLD_DATADIR= `select @@datadir`;
SELECT Nom, Fonction FROM contact WHERE Repertoire='ascii';
DROP TABLE contact;
+
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Tables TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineXLS;DBQ=$MYSQLD_DATADIR/test/contacts.xls' CHARSET=utf8 DATA_CHARSET=latin1;
+--replace_result $MYSQLD_DATADIR DATADIR
+SELECT * FROM t1 WHERE Table_name='CONTACT';
+DROP TABLE t1;
+
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Columns TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineXLS;DBQ=$MYSQLD_DATADIR/test/contacts.xls' CHARSET=utf8 DATA_CHARSET=latin1;
+--replace_result $MYSQLD_DATADIR DATADIR
+SELECT * FROM t1 WHERE Table_name='CONTACT' AND Column_name IN ('Nom','Fonction');
+DROP TABLE t1;
+
--remove_file $MYSQLD_DATADIR/test/contacts.xls
diff --git a/storage/connect/mysql-test/connect/t/vec.test b/storage/connect/mysql-test/connect/t/vec.test
index ee504e9925a..aca78987a97 100644
--- a/storage/connect/mysql-test/connect/t/vec.test
+++ b/storage/connect/mysql-test/connect/t/vec.test
@@ -1,80 +1,80 @@
-let $MYSQLD_DATADIR= `select @@datadir`;
-
-CREATE TABLE dir1 (
- spath VARCHAR(256) NOT NULL flag=1,
- fname VARCHAR(256) NOT NULL,
- ftype CHAR(4) NOT NULL,
- size DOUBLE(12,0) NOT NULL flag=5
-) ENGINE=CONNECT TABLE_TYPE=DIR FILE_NAME='*vec*';
-
-
-CREATE TABLE t1
-(
- a INT NOT NULL,
- b CHAR(10) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=VEC FILE_NAME='t1vec';
-SHOW CREATE TABLE t1;
-# Testing SELECT on empty file
---replace_regex /Open.rb. error 2 on .*\/test\/t1vec/Open(rb) error 2 on DATADIR\/test\/t1vec/
-SELECT * FROM t1;
-INSERT INTO t1 VALUES (0,'test01'), (1,'test01'), (2,'test02'), (3,'test03');
-SELECT * FROM t1;
-SELECT a FROM t1;
-SELECT b FROM t1;
---replace_result $MYSQLD_DATADIR DATADIR/
-SELECT fname, ftype, size FROM dir1 ORDER BY fname, ftype;
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1vec1
---remove_file $MYSQLD_DATADIR/test/t1vec2
-
-
-CREATE TABLE t1
-(
- a INT NOT NULL,
- b CHAR(10) NOT NULL
-) ENGINE=CONNECT TABLE_TYPE=VEC FILE_NAME='t1vec' MAX_ROWS=10;
-SHOW CREATE TABLE t1;
-# Testing SELECTs on empty file
---replace_regex /Open.rb. error 2 on .*\/test\/t1vec/Open(rb) error 2 on DATADIR\/test\/t1vec/
-SELECT * FROM t1;
---replace_regex /Open.rb. error 2 on .*\/test\/t1vec/Open(rb) error 2 on DATADIR\/test\/t1vec/
-SELECT a FROM t1;
---replace_regex /Open.rb. error 2 on .*\/test\/t1vec/Open(rb) error 2 on DATADIR\/test\/t1vec/
-SELECT b FROM t1;
-INSERT INTO t1 VALUES (0,'test01'), (1,'test01'), (2,'test02'), (3,'test03');
-SELECT * FROM t1;
-SELECT a FROM t1;
-SELECT b FROM t1;
---replace_result $MYSQLD_DATADIR DATADIR/
-SELECT fname, ftype, size FROM dir1 ORDER BY fname, ftype;
---echo #
---echo # Testing READONLY
---echo #
-ALTER TABLE t1 READONLY=yes;
-SHOW CREATE TABLE t1;
---error ER_GET_ERRMSG
-INSERT INTO t1 VALUES (4,'test04');
---error ER_GET_ERRMSG
-UPDATE t1 SET b='test04' WHERE a=3;
---error ER_GET_ERRMSG
-DELETE FROM t1 WHERE a=3;
---error ER_GET_ERRMSG
-TRUNCATE TABLE t1;
-ALTER TABLE t1 READONLY=no;
-SHOW CREATE TABLE t1;
-INSERT INTO t1 VALUES (4,'test04');
-UPDATE t1 SET b='test04a' WHERE a=4;
-DELETE FROM t1 WHERE a=0;
-SELECT * FROM t1;
-TRUNCATE TABLE t1;
-SELECT fname, ftype, size FROM dir1 ORDER BY fname, ftype;
-SELECT * FROM t1;
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1vec
---remove_file $MYSQLD_DATADIR/test/t1vec.blk
-
-
---echo #
---echo # Clean up
---echo #
-DROP TABLE dir1;
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+CREATE TABLE dir1 (
+ spath VARCHAR(256) NOT NULL flag=1,
+ fname VARCHAR(256) NOT NULL,
+ ftype CHAR(4) NOT NULL,
+ size DOUBLE(12,0) NOT NULL flag=5
+) ENGINE=CONNECT TABLE_TYPE=DIR FILE_NAME='*vec*';
+
+
+CREATE TABLE t1
+(
+ a INT NOT NULL,
+ b CHAR(10) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=VEC FILE_NAME='t1vec';
+SHOW CREATE TABLE t1;
+# Testing SELECT on empty file
+--replace_regex /Open.rb. error 2 on .*\/test\/t1vec/Open(rb) error 2 on DATADIR\/test\/t1vec/
+SELECT * FROM t1;
+INSERT INTO t1 VALUES (0,'test01'), (1,'test01'), (2,'test02'), (3,'test03');
+SELECT * FROM t1;
+SELECT a FROM t1;
+SELECT b FROM t1;
+--replace_result $MYSQLD_DATADIR DATADIR/
+SELECT fname, ftype, size FROM dir1 ORDER BY fname, ftype;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1vec1
+--remove_file $MYSQLD_DATADIR/test/t1vec2
+
+
+CREATE TABLE t1
+(
+ a INT NOT NULL,
+ b CHAR(10) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=VEC FILE_NAME='t1vec' MAX_ROWS=10;
+SHOW CREATE TABLE t1;
+# Testing SELECTs on empty file
+--replace_regex /Open.rb. error 2 on .*\/test\/t1vec/Open(rb) error 2 on DATADIR\/test\/t1vec/
+SELECT * FROM t1;
+--replace_regex /Open.rb. error 2 on .*\/test\/t1vec/Open(rb) error 2 on DATADIR\/test\/t1vec/
+SELECT a FROM t1;
+--replace_regex /Open.rb. error 2 on .*\/test\/t1vec/Open(rb) error 2 on DATADIR\/test\/t1vec/
+SELECT b FROM t1;
+INSERT INTO t1 VALUES (0,'test01'), (1,'test01'), (2,'test02'), (3,'test03');
+SELECT * FROM t1;
+SELECT a FROM t1;
+SELECT b FROM t1;
+--replace_result $MYSQLD_DATADIR DATADIR/
+SELECT fname, ftype, size FROM dir1 ORDER BY fname, ftype;
+--echo #
+--echo # Testing READONLY
+--echo #
+ALTER TABLE t1 READONLY=yes;
+SHOW CREATE TABLE t1;
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES (4,'test04');
+--error ER_OPEN_AS_READONLY
+UPDATE t1 SET b='test04' WHERE a=3;
+--error ER_OPEN_AS_READONLY
+DELETE FROM t1 WHERE a=3;
+--error ER_OPEN_AS_READONLY
+TRUNCATE TABLE t1;
+ALTER TABLE t1 READONLY=no;
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES (4,'test04');
+UPDATE t1 SET b='test04a' WHERE a=4;
+DELETE FROM t1 WHERE a=0;
+SELECT * FROM t1;
+TRUNCATE TABLE t1;
+SELECT fname, ftype, size FROM dir1 ORDER BY fname, ftype;
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1vec
+--remove_file $MYSQLD_DATADIR/test/t1vec.blk
+
+
+--echo #
+--echo # Clean up
+--echo #
+DROP TABLE dir1;
diff --git a/storage/connect/myutil.cpp b/storage/connect/myutil.cpp
index b266b7b79c1..1b6cbaa84c7 100644
--- a/storage/connect/myutil.cpp
+++ b/storage/connect/myutil.cpp
@@ -29,7 +29,7 @@
/************************************************************************/
/* Convert from MySQL type name to PlugDB type number */
/************************************************************************/
-int MYSQLtoPLG(char *typname)
+int MYSQLtoPLG(char *typname, char *var)
{
int type;
@@ -56,6 +56,28 @@ int MYSQLtoPLG(char *typname)
else
type = TYPE_ERROR;
+ if (var) {
+ // This is to make the difference between CHAR and VARCHAR
+ if (type == TYPE_STRING && stricmp(typname, "char"))
+ *var = 'V';
+
+ // This is to make the difference between temporal values
+ if (type == TYPE_DATE) {
+ if (!stricmp(typname, "date"))
+ *var = 'D';
+ else if (!stricmp(typname, "datetime"))
+ *var = 'A';
+ else if (!stricmp(typname, "timestamp"))
+ *var = 'S';
+ else if (!stricmp(typname, "time"))
+ *var = 'T';
+ else if (!stricmp(typname, "year"))
+ *var = 'Y';
+
+ } // endif type
+
+ } // endif var
+
return type;
} // end of MYSQLtoPLG
@@ -98,14 +120,18 @@ enum enum_field_types PLGtoMYSQL(int type, bool dbf)
/************************************************************************/
/* Convert from PlugDB type to MySQL type name */
/************************************************************************/
-const char *PLGtoMYSQLtype(int type, bool dbf)
+const char *PLGtoMYSQLtype(int type, bool dbf, char v)
{
switch (type) {
case TYPE_INT: return "INT";
case TYPE_SHORT: return "SMALLINT";
case TYPE_FLOAT: return "DOUBLE";
- case TYPE_DATE: return dbf ? "DATE" : "DATETIME";
- case TYPE_STRING: return "VARCHAR";
+ case TYPE_DATE: return dbf ? "DATE" :
+ (v == 'S') ? "TIMESTAMP" :
+ (v == 'D') ? "DATE" :
+ (v == 'T') ? "TIME" :
+ (v == 'Y') ? "YEAR" : "DATETIME";
+ case TYPE_STRING: return v ? "VARCHAR" : "CHAR";
case TYPE_BIGINT: return "BIGINT";
case TYPE_TINY: return "TINYINT";
default: return "CHAR(0)";
diff --git a/storage/connect/myutil.h b/storage/connect/myutil.h
index 7ddfcbe599c..46f060e3e17 100644
--- a/storage/connect/myutil.h
+++ b/storage/connect/myutil.h
@@ -1,9 +1,14 @@
/***********************************************************************/
/* Prototypes of Functions used externally. */
/***********************************************************************/
+#ifndef __MYUTIL__H
+#define __MYUTIL__H
+
enum enum_field_types PLGtoMYSQL(int type, bool dbf);
-const char *PLGtoMYSQLtype(int type, bool dbf);
-int MYSQLtoPLG(char *typname);
+const char *PLGtoMYSQLtype(int type, bool dbf, char var = NULL);
+int MYSQLtoPLG(char *typname, char *var = NULL);
int MYSQLtoPLG(int mytype);
char *MyDateFmt(int mytype);
char *MyDateFmt(char *typname);
+
+#endif // __MYUTIL__H
diff --git a/storage/connect/odbccat.h b/storage/connect/odbccat.h
index ba4074bf276..1c89334f5a9 100644
--- a/storage/connect/odbccat.h
+++ b/storage/connect/odbccat.h
@@ -1,7 +1,9 @@
/***********************************************************************/
/* ODBC catalog function prototypes. */
/***********************************************************************/
+#if defined(PROMPT_OK)
char *ODBCCheckConnection(PGLOBAL g, char *dsn, int cop);
+#endif // PROMPT_OK
PQRYRES ODBCDataSources(PGLOBAL g, bool info);
PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table,
char *colpat, bool info);
diff --git a/storage/connect/odbconn.cpp b/storage/connect/odbconn.cpp
index 0a19d90a422..78731cee22c 100644
--- a/storage/connect/odbconn.cpp
+++ b/storage/connect/odbconn.cpp
@@ -108,16 +108,18 @@ static int GetSQLCType(int type)
/***********************************************************************/
/* TranslateSQLType: translate a SQL Type to a PLG type. */
/***********************************************************************/
-int TranslateSQLType(int stp, int prec, int& len)
+int TranslateSQLType(int stp, int prec, int& len, char& v)
{
int type;
switch (stp) {
- case SQL_CHAR: // 1
case SQL_VARCHAR: // 12
+ v = 'V';
+ case SQL_CHAR: // 1
type = TYPE_STRING;
break;
case SQL_LONGVARCHAR: // (-1)
+ v = 'V';
type = TYPE_STRING;
len = min(abs(len), 255);
break;
@@ -172,6 +174,7 @@ int TranslateSQLType(int stp, int prec, int& len)
return type;
} // end of TranslateSQLType
+#if defined(PROMPT_OK)
/***********************************************************************/
/* ODBCCheckConnection: Check completeness of connection string. */
/***********************************************************************/
@@ -203,6 +206,7 @@ char *ODBCCheckConnection(PGLOBAL g, char *dsn, int cop)
ocp->Close();
return newdsn; // Return complete connection string
} // end of ODBCCheckConnection
+#endif // PROMPT_OK
/***********************************************************************/
/* Allocate the structure used to refer to the result set. */
@@ -871,7 +875,8 @@ ODBConn::ODBConn(PGLOBAL g, TDBODBC *tdbp)
m_Connect = NULL;
m_Updatable = true;
m_Transact = false;
- m_IDQuoteChar = '\'';
+ m_IDQuoteChar[0] = '"';
+ m_IDQuoteChar[1] = 0;
//*m_ErrMsg = '\0';
} // end of ODBConn
@@ -889,7 +894,7 @@ bool ODBConn::Check(RETCODE rc)
{
switch (rc) {
case SQL_SUCCESS_WITH_INFO:
- if (trace > 1) {
+ if (trace) {
DBX x(rc);
x.BuildErrorMessage(this, m_hstmt);
@@ -1113,7 +1118,7 @@ bool ODBConn::Connect(DWORD Options)
if (hWnd == NULL)
hWnd = GetDesktopWindow();
#else // !WIN32
- HWND hWnd = 1;
+ HWND hWnd = (HWND)1;
#endif // !WIN32
PGLOBAL& g = m_G;
PDBUSER dup = PlgGetUser(g);
@@ -1230,20 +1235,13 @@ void ODBConn::GetConnectInfo()
SQL_MODE_READ_ONLY);
#endif // 0
- // Cache the quote char to use when constructing SQL
- char QuoteChar[2];
-
+ // Get the quote char to use when constructing SQL
rc = SQLGetInfo(m_hdbc, SQL_IDENTIFIER_QUOTE_CHAR,
- QuoteChar, sizeof(QuoteChar), &nResult);
-
- if (Check(rc) && nResult == 1)
- m_IDQuoteChar = QuoteChar[0];
- else
- m_IDQuoteChar = ' ';
+ m_IDQuoteChar, sizeof(m_IDQuoteChar), &nResult);
if (trace)
- htrc("DBMS: %s, Version: %s",
- GetStringInfo(SQL_DBMS_NAME), GetStringInfo(SQL_DBMS_VER));
+ htrc("DBMS: %s, Version: %s, rc=%d\n",
+ GetStringInfo(SQL_DBMS_NAME), GetStringInfo(SQL_DBMS_VER), rc);
} // end of GetConnectInfo
@@ -1511,14 +1509,16 @@ int ODBConn::PrepareSQL(char *sql)
hstmt = m_hstmt;
m_hstmt = NULL;
- ThrowDBX(MSG(SEQUENCE_ERROR));
- } else {
- rc = SQLAllocStmt(m_hdbc, &hstmt);
- if (!Check(rc))
- ThrowDBX(SQL_INVALID_HANDLE, "SQLAllocStmt");
+ if (m_Tdb->GetAmType() != TYPE_AM_XDBC)
+ ThrowDBX(MSG(SEQUENCE_ERROR));
- } // endif hstmt
+ } // endif m_hstmt
+
+ rc = SQLAllocStmt(m_hdbc, &hstmt);
+
+ if (!Check(rc))
+ ThrowDBX(SQL_INVALID_HANDLE, "SQLAllocStmt");
OnSetOptions(hstmt);
b = true;
@@ -1565,7 +1565,7 @@ int ODBConn::PrepareSQL(char *sql)
/***********************************************************************/
/* Execute a prepared statement. */
/***********************************************************************/
-int ODBConn::ExecuteSQL(bool x)
+int ODBConn::ExecuteSQL(void)
{
PGLOBAL& g = m_G;
SWORD ncol = 0;
@@ -1580,26 +1580,17 @@ int ODBConn::ExecuteSQL(bool x)
if (!Check(rc))
ThrowDBX(rc, "SQLExecute", m_hstmt);
- if (!Check(SQLNumResultCols(m_hstmt, &ncol)))
+ if (!Check(rc = SQLNumResultCols(m_hstmt, &ncol)))
ThrowDBX(rc, "SQLNumResultCols", m_hstmt);
if (ncol) {
- if (x) {
- afrw = ncol;
- strcpy(g->Message, "Result set column number");
- } else {
- // This should never happen while inserting
- strcpy(g->Message, "Logical error while inserting");
- } // endif ncol
-
+ // This should never happen while inserting
+ strcpy(g->Message, "Logical error while inserting");
} else {
// Insert, Update or Delete statement
- if (!Check(SQLRowCount(m_hstmt, &afrw)))
+ if (!Check(rc = SQLRowCount(m_hstmt, &afrw)))
ThrowDBX(rc, "SQLRowCount", m_hstmt);
- if (x)
- strcpy(g->Message, "Affected rows");
-
} // endif ncol
} catch(DBX *x) {
@@ -1613,6 +1604,7 @@ int ODBConn::ExecuteSQL(bool x)
m_Transact = false;
} // endif m_Transact
+ afrw = -1;
} // end try/catch
return (int)afrw;
@@ -1667,6 +1659,112 @@ bool ODBConn::BindParam(ODBCCOL *colp)
return false;
} // end of BindParam
+/***********************************************************************/
+/* Execute an SQL command. */
+/***********************************************************************/
+bool ODBConn::ExecSQLcommand(char *sql)
+ {
+ char cmd[16];
+ bool b, rcd = false;
+ UINT txn = 0;
+ PGLOBAL& g = m_G;
+ SWORD ncol = 0;
+ SQLLEN afrw;
+ RETCODE rc;
+ HSTMT hstmt;
+
+ try {
+ b = FALSE;
+
+ // Check whether we should use transaction
+ if (sscanf(sql, " %15s ", cmd) == 1) {
+ if (!stricmp(cmd, "INSERT") || !stricmp(cmd, "UPDATE") ||
+ !stricmp(cmd, "DELETE") || !stricmp(cmd, "REPLACE")) {
+ // Does the data source support transactions
+ rc = SQLGetInfo(m_hdbc, SQL_TXN_CAPABLE, &txn, 0, NULL);
+
+ if (Check(rc) && txn != SQL_TC_NONE) {
+ rc = SQLSetConnectAttr(m_hdbc, SQL_ATTR_AUTOCOMMIT,
+ SQL_AUTOCOMMIT_OFF, SQL_IS_UINTEGER);
+
+ if (!Check(rc))
+ ThrowDBX(SQL_INVALID_HANDLE, "SQLSetConnectAttr");
+
+ m_Transact = TRUE;
+ } // endif txn
+
+ } // endif cmd
+
+ } // endif sql
+
+ // Allocate the statement handle
+ rc = SQLAllocStmt(m_hdbc, &hstmt);
+
+ if (!Check(rc))
+ ThrowDBX(SQL_INVALID_HANDLE, "SQLAllocStmt");
+
+ OnSetOptions(hstmt);
+ b = true;
+
+ if (trace)
+ htrc("ExecSQLcommand hstmt=%p %.64s\n", hstmt, sql);
+
+ // Proceed with command execution
+ do {
+ rc = SQLExecDirect(hstmt, (PUCHAR)sql, SQL_NTS);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLExecDirect", hstmt);
+
+ // Check whether this is a query returning a result set
+ if (!Check(rc = SQLNumResultCols(hstmt, &ncol)))
+ ThrowDBX(rc, "SQLNumResultCols", hstmt);
+
+ if (!ncol) {
+ if (!Check(SQLRowCount(hstmt, &afrw)))
+ ThrowDBX(rc, "SQLRowCount", hstmt);
+
+ m_Tdb->AftRows = (int)afrw;
+ strcpy(g->Message, "Affected rows");
+ } else {
+ m_Tdb->AftRows = (int)ncol;
+ strcpy(g->Message, "Result set column number");
+ } // endif ncol
+
+ } catch(DBX *x) {
+ if (trace)
+ for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
+ htrc(x->m_ErrMsg[i]);
+
+ sprintf(g->Message, "Remote: %s", x->GetErrorMessage(0));
+
+ if (b)
+ SQLCancel(hstmt);
+
+ m_Tdb->AftRows = -1;
+ rcd = true;
+ } // end try/catch
+
+ if (!Check(rc = SQLFreeStmt(hstmt, SQL_CLOSE)))
+ sprintf(g->Message, "SQLFreeStmt: rc=%d", rc);
+
+ if (m_Transact) {
+ // Terminate the transaction
+ if (!Check(rc = SQLEndTran(SQL_HANDLE_DBC, m_hdbc,
+ (rcd) ? SQL_ROLLBACK : SQL_COMMIT)))
+ sprintf(g->Message, "SQLEndTran: rc=%d", rc);
+
+ if (!Check(rc = SQLSetConnectAttr(m_hdbc, SQL_ATTR_AUTOCOMMIT,
+ (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_IS_UINTEGER)))
+ sprintf(g->Message, "SQLSetConnectAttr: rc=%d", rc);
+
+ m_Transact = false;
+ } // endif m_Transact
+
+ return rcd;
+ } // end of ExecSQLcommand
+
/**************************************************************************/
/* GetMetaData: constructs the result blocks containing the */
/* description of all the columns of an SQL command. */
diff --git a/storage/connect/odbconn.h b/storage/connect/odbconn.h
index 448ce2d428f..9b8f2d100f4 100644
--- a/storage/connect/odbconn.h
+++ b/storage/connect/odbconn.h
@@ -127,7 +127,7 @@ class ODBConn : public BLOCK {
// Attributes
public:
- char GetQuoteChar(void) {return m_IDQuoteChar;}
+ char *GetQuoteChar(void) {return m_IDQuoteChar;}
// Database successfully opened?
bool IsOpen(void) {return m_hdbc != SQL_NULL_HDBC;}
PSZ GetStringInfo(ushort infotype);
@@ -142,8 +142,9 @@ class ODBConn : public BLOCK {
int ExecDirectSQL(char *sql, ODBCCOL *tocols);
int Fetch(void);
int PrepareSQL(char *sql);
- int ExecuteSQL(bool x);
+ int ExecuteSQL(void);
bool BindParam(ODBCCOL *colp);
+ bool ExecSQLcommand(char *sql);
int GetCatInfo(CATPARM *cap);
bool GetDataSources(PQRYRES qrp);
bool GetDrivers(PQRYRES qrp);
@@ -183,9 +184,9 @@ class ODBConn : public BLOCK {
DWORD m_QueryTimeout;
DWORD m_UpdateOptions;
DWORD m_RowsetSize;
+ char m_IDQuoteChar[2];
int m_Catver;
PSZ m_Connect;
bool m_Updatable;
bool m_Transact;
- char m_IDQuoteChar;
}; // end of ODBConn class definition
diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h
index 550153921a5..d8f27603f6c 100644
--- a/storage/connect/plgdbsem.h
+++ b/storage/connect/plgdbsem.h
@@ -106,13 +106,20 @@ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */
TYPE_AM_DOM = 80, /* DOM access method type no */
TYPE_AM_DIR = 90, /* DIR access method type no */
TYPE_AM_ODBC = 100, /* ODBC access method type no */
+ TYPE_AM_XDBC = 101, /* XDBC access method type no */
TYPE_AM_OEM = 110, /* OEM access method type no */
TYPE_AM_TBL = 115, /* TBL access method type no */
TYPE_AM_PIVOT = 120, /* PIVOT access method type no */
TYPE_AM_SRC = 121, /* PIVOT multiple column type no */
TYPE_AM_FNC = 122, /* PIVOT source column type no */
+ TYPE_AM_XCOL = 124, /* XCOL access method type no */
TYPE_AM_XML = 127, /* XML access method type no */
+ TYPE_AM_OCCUR = 128, /* OCCUR access method type no */
+ TYPE_AM_PRX = 129, /* PROXY access method type no */
TYPE_AM_XTB = 130, /* SYS table access method type */
+ TYPE_AM_BLK = 131, /* BLK access method type no */
+ TYPE_AM_ZIP = 132, /* ZIP access method type no */
+ TYPE_AM_ZLIB = 133, /* ZLIB access method type no */
TYPE_AM_MAC = 137, /* MAC table access method type */
TYPE_AM_WMI = 139, /* WMI table access method type */
TYPE_AM_XCL = 140, /* SYS column access method type */
@@ -123,7 +130,8 @@ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */
TYPE_AM_DMY = 172, /* DMY Dummy tables am type no */
TYPE_AM_SET = 180, /* SET Set tables am type no */
TYPE_AM_MYSQL = 192, /* MYSQL access method type no */
- TYPE_AM_CAT = 193, /* Catalog access method type no */
+ TYPE_AM_MYX = 193, /* MYSQL EXEC access method type */
+ TYPE_AM_CAT = 195, /* Catalog access method type no */
TYPE_AM_OUT = 200}; /* Output relations (storage) */
enum RECFM {RECFM_NAF = -2, /* Not a file */
@@ -585,4 +593,4 @@ int global_open(GLOBAL *g, int msgid, const char *filename, int flags, int mode)
DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir);
char *MakeEscape(PGLOBAL g, char* str, char q);
-bool PushWarning(PGLOBAL, PTDBASE);
+bool PushWarning(PGLOBAL, PTDBASE, int level = 1);
diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp
index 270a0381bad..3649632be10 100644
--- a/storage/connect/plgdbutl.cpp
+++ b/storage/connect/plgdbutl.cpp
@@ -330,7 +330,7 @@ PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
// Allocate the Value Block that will contain data
if (crp->Length || nonull)
crp->Kdata = AllocValBlock(g, NULL, crp->Type, maxres,
- crp->Length, 0, true, blank);
+ crp->Length, 0, true, blank, false);
else
crp->Kdata = NULL;
diff --git a/storage/connect/tabdos.cpp b/storage/connect/tabdos.cpp
index b828c44d648..72b3a27b057 100644
--- a/storage/connect/tabdos.cpp
+++ b/storage/connect/tabdos.cpp
@@ -77,7 +77,7 @@ extern "C" int trace;
/* No conversion of block values (check = true). */
/***********************************************************************/
PVBLK AllocValBlock(PGLOBAL, void *, int, int, int len = 0, int prec = 0,
- bool check = true, bool blank = false);
+ bool check = true, bool blank = false, bool un = false);
/* --------------------------- Class DOSDEF -------------------------- */
diff --git a/storage/connect/table.cpp b/storage/connect/table.cpp
index 8f12a04a71a..6eda28cfb14 100644
--- a/storage/connect/table.cpp
+++ b/storage/connect/table.cpp
@@ -524,6 +524,7 @@ bool TDBCAT::OpenDB(PGLOBAL g)
if (Initialize(g))
return true;
+ Use = USE_OPEN;
return InitCol(g);
} // end of OpenDB
diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp
index f37cb6d349e..7db44658058 100644
--- a/storage/connect/tabmysql.cpp
+++ b/storage/connect/tabmysql.cpp
@@ -321,7 +321,7 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
Portnumber = Cat->GetIntCatInfo("Port", GetDefaultPort());
Server = Hostname;
} else if (ParseURL(g, url))
- return TRUE;
+ return true;
Bind = !!Cat->GetIntCatInfo("Bind", 0);
Delayed = !!Cat->GetIntCatInfo("Delayed", 0);
@@ -344,7 +344,7 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
char *locdb = Database;
if (ParseURL(g, url))
- return TRUE;
+ return true;
Database = locdb;
} // endif url
@@ -353,9 +353,15 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
} // endif am
if ((Srcdef = Cat->GetStringCatInfo(g, "Srcdef", NULL)))
- Isview = TRUE;
+ Isview = true;
- Xsrc = Cat->GetBoolCatInfo("Execsrc", FALSE);
+ // Used for Update and Delete
+ Qrystr = Cat->GetStringCatInfo(g, "Query_String", "?");
+ Quoted = Cat->GetIntCatInfo("Quoted", 0);
+
+ // Specific for command executing tables
+ Xsrc = Cat->GetBoolCatInfo("Execsrc", false);
+ Mxr = Cat->GetIntCatInfo("Maxerr", 0);
return FALSE;
} // end of DefineAM
@@ -388,6 +394,8 @@ TDBMYSQL::TDBMYSQL(PMYDEF tdp) : TDBASE(tdp)
User = tdp->Username;
Pwd = tdp->Password;
Server = tdp->Server;
+ Qrystr = tdp->Qrystr;
+ Quoted = max(0, tdp->Quoted);
Port = tdp->Portnumber;
Isview = tdp->Isview;
Prep = tdp->Bind;
@@ -400,6 +408,8 @@ TDBMYSQL::TDBMYSQL(PMYDEF tdp) : TDBASE(tdp)
User = NULL;
Pwd = NULL;
Server = NULL;
+ Qrystr = NULL;
+ Quoted = 0;
Port = 0;
Isview = FALSE;
Prep = FALSE;
@@ -424,6 +434,8 @@ TDBMYSQL::TDBMYSQL(PGLOBAL g, PTDBMY tdbp) : TDBASE(tdbp)
Srcdef = tdbp->Srcdef;
User = tdbp->User;
Pwd = tdbp->Pwd;
+ Qrystr = tdbp->Qrystr;
+ Quoted = tdbp->Quoted;
Port = tdbp->Port;
Isview = tdbp->Isview;
Prep = tdbp->Prep;
@@ -516,7 +528,7 @@ bool TDBMYSQL::MakeSelect(PGLOBAL g)
strcat(strcat(strcat(strcat(Query, " FROM "), tk), Tabname), tk);
if (To_Filter)
- strcat(strcat(Query, " WHERE "), To_Filter);
+ strcat(strcat(Query, " WHERE "), To_Filter->Body);
if (trace)
htrc("Query=%s\n", Query);
@@ -610,118 +622,109 @@ bool TDBMYSQL::MakeInsert(PGLOBAL g)
return FALSE;
} // end of MakeInsert
-#if 0
/***********************************************************************/
-/* MakeUpdate: make the Update statement use with MySQL connection. */
-/* Note: currently limited to local values and filtering. */
+/* MakeCommand: make the Update or Delete statement to send to the */
+/* MySQL server. Limited to remote values and filtering. */
/***********************************************************************/
-bool TDBMYSQL::MakeUpdate(PGLOBAL g, PSELECT selist)
+int TDBMYSQL::MakeCommand(PGLOBAL g)
{
- char *setlist, *colname, *where = NULL, *tk = "`";
- int len = 0, nset = 0;
- bool b = FALSE;
- PXOB xp;
- PSELECT selp;
+ Query = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
- if (Query)
- return FALSE; // already done
+ if (Quoted > 0 || stricmp(Name, Tabname)) {
+ char *p, *qrystr, name[68];
+ bool qtd = Quoted > 0;
- if (To_Filter)
- if (To_Filter->CheckLocal(this)) {
- where = (char*)PlugSubAlloc(g, NULL, 512); // Should be enough
- *where = '\0';
- if (!PlugRephraseSQL(g, where, To_Filter, TYPE_FILTER, tk))
- return TRUE;
+ // Make a lower case copy of the originale query
+ qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 1);
+ strlwr(strcpy(qrystr, Qrystr));
- To_Filter = NULL;
- len = strlen(where);
- } else {
- strcpy(g->Message, MSG(NO_REF_UPDATE));
- return TRUE;
- } // endif Local
+ // Check whether the table name is equal to a keyword
+ // If so, it must be quoted in the original query
+ strlwr(strcat(strcat(strcpy(name, "`"), Name), "`"));
- for (selp = selist; selp; selp = selp->GetNext_Proj())
- nset++;
+ if (!strstr("`update`delete`low_priority`ignore`quick`from`", name))
+ strlwr(strcpy(name, Name)); // Not a keyword
- assert(nset);
+ if ((p = strstr(qrystr, name))) {
+ memcpy(Query, Qrystr, p - qrystr);
+ Query[p - qrystr] = 0;
- // Allocate a pretty big buffer
- setlist = (char*)PlugSubAlloc(g, NULL, 256 * nset);
- *setlist = '\0';
+ if (qtd && *(p-1) == ' ')
+ strcat(strcat(strcat(Query, "`"), Tabname), "`");
+ else
+ strcat(Query, Tabname);
- for (selp = selist; selp; selp = selp->GetNext_Proj()) {
- if (selp->GetSetType() == TYPE_COLBLK) {
- colname = selp->GetSetCol()->GetName();
- } else if (selp->GetSetType() == TYPE_COLUMN) {
- colname = (char*)((PCOLUMN)selp->GetSetCol())->GetName();
+ strcat(Query, Qrystr + (p - qrystr) + strlen(name));
} else {
- sprintf(g->Message, MSG(BAD_SET_TYPE), selp->GetSetType());
- return TRUE;
- } // endif Type
-
- if (b)
- strcat(setlist, ", ");
- else
- b = TRUE;
-
- strcat(strcat(strcat(strcat(setlist, tk), colname), tk), " = ");
+ sprintf(g->Message, "Cannot use this %s command",
+ (Mode == MODE_UPDATE) ? "UPDATE" : "DELETE");
+ return RC_FX;
+ } // endif p
- xp = selp->GetObject();
-
- if (!xp->CheckLocal(this)) {
- strcpy(g->Message, MSG(NO_REF_UPDATE));
- return TRUE;
- } else if (xp->GetType() == TYPE_SUBQ)
- // Cannot be correlated because CheckLocal would have failed
- xp = new(g) CONSTANT(xp->GetValue());
+ } else
+ strcpy(Query, Qrystr);
- if (!PlugRephraseSQL(g, setlist + strlen(setlist),
- xp, TYPE_XOBJECT, tk))
- return TRUE;
+ return RC_OK;
+ } // end of MakeCommand
- } // endfor selp
+#if 0
+/***********************************************************************/
+/* MakeUpdate: make the Update statement use with MySQL connection. */
+/* Limited to remote values and filtering. */
+/***********************************************************************/
+int TDBMYSQL::MakeUpdate(PGLOBAL g)
+ {
+ char *qc, cmd[8], tab[96], end[1024];
- // Below 16 is enough to take care of the fixed part of the query
- len += (strlen(setlist) + strlen(Tabname) + 16);
- Query = (char*)PlugSubAlloc(g, NULL, len);
- strcat(strcat(strcat(strcpy(Query, "UPDATE "), tk), Tabname), tk);
- strcat(strcat(Query, " SET "), setlist);
+ Query = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
+ memset(end, 0, sizeof(end));
- if (where)
- strcat(Query, where);
+ if (sscanf(Qrystr, "%s `%[^`]`%1023c", cmd, tab, end) > 2 ||
+ sscanf(Qrystr, "%s \"%[^\"]\"%1023c", cmd, tab, end) > 2)
+ qc = "`";
+ else if (sscanf(Qrystr, "%s %s%1023c", cmd, tab, end) > 2
+ && !stricmp(tab, Name))
+ qc = (Quoted) ? "`" : "";
+ else {
+ strcpy(g->Message, "Cannot use this UPDATE command");
+ return RC_FX;
+ } // endif sscanf
- return FALSE;
+ assert(!stricmp(cmd, "update"));
+ strcat(strcat(strcat(strcpy(Query, "UPDATE "), qc), Tabname), qc);
+ strcat(Query, end);
+ return RC_OK;
} // end of MakeUpdate
/***********************************************************************/
-/* MakeDelete: make the Delete statement use with MySQL connection. */
-/* If no filtering Truncate is used because it is faster than Delete. */
-/* However, the number of deleted lines is not returned by MySQL. */
-/* Note: currently limited to local filtering. */
+/* MakeDelete: make the Delete statement used with MySQL connection. */
+/* Limited to remote filtering. */
/***********************************************************************/
-bool TDBMYSQL::MakeDelete(PGLOBAL g)
+int TDBMYSQL::MakeDelete(PGLOBAL g)
{
- char *tk = "`";
- int len = 0;
+ char *qc, cmd[8], from[8], tab[96], end[512];
- if (Query)
- return FALSE; // already done
+ Query = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
+ memset(end, 0, sizeof(end));
- if (!To_Filter)
- AftRows = -1; // Means "all lines deleted"
+ if (sscanf(Qrystr, "%s %s `%[^`]`%511c", cmd, from, tab, end) > 2 ||
+ sscanf(Qrystr, "%s %s \"%[^\"]\"%511c", cmd, from, tab, end) > 2)
+ qc = "`";
+ else if (sscanf(Qrystr, "%s %s %s%511c", cmd, from, tab, end) > 2)
+ qc = (Quoted) ? "`" : "";
+ else {
+ strcpy(g->Message, "Cannot use this DELETE command");
+ return RC_FX;
+ } // endif sscanf
- // Below 16 is more than length of 'delete from ' + 3
- len += (strlen(Tabname) + 16);
- len += (To_Filter ? strlen(To_Filter) + 7 : 0);
- Query = (char*)PlugSubAlloc(g, NULL, len);
- strcpy(Query, (To_Filter) ? "DELETE FROM " : "TRUNCATE ");
- strcat(strcat(strcat(Query, tk), Tabname), tk);
+ assert(!stricmp(cmd, "delete") && !stricmp(from, "from"));
+ strcat(strcat(strcat(strcpy(Query, "DELETE FROM "), qc), Tabname), qc);
- if (To_Filter)
- strcat(strcat(Query, " WHERE "), To_Filter);
+ if (*end)
+ strcat(Query, end);
- return FALSE;
+ return RC_OK;
} // end of MakeDelete
#endif // 0
@@ -751,7 +754,8 @@ int TDBMYSQL::GetMaxSize(PGLOBAL g)
Query = NULL; // Must be remade when columns are known
#endif // 0
- MaxSize = 10; // To make MySQL happy
+ // Return 0 in mode DELETE in case of delete all.
+ MaxSize = (Mode == MODE_DELETE) ? 0 : 10; // To make MySQL happy
} // endif MaxSize
return MaxSize;
@@ -766,12 +770,11 @@ int TDBMYSQL::RowNumber(PGLOBAL g, bool b)
} // end of RowNumber
/***********************************************************************/
-/* Return 0 in mode DELETE to tell that the delete is done. */
+/* Return 0 in mode UPDATE to tell that the update is done. */
/***********************************************************************/
int TDBMYSQL::GetProgMax(PGLOBAL g)
{
- return (Mode == MODE_DELETE || Mode == MODE_UPDATE) ? 0
- : GetMaxSize(g);
+ return (Mode == MODE_UPDATE) ? 0 : GetMaxSize(g);
} // end of GetProgMax
/***********************************************************************/
@@ -874,33 +877,17 @@ bool TDBMYSQL::OpenDB(PGLOBAL g)
m_Rc = Myc.ExecSQL(g, cmd, &w);
} // endif m_Rc
-#if 0
- } else if (Next) {
- strcpy(g->Message, MSG(NO_JOIN_UPDEL));
- } else if (Mode == MODE_DELETE) {
- strcpy(g->Message, "MySQL table delete not implemented yet\n");
- bool rc = MakeDelete(g);
-
- if (!rc && Myc.ExecSQL(g, Query) == RC_NF) {
- if (!AftRows)
- AftRows = Myc.GetRows();
-
- m_Rc = RC_OK;
- } // endif ExecSQL
-#endif // 0
-
- } else {
-// bool rc = MakeUpdate(g, sqlp->GetProj());
- strcpy(g->Message, "MySQL table delete/update not implemented yet\n");
- } // endelse
+ } else
+// m_Rc = (Mode == MODE_DELETE) ? MakeDelete(g) : MakeUpdate(g);
+ m_Rc = MakeCommand(g);
if (m_Rc == RC_FX) {
Myc.Close();
- return TRUE;
+ return true;
} // endif rc
- Use = USE_OPEN; // Do it now in case we are recursively called
- return FALSE;
+ Use = USE_OPEN;
+ return false;
} // end of OpenDB
/***********************************************************************/
@@ -976,6 +963,38 @@ char *TDBMYSQL::FindFieldColumn(char *name)
} // end of FindFieldColumn
/***********************************************************************/
+/* Send an UPDATE or DELETE command to the remote server. */
+/***********************************************************************/
+int TDBMYSQL::SendCommand(PGLOBAL g)
+ {
+ int w;
+
+ if (Myc.ExecSQLcmd(g, Query, &w) == RC_NF) {
+ AftRows = Myc.m_Afrw;
+ sprintf(g->Message, "%s: %d affected rows", Tabname, AftRows);
+ PushWarning(g, this, 0); // 0 means a Note
+
+ if (trace)
+ htrc("%s\n", g->Message);
+
+ if (w && Myc.ExecSQL(g, "SHOW WARNINGS") == RC_OK) {
+ // We got warnings from the remote server
+ while (Myc.Fetch(g, -1) == RC_OK) {
+ sprintf(g->Message, "%s: (%s) %s", Tabname,
+ Myc.GetCharField(1), Myc.GetCharField(2));
+ PushWarning(g, this);
+ } // endwhile Fetch
+
+ Myc.FreeResult();
+ } // endif w
+
+ return RC_EF; // Nothing else to do
+ } else
+ return RC_FX; // Error
+
+ } // end of SendCommand
+
+/***********************************************************************/
/* Data Base read routine for MYSQL access method. */
/***********************************************************************/
int TDBMYSQL::ReadDB(PGLOBAL g)
@@ -986,6 +1005,9 @@ int TDBMYSQL::ReadDB(PGLOBAL g)
htrc("MySQL ReadDB: R%d Mode=%d key=%p link=%p Kindex=%p\n",
GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex);
+ if (Mode == MODE_UPDATE || Mode == MODE_DELETE)
+ return SendCommand(g);
+
/*********************************************************************/
/* Now start the reading process. */
/* Here is the place to fetch the line. */
@@ -1041,12 +1063,16 @@ int TDBMYSQL::WriteDB(PGLOBAL g)
} // end of WriteDB
/***********************************************************************/
-/* Data Base delete line routine for MYSQL access methods. */
+/* Data Base delete all routine for MYSQL access methods. */
/***********************************************************************/
int TDBMYSQL::DeleteDB(PGLOBAL g, int irc)
{
- strcpy(g->Message, MSG(NO_MYSQL_DELETE));
- return RC_FX;
+ if (irc == RC_FX)
+ // Send the DELETE (all) command to the remote table
+ return (SendCommand(g) == RC_FX) ? RC_FX : RC_OK;
+ else
+ return RC_OK; // Ignore
+
} // end of DeleteDB
/***********************************************************************/
@@ -1237,7 +1263,7 @@ void MYSQLCOL::InitBind(PGLOBAL g)
/***********************************************************************/
void MYSQLCOL::ReadColumn(PGLOBAL g)
{
- char *buf;
+ char *p, *buf, tim[20];
int rc;
PTDBMY tdbp = (PTDBMY)To_Tdb;
@@ -1257,7 +1283,14 @@ void MYSQLCOL::ReadColumn(PGLOBAL g)
if (trace)
htrc("MySQL ReadColumn: name=%s buf=%s\n", Name, buf);
- Value->SetValue_char(buf, min((unsigned)Long, strlen(buf)));
+ // TODO: have a true way to differenciate temporal values
+ if (strlen(buf) == 8)
+ // This is a TIME value
+ p = strcat(strcpy(tim, "1970-01-01 "), buf);
+ else
+ p = buf;
+
+ Value->SetValue_char(p, strlen(p));
} else {
if (Nullable)
Value->SetNull(true);
@@ -1294,8 +1327,30 @@ void MYSQLCOL::WriteColumn(PGLOBAL g)
/* ------------------------------------------------------------------- */
/***********************************************************************/
-/* Implementation of the TDBMYSQL class. */
+/* Implementation of the TDBMYEXC class. */
/***********************************************************************/
+TDBMYEXC::TDBMYEXC(PMYDEF tdp) : TDBMYSQL(tdp)
+{
+ Cmdlist = NULL;
+ Cmdcol = NULL;
+ Shw = false;
+ Havew = false;
+ Isw = false;
+ Warnings = 0;
+ Mxr = tdp->Mxr;
+ Nerr = 0;
+} // end of TDBMYEXC constructor
+
+TDBMYEXC::TDBMYEXC(PGLOBAL g, PTDBMYX tdbp) : TDBMYSQL(g, tdbp)
+{
+ Cmdlist = tdbp->Cmdlist;
+ Cmdcol = tdbp->Cmdcol;
+ Shw = tdbp->Shw;
+ Havew = tdbp->Havew;
+ Isw = tdbp->Isw;
+ Mxr = tdbp->Mxr;
+ Nerr = tdbp->Nerr;
+} // end of TDBMYEXC copy constructor
// Is this really useful ???
PTDB TDBMYEXC::CopyOne(PTABS t)
@@ -1331,23 +1386,15 @@ PCOL TDBMYEXC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
/***********************************************************************/
/* MakeCMD: make the SQL statement to send to MYSQL connection. */
/***********************************************************************/
-char *TDBMYEXC::MakeCMD(PGLOBAL g)
+PCMD TDBMYEXC::MakeCMD(PGLOBAL g)
{
- char *xcmd = NULL;
+ PCMD xcmd = NULL;
if (To_Filter) {
if (Cmdcol) {
- char col[128], cmd[1024];
- int n;
-
- memset(cmd, 0, sizeof(cmd));
- n = sscanf(To_Filter, "%s = '%1023c", col, cmd);
-
- if (n == 2 && !stricmp(col, Cmdcol)) {
- xcmd = (char*)PlugSubAlloc(g, NULL, strlen(cmd) + 1);
-
- strcpy(xcmd, cmd);
- xcmd[strlen(xcmd) - 1] = 0;
+ if (!stricmp(Cmdcol, To_Filter->Body) &&
+ (To_Filter->Op == OP_EQ || To_Filter->Op == OP_IN)) {
+ xcmd = To_Filter->Cmds;
} else
strcpy(g->Message, "Invalid command specification filter");
@@ -1357,7 +1404,7 @@ char *TDBMYEXC::MakeCMD(PGLOBAL g)
} else if (!Srcdef)
strcpy(g->Message, "No Srcdef default command");
else
- xcmd = Srcdef;
+ xcmd = new(g) CMD(g, Srcdef);
return xcmd;
} // end of MakeCMD
@@ -1368,7 +1415,7 @@ char *TDBMYEXC::MakeCMD(PGLOBAL g)
int TDBMYEXC::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0) {
- MaxSize = 1;
+ MaxSize = 10; // a guess
} // endif MaxSize
return MaxSize;
@@ -1379,8 +1426,6 @@ int TDBMYEXC::GetMaxSize(PGLOBAL g)
/***********************************************************************/
bool TDBMYEXC::OpenDB(PGLOBAL g)
{
- int rc;
-
if (Use == USE_OPEN) {
strcpy(g->Message, "Multiple execution is not allowed");
return true;
@@ -1407,20 +1452,11 @@ bool TDBMYEXC::OpenDB(PGLOBAL g)
/*********************************************************************/
/* Get the command to execute. */
/*********************************************************************/
- if (!(Query = MakeCMD(g))) {
+ if (!(Cmdlist = MakeCMD(g))) {
Myc.Close();
return true;
} // endif Query
- if ((rc = Myc.ExecSQL(g, Query)) == RC_NF) {
- strcpy(g->Message, "Affected rows");
- AftRows = Myc.m_Rows;
- } else if (rc == RC_OK) {
- sprintf(g->Message, "Columns and %d rows", Myc.m_Rows);
- AftRows = Myc.m_Fields;
- } else
- return true;
-
return false;
} // end of OpenDB
@@ -1429,7 +1465,54 @@ bool TDBMYEXC::OpenDB(PGLOBAL g)
/***********************************************************************/
int TDBMYEXC::ReadDB(PGLOBAL g)
{
- return (++N) ? RC_EF : RC_OK;
+ if (Havew) {
+ // Process result set from SHOW WARNINGS
+ if (Myc.Fetch(g, -1) != RC_OK) {
+ Myc.FreeResult();
+ Havew = Isw = false;
+ } else {
+ N++;
+ Isw = true;
+ return RC_OK;
+ } // endif Fetch
+
+ } // endif m_Res
+
+ if (Cmdlist) {
+ // Process query to send
+ int rc;
+
+ do {
+ Query = Cmdlist->Cmd;
+
+ switch (rc = Myc.ExecSQLcmd(g, Query, &Warnings)) {
+ case RC_NF:
+ AftRows = Myc.m_Afrw;
+ strcpy(g->Message, "Affected rows");
+ break;
+ case RC_OK:
+ AftRows = Myc.m_Fields;
+ strcpy(g->Message, "Result set columns");
+ break;
+ case RC_FX:
+ AftRows = Myc.m_Afrw;
+ Nerr++;
+ break;
+ case RC_INFO:
+ Shw = true;
+ } // endswitch rc
+
+ Cmdlist = (Nerr > Mxr) ? NULL : Cmdlist->Next;
+ } while (rc == RC_INFO);
+
+ if (Shw && Warnings)
+ Havew = (Myc.ExecSQL(g, "SHOW WARNINGS") == RC_OK);
+
+ ++N;
+ return RC_OK;
+ } else
+ return RC_EF;
+
} // end of ReadDB
/***********************************************************************/
@@ -1480,12 +1563,23 @@ void MYXCOL::ReadColumn(PGLOBAL g)
{
PTDBMYX tdbp = (PTDBMYX)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;
- } // endswitch Flag
+ if (tdbp->Isw) {
+ char *buf = NULL;
+
+ if (Flag < 3) {
+ buf = tdbp->Myc.GetCharField(Flag);
+ Value->SetValue_psz(buf);
+ } else
+ Value->Reset();
+
+ } else
+ 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;
+ case 3: Value->SetValue(tdbp->Warnings); break;
+ default: Value->SetValue_psz("Invalid Flag"); break;
+ } // endswitch Flag
} // end of ReadColumn
diff --git a/storage/connect/tabmysql.h b/storage/connect/tabmysql.h
index bcac10dcaa7..74b1d49e227 100644
--- a/storage/connect/tabmysql.h
+++ b/storage/connect/tabmysql.h
@@ -20,6 +20,7 @@ typedef class MYSQLC *PMYC;
/***********************************************************************/
class MYSQLDEF : public TABDEF {/* Logical table description */
friend class TDBMYSQL;
+ friend class TDBMYEXC;
friend class TDBMCL;
friend class ha_connect;
public:
@@ -52,7 +53,10 @@ class MYSQLDEF : public TABDEF {/* Logical table description */
PSZ Username; /* User logon name */
PSZ Password; /* Password logon info */
PSZ Server; /* PServerID */
+ PSZ Qrystr; /* The original query */
int Portnumber; /* MySQL port number (0 = default) */
+ int Mxr; /* Maxerr for an Exec table */
+ int Quoted; /* Identifier quoting level */
bool Isview; /* TRUE if this table is a MySQL view */
bool Bind; /* Use prepared statement on insert */
bool Delayed; /* Delayed insert */
@@ -102,9 +106,11 @@ class TDBMYSQL : public TDBASE {
// Internal functions
bool MakeSelect(PGLOBAL g);
bool MakeInsert(PGLOBAL g);
-//bool MakeUpdate(PGLOBAL g);
-//bool MakeDelete(PGLOBAL g);
int BindColumns(PGLOBAL g);
+ int MakeCommand(PGLOBAL g);
+//int MakeUpdate(PGLOBAL g);
+//int MakeDelete(PGLOBAL g);
+ int SendCommand(PGLOBAL g);
// Members
MYSQLC Myc; // MySQL connection class
@@ -118,6 +124,7 @@ class TDBMYSQL : public TDBASE {
char *Server; // The server ID
char *Query; // Points to SQL query
char *Qbuf; // Used for not prepared insert
+ char *Qrystr; // The original query
bool Fetched; // True when fetch was done
bool Isview; // True if this table is a MySQL view
bool Prep; // Use prepared statement on insert
@@ -127,6 +134,7 @@ class TDBMYSQL : public TDBASE {
int N; // The current table index
int Port; // MySQL port number (0 = default)
int Nparm; // The number of statement parameters
+ int Quoted; // The identifier quoting level
}; // end of class TDBMYSQL
/***********************************************************************/
@@ -167,13 +175,12 @@ class MYSQLCOL : public COLBLK {
class TDBMYEXC : public TDBMYSQL {
friend class MYXCOL;
public:
- // Constructor
- TDBMYEXC(PMYDEF tdp) : TDBMYSQL(tdp) {Cmdcol = NULL;}
- TDBMYEXC(PGLOBAL g, PTDBMYX tdbp) : TDBMYSQL(g, tdbp)
- {Cmdcol = tdbp->Cmdcol;}
+ // Constructors
+ TDBMYEXC(PMYDEF tdp);
+ TDBMYEXC(PGLOBAL g, PTDBMYX tdbp);
// Implementation
-//virtual AMT GetAmType(void) {return TYPE_AM_MYSQL;}
+ virtual AMT GetAmType(void) {return TYPE_AM_MYX;}
virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBMYEXC(g, this);}
// Methods
@@ -203,13 +210,20 @@ class TDBMYEXC : public TDBMYSQL {
protected:
// Internal functions
- char *MakeCMD(PGLOBAL g);
+ PCMD MakeCMD(PGLOBAL g);
//bool MakeSelect(PGLOBAL g);
//bool MakeInsert(PGLOBAL g);
//int BindColumns(PGLOBAL g);
// Members
+ PCMD Cmdlist; // The commands to execute
char *Cmdcol; // The name of the Xsrc command column
+ bool Shw; // Show warnings
+ bool Havew; // True when processing warnings
+ bool Isw; // True for warning lines
+ int Warnings; // Warnings number
+ int Mxr; // Maximum errors before closing
+ int Nerr; // Number of errors so far
}; // end of class TDBMYEXC
/***********************************************************************/
diff --git a/storage/connect/taboccur.cpp b/storage/connect/taboccur.cpp
index f0a5a1c38f0..5edbe932d50 100644
--- a/storage/connect/taboccur.cpp
+++ b/storage/connect/taboccur.cpp
@@ -495,6 +495,7 @@ bool TDBOCCUR::OpenDB(PGLOBAL g)
if (Tdbp->OpenDB(g))
return TRUE;
+ Use = USE_OPEN;
return ViewColumnList(g);
} // end of OpenDB
diff --git a/storage/connect/taboccur.h b/storage/connect/taboccur.h
index 6cfece5634e..0bee074234c 100644
--- a/storage/connect/taboccur.h
+++ b/storage/connect/taboccur.h
@@ -3,8 +3,6 @@
#include "tabutil.h"
-#define TYPE_AM_OCCUR (AMT)128
-
typedef class OCCURDEF *POCCURDEF;
typedef class TDBOCCUR *PTDBOCCUR;
typedef class OCCURCOL *POCCURCOL;
diff --git a/storage/connect/tabodbc.cpp b/storage/connect/tabodbc.cpp
index d9d794ef4e4..10b730fd834 100644
--- a/storage/connect/tabodbc.cpp
+++ b/storage/connect/tabodbc.cpp
@@ -90,8 +90,8 @@ extern int num_read, num_there, num_eq[2]; // Statistics
/***********************************************************************/
ODBCDEF::ODBCDEF(void)
{
- Connect = Tabname = Tabowner = Tabqual = Srcdef = Qchar = NULL;
- Catver = Options = 0;
+ Connect = Tabname = Tabowner = Tabqual = Srcdef = Qrystr = NULL;
+ Catver = Options = Quoted = 0;
Xsrc = false;
} // end of ODBCDEF constructor
@@ -107,9 +107,11 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
Tabowner = Cat->GetStringCatInfo(g, "Owner", "");
Tabqual = Cat->GetStringCatInfo(g, "Qualifier", "");
Srcdef = Cat->GetStringCatInfo(g, "Srcdef", NULL);
- Qchar = Cat->GetStringCatInfo(g, "Qchar", "");
+ Qrystr = Cat->GetStringCatInfo(g, "Query_String", "?");
Catver = Cat->GetIntCatInfo("Catver", 2);
Xsrc = Cat->GetBoolCatInfo("Execsrc", FALSE);
+ Mxr = Cat->GetIntCatInfo("Maxerr", 0);
+ Quoted = Cat->GetIntCatInfo("Quoted", 0);
Options = ODBConn::noOdbcDialog;
Pseudo = 2; // FILID is Ok but not ROWID
return false;
@@ -169,8 +171,9 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp)
Owner = tdp->Tabowner;
Qualifier = tdp->Tabqual;
Srcdef = tdp->Srcdef;
- Quote = tdp->GetQchar();
+ Qrystr = tdp->Qrystr;
Options = tdp->Options;
+ Quoted = max(0, tdp->GetQuoted());
Rows = tdp->GetElemt();
Catver = tdp->Catver;
} else {
@@ -179,12 +182,14 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp)
Owner = NULL;
Qualifier = NULL;
Srcdef = NULL;
- Quote = NULL;
+ Qrystr = NULL;
Options = 0;
+ Quoted = 0;
Rows = 0;
Catver = 0;
} // endif tdp
+ Quote = NULL;
Query = NULL;
Count = NULL;
//Where = NULL;
@@ -207,6 +212,7 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp)
Owner = tdbp->Owner;
Qualifier = tdbp->Qualifier;
Srcdef = tdbp->Srcdef;
+ Qrystr = tdbp->Qrystr;
Quote = tdbp->Quote;
Query = tdbp->Query;
Count = tdbp->Count;
@@ -214,6 +220,7 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp)
MulConn = tdbp->MulConn;
DBQ = tdbp->DBQ;
Options = tdbp->Options;
+ Quoted = tdbp->Quoted;
Rows = tdbp->Rows;
Fpos = tdbp->Fpos;
AftRows = tdbp->AftRows;
@@ -395,7 +402,7 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
// Below 14 is length of 'select ' + length of ' from ' + 1
len = (strlen(colist) + strlen(buf) + 14);
- len += (To_Filter ? strlen(To_Filter) + 7 : 0);
+ len += (To_Filter ? strlen(To_Filter->Body) + 7 : 0);
// if (tablep->GetQualifier()) This is used when using a table
// qualp = tablep->GetQualifier(); from anotherPlugDB database but
@@ -432,7 +439,7 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
strcat(sql, tabname);
if (To_Filter)
- strcat(strcat(sql, " WHERE "), To_Filter);
+ strcat(strcat(sql, " WHERE "), To_Filter->Body);
return sql;
} // end of MakeSQL
@@ -440,21 +447,18 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
/***********************************************************************/
/* MakeInsert: make the Insert statement used with ODBC connection. */
/***********************************************************************/
-bool TDBODBC::MakeInsert(PGLOBAL g)
+char *TDBODBC::MakeInsert(PGLOBAL g)
{
- char *colist, *valist;
+ char *stmt, *colist, *valist;
// char *tk = "`";
int len = 0;
bool b = FALSE;
PCOL colp;
- if (Query)
- return false; // already done
-
for (colp = Columns; colp; colp = colp->GetNext())
if (colp->IsSpecial()) {
strcpy(g->Message, MSG(NO_ODBC_SPECOL));
- return true;
+ return NULL;
} else {
len += (strlen(colp->GetName()) + 4);
((PODBCCOL)colp)->Rank = ++Nparm;
@@ -482,18 +486,18 @@ bool TDBODBC::MakeInsert(PGLOBAL g)
// Below 32 is enough to contain the fixed part of the query
len = (strlen(TableName) + strlen(colist) + strlen(valist) + 32);
- Query = (char*)PlugSubAlloc(g, NULL, len);
- strcpy(Query, "INSERT INTO ");
+ stmt = (char*)PlugSubAlloc(g, NULL, len);
+ strcpy(stmt, "INSERT INTO ");
if (Quote)
- strcat(strcat(strcat(Query, Quote), TableName), Quote);
+ strcat(strcat(strcat(stmt, Quote), TableName), Quote);
else
- strcat(Query, TableName);
+ strcat(stmt, TableName);
- strcat(strcat(strcat(Query, " ("), colist), ") VALUES (");
- strcat(strcat(Query, valist), ")");
+ strcat(strcat(strcat(stmt, " ("), colist), ") VALUES (");
+ strcat(strcat(stmt, valist), ")");
- return false;
+ return stmt;
} // end of MakeInsert
/***********************************************************************/
@@ -515,6 +519,127 @@ bool TDBODBC::BindParameters(PGLOBAL g)
} // end of BindParameters
/***********************************************************************/
+/* MakeCommand: make the Update or Delete statement to send to the */
+/* MySQL server. Limited to remote values and filtering. */
+/***********************************************************************/
+char *TDBODBC::MakeCommand(PGLOBAL g)
+ {
+ char *p, name[68], *qc = Ocp->GetQuoteChar();
+ char *stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
+ char *qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 1);
+ bool qtd = Quoted > 0;
+ int i = 0, k = 0;
+
+ // Make a lower case copy of the originale query and change
+ // back ticks to the data source identifier quoting character
+ do {
+ qrystr[i] = (Qrystr[i] == '`') ? *qc : tolower(Qrystr[i]);
+ } while (Qrystr[i++]);
+
+ // Check whether the table name is equal to a keyword
+ // If so, it must be quoted in the original query
+ strlwr(strcat(strcat(strcpy(name, " "), Name), " "));
+
+ if (!strstr(" update delete low_priority ignore quick from ", name))
+ strlwr(strcpy(name, Name)); // Not a keyword
+ else
+ strlwr(strcat(strcat(strcpy(name, qc), Name), qc));
+
+ if ((p = strstr(qrystr, name))) {
+ for (i = 0; i < p - qrystr; i++)
+ stmt[i] = (Qrystr[i] == '`') ? *qc : Qrystr[i];
+
+ stmt[i] = 0;
+ k = i + (int)strlen(Name);
+
+ if (qtd && *(p-1) == ' ')
+ strcat(strcat(strcat(stmt, qc), TableName), qc);
+ else
+ strcat(stmt, TableName);
+
+ i = (int)strlen(stmt);
+
+ do {
+ stmt[i++] = (Qrystr[k] == '`') ? *qc : Qrystr[k];
+ } while (Qrystr[k++]);
+
+ } else {
+ sprintf(g->Message, "Cannot use this %s command",
+ (Mode == MODE_UPDATE) ? "UPDATE" : "DELETE");
+ return NULL;
+ } // endif p
+
+ return stmt;
+ } // end of MakeCommand
+
+#if 0
+/***********************************************************************/
+/* MakeUpdate: make the SQL statement to send to ODBC connection. */
+/***********************************************************************/
+char *TDBODBC::MakeUpdate(PGLOBAL g)
+ {
+ char *qc, *stmt = NULL, cmd[8], tab[96], end[1024];
+
+ stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
+ memset(end, 0, sizeof(end));
+
+ if (sscanf(Qrystr, "%s `%[^`]`%1023c", cmd, tab, end) > 2 ||
+ sscanf(Qrystr, "%s \"%[^\"]\"%1023c", cmd, tab, end) > 2)
+ qc = Ocp->GetQuoteChar();
+ else if (sscanf(Qrystr, "%s %s%1023c", cmd, tab, end) > 2)
+ qc = (Quoted) ? Quote : "";
+ else {
+ strcpy(g->Message, "Cannot use this UPDATE command");
+ return NULL;
+ } // endif sscanf
+
+ assert(!stricmp(cmd, "update"));
+ strcat(strcat(strcat(strcpy(stmt, "UPDATE "), qc), TableName), qc);
+
+ for (int i = 0; end[i]; i++)
+ if (end[i] == '`')
+ end[i] = *qc;
+
+ strcat(stmt, end);
+ return stmt;
+ } // end of MakeUpdate
+
+/***********************************************************************/
+/* MakeDelete: make the SQL statement to send to ODBC connection. */
+/***********************************************************************/
+char *TDBODBC::MakeDelete(PGLOBAL g)
+ {
+ char *qc, *stmt = NULL, cmd[8], from[8], tab[96], end[512];
+
+ stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
+ memset(end, 0, sizeof(end));
+
+ if (sscanf(Qrystr, "%s %s `%[^`]`%511c", cmd, from, tab, end) > 2 ||
+ sscanf(Qrystr, "%s %s \"%[^\"]\"%511c", cmd, from, tab, end) > 2)
+ qc = Ocp->GetQuoteChar();
+ else if (sscanf(Qrystr, "%s %s %s%511c", cmd, from, tab, end) > 2)
+ qc = (Quoted) ? Quote : "";
+ else {
+ strcpy(g->Message, "Cannot use this DELETE command");
+ return NULL;
+ } // endif sscanf
+
+ assert(!stricmp(cmd, "delete") && !stricmp(from, "from"));
+ strcat(strcat(strcat(strcpy(stmt, "DELETE FROM "), qc), TableName), qc);
+
+ if (*end) {
+ for (int i = 0; end[i]; i++)
+ if (end[i] == '`')
+ end[i] = *qc;
+
+ strcat(stmt, end);
+ } // endif end
+
+ return stmt;
+ } // end of MakeDelete
+#endif // 0
+
+/***********************************************************************/
/* ResetSize: call by TDBMUL when calculating size estimate. */
/***********************************************************************/
void TDBODBC::ResetSize(void)
@@ -533,7 +658,7 @@ int TDBODBC::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0) {
// Make MariaDB happy
- MaxSize = 100;
+ MaxSize = (Mode == MODE_DELETE) ? 0 : 10;
#if 0
// This is unuseful and takes time
if (Srcdef) {
@@ -616,51 +741,40 @@ bool TDBODBC::OpenDB(PGLOBAL g)
if (Ocp->Open(Connect, Options) < 1)
return true;
+ else if (Quoted)
+ Quote = Ocp->GetQuoteChar();
Use = USE_OPEN; // Do it now in case we are recursively called
/*********************************************************************/
- /* Allocate whatever is used for getting results. */
+ /* Make the command and allocate whatever is used for getting results. */
/*********************************************************************/
if (Mode == MODE_READ) {
- /*******************************************************************/
- /* The issue here is that if max result size is needed, it must be */
- /* calculated before the result set for the final data retrieval is*/
- /* allocated and the final statement prepared so we call GetMaxSize*/
- /* here. It can be a waste of time if the max size is not needed */
- /* but currently we always are asking for it (for progress info). */
- /*******************************************************************/
- GetMaxSize(g); // Will be set for next call
-
- if (!Query)
- if ((Query = MakeSQL(g, false))) {
- for (PODBCCOL colp = (PODBCCOL)Columns;
- colp; colp = (PODBCCOL)colp->GetNext())
- if (!colp->IsSpecial())
- colp->AllocateBuffers(g, Rows);
-
- } else {
- Ocp->Close();
- return true;
- } // endif Query
+ if ((Query = MakeSQL(g, false))) {
+ for (PODBCCOL colp = (PODBCCOL)Columns; colp;
+ colp = (PODBCCOL)colp->GetNext())
+ if (!colp->IsSpecial())
+ colp->AllocateBuffers(g, Rows);
- if (!rc)
rc = ((Rows = Ocp->ExecDirectSQL(Query, (PODBCCOL)Columns)) < 0);
+ } // endif Query
} else if (Mode == MODE_INSERT) {
- if (!(rc = MakeInsert(g)))
+ if ((Query = MakeInsert(g))) {
if (Nparm != Ocp->PrepareSQL(Query)) {
strcpy(g->Message, MSG(PARM_CNT_MISS));
rc = true;
} else
rc = BindParameters(g);
- } else {
- strcpy(g->Message, "No DELETE/UPDATE of ODBC tablesd");
- return true;
- } // endelse
+ } // endif Query
+
+ } else if (Mode == MODE_UPDATE || Mode == MODE_DELETE)
+ Query = MakeCommand(g);
+ else
+ sprintf(g->Message, "Invalid mode %d", Mode);
- if (rc) {
+ if (!Query || rc) {
Ocp->Close();
return true;
} // endif rc
@@ -691,6 +805,21 @@ int TDBODBC::ReadDB(PGLOBAL g)
htrc("ODBC ReadDB: R%d Mode=%d key=%p link=%p Kindex=%p\n",
GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex);
+ if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
+ // Send the UPDATE/DELETE command to the remote table
+ if (!Ocp->ExecSQLcommand(Query)) {
+ sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
+
+ if (trace)
+ htrc("%s\n", g->Message);
+
+ PushWarning(g, this, 0); // 0 means a Note
+ return RC_EF; // Nothing else to do
+ } else
+ return RC_FX; // Error
+
+ } // endif Mode
+
if (To_Kindex) {
// Direct access of ODBC tables is not implemented yet
strcpy(g->Message, MSG(NO_ODBC_DIRECT));
@@ -720,7 +849,7 @@ int TDBODBC::ReadDB(PGLOBAL g)
/***********************************************************************/
int TDBODBC::WriteDB(PGLOBAL g)
{
- int n = Ocp->ExecuteSQL(false);
+ int n = Ocp->ExecuteSQL();
if (n < 0) {
AftRows = n;
@@ -736,8 +865,22 @@ int TDBODBC::WriteDB(PGLOBAL g)
/***********************************************************************/
int TDBODBC::DeleteDB(PGLOBAL g, int irc)
{
- strcpy(g->Message, MSG(NO_ODBC_DELETE));
- return RC_FX;
+ if (irc == RC_FX) {
+ // Send the DELETE (all) command to the remote table
+ if (!Ocp->ExecSQLcommand(Query)) {
+ sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
+
+ if (trace)
+ htrc("%s\n", g->Message);
+
+ PushWarning(g, this, 0); // 0 means a Note
+ return RC_OK; // This is a delete all
+ } else
+ return RC_FX; // Error
+
+ } else
+ return RC_OK; // Ignore
+
} // end of DeleteDB
/***********************************************************************/
@@ -751,6 +894,7 @@ void TDBODBC::CloseDB(PGLOBAL g)
// } // endif
if (Ocp)
+
Ocp->Close();
if (trace)
@@ -934,7 +1078,7 @@ void ODBCCOL::AllocateBuffers(PGLOBAL g, int rows)
if (Buf_Type == TYPE_DATE)
Bufp = PlugSubAlloc(g, NULL, rows * sizeof(TIMESTAMP_STRUCT));
else {
- Blkp = AllocValBlock(g, NULL, Buf_Type, rows, Long+1, 0, true, false);
+ Blkp = AllocValBlock(g, NULL, Buf_Type, rows, Long+1, 0, true, false, false);
Bufp = Blkp->GetValPointer();
} // endelse
@@ -1004,6 +1148,22 @@ void ODBCCOL::WriteColumn(PGLOBAL g)
/***********************************************************************/
/* Implementation of the TDBODBC class. */
/***********************************************************************/
+TDBXDBC::TDBXDBC(PODEF tdp) : TDBODBC(tdp)
+{
+ Cmdlist = NULL;
+ Cmdcol = NULL;
+ Mxr = tdp->Mxr;
+ Nerr = 0;
+} // end of TDBXDBC constructor
+
+TDBXDBC::TDBXDBC(PTDBXDBC tdbp) : TDBODBC(tdbp)
+{
+ Cmdlist = tdbp->Cmdlist;
+ Cmdcol = tdbp->Cmdcol;
+ Mxr = tdbp->Mxr;
+ Nerr = tdbp->Nerr;
+} // end of TDBXDBC copy constructor
+
PTDB TDBXDBC::CopyOne(PTABS t)
{
PTDB tp;
@@ -1036,23 +1196,15 @@ PCOL TDBXDBC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
/***********************************************************************/
/* MakeCMD: make the SQL statement to send to ODBC connection. */
/***********************************************************************/
-char *TDBXDBC::MakeCMD(PGLOBAL g)
+PCMD TDBXDBC::MakeCMD(PGLOBAL g)
{
- char *xcmd = NULL;
+ PCMD xcmd = NULL;
if (To_Filter) {
if (Cmdcol) {
- char col[128], cmd[1024];
- int n;
-
- memset(cmd, 0, sizeof(cmd));
- n = sscanf(To_Filter, "%s = '%1023c", col, cmd);
-
- if (n == 2 && !stricmp(col, Cmdcol)) {
- xcmd = (char*)PlugSubAlloc(g, NULL, strlen(cmd) + 1);
-
- strcpy(xcmd, cmd);
- xcmd[strlen(xcmd) - 1] = 0;
+ if (!stricmp(Cmdcol, To_Filter->Body) &&
+ (To_Filter->Op == OP_EQ || To_Filter->Op == OP_IN)) {
+ xcmd = To_Filter->Cmds;
} else
strcpy(g->Message, "Invalid command specification filter");
@@ -1062,7 +1214,7 @@ char *TDBXDBC::MakeCMD(PGLOBAL g)
} else if (!Srcdef)
strcpy(g->Message, "No Srcdef default command");
else
- xcmd = Srcdef;
+ xcmd = new(g) CMD(g, Srcdef);
return xcmd;
} // end of MakeCMD
@@ -1088,12 +1240,12 @@ bool TDBXDBC::BindParameters(PGLOBAL g)
#endif // 0
/***********************************************************************/
-/* XDBC GetMaxSize: returns table size (always one row). */
+/* XDBC GetMaxSize: returns table size (not always one row). */
/***********************************************************************/
int TDBXDBC::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0)
- MaxSize = 1;
+ MaxSize = 10; // Just a guess
return MaxSize;
} // end of GetMaxSize
@@ -1142,19 +1294,12 @@ bool TDBXDBC::OpenDB(PGLOBAL g)
/*********************************************************************/
/* Get the command to execute. */
/*********************************************************************/
- if (!(Query = MakeCMD(g))) {
+ if (!(Cmdlist = MakeCMD(g))) {
Ocp->Close();
return true;
} // endif Query
Rows = 1;
-
- if (Ocp->PrepareSQL(Query)) {
- strcpy(g->Message, "Parameters not supported");
- AftRows = -1;
- } else
- AftRows = 0;
-
return false;
} // end of OpenDB
@@ -1163,18 +1308,18 @@ bool TDBXDBC::OpenDB(PGLOBAL g)
/***********************************************************************/
int TDBXDBC::ReadDB(PGLOBAL g)
{
- if (trace)
- htrc("XDBC ReadDB: query=%s\n", SVP(Query));
+ if (Cmdlist) {
+ Query = Cmdlist->Cmd;
- if (Rows--) {
- if (!AftRows)
- AftRows = Ocp->ExecuteSQL(true);
+ if (Ocp->ExecSQLcommand(Query))
+ Nerr++;
- } else
+ Fpos++; // Used for progress info
+ Cmdlist = (Nerr > Mxr) ? NULL : Cmdlist->Next;
+ return RC_OK;
+ } else
return RC_EF;
- Fpos++; // Used for progress info
- return RC_OK;
} // end of ReadDB
/***********************************************************************/
@@ -1186,6 +1331,15 @@ int TDBXDBC::WriteDB(PGLOBAL g)
return RC_FX;
} // end of DeleteDB
+/***********************************************************************/
+/* Data Base delete line routine for ODBC access method. */
+/***********************************************************************/
+int TDBXDBC::DeleteDB(PGLOBAL g, int irc)
+ {
+ strcpy(g->Message, MSG(NO_ODBC_DELETE));
+ return RC_FX;
+ } // end of DeleteDB
+
/* --------------------------- XSRCCOL ------------------------------- */
/***********************************************************************/
diff --git a/storage/connect/tabodbc.h b/storage/connect/tabodbc.h
index b3577bce5be..10c7207b954 100644
--- a/storage/connect/tabodbc.h
+++ b/storage/connect/tabodbc.h
@@ -34,7 +34,7 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
PSZ GetTabowner(void) {return Tabowner;}
PSZ GetTabqual(void) {return Tabqual;}
PSZ GetSrcdef(void) {return Srcdef;}
- PSZ GetQchar(void) {return (Qchar && *Qchar) ? Qchar : NULL;}
+ int GetQuoted(void) {return Quoted;}
int GetCatver(void) {return Catver;}
int GetOptions(void) {return Options;}
@@ -50,8 +50,11 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
PSZ Tabqual; /* External table qualifier */
PSZ Srcdef; /* The source table SQL definition */
PSZ Qchar; /* Identifier quoting character */
+ PSZ Qrystr; /* The original query */
int Catver; /* ODBC version for catalog functions */
int Options; /* Open connection options */
+ int Quoted; /* Identifier quoting level */
+ int Mxr; /* Maxerr for an Exec table */
bool Xsrc; /* Execution type */
}; // end of ODBCDEF
@@ -96,13 +99,14 @@ class TDBODBC : public TDBASE {
protected:
// Internal functions
- int Decode(char *utf, char *buf, size_t n);
+ int Decode(char *utf, char *buf, size_t n);
char *MakeSQL(PGLOBAL g, bool cnt);
-//bool MakeUpdate(PGLOBAL g, PSELECT selist);
- bool MakeInsert(PGLOBAL g);
-//bool MakeDelete(PGLOBAL g);
+ char *MakeInsert(PGLOBAL g);
+ char *MakeCommand(PGLOBAL g);
//bool MakeFilter(PGLOBAL g, bool c);
bool BindParameters(PGLOBAL g);
+//char *MakeUpdate(PGLOBAL g);
+//char *MakeDelete(PGLOBAL g);
// Members
ODBConn *Ocp; // Points to an ODBC connection class
@@ -118,7 +122,9 @@ class TDBODBC : public TDBASE {
char *Quote; // The identifier quoting character
char *MulConn; // Used for multiple ODBC tables
char *DBQ; // The address part of Connect string
+ char *Qrystr; // The original query
int Options; // Connect options
+ int Quoted; // The identifier quoting level
int Fpos; // Position of last read record
int AftRows; // The number of affected rows
int Rows; // Rowset size
@@ -179,12 +185,12 @@ class TDBXDBC : public TDBODBC {
friend class XSRCCOL;
friend class ODBConn;
public:
- // Constructor
- TDBXDBC(PODEF tdp = NULL) : TDBODBC(tdp) {Cmdcol = NULL;}
- TDBXDBC(PTDBXDBC tdbp) : TDBODBC(tdbp) {Cmdcol = tdbp->Cmdcol;}
+ // Constructors
+ TDBXDBC(PODEF tdp = NULL);
+ TDBXDBC(PTDBXDBC tdbp);
// Implementation
-//virtual AMT GetAmType(void) {return TYPE_AM_ODBC;}
+ virtual AMT GetAmType(void) {return TYPE_AM_XDBC;}
virtual PTDB Duplicate(PGLOBAL g)
{return (PTDB)new(g) TDBXDBC(this);}
@@ -204,16 +210,19 @@ class TDBXDBC : public TDBODBC {
virtual bool OpenDB(PGLOBAL g);
virtual int ReadDB(PGLOBAL g);
virtual int WriteDB(PGLOBAL g);
-//virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual int DeleteDB(PGLOBAL g, int irc);
//virtual void CloseDB(PGLOBAL g);
protected:
// Internal functions
- char *MakeCMD(PGLOBAL g);
+ PCMD MakeCMD(PGLOBAL g);
//bool BindParameters(PGLOBAL g);
// Members
+ PCMD Cmdlist; // The commands to execute
char *Cmdcol; // The name of the Xsrc command column
+ int Mxr; // Maximum errors before closing
+ int Nerr; // Number of errors so far
}; // end of class TDBXDBC
/***********************************************************************/
diff --git a/storage/connect/tabpivot.cpp b/storage/connect/tabpivot.cpp
index c28091df34f..bc0dbb9bfc9 100644
--- a/storage/connect/tabpivot.cpp
+++ b/storage/connect/tabpivot.cpp
@@ -607,6 +607,8 @@ bool TDBPIVOT::OpenDB(PGLOBAL g)
if (Tdbp->OpenDB(g))
return TRUE;
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
/*********************************************************************/
/* Make all required pivot columns for object views. */
/*********************************************************************/
diff --git a/storage/connect/tabtbl.cpp b/storage/connect/tabtbl.cpp
index 2ed6c150d85..56305871c69 100644
--- a/storage/connect/tabtbl.cpp
+++ b/storage/connect/tabtbl.cpp
@@ -295,15 +295,18 @@ bool TDBTBL::InitTableList(PGLOBAL g)
/***********************************************************************/
bool TDBTBL::TestFil(PGLOBAL g, PFIL filp, PTABLE tabp)
{
- char *fil, op[8], tn[NAME_LEN];
+ char *body, *fil, op[8], tn[NAME_LEN];
bool neg;
if (!filp)
return TRUE;
- else if (strstr(filp, " OR ") || strstr(filp, " AND "))
+ else
+ body = filp->Body;
+
+ if (strstr(body, " OR ") || strstr(body, " AND "))
return TRUE; // Not handled yet
else
- fil = filp + (*filp == '(' ? 1 : 0);
+ fil = body + (*body == '(' ? 1 : 0);
if (sscanf(fil, "TABID %s", op) != 1)
return TRUE; // ignore invalid filter
diff --git a/storage/connect/tabutil.cpp b/storage/connect/tabutil.cpp
index 2405b1853a2..fa4c8667a70 100644
--- a/storage/connect/tabutil.cpp
+++ b/storage/connect/tabutil.cpp
@@ -495,6 +495,7 @@ bool TDBPRX::OpenDB(PGLOBAL g)
if (Tdbp->OpenDB(g))
return TRUE;
+ Use = USE_OPEN;
return FALSE;
} // end of OpenDB
diff --git a/storage/connect/tabutil.h b/storage/connect/tabutil.h
index a6202950390..7b2161a4b8b 100644
--- a/storage/connect/tabutil.h
+++ b/storage/connect/tabutil.h
@@ -6,8 +6,6 @@
//#include "tabtbl.h"
-#define TYPE_AM_PRX (AMT)129
-
typedef class PRXDEF *PPRXDEF;
typedef class TDBPRX *PTDBPRX;
typedef class XXLCOL *PXXLCOL;
diff --git a/storage/connect/tabvct.cpp b/storage/connect/tabvct.cpp
index 8c2474d61a2..8b7d8ba91eb 100644
--- a/storage/connect/tabvct.cpp
+++ b/storage/connect/tabvct.cpp
@@ -81,7 +81,7 @@ char *strerror(int num);
/* Conversion of block values allowed conditionally for insert only. */
/***********************************************************************/
PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int,
- bool check = true, bool blank = true);
+ bool check = true, bool blank = true, bool un = false);
/* --------------------------- Class VCTDEF -------------------------- */
diff --git a/storage/connect/tabwmi.cpp b/storage/connect/tabwmi.cpp
index 1c626a06256..5fb349fa5c0 100644
--- a/storage/connect/tabwmi.cpp
+++ b/storage/connect/tabwmi.cpp
@@ -480,18 +480,19 @@ bool TDBWMI::Initialize(PGLOBAL g)
/***********************************************************************/
void TDBWMI::DoubleSlash(PGLOBAL g)
{
- if (To_Filter && strchr(To_Filter, '\\')) {
- char *buf = (char*)PlugSubAlloc(g, NULL, strlen(To_Filter) * 2);
+ if (To_Filter && strchr(To_Filter->Body, '\\')) {
+ char *body = To_Filter->Body;
+ char *buf = (char*)PlugSubAlloc(g, NULL, strlen(body) * 2);
int i = 0, k = 0;
do {
- if (To_Filter[i] == '\\')
+ if (body[i] == '\\')
buf[k++] = '\\';
- buf[k++] = To_Filter[i];
- } while (To_Filter[i++]);
+ buf[k++] = body[i];
+ } while (body[i++]);
- To_Filter = buf;
+ To_Filter->Body = buf;
} // endif To_Filter
} // end of DoubleSlash
@@ -539,13 +540,13 @@ char *TDBWMI::MakeWQL(PGLOBAL g)
// Below 14 is length of 'select ' + length of ' from ' + 1
len = (strlen(colist) + strlen(Wclass) + 14);
- len += (To_Filter ? strlen(To_Filter) + 7 : 0);
+ len += (To_Filter ? strlen(To_Filter->Body) + 7 : 0);
wql = (char*)PlugSubAlloc(g, NULL, len);
strcat(strcat(strcpy(wql, "SELECT "), colist), " FROM ");
strcat(wql, Wclass);
if (To_Filter)
- strcat(strcat(wql, " WHERE "), To_Filter);
+ strcat(strcat(wql, " WHERE "), To_Filter->Body);
return wql;
} // end of MakeWQL
@@ -666,6 +667,8 @@ bool TDBWMI::OpenDB(PGLOBAL g)
} else
DoubleSlash(g);
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
/*********************************************************************/
/* Initialize the WMI processing. */
/*********************************************************************/
diff --git a/storage/connect/tabxcl.cpp b/storage/connect/tabxcl.cpp
index 33ec8984219..41a4283fd22 100644
--- a/storage/connect/tabxcl.cpp
+++ b/storage/connect/tabxcl.cpp
@@ -193,6 +193,7 @@ bool TDBXCL::OpenDB(PGLOBAL g)
if (Tdbp->OpenDB(g))
return TRUE;
+ Use = USE_OPEN;
return FALSE;
} // end of OpenDB
diff --git a/storage/connect/tabxcl.h b/storage/connect/tabxcl.h
index 0189775cd8d..24122573100 100644
--- a/storage/connect/tabxcl.h
+++ b/storage/connect/tabxcl.h
@@ -3,8 +3,6 @@
#include "tabutil.h"
-#define TYPE_AM_XCOL (AMT)124
-
typedef class XCLDEF *PXCLDEF;
typedef class TDBXCL *PTDBXCL;
typedef class XCLCOL *PXCLCOL;
diff --git a/storage/connect/valblk.cpp b/storage/connect/valblk.cpp
index 06c7776d2f5..7fabad88794 100644
--- a/storage/connect/valblk.cpp
+++ b/storage/connect/valblk.cpp
@@ -1,5 +1,5 @@
/************ Valblk C++ Functions Source Code File (.CPP) *************/
-/* Name: VALBLK.CPP Version 1.7 */
+/* Name: VALBLK.CPP Version 2.0 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
/* */
@@ -16,7 +16,7 @@
/* types of objects, we shall have more classes to update. */
/* This is why we are now using a template class for many types. */
/* Currently the only implemented types are PSZ, chars, int, short, */
-/* DATE, longlong, and double. Shortly we should add more types. */
+/* DATE, longlong, double and tiny. Fix numeric ones can be unsigned. */
/***********************************************************************/
/***********************************************************************/
@@ -46,7 +46,7 @@
/* AllocValBlock: allocate a VALBLK according to type. */
/***********************************************************************/
PVBLK AllocValBlock(PGLOBAL g, void *mp, int type, int nval, int len,
- int prec, bool check, bool blank)
+ int prec, bool check, bool blank, bool un)
{
PVBLK blkp;
@@ -64,22 +64,38 @@ PVBLK AllocValBlock(PGLOBAL g, void *mp, int type, int nval, int len,
break;
case TYPE_SHORT:
- blkp = new(g) TYPBLK<short>(mp, nval, type);
+ if (un)
+ blkp = new(g) TYPBLK<ushort>(mp, nval, type, 0, true);
+ else
+ blkp = new(g) TYPBLK<short>(mp, nval, type);
+
break;
case TYPE_INT:
- blkp = new(g) TYPBLK<int>(mp, nval, type);
+ if (un)
+ blkp = new(g) TYPBLK<uint>(mp, nval, type, 0, true);
+ else
+ blkp = new(g) TYPBLK<int>(mp, nval, type);
+
break;
case TYPE_DATE: // ?????
blkp = new(g) DATBLK(mp, nval);
break;
case TYPE_BIGINT:
- blkp = new(g) TYPBLK<longlong>(mp, nval, type);
+ if (un)
+ blkp = new(g) TYPBLK<ulonglong>(mp, nval, type, 0, true);
+ else
+ blkp = new(g) TYPBLK<longlong>(mp, nval, type);
+
break;
case TYPE_FLOAT:
- blkp = new(g) TYPBLK<double>(mp, nval, prec, type);
+ blkp = new(g) TYPBLK<double>(mp, nval, type, prec);
break;
case TYPE_TINY:
- blkp = new(g) TYPBLK<char>(mp, nval, type);
+ if (un)
+ blkp = new(g) TYPBLK<uchar>(mp, nval, type, 0, true);
+ else
+ blkp = new(g) TYPBLK<char>(mp, nval, type);
+
break;
default:
sprintf(g->Message, MSG(BAD_VALBLK_TYPE), type);
@@ -95,12 +111,13 @@ PVBLK AllocValBlock(PGLOBAL g, void *mp, int type, int nval, int len,
/***********************************************************************/
/* Constructor. */
/***********************************************************************/
-VALBLK::VALBLK(void *mp, int type, int nval)
+VALBLK::VALBLK(void *mp, int type, int nval, bool un)
{
Blkp = mp;
To_Nulls = NULL;
Check = true;
Nullable = false;
+ Unsigned = un;
Type = type;
Nval = nval;
Prec = 0;
@@ -195,23 +212,15 @@ void VALBLK::ChkTyp(PVBLK vb)
/* -------------------------- Class TYPBLK --------------------------- */
/***********************************************************************/
-/* Constructors. */
+/* Constructor. */
/***********************************************************************/
template <class TYPE>
-TYPBLK<TYPE>::TYPBLK(void *mp, int nval, int type)
- : VALBLK(mp, type, nval), Typp((TYPE*&)Blkp)
- {
- Fmt = GetFmt(Type);
- } // end of TYPBLK constructor
-
-template <class TYPE>
-TYPBLK<TYPE>::TYPBLK(void *mp, int nval, int prec, int type)
- : VALBLK(mp, type, nval), Typp((TYPE*&)Blkp)
+TYPBLK<TYPE>::TYPBLK(void *mp, int nval, int type, int prec, bool un)
+ : VALBLK(mp, type, nval, un), Typp((TYPE*&)Blkp)
{
- DBUG_ASSERT(Type == TYPE_FLOAT);
Prec = prec;
Fmt = GetFmt(Type);
- } // end of DBLBLK constructor
+ } // end of TYPBLK constructor
/***********************************************************************/
/* Initialization routine. */
@@ -250,14 +259,26 @@ int TYPBLK<int>::GetTypedValue(PVAL valp)
{return valp->GetIntValue();}
template <>
+uint TYPBLK<uint>::GetTypedValue(PVAL valp)
+ {return valp->GetUIntValue();}
+
+template <>
short TYPBLK<short>::GetTypedValue(PVAL valp)
{return valp->GetShortValue();}
template <>
+ushort TYPBLK<ushort>::GetTypedValue(PVAL valp)
+ {return valp->GetUShortValue();}
+
+template <>
longlong TYPBLK<longlong>::GetTypedValue(PVAL valp)
{return valp->GetBigintValue();}
template <>
+ulonglong TYPBLK<ulonglong>::GetTypedValue(PVAL valp)
+ {return valp->GetUBigintValue();}
+
+template <>
double TYPBLK<double>::GetTypedValue(PVAL valp)
{return valp->GetFloatValue();}
@@ -265,6 +286,10 @@ template <>
char TYPBLK<char>::GetTypedValue(PVAL valp)
{return valp->GetTinyValue();}
+template <>
+uchar TYPBLK<uchar>::GetTypedValue(PVAL valp)
+ {return valp->GetUTinyValue();}
+
/***********************************************************************/
/* Set one value in a block from a zero terminated string. */
/***********************************************************************/
@@ -286,13 +311,21 @@ void TYPBLK<TYPE>::SetValue(PSZ p, int n)
template <>
int TYPBLK<int>::GetTypedValue(PSZ p) {return atol(p);}
template <>
+uint TYPBLK<uint>::GetTypedValue(PSZ p) {return (unsigned)atol(p);}
+template <>
short TYPBLK<short>::GetTypedValue(PSZ p) {return (short)atoi(p);}
template <>
+ushort TYPBLK<ushort>::GetTypedValue(PSZ p) {return (ushort)atoi(p);}
+template <>
longlong TYPBLK<longlong>::GetTypedValue(PSZ p) {return atoll(p);}
template <>
+ulonglong TYPBLK<ulonglong>::GetTypedValue(PSZ p) {return (unsigned)atoll(p);}
+template <>
double TYPBLK<double>::GetTypedValue(PSZ p) {return atof(p);}
template <>
char TYPBLK<char>::GetTypedValue(PSZ p) {return (char)atoi(p);}
+template <>
+uchar TYPBLK<uchar>::GetTypedValue(PSZ p) {return (uchar)atoi(p);}
/***********************************************************************/
/* Set one value in a block from an array of characters. */
@@ -334,14 +367,26 @@ int TYPBLK<int>::GetTypedValue(PVBLK blk, int n)
{return blk->GetIntValue(n);}
template <>
+uint TYPBLK<uint>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetUIntValue(n);}
+
+template <>
short TYPBLK<short>::GetTypedValue(PVBLK blk, int n)
{return blk->GetShortValue(n);}
template <>
+ushort TYPBLK<ushort>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetUShortValue(n);}
+
+template <>
longlong TYPBLK<longlong>::GetTypedValue(PVBLK blk, int n)
{return blk->GetBigintValue(n);}
template <>
+ulonglong TYPBLK<ulonglong>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetUBigintValue(n);}
+
+template <>
double TYPBLK<double>::GetTypedValue(PVBLK blk, int n)
{return blk->GetFloatValue(n);}
@@ -349,6 +394,10 @@ template <>
char TYPBLK<char>::GetTypedValue(PVBLK blk, int n)
{return blk->GetTinyValue(n);}
+template <>
+uchar TYPBLK<uchar>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetUTinyValue(n);}
+
#if 0
/***********************************************************************/
/* Set many values in a block from values in another block. */
@@ -517,6 +566,14 @@ short CHRBLK::GetShortValue(int n)
} // end of GetShortValue
/***********************************************************************/
+/* Return the value of the nth element converted to ushort. */
+/***********************************************************************/
+ushort CHRBLK::GetUShortValue(int n)
+ {
+ return (ushort)atoi((char *)GetValPtrEx(n));
+ } // end of GetShortValue
+
+/***********************************************************************/
/* Return the value of the nth element converted to int. */
/***********************************************************************/
int CHRBLK::GetIntValue(int n)
@@ -525,6 +582,14 @@ int CHRBLK::GetIntValue(int n)
} // end of GetIntValue
/***********************************************************************/
+/* Return the value of the nth element converted to uint. */
+/***********************************************************************/
+uint CHRBLK::GetUIntValue(int n)
+ {
+ return (unsigned)atol((char *)GetValPtrEx(n));
+ } // end of GetIntValue
+
+/***********************************************************************/
/* Return the value of the nth element converted to big int. */
/***********************************************************************/
longlong CHRBLK::GetBigintValue(int n)
@@ -533,6 +598,14 @@ longlong CHRBLK::GetBigintValue(int n)
} // end of GetBigintValue
/***********************************************************************/
+/* Return the value of the nth element converted to unsigned big int. */
+/***********************************************************************/
+ulonglong CHRBLK::GetUBigintValue(int n)
+ {
+ return (unsigned)atoll((char *)GetValPtrEx(n));
+ } // end of GetBigintValue
+
+/***********************************************************************/
/* Return the value of the nth element converted to double. */
/***********************************************************************/
double CHRBLK::GetFloatValue(int n)
@@ -549,6 +622,14 @@ char CHRBLK::GetTinyValue(int n)
} // end of GetTinyValue
/***********************************************************************/
+/* Return the value of the nth element converted to unsigned tiny int.*/
+/***********************************************************************/
+uchar CHRBLK::GetUTinyValue(int n)
+ {
+ return (uchar)atoi((char *)GetValPtrEx(n));
+ } // end of GetTinyValue
+
+/***********************************************************************/
/* Set one value in a block. */
/***********************************************************************/
void CHRBLK::SetValue(PVAL valp, int n)
diff --git a/storage/connect/valblk.h b/storage/connect/valblk.h
index d9286b72f9f..fb3b0b7e72b 100644
--- a/storage/connect/valblk.h
+++ b/storage/connect/valblk.h
@@ -1,5 +1,5 @@
/*************** Valblk H Declares Source Code File (.H) ***************/
-/* Name: VALBLK.H Version 1.9 */
+/* Name: VALBLK.H Version 2.0 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
/* */
@@ -18,8 +18,9 @@
/***********************************************************************/
/* Utility used to allocate value blocks. */
/***********************************************************************/
-DllExport PVBLK AllocValBlock(PGLOBAL, void*, int, int, int, int, bool, bool);
-const char *GetFmt(int type);
+DllExport PVBLK AllocValBlock(PGLOBAL, void*, int, int, int, int,
+ bool, bool, bool);
+const char *GetFmt(int type, bool un = false);
/***********************************************************************/
/* Class VALBLK represent a base class for variable blocks. */
@@ -28,7 +29,7 @@ class VALBLK : public BLOCK {
//friend void SemColData(PGLOBAL g, PSEM semp);
public:
// Constructors
- VALBLK(void *mp, int type, int nval);
+ VALBLK(void *mp, int type, int nval, bool un = false);
// Implementation
int GetNval(void) {return Nval;}
@@ -48,10 +49,14 @@ class VALBLK : public BLOCK {
virtual int GetVlen(void) = 0;
virtual PSZ GetCharValue(int n);
virtual short GetShortValue(int n) = 0;
+ virtual ushort GetUShortValue(int n) = 0;
virtual int GetIntValue(int n) = 0;
+ virtual uint GetUIntValue(int n) = 0;
virtual longlong GetBigintValue(int n) = 0;
+ virtual ulonglong GetUBigintValue(int n) = 0;
virtual double GetFloatValue(int n) = 0;
virtual char GetTinyValue(int n) = 0;
+ virtual uchar GetUTinyValue(int n) = 0;
virtual void ReAlloc(void *mp, int n) {Blkp = mp; Nval = n;}
virtual void Reset(int n) = 0;
virtual bool SetFormat(PGLOBAL g, PSZ fmt, int len, int year = 0);
@@ -60,10 +65,14 @@ class VALBLK : public BLOCK {
// Methods
virtual void SetValue(short sval, int n) {assert(false);}
+ virtual void SetValue(ushort sval, int n) {assert(false);}
virtual void SetValue(int lval, int n) {assert(false);}
+ virtual void SetValue(uint lval, int n) {assert(false);}
virtual void SetValue(longlong lval, int n) {assert(false);}
+ virtual void SetValue(ulonglong lval, int n) {assert(false);}
virtual void SetValue(double fval, int n) {assert(false);}
virtual void SetValue(char cval, int n) {assert(false);}
+ virtual void SetValue(uchar cval, int n) {assert(false);}
virtual void SetValue(PSZ sp, int n) {assert(false);}
virtual void SetValue(char *sp, uint len, int n) {assert(false);}
virtual void SetValue(PVAL valp, int n) = 0;
@@ -94,6 +103,7 @@ class VALBLK : public BLOCK {
void *Blkp; // To value block
bool Check; // If true SetValue types must match
bool Nullable; // True if values can be null
+ bool Unsigned; // True if values are unsigned
int Type; // Type of individual values
int Nval; // Max number of values in block
int Prec; // Precision of float values
@@ -106,18 +116,22 @@ template <class TYPE>
class TYPBLK : public VALBLK {
public:
// Constructors
- TYPBLK(void *mp, int size, int type);
- TYPBLK(void *mp, int size, int prec, int type);
+ TYPBLK(void *mp, int size, int type, int prec = 0, bool un = false);
+//TYPBLK(void *mp, int size, int prec, int type);
// Implementation
virtual void Init(PGLOBAL g, bool check);
virtual int GetVlen(void) {return sizeof(TYPE);}
//virtual PSZ GetCharValue(int n);
virtual short GetShortValue(int n) {return (short)Typp[n];}
+ virtual ushort GetUShortValue(int n) {return (ushort)Typp[n];}
virtual int GetIntValue(int n) {return (int)Typp[n];}
+ virtual uint GetUIntValue(int n) {return (uint)Typp[n];}
virtual longlong GetBigintValue(int n) {return (longlong)Typp[n];}
+ virtual ulonglong GetUBigintValue(int n) {return (ulonglong)Typp[n];}
virtual double GetFloatValue(int n) {return (double)Typp[n];}
virtual char GetTinyValue(int n) {return (char)Typp[n];}
+ virtual uchar GetUTinyValue(int n) {return (uchar)Typp[n];}
virtual void Reset(int n) {Typp[n] = 0;}
// Methods
@@ -125,14 +139,22 @@ class TYPBLK : public VALBLK {
virtual void SetValue(char *sp, uint len, int n);
virtual void SetValue(short sval, int n)
{Typp[n] = (TYPE)sval; SetNull(n, false);}
+ virtual void SetValue(ushort sval, int n)
+ {Typp[n] = (TYPE)sval; SetNull(n, false);}
virtual void SetValue(int lval, int n)
{Typp[n] = (TYPE)lval; SetNull(n, false);}
+ virtual void SetValue(uint lval, int n)
+ {Typp[n] = (TYPE)lval; SetNull(n, false);}
virtual void SetValue(longlong lval, int n)
{Typp[n] = (TYPE)lval; SetNull(n, false);}
+ virtual void SetValue(ulonglong lval, int n)
+ {Typp[n] = (TYPE)lval; SetNull(n, false);}
virtual void SetValue(double fval, int n)
{Typp[n] = (TYPE)fval; SetNull(n, false);}
virtual void SetValue(char cval, int n)
{Typp[n] = (TYPE)cval; SetNull(n, false);}
+ virtual void SetValue(uchar cval, int n)
+ {Typp[n] = (TYPE)cval; SetNull(n, false);}
virtual void SetValue(PVAL valp, int n);
virtual void SetValue(PVBLK pv, int n1, int n2);
//virtual void SetValues(PVBLK pv, int k, int n);
@@ -168,10 +190,14 @@ class CHRBLK : public VALBLK {
virtual int GetVlen(void) {return Long;}
virtual PSZ GetCharValue(int n);
virtual short GetShortValue(int n);
+ virtual ushort GetUShortValue(int n);
virtual int GetIntValue(int n);
+ virtual uint GetUIntValue(int n);
virtual longlong GetBigintValue(int n);
+ virtual ulonglong GetUBigintValue(int n);
virtual double GetFloatValue(int n);
virtual char GetTinyValue(int n);
+ virtual uchar GetUTinyValue(int n);
virtual void Reset(int n);
virtual void SetPrec(int p) {Ci = (p != 0);}
virtual bool IsCi(void) {return Ci;}
@@ -217,10 +243,14 @@ class STRBLK : public VALBLK {
virtual int GetVlen(void) {return sizeof(PSZ);}
virtual PSZ GetCharValue(int n) {return Strp[n];}
virtual short GetShortValue(int n) {return (short)atoi(Strp[n]);}
+ virtual ushort GetUShortValue(int n) {return (ushort)atoi(Strp[n]);}
virtual int GetIntValue(int n) {return atol(Strp[n]);}
+ virtual uint GetUIntValue(int n) {return (unsigned)atol(Strp[n]);}
virtual longlong GetBigintValue(int n) {return atoll(Strp[n]);}
+ virtual ulonglong GetUBigintValue(int n) {return (unsigned)atoll(Strp[n]);}
virtual double GetFloatValue(int n) {return atof(Strp[n]);}
virtual char GetTinyValue(int n) {return (char)atoi(Strp[n]);}
+ virtual uchar GetUTinyValue(int n) {return (uchar)atoi(Strp[n]);}
virtual void Reset(int n) {Strp[n] = NULL;}
// Methods
diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp
index e59575534c9..077df346459 100644
--- a/storage/connect/value.cpp
+++ b/storage/connect/value.cpp
@@ -1,5 +1,5 @@
/************* Value C++ Functions Source Code File (.CPP) *************/
-/* Name: VALUE.CPP Version 2.2 */
+/* Name: VALUE.CPP Version 2.3 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2001-2013 */
/* */
@@ -20,7 +20,7 @@
/* functions used on one family only. The drawback is that for new */
/* types of objects, we shall have more classes to update. */
/* Currently the only implemented types are STRING, INT, SHORT, TINY, */
-/* DATE and LONGLONG. Shortly we should add at least UNSIGNED types. */
+/* DATE and LONGLONG. Recently we added some UNSIGNED types. */
/***********************************************************************/
/***********************************************************************/
@@ -92,40 +92,12 @@ PSZ strlwr(PSZ s);
}
#endif // !WIN32
-#ifdef NOT_USED
-/***********************************************************************/
-/* Returns the bitmap representing the conditions that must not be */
-/* met when returning from TestValue for a given operator. */
-/* Bit one is EQ, bit 2 is LT, and bit 3 is GT. */
-/***********************************************************************/
-static BYTE OpBmp(PGLOBAL g, OPVAL opc)
- {
- BYTE bt;
-
- switch (opc) {
- case OP_IN:
- case OP_EQ: bt = 0x06; break;
- case OP_NE: bt = 0x01; break;
- case OP_GT: bt = 0x03; break;
- case OP_GE: bt = 0x02; break;
- case OP_LT: bt = 0x05; break;
- case OP_LE: bt = 0x04; break;
- case OP_EXIST: bt = 0x00; break;
- default:
- sprintf(g->Message, MSG(BAD_FILTER_OP), opc);
- longjmp(g->jumper[g->jump_level], 777);
- } // endswitch opc
-
- return bt;
- } // end of OpBmp
-#endif
-
/***********************************************************************/
/* GetTypeName: returns the PlugDB internal type name. */
/***********************************************************************/
PSZ GetTypeName(int type)
{
- PSZ name = "UNKNOWN";
+ PSZ name;
switch (type) {
case TYPE_STRING: name = "CHAR"; break;
@@ -135,6 +107,7 @@ PSZ GetTypeName(int type)
case TYPE_DATE: name = "DATE"; break;
case TYPE_FLOAT: name = "FLOAT"; break;
case TYPE_TINY: name = "TINY"; break;
+ default: name = "UNKNOWN"; break;
} // endswitch type
return name;
@@ -153,7 +126,6 @@ int GetTypeSize(int type, int len)
case TYPE_DATE: len = sizeof(int); break;
case TYPE_FLOAT: len = sizeof(double); break;
case TYPE_TINY: len = sizeof(char); break;
- break;
default: len = 0;
} // endswitch type
@@ -236,21 +208,22 @@ bool IsTypeNum(int type)
/***********************************************************************/
/* GetFmt: returns the format to use with a typed value. */
/***********************************************************************/
-const char *GetFmt(int type)
+const char *GetFmt(int type, bool un)
{
const char *fmt;
switch (type) {
- case TYPE_STRING: fmt = "%s"; break;
- case TYPE_SHORT: fmt = "%hd"; break;
- case TYPE_BIGINT: fmt = "%lld"; break;
- case TYPE_FLOAT: fmt = "%.*lf"; break;
- default: fmt = "%d"; break;
+ case TYPE_STRING: fmt = "%s"; break;
+ case TYPE_SHORT: fmt = (un) ? "%hu" : "%hd"; break;
+ case TYPE_BIGINT: fmt = (un) ? "%llu" : "%lld"; break;
+ case TYPE_FLOAT: fmt = "%.*lf"; break;
+ default: fmt = (un) ? "%u" : "%d"; break;
} // endswitch Type
return fmt;
} // end of GetFmt
+#if 0
/***********************************************************************/
/* ConvertType: what this function does is to determine the type to */
/* which should be converted a value so no precision would be lost. */
@@ -297,6 +270,7 @@ int ConvertType(int target, int type, CONV kind, bool match)
} // endswitch kind
} // end of ConvertType
+#endif // 0
/***********************************************************************/
/* AllocateConstant: allocates a constant Value. */
@@ -322,7 +296,7 @@ PVAL AllocateValue(PGLOBAL g, void *value, short type)
valp = new(g) TYPVAL<longlong>(*(longlong*)value, TYPE_BIGINT);
break;
case TYPE_FLOAT:
- valp = new(g) TYPVAL<double>(*(double *)value, TYPE_FLOAT);
+ valp = new(g) TYPVAL<double>(*(double *)value, TYPE_FLOAT, 2);
break;
case TYPE_TINY:
valp = new(g) TYPVAL<char>(*(char *)value, TYPE_TINY);
@@ -339,8 +313,7 @@ PVAL AllocateValue(PGLOBAL g, void *value, short type)
/***********************************************************************/
/* Allocate a variable Value according to type, length and precision. */
/***********************************************************************/
-PVAL AllocateValue(PGLOBAL g, int type, int len, int prec,
- PSZ dom, PCATLG cat)
+PVAL AllocateValue(PGLOBAL g, int type, int len, int prec, PSZ fmt)
{
PVAL valp;
@@ -349,22 +322,38 @@ PVAL AllocateValue(PGLOBAL g, int type, int len, int prec,
valp = new(g) TYPVAL<PSZ>(g, (PSZ)NULL, len, prec);
break;
case TYPE_DATE:
- valp = new(g) DTVAL(g, len, prec, dom);
+ valp = new(g) DTVAL(g, len, prec, fmt);
break;
case TYPE_INT:
- valp = new(g) TYPVAL<int>((int)0, TYPE_INT);
+ if (prec)
+ valp = new(g) TYPVAL<uint>((uint)0, TYPE_INT, 0, true);
+ else
+ valp = new(g) TYPVAL<int>((int)0, TYPE_INT);
+
break;
case TYPE_BIGINT:
- valp = new(g) TYPVAL<longlong>((longlong)0, TYPE_BIGINT);
+ if (prec)
+ valp = new(g) TYPVAL<ulonglong>((ulonglong)0, TYPE_BIGINT, 0, true);
+ else
+ valp = new(g) TYPVAL<longlong>((longlong)0, TYPE_BIGINT);
+
break;
case TYPE_SHORT:
- valp = new(g) TYPVAL<short>((short)0, TYPE_SHORT);
+ if (prec)
+ valp = new(g) TYPVAL<ushort>((ushort)0, TYPE_SHORT, 0, true);
+ else
+ valp = new(g) TYPVAL<short>((short)0, TYPE_SHORT);
+
break;
case TYPE_FLOAT:
- valp = new(g) TYPVAL<double>(0.0, prec, TYPE_FLOAT);
+ valp = new(g) TYPVAL<double>(0.0, TYPE_FLOAT, prec);
break;
case TYPE_TINY:
- valp = new(g) TYPVAL<char>((char)0, TYPE_TINY);
+ if (prec)
+ valp = new(g) TYPVAL<uchar>((uchar)0, TYPE_TINY, 0, true);
+ else
+ valp = new(g) TYPVAL<char>((char)0, TYPE_TINY);
+
break;
default:
sprintf(g->Message, MSG(BAD_VALUE_TYPE), type);
@@ -379,9 +368,10 @@ PVAL AllocateValue(PGLOBAL g, int type, int len, int prec,
/* Allocate a constant Value converted to newtype. */
/* Can also be used to copy a Value eventually converted. */
/***********************************************************************/
-PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype)
+PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype, int uns)
{
- PSZ p, sp;
+ PSZ p, sp;
+ bool un = (uns < 0) ? false : (uns > 0) ? true : valp->IsUnsigned();
if (newtype == TYPE_VOID) // Means allocate a value of the same type
newtype = valp->GetType();
@@ -395,23 +385,43 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype)
valp = new(g) TYPVAL<PSZ>(g, p, valp->GetValLen(), valp->GetValPrec());
break;
- case TYPE_SHORT:
- valp = new(g) TYPVAL<short>(valp->GetShortValue(), TYPE_SHORT);
+ case TYPE_SHORT:
+ if (un)
+ valp = new(g) TYPVAL<ushort>(valp->GetUShortValue(),
+ TYPE_SHORT, 0, true);
+ else
+ valp = new(g) TYPVAL<short>(valp->GetShortValue(), TYPE_SHORT);
+
break;
case TYPE_INT:
- valp = new(g) TYPVAL<int>(valp->GetIntValue(), TYPE_INT);
+ if (un)
+ valp = new(g) TYPVAL<uint>(valp->GetUIntValue(), TYPE_INT, 0, true);
+ else
+ valp = new(g) TYPVAL<int>(valp->GetIntValue(), TYPE_INT);
+
break;
case TYPE_BIGINT:
- valp = new(g) TYPVAL<longlong>(valp->GetBigintValue(), TYPE_BIGINT);
+ if (un)
+ valp = new(g) TYPVAL<ulonglong>(valp->GetUBigintValue(),
+ TYPE_BIGINT, 0, true);
+ else
+ valp = new(g) TYPVAL<longlong>(valp->GetBigintValue(), TYPE_BIGINT);
+
break;
case TYPE_DATE:
valp = new(g) DTVAL(g, valp->GetIntValue());
break;
case TYPE_FLOAT:
- valp = new(g) TYPVAL<double>(valp->GetFloatValue(), TYPE_FLOAT);
+ valp = new(g) TYPVAL<double>(valp->GetFloatValue(), TYPE_FLOAT,
+ valp->GetValPrec());
break;
case TYPE_TINY:
- valp = new(g) TYPVAL<char>(valp->GetTinyValue(), TYPE_TINY);
+ if (un)
+ valp = new(g) TYPVAL<uchar>(valp->GetUTinyValue(),
+ TYPE_TINY, 0, true);
+ else
+ valp = new(g) TYPVAL<char>(valp->GetTinyValue(), TYPE_TINY);
+
break;
default:
sprintf(g->Message, MSG(BAD_VALUE_TYPE), newtype);
@@ -428,14 +438,15 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype)
/***********************************************************************/
/* Class VALUE protected constructor. */
/***********************************************************************/
-VALUE::VALUE(int type) : Type(type)
+VALUE::VALUE(int type, bool un) : Type(type)
{
- Fmt = GetFmt(Type);
- Xfmt = GetXfmt();
Null = false;
- Nullable = false;
+ Nullable = false;
+ Unsigned = un;
Clen = 0;
Prec = 0;
+ Fmt = GetFmt(Type, Unsigned);
+ Xfmt = GetXfmt();
} // end of VALUE constructor
/***********************************************************************/
@@ -446,11 +457,11 @@ const char *VALUE::GetXfmt(void)
const char *fmt;
switch (Type) {
- case TYPE_STRING: fmt = "%*s"; break;
- case TYPE_SHORT: fmt = "%*hd"; break;
- case TYPE_BIGINT: fmt = "%*lld"; break;
- case TYPE_FLOAT: fmt = "%*.*lf"; break;
- default: fmt = "%*d"; break;
+ case TYPE_STRING: fmt = "%*s"; break;
+ case TYPE_SHORT: fmt = (Unsigned) ? "%*hu" : "%*hd"; break;
+ case TYPE_BIGINT: fmt = (Unsigned) ? "%*llu" : "%*lld"; break;
+ case TYPE_FLOAT: fmt = "%*.*lf"; break;
+ default: fmt = (Unsigned) ? "%*u" : "%*d"; break;
} // endswitch Type
return fmt;
@@ -462,20 +473,9 @@ const char *VALUE::GetXfmt(void)
/* TYPVAL public constructor from a constant typed value. */
/***********************************************************************/
template <class TYPE>
-TYPVAL<TYPE>::TYPVAL(TYPE n, int type) : VALUE(type)
- {
- Tval = n;
- Clen = sizeof(TYPE);
- Prec = (Type == TYPE_FLOAT) ? 2 : 0;
- } // end of TYPVAL constructor
-
-/***********************************************************************/
-/* TYPVAL public constructor from typed value. */
-/***********************************************************************/
-template <class TYPE>
-TYPVAL<TYPE>::TYPVAL(TYPE n, int prec, int type) : VALUE(type)
+TYPVAL<TYPE>::TYPVAL(TYPE n, int type, int prec, bool un)
+ : VALUE(type, un)
{
- assert(Type == TYPE_FLOAT);
Tval = n;
Clen = sizeof(TYPE);
Prec = prec;
@@ -523,14 +523,26 @@ short TYPVAL<short>::GetTypedValue(PVAL valp)
{return valp->GetShortValue();}
template <>
+ushort TYPVAL<ushort>::GetTypedValue(PVAL valp)
+ {return valp->GetUShortValue();}
+
+template <>
int TYPVAL<int>::GetTypedValue(PVAL valp)
{return valp->GetIntValue();}
template <>
+uint TYPVAL<uint>::GetTypedValue(PVAL valp)
+ {return valp->GetUIntValue();}
+
+template <>
longlong TYPVAL<longlong>::GetTypedValue(PVAL valp)
{return valp->GetBigintValue();}
template <>
+ulonglong TYPVAL<ulonglong>::GetTypedValue(PVAL valp)
+ {return valp->GetUBigintValue();}
+
+template <>
double TYPVAL<double>::GetTypedValue(PVAL valp)
{return valp->GetFloatValue();}
@@ -538,6 +550,10 @@ template <>
char TYPVAL<char>::GetTypedValue(PVAL valp)
{return valp->GetTinyValue();}
+template <>
+uchar TYPVAL<uchar>::GetTypedValue(PVAL valp)
+ {return valp->GetUTinyValue();}
+
/***********************************************************************/
/* TYPVAL SetValue: convert chars extracted from a line to TYPE value.*/
/***********************************************************************/
@@ -545,7 +561,7 @@ template <class TYPE>
void TYPVAL<TYPE>::SetValue_char(char *p, int n)
{
char *p2, buf[32];
- bool minus;
+ bool minus = false;
for (p2 = p + n; p < p2 && *p == ' '; p++) ;
@@ -570,7 +586,7 @@ void TYPVAL<TYPE>::SetValue_char(char *p, int n)
} // endswitch *p
if (minus && Tval)
- Tval = - Tval;
+ Tval = (-(signed)Tval) ? -(signed)Tval : Tval;
if (trace > 1)
htrc(strcat(strcat(strcpy(buf, " setting %s to: "), Fmt), "\n"),
@@ -622,13 +638,21 @@ void TYPVAL<TYPE>::SetValue_psz(PSZ s)
template <>
int TYPVAL<int>::GetTypedValue(PSZ s) {return atol(s);}
template <>
+uint TYPVAL<uint>::GetTypedValue(PSZ s) {return (unsigned)atol(s);}
+template <>
short TYPVAL<short>::GetTypedValue(PSZ s) {return (short)atoi(s);}
template <>
+ushort TYPVAL<ushort>::GetTypedValue(PSZ s) {return (ushort)atoi(s);}
+template <>
longlong TYPVAL<longlong>::GetTypedValue(PSZ s) {return atoll(s);}
template <>
+ulonglong TYPVAL<ulonglong>::GetTypedValue(PSZ s) {return (unsigned)atoll(s);}
+template <>
double TYPVAL<double>::GetTypedValue(PSZ s) {return atof(s);}
template <>
char TYPVAL<char>::GetTypedValue(PSZ s) {return (char)atoi(s);}
+template <>
+uchar TYPVAL<uchar>::GetTypedValue(PSZ s) {return (uchar)atoi(s);}
/***********************************************************************/
/* TYPVAL SetValue: set value with a TYPE extracted from a block. */
@@ -645,14 +669,26 @@ int TYPVAL<int>::GetTypedValue(PVBLK blk, int n)
{return blk->GetIntValue(n);}
template <>
+uint TYPVAL<uint>::GetTypedValue(PVBLK blk, int n)
+ {return (unsigned)blk->GetIntValue(n);}
+
+template <>
short TYPVAL<short>::GetTypedValue(PVBLK blk, int n)
{return blk->GetShortValue(n);}
template <>
+ushort TYPVAL<ushort>::GetTypedValue(PVBLK blk, int n)
+ {return (unsigned)blk->GetShortValue(n);}
+
+template <>
longlong TYPVAL<longlong>::GetTypedValue(PVBLK blk, int n)
{return blk->GetBigintValue(n);}
template <>
+ulonglong TYPVAL<ulonglong>::GetTypedValue(PVBLK blk, int n)
+ {return (unsigned)blk->GetBigintValue(n);}
+
+template <>
double TYPVAL<double>::GetTypedValue(PVBLK blk, int n)
{return blk->GetFloatValue(n);}
@@ -660,6 +696,10 @@ template <>
char TYPVAL<char>::GetTypedValue(PVBLK blk, int n)
{return blk->GetTinyValue(n);}
+template <>
+uchar TYPVAL<uchar>::GetTypedValue(PVBLK blk, int n)
+ {return (unsigned)blk->GetTinyValue(n);}
+
/***********************************************************************/
/* TYPVAL SetBinValue: with bytes extracted from a line. */
/***********************************************************************/
@@ -684,7 +724,7 @@ bool TYPVAL<TYPE>::GetBinValue(void *buf, int buflen, bool go)
// be different from the variable length because no conversion is done.
// Therefore this test is useless anyway.
//#if defined(_DEBUG)
-// if (sizeof(int) > buflen)
+// if (sizeof(TYPE) > buflen)
// return true;
//#endif
@@ -730,6 +770,7 @@ char *TYPVAL<double>::GetCharString(char *p)
return p;
} // end of GetCharString
+#if 0
/***********************************************************************/
/* TYPVAL GetShortString: get short representation of a typed value. */
/***********************************************************************/
@@ -779,6 +820,7 @@ char *TYPVAL<TYPE>::GetTinyString(char *p, int n)
sprintf(p, "%*d", n, (int)(char)Tval);
return p;
} // end of GetIntString
+#endif // 0
/***********************************************************************/
/* TYPVAL compare value with another Value. */
@@ -875,7 +917,6 @@ TYPVAL<PSZ>::TYPVAL(PSZ s) : VALUE(TYPE_STRING)
TYPVAL<PSZ>::TYPVAL(PGLOBAL g, PSZ s, int n, int c)
: VALUE(TYPE_STRING)
{
- assert(Type == TYPE_STRING);
Len = (g) ? n : strlen(s);
if (!s) {
@@ -982,6 +1023,24 @@ void TYPVAL<PSZ>::SetValue(int n)
} // end of SetValue
/***********************************************************************/
+/* STRING SetValue: get the character representation of an uint. */
+/***********************************************************************/
+void TYPVAL<PSZ>::SetValue(uint n)
+ {
+ char buf[16];
+ PGLOBAL& g = Global;
+ int k = sprintf(buf, "%u", n);
+
+ if (k > Len) {
+ sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
+ longjmp(g->jumper[g->jump_level], 138);
+ } else
+ SetValue_psz(buf);
+
+ Null = false;
+ } // end of SetValue
+
+/***********************************************************************/
/* STRING SetValue: get the character representation of a short int. */
/***********************************************************************/
void TYPVAL<PSZ>::SetValue(short i)
@@ -991,6 +1050,15 @@ void TYPVAL<PSZ>::SetValue(short i)
} // end of SetValue
/***********************************************************************/
+/* STRING SetValue: get the character representation of a ushort int. */
+/***********************************************************************/
+void TYPVAL<PSZ>::SetValue(ushort i)
+ {
+ SetValue((uint)i);
+ Null = false;
+ } // end of SetValue
+
+/***********************************************************************/
/* STRING SetValue: get the character representation of a big integer.*/
/***********************************************************************/
void TYPVAL<PSZ>::SetValue(longlong n)
@@ -1009,6 +1077,24 @@ void TYPVAL<PSZ>::SetValue(longlong n)
} // end of SetValue
/***********************************************************************/
+/* STRING SetValue: get the character representation of a big integer.*/
+/***********************************************************************/
+void TYPVAL<PSZ>::SetValue(ulonglong n)
+ {
+ char buf[24];
+ PGLOBAL& g = Global;
+ int k = sprintf(buf, "%llu", n);
+
+ if (k > Len) {
+ sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
+ longjmp(g->jumper[g->jump_level], 138);
+ } else
+ SetValue_psz(buf);
+
+ Null = false;
+ } // end of SetValue
+
+/***********************************************************************/
/* STRING SetValue: get the character representation of a double. */
/***********************************************************************/
void TYPVAL<PSZ>::SetValue(double f)
@@ -1043,6 +1129,15 @@ void TYPVAL<PSZ>::SetValue(char c)
} // end of SetValue
/***********************************************************************/
+/* STRING SetValue: get the character representation of a tiny int. */
+/***********************************************************************/
+void TYPVAL<PSZ>::SetValue(uchar c)
+ {
+ SetValue((uint)c);
+ Null = false;
+ } // end of SetValue
+
+/***********************************************************************/
/* STRING SetBinValue: fill string with chars extracted from a line. */
/***********************************************************************/
void TYPVAL<PSZ>::SetBinValue(void *p)
@@ -1086,6 +1181,7 @@ char *TYPVAL<PSZ>::GetCharString(char *p)
return Strp;
} // end of GetCharString
+#if 0
/***********************************************************************/
/* STRING GetShortString: get short representation of a char value. */
/***********************************************************************/
@@ -1130,6 +1226,7 @@ char *TYPVAL<PSZ>::GetTinyString(char *p, int n)
sprintf(p, "%*d", n, (Null) ? 0 : (char)atoi(Strp));
return p;
} // end of GetIntString
+#endif // 0
/***********************************************************************/
/* STRING compare value with another Value. */
diff --git a/storage/connect/value.h b/storage/connect/value.h
index d94c1da6920..5dc4ef98d51 100644
--- a/storage/connect/value.h
+++ b/storage/connect/value.h
@@ -1,5 +1,5 @@
/**************** Value H Declares Source Code File (.H) ***************/
-/* Name: VALUE.H Version 1.9 */
+/* Name: VALUE.H Version 2.0 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2001-2013 */
/* */
@@ -45,16 +45,16 @@ DllExport PSZ GetTypeName(int);
DllExport int GetTypeSize(int, int);
#ifdef ODBC_SUPPORT
/* This function is exported for use in EOM table type DLLs */
-DllExport int TranslateSQLType(int stp, int prec, int& len);
+DllExport int TranslateSQLType(int stp, int prec, int& len, char& v);
#endif
DllExport char *GetFormatType(int);
DllExport int GetFormatType(char);
DllExport bool IsTypeChar(int type);
DllExport bool IsTypeNum(int type);
-DllExport int ConvertType(int, int, CONV, bool match = false);
-DllExport PVAL AllocateValue(PGLOBAL, PVAL, int = TYPE_VOID);
-DllExport PVAL AllocateValue(PGLOBAL, int, int len = 0, int prec = 2,
- PSZ dom = NULL, PCATLG cat = NULL);
+//lExport int ConvertType(int, int, CONV, bool match = false);
+DllExport PVAL AllocateValue(PGLOBAL, PVAL, int = TYPE_VOID, int = 0);
+DllExport PVAL AllocateValue(PGLOBAL, int, int len = 0, int prec = 0,
+ PSZ fmt = NULL);
/***********************************************************************/
/* Class VALUE represents a constant or variable of any valid type. */
@@ -68,6 +68,7 @@ class DllExport VALUE : public BLOCK {
virtual bool IsTypeNum(void) = 0;
virtual bool IsZero(void) = 0;
virtual bool IsCi(void) {return false;}
+ virtual bool IsUnsigned(void) {return Unsigned;}
virtual void Reset(void) = 0;
virtual int GetSize(void) = 0;
virtual int GetValLen(void) = 0;
@@ -75,9 +76,13 @@ class DllExport VALUE : public BLOCK {
virtual int GetLength(void) {return 1;}
virtual PSZ GetCharValue(void) {assert(false); return NULL;}
virtual char GetTinyValue(void) {assert(false); return 0;}
+ virtual uchar GetUTinyValue(void) {assert(false); return 0;}
virtual short GetShortValue(void) {assert(false); return 0;}
+ virtual ushort GetUShortValue(void) {assert(false); return 0;}
virtual int GetIntValue(void) = 0;
+ virtual uint GetUIntValue(void) = 0;
virtual longlong GetBigintValue(void) = 0;
+ virtual ulonglong GetUBigintValue(void) = 0;
virtual double GetFloatValue(void) = 0;
virtual void *GetTo_Val(void) = 0;
virtual void SetPrec(int prec) {Prec = prec;}
@@ -94,20 +99,24 @@ class DllExport VALUE : public BLOCK {
virtual void SetValue_char(char *p, int n) = 0;
virtual void SetValue_psz(PSZ s) = 0;
virtual void SetValue(char c) {assert(false);}
+ virtual void SetValue(uchar c) {assert(false);}
virtual void SetValue(short i) {assert(false);}
+ virtual void SetValue(ushort i) {assert(false);}
virtual void SetValue(int n) {assert(false);}
+ virtual void SetValue(uint n) {assert(false);}
virtual void SetValue(longlong n) {assert(false);}
+ virtual void SetValue(ulonglong n) {assert(false);}
virtual void SetValue(double f) {assert(false);}
virtual void SetValue_pvblk(PVBLK blk, int n) = 0;
virtual void SetBinValue(void *p) = 0;
virtual bool GetBinValue(void *buf, int buflen, bool go) = 0;
virtual char *ShowValue(char *buf, int len = 0) = 0;
virtual char *GetCharString(char *p) = 0;
- virtual char *GetShortString(char *p, int n) {return "#####";}
- virtual char *GetIntString(char *p, int n) = 0;
- virtual char *GetBigintString(char *p, int n) = 0;
- virtual char *GetFloatString(char *p, int n, int prec) = 0;
- virtual char *GetTinyString(char *p, int n) {return "?";}
+//virtual char *GetShortString(char *p, int n) {return "#####";}
+//virtual char *GetIntString(char *p, int n) = 0;
+//virtual char *GetBigintString(char *p, int n) = 0;
+//virtual char *GetFloatString(char *p, int n, int prec) = 0;
+//virtual char *GetTinyString(char *p, int n) {return "?";}
virtual bool IsEqual(PVAL vp, bool chktype) = 0;
virtual bool FormatValue(PVAL vp, char *fmt) = 0;
@@ -116,7 +125,7 @@ class DllExport VALUE : public BLOCK {
const char *GetXfmt(void);
// Constructor used by derived classes
- VALUE(int type);
+ VALUE(int type, bool un = false);
// Members
PGLOBAL Global; // To reduce arglist
@@ -124,6 +133,7 @@ class DllExport VALUE : public BLOCK {
const char *Xfmt;
bool Nullable; // True if value can be null
bool Null; // True if value is null
+ bool Unsigned; // True if unsigned
int Type; // The value type
int Clen; // Internal value length
int Prec;
@@ -135,9 +145,8 @@ class DllExport VALUE : public BLOCK {
template <class TYPE>
class DllExport TYPVAL : public VALUE {
public:
- // Constructors
- TYPVAL(TYPE n, int type);
- TYPVAL(TYPE n, int prec, int type);
+ // Constructor
+ TYPVAL(TYPE n, int type, int prec = 0, bool un = false);
// Implementation
virtual bool IsTypeNum(void) {return true;}
@@ -148,9 +157,13 @@ class DllExport TYPVAL : public VALUE {
virtual int GetSize(void) {return sizeof(TYPE);}
virtual PSZ GetCharValue(void) {return VALUE::GetCharValue();}
virtual char GetTinyValue(void) {return (char)Tval;}
+ virtual uchar GetUTinyValue(void) {return (uchar)Tval;}
virtual short GetShortValue(void) {return (short)Tval;}
+ virtual ushort GetUShortValue(void) {return (ushort)Tval;}
virtual int GetIntValue(void) {return (int)Tval;}
+ virtual uint GetUIntValue(void) {return (uint)Tval;}
virtual longlong GetBigintValue(void) {return (longlong)Tval;}
+ virtual ulonglong GetUBigintValue(void) {return (ulonglong)Tval;}
virtual double GetFloatValue(void) {return (double)Tval;}
virtual void *GetTo_Val(void) {return &Tval;}
@@ -159,20 +172,24 @@ class DllExport TYPVAL : public VALUE {
virtual void SetValue_char(char *p, int n);
virtual void SetValue_psz(PSZ s);
virtual void SetValue(char c) {Tval = (TYPE)c; Null = false;}
+ virtual void SetValue(uchar c) {Tval = (TYPE)c; Null = false;}
virtual void SetValue(short i) {Tval = (TYPE)i; Null = false;}
+ virtual void SetValue(ushort i) {Tval = (TYPE)i; Null = false;}
virtual void SetValue(int n) {Tval = (TYPE)n; Null = false;}
+ virtual void SetValue(uint n) {Tval = (TYPE)n; Null = false;}
virtual void SetValue(longlong n) {Tval = (TYPE)n; Null = false;}
+ virtual void SetValue(ulonglong n) {Tval = (TYPE)n; Null = false;}
virtual void SetValue(double f) {Tval = (TYPE)f; Null = false;}
virtual void SetValue_pvblk(PVBLK blk, int n);
virtual void SetBinValue(void *p);
virtual bool GetBinValue(void *buf, int buflen, bool go);
virtual char *ShowValue(char *buf, int);
virtual char *GetCharString(char *p);
- virtual char *GetShortString(char *p, int n);
- virtual char *GetIntString(char *p, int n);
- virtual char *GetBigintString(char *p, int n);
- virtual char *GetFloatString(char *p, int n, int prec = -1);
- virtual char *GetTinyString(char *p, int n);
+//virtual char *GetShortString(char *p, int n);
+//virtual char *GetIntString(char *p, int n);
+//virtual char *GetBigintString(char *p, int n);
+//virtual char *GetFloatString(char *p, int n, int prec = -1);
+//virtual char *GetTinyString(char *p, int n);
virtual bool IsEqual(PVAL vp, bool chktype);
virtual bool SetConstFormat(PGLOBAL, FORMAT&);
virtual bool FormatValue(PVAL vp, char *fmt);
@@ -211,9 +228,13 @@ class DllExport TYPVAL<PSZ>: public VALUE {
virtual int GetSize(void) {return (Strp) ? strlen(Strp) : 0;}
virtual PSZ GetCharValue(void) {return Strp;}
virtual char GetTinyValue(void) {return (char)atoi(Strp);}
+ virtual uchar GetUTinyValue(void) {return (uchar)atoi(Strp);}
virtual short GetShortValue(void) {return (short)atoi(Strp);}
+ virtual ushort GetUShortValue(void) {return (ushort)atoi(Strp);}
virtual int GetIntValue(void) {return atol(Strp);}
+ virtual uint GetUIntValue(void) {return (uint)atol(Strp);}
virtual longlong GetBigintValue(void) {return atoll(Strp);}
+ virtual ulonglong GetUBigintValue(void) {return (ulonglong)atoll(Strp);}
virtual double GetFloatValue(void) {return atof(Strp);}
virtual void *GetTo_Val(void) {return Strp;}
virtual void SetPrec(int prec) {Ci = prec != 0;}
@@ -224,30 +245,34 @@ class DllExport TYPVAL<PSZ>: public VALUE {
virtual void SetValue_psz(PSZ s);
virtual void SetValue_pvblk(PVBLK blk, int n);
virtual void SetValue(char c);
+ virtual void SetValue(uchar c);
virtual void SetValue(short i);
+ virtual void SetValue(ushort i);
virtual void SetValue(int n);
+ virtual void SetValue(uint n);
virtual void SetValue(longlong n);
+ virtual void SetValue(ulonglong n);
virtual void SetValue(double f);
virtual void SetBinValue(void *p);
virtual bool GetBinValue(void *buf, int buflen, bool go);
virtual char *ShowValue(char *buf, int);
virtual char *GetCharString(char *p);
- virtual char *GetShortString(char *p, int n);
- virtual char *GetIntString(char *p, int n);
- virtual char *GetBigintString(char *p, int n);
- virtual char *GetFloatString(char *p, int n, int prec = -1);
- virtual char *GetTinyString(char *p, int n);
+//virtual char *GetShortString(char *p, int n);
+//virtual char *GetIntString(char *p, int n);
+//virtual char *GetBigintString(char *p, int n);
+//virtual char *GetFloatString(char *p, int n, int prec = -1);
+//virtual char *GetTinyString(char *p, int n);
virtual bool IsEqual(PVAL vp, bool chktype);
virtual bool FormatValue(PVAL vp, char *fmt);
virtual bool SetConstFormat(PGLOBAL, FORMAT&);
// Specialized functions
- template <class T>
- T GetValue_as(T type) {return Strp;}
- int GetValue_as(int type) {return atol(Strp);}
- short GetValue_as(short type) {return (short)atoi(Strp);}
- longlong GetValue_as(longlong type) {return atoll(Strp);}
- double GetValue_as(double type) {return atof(Strp);}
+//template <class T>
+//T GetValue_as(T type) {return Strp;}
+//int GetValue_as(int type) {return atol(Strp);}
+//short GetValue_as(short type) {return (short)atoi(Strp);}
+//longlong GetValue_as(longlong type) {return atoll(Strp);}
+//double GetValue_as(double type) {return atof(Strp);}
// Members
PSZ Strp;
diff --git a/storage/connect/xindex.cpp b/storage/connect/xindex.cpp
index 1086e46650b..46ddba52332 100755
--- a/storage/connect/xindex.cpp
+++ b/storage/connect/xindex.cpp
@@ -66,7 +66,7 @@ extern MBLOCK Nmblk; /* Used to initialize MBLOCK's */
/* to have rows filled by blanks to be compatible with QRY blocks. */
/***********************************************************************/
PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int,
- bool check = true, bool blank = true);
+ bool check = true, bool blank = true, bool un = false);
/***********************************************************************/
/* Check whether we have to create/update permanent indexes. */
@@ -2919,7 +2919,7 @@ void KXYCOL::SetValue(PCOL colp, int i)
assert (Kblp != NULL);
#endif
- Kblp->SetValue(colp->GetValue(), (int)i);
+ Kblp->SetValue(colp->GetValue(), i);
} // end of SetValue
/***********************************************************************/
@@ -2970,7 +2970,7 @@ void KXYCOL::FillValue(PVAL valp)
int KXYCOL::Compare(int i1, int i2)
{
// Do the actual comparison between values.
- register int k = (int)Kblp->CompVal((int)i1, (int)i2);
+ register int k = Kblp->CompVal(i1, i2);
#ifdef DEBUG2
htrc("Compare done result=%d\n", k);
@@ -2991,7 +2991,7 @@ int KXYCOL::CompVal(int i)
htrc("Compare done result=%d\n", k);
return k;
#endif
- return (int)Kblp->CompVal(Valp, (int)i);
+ return Kblp->CompVal(Valp, i);
} // end of CompVal
/***********************************************************************/
@@ -3000,7 +3000,7 @@ int KXYCOL::CompVal(int i)
int KXYCOL::CompBval(int i)
{
// Do the actual comparison between key values.
- return (int)Blkp->CompVal(Valp, (int)i);
+ return Blkp->CompVal(Valp, i);
} // end of CompBval
/***********************************************************************/
diff --git a/storage/connect/xtable.h b/storage/connect/xtable.h
index 98c7305acd4..e308dedb3e1 100644
--- a/storage/connect/xtable.h
+++ b/storage/connect/xtable.h
@@ -18,8 +18,28 @@
#include "colblk.h"
#include "m_ctype.h"
-//pedef class INDEXDEF *PIXDEF;
-typedef char *PFIL; // Specific to CONNECT
+typedef class CMD *PCMD;
+
+// Commands executed by XDBC and MYX tables
+class CMD : public BLOCK {
+ public:
+ // Constructor
+ CMD(PGLOBAL g, char *cmd) {
+ Cmd = (char*)PlugSubAlloc(g, NULL, strlen(cmd) + 1);
+ strcpy(Cmd, cmd); Next = NULL; }
+
+ // Members
+ PCMD Next;
+ char *Cmd;
+}; // end of class CMD
+
+// Filter passed all tables
+typedef struct _filter {
+ char *Body;
+ OPVAL Op;
+ PCMD Cmds;
+} FILTER, *PFIL;
+
typedef class TDBCAT *PTDBCAT;
typedef class CATCOL *PCATCOL;
@@ -39,24 +59,16 @@ class DllExport TBX: public BLOCK { // Base class for OPJOIN and TDB classes.
inline PFIL GetFilter(void) {return To_Filter;}
inline void SetOrig(PTBX txp) {To_Orig = txp;}
inline void SetFilter(PFIL fp) {To_Filter = fp;}
-//inline JTYPE GetJtype(void) {return Jtype;}
-//inline void SetJtype(JTYPE jt) {Jtype = jt;}
-//inline PFIL GetNoleft(void) {return To_Noleft;}
-//inline void SetNoleft(PFIL fp) {To_Noleft = fp;}
// Methods
virtual bool IsSame(PTBX tp) {return tp == this;}
-//virtual bool Include(PTBX tbxp) = 0;
-//virtual bool CheckFilter(void) = 0;
virtual int GetTdb_No(void) = 0; // Convenience during conversion
virtual PTDB GetNext(void) = 0;
-//virtual int GetMaxSame(PGLOBAL) = 0;
virtual int Cardinality(PGLOBAL) = 0;
virtual int GetMaxSize(PGLOBAL) = 0;
virtual int GetProgMax(PGLOBAL) = 0;
virtual int GetProgCur(void) = 0;
virtual int GetBadLines(void) {return 0;}
-//virtual bool IsJoin(void) = 0;
virtual PTBX Copy(PTABS t) = 0;
protected:
@@ -66,8 +78,6 @@ class DllExport TBX: public BLOCK { // Base class for OPJOIN and TDB classes.
// Members
PTBX To_Orig; // Pointer to original if it is a copy
PFIL To_Filter;
-//PFIL To_Noleft; // To filter not involved in LEFT JOIN
-//JTYPE Jtype;
TUSE Use;
}; // end of class TBX