diff options
author | Alexander Barkov <bar@mnogosearch.org> | 2013-12-03 14:12:53 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mnogosearch.org> | 2013-12-03 14:12:53 +0400 |
commit | d240a0418cf6d59fba711f0677f164d9ee881b7e (patch) | |
tree | fc2dedfcd5437f1c59c1b5bc59ead689f5736246 /storage | |
parent | 5bb01fa1ace1dcfe87c9c1eae3cd30a55c9de032 (diff) | |
parent | 0d37409fe7fd6cc4b576c62ed5c0a6804e049e8f (diff) | |
download | mariadb-git-d240a0418cf6d59fba711f0677f164d9ee881b7e.tar.gz |
Merge 10.0-connect -> 10.0
Diffstat (limited to 'storage')
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, + ¬_used_1, ¬_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 |