From 3a424fc1190e876c3bc6fcf25b45586c1f22bed7 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 29 Oct 2013 13:44:05 +0400 Subject: [PATCH 01/14] ConnectSE: fixing memory leaks reported by valgrind --- storage/connect/libdoc.cpp | 43 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) 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 #include #include +#include +#include +#include //#if defined(WIN32) //#include //#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 /******************************************************************/ From 671e5cbb7f6eea31d1ee5a894112958016c5e59c Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Tue, 29 Oct 2013 16:21:57 +0100 Subject: [PATCH 02/14] - Update version number and date - Replace test on args[i]->type() by args[i]->field_type() in ha_connect::CheckCond. This to take care of cached items generated by executing a query in a procedure. modified: storage/connect/ha_connect.cc storage/connect/mysql-test/connect/r/xml.result --- storage/connect/ha_connect.cc | 4 ++-- storage/connect/mysql-test/connect/r/xml.result | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index a066c48bf0e..bd02b8ab1d5 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 @@ -1702,7 +1702,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) return NULL; // Append the value to the filter - if (args[i]->type() == COND::STRING_ITEM) + if (args[i]->field_type() == MYSQL_TYPE_VARCHAR) strcat(strcat(strcat(filp, "'"), res->ptr()), "'"); else strncat(filp, res->ptr(), res->length()); 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) - + ÀÁÂÃ From f1325549e9eca1311435255854da0a93923eff9b Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 31 Oct 2013 11:53:00 +0400 Subject: [PATCH 03/14] - Adding cmake code to install ConnectSE mtr tests - Including "connect" suite into the list of the default suites --- mysql-test/mysql-test-run.pl | 2 +- storage/connect/CMakeLists.txt | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index a7a53166563..7b29ef2cb9d 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -166,6 +166,7 @@ my $DEFAULT_SUITES= join(',', map { "$_-" } qw( main archive binlog + connect csv federated funcs_1 @@ -379,7 +380,6 @@ sub main { mtr_report("Logging: $0 ", join(" ", @ARGV)); $DEFAULT_SUITES.= ',' . join(',', qw( - connect query_response_time sequence spider 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 From 056f35d0c136af4437344d4fbce80172e6d96817 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Wed, 6 Nov 2013 18:22:09 +0100 Subject: [PATCH 04/14] - Move all enum AMT definitions in one place (plgdbsem.h) modified: storage/connect/filamtxt.h storage/connect/filamzip.h storage/connect/myconn.h storage/connect/plgdbsem.h storage/connect/taboccur.h storage/connect/tabutil.h storage/connect/tabxcl.h - Add the possibility to execute several commands in one query of an EXECSRC tables (using ...where command in (cmd list);) modified: storage/connect/ha_connect.cc storage/connect/odbconn.cpp storage/connect/odbconn.h storage/connect/tabmysql.cpp storage/connect/tabmysql.h storage/connect/tabodbc.cpp storage/connect/tabodbc.h storage/connect/tabtbl.cpp storage/connect/tabwmi.cpp storage/connect/xtable.h - Enhance retrieving column definitions in discovery: From SRCDEF adding LIMIT 0 to the executed query Testing if type, length, and precision are compatible Making the distinction between CHAR and VARCHAR modified: storage/connect/ha_connect.cc storage/connect/myconn.cpp storage/connect/mysql-test/connect/r/mysql.result storage/connect/mysql-test/connect/r/odbc_sqlite3.result storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result storage/connect/myutil.h storage/connect/myutil.h storage/connect/odbconn.cpp storage/connect/value.h --- storage/connect/filamtxt.h | 2 - storage/connect/filamzip.h | 3 - storage/connect/ha_connect.cc | 118 +++++++++----- storage/connect/myconn.cpp | 54 ++++++- storage/connect/myconn.h | 5 +- .../connect/mysql-test/connect/r/mysql.result | 4 +- .../mysql-test/connect/r/odbc_sqlite3.result | 2 +- .../connect/r/odbc_sqlite3_grant.result | 2 +- storage/connect/myutil.cpp | 10 +- storage/connect/myutil.h | 9 +- storage/connect/odbconn.cpp | 150 +++++++++++++++--- storage/connect/odbconn.h | 3 +- storage/connect/plgdbsem.h | 10 +- storage/connect/tabmysql.cpp | 135 +++++++++++----- storage/connect/tabmysql.h | 20 ++- storage/connect/taboccur.h | 2 - storage/connect/tabodbc.cpp | 72 +++++---- storage/connect/tabodbc.h | 14 +- storage/connect/tabtbl.cpp | 9 +- storage/connect/tabutil.h | 2 - storage/connect/tabwmi.cpp | 17 +- storage/connect/tabxcl.h | 2 - storage/connect/value.h | 2 +- storage/connect/xtable.h | 34 ++-- 24 files changed, 485 insertions(+), 196 deletions(-) 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/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 bd02b8ab1d5..31d56dce7e2 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -1557,8 +1557,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 +1573,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 +1590,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) List_iterator li(*arglist); Item *subitem; - p1= filp + strlen(filp); + p1= body + strlen(body); strcpy(p1, "("); p2= p1 + 1; @@ -1615,7 +1619,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 +1648,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 +1667,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 +1695,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 +1708,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]->field_type() == MYSQL_TYPE_VARCHAR) - 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 +1783,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 @@ -3461,12 +3499,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 +3518,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 +3558,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 +3619,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 @@ -3777,7 +3818,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, //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); @@ -4097,7 +4138,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 @@ -4121,6 +4162,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); @@ -4151,7 +4193,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; @@ -4176,7 +4218,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, true, v)) rc= HA_ERR_OUT_OF_MEM; #endif // !NEW_WAY } // endfor i diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp index e2de93e8fc8..d29c116756a 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, 255); 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(); @@ -778,6 +786,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, "%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. */ /***********************************************************************/ 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/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/odbc_sqlite3.result b/storage/connect/mysql-test/connect/r/odbc_sqlite3.result index 339dbb6a53d..3ff99791760 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; 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/myutil.cpp b/storage/connect/myutil.cpp index b266b7b79c1..ecea6a0eada 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,10 @@ int MYSQLtoPLG(char *typname) else type = TYPE_ERROR; + // This is to make the difference between CHAR and VARCHAR + if (var && type == TYPE_STRING && stricmp(typname, "char")) + *var = 'V'; + return type; } // end of MYSQLtoPLG @@ -98,14 +102,14 @@ 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 var) { 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_STRING: return var ? "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/odbconn.cpp b/storage/connect/odbconn.cpp index 0a19d90a422..04ec147d91c 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; @@ -889,7 +891,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); @@ -1242,7 +1244,7 @@ void ODBConn::GetConnectInfo() m_IDQuoteChar = ' '; if (trace) - htrc("DBMS: %s, Version: %s", + htrc("DBMS: %s, Version: %s\n", GetStringInfo(SQL_DBMS_NAME), GetStringInfo(SQL_DBMS_VER)); } // end of GetConnectInfo @@ -1511,14 +1513,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 +1569,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 +1584,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 +1608,7 @@ int ODBConn::ExecuteSQL(bool x) m_Transact = false; } // endif m_Transact + afrw = -1; } // end try/catch return (int)afrw; @@ -1667,6 +1663,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]); + + strcpy(g->Message, 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..b747a07f439 100644 --- a/storage/connect/odbconn.h +++ b/storage/connect/odbconn.h @@ -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); diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h index 550153921a5..0b8c7122192 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 */ diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp index f37cb6d349e..d1f3d90fade 100644 --- a/storage/connect/tabmysql.cpp +++ b/storage/connect/tabmysql.cpp @@ -355,7 +355,9 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) if ((Srcdef = Cat->GetStringCatInfo(g, "Srcdef", NULL))) Isview = TRUE; + // Specific for command executing tables Xsrc = Cat->GetBoolCatInfo("Execsrc", FALSE); + Mxr = Cat->GetIntCatInfo("Maxerr", 0); return FALSE; } // end of DefineAM @@ -516,7 +518,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); @@ -1294,8 +1296,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 +1355,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 +1373,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 +1384,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 +1395,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 +1421,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 +1434,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 +1532,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..70c75506470 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: @@ -53,6 +54,7 @@ class MYSQLDEF : public TABDEF {/* Logical table description */ PSZ Password; /* Password logon info */ PSZ Server; /* PServerID */ int Portnumber; /* MySQL port number (0 = default) */ + int Mxr; /* Maxerr for an Exec table */ bool Isview; /* TRUE if this table is a MySQL view */ bool Bind; /* Use prepared statement on insert */ bool Delayed; /* Delayed insert */ @@ -167,13 +169,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 +204,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.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..bf0216d52eb 100644 --- a/storage/connect/tabodbc.cpp +++ b/storage/connect/tabodbc.cpp @@ -110,6 +110,7 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) Qchar = Cat->GetStringCatInfo(g, "Qchar", ""); Catver = Cat->GetIntCatInfo("Catver", 2); Xsrc = Cat->GetBoolCatInfo("Execsrc", FALSE); + Mxr = Cat->GetIntCatInfo("Maxerr", 0); Options = ODBConn::noOdbcDialog; Pseudo = 2; // FILID is Ok but not ROWID return false; @@ -395,7 +396,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 +433,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 @@ -720,7 +721,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; @@ -1004,6 +1005,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 +1053,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 +1071,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 +1097,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 +1151,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 +1165,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 /***********************************************************************/ diff --git a/storage/connect/tabodbc.h b/storage/connect/tabodbc.h index b3577bce5be..f5a3098e843 100644 --- a/storage/connect/tabodbc.h +++ b/storage/connect/tabodbc.h @@ -52,6 +52,7 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */ PSZ Qchar; /* Identifier quoting character */ int Catver; /* ODBC version for catalog functions */ int Options; /* Open connection options */ + int Mxr; /* Maxerr for an Exec table */ bool Xsrc; /* Execution type */ }; // end of ODBCDEF @@ -179,12 +180,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);} @@ -209,11 +210,14 @@ class TDBXDBC : public TDBODBC { 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/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.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/tabwmi.cpp b/storage/connect/tabwmi.cpp index 1c626a06256..7926505e672 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 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/value.h b/storage/connect/value.h index d94c1da6920..13ce1436b39 100644 --- a/storage/connect/value.h +++ b/storage/connect/value.h @@ -45,7 +45,7 @@ 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); 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 From e5c589a8da02211e3b0ac9ad8a785c4669b63fda Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Sat, 9 Nov 2013 17:32:57 +0100 Subject: [PATCH 05/14] - BUG fixed: 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. modified: storage/connect/ha_connect.cc - Preparing UPDATE ad DELETE on ODBC tables (new function added but not used yet) modified: storage/connect/tabodbc.cpp storage/connect/tabodbc.h --- storage/connect/ha_connect.cc | 44 ++++++++++++++++++++--------------- storage/connect/tabodbc.cpp | 40 ++++++++++++++++++++++++++++++- storage/connect/tabodbc.h | 7 +++--- 3 files changed, 68 insertions(+), 23 deletions(-) diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 31d56dce7e2..af5d4c8ec4a 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -659,6 +659,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); @@ -1239,15 +1241,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 +1266,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++) { @@ -2382,18 +2385,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 (OpenTable(g, xmod == MODE_DELETE)) + DBUG_RETURN(HA_ERR_INITIALIZATION); xp->nrd= xp->fnd= xp->nfd= 0; xp->tb1= my_interval_timer(); diff --git a/storage/connect/tabodbc.cpp b/storage/connect/tabodbc.cpp index bf0216d52eb..f2225ebef95 100644 --- a/storage/connect/tabodbc.cpp +++ b/storage/connect/tabodbc.cpp @@ -90,7 +90,7 @@ extern int num_read, num_there, num_eq[2]; // Statistics /***********************************************************************/ ODBCDEF::ODBCDEF(void) { - Connect = Tabname = Tabowner = Tabqual = Srcdef = Qchar = NULL; + Connect = Tabname = Tabowner = Tabqual = Srcdef = Qchar = Qrystr = NULL; Catver = Options = 0; Xsrc = false; } // end of ODBCDEF constructor @@ -108,6 +108,7 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) 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); @@ -171,6 +172,7 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp) Qualifier = tdp->Tabqual; Srcdef = tdp->Srcdef; Quote = tdp->GetQchar(); + Qrystr = tdp->Qrystr; Options = tdp->Options; Rows = tdp->GetElemt(); Catver = tdp->Catver; @@ -181,6 +183,7 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp) Qualifier = NULL; Srcdef = NULL; Quote = NULL; + Qrystr = NULL; Options = 0; Rows = 0; Catver = 0; @@ -209,6 +212,7 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp) Qualifier = tdbp->Qualifier; Srcdef = tdbp->Srcdef; Quote = tdbp->Quote; + Qrystr = tdbp->Qrystr; Query = tdbp->Query; Count = tdbp->Count; //Where = tdbp->Where; @@ -515,6 +519,40 @@ bool TDBODBC::BindParameters(PGLOBAL g) return false; } // end of BindParameters +/***********************************************************************/ +/* MakeCMD: make the SQL statement to send to ODBC connection. */ +/***********************************************************************/ +char *TDBODBC::MakeStmt(PGLOBAL g) + { + char *qc, *stmt = NULL, cmd[8], tab[96], end[512]; + int n = (Mode == MODE_DELETE) ? 1 : 2; + + stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64); + *end = 0; + qc = (Quote) ? Quote : "\""; + + if (sscanf(Qrystr, "%s `%[^`]`%511c", cmd, tab, end) > n || + sscanf(Qrystr, "%s \"%[^\"]\"%511c", cmd, tab, end) > n || + sscanf(Qrystr, "%s %s%511c", cmd, tab, end) > n) + strcat(strcat(strcpy(tab, qc), TableName), qc); + else { + strcpy(g->Message, "Cannot use this UPDATE/DELETE command"); + return NULL; + } // endif sscanf + + strcat(strcat(strcpy(stmt, cmd), " "), tab); + + if (*end) { + for (int i = 0; end[i]; i++) + if (end[i] == '`') + end[i] = *qc; + + strcat(stmt, end); + } // endif end + + return stmt; + } // end of MakeStmt + /***********************************************************************/ /* ResetSize: call by TDBMUL when calculating size estimate. */ /***********************************************************************/ diff --git a/storage/connect/tabodbc.h b/storage/connect/tabodbc.h index f5a3098e843..c58d0ca1559 100644 --- a/storage/connect/tabodbc.h +++ b/storage/connect/tabodbc.h @@ -50,6 +50,7 @@ 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 Mxr; /* Maxerr for an Exec table */ @@ -97,13 +98,12 @@ 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); //bool MakeFilter(PGLOBAL g, bool c); bool BindParameters(PGLOBAL g); + char *MakeStmt(PGLOBAL g); // Members ODBConn *Ocp; // Points to an ODBC connection class @@ -119,6 +119,7 @@ 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 Fpos; // Position of last read record int AftRows; // The number of affected rows From eca84a9b1837304ce4be50994ef7077b31ccf50c Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Mon, 11 Nov 2013 13:00:39 +0100 Subject: [PATCH 06/14] - Add (limited) support for UPDATE and DELETE to ODBC tables (also provide the possibility to issue NOTE warnings) modified: storage/connect/connect.cc storage/connect/ha_connect.cc storage/connect/ha_connect.h storage/connect/odbconn.cpp storage/connect/odbconn.h storage/connect/plgdbsem.h storage/connect/tabodbc.cpp storage/connect/tabodbc.h - Return proper error number when modifying read only tables modified: storage/connect/connect.cc storage/connect/ha_connect.cc storage/connect/ha_connect.h storage/connect/mysql-test/connect/r/bin.result storage/connect/mysql-test/connect/r/csv.result storage/connect/mysql-test/connect/r/dbf.result storage/connect/mysql-test/connect/r/fix.result storage/connect/mysql-test/connect/r/ini.result storage/connect/mysql-test/connect/r/vec.result storage/connect/mysql-test/connect/t/bin.test storage/connect/mysql-test/connect/t/csv.test storage/connect/mysql-test/connect/t/dbf.test storage/connect/mysql-test/connect/t/fix.test storage/connect/mysql-test/connect/t/ini.test storage/connect/mysql-test/connect/t/vec.test storage/connect/table.cpp storage/connect/taboccur.cpp storage/connect/tabpivot.cpp storage/connect/tabutil.cpp storage/connect/tabwmi.cpp storage/connect/tabxcl.cpp --- storage/connect/connect.cc | 18 +- storage/connect/ha_connect.cc | 44 +- storage/connect/ha_connect.h | 2 +- .../connect/mysql-test/connect/r/bin.result | 4 +- .../connect/mysql-test/connect/r/csv.result | 10 +- .../connect/mysql-test/connect/r/dbf.result | 8 +- .../connect/mysql-test/connect/r/fix.result | 8 +- .../connect/mysql-test/connect/r/ini.result | 8 +- .../connect/mysql-test/connect/r/vec.result | 8 +- storage/connect/mysql-test/connect/t/bin.test | 154 +-- storage/connect/mysql-test/connect/t/csv.test | 370 +++--- storage/connect/mysql-test/connect/t/dbf.test | 1018 ++++++++--------- storage/connect/mysql-test/connect/t/fix.test | 216 ++-- storage/connect/mysql-test/connect/t/ini.test | 312 ++--- storage/connect/mysql-test/connect/t/vec.test | 160 +-- storage/connect/odbconn.cpp | 14 +- storage/connect/odbconn.h | 4 +- storage/connect/plgdbsem.h | 2 +- storage/connect/table.cpp | 1 + storage/connect/taboccur.cpp | 1 + storage/connect/tabodbc.cpp | 186 ++- storage/connect/tabodbc.h | 11 +- storage/connect/tabpivot.cpp | 2 + storage/connect/tabutil.cpp | 1 + storage/connect/tabwmi.cpp | 2 + storage/connect/tabxcl.cpp | 1 + 26 files changed, 1314 insertions(+), 1251 deletions(-) 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/ha_connect.cc b/storage/connect/ha_connect.cc index af5d4c8ec4a..5a5ed8c9944 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -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 @@ -1098,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; @@ -1118,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: @@ -1130,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 @@ -1207,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 @@ -2006,14 +2011,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 @@ -2378,6 +2377,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"); @@ -2398,8 +2398,8 @@ int ha_connect::rnd_init(bool scan) if (xmod == MODE_UPDATE) bitmap_union(table->read_set, table->write_set); - if (OpenTable(g, xmod == MODE_DELETE)) - DBUG_RETURN(HA_ERR_INITIALIZATION); + if ((rc= OpenTable(g, xmod == MODE_DELETE))) + DBUG_RETURN(rc); xp->nrd= xp->fnd= xp->nfd= 0; xp->tb1= my_interval_timer(); @@ -2610,7 +2610,6 @@ int ha_connect::info(uint flag) xp->CheckCleanup(); } // endif xmod -// tdbp= OpenTable(g, xmod == MODE_DELETE); tdbp= GetTDB(g); } // endif tdbp @@ -2705,18 +2704,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 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/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/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/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/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/odbconn.cpp b/storage/connect/odbconn.cpp index 04ec147d91c..c6a6fe0ed02 100644 --- a/storage/connect/odbconn.cpp +++ b/storage/connect/odbconn.cpp @@ -873,7 +873,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 @@ -1232,16 +1233,9 @@ 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\n", diff --git a/storage/connect/odbconn.h b/storage/connect/odbconn.h index b747a07f439..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); @@ -184,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 0b8c7122192..d8f27603f6c 100644 --- a/storage/connect/plgdbsem.h +++ b/storage/connect/plgdbsem.h @@ -593,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/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/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/tabodbc.cpp b/storage/connect/tabodbc.cpp index f2225ebef95..e35da989cd2 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 = Qrystr = NULL; - Catver = Options = 0; + Connect = Tabname = Tabowner = Tabqual = Srcdef = Qrystr = NULL; + Catver = Options = Quoted = 0; Xsrc = false; } // end of ODBCDEF constructor @@ -107,11 +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; @@ -171,9 +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 { @@ -182,13 +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; @@ -211,14 +212,15 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp) Owner = tdbp->Owner; Qualifier = tdbp->Qualifier; Srcdef = tdbp->Srcdef; - Quote = tdbp->Quote; Qrystr = tdbp->Qrystr; + Quote = tdbp->Quote; Query = tdbp->Query; Count = tdbp->Count; //Where = tdbp->Where; MulConn = tdbp->MulConn; DBQ = tdbp->DBQ; Options = tdbp->Options; + Quoted = tdbp->Quoted; Rows = tdbp->Rows; Fpos = tdbp->Fpos; AftRows = tdbp->AftRows; @@ -445,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; @@ -487,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 /***********************************************************************/ @@ -520,27 +519,58 @@ bool TDBODBC::BindParameters(PGLOBAL g) } // end of BindParameters /***********************************************************************/ -/* MakeCMD: make the SQL statement to send to ODBC connection. */ +/* MakeUpdate: make the SQL statement to send to ODBC connection. */ /***********************************************************************/ -char *TDBODBC::MakeStmt(PGLOBAL g) +char *TDBODBC::MakeUpdate(PGLOBAL g) { - char *qc, *stmt = NULL, cmd[8], tab[96], end[512]; - int n = (Mode == MODE_DELETE) ? 1 : 2; + char *qc, *stmt = NULL, cmd[8], tab[96], end[1024]; stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64); - *end = 0; - qc = (Quote) ? Quote : "\""; + memset(end, 0, sizeof(end)); - if (sscanf(Qrystr, "%s `%[^`]`%511c", cmd, tab, end) > n || - sscanf(Qrystr, "%s \"%[^\"]\"%511c", cmd, tab, end) > n || - sscanf(Qrystr, "%s %s%511c", cmd, tab, end) > n) - strcat(strcat(strcpy(tab, qc), TableName), qc); + 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/DELETE command"); + strcpy(g->Message, "Cannot use this UPDATE command"); return NULL; } // endif sscanf - strcat(strcat(strcpy(stmt, cmd), " "), tab); + 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++) @@ -551,7 +581,7 @@ char *TDBODBC::MakeStmt(PGLOBAL g) } // endif end return stmt; - } // end of MakeStmt + } // end of MakeDelete /***********************************************************************/ /* ResetSize: call by TDBMUL when calculating size estimate. */ @@ -572,7 +602,7 @@ int TDBODBC::GetMaxSize(PGLOBAL g) { if (MaxSize < 0) { // Make MariaDB happy - MaxSize = 100; + MaxSize = (Mode == MODE_READ) ? 100 : 0; #if 0 // This is unuseful and takes time if (Srcdef) { @@ -655,51 +685,42 @@ 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 = MakeSQL(g, false))) { + for (PODBCCOL colp = (PODBCCOL)Columns; colp; + colp = (PODBCCOL)colp->GetNext()) + if (!colp->IsSpecial()) + colp->AllocateBuffers(g, Rows); - 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; + rc = ((Rows = Ocp->ExecDirectSQL(Query, (PODBCCOL)Columns)) < 0); } // endif Query - if (!rc) - rc = ((Rows = Ocp->ExecDirectSQL(Query, (PODBCCOL)Columns)) < 0); - } 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 - if (rc) { + } else if (Mode == MODE_UPDATE) + Query = MakeUpdate(g); + else if (Mode == MODE_DELETE) + Query = MakeDelete(g); + else + sprintf(g->Message, "Invalid mode %d", Mode); + + if (!Query || rc) { Ocp->Close(); return true; } // endif rc @@ -730,6 +751,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)); @@ -775,8 +811,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 /***********************************************************************/ @@ -790,6 +840,7 @@ void TDBODBC::CloseDB(PGLOBAL g) // } // endif if (Ocp) + Ocp->Close(); if (trace) @@ -1226,6 +1277,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 c58d0ca1559..10a3f819f69 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;} @@ -53,6 +53,7 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */ 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 @@ -100,10 +101,11 @@ class TDBODBC : public TDBASE { // Internal functions int Decode(char *utf, char *buf, size_t n); char *MakeSQL(PGLOBAL g, bool cnt); - bool MakeInsert(PGLOBAL g); + char *MakeInsert(PGLOBAL g); //bool MakeFilter(PGLOBAL g, bool c); bool BindParameters(PGLOBAL g); - char *MakeStmt(PGLOBAL g); + char *MakeUpdate(PGLOBAL g); + char *MakeDelete(PGLOBAL g); // Members ODBConn *Ocp; // Points to an ODBC connection class @@ -121,6 +123,7 @@ class TDBODBC : public TDBASE { 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 @@ -206,7 +209,7 @@ 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: 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/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/tabwmi.cpp b/storage/connect/tabwmi.cpp index 7926505e672..5fb349fa5c0 100644 --- a/storage/connect/tabwmi.cpp +++ b/storage/connect/tabwmi.cpp @@ -667,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 From 260c0de9188727f3a7ced1e96c7e368bf7a37437 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Mon, 11 Nov 2013 18:30:36 +0100 Subject: [PATCH 07/14] - Add (limited) UPDATE/DELETE support to MYSQL type CONNECT tables modified: storage/connect/ha_connect.cc storage/connect/tabmysql.cpp storage/connect/tabmysql.h storage/connect/tabodbc.cpp --- storage/connect/ha_connect.cc | 2 +- storage/connect/tabmysql.cpp | 232 +++++++++++++++------------------- storage/connect/tabmysql.h | 9 +- storage/connect/tabodbc.cpp | 2 +- 4 files changed, 112 insertions(+), 133 deletions(-) diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 5a5ed8c9944..6a294b8380d 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -4718,6 +4718,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/tabmysql.cpp b/storage/connect/tabmysql.cpp index d1f3d90fade..469e659ade9 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,10 +353,14 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) } // endif am if ((Srcdef = Cat->GetStringCatInfo(g, "Srcdef", NULL))) - Isview = TRUE; + Isview = true; + + // 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); + Xsrc = Cat->GetBoolCatInfo("Execsrc", false); Mxr = Cat->GetIntCatInfo("Maxerr", 0); return FALSE; } // end of DefineAM @@ -390,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; @@ -402,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; @@ -426,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; @@ -612,120 +622,62 @@ 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. */ +/* Limited to remote values and filtering. */ /***********************************************************************/ -bool TDBMYSQL::MakeUpdate(PGLOBAL g, PSELECT selist) +int TDBMYSQL::MakeUpdate(PGLOBAL g) { - char *setlist, *colname, *where = NULL, *tk = "`"; - int len = 0, nset = 0; - bool b = FALSE; - PXOB xp; - PSELECT selp; + char *qc, cmd[8], tab[96], end[1024]; - if (Query) - return FALSE; // already done + Query = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64); + memset(end, 0, sizeof(end)); - if (To_Filter) - if (To_Filter->CheckLocal(this)) { - where = (char*)PlugSubAlloc(g, NULL, 512); // Should be enough - *where = '\0'; + 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) + qc = (Quoted) ? "`" : ""; + else { + strcpy(g->Message, "Cannot use this UPDATE command"); + return RC_FX; + } // endif sscanf - if (!PlugRephraseSQL(g, where, To_Filter, TYPE_FILTER, tk)) - return TRUE; - - To_Filter = NULL; - len = strlen(where); - } else { - strcpy(g->Message, MSG(NO_REF_UPDATE)); - return TRUE; - } // endif Local - - for (selp = selist; selp; selp = selp->GetNext_Proj()) - nset++; - - assert(nset); - - // Allocate a pretty big buffer - setlist = (char*)PlugSubAlloc(g, NULL, 256 * nset); - *setlist = '\0'; - - 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(); - } 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), " = "); - - 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()); - - if (!PlugRephraseSQL(g, setlist + strlen(setlist), - xp, TYPE_XOBJECT, tk)) - return TRUE; - - } // endfor selp - - // 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); - - if (where) - strcat(Query, where); - - 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 /***********************************************************************/ /* XCV GetMaxSize: returns the maximum number of rows in the table. */ @@ -753,7 +705,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; @@ -768,12 +721,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 /***********************************************************************/ @@ -876,33 +828,16 @@ 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); 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 /***********************************************************************/ @@ -977,6 +912,38 @@ char *TDBMYSQL::FindFieldColumn(char *name) return cp; } // 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. */ /***********************************************************************/ @@ -988,6 +955,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. */ @@ -1043,12 +1013,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 /***********************************************************************/ diff --git a/storage/connect/tabmysql.h b/storage/connect/tabmysql.h index 70c75506470..969d51beff9 100644 --- a/storage/connect/tabmysql.h +++ b/storage/connect/tabmysql.h @@ -53,8 +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 */ @@ -104,9 +106,10 @@ class TDBMYSQL : public TDBASE { // Internal functions bool MakeSelect(PGLOBAL g); bool MakeInsert(PGLOBAL g); -//bool MakeUpdate(PGLOBAL g); -//bool MakeDelete(PGLOBAL g); + int MakeUpdate(PGLOBAL g); + int MakeDelete(PGLOBAL g); int BindColumns(PGLOBAL g); + int SendCommand(PGLOBAL g); // Members MYSQLC Myc; // MySQL connection class @@ -120,6 +123,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 @@ -129,6 +133,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 /***********************************************************************/ diff --git a/storage/connect/tabodbc.cpp b/storage/connect/tabodbc.cpp index e35da989cd2..bb7588e0d66 100644 --- a/storage/connect/tabodbc.cpp +++ b/storage/connect/tabodbc.cpp @@ -602,7 +602,7 @@ int TDBODBC::GetMaxSize(PGLOBAL g) { if (MaxSize < 0) { // Make MariaDB happy - MaxSize = (Mode == MODE_READ) ? 100 : 0; + MaxSize = (Mode == MODE_DELETE) ? 0 : 10; #if 0 // This is unuseful and takes time if (Srcdef) { From 793f05c32187d5ca8d1cbf736e36e87c48f7c1de Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Wed, 13 Nov 2013 00:15:38 +0100 Subject: [PATCH 08/14] - Modify the way UPDATE and DELETE statements are sent to ODBC and MYSQL CONNECT tables to take care of kewords such as IGNORE. modified: storage/connect/myconn.cpp storage/connect/odbconn.cpp storage/connect/tabmysql.cpp storage/connect/tabmysql.h storage/connect/tabodbc.cpp storage/connect/tabodbc.h --- storage/connect/myconn.cpp | 2 +- storage/connect/odbconn.cpp | 2 +- storage/connect/tabmysql.cpp | 54 +++++++++++++++++++++++++++++-- storage/connect/tabmysql.h | 5 +-- storage/connect/tabodbc.cpp | 62 +++++++++++++++++++++++++++++++++--- storage/connect/tabodbc.h | 5 +-- 6 files changed, 118 insertions(+), 12 deletions(-) diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp index d29c116756a..643d25daac1 100644 --- a/storage/connect/myconn.cpp +++ b/storage/connect/myconn.cpp @@ -808,7 +808,7 @@ int MYSQLC::ExecSQLcmd(PGLOBAL g, const char *query, int *w) //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, "%s", mysql_error(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)) { diff --git a/storage/connect/odbconn.cpp b/storage/connect/odbconn.cpp index c6a6fe0ed02..36cdd8e7330 100644 --- a/storage/connect/odbconn.cpp +++ b/storage/connect/odbconn.cpp @@ -1735,7 +1735,7 @@ bool ODBConn::ExecSQLcommand(char *sql) for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++) htrc(x->m_ErrMsg[i]); - strcpy(g->Message, x->GetErrorMessage(0)); + sprintf(g->Message, "Remote: %s", x->GetErrorMessage(0)); if (b) SQLCancel(hstmt); diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp index 469e659ade9..520b301ee68 100644 --- a/storage/connect/tabmysql.cpp +++ b/storage/connect/tabmysql.cpp @@ -622,6 +622,53 @@ bool TDBMYSQL::MakeInsert(PGLOBAL g) return FALSE; } // end of MakeInsert +/***********************************************************************/ +/* MakeCommand: make the Update or Delete statement to send to the */ +/* MySQL server. Limited to remote values and filtering. */ +/***********************************************************************/ +int TDBMYSQL::MakeCommand(PGLOBAL g) + { + Query = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64); + + if (Quoted > 0 || stricmp(Name, Tabname)) { + char *p, *qrystr, name[68]; + bool qtd = Quoted > 0; + + + // Make a lower case copy of the originale query + qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 1); + strlwr(strcpy(qrystr, Qrystr)); + + // 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 + + if ((p = strstr(qrystr, name))) { + memcpy(Query, Qrystr, p - qrystr); + Query[p - qrystr] = 0; + + if (qtd && *(p-1) == ' ') + strcat(strcat(strcat(Query, "`"), Tabname), "`"); + else + strcat(Query, Tabname); + + strcat(Query, Qrystr + (p - qrystr) + strlen(name)); + } else { + sprintf(g->Message, "Cannot use this %s command", + (Mode == MODE_UPDATE) ? "UPDATE" : "DELETE"); + return RC_FX; + } // endif p + + } else + strcpy(Query, Qrystr); + + return RC_OK; + } // end of MakeCommand + +#if 0 /***********************************************************************/ /* MakeUpdate: make the Update statement use with MySQL connection. */ /* Limited to remote values and filtering. */ @@ -636,7 +683,8 @@ int TDBMYSQL::MakeUpdate(PGLOBAL g) 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) + 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"); @@ -678,6 +726,7 @@ int TDBMYSQL::MakeDelete(PGLOBAL g) return RC_OK; } // end of MakeDelete +#endif // 0 /***********************************************************************/ /* XCV GetMaxSize: returns the maximum number of rows in the table. */ @@ -829,7 +878,8 @@ bool TDBMYSQL::OpenDB(PGLOBAL g) } // endif m_Rc } else - m_Rc = (Mode == MODE_DELETE) ? MakeDelete(g) : MakeUpdate(g); +// m_Rc = (Mode == MODE_DELETE) ? MakeDelete(g) : MakeUpdate(g); + m_Rc = MakeCommand(g); if (m_Rc == RC_FX) { Myc.Close(); diff --git a/storage/connect/tabmysql.h b/storage/connect/tabmysql.h index 969d51beff9..74b1d49e227 100644 --- a/storage/connect/tabmysql.h +++ b/storage/connect/tabmysql.h @@ -106,9 +106,10 @@ class TDBMYSQL : public TDBASE { // Internal functions bool MakeSelect(PGLOBAL g); bool MakeInsert(PGLOBAL g); - int MakeUpdate(PGLOBAL g); - int MakeDelete(PGLOBAL g); int BindColumns(PGLOBAL g); + int MakeCommand(PGLOBAL g); +//int MakeUpdate(PGLOBAL g); +//int MakeDelete(PGLOBAL g); int SendCommand(PGLOBAL g); // Members diff --git a/storage/connect/tabodbc.cpp b/storage/connect/tabodbc.cpp index bb7588e0d66..643b5e734c4 100644 --- a/storage/connect/tabodbc.cpp +++ b/storage/connect/tabodbc.cpp @@ -518,6 +518,61 @@ bool TDBODBC::BindParameters(PGLOBAL g) return false; } // 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. */ /***********************************************************************/ @@ -582,6 +637,7 @@ char *TDBODBC::MakeDelete(PGLOBAL g) return stmt; } // end of MakeDelete +#endif // 0 /***********************************************************************/ /* ResetSize: call by TDBMUL when calculating size estimate. */ @@ -713,10 +769,8 @@ bool TDBODBC::OpenDB(PGLOBAL g) } // endif Query - } else if (Mode == MODE_UPDATE) - Query = MakeUpdate(g); - else if (Mode == MODE_DELETE) - Query = MakeDelete(g); + } else if (Mode == MODE_UPDATE || Mode == MODE_DELETE) + Query = MakeCommand(g); else sprintf(g->Message, "Invalid mode %d", Mode); diff --git a/storage/connect/tabodbc.h b/storage/connect/tabodbc.h index 10a3f819f69..10c7207b954 100644 --- a/storage/connect/tabodbc.h +++ b/storage/connect/tabodbc.h @@ -102,10 +102,11 @@ class TDBODBC : public TDBASE { int Decode(char *utf, char *buf, size_t n); char *MakeSQL(PGLOBAL g, bool cnt); 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); +//char *MakeUpdate(PGLOBAL g); +//char *MakeDelete(PGLOBAL g); // Members ODBConn *Ocp; // Points to an ODBC connection class From a392a911c2e231ac892a175992909c54a2842520 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 20 Nov 2013 14:50:52 +0400 Subject: [PATCH 09/14] Adding tests for CATFUC=Tables and CATFUNC=Columns into odbc_sqlite3.test. --- .../connect/mysql-test/connect/r/odbc_sqlite3.result | 10 ++++++++++ storage/connect/mysql-test/connect/t/odbc_sqlite3.test | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/storage/connect/mysql-test/connect/r/odbc_sqlite3.result b/storage/connect/mysql-test/connect/r/odbc_sqlite3.result index 3ff99791760..00ef94c4791 100644 --- a/storage/connect/mysql-test/connect/r/odbc_sqlite3.result +++ b/storage/connect/mysql-test/connect/r/odbc_sqlite3.result @@ -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/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; From 8780e1ab24ff2671d200bd6eb14cd98d620ab361 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 20 Nov 2013 18:27:13 +0400 Subject: [PATCH 10/14] ConnectSE: Adding CATFUNC=Tables and CATFUC=Columns for the XLS ODBC data source. --- .../connect/mysql-test/connect/r/odbc_xls.result | 11 +++++++++++ storage/connect/mysql-test/connect/t/odbc_xls.test | 13 +++++++++++++ 2 files changed, 24 insertions(+) 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/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 From aaa982e7908b4d8464e9ac799336c5d890f72fad Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Fri, 22 Nov 2013 16:03:54 +0100 Subject: [PATCH 11/14] - Fix good recognition of MYSQL table column types. modified: storage/connect/ha_connect.cc storage/connect/myconn.cpp storage/connect/myutil.cpp storage/connect/odbccat.h storage/connect/odbconn.cpp storage/connect/tabmysql.cpp - Add tests on new MYSQL features added: storage/connect/mysql-test/connect/my.cnf storage/connect/mysql-test/connect/r/mysql_discovery.result storage/connect/mysql-test/connect/r/mysql_exec.result storage/connect/mysql-test/connect/r/mysql_new.result storage/connect/mysql-test/connect/t/myconn.inc storage/connect/mysql-test/connect/t/myconn_cleanup.inc storage/connect/mysql-test/connect/t/mysql_discovery.test storage/connect/mysql-test/connect/t/mysql_exec.test storage/connect/mysql-test/connect/t/mysql_new.test --- storage/connect/ha_connect.cc | 44 ++- storage/connect/myconn.cpp | 2 +- storage/connect/mysql-test/connect/my.cnf | 15 + .../connect/r/mysql_discovery.result | 42 +++ .../mysql-test/connect/r/mysql_exec.result | 62 ++++ .../mysql-test/connect/r/mysql_new.result | 218 ++++++++++++ .../connect/mysql-test/connect/t/myconn.inc | 27 ++ .../mysql-test/connect/t/myconn_cleanup.inc | 9 + .../mysql-test/connect/t/mysql_discovery.test | 33 ++ .../mysql-test/connect/t/mysql_exec.test | 45 +++ .../mysql-test/connect/t/mysql_new.test | 325 ++++++++++++++++++ storage/connect/myutil.cpp | 34 +- storage/connect/odbccat.h | 2 + storage/connect/odbconn.cpp | 2 + storage/connect/tabmysql.cpp | 11 +- 15 files changed, 844 insertions(+), 27 deletions(-) create mode 100644 storage/connect/mysql-test/connect/my.cnf create mode 100644 storage/connect/mysql-test/connect/r/mysql_discovery.result create mode 100644 storage/connect/mysql-test/connect/r/mysql_exec.result create mode 100644 storage/connect/mysql-test/connect/r/mysql_new.result create mode 100644 storage/connect/mysql-test/connect/t/myconn.inc create mode 100644 storage/connect/mysql-test/connect/t/myconn_cleanup.inc create mode 100644 storage/connect/mysql-test/connect/t/mysql_discovery.test create mode 100644 storage/connect/mysql-test/connect/t/mysql_exec.test create mode 100644 storage/connect/mysql-test/connect/t/mysql_new.test diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 6a294b8380d..414a4ee3443 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -1308,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; @@ -1409,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); @@ -3867,7 +3871,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"; @@ -3925,14 +3931,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); @@ -4224,7 +4232,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, v)) + if (add_field(&sql, cnm, typ, len, dec, tm, rem, 0, dbf, v)) rc= HA_ERR_OUT_OF_MEM; #endif // !NEW_WAY } // endfor i diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp index 643d25daac1..ab05bb9b952 100644 --- a/storage/connect/myconn.cpp +++ b/storage/connect/myconn.cpp @@ -182,7 +182,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, myc.Close(); return NULL; } else if (type == TYPE_STRING) - len = min(len, 255); + len = min(len, 4096); crp = crp->Next; // Data_Type crp->Kdata->SetValue(type, i); 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/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/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/myutil.cpp b/storage/connect/myutil.cpp index ecea6a0eada..1b6cbaa84c7 100644 --- a/storage/connect/myutil.cpp +++ b/storage/connect/myutil.cpp @@ -56,9 +56,27 @@ int MYSQLtoPLG(char *typname, char *var) else type = TYPE_ERROR; - // This is to make the difference between CHAR and VARCHAR - if (var && type == TYPE_STRING && stricmp(typname, "char")) - *var = 'V'; + 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 @@ -102,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, char var) +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 var ? "VARCHAR" : "CHAR"; + 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/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 36cdd8e7330..3ae1bb9b9fb 100644 --- a/storage/connect/odbconn.cpp +++ b/storage/connect/odbconn.cpp @@ -174,6 +174,7 @@ int TranslateSQLType(int stp, int prec, int& len, char& v) return type; } // end of TranslateSQLType +#if defined(PROMPT_OK) /***********************************************************************/ /* ODBCCheckConnection: Check completeness of connection string. */ /***********************************************************************/ @@ -205,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. */ diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp index 520b301ee68..7db44658058 100644 --- a/storage/connect/tabmysql.cpp +++ b/storage/connect/tabmysql.cpp @@ -1263,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; @@ -1283,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); From 385dbaeae01b0ebb22a271263f96d9ff778c85ec Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Tue, 26 Nov 2013 11:47:48 +0100 Subject: [PATCH 12/14] - Fix gcc compilation warnings modified: storage/connect/odbconn.cpp - Prepare Value and Valblk to support unsigned data types (not operational yet) modified: storage/connect/colblk.cpp storage/connect/filamvct.cpp storage/connect/myconn.cpp storage/connect/plgdbutl.cpp storage/connect/tabdos.cpp storage/connect/tabodbc.cpp storage/connect/tabvct.cpp storage/connect/valblk.cpp storage/connect/valblk.h storage/connect/value.cpp storage/connect/value.h storage/connect/xindex.cpp --- storage/connect/colblk.cpp | 6 +- storage/connect/filamvct.cpp | 2 +- storage/connect/myconn.cpp | 2 +- storage/connect/odbconn.cpp | 6 +- storage/connect/plgdbutl.cpp | 2 +- storage/connect/tabdos.cpp | 2 +- storage/connect/tabodbc.cpp | 2 +- storage/connect/tabvct.cpp | 2 +- storage/connect/valblk.cpp | 122 ++++++++++++++--- storage/connect/valblk.h | 42 +++++- storage/connect/value.cpp | 249 ++++++++++++++++++++++++----------- storage/connect/value.h | 85 +++++++----- storage/connect/xindex.cpp | 10 +- 13 files changed, 379 insertions(+), 153 deletions(-) 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/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/myconn.cpp b/storage/connect/myconn.cpp index ab05bb9b952..f9763f0eb2f 100644 --- a/storage/connect/myconn.cpp +++ b/storage/connect/myconn.cpp @@ -709,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; diff --git a/storage/connect/odbconn.cpp b/storage/connect/odbconn.cpp index 3ae1bb9b9fb..78731cee22c 100644 --- a/storage/connect/odbconn.cpp +++ b/storage/connect/odbconn.cpp @@ -1118,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); @@ -1240,8 +1240,8 @@ void ODBConn::GetConnectInfo() m_IDQuoteChar, sizeof(m_IDQuoteChar), &nResult); if (trace) - htrc("DBMS: %s, Version: %s\n", - 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 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/tabodbc.cpp b/storage/connect/tabodbc.cpp index 643b5e734c4..10b730fd834 100644 --- a/storage/connect/tabodbc.cpp +++ b/storage/connect/tabodbc.cpp @@ -1078,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 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/valblk.cpp b/storage/connect/valblk.cpp index 06c7776d2f5..128e7e924c7 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(mp, nval, type); + if (un) + blkp = new(g) TYPBLK(mp, nval, type, 0, true); + else + blkp = new(g) TYPBLK(mp, nval, type); + break; case TYPE_INT: - blkp = new(g) TYPBLK(mp, nval, type); + if (un) + blkp = new(g) TYPBLK(mp, nval, type, 0, true); + else + blkp = new(g) TYPBLK(mp, nval, type); + break; case TYPE_DATE: // ????? blkp = new(g) DATBLK(mp, nval); break; case TYPE_BIGINT: - blkp = new(g) TYPBLK(mp, nval, type); + if (un) + blkp = new(g) TYPBLK(mp, nval, type, 0, true); + else + blkp = new(g) TYPBLK(mp, nval, type); + break; case TYPE_FLOAT: - blkp = new(g) TYPBLK(mp, nval, prec, type); + blkp = new(g) TYPBLK(mp, nval, type, prec); break; case TYPE_TINY: - blkp = new(g) TYPBLK(mp, nval, type); + if (un) + blkp = new(g) TYPBLK(mp, nval, type, 0, true); + else + blkp = new(g) TYPBLK(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 -TYPBLK::TYPBLK(void *mp, int nval, int type) - : VALBLK(mp, type, nval), Typp((TYPE*&)Blkp) +TYPBLK::TYPBLK(void *mp, int nval, int type, int prec, bool un) + : VALBLK(mp, type, nval, un), Typp((TYPE*&)Blkp) { - Fmt = GetFmt(Type); - } // end of TYPBLK constructor - -template -TYPBLK::TYPBLK(void *mp, int nval, int prec, int type) - : VALBLK(mp, type, nval), Typp((TYPE*&)Blkp) - { - DBUG_ASSERT(Type == TYPE_FLOAT); Prec = prec; Fmt = GetFmt(Type); - } // end of DBLBLK constructor + } // end of TYPBLK constructor /***********************************************************************/ /* Initialization routine. */ @@ -249,14 +258,25 @@ template <> int TYPBLK::GetTypedValue(PVAL valp) {return valp->GetIntValue();} +uint TYPBLK::GetTypedValue(PVAL valp) + {return valp->GetUIntValue();} + template <> short TYPBLK::GetTypedValue(PVAL valp) {return valp->GetShortValue();} +template <> +ushort TYPBLK::GetTypedValue(PVAL valp) + {return valp->GetUShortValue();} + template <> longlong TYPBLK::GetTypedValue(PVAL valp) {return valp->GetBigintValue();} +template <> +ulonglong TYPBLK::GetTypedValue(PVAL valp) + {return valp->GetUBigintValue();} + template <> double TYPBLK::GetTypedValue(PVAL valp) {return valp->GetFloatValue();} @@ -265,6 +285,10 @@ template <> char TYPBLK::GetTypedValue(PVAL valp) {return valp->GetTinyValue();} +template <> +uchar TYPBLK::GetTypedValue(PVAL valp) + {return valp->GetUTinyValue();} + /***********************************************************************/ /* Set one value in a block from a zero terminated string. */ /***********************************************************************/ @@ -286,13 +310,21 @@ void TYPBLK::SetValue(PSZ p, int n) template <> int TYPBLK::GetTypedValue(PSZ p) {return atol(p);} template <> +uint TYPBLK::GetTypedValue(PSZ p) {return (unsigned)atol(p);} +template <> short TYPBLK::GetTypedValue(PSZ p) {return (short)atoi(p);} template <> +ushort TYPBLK::GetTypedValue(PSZ p) {return (ushort)atoi(p);} +template <> longlong TYPBLK::GetTypedValue(PSZ p) {return atoll(p);} template <> +ulonglong TYPBLK::GetTypedValue(PSZ p) {return (unsigned)atoll(p);} +template <> double TYPBLK::GetTypedValue(PSZ p) {return atof(p);} template <> char TYPBLK::GetTypedValue(PSZ p) {return (char)atoi(p);} +template <> +uchar TYPBLK::GetTypedValue(PSZ p) {return (uchar)atoi(p);} /***********************************************************************/ /* Set one value in a block from an array of characters. */ @@ -333,14 +365,26 @@ template <> int TYPBLK::GetTypedValue(PVBLK blk, int n) {return blk->GetIntValue(n);} +template <> +uint TYPBLK::GetTypedValue(PVBLK blk, int n) + {return blk->GetUIntValue(n);} + template <> short TYPBLK::GetTypedValue(PVBLK blk, int n) {return blk->GetShortValue(n);} +template <> +ushort TYPBLK::GetTypedValue(PVBLK blk, int n) + {return blk->GetUShortValue(n);} + template <> longlong TYPBLK::GetTypedValue(PVBLK blk, int n) {return blk->GetBigintValue(n);} +template <> +ulonglong TYPBLK::GetTypedValue(PVBLK blk, int n) + {return blk->GetUBigintValue(n);} + template <> double TYPBLK::GetTypedValue(PVBLK blk, int n) {return blk->GetFloatValue(n);} @@ -349,6 +393,10 @@ template <> char TYPBLK::GetTypedValue(PVBLK blk, int n) {return blk->GetTinyValue(n);} +template <> +uchar TYPBLK::GetTypedValue(PVBLK blk, int n) + {return blk->GetUTinyValue(n);} + #if 0 /***********************************************************************/ /* Set many values in a block from values in another block. */ @@ -516,6 +564,14 @@ short CHRBLK::GetShortValue(int n) return (short)atoi((char *)GetValPtrEx(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. */ /***********************************************************************/ @@ -524,6 +580,14 @@ int CHRBLK::GetIntValue(int n) return atol((char *)GetValPtrEx(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. */ /***********************************************************************/ @@ -532,6 +596,14 @@ longlong CHRBLK::GetBigintValue(int n) return atoll((char *)GetValPtrEx(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. */ /***********************************************************************/ @@ -548,6 +620,14 @@ char CHRBLK::GetTinyValue(int n) return (char)atoi((char *)GetValPtrEx(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. */ /***********************************************************************/ 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 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..3a10a04aa1a 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. */ @@ -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(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)0, TYPE_INT); + if (prec) + valp = new(g) TYPVAL((uint)0, TYPE_INT, true); + else + valp = new(g) TYPVAL((int)0, TYPE_INT); + break; case TYPE_BIGINT: - valp = new(g) TYPVAL((longlong)0, TYPE_BIGINT); + if (prec) + valp = new(g) TYPVAL((ulonglong)0, TYPE_BIGINT, true); + else + valp = new(g) TYPVAL((longlong)0, TYPE_BIGINT); + break; case TYPE_SHORT: - valp = new(g) TYPVAL((short)0, TYPE_SHORT); + if (prec) + valp = new(g) TYPVAL((ushort)0, TYPE_SHORT, true); + else + valp = new(g) TYPVAL((short)0, TYPE_SHORT); + break; case TYPE_FLOAT: valp = new(g) TYPVAL(0.0, prec, TYPE_FLOAT); break; case TYPE_TINY: - valp = new(g) TYPVAL((char)0, TYPE_TINY); + if (prec) + valp = new(g) TYPVAL((uchar)0, TYPE_TINY, true); + else + valp = new(g) TYPVAL((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,14 +385,26 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype) valp = new(g) TYPVAL(g, p, valp->GetValLen(), valp->GetValPrec()); break; - case TYPE_SHORT: - valp = new(g) TYPVAL(valp->GetShortValue(), TYPE_SHORT); + case TYPE_SHORT: + if (un) + valp = new(g) TYPVAL(valp->GetUShortValue(), TYPE_SHORT, true); + else + valp = new(g) TYPVAL(valp->GetShortValue(), TYPE_SHORT); + break; case TYPE_INT: - valp = new(g) TYPVAL(valp->GetIntValue(), TYPE_INT); + if (un) + valp = new(g) TYPVAL(valp->GetUIntValue(), TYPE_INT, true); + else + valp = new(g) TYPVAL(valp->GetIntValue(), TYPE_INT); + break; case TYPE_BIGINT: - valp = new(g) TYPVAL(valp->GetBigintValue(), TYPE_BIGINT); + if (un) + valp = new(g) TYPVAL(valp->GetUBigintValue(), TYPE_BIGINT, true); + else + valp = new(g) TYPVAL(valp->GetBigintValue(), TYPE_BIGINT); + break; case TYPE_DATE: valp = new(g) DTVAL(g, valp->GetIntValue()); @@ -411,7 +413,11 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype) valp = new(g) TYPVAL(valp->GetFloatValue(), TYPE_FLOAT); break; case TYPE_TINY: - valp = new(g) TYPVAL(valp->GetTinyValue(), TYPE_TINY); + if (un) + valp = new(g) TYPVAL(valp->GetUTinyValue(), TYPE_TINY, true); + else + valp = new(g) TYPVAL(valp->GetTinyValue(), TYPE_TINY); + break; default: sprintf(g->Message, MSG(BAD_VALUE_TYPE), newtype); @@ -428,14 +434,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 +453,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,22 +469,11 @@ const char *VALUE::GetXfmt(void) /* TYPVAL public constructor from a constant typed value. */ /***********************************************************************/ template -TYPVAL::TYPVAL(TYPE n, int type) : VALUE(type) +TYPVAL::TYPVAL(TYPE n, int type, int prec, bool un) + : VALUE(type, un) { Tval = n; Clen = sizeof(TYPE); - Prec = (Type == TYPE_FLOAT) ? 2 : 0; - } // end of TYPVAL constructor - -/***********************************************************************/ -/* TYPVAL public constructor from typed value. */ -/***********************************************************************/ -template -TYPVAL::TYPVAL(TYPE n, int prec, int type) : VALUE(type) - { - assert(Type == TYPE_FLOAT); - Tval = n; - Clen = sizeof(TYPE); Prec = prec; } // end of TYPVAL constructor @@ -522,14 +518,26 @@ template <> short TYPVAL::GetTypedValue(PVAL valp) {return valp->GetShortValue();} +template <> +ushort TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetUShortValue();} + template <> int TYPVAL::GetTypedValue(PVAL valp) {return valp->GetIntValue();} +template <> +uint TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetUIntValue();} + template <> longlong TYPVAL::GetTypedValue(PVAL valp) {return valp->GetBigintValue();} +template <> +ulonglong TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetUBigintValue();} + template <> double TYPVAL::GetTypedValue(PVAL valp) {return valp->GetFloatValue();} @@ -538,6 +546,10 @@ template <> char TYPVAL::GetTypedValue(PVAL valp) {return valp->GetTinyValue();} +template <> +uchar TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetUTinyValue();} + /***********************************************************************/ /* TYPVAL SetValue: convert chars extracted from a line to TYPE value.*/ /***********************************************************************/ @@ -545,7 +557,7 @@ template void TYPVAL::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 +582,7 @@ void TYPVAL::SetValue_char(char *p, int n) } // endswitch *p if (minus && Tval) - Tval = - Tval; + Tval = - (signed)Tval; if (trace > 1) htrc(strcat(strcat(strcpy(buf, " setting %s to: "), Fmt), "\n"), @@ -622,13 +634,21 @@ void TYPVAL::SetValue_psz(PSZ s) template <> int TYPVAL::GetTypedValue(PSZ s) {return atol(s);} template <> +uint TYPVAL::GetTypedValue(PSZ s) {return (unsigned)atol(s);} +template <> short TYPVAL::GetTypedValue(PSZ s) {return (short)atoi(s);} template <> +ushort TYPVAL::GetTypedValue(PSZ s) {return (ushort)atoi(s);} +template <> longlong TYPVAL::GetTypedValue(PSZ s) {return atoll(s);} template <> +ulonglong TYPVAL::GetTypedValue(PSZ s) {return (unsigned)atoll(s);} +template <> double TYPVAL::GetTypedValue(PSZ s) {return atof(s);} template <> char TYPVAL::GetTypedValue(PSZ s) {return (char)atoi(s);} +template <> +uchar TYPVAL::GetTypedValue(PSZ s) {return (uchar)atoi(s);} /***********************************************************************/ /* TYPVAL SetValue: set value with a TYPE extracted from a block. */ @@ -644,14 +664,26 @@ template <> int TYPVAL::GetTypedValue(PVBLK blk, int n) {return blk->GetIntValue(n);} +template <> +uint TYPVAL::GetTypedValue(PVBLK blk, int n) + {return (unsigned)blk->GetIntValue(n);} + template <> short TYPVAL::GetTypedValue(PVBLK blk, int n) {return blk->GetShortValue(n);} +template <> +ushort TYPVAL::GetTypedValue(PVBLK blk, int n) + {return (unsigned)blk->GetShortValue(n);} + template <> longlong TYPVAL::GetTypedValue(PVBLK blk, int n) {return blk->GetBigintValue(n);} +template <> +ulonglong TYPVAL::GetTypedValue(PVBLK blk, int n) + {return (unsigned)blk->GetBigintValue(n);} + template <> double TYPVAL::GetTypedValue(PVBLK blk, int n) {return blk->GetFloatValue(n);} @@ -660,6 +692,10 @@ template <> char TYPVAL::GetTypedValue(PVBLK blk, int n) {return blk->GetTinyValue(n);} +template <> +uchar TYPVAL::GetTypedValue(PVBLK blk, int n) + {return (unsigned)blk->GetTinyValue(n);} + /***********************************************************************/ /* TYPVAL SetBinValue: with bytes extracted from a line. */ /***********************************************************************/ @@ -684,7 +720,7 @@ bool TYPVAL::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 +766,7 @@ char *TYPVAL::GetCharString(char *p) return p; } // end of GetCharString +#if 0 /***********************************************************************/ /* TYPVAL GetShortString: get short representation of a typed value. */ /***********************************************************************/ @@ -779,6 +816,7 @@ char *TYPVAL::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 +913,6 @@ TYPVAL::TYPVAL(PSZ s) : VALUE(TYPE_STRING) TYPVAL::TYPVAL(PGLOBAL g, PSZ s, int n, int c) : VALUE(TYPE_STRING) { - assert(Type == TYPE_STRING); Len = (g) ? n : strlen(s); if (!s) { @@ -981,6 +1018,24 @@ void TYPVAL::SetValue(int n) Null = false; } // end of SetValue +/***********************************************************************/ +/* STRING SetValue: get the character representation of an uint. */ +/***********************************************************************/ +void TYPVAL::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. */ /***********************************************************************/ @@ -990,6 +1045,15 @@ void TYPVAL::SetValue(short i) Null = false; } // end of SetValue +/***********************************************************************/ +/* STRING SetValue: get the character representation of a ushort int. */ +/***********************************************************************/ +void TYPVAL::SetValue(ushort i) + { + SetValue((uint)i); + Null = false; + } // end of SetValue + /***********************************************************************/ /* STRING SetValue: get the character representation of a big integer.*/ /***********************************************************************/ @@ -1008,6 +1072,24 @@ void TYPVAL::SetValue(longlong n) Null = false; } // end of SetValue +/***********************************************************************/ +/* STRING SetValue: get the character representation of a big integer.*/ +/***********************************************************************/ +void TYPVAL::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. */ /***********************************************************************/ @@ -1042,6 +1124,15 @@ void TYPVAL::SetValue(char c) Null = false; } // end of SetValue +/***********************************************************************/ +/* STRING SetValue: get the character representation of a tiny int. */ +/***********************************************************************/ +void TYPVAL::SetValue(uchar c) + { + SetValue((uint)c); + Null = false; + } // end of SetValue + /***********************************************************************/ /* STRING SetBinValue: fill string with chars extracted from a line. */ /***********************************************************************/ @@ -1086,6 +1177,7 @@ char *TYPVAL::GetCharString(char *p) return Strp; } // end of GetCharString +#if 0 /***********************************************************************/ /* STRING GetShortString: get short representation of a char value. */ /***********************************************************************/ @@ -1130,6 +1222,7 @@ char *TYPVAL::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 13ce1436b39..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 */ /* */ @@ -51,10 +51,10 @@ 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 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: 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: 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 - 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 +//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 /***********************************************************************/ From f53ad74cd1f307c368b0ccd114278a4beaec8b6e Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Thu, 28 Nov 2013 01:25:39 +0100 Subject: [PATCH 13/14] - Fix some wrong changes preparing for unsigned data types modified: storage/connect/ha_connect.cc storage/connect/value.cpp - Fix the way GetPlug works (was not updating xp) modified: storage/connect/ha_connect.cc --- storage/connect/ha_connect.cc | 7 ++++--- storage/connect/value.cpp | 28 ++++++++++++++++------------ 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 414a4ee3443..3232d12af27 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -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, @@ -556,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; @@ -3822,7 +3822,8 @@ 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; diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index 3a10a04aa1a..077df346459 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -296,7 +296,7 @@ PVAL AllocateValue(PGLOBAL g, void *value, short type) valp = new(g) TYPVAL(*(longlong*)value, TYPE_BIGINT); break; case TYPE_FLOAT: - valp = new(g) TYPVAL(*(double *)value, TYPE_FLOAT); + valp = new(g) TYPVAL(*(double *)value, TYPE_FLOAT, 2); break; case TYPE_TINY: valp = new(g) TYPVAL(*(char *)value, TYPE_TINY); @@ -326,31 +326,31 @@ PVAL AllocateValue(PGLOBAL g, int type, int len, int prec, PSZ fmt) break; case TYPE_INT: if (prec) - valp = new(g) TYPVAL((uint)0, TYPE_INT, true); + valp = new(g) TYPVAL((uint)0, TYPE_INT, 0, true); else valp = new(g) TYPVAL((int)0, TYPE_INT); break; case TYPE_BIGINT: if (prec) - valp = new(g) TYPVAL((ulonglong)0, TYPE_BIGINT, true); + valp = new(g) TYPVAL((ulonglong)0, TYPE_BIGINT, 0, true); else valp = new(g) TYPVAL((longlong)0, TYPE_BIGINT); break; case TYPE_SHORT: if (prec) - valp = new(g) TYPVAL((ushort)0, TYPE_SHORT, true); + valp = new(g) TYPVAL((ushort)0, TYPE_SHORT, 0, true); else valp = new(g) TYPVAL((short)0, TYPE_SHORT); break; case TYPE_FLOAT: - valp = new(g) TYPVAL(0.0, prec, TYPE_FLOAT); + valp = new(g) TYPVAL(0.0, TYPE_FLOAT, prec); break; case TYPE_TINY: if (prec) - valp = new(g) TYPVAL((uchar)0, TYPE_TINY, true); + valp = new(g) TYPVAL((uchar)0, TYPE_TINY, 0, true); else valp = new(g) TYPVAL((char)0, TYPE_TINY); @@ -387,21 +387,23 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype, int uns) break; case TYPE_SHORT: if (un) - valp = new(g) TYPVAL(valp->GetUShortValue(), TYPE_SHORT, true); + valp = new(g) TYPVAL(valp->GetUShortValue(), + TYPE_SHORT, 0, true); else valp = new(g) TYPVAL(valp->GetShortValue(), TYPE_SHORT); break; case TYPE_INT: if (un) - valp = new(g) TYPVAL(valp->GetUIntValue(), TYPE_INT, true); + valp = new(g) TYPVAL(valp->GetUIntValue(), TYPE_INT, 0, true); else valp = new(g) TYPVAL(valp->GetIntValue(), TYPE_INT); break; case TYPE_BIGINT: if (un) - valp = new(g) TYPVAL(valp->GetUBigintValue(), TYPE_BIGINT, true); + valp = new(g) TYPVAL(valp->GetUBigintValue(), + TYPE_BIGINT, 0, true); else valp = new(g) TYPVAL(valp->GetBigintValue(), TYPE_BIGINT); @@ -410,11 +412,13 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype, int uns) valp = new(g) DTVAL(g, valp->GetIntValue()); break; case TYPE_FLOAT: - valp = new(g) TYPVAL(valp->GetFloatValue(), TYPE_FLOAT); + valp = new(g) TYPVAL(valp->GetFloatValue(), TYPE_FLOAT, + valp->GetValPrec()); break; case TYPE_TINY: if (un) - valp = new(g) TYPVAL(valp->GetUTinyValue(), TYPE_TINY, true); + valp = new(g) TYPVAL(valp->GetUTinyValue(), + TYPE_TINY, 0, true); else valp = new(g) TYPVAL(valp->GetTinyValue(), TYPE_TINY); @@ -582,7 +586,7 @@ void TYPVAL::SetValue_char(char *p, int n) } // endswitch *p if (minus && Tval) - Tval = - (signed)Tval; + Tval = (-(signed)Tval) ? -(signed)Tval : Tval; if (trace > 1) htrc(strcat(strcat(strcpy(buf, " setting %s to: "), Fmt), "\n"), From 0d37409fe7fd6cc4b576c62ed5c0a6804e049e8f Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Thu, 28 Nov 2013 23:37:27 +0100 Subject: [PATCH 14/14] - Fix gcc compiling error modified: storage/connect/valblk.cpp --- storage/connect/valblk.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/storage/connect/valblk.cpp b/storage/connect/valblk.cpp index 128e7e924c7..7fabad88794 100644 --- a/storage/connect/valblk.cpp +++ b/storage/connect/valblk.cpp @@ -258,6 +258,7 @@ template <> int TYPBLK::GetTypedValue(PVAL valp) {return valp->GetIntValue();} +template <> uint TYPBLK::GetTypedValue(PVAL valp) {return valp->GetUIntValue();}