diff options
author | Olivier Bertrand <bertrandop@gmail.com> | 2013-11-06 18:22:09 +0100 |
---|---|---|
committer | Olivier Bertrand <bertrandop@gmail.com> | 2013-11-06 18:22:09 +0100 |
commit | 056f35d0c136af4437344d4fbce80172e6d96817 (patch) | |
tree | 954befda500a4f7b1fb3b6d5b1e814a7077c3d96 | |
parent | f1325549e9eca1311435255854da0a93923eff9b (diff) | |
download | mariadb-git-056f35d0c136af4437344d4fbce80172e6d96817.tar.gz |
- 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
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<Item> 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(); @@ -779,6 +787,42 @@ void MYSQLC::Rewind(void) } // end of Rewind /***********************************************************************/ +/* Exec the Select SQL command and return ncol or afrws (TDBMYEXC). */ +/***********************************************************************/ +int MYSQLC::ExecSQLcmd(PGLOBAL g, const char *query, int *w) + { + int rc = RC_OK; + + if (!m_DB) { + strcpy(g->Message, "MySQL not connected"); + return RC_FX; + } else + *w = 0; + + if (!stricmp(query, "Warning") || !stricmp(query, "Note") + || !stricmp(query, "Error")) + return RC_INFO; + else + m_Afrw = 0; + +//if (mysql_query(m_DB, query) != 0) { + if (mysql_real_query(m_DB, query, strlen(query))) { + m_Afrw = (int)mysql_errno(m_DB); + sprintf(g->Message, "%s", mysql_error(m_DB)); + rc = RC_FX; +//} else if (!(m_Fields = mysql_field_count(m_DB))) { + } else if (!(m_Fields = (int)m_DB->field_count)) { +// m_Afrw = (int)mysql_affected_rows(m_DB); + m_Afrw = (int)m_DB->affected_rows; + rc = RC_NF; + } // endif's + +//*w = mysql_warning_count(m_DB); + *w = m_DB->warning_count; + return rc; + } // end of ExecSQLcmd + +/***********************************************************************/ /* Close the connection. */ /***********************************************************************/ void MYSQLC::Close(void) diff --git a/storage/connect/myconn.h b/storage/connect/myconn.h index 10ff76c3273..8a49239ec7a 100644 --- a/storage/connect/myconn.h +++ b/storage/connect/myconn.h @@ -26,7 +26,6 @@ #define DllItem #endif // !WIN32 -//#define TYPE_AM_MYSQL (AMT)192 #define MYSQL_ENABLED 0x00000001 #define MYSQL_LOGON 0x00000002 @@ -75,9 +74,12 @@ class DllItem MYSQLC { //const char *ServerInfo(void); int KillQuery(ulong id); int ExecSQL(PGLOBAL g, const char *query, int *w = NULL); + int ExecSQLcmd(PGLOBAL g, const char *query, int *w); +#if defined(MYSQL_PREPARED_STATEMENTS) int PrepareSQL(PGLOBAL g, const char *query); int ExecStmt(PGLOBAL g); int BindParams(PGLOBAL g, MYSQL_BIND *bind); +#endif // MYSQL_PREPARED_STATEMENTS PQRYRES GetResult(PGLOBAL g, bool pdb = FALSE); int Fetch(PGLOBAL g, int pos); char *GetCharField(int i); @@ -99,5 +101,6 @@ class DllItem MYSQLC { int m_Rows; // The number of rows of the result int N; int m_Fields; // The number of result fields + int m_Afrw; // The number of affected rows }; // end of class MYSQLC diff --git a/storage/connect/mysql-test/connect/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 |