diff options
author | Alexander Barkov <bar@mnogosearch.org> | 2013-06-08 01:16:00 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mnogosearch.org> | 2013-06-08 01:16:00 +0400 |
commit | a2cfb8023f3f2dfe06462a5294b53655abad4c9f (patch) | |
tree | c79e435fcc8fe09a750d89699f756ad56caf50da /storage | |
parent | 72ba95873a6d99def07a4bfecda44fb942165142 (diff) | |
parent | ffa2eb43560faca9f7d05c79d4c54657d33c62a6 (diff) | |
download | mariadb-git-a2cfb8023f3f2dfe06462a5294b53655abad4c9f.tar.gz |
Merge from 10.0-connect
added:
include/mysql/service_thd_timezone.h
libservices/thd_timezone_service.c
storage/connect/inihandl.h
storage/connect/mysql-test/connect/r/grant.result
storage/connect/mysql-test/connect/r/ini_grant.result
storage/connect/mysql-test/connect/r/mysql_grant.result
storage/connect/mysql-test/connect/r/occur.result
storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result
storage/connect/mysql-test/connect/r/pivot.result
storage/connect/mysql-test/connect/r/xcol.result
storage/connect/mysql-test/connect/r/xml_grant.result
storage/connect/mysql-test/connect/std_data/expenses.txt
storage/connect/mysql-test/connect/t/grant.test
storage/connect/mysql-test/connect/t/have_odbc_sqlite3.inc
storage/connect/mysql-test/connect/t/ini_grant.test
storage/connect/mysql-test/connect/t/mysql_grant.test
storage/connect/mysql-test/connect/t/occur.test
storage/connect/mysql-test/connect/t/odbc_sqlite3_grant.test
storage/connect/mysql-test/connect/t/pivot.test
storage/connect/mysql-test/connect/t/xcol.test
storage/connect/mysql-test/connect/t/xml_grant.test
storage/connect/rcmsg.h
storage/connect/taboccur.cpp
storage/connect/taboccur.h
storage/connect/tabutil.cpp
storage/connect/tabutil.h
storage/connect/tabxcl.cpp
storage/connect/tabxcl.h
modified:
include/my_global.h
include/my_time.h
include/mysql.h.pp
include/mysql/plugin.h
include/mysql/plugin_audit.h.pp
include/mysql/plugin_auth.h.pp
include/mysql/plugin_ftparser.h.pp
include/mysql/services.h
include/mysql_time.h
include/probes_mysql_nodtrace.h
include/service_versions.h
libservices/CMakeLists.txt
mysql-test/r/handlersocket.result
mysql-test/r/plugin.result
mysql-test/suite/plugins/r/show_all_plugins.result
sql/item_func.cc
sql/mysqld.cc
sql/set_var.cc
sql/sql_class.cc
sql/sql_plugin.cc
sql/sql_plugin.h
sql/sql_plugin_services.h
sql/sql_show.cc
sql/sys_vars.cc
storage/connect/CMakeLists.txt
storage/connect/catalog.h
storage/connect/colblk.cpp
storage/connect/colblk.h
storage/connect/connect.cc
storage/connect/connect.h
storage/connect/filamdbf.cpp
storage/connect/global.h
storage/connect/ha_connect.cc
storage/connect/ha_connect.h
storage/connect/inihandl.c
storage/connect/maputil.h
storage/connect/mycat.cc
storage/connect/myconn.cpp
storage/connect/myconn.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/dir.result
storage/connect/mysql-test/connect/r/fix.result
storage/connect/mysql-test/connect/r/fmt.result
storage/connect/mysql-test/connect/r/ini.result
storage/connect/mysql-test/connect/r/mysql.result
storage/connect/mysql-test/connect/r/odbc_sqlite3.result
storage/connect/mysql-test/connect/r/tbl.result
storage/connect/mysql-test/connect/r/upd.result
storage/connect/mysql-test/connect/r/vec.result
storage/connect/mysql-test/connect/r/xml.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/dir.test
storage/connect/mysql-test/connect/t/fix.test
storage/connect/mysql-test/connect/t/fmt.test
storage/connect/mysql-test/connect/t/ini.test
storage/connect/mysql-test/connect/t/mysql.test
storage/connect/mysql-test/connect/t/odbc_sqlite3.test
storage/connect/mysql-test/connect/t/tbl.test
storage/connect/mysql-test/connect/t/vec.test
storage/connect/mysql-test/connect/t/xml.test
storage/connect/odbconn.cpp
storage/connect/osutil.c
storage/connect/osutil.h
storage/connect/plgcnx.h
storage/connect/plgdbsem.h
storage/connect/plgdbutl.cpp
storage/connect/plugutil.c
storage/connect/rcmsg.c
storage/connect/reldef.cpp
storage/connect/tabcol.cpp
storage/connect/tabcol.h
storage/connect/tabfmt.cpp
storage/connect/tabmysql.cpp
storage/connect/tabmysql.h
storage/connect/tabodbc.cpp
storage/connect/tabpivot.cpp
storage/connect/tabpivot.h
storage/connect/tabsys.cpp
storage/connect/tabsys.h
storage/connect/tabtbl.cpp
storage/connect/tabtbl.h
storage/connect/tabwmi.cpp
storage/connect/user_connect.cc
storage/connect/valblk.cpp
storage/connect/valblk.h
storage/connect/value.cpp
storage/connect/value.h
storage/connect/xobject.h
storage/connect/xtable.h
storage/perfschema/ha_perfschema.cc
pending merges:
Alexander Barkov 2013-06-08 Fixing a few compiler warnings
Olivier Bertrand 2013-06-05 - Change CRLF line endings to LF
Olivier Bertrand 2013-06-04 - Adding parallelism to the TBL table type
Sergei Golubchik 2013-06-03 compiler warnings
Alexander Barkov 2013-06-03 Fixing the problem with my_bool_t define...
Olivier Bertrand 2013-05-28 - Fix crash when a null qrp is returned ...
Olivier Bertrand 2013-05-28 - Extending connect_assisted_discovery c...
Alexander Barkov 2013-05-28 Recording test results forgotten in the ...
Alexander Barkov 2013-05-27 [merge] Merging with the latest 10.0
Alexander Barkov 2013-05-27 - Fixing embedded verision of the Connec...
Alexander Barkov 2013-05-27 Fixing ABI template, to take into accoun...
Alexander Barkov 2013-05-27 Fixing ABI template, to take into accoun...
Olivier Bertrand 2013-05-27 - Fix Windows compile error
Alexander Barkov 2013-05-24 Adding the timezone plugin service, to c...
Alexander Barkov 2013-05-24 Do not run mysql.test in case of embedde...
Alexander Barkov 2013-05-24 Splitting SQLite3 tests into two parts:
Alexander Barkov 2013-05-24 Removing more cases of direct use of thd.
Alexander Barkov 2013-05-24 Removing direct access to thd, using fun...
Olivier Bertrand 2013-05-24 - Fix setting default type to MYSQL->PRO...
Alexander Barkov 2013-05-23 Connect: fixing non thread-safe code.
Olivier Bertrand 2013-05-22 - Changing CONNECT version number and date
Alexander Barkov 2013-05-21 "mtr --suite=connect --embedded" tests d...
Olivier Bertrand 2013-05-20 - Correct misplaced parenthesis in last ...
Olivier Bertrand 2013-05-20 - Save and restore srcdef when getting a...
Olivier Bertrand 2013-05-19 - Removing unused copy file
Olivier Bertrand 2013-05-19 [merge] - Commit merged and resolve
Alexander Barkov 2013-05-13 Fixing warnings (mostly "no previous dec...
Alexander Barkov 2013-05-13 Fixing compiler warnings ("no previous d...
Alexander Barkov 2013-05-13 Fixing a few "no previous declaration" w...
Alexander Barkov 2013-05-13 Fixing a few compilation warnings ("no p...
Olivier Bertrand 2013-05-19 - Allowing views and queries as paramete...
Olivier Bertrand 2013-05-13 [merge] - Commit merged changes
Alexander Barkov 2013-05-13 [merge] Merge from maria-10.0
Alexander Barkov 2013-05-13 Enabling --suite=connect by default
Olivier Bertrand 2013-05-13 - Code cleaning. Eliminating unused code...
Olivier Bertrand 2013-05-13 - fix use of uninitialized variable (colp)
Olivier Bertrand 2013-05-13 - Set tdbp to NULL when ignored
Olivier Bertrand 2013-05-12 - Changing mode from +x to -x
Olivier Bertrand 2013-05-12 - Code cleaning.
Olivier Bertrand 2013-05-11 - Fix tabpivot compile errors on Linux.
Olivier Bertrand 2013-05-11 - Added a test case for PIVOT tables
Olivier Bertrand 2013-05-10 - Add pivot table files and support
Olivier Bertrand 2013-05-10 - Added table type PIVOT
Olivier Bertrand 2013-05-09 - Fix inverted test on am in MYSQLDEF::D...
Olivier Bertrand 2013-05-05 - General code cleaning, eliminating a f...
Olivier Bertrand 2013-05-04 - Add test for XCOL and OCCUR tables
Olivier Bertrand 2013-05-02 - Adding a loop test to prevent PROXY ba...
Olivier Bertrand 2013-04-30 - Change in connect_assisted_discovery t...
Olivier Bertrand 2013-04-30 - Allow PROXY based tables to specify My...
Olivier Bertrand 2013-04-29 - Fix a bug causing a crash when using O...
Olivier Bertrand 2013-04-29 - Adding 3 new table types:
Diffstat (limited to 'storage')
96 files changed, 6077 insertions, 3203 deletions
diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index 4f02924d6b3..34bf7fc2491 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -18,25 +18,27 @@ SET(CONNECT_PLUGIN_DYNAMIC "connect") SET(CONNECT_SOURCES ha_connect.cc connect.cc user_connect.cc mycat.cc -fmdlex.c osutil.c plugutil.c rcmsg.c +fmdlex.c osutil.c plugutil.c rcmsg.c rcmsg.h csort.cpp maputil.cpp plgdbutl.cpp colblk.cpp reldef.cpp tabcol.cpp table.cpp filamap.cpp filamdbf.cpp filamfix.cpp filamtxt.cpp filamvct.cpp tabdos.cpp tabfix.cpp tabfmt.cpp tabmul.cpp tabsys.cpp tabvct.cpp valblk.cpp value.cpp xindex.cpp xobject.cpp filamzip.cpp tabtbl.cpp myutil.cpp +tabutil.cpp tabxcl.cpp taboccur.cpp tabpivot.cpp block.h catalog.h checklvl.h colblk.h connect.h csort.h engmsg.h filamap.h filamdbf.h filamfix.h filamtxt.h filamvct.h filamzip.h -global.h ha_connect.h maputil.h msgid.h mycat.h myutil.h os.h +global.h ha_connect.h inihandl.h maputil.h msgid.h mycat.h myutil.h os.h osutil.h plgcnx.h plgdbsem.h preparse.h reldef.h resource.h tabcol.h tabdos.h tabfix.h tabfmt.h tabmul.h tabsys.h tabtbl.h tabvct.h -user_connect.h valblk.h value.h xindex.h xobject.h xtable.h) +user_connect.h valblk.h value.h xindex.h xobject.h xtable.h +tabutil.h tabxcl.h taboccur.h tabpivot.h) # # Definitions that are shared for all OSes # add_definitions( -DMARIADB -DFORCE_INIT_OF_VARS ) -add_definitions( -DHUGE_SUPPORT -DZIP_SUPPORT ) +add_definitions( -DHUGE_SUPPORT -DZIP_SUPPORT -DPIVOT_SUPPORT ) # @@ -46,7 +48,6 @@ IF(UNIX) # Bar: -Wfatal-errors removed (does not present in gcc on solaris10) if(WITH_WARNINGS) add_definitions(-Wall -Wextra -Wmissing-declarations) - add_definitions(-Wno-non-virtual-dtor) message(STATUS "CONNECT: GCC: All warnings enabled") else() add_definitions(-Wall -Wmissing-declarations) @@ -62,13 +63,11 @@ IF(UNIX) # add_definitions(-Wno-int-to-pointer-cast) # Bar: -Wno-narrowing commented (does not present in gcc on solaris10) # add_definitions(-Wno-narrowing) - add_definitions(-Wno-non-virtual-dtor) # This switch is for pure C only: # add_definitions(-Wno-implicit-function-declaration) # These switches are for C++ only # add_definitions(-Wno-reorder) -# add_definitions(-Wno-delete-non-virtual-dtor) message(STATUS "CONNECT: GCC: Some warnings disabled") endif(WITH_WARNINGS) @@ -176,7 +175,7 @@ OPTION(CONNECT_WITH_MYSQL IF(CONNECT_WITH_MYSQL) SET(CONNECT_SOURCES ${CONNECT_SOURCES} - myconn.cpp myconn.h tabmysql.cpp tabxml.h) + myconn.cpp myconn.h tabmysql.cpp tabmysql.h) add_definitions(-DMYSQL_SUPPORT) IF(NOT UNIX) # diff --git a/storage/connect/catalog.h b/storage/connect/catalog.h index 4f0584ef7bc..3a06aea7a30 100644 --- a/storage/connect/catalog.h +++ b/storage/connect/catalog.h @@ -62,14 +62,9 @@ class DllExport CATALOG { virtual ~CATALOG() { } // Make -Wdelete-non-virtual-dtor happy // Implementation - void *GetDescp(void) {return Descp;} - PRELDEF GetTo_Desc(void) {return To_Desc;} -//PSZ GetDescFile(void) {return DescFile;} int GetCblen(void) {return Cblen;} bool GetDefHuge(void) {return DefHuge;} void SetDefHuge(bool b) {DefHuge = b;} -//bool GetSepIndex(void) {return SepIndex;} -//void SetSepIndex(bool b) {SepIndex = b;} char *GetCbuf(void) {return Cbuf;} char *GetDataPath(void) {return (char*)DataPath;} @@ -115,15 +110,10 @@ class DllExport CATALOG { virtual PRELDEF MakeTableDesc(PGLOBAL g, LPCSTR name, LPCSTR am) {return NULL;} // Members - PRELDEF To_Desc; /* To chain of relation desc. */ - void *Descp; /* To DB description area */ -//AREADEF DescArea; /* Table desc. area size */ char *Cbuf; /* Buffer used for col section */ int Cblen; /* Length of suballoc. buffer */ CURTAB Ctb; /* Used to enumerate tables */ bool DefHuge; /* true: tables default to huge */ -//bool SepIndex; /* true: separate index files */ -//char DescFile[_MAX_PATH]; /* DB description filename */ LPCSTR DataPath; /* Is the Path of DB data dir */ }; // end of class CATALOG diff --git a/storage/connect/colblk.cpp b/storage/connect/colblk.cpp index cdbf6f4b42b..dfdc82e99a7 100644 --- a/storage/connect/colblk.cpp +++ b/storage/connect/colblk.cpp @@ -160,19 +160,6 @@ bool COLBLK::CheckSort(PTDB tdbp) } // end of CheckSort /***********************************************************************/ -/* MarkCol: see PlugMarkCol for column references to mark. */ -/***********************************************************************/ -void COLBLK::MarkCol(ushort bits) - { - ColUse |= bits; - -#ifdef DEBTRACE - htrc(" column R%d.%s marked as %04X\n", - To_Tdb->GetTdb_No(), Name, ColUse); -#endif - } // end of MarkCol - -/***********************************************************************/ /* InitValue: prepare a column block for read operation. */ /* Now we use Format.Length for the len parameter to avoid strings */ /* to be truncated when converting from string to coded string. */ diff --git a/storage/connect/colblk.h b/storage/connect/colblk.h index cf6fb443308..5fbb118fc72 100644 --- a/storage/connect/colblk.h +++ b/storage/connect/colblk.h @@ -64,7 +64,6 @@ class DllExport COLBLK : public XOBJECT { virtual bool IsSpecial(void) {return false;} virtual int CheckSpcCol(PTDB tdbp, int n) {return 2;} virtual bool CheckSort(PTDB tdbp); - virtual void MarkCol(ushort bits); virtual bool Eval(PGLOBAL g); virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check); virtual void SetTo_Val(PVAL valp) {} diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc index 54816f80e5c..41fb061bd7f 100644 --- a/storage/connect/connect.cc +++ b/storage/connect/connect.cc @@ -31,7 +31,6 @@ /* global.h is header containing all global declarations. */ /* plgdbsem.h is header containing the DB applic. declarations. */ /***********************************************************************/ -#define MYSQL_SERVER 1 #define DONT_DEFINE_VOID #include "handler.h" #undef OFFSET @@ -71,10 +70,7 @@ int rename_file_ext(const char *from, const char *to,const char *ext); PGLOBAL CntExit(PGLOBAL g) { if (g) { - PDBUSER dup= PlgGetUser(g); - CntEndDB(g); - free(dup); if (g->Activityp) delete g->Activityp; @@ -94,13 +90,10 @@ void CntEndDB(PGLOBAL g) PDBUSER dbuserp= PlgGetUser(g); if (dbuserp) { - if (dbuserp->Catalog) { + if (dbuserp->Catalog) delete dbuserp->Catalog; - dbuserp->Catalog= NULL; - } // endif Catalog - *dbuserp->Name= '\0'; -// *dbuserp->Work= '\0'; + free(dbuserp); } // endif dbuserp } // end of CntEndDB @@ -258,10 +251,12 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2, return true; } // endif tdbp - if (!c1) - // Allocate all column blocks for that table - tdbp->ColDB(g, NULL, 0); - else for (p= c1; *p; p+= n) { + if (!c1) { + if (mode == MODE_INSERT) + // Allocate all column blocks for that table + tdbp->ColDB(g, NULL, 0); + + } else for (p= c1; *p; p+= n) { // Allocate only used column blocks if (xtrace) printf("Allocating column %s\n", p); @@ -657,11 +652,6 @@ int CntIndexInit(PGLOBAL g, PTDB ptdb, int id) cdp= tdbp->Key(k)->GetCdp(); valp= AllocateValue(g, cdp->GetType(), cdp->GetLength()); tdbp->To_Link[k]= new(g) CONSTANT(valp); - -//if (kdp->Klen && tdbp->To_Link[k]->GetResultType() == TYPE_STRING) -// ((XCOLBLK*)tdbp->To_Link[k])->SetLength(kdp->Klen); - -//((PCOL)tdbp->To_Link[k])->InitValue(g); } // endfor k // Make the index on xdp diff --git a/storage/connect/connect.h b/storage/connect/connect.h index 3fd52d283c6..e81e54776c9 100644 --- a/storage/connect/connect.h +++ b/storage/connect/connect.h @@ -44,6 +44,7 @@ RCODE CntDeleteRow(PGLOBAL g, PTDB tdbp, bool all); bool CntInfo(PGLOBAL g, PTDB tdbp, PXF info); int CntIndexRange(PGLOBAL g, PTDB ptdb, const uchar* *key, uint *len, bool *incl, key_part_map *kmap); +PGLOBAL CntExit(PGLOBAL g); /***********************************************************************/ /* Definition of classes XCOLCRT, XIXDEF, XKPDEF, DOXDEF, TDBDOX */ diff --git a/storage/connect/filamdbf.cpp b/storage/connect/filamdbf.cpp index 3575a6b422a..0a67195b200 100644 --- a/storage/connect/filamdbf.cpp +++ b/storage/connect/filamdbf.cpp @@ -178,15 +178,13 @@ static int dbfhead(PGLOBAL g, FILE *file, PSZ fn, DBFHEADER *buf) /****************************************************************************/ PQRYRES DBFColumns(PGLOBAL g, const char *fn, BOOL info) { - static int dbtype[] = {DB_CHAR, DB_SHORT, DB_CHAR, - DB_INT, DB_INT, DB_SHORT}; static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT}; static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH, FLD_SCALE}; static unsigned int length[] = {11, 6, 8, 10, 10, 6}; char buf[2], filename[_MAX_PATH]; - int ncol = sizeof(dbtype) / sizeof(int); + int ncol = sizeof(buftyp) / sizeof(int); int rc, type, len, field, fields; BOOL bad; DBFHEADER mainhead; @@ -228,8 +226,7 @@ PQRYRES DBFColumns(PGLOBAL g, const char *fn, BOOL info) fields = 0; qrp = PlgAllocResult(g, ncol, fields, IDS_COLUMNS + 3, - dbtype, buftyp, fldtyp, length, true, false); -//qrp->Info = info || (rc == RC_INFO); + buftyp, fldtyp, length, true, false); if (info) return qrp; diff --git a/storage/connect/global.h b/storage/connect/global.h index ae50e5ac160..303078f5a18 100644 --- a/storage/connect/global.h +++ b/storage/connect/global.h @@ -239,7 +239,8 @@ DllExport short GetLineLength(PGLOBAL); // Console line length DllExport PGLOBAL PlugInit(LPCSTR, uint); // Plug global initialization DllExport int PlugExit(PGLOBAL); // Plug global termination DllExport LPSTR PlugRemoveType(LPSTR, LPCSTR); -DllExport LPCSTR PlugSetPath(LPSTR, LPCSTR, LPCSTR); +DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR prefix, LPCSTR name, LPCSTR dir); +DllExport BOOL PlugIsAbsolutePath(LPCSTR path); DllExport void *PlugAllocMem(PGLOBAL, uint); DllExport BOOL PlugSubSet(PGLOBAL, void *, uint); DllExport void *PlugSubAlloc(PGLOBAL, void *, size_t); diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 8136e6d0263..7d37b79bae8 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -27,11 +27,12 @@ ha_connect will let you create/open/delete tables, the created table can be done specifying an already existing file, the drop table command will just suppress the table definition but not the eventual data file. - Indexes are not yet supported but data can be inserted, updated or deleted. + Indexes are not supported for all table types but data can be inserted, + updated or deleted. You can enable the CONNECT storage engine in your build by doing the following during your build process:<br> ./configure - --with-connect-storage-engine (not implemented yet) + --with-connect-storage-engine You can install the CONNECT handler as all other storage handlers. @@ -122,6 +123,7 @@ #include "tabmysql.h" #endif // MYSQL_SUPPORT #include "filamdbf.h" +#include "tabxcl.h" #include "tabfmt.h" #include "reldef.h" #include "tabcol.h" @@ -136,6 +138,7 @@ #include "mycat.h" #include "myutil.h" #include "preparse.h" +#include "inihandl.h" #define PLGXINI "plgcnx.ini" /* Configuration settings file */ #define my_strupr(p) my_caseup_str(default_charset_info, (p)); @@ -156,7 +159,7 @@ extern "C" char nmfile[]; extern "C" char pdebug[]; extern "C" { - char version[]= "Version 1.01.0004 April 10, 2013"; + char version[]= "Version 1.01.0006 Mai 21, 2013"; #if defined(XMSG) char msglang[]; // Default message language @@ -164,6 +167,16 @@ extern "C" { int trace= 0; // The general trace value } // extern "C" +bool OcrColumns(PGLOBAL g, PQRYRES qrp, const char *col, + const char *ocr, const char *rank); +bool OcrSrcCols(PGLOBAL g, PQRYRES qrp, const char *col, + const char *ocr, const char *rank); +PQRYRES PivotColumns(PGLOBAL g, const char *tab, const char *src, + const char *picol, const char *fncol, + const char *host, const char *db, + const char *user, const char *pwd, + int port); + /****************************************************************************/ /* Initialize the ha_connect static members. */ /****************************************************************************/ @@ -187,44 +200,13 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, handlerton *connect_hton; /** - structure for CREATE TABLE options (table options) + CREATE TABLE option list (table options) These can be specified in the CREATE TABLE: CREATE TABLE ( ... ) {...here...} */ -struct ha_table_option_struct { - const char *type; - const char *filename; - const char *optname; - const char *tabname; - const char *tablist; - const char *dbname; - const char *separator; -//const char *connect; - const char *qchar; - const char *module; - const char *subtype; - const char *catfunc; - const char *oplist; - const char *data_charset; - ulonglong lrecl; - ulonglong elements; -//ulonglong estimate; - ulonglong multiple; - ulonglong header; - ulonglong quoted; - ulonglong ending; - ulonglong compressed; - bool mapped; - bool huge; - bool split; - bool readonly; - bool sepindex; - }; - ha_create_table_option connect_table_option_list[]= { - // These option are for stand alone Connect tables HA_TOPTION_STRING("TABLE_TYPE", type), HA_TOPTION_STRING("FILE_NAME", filename), HA_TOPTION_STRING("XFILE_NAME", optname), @@ -237,6 +219,8 @@ ha_create_table_option connect_table_option_list[]= HA_TOPTION_STRING("MODULE", module), HA_TOPTION_STRING("SUBTYPE", subtype), HA_TOPTION_STRING("CATFUNC", catfunc), + HA_TOPTION_STRING("SRCDEF", srcdef), + HA_TOPTION_STRING("COLIST", colist), HA_TOPTION_STRING("OPTION_LIST", oplist), HA_TOPTION_STRING("DATA_CHARSET", data_charset), HA_TOPTION_NUMBER("LRECL", lrecl, 0, 0, INT_MAX32, 1), @@ -244,8 +228,8 @@ ha_create_table_option connect_table_option_list[]= //HA_TOPTION_NUMBER("ESTIMATE", estimate, 0, 0, INT_MAX32, 1), HA_TOPTION_NUMBER("MULTIPLE", multiple, 0, 0, 2, 1), HA_TOPTION_NUMBER("HEADER", header, 0, 0, 3, 1), - HA_TOPTION_NUMBER("QUOTED", quoted, -1, 0, 3, 1), - HA_TOPTION_NUMBER("ENDING", ending, -1, 0, INT_MAX32, 1), + HA_TOPTION_NUMBER("QUOTED", quoted, (ulonglong) -1, 0, 3, 1), + HA_TOPTION_NUMBER("ENDING", ending, (ulonglong) -1, 0, INT_MAX32, 1), HA_TOPTION_NUMBER("COMPRESS", compressed, 0, 0, 2, 1), //HA_TOPTION_BOOL("COMPRESS", compressed, 0), HA_TOPTION_BOOL("MAPPED", mapped, 0), @@ -258,25 +242,14 @@ ha_create_table_option connect_table_option_list[]= /** - structure for CREATE TABLE options (field options) + CREATE TABLE option list (field options) These can be specified in the CREATE TABLE per field: CREATE TABLE ( field ... {...here...}, ... ) */ -struct ha_field_option_struct -{ - ulonglong offset; - ulonglong freq; // Not used by this version - ulonglong opt; // Not used by this version - ulonglong fldlen; - const char *dateformat; - const char *fieldformat; - char *special; -}; - ha_create_table_option connect_field_option_list[]= { - HA_FOPTION_NUMBER("FLAG", offset, -1, 0, INT_MAX32, 1), + HA_FOPTION_NUMBER("FLAG", offset, (ulonglong) -1, 0, INT_MAX32, 1), HA_FOPTION_NUMBER("FREQUENCY", freq, 0, 0, INT_MAX32, 1), // not used HA_FOPTION_NUMBER("OPT_VALUE", opt, 0, 0, 2, 1), // used for indexing HA_FOPTION_NUMBER("FIELD_LENGTH", fldlen, 0, 0, INT_MAX32, 1), @@ -327,6 +300,13 @@ static void init_connect_psi_keys() {} #endif +DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir) +{ + const char *res= PlugSetPath(to, mysql_data_home, name, dir); + return res; +} + + /** @brief If frm_error() is called then we will use this to determine @@ -345,9 +325,8 @@ static void init_connect_psi_keys() {} delete_table method in handler.cc */ static const char *ha_connect_exts[]= { - ".tbl", ".dnx", ".fnx", ".bnx", ".vnx", ".dbx", ".dos", ".fix", ".csv", - ".fmt", ".dbf", ".xml", ".ini", ".vec", ".odbc", ".mysql", ".dir", - ".mac", ".wmi", ".bin", ".oem", + ".dos", ".fix", ".csv",".bin", ".fmt", ".dbf", ".xml", ".ini", ".vec", + ".dnx", ".fnx", ".bnx", ".vnx", ".dbx", NULL }; @@ -632,7 +611,7 @@ static char *GetListOption(PGLOBAL g, const char *opname, } else { if (pn) { - n= pn - pk; + n= min(pn - pk, 15); memcpy(key, pk, n); key[n]= 0; } else @@ -697,6 +676,10 @@ char *ha_connect::GetStringOption(char *opname, char *sdef) opval= (char*)options->subtype; else if (!stricmp(opname, "Catfunc")) opval= (char*)options->catfunc; + else if (!stricmp(opname, "Srcdef")) + opval= (char*)options->srcdef; + else if (!stricmp(opname, "Colist")) + opval= (char*)options->colist; else if (!stricmp(opname, "Data_charset")) opval= (char*)options->data_charset; @@ -708,6 +691,14 @@ char *ha_connect::GetStringOption(char *opname, char *sdef) // Return the handler default value if (!stricmp(opname, "Dbname") || !stricmp(opname, "Database")) opval= (char*)GetDBName(NULL); // Current database + else if (!stricmp(opname, "Type")) // Default type + opval= (!options) ? NULL : + (options->srcdef) ? (char*)"MYSQL" : + (options->tabname) ? (char*)"PROXY" : (char*)"DOS"; + else if (!stricmp(opname, "User")) // Connected user + opval= (char *) "root"; + else if (!stricmp(opname, "Host")) // Connected user host + opval= (char *) "localhost"; else opval= sdef; // Caller default @@ -728,7 +719,9 @@ bool ha_connect::GetBooleanOption(char *opname, bool bdef) char *pv; PTOS options= GetTableOptionStruct(table); - if (!options) + if (!stricmp(opname, "View")) + opval= (tshp) ? tshp->is_view : table->s->is_view; + else if (!options) ; else if (!stricmp(opname, "Mapped")) opval= options->mapped; @@ -773,9 +766,9 @@ bool ha_connect::SetBooleanOption(char *opname, bool b) /****************************************************************************/ int ha_connect::GetIntegerOption(char *opname) { - int opval= NO_IVAL; - char *pv; - PTOS options= GetTableOptionStruct(table); + ulonglong opval= NO_IVAL; + char *pv; + PTOS options= GetTableOptionStruct(table); if (!options) ; @@ -799,11 +792,11 @@ int ha_connect::GetIntegerOption(char *opname) else if (!stricmp(opname, "Compressed")) opval= (options->compressed); - if (opval == NO_IVAL && options && options->oplist) + if (opval == (ulonglong)NO_IVAL && options && options->oplist) if ((pv= GetListOption(xp->g, opname, options->oplist))) - opval= atoi(pv); + opval= (unsigned)atoll(pv); - return opval; + return (int)opval; } // end of GetIntegerOption /****************************************************************************/ @@ -870,7 +863,7 @@ void *ha_connect::GetColumnOption(void *field, PCOLINFO pcf) } else fldp= (tshp) ? tshp->field : table->field; - if (!(fp= *fldp)) + if (!fldp || !(fp= *fldp)) return NULL; // Get the CONNECT field options structure @@ -885,13 +878,13 @@ void *ha_connect::GetColumnOption(void *field, PCOLINFO pcf) pcf->Name= (char*)fp->field_name; pcf->Prec= 0; - pcf->Opt= (fop) ? fop->opt : 0; + pcf->Opt= (fop) ? (int)fop->opt : 0; if ((pcf->Length= fp->field_length) < 0) pcf->Length= 256; // BLOB? if (fop) { - pcf->Offset= fop->offset; + pcf->Offset= (int)fop->offset; // pcf->Freq= fop->freq; pcf->Datefmt= (char*)fop->dateformat; pcf->Fieldfmt= (char*)fop->fieldformat; @@ -905,6 +898,7 @@ void *ha_connect::GetColumnOption(void *field, PCOLINFO pcf) switch (fp->type()) { case MYSQL_TYPE_BLOB: case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_VAR_STRING: pcf->Flags |= U_VAR; case MYSQL_TYPE_STRING: pcf->Type= TYPE_STRING; @@ -941,7 +935,7 @@ void *ha_connect::GetColumnOption(void *field, PCOLINFO pcf) // Field_length is only used for DATE columns if (fop->fldlen) - pcf->Length= fop->fldlen; + pcf->Length= (int)fop->fldlen; else { int len; @@ -1122,8 +1116,9 @@ PTDB ha_connect::GetTDB(PGLOBAL g) table_name= GetTableName(); - if (tdbp && !stricmp(tdbp->GetName(), table_name) - && tdbp->GetMode() == xmod && !xp->CheckQuery(valid_query_id)) { + if (!xp->CheckQuery(valid_query_id) && tdbp + && !stricmp(tdbp->GetName(), table_name) + && tdbp->GetMode() == xmod) { tp= tdbp; tp->SetMode(xmod); } else if ((tp= CntGetTDB(g, table_name, xmod, this))) @@ -1874,11 +1869,13 @@ int ha_connect::open(const char *name, int mode, uint test_if_locked) // Try to get the user if possible xp= GetUser(ha_thd(), xp); - PGLOBAL g= xp->g; + PGLOBAL g= (xp) ? xp->g : NULL; // Try to set the database environment if (g) rc= (CntCheckDB(g, this, name)) ? (-2) : 0; + else + rc= HA_ERR_INTERNAL_ERROR; DBUG_RETURN(rc); } // end of open @@ -2688,18 +2685,24 @@ int ha_connect::delete_all_rows() bool ha_connect::check_privileges(THD *thd, PTOS options) { - if (!options->type) - options->type= "DOS"; + if (!options->type) { + if (options->srcdef) + options->type= "MYSQL"; + else if (options->tabname) + options->type= "PROXY"; + else + options->type= "DOS"; + + } // endif type switch (GetTypeID(options->type)) { case TAB_UNDEF: - case TAB_CATLG: +// case TAB_CATLG: case TAB_PLG: case TAB_JCT: case TAB_DMY: case TAB_NIY: - case TAB_PIVOT: my_printf_error(ER_UNKNOWN_ERROR, "Unsupported table type %s", MYF(0), options->type); return true; @@ -2733,13 +2736,18 @@ bool ha_connect::check_privileges(THD *thd, PTOS options) case TAB_OEM: return check_access(thd, FILE_ACL, NULL, NULL, NULL, 0, 0); + // This is temporary until a solution is found case TAB_TBL: + case TAB_XCL: + case TAB_PRX: + case TAB_OCCUR: + case TAB_PIVOT: return false; } my_printf_error(ER_UNKNOWN_ERROR, "check_privileges failed", MYF(0)); return true; -} +} // end of check_privileges // Check that two indexes are equivalent bool ha_connect::IsSameIndex(PIXDEF xp1, PIXDEF xp2) @@ -2791,12 +2799,14 @@ bool ha_connect::IsSameIndex(PIXDEF xp1, PIXDEF xp2) int ha_connect::external_lock(THD *thd, int lock_type) { int rc= 0; - bool del= false, xcheck=false, cras= false; + bool xcheck=false, cras= false; MODE newmode; PTOS options= GetTableOptionStruct(table); PGLOBAL g= GetPlug(thd, xp); DBUG_ENTER("ha_connect::external_lock"); + DBUG_ASSERT(thd == current_thd); + if (xtrace) printf("%p external_lock: lock_type=%d\n", this, lock_type); @@ -2831,6 +2841,10 @@ int ha_connect::external_lock(THD *thd, int lock_type) bool oldsep= ((PCHK)g->Xchk)->oldsep; bool newsep= ((PCHK)g->Xchk)->newsep; PTDBDOS tdp= (PTDBDOS)(tdbp ? tdbp : GetTDB(g)); + + if (!tdp) + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + PDOSDEF ddp= (PDOSDEF)tdp->GetDef(); PIXDEF xp, xp1, xp2, drp=NULL, adp= NULL; PIXDEF oldpix= ((PCHK)g->Xchk)->oldpix; @@ -2913,16 +2927,16 @@ int ha_connect::external_lock(THD *thd, int lock_type) } // endif MODE_ANY if (xtrace) { - printf("%p external_lock: cmdtype=%d\n", this, thd->lex->sql_command); - printf("Cmd=%.*s\n", (int) thd->query_string.length(), - thd->query_string.str()); + LEX_STRING *query_string= thd_query_string(thd); + printf("%p external_lock: cmdtype=%d\n", this, thd_sql_command(thd)); + printf("Cmd=%.*s\n", (int) query_string->length, query_string->str); } // endif xtrace // Next code is temporarily replaced until sql_command is set stop= false; if (newmode == MODE_WRITE) { - switch (thd->lex->sql_command) { + switch (thd_sql_command(thd)) { case SQLCOM_CREATE_TABLE: case SQLCOM_INSERT: case SQLCOM_LOAD: @@ -2935,7 +2949,6 @@ int ha_connect::external_lock(THD *thd, int lock_type) // break; case SQLCOM_DELETE: case SQLCOM_DELETE_MULTI: - del= true; case SQLCOM_TRUNCATE: newmode= MODE_DELETE; break; @@ -2962,13 +2975,13 @@ int ha_connect::external_lock(THD *thd, int lock_type) newmode= MODE_ANY; break; default: - printf("Unsupported sql_command=%d", thd->lex->sql_command); - sprintf(g->Message, "Unsupported sql_command=%d", thd->lex->sql_command); + printf("Unsupported sql_command=%d", thd_sql_command(thd)); + sprintf(g->Message, "Unsupported sql_command=%d", thd_sql_command(thd)); DBUG_RETURN(HA_ERR_INTERNAL_ERROR); } // endswitch newmode } else if (newmode == MODE_READ) { - switch (thd->lex->sql_command) { + switch (thd_sql_command(thd)) { case SQLCOM_CREATE_TABLE: xcheck= true; cras= true; @@ -2999,8 +3012,8 @@ int ha_connect::external_lock(THD *thd, int lock_type) newmode= MODE_ANY; break; default: - printf("Unsupported sql_command=%d", thd->lex->sql_command); - sprintf(g->Message, "Unsupported sql_command=%d", thd->lex->sql_command); + printf("Unsupported sql_command=%d", thd_sql_command(thd)); + sprintf(g->Message, "Unsupported sql_command=%d", thd_sql_command(thd)); DBUG_RETURN(HA_ERR_INTERNAL_ERROR); } // endswitch newmode @@ -3036,8 +3049,15 @@ int ha_connect::external_lock(THD *thd, int lock_type) // This can NOT be called without open called first, but // the table can have been closed since then } else if (!tdbp || xp->CheckQuery(valid_query_id) || xmod != newmode) { - if (tdbp) - CloseTable(g); + if (tdbp) { + // If this is called by a later query, the table may have + // been already closed and the tdbp is not valid anymore. + if (xp->last_query_id == valid_query_id) + rc= CloseTable(g); + else + tdbp= NULL; + + }// endif tdbp xmod= newmode; @@ -3103,6 +3123,63 @@ THR_LOCK_DATA **ha_connect::store_lock(THD *thd, /** + Searches for a pointer to the last occurrence of the + character c in the string src. + Returns true on failure, false on success. +*/ +static bool +strnrchr(LEX_CSTRING *ls, const char *src, size_t length, int c) +{ + const char *srcend, *s; + for (s= srcend= src + length; s > src; s--) + { + if (s[-1] == c) + { + ls->str= s; + ls->length= srcend - s; + return false; + } + } + return true; +} + + +/** + Split filename into database and table name. +*/ +static bool +filename_to_dbname_and_tablename(const char *filename, + char *database, size_t database_size, + char *table, size_t table_size) +{ +#if defined(WIN32) + char slash= '\\'; +#else // !WIN32 + char slash= '/'; +#endif // !WIN32 + LEX_CSTRING d, t; + size_t length= strlen(filename); + + /* Find filename - the rightmost directory part */ + if (strnrchr(&t, filename, length, slash) || t.length + 1 > table_size) + return true; + memcpy(table, t.str, t.length); + table[t.length]= '\0'; + if (!(length-= t.length)) + return true; + + length--; /* Skip slash */ + + /* Find database name - the second rightmost directory part */ + if (strnrchr(&d, filename, length, slash) || d.length + 1 > database_size) + return true; + memcpy(database, d.str, d.length); + database[d.length]= '\0'; + return false; +} + + +/** @brief Used to delete or rename a table. By the time delete_table() has been called all opened references to this table will have been closed @@ -3128,22 +3205,20 @@ int ha_connect::delete_or_rename_table(const char *name, const char *to) DBUG_ENTER("ha_connect::delete_or_rename_table"); /* We have to retrieve the information about this table options. */ ha_table_option_struct *pos; -#if defined(WIN32) - const char *fmt= ".\\%[^\\]\\%s"; -#else // !WIN32 - const char *fmt= "./%[^/]/%s"; -#endif // !WIN32 char key[MAX_DBKEY_LENGTH], db[128], tabname[128]; - int rc; + int rc = 0; uint key_length; TABLE_SHARE *share; THD *thd= current_thd; - if (to) - if (sscanf(to, fmt, db, tabname) != 2 || *tabname == '#') - goto fin; + if (to && (filename_to_dbname_and_tablename(to, db, sizeof(db), + tabname, sizeof(tabname)) || + *tabname == '#')) + goto fin; - if (sscanf(name, fmt, db, tabname) != 2 || *tabname == '#') + if (filename_to_dbname_and_tablename(name, db, sizeof(db), + tabname, sizeof(tabname)) || + *tabname == '#') goto fin; key_length= create_table_def_key(key, db, tabname); @@ -3177,7 +3252,7 @@ int ha_connect::delete_or_rename_table(const char *name, const char *to) err: free_table_share(share); fin: - DBUG_RETURN(0); + DBUG_RETURN(rc); } // end of delete_or_rename_table int ha_connect::delete_table(const char *name) @@ -3267,35 +3342,43 @@ static char *encode(PGLOBAL g, char *cnm) Return 0 if ok */ -bool add_field(String *sql, const char *field_name, const char *type, - int len, int dec, uint tm, const char *rem) +static bool add_field(String *sql, const char *field_name, const char *type, + int len, int dec, uint tm, const char *rem, int flag) { bool error= false; + error|= sql->append('`'); error|= sql->append(field_name); - error|= sql->append(' '); + error|= sql->append("` "); error|= sql->append(type); + if (len) { error|= sql->append('('); error|= sql->append_ulonglong(len); - if (dec) { + + if (dec || !strcmp(type, "DOUBLE")) { error|= sql->append(','); error|= sql->append_ulonglong(dec); - } + } // endif dec + error|= sql->append(')'); - } + } // endif len if (tm) error|= sql->append(STRING_WITH_LEN(" NOT NULL"), system_charset_info); if (rem && *rem) { - error|= sql->append(" COMMENT='"); + error|= sql->append(" COMMENT '"); error|= sql->append_for_single_quote(rem, strlen(rem)); error|= sql->append("'"); - } + } // endif rem - sql->append(','); + if (flag) { + error|= sql->append(" FLAG="); + error|= sql->append_ulonglong(flag); + } // endif flag + sql->append(','); return error; } // end of add_field @@ -3314,17 +3397,16 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, { char spc= ',', qch= 0; const char *fncn= "?"; - const char *user, *fn, *tab, *db, *host, *pwd, *prt, *sep; // *csn; - char *dsn; + const char *user, *fn, *db, *host, *pwd, *prt, *sep, *tbl, *src; + const char *col, *ocl, *rnk, *pic, *fcl; + char *tab, *dsn; #if defined(WIN32) char *nsp= NULL, *cls= NULL; #endif // WIN32 - int port= MYSQL_PORT, hdr= 0, mxr= 0, b= 0; + int port= 0, hdr= 0, mxr= 0, b= 0; uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL); - bool ok= false, dbf= false; + bool bif, ok= false, dbf= false; TABTYPE ttp= TAB_UNDEF; - MEM_ROOT *mem= thd->mem_root; - CHARSET_INFO *cs; PQRYRES qrp; PCOLRES crp; PGLOBAL g= GetPlug(thd, NULL); @@ -3338,51 +3420,88 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, sql.copy(STRING_WITH_LEN("CREATE TABLE whatever ("), system_charset_info); - user= host= pwd= prt= dsn= NULL; + user= host= pwd= prt= tbl= src= col= ocl= pic= fcl= rnk= dsn= NULL; // Get the useful create options - ttp= GetTypeID(topt->type); - fn= topt->filename; - tab= topt->tabname; - db= topt->dbname; + ttp= GetTypeID(topt->type); + fn= topt->filename; + tab= (char*)topt->tabname; + src= topt->srcdef; + db= topt->dbname; fncn= topt->catfunc; fnc= GetFuncID(fncn); - sep= topt->separator; + sep= topt->separator; spc= (!sep || !strcmp(sep, "\\t")) ? '\t' : *sep; qch= topt->qchar ? *topt->qchar : topt->quoted >= 0 ? '"' : 0; - hdr= topt->header; + hdr= (int)topt->header; + tbl= topt->tablist; + col= topt->colist; + if (topt->oplist) { - host= GetListOption(g,"host", topt->oplist, "localhost"); - user= GetListOption(g,"user", topt->oplist, "root"); - // Default value db can come from the DBNAME=xxx option. - db= GetListOption(g,"database", topt->oplist, db); - pwd= GetListOption(g,"password", topt->oplist); - prt= GetListOption(g,"port", topt->oplist); - port= (prt) ? atoi(prt) : MYSQL_PORT; + host= GetListOption(g,"host", topt->oplist, "localhost"); + user= GetListOption(g,"user", topt->oplist, "root"); + // Default value db can come from the DBNAME=xxx option. + db= GetListOption(g,"database", topt->oplist, db); + col= GetListOption(g,"colist", topt->oplist, col); + ocl= GetListOption(g,"occurcol", topt->oplist, NULL); + pic= GetListOption(g,"pivotcol", topt->oplist, NULL); + fcl= GetListOption(g,"fnccol", topt->oplist, NULL); + rnk= GetListOption(g,"rankcol", topt->oplist, NULL); + pwd= GetListOption(g,"password", topt->oplist); + prt= GetListOption(g,"port", topt->oplist); + port= (prt) ? atoi(prt) : 0; #if defined(WIN32) - nsp= GetListOption(g,"namespace", topt->oplist); - cls= GetListOption(g,"class", topt->oplist); + nsp= GetListOption(g,"namespace", topt->oplist); + cls= GetListOption(g,"class", topt->oplist); #endif // WIN32 - mxr= atoi(GetListOption(g,"maxerr", topt->oplist, "0")); - } // endelse option_list + mxr= atoi(GetListOption(g,"maxerr", topt->oplist, "0")); + } else { + host= "localhost"; + user= "root"; + } // endif option_list if (!db) - db= thd->db; // Default value + db= table_s->db.str; // Default value // Check table type if (ttp == TAB_UNDEF) { - strcpy(g->Message, "No table_type. Was set to DOS"); + topt->type= (src) ? "MYSQL" : (tab) ? "PROXY" : "DOS"; + ttp= GetTypeID(topt->type); + sprintf(g->Message, "No table_type. Was set to %s", topt->type); push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message); - ttp= TAB_DOS; - topt->type= "DOS"; } else if (ttp == TAB_NIY) { sprintf(g->Message, "Unsupported table type %s", topt->type); my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); return HA_ERR_INTERNAL_ERROR; } // endif ttp - if (!tab && !(fnc & (FNC_TABLE | FNC_COL))) - tab= (char*)create_info->alias; + if (!tab) { + if (ttp == TAB_TBL) { + // Make tab the first table of the list + char *p; + + if (!tbl) { + strcpy(g->Message, "Missing table list"); + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + return HA_ERR_INTERNAL_ERROR; + } // endif tbl + + tab= (char*)PlugSubAlloc(g, NULL, strlen(tbl) + 1); + strcpy(tab, tbl); + + if ((p= strchr(tab, ','))) + *p= 0; + + if ((p=strchr(tab, '.'))) { + *p= 0; + db= tab; + tab= p + 1; + } // endif p + + } else if (ttp != TAB_ODBC || !(fnc & (FNC_TABLE | FNC_COL))) + tab= (char*)create_info->alias; + + } // endif tab switch (ttp) { #if defined(ODBC_SUPPORT) @@ -3433,7 +3552,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ok= false; } else if (!user) - user= "root"; // Avoid crash + user= "root"; break; #endif // MYSQL_SUPPORT @@ -3442,6 +3561,14 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ok= true; break; #endif // WIN32 + case TAB_PIVOT: + supfnc = FNC_NO; + case TAB_PRX: + case TAB_TBL: + case TAB_XCL: + case TAB_OCCUR: + ok= true; + break; default: sprintf(g->Message, "Cannot get column info for table type %s", topt->type); } // endif ttp @@ -3453,19 +3580,36 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ok= false; } // endif supfnc + if (src && fnc != FNC_NO) { + strcpy(g->Message, "Cannot make catalog table from srcdef"); + ok= false; + } // endif src + + // Here we should test the flag column options when + // this function is called in case of CREATE .. SELECT + if (ok) { char *cnm, *rem; - int i, len, dec, typ; + int i, len, dec, typ, flg; const char *type; PDBUSER dup= PlgGetUser(g); PCATLG cat= (dup) ? dup->Catalog : NULL; if (cat) - cat->SetDataPath(g, thd->db); + cat->SetDataPath(g, table_s->db.str); else return HA_ERR_INTERNAL_ERROR; // Should never happen - switch (ttp) { + if (src && ttp != TAB_PIVOT) { + qrp= SrcColumns(g, host, db, user, pwd, src, port); + + if (qrp && ttp == TAB_OCCUR) + if (OcrSrcCols(g, qrp, col, ocl, rnk)) { + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + return HA_ERR_INTERNAL_ERROR; + } // endif OcrSrcCols + + } else switch (ttp) { case TAB_DBF: qrp= DBFColumns(g, fn, fnc == FNC_COL); break; @@ -3494,7 +3638,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, #if defined(MYSQL_SUPPORT) case TAB_MYSQL: qrp= MyColumns(g, host, db, user, pwd, tab, - NULL, port, false, fnc == FNC_COL); + NULL, port, fnc == FNC_COL); break; #endif // MYSQL_SUPPORT case TAB_CSV: @@ -3505,6 +3649,26 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, qrp= WMIColumns(g, nsp, cls, fnc == FNC_COL); break; #endif // WIN32 + case TAB_PRX: + case TAB_TBL: + case TAB_XCL: + case TAB_OCCUR: + bif= fnc == FNC_COL; + qrp= TabColumns(g, thd, db, tab, bif); + + if (!qrp && bif && fnc != FNC_COL) // tab is a view + qrp= MyColumns(g, host, db, user, pwd, tab, NULL, port, false); + + if (qrp && ttp == TAB_OCCUR && fnc != FNC_COL) + if (OcrColumns(g, qrp, col, ocl, rnk)) { + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + return HA_ERR_INTERNAL_ERROR; + } // endif OcrColumns + + break; + case TAB_PIVOT: + qrp= PivotColumns(g, tab, src, pic, fcl, host, db, user, pwd, port); + break; default: strcpy(g->Message, "System error during assisted discovery"); break; @@ -3515,15 +3679,17 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, return HA_ERR_INTERNAL_ERROR; } // endif qrp - if (fnc != FNC_NO) { - // Catalog table + if (fnc != FNC_NO || src || ttp == TAB_PIVOT) { + // Catalog like table for (crp=qrp->Colresp; !b && crp; crp= crp->Next) { cnm= encode(g, crp->Name); type= PLGtoMYSQLtype(crp->Type, dbf); len= crp->Length; + dec= crp->Prec; + flg= crp->Flag; // Now add the field - if (add_field(&sql, cnm, type, len, 0, NOT_NULL_FLAG, 0)) + if (add_field(&sql, cnm, type, len, dec, NOT_NULL_FLAG, 0, flg)) b= HA_ERR_OUT_OF_MEM; } // endfor crp @@ -3532,7 +3698,6 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, rem= NULL; typ= len= dec= 0; tm= NOT_NULL_FLAG; - cs= NULL; for (crp= qrp->Colresp; crp; crp= crp->Next) switch (crp->Fld) { @@ -3587,11 +3752,16 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, } // endif ttp #endif // ODBC_SUPPORT + // Make the arguments as required by add_fields type= PLGtoMYSQLtype(typ, true); + if (typ == TYPE_DATE) len= 0; - if (add_field(&sql, cnm, type, len, dec, tm, rem)) + + // Now add the field + if (add_field(&sql, cnm, type, len, dec, tm, rem, 0)) b= HA_ERR_OUT_OF_MEM; + } // endfor i sql.length(sql.length()-1); // remove the trailing comma @@ -3602,59 +3772,79 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ulonglong vull; const char *vstr; bool oom= false; + switch (opt->type) { case HA_OPTION_TYPE_ULL: - vull= *(ulonglong*)(((char*)topt) + opt->offset); + vull= *(ulonglong*)(((char*)topt) + opt->offset); + if (vull != opt->def_value) { oom|= sql.append(' '); oom|= sql.append(opt->name); oom|= sql.append('='); oom|= sql.append_ulonglong(vull); - } + } // endif vull + break; case HA_OPTION_TYPE_STRING: - vstr= *(char**)(((char*)topt) + opt->offset); + vstr= *(char**)(((char*)topt) + opt->offset); + if (vstr) { oom|= sql.append(' '); oom|= sql.append(opt->name); oom|= sql.append("='"); oom|= sql.append_for_single_quote(vstr, strlen(vstr)); oom|= sql.append('\''); - } + } // endif vstr + break; case HA_OPTION_TYPE_BOOL: - vull= *(bool*)(((char*)topt) + opt->offset); + vull= *(bool*)(((char*)topt) + opt->offset); + if (vull != opt->def_value) { oom|= sql.append(' '); oom|= sql.append(opt->name); oom|= sql.append('='); oom|= sql.append(vull ? "ON" : "OFF"); - } + } // endif vull + break; default: // no enums here, good :) break; - } + } // endswitch type + if (oom) b= HA_ERR_OUT_OF_MEM; - } + + } // endfor opt if (create_info->connect_string.length) { bool oom= false; + oom|= sql.append(' '); oom|= sql.append("CONNECTION='"); oom|= sql.append_for_single_quote(create_info->connect_string.str, create_info->connect_string.length); oom|= sql.append('\''); + if (oom) b= HA_ERR_OUT_OF_MEM; - } + + } // endif string if (create_info->default_table_charset) { bool oom= false; + oom|= sql.append(' '); oom|= sql.append("CHARSET="); oom|= sql.append(create_info->default_table_charset->csname); - } + + if (oom) + b= HA_ERR_OUT_OF_MEM; + + } // endif charset + + if (xtrace) + printf("s_init: %.*s\n", sql.length(), sql.ptr()); if (!b) b= table_s->init_from_sql_statement_string(thd, true, @@ -3664,7 +3854,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); return HA_ERR_INTERNAL_ERROR; -} // end of pre_create +} // end of connect_assisted_discovery /** @brief @@ -3700,7 +3890,8 @@ int ha_connect::create(const char *name, TABLE *table_arg, Field *fp; TABTYPE type; TABLE *st= table; // Probably unuseful - xp= GetUser(ha_thd(), xp); + THD *thd= ha_thd(); + xp= GetUser(thd, xp); PGLOBAL g= xp->g; DBUG_ENTER("ha_connect::create"); @@ -3710,7 +3901,20 @@ int ha_connect::create(const char *name, TABLE *table_arg, DBUG_ASSERT(options); type= GetTypeID(options->type); - if (check_privileges(ha_thd(), options)) + // Check table type + if (type == TAB_UNDEF) { + options->type= (options->srcdef) ? "MYSQL" : + (options->tabname) ? "PROXY" : "DOS"; + type= GetTypeID(options->type); + sprintf(g->Message, "No table_type. Will be set to %s", options->type); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message); + } else if (type == TAB_NIY) { + sprintf(g->Message, "Unsupported table type %s", options->type); + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } // endif ttp + + if (check_privileges(thd, options)) DBUG_RETURN(HA_ERR_INTERNAL_ERROR); if (options->data_charset) { @@ -3737,6 +3941,34 @@ int ha_connect::create(const char *name, TABLE *table_arg, } else dbf= (GetTypeID(options->type) == TAB_DBF && !options->catfunc); + // Can be null in ALTER TABLE + if (create_info->alias) + // Check whether a table is defined on itself + switch (type) { + case TAB_PRX: + case TAB_XCL: + case TAB_OCCUR: + if (options->srcdef) { + strcpy(g->Message, "Cannot check looping reference"); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message); + } else if (options->tabname) { + if (!stricmp(options->tabname, create_info->alias) && + (!options->dbname || !stricmp(options->dbname, table_arg->s->db.str))) { + sprintf(g->Message, "A %s table cannot refer to itself", + options->type); + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } // endif tab + + } else { + strcpy(g->Message, "Missing object table name or definition"); + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } // endif tabname + + default: /* do nothing */; + } // endswitch ttp + if (type == TAB_XML) { bool dom; // True: MS-DOM, False libxml2 char *xsup= GetListOption(g, "Xmlsup", options->oplist, "*"); @@ -3906,8 +4138,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, strcat(strcat(buf, "."), lwt); sprintf(g->Message, "No file name. Table will use %s", buf); - push_warning(table->in_use, - MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message); strcat(strcat(strcpy(dbpath, "./"), table->s->db.str), "/"); PlugSetPath(fn, buf, dbpath); @@ -3935,8 +4166,8 @@ int ha_connect::create(const char *name, TABLE *table_arg, PIXDEF xdp; // We should be in CREATE TABLE - if (table->in_use->lex->sql_command != SQLCOM_CREATE_TABLE) - push_warning(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN, 0, + if (thd_sql_command(table->in_use) != SQLCOM_CREATE_TABLE) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, "Wrong command in create, please contact CONNECT team"); // Get the index definitions @@ -3945,7 +4176,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, PCATLG cat= (dup) ? dup->Catalog : NULL; if (cat) { - cat->SetDataPath(g, table_arg->in_use->db); + cat->SetDataPath(g, table_arg->s->db.str); if ((rc= optimize(table->in_use, NULL))) { printf("Create rc=%d %s\n", rc, g->Message); diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h index b8c92479543..0d6354ca078 100644 --- a/storage/connect/ha_connect.h +++ b/storage/connect/ha_connect.h @@ -1,4 +1,4 @@ -/* Copyright (C) Olivier Bertrand 2004 - 2011 +/* Copyright (C) Olivier Bertrand 2004 - 2013 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -64,6 +64,61 @@ typedef struct ha_field_option_struct FOS, *PFOS; extern handlerton *connect_hton; +/** + structure for CREATE TABLE options (table options) + + These can be specified in the CREATE TABLE: + CREATE TABLE ( ... ) {...here...} +*/ +struct ha_table_option_struct { + const char *type; + const char *filename; + const char *optname; + const char *tabname; + const char *tablist; + const char *dbname; + const char *separator; +//const char *connect; + const char *qchar; + const char *module; + const char *subtype; + const char *catfunc; + const char *srcdef; + const char *colist; + const char *oplist; + const char *data_charset; + ulonglong lrecl; + ulonglong elements; +//ulonglong estimate; + ulonglong multiple; + ulonglong header; + ulonglong quoted; + ulonglong ending; + ulonglong compressed; + bool mapped; + bool huge; + bool split; + bool readonly; + bool sepindex; + }; + +/** + structure for CREATE TABLE options (field options) + + These can be specified in the CREATE TABLE per field: + CREATE TABLE ( field ... {...here...}, ... ) +*/ +struct ha_field_option_struct +{ + ulonglong offset; + ulonglong freq; // Not used by this version + ulonglong opt; // Not used by this version + ulonglong fldlen; + const char *dateformat; + const char *fieldformat; + char *special; +}; + /** @brief CONNECT_SHARE is a structure that will be shared among all open handlers. This example implements the minimum of what you will probably need. @@ -143,8 +198,7 @@ public: { return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_HAS_RECORDS | HA_NO_AUTO_INCREMENT | HA_NO_PREFIX_CHAR_KEYS | - HA_NO_COPY_ON_ALTER | - HA_CAN_VIRTUAL_COLUMNS | + HA_NO_COPY_ON_ALTER | HA_CAN_VIRTUAL_COLUMNS | HA_NULL_IN_KEY | HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE); } diff --git a/storage/connect/inihandl.c b/storage/connect/inihandl.c index 25629b04e60..60b72bd2604 100644 --- a/storage/connect/inihandl.c +++ b/storage/connect/inihandl.c @@ -29,9 +29,8 @@ //#include <sys/types.h> //#include <memory.h> #include "my_global.h" -//#include "osutil.h" #include "global.h" - +#include "inihandl.h" // The types and variables used locally //typedef int bool; @@ -672,7 +671,7 @@ static BOOL PROFILE_DeleteKey(PROFILESECTION* *section, * * Delete all keys from a profile tree. ***********************************************************************/ -void PROFILE_DeleteAllKeys(LPCSTR section_name) +static void PROFILE_DeleteAllKeys(LPCSTR section_name) { PROFILESECTION* *section= &CurProfile->section; @@ -1038,6 +1037,7 @@ static BOOL PROFILE_SetString(LPCSTR section_name, LPCSTR key_name, * Convenience function that turns a string 'xxx, yyy, zzz' into * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'. ***********************************************************************/ +#if 0 char *PROFILE_GetStringItem(char* start) { char *lpchX, *lpch; @@ -1065,6 +1065,7 @@ char *PROFILE_GetStringItem(char* start) return NULL; } // end of PROFILE_GetStringItem +#endif /********************************************************************** * if allow_section_name_copy is TRUE, allow the copying : @@ -1132,7 +1133,7 @@ static int PROFILE_GetPrivateProfileString(LPCSTR section, LPCSTR entry, * GetPrivateProfileStringA (KERNEL32.@) ***********************************************************************/ int GetPrivateProfileString(LPCSTR section, LPCSTR entry, LPCSTR def_val, - LPSTR buffer, uint len, LPCSTR filename) + LPSTR buffer, DWORD len, LPCSTR filename) { return PROFILE_GetPrivateProfileString(section, entry, def_val, buffer, len, filename, TRUE); @@ -1308,7 +1309,8 @@ BOOL WritePrivateProfileSection(LPCSTR section, * Note that when the buffer is big enough then the return value may be any * value between 1 and len-1 (or len in Win95), including len-2. */ -DWORD GetPrivateProfileSectionNames(LPSTR buffer, DWORD size, LPCSTR filename) +static DWORD +GetPrivateProfileSectionNames(LPSTR buffer, DWORD size, LPCSTR filename) { DWORD ret = 0; diff --git a/storage/connect/inihandl.h b/storage/connect/inihandl.h new file mode 100644 index 00000000000..7f6fcb1f582 --- /dev/null +++ b/storage/connect/inihandl.h @@ -0,0 +1,54 @@ +#ifndef __INIHANDL_H__ +#define __INIHANDL_H__ + +#if defined(UNIX) || defined(UNIV_LINUX) + +#ifdef __cplusplus +extern "C" { +#endif + +void PROFILE_Close(LPCSTR filename); + +int GetPrivateProfileString( + LPCTSTR lpAppName, // section name + LPCTSTR lpKeyName, // key name + LPCTSTR lpDefault, // default string + LPTSTR lpReturnedString, // destination buffer + DWORD nSize, // size of destination buffer + LPCTSTR lpFileName // initialization file name + ); + +uint GetPrivateProfileInt( + LPCTSTR lpAppName, // section name + LPCTSTR lpKeyName, // key name + INT nDefault, // return value if key name not found + LPCTSTR lpFileName // initialization file name + ); + +BOOL WritePrivateProfileString( + LPCTSTR lpAppName, // section name + LPCTSTR lpKeyName, // key name + LPCTSTR lpString, // string to add + LPCTSTR lpFileName // initialization file + ); + +int GetPrivateProfileSection( + LPCTSTR lpAppName, // section name + LPTSTR lpReturnedString, // return buffer + DWORD nSize, // size of return buffer + LPCTSTR lpFileName // initialization file name + ); + +BOOL WritePrivateProfileSection( + LPCTSTR lpAppName, // section name + LPCTSTR lpString, // data + LPCTSTR lpFileName // file name + ); + +#ifdef __cplusplus +} +#endif + +#endif /* defined(UNIX) */ + +#endif /* __INIHANDL_H__ */ diff --git a/storage/connect/maputil.h b/storage/connect/maputil.h index 8ab41487a63..b5e54affcea 100644 --- a/storage/connect/maputil.h +++ b/storage/connect/maputil.h @@ -13,7 +13,6 @@ typedef struct { HANDLE CreateFileMap(PGLOBAL, LPCSTR, MEMMAP *, MODE, bool); bool CloseMemMap(void *memory, size_t dwSize); -my_bool CloseFileHandle(HANDLE h); #ifdef __cplusplus } diff --git a/storage/connect/mycat.cc b/storage/connect/mycat.cc index 4db70efe27f..e243a706f01 100644 --- a/storage/connect/mycat.cc +++ b/storage/connect/mycat.cc @@ -68,7 +68,10 @@ #include "tabmac.h" #include "tabwmi.h" #endif // WIN32 +//#include "tabtbl.h" +#include "tabxcl.h" #include "tabtbl.h" +#include "taboccur.h" #if defined(XML_SUPPORT) #include "tabxml.h" #endif // XML_SUPPORT @@ -117,6 +120,7 @@ TABTYPE GetTypeID(const char *type) #endif #ifdef MYSQL_SUPPORT : (!stricmp(type, "MYSQL")) ? TAB_MYSQL + : (!stricmp(type, "MYPRX")) ? TAB_MYSQL #endif : (!stricmp(type, "DIR")) ? TAB_DIR #ifdef WIN32 @@ -124,6 +128,13 @@ TABTYPE GetTypeID(const char *type) : (!stricmp(type, "WMI")) ? TAB_WMI #endif : (!stricmp(type, "TBL")) ? TAB_TBL + : (!stricmp(type, "XCOL")) ? TAB_XCL + : (!stricmp(type, "OCCUR")) ? TAB_OCCUR + : (!stricmp(type, "CATLG")) ? TAB_PRX // Legacy + : (!stricmp(type, "PROXY")) ? TAB_PRX +#ifdef PIVOT_SUPPORT + : (!stricmp(type, "PIVOT")) ? TAB_PIVOT +#endif : (!stricmp(type, "OEM")) ? TAB_OEM : TAB_NIY; } // end of GetTypeID @@ -186,7 +197,6 @@ bool IsTypeNullable(TABTYPE type) break; } // endswitch type - return nullable; } // end of IsTypeNullable @@ -246,15 +256,11 @@ uint GetFuncID(const char *func) /***********************************************************************/ CATALOG::CATALOG(void) { - To_Desc= NULL; -//*DescFile= '\0'; #if defined(WIN32) DataPath= ".\\"; #else // !WIN32 DataPath= "./"; #endif // !WIN32 - Descp= NULL; -//memset(&DescArea, 0, sizeof(AREADEF)); memset(&Ctb, 0, sizeof(CURTAB)); Cbuf= NULL; Cblen= 0; @@ -269,17 +275,14 @@ CATALOG::CATALOG(void) MYCAT::MYCAT(PHC hc) : CATALOG() { Hc= hc; - To_Desc= NULL; DefHuge= false; -//SepIndex= true; // Temporay until we can store offet and size } // end of MYCAT constructor /***********************************************************************/ -/* When using volatile storage, reset values pointing to Sarea. */ +/* Nothing to do for CONNECT. */ /***********************************************************************/ void MYCAT::Reset(void) { - To_Desc= NULL; } // end of Reset /***********************************************************************/ @@ -290,6 +293,13 @@ void MYCAT::SetPath(PGLOBAL g, LPCSTR *datapath, const char *path) if (path) { size_t len= strlen(path) + (*path != '.' ? 4 : 1); char *buf= (char*)PlugSubAlloc(g, NULL, len); + + if (PlugIsAbsolutePath(path)) + { + strcpy(buf, path); + *datapath= buf; + return; + } if (*path != '.') { #if defined(WIN32) @@ -380,20 +390,23 @@ char *MYCAT::GetStringCatInfo(PGLOBAL g, PSZ what, PSZ sdef) strcpy(sval, s); } else if (!stricmp(what, "filename")) { // Return default file name - char *ftype= Hc->GetStringOption("Type", "dos"); + char *ftype= Hc->GetStringOption("Type", "*"); int i, n; - sval= (char*)PlugSubAlloc(g, NULL, strlen(Hc->GetTableName()) + 12); - strcat(strcpy(sval, Hc->GetTableName()), "."); - n= strlen(sval); - - // Fold ftype to lower case - for (i= 0; i < 12; i++) - if (!ftype[i]) { - sval[n+i]= 0; - break; - } else - sval[n+i]= tolower(ftype[i]); + if (IsFileType(GetTypeID(ftype))) { + sval= (char*)PlugSubAlloc(g, NULL, strlen(Hc->GetTableName()) + 12); + strcat(strcpy(sval, Hc->GetTableName()), "."); + n= strlen(sval); + + // Fold ftype to lower case + for (i= 0; i < 12; i++) + if (!ftype[i]) { + sval[n+i]= 0; + break; + } else + sval[n+i]= tolower(ftype[i]); + + } // endif FileType } else sval = NULL; @@ -406,7 +419,7 @@ char *MYCAT::GetStringCatInfo(PGLOBAL g, PSZ what, PSZ sdef) /***********************************************************************/ int MYCAT::GetColCatInfo(PGLOBAL g, PTABDEF defp) { - char *type= GetStringCatInfo(g, "Type", "DOS"); + char *type= GetStringCatInfo(g, "Type", "*"); int i, loff, poff, nof, nlg; void *field= NULL; TABTYPE tc; @@ -414,7 +427,7 @@ int MYCAT::GetColCatInfo(PGLOBAL g, PTABDEF defp) PCOLINFO pcf= (PCOLINFO)PlugSubAlloc(g, NULL, sizeof(COLINFO)); // Get a unique char identifier for type - tc= (defp->Catfunc == FNC_NO) ? GetTypeID(type) : TAB_CATLG; + tc= (defp->Catfunc == FNC_NO) ? GetTypeID(type) : TAB_PRX; // Take care of the column definitions i= poff= nof= nlg= 0; @@ -443,6 +456,9 @@ int MYCAT::GetColCatInfo(PGLOBAL g, PTABDEF defp) case TAB_INI: case TAB_MAC: case TAB_TBL: + case TAB_XCL: + case TAB_OCCUR: + case TAB_PRX: case TAB_OEM: poff = 0; // Offset represents an independant flag break; @@ -576,9 +592,7 @@ bool MYCAT::GetIndexInfo(PGLOBAL g, PTABDEF defp) /***********************************************************************/ /* GetTableDesc: retrieve a table descriptor. */ -/* Look for a table descriptor matching the name and type. If found */ -/* in storage, return a pointer to it, else look in the XDB file. If */ -/* found, make and add the descriptor and return a pointer to it. */ +/* Look for a table descriptor matching the name and type. */ /***********************************************************************/ PRELDEF MYCAT::GetTableDesc(PGLOBAL g, LPCSTR name, LPCSTR type, PRELDEF *prp) @@ -586,13 +600,9 @@ PRELDEF MYCAT::GetTableDesc(PGLOBAL g, LPCSTR name, if (xtrace) printf("GetTableDesc: name=%s am=%s\n", name, SVP(type)); - // Firstly check whether this table descriptor is in memory - if (To_Desc) - return To_Desc; - // If not specified get the type of this table - if (!type && !(type= Hc->GetStringOption("Type"))) - type= "DOS"; + if (!type) + type= Hc->GetStringOption("Type","*"); return MakeTableDesc(g, name, type); } // end of GetTableDesc @@ -636,17 +646,20 @@ PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, LPCSTR name, LPCSTR am) #endif // WIN32 case TAB_OEM: tdp= new(g) OEMDEF; break; case TAB_TBL: tdp= new(g) TBLDEF; break; + case TAB_XCL: tdp= new(g) XCLDEF; break; + case TAB_PRX: tdp= new(g) PRXDEF; break; + case TAB_OCCUR: tdp= new(g) OCCURDEF; break; #if defined(MYSQL_SUPPORT) case TAB_MYSQL: tdp= new(g) MYSQLDEF; break; #endif // MYSQL_SUPPORT -//#if defined(PIVOT_SUPPORT) -// case TAB_PIVOT: tdp= new(g) PIVOTDEF; break; -//#endif // PIVOT_SUPPORT +#if defined(PIVOT_SUPPORT) + case TAB_PIVOT: tdp= new(g) PIVOTDEF; break; +#endif // PIVOT_SUPPORT default: sprintf(g->Message, MSG(BAD_TABLE_TYPE), am, name); } // endswitch - // Do make the table/view definition from XDB file information + // Do make the table/view definition if (tdp && tdp->Define(g, this, name, am)) tdp= NULL; @@ -694,7 +707,6 @@ PTDB MYCAT::GetTable(PGLOBAL g, PTABLE tablep, MODE mode, LPCSTR type) /***********************************************************************/ void MYCAT::ClearDB(PGLOBAL g) { - To_Desc= NULL; } // end of ClearDB /* ------------------------ End of MYCAT --------------------------- */ diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp index 3edf07004ea..9ebf77ff35a 100644 --- a/storage/connect/myconn.cpp +++ b/storage/connect/myconn.cpp @@ -62,21 +62,25 @@ static char *server_groups[] = { #endif // EMBEDDED extern "C" int trace; +extern MYSQL_PLUGIN_IMPORT uint mysqld_port; + +// Returns the current used port +uint GetDefaultPort(void) +{ + return mysqld_port; +} // end of GetDefaultPort /************************************************************************/ /* MyColumns: constructs the result blocks containing all columns */ -/* of a MySQL table that will be retrieved by GetData commands. */ -/* key = TRUE when called from Create Table to get key informations. */ +/* of a MySQL table or view. */ +/* info = TRUE to get catalog column informations. */ /************************************************************************/ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, const char *user, const char *pwd, const char *table, const char *colpat, - int port, bool key, bool info) + int port, bool info) { - static int dbtype[] = {DB_CHAR, DB_SHORT, DB_CHAR, DB_INT, - DB_CHAR, DB_SHORT, DB_SHORT, DB_SHORT, - DB_CHAR, DB_CHAR, DB_CHAR}; - static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, + static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_STRING, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING, TYPE_STRING, TYPE_STRING}; static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, @@ -84,12 +88,15 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, 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]; - int i, n, nf, ncol = sizeof(dbtype) / sizeof(int); + int i, n, nf, ncol = sizeof(buftyp) / sizeof(int); int len, type, prec, rc, k = 0; PQRYRES qrp; PCOLRES crp; MYSQLC myc; + if (!port) + port = mysqld_port; + if (!info) { /********************************************************************/ /* Open the connection with the MySQL server. */ @@ -123,14 +130,11 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, length[0] = 128; } // endif info -//if (!key) // We are not called from Create table -// ncol--; // No date format column yet - /**********************************************************************/ /* Allocate the structures used to refer to the result set. */ /**********************************************************************/ qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3, - dbtype, buftyp, fldtyp, length, true, true); + buftyp, fldtyp, length, true, true); // Some columns must be renamed for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next) @@ -218,6 +222,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, crp->Kdata->SetValue(fld, i); } // endfor i +#if 0 if (k > 1) { // Multicolumn primary key PVBLK vbp = qrp->Colresp->Next->Next->Next->Next->Kdata; @@ -227,6 +232,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, vbp->SetValue(k, i); } // endif k +#endif // 0 /**********************************************************************/ /* Close MySQL connection. */ @@ -239,6 +245,33 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, return qrp; } // end of MyColumns +/************************************************************************/ +/* SrcColumns: constructs the result blocks containing all columns */ +/* resulting from an SQL source definition query execution. */ +/************************************************************************/ +PQRYRES SrcColumns(PGLOBAL g, const char *host, const char *db, + const char *user, const char *pwd, + const char *srcdef, int port) + { + int w; + MYSQLC myc; + PQRYRES qrp = NULL; + + if (!port) + port = mysqld_port; + + // 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) + qrp = myc.GetResult(g); + + myc.Close(); + return qrp; + } // end of SrcColumns + /* -------------------------- Class MYSQLC --------------------------- */ /***********************************************************************/ @@ -289,6 +322,7 @@ int MYSQLC::Open(PGLOBAL g, const char *host, const char *db, // This is critical, because the server will not accept the // client's options, and vice versa. mysql_options(m_DB, MYSQL_READ_DEFAULT_GROUP, "PlugDB_CLIENT"); + mysql_options(m_DB, MYSQL_OPT_USE_REMOTE_CONNECTION, NULL); #if 0 if (pwd && !strcmp(pwd, "*")) { @@ -645,6 +679,7 @@ PQRYRES MYSQLC::GetResult(PGLOBAL g, bool pdb) *pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES)); crp = *pcrp; pcrp = &crp->Next; + memset(crp, 0, sizeof(COLRES)); crp->Ncol = ++qrp->Nbcol; crp->Name = (char*)PlugSubAlloc(g, NULL, fld->name_length + 1); @@ -658,10 +693,9 @@ PQRYRES MYSQLC::GetResult(PGLOBAL g, bool pdb) // For direct MySQL connection, display the MySQL date string crp->Type = TYPE_STRING; - crp->Prec = fld->decimals; + crp->Prec = (crp->Type == TYPE_FLOAT) ? fld->decimals : 0; crp->Length = fld->max_length; crp->Clen = GetTypeSize(crp->Type, crp->Length); - crp->DBtype = GetDBType((int)crp->Type); if (!(crp->Kdata = AllocValBlock(g, NULL, crp->Type, m_Rows, crp->Clen, 0, FALSE, TRUE))) { diff --git a/storage/connect/myconn.h b/storage/connect/myconn.h index 72ce58e70aa..f8c8c3dcbae 100644 --- a/storage/connect/myconn.h +++ b/storage/connect/myconn.h @@ -38,7 +38,13 @@ typedef class MYSQLC *PMYC; PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, const char *user, const char *pwd, const char *table, const char *colpat, - int port, bool key, bool info); + int port, bool info); + +PQRYRES SrcColumns(PGLOBAL g, const char *host, const char *db, + const char *user, const char *pwd, + const char *srcdef, int port); + +uint GetDefaultPort(void); /* -------------------------- MYCONN class --------------------------- */ @@ -47,6 +53,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, /***********************************************************************/ class DllItem MYSQLC { friend class TDBMYSQL; + friend class MYSQLCOL; // Construction public: MYSQLC(void); diff --git a/storage/connect/mysql-test/connect/r/bin.result b/storage/connect/mysql-test/connect/r/bin.result index d476aef6293..c64b270b538 100644 --- a/storage/connect/mysql-test/connect/r/bin.result +++ b/storage/connect/mysql-test/connect/r/bin.result @@ -1,98 +1,4 @@ # -# Beginning of grant.inc -# -GRANT ALL PRIVILEGES ON *.* TO user@localhost; -REVOKE FILE ON *.* FROM user@localhost; -SELECT user(); -user() -user@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=BIN; -Warnings: -Warning 1105 No file name. Table will use t1.bin -INSERT INTO t1 VALUES (10); -SELECT * FROM t1; -a -10 -UPDATE t1 SET a=20; -SELECT * FROM t1; -a -20 -DELETE FROM t1; -SELECT * FROM t1; -a -INSERT INTO t1 VALUES(10); -TRUNCATE TABLE t1; -SELECT * FROM t1; -a -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT * FROM v1; -a -DROP VIEW v1; -DROP TABLE t1; -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=BIN FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=BIN FILE_NAME='t1.EXT'; -INSERT INTO t1 VALUES (10); -SELECT user(); -user() -user@localhost -INSERT INTO t1 VALUES (10); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE t1 SET a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 FILE_NAME='t2.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -# Testing a VIEW created with FILE privileges but accessed with no FILE -SELECT user(); -user() -root@localhost -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT user(); -user() -user@localhost -SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -DROP VIEW v1; -DROP TABLE t1; -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=BIN; -Warnings: -Warning 1105 No file name. Table will use t1.bin -INSERT INTO t1 VALUES (10); -SELECT user(); -user() -user@localhost -ALTER TABLE t1 FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DROP TABLE t1; -DROP USER user@localhost; -# -# End of grant.inc -# -# # Testing errors # CREATE TABLE t1 diff --git a/storage/connect/mysql-test/connect/r/csv.result b/storage/connect/mysql-test/connect/r/csv.result index 34734e164c0..b2498326edb 100644 --- a/storage/connect/mysql-test/connect/r/csv.result +++ b/storage/connect/mysql-test/connect/r/csv.result @@ -1,97 +1,3 @@ -# -# Beginning of grant.inc -# -GRANT ALL PRIVILEGES ON *.* TO user@localhost; -REVOKE FILE ON *.* FROM user@localhost; -SELECT user(); -user() -user@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV; -Warnings: -Warning 1105 No file name. Table will use t1.csv -INSERT INTO t1 VALUES (10); -SELECT * FROM t1; -a -10 -UPDATE t1 SET a=20; -SELECT * FROM t1; -a -20 -DELETE FROM t1; -SELECT * FROM t1; -a -INSERT INTO t1 VALUES(10); -TRUNCATE TABLE t1; -SELECT * FROM t1; -a -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT * FROM v1; -a -DROP VIEW v1; -DROP TABLE t1; -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.EXT'; -INSERT INTO t1 VALUES (10); -SELECT user(); -user() -user@localhost -INSERT INTO t1 VALUES (10); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE t1 SET a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 FILE_NAME='t2.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -# Testing a VIEW created with FILE privileges but accessed with no FILE -SELECT user(); -user() -root@localhost -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT user(); -user() -user@localhost -SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -DROP VIEW v1; -DROP TABLE t1; -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV; -Warnings: -Warning 1105 No file name. Table will use t1.csv -INSERT INTO t1 VALUES (10); -SELECT user(); -user() -user@localhost -ALTER TABLE t1 FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DROP TABLE t1; -DROP USER user@localhost; -# -# End of grant.inc -# SET NAMES utf8; # # Testing errors diff --git a/storage/connect/mysql-test/connect/r/dbf.result b/storage/connect/mysql-test/connect/r/dbf.result index 27abbb84dc6..2e84c5b3090 100644 --- a/storage/connect/mysql-test/connect/r/dbf.result +++ b/storage/connect/mysql-test/connect/r/dbf.result @@ -1,98 +1,4 @@ # -# Beginning of grant.inc -# -GRANT ALL PRIVILEGES ON *.* TO user@localhost; -REVOKE FILE ON *.* FROM user@localhost; -SELECT user(); -user() -user@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF; -Warnings: -Warning 1105 No file name. Table will use t1.dbf -INSERT INTO t1 VALUES (10); -SELECT * FROM t1; -a -10 -UPDATE t1 SET a=20; -SELECT * FROM t1; -a -20 -DELETE FROM t1; -SELECT * FROM t1; -a -INSERT INTO t1 VALUES(10); -TRUNCATE TABLE t1; -SELECT * FROM t1; -a -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT * FROM v1; -a -DROP VIEW v1; -DROP TABLE t1; -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.EXT'; -INSERT INTO t1 VALUES (10); -SELECT user(); -user() -user@localhost -INSERT INTO t1 VALUES (10); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE t1 SET a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 FILE_NAME='t2.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -# Testing a VIEW created with FILE privileges but accessed with no FILE -SELECT user(); -user() -root@localhost -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT user(); -user() -user@localhost -SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -DROP VIEW v1; -DROP TABLE t1; -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF; -Warnings: -Warning 1105 No file name. Table will use t1.dbf -INSERT INTO t1 VALUES (10); -SELECT user(); -user() -user@localhost -ALTER TABLE t1 FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DROP TABLE t1; -DROP USER user@localhost; -# -# End of grant.inc -# -# # Testing errors # CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf'; diff --git a/storage/connect/mysql-test/connect/r/dir.result b/storage/connect/mysql-test/connect/r/dir.result index 7beae815580..f4feb5fa960 100644 --- a/storage/connect/mysql-test/connect/r/dir.result +++ b/storage/connect/mysql-test/connect/r/dir.result @@ -1,72 +1,3 @@ -# -# Testing FILE privilege -# -GRANT ALL PRIVILEGES ON *.* TO user@localhost; -REVOKE FILE ON *.* FROM user@localhost; -SELECT user(); -user() -user@localhost -CREATE TABLE t1 ( -path 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='*.*'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -CREATE TABLE t1 ( -path 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='*.*'; -SELECT fname, ftype, size FROM t1 WHERE size>0; -fname ftype size -t1 .frm 1081 -SELECT user(); -user() -user@localhost -SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -INSERT INTO t1 VALUES (); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM t1 WHERE path='xxx'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE t1 SET path='yyy' WHERE path='xxx'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -# Testing a VIEW created with FILE privileges but accessed with no FILE -SELECT user(); -user() -root@localhost -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT user(); -user() -user@localhost -SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -INSERT INTO v1 VALUES (1,1,1,1); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE v1 SET path=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -DROP VIEW v1; -DROP TABLE t1; -DROP USER user@localhost; -# -# Testing FILE privileges done -# CREATE TABLE t1 ( path VARCHAR(256) NOT NULL flag=1, fname VARCHAR(256) NOT NULL, diff --git a/storage/connect/mysql-test/connect/r/fix.result b/storage/connect/mysql-test/connect/r/fix.result index e9eb31d9bc8..c8f51abe961 100644 --- a/storage/connect/mysql-test/connect/r/fix.result +++ b/storage/connect/mysql-test/connect/r/fix.result @@ -1,98 +1,4 @@ # -# Beginning of grant.inc -# -GRANT ALL PRIVILEGES ON *.* TO user@localhost; -REVOKE FILE ON *.* FROM user@localhost; -SELECT user(); -user() -user@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=FIX; -Warnings: -Warning 1105 No file name. Table will use t1.fix -INSERT INTO t1 VALUES (10); -SELECT * FROM t1; -a -10 -UPDATE t1 SET a=20; -SELECT * FROM t1; -a -20 -DELETE FROM t1; -SELECT * FROM t1; -a -INSERT INTO t1 VALUES(10); -TRUNCATE TABLE t1; -SELECT * FROM t1; -a -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT * FROM v1; -a -DROP VIEW v1; -DROP TABLE t1; -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='t1.EXT'; -INSERT INTO t1 VALUES (10); -SELECT user(); -user() -user@localhost -INSERT INTO t1 VALUES (10); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE t1 SET a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 FILE_NAME='t2.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -# Testing a VIEW created with FILE privileges but accessed with no FILE -SELECT user(); -user() -root@localhost -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT user(); -user() -user@localhost -SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -DROP VIEW v1; -DROP TABLE t1; -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=FIX; -Warnings: -Warning 1105 No file name. Table will use t1.fix -INSERT INTO t1 VALUES (10); -SELECT user(); -user() -user@localhost -ALTER TABLE t1 FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DROP TABLE t1; -DROP USER user@localhost; -# -# End of grant.inc -# -# # Testing errors # CREATE TABLE t1 diff --git a/storage/connect/mysql-test/connect/r/fmt.result b/storage/connect/mysql-test/connect/r/fmt.result index dc3b42b2231..0be10f69bfd 100644 --- a/storage/connect/mysql-test/connect/r/fmt.result +++ b/storage/connect/mysql-test/connect/r/fmt.result @@ -18,7 +18,7 @@ CREATE TABLE t1 id INT NOT NULL field_format=' %n%d%n' ) ENGINE=CONNECT TABLE_TYPE=FMT FILE_NAME='t1.txt'; INSERT INTO t1 VALUES (10),(20); -ERROR HY000: Got error 122 'Writing FMT files is not implemented yet' from CONNECT +ERROR HY000: Got error 174 'Writing FMT files is not implemented yet' from CONNECT DROP TABLE t1; # # Testing manual examples @@ -59,7 +59,7 @@ ID NAME DEPNO SALARY 56 POIROT-DELMOTTE 0 18009.00 345 67 19000.25 UPDATE t1 SET SALARY=1234; -ERROR HY000: Got error 122 'Writing FMT files is not implemented yet' from CONNECT +ERROR HY000: Got error 174 'Writing FMT files is not implemented yet' from CONNECT DELETE FROM t1 WHERE ID=56; SELECT * FROM t1; ID NAME DEPNO SALARY diff --git a/storage/connect/mysql-test/connect/r/grant.result b/storage/connect/mysql-test/connect/r/grant.result new file mode 100644 index 00000000000..ba5728703a5 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/grant.result @@ -0,0 +1,539 @@ +# +# Testing FILE privilege +# +GRANT ALL PRIVILEGES ON *.* TO user@localhost; +REVOKE FILE ON *.* FROM user@localhost; +SELECT user(); +user() +user@localhost +CREATE TABLE t1 ( +path 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='*.*'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +CREATE TABLE t1 ( +path 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='*.*'; +SELECT fname, ftype, size FROM t1 WHERE size>0; +fname ftype size +t1 .frm 1081 +SELECT user(); +user() +user@localhost +SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +INSERT INTO t1 VALUES (); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM t1 WHERE path='xxx'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE t1 SET path='yyy' WHERE path='xxx'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +TRUNCATE TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 READONLY=1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +CREATE VIEW v1 AS SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +# Testing a VIEW created with FILE privileges but accessed with no FILE +SELECT user(); +user() +root@localhost +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT user(); +user() +user@localhost +SELECT * FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +INSERT INTO v1 VALUES (1,1,1,1); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE v1 SET path=123; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +DROP VIEW v1; +DROP TABLE t1; +DROP USER user@localhost; +# +# Testing FILE privileges done +# +# +# Beginning of grant.inc +# +GRANT ALL PRIVILEGES ON *.* TO user@localhost; +REVOKE FILE ON *.* FROM user@localhost; +SELECT user(); +user() +user@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=BIN; +Warnings: +Warning 1105 No file name. Table will use t1.bin +INSERT INTO t1 VALUES (10); +SELECT * FROM t1; +a +10 +UPDATE t1 SET a=20; +SELECT * FROM t1; +a +20 +DELETE FROM t1; +SELECT * FROM t1; +a +INSERT INTO t1 VALUES(10); +TRUNCATE TABLE t1; +SELECT * FROM t1; +a +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT * FROM v1; +a +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=BIN FILE_NAME='t1.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=BIN FILE_NAME='t1.EXT'; +INSERT INTO t1 VALUES (10); +SELECT user(); +user() +user@localhost +INSERT INTO t1 VALUES (10); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE t1 SET a=20; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +TRUNCATE TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 READONLY=1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 FILE_NAME='t2.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DROP TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +CREATE VIEW v1 AS SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +# Testing a VIEW created with FILE privileges but accessed with no FILE +SELECT user(); +user() +root@localhost +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT user(); +user() +user@localhost +SELECT * FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +INSERT INTO v1 VALUES (2); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE v1 SET a=123; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=BIN; +Warnings: +Warning 1105 No file name. Table will use t1.bin +INSERT INTO t1 VALUES (10); +SELECT user(); +user() +user@localhost +ALTER TABLE t1 FILE_NAME='t1.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DROP TABLE t1; +DROP USER user@localhost; +# +# End of grant.inc +# +# +# Beginning of grant.inc +# +GRANT ALL PRIVILEGES ON *.* TO user@localhost; +REVOKE FILE ON *.* FROM user@localhost; +SELECT user(); +user() +user@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV; +Warnings: +Warning 1105 No file name. Table will use t1.csv +INSERT INTO t1 VALUES (10); +SELECT * FROM t1; +a +10 +UPDATE t1 SET a=20; +SELECT * FROM t1; +a +20 +DELETE FROM t1; +SELECT * FROM t1; +a +INSERT INTO t1 VALUES(10); +TRUNCATE TABLE t1; +SELECT * FROM t1; +a +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT * FROM v1; +a +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.EXT'; +INSERT INTO t1 VALUES (10); +SELECT user(); +user() +user@localhost +INSERT INTO t1 VALUES (10); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE t1 SET a=20; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +TRUNCATE TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 READONLY=1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 FILE_NAME='t2.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DROP TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +CREATE VIEW v1 AS SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +# Testing a VIEW created with FILE privileges but accessed with no FILE +SELECT user(); +user() +root@localhost +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT user(); +user() +user@localhost +SELECT * FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +INSERT INTO v1 VALUES (2); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE v1 SET a=123; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV; +Warnings: +Warning 1105 No file name. Table will use t1.csv +INSERT INTO t1 VALUES (10); +SELECT user(); +user() +user@localhost +ALTER TABLE t1 FILE_NAME='t1.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DROP TABLE t1; +DROP USER user@localhost; +# +# End of grant.inc +# +# +# Beginning of grant.inc +# +GRANT ALL PRIVILEGES ON *.* TO user@localhost; +REVOKE FILE ON *.* FROM user@localhost; +SELECT user(); +user() +user@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF; +Warnings: +Warning 1105 No file name. Table will use t1.dbf +INSERT INTO t1 VALUES (10); +SELECT * FROM t1; +a +10 +UPDATE t1 SET a=20; +SELECT * FROM t1; +a +20 +DELETE FROM t1; +SELECT * FROM t1; +a +INSERT INTO t1 VALUES(10); +TRUNCATE TABLE t1; +SELECT * FROM t1; +a +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT * FROM v1; +a +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.EXT'; +INSERT INTO t1 VALUES (10); +SELECT user(); +user() +user@localhost +INSERT INTO t1 VALUES (10); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE t1 SET a=20; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +TRUNCATE TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 READONLY=1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 FILE_NAME='t2.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DROP TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +CREATE VIEW v1 AS SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +# Testing a VIEW created with FILE privileges but accessed with no FILE +SELECT user(); +user() +root@localhost +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT user(); +user() +user@localhost +SELECT * FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +INSERT INTO v1 VALUES (2); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE v1 SET a=123; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF; +Warnings: +Warning 1105 No file name. Table will use t1.dbf +INSERT INTO t1 VALUES (10); +SELECT user(); +user() +user@localhost +ALTER TABLE t1 FILE_NAME='t1.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DROP TABLE t1; +DROP USER user@localhost; +# +# End of grant.inc +# +# +# Beginning of grant.inc +# +GRANT ALL PRIVILEGES ON *.* TO user@localhost; +REVOKE FILE ON *.* FROM user@localhost; +SELECT user(); +user() +user@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=FIX; +Warnings: +Warning 1105 No file name. Table will use t1.fix +INSERT INTO t1 VALUES (10); +SELECT * FROM t1; +a +10 +UPDATE t1 SET a=20; +SELECT * FROM t1; +a +20 +DELETE FROM t1; +SELECT * FROM t1; +a +INSERT INTO t1 VALUES(10); +TRUNCATE TABLE t1; +SELECT * FROM t1; +a +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT * FROM v1; +a +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='t1.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='t1.EXT'; +INSERT INTO t1 VALUES (10); +SELECT user(); +user() +user@localhost +INSERT INTO t1 VALUES (10); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE t1 SET a=20; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +TRUNCATE TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 READONLY=1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 FILE_NAME='t2.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DROP TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +CREATE VIEW v1 AS SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +# Testing a VIEW created with FILE privileges but accessed with no FILE +SELECT user(); +user() +root@localhost +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT user(); +user() +user@localhost +SELECT * FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +INSERT INTO v1 VALUES (2); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE v1 SET a=123; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=FIX; +Warnings: +Warning 1105 No file name. Table will use t1.fix +INSERT INTO t1 VALUES (10); +SELECT user(); +user() +user@localhost +ALTER TABLE t1 FILE_NAME='t1.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DROP TABLE t1; +DROP USER user@localhost; +# +# End of grant.inc +# +# +# Beginning of grant.inc +# +GRANT ALL PRIVILEGES ON *.* TO user@localhost; +REVOKE FILE ON *.* FROM user@localhost; +SELECT user(); +user() +user@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=VEC MAX_ROWS=100; +Warnings: +Warning 1105 No file name. Table will use t1.vec +INSERT INTO t1 VALUES (10); +SELECT * FROM t1; +a +10 +UPDATE t1 SET a=20; +SELECT * FROM t1; +a +20 +DELETE FROM t1; +SELECT * FROM t1; +a +INSERT INTO t1 VALUES(10); +TRUNCATE TABLE t1; +SELECT * FROM t1; +a +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT * FROM v1; +a +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=VEC MAX_ROWS=100 FILE_NAME='t1.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=VEC MAX_ROWS=100 FILE_NAME='t1.EXT'; +INSERT INTO t1 VALUES (10); +SELECT user(); +user() +user@localhost +INSERT INTO t1 VALUES (10); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE t1 SET a=20; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +TRUNCATE TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 READONLY=1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 FILE_NAME='t2.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DROP TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +CREATE VIEW v1 AS SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +# Testing a VIEW created with FILE privileges but accessed with no FILE +SELECT user(); +user() +root@localhost +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT user(); +user() +user@localhost +SELECT * FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +INSERT INTO v1 VALUES (2); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE v1 SET a=123; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=VEC MAX_ROWS=100; +Warnings: +Warning 1105 No file name. Table will use t1.vec +INSERT INTO t1 VALUES (10); +SELECT user(); +user() +user@localhost +ALTER TABLE t1 FILE_NAME='t1.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DROP TABLE t1; +DROP USER user@localhost; +# +# End of grant.inc +# diff --git a/storage/connect/mysql-test/connect/r/ini.result b/storage/connect/mysql-test/connect/r/ini.result index da846d466ba..83ba98fbd84 100644 --- a/storage/connect/mysql-test/connect/r/ini.result +++ b/storage/connect/mysql-test/connect/r/ini.result @@ -1,83 +1,4 @@ # -# Checking FILE privileges -# -GRANT ALL PRIVILEGES ON *.* TO user@localhost; -REVOKE FILE ON *.* FROM user@localhost; -SELECT user(); -user() -user@localhost -CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI; -Warnings: -Warning 1105 No file name. Table will use t1.ini -INSERT INTO t1 VALUES ('sec1','val1'); -SELECT * FROM t1; -sec val -sec1 val1 -UPDATE t1 SET val='val11'; -SELECT * FROM t1; -sec val -sec1 val11 -DELETE FROM t1; -SELECT * FROM t1; -sec val -INSERT INTO t1 VALUES('sec2','val2'); -TRUNCATE TABLE t1; -SELECT * FROM t1; -sec val -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT * FROM v1; -sec val -DROP VIEW v1; -DROP TABLE t1; -CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.EXT'; -INSERT INTO t1 VALUES ('sec1','val1'); -SELECT user(); -user() -user@localhost -INSERT INTO t1 VALUES ('sec2','val2'); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE t1 SET val='val11'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -# Testing a VIEW created with FILE privileges but accessed with no FILE -SELECT user(); -user() -root@localhost -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT user(); -user() -user@localhost -SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -INSERT INTO v1 VALUES ('sec3','val3'); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE v1 SET val='val11'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DROP VIEW v1; -DROP TABLE t1; -DROP USER user@localhost; -# -# Checking FILE privileges: done -# -# # Testing errors # CREATE TABLE t1 diff --git a/storage/connect/mysql-test/connect/r/ini_grant.result b/storage/connect/mysql-test/connect/r/ini_grant.result new file mode 100644 index 00000000000..c3acf7c8dfc --- /dev/null +++ b/storage/connect/mysql-test/connect/r/ini_grant.result @@ -0,0 +1,79 @@ +# +# Checking FILE privileges +# +GRANT ALL PRIVILEGES ON *.* TO user@localhost; +REVOKE FILE ON *.* FROM user@localhost; +SELECT user(); +user() +user@localhost +CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI; +Warnings: +Warning 1105 No file name. Table will use t1.ini +INSERT INTO t1 VALUES ('sec1','val1'); +SELECT * FROM t1; +sec val +sec1 val1 +UPDATE t1 SET val='val11'; +SELECT * FROM t1; +sec val +sec1 val11 +DELETE FROM t1; +SELECT * FROM t1; +sec val +INSERT INTO t1 VALUES('sec2','val2'); +TRUNCATE TABLE t1; +SELECT * FROM t1; +sec val +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT * FROM v1; +sec val +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.EXT'; +INSERT INTO t1 VALUES ('sec1','val1'); +SELECT user(); +user() +user@localhost +INSERT INTO t1 VALUES ('sec2','val2'); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE t1 SET val='val11'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +TRUNCATE TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 READONLY=1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DROP TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +CREATE VIEW v1 AS SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +# Testing a VIEW created with FILE privileges but accessed with no FILE +SELECT user(); +user() +root@localhost +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT user(); +user() +user@localhost +SELECT * FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +INSERT INTO v1 VALUES ('sec3','val3'); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE v1 SET val='val11'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DROP VIEW v1; +DROP TABLE t1; +DROP USER user@localhost; +# +# Checking FILE privileges: done +# diff --git a/storage/connect/mysql-test/connect/r/mysql.result b/storage/connect/mysql-test/connect/r/mysql.result index a538c57c5ce..8d5507e121a 100644 --- a/storage/connect/mysql-test/connect/r/mysql.result +++ b/storage/connect/mysql-test/connect/r/mysql.result @@ -1,66 +1,3 @@ -# -# Testing FILE privilege -# -GRANT ALL PRIVILEGES ON *.* TO user@localhost; -REVOKE FILE ON *.* FROM user@localhost; -SELECT user(); -user() -user@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL OPTION_LIST='host=localhost,user=root1,port=PORT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -CREATE TABLE t1remote (a INT NOT NULL); -INSERT INTO t1remote VALUES (10),(20),(30); -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL TABNAME=t1remote OPTION_LIST='host=localhost,user=root,port=PORT'; -SELECT * FROM t1; -a -10 -20 -30 -SELECT user(); -user() -user@localhost -SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -INSERT INTO t1 VALUES ('xxx'); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM t1 WHERE a='xxx'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE t1 SET a='yyy' WHERE a='xxx'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -# Testing a VIEW created with FILE privileges but accessed with no FILE -SELECT user(); -user() -root@localhost -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT user(); -user() -user@localhost -SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -DROP VIEW v1; -DROP TABLE t1, t1remote; -DROP USER user@localhost; -# -# Testing FILE privileges done -# 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; diff --git a/storage/connect/mysql-test/connect/r/mysql_grant.result b/storage/connect/mysql-test/connect/r/mysql_grant.result new file mode 100644 index 00000000000..f8d0ee6ad6f --- /dev/null +++ b/storage/connect/mysql-test/connect/r/mysql_grant.result @@ -0,0 +1,63 @@ +# +# Testing FILE privilege +# +GRANT ALL PRIVILEGES ON *.* TO user@localhost; +REVOKE FILE ON *.* FROM user@localhost; +SELECT user(); +user() +user@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL OPTION_LIST='host=localhost,user=root1,port=PORT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +CREATE TABLE t1remote (a INT NOT NULL); +INSERT INTO t1remote VALUES (10),(20),(30); +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL TABNAME=t1remote OPTION_LIST='host=localhost,user=root,port=PORT'; +SELECT * FROM t1; +a +10 +20 +30 +SELECT user(); +user() +user@localhost +SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +INSERT INTO t1 VALUES ('xxx'); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM t1 WHERE a='xxx'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE t1 SET a='yyy' WHERE a='xxx'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +TRUNCATE TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 READONLY=1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +CREATE VIEW v1 AS SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +# Testing a VIEW created with FILE privileges but accessed with no FILE +SELECT user(); +user() +root@localhost +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT user(); +user() +user@localhost +SELECT * FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +INSERT INTO v1 VALUES (2); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE v1 SET a=123; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +DROP VIEW v1; +DROP TABLE t1, t1remote; +DROP USER user@localhost; +# +# Testing FILE privileges done +# diff --git a/storage/connect/mysql-test/connect/r/occur.result b/storage/connect/mysql-test/connect/r/occur.result new file mode 100644 index 00000000000..a497dfc9942 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/occur.result @@ -0,0 +1,255 @@ +CREATE TABLE employee ( +serialno CHAR(5) NOT NULL, +name VARCHAR(12) NOT NULL FLAG=6, +sex TINYINT(1) NOT NULL, +title VARCHAR(15) NOT NULL FLAG=20, +manager CHAR(5) DEFAULT NULL, +department CHAR(4) NOT NULL FLAG=41, +secretary CHAR(5) DEFAULT NULL FLAG=46, +salary DOUBLE(8,2) NOT NULL FLAG=52 +) ENGINE=connect TABLE_TYPE=fix FILE_NAME='employee.dat' ENDING=1; +SELECT * FROM employee; +serialno name sex title manager department secretary salary +74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00 +02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00 +78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00 +07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00 +45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00 +34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00 +77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00 +74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00 +56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00 +73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00 +22222 SHORTSIGHT 2 SECRETARY 87777 0021 NULL 5500.00 +55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50 +27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00 +98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00 +11111 CHERRY 2 SECRETARY 31416 2452 NULL 4500.00 +33333 MONAPENNY 2 SECRETARY 07654 0319 NULL 3800.00 +12345 KITTY 2 TYPIST 40567 0319 NULL 3000.45 +24888 PLUMHEAD 2 TYPIST 27845 0318 NULL 2800.00 +87777 STRONG 1 DIRECTOR NULL 0021 22222 23000.00 +76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00 +70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00 +40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00 +31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00 +36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00 +00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00 +73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00 +00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00 +CREATE TABLE occurs (name CHAR(12), sex CHAR(1), title CHAR(15), department CHAR(4), salary DOUBLE(8,2), id_of CHAR(12), id CHAR(5) NOT NULL) ENGINE=CONNECT TABLE_TYPE=OCCUR TABNAME=employee OPTION_LIST='OccurCol=ID,RankCol=ID_OF,Colist=serialno;manager;secretary,port=PORT';; +SELECT * FROM occurs; +name sex title department salary id_of id +BANCROFT 2 SALESMAN 0318 9600.00 serialno 74200 +BANCROFT 2 SALESMAN 0318 9600.00 manager 70012 +BANCROFT 2 SALESMAN 0318 9600.00 secretary 24888 +SMITH 1 ENGINEER 2452 9000.00 serialno 02345 +SMITH 1 ENGINEER 2452 9000.00 manager 31416 +SMITH 1 ENGINEER 2452 9000.00 secretary 11111 +MERCHANT 1 SALESMAN 0318 8700.00 serialno 78943 +MERCHANT 1 SALESMAN 0318 8700.00 manager 70012 +MERCHANT 1 SALESMAN 0318 8700.00 secretary 24888 +FUNNIGUY 1 ADMINISTRATOR 0319 8500.00 serialno 07654 +FUNNIGUY 1 ADMINISTRATOR 0319 8500.00 manager 40567 +FUNNIGUY 1 ADMINISTRATOR 0319 8500.00 secretary 33333 +BUGHAPPY 1 PROGRAMMER 0319 8500.00 serialno 45678 +BUGHAPPY 1 PROGRAMMER 0319 8500.00 manager 40567 +BUGHAPPY 1 PROGRAMMER 0319 8500.00 secretary 12345 +BIGHEAD 1 SCIENTIST 2452 8000.00 serialno 34567 +BIGHEAD 1 SCIENTIST 2452 8000.00 manager 31416 +BIGHEAD 1 SCIENTIST 2452 8000.00 secretary 11111 +SHRINKY 2 ADMINISTRATOR 0318 7500.00 serialno 77777 +SHRINKY 2 ADMINISTRATOR 0318 7500.00 manager 70012 +SHRINKY 2 ADMINISTRATOR 0318 7500.00 secretary 27845 +WALTER 1 ENGINEER 0318 7400.00 serialno 74234 +WALTER 1 ENGINEER 0318 7400.00 manager 70012 +WALTER 1 ENGINEER 0318 7400.00 secretary 24888 +FODDERMAN 1 SALESMAN 0319 7000.00 serialno 56789 +FODDERMAN 1 SALESMAN 0319 7000.00 manager 40567 +FODDERMAN 1 SALESMAN 0319 7000.00 secretary 12345 +TONGHO 1 ENGINEER 0318 6800.00 serialno 73452 +TONGHO 1 ENGINEER 0318 6800.00 manager 70012 +TONGHO 1 ENGINEER 0318 6800.00 secretary 24888 +SHORTSIGHT 2 SECRETARY 0021 5500.00 serialno 22222 +SHORTSIGHT 2 SECRETARY 0021 5500.00 manager 87777 +MESSIFUL 2 SECRETARY 0319 5000.50 serialno 55555 +MESSIFUL 2 SECRETARY 0319 5000.50 manager 40567 +MESSIFUL 2 SECRETARY 0319 5000.50 secretary 12345 +HONEY 2 SECRETARY 0318 4900.00 serialno 27845 +HONEY 2 SECRETARY 0318 4900.00 manager 70012 +HONEY 2 SECRETARY 0318 4900.00 secretary 24888 +GOOSEPEN 1 ADMINISTRATOR 0319 4700.00 serialno 98765 +GOOSEPEN 1 ADMINISTRATOR 0319 4700.00 manager 07654 +GOOSEPEN 1 ADMINISTRATOR 0319 4700.00 secretary 33333 +CHERRY 2 SECRETARY 2452 4500.00 serialno 11111 +CHERRY 2 SECRETARY 2452 4500.00 manager 31416 +MONAPENNY 2 SECRETARY 0319 3800.00 serialno 33333 +MONAPENNY 2 SECRETARY 0319 3800.00 manager 07654 +KITTY 2 TYPIST 0319 3000.45 serialno 12345 +KITTY 2 TYPIST 0319 3000.45 manager 40567 +PLUMHEAD 2 TYPIST 0318 2800.00 serialno 24888 +PLUMHEAD 2 TYPIST 0318 2800.00 manager 27845 +STRONG 1 DIRECTOR 0021 23000.00 serialno 87777 +STRONG 1 DIRECTOR 0021 23000.00 secretary 22222 +BULLOZER 1 SALESMAN 0319 14800.00 serialno 76543 +BULLOZER 1 SALESMAN 0319 14800.00 manager 40567 +BULLOZER 1 SALESMAN 0319 14800.00 secretary 12345 +WERTHER 1 DIRECTOR 0318 14500.00 serialno 70012 +WERTHER 1 DIRECTOR 0318 14500.00 manager 87777 +WERTHER 1 DIRECTOR 0318 14500.00 secretary 27845 +QUINN 1 DIRECTOR 0319 14000.00 serialno 40567 +QUINN 1 DIRECTOR 0319 14000.00 manager 87777 +QUINN 1 DIRECTOR 0319 14000.00 secretary 55555 +ORELLY 1 ENGINEER 2452 13400.00 serialno 31416 +ORELLY 1 ENGINEER 2452 13400.00 manager 87777 +ORELLY 1 ENGINEER 2452 13400.00 secretary 11111 +BIGHORN 1 SCIENTIST 2452 11000.00 serialno 36666 +BIGHORN 1 SCIENTIST 2452 11000.00 manager 31416 +BIGHORN 1 SCIENTIST 2452 11000.00 secretary 11111 +BROWNY 1 ENGINEER 0319 10500.00 serialno 00137 +BROWNY 1 ENGINEER 0319 10500.00 manager 40567 +BROWNY 1 ENGINEER 0319 10500.00 secretary 12345 +WHEELFOR 1 SALESMAN 0318 10030.00 serialno 73111 +WHEELFOR 1 SALESMAN 0318 10030.00 manager 70012 +WHEELFOR 1 SALESMAN 0318 10030.00 secretary 24888 +MARTIN 1 ENGINEER 0319 10000.00 serialno 00023 +MARTIN 1 ENGINEER 0319 10000.00 manager 40567 +MARTIN 1 ENGINEER 0319 10000.00 secretary 12345 +DROP TABLE occurs; +DROP TABLE employee; +CREATE TABLE pets ( +name VARCHAR(12) NOT NULL, +dog INT NOT NULL DEFAULT 0, +cat INT NOT NULL DEFAULT 0, +rabbit INT NOT NULL DEFAULT 0, +bird INT NOT NULL DEFAULT 0, +fish INT NOT NULL DEFAULT 0) ENGINE=MYISAM; +INSERT INTO pets(name,dog) VALUES('John',2); +INSERT INTO pets(name,cat) VALUES('Bill',1); +INSERT INTO pets(name,dog,cat) VALUES('Mary',1,1); +INSERT INTO pets(name,rabbit) VALUES('Lisbeth',2); +INSERT INTO pets(name,cat,bird) VALUES('Kevin',2,6); +INSERT INTO pets(name,dog,fish) VALUES('Donald',1,3); +SELECT * FROM pets; +name dog cat rabbit bird fish +John 2 0 0 0 0 +Bill 0 1 0 0 0 +Mary 1 1 0 0 0 +Lisbeth 0 0 2 0 0 +Kevin 0 2 0 6 0 +Donald 1 0 0 0 3 +CREATE TABLE xpet (name VARCHAR(12) NOT NULL, race CHAR(6) NOT NULL, number INT) ENGINE=CONNECT TABLE_TYPE=OCCUR TABNAME=pets OPTION_LIST='OccurCol=number,RankCol=race,Colist=dog;cat;rabbit;bird;fish,port=PORT'; +SELECT * FROM xpet; +name race number +John dog 2 +John cat 0 +John rabbit 0 +John bird 0 +John fish 0 +Bill dog 0 +Bill cat 1 +Bill rabbit 0 +Bill bird 0 +Bill fish 0 +Mary dog 1 +Mary cat 1 +Mary rabbit 0 +Mary bird 0 +Mary fish 0 +Lisbeth dog 0 +Lisbeth cat 0 +Lisbeth rabbit 2 +Lisbeth bird 0 +Lisbeth fish 0 +Kevin dog 0 +Kevin cat 2 +Kevin rabbit 0 +Kevin bird 6 +Kevin fish 0 +Donald dog 1 +Donald cat 0 +Donald rabbit 0 +Donald bird 0 +Donald fish 3 +SELECT name FROM xpet; +name +John +Bill +Mary +Lisbeth +Kevin +Donald +SELECT name FROM xpet WHERE race = 'cat' AND number = 0; +name +John +Lisbeth +Donald +SELECT name, SUM(number) pets FROM xpet GROUP BY name; +name pets +Bill 1 +Donald 4 +John 2 +Kevin 8 +Lisbeth 2 +Mary 2 +ALTER TABLE xpet MODIFY number INT NOT NULL; +SELECT * FROM xpet; +name race number +John dog 2 +Bill cat 1 +Mary dog 1 +Mary cat 1 +Lisbeth rabbit 2 +Kevin cat 2 +Kevin bird 6 +Donald dog 1 +Donald fish 3 +SELECT * FROM xpet WHERE number > 1; +name race number +John dog 2 +Lisbeth rabbit 2 +Kevin cat 2 +Kevin bird 6 +Donald fish 3 +SELECT DISTINCT name FROM xpet WHERE number > 1; +name +John +Lisbeth +Kevin +Donald +SELECT name FROM xpet; +name +John +Bill +Mary +Lisbeth +Kevin +Donald +SELECT name, race FROM xpet; +name race +John +Bill +Mary +Lisbeth +Kevin +Donald +SELECT name, count(*) FROM xpet GROUP BY name, LEAST(number,1); +name count(*) +Bill 1 +Donald 2 +John 1 +Kevin 2 +Lisbeth 1 +Mary 2 +SELECT name, number, count(*) FROM xpet GROUP BY name, number; +name number count(*) +Bill 1 1 +Donald 1 1 +Donald 3 1 +John 2 1 +Kevin 2 1 +Kevin 6 1 +Lisbeth 2 1 +Mary 1 2 +DROP TABLE xpet; +DROP TABLE pets; diff --git a/storage/connect/mysql-test/connect/r/odbc_sqlite3.result b/storage/connect/mysql-test/connect/r/odbc_sqlite3.result index 87f7803166c..339dbb6a53d 100644 --- a/storage/connect/mysql-test/connect/r/odbc_sqlite3.result +++ b/storage/connect/mysql-test/connect/r/odbc_sqlite3.result @@ -4,20 +4,6 @@ t1 CREATE TABLE `t1` ( `Attributes` varchar(256) NOT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Drivers' SET NAMES utf8; -GRANT ALL PRIVILEGES ON *.* TO user@localhost; -REVOKE FILE ON *.* FROM user@localhost; -SELECT user(); -user() -user@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Sources; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=MTR_SUITE_DIR/std_data/test.sqlite3;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8;; SHOW CREATE TABLE t1; Table Create Table @@ -31,42 +17,27 @@ test2 тест1 тест2 ÆÇÈÉË -SELECT user(); -user() -user@localhost -SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -INSERT INTO t1 VALUES ('xxx'); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM t1 WHERE a='xxx'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE t1 SET a='yyy' WHERE a='xxx'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -# Testing a VIEW created with FILE privileges but accessed with no FILE -SELECT user(); -user() -root@localhost +CREATE TABLE t2 AS SELECT * FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` varchar(64) CHARACTER SET utf8 DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t2; +a +test1 +test2 +тест1 +тест2 +ÆÇÈÉË +DROP TABLE t2; CREATE VIEW v1 AS SELECT * FROM t1; -SELECT user(); -user() -user@localhost SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost +a +test1 +test2 +тест1 +тест2 +ÆÇÈÉË DROP VIEW v1; DROP TABLE t1; -DROP USER user@localhost; diff --git a/storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result b/storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result new file mode 100644 index 00000000000..87f7803166c --- /dev/null +++ b/storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result @@ -0,0 +1,72 @@ +Table Create Table +t1 CREATE TABLE `t1` ( + `Description` varchar(128) NOT NULL, + `Attributes` varchar(256) NOT NULL +) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Drivers' +SET NAMES utf8; +GRANT ALL PRIVILEGES ON *.* TO user@localhost; +REVOKE FILE ON *.* FROM user@localhost; +SELECT user(); +user() +user@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Sources; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=MTR_SUITE_DIR/std_data/test.sqlite3;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8;; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(64) DEFAULT NULL +) ENGINE=CONNECT DEFAULT CHARSET=utf8 CONNECTION='Driver=SQLite3 ODBC Driver;Database=MTR_SUITE_DIR/std_data/test.sqlite3;NoWCHAR=yes' `TABLE_TYPE`='ODBC' `DATA_CHARSET`='utf8' +SELECT * FROM t1; +a +test1 +test2 +тест1 +тест2 +ÆÇÈÉË +SELECT user(); +user() +user@localhost +SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +INSERT INTO t1 VALUES ('xxx'); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM t1 WHERE a='xxx'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE t1 SET a='yyy' WHERE a='xxx'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +TRUNCATE TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 READONLY=1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +CREATE VIEW v1 AS SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +# Testing a VIEW created with FILE privileges but accessed with no FILE +SELECT user(); +user() +root@localhost +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT user(); +user() +user@localhost +SELECT * FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +INSERT INTO v1 VALUES (2); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE v1 SET a=123; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +DROP VIEW v1; +DROP TABLE t1; +DROP USER user@localhost; diff --git a/storage/connect/mysql-test/connect/r/pivot.result b/storage/connect/mysql-test/connect/r/pivot.result new file mode 100644 index 00000000000..1b790662c4b --- /dev/null +++ b/storage/connect/mysql-test/connect/r/pivot.result @@ -0,0 +1,230 @@ +# +# Testing the PIVOT table type +# +CREATE TABLE expenses ( +Who CHAR(10) NOT NULL, +Week INT(2) NOT NULL, +What CHAR(12) NOT NULL, +Amount DOUBLE(8,2)) +ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='expenses.txt' ENDING=2; +SELECT * FROM expenses; +Who Week What Amount +Joe 3 Beer 18.00 +Beth 4 Food 17.00 +Janet 5 Beer 14.00 +Joe 3 Food 12.00 +Joe 4 Beer 19.00 +Janet 5 Car 12.00 +Joe 3 Food 19.00 +Beth 4 Beer 15.00 +Janet 5 Beer 19.00 +Joe 3 Car 20.00 +Joe 4 Beer 16.00 +Beth 5 Food 12.00 +Beth 3 Beer 16.00 +Joe 4 Food 17.00 +Joe 5 Beer 14.00 +Janet 3 Car 19.00 +Joe 4 Food 17.00 +Beth 5 Beer 20.00 +Janet 3 Food 18.00 +Joe 4 Beer 14.00 +Joe 5 Food 12.00 +Janet 3 Beer 18.00 +Janet 4 Car 17.00 +Janet 5 Food 12.00 +# +# Pivoting from What +# +CREATE TABLE pivex ( +Who CHAR(10) NOT NULL, +Week INT(2) NOT NULL, +Beer DOUBLE(8,2) FLAG=1, +Car DOUBLE(8,2) FLAG=1, +Food DOUBLE(8,2) FLAG=1) +ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses; +ALTER TABLE pivex OPTION_LIST='port=PORT'; +Warnings: +Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk +SELECT * FROM pivex; +Who Week Beer Car Food +Beth 3 16.00 0.00 0.00 +Beth 4 15.00 0.00 17.00 +Beth 5 20.00 0.00 12.00 +Janet 3 18.00 19.00 18.00 +Janet 4 0.00 17.00 0.00 +Janet 5 33.00 12.00 12.00 +Joe 3 18.00 20.00 31.00 +Joe 4 49.00 0.00 34.00 +Joe 5 14.00 0.00 12.00 +# +# Restricting the columns in a Pivot Table +# +ALTER TABLE pivex DROP COLUMN week; +SELECT * FROM pivex; +Who Beer Car Food +Beth 51.00 0.00 29.00 +Janet 51.00 48.00 30.00 +Joe 81.00 20.00 77.00 +# +# Using a source definition +# +DROP TABLE pivex; +CREATE TABLE pivex ( +Who CHAR(10) NOT NULL, +Week INT(2) NOT NULL, +Beer DOUBLE(8,2) FLAG=1, +Car DOUBLE(8,2) FLAG=1, +Food DOUBLE(8,2) FLAG=1) +ENGINE=CONNECT TABLE_TYPE=PIVOT +SRCDEF='select who, week, what, sum(amount) as amount from expenses where week in (4,5) group by who, week, what'; +ALTER TABLE pivex OPTION_LIST='PivotCol=what,FncCol=amount,port=PORT'; +Warnings: +Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk +SELECT * FROM pivex; +Who Week Beer Car Food +Beth 4 15.00 0.00 17.00 +Beth 5 20.00 0.00 12.00 +Janet 4 0.00 17.00 0.00 +Janet 5 33.00 12.00 12.00 +Joe 4 49.00 0.00 34.00 +Joe 5 14.00 0.00 12.00 +# +# Pivoting from Week +# +DROP TABLE pivex; +CREATE TABLE pivex ( +Who CHAR(10) NOT NULL, +What CHAR(12) NOT NULL, +`3` DOUBLE(8,2) FLAG=1, +`4` DOUBLE(8,2) FLAG=1, +`5` DOUBLE(8,2) FLAG=1) +ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses; +ALTER TABLE pivex OPTION_LIST='PivotCol=Week,port=PORT'; +Warnings: +Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk +SELECT * FROM pivex; +Who What 3 4 5 +Beth Beer 16.00 15.00 20.00 +Beth Food 0.00 17.00 12.00 +Janet Beer 18.00 0.00 33.00 +Janet Car 19.00 17.00 12.00 +Janet Food 18.00 0.00 12.00 +Joe Beer 18.00 49.00 14.00 +Joe Car 20.00 0.00 0.00 +Joe Food 31.00 34.00 12.00 +# +# Using scalar functions and expresssions +# +DROP TABLE pivex; +CREATE TABLE pivex ( +Who CHAR(10) NOT NULL, +What CHAR(12) NOT NULL, +First DOUBLE(8,2) FLAG=1, +Middle DOUBLE(8,2) FLAG=1, +Last DOUBLE(8,2) FLAG=1) +ENGINE=CONNECT TABLE_TYPE=PIVOT +SRCDEF='select who, what, case when week=3 then ''First'' when week=5 then ''Last'' else ''Middle'' end as wk, sum(amount) * 6.56 as amnt from expenses group by who, what, wk'; +ALTER TABLE pivex OPTION_LIST='PivotCol=wk,FncCol=amnt,port=PORT'; +Warnings: +Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk +SELECT * FROM pivex; +Who What First Middle Last +Beth Beer 104.96 98.40 131.20 +Beth Food 0.00 111.52 78.72 +Janet Beer 118.08 0.00 216.48 +Janet Car 124.64 111.52 78.72 +Janet Food 118.08 0.00 78.72 +Joe Beer 118.08 321.44 91.84 +Joe Car 131.20 0.00 0.00 +Joe Food 203.36 223.04 78.72 +DROP TABLE pivex; +DROP TABLE expenses; +# +# Make the PETS table +# +CREATE TABLE pets ( +Name VARCHAR(12) NOT NULL, +Race CHAR(6) NOT NULL, +Number INT NOT NULL) ENGINE=MYISAM; +INSERT INTO pets VALUES('John','dog',2); +INSERT INTO pets VALUES('Bill','cat',1); +INSERT INTO pets VALUES('Mary','dog',1); +INSERT INTO pets VALUES('Mary','cat',1); +INSERT INTO pets VALUES('Lisbeth','rabbit',2); +INSERT INTO pets VALUES('Kevin','cat',2); +INSERT INTO pets VALUES('Kevin','bird',6); +INSERT INTO pets VALUES('Donald','dog',1); +INSERT INTO pets VALUES('Donald','fish',3); +SELECT * FROM pets; +Name Race Number +John dog 2 +Bill cat 1 +Mary dog 1 +Mary cat 1 +Lisbeth rabbit 2 +Kevin cat 2 +Kevin bird 6 +Donald dog 1 +Donald fish 3 +# +# Pivot the PETS table +# +CREATE TABLE pivet ( +name VARCHAR(12) NOT NULL, +dog INT NOT NULL DEFAULT 0 FLAG=1, +cat INT NOT NULL DEFAULT 0 FLAG=1, +rabbit INT NOT NULL DEFAULT 0 FLAG=1, +bird INT NOT NULL DEFAULT 0 FLAG=1, +fish INT NOT NULL DEFAULT 0 FLAG=1) +ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1'; +SELECT * FROM pivet; +name dog cat rabbit bird fish +John 2 0 0 0 0 +Bill 0 1 0 0 0 +Mary 1 1 0 0 0 +Lisbeth 0 0 2 0 0 +Kevin 0 2 0 6 0 +Donald 1 0 0 0 3 +DROP TABLE pivet; +# +# Testing the "data" column list +# +CREATE TABLE pivet ( +name VARCHAR(12) NOT NULL, +dog INT NOT NULL DEFAULT 0 FLAG=1, +cat INT NOT NULL DEFAULT 0 FLAG=1) +ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1'; +SELECT * FROM pivet; +ERROR HY000: Got error 122 'Cannot find matching column' from CONNECT +ALTER TABLE pivet OPTION_LIST='PivotCol=race,groupby=1,accept=1'; +Warnings: +Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk +SELECT * FROM pivet; +name dog cat +John 2 0 +Bill 0 1 +Mary 1 1 +Lisbeth 0 0 +Kevin 0 2 +Donald 1 0 +DROP TABLE pivet; +# +# Adding a "dump" column +# +CREATE TABLE pivet ( +name VARCHAR(12) NOT NULL, +dog INT NOT NULL DEFAULT 0 FLAG=1, +cat INT NOT NULL DEFAULT 0 FLAG=1, +other INT NOT NULL DEFAULT 0 FLAG=2) +ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1'; +SELECT * FROM pivet; +name dog cat other +John 2 0 0 +Bill 0 1 0 +Mary 1 1 0 +Lisbeth 0 0 2 +Kevin 0 2 6 +Donald 1 0 3 +DROP TABLE pivet; +DROP TABLE pets; diff --git a/storage/connect/mysql-test/connect/r/tbl.result b/storage/connect/mysql-test/connect/r/tbl.result index 01a6afcebe8..bc77516c22d 100644 --- a/storage/connect/mysql-test/connect/r/tbl.result +++ b/storage/connect/mysql-test/connect/r/tbl.result @@ -4,6 +4,9 @@ CREATE TABLE t1 ( a INT NOT NULL, message CHAR(10)) ENGINE=connect; +Warnings: +Warning 1105 No table_type. Will be set to DOS +Warning 1105 No file name. Table will use t1.dos INSERT INTO t1 VALUES (1,'Testing'),(2,'dos table'),(3,'t1'); SELECT * FROM t1; a message diff --git a/storage/connect/mysql-test/connect/r/upd.result b/storage/connect/mysql-test/connect/r/upd.result index 24cfdafaa9a..fa519c4b688 100644 --- a/storage/connect/mysql-test/connect/r/upd.result +++ b/storage/connect/mysql-test/connect/r/upd.result @@ -59,6 +59,9 @@ END// # Testing DOS table changes # CREATE TABLE t1 ENGINE=connect AS SELECT * FROM employee; +Warnings: +Warning 1105 No table_type. Will be set to DOS +Warning 1105 No file name. Table will use t1.dos CALL test.tst_up(); serialno name sex title manager department secretary salary 74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00 @@ -154,6 +157,9 @@ serialno name sex title manager department secretary salary # Testing DOS table changes # CREATE TABLE t1 ENGINE=connect mapped=yes AS SELECT * FROM employee; +Warnings: +Warning 1105 No table_type. Will be set to DOS +Warning 1105 No file name. Table will use t1.dos CALL test.tst_up(); serialno name sex title manager department secretary salary 74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00 diff --git a/storage/connect/mysql-test/connect/r/vec.result b/storage/connect/mysql-test/connect/r/vec.result index 9461966aef7..65513dc07db 100644 --- a/storage/connect/mysql-test/connect/r/vec.result +++ b/storage/connect/mysql-test/connect/r/vec.result @@ -1,97 +1,3 @@ -# -# Beginning of grant.inc -# -GRANT ALL PRIVILEGES ON *.* TO user@localhost; -REVOKE FILE ON *.* FROM user@localhost; -SELECT user(); -user() -user@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=VEC MAX_ROWS=100; -Warnings: -Warning 1105 No file name. Table will use t1.vec -INSERT INTO t1 VALUES (10); -SELECT * FROM t1; -a -10 -UPDATE t1 SET a=20; -SELECT * FROM t1; -a -20 -DELETE FROM t1; -SELECT * FROM t1; -a -INSERT INTO t1 VALUES(10); -TRUNCATE TABLE t1; -SELECT * FROM t1; -a -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT * FROM v1; -a -DROP VIEW v1; -DROP TABLE t1; -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=VEC MAX_ROWS=100 FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=VEC MAX_ROWS=100 FILE_NAME='t1.EXT'; -INSERT INTO t1 VALUES (10); -SELECT user(); -user() -user@localhost -INSERT INTO t1 VALUES (10); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE t1 SET a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 FILE_NAME='t2.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -# Testing a VIEW created with FILE privileges but accessed with no FILE -SELECT user(); -user() -root@localhost -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT user(); -user() -user@localhost -SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -DROP VIEW v1; -DROP TABLE t1; -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=VEC MAX_ROWS=100; -Warnings: -Warning 1105 No file name. Table will use t1.vec -INSERT INTO t1 VALUES (10); -SELECT user(); -user() -user@localhost -ALTER TABLE t1 FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DROP TABLE t1; -DROP USER user@localhost; -# -# End of grant.inc -# CREATE TABLE dir1 ( spath VARCHAR(256) NOT NULL flag=1, fname VARCHAR(256) NOT NULL, diff --git a/storage/connect/mysql-test/connect/r/xcol.result b/storage/connect/mysql-test/connect/r/xcol.result new file mode 100644 index 00000000000..f6899b47504 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/xcol.result @@ -0,0 +1,85 @@ +# +# Checking XCOL tables +# +CREATE TABLE chlist ( +mother char(12) NOT NULL COMMENT 'The mother of the listed children', +children varchar(30) DEFAULT NULL COMMENT 'The comma separated list of children' +) ENGINE=CONNECT; +Warnings: +Warning 1105 No table_type. Will be set to DOS +Warning 1105 No file name. Table will use chlist.dos +INSERT INTO chlist VALUES('Sophia','Vivian, Antony'); +INSERT INTO chlist VALUES('Lisbeth','Lucy,Charles,Diana'); +INSERT INTO chlist VALUES('Corinne',NULL); +INSERT INTO chlist VALUES('Claude','Marc'); +INSERT INTO chlist VALUES('Janet','Arthur,Sandra,Peter,John'); +SELECT * FROM chlist; +mother children +Sophia Vivian, Antony +Lisbeth Lucy,Charles,Diana +Corinne NULL +Claude Marc +Janet Arthur,Sandra,Peter,John +CREATE TABLE child ENGINE=CONNECT TABLE_TYPE=XCOL TABNAME=chlist OPTION_LIST='colname=children,port=PORT'; +SELECT * FROM child; +mother children +Sophia Vivian +Sophia Antony +Lisbeth Lucy +Lisbeth Charles +Lisbeth Diana +Corinne NULL +Claude Marc +Janet Arthur +Janet Sandra +Janet Peter +Janet John +SELECT * FROM child ORDER BY mother; +mother children +Claude Marc +Corinne NULL +Janet Peter +Janet Sandra +Janet Arthur +Janet John +Lisbeth Diana +Lisbeth Charles +Lisbeth Lucy +Sophia Antony +Sophia Vivian +SELECT * FROM child ORDER BY children; +mother children +Corinne NULL +Sophia Antony +Janet Arthur +Lisbeth Charles +Lisbeth Diana +Janet John +Lisbeth Lucy +Claude Marc +Janet Peter +Janet Sandra +Sophia Vivian +SELECT mother FROM child; +mother +Sophia +Lisbeth +Corinne +Claude +Janet +SELECT mother, COUNT(*) FROM child GROUP BY mother; +mother COUNT(*) +Claude 1 +Corinne 1 +Janet 1 +Lisbeth 1 +Sophia 1 +SELECT mother, COUNT(children) FROM child GROUP BY mother; +mother COUNT(children) +Claude 1 +Corinne 0 +Janet 4 +Lisbeth 3 +Sophia 2 +DROP TABLE child; +DROP TABLE chlist; diff --git a/storage/connect/mysql-test/connect/r/xml.result b/storage/connect/mysql-test/connect/r/xml.result index e7dcf8f4c73..67fcc5f121e 100644 --- a/storage/connect/mysql-test/connect/r/xml.result +++ b/storage/connect/mysql-test/connect/r/xml.result @@ -1,99 +1,5 @@ Warnings: Warning 1105 No file name. Table will use t1.xml -# -# Beginning of grant.inc -# -GRANT ALL PRIVILEGES ON *.* TO user@localhost; -REVOKE FILE ON *.* FROM user@localhost; -SELECT user(); -user() -user@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row'; -Warnings: -Warning 1105 No file name. Table will use t1.xml -INSERT INTO t1 VALUES (10); -SELECT * FROM t1; -a -10 -UPDATE t1 SET a=20; -SELECT * FROM t1; -a -20 -DELETE FROM t1; -SELECT * FROM t1; -a -INSERT INTO t1 VALUES(10); -TRUNCATE TABLE t1; -SELECT * FROM t1; -a -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT * FROM v1; -a -DROP VIEW v1; -DROP TABLE t1; -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row' FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row' FILE_NAME='t1.EXT'; -INSERT INTO t1 VALUES (10); -SELECT user(); -user() -user@localhost -INSERT INTO t1 VALUES (10); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE t1 SET a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -ALTER TABLE t1 FILE_NAME='t2.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -# Testing a VIEW created with FILE privileges but accessed with no FILE -SELECT user(); -user() -root@localhost -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT user(); -user() -user@localhost -SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -SELECT user(); -user() -root@localhost -DROP VIEW v1; -DROP TABLE t1; -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row'; -Warnings: -Warning 1105 No file name. Table will use t1.xml -INSERT INTO t1 VALUES (10); -SELECT user(); -user() -user@localhost -ALTER TABLE t1 FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) -DROP TABLE t1; -DROP USER user@localhost; -# -# End of grant.inc -# SET NAMES utf8; # # Testing tag values @@ -253,8 +159,8 @@ TITLE XML, Langage et Applications TRANSLATOR NULL PUBLISHER Eyrolles Paris DATEPUB 1998 -SELECT LOAD_FILE('test/xsample2.xml'); -LOAD_FILE('test/xsample2.xml') <?xml version="1.0" encoding="UTF-8"?> +SELECT LOAD_FILE('MYSQLD_DATADIR/test/xsample2.xml') AS xml; +xml <?xml version="1.0" encoding="UTF-8"?> <BIBLIO SUBJECT="XML"> <BOOK ISBN="9782212090819" LANG="fr" SUBJECT="applications"> <AUTHOR> @@ -467,7 +373,7 @@ SELECT node, hex(node) FROM t1; node ÀÁÂÃ hex(node) C0C1C2C3 DROP TABLE t1; -SET @a=LOAD_FILE('test/t1.xml'); +SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml'); SELECT LEFT(@a,38); LEFT(@a,38) <?xml version="1.0" encoding="utf-8"?> SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node')); @@ -481,7 +387,7 @@ SELECT node, hex(node) FROM t1; node ÀÁÂÃ hex(node) C0C1C2C3 DROP TABLE t1; -SET @a=LOAD_FILE('test/t1.xml'); +SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml'); SELECT LEFT(@a,43); LEFT(@a,43) <?xml version="1.0" encoding="iso-8859-1"?> SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node')); @@ -504,10 +410,10 @@ hex(node) D090D091D092D093 node &<>"' hex(node) 263C3E2227 DROP TABLE t1; -SET @a=LOAD_FILE('test/t1.xml'); +SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml'); SELECT CAST(@a AS CHAR CHARACTER SET latin1); CAST(@a AS CHAR CHARACTER SET latin1) <?xml version="1.0" encoding="iso-8859-1"?> -<!-- Created by CONNECT Version 1.01.0004 April 10, 2013 --> +<!-- Created by CONNECT Version 1.01.0006 Mai 21, 2013 --> <t1> <line> <node>ÀÁÂÃ</node> diff --git a/storage/connect/mysql-test/connect/r/xml_grant.result b/storage/connect/mysql-test/connect/r/xml_grant.result new file mode 100644 index 00000000000..ea38e57af86 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/xml_grant.result @@ -0,0 +1,96 @@ +Warnings: +Warning 1105 No file name. Table will use t1.xml +# +# Beginning of grant.inc +# +GRANT ALL PRIVILEGES ON *.* TO user@localhost; +REVOKE FILE ON *.* FROM user@localhost; +SELECT user(); +user() +user@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row'; +Warnings: +Warning 1105 No file name. Table will use t1.xml +INSERT INTO t1 VALUES (10); +SELECT * FROM t1; +a +10 +UPDATE t1 SET a=20; +SELECT * FROM t1; +a +20 +DELETE FROM t1; +SELECT * FROM t1; +a +INSERT INTO t1 VALUES(10); +TRUNCATE TABLE t1; +SELECT * FROM t1; +a +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT * FROM v1; +a +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row' FILE_NAME='t1.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row' FILE_NAME='t1.EXT'; +INSERT INTO t1 VALUES (10); +SELECT user(); +user() +user@localhost +INSERT INTO t1 VALUES (10); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE t1 SET a=20; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +TRUNCATE TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 READONLY=1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 FILE_NAME='t2.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DROP TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +CREATE VIEW v1 AS SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +# Testing a VIEW created with FILE privileges but accessed with no FILE +SELECT user(); +user() +root@localhost +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT user(); +user() +user@localhost +SELECT * FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +INSERT INTO v1 VALUES (2); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE v1 SET a=123; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT user(); +user() +root@localhost +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row'; +Warnings: +Warning 1105 No file name. Table will use t1.xml +INSERT INTO t1 VALUES (10); +SELECT user(); +user() +user@localhost +ALTER TABLE t1 FILE_NAME='t1.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DROP TABLE t1; +DROP USER user@localhost; +# +# End of grant.inc +# diff --git a/storage/connect/mysql-test/connect/std_data/expenses.txt b/storage/connect/mysql-test/connect/std_data/expenses.txt new file mode 100644 index 00000000000..66a94edbb9a --- /dev/null +++ b/storage/connect/mysql-test/connect/std_data/expenses.txt @@ -0,0 +1,24 @@ +Joe 3Beer 18.00
+Beth 4Food 17.00
+Janet 5Beer 14.00
+Joe 3Food 12.00
+Joe 4Beer 19.00
+Janet 5Car 12.00
+Joe 3Food 19.00
+Beth 4Beer 15.00
+Janet 5Beer 19.00
+Joe 3Car 20.00
+Joe 4Beer 16.00
+Beth 5Food 12.00
+Beth 3Beer 16.00
+Joe 4Food 17.00
+Joe 5Beer 14.00
+Janet 3Car 19.00
+Joe 4Food 17.00
+Beth 5Beer 20.00
+Janet 3Food 18.00
+Joe 4Beer 14.00
+Joe 5Food 12.00
+Janet 3Beer 18.00
+Janet 4Car 17.00
+Janet 5Food 12.00
diff --git a/storage/connect/mysql-test/connect/t/bin.test b/storage/connect/mysql-test/connect/t/bin.test index 0266fd3e357..a9dab32987e 100644 --- a/storage/connect/mysql-test/connect/t/bin.test +++ b/storage/connect/mysql-test/connect/t/bin.test @@ -1,9 +1,5 @@ let $MYSQLD_DATADIR= `select @@datadir`; -let $TABLE_OPTIONS=TABLE_TYPE=BIN; -let $FILE_EXT=BIN; ---source grant.inc - --copy_file $MTR_SUITE_DIR/std_data/Testbal.dat $MYSQLD_DATADIR/test/Testbal.dat --echo # diff --git a/storage/connect/mysql-test/connect/t/csv.test b/storage/connect/mysql-test/connect/t/csv.test index 6578ba83a9a..685ac434df7 100644 --- a/storage/connect/mysql-test/connect/t/csv.test +++ b/storage/connect/mysql-test/connect/t/csv.test @@ -1,9 +1,5 @@ let $MYSQLD_DATADIR= `select @@datadir`; -let $TABLE_OPTIONS=TABLE_TYPE=CSV; -let $FILE_EXT=CSV; ---source grant.inc - --copy_file $MTR_SUITE_DIR/std_data/people.csv $MYSQLD_DATADIR/test/people.csv SET NAMES utf8; diff --git a/storage/connect/mysql-test/connect/t/dbf.test b/storage/connect/mysql-test/connect/t/dbf.test index fb0bc21f52d..b9a1b6e2183 100644 --- a/storage/connect/mysql-test/connect/t/dbf.test +++ b/storage/connect/mysql-test/connect/t/dbf.test @@ -1,9 +1,5 @@ let $MYSQLD_DATADIR= `select @@datadir`; -let $TABLE_OPTIONS=TABLE_TYPE=DBF; -let $FILE_EXT=DBF; ---source grant.inc - --echo # --echo # Testing errors --echo # diff --git a/storage/connect/mysql-test/connect/t/dir.test b/storage/connect/mysql-test/connect/t/dir.test index 073cdaa380b..fb69813d9f0 100644 --- a/storage/connect/mysql-test/connect/t/dir.test +++ b/storage/connect/mysql-test/connect/t/dir.test @@ -1,76 +1,6 @@ let $MYSQLD_DATADIR= `select @@datadir`; ---echo # ---echo # Testing FILE privilege ---echo # -GRANT ALL PRIVILEGES ON *.* TO user@localhost; -REVOKE FILE ON *.* FROM user@localhost; ---connect(user,localhost,user,,) ---connection user -SELECT user(); ---error ER_ACCESS_DENIED_ERROR -CREATE TABLE t1 ( - path 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='*.*'; ---connection default -SELECT user(); -CREATE TABLE t1 ( - path 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='*.*'; -# "size>0" to skip directory names on Windows ---replace_result $MYSQLD_DATADIR DATADIR/ -SELECT fname, ftype, size FROM t1 WHERE size>0; - ---connection user -SELECT user(); ---error ER_ACCESS_DENIED_ERROR -SELECT * FROM t1; ---error ER_ACCESS_DENIED_ERROR -INSERT INTO t1 VALUES (); ---error ER_ACCESS_DENIED_ERROR -DELETE FROM t1 WHERE path='xxx'; ---error ER_ACCESS_DENIED_ERROR -UPDATE t1 SET path='yyy' WHERE path='xxx'; ---error ER_ACCESS_DENIED_ERROR -TRUNCATE TABLE t1; ---error ER_ACCESS_DENIED_ERROR -ALTER TABLE t1 READONLY=1; ---error ER_ACCESS_DENIED_ERROR -CREATE VIEW v1 AS SELECT * FROM t1; - ---echo # Testing a VIEW created with FILE privileges but accessed with no FILE ---connection default -SELECT user(); -CREATE VIEW v1 AS SELECT * FROM t1; ---connection user -SELECT user(); ---error ER_ACCESS_DENIED_ERROR -SELECT * FROM v1; ---error ER_ACCESS_DENIED_ERROR -INSERT INTO v1 VALUES (1,1,1,1); ---error ER_ACCESS_DENIED_ERROR -UPDATE v1 SET path=123; ---error ER_ACCESS_DENIED_ERROR -DELETE FROM v1; - ---disconnect user ---connection default -SELECT user(); -DROP VIEW v1; -DROP TABLE t1; -DROP USER user@localhost; ---echo # ---echo # Testing FILE privileges done ---echo # - - CREATE TABLE t1 ( path VARCHAR(256) NOT NULL flag=1, fname VARCHAR(256) NOT NULL, diff --git a/storage/connect/mysql-test/connect/t/fix.test b/storage/connect/mysql-test/connect/t/fix.test index d2dfeb21352..c3cec55a217 100644 --- a/storage/connect/mysql-test/connect/t/fix.test +++ b/storage/connect/mysql-test/connect/t/fix.test @@ -1,9 +1,5 @@ let $MYSQLD_DATADIR= `select @@datadir`; -let $TABLE_OPTIONS=TABLE_TYPE=FIX; -let $FILE_EXT=FIX; ---source grant.inc - --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 diff --git a/storage/connect/mysql-test/connect/t/fmt.test b/storage/connect/mysql-test/connect/t/fmt.test index de7f8c06c1b..662bc70c8b1 100644 --- a/storage/connect/mysql-test/connect/t/fmt.test +++ b/storage/connect/mysql-test/connect/t/fmt.test @@ -1,85 +1,85 @@ -let $MYSQLD_DATADIR= `select @@datadir`; ---copy_file $MTR_SUITE_DIR/std_data/funny.txt $MYSQLD_DATADIR/test/funny.txt ---copy_file $MTR_SUITE_DIR/std_data/funny2.txt $MYSQLD_DATADIR/test/funny2.txt - ---echo # ---echo # Testing errors ---echo # -CREATE TABLE t1 -( - ID INT NOT NULL field_format=' %n%d%n' -) Engine=CONNECT table_type=FMT 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 update on FMT tables ---echo # -CREATE TABLE t1 -( - id INT NOT NULL field_format=' %n%d%n' -) ENGINE=CONNECT TABLE_TYPE=FMT FILE_NAME='t1.txt'; ---error ER_GET_ERRMSG -INSERT INTO t1 VALUES (10),(20); -# TODO: -#--error ER_GET_ERRMSG -#UPDATE t1 SET id=20; -#TRUNCATE TABLE t1; -#DELETE FROM t1 WHERE id=10; -#SELECT * FROM t1; -DROP TABLE t1; ---remove_file $MYSQLD_DATADIR/test/t1.txt - - ---echo # ---echo # Testing manual examples ---echo # -CREATE TABLE t1 -( - ID Integer(5) not null field_format=' %n%d%n', - NAME Char(16) not null field_format=" , '%n%[^']%n'", - DEPNO Integer(4) not null field_format=' , #%n%d%n', - SALARY Double(12,2) not null field_format=' ; %n%f%n' -) Engine=CONNECT table_type=FMT file_name='funny.txt'; -SELECT * FROM t1; -DROP TABLE t1; - -# -# TODO: shoudn't a warning instead of error be returned on bad format? -# -CREATE TABLE t1 -( - ID Integer(5) not null field_format=' %n%d%n', - NAME Char(16) not null field_format=" , '%n%[^']%n'", - DEPNO Integer(4) not null field_format=' , #%n%d%n', - SALARY Double(12,2) not null field_format=' ; %n%f%n' -) Engine=CONNECT table_type=FMT file_name='funny2.txt'; ---error ER_GET_ERRMSG -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 -( - ID Integer(5) not null field_format=' %n%d%n', - NAME Char(16) not null field_format=' , ''%n%[^'']%m', - DEPNO Integer(4) not null field_format=''' , #%n%d%m', - SALARY Double(12,2) not null field_format=' ; %n%f%n' -) Engine=CONNECT table_type=FMT file_name='funny2.txt'; -SELECT * FROM t1; ---error ER_GET_ERRMSG -UPDATE t1 SET SALARY=1234; -# TODO: this query crashes -# UPDATE t1 SET SALARY=1234 WHERE ID=56; -DELETE FROM t1 WHERE ID=56; -SELECT * FROM t1; -DROP TABLE t1; - -# -# Clean up -# ---remove_file $MYSQLD_DATADIR/test/funny.txt ---remove_file $MYSQLD_DATADIR/test/funny2.txt +let $MYSQLD_DATADIR= `select @@datadir`;
+--copy_file $MTR_SUITE_DIR/std_data/funny.txt $MYSQLD_DATADIR/test/funny.txt
+--copy_file $MTR_SUITE_DIR/std_data/funny2.txt $MYSQLD_DATADIR/test/funny2.txt
+
+--echo #
+--echo # Testing errors
+--echo #
+CREATE TABLE t1
+(
+ ID INT NOT NULL field_format=' %n%d%n'
+) Engine=CONNECT table_type=FMT 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 update on FMT tables
+--echo #
+CREATE TABLE t1
+(
+ id INT NOT NULL field_format=' %n%d%n'
+) ENGINE=CONNECT TABLE_TYPE=FMT FILE_NAME='t1.txt';
+--error ER_GET_ERRMSG
+INSERT INTO t1 VALUES (10),(20);
+# TODO:
+#--error ER_GET_ERRMSG
+#UPDATE t1 SET id=20;
+#TRUNCATE TABLE t1;
+#DELETE FROM t1 WHERE id=10;
+#SELECT * FROM t1;
+DROP TABLE t1;
+#--remove_file $MYSQLD_DATADIR/test/t1.txt
+
+
+--echo #
+--echo # Testing manual examples
+--echo #
+CREATE TABLE t1
+(
+ ID Integer(5) not null field_format=' %n%d%n',
+ NAME Char(16) not null field_format=" , '%n%[^']%n'",
+ DEPNO Integer(4) not null field_format=' , #%n%d%n',
+ SALARY Double(12,2) not null field_format=' ; %n%f%n'
+) Engine=CONNECT table_type=FMT file_name='funny.txt';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+#
+# TODO: shoudn't a warning instead of error be returned on bad format?
+#
+CREATE TABLE t1
+(
+ ID Integer(5) not null field_format=' %n%d%n',
+ NAME Char(16) not null field_format=" , '%n%[^']%n'",
+ DEPNO Integer(4) not null field_format=' , #%n%d%n',
+ SALARY Double(12,2) not null field_format=' ; %n%f%n'
+) Engine=CONNECT table_type=FMT file_name='funny2.txt';
+--error ER_GET_ERRMSG
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1
+(
+ ID Integer(5) not null field_format=' %n%d%n',
+ NAME Char(16) not null field_format=' , ''%n%[^'']%m',
+ DEPNO Integer(4) not null field_format=''' , #%n%d%m',
+ SALARY Double(12,2) not null field_format=' ; %n%f%n'
+) Engine=CONNECT table_type=FMT file_name='funny2.txt';
+SELECT * FROM t1;
+--error ER_GET_ERRMSG
+UPDATE t1 SET SALARY=1234;
+# TODO: this query crashes
+# UPDATE t1 SET SALARY=1234 WHERE ID=56;
+DELETE FROM t1 WHERE ID=56;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/funny.txt
+--remove_file $MYSQLD_DATADIR/test/funny2.txt
diff --git a/storage/connect/mysql-test/connect/t/grant.test b/storage/connect/mysql-test/connect/t/grant.test new file mode 100644 index 00000000000..909bb4117a1 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/grant.test @@ -0,0 +1,95 @@ +-- source include/not_embedded.inc + +let $MYSQLD_DATADIR= `select @@datadir`; + +--echo # +--echo # Testing FILE privilege +--echo # +GRANT ALL PRIVILEGES ON *.* TO user@localhost; +REVOKE FILE ON *.* FROM user@localhost; +--connect(user,localhost,user,,) +--connection user +SELECT user(); +--error ER_ACCESS_DENIED_ERROR +CREATE TABLE t1 ( + path 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='*.*'; +--connection default +SELECT user(); +CREATE TABLE t1 ( + path 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='*.*'; +# "size>0" to skip directory names on Windows +--replace_result $MYSQLD_DATADIR DATADIR/ +SELECT fname, ftype, size FROM t1 WHERE size>0; + +--connection user +SELECT user(); +--error ER_ACCESS_DENIED_ERROR +SELECT * FROM t1; +--error ER_ACCESS_DENIED_ERROR +INSERT INTO t1 VALUES (); +--error ER_ACCESS_DENIED_ERROR +DELETE FROM t1 WHERE path='xxx'; +--error ER_ACCESS_DENIED_ERROR +UPDATE t1 SET path='yyy' WHERE path='xxx'; +--error ER_ACCESS_DENIED_ERROR +TRUNCATE TABLE t1; +--error ER_ACCESS_DENIED_ERROR +ALTER TABLE t1 READONLY=1; +--error ER_ACCESS_DENIED_ERROR +CREATE VIEW v1 AS SELECT * FROM t1; + +--echo # Testing a VIEW created with FILE privileges but accessed with no FILE +--connection default +SELECT user(); +CREATE VIEW v1 AS SELECT * FROM t1; +--connection user +SELECT user(); +--error ER_ACCESS_DENIED_ERROR +SELECT * FROM v1; +--error ER_ACCESS_DENIED_ERROR +INSERT INTO v1 VALUES (1,1,1,1); +--error ER_ACCESS_DENIED_ERROR +UPDATE v1 SET path=123; +--error ER_ACCESS_DENIED_ERROR +DELETE FROM v1; + +--disconnect user +--connection default +SELECT user(); +DROP VIEW v1; +DROP TABLE t1; +DROP USER user@localhost; +--echo # +--echo # Testing FILE privileges done +--echo # + + +let $TABLE_OPTIONS=TABLE_TYPE=BIN; +let $FILE_EXT=BIN; +--source grant.inc + +let $TABLE_OPTIONS=TABLE_TYPE=CSV; +let $FILE_EXT=CSV; +--source grant.inc + +let $TABLE_OPTIONS=TABLE_TYPE=DBF; +let $FILE_EXT=DBF; +--source grant.inc + +let $TABLE_OPTIONS=TABLE_TYPE=FIX; +let $FILE_EXT=FIX; +--source grant.inc + +let $TABLE_OPTIONS=TABLE_TYPE=VEC MAX_ROWS=100; +let $FILE_EXT=VEC; +--source grant.inc + + diff --git a/storage/connect/mysql-test/connect/t/have_odbc_sqlite3.inc b/storage/connect/mysql-test/connect/t/have_odbc_sqlite3.inc new file mode 100644 index 00000000000..9528e00ff56 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/have_odbc_sqlite3.inc @@ -0,0 +1,15 @@ +--disable_query_log +--error 0,ER_UNKNOWN_ERROR +CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers; +if ($mysql_errno) +{ + Skip No ODBC support; +} +if (!`SELECT count(*) FROM t1 WHERE Description='SQLite3 ODBC Driver'`) +{ + DROP TABLE t1; + Skip Need SQLite3 ODBC Driver; +} +SHOW CREATE TABLE t1; +DROP TABLE t1; +--enable_query_log diff --git a/storage/connect/mysql-test/connect/t/ini.test b/storage/connect/mysql-test/connect/t/ini.test index e862f3cd672..0d23142ac9e 100644 --- a/storage/connect/mysql-test/connect/t/ini.test +++ b/storage/connect/mysql-test/connect/t/ini.test @@ -1,80 +1,5 @@ let $MYSQLD_DATADIR= `select @@datadir`; ---echo # ---echo # Checking FILE privileges ---echo # -GRANT ALL PRIVILEGES ON *.* TO user@localhost; -REVOKE FILE ON *.* FROM user@localhost; ---connect(user,localhost,user,,) ---connection user -SELECT user(); -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'); -SELECT * FROM t1; -UPDATE t1 SET val='val11'; -SELECT * FROM t1; -DELETE FROM t1; -SELECT * FROM t1; -INSERT INTO t1 VALUES('sec2','val2'); -TRUNCATE TABLE t1; -SELECT * FROM t1; -CREATE VIEW v1 AS SELECT * FROM t1; -SELECT * FROM v1; -DROP VIEW v1; -DROP TABLE t1; -# Making sure DROP erased the data file ---error 1 ---remove_file $MYSQLD_DATADIR/test/t1.ini ---error ER_ACCESS_DENIED_ERROR -CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.EXT'; ---connection default -SELECT user(); -CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.EXT'; -INSERT INTO t1 VALUES ('sec1','val1'); ---connection user -SELECT user(); ---error ER_ACCESS_DENIED_ERROR -INSERT INTO t1 VALUES ('sec2','val2'); ---error ER_ACCESS_DENIED_ERROR -SELECT * FROM t1; ---error ER_ACCESS_DENIED_ERROR -UPDATE t1 SET val='val11'; ---error ER_ACCESS_DENIED_ERROR -DELETE FROM t1; ---error ER_ACCESS_DENIED_ERROR -TRUNCATE TABLE t1; ---error ER_ACCESS_DENIED_ERROR -ALTER TABLE t1 READONLY=1; ---error ER_ACCESS_DENIED_ERROR -DROP TABLE t1; ---error ER_ACCESS_DENIED_ERROR -CREATE VIEW v1 AS SELECT * FROM t1; ---echo # Testing a VIEW created with FILE privileges but accessed with no FILE ---connection default -SELECT user(); -CREATE VIEW v1 AS SELECT * FROM t1; ---connection user -SELECT user(); ---error ER_ACCESS_DENIED_ERROR -SELECT * FROM v1; ---error ER_ACCESS_DENIED_ERROR -INSERT INTO v1 VALUES ('sec3','val3'); ---error ER_ACCESS_DENIED_ERROR -UPDATE v1 SET val='val11'; ---error ER_ACCESS_DENIED_ERROR -DELETE FROM v1; ---disconnect user ---connection default -DROP VIEW v1; -DROP TABLE t1; ---remove_file $MYSQLD_DATADIR/test/t1.EXT -DROP USER user@localhost; - ---echo # ---echo # Checking FILE privileges: done ---echo # - - --copy_file $MTR_SUITE_DIR/std_data/contact.ini $MYSQLD_DATADIR/test/contact.ini --echo # diff --git a/storage/connect/mysql-test/connect/t/ini_grant.test b/storage/connect/mysql-test/connect/t/ini_grant.test new file mode 100644 index 00000000000..30678645692 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/ini_grant.test @@ -0,0 +1,79 @@ +-- source include/not_embedded.inc + +let $MYSQLD_DATADIR= `select @@datadir`; + +--echo # +--echo # Checking FILE privileges +--echo # +GRANT ALL PRIVILEGES ON *.* TO user@localhost; +REVOKE FILE ON *.* FROM user@localhost; +--connect(user,localhost,user,,) +--connection user +SELECT user(); +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'); +SELECT * FROM t1; +UPDATE t1 SET val='val11'; +SELECT * FROM t1; +DELETE FROM t1; +SELECT * FROM t1; +INSERT INTO t1 VALUES('sec2','val2'); +TRUNCATE TABLE t1; +SELECT * FROM t1; +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT * FROM v1; +DROP VIEW v1; +DROP TABLE t1; +# Making sure DROP erased the data file +--error 1 +--remove_file $MYSQLD_DATADIR/test/t1.ini +--error ER_ACCESS_DENIED_ERROR +CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.EXT'; +--connection default +SELECT user(); +CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.EXT'; +INSERT INTO t1 VALUES ('sec1','val1'); +--connection user +SELECT user(); +--error ER_ACCESS_DENIED_ERROR +INSERT INTO t1 VALUES ('sec2','val2'); +--error ER_ACCESS_DENIED_ERROR +SELECT * FROM t1; +--error ER_ACCESS_DENIED_ERROR +UPDATE t1 SET val='val11'; +--error ER_ACCESS_DENIED_ERROR +DELETE FROM t1; +--error ER_ACCESS_DENIED_ERROR +TRUNCATE TABLE t1; +--error ER_ACCESS_DENIED_ERROR +ALTER TABLE t1 READONLY=1; +--error ER_ACCESS_DENIED_ERROR +DROP TABLE t1; +--error ER_ACCESS_DENIED_ERROR +CREATE VIEW v1 AS SELECT * FROM t1; +--echo # Testing a VIEW created with FILE privileges but accessed with no FILE +--connection default +SELECT user(); +CREATE VIEW v1 AS SELECT * FROM t1; +--connection user +SELECT user(); +--error ER_ACCESS_DENIED_ERROR +SELECT * FROM v1; +--error ER_ACCESS_DENIED_ERROR +INSERT INTO v1 VALUES ('sec3','val3'); +--error ER_ACCESS_DENIED_ERROR +UPDATE v1 SET val='val11'; +--error ER_ACCESS_DENIED_ERROR +DELETE FROM v1; +--disconnect user +--connection default +DROP VIEW v1; +DROP TABLE t1; +--remove_file $MYSQLD_DATADIR/test/t1.EXT +DROP USER user@localhost; + +--echo # +--echo # Checking FILE privileges: done +--echo # + + diff --git a/storage/connect/mysql-test/connect/t/mysql.test b/storage/connect/mysql-test/connect/t/mysql.test index 45d26cdf9eb..c7eacbd3d06 100644 --- a/storage/connect/mysql-test/connect/t/mysql.test +++ b/storage/connect/mysql-test/connect/t/mysql.test @@ -1,3 +1,10 @@ +-- source include/not_embedded.inc + +# +# TODO: consider a possibility to run this test +# against some remote MySQL server +# + let $PORT= `select @@port`; --disable_query_log @@ -14,66 +21,6 @@ if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES DROP TABLE t1; --enable_query_log ---echo # ---echo # Testing FILE privilege ---echo # -GRANT ALL PRIVILEGES ON *.* TO user@localhost; -REVOKE FILE ON *.* FROM user@localhost; ---connect(user,localhost,user,,) ---connection user -SELECT user(); ---replace_result $PORT PORT ---error ER_ACCESS_DENIED_ERROR ---eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL OPTION_LIST='host=localhost,user=root1,port=$PORT' ---connection default -SELECT user(); -CREATE TABLE t1remote (a INT NOT NULL); -INSERT INTO t1remote VALUES (10),(20),(30); ---replace_result $PORT PORT ---eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL TABNAME=t1remote OPTION_LIST='host=localhost,user=root,port=$PORT' -SELECT * FROM t1; ---connection user -SELECT user(); ---error ER_ACCESS_DENIED_ERROR -SELECT * FROM t1; ---error ER_ACCESS_DENIED_ERROR -INSERT INTO t1 VALUES ('xxx'); ---error ER_ACCESS_DENIED_ERROR -DELETE FROM t1 WHERE a='xxx'; ---error ER_ACCESS_DENIED_ERROR -UPDATE t1 SET a='yyy' WHERE a='xxx'; ---error ER_ACCESS_DENIED_ERROR -TRUNCATE TABLE t1; ---error ER_ACCESS_DENIED_ERROR -ALTER TABLE t1 READONLY=1; ---error ER_ACCESS_DENIED_ERROR -CREATE VIEW v1 AS SELECT * FROM t1; - ---echo # Testing a VIEW created with FILE privileges but accessed with no FILE ---connection default -SELECT user(); -CREATE VIEW v1 AS SELECT * FROM t1; ---connection user -SELECT user(); ---error ER_ACCESS_DENIED_ERROR -SELECT * FROM v1; ---error ER_ACCESS_DENIED_ERROR -INSERT INTO v1 VALUES (2); ---error ER_ACCESS_DENIED_ERROR -UPDATE v1 SET a=123; ---error ER_ACCESS_DENIED_ERROR -DELETE FROM v1; - ---disconnect user ---connection default -SELECT user(); -DROP VIEW v1; -DROP TABLE t1, t1remote; -DROP USER user@localhost; ---echo # ---echo # Testing FILE privileges done ---echo # - # TODO: remote VARCHAR is displayed as CHAR CREATE TABLE t1 (a int, b char(10)); diff --git a/storage/connect/mysql-test/connect/t/mysql_grant.test b/storage/connect/mysql-test/connect/t/mysql_grant.test new file mode 100644 index 00000000000..e825e70a84b --- /dev/null +++ b/storage/connect/mysql-test/connect/t/mysql_grant.test @@ -0,0 +1,78 @@ +-- 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 TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1' + AND ENGINE='CONNECT' + AND CREATE_OPTIONS LIKE '%`table_type`=MySQL%'`) +{ + Skip Need MySQL support; +} +DROP TABLE t1; +--enable_query_log + +--echo # +--echo # Testing FILE privilege +--echo # +GRANT ALL PRIVILEGES ON *.* TO user@localhost; +REVOKE FILE ON *.* FROM user@localhost; +--connect(user,localhost,user,,) +--connection user +SELECT user(); +--replace_result $PORT PORT +--error ER_ACCESS_DENIED_ERROR +--eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL OPTION_LIST='host=localhost,user=root1,port=$PORT' +--connection default +SELECT user(); +CREATE TABLE t1remote (a INT NOT NULL); +INSERT INTO t1remote VALUES (10),(20),(30); +--replace_result $PORT PORT +--eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL TABNAME=t1remote OPTION_LIST='host=localhost,user=root,port=$PORT' +SELECT * FROM t1; +--connection user +SELECT user(); +--error ER_ACCESS_DENIED_ERROR +SELECT * FROM t1; +--error ER_ACCESS_DENIED_ERROR +INSERT INTO t1 VALUES ('xxx'); +--error ER_ACCESS_DENIED_ERROR +DELETE FROM t1 WHERE a='xxx'; +--error ER_ACCESS_DENIED_ERROR +UPDATE t1 SET a='yyy' WHERE a='xxx'; +--error ER_ACCESS_DENIED_ERROR +TRUNCATE TABLE t1; +--error ER_ACCESS_DENIED_ERROR +ALTER TABLE t1 READONLY=1; +--error ER_ACCESS_DENIED_ERROR +CREATE VIEW v1 AS SELECT * FROM t1; + +--echo # Testing a VIEW created with FILE privileges but accessed with no FILE +--connection default +SELECT user(); +CREATE VIEW v1 AS SELECT * FROM t1; +--connection user +SELECT user(); +--error ER_ACCESS_DENIED_ERROR +SELECT * FROM v1; +--error ER_ACCESS_DENIED_ERROR +INSERT INTO v1 VALUES (2); +--error ER_ACCESS_DENIED_ERROR +UPDATE v1 SET a=123; +--error ER_ACCESS_DENIED_ERROR +DELETE FROM v1; + +--disconnect user +--connection default +SELECT user(); +DROP VIEW v1; +DROP TABLE t1, t1remote; +DROP USER user@localhost; +--echo # +--echo # Testing FILE privileges done +--echo # + diff --git a/storage/connect/mysql-test/connect/t/occur.test b/storage/connect/mysql-test/connect/t/occur.test new file mode 100644 index 00000000000..36a4caafda1 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/occur.test @@ -0,0 +1,61 @@ +-- source include/not_embedded.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+let $PORT= `select @@port`;
+--copy_file $MTR_SUITE_DIR/std_data/employee.dat $MYSQLD_DATADIR/test/employee.dat
+
+CREATE TABLE employee (
+serialno CHAR(5) NOT NULL,
+name VARCHAR(12) NOT NULL FLAG=6,
+sex TINYINT(1) NOT NULL,
+title VARCHAR(15) NOT NULL FLAG=20,
+manager CHAR(5) DEFAULT NULL,
+department CHAR(4) NOT NULL FLAG=41,
+secretary CHAR(5) DEFAULT NULL FLAG=46,
+salary DOUBLE(8,2) NOT NULL FLAG=52
+) ENGINE=connect TABLE_TYPE=fix FILE_NAME='employee.dat' ENDING=1;
+SELECT * FROM employee;
+
+--replace_result $PORT PORT
+--eval CREATE TABLE occurs (name CHAR(12), sex CHAR(1), title CHAR(15), department CHAR(4), salary DOUBLE(8,2), id_of CHAR(12), id CHAR(5) NOT NULL) ENGINE=CONNECT TABLE_TYPE=OCCUR TABNAME=employee OPTION_LIST='OccurCol=ID,RankCol=ID_OF,Colist=serialno;manager;secretary,port=$PORT';
+SELECT * FROM occurs;
+
+DROP TABLE occurs;
+DROP TABLE employee;
+
+CREATE TABLE pets (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0,
+cat INT NOT NULL DEFAULT 0,
+rabbit INT NOT NULL DEFAULT 0,
+bird INT NOT NULL DEFAULT 0,
+fish INT NOT NULL DEFAULT 0) ENGINE=MYISAM;
+INSERT INTO pets(name,dog) VALUES('John',2);
+INSERT INTO pets(name,cat) VALUES('Bill',1);
+INSERT INTO pets(name,dog,cat) VALUES('Mary',1,1);
+INSERT INTO pets(name,rabbit) VALUES('Lisbeth',2);
+INSERT INTO pets(name,cat,bird) VALUES('Kevin',2,6);
+INSERT INTO pets(name,dog,fish) VALUES('Donald',1,3);
+SELECT * FROM pets;
+
+--replace_result $PORT PORT
+--eval CREATE TABLE xpet (name VARCHAR(12) NOT NULL, race CHAR(6) NOT NULL, number INT) ENGINE=CONNECT TABLE_TYPE=OCCUR TABNAME=pets OPTION_LIST='OccurCol=number,RankCol=race,Colist=dog;cat;rabbit;bird;fish,port=$PORT'
+
+SELECT * FROM xpet;
+SELECT name FROM xpet;
+SELECT name FROM xpet WHERE race = 'cat' AND number = 0;
+SELECT name, SUM(number) pets FROM xpet GROUP BY name;
+
+ALTER TABLE xpet MODIFY number INT NOT NULL;
+
+SELECT * FROM xpet;
+SELECT * FROM xpet WHERE number > 1;
+SELECT DISTINCT name FROM xpet WHERE number > 1;
+SELECT name FROM xpet;
+SELECT name, race FROM xpet;
+SELECT name, count(*) FROM xpet GROUP BY name, LEAST(number,1);
+SELECT name, number, count(*) FROM xpet GROUP BY name, number;
+
+DROP TABLE xpet;
+DROP TABLE pets;
+--remove_file $MYSQLD_DATADIR/test/employee.dat
diff --git a/storage/connect/mysql-test/connect/t/odbc_sqlite3.test b/storage/connect/mysql-test/connect/t/odbc_sqlite3.test index 5f6abb0e2bc..f32196e3f04 100644 --- a/storage/connect/mysql-test/connect/t/odbc_sqlite3.test +++ b/storage/connect/mysql-test/connect/t/odbc_sqlite3.test @@ -1,3 +1,5 @@ +--source have_odbc_sqlite3.inc + # # To run this test, install SQLite3 ODBC Driver from # http://www.ch-werner.de/sqliteodbc/ @@ -18,42 +20,11 @@ # Note, the test does not need a DSN to be created. # ---disable_query_log ---error 0,ER_UNKNOWN_ERROR -CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers; -if ($mysql_errno) -{ - Skip No ODBC support; -} -if (!`SELECT count(*) FROM t1 WHERE Description='SQLite3 ODBC Driver'`) -{ - DROP TABLE t1; - Skip Need SQLite3 ODBC Driver; -} -SHOW CREATE TABLE t1; -DROP TABLE t1; ---enable_query_log - SET NAMES utf8; let $MYSQLD_DATADIR= `select @@datadir`; -GRANT ALL PRIVILEGES ON *.* TO user@localhost; -REVOKE FILE ON *.* FROM user@localhost; ---connect(user,localhost,user,,) ---connection user -SELECT user(); ---error ER_ACCESS_DENIED_ERROR -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC; ---error ER_ACCESS_DENIED_ERROR -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers; ---error ER_ACCESS_DENIED_ERROR -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Sources; ---connection default -SELECT user(); - - # # For some reasons Windows does not allow to remove the data base # file after "DROP TABLE t1". So unlike in odbc_xls.test we won't copy @@ -66,42 +37,14 @@ let $Database=$MTR_SUITE_DIR/std_data/test.sqlite3; --replace_result $MTR_SUITE_DIR MTR_SUITE_DIR SHOW CREATE TABLE t1; SELECT * FROM t1; ---connection user -SELECT user(); ---error ER_ACCESS_DENIED_ERROR -SELECT * FROM t1; ---error ER_ACCESS_DENIED_ERROR -INSERT INTO t1 VALUES ('xxx'); ---error ER_ACCESS_DENIED_ERROR -DELETE FROM t1 WHERE a='xxx'; ---error ER_ACCESS_DENIED_ERROR -UPDATE t1 SET a='yyy' WHERE a='xxx'; ---error ER_ACCESS_DENIED_ERROR -TRUNCATE TABLE t1; ---error ER_ACCESS_DENIED_ERROR -ALTER TABLE t1 READONLY=1; ---error ER_ACCESS_DENIED_ERROR -CREATE VIEW v1 AS SELECT * FROM t1; ---echo # Testing a VIEW created with FILE privileges but accessed with no FILE ---connection default -SELECT user(); +CREATE TABLE t2 AS SELECT * FROM t1; +SHOW CREATE TABLE t2; +SELECT * FROM t2; +DROP TABLE t2; + CREATE VIEW v1 AS SELECT * FROM t1; ---connection user -SELECT user(); ---error ER_ACCESS_DENIED_ERROR SELECT * FROM v1; ---error ER_ACCESS_DENIED_ERROR -INSERT INTO v1 VALUES (2); ---error ER_ACCESS_DENIED_ERROR -UPDATE v1 SET a=123; ---error ER_ACCESS_DENIED_ERROR -DELETE FROM v1; ---disconnect user ---connection default -SELECT user(); DROP VIEW v1; DROP TABLE t1; - -DROP USER user@localhost; diff --git a/storage/connect/mysql-test/connect/t/odbc_sqlite3_grant.test b/storage/connect/mysql-test/connect/t/odbc_sqlite3_grant.test new file mode 100644 index 00000000000..7664a4473ba --- /dev/null +++ b/storage/connect/mysql-test/connect/t/odbc_sqlite3_grant.test @@ -0,0 +1,79 @@ +-- source include/not_embedded.inc +-- source have_odbc_sqlite3.inc + +# +# For the instructions on how to setup SQLite3 ODBC DSN, +# please see odbc_sqlite3.test +# + +SET NAMES utf8; + +let $MYSQLD_DATADIR= `select @@datadir`; + + +GRANT ALL PRIVILEGES ON *.* TO user@localhost; +REVOKE FILE ON *.* FROM user@localhost; +--connect(user,localhost,user,,) +--connection user +SELECT user(); +--error ER_ACCESS_DENIED_ERROR +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC; +--error ER_ACCESS_DENIED_ERROR +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers; +--error ER_ACCESS_DENIED_ERROR +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Sources; +--connection default +SELECT user(); + + +# +# For some reasons Windows does not allow to remove the data base +# file after "DROP TABLE t1". So unlike in odbc_xls.test we won't copy +# the data file, we'll use directly the file in std_data. +# As we do not do any modifications in the database, this should be OK. +# +let $Database=$MTR_SUITE_DIR/std_data/test.sqlite3; +--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR +--eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=$Database;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8; +--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR +SHOW CREATE TABLE t1; +SELECT * FROM t1; +--connection user +SELECT user(); +--error ER_ACCESS_DENIED_ERROR +SELECT * FROM t1; +--error ER_ACCESS_DENIED_ERROR +INSERT INTO t1 VALUES ('xxx'); +--error ER_ACCESS_DENIED_ERROR +DELETE FROM t1 WHERE a='xxx'; +--error ER_ACCESS_DENIED_ERROR +UPDATE t1 SET a='yyy' WHERE a='xxx'; +--error ER_ACCESS_DENIED_ERROR +TRUNCATE TABLE t1; +--error ER_ACCESS_DENIED_ERROR +ALTER TABLE t1 READONLY=1; +--error ER_ACCESS_DENIED_ERROR +CREATE VIEW v1 AS SELECT * FROM t1; + +--echo # Testing a VIEW created with FILE privileges but accessed with no FILE +--connection default +SELECT user(); +CREATE VIEW v1 AS SELECT * FROM t1; +--connection user +SELECT user(); +--error ER_ACCESS_DENIED_ERROR +SELECT * FROM v1; +--error ER_ACCESS_DENIED_ERROR +INSERT INTO v1 VALUES (2); +--error ER_ACCESS_DENIED_ERROR +UPDATE v1 SET a=123; +--error ER_ACCESS_DENIED_ERROR +DELETE FROM v1; + +--disconnect user +--connection default +SELECT user(); +DROP VIEW v1; +DROP TABLE t1; + +DROP USER user@localhost; diff --git a/storage/connect/mysql-test/connect/t/pivot.test b/storage/connect/mysql-test/connect/t/pivot.test new file mode 100644 index 00000000000..7679434bca8 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/pivot.test @@ -0,0 +1,146 @@ +-- source include/not_embedded.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+let $PORT= `select @@port`;
+--copy_file $MTR_SUITE_DIR/std_data/expenses.txt $MYSQLD_DATADIR/test/expenses.txt
+
+--echo #
+--echo # Testing the PIVOT table type
+--echo #
+CREATE TABLE expenses (
+Who CHAR(10) NOT NULL,
+Week INT(2) NOT NULL,
+What CHAR(12) NOT NULL,
+Amount DOUBLE(8,2))
+ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='expenses.txt' ENDING=2;
+SELECT * FROM expenses;
+
+--echo #
+--echo # Pivoting from What
+--echo #
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+Week INT(2) NOT NULL,
+Beer DOUBLE(8,2) FLAG=1,
+Car DOUBLE(8,2) FLAG=1,
+Food DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses;
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='port=$PORT'
+SELECT * FROM pivex;
+
+--echo #
+--echo # Restricting the columns in a Pivot Table
+--echo #
+ALTER TABLE pivex DROP COLUMN week;
+SELECT * FROM pivex;
+
+--echo #
+--echo # Using a source definition
+--echo #
+DROP TABLE pivex;
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+Week INT(2) NOT NULL,
+Beer DOUBLE(8,2) FLAG=1,
+Car DOUBLE(8,2) FLAG=1,
+Food DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT
+SRCDEF='select who, week, what, sum(amount) as amount from expenses where week in (4,5) group by who, week, what';
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='PivotCol=what,FncCol=amount,port=$PORT'
+SELECT * FROM pivex;
+
+--echo #
+--echo # Pivoting from Week
+--echo #
+DROP TABLE pivex;
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+What CHAR(12) NOT NULL,
+`3` DOUBLE(8,2) FLAG=1,
+`4` DOUBLE(8,2) FLAG=1,
+`5` DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses;
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='PivotCol=Week,port=$PORT'
+SELECT * FROM pivex;
+
+--echo #
+--echo # Using scalar functions and expresssions
+--echo #
+DROP TABLE pivex;
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+What CHAR(12) NOT NULL,
+First DOUBLE(8,2) FLAG=1,
+Middle DOUBLE(8,2) FLAG=1,
+Last DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT
+SRCDEF='select who, what, case when week=3 then ''First'' when week=5 then ''Last'' else ''Middle'' end as wk, sum(amount) * 6.56 as amnt from expenses group by who, what, wk';
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='PivotCol=wk,FncCol=amnt,port=$PORT'
+SELECT * FROM pivex;
+DROP TABLE pivex;
+DROP TABLE expenses;
+
+--echo #
+--echo # Make the PETS table
+--echo #
+CREATE TABLE pets (
+Name VARCHAR(12) NOT NULL,
+Race CHAR(6) NOT NULL,
+Number INT NOT NULL) ENGINE=MYISAM;
+INSERT INTO pets VALUES('John','dog',2);
+INSERT INTO pets VALUES('Bill','cat',1);
+INSERT INTO pets VALUES('Mary','dog',1);
+INSERT INTO pets VALUES('Mary','cat',1);
+INSERT INTO pets VALUES('Lisbeth','rabbit',2);
+INSERT INTO pets VALUES('Kevin','cat',2);
+INSERT INTO pets VALUES('Kevin','bird',6);
+INSERT INTO pets VALUES('Donald','dog',1);
+INSERT INTO pets VALUES('Donald','fish',3);
+SELECT * FROM pets;
+
+--echo #
+--echo # Pivot the PETS table
+--echo #
+CREATE TABLE pivet (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0 FLAG=1,
+cat INT NOT NULL DEFAULT 0 FLAG=1,
+rabbit INT NOT NULL DEFAULT 0 FLAG=1,
+bird INT NOT NULL DEFAULT 0 FLAG=1,
+fish INT NOT NULL DEFAULT 0 FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
+SELECT * FROM pivet;
+DROP TABLE pivet;
+
+--echo #
+--echo # Testing the "data" column list
+--echo #
+CREATE TABLE pivet (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0 FLAG=1,
+cat INT NOT NULL DEFAULT 0 FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
+--error ER_GET_ERRMSG
+SELECT * FROM pivet;
+ALTER TABLE pivet OPTION_LIST='PivotCol=race,groupby=1,accept=1';
+SELECT * FROM pivet;
+DROP TABLE pivet;
+
+--echo #
+--echo # Adding a "dump" column
+--echo #
+CREATE TABLE pivet (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0 FLAG=1,
+cat INT NOT NULL DEFAULT 0 FLAG=1,
+other INT NOT NULL DEFAULT 0 FLAG=2)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
+SELECT * FROM pivet;
+
+DROP TABLE pivet;
+DROP TABLE pets;
+--remove_file $MYSQLD_DATADIR/test/expenses.txt
diff --git a/storage/connect/mysql-test/connect/t/tbl.test b/storage/connect/mysql-test/connect/t/tbl.test index 143c7643afd..bdd928366ef 100644 --- a/storage/connect/mysql-test/connect/t/tbl.test +++ b/storage/connect/mysql-test/connect/t/tbl.test @@ -1,3 +1,5 @@ +-- source include/not_embedded.inc
+
let $MYSQLD_DATADIR= `select @@datadir`;
let $PORT= `select @@port`;
diff --git a/storage/connect/mysql-test/connect/t/vec.test b/storage/connect/mysql-test/connect/t/vec.test index 79ed4eabd86..ee504e9925a 100644 --- a/storage/connect/mysql-test/connect/t/vec.test +++ b/storage/connect/mysql-test/connect/t/vec.test @@ -1,9 +1,5 @@ let $MYSQLD_DATADIR= `select @@datadir`; -let $TABLE_OPTIONS=TABLE_TYPE=VEC MAX_ROWS=100; -let $FILE_EXT=VEC; ---source grant.inc - CREATE TABLE dir1 ( spath VARCHAR(256) NOT NULL flag=1, fname VARCHAR(256) NOT NULL, diff --git a/storage/connect/mysql-test/connect/t/xcol.test b/storage/connect/mysql-test/connect/t/xcol.test new file mode 100644 index 00000000000..b6998ee77e0 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/xcol.test @@ -0,0 +1,28 @@ +let $MYSQLD_DATADIR= `select @@datadir`;
+let $PORT= `select @@port`;
+
+--echo #
+--echo # Checking XCOL tables
+--echo #
+CREATE TABLE chlist (
+mother char(12) NOT NULL COMMENT 'The mother of the listed children',
+children varchar(30) DEFAULT NULL COMMENT 'The comma separated list of children'
+) ENGINE=CONNECT;
+INSERT INTO chlist VALUES('Sophia','Vivian, Antony');
+INSERT INTO chlist VALUES('Lisbeth','Lucy,Charles,Diana');
+INSERT INTO chlist VALUES('Corinne',NULL);
+INSERT INTO chlist VALUES('Claude','Marc');
+INSERT INTO chlist VALUES('Janet','Arthur,Sandra,Peter,John');
+SELECT * FROM chlist;
+
+--replace_result $PORT PORT
+--eval CREATE TABLE child ENGINE=CONNECT TABLE_TYPE=XCOL TABNAME=chlist OPTION_LIST='colname=children,port=$PORT'
+SELECT * FROM child;
+SELECT * FROM child ORDER BY mother;
+SELECT * FROM child ORDER BY children;
+SELECT mother FROM child;
+SELECT mother, COUNT(*) FROM child GROUP BY mother;
+SELECT mother, COUNT(children) FROM child GROUP BY mother;
+
+DROP TABLE child;
+DROP TABLE chlist;
diff --git a/storage/connect/mysql-test/connect/t/xml.test b/storage/connect/mysql-test/connect/t/xml.test index 96e7e1a3a97..3914bed307d 100644 --- a/storage/connect/mysql-test/connect/t/xml.test +++ b/storage/connect/mysql-test/connect/t/xml.test @@ -16,11 +16,6 @@ DROP TABLE t1; let $MYSQLD_DATADIR= `select @@datadir`; -let $TABLE_OPTIONS=TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row'; -let $FILE_EXT=XML; ---source grant.inc - - SET NAMES utf8; --vertical_results @@ -132,7 +127,8 @@ INSERT INTO t1 (ISBN, LANG, SUBJECT, AUTHOR, TITLE, PUBLISHEr, DATEPUB) VALUES('9782212090529','fr','général','Alain Michard', 'XML, Langage et Applications','Eyrolles Paris',1998); SELECT * FROM t1; -SELECT LOAD_FILE('test/xsample2.xml'); +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--eval SELECT LOAD_FILE('$MYSQLD_DATADIR/test/xsample2.xml') AS xml DROP TABLE t1; --remove_file $MYSQLD_DATADIR/test/xsample2.xml @@ -289,7 +285,8 @@ INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3); SELECT node, hex(node) FROM t1; DROP TABLE t1; --chmod 0777 $MYSQLD_DATADIR/test/t1.xml -SET @a=LOAD_FILE('test/t1.xml'); +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--eval SET @a=LOAD_FILE('$MYSQLD_DATADIR/test/t1.xml') SELECT LEFT(@a,38); SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node')); --remove_file $MYSQLD_DATADIR/test/t1.xml @@ -302,7 +299,8 @@ INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3); SELECT node, hex(node) FROM t1; DROP TABLE t1; --chmod 0777 $MYSQLD_DATADIR/test/t1.xml -SET @a=LOAD_FILE('test/t1.xml'); +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--eval SET @a=LOAD_FILE('$MYSQLD_DATADIR/test/t1.xml') SELECT LEFT(@a,43); SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node')); --remove_file $MYSQLD_DATADIR/test/t1.xml @@ -321,7 +319,8 @@ INSERT INTO t1 VALUES ('&<>"\''); SELECT node, hex(node) FROM t1; DROP TABLE t1; --chmod 0777 $MYSQLD_DATADIR/test/t1.xml -SET @a=LOAD_FILE('test/t1.xml'); +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--eval SET @a=LOAD_FILE('$MYSQLD_DATADIR/test/t1.xml') SELECT CAST(@a AS CHAR CHARACTER SET latin1); --remove_file $MYSQLD_DATADIR/test/t1.xml diff --git a/storage/connect/mysql-test/connect/t/xml_grant.test b/storage/connect/mysql-test/connect/t/xml_grant.test new file mode 100644 index 00000000000..f8401efaa64 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/xml_grant.test @@ -0,0 +1,23 @@ +-- source include/not_embedded.inc + +--disable_query_log +--error 0,ER_UNKNOWN_ERROR +CREATE TABLE t1 (a VARCHAR(10)) +ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2'; +if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1' + AND ENGINE='CONNECT' + AND CREATE_OPTIONS LIKE '%`table_type`=XML%' + AND CREATE_OPTIONS LIKE '%xmlsup=libxml2%'`) +{ + Skip Need LIBXML2; +} +DROP TABLE t1; +--enable_query_log + + +let $MYSQLD_DATADIR= `select @@datadir`; + +let $TABLE_OPTIONS=TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row'; +let $FILE_EXT=XML; +--source grant.inc diff --git a/storage/connect/odbconn.cpp b/storage/connect/odbconn.cpp index 6de2acef391..b39f1c9ba5b 100644 --- a/storage/connect/odbconn.cpp +++ b/storage/connect/odbconn.cpp @@ -36,6 +36,7 @@ //#include "kindex.h" #include "xtable.h" #include "tabodbc.h" +#include "odbccat.h" #include "plgcnx.h" // For DB types #include "resource.h" #include "valblk.h" @@ -47,9 +48,7 @@ /***********************************************************************/ #pragma comment(lib, "odbc32.lib") extern "C" HINSTANCE s_hModule; // Saved module handle -#else // !WIN32 -extern "C" int GetRcString(int id, char *buf, int bufsize); -#endif // !WIN32 +#endif // WIN32 /***********************************************************************/ /* Some macro's (should be defined elsewhere to be more accessible) */ @@ -176,7 +175,7 @@ int TranslateSQLType(int stp, int prec, int& len) /***********************************************************************/ /* Allocate the structure used to refer to the result set. */ /***********************************************************************/ -CATPARM *AllocCatInfo(PGLOBAL g, CATINFO fid, char *tab, PQRYRES qrp) +static CATPARM *AllocCatInfo(PGLOBAL g, CATINFO fid, char *tab, PQRYRES qrp) { size_t i, m, n; CATPARM *cap; @@ -203,7 +202,7 @@ CATPARM *AllocCatInfo(PGLOBAL g, CATINFO fid, char *tab, PQRYRES qrp) /***********************************************************************/ /* Check for nulls and reset them to Null (?) values. */ /***********************************************************************/ -void ResetNullValues(CATPARM *cap) +static void ResetNullValues(CATPARM *cap) { int i, n, ncol; PCOLRES crp; @@ -230,11 +229,7 @@ void ResetNullValues(CATPARM *cap) PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table, char *colpat, bool info) { - static int dbtype[] = {DB_CHAR, DB_CHAR, DB_CHAR, - DB_CHAR, DB_SHORT, DB_CHAR, - DB_INT, DB_INT, DB_SHORT, - DB_SHORT, DB_SHORT, DB_CHAR}; - static int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING, + static int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING}; @@ -285,7 +280,7 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table, /* Allocate the structures used to refer to the result set. */ /************************************************************************/ qrp = PlgAllocResult(g, ncol, maxres, IDS_COLUMNS, - dbtype, buftyp, fldtyp, length, true, true); + buftyp, fldtyp, length, true, true); if (info) // Info table return qrp; @@ -396,7 +391,6 @@ PQRYRES MyODBCCols(PGLOBAL g, char *dsn, char *tab, bool info) /*************************************************************************/ PQRYRES ODBCDataSources(PGLOBAL g, bool info) { - static int dbtype[] = {DB_CHAR, DB_CHAR}; static int buftyp[] = {TYPE_STRING, TYPE_STRING}; static XFLD fldtyp[] = {FLD_NAME, FLD_REM}; static unsigned int length[] = {0, 256}; @@ -425,7 +419,7 @@ PQRYRES ODBCDataSources(PGLOBAL g, bool info) /* Allocate the structures used to refer to the result set. */ /************************************************************************/ qrp = PlgAllocResult(g, ncol, maxres, IDS_DSRC, - dbtype, buftyp, fldtyp, length, true, true); + buftyp, fldtyp, length, true, true); /************************************************************************/ /* Now get the results into blocks. */ @@ -446,7 +440,6 @@ PQRYRES ODBCDataSources(PGLOBAL g, bool info) /*************************************************************************/ PQRYRES ODBCDrivers(PGLOBAL g, bool info) { - static int dbtype[] = {DB_CHAR, DB_CHAR}; static int buftyp[] = {TYPE_STRING, TYPE_STRING}; static XFLD fldtyp[] = {FLD_NAME, FLD_REM}; static unsigned int length[] = {128, 256}; @@ -471,7 +464,7 @@ PQRYRES ODBCDrivers(PGLOBAL g, bool info) /* Allocate the structures used to refer to the result set. */ /************************************************************************/ qrp = PlgAllocResult(g, ncol, maxres, IDS_DRIVER, - dbtype, buftyp, fldtyp, length, true, true); + buftyp, fldtyp, length, true, true); /************************************************************************/ /* Now get the results into blocks. */ @@ -492,8 +485,7 @@ PQRYRES ODBCDrivers(PGLOBAL g, bool info) /***********************************************************************/ PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *tabpat, bool info) { - static int dbtype[] = {DB_CHAR, DB_CHAR, DB_CHAR, DB_CHAR, DB_CHAR}; - static int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING, + static int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING}; static XFLD fldtyp[] = {FLD_QUALIF, FLD_OWNER, FLD_NAME, FLD_TYPE, FLD_REM}; @@ -536,7 +528,7 @@ PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *tabpat, bool info) /************************************************************************/ /* Allocate the structures used to refer to the result set. */ /************************************************************************/ - qrp = PlgAllocResult(g, ncol, maxres, IDS_TABLES, dbtype, buftyp, + qrp = PlgAllocResult(g, ncol, maxres, IDS_TABLES, buftyp, fldtyp, length, true, true); if (info) @@ -579,8 +571,6 @@ PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *tabpat, bool info) /**************************************************************************/ PQRYRES ODBCPrimaryKeys(PGLOBAL g, ODBConn *op, char *dsn, char *table) { - static int dbtype[] = {DB_CHAR, DB_CHAR, DB_CHAR, - DB_CHAR, DB_SHORT, DB_CHAR}; static int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_SHORT, TYPE_STRING}; static unsigned int length[] = {0, 0, 0, 0, 6, 128}; @@ -623,7 +613,7 @@ PQRYRES ODBCPrimaryKeys(PGLOBAL g, ODBConn *op, char *dsn, char *table) /* Allocate the structure used to refer to the result set. */ /************************************************************************/ qrp = PlgAllocResult(g, ncol, maxres, IDS_PKEY, - dbtype, buftyp, NULL, length, true, true); + buftyp, NULL, length, true, true); if (trace) htrc("Getting pkey results ncol=%d\n", qrp->Nbcol); @@ -662,9 +652,6 @@ PQRYRES ODBCPrimaryKeys(PGLOBAL g, ODBConn *op, char *dsn, char *table) PQRYRES ODBCStatistics(PGLOBAL g, ODBConn *op, char *dsn, char *pat, int un, int acc) { - static int dbtype[] = {DB_CHAR, DB_CHAR, DB_CHAR, DB_SHORT, DB_CHAR, - DB_CHAR, DB_SHORT, DB_SHORT, DB_CHAR, DB_CHAR, - DB_INT, DB_INT, DB_CHAR}; static int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_STRING, TYPE_SHORT, TYPE_SHORT, TYPE_STRING, @@ -708,7 +695,7 @@ PQRYRES ODBCStatistics(PGLOBAL g, ODBConn *op, char *dsn, char *pat, /* Allocate the structure used to refer to the result set. */ /************************************************************************/ qrp = PlgAllocResult(g, ncol, maxres, IDS_STAT, - dbtype, buftyp, NULL, length, true, true); + buftyp, NULL, length, true, true); if (trace) htrc("Getting stat results ncol=%d\n", qrp->Nbcol); diff --git a/storage/connect/osutil.c b/storage/connect/osutil.c index 45c834a4cfc..1b7332357e6 100644 --- a/storage/connect/osutil.c +++ b/storage/connect/osutil.c @@ -142,10 +142,12 @@ my_bool CloseFileHandle(HANDLE h) return (close(h)) ? TRUE : FALSE; } /* end of CloseFileHandle */ +#if 0 void Sleep(DWORD time) { //FIXME: TODO } /* end of Sleep */ +#endif int GetLastError() { @@ -213,6 +215,7 @@ int _isatty(int fileNo) return isatty(fileNo); } /* end of _isatty */ +#if 0 /* This function is ridiculous and should be revisited */ DWORD FormatMessage(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize, ...) @@ -227,5 +230,6 @@ DWORD FormatMessage(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, strncpy(lpBuffer, buff, nSize); return min(n, nSize); } /* end of FormatMessage */ +#endif #endif // UNIX diff --git a/storage/connect/osutil.h b/storage/connect/osutil.h index 440373dd7a1..63a3e18084c 100644 --- a/storage/connect/osutil.h +++ b/storage/connect/osutil.h @@ -32,44 +32,6 @@ char *_fullpath(char *absPath, const char *relPath, size_t maxLength); BOOL MessageBeep(uint); unsigned long _filelength(int fd); -void PROFILE_Close(LPCSTR filename); - -int GetPrivateProfileString( - LPCTSTR lpAppName, // section name - LPCTSTR lpKeyName, // key name - LPCTSTR lpDefault, // default string - LPTSTR lpReturnedString, // destination buffer - int nSize, // size of destination buffer - LPCTSTR lpFileName // initialization file name - ); - -uint GetPrivateProfileInt( - LPCTSTR lpAppName, // section name - LPCTSTR lpKeyName, // key name - INT nDefault, // return value if key name not found - LPCTSTR lpFileName // initialization file name - ); - -BOOL WritePrivateProfileString( - LPCTSTR lpAppName, // section name - LPCTSTR lpKeyName, // key name - LPCTSTR lpString, // string to add - LPCTSTR lpFileName // initialization file - ); - -int GetPrivateProfileSection( - LPCTSTR lpAppName, // section name - LPTSTR lpReturnedString, // return buffer - int nSize, // size of return buffer - LPCTSTR lpFileName // initialization file name - ); - -BOOL WritePrivateProfileSection( - LPCTSTR lpAppName, // section name - LPCTSTR lpString, // data - LPCTSTR lpFileName // file name - ); - PSZ strupr(PSZ s); PSZ strlwr(PSZ s); @@ -90,12 +52,14 @@ typedef __int64 FILEPOS; #define XSTR(x) ((x)?(x):"<null>") + #ifdef __cplusplus extern "C" { #endif - +my_bool CloseFileHandle(HANDLE h); #ifdef __cplusplus } #endif + #endif /* __OSUTIL_H__ */ diff --git a/storage/connect/plgcnx.h b/storage/connect/plgcnx.h index 33b0ba64edc..7ce72b45268 100644 --- a/storage/connect/plgcnx.h +++ b/storage/connect/plgcnx.h @@ -50,17 +50,6 @@ enum RCODE {RC_OK = 0, /* No error return code */ #endif // !RC_OK_DEFINED /**************************************************************************/ -/* Data types. */ -/**************************************************************************/ -enum XDBTYPE {DB_ERROR = 0, /* Unknown or wrong type */ - DB_STRING = 1, /* Null terminated string */ - DB_CHAR = 2, /* Character array */ - DB_SHORT = 3, /* Used by some catalog functions */ - DB_INT = 4, /* Long integer array */ - DB_DOUBLE = 5, /* Double float array */ - DB_DATE = 6}; /* Datetime value array */ - -/**************************************************************************/ /* Index of info values within the info int integer array. */ /**************************************************************************/ enum INFO {INDX_RC, /* Index of PlugDB return code field */ diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h index 611b0067e18..919f3452a4d 100644 --- a/storage/connect/plgdbsem.h +++ b/storage/connect/plgdbsem.h @@ -24,8 +24,8 @@ #define DOS_BUFF_LEN 100 /* Number of lines in binary file buffer */ #undef DOMAIN /* For Unix version */ -enum BLKTYP {TYPE_TABLE = 50, /* Table Name/Correl Block */ - TYPE_COLUMN = 51, /* Column Name/Correl Block */ +enum BLKTYP {TYPE_TABLE = 50, /* Table Name/Srcdef/... Block */ + TYPE_COLUMN = 51, /* Column Name/Qualifier Block */ // TYPE_OPVAL = 52, /* Operator value (OPVAL) */ TYPE_TDB = 53, /* Table Description Block */ TYPE_COLBLK = 54, /* Column Description Block */ @@ -69,12 +69,14 @@ enum TABTYPE {TAB_UNDEF = 0, /* Table of undefined type */ TAB_WMI = 14, /* WMI tables (Windows only) */ TAB_TBL = 15, /* Collection of CONNECT tables */ TAB_OEM = 16, /* OEM implemented table */ - TAB_CATLG = 17, /* Catalog table */ - TAB_PLG = 18, /* PLG NIY */ - TAB_PIVOT = 19, /* PIVOT NIY */ - TAB_JCT = 20, /* Junction tables NIY */ - TAB_DMY = 21, /* DMY Dummy tables NIY */ - TAB_NIY = 22}; /* Table not implemented yet */ + TAB_XCL = 17, /* XCL table */ + TAB_OCCUR = 18, /* OCCUR table */ + TAB_PRX = 19, /* Proxy (catalog) table */ + TAB_PLG = 20, /* PLG NIY */ + TAB_PIVOT = 21, /* PIVOT NIY */ + TAB_JCT = 22, /* Junction tables NIY */ + TAB_DMY = 23, /* DMY Dummy tables NIY */ + TAB_NIY = 24}; /* Table not implemented yet */ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */ TYPE_AM_ROWID = 1, /* ROWID type (special column) */ @@ -511,12 +513,12 @@ typedef struct _colres { PVBLK Kdata; /* Column block of values */ char *Nulls; /* Column null value array */ int Type; /* Internal type */ - int DBtype; /* Data type */ int Datasize; /* Overall data size */ int Ncol; /* Column number */ int Clen; /* Data individual internal size */ int Length; /* Data individual print length */ int Prec; /* Precision */ + int Flag; /* Flag option value */ XFLD Fld; /* Type of field info */ } COLRES; @@ -543,7 +545,7 @@ int ExtractDate(char *, PDTP, int, int val[6]); /* Allocate the result structure that will contain result data. */ /**************************************************************************/ PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids, - int *dbtype, int *buftyp, XFLD *fldtyp, + int *buftyp, XFLD *fldtyp, unsigned int *length, bool blank, bool nonull); /***********************************************************************/ @@ -576,5 +578,6 @@ DllExport void NewPointer(PTABS, void *, void *); FILE *global_fopen(GLOBAL *g, int msgid, const char *path, const char *mode); int global_open(GLOBAL *g, int msgid, const char *filename, int flags); int global_open(GLOBAL *g, int msgid, const char *filename, int flags, int mode); +DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir); bool PushWarning(PGLOBAL, PTDBASE); diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp index 6d1e502945b..73b468c9209 100644 --- a/storage/connect/plgdbutl.cpp +++ b/storage/connect/plgdbutl.cpp @@ -67,6 +67,7 @@ #include "xtable.h" // header of TBX, TDB and TDBASE classes #include "tabcol.h" // header of XTAB and COLUMN classes #include "valblk.h" +#include "rcmsg.h" /***********************************************************************/ /* Macro or external routine definition */ @@ -129,7 +130,6 @@ void CloseXMLFile(PGLOBAL, PFBLOCK, bool); void CloseXML2File(PGLOBAL, PFBLOCK, bool); #endif // LIBXML2_SUPPORT -extern "C" int GetRcString(int id, char *buf, int bufsize); /***********************************************************************/ /* Routines for file IO with error reporting to g->Message */ @@ -270,7 +270,7 @@ void ptrc(char const *fmt, ...) /* Allocate the result structure that will contain result data. */ /**************************************************************************/ PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids, - int *dbtype, int *buftyp, XFLD *fldtyp, + int *buftyp, XFLD *fldtyp, unsigned int *length, bool blank, bool nonull) { char cname[NAM_LEN+1]; @@ -298,13 +298,13 @@ PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids, *pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES)); crp = *pcrp; pcrp = &crp->Next; + memset(crp, 0, sizeof(COLRES)); crp->Colp = NULL; crp->Ncol = ++qrp->Nbcol; crp->Type = buftyp[i]; crp->Length = length[i]; crp->Clen = GetTypeSize(crp->Type, length[i]); crp->Prec = 0; - crp->DBtype = dbtype[i]; if (ids > 0) { #if defined(XMSG) @@ -520,6 +520,7 @@ bool PlgSetXdbPath(PGLOBAL g, PSZ dbname, PSZ dbpath, /* Extract from a path name the required component. */ /* This function assumes there is enough space in the buffer. */ /***********************************************************************/ +#if 0 char *ExtractFromPath(PGLOBAL g, char *pBuff, char *FileName, OPVAL op) { char *drive = NULL, *direc = NULL, *fname = NULL, *ftype = NULL; @@ -540,13 +541,14 @@ char *ExtractFromPath(PGLOBAL g, char *pBuff, char *FileName, OPVAL op) _splitpath(FileName, drive, direc, fname, ftype); return pBuff; } // end of PlgExtractFromPath +#endif /***********************************************************************/ /* Check the occurence and matching of a pattern against a string. */ /* Because this function is only used for catalog name checking, */ /* it must be case insensitive. */ /***********************************************************************/ -bool PlugCheckPattern(PGLOBAL g, LPCSTR string, LPCSTR pat) +static bool PlugCheckPattern(PGLOBAL g, LPCSTR string, LPCSTR pat) { if (pat && strlen(pat)) { // This leaves 512 bytes (MAX_STR / 2) for each components diff --git a/storage/connect/plugutil.c b/storage/connect/plugutil.c index 693ae96cf52..e8098bb2512 100644 --- a/storage/connect/plugutil.c +++ b/storage/connect/plugutil.c @@ -107,7 +107,7 @@ ACTIVITY defActivity = { /* Describes activity and language */ #endif // XMSG || NEWMSG #if defined(UNIX) || defined(UNIV_LINUX) -int GetRcString(int id, char *buf, int bufsize); +#include "rcmsg.h" #endif // UNIX /**************************************************************************/ @@ -147,6 +147,7 @@ PGLOBAL PlugInit(LPCSTR Language, uint worksize) if (!(g = malloc(sizeof(GLOBAL)))) { fprintf(stderr, MSG(GLOBAL_ERROR), (int)sizeof(GLOBAL)); + return NULL; } else { g->Sarea_Size = worksize; g->Trace = 0; @@ -180,7 +181,9 @@ int PlugExit(PGLOBAL g) if (!g) return rc; - free(g->Sarea); + if (g->Sarea) + free(g->Sarea); + free(g); return rc; } /* end of PlugExit */ @@ -216,11 +219,23 @@ LPSTR PlugRemoveType(LPSTR pBuff, LPCSTR FileName) return pBuff; } // end of PlugRemoveType + +BOOL PlugIsAbsolutePath(LPCSTR path) +{ +#if defined(WIN32) + return ((path[0] >= 'a' && path[0] <= 'z') || + (path[0] >= 'A' && path[0] <= 'Z')) && path[1] == ':'; +#else + return path[0] == '/'; +#endif +} + + /***********************************************************************/ /* Set the full path of a file relatively to a given path. */ /* Note: this routine is not really implemented for Unix. */ /***********************************************************************/ -LPCSTR PlugSetPath(LPSTR pBuff, LPCSTR FileName, LPCSTR defpath) +LPCSTR PlugSetPath(LPSTR pBuff, LPCSTR prefix, LPCSTR FileName, LPCSTR defpath) { char newname[_MAX_PATH]; char direc[_MAX_DIR], defdir[_MAX_DIR]; @@ -237,6 +252,22 @@ LPCSTR PlugSetPath(LPSTR pBuff, LPCSTR FileName, LPCSTR defpath) return pBuff; } // endif + if (PlugIsAbsolutePath(FileName)) + { + strcpy(pBuff, FileName); // FileName includes absolute path + return pBuff; + } // endif + + if (strcmp(prefix, ".") && !PlugIsAbsolutePath(defpath)) + { + char tmp[_MAX_PATH]; + int len= snprintf(tmp, sizeof(tmp) - 1, "%s%s%s", + prefix, defpath, FileName); + memcpy(pBuff, tmp, (size_t) len); + pBuff[len]= '\0'; + return pBuff; + } + _splitpath(FileName, drive, direc, fname, ftype); _splitpath(defpath, defdrv, defdir, NULL, NULL); @@ -491,9 +522,10 @@ void *MakePtr(void *memp, OFFSET offset) /***********************************************************************/ /* This routine makes an offset from a pointer new format. */ /***********************************************************************/ +#if 0 OFFSET MakeOff(void *memp, void *ptr) { return ((!ptr) ? 0 : (OFFSET)((char *)ptr - (char *)memp)); } /* end of MakeOff */ - +#endif /*--------------------- End of PLUGUTIL program -----------------------*/ diff --git a/storage/connect/rcmsg.c b/storage/connect/rcmsg.c index e1a71cde9c6..0c63fd55242 100644 --- a/storage/connect/rcmsg.c +++ b/storage/connect/rcmsg.c @@ -14,6 +14,7 @@ /***********************************************************************/ #include <stdio.h> #include "resource.h" +#include "rcmsg.h" char *GetMsgid(int id) { diff --git a/storage/connect/rcmsg.h b/storage/connect/rcmsg.h new file mode 100644 index 00000000000..b22e77f5175 --- /dev/null +++ b/storage/connect/rcmsg.h @@ -0,0 +1,15 @@ +#ifndef __RCMSG_H__ +#define __RCMSG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +char *GetMsgid(int id); +int GetRcString(int id, char *buf, int bufsize); + +#ifdef __cplusplus +} +#endif + +#endif /* __RCMSG_H__ */ diff --git a/storage/connect/reldef.cpp b/storage/connect/reldef.cpp index 77f2f43ec31..8525fd09cbc 100644 --- a/storage/connect/reldef.cpp +++ b/storage/connect/reldef.cpp @@ -90,11 +90,9 @@ TABDEF::TABDEF(void) /***********************************************************************/ bool TABDEF::Define(PGLOBAL g, PCATLG cat, LPCSTR name, LPCSTR am) { -//char buf[8]; int poff = 0; - void *memp = cat->Descp; - Name = (PSZ)PlugSubAlloc(g, memp, strlen(name) + 1); + Name = (PSZ)PlugSubAlloc(g, NULL, strlen(name) + 1); strcpy(Name, name); Cat = cat; Catfunc = GetFuncID(Cat->GetStringCatInfo(g, "Catfunc", NULL)); @@ -127,7 +125,6 @@ PTABDEF OEMDEF::GetXdef(PGLOBAL g) PTABDEF xdefp; XGETDEF getdef = NULL; PCATLG cat = Cat; - void *memp = cat->Descp; #if defined(WIN32) // Is the DLL already loaded? @@ -189,7 +186,7 @@ PTABDEF OEMDEF::GetXdef(PGLOBAL g) sprintf(g->Message, MSG(DEF_ALLOC_ERROR), Subtype); // Get the table definition block - if (!(xdefp = getdef(g, memp))) + if (!(xdefp = getdef(g, NULL))) return NULL; // Have the external class do its complete definition @@ -223,15 +220,13 @@ bool OEMDEF::DeleteTableFile(PGLOBAL g) /***********************************************************************/ bool OEMDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) { - void *memp = Cat->Descp; - Module = Cat->GetStringCatInfo(g, "Module", ""); Subtype = Cat->GetStringCatInfo(g, "Subtype", Module); if (!*Module) Module = Subtype; - Desc = (char*)PlugSubAlloc(g, memp, strlen(Module) + Desc = (char*)PlugSubAlloc(g, NULL, strlen(Module) + strlen(Subtype) + 3); sprintf(Desc, "%s(%s)", Module, Subtype); return false; @@ -304,7 +299,7 @@ PTDB OEMDEF::GetTable(PGLOBAL g, MODE mode) else txfp = new(g) DOSFAM(defp); - } else if (rfm == RECFM_FIX || rfm == RECFM_FIX) { + } else if (rfm == RECFM_FIX || rfm == RECFM_BIN) { if (map) txfp = new(g) MPXFAM(defp); else diff --git a/storage/connect/tabcol.cpp b/storage/connect/tabcol.cpp index f0e010291c3..9af52043f0c 100644 --- a/storage/connect/tabcol.cpp +++ b/storage/connect/tabcol.cpp @@ -1,7 +1,7 @@ /************* TabCol C++ Functions Source Code File (.CPP) ************/ -/* Name: TABCOL.CPP Version 2.6 */ +/* Name: TABCOL.CPP Version 2.7 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */ +/* (C) Copyright to the author Olivier BERTRAND 1998-2013 */ /* */ /* This file contains the PlugDB++ XTAB, COLUMN and XORDER methods. */ /***********************************************************************/ @@ -23,18 +23,18 @@ #include "tabcol.h" /***********************************************************************/ -/* XTAB public constructor (in which Correl defaults to Name). */ +/* XTAB public constructor. */ /***********************************************************************/ -XTAB::XTAB(LPCSTR name, LPCSTR correl) : Name(name) +XTAB::XTAB(LPCSTR name, LPCSTR srcdef) : Name(name) { Next = NULL; To_Tdb = NULL; - Correl = (correl) ? correl : name; + Srcdef = srcdef; Creator = NULL; Qualifier = NULL; #ifdef DEBTRACE - htrc(" making new TABLE %s %s\n", Name, Correl); + htrc(" making new TABLE %s %s\n", Name, Srcdef); #endif } // end of XTAB constructor @@ -45,12 +45,12 @@ XTAB::XTAB(PTABLE tp) : Name(tp->Name) { Next = NULL; To_Tdb = NULL; - Correl = tp->Correl; + Srcdef = tp->Srcdef; Creator = tp->Creator; Qualifier = tp->Qualifier; #ifdef DEBTRACE - htrc(" making copy TABLE %s %s\n", Name, Correl); + htrc(" making copy TABLE %s %s\n", Name, Srcdef); #endif } // end of XTAB constructor @@ -83,7 +83,7 @@ void XTAB::Print(PGLOBAL g, FILE *f, uint n) for (PTABLE tp = this; tp; tp = tp->Next) { fprintf(f, "%sTABLE: %s.%s %s\n", - m, SVP(tp->Creator), tp->Name, SVP(tp->Correl)); + m, SVP(tp->Creator), tp->Name, SVP(tp->Srcdef)); PlugPutOut(g, f, TYPE_TDB, tp->To_Tdb, n + 2); } /* endfor tp */ @@ -101,7 +101,7 @@ void XTAB::Print(PGLOBAL g, char *ps, uint z) for (PTABLE tp = this; tp && n > 0; tp = tp->Next) { i = sprintf(buf, "TABLE: %s.%s %s To_Tdb=%p ", - SVP(tp->Creator), tp->Name, SVP(tp->Correl), tp->To_Tdb); + SVP(tp->Creator), tp->Name, SVP(tp->Srcdef), tp->To_Tdb); strncat(ps, buf, n); n -= i; } // endif tp diff --git a/storage/connect/tabcol.h b/storage/connect/tabcol.h index 5cc2050f872..c5ebfdbb10d 100644 --- a/storage/connect/tabcol.h +++ b/storage/connect/tabcol.h @@ -1,7 +1,7 @@ /*************** TabCol H Declares Source Code File (.H) ***************/ -/* Name: TABCOL.H Version 2.7 */ +/* Name: TABCOL.H Version 2.8 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */ +/* (C) Copyright to the author Olivier BERTRAND 1998-2013 */ /* */ /* This file contains the XTAB, COLUMN and XORDER class definitions. */ /***********************************************************************/ @@ -15,22 +15,24 @@ /***********************************************************************/ /* Definition of class XTAB with all its method functions. */ /***********************************************************************/ - class DllExport XTAB: public BLOCK { // Table Name-Owner-Correl block. +class DllExport XTAB: public BLOCK { // Table Name-Owner-Srcdef block. + friend class TDBPRX; + friend class TDBTBM; public: // Constructors - XTAB(LPCSTR name, LPCSTR correl = NULL); + XTAB(LPCSTR name, LPCSTR srcdef = NULL); XTAB(PTABLE tp); // Implementation PTABLE GetNext(void) {return Next;} PTDB GetTo_Tdb(void) {return To_Tdb;} LPCSTR GetName(void) {return Name;} - LPCSTR GetCorrel(void) {return Correl;} + LPCSTR GetSrc(void) {return Srcdef;} LPCSTR GetCreator(void) {return Creator;} LPCSTR GetQualifier(void) {return Qualifier;} void SetTo_Tdb(PTDB tdbp) {To_Tdb = tdbp;} void SetName(LPCSTR name) {Name = name;} - void SetCorrel(LPCSTR correl) {Correl = correl;} + void SetSrc(LPCSTR srcdef) {Srcdef = srcdef;} void SetCreator(LPCSTR crname) {Creator = crname;} void SetQualifier(LPCSTR qname) {Qualifier = qname;} @@ -43,8 +45,8 @@ // Members PTABLE Next; // Points to next table in chain PTDB To_Tdb; // Points to Table description Block - LPCSTR Name; // Table name (can be changed by LNA and PLG) - LPCSTR Correl; // Correlation name + LPCSTR Name; // Table name + LPCSTR Srcdef; // Table Source definition LPCSTR Creator; // Creator name LPCSTR Qualifier; // Qualifier name }; // end of class XTAB @@ -85,7 +87,6 @@ class DllExport COLUMN: public XOBJECT { // Column Name/Qualifier block. virtual bool Eval(PGLOBAL) {assert(false); return true;} virtual int CheckSpcCol(PTDB, int) {assert(false); return 2;} virtual bool CheckSort(PTDB) {assert(false); return false;} - virtual void MarkCol(ushort) {assert(false);} private: // Members diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp index 51631107f6e..860a1304a14 100644 --- a/storage/connect/tabfmt.cpp +++ b/storage/connect/tabfmt.cpp @@ -78,8 +78,6 @@ extern "C" int trace; PQRYRES CSVColumns(PGLOBAL g, const char *fn, char sep, char q, int hdr, int mxr, bool info) { - static int dbtype[] = {DB_CHAR, DB_SHORT, DB_CHAR, - DB_INT, DB_INT, DB_SHORT}; static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT}; static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, @@ -87,7 +85,7 @@ PQRYRES CSVColumns(PGLOBAL g, const char *fn, char sep, char q, static unsigned int length[] = {6, 6, 8, 10, 10, 6}; char *p, *colname[MAXCOL], dechar, filename[_MAX_PATH], buf[4096]; int i, imax, hmax, n, nerr, phase, blank, digit, dec, type; - int ncol = sizeof(dbtype) / sizeof(int); + int ncol = sizeof(buftyp) / sizeof(int); int num_read = 0, num_max = 10000000; // Statistics int len[MAXCOL], typ[MAXCOL], prc[MAXCOL]; FILE *infile; @@ -341,7 +339,7 @@ PQRYRES CSVColumns(PGLOBAL g, const char *fn, char sep, char q, /* Allocate the structures used to refer to the result set. */ /*********************************************************************/ qrp = PlgAllocResult(g, ncol, imax, IDS_COLUMNS + 3, - dbtype, buftyp, fldtyp, length, true, false); + buftyp, fldtyp, length, true, false); qrp->Nblin = imax; if (info) @@ -1090,7 +1088,12 @@ bool TDBFMT::OpenDB(PGLOBAL g) { Linenum = 0; - if (Use != USE_OPEN && (Columns || Mode == MODE_UPDATE)) { + if (Mode == MODE_INSERT || Mode == MODE_UPDATE) { + sprintf(g->Message, MSG(FMT_WRITE_NIY), "FMT"); + return true; // NIY + } // endif Mode + + if (Use != USE_OPEN && Columns) { // Make the formats used to read records PSZ pfm; int i, n; @@ -1098,17 +1101,12 @@ bool TDBFMT::OpenDB(PGLOBAL g) PCOLDEF cdp; PDOSDEF tdp = (PDOSDEF)To_Def; -// if (Mode != MODE_UPDATE) { - for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next) - if (!colp->IsSpecial()) // Not a pseudo column - Fields = max(Fields, (int)colp->Fldnum); - - if (Columns) - Fields++; // Fldnum was 0 based + for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next) + if (!colp->IsSpecial()) // Not a pseudo column + Fields = max(Fields, (int)colp->Fldnum); -// } else -// for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) -// Fields++; + if (Columns) + Fields++; // Fldnum was 0 based To_Fld = PlugSubAlloc(g, NULL, Lrecl + 1); FldFormat = (PSZ*)PlugSubAlloc(g, NULL, sizeof(PSZ) * Fields); diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp index 7b38cc8ab1b..1a19b4cbf33 100644 --- a/storage/connect/tabmysql.cpp +++ b/storage/connect/tabmysql.cpp @@ -57,12 +57,14 @@ #include "reldef.h" #include "tabmysql.h" #include "valblk.h" +#include "tabutil.h" #if defined(_CONSOLE) void PrintResult(PGLOBAL, PSEM, PQRYRES); #endif // _CONSOLE extern "C" int trace; +extern MYSQL_PLUGIN_IMPORT uint mysqld_port; /* -------------- Implementation of the MYSQLDEF class --------------- */ @@ -75,9 +77,11 @@ MYSQLDEF::MYSQLDEF(void) Hostname = NULL; Database = NULL; Tabname = NULL; + Srcdef = NULL; Username = NULL; Password = NULL; Portnumber = 0; + Isview = FALSE; Bind = FALSE; Delayed = FALSE; } // end of MYSQLDEF constructor @@ -243,10 +247,13 @@ bool MYSQLDEF::ParseURL(PGLOBAL g, char *url) if ((sport = strchr(Hostname, ':'))) *sport++ = 0; - Portnumber = (sport && sport[0]) ? atoi(sport) : MYSQL_PORT; + Portnumber = (sport && sport[0]) ? atoi(sport) : mysqld_port; + + if (Username[0] == 0) + Username = Cat->GetStringCatInfo(g, "User", "*"); if (Hostname[0] == 0) - Hostname = "localhost"; + Hostname = Cat->GetStringCatInfo(g, "Host", "localhost"); if (!Database || !*Database) Database = Cat->GetStringCatInfo(g, "Database", "*"); @@ -276,20 +283,39 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) Desc = "MySQL Table"; - if (!url || !*url) { - // Not using the connection URL - Hostname = Cat->GetStringCatInfo(g, "Host", "localhost"); + if (stricmp(am, "MYPRX")) { + // Normal case of specific MYSQL table + if (!url || !*url) { + // Not using the connection URL + Hostname = Cat->GetStringCatInfo(g, "Host", "localhost"); + Database = Cat->GetStringCatInfo(g, "Database", "*"); + Tabname = Cat->GetStringCatInfo(g, "Name", Name); // Deprecated + Tabname = Cat->GetStringCatInfo(g, "Tabname", Tabname); + Username = Cat->GetStringCatInfo(g, "User", "*"); + Password = Cat->GetStringCatInfo(g, "Password", NULL); + Portnumber = Cat->GetIntCatInfo("Port", mysqld_port); + } else if (ParseURL(g, url)) + return TRUE; + + Bind = !!Cat->GetIntCatInfo("Bind", 0); + Delayed = !!Cat->GetIntCatInfo("Delayed", 0); + } else { + // MYSQL access from a PROXY table, not using URL Database = Cat->GetStringCatInfo(g, "Database", "*"); - Tabname = Cat->GetStringCatInfo(g, "Name", Name); // Deprecated - Tabname = Cat->GetStringCatInfo(g, "Tabname", Tabname); - Username = Cat->GetStringCatInfo(g, "User", "root"); + Tabname = Name; + Isview = Cat->GetBoolCatInfo("View", FALSE); + + // We must get connection parms from the calling table + Remove_tshp(Cat); + Hostname = Cat->GetStringCatInfo(g, "Host", "localhost"); + Username = Cat->GetStringCatInfo(g, "User", "*"); Password = Cat->GetStringCatInfo(g, "Password", NULL); - Portnumber = Cat->GetIntCatInfo("Port", MYSQL_PORT); - } else if (ParseURL(g, url)) - return TRUE; + Portnumber = Cat->GetIntCatInfo("Port", mysqld_port); + } // endif am + + if ((Srcdef = Cat->GetStringCatInfo(g, "Srcdef", NULL))) + Isview = TRUE; - Bind = !!Cat->GetIntCatInfo("Bind", 0); - Delayed = !!Cat->GetIntCatInfo("Delayed", 0); return FALSE; } // end of DefineAM @@ -316,18 +342,22 @@ TDBMYSQL::TDBMYSQL(PMYDEF tdp) : TDBASE(tdp) Host = tdp->GetHostname(); Database = tdp->GetDatabase(); Tabname = tdp->GetTabname(); + Srcdef = tdp->GetSrcdef(); User = tdp->GetUsername(); Pwd = tdp->GetPassword(); Port = tdp->GetPortnumber(); + Isview = tdp->Isview; Prep = tdp->Bind; Delayed = tdp->Delayed; } else { Host = NULL; Database = NULL; Tabname = NULL; + Srcdef = NULL; User = NULL; Pwd = NULL; Port = 0; + Isview = FALSE; Prep = FALSE; Delayed = FALSE; } // endif tdp @@ -347,9 +377,11 @@ TDBMYSQL::TDBMYSQL(PGLOBAL g, PTDBMY tdbp) : TDBASE(tdbp) Host = tdbp->Host; Database = tdbp->Database; Tabname = tdbp->Tabname; + Srcdef = tdbp->Srcdef; User = tdbp->User; Pwd = tdbp->Pwd; Port = tdbp->Port; + Isview = tdbp->Isview; Prep = tdbp->Prep; Delayed = tdbp->Delayed; Bind = NULL; @@ -395,55 +427,54 @@ PCOL TDBMYSQL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) /***********************************************************************/ bool TDBMYSQL::MakeSelect(PGLOBAL g) { - char *colist; char *tk = "`"; - int len = 0, ncol = 0, rank = 0; + int rank = 0; bool b = FALSE; PCOL colp; - PDBUSER dup = PlgGetUser(g); +//PDBUSER dup = PlgGetUser(g); if (Query) return FALSE; // already done - for (colp = Columns; colp; colp = colp->GetNext()) - ncol++; + if (Srcdef) { + Query = Srcdef; + return false; + } // endif Srcdef - if (ncol) { - colist = (char*)PlugSubAlloc(g, NULL, (NAM_LEN + 4) * ncol); - *colist = '\0'; + //Find the address of the suballocated query + Query = (char*)PlugSubAlloc(g, NULL, 0); + strcpy(Query, "SELECT "); + if (Columns) { for (colp = Columns; colp; colp = colp->GetNext()) if (colp->IsSpecial()) { strcpy(g->Message, MSG(NO_SPEC_COL)); return TRUE; } else { if (b) - strcat(colist, ", "); + strcat(Query, ", "); else b = TRUE; - strcat(strcat(strcat(colist, tk), colp->GetName()), tk); + strcat(strcat(strcat(Query, tk), colp->GetName()), tk); ((PMYCOL)colp)->Rank = rank++; } // endif colp } else { - // ncol == 0 can occur for queries such as Query count(*) from... - // for which we will count the rows from Query '*' from... + // ncol == 0 can occur for views or queries such as + // Query count(*) from... for which we will count the rows from + // Query '*' from... // (the use of a char constant minimize the result storage) - colist = (char*)PlugSubAlloc(g, NULL, 2); - strcpy(colist, "'*'"); + strcat(Query, (Isview) ? "*" : "'*'"); } // endif ncol - // Below 32 is space to contain extra stuff - len += (strlen(colist) + strlen(Tabname) + 32); - len += (To_Filter ? strlen(To_Filter) + 7 : 0); - Query = (char*)PlugSubAlloc(g, NULL, len); - strcat(strcpy(Query, "SELECT "), colist); strcat(strcat(strcat(strcat(Query, " FROM "), tk), Tabname), tk); if (To_Filter) strcat(strcat(Query, " WHERE "), To_Filter); + // Now we know how much to suballocate + PlugSubAlloc(g, NULL, strlen(Query) + 1); return FALSE; } // end of MakeSelect @@ -728,7 +759,7 @@ bool TDBMYSQL::OpenDB(PGLOBAL g) /* Table already open, just replace it at its beginning. */ /*******************************************************************/ Myc.Rewind(); - return FALSE; + return false; } // endif use /*********************************************************************/ @@ -740,7 +771,7 @@ bool TDBMYSQL::OpenDB(PGLOBAL g) /*********************************************************************/ if (!Myc.Connected()) { if (Myc.Open(g, Host, Database, User, Pwd, Port)) - return TRUE; + return true; } // endif Connected @@ -751,7 +782,24 @@ bool TDBMYSQL::OpenDB(PGLOBAL g) if (!MakeSelect(g)) m_Rc = Myc.ExecSQL(g, Query); +#if 0 + if (!Myc.m_Res || !Myc.m_Fields) { + sprintf(g->Message, "%s result", (Myc.m_Res) ? "Void" : "No"); + Myc.Close(); + return true; + } // endif m_Res +#endif // 0 + + if (!m_Rc && Srcdef) + if (SetColumnRanks(g)) + return true; + } else if (Mode == MODE_INSERT) { + if (Srcdef) { + strcpy(g->Message, "No insert into anonym views"); + return true; + } // endif Srcdef + if (!MakeInsert(g)) { #if defined(MYSQL_PREPARED_STATEMENTS) int n = (Prep) ? Myc.PrepareSQL(g, Query) : Nparm; @@ -804,6 +852,78 @@ bool TDBMYSQL::OpenDB(PGLOBAL g) } // end of OpenDB /***********************************************************************/ +/* Set the rank of columns in the result set. */ +/***********************************************************************/ +bool TDBMYSQL::SetColumnRanks(PGLOBAL g) + { + for (PCOL colp = Columns; colp; colp = colp->GetNext()) + if (((PMYCOL)colp)->FindRank(g)) + return TRUE; + + return FALSE; + } // end of SetColumnRanks + +/***********************************************************************/ +/* Called by Parent table to make the columns of a View. */ +/***********************************************************************/ +PCOL TDBMYSQL::MakeFieldColumn(PGLOBAL g, char *name) + { + int n; + MYSQL_FIELD *fld; + PCOL cp, colp = NULL; + + for (n = 0; n < Myc.m_Fields; n++) { + fld = &Myc.m_Res->fields[n]; + + if (!stricmp(name, fld->name)) { + colp = new(g) MYSQLCOL(fld, this, n); + + if (colp->InitValue(g)) + return NULL; + + if (!Columns) + Columns = colp; + else for (cp = Columns; cp; cp = cp->GetNext()) + if (!cp->GetNext()) { + cp->SetNext(colp); + break; + } // endif Next + + break; + } // endif name + + } // endfor n + + if (!colp) + sprintf(g->Message, "Column %s is not in view", name); + + return colp; + } // end of MakeFieldColumn + +/***********************************************************************/ +/* Called by Pivot tables to find default column names in a View */ +/* as the name of last field not equal to the passed name. */ +/***********************************************************************/ +char *TDBMYSQL::FindFieldColumn(char *name) + { + int n; + MYSQL_FIELD *fld; + char *cp = NULL; + + for (n = Myc.m_Fields - 1; n >= 0; n--) { + fld = &Myc.m_Res->fields[n]; + + if (!name || stricmp(name, fld->name)) { + cp = fld->name; + break; + } // endif name + + } // endfor n + + return cp; + } // end of FindFieldColumn + +/***********************************************************************/ /* Data Base read routine for MYSQL access method. */ /***********************************************************************/ int TDBMYSQL::ReadDB(PGLOBAL g) @@ -916,7 +1036,7 @@ MYSQLCOL::MYSQLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am) tdbp->SetColumns(this); } // endif cprec - // Set additional Dos access method information for column. + // Set additional MySQL access method information for column. Long = cdp->GetLong(); Bind = NULL; To_Val = NULL; @@ -929,6 +1049,33 @@ MYSQLCOL::MYSQLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am) } // end of MYSQLCOL constructor /***********************************************************************/ +/* MYSQLCOL public constructor. */ +/***********************************************************************/ +MYSQLCOL::MYSQLCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PSZ am) + : COLBLK(NULL, tdbp, i) + { + Name = fld->name; + Opt = 0; + Long = fld->length; + Buf_Type = MYSQLtoPLG(fld->type); + strcpy(Format.Type, GetFormatType(Buf_Type)); + Format.Length = Long; + Format.Prec = fld->decimals; + ColUse = U_P; + Nullable = !IS_NOT_NULL(fld->flags); + + // Set additional MySQL access method information for column. + Bind = NULL; + To_Val = NULL; + Slen = 0; + Rank = i; + + if (trace) + htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this); + + } // end of MYSQLCOL constructor + +/***********************************************************************/ /* MYSQLCOL constructor used for copying columns. */ /* tdbp is the pointer to the new table descriptor. */ /***********************************************************************/ @@ -942,6 +1089,24 @@ MYSQLCOL::MYSQLCOL(MYSQLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp) } // end of MYSQLCOL copy constructor /***********************************************************************/ +/* FindRank: Find the rank of this column in the result set. */ +/***********************************************************************/ +bool MYSQLCOL::FindRank(PGLOBAL g) +{ + int n; + MYSQLC myc = ((PTDBMY)To_Tdb)->Myc; + + for (n = 0; n < myc.m_Fields; n++) + if (!stricmp(Name, myc.m_Res->fields[n].name)) { + Rank = n; + return false; + } // endif Name + + sprintf(g->Message, "Column %s not in result set", Name); + return true; +} // end of FindRank + +/***********************************************************************/ /* SetBuffer: prepare a column block for write operation. */ /***********************************************************************/ bool MYSQLCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check) @@ -1026,11 +1191,6 @@ void MYSQLCOL::ReadColumn(PGLOBAL g) int rc; PTDBMY tdbp = (PTDBMY)To_Tdb; - if (trace) - htrc("MySQL ReadColumn: name=%s\n", Name); - - assert (Rank >= 0); - /*********************************************************************/ /* If physical fetching of the line was deferred, do it now. */ /*********************************************************************/ @@ -1043,14 +1203,17 @@ void MYSQLCOL::ReadColumn(PGLOBAL g) } else tdbp->Fetched = TRUE; - if ((buf = ((PTDBMY)To_Tdb)->Myc.GetCharField(Rank))) + if ((buf = ((PTDBMY)To_Tdb)->Myc.GetCharField(Rank))) { + if (trace) + htrc("MySQL ReadColumn: name=%s buf=%s\n", Name, buf); + Value->SetValue_char(buf, Long); - else { + } else { if (Nullable) Value->SetNull(true); Value->Reset(); // Null value - } // endelse + } // endif buf } // end of ReadColumn @@ -1098,5 +1261,5 @@ TDBMCL::TDBMCL(PMYDEF tdp) : TDBCAT(tdp) /***********************************************************************/ PQRYRES TDBMCL::GetResult(PGLOBAL g) { - return MyColumns(g, Host, Db, User, Pwd, Tab, NULL, Port, false, false); + return MyColumns(g, Host, Db, User, Pwd, Tab, NULL, Port, false); } // end of GetResult diff --git a/storage/connect/tabmysql.h b/storage/connect/tabmysql.h index 56d21550df6..24f8c4cdef2 100644 --- a/storage/connect/tabmysql.h +++ b/storage/connect/tabmysql.h @@ -30,6 +30,7 @@ class MYSQLDEF : public TABDEF {/* Logical table description */ inline PSZ GetHostname(void) {return Hostname;}; inline PSZ GetDatabase(void) {return Database;}; inline PSZ GetTabname(void) {return Tabname;} + inline PSZ GetSrcdef(void) {return Srcdef;} inline PSZ GetUsername(void) {return Username;}; inline PSZ GetPassword(void) {return Password;}; inline int GetPortnumber(void) {return Portnumber;} @@ -44,9 +45,11 @@ class MYSQLDEF : public TABDEF {/* Logical table description */ PSZ Hostname; /* Host machine to use */ PSZ Database; /* Database to be used by server */ PSZ Tabname; /* External table name */ + PSZ Srcdef; /* The source table SQL definition */ PSZ Username; /* User logon name */ PSZ Password; /* Password logon info */ int Portnumber; /* MySQL port number (0 = default) */ + bool Isview; /* TRUE if this table is a MySQL view */ bool Bind; /* Use prepared statement on insert */ bool Delayed; /* Delayed insert */ }; // end of MYSQLDEF @@ -72,6 +75,7 @@ class TDBMYSQL : public TDBASE { virtual int GetProgMax(PGLOBAL g); virtual void ResetDB(void) {N = 0;} virtual int RowNumber(PGLOBAL g, bool b = FALSE); + virtual bool IsView(void) {return Isview;} void SetDatabase(LPCSTR db) {Database = (char*)db;} // Database routines @@ -83,6 +87,11 @@ class TDBMYSQL : public TDBASE { virtual int DeleteDB(PGLOBAL g, int irc); virtual void CloseDB(PGLOBAL g); + // Specific routines + bool SetColumnRanks(PGLOBAL g); + PCOL MakeFieldColumn(PGLOBAL g, char *name); + PSZ FindFieldColumn(char *name); + protected: // Internal functions bool MakeSelect(PGLOBAL g); @@ -99,9 +108,11 @@ class TDBMYSQL : public TDBASE { char *Pwd; // Password logon info char *Database; // Database to be used by server char *Tabname; // External table name + char *Srcdef; // The source table SQL definition char *Query; // Points to SQL query - char *Qbuf; // Used for not prepared insert + char *Qbuf; // Used for not prepared insert bool Fetched; // True when fetch was done + bool Isview; // True if this table is a MySQL view bool Prep; // Use prepared statement on insert bool Delayed; // Use delayed insert int m_Rc; // Return code from command @@ -119,6 +130,7 @@ class MYSQLCOL : public COLBLK { public: // Constructors MYSQLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "MYSQL"); + MYSQLCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PSZ am = "MYSQL"); MYSQLCOL(MYSQLCOL *colp, PTDB tdbp); // Constructor used in copy process // Implementation @@ -129,6 +141,7 @@ class MYSQLCOL : public COLBLK { virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check); virtual void ReadColumn(PGLOBAL g); virtual void WriteColumn(PGLOBAL g); + bool FindRank(PGLOBAL g); protected: // Default constructor not to be used diff --git a/storage/connect/taboccur.cpp b/storage/connect/taboccur.cpp new file mode 100644 index 00000000000..065da269caa --- /dev/null +++ b/storage/connect/taboccur.cpp @@ -0,0 +1,592 @@ +/************ TabOccur CPP Declares Source Code File (.CPP) ************/ +/* Name: TABOCCUR.CPP Version 1.1 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2013 */ +/* */ +/* OCCUR: Table that provides a view of a source table where the */ +/* contain of several columns of the source table is placed in only */ +/* one column, the OCCUR column, this resulting into several rows. */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant section of system dependant header files. */ +/***********************************************************************/ +#include "my_global.h" +#if defined(WIN32) +#include <stdlib.h> +#include <stdio.h> +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif +//#include <windows.h> +#else +#if defined(UNIX) +#include <fnmatch.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "osutil.h" +#else +//#include <io.h> +#endif +//#include <fcntl.h> +#endif + +/***********************************************************************/ +/* Include application header files: */ +/***********************************************************************/ +#include "table.h" // MySQL table definitions +#include "global.h" +#include "plgdbsem.h" +#include "reldef.h" +#include "filamtxt.h" +#include "tabdos.h" +#include "tabcol.h" +#include "taboccur.h" +#include "xtable.h" +#if defined(MYSQL_SUPPORT) +#include "tabmysql.h" +#endif // MYSQL_SUPPORT +#include "ha_connect.h" +#include "mycat.h" + +extern "C" int trace; + +/***********************************************************************/ +/* Prepare and count columns in the column list. */ +/***********************************************************************/ +int PrepareColist(char *colist) + { + char *p, *pn; + int n = 0; + + // Count the number of columns and change separator into null char + for (pn = colist; ; pn += (strlen(pn) + 1)) + // Separator can be ; if colist was specified in the option_list + if ((p = strchr(pn, ',')) || (p = strchr(pn, ';'))) { + *p++ = '\0'; + n++; + } else { + if (*pn) + n++; + + break; + } // endif p + + return n; + } // end of PrepareColist + +/************************************************************************/ +/* OcrColumns: constructs the result blocks containing all the columns */ +/* of the object table that will be retrieved by GetData commands. */ +/************************************************************************/ +bool OcrColumns(PGLOBAL g, PQRYRES qrp, const char *col, + const char *ocr, const char *rank) + { + char *pn, *colist; + int i, k, m, n = 0, c = 0, j = qrp->Nblin; + bool rk, b = false; + PCOLRES crp; + + if (!col || !*col) { + strcpy(g->Message, "Missing colist"); + return true; + } // endif col + + // Prepare the column list + colist = (char*)PlugSubAlloc(g, NULL, strlen(col) + 1); + strcpy(colist, col); + m = PrepareColist(colist); + + if ((rk = (rank && *rank))) { + if (m == 1) { + strcpy(g->Message, "Cannot handle one column colist and rank"); + return true; + } // endif m + + for (k = 0, pn = colist; k < m; k++, pn += (strlen(pn) + 1)) + n = max(n, (signed)strlen(pn)); + + } // endif k + + // Default occur column name is the 1st colist column name + if (!ocr || !*ocr) + ocr = colist; + + /**********************************************************************/ + /* Replace the columns of the colist by the rank and occur columns. */ + /**********************************************************************/ + for (i = 0; i < qrp->Nblin; i++) { + for (k = 0, pn = colist; k < m; k++, pn += (strlen(pn) + 1)) + if (!stricmp(pn, qrp->Colresp->Kdata->GetCharValue(i))) + break; + + if (k < m) { + // This column belongs to colist + if (rk) { + // Place the rank column here + for (crp = qrp->Colresp; crp; crp = crp->Next) + switch (crp->Fld) { + case FLD_NAME: crp->Kdata->SetValue((char*)rank, i); break; + case FLD_TYPE: crp->Kdata->SetValue(TYPE_STRING, i); break; + case FLD_PREC: crp->Kdata->SetValue(n, i); break; + case FLD_SCALE: crp->Kdata->SetValue(0, i); break; + case FLD_NULL: crp->Kdata->SetValue(0, i); break; + case FLD_REM: crp->Kdata->Reset(i); break; + default: ; // Ignored by CONNECT + } // endswich Fld + + rk = false; + } else if (!b) { + // First remaining listed column, will be the occur column + for (crp = qrp->Colresp; crp; crp = crp->Next) + switch (crp->Fld) { + case FLD_NAME: crp->Kdata->SetValue((char*)ocr, i); break; + case FLD_REM: crp->Kdata->Reset(i); break; + default: ; // Nothing to do + } // endswich Fld + + b = true; + } else if (j == qrp->Nblin) + j = i; // Column to remove + + c++; + } else if (j < i) { + // Move this column in empty spot + for (crp = qrp->Colresp; crp; crp = crp->Next) + crp->Kdata->Move(i, j); + + j++; + } // endif k + + } // endfor i + + // Check whether all columns of the list where found + if (c < m) { + strcpy(g->Message, "Some colist columns are not in the source table"); + return true; + } // endif crp + + /**********************************************************************/ + /* Set the number of columns of the table. */ + /**********************************************************************/ + qrp->Nblin = j; + return false; + } // end of OcrColumns + +/************************************************************************/ +/* OcrSrcCols: constructs the result blocks containing all the columns */ +/* of the object table that will be retrieved by GetData commands. */ +/************************************************************************/ +bool OcrSrcCols(PGLOBAL g, PQRYRES qrp, const char *col, + const char *ocr, const char *rank) + { + char *pn, *colist; + int i, k, m, n = 0, c = 0; + bool rk, b = false; + PCOLRES crp, rcrp, *pcrp; + + if (!col || !*col) { + strcpy(g->Message, "Missing colist"); + return true; + } // endif col + + // Prepare the column list + colist = (char*)PlugSubAlloc(g, NULL, strlen(col) + 1); + strcpy(colist, col); + m = PrepareColist(colist); + + if ((rk = (rank && *rank))) + for (k = 0, pn = colist; k < m; k++, pn += (strlen(pn) + 1)) + n = max(n, (signed)strlen(pn)); + + // Default occur column name is the 1st colist column name + if (!ocr || !*ocr) + ocr = colist; + + /**********************************************************************/ + /* Replace the columns of the colist by the rank and occur columns. */ + /**********************************************************************/ + for (i = 0, pcrp = &qrp->Colresp; crp = *pcrp; ) { + for (k = 0, pn = colist; k < m; k++, pn += (strlen(pn) + 1)) + if (!stricmp(pn, crp->Name)) + break; + + if (k < m) { + // This column belongs to colist + c++; + + if (!b) { + if (rk) { + // Add the rank column here + rcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES)); + memset(rcrp, 0, sizeof(COLRES)); + rcrp->Next = crp; + rcrp->Name = (char*)rank; + rcrp->Type = TYPE_STRING; + rcrp->Length = n; + rcrp->Ncol = ++i; + *pcrp = rcrp; + } // endif rk + + // First remaining listed column, will be the occur column + crp->Name = (char*)ocr; + b = true; + } else { + *pcrp = crp->Next; // Remove this column + continue; + } // endif b + + } // endif k + + crp->Ncol = ++i; + pcrp = &crp->Next; + } // endfor pcrp + + // Check whether all columns of the list where found + if (c < m) { + strcpy(g->Message, "Some colist columns are not in the source table"); + return true; + } // endif crp + + /**********************************************************************/ + /* Set the number of columns of the table. */ + /**********************************************************************/ + qrp->Nblin = i; + return false; + } // end of OcrSrcCols + +/* -------------- Implementation of the OCCUR classes ---------------- */ + +/***********************************************************************/ +/* DefineAM: define specific AM block values from OCCUR table. */ +/***********************************************************************/ +bool OCCURDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) + { + Rcol = Cat->GetStringCatInfo(g, "RankCol", ""); + Colist = Cat->GetStringCatInfo(g, "Colist", ""); + Xcol = Cat->GetStringCatInfo(g, "OccurCol", Colist); + return PRXDEF::DefineAM(g, am, poff); + } // end of DefineAM + +/***********************************************************************/ +/* GetTable: makes a new TDB of the proper type. */ +/***********************************************************************/ +PTDB OCCURDEF::GetTable(PGLOBAL g, MODE m) + { + if (Catfunc != FNC_COL) + return new(g) TDBOCCUR(this); + else + return new(g) TDBTBC(this); + + } // end of GetTable + +/* ------------------------------------------------------------------- */ + +/***********************************************************************/ +/* Implementation of the TDBOCCUR class. */ +/***********************************************************************/ +TDBOCCUR::TDBOCCUR(POCCURDEF tdp) : TDBPRX(tdp) + { +//Tdbp = NULL; // Source table (in TDBPRX) + Tabname = tdp->Tablep->GetName(); // Name of source table + Colist = tdp->Colist; // List of source columns + Xcolumn = tdp->Xcol; // Occur column name + Rcolumn = tdp->Rcol; // Rank column name + Xcolp = NULL; // To the OCCURCOL column + Col = NULL; // To source column blocks array + Mult = PrepareColist(Colist); // Multiplication factor + N = 0; // The current table index + M = 0; // The occurence rank + RowFlag = 0; // 0: Ok, 1: Same, 2: Skip + } // end of TDBOCCUR constructor + +/***********************************************************************/ +/* Allocate OCCUR/SRC column description block. */ +/***********************************************************************/ +PCOL TDBOCCUR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) + { + PCOL colp = NULL; + + if (!stricmp(cdp->GetName(), Rcolumn)) { + // Allocate a RANK column + colp = new(g) RANKCOL(cdp, this, n); + } else if (!stricmp(cdp->GetName(), Xcolumn)) { + // Allocate the OCCUR column + colp = Xcolp = new(g) OCCURCOL(cdp, this, n); + } else + return new(g) PRXCOL(cdp, this, cprec, n); + + if (cprec) { + colp->SetNext(cprec->GetNext()); + cprec->SetNext(colp); + } else { + colp->SetNext(Columns); + Columns = colp; + } // endif cprec + + return colp; + } // end of MakeCol + +/***********************************************************************/ +/* Initializes the table. */ +/***********************************************************************/ +bool TDBOCCUR::InitTable(PGLOBAL g) + { + if (!Tdbp) + // Get the table description block of this table + if (!(Tdbp = GetSubTable(g, ((POCCURDEF)To_Def)->Tablep, TRUE))) + return TRUE; + + if (!Tdbp->IsView()) + if (MakeColumnList(g)) + return TRUE; + + return FALSE; + } // end of InitTable + +/***********************************************************************/ +/* Allocate OCCUR column description block. */ +/***********************************************************************/ +bool TDBOCCUR::MakeColumnList(PGLOBAL g) + { + char *pn; + int i; + PCOL colp; + + for (colp = Columns; colp; colp = colp->GetNext()) + if (colp->GetAmType() == TYPE_AM_PRX) + if (((PPRXCOL)colp)->Init(g)) + return true; + + Col = (PCOL*)PlugSubAlloc(g, NULL, Mult * sizeof(PCOL)); + + for (i = 0, pn = Colist; i < Mult; i++, pn += (strlen(pn) + 1)) { + if (!(Col[i] = Tdbp->ColDB(g, pn, 0))) { + // Column not found in table + sprintf(g->Message, MSG(COL_ISNOT_TABLE), pn, Tabname); + return true; + } // endif Col + + if (Col[i]->InitValue(g)) { + strcpy(g->Message, "OCCUR InitValue failed"); + return true; + } // endif InitValue + + } // endfor i + + return false; + } // end of MakeColumnList + +/***********************************************************************/ +/* Allocate OCCUR column description block for a view. */ +/***********************************************************************/ +bool TDBOCCUR::ViewColumnList(PGLOBAL g) + { + char *pn; + int i; + PCOL colp, cp; + PTDBMY tdbp; + + if (!Tdbp->IsView()) + return false; + + if (Tdbp->GetAmType() != TYPE_AM_MYSQL) { + strcpy(g->Message, "View is not MySQL"); + return true; + } else + tdbp = (PTDBMY)Tdbp; + + for (cp = Columns; cp; cp = cp->GetNext()) + if (cp->GetAmType() == TYPE_AM_PRX) { + if ((colp = tdbp->MakeFieldColumn(g, cp->GetName()))) { + ((PPRXCOL)cp)->Colp = colp; + ((PPRXCOL)cp)->To_Val = colp->GetValue(); + } else + return true; + + } // endif Type + + Col = (PCOL*)PlugSubAlloc(g, NULL, Mult * sizeof(PCOL)); + + for (i = 0, pn = Colist; i < Mult; i++, pn += (strlen(pn) + 1)) + if (!(Col[i] = tdbp->MakeFieldColumn(g, pn))) { + // Column not found in table + sprintf(g->Message, MSG(COL_ISNOT_TABLE), pn, Tabname); + return true; + } // endif Col + + return false; + } // end of ViewColumnList + +/***********************************************************************/ +/* OCCUR GetMaxSize: returns the maximum number of rows in the table. */ +/***********************************************************************/ +int TDBOCCUR::GetMaxSize(PGLOBAL g) + { + if (MaxSize < 0) { + if (!(Tdbp = GetSubTable(g, ((POCCURDEF)To_Def)->Tablep, TRUE))) + return 0; + + MaxSize = Mult * Tdbp->GetMaxSize(g); + } // endif MaxSize + + return MaxSize; + } // end of GetMaxSize + +/***********************************************************************/ +/* In this sample, ROWID will be the (virtual) row number, */ +/* while ROWNUM will be the occurence rank in the multiple column. */ +/***********************************************************************/ +int TDBOCCUR::RowNumber(PGLOBAL g, bool b) + { + return (b) ? M : N; + } // end of RowNumber + +/***********************************************************************/ +/* OCCUR Access Method opening routine. */ +/***********************************************************************/ +bool TDBOCCUR::OpenDB(PGLOBAL g) + { + if (Use == USE_OPEN) { + /*******************************************************************/ + /* Table already open, just replace it at its beginning. */ + /*******************************************************************/ + N = M = 0; + RowFlag = 0; + + if (Xcolp) + Xcolp->Xreset(); + + return Tdbp->OpenDB(g); + } // endif use + + + if (Mode != MODE_READ) { + /*******************************************************************/ + /* Currently OCCUR tables cannot be modified. */ + /*******************************************************************/ + strcpy(g->Message, "OCCUR tables are read only"); + return TRUE; + } // endif Mode + + /*********************************************************************/ + /* Do it here if not done yet. */ + /*********************************************************************/ + if (InitTable(g)) + return TRUE; + + if (Xcolp) + // Lock this column so it is evaluated by its table only + Xcolp->AddStatus(BUF_READ); + + if (To_Key_Col || To_Kindex) { + /*******************************************************************/ + /* Direct access of OCCUR tables is not implemented yet. */ + /*******************************************************************/ + strcpy(g->Message, "No direct access to OCCUR tables"); + return TRUE; + } // endif To_Key_Col + + /*********************************************************************/ + /* Do open the source table. */ + /*********************************************************************/ + if (Tdbp->OpenDB(g)) + return TRUE; + + return ViewColumnList(g); + } // end of OpenDB + +/***********************************************************************/ +/* Data Base read routine for OCCUR access method. */ +/***********************************************************************/ +int TDBOCCUR::ReadDB(PGLOBAL g) + { + int rc = RC_OK; + + /*********************************************************************/ + /* Now start the multi reading process. */ + /*********************************************************************/ + do { + if (RowFlag != 1) + if ((rc = Tdbp->ReadDB(g)) != RC_OK) + break; + + if (Xcolp) { + RowFlag = 0; + Xcolp->ReadColumn(g); + M = Xcolp->GetI(); + } // endif Xcolp + + } while (RowFlag == 2); + + N++; + return rc; + } // end of ReadDB + +// ------------------------ OCCURCOL functions ---------------------------- + +/***********************************************************************/ +/* OCCURCOL public constructor. */ +/***********************************************************************/ +OCCURCOL::OCCURCOL(PCOLDEF cdp, PTDBOCCUR tdbp, int n) + : COLBLK(cdp, tdbp, n) + { + // Set additional OCCUR access method information for column. + I = 0; + } // end of OCCURCOL constructor + +/***********************************************************************/ +/* ReadColumn: what this routine does is to access the columns of */ +/* list, extract their value and convert it to buffer type. */ +/***********************************************************************/ +void OCCURCOL::ReadColumn(PGLOBAL g) + { + PTDBOCCUR tdbp = (PTDBOCCUR)To_Tdb; + PCOL *col = tdbp->Col; + + for (; I < tdbp->Mult; I++) { + col[I]->ReadColumn(g); + + if (Nullable || !col[I]->GetValue()->IsZero()) + break; + + } // endfor I + + if (I == tdbp->Mult) { + // No more values, go to next source row + tdbp->RowFlag = 2; + I = 0; + return; + } // endif I + + // Set the OCCUR column value from the Ith source column value + Value->SetValue_pval(col[I++]->GetValue()); + tdbp->RowFlag = 1; + } // end of ReadColumn + + +// ------------------------ RANKCOL functions --------------------------- + +/***********************************************************************/ +/* ReadColumn: what this routine does is to access the Mth columns of */ +/* list, extract its name and set to it the rank column value. */ +/***********************************************************************/ +void RANKCOL::ReadColumn(PGLOBAL g) + { + PTDBOCCUR tdbp = (PTDBOCCUR)To_Tdb; + PCOL *col = tdbp->Col; + + // Set the RANK column value from the Mth source column name + if (tdbp->M) + Value->SetValue_psz(col[tdbp->M - 1]->GetName()); + else { + Value->Reset(); + + if (Nullable) + Value->SetNull(true); + + } // endelse + + } // end of ReadColumn diff --git a/storage/connect/taboccur.h b/storage/connect/taboccur.h new file mode 100644 index 00000000000..10f94329703 --- /dev/null +++ b/storage/connect/taboccur.h @@ -0,0 +1,139 @@ +// TABOCCUR.H Olivier Bertrand 2013 +// Defines the OCCUR tables + +#include "tabutil.h" + +#define TYPE_AM_OCCUR (AMT)128 + +typedef class OCCURDEF *POCCURDEF; +typedef class TDBOCCUR *PTDBOCCUR; +typedef class OCCURCOL *POCCURCOL; +typedef class RANKCOL *PRANKCOL; + +/* -------------------------- OCCUR classes -------------------------- */ + +/***********************************************************************/ +/* OCCUR: Table that provides a view of a source table where the */ +/* contain of several columns of the source table is placed in only */ +/* one column, the OCCUR column, this resulting into several rows. */ +/***********************************************************************/ + +/***********************************************************************/ +/* OCCUR table. */ +/***********************************************************************/ +class OCCURDEF : public PRXDEF { /* Logical table description */ + friend class TDBOCCUR; + public: + // Constructor + OCCURDEF(void) {Pseudo = 3; Colist = Xcol = NULL;} + + // Implementation + virtual const char *GetType(void) {return "OCCUR";} + + // Methods + virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); + virtual PTDB GetTable(PGLOBAL g, MODE m); + + protected: + // Members + char *Colist; /* The source column list */ + char *Xcol; /* The multiple occurence column */ + char *Rcol; /* The rank column */ + }; // end of OCCURDEF + +/***********************************************************************/ +/* This is the class declaration for the OCCUR table. */ +/***********************************************************************/ +class TDBOCCUR : public TDBPRX { + friend class OCCURCOL; + friend class RANKCOL; + public: + // Constructor + TDBOCCUR(POCCURDEF tdp); + + // Implementation + virtual AMT GetAmType(void) {return TYPE_AM_OCCUR;} + void SetTdbp(PTDBASE tdbp) {Tdbp = tdbp;} + + // Methods + virtual void ResetDB(void) {N = 0; Tdbp->ResetDB();} + virtual int RowNumber(PGLOBAL g, bool b = FALSE); + bool MakeColumnList(PGLOBAL g); + bool ViewColumnList(PGLOBAL g); + + // Database routines + virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); + virtual bool InitTable(PGLOBAL g); + virtual int GetMaxSize(PGLOBAL g); + virtual bool OpenDB(PGLOBAL g); + virtual int ReadDB(PGLOBAL g); + + protected: + // Members +//PTDBASE Tdbp; // To the source table or view + LPCSTR Tabname; // Name of source table + char *Colist; // Source column list + char *Xcolumn; // Occurence column name + char *Rcolumn; // Rank column name + POCCURCOL Xcolp; // To the OCCURCOL column + PCOL *Col; // To source multiple columns + int Mult; // Multiplication factor + int N; // The current table index + int M; // The occurence rank + BYTE RowFlag; // 0: Ok, 1: Same, 2: Skip + }; // end of class TDBOCCUR + +/***********************************************************************/ +/* Class OCCURCOL: for the multiple occurence column. */ +/***********************************************************************/ +class OCCURCOL : public COLBLK { + public: + // Constructors + OCCURCOL(PCOLDEF cdp, PTDBOCCUR tdbp, int n); + + // Implementation + virtual int GetAmType(void) {return TYPE_AM_OCCUR;} + int GetI(void) {return I;} + + // Methods + virtual void Reset(void) {} // Evaluated only by TDBOCCUR + virtual void ReadColumn(PGLOBAL g); + void Xreset(void) {I = 0;}; + + protected: + // Default constructor not to be used + OCCURCOL(void) {} + + // Members + int I; + }; // end of class OCCURCOL + +/***********************************************************************/ +/* Class RANKCOL: for the multiple occurence column ranking. */ +/***********************************************************************/ +class RANKCOL : public COLBLK { + public: + // Constructors + RANKCOL(PCOLDEF cdp, PTDBOCCUR tdbp, int n) : COLBLK(cdp, tdbp, n) {} + + // Implementation + virtual int GetAmType(void) {return TYPE_AM_OCCUR;} + + // Methods + virtual void ReadColumn(PGLOBAL g); + + protected: + // Default constructor not to be used + RANKCOL(void) {} + + // Members + }; // end of class RANKCOL + +/***********************************************************************/ +/* Definition of class XCOLDEF. */ +/* This class purpose is just to access COLDEF protected items! */ +/***********************************************************************/ +class XCOLDEF: public COLDEF { + friend class TDBOCCUR; + }; // end of class XCOLDEF + diff --git a/storage/connect/tabodbc.cpp b/storage/connect/tabodbc.cpp index 5bbc9effa92..599f9c7e80f 100644 --- a/storage/connect/tabodbc.cpp +++ b/storage/connect/tabodbc.cpp @@ -75,7 +75,6 @@ #include "sql_string.h" -extern "C" char *GetMsgid(int id); extern "C" int trace; /***********************************************************************/ @@ -896,7 +895,7 @@ void ODBCCOL::WriteColumn(PGLOBAL g) Value->SetValue_pval(To_Val, false); // Convert the inserted value if (Buf_Type == TYPE_DATE) { - struct tm *dbtime = ((DTVAL*)Value)->GetGmTime(); + struct tm tm, *dbtime = ((DTVAL*)Value)->GetGmTime(&tm); Sqlbuf->second = dbtime->tm_sec; Sqlbuf->minute = dbtime->tm_min; diff --git a/storage/connect/tabpivot.cpp b/storage/connect/tabpivot.cpp index fccd8338d8a..9beca56e773 100644 --- a/storage/connect/tabpivot.cpp +++ b/storage/connect/tabpivot.cpp @@ -1,11 +1,11 @@ /************ TabPivot C++ Program Source Code File (.CPP) *************/ /* PROGRAM NAME: TABPIVOT */ /* ------------- */ -/* Version 1.3 */ +/* Version 1.6 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -41,10 +41,11 @@ #include "global.h" #include "plgdbsem.h" #include "xtable.h" -#include "xindex.h" +#include "tabcol.h" #include "colblk.h" #include "tabmysql.h" #include "csort.h" +#include "tabutil.h" #include "tabpivot.h" #include "valblk.h" #include "ha_connect.h" @@ -52,9 +53,196 @@ extern "C" int trace; +/***********************************************************************/ +/* Make the Pivot table column list. */ +/***********************************************************************/ +PQRYRES PivotColumns(PGLOBAL g, const char *tab, const char *src, + const char *picol, const char *fncol, + const char *host, const char *db, + const char *user, const char *pwd, + int port) + { + PIVAID pvd(tab, src, picol, fncol, host, db, user, pwd, port); + + return pvd.MakePivotColumns(g); + } // end of PivotColumns + +/* --------------- Implementation of the PIVAID classe --------------- */ + +/***********************************************************************/ +/* PIVAID constructor. */ +/***********************************************************************/ +PIVAID::PIVAID(const char *tab, const char *src, const char *picol, + const char *fncol, const char *host, const char *db, + const char *user, const char *pwd, int port) + : CSORT(false) + { + Host = (char*)host; + User = (char*)user; + Pwd = (char*)pwd; + Qryp = NULL; + Database = (char*)db; + Tabname = (char*)tab; + Tabsrc = (char*)src; + Picol = (char*)picol; + Fncol = (char*)fncol; + Rblkp = NULL; + Port = (port) ? port : GetDefaultPort(); + } // end of PIVAID constructor + +/***********************************************************************/ +/* Make the Pivot table column list. */ +/***********************************************************************/ +PQRYRES PIVAID::MakePivotColumns(PGLOBAL g) + { + char *query, *colname, buf[32]; + int ndif, nblin, w = 0; + PVAL valp; + PCOLRES *pcrp, crp, fncrp = NULL; + + if (!Tabsrc && Tabname) { + // Locate the query + query = (char*)PlugSubAlloc(g, NULL, strlen(Tabname) + 16); + sprintf(query, "SELECT * FROM %s", Tabname); + } else if (!Tabsrc) { + strcpy(g->Message, MSG(SRC_TABLE_UNDEF)); + return NULL; + } else + query = Tabsrc; + + // Open a MySQL connection for this table + if (Myc.Open(g, Host, Database, User, Pwd, Port)) + return NULL; + + // Send the source command to MySQL + if (Myc.ExecSQL(g, query, &w) == RC_FX) { + Myc.Close(); + return NULL; + } // endif Exec + + // We must have a storage query to get pivot column values + Qryp = Myc.GetResult(g); + Myc.Close(); + + if (!Fncol) { + for (crp = Qryp->Colresp; crp; crp = crp->Next) + if (!Picol || stricmp(Picol, crp->Name)) + Fncol = crp->Name; + + if (!Fncol) { + strcpy(g->Message, MSG(NO_DEF_FNCCOL)); + return NULL; + } // endif Fncol + + } // endif Fncol + + if (!Picol) { + // Find default Picol as the last one not equal to Fncol + for (crp = Qryp->Colresp; crp; crp = crp->Next) + if (stricmp(Fncol, crp->Name)) + Picol = crp->Name; + + if (!Picol) { + strcpy(g->Message, MSG(NO_DEF_PIVOTCOL)); + return NULL; + } // endif Picol + + } // endif picol + + // Prepare the column list + for (pcrp = &Qryp->Colresp; crp = *pcrp; ) + if (!stricmp(Picol, crp->Name)) { + Rblkp = crp->Kdata; + *pcrp = crp->Next; + } else if (!stricmp(Fncol, crp->Name)) { + fncrp = crp; + *pcrp = crp->Next; + } else + pcrp = &crp->Next; + + if (!Rblkp) { + strcpy(g->Message, MSG(NO_DEF_PIVOTCOL)); + return NULL; + } else if (!fncrp) { + strcpy(g->Message, MSG(NO_DEF_FNCCOL)); + return NULL; + } // endif + + // Before calling sort, initialize all + nblin = Qryp->Nblin; + + Index.Size = nblin * sizeof(int); + Index.Sub = TRUE; // Should be small enough + + if (!PlgDBalloc(g, NULL, Index)) + return NULL; + + Offset.Size = (nblin + 1) * sizeof(int); + Offset.Sub = TRUE; // Should be small enough + + if (!PlgDBalloc(g, NULL, Offset)) + return NULL; + + ndif = Qsort(g, nblin); + + if (ndif < 0) // error + return NULL; + + // Allocate the Value used to retieve column names + if (!(valp = AllocateValue(g, Rblkp->GetType(), + Rblkp->GetVlen(), + Rblkp->GetPrec()))) + return NULL; + + // Now make the functional columns + for (int i = 0; i < ndif; i++) { + if (i) { + crp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES)); + memcpy(crp, fncrp, sizeof(COLRES)); + } else + crp = fncrp; + + // Get the value that will be the generated column name + valp->SetValue_pvblk(Rblkp, Pex[Pof[i]]); + colname = valp->GetCharString(buf); + crp->Name = (char*)PlugSubAlloc(g, NULL, strlen(colname) + 1); + strcpy(crp->Name, colname); + crp->Flag = 1; + + // Add this column + *pcrp = crp; + crp->Next = NULL; + pcrp = &crp->Next; + } // endfor i + + // We added ndif columns and removed 2 (picol and fncol) + Qryp->Nbcol += (ndif - 2); + return Qryp; + } // end of MakePivotColumns + +/***********************************************************************/ +/* PIVAID: Compare routine for sorting pivot column values. */ +/***********************************************************************/ +int PIVAID::Qcompare(int *i1, int *i2) + { + // TODO: the actual comparison between pivot column result values. + return Rblkp->CompVal(*i1, *i2); + } // end of Qcompare + /* --------------- Implementation of the PIVOT classes --------------- */ /***********************************************************************/ +/* PIVOTDEF constructor. */ +/***********************************************************************/ + PIVOTDEF::PIVOTDEF(void) + { + Host = User = Pwd = DB = NULL; + Tabname = Tabsrc = Picol = Fncol = Function = NULL; + GBdone = Accept = false; + Port = 0; + } // end of PIVOTDEF constructor + +/***********************************************************************/ /* DefineAM: define specific AM block values from PIVOT table. */ /***********************************************************************/ bool PIVOTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) @@ -62,14 +250,18 @@ bool PIVOTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) char *p1, *p2; PHC hc = ((MYCAT*)Cat)->GetHandler(); - Host = Cat->GetStringCatInfo(g, Name, "Host", "localhost"); - User = Cat->GetStringCatInfo(g, Name, "User", "root"); - Pwd = Cat->GetStringCatInfo(g, Name, "Password", NULL); - DB = Cat->GetStringCatInfo(g, Name, "Database", (PSZ)hc->GetDBName(NULL)); - Tabsrc = Cat->GetStringCatInfo(g, Name, "SrcDef", NULL); - Tabname = Cat->GetStringCatInfo(g, Name, "Name", NULL); - Picol = Cat->GetStringCatInfo(g, Name, "PivotCol", NULL); - Fncol = Cat->GetStringCatInfo(g, Name, "FncCol", NULL); + if (PRXDEF::DefineAM(g, am, poff)) + return TRUE; + + Tabname = (char*)Tablep->GetName(); + DB = (char*)Tablep->GetQualifier(); + Tabsrc = (char*)Tablep->GetSrc(); + + Host = Cat->GetStringCatInfo(g, "Host", "localhost"); + User = Cat->GetStringCatInfo(g, "User", "*"); + Pwd = Cat->GetStringCatInfo(g, "Password", NULL); + Picol = Cat->GetStringCatInfo(g, "PivotCol", NULL); + Fncol = Cat->GetStringCatInfo(g, "FncCol", NULL); // If fncol is like avg(colname), separate Fncol and Function if (Fncol && (p1 = strchr(Fncol, '(')) && (p2 = strchr(p1, ')')) && @@ -78,11 +270,12 @@ bool PIVOTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) Function = Fncol; Fncol = p1; } else - Function = Cat->GetStringCatInfo(g, Name, "Function", "SUM"); + Function = Cat->GetStringCatInfo(g, "Function", "SUM"); - GBdone = Cat->GetIntCatInfo(Name, "Groupby", 0) ? TRUE : FALSE; - Port = Cat->GetIntCatInfo(Name, "Port", 3306); - Desc = (*Tabname) ? Tabname : Tabsrc; + GBdone = Cat->GetBoolCatInfo("Groupby", false); + Accept = Cat->GetBoolCatInfo("Accept", false); + Port = Cat->GetIntCatInfo("Port", 3306); + Desc = (Tabsrc) ? Tabsrc : Tabname; return FALSE; } // end of DefineAM @@ -99,15 +292,13 @@ PTDB PIVOTDEF::GetTable(PGLOBAL g, MODE m) /***********************************************************************/ /* Implementation of the TDBPIVOT class. */ /***********************************************************************/ -TDBPIVOT::TDBPIVOT(PPIVOTDEF tdp) : TDBASE(tdp), CSORT(FALSE) +TDBPIVOT::TDBPIVOT(PPIVOTDEF tdp) : TDBPRX(tdp) { - Tqrp = NULL; Host = tdp->Host; Database = tdp->DB; User = tdp->User; Pwd = tdp->Pwd; Port = tdp->Port; - Qryp = NULL; Tabname = tdp->Tabname; // Name of source table Tabsrc = tdp->Tabsrc; // SQL description of source table Picol = tdp->Picol; // Pivot column name @@ -117,7 +308,9 @@ TDBPIVOT::TDBPIVOT(PPIVOTDEF tdp) : TDBASE(tdp), CSORT(FALSE) //Xresp = NULL; // To the pivot result column //Rblkp = NULL; // The value block of the pivot column Fcolp = NULL; // To the function column + Dcolp = NULL; // To the dump column GBdone = tdp->GBdone; + Accept = tdp->Accept; Mult = -1; // Estimated table size N = 0; // The current table index M = 0; // The occurence rank @@ -125,438 +318,224 @@ TDBPIVOT::TDBPIVOT(PPIVOTDEF tdp) : TDBASE(tdp), CSORT(FALSE) RowFlag = 0; // 0: Ok, 1: Same, 2: Skip } // end of TDBPIVOT constructor -#if 0 -TDBPIVOT::TDBPIVOT(PTDBPIVOT tdbp) : TDBASE(tdbp), CSORT(FALSE) - { - Tdbp = tdbp->Tdbp; - Sqlp = tdbp->Sqlp; - Qryp = tdbp->Qryp; - Tabname = tdbp->Tabname; - Tabsrc = tdbp->Tabsrc; - Picol = tdbp->Picol; - Fncol = tdbp->Fncol; - Function = tdbp->Function; - Xcolp = tdbp->Xcolp; - Xresp = tdbp->Xresp; - Rblkp = tdbp->Rblkp; - Fcolp = tdbp->Fcolp; - Mult = tdbp->Mult; - N = tdbp->N; - M = tdbp->M; - FileStatus = tdbp->FileStatus; - RowFlag = tdbp->RowFlag; - } // end of TDBPIVOT copy constructor - -// Is this really useful ??? -PTDB TDBPIVOT::CopyOne(PTABS t) - { - PTDB tp = new(t->G) TDBPIVOT(this); - - tp->SetColumns(Columns); - return tp; - } // end of CopyOne -#endif // 0 - /***********************************************************************/ -/* Prepare the source table Query. */ +/* Allocate source column description block. */ /***********************************************************************/ -PQRYRES TDBPIVOT::GetSourceTable(PGLOBAL g) +PCOL TDBPIVOT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) { - if (Qryp) - return Qryp; // Already done - - if (!Tabsrc && Tabname) { - char *def, *colist; - size_t len = 0; - PCOL colp; - PDBUSER dup = (PDBUSER)g->Activityp->Aptr; + PCOL colp; - // Evaluate the length of the column list - for (colp = Columns; colp; colp = colp->GetNext()) - len += (strlen(colp->GetName()) + 2); + if (cdp->GetOffset()) { + colp = new(g) FNCCOL(cdp, this, cprec, n); - *(colist = (char*)PlugSubAlloc(g, NULL, len)) = 0; + if (cdp->GetOffset() > 1) + Dcolp = colp; - // Locate the suballocated string (size is not known yet) - def = (char*)PlugSubAlloc(g, NULL, 0); - strcpy(def, "SELECT "); - - if (!Fncol) { - for (colp = Columns; colp; colp = colp->GetNext()) - if (!Picol || stricmp(Picol, colp->GetName())) - Fncol = colp->GetName(); + } else + colp = new(g) SRCCOL(cdp, this, cprec, n); - if (!Fncol) { - strcpy(g->Message, MSG(NO_DEF_FNCCOL)); - return NULL; - } // endif Fncol + return colp; + } // end of MakeCol - } else if (!(ColDB(g, Fncol, 0))) { - // Function column not found in table - sprintf(g->Message, MSG(COL_ISNOT_TABLE), Fncol, Tabname); - return NULL; - } // endif Fcolp +/***********************************************************************/ +/* Find default fonction and pivot columns. */ +/***********************************************************************/ +bool TDBPIVOT::FindDefaultColumns(PGLOBAL g) + { + PCOLDEF cdp; + PTABDEF defp = Tdbp->GetDef(); + if (!Fncol) { + for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext()) + if (!Picol || stricmp(Picol, cdp->GetName())) + Fncol = cdp->GetName(); + + if (!Fncol) { + strcpy(g->Message, MSG(NO_DEF_FNCCOL)); + return true; + } // endif Fncol + + } // endif Fncol + + if (!Picol) { + // Find default Picol as the last one not equal to Fncol + for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext()) + if (stricmp(Fncol, cdp->GetName())) + Picol = cdp->GetName(); + if (!Picol) { - // Find default Picol as the last one not equal to Fncol - for (colp = Columns; colp; colp = colp->GetNext()) - if (!Fncol || stricmp(Fncol, colp->GetName())) - Picol = colp->GetName(); - - if (!Picol) { - strcpy(g->Message, MSG(NO_DEF_PIVOTCOL)); - return NULL; - } // endif Picol - - } else if (!(ColDB(g, Picol, 0))) { - // Pivot column not found in table - sprintf(g->Message, MSG(COL_ISNOT_TABLE), Picol, Tabname); - return NULL; - } // endif Xcolp + strcpy(g->Message, MSG(NO_DEF_PIVOTCOL)); + return true; + } // endif Picol + + } // endif Picol + + return false; + } // end of FindDefaultColumns - // Make the other column list - for (colp = Columns; colp; colp = colp->GetNext()) - if (stricmp(Picol, colp->GetName()) && - stricmp(Fncol, colp->GetName())) - strcat(strcat(colist, colp->GetName()), ", "); +/***********************************************************************/ +/* Prepare the source table Query. */ +/***********************************************************************/ +bool TDBPIVOT::GetSourceTable(PGLOBAL g) + { + if (Tdbp) + return false; // Already done - // Add the Pivot column at the end of the list - strcat(strcat(def, strcat(colist, Picol)), ", "); + if (!Tabsrc && Tabname) { + // Get the table description block of this table + if (!(Tdbp = GetSubTable(g, ((PPIVOTDEF)To_Def)->Tablep, true))) + return true; - // Continue making the definition if (!GBdone) { + char *colist; + PCOLDEF cdp; + + if (FindDefaultColumns(g)) + return true; + + // Locate the suballocated colist (size is not known yet) + *(colist = (char*)PlugSubAlloc(g, NULL, 0)) = 0; + + // Make the column list + for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext()) + if (!cdp->GetOffset()) + strcat(strcat(colist, cdp->GetName()), ", "); + + // Add the Pivot column at the end of the list + strcat(colist, Picol); + + // Now we know how much was suballocated + PlugSubAlloc(g, NULL, strlen(colist)); + + // Locate the source string (size is not known yet) + Tabsrc = (char*)PlugSubAlloc(g, NULL, 0); + + // Start making the definition + strcat(strcat(strcpy(Tabsrc, "SELECT "), colist), ", "); + // Make it suitable for Pivot by doing the group by - strcat(strcat(def, Function), "("); - strcat(strcat(strcat(def, Fncol), ") "), Fncol); - strcat(strcat(def, " FROM "), Tabname); - strcat(strcat(def, " GROUP BY "), colist); - } else // Gbdone - strcat(strcat(strcat(def, Fncol), " FROM "), Tabname); - - // Now we know how much was suballocated - Tabsrc = (char*)PlugSubAlloc(g, NULL, strlen(def)); - } else { - strcpy(g->Message, MSG(SRC_TABLE_UNDEF)); - return NULL; - } // endif Tabsrc + strcat(strcat(Tabsrc, Function), "("); + strcat(strcat(strcat(Tabsrc, Fncol), ") "), Fncol); + strcat(strcat(Tabsrc, " FROM "), Tabname); + strcat(strcat(Tabsrc, " GROUP BY "), colist); + + if (Tdbp->IsView()) // Until MariaDB bug is fixed + strcat(strcat(Tabsrc, " ORDER BY "), colist); - int w; + // Now we know how much was suballocated + PlugSubAlloc(g, NULL, strlen(Tabsrc)); + } // endif !GBdone - // Open a MySQL connection for this table - if (Myc.Open(g, Host, Database, User, Pwd, Port)) - return NULL; + } else if (!Tabsrc) { + strcpy(g->Message, MSG(SRC_TABLE_UNDEF)); + return true; + } // endif - // Send the source command to MySQL - if (Myc.ExecSQL(g, Tabsrc, &w) == RC_FX) { - Myc.Close(); - return NULL; - } // endif Exec + if (Tabsrc) { + // Get the new table description block of this source table + PTABLE tablep = new(g) XTAB("whatever", Tabsrc); - // We must have a storage query to get pivot column values - Qryp = Myc.GetResult(g); - Myc.Close(); - Tqrp = new(g) TDBQRS(Qryp); - Tqrp->OpenDB(g); + tablep->SetQualifier(Database); - if (MakePivotColumns(g) < 0) - return NULL; + if (!(Tdbp = GetSubTable(g, tablep, true))) + return true; - return Qryp; + } // endif Tabsrc + + return false; } // end of GetSourceTable /***********************************************************************/ -/* Allocate PIVOT columns description block. */ +/* Make the required pivot columns. */ /***********************************************************************/ -int TDBPIVOT::MakePivotColumns(PGLOBAL g) +bool TDBPIVOT::MakePivotColumns(PGLOBAL g) { - if (Mult < 0) { - int ndif, n = 0, nblin = Qryp->Nblin; - PVAL valp; - PCOL cp; - PSRCCOL colp; - PFNCCOL cfnp; - - // Allocate all the source columns - Tqrp->ColDB(g, NULL, 0); - Columns = NULL; // Discard dummy columns blocks - - for (cp = Tqrp->GetColumns(); cp; cp = cp->GetNext()) { - if (cp->InitValue(g)) - return -1; - - if (!stricmp(cp->GetName(), Picol)) { - Xcolp = (PQRSCOL)cp; - Xresp = Xcolp->GetCrp(); - Rblkp = Xresp->Kdata; - } else if (!stricmp(cp->GetName(), Fncol)) { - Fcolp = (PQRSCOL)cp; - } else - if ((colp = new(g) SRCCOL(cp, this, ++n))->Init(g, this)) - return -1; - - } // endfor cp - - if (!Xcolp) { - sprintf(g->Message, MSG(COL_ISNOT_TABLE), - Picol, Tabname ? Tabname : "TabSrc"); - return -1; - } else if (!Fcolp) { - sprintf(g->Message, MSG(COL_ISNOT_TABLE), - Fncol, Tabname ? Tabname : "TabSrc"); - return -1; - } // endif Fcolp - - // Before calling sort, initialize all - Index.Size = nblin * sizeof(int); - Index.Sub = TRUE; // Should be small enough - - if (!PlgDBalloc(g, NULL, Index)) - return -1; - - Offset.Size = (nblin + 1) * sizeof(int); - Offset.Sub = TRUE; // Should be small enough - - if (!PlgDBalloc(g, NULL, Offset)) - return -2; - - ndif = Qsort(g, nblin); - - if (ndif < 0) { // error - return -3; - } else - Ncol = ndif; - - // Now make the functional columns - for (int i = 0; i < Ncol; i++) { - // Allocate the Value used to retieve column names - if (!(valp = AllocateValue(g, Xcolp->GetResultType(), - Xcolp->GetLengthEx(), Xcolp->GetPrecision(), - Xcolp->GetDomain(), Xcolp->GetTo_Tdb()->GetCat()))) - return -4; - - // Get the value that will be the generated column name - valp->SetValue_pvblk(Rblkp, Pex[Pof[i]]); - - // Copy the functional column with new Name and new Value - cfnp = (PFNCCOL)new(g) FNCCOL(Fcolp, this); + if (!Tdbp->IsView()) { + // This was not done yet if GBdone is true + if (FindDefaultColumns(g)) + return true; + + // Now it is time to allocate the pivot and function columns + if (!(Fcolp = Tdbp->ColDB(g, Fncol, 0))) { + // Function column not found in table + sprintf(g->Message, MSG(COL_ISNOT_TABLE), Fncol, Tabname); + return true; + } else if (Fcolp->InitValue(g)) + return true; - // Initialize the generated column - if (cfnp->InitColumn(g, valp)) - return -5; + if (!(Xcolp = Tdbp->ColDB(g, Picol, 0))) { + // Pivot column not found in table + sprintf(g->Message, MSG(COL_ISNOT_TABLE), Picol, Tabname); + return true; + } else if (Xcolp->InitValue(g)) + return true; - } // endfor i + // Check and initialize the subtable columns + for (PCOL cp = Columns; cp; cp = cp->GetNext()) + if (cp->GetAmType() == TYPE_AM_SRC) { + if (((PSRCCOL)cp)->Init(g)) + return TRUE; - // Fields must be updated for ha_connect -// if (UpdateTableFields(g, n + Ncol)) -// return -6; + } else if (cp->GetAmType() == TYPE_AM_FNC) + if (((PFNCCOL)cp)->InitColumn(g)) + return TRUE; - // This should be refined later - Mult = nblin; - } // endif Mult + } // endif isview - return Mult; + return false; } // end of MakePivotColumns -#if 0 /***********************************************************************/ -/* Update fields in the MySQL table structure */ -/* Note: this does not work. Indeed the new rows are correctly made */ -/* but the final result still specify the unmodified table and the */ -/* returned table only contains the original column values. */ -/* In addition, a new query on the table, when it is into the cache, */ -/* specifies all the new columns and fails because they do not belong */ -/* to the original table. */ +/* Make the required pivot columns for an object view. */ /***********************************************************************/ -bool TDBPIVOT::UpdateTableFields(PGLOBAL g, int n) +bool TDBPIVOT::MakeViewColumns(PGLOBAL g) { - uchar *trec, *srec, *tptr, *sptr; - int i = 0, k = 0; - uint len; - uint32 nmp, lwm; - size_t buffsize; - PCOL colp; - PHC hc = ((MYCAT*)((PIVOTDEF*)To_Def)->Cat)->GetHandler(); - TABLE *table = hc->GetTable(); - st_mem_root *tmr = &table->mem_root; - st_mem_root *smr = &table->s->mem_root; - Field* *field; - Field *fp, *tfncp, *sfncp; - Field* *ntf; - Field* *nsf; -//my_bitmap_map *org_bitmap; - const MY_BITMAP *map; - - // When sorting read_set selects all columns, so we use def_read_set - map= (const MY_BITMAP *)&table->def_read_set; - - // Find the function field - for (field= table->field; *field; field++) { - fp= *field; - - if (bitmap_is_set(map, fp->field_index)) - if (!stricmp(fp->field_name, Fncol)) { - tfncp = fp; - break; - } // endif Name - - } // endfor field - - for (field= table->s->field; *field; field++) { - fp= *field; - - if (bitmap_is_set(map, fp->field_index)) - if (!stricmp(fp->field_name, Fncol)) { - sfncp = fp; - break; - } // endif Name - - } // endfor field - - // Calculate the new buffer size - len = tfncp->max_data_length(); - buffsize = table->s->rec_buff_length + len * Ncol; - - // Allocate the new record space - if (!(tptr = trec = (uchar*)alloc_root(tmr, 2 * buffsize))) - return TRUE; - - if (!(sptr = srec = (uchar*)alloc_root(smr, 2 * buffsize))) - return TRUE; - + if (Tdbp->IsView()) { + // Tdbp is a view ColDB cannot be used + PCOL colp, cp; + PTDBMY tdbp; - // Allocate the array of all new table field pointers - if (!(ntf = (Field**)alloc_root(tmr, (uint)((n+1) * sizeof(Field*))))) - return TRUE; + if (Tdbp->GetAmType() != TYPE_AM_MYSQL) { + strcpy(g->Message, "View is not MySQL"); + return true; + } else + tdbp = (PTDBMY)Tdbp; - // Allocate the array of all new table share field pointers - if (!(nsf = (Field**)alloc_root(smr, (uint)((n+1) * sizeof(Field*))))) - return TRUE; + if (!Fncol && !(Fncol = tdbp->FindFieldColumn(Picol))) { + strcpy(g->Message, MSG(NO_DEF_FNCCOL)); + return true; + } // endif Fncol - // First fields are the the ones of the source columns - for (colp = Columns; colp; colp = colp->GetNext()) - if (colp->GetAmType() == TYPE_AM_SRC) { - for (field= table->field; *field; field++) { - fp= *field; - - if (bitmap_is_set(map, fp->field_index)) - if (!stricmp(colp->GetName(), fp->field_name)) { - ntf[i] = fp; - fp->field_index = i++; - fp->ptr = tptr; - tptr += fp->max_data_length(); - break; - } // endif Name - - } // endfor field - - for (field= table->s->field; *field; field++) { - fp= *field; - - if (bitmap_is_set(map, fp->field_index)) - if (!stricmp(colp->GetName(), fp->field_name)) { - nsf[k] = fp; - fp->field_index = k++; - fp->ptr = srec; - srec += fp->max_data_length(); - break; - } // endif Name - - } // endfor field - - } // endif AmType - - // Now add the pivot generated columns - for (colp = Columns; colp; colp = colp->GetNext()) - if (colp->GetAmType() == TYPE_AM_FNC) { - if ((fp = (Field*)memdup_root(tmr, (char*)tfncp, tfncp->size_of()))) { - ntf[i] = fp; - fp->ptr = tptr; - fp->field_name = colp->GetName(); - fp->field_index = i++; - fp->vcol_info = NULL; - fp->stored_in_db = TRUE; - tptr += len; - } else - return TRUE; - - if ((fp = (Field*)memdup_root(smr, (char*)sfncp, sfncp->size_of()))) { - nsf[i] = fp; - fp->ptr = sptr; - fp->field_name = colp->GetName(); - fp->field_index = k++; - fp->vcol_info = NULL; - fp->stored_in_db = TRUE; - sptr += len; - } else - return TRUE; - - } // endif AM_FNC - - // Mark end of the list - ntf[i] = NULL; - nsf[k] = NULL; - - // Update the table fields - nmp = (uint32)((1<<i) - 1); - lwm = (uint32)((-1)<<i); - table->field = ntf; - table->used_fields = i; - table->record[0] = trec; - table->record[1] = trec + buffsize; - *table->def_read_set.bitmap = nmp; - *table->def_read_set.last_word_ptr = nmp; - table->def_read_set.last_word_mask = lwm; - table->def_read_set.n_bits = i; - *table->read_set->bitmap = nmp; - *table->read_set->last_word_ptr = nmp; - table->read_set->last_word_mask = lwm; - table->read_set->n_bits = i; - table->write_set->n_bits = i; - *table->vcol_set->bitmap = 0; - table->vcol_set->n_bits = i; - - // and the share fields - table->s->field = nsf; - table->s->reclength = sptr - srec; - table->s->stored_rec_length = sptr - srec; - table->s->fields = k; - table->s->stored_fields = k; - table->s->rec_buff_length = buffsize; -//table->s->varchar_fields = ???; -//table->s->db_record_offset = ???; -//table->s->null_field_first = ???; - return FALSE; - } // end of UpdateTableFields -#endif // 0 + if (!Picol && !(Picol = tdbp->FindFieldColumn(Fncol))) { + strcpy(g->Message, MSG(NO_DEF_PIVOTCOL)); + return true; + } // endif Picol -/***********************************************************************/ -/* Allocate source column description block. */ -/***********************************************************************/ -PCOL TDBPIVOT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) - { - PCOL colp = NULL; + // Now it is time to allocate the pivot and function columns + if (!(Fcolp = tdbp->MakeFieldColumn(g, Fncol))) + return true; -//if (stricmp(cdp->GetName(), Picol) && stricmp(cdp->GetName(), Fncol)) { - colp = new(g) COLBLK(cdp, this, n); + if (!(Xcolp = tdbp->MakeFieldColumn(g, Picol))) + return true; -// if (((PSRCCOL)colp)->Init(g, this)) -// return NULL; + // Check and initialize the subtable columns + for (cp = Columns; cp; cp = cp->GetNext()) + if (cp->GetAmType() == TYPE_AM_SRC) { + if ((colp = tdbp->MakeFieldColumn(g, cp->GetName()))) { + ((PSRCCOL)cp)->Colp = colp; + ((PSRCCOL)cp)->To_Val = colp->GetValue(); + cp->AddStatus(BUF_READ); // All is done here + } else + return true; -//} else { -// sprintf(g->Message, MSG(NO_MORE_COL), cdp->GetName()); -// return NULL; -//} // endif Name + } else if (cp->GetAmType() == TYPE_AM_FNC) + if (((PFNCCOL)cp)->InitColumn(g)) + return TRUE; - if (cprec) { - colp->SetNext(cprec->GetNext()); - cprec->SetNext(colp); - } else { - colp->SetNext(Columns); - Columns = colp; - } // endif cprec + } // endif isview - return colp; - } // end of MakeCol + return false; + } // end of MakeViewColumns /***********************************************************************/ /* PIVOT GetMaxSize: returns the maximum number of rows in the table. */ @@ -569,7 +548,7 @@ int TDBPIVOT::GetMaxSize(PGLOBAL g) return MaxSize; #endif // 0 - return 0; + return 10; } // end of GetMaxSize /***********************************************************************/ @@ -586,8 +565,6 @@ int TDBPIVOT::RowNumber(PGLOBAL g, bool b) /***********************************************************************/ bool TDBPIVOT::OpenDB(PGLOBAL g) { -//PDBUSER dup = (PDBUSER)g->Activityp->Aptr; - if (Use == USE_OPEN) { /*******************************************************************/ /* Table already open, just replace it at its beginning. */ @@ -598,13 +575,6 @@ bool TDBPIVOT::OpenDB(PGLOBAL g) return FALSE; } // endif use - /*********************************************************************/ - /* Do it here if not done yet (should not be the case). */ - /*********************************************************************/ -//if (MakePivotColumns(g) < 0) - if (!(Qryp = GetSourceTable(g))) - return TRUE; - if (Mode != MODE_READ) { /*******************************************************************/ /* Currently PIVOT tables cannot be modified. */ @@ -621,7 +591,26 @@ bool TDBPIVOT::OpenDB(PGLOBAL g) return TRUE; } // endif To_Key_Col - return FALSE; + /*********************************************************************/ + /* Do it here if not done yet (should not be the case). */ + /*********************************************************************/ + if (GetSourceTable(g)) + return TRUE; + + // For tables, columns must be allocated before opening + if (MakePivotColumns(g)) + return TRUE; + + /*********************************************************************/ + /* Physically open the object table. */ + /*********************************************************************/ + if (Tdbp->OpenDB(g)) + return TRUE; + + /*********************************************************************/ + /* Make all required pivot columns for object views. */ + /*********************************************************************/ + return MakeViewColumns(g); } // end of OpenDB /***********************************************************************/ @@ -632,7 +621,6 @@ int TDBPIVOT::ReadDB(PGLOBAL g) int rc = RC_OK; bool newrow = FALSE; PCOL colp; - PVAL vp1, vp2; if (FileStatus == 2) return RC_EF; @@ -652,7 +640,7 @@ int TDBPIVOT::ReadDB(PGLOBAL g) /*********************************************************************/ do { if (RowFlag != 1) { - if ((rc = Tqrp->ReadDB(g)) != RC_OK) { + if ((rc = Tdbp->ReadDB(g)) != RC_OK) { if (FileStatus && rc == RC_EF) { // A prepared row remains to be sent FileStatus = 2; @@ -662,14 +650,16 @@ int TDBPIVOT::ReadDB(PGLOBAL g) break; } // endif rc - for (colp = Tqrp->GetColumns(); colp; colp = colp->GetNext()) + for (colp = Tdbp->GetColumns(); colp; colp = colp->GetNext()) colp->ReadColumn(g); for (colp = Columns; colp; colp = colp->GetNext()) if (colp->GetAmType() == TYPE_AM_SRC) if (FileStatus) { - if (((PSRCCOL)colp)->CompareColumn()) + if (((PSRCCOL)colp)->CompareLast()) { newrow = (RowFlag) ? TRUE : FALSE; + break; + } // endif CompareLast } else ((PSRCCOL)colp)->SetColumn(); @@ -683,21 +673,21 @@ int TDBPIVOT::ReadDB(PGLOBAL g) } else RowFlag = 2; - vp1 = Xcolp->GetValue(); - // Look for the column having this header for (colp = Columns; colp; colp = colp->GetNext()) if (colp->GetAmType() == TYPE_AM_FNC) { - vp2 = ((PFNCCOL)colp)->Hval; - - if (!vp1->CompareValue(vp2)) + if (((PFNCCOL)colp)->CompareColumn()) break; } // endif AmType - if (!colp) { - strcpy(g->Message, MSG(NO_MATCH_COL)); - return RC_FX; + if (!colp && !(colp = Dcolp)) { + if (!Accept) { + strcpy(g->Message, MSG(NO_MATCH_COL)); + return RC_FX; + } else + continue; + } // endif colp // Set the value of the matching column from the fonction value @@ -731,131 +721,79 @@ int TDBPIVOT::DeleteDB(PGLOBAL g, int irc) /***********************************************************************/ void TDBPIVOT::CloseDB(PGLOBAL g) { -//Tdbp->CloseDB(g); - } // end of CloseDB + if (Tdbp) + Tdbp->CloseDB(g); -/***********************************************************************/ -/* TDBPIVOT: Compare routine for sorting pivot column values. */ -/***********************************************************************/ -int TDBPIVOT::Qcompare(int *i1, int *i2) - { - // TODO: the actual comparison between pivot column result values. - return Rblkp->CompVal(*i1, *i2); - } // end of Qcompare + } // end of CloseDB // ------------------------ FNCCOL functions ---------------------------- /***********************************************************************/ /* FNCCOL public constructor. */ /***********************************************************************/ -FNCCOL::FNCCOL(PCOL col1, PTDBPIVOT tdbp) - : COLBLK(col1, tdbp) +FNCCOL::FNCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) + : COLBLK(cdp, tdbp, i) { + if (cprec) { + Next = cprec->GetNext(); + cprec->SetNext(this); + } else { + Next = tdbp->GetColumns(); + tdbp->SetColumns(this); + } // endif cprec + Value = NULL; // We'll get a new one later - Hval = NULL; // The unconverted header value + Hval = NULL; // The unconverted header value + Xcolp = NULL; } // end of FNCCOL constructor /***********************************************************************/ -/* FNCCOL initialization function. */ +/* FNCCOL initialization function. */ /***********************************************************************/ -bool FNCCOL::InitColumn(PGLOBAL g, PVAL valp) +bool FNCCOL::InitColumn(PGLOBAL g) { - char *p, buf[128]; - int len; - // Must have its own value block if (InitValue(g)) return TRUE; - // Convert header value to a null terminated character string - Hval = valp; - p = Hval->GetCharString(buf); - len = strlen(p) + 1; + // Make a value from the column name + Hval = AllocateValue(g, Name, TYPE_STRING); + Hval->SetPrec(1); // Case insensitive - if (len > (signed)sizeof(buf)) { - strcpy(g->Message, MSG(COLNAM_TOO_LONG)); - return TRUE; - } // endif buf - - // Set the name of the functional pivot column - Name = (PSZ)PlugSubAlloc(g, NULL, len); - strcpy(Name, p); + Xcolp = ((PTDBPIVOT)To_Tdb)->Xcolp; AddStatus(BUF_READ); // All is done here return FALSE; } // end of InitColumn -// ------------------------ SRCCOL functions ---------------------------- - -#if 0 /***********************************************************************/ -/* SRCCOL public constructor. */ +/* CompareColumn: Compare column value with source column value. */ /***********************************************************************/ -SRCCOL::SRCCOL(PCOLDEF cdp, PTDBPIVOT tdbp, int n) - : COLBLK(cdp, tdbp, n) +bool FNCCOL::CompareColumn(void) { - // Set additional SRC access method information for column. - Colp = NULL; - Cnval = NULL; - } // end of SRCCOL constructor -#endif // 0 + // Compare the unconverted values + return Hval->IsEqual(Xcolp->GetValue(), false); + } // end of CompareColumn + +// ------------------------ SRCCOL functions ---------------------------- /***********************************************************************/ /* SRCCOL public constructor. */ /***********************************************************************/ -SRCCOL::SRCCOL(PCOL cp, PTDBPIVOT tdbp, int n) - : COLBLK(cp, tdbp) +SRCCOL::SRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int n) + : PRXCOL(cdp, tdbp, cprec, n) { - Index = n; - - // Set additional SRC access method information for column. - Colp = (PQRSCOL)cp; - - // Don't share Value with the source column so we can compare - Cnval = Value = NULL; } // end of SRCCOL constructor -#if 0 -/***********************************************************************/ -/* SRCCOL constructor used for copying columns. */ -/* tdbp is the pointer to the new table descriptor. */ -/***********************************************************************/ -SRCCOL::SRCCOL(SRCCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp) - { - Colp = col1->Colp; - } // end of SRCCOL copy constructor -#endif // 0 - /***********************************************************************/ /* Initialize the column as pointing to the source column. */ /***********************************************************************/ -bool SRCCOL::Init(PGLOBAL g, PTDBPIVOT tdbp) +bool SRCCOL::Init(PGLOBAL g) { - // Currently we ignore the type of the create table column - bool conv = FALSE; - -#if 0 - if (!Colp) { - // Column was defined in the Create Table statement - if (!(Colp = tdbp->ColDB(g, Name, 0))) - return TRUE; - - // We can have a conversion problem converting from numeric to - // character because GetCharValue does not exist for numeric types. - conv = (IsTypeChar(Buf_Type) && IsTypeNum(Colp->GetResultType())); - } else -#endif // 0 - conv = FALSE; - - if (InitValue(g)) - return TRUE; - -//if (conv) -// Cnval = AllocateValue(g, Colp->GetValue()); -//else - Cnval = Value; + if (PRXCOL::Init(g)) + return true; AddStatus(BUF_READ); // All is done here - return FALSE; + return false; } // end of SRCCOL constructor /***********************************************************************/ @@ -863,340 +801,16 @@ bool SRCCOL::Init(PGLOBAL g, PTDBPIVOT tdbp) /***********************************************************************/ void SRCCOL::SetColumn(void) { -#if defined(_DEBUG) - Cnval->SetValue_pval(Colp->GetValue(), TRUE); -#else - Cnval->SetValue_pval(Colp->GetValue()); -#endif // _DEBUG - - if (Value != Cnval) - // Convert value - Value->SetValue_pval(Cnval); - + Value->SetValue_pval(To_Val); } // end of SetColumn /***********************************************************************/ /* SetColumn: Compare column value with source column value. */ /***********************************************************************/ -bool SRCCOL::CompareColumn(void) +bool SRCCOL::CompareLast(void) { // Compare the unconverted values - return Cnval->CompareValue(Colp->GetValue()); + return !Value->IsEqual(To_Val, true); } // end of CompareColumn - -/* ------------------------------------------------------------------- */ - -/***********************************************************************/ -/* Implementation of the TDBQRS class. */ -/***********************************************************************/ -TDBQRS::TDBQRS(PTDBQRS tdbp) : TDBASE(tdbp) - { - Qrp = tdbp->Qrp; - CurPos = tdbp->CurPos; - } // end of TDBQRS copy constructor - -// Method -PTDB TDBQRS::CopyOne(PTABS t) - { - PTDB tp; - PQRSCOL cp1, cp2; - PGLOBAL g = t->G; // Is this really useful ??? - - tp = new(g) TDBQRS(this); - - for (cp1 = (PQRSCOL)Columns; cp1; cp1 = (PQRSCOL)cp1->GetNext()) { - cp2 = new(g) QRSCOL(cp1, tp); // Make a copy - NewPointer(t, cp1, cp2); - } // endfor cp1 - - return tp; - } // end of CopyOne - -#if 0 // The TDBASE functions return NULL when To_Def is NULL -/***********************************************************************/ -/* Return the pointer on the DB catalog this table belongs to. */ -/***********************************************************************/ -PCATLG TDBQRS::GetCat(void) - { - // To_Def is null for QRYRES tables - return NULL; - } // end of GetCat - -/***********************************************************************/ -/* Return the datapath of the DB this table belongs to. */ -/***********************************************************************/ -PSZ TDBQRS::GetPath(void) - { - // To_Def is null for QRYRES tables - return NULL; - } // end of GetPath -#endif // 0 - -/***********************************************************************/ -/* Initialize QRS column description block construction. */ -/* name is used to call columns by name. */ -/* num is used by LNA to construct columns by index number. */ -/* Note: name=Null and num=0 for constructing all columns (select *) */ -/***********************************************************************/ -PCOL TDBQRS::ColDB(PGLOBAL g, PSZ name, int num) - { - int i; - PCOLRES crp; - PCOL cp, colp = NULL, cprec = NULL; - - if (trace) - htrc("QRS ColDB: colname=%s tabname=%s num=%d\n", - SVP(name), Name, num); - - for (crp = Qrp->Colresp, i = 1; crp; crp = crp->Next, i++) - if ((!name && !num) || - (name && !stricmp(crp->Name, name)) || num == i) { - // Check for existence of desired column - // Also find where to insert the new block - for (cp = Columns; cp; cp = cp->GetNext()) - if (cp->GetIndex() < i) - cprec = cp; - else if (cp->GetIndex() == i) - break; - - if (trace) { - if (cp) - htrc("cp(%d).Name=%s cp=%p\n", i, cp->GetName(), cp); - else - htrc("cp(%d) cp=%p\n", i, cp); - } // endif trace - - // Now take care of Column Description Block - if (cp) - colp = cp; - else - colp = new(g) QRSCOL(g, crp, this, cprec, i); - - if (name || num) - break; - else - cprec = colp; - - } // endif Name - - return (colp); - } // end of ColDB - -/***********************************************************************/ -/* QRS GetMaxSize: returns maximum table size in number of lines. */ -/***********************************************************************/ -int TDBQRS::GetMaxSize(PGLOBAL g) - { - MaxSize = Qrp->Maxsize; - return MaxSize; - } // end of GetMaxSize - -/***********************************************************************/ -/* RowNumber: returns the current row ordinal number. */ -/***********************************************************************/ -int TDBQRS::RowNumber(PGLOBAL g, BOOL b) - { - return (CurPos + 1); - } // end of RowNumber - -/***********************************************************************/ -/* QRS Access Method opening routine. */ -/* New method now that this routine is called recursively (last table */ -/* first in reverse order): index blocks are immediately linked to */ -/* join block of next table if it exists or else are discarted. */ -/***********************************************************************/ -bool TDBQRS::OpenDB(PGLOBAL g) - { - if (trace) - htrc("QRS OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n", - this, Tdb_No, Use, To_Key_Col, Mode); - - if (Mode != MODE_READ) { - sprintf(g->Message, MSG(BAD_QUERY_OPEN), Mode); - return TRUE; - } // endif Mode - - CurPos = -1; - - if (Use == USE_OPEN) { - /*******************************************************************/ - /* Table already open, just replace it at its beginning. */ - /*******************************************************************/ - if (To_Kindex) - /*****************************************************************/ - /* Table is to be accessed through a sorted index table. */ - /*****************************************************************/ - To_Kindex->Reset(); - - return FALSE; - } // endif use - - /*********************************************************************/ - /* Open (retrieve data from) the query if not already open. */ - /*********************************************************************/ - Use = USE_OPEN; // Do it now in case we are recursively called - - return FALSE; - } // end of OpenDB - -/***********************************************************************/ -/* GetRecpos: returns current position of next sequential read. */ -/***********************************************************************/ -int TDBQRS::GetRecpos(void) - { - return (CurPos); - } // end of GetRecpos - -/***********************************************************************/ -/* ReadDB: Data Base read routine for QRS access method. */ -/***********************************************************************/ -int TDBQRS::ReadDB(PGLOBAL g) - { - int rc = RC_OK; - - if (trace) - htrc("QRS ReadDB: R%d CurPos=%d key=%p link=%p Kindex=%p\n", - GetTdb_No(), CurPos, To_Key_Col, To_Link, To_Kindex); - - if (To_Kindex) { - /*******************************************************************/ - /* Reading is by an index table. */ - /*******************************************************************/ - int recpos = To_Kindex->Fetch(g); - - switch (recpos) { - case -1: // End of file reached - rc = RC_EF; - break; - case -2: // No match for join - rc = RC_NF; - break; - case -3: // Same record as last non null one - rc = RC_OK; - break; - default: - /***************************************************************/ - /* Set the file position according to record to read. */ - /***************************************************************/ - CurPos = recpos; - } // endswitch recpos - - if (trace) - htrc("Position is now %d\n", CurPos); - - } else - /*******************************************************************/ - /* !To_Kindex ---> sequential reading */ - /*******************************************************************/ - rc = (++CurPos < Qrp->Nblin) ? RC_OK : RC_EF; - - return rc; - } // end of ReadDB - -/***********************************************************************/ -/* Dummy WriteDB: just send back an error return. */ -/***********************************************************************/ -int TDBQRS::WriteDB(PGLOBAL g) - { - strcpy(g->Message, MSG(QRY_READ_ONLY)); - return RC_FX; - } // end of WriteDB - -/***********************************************************************/ -/* Dummy DeleteDB routine, just returns an error code. */ -/***********************************************************************/ -int TDBQRS::DeleteDB(PGLOBAL g, int irc) - { - strcpy(g->Message, MSG(NO_QRY_DELETE)); - return RC_FX; - } // end of DeleteDB - -/***********************************************************************/ -/* Data Base close routine for QRS access method. */ -/***********************************************************************/ -void TDBQRS::CloseDB(PGLOBAL g) - { - if (To_Kindex) { - To_Kindex->Close(); - To_Kindex = NULL; - } // endif - - if (trace) - htrc("Qryres CloseDB"); - -//Qryp->Sqlp->CloseDB(); - } // end of CloseDB - -// ------------------------ QRSCOL functions ---------------------------- - -/***********************************************************************/ -/* QRSCOL public constructor. */ -/***********************************************************************/ -QRSCOL::QRSCOL(PGLOBAL g, PCOLRES crp, PTDB tdbp, PCOL cprec, int i) - : COLBLK(NULL, tdbp, i) - { - if (cprec) { - Next = cprec->GetNext(); - cprec->SetNext(this); - } else { - Next = tdbp->GetColumns(); - tdbp->SetColumns(this); - } // endif cprec - - // Set additional QRS access method information for column. - Crp = crp; - Name = Crp->Name; - Long = Crp->Clen; - Buf_Type = crp->Type; - strcpy(Format.Type, GetFormatType(Buf_Type)); - Format.Length = (SHORT)Long; - Format.Prec = (SHORT)Crp->Prec; - - if (trace) { - htrc("Making new QRSCOL C%d %s at %p\n", Index, Name, this); - htrc(" BufType=%d Long=%d length=%d clen=%d\n", - Buf_Type, Long, Format.Length, Crp->Clen); - } // endif trace - - } // end of QRSCOL constructor - -/***********************************************************************/ -/* QRSCOL constructor used for copying columns. */ -/* tdbp is the pointer to the new table descriptor. */ -/***********************************************************************/ -QRSCOL::QRSCOL(QRSCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp) - { - Crp = col1->Crp; - } // end of QRSCOL copy constructor - -/***********************************************************************/ -/* ReadColumn: what this routine does is to extract the RESCOL block */ -/* current value and convert it to the column buffer type. */ -/***********************************************************************/ -void QRSCOL::ReadColumn(PGLOBAL g) - { - PTDBQRS tdbp = (PTDBQRS)To_Tdb; - - if (trace) - htrc("QRS RC: col %s R%d type=%d CurPos=%d Len=%d\n", - Name, tdbp->GetTdb_No(), Buf_Type, tdbp->CurPos, Crp->Clen); - - if (Crp->Kdata) - Value->SetValue_pvblk(Crp->Kdata, tdbp->CurPos); - else - Value->Reset(); - - } // end of ReadColumn - -/***********************************************************************/ -/* Make file output of a Dos column descriptor block. */ -/***********************************************************************/ -void QRSCOL::Print(PGLOBAL g, FILE *f, UINT n) - { - COLBLK::Print(g, f, n); - - fprintf(f, " Crp=%p\n", Crp); - } // end of Print - /* --------------------- End of TabPivot/TabQrs ---------------------- */ diff --git a/storage/connect/tabpivot.h b/storage/connect/tabpivot.h index fb480b9abbf..170c6b67ea4 100644 --- a/storage/connect/tabpivot.h +++ b/storage/connect/tabpivot.h @@ -1,15 +1,48 @@ /************** TabPivot H Declares Source Code File (.H) **************/ -/* Name: TABPIVOT.H Version 1.3 */ +/* Name: TABPIVOT.H Version 1.5 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */ /* */ /* This file contains the PIVOT classes declares. */ /***********************************************************************/ +typedef class PIVOTDEF *PPIVOTDEF; typedef class TDBPIVOT *PTDBPIVOT; typedef class FNCCOL *PFNCCOL; typedef class SRCCOL *PSRCCOL; -typedef class TDBQRS *PTDBQRS; -typedef class QRSCOL *PQRSCOL; + +/***********************************************************************/ +/* This class is used to generate PIVOT table column definitions. */ +/***********************************************************************/ +class PIVAID : public CSORT { + friend class FNCCOL; + friend class SRCCOL; + public: + // Constructor + PIVAID(const char *tab, const char *src, const char *picol, + const char *fncol, const char *host, const char *db, + const char *user, const char *pwd, int port); + + // Methods + PQRYRES MakePivotColumns(PGLOBAL g); + + // The sorting function + virtual int Qcompare(int *, int *); + + protected: + // Members + MYSQLC Myc; // MySQL connection class + char *Host; // Host machine to use + char *User; // User logon info + char *Pwd; // Password logon info + char *Database; // Database to be used by server + PQRYRES Qryp; // Points to Query result block + char *Tabname; // Name of source table + char *Tabsrc; // SQL of source table + char *Picol; // Pivot column name + char *Fncol; // Function column name + PVBLK Rblkp; // The value block of the pivot column + int Port; // MySQL port number + }; // end of class PIVAID /* -------------------------- PIVOT classes -------------------------- */ @@ -22,13 +55,11 @@ typedef class QRSCOL *PQRSCOL; /***********************************************************************/ /* PIVOT table. */ /***********************************************************************/ -//ass DllExport PIVOTDEF : public TABDEF {/* Logical table description */ -class PIVOTDEF : public TABDEF { /* Logical table description */ +class PIVOTDEF : public PRXDEF { /* Logical table description */ friend class TDBPIVOT; public: // Constructor - PIVOTDEF(void) {Pseudo = 3; - Tabname = Tabsrc = Picol = Fncol = Function = NULL;} + PIVOTDEF(void); // Implementation virtual const char *GetType(void) {return "PIVOT";} @@ -39,38 +70,33 @@ class PIVOTDEF : public TABDEF { /* Logical table description */ protected: // Members - char *Host; /* Host machine to use */ - char *User; /* User logon info */ - char *Pwd; /* Password logon info */ - char *DB; /* Database to be used by server */ - char *Tabname; /* Name of source table */ + char *Host; /* Host machine to use */ + char *User; /* User logon info */ + char *Pwd; /* Password logon info */ + char *DB; /* Database to be used by server */ + char *Tabname; /* Name of source table */ char *Tabsrc; /* The source table SQL description */ - char *Picol; /* The pivot column */ + char *Picol; /* The pivot column */ char *Fncol; /* The function column */ char *Function; /* The function applying to group by */ bool GBdone; /* True if tabname as group by format */ - int Port; /* MySQL port number */ + bool Accept; /* TRUE if no match is accepted */ + int Port; /* MySQL port number */ }; // end of PIVOTDEF /***********************************************************************/ /* This is the class declaration for the PIVOT table. */ /***********************************************************************/ -//ass DllExport TDBPIVOT : public TDBASE, public CSORT { -class TDBPIVOT : public TDBASE, public CSORT { +class TDBPIVOT : public TDBPRX { friend class FNCCOL; - friend class SRCCOL; public: // Constructor TDBPIVOT(PPIVOTDEF tdp); -//TDBPIVOT(PTDBPIVOT tdbp); // Implementation virtual AMT GetAmType(void) {return TYPE_AM_PIVOT;} -//virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBPIVOT(this);} -// void SetTdbp(PTDB tdbp) {Tdbp = tdbp;} // Methods -//virtual PTDB CopyOne(PTABS t); virtual int GetRecpos(void) {return N;} virtual void ResetDB(void) {N = 0;} virtual int RowNumber(PGLOBAL g, bool b = FALSE); @@ -84,40 +110,35 @@ class TDBPIVOT : public TDBASE, public CSORT { virtual int DeleteDB(PGLOBAL g, int irc); virtual void CloseDB(PGLOBAL g); - // The sorting function - virtual int Qcompare(int *, int *); - protected: - PQRYRES GetSourceTable(PGLOBAL g); - int MakePivotColumns(PGLOBAL g); - bool UpdateTableFields(PGLOBAL g, int n); + // Internal routines + bool FindDefaultColumns(PGLOBAL g); + bool GetSourceTable(PGLOBAL g); + bool MakePivotColumns(PGLOBAL g); + bool MakeViewColumns(PGLOBAL g); // Members - MYSQLC Myc; // MySQL connection class - PTDBQRS Tqrp; // To the source table result - char *Host; // Host machine to use - char *User; // User logon info - char *Pwd; // Password logon info - char *Database; // Database to be used by server - PQRYRES Qryp; // Points to Query result block - char *Tabname; // Name of source table - char *Tabsrc; // SQL of source table - char *Picol; // Pivot column name - char *Fncol; // Function column name - char *Function; // The function applying to group by - PQRSCOL Fcolp; // To the function column in source - PQRSCOL Xcolp; // To the pivot column in source - PCOLRES Xresp; // To the pivot result column -//PCOLRES To_Sort; // Saved Qryp To_Sort pointer - PVBLK Rblkp; // The value block of the pivot column - bool GBdone; // True when subtable is "Group by" - int Mult; // Multiplication factor - int Ncol; // The number of generated columns - int N; // The current table index - int M; // The occurence rank - int Port; // MySQL port number - BYTE FileStatus; // 0: First 1: Rows 2: End-of-File - BYTE RowFlag; // 0: Ok, 1: Same, 2: Skip + char *Host; // Host machine to use + char *User; // User logon info + char *Pwd; // Password logon info + char *Database; // Database to be used by server + char *Tabname; // Name of source table + char *Tabsrc; // SQL of source table + char *Picol; // Pivot column name + char *Fncol; // Function column name + char *Function; // The function applying to group by + PCOL Fcolp; // To the function column in source + PCOL Xcolp; // To the pivot column in source + PCOL Dcolp; // To the dump column + bool GBdone; // True when subtable is "Group by" + bool Accept; // TRUE if no match is accepted + int Mult; // Multiplication factor + int Ncol; // The number of generated columns + int N; // The current table index + int M; // The occurence rank + int Port; // MySQL port number + BYTE FileStatus; // 0: First 1: Rows 2: End-of-File + BYTE RowFlag; // 0: Ok, 1: Same, 2: Skip }; // end of class TDBPIVOT /***********************************************************************/ @@ -127,30 +148,30 @@ class FNCCOL : public COLBLK { friend class TDBPIVOT; public: // Constructor - FNCCOL(PCOL colp, PTDBPIVOT tdbp); + FNCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i); // Implementation virtual int GetAmType(void) {return TYPE_AM_FNC;} // Methods virtual void Reset(void) {} - bool InitColumn(PGLOBAL g, PVAL valp); + bool InitColumn(PGLOBAL g); + bool CompareColumn(void); protected: // Member - PVAL Hval; // The original value used to generate the header + PVAL Hval; // The value containing the header + PCOL Xcolp; }; // end of class FNCCOL /***********************************************************************/ /* Class SRCCOL: for other source columns. */ /***********************************************************************/ -class SRCCOL : public COLBLK { +class SRCCOL : public PRXCOL { friend class TDBPIVOT; public: // Constructors -//SRCCOL(PCOLDEF cdp, PTDBPIVOT tdbp, int n); - SRCCOL(PCOL cp, PTDBPIVOT tdbp, int n); -//SRCCOL(SRCCOL *colp, PTDB tdbp); // Constructor used in copy process + SRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int n); // Implementation virtual int GetAmType(void) {return TYPE_AM_SRC;} @@ -158,84 +179,12 @@ class SRCCOL : public COLBLK { // Methods virtual void Reset(void) {} void SetColumn(void); - bool Init(PGLOBAL g, PTDBPIVOT tdbp); - bool CompareColumn(void); + bool Init(PGLOBAL g); + bool CompareLast(void); protected: // Default constructor not to be used SRCCOL(void) {} // Members - PQRSCOL Colp; - PVAL Cnval; }; // end of class SRCCOL - -/***********************************************************************/ -/* TDBQRS: This is the Access Method class declaration for the Query */ -/* Result stored in memory in the current work area (volatil). */ -/***********************************************************************/ -class DllExport TDBQRS : public TDBASE { - friend class QRSCOL; - public: - // Constructor - TDBQRS(PQRYRES qrp) : TDBASE() {Qrp = qrp; CurPos = 0;} - TDBQRS(PTDBQRS tdbp); - - // Implementation - virtual AMT GetAmType(void) {return TYPE_AM_QRS;} - virtual PTDB Duplicate(PGLOBAL g) - {return (PTDB)new(g) TDBQRS(this);} - PQRYRES GetQrp(void) {return Qrp;} - - // Methods - virtual PTDB CopyOne(PTABS t); - virtual int RowNumber(PGLOBAL g, BOOL b = FALSE); - virtual int GetRecpos(void); -//virtual PCATLG GetCat(void); -//virtual PSZ GetPath(void); - virtual int GetBadLines(void) {return Qrp->BadLines;} - - // Database routines - virtual PCOL ColDB(PGLOBAL g, PSZ name, int num); - virtual int GetMaxSize(PGLOBAL g); - virtual bool OpenDB(PGLOBAL g); - virtual int ReadDB(PGLOBAL g); - virtual int WriteDB(PGLOBAL g); - virtual int DeleteDB(PGLOBAL g, int irc); - virtual void CloseDB(PGLOBAL g); - - private: - TDBQRS(void) : TDBASE() {} // Standard constructor not to be used - - protected: - // Members - PQRYRES Qrp; // Points to Query Result block - int CurPos; // Current line position - }; // end of class TDBQRS - -/***********************************************************************/ -/* Class QRSCOL: QRS access method column descriptor. */ -/***********************************************************************/ -class DllExport QRSCOL : public COLBLK { - friend class TDBQRS; - public: - // Constructors - QRSCOL(PGLOBAL g, PCOLRES crp, PTDB tdbp, PCOL cprec, int i); - QRSCOL(QRSCOL *colp, PTDB tdbp); // Constructor used in copy process - - // Implementation - virtual int GetAmType(void) {return TYPE_AM_QRS;} - PCOLRES GetCrp(void) {return Crp;} - void *GetQrsData(void) {return Crp->Kdata;} - - // Methods - virtual void ReadColumn(PGLOBAL g); - virtual void Print(PGLOBAL g, FILE *, UINT); - - protected: - QRSCOL(void) {} // Default constructor not to be used - - // Members - PCOLRES Crp; - }; // end of class QRSCOL - diff --git a/storage/connect/tabsys.cpp b/storage/connect/tabsys.cpp index 9f933e4e2b8..6434e011882 100644 --- a/storage/connect/tabsys.cpp +++ b/storage/connect/tabsys.cpp @@ -41,9 +41,7 @@ #include "tabdos.h" #include "tabsys.h" #include "tabmul.h" -#if defined(UNIX) -#include "osutil.h" -#endif // UNIX +#include "inihandl.h" #define CSZ 36 // Column section name length #define CDZ 256 // Column definition length @@ -65,7 +63,6 @@ INIDEF::INIDEF(void) Pseudo = 3; Fn = NULL; Xname = NULL; - Subtype = '?'; Layout = '?'; Ln = 0; } // end of INIDEF constructor @@ -75,63 +72,23 @@ INIDEF::INIDEF(void) /***********************************************************************/ bool INIDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) { - char buf[8], ds[2]; - void *memp = Cat->GetDescp(); - - if (!stricmp(am, "SYS")) - strcpy(ds, "T"); // SYS tables default to T(able) - else - strcpy(ds, "I"); // INI tables default to I(ni) + char buf[8]; Fn = Cat->GetStringCatInfo(g, "Filename", NULL); - Cat->GetCharCatInfo("Subtype", ds, buf, sizeof(buf)); - Subtype = toupper(*buf); Cat->GetCharCatInfo("Layout", "C", buf, sizeof(buf)); Layout = toupper(*buf); - switch (Subtype) { -#if 0 - case 'C': - case 'T': - // Restricted table - Xname = Cat->GetStringCatInfo(g, "Name", "?"); - - if (!strcmp(Xname, "?")) - Xname = NULL; - - if (*Fn == '?') - Fn = Cat->GetStringCatInfo(g, "Database", "?"); - - if (*Fn != '?') { - char *p = (char*)PlugSubAlloc(g, memp, _MAX_PATH); - - if (!PlgSetXdbPath(g, Fn, NULL, p, _MAX_PATH, NULL, 0)) - Fn = p; - - } else - Fn = Cat->GetDescFile(); + if (Fn) { + char *p = (char*)PlugSubAlloc(g, NULL, _MAX_PATH); - Ln = GetIniSize("Database", "Tabsize", "2K", Fn); - break; -#endif // 0 - case 'I': - if (*Fn != '?') { - char *p = (char*)PlugSubAlloc(g, memp, _MAX_PATH); - - PlugSetPath(p, Fn, GetPath()); - Fn = p; - } else { - strcpy(g->Message, MSG(MISSING_FNAME)); - return true; - } // endif Fn - - Ln = Cat->GetSizeCatInfo("Secsize", "8K"); - break; - default: - sprintf(g->Message, MSG(INV_SUBTYPE), buf); - return true; - } // endswitch Subtype + PlugSetPath(p, Fn, GetPath()); + Fn = p; + } else { + strcpy(g->Message, MSG(MISSING_FNAME)); + return true; + } // endif Fn + Ln = Cat->GetSizeCatInfo("Secsize", "8K"); Desc = Fn; return false; } // end of DefineAM @@ -143,17 +100,10 @@ PTDB INIDEF::GetTable(PGLOBAL g, MODE m) { PTDBASE tdbp; - switch (Subtype) { - case 'I': - if (Layout == 'C') - tdbp = new(g) TDBINI(this); - else - tdbp = new(g) TDBXIN(this); - - break; - default: - return NULL; - } // endswitch Subtype + if (Layout == 'C') + tdbp = new(g) TDBINI(this); + else + tdbp = new(g) TDBXIN(this); if (Multiple) tdbp = new(g) TDBMUL(tdbp); // No block optimization yet @@ -163,7 +113,6 @@ PTDB INIDEF::GetTable(PGLOBAL g, MODE m) /***********************************************************************/ /* DeleteTableFile: Delete INI table files using platform API. */ -/* SysTable and SysColumn tables are readonly and not erasable. */ /***********************************************************************/ bool INIDEF::DeleteTableFile(PGLOBAL g) { @@ -171,7 +120,7 @@ bool INIDEF::DeleteTableFile(PGLOBAL g) bool rc; // Delete the INI table file if not protected - if (Subtype == 'I' && !IsReadOnly()) { + if (!IsReadOnly()) { PlugSetPath(filename, Fn, GetPath()); #if defined(WIN32) rc = !DeleteFile(filename); diff --git a/storage/connect/tabsys.h b/storage/connect/tabsys.h index ac8ae05aee9..2780eb3ca98 100644 --- a/storage/connect/tabsys.h +++ b/storage/connect/tabsys.h @@ -38,7 +38,6 @@ class DllExport INIDEF : public TABDEF { /* INI table description */ // Members char *Fn; /* Path/Name of corresponding file */ char *Xname; /* The eventual table name */ - char Subtype; /* I: INI, T: Table, C: Column */ char Layout; /* R: Row, C: Column */ int Ln; /* Length of section list buffer */ }; // end of INIDEF @@ -83,8 +82,8 @@ class TDBINI : public TDBASE { // Members char *Ifile; // The INI file char *Seclist; // The section list - char *Section; // The current section - int Seclen; // Length of seclist buffer + char *Section; // The current section + int Seclen; // Length of seclist buffer int N; // The current section index }; // end of class TDBINI diff --git a/storage/connect/tabtbl.cpp b/storage/connect/tabtbl.cpp index b194da3fc09..89acc53fd4a 100644 --- a/storage/connect/tabtbl.cpp +++ b/storage/connect/tabtbl.cpp @@ -1,7 +1,7 @@ /************* TabTbl C++ Program Source Code File (.CPP) **************/ /* PROGRAM NAME: TABTBL */ /* ------------- */ -/* Version 1.4 */ +/* Version 1.6 */ /* */ /* COPYRIGHT: */ /* ---------- */ @@ -70,13 +70,23 @@ #include "filamtxt.h" #include "tabcol.h" #include "tabdos.h" // TDBDOS and DOSCOL class dcls -#include "tabtbl.h" // TDBTBL and TBLCOL classes dcls +#include "tabtbl.h" #if defined(MYSQL_SUPPORT) #include "tabmysql.h" #endif // MYSQL_SUPPORT #include "ha_connect.h" #include "mycat.h" // For GetHandler +#if defined(WIN32) +#if defined(__BORLANDC__) +#define SYSEXIT void _USERENTRY +#else +#define SYSEXIT void +#endif +#else // !WIN32 +#define SYSEXIT void * +#endif // !WIN32 + extern "C" int trace; /* ---------------------------- Class TBLDEF ---------------------------- */ @@ -86,7 +96,10 @@ extern "C" int trace; /**************************************************************************/ TBLDEF::TBLDEF(void) { - To_Tables = NULL; +//To_Tables = NULL; + Accept = false; + Thread = false; + Maxerr = 0; Ntables = 0; Pseudo = 3; } // end of TBLDEF constructor @@ -100,18 +113,18 @@ bool TBLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) Desc = "Table list table"; tablist = Cat->GetStringCatInfo(g, "Tablist", ""); - dbname = Cat->GetStringCatInfo(g, "Database", NULL); + dbname = Cat->GetStringCatInfo(g, "Dbname", "*"); Ntables = 0; if (*tablist) { - char *p, *pn, *pdb; - PTBL *ptbl = &To_Tables, tbl; + char *p, *pn, *pdb; + PTABLE tbl; for (pdb = tablist; ;) { if ((p = strchr(pdb, ','))) *p = 0; - // Analyze the table name, it has the format: + // Analyze the table name, it may have the format: // [dbname.]tabname if ((pn = strchr(pdb, '.'))) { *pn++ = 0; @@ -121,17 +134,18 @@ bool TBLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) } // endif p // Allocate the TBLIST block for that table - tbl = (PTBL)PlugSubAlloc(g, NULL, sizeof(TBLIST)); - tbl->Next = NULL; - tbl->Name = pn; - tbl->DB = pdb; + tbl = new(g) XTAB(pn); + tbl->SetQualifier(pdb); if (trace) - htrc("TBL: Name=%s db=%s\n", tbl->Name, SVP(tbl->DB)); + htrc("TBL: Name=%s db=%s\n", tbl->GetName(), tbl->GetQualifier()); // Link the blocks - *ptbl = tbl; - ptbl = &tbl->Next; + if (Tablep) + Tablep->Link(tbl); + else + Tablep = tbl; + Ntables++; if (p) @@ -142,8 +156,9 @@ bool TBLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) } // endfor pdb Maxerr = Cat->GetIntCatInfo("Maxerr", 0); - Accept = (Cat->GetBoolCatInfo("Accept", 0) != 0); - } // endif fsec || tablist + Accept = Cat->GetBoolCatInfo("Accept", false); + Thread = Cat->GetBoolCatInfo("Thread", false); + } // endif tablist return FALSE; } // end of DefineAM @@ -153,15 +168,13 @@ bool TBLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) /***********************************************************************/ PTDB TBLDEF::GetTable(PGLOBAL g, MODE m) { - PTDB tdbp; - - /*********************************************************************/ - /* Allocate a TDB of the proper type. */ - /* Column blocks will be allocated only when needed. */ - /*********************************************************************/ - tdbp = new(g) TDBTBL(this); + if (Catfunc == FNC_COL) + return new(g) TDBTBC(this); + else if (Thread) + return new(g) TDBTBM(this); + else + return new(g) TDBTBL(this); - return tdbp; } // end of GetTable /* ------------------------- Class TDBTBL ---------------------------- */ @@ -169,14 +182,14 @@ PTDB TBLDEF::GetTable(PGLOBAL g, MODE m) /***********************************************************************/ /* TDBTBL constructors. */ /***********************************************************************/ -TDBTBL::TDBTBL(PTBLDEF tdp) : TDBASE(tdp) +TDBTBL::TDBTBL(PTBLDEF tdp) : TDBPRX(tdp) { Tablist = NULL; CurTable = NULL; - Tdbp = NULL; +//Tdbp = NULL; Accept = tdp->Accept; Maxerr = tdp->Maxerr; - Nbf = 0; + Nbc = 0; Rows = 0; Crp = 0; // NTables = 0; @@ -188,7 +201,7 @@ TDBTBL::TDBTBL(PTBLDEF tdp) : TDBASE(tdp) /***********************************************************************/ PCOL TDBTBL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) { - return new(g) TBLCOL(cdp, this, cprec, n); + return new(g) PRXCOL(cdp, this, cprec, n); } // end of MakeCol /***********************************************************************/ @@ -213,125 +226,38 @@ PCOL TDBTBL::InsertSpecialColumn(PGLOBAL g, PCOL scp) } // end of InsertSpecialColumn /***********************************************************************/ -/* Get the PTDB of a table of the list. */ -/***********************************************************************/ -PTDB TDBTBL::GetSubTable(PGLOBAL g, PTBL tblp, PTABLE tabp) - { - char *db, key[256]; - uint k; - PTDB tdbp = NULL; - TABLE_SHARE *s; - PCATLG cat = To_Def->GetCat(); - PHC hc = ((MYCAT*)cat)->GetHandler(); - THD *thd = (hc->GetTable())->in_use; - - if (!thd) - return NULL; // Should not happen anymore - - if (tblp->DB) - db = tblp->DB; - else - db = (char*)hc->GetDBName(NULL); - - k = sprintf(key, "%s", db) + 1; - k += sprintf(key + k, "%s", tblp->Name); - key[++k] = 0; - - if (!(s = alloc_table_share(db, tblp->Name, key, ++k))) { - strcpy(g->Message, "Error allocating share\n"); - return NULL; - } // endif s - - if (!open_table_def(thd, s)) { - if (plugin_data(s->db_plugin, handlerton*) != connect_hton) { -#if defined(MYSQL_SUPPORT) - // Access sub-table via MySQL API - if (!(tdbp= cat->GetTable(g, tabp, MODE_READ, "MYSQL"))) { - sprintf(g->Message, "Cannot access %s.%s", db, tblp->Name); - return NULL; - } // endif Define - - if (tabp->GetQualifier()) - ((PTDBMY)tdbp)->SetDatabase(tabp->GetQualifier()); - -#else // !MYSQL_SUPPORT - sprintf(g->Message, "%s.%s is not a CONNECT table", - db, tblp->Name); - return NULL; -#endif // MYSQL_SUPPORT - } else { - // Sub-table is a CONNECT table - hc->tshp = s; - tdbp = cat->GetTable(g, tabp); - hc->tshp = NULL; - } // endif plugin - - } else - sprintf(g->Message, "Error %d opening share\n", s->error); - - if (trace && tdbp) - htrc("Subtable %s in %s\n", - tblp->Name, SVP(((PTDBASE)tdbp)->GetDef()->GetDB())); - - free_table_share(s); - return tdbp; - } // end of GetSubTable - -/***********************************************************************/ /* Initializes the table table list. */ /***********************************************************************/ bool TDBTBL::InitTableList(PGLOBAL g) { - char *colname; - int n, colpos; - PTBL tblp; - PTABLE tabp; - PTDB tdbp; + int n; + PTABLE tp, tabp; PCOL colp; PTBLDEF tdp = (PTBLDEF)To_Def; // PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath()); - for (n = 0, tblp = tdp->GetTables(); tblp; tblp = tblp->Next) { - if (TestFil(g, To_Filter, tblp)) { - // Table or named view - tabp = new(g) XTAB(tblp->Name); - tabp->SetQualifier(tblp->DB); + for (n = 0, tp = tdp->Tablep; tp; tp = tp->GetNext()) { + if (TestFil(g, To_Filter, tp)) { + tabp = new(g) XTAB(tp); // Get the table description block of this table - if (!(tdbp = GetSubTable(g, tblp, tabp))) { - if (++Nbf > Maxerr) + if (!(Tdbp = GetSubTable(g, tabp))) { + if (++Nbc > Maxerr) return TRUE; // Error return else continue; // Skip this table - } // endif tdbp + } else + RemoveNext(tabp); // To avoid looping // We must allocate subtable columns before GetMaxSize is called // because some (PLG, ODBC?) need to have their columns attached. // Real initialization will be done later. - for (PCOL cp = Columns; cp; cp = cp->GetNext()) - if (!cp->IsSpecial()) { - colname = cp->GetName(); - colpos = ((PTBLCOL)cp)->Colnum; - - // We try first to get the column by name - if (!(colp = tdbp->ColDB(g, colname, 0)) && colpos) - // When unsuccessful, if a column number was specified - // try to get the column by its position in the table - colp = tdbp->ColDB(g, NULL, colpos); - - if (!colp) { - if (!Accept) { - sprintf(g->Message, MSG(NO_MATCHING_COL), - colname, tdbp->GetName()); - return TRUE; // Error return - } // endif !Accept - - } else // this is needed in particular by PLG tables - colp->SetColUse(cp->GetColUse()); - - } // endif !special + for (colp = Columns; colp; colp = colp->GetNext()) + if (!colp->IsSpecial()) + if (((PPRXCOL)colp)->Init(g) && !Accept) + return TRUE; if (Tablist) Tablist->Link(tabp); @@ -341,7 +267,7 @@ bool TDBTBL::InitTableList(PGLOBAL g) n++; } // endif filp - } // endfor tblp + } // endfor tp //NumTables = n; To_Filter = NULL; // To avoid doing it several times @@ -351,7 +277,7 @@ bool TDBTBL::InitTableList(PGLOBAL g) /***********************************************************************/ /* Test the tablename against the pseudo "local" filter. */ /***********************************************************************/ -bool TDBTBL::TestFil(PGLOBAL g, PFIL filp, PTBL tblp) +bool TDBTBL::TestFil(PGLOBAL g, PFIL filp, PTABLE tabp) { char *fil, op[8], tn[NAME_LEN]; bool neg; @@ -374,7 +300,7 @@ bool TDBTBL::TestFil(PGLOBAL g, PFIL filp, PTBL tblp) if (sscanf(fil, "TABID = '%[^']'", tn) != 1) return TRUE; // ignore invalid filter - return !stricmp(tn, tblp->Name); + return !stricmp(tn, tabp->GetName()); } else if (!strcmp(op, "IN")) { char *p, *tnl = (char*)PlugSubAlloc(g, NULL, strlen(fil) - 10); int n; @@ -393,7 +319,7 @@ bool TDBTBL::TestFil(PGLOBAL g, PFIL filp, PTBL tblp) if (sscanf(tnl, "'%[^']'", tn) != 1) return TRUE; // ignore invalid filter - else if (!stricmp(tn, tblp->Name)) + else if (!stricmp(tn, tabp->GetName())) return !neg; // Found tnl = p; @@ -406,84 +332,20 @@ bool TDBTBL::TestFil(PGLOBAL g, PFIL filp, PTBL tblp) } // end of TestFil /***********************************************************************/ -/* TBL GetProgMax: get the max value for progress information. */ -/***********************************************************************/ -int TDBTBL::GetProgMax(PGLOBAL g) - { - PTABLE tblp; - int n, pmx = 0; - - if (!Tablist && InitTableList(g)) - return -1; - - for (tblp = Tablist; tblp; tblp = tblp->GetNext()) - if ((n = tblp->GetTo_Tdb()->GetProgMax(g)) > 0) - pmx += n; - - return pmx; - } // end of GetProgMax - -/***********************************************************************/ -/* TBL GetProgCur: get the current value for progress information. */ -/***********************************************************************/ -int TDBTBL::GetProgCur(void) - { - return Crp + Tdbp->GetProgCur(); - } // end of GetProgCur - -#if 0 -/***********************************************************************/ -/* TBL Cardinality: returns table cardinality in number of rows. */ -/* This function can be called with a null argument to test the */ -/* availability of Cardinality implementation (1 yes, 0 no). */ -/* Can be used on Multiple FIX table only. */ -/***********************************************************************/ -int TDBTBL::Cardinality(PGLOBAL g) - { - if (!g) - return Tdbp->Cardinality(g); - - if (!Tablist && InitTableList(g)) - return -1; - - int n, card = 0; - - for (int i = 0; i < NumFiles; i++) { - Tdbp->SetFile(g, Filenames[i]); - Tdbp->ResetSize(); - - if ((n = Tdbp->Cardinality(g)) < 0) { -// strcpy(g->Message, MSG(BAD_CARDINALITY)); - return -1; - } // endif n - - card += n; - } // endfor i - - return card; - } // end of Cardinality -#endif // 0 - -/***********************************************************************/ /* Sum up the sizes of all sub-tables. */ /***********************************************************************/ int TDBTBL::GetMaxSize(PGLOBAL g) { if (MaxSize < 0) { - PTABLE tblp; - int mxsz; + int mxsz; if (!Tablist && InitTableList(g)) return 0; // Cannot be calculated at this stage -// if (Use == USE_OPEN) { -// strcpy(g->Message, MSG(MAXSIZE_ERROR)); -// return -1; -// } else - MaxSize = 0; + MaxSize = 0; - for (tblp = Tablist; tblp; tblp = tblp->GetNext()) { - if ((mxsz = tblp->GetTo_Tdb()->GetMaxSize(g)) < 0) { + for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext()) { + if ((mxsz = tabp->GetTo_Tdb()->GetMaxSize(g)) < 0) { MaxSize = -1; return mxsz; } // endif mxsz @@ -505,8 +367,8 @@ void TDBTBL::ResetDB(void) if (colp->GetAmType() == TYPE_AM_TABID) colp->COLBLK::Reset(); - for (PTABLE tblp = Tablist; tblp; tblp = tblp->GetNext()) - ((PTDBASE)tblp->GetTo_Tdb())->ResetDB(); + for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext()) + ((PTDBASE)tabp->GetTo_Tdb())->ResetDB(); Tdbp = (PTDBASE)Tablist->GetTo_Tdb(); Crp = 0; @@ -538,23 +400,12 @@ bool TDBTBL::OpenDB(PGLOBAL g) return Tdbp->OpenDB(g); // Re-open fist table } // endif use -#if 0 - /*********************************************************************/ - /* Direct access needed for join or sorting. */ - /*********************************************************************/ - if (NeedIndexing(g)) { - // Direct access of TBL tables is not implemented yet - strcpy(g->Message, MSG(NO_MUL_DIR_ACC)); - return TRUE; - } // endif NeedIndexing -#endif // 0 - /*********************************************************************/ /* When GetMaxsize was called, To_Filter was not set yet. */ /*********************************************************************/ if (To_Filter && Tablist) { Tablist = NULL; - Nbf = 0; + Nbc = 0; } // endif To_Filter /*********************************************************************/ @@ -573,7 +424,7 @@ bool TDBTBL::OpenDB(PGLOBAL g) for (PCOL cp = Columns; cp; cp = cp->GetNext()) if (cp->GetAmType() == TYPE_AM_TABID) cp->COLBLK::Reset(); - else if (((PTBLCOL)cp)->Init(g)) + else if (((PPRXCOL)cp)->Init(g) && !Accept) return TRUE; if (trace) @@ -627,7 +478,7 @@ int TDBTBL::ReadDB(PGLOBAL g) for (PCOL cp = Columns; cp; cp = cp->GetNext()) if (cp->GetAmType() == TYPE_AM_TABID) cp->COLBLK::Reset(); - else if (((PTBLCOL)cp)->Init(g)) + else if (((PPRXCOL)cp)->Init(g) && !Accept) return RC_FX; if (trace) @@ -648,154 +499,276 @@ int TDBTBL::ReadDB(PGLOBAL g) return rc; } // end of ReadDB +/* ---------------------------- TBTBLK ------------------------------- */ + /***********************************************************************/ -/* Data Base write routine for MUL access method. */ +/* ReadColumn: */ /***********************************************************************/ -int TDBTBL::WriteDB(PGLOBAL g) +void TBTBLK::ReadColumn(PGLOBAL g) { - strcpy(g->Message, MSG(TABMUL_READONLY)); - return RC_FX; // NIY - } // end of WriteDB + if (trace) + htrc("TBT ReadColumn: name=%s\n", Name); + + Value->SetValue_psz((char*)((PTDBTBL)To_Tdb)->Tdbp->GetName()); + + } // end of ReadColumn + +/* ------------------------- Class TDBTBM ---------------------------- */ /***********************************************************************/ -/* Data Base delete line routine for MUL access method. */ +/* Thread routine that check and open one remote connection. */ /***********************************************************************/ -int TDBTBL::DeleteDB(PGLOBAL g, int irc) +pthread_handler_t ThreadOpen(void *p) { - strcpy(g->Message, MSG(TABMUL_READONLY)); - return RC_FX; // NIY - } // end of DeleteDB + PTBMT cmp = (PTBMT)p; + + if (!my_thread_init()) { + set_current_thd(cmp->Thd); + + // Try to open the connection + if (!cmp->Tap->GetTo_Tdb()->OpenDB(cmp->G)) { + cmp->Ready = true; + } else + cmp->Rc = RC_FX; + + my_thread_end(); + } else + cmp->Rc = RC_FX; + + return NULL; + } // end of ThreadOpen /***********************************************************************/ -/* Data Base close routine for MUL access method. */ +/* TDBTBM constructors. */ /***********************************************************************/ -void TDBTBL::CloseDB(PGLOBAL g) +TDBTBM::TDBTBM(PTBLDEF tdp) : TDBTBL(tdp) { - if (Tdbp) - Tdbp->CloseDB(g); - - } // end of CloseDB - -/* ---------------------------- TBLCOL ------------------------------- */ + Tmp = NULL; // To data table TBMT structures + Cmp = NULL; // Current data table TBMT + Bmp = NULL; // To bad (unconnected) TBMT structures + Done = false; // TRUE after first GetAllResults + Nrc = 0; // Number of remote connections + Nlc = 0; // Number of local connections + } // end of TDBTBL standard constructor /***********************************************************************/ -/* TBLCOL public constructor. */ +/* Reset read/write position values. */ /***********************************************************************/ -TBLCOL::TBLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am) - : COLBLK(cdp, tdbp, i) +void TDBTBM::ResetDB(void) { - if (cprec) { - Next = cprec->GetNext(); - cprec->SetNext(this); - } else { - Next = tdbp->GetColumns(); - tdbp->SetColumns(this); - } // endif cprec - - // Set additional Dos access method information for column. - Long = cdp->GetLong(); // ??? -//strcpy(F_Date, cdp->F_Date); - Colp = NULL; - To_Val = NULL; - Pseudo = FALSE; - Colnum = cdp->GetOffset(); // If columns are retrieved by number + for (PCOL colp = Columns; colp; colp = colp->GetNext()) + if (colp->GetAmType() == TYPE_AM_TABID) + colp->COLBLK::Reset(); - if (trace) - htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this); + for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext()) + ((PTDBASE)tabp->GetTo_Tdb())->ResetDB(); - } // end of TBLCOL constructor + Tdbp = (PTDBASE)Tablist->GetTo_Tdb(); + Crp = 0; + } // end of ResetDB -#if 0 /***********************************************************************/ -/* TBLCOL public constructor. */ +/* Returns RowId if b is false or Rownum if b is true. */ /***********************************************************************/ -TBLCOL::TBLCOL(SPCBLK *scp, PTDB tdbp) : COLBLK(scp->GetName(), tdbp, 0) +int TDBTBM::RowNumber(PGLOBAL g, bool b) { - // Set additional TBL access method information for pseudo column. - Is_Key = Was_Key = scp->IsKey(); - Long = scp->GetLength(); - Buf_Type = scp->GetResultType(); - *Format.Type = (Buf_Type == TYPE_INT) ? 'N' : 'C'; - Format.Length = Long; - Colp = NULL; - To_Val = NULL; - Pseudo = TRUE; - } // end of TBLCOL constructor - -/***********************************************************************/ -/* TBLCOL constructor used for copying columns. */ -/* tdbp is the pointer to the new table descriptor. */ -/***********************************************************************/ -TBLCOL::TBLCOL(TBLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp) + return Tdbp->RowNumber(g) + ((b) ? 0 : Rows); + } // end of RowNumber + +/***********************************************************************/ +/* Initialyze table parallel processing. */ +/***********************************************************************/ +bool TDBTBM::OpenTables(PGLOBAL g) { - Long = col1->Long; - Colp = col1->Colp; - To_Val = col1->To_Val; - Pseudo = col1->Pseudo; - } // end of TBLCOL copy constructor -#endif + int k; + THD *thd = current_thd; + PTABLE tabp, *ptabp = &Tablist; + PTBMT tp, *ptp = &Tmp; + + // Allocates the TBMT blocks for the tables + for (tabp = Tablist; tabp; tabp = tabp->Next) + if (tabp->GetTo_Tdb()->GetAmType() == TYPE_AM_MYSQL) { + // Remove remote table from the local list + *ptabp = tabp->Next; + + // Make the remote table block + tp = (PTBMT)PlugSubAlloc(g, NULL, sizeof(TBMT)); + memset(tp, 0, sizeof(TBMT)); + tp->G = g; + tp->Tap = tabp; + tp->Thd = thd; + + // Create the thread that will do the table opening. + pthread_attr_init(&tp->attr); +// pthread_attr_setdetachstate(&tp->attr, PTHREAD_CREATE_JOINABLE); + + if ((k = pthread_create(&tp->Tid, &tp->attr, ThreadOpen, tp))) { + sprintf(g->Message, "pthread_create error %d", k); + Nbc++; + continue; + } // endif k + + // Add it to the remote list + *ptp = tp; + ptp = &tp->Next; + Nrc++; // Number of remote connections + } else { + ptabp = &tabp->Next; + Nlc++; // Number of local connections + } // endif Type + + return false; + } // end of OpenTables /***********************************************************************/ -/* TBLCOL initialization routine. */ -/* Look for the matching column in the current table. */ +/* TBL Access Method opening routine. */ +/* Open first file, other will be opened sequencially when reading. */ /***********************************************************************/ -bool TBLCOL::Init(PGLOBAL g) +bool TDBTBM::OpenDB(PGLOBAL g) { - PTDBTBL tdbp = (PTDBTBL)To_Tdb; + if (trace) + htrc("TBM OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n", + this, Tdb_No, Use, To_Key_Col, Mode); + + if (Use == USE_OPEN) { + /*******************************************************************/ + /* Table already open, replace it at its beginning. */ + /*******************************************************************/ + ResetDB(); + return Tdbp->OpenDB(g); // Re-open fist table + } // endif use - To_Val = NULL; +#if 0 + /*********************************************************************/ + /* When GetMaxsize was called, To_Filter was not set yet. */ + /*********************************************************************/ + if (To_Filter && Tablist) { + Tablist = NULL; + Nbc = 0; + } // endif To_Filter +#endif // 0 - if (!(Colp = tdbp->Tdbp->ColDB(g, Name, 0)) && Colnum) - Colp = tdbp->Tdbp->ColDB(g, NULL, Colnum); + /*********************************************************************/ + /* Make the table list. */ + /*********************************************************************/ + if (/*!Tablist &&*/ InitTableList(g)) + return TRUE; - if (Colp) { - Colp->InitValue(g); // May not have been done elsewhere - To_Val = Colp->GetValue(); - } else if (!tdbp->Accept) { - sprintf(g->Message, MSG(NO_MATCHING_COL), Name, tdbp->Tdbp->GetName()); + /*********************************************************************/ + /* Open all remote tables of the list. */ + /*********************************************************************/ + if (OpenTables(g)) return TRUE; - } else { - if (Nullable) - Value->SetNull(true); - Value->Reset(); - } // endif's + /*********************************************************************/ + /* Proceed with local tables. */ + /*********************************************************************/ + if ((CurTable = Tablist)) { + Tdbp = (PTDBASE)CurTable->GetTo_Tdb(); + Tdbp->SetMode(Mode); + + // Check and initialize the subtable columns + for (PCOL cp = Columns; cp; cp = cp->GetNext()) + if (cp->GetAmType() == TYPE_AM_TABID) + cp->COLBLK::Reset(); + else if (((PPRXCOL)cp)->Init(g) && !Accept) + return TRUE; + + if (trace) + htrc("Opening subtable %s\n", Tdbp->GetName()); + + // Now we can safely open the table + if (Tdbp->OpenDB(g)) + return TRUE; + + } // endif *Tablist + Use = USE_OPEN; return FALSE; - } // end of Init + } // end of OpenDB /***********************************************************************/ -/* ReadColumn: */ +/* ReadDB: Data Base read routine for MUL access method. */ /***********************************************************************/ -void TBLCOL::ReadColumn(PGLOBAL g) +int TDBTBM::ReadDB(PGLOBAL g) { - if (trace) - htrc("TBL ReadColumn: name=%s\n", Name); + int rc; - if (Colp) { - Colp->ReadColumn(g); - Value->SetValue_pval(To_Val); + if (!Done) { + // Get result from local tables + if ((rc = TDBTBL::ReadDB(g)) != RC_EF) + return rc; + else if ((rc = ReadNextRemote(g)) != RC_OK) + return rc; - // Set null when applicable - if (Nullable) - Value->SetNull(Value->IsNull()); + Done = true; + } // endif Done - } // endif Colp + /*********************************************************************/ + /* Now start the reading process of remote tables. */ + /*********************************************************************/ + retry: + rc = Tdbp->ReadDB(g); - } // end of ReadColumn + if (rc == RC_EF) { + // Total number of rows met so far + Rows += Tdbp->RowNumber(g) - 1; + Crp += Tdbp->GetProgMax(g); + Cmp->Complete = true; -/* ---------------------------- TBTBLK ------------------------------- */ + if ((rc = ReadNextRemote(g)) == RC_OK) + goto retry; + + } else if (rc == RC_FX) + strcat(strcat(strcat(g->Message, " ("), Tdbp->GetName()), ")"); + + return rc; + } // end of ReadDB /***********************************************************************/ -/* ReadColumn: */ +/* ReadNext: Continue reading from next table. */ /***********************************************************************/ -void TBTBLK::ReadColumn(PGLOBAL g) +int TDBTBM::ReadNextRemote(PGLOBAL g) { - if (trace) - htrc("TBT ReadColumn: name=%s\n", Name); + bool b = false; - Value->SetValue_psz((char*)((PTDBTBL)To_Tdb)->Tdbp->GetName()); + if (Tdbp) + Tdbp->CloseDB(g); - } // end of ReadColumn + Cmp = NULL; + + retry: + // Search for a remote table having its result set + for (PTBMT tp = Tmp; tp; tp = tp->Next) + if (tp->Ready) { + if (!tp->Complete) + Cmp = tp; + + } else + b = true; + + if (!Cmp) { + if (b) { // more result to come +// sleep(20); + goto retry; + } else + return RC_EF; + + } // endif Curtable + + Tdbp = (PTDBASE)Cmp->Tap->GetTo_Tdb(); + + // Check and initialize the subtable columns + for (PCOL cp = Columns; cp; cp = cp->GetNext()) + if (cp->GetAmType() == TYPE_AM_TABID) + cp->COLBLK::Reset(); + else if (((PPRXCOL)cp)->Init(g) && !Accept) + return RC_FX; + + if (trace) + htrc("Reading subtable %s\n", Tdbp->GetName()); + + return RC_OK; + } // end of ReadNextRemote /* ------------------------------------------------------------------- */ diff --git a/storage/connect/tabtbl.h b/storage/connect/tabtbl.h index 07a20bb2867..7cc2ff0b92c 100644 --- a/storage/connect/tabtbl.h +++ b/storage/connect/tabtbl.h @@ -1,42 +1,51 @@ /*************** TabTbl H Declares Source Code File (.H) ***************/ -/* Name: TABTBL.H Version 1.2 */ +/* Name: TABTBL.H Version 1.3 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2008-2012 */ +/* (C) Copyright to the author Olivier BERTRAND 2008-2013 */ /* */ /* This file contains the TDBTBL classes declares. */ /***********************************************************************/ -//#include "osutil.h" #include "block.h" #include "colblk.h" +#include "tabutil.h" typedef class TBLDEF *PTBLDEF; typedef class TDBTBL *PTDBTBL; -typedef class TBLCOL *PTBLCOL; +typedef class TDBTBM *PTDBTBM; +typedef class MYSQLC *PMYC; /***********************************************************************/ -/* Defines the structure used for multiple tables. */ +/* Defines the structures used for distributed TBM tables. */ /***********************************************************************/ -typedef struct _tablist *PTBL; - -typedef struct _tablist { - PTBL Next; - char *Name; - char *DB; - } TBLIST; +typedef struct _TBMtable *PTBMT; + +typedef struct _TBMtable { + PTBMT Next; // Points to next data table struct + PTABLE Tap; // Points to the sub table + PGLOBAL G; // Needed in thread routine + bool Complete; // TRUE when all results are read + bool Ready; // TRUE when results are there + int Rows; // Total number of rows read so far + int ProgCur; // Current pos + int ProgMax; // Max pos + int Rc; // Return code + THD *Thd; + pthread_attr_t attr; // ??? + pthread_t Tid; // CheckOpen thread ID + } TBMT; /***********************************************************************/ /* TBL table. */ /***********************************************************************/ -class DllExport TBLDEF : public TABDEF { /* Logical table description */ +class DllExport TBLDEF : public PRXDEF { /* Logical table description */ friend class TDBTBL; + friend class TDBTBC; public: // Constructor TBLDEF(void); // Implementation virtual const char *GetType(void) {return "TBL";} - PTBL GetTables(void) {return To_Tables;} -//int GetNtables(void) {return Ntables;} // Methods virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); @@ -44,8 +53,8 @@ class DllExport TBLDEF : public TABDEF { /* Logical table description */ protected: // Members - PTBL To_Tables; /* To the list of tables */ bool Accept; /* TRUE if bad tables are accepted */ + bool Thread; /* Use thread for remote tables */ int Maxerr; /* Maximum number of bad tables */ int Ntables; /* Number of tables */ }; // end of TBLDEF @@ -53,91 +62,44 @@ class DllExport TBLDEF : public TABDEF { /* Logical table description */ /***********************************************************************/ /* This is the TBL Access Method class declaration. */ /***********************************************************************/ -class DllExport TDBTBL : public TDBASE { - friend class TBLCOL; +class DllExport TDBTBL : public TDBPRX { friend class TBTBLK; - friend class TDBPLG; public: // Constructor TDBTBL(PTBLDEF tdp = NULL); -//TDBTBL(PTDBTBL tdbp); // Implementation virtual AMT GetAmType(void) {return TYPE_AM_TBL;} -//virtual PTDB Duplicate(PGLOBAL g) -// {return (PTDB)new(g) TDBTBL(this);} // Methods virtual void ResetDB(void); -//virtual PTABLE GetTablist(void) {return (PSZ)Tablist;} -//virtual PTDB CopyOne(PTABS t); - virtual int GetRecpos(void) {return Rows;} - virtual int GetBadLines(void) {return (int)Nbf;} + virtual int GetRecpos(void) {return Rows;} + virtual int GetBadLines(void) {return (int)Nbc;} // Database routines virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); virtual int GetMaxSize(PGLOBAL g); - virtual int GetProgMax(PGLOBAL g); - virtual int GetProgCur(void); virtual int RowNumber(PGLOBAL g, bool b = FALSE); virtual PCOL InsertSpecialColumn(PGLOBAL g, PCOL scp); virtual bool OpenDB(PGLOBAL g); virtual int ReadDB(PGLOBAL g); - virtual int WriteDB(PGLOBAL g); - virtual int DeleteDB(PGLOBAL g, int irc); - virtual void CloseDB(PGLOBAL g); protected: // Internal functions - PTDB GetSubTable(PGLOBAL g, PTBL tblp, PTABLE tabp); bool InitTableList(PGLOBAL g); - bool TestFil(PGLOBAL g, PFIL filp, PTBL tblp); + bool TestFil(PGLOBAL g, PFIL filp, PTABLE tabp); // Members PTABLE Tablist; // Points to the table list PTABLE CurTable; // Points to the current table - PTDBASE Tdbp; // Current table PTDB bool Accept; // TRUE if bad tables are accepted int Maxerr; // Maximum number of bad tables - int Nbf; // Number of bad connections + int Nbc; // Number of bad connections int Rows; // Used for RowID int Crp; // Used for CurPos }; // end of class TDBTBL /***********************************************************************/ -/* Class TBLCOL: TBL access method column descriptor. */ -/* This A.M. is used for TBL tables. */ -/***********************************************************************/ -class DllExport TBLCOL : public COLBLK { - friend class TDBTBL; - public: - // Constructors - TBLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "TBL"); - TBLCOL(TBLCOL *colp, PTDB tdbp); // Constructor used in copy process -//TBLCOL(SPCBLK *colp, PTDB tdbp); // Constructor used for pseudo columns - - // Implementation - virtual int GetAmType(void) {return TYPE_AM_TBL;} - - // Methods - virtual bool IsSpecial(void) {return Pseudo;} - virtual void ReadColumn(PGLOBAL g); -//virtual void WriteColumn(PGLOBAL g); -// void Print(PGLOBAL g, FILE *, UINT); - bool Init(PGLOBAL g); - - protected: - // Default constructor not to be used - TBLCOL(void) {} - - // Members - PCOL Colp; // Points to matching table column - PVAL To_Val; // To the matching column value - bool Pseudo; // TRUE for special columns - int Colnum; // Used when retrieving columns by number - }; // end of class TBLCOL - -/***********************************************************************/ /* Class TBTBLK: TDBPLG TABID special column descriptor. */ /***********************************************************************/ class TBTBLK : public TIDBLK { @@ -160,3 +122,44 @@ class TBTBLK : public TIDBLK { protected: // Must not have additional members }; // end of class TBTBLK + +/***********************************************************************/ +/* This is the TBM Access Method class declaration. */ +/***********************************************************************/ +class DllExport TDBTBM : public TDBTBL { + friend class TBTBLK; + public: + // Constructor + TDBTBM(PTBLDEF tdp = NULL); + + // Implementation +//virtual AMT GetAmType(void) {return TYPE_AM_TBL;} + + // Methods + virtual void ResetDB(void); +//virtual int GetRecpos(void) {return Rows;} +//virtual int GetBadLines(void) {return (int)Nbc;} + + // Database routines +//virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); + virtual int GetMaxSize(PGLOBAL g) {return 10;} // Temporary + virtual int RowNumber(PGLOBAL g, bool b = FALSE); +//virtual PCOL InsertSpecialColumn(PGLOBAL g, PCOL scp); + virtual bool OpenDB(PGLOBAL g); + virtual int ReadDB(PGLOBAL g); + + protected: + // Internal functions +//bool InitTableList(PGLOBAL g); +//bool TestFil(PGLOBAL g, PFIL filp, PTABLE tabp); + bool OpenTables(PGLOBAL g); + int ReadNextRemote(PGLOBAL g); + + // Members + PTBMT Tmp; // To data table TBMT structures + PTBMT Cmp; // Current data table PLGF (to move to TDBTBL) + PTBMT Bmp; // To bad (unconnected) PLGF structures + bool Done; // TRUE after first GetAllResults + int Nrc; // Number of remote connections + int Nlc; // Number of local connections + }; // end of class TDBTBM diff --git a/storage/connect/tabutil.cpp b/storage/connect/tabutil.cpp new file mode 100644 index 00000000000..21dee4e1856 --- /dev/null +++ b/storage/connect/tabutil.cpp @@ -0,0 +1,624 @@ +/************* Tabutil cpp Declares Source Code File (.CPP) ************/ +/* Name: TABUTIL.CPP Version 1.0 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2013 */ +/* */ +/* Utility function used by the PROXY, XCOL, OCCUR, and TBL tables. */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant section of system dependant header files. */ +/***********************************************************************/ +#include "my_global.h" +#include "sql_class.h" +#include "table.h" +#include "field.h" +#if defined(WIN32) +#include <stdlib.h> +#include <stdio.h> +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif +//#include <windows.h> +#else +#if defined(UNIX) +#include <fnmatch.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "osutil.h" +#else +//#include <io.h> +#endif +//#include <fcntl.h> +#endif + +/***********************************************************************/ +/* Include application header files: */ +/***********************************************************************/ +#include "table.h" // MySQL table definitions +#include "global.h" +#include "plgdbsem.h" +#include "plgcnx.h" // For DB types +#include "myutil.h" +#include "mycat.h" +#include "valblk.h" +#include "resource.h" +#include "reldef.h" +#include "xtable.h" +#if defined(MYSQL_SUPPORT) +#include "tabmysql.h" +#endif // MYSQL_SUPPORT +#include "tabcol.h" +#include "tabutil.h" +#include "ha_connect.h" + +extern "C" int trace; + +/************************************************************************/ +/* Used by MYSQL tables to get MySQL parameters from the calling proxy */ +/* table (PROXY, TBL, XCL, or OCCUR) when used by one of these. */ +/************************************************************************/ +void Remove_tshp(PCATLG cat) +{ + ((MYCAT*)cat)->GetHandler()->tshp = NULL; +} // end of Remove_thsp + +/************************************************************************/ +/* GetTableShare: allocates and open a table share. */ +/************************************************************************/ +TABLE_SHARE *GetTableShare(PGLOBAL g, THD *thd, const char *db, + const char *name, bool& mysql) +{ + char key[256]; + uint k; +//TABLE_LIST table_list; + TABLE_SHARE *s; + +//table_list.init_one_table(db, strlen(db), name, strlen(name), +// NULL, TL_IGNORE); + k = sprintf(key, "%s", db) + 1; + k += sprintf(key + k, "%s", name); + key[++k] = 0; + + if (!(s = alloc_table_share(db, name, key, ++k))) { + strcpy(g->Message, "Error allocating share\n"); + return NULL; + } // endif s + +// 1 2 4 8 +//flags = GTS_TABLE | GTS_VIEW | GTS_NOLOCK | GTS_FORCE_DISCOVERY; + + if (!open_table_def(thd, s, GTS_TABLE | GTS_VIEW)) { + if (!s->is_view) { + if (stricmp(plugin_name(s->db_plugin)->str, "connect")) { +#if defined(MYSQL_SUPPORT) + mysql = true; +#else // !MYSQL_SUPPORT + sprintf(g->Message, "%s.%s is not a CONNECT table", db, name); + return NULL; +#endif // MYSQL_SUPPORT + } else + mysql = false; + + } else { + mysql = true; + } // endif is_view + + } else { + sprintf(g->Message, "Error %d opening share\n", s->error); + free_table_share(s); + return NULL; + } // endif open_table_def + + return s; +} // end of GetTableShare + +/************************************************************************/ +/* TabColumns: constructs the result blocks containing all the columns */ +/* of the object table that will be retrieved by GetData commands. */ +/************************************************************************/ +PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, + const char *name, bool& info) + { + static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, + TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, + TYPE_STRING, TYPE_STRING, TYPE_STRING}; + static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, + FLD_LENGTH, 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; + int i, n, ncol = sizeof(buftyp) / sizeof(int); + int len, type, prec; + bool mysql; + TABLE_SHARE *s; + Field* *field; + Field *fp; + PQRYRES qrp; + PCOLRES crp; + + if (!info) { + if (!(s = GetTableShare(g, thd, db, name, mysql))) { + return NULL; + } else if (s->is_view) { + strcpy(g->Message, "Use MYSQL type to see columns from a view"); + info = true; // To tell caller name is a view + free_table_share(s); + return NULL; + } else + n = s->fieldnames.count; + + } else { + n = 0; + length[0] = 128; + } // endif info + + /**********************************************************************/ + /* Allocate the structures used to refer to the result set. */ + /**********************************************************************/ + qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3, + buftyp, fldtyp, length, true, true); + + // Some columns must be renamed + for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next) + switch (++i) { + case 10: crp->Name = "Date_fmt"; break; + case 11: crp->Name = "Collation"; break; + } // endswitch i + + if (info) + return qrp; + + /**********************************************************************/ + /* Now get the results into blocks. */ + /**********************************************************************/ + for (i = 0, field= s->field; *field; i++, field++) { + fp= *field; + + // Get column name + crp = qrp->Colresp; // Column_Name + fld = (char *)fp->field_name; + crp->Kdata->SetValue(fld, i); + + if ((type = MYSQLtoPLG(fp->type())) == TYPE_ERROR) { + sprintf(g->Message, "Unsupported column type %s", GetTypeName(type)); + qrp = NULL; + break; + } // endif type + + crp = crp->Next; // Data_Type + crp->Kdata->SetValue(type, i); + crp = crp->Next; // Type_Name + crp->Kdata->SetValue(GetTypeName(type), i); + + if (type == TYPE_DATE) { + // When creating tables we do need info about date columns + if (mysql) { + fmt = MyDateFmt(fp->type()); + len = strlen(fmt); + } else { + fmt = (char*)fp->option_struct->dateformat; + len = fp->field_length; + } // endif mysql + + } else { + fmt = NULL; + len = fp->char_length(); + } // endif type + + crp = crp->Next; // Precision + crp->Kdata->SetValue(len, i); + + crp = crp->Next; // Length + len = fp->field_length; + crp->Kdata->SetValue(len, i); + + prec = (type == TYPE_FLOAT) ? fp->decimals() : 0; + crp = crp->Next; // Scale + crp->Kdata->SetValue(prec, i); + + crp = crp->Next; // Radix + crp->Kdata->SetValue(0, i); + + crp = crp->Next; // Nullable + crp->Kdata->SetValue((fp->null_ptr != 0) ? 1 : 0, i); + + crp = crp->Next; // Remark + fld = fp->comment.str; + crp->Kdata->SetValue(fld, fp->comment.length, i); + + crp = crp->Next; // New + crp->Kdata->SetValue((fmt) ? fmt : (char*) "", i); + + crp = crp->Next; // New (charset) + fld = (char *)fp->charset()->name; + crp->Kdata->SetValue(fld, i); + + // Add this item + qrp->Nblin++; + } // endfor field + + /**********************************************************************/ + /* Return the result pointer for use by GetData routines. */ + /**********************************************************************/ + free_table_share(s); + return qrp; + } // end of TabColumns + +/* -------------- Implementation of the PROXY classes ---------------- */ + +/***********************************************************************/ +/* PRXDEF constructor. */ +/***********************************************************************/ +PRXDEF::PRXDEF(void) + { + Tablep = NULL; + Pseudo = 3; +} // end of PRXDEF constructor + +/***********************************************************************/ +/* DefineAM: define specific AM block values from XCOL file. */ +/***********************************************************************/ +bool PRXDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) + { + char *pn, *db, *tab, *def = NULL; + + db = Cat->GetStringCatInfo(g, "Dbname", "*"); + def = Cat->GetStringCatInfo(g, "Srcdef", NULL); + + if (!(tab = Cat->GetStringCatInfo(g, "Tabname", NULL))) { + if (!def) { + strcpy(g->Message, "Missing object table definition"); + return TRUE; + } else + tab = "Noname"; + + } else + // Analyze the table name, it may have the format: [dbname.]tabname + if ((pn = strchr(tab, '.'))) { + *pn++ = 0; + db = tab; + tab = pn; + } // endif pn + + Tablep = new(g) XTAB(tab, def); + Tablep->SetQualifier(db); + return FALSE; + } // end of DefineAM + +/***********************************************************************/ +/* GetTable: makes a new TDB of the proper type. */ +/***********************************************************************/ +PTDB PRXDEF::GetTable(PGLOBAL g, MODE mode) + { + if (Catfunc == FNC_COL) + return new(g) TDBTBC(this); + else + return new(g) TDBPRX(this); + + } // end of GetTable + +/* ------------------------------------------------------------------- */ + +/***********************************************************************/ +/* Implementation of the TDBPRX class. */ +/***********************************************************************/ +TDBPRX::TDBPRX(PPRXDEF tdp) : TDBASE(tdp) + { + Tdbp = NULL; // The object table + } // end of TDBPRX constructor + +/***********************************************************************/ +/* Get the PTDB of the sub-table. */ +/***********************************************************************/ +PTDBASE TDBPRX::GetSubTable(PGLOBAL g, PTABLE tabp, bool b) + { + const char *sp; + char *db, *name; + bool mysql = true; + PTDB tdbp = NULL; + TABLE_SHARE *s = NULL; + Field* *fp; + PCATLG cat = To_Def->GetCat(); + PHC hc = ((MYCAT*)cat)->GetHandler(); + LPCSTR cdb, curdb = hc->GetDBName(NULL); + THD *thd = (hc->GetTable())->in_use; + + db = (char*)tabp->GetQualifier(); + name = (char*)tabp->GetName(); + + // Check for eventual loop + for (PTABLE tp = To_Table; tp; tp = tp->Next) { + cdb = (tp->Qualifier) ? tp->Qualifier : curdb; + + if (!stricmp(name, tp->Name) && !stricmp(db, cdb)) { + sprintf(g->Message, "Table %s.%s pointing on itself", db, name); + return NULL; + } // endif + + } // endfor tp + + if (!tabp->GetSrc()) { + if (!(s = GetTableShare(g, thd, db, name, mysql))) + return NULL; + + if (s->is_view && !b) + s->field = hc->get_table()->s->field; + + hc->tshp = s; + } else if (b) { + // Don't use caller's columns + fp = hc->get_table()->field; + hc->get_table()->field = NULL; + + // Make caller use the source definition + sp = hc->get_table()->s->option_struct->srcdef; + hc->get_table()->s->option_struct->srcdef = tabp->GetSrc(); + } // endif srcdef + + if (mysql) { +#if defined(MYSQL_SUPPORT) + // Access sub-table via MySQL API + if (!(tdbp= cat->GetTable(g, tabp, MODE_READ, "MYPRX"))) { + sprintf(g->Message, "Cannot access %s.%s", db, name); + goto err; + } // endif Define + + if (db) + ((PTDBMY)tdbp)->SetDatabase(tabp->GetQualifier()); + +#else // !MYSQL_SUPPORT + sprintf(g->Message, "%s.%s is not a CONNECT table", + db, tblp->Name); + goto err; +#endif // MYSQL_SUPPORT + } else { + // Sub-table is a CONNECT table + tabp->Next = To_Table; // For loop checking + tdbp = cat->GetTable(g, tabp); + } // endif mysql + + if (s) { + if (s->is_view && !b) + s->field = NULL; + + hc->tshp = NULL; + } else if (b) { + // Restore s structure that can be in cache + hc->get_table()->field = fp; + hc->get_table()->s->option_struct->srcdef = sp; + } // endif s + + if (trace && tdbp) + htrc("Subtable %s in %s\n", + name, SVP(((PTDBASE)tdbp)->GetDef()->GetDB())); + + err: + if (s) + free_table_share(s); + + return (PTDBASE)tdbp; + } // end of GetSubTable + +/***********************************************************************/ +/* Initializes the table. */ +/***********************************************************************/ +bool TDBPRX::InitTable(PGLOBAL g) + { + if (!Tdbp) { + // Get the table description block of this table + if (!(Tdbp = GetSubTable(g, ((PPRXDEF)To_Def)->Tablep))) + return TRUE; + + } // endif Tdbp + + return FALSE; + } // end of InitTable + +/***********************************************************************/ +/* Allocate PRX column description block. */ +/***********************************************************************/ +PCOL TDBPRX::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) + { + return new(g) PRXCOL(cdp, this, cprec, n); + } // end of MakeCol + +/***********************************************************************/ +/* PRX GetMaxSize: returns the maximum number of rows in the table. */ +/***********************************************************************/ +int TDBPRX::GetMaxSize(PGLOBAL g) + { + if (MaxSize < 0) { + if (InitTable(g)) + return 0; + + MaxSize = Tdbp->GetMaxSize(g); + } // endif MaxSize + + return MaxSize; + } // end of GetMaxSize + +/***********************************************************************/ +/* In this sample, ROWID will be the (virtual) row number, */ +/* while ROWNUM will be the occurence rank in the multiple column. */ +/***********************************************************************/ +int TDBPRX::RowNumber(PGLOBAL g, bool b) + { + return Tdbp->RowNumber(g, b); + } // end of RowNumber + +/***********************************************************************/ +/* PROXY Access Method opening routine. */ +/***********************************************************************/ +bool TDBPRX::OpenDB(PGLOBAL g) + { + if (Use == USE_OPEN) { + /*******************************************************************/ + /* Table already open, just replace it at its beginning. */ + /*******************************************************************/ + return Tdbp->OpenDB(g); + } // endif use + + if (Mode != MODE_READ) { + /*******************************************************************/ + /* Currently XCOL tables cannot be modified. */ + /*******************************************************************/ + strcpy(g->Message, "PROXY tables are read only"); + return TRUE; + } // endif Mode + + if (InitTable(g)) + return TRUE; + + /*********************************************************************/ + /* Check and initialize the subtable columns. */ + /*********************************************************************/ + for (PCOL cp = Columns; cp; cp = cp->GetNext()) + if (((PPRXCOL)cp)->Init(g)) + return TRUE; + + /*********************************************************************/ + /* Physically open the object table. */ + /*********************************************************************/ + if (Tdbp->OpenDB(g)) + return TRUE; + + return FALSE; + } // end of OpenDB + +/***********************************************************************/ +/* Data Base read routine for PROY access method. */ +/***********************************************************************/ +int TDBPRX::ReadDB(PGLOBAL g) + { + /*********************************************************************/ + /* Now start the reading process. */ + /*********************************************************************/ + return Tdbp->ReadDB(g); + } // end of ReadDB + +/***********************************************************************/ +/* WriteDB: Data Base write routine for PROXY access methods. */ +/***********************************************************************/ +int TDBPRX::WriteDB(PGLOBAL g) + { + sprintf(g->Message, "%s tables are read only", To_Def->GetType()); + return RC_FX; + } // end of WriteDB + +/***********************************************************************/ +/* Data Base delete line routine for PROXY access methods. */ +/***********************************************************************/ +int TDBPRX::DeleteDB(PGLOBAL g, int irc) + { + sprintf(g->Message, "Delete not enabled for %s tables", + To_Def->GetType()); + return RC_FX; + } // end of DeleteDB + +/***********************************************************************/ +/* Used by the TBL tables. */ +/***********************************************************************/ +void TDBPRX::RemoveNext(PTABLE tp) + { + tp->Next = NULL; + } // end of RemoveNext + +/* ---------------------------- PRXCOL ------------------------------- */ + +/***********************************************************************/ +/* PRXCOL public constructor. */ +/***********************************************************************/ +PRXCOL::PRXCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am) + : COLBLK(cdp, tdbp, i) + { + if (cprec) { + Next = cprec->GetNext(); + cprec->SetNext(this); + } else { + Next = tdbp->GetColumns(); + tdbp->SetColumns(this); + } // endif cprec + + // Set additional Dos access method information for column. + Long = cdp->GetLong(); // Useful ??? +//strcpy(F_Date, cdp->F_Date); + Colp = NULL; + To_Val = NULL; + Pseudo = FALSE; + Colnum = cdp->GetOffset(); // If columns are retrieved by number + + if (trace) + htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this); + + } // end of PRXCOL constructor + +/***********************************************************************/ +/* PRXCOL initialization routine. */ +/* Look for the matching column in the object table. */ +/***********************************************************************/ +bool PRXCOL::Init(PGLOBAL g) + { + PTDBPRX tdbp = (PTDBPRX)To_Tdb; + + if (!(Colp = tdbp->Tdbp->ColDB(g, Name, 0)) && Colnum) + Colp = tdbp->Tdbp->ColDB(g, NULL, Colnum); + + if (Colp) { + // May not have been done elsewhere + Colp->InitValue(g); + To_Val = Colp->GetValue(); + + // this may be needed by some tables (which?) + Colp->SetColUse(ColUse); + } else { + sprintf(g->Message, MSG(NO_MATCHING_COL), Name, tdbp->Tdbp->GetName()); + return TRUE; + } // endif Colp + + return FALSE; + } // end of Init + +/***********************************************************************/ +/* ReadColumn: */ +/***********************************************************************/ +void PRXCOL::ReadColumn(PGLOBAL g) + { + if (trace) + htrc("PRX ReadColumn: name=%s\n", Name); + + if (Colp) { + Colp->ReadColumn(g); + Value->SetValue_pval(To_Val); + + // Set null when applicable + if (Nullable) + Value->SetNull(Value->IsNull()); + + } // endif Colp + + } // end of ReadColumn + +/* ---------------------------TDBTBC class --------------------------- */ + +/***********************************************************************/ +/* TDBTBC class constructor. */ +/***********************************************************************/ +TDBTBC::TDBTBC(PPRXDEF tdp) : TDBCAT(tdp) + { + Db = (PSZ)tdp->Tablep->GetQualifier(); + Tab = (PSZ)tdp->Tablep->GetName(); + } // end of TDBTBC constructor + +/***********************************************************************/ +/* GetResult: Get the list the MYSQL table columns. */ +/***********************************************************************/ +PQRYRES TDBTBC::GetResult(PGLOBAL g) + { + bool b = false; + + return TabColumns(g, current_thd, Db, Tab, b); + } // end of GetResult + diff --git a/storage/connect/tabutil.h b/storage/connect/tabutil.h new file mode 100644 index 00000000000..ddf6c2eb601 --- /dev/null +++ b/storage/connect/tabutil.h @@ -0,0 +1,141 @@ +// TABUTIL.H Olivier Bertrand 2013 +// Defines the TAB catalog tables + +#ifndef TABUTIL +#define TABUTIL 1 + +//#include "tabtbl.h" + +#define TYPE_AM_PRX (AMT)129 + +typedef class PRXDEF *PPRXDEF; +typedef class TDBPRX *PTDBPRX; +typedef class XXLCOL *PXXLCOL; +typedef class PRXCOL *PPRXCOL; +typedef class TBCDEF *PTBCDEF; +typedef class TDBTBC *PTDBTBC; + +TABLE_SHARE *GetTableShare(PGLOBAL g, THD *thd, const char *db, + const char *name, bool& mysql); +PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, + const char *name, bool& info); + +void Remove_tshp(PCATLG cat); + +/* -------------------------- PROXY classes -------------------------- */ + +/***********************************************************************/ +/* PROXY: table based on another table. Can be used to have a */ +/* different view on an existing table. */ +/* However, its real use is to be the base of TBL and PRX tables. */ +/***********************************************************************/ + +/***********************************************************************/ +/* PRX table. */ +/***********************************************************************/ +class DllExport PRXDEF : public TABDEF { /* Logical table description */ + friend class TDBPRX; + friend class TDBTBC; + public: + // Constructor + PRXDEF(void); + + // Implementation + virtual const char *GetType(void) {return "PRX";} + + // Methods + virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); + virtual PTDB GetTable(PGLOBAL g, MODE mode); + + protected: + // Members + PTABLE Tablep; /* The object table */ + }; // end of PRXDEF + +/***********************************************************************/ +/* This is the class declaration for the XCSV table. */ +/***********************************************************************/ +class DllExport TDBPRX : public TDBASE { +//friend class MULINDX; + friend class PRXDEF; + friend class PRXCOL; + public: + // Constructor + TDBPRX(PPRXDEF tdp); + + // Implementation + virtual AMT GetAmType(void) {return TYPE_AM_PRX;} + + // Methods + virtual int GetRecpos(void) {return Tdbp->GetRecpos();} + virtual void ResetDB(void) {Tdbp->ResetDB();} + virtual int RowNumber(PGLOBAL g, bool b = FALSE); + + // Database routines + virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); + virtual bool InitTable(PGLOBAL g); + virtual int GetMaxSize(PGLOBAL g); + virtual bool OpenDB(PGLOBAL g); + virtual int ReadDB(PGLOBAL g); + virtual int WriteDB(PGLOBAL g); + virtual int DeleteDB(PGLOBAL g, int irc); + virtual void CloseDB(PGLOBAL g) {if (Tdbp) Tdbp->CloseDB(g);} + PTDBASE GetSubTable(PGLOBAL g, PTABLE tabp, bool b = false); + void RemoveNext(PTABLE tp); + + protected: + // Members + PTDBASE Tdbp; // The object table + }; // end of class TDBPRX + +/***********************************************************************/ +/* Class PRXCOL: PRX access method column descriptor. */ +/* This A.M. is used for PRX tables. */ +/***********************************************************************/ +class DllExport PRXCOL : public COLBLK { + friend class TDBPRX; + friend class TDBTBL; + friend class TDBOCCUR; + public: + // Constructors + PRXCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "PRX"); + + // Implementation + virtual int GetAmType(void) {return TYPE_AM_PRX;} + + // Methods + virtual bool IsSpecial(void) {return Pseudo;} + virtual void ReadColumn(PGLOBAL g); + bool Init(PGLOBAL g); + + protected: + // Default constructor not to be used + PRXCOL(void) {} + + // Members + PCOL Colp; // Points to matching table column + PVAL To_Val; // To the matching column value + bool Pseudo; // TRUE for special columns + int Colnum; // Used when retrieving columns by number + }; // end of class PRXCOL + +/***********************************************************************/ +/* This is the class declaration for the TBC column catalog table. */ +/***********************************************************************/ +class TDBTBC : public TDBCAT { + public: + // Constructors + TDBTBC(PPRXDEF tdp); +//TDBTBC(PTBLDEF tdp); +//TDBTBC(PXCLDEF tdp); + + protected: + // Specific routines + virtual PQRYRES GetResult(PGLOBAL g); + + // Members + PSZ Db; // Database of the table + PSZ Tab; // Table name + }; // end of class TDBMCL + +#endif // TABUTIL diff --git a/storage/connect/tabwmi.cpp b/storage/connect/tabwmi.cpp index d89d61dc11c..dbd4330a2f9 100644 --- a/storage/connect/tabwmi.cpp +++ b/storage/connect/tabwmi.cpp @@ -135,14 +135,12 @@ PWMIUT InitWMI(PGLOBAL g, char *nsp, char *classname) /***********************************************************************/ PQRYRES WMIColumns(PGLOBAL g, char *nsp, char *cls, bool info) { - static int dbtype[] = {DB_CHAR, DB_SHORT, DB_CHAR, - DB_INT, DB_INT, DB_SHORT}; static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT}; static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH, FLD_SCALE}; static unsigned int len, length[] = {0, 6, 8, 10, 10, 6}; - int i = 0, n = 0, ncol = sizeof(dbtype) / sizeof(int); + int i = 0, n = 0, ncol = sizeof(buftyp) / sizeof(int); int lng, typ, prec; LONG low, upp; BSTR propname; @@ -213,7 +211,7 @@ PQRYRES WMIColumns(PGLOBAL g, char *nsp, char *cls, bool info) /* Allocate the structures used to refer to the result set. */ /*********************************************************************/ qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3, - dbtype, buftyp, fldtyp, length, true, true); + buftyp, fldtyp, length, true, true); if (info) return qrp; diff --git a/storage/connect/tabxcl.cpp b/storage/connect/tabxcl.cpp new file mode 100644 index 00000000000..96da0571271 --- /dev/null +++ b/storage/connect/tabxcl.cpp @@ -0,0 +1,283 @@ +/************* TabXcl CPP Declares Source Code File (.CPP) *************/ +/* Name: TABXCL.CPP Version 1.0 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2013 */ +/* */ +/* XCOL: Table having one column containing several values */ +/* comma separated. When creating the table, the name of the X */ +/* column is given by the Name option. */ +/* This first version has one limitation: */ +/* - The X column has the same length than in the physical file. */ +/* This tables produces as many rows for a physical row than the */ +/* number of items in the X column (eventually 0). */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant section of system dependant header files. */ +/***********************************************************************/ +#include "my_global.h" +#if defined(WIN32) +#include <stdlib.h> +#include <stdio.h> +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif +//#include <windows.h> +#else +#if defined(UNIX) +#include <fnmatch.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "osutil.h" +#else +//#include <io.h> +#endif +//#include <fcntl.h> +#endif + +/***********************************************************************/ +/* Include application header files: */ +/***********************************************************************/ +#include "table.h" // MySQL table definitions +#include "global.h" +#include "plgdbsem.h" +#include "plgcnx.h" // For DB types +#include "resource.h" +#include "reldef.h" +#include "filamtxt.h" +#include "tabdos.h" +#include "tabcol.h" +#include "tabxcl.h" +#include "xtable.h" +#if defined(MYSQL_SUPPORT) +#include "tabmysql.h" +#endif // MYSQL_SUPPORT +#include "ha_connect.h" +#include "mycat.h" + +extern "C" int trace; + +/* -------------- Implementation of the XCOL classes ---------------- */ + +/***********************************************************************/ +/* XCLDEF constructor. */ +/***********************************************************************/ +XCLDEF::XCLDEF(void) + { + Xcol = NULL; + Sep = ','; + Mult = 10; +} // end of XCLDEF constructor + +/***********************************************************************/ +/* DefineAM: define specific AM block values from XCOL table. */ +/***********************************************************************/ +bool XCLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) + { + char buf[8]; + + Xcol = Cat->GetStringCatInfo(g, "Colname", ""); + Cat->GetCharCatInfo("Separator", ",", buf, sizeof(buf)); + Sep = (strlen(buf) == 2 && buf[0] == '\\' && buf[1] == 't') ? '\t' : *buf; + Mult = Cat->GetIntCatInfo("Mult", 10); + return PRXDEF::DefineAM(g, am, poff); + } // end of DefineAM + +/***********************************************************************/ +/* GetTable: makes a new TDB of the proper type. */ +/***********************************************************************/ +PTDB XCLDEF::GetTable(PGLOBAL g, MODE mode) + { + if (Catfunc == FNC_COL) + return new(g) TDBTBC(this); + else + return new(g) TDBXCL(this); + + } // end of GetTable + +/* ------------------------------------------------------------------- */ + +/***********************************************************************/ +/* Implementation of the TDBXCL class. */ +/***********************************************************************/ +TDBXCL::TDBXCL(PXCLDEF tdp) : TDBPRX(tdp) + { + Xcolumn = tdp->Xcol; // CSV column name + Xcolp = NULL; // To the XCLCOL column + Mult = tdp->Mult; // Multiplication factor + N = 0; // The current table index + M = 0; // The occurence rank + RowFlag = 0; // 0: Ok, 1: Same, 2: Skip + New = TRUE; // TRUE for new line + Sep = tdp->Sep; // The Xcol separator + } // end of TDBXCL constructor + +/***********************************************************************/ +/* Allocate XCL column description block. */ +/***********************************************************************/ +PCOL TDBXCL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) + { + PCOL colp; + + if (!stricmp(cdp->GetName(), Xcolumn)) { + Xcolp = new(g) XCLCOL(g, cdp, this, cprec, n); + colp = Xcolp; + } else + colp = new(g) PRXCOL(cdp, this, cprec, n); + + return colp; + } // end of MakeCol + +/***********************************************************************/ +/* XCL GetMaxSize: returns the maximum number of rows in the table. */ +/***********************************************************************/ +int TDBXCL::GetMaxSize(PGLOBAL g) + { + if (MaxSize < 0) { + if (InitTable(g)) + return 0; + + MaxSize = Mult * Tdbp->GetMaxSize(g); + } // endif MaxSize + + return MaxSize; + } // end of GetMaxSize + +/***********************************************************************/ +/* For this table type, ROWID is the (virtual) row number, */ +/* while ROWNUM is be the occurence rank in the multiple column. */ +/***********************************************************************/ +int TDBXCL::RowNumber(PGLOBAL g, bool b) + { + return (b) ? M : N; + } // end of RowNumber + +/***********************************************************************/ +/* XCL Access Method opening routine. */ +/***********************************************************************/ +bool TDBXCL::OpenDB(PGLOBAL g) + { + if (Use == USE_OPEN) { + /*******************************************************************/ + /* Table already open, just replace it at its beginning. */ + /*******************************************************************/ + M = N = 0; + RowFlag = 0; + New = TRUE; + return Tdbp->OpenDB(g); + } // endif use + + if (Mode != MODE_READ) { + /*******************************************************************/ + /* Currently XCOL tables cannot be modified. */ + /*******************************************************************/ + strcpy(g->Message, "XCOL tables are read only"); + return TRUE; + } // endif Mode + + if (InitTable(g)) + return TRUE; + + /*********************************************************************/ + /* Check and initialize the subtable columns. */ + /*********************************************************************/ + for (PCOL cp = Columns; cp; cp = cp->GetNext()) + if (((PXCLCOL)cp)->Init(g)) + return TRUE; + + /*********************************************************************/ + /* Physically open the object table. */ + /*********************************************************************/ + if (Tdbp->OpenDB(g)) + return TRUE; + + return FALSE; + } // end of OpenDB + +/***********************************************************************/ +/* Data Base read routine for XCL access method. */ +/***********************************************************************/ +int TDBXCL::ReadDB(PGLOBAL g) + { + int rc = RC_OK; + + /*********************************************************************/ + /* Now start the multi reading process. */ + /*********************************************************************/ + do { + if (RowFlag != 1) { + if ((rc = Tdbp->ReadDB(g)) != RC_OK) + break; + + New = TRUE; + M = 1; + } else { + New = FALSE; + M++; + } // endif RowFlag + + if (Xcolp) { + RowFlag = 0; + Xcolp->ReadColumn(g); + } // endif Xcolp + + N++; + } while (RowFlag == 2); + + return rc; + } // end of ReadDB + + +// ------------------------ XCLCOL functions ---------------------------- + +/***********************************************************************/ +/* XCLCOL public constructor. */ +/***********************************************************************/ +XCLCOL::XCLCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) + : PRXCOL(cdp, tdbp, cprec, i, "XCL") + { + // Set additional XXL access method information for column. + Cbuf = (char*)PlugSubAlloc(g, NULL, Long + 1); + Cp = NULL; // Pointer to current position in Cbuf + Sep = ((PTDBXCL)tdbp)->Sep; + AddStatus(BUF_READ); // Only evaluated from TDBXCL::ReadDB + } // end of XCLCOL constructor + +/***********************************************************************/ +/* What this routine does is to get the comma-separated string */ +/* from the source table column, extract the single values and */ +/* set the flag for the table ReadDB function. */ +/***********************************************************************/ +void XCLCOL::ReadColumn(PGLOBAL g) + { + if (((PTDBXCL)To_Tdb)->New) { + Colp->ReadColumn(g); + strcpy(Cbuf, To_Val->GetCharValue()); + Cp = Cbuf; + } // endif New + + if (*Cp) { + PSZ p; + + // Trim left + for (p = Cp; *p == ' '; p++) ; + + if ((Cp = strchr(Cp, Sep))) + // Separator is found + *Cp++ = '\0'; + + Value->SetValue_psz(p); + } else if (Nullable) { + Value->Reset(); + Value->SetNull(true); + } else + // Skip that row + ((PTDBXCL)To_Tdb)->RowFlag = 2; + + if (Cp && *Cp) + // More to come from the same row + ((PTDBXCL)To_Tdb)->RowFlag = 1; + + } // end of ReadColumn diff --git a/storage/connect/tabxcl.h b/storage/connect/tabxcl.h new file mode 100644 index 00000000000..28fbf85d509 --- /dev/null +++ b/storage/connect/tabxcl.h @@ -0,0 +1,104 @@ +// TABXCL.H Olivier Bertrand 2013 +// Defines the XCOL tables + +#include "tabutil.h" + +#define TYPE_AM_XCOL (AMT)124 + +typedef class XCLDEF *PXCLDEF; +typedef class TDBXCL *PTDBXCL; +typedef class XCLCOL *PXCLCOL; + +/* -------------------------- XCOL classes --------------------------- */ + +/***********************************************************************/ +/* XCOL: table having one column containing several values comma */ +/* (or any other character) separated. When creating the table, the */ +/* name of the X column is given by the NAME option. */ +/* This sample has a limitation: */ +/* - The X column has the same length than in the physical file. */ +/* This tables produces as many rows for a physical row than the */ +/* number of items in the X column (eventually 0). */ +/***********************************************************************/ + +/***********************************************************************/ +/* XCL table. */ +/***********************************************************************/ +class XCLDEF : public PRXDEF { /* Logical table description */ + friend class TDBXCL; + public: + // Constructor + XCLDEF(void); + + // Implementation + virtual const char *GetType(void) {return "XCL";} + + // Methods + virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); + virtual PTDB GetTable(PGLOBAL g, MODE mode); + + protected: + // Members + char *Xcol; /* The column containing separated fields */ + char Sep; /* The field separator, defaults to comma */ + int Mult; /* Multiplication factor */ + }; // end of XCLDEF + +/***********************************************************************/ +/* This is the class declaration for the XCOL table. */ +/***********************************************************************/ +class TDBXCL : public TDBPRX { + friend class XCLDEF; + friend class PRXCOL; + friend class XCLCOL; + public: + // Constructor + TDBXCL(PXCLDEF tdp); + + // Implementation + virtual AMT GetAmType(void) {return TYPE_AM_XCOL;} + + // Methods + virtual void ResetDB(void) {N = 0; Tdbp->ResetDB();} + virtual int RowNumber(PGLOBAL g, bool b = FALSE); + + // Database routines + virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); + virtual int GetMaxSize(PGLOBAL g); + virtual bool OpenDB(PGLOBAL g); + virtual int ReadDB(PGLOBAL g); + + protected: + // Members + char *Xcolumn; // Multiple column name + PXCLCOL Xcolp; // To the XCVCOL column + int Mult; // Multiplication factor + int N; // The current table index + int M; // The occurence rank + BYTE RowFlag; // 0: Ok, 1: Same, 2: Skip + bool New; // TRUE for new line + char Sep; // The Xcol separator + }; // end of class TDBXCL + +/***********************************************************************/ +/* Class XCLCOL: for the multiple CSV column. */ +/***********************************************************************/ +class XCLCOL : public PRXCOL { + friend class TDBXCL; + public: + // Constructors + XCLCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i); + + // Methods + virtual void Reset(void) {} // Evaluated only by TDBXCL + virtual void ReadColumn(PGLOBAL g); + + protected: + // Default constructor not to be used + XCLCOL(void) {} + + // Members + char *Cbuf; // The column buffer + char *Cp; // Pointer to current position + char Sep; // The separator + }; // end of class XCLCOL diff --git a/storage/connect/user_connect.cc b/storage/connect/user_connect.cc index 3fd3ac43e32..d85f11d1950 100644 --- a/storage/connect/user_connect.cc +++ b/storage/connect/user_connect.cc @@ -43,6 +43,7 @@ #include "osutil.h" #include "global.h" #include "plgdbsem.h" +#include "connect.h" #include "user_connect.h" #include "mycat.h" @@ -54,11 +55,6 @@ extern int xtrace; /****************************************************************************/ PCONNECT user_connect::to_users= NULL; -/****************************************************************************/ -/* CONNECT functions called externally. */ -/****************************************************************************/ -PGLOBAL CntExit(PGLOBAL g); - /* -------------------------- class user_connect -------------------------- */ /****************************************************************************/ diff --git a/storage/connect/valblk.cpp b/storage/connect/valblk.cpp index a56841d8980..a96dec2565c 100644 --- a/storage/connect/valblk.cpp +++ b/storage/connect/valblk.cpp @@ -266,7 +266,7 @@ char TYPBLK<char>::GetTypedValue(PVAL valp) {return valp->GetTinyValue();} /***********************************************************************/ -/* Set one value in a block. */ +/* Set one value in a block from a zero terminated string. */ /***********************************************************************/ template <class TYPE> void TYPBLK<TYPE>::SetValue(PSZ p, int n) @@ -295,6 +295,22 @@ template <> char TYPBLK<char>::GetTypedValue(PSZ p) {return (char)atoi(p);} /***********************************************************************/ +/* Set one value in a block from an array of characters. */ +/***********************************************************************/ +template <class TYPE> +void TYPBLK<TYPE>::SetValue(char *sp, uint len, int n) + { + PGLOBAL& g = Global; + PSZ spz = (PSZ)PlugSubAlloc(g, NULL, 0); // Temporary + + if (sp) + memcpy(spz, sp, len); + + spz[len] = 0; + SetValue(spz, n); + } // end of SetValue + +/***********************************************************************/ /* Set one value in a block from a value in another block. */ /***********************************************************************/ template <class TYPE> @@ -552,11 +568,19 @@ void CHRBLK::SetValue(PVAL valp, int n) } // end of SetValue /***********************************************************************/ -/* Set one value in a block. */ +/* Set one value in a block from a zero terminated string. */ /***********************************************************************/ void CHRBLK::SetValue(PSZ sp, int n) { - size_t len = (sp) ? strlen(sp) : 0; + uint len = (sp) ? strlen(sp) : 0; + SetValue(sp, len, n); + } // end of SetValue + +/***********************************************************************/ +/* Set one value in a block from an array of characters. */ +/***********************************************************************/ +void CHRBLK::SetValue(char *sp, uint len, int n) + { char *p = Chrp + n * Long; #if defined(_DEBUG) || defined(DEBTRACE) @@ -568,15 +592,16 @@ void CHRBLK::SetValue(PSZ sp, int n) #endif if (sp) - strncpy(p, sp, Long); - else - *p = '\0'; + memcpy(p, sp, len); - if (Blanks) + if (Blanks) { // Suppress eventual ending zero and right fill with blanks for (register int i = len; i < Long; i++) p[i] = ' '; + } else if ((signed)len < Long) + p[len] = 0; + SetNull(n, false); } // end of SetValue @@ -801,12 +826,33 @@ void STRBLK::SetValue(PVAL valp, int n) } // end of SetValue /***********************************************************************/ -/* Set one value in a block. */ +/* Set one value in a block from a zero terminated string. */ /***********************************************************************/ void STRBLK::SetValue(PSZ p, int n) { - Strp[n] = (PSZ)PlugSubAlloc(Global, NULL, strlen(p) + 1); - strcpy(Strp[n], p); + if (p) { + Strp[n] = (PSZ)PlugSubAlloc(Global, NULL, strlen(p) + 1); + strcpy(Strp[n], p); + } else + Strp[n] = NULL; + + } // end of SetValue + +/***********************************************************************/ +/* Set one value in a block from an array of characters. */ +/***********************************************************************/ +void STRBLK::SetValue(char *sp, uint len, int n) + { + PSZ p; + + if (sp) { + p = (PSZ)PlugSubAlloc(Global, NULL, len + 1); + memcpy(p, sp, len); + p[len] = 0; + } else + p = NULL; + + Strp[n] = p; } // end of SetValue /***********************************************************************/ diff --git a/storage/connect/valblk.h b/storage/connect/valblk.h index 9a85577a104..d9286b72f9f 100644 --- a/storage/connect/valblk.h +++ b/storage/connect/valblk.h @@ -36,6 +36,7 @@ class VALBLK : public BLOCK { void *GetValPointer(void) {return Blkp;} void SetValPointer(void *mp) {Blkp = mp;} int GetType(void) {return Type;} + int GetPrec(void) {return Prec;} void SetCheck(bool b) {Check = b;} void MoveNull(int i, int j) {if (To_Nulls) To_Nulls[j] = To_Nulls[j];} @@ -64,6 +65,7 @@ class VALBLK : public BLOCK { virtual void SetValue(double fval, int n) {assert(false);} virtual void SetValue(char 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; virtual void SetValue(PVBLK pv, int n1, int n2) = 0; #if 0 @@ -109,7 +111,7 @@ class TYPBLK : public VALBLK { // Implementation virtual void Init(PGLOBAL g, bool check); - virtual int GetVlen(void) {return sizeof(int);} + virtual int GetVlen(void) {return sizeof(TYPE);} //virtual PSZ GetCharValue(int n); virtual short GetShortValue(int n) {return (short)Typp[n];} virtual int GetIntValue(int n) {return (int)Typp[n];} @@ -120,6 +122,7 @@ class TYPBLK : public VALBLK { // Methods virtual void SetValue(PSZ sp, int n); + 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(int lval, int n) @@ -175,6 +178,7 @@ class CHRBLK : public VALBLK { // Methods virtual void SetValue(PSZ sp, int n); + virtual void SetValue(char *sp, uint len, int n); 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); @@ -221,6 +225,7 @@ class STRBLK : public VALBLK { // Methods virtual void SetValue(PSZ sp, int n); + virtual void SetValue(char *sp, uint len, int n); 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); diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index 9053658b461..e60f3889ef5 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -88,12 +88,13 @@ 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. */ /***********************************************************************/ -BYTE OpBmp(PGLOBAL g, OPVAL opc) +static BYTE OpBmp(PGLOBAL g, OPVAL opc) { BYTE bt; @@ -113,6 +114,7 @@ BYTE OpBmp(PGLOBAL g, OPVAL opc) return bt; } // end of OpBmp +#endif /***********************************************************************/ /* GetTypeName: returns the PlugDB internal type name. */ @@ -155,46 +157,6 @@ int GetTypeSize(int type, int len) } // end of GetTypeSize /***********************************************************************/ -/* GetPLGType: returns the PlugDB type corresponding to a DB type. */ -/***********************************************************************/ -int GetPLGType(int type) - { - int tp; - - switch (type) { - case DB_CHAR: - case DB_STRING: tp = TYPE_STRING; break; - case DB_SHORT: tp = TYPE_SHORT; break; - case DB_INT: tp = TYPE_INT; break; - case DB_DOUBLE: tp = TYPE_FLOAT; break; - case DB_DATE: tp = TYPE_DATE; break; - default: tp = TYPE_ERROR; - } // endswitch type - - return tp; - } // end of GetPLGType - -/***********************************************************************/ -/* GetDBType: returns the DB type corresponding to a PlugDB type. */ -/***********************************************************************/ -int GetDBType(int type) - { - int tp; - - switch (type) { - case TYPE_STRING: tp = DB_CHAR; break; - case TYPE_SHORT: tp = DB_SHORT; break; - case TYPE_INT: tp = DB_INT; break; - case TYPE_BIGINT: - case TYPE_FLOAT: tp = DB_DOUBLE; break; - case TYPE_DATE: tp = DB_DATE; break; - default: tp = DB_ERROR; - } // endswitch type - - return tp; - } // end of GetPLGType - -/***********************************************************************/ /* GetFormatType: returns the FORMAT character(s) according to type. */ /***********************************************************************/ char *GetFormatType(int type) @@ -606,7 +568,7 @@ void TYPVAL<TYPE>::SetValue_char(char *p, int n) if (minus && Tval) Tval = - Tval; - if (trace) + if (trace > 1) htrc(strcat(strcat(strcpy(buf, " setting %s to: "), Fmt), "\n"), GetTypeName(Type), Tval); @@ -625,7 +587,7 @@ void TYPVAL<double>::SetValue_char(char *p, int n) buf[n] = '\0'; Tval = atof(buf); - if (trace) + if (trace > 1) htrc(" setting double: '%s' -> %lf\n", buf, Tval); Null = false; @@ -940,7 +902,7 @@ void TYPVAL<PSZ>::SetValue_char(char *p, int n) *(++p) = '\0'; - if (trace) + if (trace > 1) htrc(" Setting string to: '%s'\n", Strp); Null = false; @@ -1143,10 +1105,13 @@ bool TYPVAL<PSZ>::IsEqual(PVAL vp, bool chktype) return false; else if (Null || vp->IsNull()) return false; - else if (Ci || vp->IsCi()) - return !stricmp(Strp, vp->GetCharValue()); + + char buf[32]; + + if (Ci || vp->IsCi()) + return !stricmp(Strp, vp->GetCharString(buf)); else // (!Ci) - return !strcmp(Strp, vp->GetCharValue()); + return !strcmp(Strp, vp->GetCharString(buf)); } // end of IsEqual @@ -1261,9 +1226,6 @@ void DTVAL::SetTimeShift(void) /* though the gmtime C function. The purpose of this function is to */ /* extend the range of valid dates by accepting negative time values. */ /***********************************************************************/ -#define MYSQL_SERVER 1 -#include "tztime.h" -#include "sql_priv.h" #include "sql_class.h" #include "sql_time.h" @@ -1282,15 +1244,14 @@ static void TIME_to_localtime(struct tm *tm, const MYSQL_TIME *ltime) static struct tm *gmtime_mysql(const time_t *timep, struct tm *tm) { MYSQL_TIME ltime; - current_thd->variables.time_zone->gmt_sec_to_TIME(<ime, (my_time_t) *timep); + thd_gmt_sec_to_TIME(current_thd, <ime, (my_time_t) *timep); TIME_to_localtime(tm, <ime); return tm; } -struct tm *DTVAL::GetGmTime(void) +struct tm *DTVAL::GetGmTime(struct tm *tm_buffer) { - static struct tm tm_static; /* TODO: Move as a parameter to GetGmTime() */ struct tm *datm; time_t t = (time_t)Tval; @@ -1300,13 +1261,13 @@ struct tm *DTVAL::GetGmTime(void) for (n = 0; t < 0; n += 4) t += FOURYEARS; - datm = gmtime_mysql(&t, &tm_static); + datm = gmtime_mysql(&t, tm_buffer); if (datm) datm->tm_year -= n; } else - datm = gmtime_mysql(&t, &tm_static); + datm = gmtime_mysql(&t, tm_buffer); return datm; } // end of GetGmTime @@ -1332,7 +1293,7 @@ bool DTVAL::MakeTime(struct tm *ptm) int n, y = ptm->tm_year; time_t t = mktime_mysql(ptm); - if (trace) + if (trace > 1) htrc("MakeTime from (%d,%d,%d,%d,%d,%d)\n", ptm->tm_year, ptm->tm_mon, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec); @@ -1355,7 +1316,7 @@ bool DTVAL::MakeTime(struct tm *ptm) } Tval= (int) t; - if (trace) + if (trace > 1) htrc("MakeTime Ival=%d\n", Tval); return false; @@ -1375,7 +1336,7 @@ bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval) datm.tm_mon=0; datm.tm_year=70; - if (trace) + if (trace > 1) htrc("MakeDate from(%d,%d,%d,%d,%d,%d) nval=%d\n", val[0], val[1], val[2], val[3], val[4], val[5], nval); @@ -1439,7 +1400,7 @@ bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval) } // endfor i - if (trace) + if (trace > 1) htrc("MakeDate datm=(%d,%d,%d,%d,%d,%d)\n", datm.tm_year, datm.tm_mon, datm.tm_mday, datm.tm_hour, datm.tm_min, datm.tm_sec); @@ -1500,7 +1461,7 @@ void DTVAL::SetValue_char(char *p, int n) ndv = ExtractDate(Sdate, Pdtp, DefYear, dval); MakeDate(NULL, dval, ndv); - if (trace) + if (trace > 1) htrc(" setting date: '%s' -> %d\n", Sdate, Tval); Null = false; @@ -1524,7 +1485,7 @@ void DTVAL::SetValue_psz(PSZ p) ndv = ExtractDate(Sdate, Pdtp, DefYear, dval); MakeDate(NULL, dval, ndv); - if (trace) + if (trace > 1) htrc(" setting date: '%s' -> %d\n", Sdate, Tval); Null = false; @@ -1556,7 +1517,7 @@ char *DTVAL::GetCharString(char *p) { if (Pdtp) { size_t n = 0; - struct tm *ptm = GetGmTime(); + struct tm tm, *ptm= GetGmTime(&tm); if (ptm) n = strftime(Sdate, Len + 1, Pdtp->OutFmt, ptm); @@ -1582,7 +1543,7 @@ char *DTVAL::ShowValue(char *buf, int len) if (Pdtp) { char *p; size_t m, n = 0; - struct tm *ptm = GetGmTime(); + struct tm tm, *ptm = GetGmTime(&tm); if (Len < len) { p = buf; @@ -1612,7 +1573,7 @@ char *DTVAL::ShowValue(char *buf, int len) bool DTVAL::GetTmMember(OPVAL op, int& mval) { bool rc = false; - struct tm *ptm = GetGmTime(); + struct tm tm, *ptm = GetGmTime(&tm); switch (op) { case OP_MDAY: mval = ptm->tm_mday; break; @@ -1640,7 +1601,7 @@ bool DTVAL::WeekNum(PGLOBAL g, int& nval) { // w is the start of the week SUN=0, MON=1, etc. int m, n, w = nval % 7; - struct tm *ptm = GetGmTime(); + struct tm tm, *ptm = GetGmTime(&tm); // Which day is January 4th of this year? m = (367 + ptm->tm_wday - ptm->tm_yday) % 7; @@ -1664,7 +1625,7 @@ bool DTVAL::WeekNum(PGLOBAL g, int& nval) bool DTVAL::FormatValue(PVAL vp, char *fmt) { char *buf = (char*)vp->GetTo_Val(); // Should be big enough - struct tm *ptm = GetGmTime(); + struct tm tm, *ptm = GetGmTime(&tm); if (trace) htrc("FormatValue: ptm=%p len=%d\n", ptm, vp->GetValLen()); diff --git a/storage/connect/value.h b/storage/connect/value.h index 0f7b795c252..62b4ea4617a 100644 --- a/storage/connect/value.h +++ b/storage/connect/value.h @@ -38,7 +38,6 @@ typedef struct _datpar *PDTP; // For DTVAL /***********************************************************************/ /* Utilities used to test types and to allocated values. */ /***********************************************************************/ -int GetPLGType(int); PVAL AllocateValue(PGLOBAL, void *, short); // Exported functions @@ -50,7 +49,6 @@ DllExport int TranslateSQLType(int stp, int prec, int& len); #endif DllExport char *GetFormatType(int); DllExport int GetFormatType(char); -DllExport int GetDBType(int); DllExport bool IsTypeChar(int type); DllExport bool IsTypeNum(int type); DllExport int ConvertType(int, int, CONV, bool match = false); @@ -82,12 +80,12 @@ class DllExport VALUE : public BLOCK { virtual longlong GetBigintValue(void) = 0; virtual double GetFloatValue(void) = 0; virtual void *GetTo_Val(void) = 0; + virtual void SetPrec(int prec) {Prec = prec;} bool IsNull(void) {return Null;} void SetNull(bool b) {Null = b;} void SetNullable(bool b) {Nullable = b;} int GetType(void) {return Type;} int GetClen(void) {return Clen;} - void SetPrec(int prec) {Prec = prec;} void SetGlobal(PGLOBAL g) {Global = g;} // Methods @@ -217,6 +215,7 @@ class DllExport TYPVAL<PSZ>: public VALUE { virtual longlong GetBigintValue(void) {return atoll(Strp);} virtual double GetFloatValue(void) {return atof(Strp);} virtual void *GetTo_Val(void) {return Strp;} + virtual void SetPrec(int prec) {Ci = prec != 0;} // Methods virtual bool SetValue_pval(PVAL valp, bool chktype); @@ -289,7 +288,7 @@ class DllExport DTVAL : public TYPVAL<int> { bool MakeDate(PGLOBAL g, int *val, int nval); bool WeekNum(PGLOBAL g, int& nval); - struct tm *GetGmTime(void); + struct tm *GetGmTime(struct tm *); protected: // Default constructor not to be used diff --git a/storage/connect/xobject.h b/storage/connect/xobject.h index c77fb703823..79325f155cf 100644 --- a/storage/connect/xobject.h +++ b/storage/connect/xobject.h @@ -71,7 +71,6 @@ class DllExport XOBJECT : public BLOCK { virtual bool VerifyColumn(PTBX txp) {return false;} virtual bool VerifyTdb(PTDB& tdbp) {return false;} virtual bool IsColInside(PCOL colp) {return false;} - virtual void MarkCol(ushort) {} protected: PVAL Value; // The current value of the object. diff --git a/storage/connect/xtable.h b/storage/connect/xtable.h index 8475c46d52d..7ef2d26136c 100644 --- a/storage/connect/xtable.h +++ b/storage/connect/xtable.h @@ -173,6 +173,7 @@ class DllExport TDBASE : public TDB { virtual int GetRecpos(void) = 0; virtual bool SetRecpos(PGLOBAL g, int recpos); virtual bool IsReadOnly(void) {return Read_Only;} + virtual bool IsView(void) {return FALSE;} virtual CHARSET_INFO *data_charset() { /* diff --git a/storage/perfschema/ha_perfschema.cc b/storage/perfschema/ha_perfschema.cc index c6c967ceb9d..aca5ad8c731 100644 --- a/storage/perfschema/ha_perfschema.cc +++ b/storage/perfschema/ha_perfschema.cc @@ -18,11 +18,9 @@ Performance schema storage engine (implementation). */ -#include "my_global.h" +#include "sql_plugin.h" #include "my_pthread.h" #include "my_atomic.h" -#include "sql_plugin.h" -#include "mysql/plugin.h" #include "ha_perfschema.h" #include "pfs_engine_table.h" #include "pfs_column_values.h" |