From 19042843613efeffb4880c4b145a7744b4810ab5 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Thu, 17 Jul 2014 18:13:51 +0200 Subject: This commit brings many changes, in particular two important ones: 1) Support of partitioning by connect. A table can be partitioned by files, this is an enhanced MULTIPLE table. It can be also partitioned by sub-tables like TBL and this enables table sharding. 2) Handling a CONNECT bug that causes in some cases extraneous rows to remain in the table after an UPDATE or DELETE when the command uses indexing (for not fixed file tables). Until a real fix is done, CONNECT tries to ignore indexing and if it cannot do it abort the command with an error message. - Add tests on partitioning added: storage/connect/mysql-test/connect/r/part_file.result storage/connect/mysql-test/connect/r/part_table.result storage/connect/mysql-test/connect/t/part_file.test storage/connect/mysql-test/connect/t/part_table.test - Temporary fix modified: sql/sql_partition.cc - Add partition support modified: storage/connect/ha_connect.cc storage/connect/ha_connect.h storage/connect/reldef.cpp storage/connect/reldef.h storage/connect/tabdos.cpp - Add functions ha_connect::IsUnique and ha_connect::CheckColumnList modified: storage/connect/ha_connect.cc storage/connect/ha_connect.h - Prevent updating a partition table column that is part of the partition function (outward tables only) modified: storage/connect/ha_connect.cc - Support INSERT/UPDATE/DELETE for PROXY tables modified: storage/connect/tabutil.cpp - Handle the bug on updating rows via indexing. Waiting for a real fix, Don't use indexing when possible else raise an error and abort. modified: storage/connect/ha_connect.cc - dbuserp->UseTemp set to TMP_AUTO modified: storage/connect/connect.cc - Add members nox, abort and only modified: storage/connect/ha_connect.cc storage/connect/ha_connect.h - Add arguments nox and abort to CntCloseTable modified: storage/connect/connect.cc storage/connect/connect.h storage/connect/filamap.cpp storage/connect/filamap.h storage/connect/filamdbf.cpp storage/connect/filamdbf.h storage/connect/filamfix.cpp storage/connect/filamfix.h storage/connect/filamtxt.cpp storage/connect/filamtxt.h storage/connect/filamvct.cpp storage/connect/filamvct.h storage/connect/filamzip.cpp storage/connect/filamzip.h storage/connect/ha_connect.cc - Add arguments abort to CloseTableFile and RenameTempFile modified: storage/connect/filamap.cpp storage/connect/filamap.h storage/connect/filamdbf.cpp storage/connect/filamdbf.h storage/connect/filamfix.cpp storage/connect/filamfix.h storage/connect/filamtxt.cpp storage/connect/filamtxt.h storage/connect/filamvct.cpp storage/connect/filamvct.h storage/connect/filamzip.cpp storage/connect/filamzip.h storage/connect/tabdos.cpp storage/connect/tabdos.h storage/connect/tabvct.cpp storage/connect/xtable.h - Fix info->records when file does not exists modified: storage/connect/connect.cc - Close XML table when opened for info modified: storage/connect/connect.cc - Add function VCTFAM::GetFileLength modified: storage/connect/filamvct.cpp storage/connect/filamvct.h - Column option DISTRIB -> ENUM modified: storage/connect/ha_connect.cc - Options connect, query_string and partname allways available modified: storage/connect/ha_connect.cc - Add function MYSQLC::GetTableSize modified: storage/connect/myconn.cpp storage/connect/myconn.h - Add new special columns (PARTNAME, FNAME, FPATH, FTYPE and FDISK) modified: storage/connect/colblk.cpp storage/connect/colblk.h storage/connect/plgdbsem.h storage/connect/table.cpp - Add function ExtractFromPath modified: storage/connect/colblk.cpp storage/connect/plgdbsem.h storage/connect/plgdbutl.cpp - Enhance Cardinality for some table types modified: storage/connect/tabdos.cpp storage/connect/tabmysql.cpp storage/connect/tabmysql.h storage/connect/tabodbc.cpp storage/connect/tabodbc.h storage/connect/tabsys.cpp storage/connect/tabsys.h storage/connect/xindex.cpp storage/connect/xindex.h storage/connect/xtable.h - Add test on special column modified: storage/connect/tabfmt.cpp - Add new files (added for block indexing) modified: storage/connect/CMakeLists.txt --- storage/connect/CMakeLists.txt | 26 +- storage/connect/colblk.cpp | 43 ++- storage/connect/colblk.h | 32 +- storage/connect/connect.cc | 35 +- storage/connect/connect.h | 4 +- storage/connect/filamap.cpp | 2 +- storage/connect/filamap.h | 4 +- storage/connect/filamdbf.cpp | 22 +- storage/connect/filamdbf.h | 2 +- storage/connect/filamfix.cpp | 59 ++-- storage/connect/filamfix.h | 4 +- storage/connect/filamtxt.cpp | 80 +++-- storage/connect/filamtxt.h | 8 +- storage/connect/filamvct.cpp | 113 ++++--- storage/connect/filamvct.h | 31 +- storage/connect/filamzip.cpp | 10 +- storage/connect/filamzip.h | 6 +- storage/connect/ha_connect.cc | 329 ++++++++++++++----- storage/connect/ha_connect.h | 8 +- storage/connect/mycat.cc | 1 + storage/connect/myconn.cpp | 37 ++- storage/connect/myconn.h | 1 + .../connect/mysql-test/connect/r/part_file.result | 355 +++++++++++++++++++++ .../connect/mysql-test/connect/r/part_table.result | 180 +++++++++++ .../connect/mysql-test/connect/t/part_file.test | 159 +++++++++ .../connect/mysql-test/connect/t/part_table.test | 85 +++++ storage/connect/plgdbsem.h | 2 + storage/connect/plgdbutl.cpp | 25 ++ storage/connect/reldef.cpp | 11 +- storage/connect/reldef.h | 1 + storage/connect/tabcol.h | 2 +- storage/connect/tabdos.cpp | 67 +++- storage/connect/tabdos.h | 3 +- storage/connect/tabfix.cpp | 2 - storage/connect/tabfmt.cpp | 7 +- storage/connect/table.cpp | 30 +- storage/connect/tabmysql.cpp | 81 +++-- storage/connect/tabmysql.h | 3 +- storage/connect/tabodbc.cpp | 88 +++-- storage/connect/tabodbc.h | 3 +- storage/connect/tabsys.cpp | 61 ++-- storage/connect/tabsys.h | 11 +- storage/connect/tabtbl.cpp | 4 +- storage/connect/tabutil.cpp | 29 +- storage/connect/tabvct.cpp | 2 +- storage/connect/tabxml.cpp | 2 +- storage/connect/xindex.cpp | 22 +- storage/connect/xindex.h | 2 +- storage/connect/xtable.h | 2 + 49 files changed, 1689 insertions(+), 407 deletions(-) create mode 100644 storage/connect/mysql-test/connect/r/part_file.result create mode 100644 storage/connect/mysql-test/connect/r/part_table.result create mode 100644 storage/connect/mysql-test/connect/t/part_file.test create mode 100644 storage/connect/mysql-test/connect/t/part_table.test (limited to 'storage/connect') diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index f8db000a486..40d38fdc3b5 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -19,20 +19,20 @@ 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 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 +array.cpp blkfil.cpp colblk.cpp csort.cpp +filamap.cpp filamdbf.cpp filamfix.cpp filamtxt.cpp filamvct.cpp filamzip.cpp +filter.cpp maputil.cpp myutil.cpp plgdbutl.cpp reldef.cpp tabcol.cpp +tabdos.cpp tabfix.cpp tabfmt.cpp table.cpp tabmul.cpp taboccur.cpp +tabpivot.cpp tabsys.cpp tabtbl.cpp tabutil.cpp tabvct.cpp tabxcl.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 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 -tabutil.h tabxcl.h taboccur.h tabpivot.h) + +array.h blkfil.h 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 +filter.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 taboccur.h tabpivot.h tabsys.h +tabtbl.h tabutil.h tabvct.h tabxcl.h user_connect.h valblk.h value.h +xindex.h xobject.h xtable.h) # # Definitions that are shared for all OSes diff --git a/storage/connect/colblk.cpp b/storage/connect/colblk.cpp index a3fb5587ba9..81ab1ad7245 100644 --- a/storage/connect/colblk.cpp +++ b/storage/connect/colblk.cpp @@ -292,7 +292,7 @@ void RIDBLK::ReadColumn(PGLOBAL g) /***********************************************************************/ /* FIDBLK constructor for the FILEID special column. */ /***********************************************************************/ -FIDBLK::FIDBLK(PCOLUMN cp) : SPCBLK(cp) +FIDBLK::FIDBLK(PCOLUMN cp, OPVAL op) : SPCBLK(cp), Op(op) { //Is_Key = 2; for when the MUL table indexed reading will be implemented. Precision = Long = _MAX_PATH; @@ -319,7 +319,14 @@ void FIDBLK::ReadColumn(PGLOBAL g) Fn = ((PTDBASE)To_Tdb)->GetFile(g); PlugSetPath(filename, Fn, ((PTDBASE)To_Tdb)->GetPath()); - Value->SetValue_psz(filename); + + if (Op != OP_XX) { + char buff[_MAX_PATH]; + + Value->SetValue_psz(ExtractFromPath(g, buff, filename, Op)); + } else + Value->SetValue_psz(filename); + } // endif Fn } // end of ReadColumn @@ -351,6 +358,38 @@ void TIDBLK::ReadColumn(PGLOBAL g) } // end of ReadColumn +/***********************************************************************/ +/* PRTBLK constructor for the PARTID special column. */ +/***********************************************************************/ +PRTBLK::PRTBLK(PCOLUMN cp) : SPCBLK(cp) + { +//Is_Key = 2; for when the MUL table indexed reading will be implemented. + Precision = Long = 64; + Buf_Type = TYPE_STRING; + *Format.Type = 'C'; + Format.Length = Long; + Format.Prec = 1; // Case insensitive + Constant = true; // TODO: check whether this is true indeed + Pname = NULL; + } // end of PRTBLK constructor + +/***********************************************************************/ +/* ReadColumn: what this routine does is to return the partition ID. */ +/***********************************************************************/ +void PRTBLK::ReadColumn(PGLOBAL g) + { + if (Pname == NULL) { + char *p; + PTDBASE tdbp = (PTDBASE)To_Tdb; + + Pname = tdbp->GetDef()->GetStringCatInfo(g, "partname", "?"); + + p = strrchr(Pname, '#'); + Value->SetValue_psz((p) ? p + 1 : Pname); + } // endif Pname + + } // end of ReadColumn + /***********************************************************************/ /* SIDBLK constructor for the SERVID special column. */ /***********************************************************************/ diff --git a/storage/connect/colblk.h b/storage/connect/colblk.h index d004b96b5b3..5e8dc77ff69 100644 --- a/storage/connect/colblk.h +++ b/storage/connect/colblk.h @@ -107,7 +107,7 @@ class DllExport SPCBLK : public COLBLK { // Implementation virtual int GetAmType(void) = 0; - virtual bool GetRnm(void) {return false;} + virtual bool GetRnm(void) {return false;} // Methods virtual bool IsSpecial(void) {return true;} @@ -129,7 +129,7 @@ class DllExport RIDBLK : public SPCBLK { // Implementation virtual int GetAmType(void) {return TYPE_AM_ROWID;} - virtual bool GetRnm(void) {return Rnm;} + virtual bool GetRnm(void) {return Rnm;} // Methods virtual void ReadColumn(PGLOBAL g); @@ -144,7 +144,7 @@ class DllExport RIDBLK : public SPCBLK { class DllExport FIDBLK : public SPCBLK { public: // Constructor - FIDBLK(PCOLUMN cp); + FIDBLK(PCOLUMN cp, OPVAL op); // Implementation virtual int GetAmType(void) {return TYPE_AM_FILID;} @@ -154,7 +154,8 @@ class DllExport FIDBLK : public SPCBLK { virtual void ReadColumn(PGLOBAL g); protected: - PSZ Fn; // The current To_File of the table + PSZ Fn; // The current To_File of the table + OPVAL Op; // The file part operator }; // end of class FIDBLK /***********************************************************************/ @@ -180,6 +181,29 @@ class DllExport TIDBLK : public SPCBLK { PSZ Tname; // The current table name }; // end of class TIDBLK +/***********************************************************************/ +/* Class PRTBLK: PARTID special column descriptor. */ +/***********************************************************************/ +class DllExport PRTBLK : public SPCBLK { + public: + // Constructor + PRTBLK(PCOLUMN cp); + + // Implementation + virtual int GetAmType(void) {return TYPE_AM_PRTID;} + + // Methods + virtual void Reset(void) {} // This is a pseudo constant column + virtual void ReadColumn(PGLOBAL g); + + protected: + // Default constructor not to be used + PRTBLK(void) {} + + // Members + PSZ Pname; // The current partition name + }; // end of class PRTBLK + /***********************************************************************/ /* Class SIDBLK: SERVID special column descriptor. */ /***********************************************************************/ diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc index 70f05b242d5..e782fbbfff3 100644 --- a/storage/connect/connect.cc +++ b/storage/connect/connect.cc @@ -142,7 +142,7 @@ bool CntCheckDB(PGLOBAL g, PHC handler, const char *pathname) return true; ((MYCAT *)dbuserp->Catalog)->SetDataPath(g, pathname); - dbuserp->UseTemp= TMP_YES; // Must use temporary file + dbuserp->UseTemp= TMP_AUTO; /*********************************************************************/ /* All is correct. */ @@ -167,7 +167,12 @@ bool CntInfo(PGLOBAL g, PTDB tp, PXF info) if (tdbp) { b= tdbp->GetFtype() != RECFM_NAF; info->data_file_length= (b) ? (ulonglong)tdbp->GetFileLength(g) : 0; - info->records= (unsigned)tdbp->GetMaxSize(g); + + if (!b || info->data_file_length) + info->records= (unsigned)tdbp->GetMaxSize(g); + else + info->records= 0; + // info->mean_rec_length= tdbp->GetLrecl(); info->mean_rec_length= 0; info->data_file_name= (b) ? tdbp->GetFile(g) : NULL; @@ -343,12 +348,12 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2, //tdbp->SetMode(mode); - if (del && ((PTDBASE)tdbp)->GetFtype() != RECFM_NAF) { + if (del/* && ((PTDBASE)tdbp)->GetFtype() != RECFM_NAF*/) { // To avoid erasing the table when doing a partial delete // make a fake Next - PDOSDEF ddp= new(g) DOSDEF; - PTDB tp= new(g) TDBDOS(ddp, NULL); - tdbp->SetNext(tp); +// PDOSDEF ddp= new(g) DOSDEF; +// PTDB tp= new(g) TDBDOS(ddp, NULL); + tdbp->SetNext((PTDB)1); dup->Check &= ~CHK_DELETE; } // endif del @@ -544,16 +549,23 @@ RCODE CntDeleteRow(PGLOBAL g, PTDB tdbp, bool all) /***********************************************************************/ /* CLOSETAB: Close a table. */ /***********************************************************************/ -int CntCloseTable(PGLOBAL g, PTDB tdbp) +int CntCloseTable(PGLOBAL g, PTDB tdbp, bool nox, bool abort) { int rc= RC_OK; TDBDOX *tbxp= NULL; - if (!tdbp || tdbp->GetUse() != USE_OPEN) + if (!tdbp) return rc; // Nothing to do + else if (tdbp->GetUse() != USE_OPEN) { + if (tdbp->GetAmType() == TYPE_AM_XML) + tdbp->CloseDB(g); // Opened by GetMaxSize + + return rc; + } // endif !USE_OPEN if (trace) - printf("CntCloseTable: tdbp=%p mode=%d\n", tdbp, tdbp->GetMode()); + printf("CntCloseTable: tdbp=%p mode=%d nox=%d abort=%d\n", + tdbp, tdbp->GetMode(), nox, abort); if (tdbp->GetMode() == MODE_DELETE && tdbp->GetUse() == USE_OPEN) rc= tdbp->DeleteDB(g, RC_EF); // Specific A.M. delete routine @@ -572,8 +584,9 @@ int CntCloseTable(PGLOBAL g, PTDB tdbp) // This will close the table file(s) and also finalize write // operations such as Insert, Update, or Delete. + tdbp->SetAbort(abort); tdbp->CloseDB(g); - + tdbp->SetAbort(false); g->jump_level--; if (trace > 1) @@ -582,7 +595,7 @@ int CntCloseTable(PGLOBAL g, PTDB tdbp) //if (!((PTDBDOX)tdbp)->GetModified()) // return 0; - if (tdbp->GetMode() == MODE_READ || tdbp->GetMode() == MODE_ANY) + if (nox || tdbp->GetMode() == MODE_READ || tdbp->GetMode() == MODE_ANY) return 0; if (trace > 1) diff --git a/storage/connect/connect.h b/storage/connect/connect.h index 380da7c29b9..145991a3b74 100644 --- a/storage/connect/connect.h +++ b/storage/connect/connect.h @@ -33,7 +33,7 @@ bool CntCheckDB(PGLOBAL g, PHC handler, const char *pathname); PTDB CntGetTDB(PGLOBAL g, const char *name, MODE xmod, PHC); bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE, char *, char *, bool, PHC); bool CntRewindTable(PGLOBAL g, PTDB tdbp); -int CntCloseTable(PGLOBAL g, PTDB tdbp); +int CntCloseTable(PGLOBAL g, PTDB tdbp, bool nox, bool abort); int CntIndexInit(PGLOBAL g, PTDB tdbp, int id); RCODE CntReadNext(PGLOBAL g, PTDB tdbp); RCODE CntIndexRead(PGLOBAL g, PTDB, OPVAL op, const void *k, int n, bool mrr); @@ -58,7 +58,7 @@ class DOXDEF: public DOSDEF { /***********************************************************************/ class TDBDOX: public TDBDOS { friend int MakeIndex(PGLOBAL, PTDB, PIXDEF); - friend int CntCloseTable(PGLOBAL, PTDB); + friend int CntCloseTable(PGLOBAL, PTDB, bool, bool); friend int CntIndexInit(PGLOBAL, PTDB, int); friend RCODE CntIndexRead(PGLOBAL, PTDB, OPVAL, const void*, int, bool); friend RCODE CntDeleteRow(PGLOBAL, PTDB, bool); diff --git a/storage/connect/filamap.cpp b/storage/connect/filamap.cpp index 87cb2e83cfa..1e7a9ba0d12 100644 --- a/storage/connect/filamap.cpp +++ b/storage/connect/filamap.cpp @@ -476,7 +476,7 @@ int MAPFAM::DeleteRecords(PGLOBAL g, int irc) /***********************************************************************/ /* Table file close routine for MAP access method. */ /***********************************************************************/ -void MAPFAM::CloseTableFile(PGLOBAL g) +void MAPFAM::CloseTableFile(PGLOBAL g, bool abort) { PlugCloseFile(g, To_Fb); To_Fb = NULL; // To get correct file size in Cardinality diff --git a/storage/connect/filamap.h b/storage/connect/filamap.h index adee5816e12..ccdbf6cb8bd 100644 --- a/storage/connect/filamap.h +++ b/storage/connect/filamap.h @@ -42,8 +42,8 @@ class DllExport MAPFAM : public TXTFAM { virtual bool DeferReading(void) {return false;} virtual int ReadBuffer(PGLOBAL g); virtual int WriteBuffer(PGLOBAL g); - virtual int DeleteRecords(PGLOBAL g, int irc); - virtual void CloseTableFile(PGLOBAL g); + virtual int DeleteRecords(PGLOBAL g, int irc); + virtual void CloseTableFile(PGLOBAL g, bool abort); virtual void Rewind(void); protected: diff --git a/storage/connect/filamdbf.cpp b/storage/connect/filamdbf.cpp index 7ca98eeff55..e840800a117 100644 --- a/storage/connect/filamdbf.cpp +++ b/storage/connect/filamdbf.cpp @@ -791,7 +791,7 @@ void DBFFAM::Rewind(void) /***********************************************************************/ /* Table file close routine for DBF access method. */ /***********************************************************************/ -void DBFFAM::CloseTableFile(PGLOBAL g) +void DBFFAM::CloseTableFile(PGLOBAL g, bool abort) { int rc = RC_OK, wrc = RC_OK; MODE mode = Tdbp->GetMode(); @@ -810,17 +810,17 @@ void DBFFAM::CloseTableFile(PGLOBAL g) } // endif Modif if (UseTemp && T_Stream && wrc == RC_OK) { - // Copy any remaining lines - bool b; - - Fpos = Tdbp->Cardinality(g); - - if ((rc = MoveIntermediateLines(g, &b)) == RC_OK) { - // Delete the old file and rename the new temp file. - RenameTempFile(g); - goto fin; - } // endif rc + if (!abort) { + // Copy any remaining lines + bool b; + + Fpos = Tdbp->Cardinality(g); + abort = MoveIntermediateLines(g, &b) != RC_OK; + } // endif abort + // Delete the old file and rename the new temp file. + RenameTempFile(g, abort); + goto fin; } // endif UseTemp } // endif's mode diff --git a/storage/connect/filamdbf.h b/storage/connect/filamdbf.h index b85b9fc47fe..0345c0338e8 100644 --- a/storage/connect/filamdbf.h +++ b/storage/connect/filamdbf.h @@ -67,7 +67,7 @@ class DllExport DBFFAM : public FIXFAM, public DBFBASE { virtual void ResetBuffer(PGLOBAL g); virtual int ReadBuffer(PGLOBAL g); virtual int DeleteRecords(PGLOBAL g, int irc); - virtual void CloseTableFile(PGLOBAL g); + virtual void CloseTableFile(PGLOBAL g, bool abort); virtual void Rewind(void); protected: diff --git a/storage/connect/filamfix.cpp b/storage/connect/filamfix.cpp index df76ca82b18..e37dff3b90e 100644 --- a/storage/connect/filamfix.cpp +++ b/storage/connect/filamfix.cpp @@ -315,8 +315,7 @@ int FIXFAM::WriteBuffer(PGLOBAL g) } else { // Mode == MODE_UPDATE // T_Stream is the temporary stream or the table file stream itself - if (!T_Stream) - { + if (!T_Stream) { if (UseTemp /*&& Tdbp->GetMode() == MODE_UPDATE*/) { if (OpenTempFile(g)) return RC_FX; @@ -326,7 +325,9 @@ int FIXFAM::WriteBuffer(PGLOBAL g) } else T_Stream = Stream; - } + + } // endif T_Stream + Modif++; // Modified line in Update mode } // endif Mode @@ -420,7 +421,7 @@ int FIXFAM::DeleteRecords(PGLOBAL g, int irc) /*****************************************************************/ /* Ok, now delete old file and rename new temp file. */ /*****************************************************************/ - if (RenameTempFile(g)) + if (RenameTempFile(g, false)) return RC_FX; } else { @@ -527,7 +528,7 @@ bool FIXFAM::MoveIntermediateLines(PGLOBAL g, bool *b) /***********************************************************************/ /* Table file close routine for FIX access method. */ /***********************************************************************/ -void FIXFAM::CloseTableFile(PGLOBAL g) +void FIXFAM::CloseTableFile(PGLOBAL g, bool abort) { int rc = RC_OK, wrc = RC_OK; MODE mode = Tdbp->GetMode(); @@ -546,17 +547,17 @@ void FIXFAM::CloseTableFile(PGLOBAL g) } // endif Modif if (UseTemp && T_Stream && wrc == RC_OK) { - // Copy any remaining lines - bool b; - - Fpos = Tdbp->Cardinality(g); - - if ((rc = MoveIntermediateLines(g, &b)) == RC_OK) { - // Delete the old file and rename the new temp file. - RenameTempFile(g); - goto fin; - } // endif rc - + if (!abort) { + // Copy any remaining lines + bool b; + + Fpos = Tdbp->Cardinality(g); + abort = MoveIntermediateLines(g, &b) != RC_OK; + } // endif // abort + + // Delete the old file and rename the new temp file. + RenameTempFile(g, abort); + goto fin; } // endif UseTemp } // endif's mode @@ -1245,7 +1246,7 @@ int BGXFAM::DeleteRecords(PGLOBAL g, int irc) /*****************************************************************/ /* Ok, now delete old file and rename new temp file. */ /*****************************************************************/ - if (RenameTempFile(g)) + if (RenameTempFile(g, false)) return RC_FX; } else { @@ -1375,7 +1376,7 @@ bool BGXFAM::MoveIntermediateLines(PGLOBAL g, bool *b) /***********************************************************************/ /* Data Base close routine for BIGFIX access method. */ /***********************************************************************/ -void BGXFAM::CloseTableFile(PGLOBAL g) +void BGXFAM::CloseTableFile(PGLOBAL g, bool abort) { int rc = RC_OK, wrc = RC_OK; MODE mode = Tdbp->GetMode(); @@ -1393,17 +1394,17 @@ void BGXFAM::CloseTableFile(PGLOBAL g) } // endif Modif if (UseTemp && Tfile && wrc == RC_OK) { - // Copy any remaining lines - bool b; - - Fpos = Tdbp->Cardinality(g); - - if ((rc = MoveIntermediateLines(g, &b)) == RC_OK) { - // Delete the old file and rename the new temp file. - RenameTempFile(g); - goto fin; - } // endif rc - + if (!abort) { + // Copy any remaining lines + bool b; + + Fpos = Tdbp->Cardinality(g); + abort = MoveIntermediateLines(g, &b) != RC_OK; + } // endif abort + + // Delete the old file and rename the new temp file. + RenameTempFile(g, abort); + goto fin; } // endif UseTemp } // endif's mode diff --git a/storage/connect/filamfix.h b/storage/connect/filamfix.h index 80523fa05e8..22f84552320 100644 --- a/storage/connect/filamfix.h +++ b/storage/connect/filamfix.h @@ -38,7 +38,7 @@ class DllExport FIXFAM : public BLKFAM { virtual int ReadBuffer(PGLOBAL g); virtual int WriteBuffer(PGLOBAL g); virtual int DeleteRecords(PGLOBAL g, int irc); - virtual void CloseTableFile(PGLOBAL g); + virtual void CloseTableFile(PGLOBAL g, bool abort); protected: virtual bool CopyHeader(PGLOBAL g) {return false;} @@ -69,7 +69,7 @@ class BGXFAM : public FIXFAM { virtual int ReadBuffer(PGLOBAL g); virtual int WriteBuffer(PGLOBAL g); virtual int DeleteRecords(PGLOBAL g, int irc); - virtual void CloseTableFile(PGLOBAL g); + virtual void CloseTableFile(PGLOBAL g, bool abort); virtual void Rewind(void); protected: diff --git a/storage/connect/filamtxt.cpp b/storage/connect/filamtxt.cpp index 60a9f944415..0812fa935fb 100644 --- a/storage/connect/filamtxt.cpp +++ b/storage/connect/filamtxt.cpp @@ -552,7 +552,7 @@ int DOSFAM::ReadBuffer(PGLOBAL g) CurBlk = (int)Rows++; - if (trace > 1) + if (trace > 1) htrc("ReadBuffer: CurBlk=%d\n", CurBlk); /********************************************************************/ @@ -922,13 +922,16 @@ bool DOSFAM::MoveIntermediateLines(PGLOBAL g, bool *b) /***********************************************************************/ /* Delete the old file and rename the new temp file. */ +/* If aborting just delete the new temp file. */ /***********************************************************************/ -int DOSFAM::RenameTempFile(PGLOBAL g) +int DOSFAM::RenameTempFile(PGLOBAL g, bool abort) { char *tempname, filetemp[_MAX_PATH], filename[_MAX_PATH]; - int rc; + int rc = RC_OK; - if (!To_Fbt) + if (To_Fbt) + tempname = (char*)To_Fbt->Fname; + else return RC_INFO; // Nothing to do ??? // This loop is necessary because, in case of join, @@ -937,26 +940,28 @@ int DOSFAM::RenameTempFile(PGLOBAL g) if (fb == To_Fb || fb == To_Fbt) rc = PlugCloseFile(g, fb); - tempname = (char*)To_Fbt->Fname; - PlugSetPath(filename, To_File, Tdbp->GetPath()); - strcat(PlugRemoveType(filetemp, filename), ".ttt"); - remove(filetemp); // May still be there from previous error + if (!abort) { + PlugSetPath(filename, To_File, Tdbp->GetPath()); + strcat(PlugRemoveType(filetemp, filename), ".ttt"); + remove(filetemp); // May still be there from previous error + + if (rename(filename, filetemp)) { // Save file for security + sprintf(g->Message, MSG(RENAME_ERROR), + filename, filetemp, strerror(errno)); + rc = RC_FX; + } else if (rename(tempname, filename)) { + sprintf(g->Message, MSG(RENAME_ERROR), + tempname, filename, strerror(errno)); + rc = rename(filetemp, filename); // Restore saved file + rc = RC_FX; + } else if (remove(filetemp)) { + sprintf(g->Message, MSG(REMOVE_ERROR), + filetemp, strerror(errno)); + rc = RC_INFO; // Acceptable + } // endif's - if (rename(filename, filetemp)) { // Save file for security - sprintf(g->Message, MSG(RENAME_ERROR), - filename, filetemp, strerror(errno)); - rc = RC_FX; - } else if (rename(tempname, filename)) { - sprintf(g->Message, MSG(RENAME_ERROR), - tempname, filename, strerror(errno)); - rc = rename(filetemp, filename); // Restore saved file - rc = RC_FX; - } else if (remove(filetemp)) { - sprintf(g->Message, MSG(REMOVE_ERROR), - filetemp, strerror(errno)); - rc = RC_INFO; // Acceptable } else - rc = RC_OK; + remove(tempname); return rc; } // end of RenameTempFile @@ -964,22 +969,22 @@ int DOSFAM::RenameTempFile(PGLOBAL g) /***********************************************************************/ /* Table file close routine for DOS access method. */ /***********************************************************************/ -void DOSFAM::CloseTableFile(PGLOBAL g) +void DOSFAM::CloseTableFile(PGLOBAL g, bool abort) { int rc; if (UseTemp && T_Stream) { - if (Tdbp->Mode == MODE_UPDATE) { + if (Tdbp->Mode == MODE_UPDATE && !abort) { // Copy eventually remaining lines bool b; fseek(Stream, 0, SEEK_END); Fpos = ftell(Stream); - rc = MoveIntermediateLines(g, &b); - } // endif Mode + abort = MoveIntermediateLines(g, &b) != RC_OK; + } // endif abort // Delete the old file and rename the new temp file. - RenameTempFile(g); // Also close all files + RenameTempFile(g, abort); // Also close all files } else { rc = PlugCloseFile(g, To_Fb); @@ -1045,9 +1050,7 @@ void BLKFAM::Reset(void) /***********************************************************************/ int BLKFAM::Cardinality(PGLOBAL g) { - // Should not be called in this version - return (g) ? -1 : 0; -//return (g) ? (int)((Block - 1) * Nrec + Last) : 1; + return (g) ? (int)((Block - 1) * Nrec + Last) : 1; } // end of Cardinality /***********************************************************************/ @@ -1382,27 +1385,22 @@ int BLKFAM::WriteBuffer(PGLOBAL g) /***********************************************************************/ /* Table file close routine for DOS access method. */ /***********************************************************************/ -void BLKFAM::CloseTableFile(PGLOBAL g) +void BLKFAM::CloseTableFile(PGLOBAL g, bool abort) { int rc, wrc = RC_OK; if (UseTemp && T_Stream) { - if (Tdbp->GetMode() == MODE_UPDATE) { + if (Tdbp->GetMode() == MODE_UPDATE && !abort) { // Copy eventually remaining lines bool b; fseek(Stream, 0, SEEK_END); Fpos = ftell(Stream); - rc = MoveIntermediateLines(g, &b); - } else - rc = RC_OK; - - if (rc == RC_OK) - // Delete the old file and rename the new temp file. - rc = RenameTempFile(g); // Also close all files - else - rc = PlugCloseFile(g, To_Fb); + abort = MoveIntermediateLines(g, &b) != RC_OK; + } // endif abort + // Delete the old file and rename the new temp file. + rc = RenameTempFile(g, abort); // Also close all files } else { // Closing is True if last Write was in error if (Tdbp->GetMode() == MODE_INSERT && CurNum && !Closing) { diff --git a/storage/connect/filamtxt.h b/storage/connect/filamtxt.h index 94d518044cc..abe8f2f2324 100644 --- a/storage/connect/filamtxt.h +++ b/storage/connect/filamtxt.h @@ -66,7 +66,7 @@ class DllExport TXTFAM : public BLOCK { virtual int ReadBuffer(PGLOBAL g) = 0; virtual int WriteBuffer(PGLOBAL g) = 0; virtual int DeleteRecords(PGLOBAL g, int irc) = 0; - virtual void CloseTableFile(PGLOBAL g) = 0; + virtual void CloseTableFile(PGLOBAL g, bool abort) = 0; virtual void Rewind(void) = 0; protected: @@ -135,13 +135,13 @@ class DllExport DOSFAM : public TXTFAM { virtual int ReadBuffer(PGLOBAL g); virtual int WriteBuffer(PGLOBAL g); virtual int DeleteRecords(PGLOBAL g, int irc); - virtual void CloseTableFile(PGLOBAL g); + virtual void CloseTableFile(PGLOBAL g, bool abort); virtual void Rewind(void); protected: virtual bool OpenTempFile(PGLOBAL g); virtual bool MoveIntermediateLines(PGLOBAL g, bool *b); - virtual int RenameTempFile(PGLOBAL g); + virtual int RenameTempFile(PGLOBAL g, bool abort); // Members FILE *Stream; // Points to Dos file structure @@ -182,7 +182,7 @@ class DllExport BLKFAM : public DOSFAM { virtual int SkipRecord(PGLOBAL g, bool header); virtual int ReadBuffer(PGLOBAL g); virtual int WriteBuffer(PGLOBAL g); - virtual void CloseTableFile(PGLOBAL g); + virtual void CloseTableFile(PGLOBAL g, bool abort); virtual void Rewind(void); protected: diff --git a/storage/connect/filamvct.cpp b/storage/connect/filamvct.cpp index b07ae8a2213..076222e9e7f 100755 --- a/storage/connect/filamvct.cpp +++ b/storage/connect/filamvct.cpp @@ -136,6 +136,39 @@ VCTFAM::VCTFAM(PVCTFAM txfp) : FIXFAM(txfp) Ncol = txfp->Ncol; } // end of VCTFAM copy constructor +/***********************************************************************/ +/* VCT GetFileLength: returns file size in number of bytes. */ +/* This function is here to be accessible by VECFAM and VMPFAM. */ +/***********************************************************************/ +int VCTFAM::GetFileLength(PGLOBAL g) + { + if (Split) { + // Get the total file length + char filename[_MAX_PATH]; + char *savfile = To_File; + int i, len = 0; + + // Initialize the array of file structures + if (!Colfn) { + // Prepare the column file name pattern and set Ncol + Colfn = (char*)PlugSubAlloc(g, NULL, _MAX_PATH); + Ncol = ((PVCTDEF)Tdbp->GetDef())->MakeFnPattern(Colfn); + } // endif Colfn + + To_File = filename; + + for (i = 0; i < Ncol; i++) { + sprintf(filename, Colfn, i+1); + len += TXTFAM::GetFileLength(g); + } // endfor i + + To_File = savfile; + return len; + } else + return TXTFAM::GetFileLength(g); + + } // end of GetFileLength + /***********************************************************************/ /* Reset read/write position values. */ /***********************************************************************/ @@ -295,7 +328,7 @@ int VCTFAM::Cardinality(PGLOBAL g) clen = cdp->GetClen(); sprintf(filename, Colfn, 1); To_File = filename; - len = GetFileLength(g); + len = TXTFAM::GetFileLength(g); To_File = savfn; if (len >= 0) { @@ -1042,7 +1075,7 @@ bool VCTFAM::CleanUnusedSpace(PGLOBAL g) /***********************************************************************/ /* Data Base close routine for VCT access method. */ /***********************************************************************/ -void VCTFAM::CloseTableFile(PGLOBAL g) +void VCTFAM::CloseTableFile(PGLOBAL g, bool abort) { int rc = 0, wrc = RC_OK; MODE mode = Tdbp->GetMode(); @@ -1078,7 +1111,7 @@ void VCTFAM::CloseTableFile(PGLOBAL g) colp->WriteBlock(g); if (UseTemp && T_Stream) { - rc = RenameTempFile(g); + rc = RenameTempFile(g, abort); if (Header) { // Header must be set because it was not set in temp file @@ -1092,7 +1125,7 @@ void VCTFAM::CloseTableFile(PGLOBAL g) if (MaxBlk) rc = CleanUnusedSpace(g); - if ((rc = RenameTempFile(g)) != RC_FX) { + if ((rc = RenameTempFile(g, abort)) != RC_FX) { Stream = T_Stream = NULL; // For SetBlockInfo rc = ResetTableSize(g, Block, Last); } // endif rc @@ -1715,7 +1748,7 @@ int VCMFAM::DeleteRecords(PGLOBAL g, int irc) /***********************************************************************/ /* Data Base close routine for VMP access method. */ /***********************************************************************/ -void VCMFAM::CloseTableFile(PGLOBAL g) +void VCMFAM::CloseTableFile(PGLOBAL g, bool abort) { int wrc = RC_OK; MODE mode = Tdbp->GetMode(); @@ -2252,7 +2285,7 @@ int VECFAM::DeleteRecords(PGLOBAL g, int irc) } else // UseTemp // Ok, now delete old files and rename new temp files - if (RenameTempFile(g) == RC_FX) + if (RenameTempFile(g, false) == RC_FX) return RC_FX; // Reset these values for TDBVCT::MakeBlockValues @@ -2382,7 +2415,7 @@ bool VECFAM::MoveIntermediateLines(PGLOBAL g, bool *bn) /***********************************************************************/ /* Delete the old files and rename the new temporary files. */ /***********************************************************************/ -int VECFAM::RenameTempFile(PGLOBAL g) +int VECFAM::RenameTempFile(PGLOBAL g, bool abort) { char *tempname, filetemp[_MAX_PATH], filename[_MAX_PATH]; int rc = RC_OK; @@ -2398,25 +2431,30 @@ int VECFAM::RenameTempFile(PGLOBAL g) continue; tempname = (char*)T_Fbs[i]->Fname; - sprintf(filename, Colfn, i+1); - PlugSetPath(filename, filename, Tdbp->GetPath()); - strcat(PlugRemoveType(filetemp, filename), ".ttt"); - remove(filetemp); // May still be there from previous error - - if (rename(filename, filetemp)) { // Save file for security - sprintf(g->Message, MSG(RENAME_ERROR), - filename, filetemp, strerror(errno)); - rc = RC_FX; - } else if (rename(tempname, filename)) { - sprintf(g->Message, MSG(RENAME_ERROR), - tempname, filename, strerror(errno)); - rc = rename(filetemp, filename); // Restore saved file - rc = RC_FX; - } else if (remove(filetemp)) { - sprintf(g->Message, MSG(REMOVE_ERROR), - filetemp, strerror(errno)); - rc = RC_INFO; // Acceptable - } // endif's + + if (!abort) { + sprintf(filename, Colfn, i+1); + PlugSetPath(filename, filename, Tdbp->GetPath()); + strcat(PlugRemoveType(filetemp, filename), ".ttt"); + remove(filetemp); // May still be there from previous error + + if (rename(filename, filetemp)) { // Save file for security + sprintf(g->Message, MSG(RENAME_ERROR), + filename, filetemp, strerror(errno)); + rc = RC_FX; + } else if (rename(tempname, filename)) { + sprintf(g->Message, MSG(RENAME_ERROR), + tempname, filename, strerror(errno)); + rc = rename(filetemp, filename); // Restore saved file + rc = RC_FX; + } else if (remove(filetemp)) { + sprintf(g->Message, MSG(REMOVE_ERROR), + filetemp, strerror(errno)); + rc = RC_INFO; // Acceptable + } // endif's + + } else + remove(tempname); } // endfor i @@ -2426,7 +2464,7 @@ int VECFAM::RenameTempFile(PGLOBAL g) /***********************************************************************/ /* Data Base close routine for VEC access method. */ /***********************************************************************/ -void VECFAM::CloseTableFile(PGLOBAL g) +void VECFAM::CloseTableFile(PGLOBAL g, bool abort) { int rc = 0, wrc = RC_OK; MODE mode = Tdbp->GetMode(); @@ -2453,10 +2491,10 @@ void VECFAM::CloseTableFile(PGLOBAL g) longjmp(g->jumper[g->jump_level], 44); } else if (mode == MODE_UPDATE) { - if (UseTemp && !InitUpdate) { + if (UseTemp && !InitUpdate && !abort) { // Write any intermediate lines to temp file Fpos = OldBlk * Nrec; - wrc = MoveIntermediateLines(g); + abort = MoveIntermediateLines(g) != RC_OK; // Spos = Fpos + Nrec; } // endif UseTemp @@ -2466,20 +2504,17 @@ void VECFAM::CloseTableFile(PGLOBAL g) colp; colp = (PVCTCOL)colp->Next) colp->WriteBlock(g); - if (wrc == RC_OK && UseTemp && !InitUpdate) { + if (wrc == RC_OK && UseTemp && !InitUpdate && !abort) { // Write any intermediate lines to temp file Fpos = (Block - 1) * Nrec + Last; - wrc = MoveIntermediateLines(g); + abort = MoveIntermediateLines(g) != RC_OK; } // endif UseTemp } // endif's mode if (UseTemp && !InitUpdate) { // If they are errors, leave files unchanged - if (wrc == RC_OK) - rc = RenameTempFile(g); - else - longjmp(g->jumper[g->jump_level], 44); + rc = RenameTempFile(g, abort); } else if (Streams) for (int i = 0; i < Ncol; i++) @@ -2950,7 +2985,7 @@ int VMPFAM::DeleteRecords(PGLOBAL g, int irc) /***********************************************************************/ /* Data Base close routine for VMP access method. */ /***********************************************************************/ -void VMPFAM::CloseTableFile(PGLOBAL g) +void VMPFAM::CloseTableFile(PGLOBAL g, bool abort) { if (Tdbp->GetMode() == MODE_DELETE) { // Set Block and Nrec values for TDBVCT::MakeBlockValues @@ -4072,7 +4107,7 @@ bool BGVFAM::CleanUnusedSpace(PGLOBAL g) /***********************************************************************/ /* Data Base close routine for huge VEC access method. */ /***********************************************************************/ -void BGVFAM::CloseTableFile(PGLOBAL g) +void BGVFAM::CloseTableFile(PGLOBAL g, bool abort) { int rc = 0, wrc = RC_OK; MODE mode = Tdbp->GetMode(); @@ -4108,7 +4143,7 @@ void BGVFAM::CloseTableFile(PGLOBAL g) colp->WriteBlock(g); if (UseTemp && Tfile) { - rc = RenameTempFile(g); + rc = RenameTempFile(g, abort); Hfile = Tfile = INVALID_HANDLE_VALUE; if (Header) @@ -4121,7 +4156,7 @@ void BGVFAM::CloseTableFile(PGLOBAL g) if (MaxBlk) rc = CleanUnusedSpace(g); - if ((rc = RenameTempFile(g)) != RC_FX) { + if ((rc = RenameTempFile(g, abort)) != RC_FX) { Hfile = Tfile = INVALID_HANDLE_VALUE; // For SetBlockInfo rc = ResetTableSize(g, Block, Last); } // endif rc diff --git a/storage/connect/filamvct.h b/storage/connect/filamvct.h index f528f00372b..2e599ccc749 100644 --- a/storage/connect/filamvct.h +++ b/storage/connect/filamvct.h @@ -37,6 +37,7 @@ class DllExport VCTFAM : public FIXFAM { virtual AMT GetAmType(void) {return TYPE_AM_VCT;} virtual PTXF Duplicate(PGLOBAL g) {return (PTXF)new(g) VCTFAM(this);} + virtual int GetFileLength(PGLOBAL g); // Methods virtual void Reset(void); @@ -51,8 +52,8 @@ class DllExport VCTFAM : public FIXFAM { virtual bool OpenTableFile(PGLOBAL g); virtual int ReadBuffer(PGLOBAL g); virtual int WriteBuffer(PGLOBAL g); - virtual int DeleteRecords(PGLOBAL g, int irc); - virtual void CloseTableFile(PGLOBAL g); + virtual int DeleteRecords(PGLOBAL g, int irc); + virtual void CloseTableFile(PGLOBAL g, bool abort); virtual void Rewind(void); // Specific functions @@ -60,19 +61,19 @@ class DllExport VCTFAM : public FIXFAM { virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp); protected: - virtual bool MakeEmptyFile(PGLOBAL g, char *fn); + virtual bool MakeEmptyFile(PGLOBAL g, char *fn); virtual bool OpenTempFile(PGLOBAL g); virtual bool MoveLines(PGLOBAL g) {return false;} virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL); virtual bool CleanUnusedSpace(PGLOBAL g); - virtual int GetBlockInfo(PGLOBAL g); - virtual bool SetBlockInfo(PGLOBAL g); + virtual int GetBlockInfo(PGLOBAL g); + virtual bool SetBlockInfo(PGLOBAL g); bool ResetTableSize(PGLOBAL g, int block, int last); // Members char *NewBlock; // To block written on Insert - char *Colfn; // Pattern for column file names (VER) - char *Tempat; // Pattern for temp file names (VER) + char *Colfn; // Pattern for column file names (VEC) + char *Tempat; // Pattern for temp file names (VEC) int *Clens; // Pointer to col size array int *Deplac; // Pointer to col start position array bool *Isnum; // Pointer to buffer type isnum result @@ -108,8 +109,8 @@ class DllExport VCMFAM : public VCTFAM { // Database routines virtual bool OpenTableFile(PGLOBAL g); virtual int WriteBuffer(PGLOBAL g); - virtual int DeleteRecords(PGLOBAL g, int irc); - virtual void CloseTableFile(PGLOBAL g); + virtual int DeleteRecords(PGLOBAL g, int irc); + virtual void CloseTableFile(PGLOBAL g, bool abort); // Specific functions virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp); @@ -145,18 +146,18 @@ class DllExport VECFAM : public VCTFAM { // Database routines virtual bool OpenTableFile(PGLOBAL g); virtual int WriteBuffer(PGLOBAL g); - virtual int DeleteRecords(PGLOBAL g, int irc); - virtual void CloseTableFile(PGLOBAL g); + virtual int DeleteRecords(PGLOBAL g, int irc); + virtual void CloseTableFile(PGLOBAL g, bool abort); // Specific functions virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp); virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp); protected: - virtual bool OpenTempFile(PGLOBAL g); + virtual bool OpenTempFile(PGLOBAL g); virtual bool MoveLines(PGLOBAL g); virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL); - virtual int RenameTempFile(PGLOBAL g); + virtual int RenameTempFile(PGLOBAL g, bool abort); bool OpenColumnFile(PGLOBAL g, char *opmode, int i); // Members @@ -190,7 +191,7 @@ class DllExport VMPFAM : public VCMFAM { // Database routines virtual bool OpenTableFile(PGLOBAL g); virtual int DeleteRecords(PGLOBAL g, int irc); - virtual void CloseTableFile(PGLOBAL g); + virtual void CloseTableFile(PGLOBAL g, bool abort); protected: bool MapColumnFile(PGLOBAL g, MODE mode, int i); @@ -221,7 +222,7 @@ class BGVFAM : public VCTFAM { virtual bool OpenTableFile(PGLOBAL g); virtual int WriteBuffer(PGLOBAL g); virtual int DeleteRecords(PGLOBAL g, int irc); - virtual void CloseTableFile(PGLOBAL g); + virtual void CloseTableFile(PGLOBAL g, bool abort); virtual void Rewind(void); // Specific functions diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamzip.cpp index 22ddffe26a1..8e4bce2bf3e 100644 --- a/storage/connect/filamzip.cpp +++ b/storage/connect/filamzip.cpp @@ -386,7 +386,7 @@ int ZIPFAM::DeleteRecords(PGLOBAL g, int irc) /***********************************************************************/ /* Data Base close routine for DOS access method. */ /***********************************************************************/ -void ZIPFAM::CloseTableFile(PGLOBAL g) +void ZIPFAM::CloseTableFile(PGLOBAL g, bool abort) { int rc = gzclose(Zfile); @@ -456,9 +456,7 @@ int ZBKFAM::MaxBlkSize(PGLOBAL g, int s) /***********************************************************************/ int ZBKFAM::Cardinality(PGLOBAL g) { - // Should not be called in this version - return (g) ? -1 : 0; -//return (g) ? (int)((Block - 1) * Nrec + Last) : 1; + return (g) ? (int)((Block - 1) * Nrec + Last) : 1; } // end of Cardinality /***********************************************************************/ @@ -671,7 +669,7 @@ int ZBKFAM::DeleteRecords(PGLOBAL g, int irc) /***********************************************************************/ /* Data Base close routine for ZBK access method. */ /***********************************************************************/ -void ZBKFAM::CloseTableFile(PGLOBAL g) +void ZBKFAM::CloseTableFile(PGLOBAL g, bool abort) { int rc = RC_OK; @@ -1328,7 +1326,7 @@ bool ZLBFAM::WriteCompressedBuffer(PGLOBAL g) /***********************************************************************/ /* Table file close routine for DOS access method. */ /***********************************************************************/ -void ZLBFAM::CloseTableFile(PGLOBAL g) +void ZLBFAM::CloseTableFile(PGLOBAL g, bool abort) { int rc = RC_OK; diff --git a/storage/connect/filamzip.h b/storage/connect/filamzip.h index 8111bc1ad97..d0b03f8cd9a 100644 --- a/storage/connect/filamzip.h +++ b/storage/connect/filamzip.h @@ -48,7 +48,7 @@ class DllExport ZIPFAM : public TXTFAM { virtual int ReadBuffer(PGLOBAL g); virtual int WriteBuffer(PGLOBAL g); virtual int DeleteRecords(PGLOBAL g, int irc); - virtual void CloseTableFile(PGLOBAL g); + virtual void CloseTableFile(PGLOBAL g, bool abort); virtual void Rewind(void); protected: @@ -86,7 +86,7 @@ class DllExport ZBKFAM : public ZIPFAM { virtual int ReadBuffer(PGLOBAL g); virtual int WriteBuffer(PGLOBAL g); virtual int DeleteRecords(PGLOBAL g, int irc); - virtual void CloseTableFile(PGLOBAL g); + virtual void CloseTableFile(PGLOBAL g, bool abort); virtual void Rewind(void); protected: @@ -152,7 +152,7 @@ class DllExport ZLBFAM : public BLKFAM { virtual bool AllocateBuffer(PGLOBAL g); virtual int ReadBuffer(PGLOBAL g); virtual int WriteBuffer(PGLOBAL g); - virtual void CloseTableFile(PGLOBAL g); + virtual void CloseTableFile(PGLOBAL g, bool abort); virtual void Rewind(void); protected: diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index e7aeddf38fb..f0261dda7ff 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -108,7 +108,6 @@ #define MYSQL_SERVER 1 #define DONT_DEFINE_VOID -//#include "sql_partition.h" #include "sql_class.h" #include "create_options.h" #include "mysql_com.h" @@ -316,11 +315,12 @@ ha_create_table_option connect_field_option_list[]= { HA_FOPTION_NUMBER("FLAG", offset, (ulonglong) -1, 0, INT_MAX32, 1), HA_FOPTION_NUMBER("MAX_DIST", freq, 0, 0, INT_MAX32, 1), // BLK_INDX - HA_FOPTION_NUMBER("DISTRIB", opt, 0, 0, 2, 1), // used for BLK_INDX +//HA_FOPTION_NUMBER("DISTRIB", opt, 0, 0, 2, 1), // used for BLK_INDX HA_FOPTION_NUMBER("FIELD_LENGTH", fldlen, 0, 0, INT_MAX32, 1), HA_FOPTION_STRING("DATE_FORMAT", dateformat), HA_FOPTION_STRING("FIELD_FORMAT", fieldformat), HA_FOPTION_STRING("SPECIAL", special), + HA_FOPTION_ENUM("DISTRIB", opt, "scattered,clustered,sorted", 0), HA_FOPTION_END }; @@ -332,7 +332,6 @@ ha_create_table_option connect_field_option_list[]= */ ha_create_table_option connect_index_option_list[]= { - HA_IOPTION_BOOL("DYNAMIC", dynamic, 0), HA_IOPTION_BOOL("DYNAM", dynamic, 0), HA_IOPTION_BOOL("MAPPED", mapped, 0), HA_IOPTION_END @@ -553,8 +552,12 @@ ha_connect::ha_connect(handlerton *hton, TABLE_SHARE *table_arg) stop= false; alter= false; mrr= false; + nox= false; + abort= false; indexing= -1; + only= -1; locked= 0; + part_id= NULL; data_file_name= NULL; index_file_name= NULL; enable_activate_all_index= 0; @@ -819,7 +822,17 @@ char *ha_connect::GetStringOption(char *opname, char *sdef) char *opval= NULL; PTOS options= GetTableOptionStruct(); - if (!options) + if (!stricmp(opname, "Connect")) { + LEX_STRING cnc= (tshp) ? tshp->connect_string : table->s->connect_string; + + if (cnc.length) + opval= cnc.str; + + } else if (!stricmp(opname, "Query_String")) + opval= thd_query_string(table->in_use)->str; + else if (!stricmp(opname, "Partname")) + opval= partname; + else if (!options) ; else if (!stricmp(opname, "Type")) opval= (char*)options->type; @@ -836,8 +849,6 @@ char *ha_connect::GetStringOption(char *opname, char *sdef) opval= (char*)options->dbname; else if (!stricmp(opname, "Separator")) opval= (char*)options->separator; - else if (!stricmp(opname, "Connect")) - opval= (tshp) ? tshp->connect_string.str : table->s->connect_string.str; else if (!stricmp(opname, "Qchar")) opval= (char*)options->qchar; else if (!stricmp(opname, "Module")) @@ -852,8 +863,6 @@ char *ha_connect::GetStringOption(char *opname, char *sdef) opval= (char*)options->colist; else if (!stricmp(opname, "Data_charset")) opval= (char*)options->data_charset; - else if (!stricmp(opname, "Query_String")) - opval= thd_query_string(table->in_use)->str; if (!opval && options && options->oplist) opval= GetListOption(xp->g, opname, options->oplist); @@ -1196,6 +1205,17 @@ bool ha_connect::GetIndexOption(KEY *kp, char *opname) return opval; } // end of GetIndexOption +/****************************************************************************/ +/* Returns the index description structure used to make the index. */ +/****************************************************************************/ +bool ha_connect::IsUnique(uint n) +{ + TABLE_SHARE *s= (table) ? table->s : NULL; + KEY kp= s->key_info[n]; + + return (kp.flags & 1) != 0; +} // end of IsUnique + /****************************************************************************/ /* Returns the index description structure used to make the index. */ /****************************************************************************/ @@ -1280,6 +1300,7 @@ bool ha_connect::IsPartitioned(void) return true; else return false; + } // end of IsPartitioned const char *ha_connect::GetDBName(const char* name) @@ -1365,7 +1386,7 @@ PTDB ha_connect::GetTDB(PGLOBAL g) tp->SetMode(xmod); } else if ((tp= CntGetTDB(g, table_name, xmod, this))) { valid_query_id= xp->last_query_id; - tp->SetMode(xmod); +// tp->SetMode(xmod); } else htrc("GetTDB: %s\n", g->Message); @@ -1444,6 +1465,17 @@ int ha_connect::OpenTable(PGLOBAL g, bool del) for (field= table->field; fp= *field; field++) if (bitmap_is_set(ump, fp->field_index)) { strcpy(p, (char*)fp->field_name); + + if (part_id && bitmap_is_set(part_id, fp->field_index)) { + // Trying to update a column used for partitioning + // This cannot be currently done because it may require + // a row to be moved in another partition. + sprintf(g->Message, + "Cannot update column %s because it is used for partitioning", + p); + return HA_ERR_INTERNAL_ERROR; + } // endif part_id + p+= (strlen(p) + 1); } // endif used field @@ -1475,6 +1507,50 @@ int ha_connect::OpenTable(PGLOBAL g, bool del) } // end of OpenTable +/****************************************************************************/ +/* CheckColumnList: check that all bitmap columns do exist. */ +/****************************************************************************/ +bool ha_connect::CheckColumnList(PGLOBAL g) +{ + // Check the list of used fields (columns) + int rc; + bool brc= false; + PCOL colp; + Field* *field; + Field* fp; + MY_BITMAP *map= table->read_set; + + // Save stack and allocation environment and prepare error return + if (g->jump_level == MAX_JUMP) { + strcpy(g->Message, MSG(TOO_MANY_JUMPS)); + return true; + } // endif jump_level + + if ((rc= setjmp(g->jumper[++g->jump_level])) == 0) { + for (field= table->field; fp= *field; field++) + if (bitmap_is_set(map, fp->field_index)) { + if (!(colp= tdbp->ColDB(g, (PSZ)fp->field_name, 0))) { + sprintf(g->Message, "Column %s not found in %s", + fp->field_name, tdbp->GetName()); + brc= true; + goto fin; + } // endif colp + + if ((brc= colp->InitValue(g))) + goto fin; + + colp->AddColUse(U_P); // For PLG tables + } // endif + + } else + brc= true; + + fin: + g->jump_level--; + return brc; +} // end of CheckColumnList + + /****************************************************************************/ /* IsOpened: returns true if the table is already opened. */ /****************************************************************************/ @@ -1490,12 +1566,15 @@ bool ha_connect::IsOpened(void) /****************************************************************************/ int ha_connect::CloseTable(PGLOBAL g) { - int rc= CntCloseTable(g, tdbp); + int rc= CntCloseTable(g, tdbp, nox, abort); tdbp= NULL; sdvalin=NULL; sdvalout=NULL; valid_info= false; indexing= -1; + nox= false; + abort= false; + only= -1; return rc; } // end of CloseTable @@ -1623,6 +1702,11 @@ int ha_connect::MakeRecord(char *buf) } // endfor field + // This is sometimes required for partition tables because the buf + // can be different from the table->record[0] buffer + if (buf != (char*)table->record[0]) + memcpy(buf, table->record[0], table->s->stored_rec_length); + // This is copied from ha_tina and is necessary to avoid asserts dbug_tmp_restore_column_map(table->write_set, org_bitmap); DBUG_RETURN(rc); @@ -1773,7 +1857,11 @@ bool ha_connect::MakeKeyWhere(PGLOBAL g, char *qry, OPVAL op, char *q, KEY_PART_INFO *kpart; if (active_index == MAX_KEY) - return 0; + return false; + else if (!key) { + strcpy(g->Message, "MakeKeyWhere: No key"); + return true; + } // endif key strcat(qry, " WHERE ("); kfp= &table->key_info[active_index]; @@ -2448,6 +2536,21 @@ bool ha_connect::get_error_message(int error, String* buf) DBUG_RETURN(false); } // end of get_error_message +/** + Convert a filename partition name to system +*/ +static char *decode(PGLOBAL g, const char *pn) + { + char *buf= (char*)PlugSubAlloc(g, NULL, strlen(pn) + 1); + uint dummy_errors; + uint32 len= copy_and_convert(buf, strlen(pn) + 1, + system_charset_info, + pn, strlen(pn), + &my_charset_filename, + &dummy_errors); + buf[len]= '\0'; + return buf; + } // end of decode /** @brief @@ -2499,11 +2602,14 @@ int ha_connect::open(const char *name, int mode, uint test_if_locked) #if defined(WITH_PARTITION_STORAGE_ENGINE) if (table->part_info) { - if (GetStringOption("Filename") || GetStringOption("Tabname")) - strcpy(partname, strrchr(name, '#') + 1); - else // Inward table + if (GetStringOption("Filename") || GetStringOption("Tabname") + || GetStringOption("Connect")) { + strcpy(partname, decode(g, strrchr(name, '#') + 1)); +// strcpy(partname, table->part_info->curr_part_elem->partition_name); + part_id= &table->part_info->full_part_field_set; + } else // Inward table strcpy(partname, strrchr(name, slash) + 1); - + part_id= &table->part_info->full_part_field_set; // Temporary } // endif part_info #endif // WITH_PARTITION_STORAGE_ENGINE } else @@ -2610,8 +2716,13 @@ int ha_connect::write_row(uchar *buf) DBUG_ENTER("ha_connect::write_row"); // This is not tested yet - if (xmod == MODE_ALTER) + if (xmod == MODE_ALTER) { + if (IsPartitioned() && GetStringOption("Filename", NULL)) + // Why does this happen now that check_if_supported_inplace_alter is called? + DBUG_RETURN(0); // Alter table on an outward partition table + xmod= MODE_INSERT; + } // endif xmod // Open the table if it was not opened yet (locked) if (!IsOpened() || xmod != tdbp->GetMode()) { @@ -2684,7 +2795,7 @@ int ha_connect::update_row(const uchar *old_data, uchar *new_data) // Check values for possible change in indexed column if ((rc= CheckRecord(g, old_data, new_data))) - return rc; + DBUG_RETURN(rc); if (CntUpdateRow(g, tdbp)) { DBUG_PRINT("update_row", ("%s", g->Message)); @@ -2742,12 +2853,19 @@ int ha_connect::index_init(uint idx, bool sorted) htrc("index_init: this=%p idx=%u sorted=%d\n", this, idx, sorted); if (GetIndexType(GetRealType()) == 2) { - // This is a remote index - xmod= MODE_READX; + if (xmod == MODE_READ) + // This is a remote index + xmod= MODE_READX; if (!(rc= rnd_init(0))) { - active_index= idx; - indexing= 2; // TO DO: mul? + if (xmod == MODE_READX) { + active_index= idx; + indexing= IsUnique(idx) ? 1 : 2; + } else { + active_index= MAX_KEY; + indexing= 0; + } // endif xmod + } //endif rc DBUG_RETURN(rc); @@ -2756,11 +2874,17 @@ int ha_connect::index_init(uint idx, bool sorted) if ((rc= rnd_init(0))) DBUG_RETURN(rc); - if (locked == 2) { + if ((xmod == MODE_UPDATE && ((TDBASE*)tdbp)->IsUsingTemp(g)) || + xmod == MODE_DELETE || locked == 2) { // Indexes are not updated in lock write mode - active_index= MAX_KEY; - indexing= 0; - DBUG_RETURN(0); + // and cannot be used for DELETE or UPDATE using temp file. + if (locked == 2 || xmod == MODE_DELETE || !IsUnique(idx)) { + active_index= MAX_KEY; + indexing= 0; + DBUG_RETURN(0); + } else + only= 1; // Indexing acceptable for only one value + } // endif locked indexing= CntIndexInit(g, tdbp, (signed)idx); @@ -2874,10 +2998,16 @@ int ha_connect::index_read(uchar * buf, const uchar * key, uint key_len, if (xtrace > 1) htrc("%p index_read: op=%d\n", this, op); - if (indexing > 0) + if ((indexing > 0 && (only < 0 || (only == 1 && op == OP_EQ))) + || GetIndexType(GetRealType()) == 2) { rc= ReadIndexed(buf, op, key, key_len); - else - rc= HA_ERR_INTERNAL_ERROR; + only= (only == 1) ? 0 : -1; + } else { + nox= true; // To block making indexes + abort= true; // Don't rename temp file + strcpy(xp->g->Message, "Cannot use indexing for this command"); + rc= HA_ERR_INTERNAL_ERROR; // HA_ERR_KEY_NOT_FOUND ? + } // endelse DBUG_RETURN(rc); } // end of index_read @@ -3032,6 +3162,10 @@ int ha_connect::rnd_init(bool scan) // Do not close the table if it was opened yet (locked?) if (IsOpened()) { + if (IsPartitioned() && xmod != MODE_INSERT) + if (CheckColumnList(g)) // map can have been changed + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + if (tdbp->OpenDB(g)) // Rewind table DBUG_RETURN(HA_ERR_INTERNAL_ERROR); else @@ -3260,27 +3394,30 @@ int ha_connect::info(uint flag) if (xtrace) htrc("%p In info: flag=%u valid_info=%d\n", this, flag, valid_info); - if (!valid_info) { - // tdbp must be available to get updated info - if (xp->CheckQuery(valid_query_id) || !tdbp) { - PDBUSER dup= PlgGetUser(g); - PCATLG cat= (dup) ? dup->Catalog : NULL; - - if (xmod == MODE_ANY || xmod == MODE_ALTER) { - // Pure info, not a query - pure= true; - xp->CheckCleanup(); - } // endif xmod - - // This is necessary for getting file length - if (cat && table) - cat->SetDataPath(g, table->s->db.str); - else - DBUG_RETURN(HA_ERR_INTERNAL_ERROR); // Should never happen + // tdbp must be available to get updated info + if (xp->CheckQuery(valid_query_id) || !tdbp) { + PDBUSER dup= PlgGetUser(g); + PCATLG cat= (dup) ? dup->Catalog : NULL; - tdbp= GetTDB(g); - } // endif tdbp + if (xmod == MODE_ANY || xmod == MODE_ALTER) { + // Pure info, not a query + pure= true; + xp->CheckCleanup(); + } // endif xmod + // This is necessary for getting file length + if (cat && table) + cat->SetDataPath(g, table->s->db.str); + else + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); // Should never happen + + if (!(tdbp= GetTDB(g))) + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); // Should never happen + + valid_info = false; + } // endif tdbp + + if (!valid_info) { valid_info= CntInfo(g, tdbp, &xinfo); if (((signed)xinfo.records) < 0) @@ -3532,11 +3669,6 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, case SQLCOM_RENAME_TABLE: newmode= MODE_ANY; break; - case SQLCOM_DROP_INDEX: - case SQLCOM_CREATE_INDEX: - newmode= MODE_ANY; -// stop= true; - break; case SQLCOM_CREATE_VIEW: case SQLCOM_DROP_VIEW: newmode= MODE_ANY; @@ -3544,6 +3676,13 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, case SQLCOM_ALTER_TABLE: newmode= MODE_ALTER; break; + case SQLCOM_DROP_INDEX: + case SQLCOM_CREATE_INDEX: +// if (!IsPartitioned()) { + newmode= MODE_ANY; + break; +// } // endif partitioned + default: htrc("Unsupported sql_command=%d\n", thd_sql_command(thd)); strcpy(g->Message, "CONNECT Unsupported command"); @@ -3573,10 +3712,6 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, case SQLCOM_LOCK_TABLES: locked= 1; break; - case SQLCOM_DROP_INDEX: - case SQLCOM_CREATE_INDEX: - *chk= true; -// stop= true; case SQLCOM_DROP_TABLE: case SQLCOM_RENAME_TABLE: newmode= MODE_ANY; @@ -3589,6 +3724,14 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, *chk= true; newmode= MODE_ALTER; break; + case SQLCOM_DROP_INDEX: + case SQLCOM_CREATE_INDEX: +// if (!IsPartitioned()) { + *chk= true; + newmode= MODE_ANY; + break; +// } // endif partitioned + default: htrc("Unsupported sql_command=%d\n", thd_sql_command(thd)); strcpy(g->Message, "CONNECT Unsupported command"); @@ -3809,6 +3952,7 @@ int ha_connect::external_lock(THD *thd, int lock_type) } // endif Close locked= 0; + xmod= MODE_ANY; // For info commands DBUG_RETURN(rc); } // endif MODE_ANY @@ -4128,7 +4272,7 @@ ha_rows ha_connect::records_in_range(uint inx, key_range *min_key, if (xtrace) htrc("records_in_range: inx=%d indexing=%d\n", inx, indexing); - if (indexing > 0) { + if (indexing > 0 && only < 0) { int nval; uint len[2]; const uchar *key[2]; @@ -4149,10 +4293,11 @@ ha_rows ha_connect::records_in_range(uint inx, key_range *min_key, else rows= (ha_rows)nval; - } else if (indexing < 0) - rows= HA_POS_ERROR; - else + } else if (indexing == 0) { rows= 100000000; // Don't use missing index + only= -1; + } else + rows= HA_POS_ERROR; DBUG_RETURN(rows); } // end of records_in_range @@ -4160,7 +4305,7 @@ ha_rows ha_connect::records_in_range(uint inx, key_range *min_key, /** Convert an ISO-8859-1 column name to UTF-8 */ -static char *encode(PGLOBAL g, char *cnm) +static char *encode(PGLOBAL g, const char *cnm) { char *buf= (char*)PlugSubAlloc(g, NULL, strlen(cnm) * 3); uint dummy_errors; @@ -4171,7 +4316,7 @@ static char *encode(PGLOBAL g, char *cnm) &dummy_errors); buf[len]= '\0'; return buf; - } // end of Encode + } // end of encode /** Store field definition for create. @@ -4547,7 +4692,7 @@ static void add_option(THD* thd, HA_CREATE_INFO *create_info, } // end of add_option // Used to check whether a MYSQL table is created on itself -static bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host, +bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host, const char *db, char *tab, const char *src, int port) { if (src) @@ -5129,7 +5274,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, HA_CREATE_INFO *create_info) { int rc= RC_OK; - bool dbf; + bool dbf, inward; Field* *field; Field *fp; TABTYPE type; @@ -5144,7 +5289,6 @@ int ha_connect::create(const char *name, TABLE *table_arg, DBUG_ENTER("ha_connect::create"); int sqlcom= thd_sql_command(table_arg->in_use); PTOS options= GetTableOptionStruct(table_arg->s); - bool inward= !options->filename; table= table_arg; // Used by called functions @@ -5175,6 +5319,8 @@ int ha_connect::create(const char *name, TABLE *table_arg, if (check_privileges(thd, options, GetDBfromName(name))) DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + inward= IsFileType(type) && !options->filename; + if (options->data_charset) { const CHARSET_INFO *data_charset; @@ -5226,6 +5372,9 @@ int ha_connect::create(const char *name, TABLE *table_arg, } // endif tabname case TAB_MYSQL: +#if defined(WITH_PARTITION_STORAGE_ENGINE) + if (!part_info) +#endif // WITH_PARTITION_STORAGE_ENGINE {const char *src= options->srcdef; char *host, *db, *tab= (char*)options->tabname; int port; @@ -5419,8 +5568,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, } // endfor field - if ((sqlcom == SQLCOM_CREATE_TABLE || *GetTableName() == '#') - && IsFileType(type) && inward) { + if ((sqlcom == SQLCOM_CREATE_TABLE || *GetTableName() == '#') && inward) { // The file name is not specified, create a default file in // the database directory named table_name.table_type. // (temporarily not done for XML because a void file causes @@ -5504,19 +5652,32 @@ int ha_connect::create(const char *name, TABLE *table_arg, // We should be in CREATE TABLE, ALTER_TABLE or CREATE INDEX if (!(sqlcom == SQLCOM_CREATE_TABLE || sqlcom == SQLCOM_ALTER_TABLE || - (sqlcom == SQLCOM_CREATE_INDEX && part_info) || - (sqlcom == SQLCOM_DROP_INDEX && part_info))) + sqlcom == SQLCOM_CREATE_INDEX || sqlcom == SQLCOM_DROP_INDEX)) +// (sqlcom == SQLCOM_CREATE_INDEX && part_info) || +// (sqlcom == SQLCOM_DROP_INDEX && part_info))) push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, "Unexpected command in create, please contact CONNECT team"); - if (sqlcom == SQLCOM_ALTER_TABLE && g->Alchecked == 0 && +#if defined(WITH_PARTITION_STORAGE_ENGINE) + if (part_info && !inward) + strcpy(partname, decode(g, strrchr(name, '#') + 1)); +// strcpy(partname, part_info->curr_part_elem->partition_name); +#endif // WITH_PARTITION_STORAGE_ENGINE + + if (g->Alchecked == 0 && (!IsFileType(type) || FileExists(options->filename))) { - // This is an ALTER to CONNECT from another engine. - // It cannot be accepted because the table data would be lost - // except when the target file does not exist. - strcpy(g->Message, "Operation denied. Table data would be lost."); - my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); - DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + if (part_info) { + sprintf(g->Message, "Data repartition in %s is unchecked", partname); + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); + } else if (sqlcom == SQLCOM_ALTER_TABLE) { + // This is an ALTER to CONNECT from another engine. + // It cannot be accepted because the table data would be modified + // except when the target file does not exist. + strcpy(g->Message, "Operation denied. Table data would be modified."); + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } // endif part_info + } // endif outward // Get the index definitions @@ -5581,7 +5742,8 @@ bool ha_connect::FileExists(const char *fn) return false; if (table) { - char *s, filename[_MAX_PATH], path[128]; + char *s, tfn[_MAX_PATH], filename[_MAX_PATH], path[128]; + bool b= false; int n; struct stat info; @@ -5594,9 +5756,18 @@ bool ha_connect::FileExists(const char *fn) #else // !WIN32 s= "/"; #endif // !WIN32 + if (IsPartitioned()) { + sprintf(tfn, fn, GetPartName()); + + // This is to avoid an initialization error raised by the + // test on check_table_flags made in ha_partition::open + // that can fail if some partition files are empty. + b= true; + } else + strcpy(tfn, fn); strcat(strcat(strcat(strcpy(path, "."), s), table->s->db.str), s); - PlugSetPath(filename, fn, path); + PlugSetPath(filename, tfn, path); n= stat(filename, &info); if (n < 0) { @@ -5610,7 +5781,7 @@ bool ha_connect::FileExists(const char *fn) return false; } else - return (info.st_size) ? true : false; + return (info.st_size || b) ? true : false; } // endif table diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h index 33e52165289..e5b58a7a6b8 100644 --- a/storage/connect/ha_connect.h +++ b/storage/connect/ha_connect.h @@ -124,8 +124,8 @@ struct ha_field_option_struct { ulonglong offset; ulonglong freq; - ulonglong opt; ulonglong fldlen; + uint opt; const char *dateformat; const char *fieldformat; char *special; @@ -208,9 +208,11 @@ public: TABLE *GetTable(void) {return table;} bool IsSameIndex(PIXDEF xp1, PIXDEF xp2); bool IsPartitioned(void); + bool IsUnique(uint n); PTDB GetTDB(PGLOBAL g); int OpenTable(PGLOBAL g, bool del= false); + bool CheckColumnList(PGLOBAL g); bool IsOpened(void); int CloseTable(PGLOBAL g); int MakeRecord(char *buf); @@ -529,8 +531,12 @@ protected: bool stop; // Used when creating index bool alter; // True when converting to other engine bool mrr; // True when getting index positions + bool nox; // True when index should not be made + bool abort; // True after error in UPDATE/DELETE int indexing; // Type of indexing for CONNECT + int only; // If only one action is accepted int locked; // Table lock + MY_BITMAP *part_id; // Columns used for partition func THR_LOCK_DATA lock_data; public: diff --git a/storage/connect/mycat.cc b/storage/connect/mycat.cc index 10b12c0809b..ca09e877b1a 100644 --- a/storage/connect/mycat.cc +++ b/storage/connect/mycat.cc @@ -571,6 +571,7 @@ PTDB MYCAT::GetTable(PGLOBAL g, PTABLE tablep, MODE mode, LPCSTR type) tdbp->GetAmType()); tablep->SetTo_Tdb(tdbp); tdbp->SetTable(tablep); + tdbp->SetMode(mode); } // endif tdbp return (tdbp); diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp index 0964e0c0bbb..0c4b50f1d0b 100644 --- a/storage/connect/myconn.cpp +++ b/storage/connect/myconn.cpp @@ -686,19 +686,48 @@ int MYSQLC::ExecSQL(PGLOBAL g, const char *query, int *w) rc = RC_NF; } // endif field count -if (w) -//*w = mysql_warning_count(m_DB); - *w = m_DB->warning_count; + if (w) +// *w = mysql_warning_count(m_DB); + *w = m_DB->warning_count; return rc; } // end of ExecSQL +/***********************************************************************/ +/* Get table size by executing "select count(*) from table_name". */ +/***********************************************************************/ +int MYSQLC::GetTableSize(PGLOBAL g, PSZ query) + { + if (mysql_real_query(m_DB, query, strlen(query))) { +#if defined(_DEBUG) + char *msg = (char*)PlugSubAlloc(g, NULL, 512 + strlen(query)); + + sprintf(msg, "(%d) %s [%s]", mysql_errno(m_DB), + mysql_error(m_DB), query); + strncpy(g->Message, msg, sizeof(g->Message) - 1); + g->Message[sizeof(g->Message) - 1] = 0; +#endif // _DEBUG + return -2; + } // endif mysql_real_query + + if (!(m_Res = mysql_store_result(m_DB))) + return -3; + + // Get the resulting count value + m_Rows = (int)mysql_num_rows(m_Res); // Should be 1 + + if (m_Rows && (m_Row = mysql_fetch_row(m_Res))) + return atoi(*m_Row); + + return -4; + } // end of GetTableSize + /***********************************************************************/ /* Move to a specific row and column */ /***********************************************************************/ void MYSQLC::DataSeek(my_ulonglong row) { - MYSQL_ROWS *tmp=0; + MYSQL_ROWS *tmp = 0; //DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row)); if (m_Res->data) diff --git a/storage/connect/myconn.h b/storage/connect/myconn.h index 7e892eece34..65e6531aee4 100644 --- a/storage/connect/myconn.h +++ b/storage/connect/myconn.h @@ -64,6 +64,7 @@ class DllItem MYSQLC { // Methods int GetResultSize(PGLOBAL g, PSZ sql); + int GetTableSize(PGLOBAL g, PSZ query); int Open(PGLOBAL g, const char *host, const char *db, const char *user= "root", const char *pwd= "*", int pt= 0); diff --git a/storage/connect/mysql-test/connect/r/part_file.result b/storage/connect/mysql-test/connect/r/part_file.result new file mode 100644 index 00000000000..b342059bff0 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/part_file.result @@ -0,0 +1,355 @@ +# This will be used to see what data files are created +CREATE TABLE dr1 ( +FNAME VARCHAR(256) NOT NULL FLAG=2, +FTYPE CHAR(8) NOT NULL FLAG=3 +# ,FSIZE INT(6) NOT NULL FLAG=5 removed because Unix size != Windows size +) engine=CONNECT table_type=DIR file_name='t1#P#*.*'; +# +# Testing partitioning on inward table +# +CREATE TABLE t1 ( +id INT NOT NULL, +msg VARCHAR(32) +) ENGINE=CONNECT TABLE_TYPE=CSV +PARTITION BY RANGE(id) ( +PARTITION first VALUES LESS THAN(10), +PARTITION middle VALUES LESS THAN(50), +PARTITION last VALUES LESS THAN(MAXVALUE)); +INSERT INTO t1 VALUES(4, 'four'),(24, 'twenty four'); +INSERT INTO t1 VALUES(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'); +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +partition_name table_rows +first 2 +middle 3 +last 2 +SELECT * FROM t1; +id msg +4 four +7 seven +24 twenty four +10 ten +40 forty +60 sixty +81 eighty one +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id > 50; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 last ALL NULL NULL NULL NULL 13 Using where +SELECT * FROM t1 WHERE id > 50; +id msg +60 sixty +81 eighty one +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 CONNECT 10 Dynamic 7 10 76 0 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL partitioned `TABLE_TYPE`=CSV +UPDATE t1 set id = 41 WHERE msg = 'four'; +ERROR HY000: Got error 174 'Cannot update column id because it is used for partitioning' from CONNECT +UPDATE t1 set msg = 'quatre' WHERE id = 4; +SELECT * FROM dr1; +FNAME FTYPE +t1#P#first .csv +t1#P#last .csv +t1#P#middle .csv +# +# Altering partitioning on inward table +# +ALTER TABLE t1 +PARTITION by range(id) ( +PARTITION first VALUES LESS THAN(11), +PARTITION middle VALUES LESS THAN(50), +PARTITION last VALUES LESS THAN(MAXVALUE)); +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +partition_name table_rows +first 3 +middle 2 +last 2 +SELECT * FROM dr1; +FNAME FTYPE +t1#P#first .csv +t1#P#last .csv +t1#P#middle .csv +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id=10; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 first ALL NULL NULL NULL NULL 14 Using where +SELECT * FROM t1 WHERE id=10; +id msg +10 ten +DELETE FROM t1 WHERE id in (4,60); +SELECT * FROM t1; +id msg +7 seven +10 ten +24 twenty four +40 forty +81 eighty one +DROP TABLE t1; +SELECT * FROM dr1; +FNAME FTYPE +# +# Testing partitioning on a void outward table +# +ALTER TABLE dr1 file_name='part*.*'; +Warnings: +Warning 1105 This is an outward table, table data were not modified. +CREATE TABLE t1 ( +rwid INT(6) DEFAULT 0 SPECIAL=ROWID, +rnum INT(6) DEFAULT 0 SPECIAL=ROWNUM, +prtn VARCHAR(64) DEFAULT '' SPECIAL=PARTID, +tbn VARCHAR(64) DEFAULT '' SPECIAL=TABID, +fid VARCHAR(256) DEFAULT '' SPECIAL=FNAME, +id INT KEY NOT NULL, +msg VARCHAR(32) +) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='part%s.txt'; +ALTER TABLE t1 +PARTITION by range columns(id) ( +PARTITION `1` VALUES LESS THAN(10), +PARTITION `2` VALUES LESS THAN(50), +PARTITION `3` VALUES LESS THAN(MAXVALUE)); +Warnings: +Warning 1105 Open(rb) error 2 on DATADIR/test/part%s.txt: No such file or directory +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 PRIMARY 1 id A NULL NULL NULL XINDEX +SELECT * FROM dr1; +FNAME FTYPE +INSERT INTO t1(id,msg) VALUES(4, 'four'); +SELECT * FROM dr1; +FNAME FTYPE +part1 .fnx +part1 .txt +INSERT INTO t1(id,msg) VALUES(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'); +INSERT INTO t1(id,msg) VALUES(72,'seventy two'),(20,'twenty'),(1,'one'),(35,'thirty five'),(8,'eight'); +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +partition_name table_rows +1 4 +2 4 +3 3 +SELECT * FROM t1; +rwid rnum prtn tbn fid id msg +1 1 1 t1 part1 4 four +2 2 1 t1 part1 7 seven +3 3 1 t1 part1 1 one +4 4 1 t1 part1 8 eight +1 1 2 t1 part2 10 ten +2 2 2 t1 part2 40 forty +3 3 2 t1 part2 20 twenty +4 4 2 t1 part2 35 thirty five +1 1 3 t1 part3 60 sixty +2 2 3 t1 part3 81 eighty one +3 3 3 t1 part3 72 seventy two +SELECT * FROM t1 order by id; +rwid rnum prtn tbn fid id msg +3 3 1 t1 part1 1 one +1 1 1 t1 part1 4 four +2 2 1 t1 part1 7 seven +4 4 1 t1 part1 8 eight +1 1 2 t1 part2 10 ten +3 3 2 t1 part2 20 twenty +4 4 2 t1 part2 35 thirty five +2 2 2 t1 part2 40 forty +1 1 3 t1 part3 60 sixty +3 3 3 t1 part3 72 seventy two +2 2 3 t1 part3 81 eighty one +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 10; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 2 const PRIMARY PRIMARY 4 const 1 +SELECT * FROM t1 WHERE id = 10; +rwid rnum prtn tbn fid id msg +1 1 2 t1 part2 10 ten +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id >= 10; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 2,3 range PRIMARY PRIMARY 4 NULL 7 Using where +SELECT * FROM t1 WHERE id >= 10; +rwid rnum prtn tbn fid id msg +1 1 2 t1 part2 10 ten +3 3 2 t1 part2 20 twenty +4 4 2 t1 part2 35 thirty five +2 2 2 t1 part2 40 forty +1 1 3 t1 part3 60 sixty +3 3 3 t1 part3 72 seventy two +2 2 3 t1 part3 81 eighty one +SELECT count(*) FROM t1 WHERE id < 10; +count(*) +4 +SELECT case when id < 10 then 1 when id < 50 then 2 else 3 end as pn, count(*) FROM t1 group by pn; +pn count(*) +1 4 +2 4 +3 3 +SELECT prtn, count(*) FROM t1 group by prtn; +prtn count(*) +1 4 +2 4 +3 3 +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id > 50; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 3 range PRIMARY PRIMARY 4 NULL 3 Using where +SELECT * FROM t1 WHERE id = 35; +rwid rnum prtn tbn fid id msg +4 4 2 t1 part2 35 thirty five +SELECT * FROM dr1; +FNAME FTYPE +part1 .fnx +part1 .txt +part2 .fnx +part2 .txt +part3 .fnx +part3 .txt +# This does not change the partition file data and is WRONG +ALTER TABLE t1 +PARTITION by range columns(id) ( +PARTITION `1` VALUES LESS THAN(11), +PARTITION `2` VALUES LESS THAN(70), +PARTITION `3` VALUES LESS THAN(MAXVALUE)); +Warnings: +Warning 1105 Data repartition in 1 is unchecked +Warning 1105 Data repartition in 2 is unchecked +Warning 1105 Data repartition in 3 is unchecked +SELECT CASE WHEN id < 11 THEN 1 WHEN id < 70 THEN 2 ELSE 3 END AS pn, COUNT(*) FROM t1 GROUP BY pn; +pn COUNT(*) +1 5 +2 4 +3 2 +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +partition_name table_rows +1 4 +2 4 +3 3 +SELECT * FROM dr1; +FNAME FTYPE +part1 .fnx +part1 .txt +part2 .fnx +part2 .txt +part3 .fnx +part3 .txt +# +# This is the correct way to change partitioning: +# Save table values, erase the table, then re-insert saved values in modified table +# +CREATE TABLE t2 ( +id INT NOT NULL, +msg VARCHAR(32) +) ENGINE=CONNECT TABLE_TYPE=FIX; +Warnings: +Warning 1105 No file name. Table will use t2.fix +INSERT INTO t2 SELECT id, msg FROM t1; +DELETE FROM t1; +INSERT INTO t1(id,msg) SELECT * FROM t2; +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +partition_name table_rows +1 5 +2 4 +3 2 +SELECT * FROM t1; +rwid rnum prtn tbn fid id msg +1 1 1 t1 part1 4 four +2 2 1 t1 part1 7 seven +3 3 1 t1 part1 1 one +4 4 1 t1 part1 8 eight +5 5 1 t1 part1 10 ten +1 1 2 t1 part2 40 forty +2 2 2 t1 part2 20 twenty +3 3 2 t1 part2 35 thirty five +4 4 2 t1 part2 60 sixty +1 1 3 t1 part3 81 eighty one +2 2 3 t1 part3 72 seventy two +SELECT * FROM dr1; +FNAME FTYPE +part1 .fnx +part1 .txt +part2 .fnx +part2 .txt +part3 .fnx +part3 .txt +DROP TABLE t2; +DROP TABLE t1; +# +# Testing partitioning on a populated outward table +# +CREATE TABLE t1 ( +id INT NOT NULL, +msg VARCHAR(32) +) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='part%s.txt' +PARTITION by range columns(id) ( +PARTITION `1` VALUES LESS THAN(11), +PARTITION `2` VALUES LESS THAN(70), +PARTITION `3` VALUES LESS THAN(MAXVALUE)); +Warnings: +Warning 1105 Data repartition in 1 is unchecked +Warning 1105 Data repartition in 2 is unchecked +Warning 1105 Data repartition in 3 is unchecked +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +partition_name table_rows +1 5 +2 4 +3 2 +SELECT * FROM t1 WHERE id < 11; +id msg +4 four +7 seven +1 one +8 eight +10 ten +SELECT * FROM t1 WHERE id >= 70; +id msg +81 eighty one +72 seventy two +SELECT * FROM dr1; +FNAME FTYPE +part1 .fnx +part1 .txt +part2 .fnx +part2 .txt +part3 .fnx +part3 .txt +# +# Testing indexing on a partitioned table +# +CREATE INDEX XID ON t1(id); +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 1 XID 1 id A NULL NULL NULL XINDEX +SELECT * FROM dr1; +FNAME FTYPE +part1 .fnx +part1 .txt +part2 .fnx +part2 .txt +part3 .fnx +part3 .txt +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 10; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 1 ref XID XID 4 const 1 +DROP INDEX XID ON t1; +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +SELECT * FROM dr1; +FNAME FTYPE +part1 .txt +part2 .txt +part3 .txt +ALTER TABLE t1 ADD PRIMARY KEY (id); +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 PRIMARY 1 id A NULL NULL NULL XINDEX +SELECT * FROM dr1; +FNAME FTYPE +part1 .fnx +part1 .txt +part2 .fnx +part2 .txt +part3 .fnx +part3 .txt +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 10; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 1 const PRIMARY PRIMARY 4 const 1 +ALTER TABLE t1 DROP PRIMARY KEY; +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +SELECT * FROM dr1; +FNAME FTYPE +part1 .txt +part2 .txt +part3 .txt +DROP TABLE t1; +DROP TABLE dr1; diff --git a/storage/connect/mysql-test/connect/r/part_table.result b/storage/connect/mysql-test/connect/r/part_table.result new file mode 100644 index 00000000000..03c130548fa --- /dev/null +++ b/storage/connect/mysql-test/connect/r/part_table.result @@ -0,0 +1,180 @@ +CREATE TABLE xt1 ( +id INT KEY NOT NULL, +msg VARCHAR(32)) +ENGINE=MyISAM; +INSERT INTO xt1 VALUES(4, 'four'),(7,'seven'),(1,'one'),(8,'eight'); +SELECT * FROM xt1; +id msg +4 four +7 seven +1 one +8 eight +CREATE TABLE xt2 ( +id INT KEY NOT NULL, +msg VARCHAR(32)); +INSERT INTO xt2 VALUES(10,'ten'),(40,'forty'),(11,'eleven'),(35,'thirty five'); +SELECT * FROM xt2; +id msg +10 ten +40 forty +11 eleven +35 thirty five +CREATE TABLE xt3 ( +id INT KEY NOT NULL, +msg VARCHAR(32)) +ENGINE=CONNECT TABLE_TYPE=CSV; +Warnings: +Warning 1105 No file name. Table will use xt3.csv +INSERT INTO xt3 VALUES(60,'sixty'),(81,'eighty one'),(72,'seventy two'); +SELECT * FROM xt3; +id msg +60 sixty +81 eighty one +72 seventy two +CREATE TABLE t1 ( +id INT NOT NULL, +msg VARCHAR(32)) +ENGINE=CONNECT TABLE_TYPE=PROXY TABNAME='xt%s' +PARTITION BY RANGE COLUMNS(id) ( +PARTITION `1` VALUES LESS THAN(10), +PARTITION `2` VALUES LESS THAN(50), +PARTITION `3` VALUES LESS THAN(MAXVALUE)); +Warnings: +Warning 1105 Data repartition in 1 is unchecked +Warning 1105 Data repartition in 2 is unchecked +Warning 1105 Data repartition in 3 is unchecked +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +partition_name table_rows +1 4 +2 4 +3 3 +SELECT * FROM t1; +id msg +4 four +7 seven +1 one +8 eight +10 ten +40 forty +11 eleven +35 thirty five +60 sixty +81 eighty one +72 seventy two +DELETE FROM t1; +Warnings: +Note 1105 xt1: 4 affected rows +Note 1105 xt2: 4 affected rows +ALTER TABLE t1 ADD INDEX XID(id); +ERROR HY000: Table type PROXY is not indexable +INSERT INTO t1 VALUES(4, 'four'); +INSERT INTO t1 VALUES(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'); +INSERT INTO t1 VALUES(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight'); +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +partition_name table_rows +1 4 +2 4 +3 3 +SELECT * FROM t1; +id msg +4 four +7 seven +1 one +8 eight +10 ten +40 forty +11 eleven +35 thirty five +60 sixty +81 eighty one +72 seventy two +EXPLAIN PARTITIONS +SELECT * FROM t1 WHERE id = 81; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 3 ALL NULL NULL NULL NULL 21 Using where +DELETE FROM t1; +Warnings: +Note 1105 xt1: 4 affected rows +Note 1105 xt2: 4 affected rows +DROP TABLE t1; +CREATE TABLE t1 ( +id INT KEY NOT NULL, +msg VARCHAR(32)) +ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='xt%s' +PARTITION BY RANGE COLUMNS(id) ( +PARTITION `1` VALUES LESS THAN(10), +PARTITION `2` VALUES LESS THAN(50), +PARTITION `3` VALUES LESS THAN(MAXVALUE)); +Warnings: +Warning 1105 Data repartition in 1 is unchecked +Warning 1105 Data repartition in 2 is unchecked +Warning 1105 Data repartition in 3 is unchecked +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 PRIMARY 1 id NULL NULL NULL NULL REMOTE +INSERT INTO t1 VALUES(4, 'four'); +INSERT INTO t1 VALUES(40, 'forty'); +INSERT INTO t1 VALUES(72,'seventy two'); +INSERT INTO t1 VALUES(7,'seven'),(10,'ten'),(60,'sixty'),(81,'eighty one'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight'); +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +partition_name table_rows +1 4 +2 4 +3 3 +SELECT * FROM t1; +id msg +4 four +7 seven +1 one +8 eight +40 forty +10 ten +11 eleven +35 thirty five +72 seventy two +60 sixty +81 eighty one +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 81; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 3 const PRIMARY PRIMARY 4 const 1 +SELECT * FROM t1 WHERE id = 7; +id msg +7 seven +SELECT * FROM t1 WHERE id = 35; +id msg +35 thirty five +UPDATE t1 SET msg = 'number' WHERE id in (60,72); +ERROR HY000: Got error 122 'Remote: Got error 122 'Cannot use indexing for this command' from CONNECT' from CONNECT +UPDATE t1 SET msg = 'soixante' WHERE id = 60; +Warnings: +Note 1105 xt3: 1 affected rows +SELECT * FROM t1 WHERE id > 50; +id msg +60 soixante +72 seventy two +81 eighty one +UPDATE t1 SET msg = 'big' WHERE id > 50; +Warnings: +Note 1105 xt3: 3 affected rows +UPDATE t1 SET msg = 'sept' WHERE id = 7; +Warnings: +Note 1105 xt1: 1 affected rows +SELECT * FROM t1; +id msg +4 four +7 sept +1 one +8 eight +40 forty +10 ten +11 eleven +35 thirty five +72 big +60 big +81 big +DELETE FROM t1 WHERE id in (60,72); +ERROR HY000: Got error 122 'Remote: Got error 122 'Cannot use indexing for this command' from CONNECT' from CONNECT +DROP TABLE t1; +DROP TABLE xt1; +DROP TABLE xt2; +DROP TABLE xt3; diff --git a/storage/connect/mysql-test/connect/t/part_file.test b/storage/connect/mysql-test/connect/t/part_file.test new file mode 100644 index 00000000000..52225a3cead --- /dev/null +++ b/storage/connect/mysql-test/connect/t/part_file.test @@ -0,0 +1,159 @@ +--source include/have_partition.inc +let $MYSQLD_DATADIR= `select @@datadir`; + +--echo # This will be used to see what data files are created +CREATE TABLE dr1 ( + FNAME VARCHAR(256) NOT NULL FLAG=2, + FTYPE CHAR(8) NOT NULL FLAG=3 +# ,FSIZE INT(6) NOT NULL FLAG=5 removed because Unix size != Windows size +) engine=CONNECT table_type=DIR file_name='t1#P#*.*'; + +--echo # +--echo # Testing partitioning on inward table +--echo # +CREATE TABLE t1 ( + id INT NOT NULL, + msg VARCHAR(32) +) ENGINE=CONNECT TABLE_TYPE=CSV +PARTITION BY RANGE(id) ( +PARTITION first VALUES LESS THAN(10), +PARTITION middle VALUES LESS THAN(50), +PARTITION last VALUES LESS THAN(MAXVALUE)); +INSERT INTO t1 VALUES(4, 'four'),(24, 'twenty four'); +INSERT INTO t1 VALUES(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'); +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +SELECT * FROM t1; +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id > 50; +SELECT * FROM t1 WHERE id > 50; +SHOW TABLE STATUS LIKE 't1'; +--error ER_GET_ERRMSG +UPDATE t1 set id = 41 WHERE msg = 'four'; +UPDATE t1 set msg = 'quatre' WHERE id = 4; +SELECT * FROM dr1; +--echo # +--echo # Altering partitioning on inward table +--echo # +ALTER TABLE t1 +PARTITION by range(id) ( +PARTITION first VALUES LESS THAN(11), +PARTITION middle VALUES LESS THAN(50), +PARTITION last VALUES LESS THAN(MAXVALUE)); +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +SELECT * FROM dr1; +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id=10; +SELECT * FROM t1 WHERE id=10; +DELETE FROM t1 WHERE id in (4,60); +SELECT * FROM t1; +DROP TABLE t1; +SELECT * FROM dr1; + +--echo # +--echo # Testing partitioning on a void outward table +--echo # +ALTER TABLE dr1 file_name='part*.*'; +CREATE TABLE t1 ( + rwid INT(6) DEFAULT 0 SPECIAL=ROWID, + rnum INT(6) DEFAULT 0 SPECIAL=ROWNUM, + prtn VARCHAR(64) DEFAULT '' SPECIAL=PARTID, + tbn VARCHAR(64) DEFAULT '' SPECIAL=TABID, + fid VARCHAR(256) DEFAULT '' SPECIAL=FNAME, + id INT KEY NOT NULL, + msg VARCHAR(32) +) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='part%s.txt'; +--replace_result $MYSQLD_DATADIR "DATADIR/" +ALTER TABLE t1 +PARTITION by range columns(id) ( +PARTITION `1` VALUES LESS THAN(10), +PARTITION `2` VALUES LESS THAN(50), +PARTITION `3` VALUES LESS THAN(MAXVALUE)); +SHOW INDEX FROM t1; +SELECT * FROM dr1; +INSERT INTO t1(id,msg) VALUES(4, 'four'); +SELECT * FROM dr1; +INSERT INTO t1(id,msg) VALUES(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'); +INSERT INTO t1(id,msg) VALUES(72,'seventy two'),(20,'twenty'),(1,'one'),(35,'thirty five'),(8,'eight'); +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +SELECT * FROM t1; +SELECT * FROM t1 order by id; +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 10; +SELECT * FROM t1 WHERE id = 10; +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id >= 10; +SELECT * FROM t1 WHERE id >= 10; +SELECT count(*) FROM t1 WHERE id < 10; +SELECT case when id < 10 then 1 when id < 50 then 2 else 3 end as pn, count(*) FROM t1 group by pn; +SELECT prtn, count(*) FROM t1 group by prtn; +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id > 50; +SELECT * FROM t1 WHERE id = 35; +SELECT * FROM dr1; +--echo # This does not change the partition file data and is WRONG +ALTER TABLE t1 +PARTITION by range columns(id) ( +PARTITION `1` VALUES LESS THAN(11), +PARTITION `2` VALUES LESS THAN(70), +PARTITION `3` VALUES LESS THAN(MAXVALUE)); +SELECT CASE WHEN id < 11 THEN 1 WHEN id < 70 THEN 2 ELSE 3 END AS pn, COUNT(*) FROM t1 GROUP BY pn; +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +SELECT * FROM dr1; +--echo # +--echo # This is the correct way to change partitioning: +--echo # Save table values, erase the table, then re-insert saved values in modified table +--echo # +CREATE TABLE t2 ( + id INT NOT NULL, + msg VARCHAR(32) +) ENGINE=CONNECT TABLE_TYPE=FIX; +INSERT INTO t2 SELECT id, msg FROM t1; +DELETE FROM t1; +INSERT INTO t1(id,msg) SELECT * FROM t2; +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +SELECT * FROM t1; +SELECT * FROM dr1; +DROP TABLE t2; +DROP TABLE t1; + +--echo # +--echo # Testing partitioning on a populated outward table +--echo # +CREATE TABLE t1 ( + id INT NOT NULL, + msg VARCHAR(32) +) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='part%s.txt' +PARTITION by range columns(id) ( +PARTITION `1` VALUES LESS THAN(11), +PARTITION `2` VALUES LESS THAN(70), +PARTITION `3` VALUES LESS THAN(MAXVALUE)); +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +SELECT * FROM t1 WHERE id < 11; +SELECT * FROM t1 WHERE id >= 70; +SELECT * FROM dr1; + +--echo # +--echo # Testing indexing on a partitioned table +--echo # +CREATE INDEX XID ON t1(id); +SHOW INDEX FROM t1; +SELECT * FROM dr1; +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 10; +DROP INDEX XID ON t1; +SHOW INDEX FROM t1; +SELECT * FROM dr1; +ALTER TABLE t1 ADD PRIMARY KEY (id); +SHOW INDEX FROM t1; +SELECT * FROM dr1; +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 10; +ALTER TABLE t1 DROP PRIMARY KEY; +SHOW INDEX FROM t1; +SELECT * FROM dr1; +DROP TABLE t1; +DROP TABLE dr1; + +# +# Clean up +# +--remove_file $MYSQLD_DATADIR/test/part1.txt +--remove_file $MYSQLD_DATADIR/test/part2.txt +--remove_file $MYSQLD_DATADIR/test/part3.txt +#--remove_file $MYSQLD_DATADIR/test/part%s.fnx +#--remove_file $MYSQLD_DATADIR/test/part1.fnx +#--remove_file $MYSQLD_DATADIR/test/part2.fnx +#--remove_file $MYSQLD_DATADIR/test/part3.fnx diff --git a/storage/connect/mysql-test/connect/t/part_table.test b/storage/connect/mysql-test/connect/t/part_table.test new file mode 100644 index 00000000000..d6cb1e80fce --- /dev/null +++ b/storage/connect/mysql-test/connect/t/part_table.test @@ -0,0 +1,85 @@ +--source include/have_partition.inc + +# +# These will be used by the t1 table partition table +# +CREATE TABLE xt1 ( +id INT KEY NOT NULL, +msg VARCHAR(32)) +ENGINE=MyISAM; +INSERT INTO xt1 VALUES(4, 'four'),(7,'seven'),(1,'one'),(8,'eight'); +SELECT * FROM xt1; + +CREATE TABLE xt2 ( +id INT KEY NOT NULL, +msg VARCHAR(32)); +INSERT INTO xt2 VALUES(10,'ten'),(40,'forty'),(11,'eleven'),(35,'thirty five'); +SELECT * FROM xt2; + +CREATE TABLE xt3 ( +id INT KEY NOT NULL, +msg VARCHAR(32)) +ENGINE=CONNECT TABLE_TYPE=CSV; +INSERT INTO xt3 VALUES(60,'sixty'),(81,'eighty one'),(72,'seventy two'); +SELECT * FROM xt3; + +# +# Based on PROXY the table is not indexable +# +CREATE TABLE t1 ( +id INT NOT NULL, +msg VARCHAR(32)) +ENGINE=CONNECT TABLE_TYPE=PROXY TABNAME='xt%s' +PARTITION BY RANGE COLUMNS(id) ( +PARTITION `1` VALUES LESS THAN(10), +PARTITION `2` VALUES LESS THAN(50), +PARTITION `3` VALUES LESS THAN(MAXVALUE)); +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +SELECT * FROM t1; +DELETE FROM t1; +--error ER_UNKNOWN_ERROR +ALTER TABLE t1 ADD INDEX XID(id); +INSERT INTO t1 VALUES(4, 'four'); +INSERT INTO t1 VALUES(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'); +INSERT INTO t1 VALUES(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight'); +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +SELECT * FROM t1; +EXPLAIN PARTITIONS +SELECT * FROM t1 WHERE id = 81; +DELETE FROM t1; +DROP TABLE t1; + +# +# Based on MYSQL the table is indexable +# +CREATE TABLE t1 ( +id INT KEY NOT NULL, +msg VARCHAR(32)) +ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='xt%s' +PARTITION BY RANGE COLUMNS(id) ( +PARTITION `1` VALUES LESS THAN(10), +PARTITION `2` VALUES LESS THAN(50), +PARTITION `3` VALUES LESS THAN(MAXVALUE)); +SHOW INDEX FROM t1; +INSERT INTO t1 VALUES(4, 'four'); +INSERT INTO t1 VALUES(40, 'forty'); +INSERT INTO t1 VALUES(72,'seventy two'); +INSERT INTO t1 VALUES(7,'seven'),(10,'ten'),(60,'sixty'),(81,'eighty one'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight'); +SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1'; +SELECT * FROM t1; +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 81; +SELECT * FROM t1 WHERE id = 7; +SELECT * FROM t1 WHERE id = 35; +--error ER_GET_ERRMSG +UPDATE t1 SET msg = 'number' WHERE id in (60,72); +UPDATE t1 SET msg = 'soixante' WHERE id = 60; +SELECT * FROM t1 WHERE id > 50; +UPDATE t1 SET msg = 'big' WHERE id > 50; +UPDATE t1 SET msg = 'sept' WHERE id = 7; +SELECT * FROM t1; +--error ER_GET_ERRMSG +DELETE FROM t1 WHERE id in (60,72); +DROP TABLE t1; +DROP TABLE xt1; +DROP TABLE xt2; +DROP TABLE xt3; diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h index d37b275ebed..e0022baed93 100644 --- a/storage/connect/plgdbsem.h +++ b/storage/connect/plgdbsem.h @@ -85,6 +85,7 @@ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */ TYPE_AM_SRVID = 5, /* SERVID type (special column) */ TYPE_AM_TABID = 6, /* TABID type (special column) */ TYPE_AM_CNSID = 7, /* CONSTID type (special column) */ + TYPE_AM_PRTID = 8, /* PARTID type (special column) */ TYPE_AM_COUNT = 10, /* CPT AM type no (count table) */ TYPE_AM_DCD = 20, /* Decode access method type no */ TYPE_AM_CMS = 30, /* CMS access method type no */ @@ -549,6 +550,7 @@ PPARM Vcolist(PGLOBAL, PTDB, PSZ, bool); void PlugPutOut(PGLOBAL, FILE *, short, void *, uint); void PlugLineDB(PGLOBAL, PSZ, short, void *, uint); char *PlgGetDataPath(PGLOBAL g); +char *ExtractFromPath(PGLOBAL, char *, char *, OPVAL); void AddPointer(PTABS, void *); PDTP MakeDateFormat(PGLOBAL, PSZ, bool, bool, int); int ExtractDate(char *, PDTP, int, int val[6]); diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp index 70fdd6c0bb5..329b78c0a1a 100644 --- a/storage/connect/plgdbutl.cpp +++ b/storage/connect/plgdbutl.cpp @@ -383,6 +383,31 @@ char *PlgGetDataPath(PGLOBAL g) return (cat) ? cat->GetDataPath() : NULL; } // end of PlgGetDataPath +/***********************************************************************/ +/* Extract from a path name the required component. */ +/* This function assumes there is enough space in the buffer. */ +/***********************************************************************/ +char *ExtractFromPath(PGLOBAL g, char *pBuff, char *FileName, OPVAL op) + { + char *drive = NULL, *direc = NULL, *fname = NULL, *ftype = NULL; + + switch (op) { // Determine which part to extract +#if !defined(UNIX) + case OP_FDISK: drive = pBuff; break; +#endif // !UNIX + case OP_FPATH: direc = pBuff; break; + case OP_FNAME: fname = pBuff; break; + case OP_FTYPE: ftype = pBuff; break; + default: + sprintf(g->Message, MSG(INVALID_OPER), op, "ExtractFromPath"); + return NULL; + } // endswitch op + + // Now do the extraction + _splitpath(FileName, drive, direc, fname, ftype); + return pBuff; + } // end of PlgExtractFromPath + /***********************************************************************/ /* Check the occurence and matching of a pattern against a string. */ /* Because this function is only used for catalog name checking, */ diff --git a/storage/connect/reldef.cpp b/storage/connect/reldef.cpp index 7b3818cc98b..f483171ea7a 100644 --- a/storage/connect/reldef.cpp +++ b/storage/connect/reldef.cpp @@ -126,6 +126,14 @@ int RELDEF::GetCharCatInfo(PSZ what, PSZ sdef, char *buf, int size) return size; } // end of GetCharCatInfo +/***********************************************************************/ +/* To be used by any TDB's. */ +/***********************************************************************/ +bool RELDEF::Partitioned(void) + { + return Hc->IsPartitioned(); + } // end of Partitioned + /***********************************************************************/ /* This function returns string table information. */ /* Default parameter is "*" to get the handler default. */ @@ -136,7 +144,8 @@ char *RELDEF::GetStringCatInfo(PGLOBAL g, PSZ what, PSZ sdef) if (s) { if (Hc->IsPartitioned() && - (!stricmp(what, "filename") || !stricmp(what, "tabname"))) { + (!stricmp(what, "filename") || !stricmp(what, "tabname") + || !stricmp(what, "connect"))) { name= Hc->GetPartName(); sval= (char*)PlugSubAlloc(g, NULL, strlen(s) + strlen(name)); sprintf(sval, s, name); diff --git a/storage/connect/reldef.h b/storage/connect/reldef.h index fbf66de373c..b6bd3cafc30 100644 --- a/storage/connect/reldef.h +++ b/storage/connect/reldef.h @@ -42,6 +42,7 @@ class DllExport RELDEF : public BLOCK { // Relation definition block // Methods bool GetBoolCatInfo(PSZ what, bool bdef); bool SetIntCatInfo(PSZ what, int ival); + bool Partitioned(void); int GetIntCatInfo(PSZ what, int idef); int GetSizeCatInfo(PSZ what, PSZ sdef); int GetCharCatInfo(PSZ what, PSZ sdef, char *buf, int size); diff --git a/storage/connect/tabcol.h b/storage/connect/tabcol.h index fdee653207e..3bfc37e69c1 100644 --- a/storage/connect/tabcol.h +++ b/storage/connect/tabcol.h @@ -97,7 +97,7 @@ class DllExport COLUMN: public XOBJECT { // Column Name/Qualifier block. /***********************************************************************/ /* Definition of class SPCCOL with all its method functions. */ /* Note: Currently the special columns are ROWID, ROWNUM, FILEID, */ -/* SERVID, TABID, and CONID. */ +/* SERVID, TABID, PARTID, and CONID. */ /***********************************************************************/ class SPCCOL: public COLUMN { // Special Column Name/Qualifier block. public: diff --git a/storage/connect/tabdos.cpp b/storage/connect/tabdos.cpp index 81e7772e062..7dbe8c71aa6 100644 --- a/storage/connect/tabdos.cpp +++ b/storage/connect/tabdos.cpp @@ -414,12 +414,12 @@ TDBDOS::TDBDOS(PDOSDEF tdp, PTXF txfp) : TDBASE(tdp) AvgLen = tdp->AvgLen; Ftype = tdp->Recfm; To_Line = NULL; - Cardinal = -1; //To_BlkIdx = NULL; To_BlkFil = NULL; SavFil = NULL; //Xeval = 0; Beval = 0; + Abort = false; } // end of TDBDOS standard constructor TDBDOS::TDBDOS(PGLOBAL g, PTDBDOS tdbp) : TDBASE(tdbp) @@ -429,7 +429,6 @@ TDBDOS::TDBDOS(PGLOBAL g, PTDBDOS tdbp) : TDBASE(tdbp) AvgLen = tdbp->AvgLen; Ftype = tdbp->Ftype; To_Line = tdbp->To_Line; - Cardinal = tdbp->Cardinal; //To_BlkIdx = tdbp->To_BlkIdx; To_BlkFil = tdbp->To_BlkFil; SavFil = tdbp->SavFil; @@ -561,8 +560,13 @@ int TDBDOS::MakeBlockValues(PGLOBAL g) //void *memp = cat->GetDescp(); if ((nrec = defp->GetElemt()) < 2) { - strcpy(g->Message, MSG(TABLE_NOT_OPT)); - return RC_INFO; // Not to be optimized + if (!To_Def->Partitioned()) { + // This may be wrong to do in some cases + strcpy(g->Message, MSG(TABLE_NOT_OPT)); + return RC_INFO; // Not to be optimized + } else + return RC_OK; + } else if (GetMaxSize(g) == 0 || !(dup->Check & CHK_OPT)) { // Suppress the opt file firstly if the table is void, // secondly when it was modified with OPTIMIZATION unchecked @@ -1565,7 +1569,13 @@ int TDBDOS::MakeIndex(PGLOBAL g, PIXDEF pxdf, bool add) Mode = MODE_READ; Use = USE_READY; dfp = (PDOSDEF)To_Def; - fixed = Cardinality(g) >= 0; + + if (!Cardinality(g)) { + // Void table erase eventual index file(s) + (void)dfp->DeleteIndexFile(g, NULL); + return RC_OK; + } else + fixed = Cardinality(g) >= 0; // Are we are called from CreateTable or CreateIndex? if (pxdf) { @@ -1823,11 +1833,50 @@ int TDBDOS::RowNumber(PGLOBAL g, bool b) /***********************************************************************/ int TDBDOS::Cardinality(PGLOBAL g) { + int n = Txfp->Cardinality(NULL); + if (!g) - return Txfp->Cardinality(g); + return (Mode == MODE_ANY) ? 1 : n; + + if (Cardinal < 0) { + if (Mode == MODE_ANY && n == 0) { + // Info command, we must return exact row number + PDOSDEF dfp = (PDOSDEF)To_Def; + PIXDEF xdp = dfp->To_Indx; + + if (xdp) { + // Cardinality can be retreived from one index + PXLOAD pxp; + + if (dfp->Huge) + pxp = new(g) XHUGE; + else + pxp = new(g) XFILE; + + PXINDEX kxp = new(g) XINDEX(this, xdp, pxp, NULL, NULL); + + if (!(kxp->GetAllSizes(g, Cardinal))) + return Cardinal; + + } // endif Mode + + // Using index impossible or failed, do it the hard way + Mode = MODE_READ; + To_Line = (char*)PlugSubAlloc(g, NULL, Lrecl + 1); + + if (Txfp->OpenTableFile(g)) + return (Cardinal = Txfp->Cardinality(g)); + + for (Cardinal = 0; n != RC_EF;) + if (!(n = Txfp->ReadBuffer(g))) + Cardinal++; + + Txfp->CloseTableFile(g, false); + Mode = MODE_ANY; + } else + Cardinal = Txfp->Cardinality(g); - if (Cardinal < 0) - Cardinal = Txfp->Cardinality(g); + } // endif Cardinal return Cardinal; } // end of Cardinality @@ -2104,7 +2153,7 @@ void TDBDOS::CloseDB(PGLOBAL g) To_Kindex = NULL; } // endif - Txfp->CloseTableFile(g); + Txfp->CloseTableFile(g, Abort); } // end of CloseDB // ------------------------ DOSCOL functions ---------------------------- diff --git a/storage/connect/tabdos.h b/storage/connect/tabdos.h index 62639787325..3f1fff0c72b 100644 --- a/storage/connect/tabdos.h +++ b/storage/connect/tabdos.h @@ -125,6 +125,7 @@ class DllExport TDBDOS : public TDBASE { virtual AMT GetAmType(void) {return Txfp->GetAmType();} virtual PSZ GetFile(PGLOBAL g) {return Txfp->To_File;} virtual void SetFile(PGLOBAL g, PSZ fn) {Txfp->To_File = fn;} + virtual void SetAbort(bool b) {Abort = b;} virtual RECFM GetFtype(void) {return Ftype;} virtual bool SkipHeader(PGLOBAL g) {return false;} virtual void RestoreNrec(void) {Txfp->SetNrec(1);} @@ -183,8 +184,8 @@ class DllExport TDBDOS : public TDBASE { PBF To_BlkFil; // To evaluation block filter PFIL SavFil; // Saved hidden filter char *To_Line; // Points to current processed line - int Cardinal; // Table Cardinality RECFM Ftype; // File type: 0-var 1-fixed 2-binary (VCT) + bool Abort; // TRUE when aborting UPDATE/DELETE int Lrecl; // Logical Record Length int AvgLen; // Logical Record Average Length //int Xeval; // BlockTest return value diff --git a/storage/connect/tabfix.cpp b/storage/connect/tabfix.cpp index c376f76d377..f4bdb3011e3 100644 --- a/storage/connect/tabfix.cpp +++ b/storage/connect/tabfix.cpp @@ -63,12 +63,10 @@ static const longlong M4G = (longlong)2 * M2G; /***********************************************************************/ TDBFIX::TDBFIX(PDOSDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp) { -//Cardinal = -1; } // end of TDBFIX standard constructor TDBFIX::TDBFIX(PGLOBAL g, PTDBFIX tdbp) : TDBDOS(g, tdbp) { -//Cardinal = tdbp->Cardinal; } // end of TDBFIX copy constructor // Method diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp index e4a280fefd2..5a944db1948 100644 --- a/storage/connect/tabfmt.cpp +++ b/storage/connect/tabfmt.cpp @@ -648,7 +648,7 @@ bool TDBCSV::OpenDB(PGLOBAL g) } else for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) - if (!cdp->IsVirtual()) + if (!cdp->IsSpecial() && !cdp->IsVirtual()) Fields++; Offset = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields); @@ -685,7 +685,7 @@ bool TDBCSV::OpenDB(PGLOBAL g) } else // MODE_UPDATE for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) - if (!cdp->IsVirtual()) { + if (!cdp->IsSpecial() && !cdp->IsVirtual()) { i = cdp->GetOffset() - 1; len = cdp->GetLength(); Field[i] = (PSZ)PlugSubAlloc(g, NULL, len + 1); @@ -1117,7 +1117,8 @@ bool TDBFMT::OpenDB(PGLOBAL g) // Get the column formats for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) - if (!cdp->IsVirtual() && (i = cdp->GetOffset() - 1) < Fields) { + if (!cdp->IsSpecial() && !cdp->IsVirtual() + && (i = cdp->GetOffset() - 1) < Fields) { if (!(pfm = cdp->GetFmt())) { sprintf(g->Message, MSG(NO_FLD_FORMAT), i + 1, Name); return true; diff --git a/storage/connect/table.cpp b/storage/connect/table.cpp index 42cca1d2691..4683cabcb41 100644 --- a/storage/connect/table.cpp +++ b/storage/connect/table.cpp @@ -52,7 +52,8 @@ TDB::TDB(PTABDEF tdp) : Tdb_No(++Tnum) To_Table = NULL; Columns = NULL; Degree = (tdp) ? tdp->GetDegree() : 0; - Mode = MODE_READ; + Mode = MODE_ANY; + Cardinal = -1; } // end of TDB standard constructor TDB::TDB(PTDB tdbp) : Tdb_No(++Tnum) @@ -67,6 +68,7 @@ TDB::TDB(PTDB tdbp) : Tdb_No(++Tnum) Columns = NULL; Degree = tdbp->Degree; Mode = tdbp->Mode; + Cardinal = tdbp->Cardinal; } // end of TDB copy constructor // Methods @@ -227,7 +229,7 @@ PCOL TDBASE::ColDB(PGLOBAL g, PSZ name, int num) colp = cp; else if (!(cdp->Flags & U_SPECIAL)) colp = MakeCol(g, cdp, cprec, i); - else if (Mode == MODE_READ) + else if (Mode != MODE_INSERT) colp = InsertSpcBlk(g, cdp); if (trace) @@ -267,22 +269,38 @@ PCOL TDBASE::InsertSpcBlk(PGLOBAL g, PCOLDEF cdp) PCOL colp; cp= new(g) COLUMN(cdp->GetName()); - cp->SetTo_Table(To_Table); - if (!stricmp(name, "FILEID") || - !stricmp(name, "SERVID")) { + if (! To_Table) { + strcpy(g->Message, "Cannot make special column: To_Table is NULL"); + return NULL; + } else + cp->SetTo_Table(To_Table); + + if (!stricmp(name, "FILEID") || !stricmp(name, "FDISK") || + !stricmp(name, "FPATH") || !stricmp(name, "FNAME") || + !stricmp(name, "FTYPE") || !stricmp(name, "SERVID")) { if (!To_Def || !(To_Def->GetPseudo() & 2)) { sprintf(g->Message, MSG(BAD_SPEC_COLUMN)); return NULL; } // endif Pseudo if (!stricmp(name, "FILEID")) - colp = new(g) FIDBLK(cp); + colp = new(g) FIDBLK(cp, OP_XX); + else if (!stricmp(name, "FDISK")) + colp = new(g) FIDBLK(cp, OP_FDISK); + else if (!stricmp(name, "FPATH")) + colp = new(g) FIDBLK(cp, OP_FPATH); + else if (!stricmp(name, "FNAME")) + colp = new(g) FIDBLK(cp, OP_FNAME); + else if (!stricmp(name, "FTYPE")) + colp = new(g) FIDBLK(cp, OP_FTYPE); else colp = new(g) SIDBLK(cp); } else if (!stricmp(name, "TABID")) { colp = new(g) TIDBLK(cp); + } else if (!stricmp(name, "PARTID")) { + colp = new(g) PRTBLK(cp); //} else if (!stricmp(name, "CONID")) { // colp = new(g) CIDBLK(cp); } else if (!stricmp(name, "ROWID")) { diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp index 931e78f598e..0d0b17c3dcc 100644 --- a/storage/connect/tabmysql.cpp +++ b/storage/connect/tabmysql.cpp @@ -1,7 +1,7 @@ /************* TabMySQL C++ Program Source Code File (.CPP) *************/ /* PROGRAM NAME: TABMYSQL */ /* ------------- */ -/* Version 1.8 */ +/* Version 1.9 */ /* */ /* AUTHOR: */ /* ------- */ @@ -69,6 +69,10 @@ void PrintResult(PGLOBAL, PSEM, PQRYRES); extern "C" int trace; +// Used to check whether a MYSQL table is created on itself +bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host, + const char *db, char *tab, const char *src, int port); + /* -------------- Implementation of the MYSQLDEF class --------------- */ /***********************************************************************/ @@ -353,8 +357,12 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) Tabname = Name; } // endif am - if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL))) + if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL))) { + Read_Only = true; Isview = true; + } else if (CheckSelf(g, Hc->GetTable()->s, Hostname, Database, + Tabname, Srcdef, Portnumber)) + return true; // Used for Update and Delete Qrystr = GetStringCatInfo(g, "Query_String", "?"); @@ -603,9 +611,7 @@ bool TDBMYSQL::MakeInsert(PGLOBAL g) else qlen += colp->GetLength(); - } // endif Prep - - if (Prep) + } else // Prep strcat(valist, "?"); } // endfor colp @@ -740,33 +746,49 @@ int TDBMYSQL::MakeDelete(PGLOBAL g) #endif // 0 /***********************************************************************/ -/* XCV GetMaxSize: returns the maximum number of rows in the table. */ +/* MYSQL Cardinality: returns the number of rows in the table. */ /***********************************************************************/ -int TDBMYSQL::GetMaxSize(PGLOBAL g) - { - if (MaxSize < 0) { -#if 0 - if (MakeSelect(g)) - return -2; +int TDBMYSQL::Cardinality(PGLOBAL g) +{ + if (!g) + return (Mode == MODE_ANY && !Srcdef) ? 1 : 0; - if (!Myc.Connected()) { - if (Myc.Open(g, Host, Database, User, Pwd, Port)) - return -1; + if (Cardinal < 0 && Mode == MODE_ANY && !Srcdef) { + // Info command, we must return the exact table row number + char query[96]; + MYSQLC myc; - } // endif connected + if (myc.Open(g, Host, Database, User, Pwd, Port)) + return -1; - if ((MaxSize = Myc.GetResultSize(g, Query)) < 0) { - Myc.Close(); - return -3; - } // endif MaxSize + strcpy(query, "SELECT COUNT(*) FROM "); - // FIXME: Columns should be known when Info calls GetMaxSize - if (!Columns) - Query = NULL; // Must be remade when columns are known -#endif // 0 + if (Quoted > 0) + strcat(strcat(strcat(query, "`"), Tabname), "`"); + else + strcat(query, Tabname); + + Cardinal = myc.GetTableSize(g, query); + myc.Close(); + } // endif Cardinal + + return Cardinal; +} // end of Cardinality + +/***********************************************************************/ +/* MYSQL GetMaxSize: returns the maximum number of rows in the table. */ +/***********************************************************************/ +int TDBMYSQL::GetMaxSize(PGLOBAL g) + { + if (MaxSize < 0) { + if (Mode == MODE_DELETE) + // Return 0 in mode DELETE in case of delete all. + MaxSize = 0; + else if (!Cardinality(NULL)) + MaxSize = 10; // To make MySQL happy + else if ((MaxSize = Cardinality(g)) < 0) + MaxSize = 12; // So we can see an error occured - // Return 0 in mode DELETE in case of delete all. - MaxSize = (Mode == MODE_DELETE) ? 0 : 10; // To make MySQL happy } // endif MaxSize return MaxSize; @@ -881,11 +903,12 @@ bool TDBMYSQL::OpenDB(PGLOBAL g) } // endif MakeInsert if (m_Rc != RC_FX) { + int rc; char cmd[64]; int w; sprintf(cmd, "ALTER TABLE `%s` DISABLE KEYS", Tabname); - m_Rc = Myc.ExecSQL(g, cmd, &w); + rc = Myc.ExecSQL(g, cmd, &w); // may fail for some engines } // endif m_Rc } else @@ -1012,7 +1035,7 @@ bool TDBMYSQL::ReadKey(PGLOBAL g, OPVAL op, const void *key, int len) { int oldlen = strlen(Query); - if (op == OP_NEXT) + if (!key || op == OP_NEXT) return false; else if (op == OP_FIRST) { if (To_CondFil) @@ -1129,7 +1152,7 @@ void TDBMYSQL::CloseDB(PGLOBAL g) dup->Step = "Enabling indexes"; sprintf(cmd, "ALTER TABLE `%s` ENABLE KEYS", Tabname); Myc.m_Rows = -1; // To execute the query - m_Rc = Myc.ExecSQL(g, cmd, &w); + m_Rc = Myc.ExecSQL(g, cmd, &w); // May fail for some engines } // endif m_Rc Myc.Close(); diff --git a/storage/connect/tabmysql.h b/storage/connect/tabmysql.h index 96991fb14c1..5400ab1985a 100644 --- a/storage/connect/tabmysql.h +++ b/storage/connect/tabmysql.h @@ -1,4 +1,4 @@ -// TDBMYSQL.H Olivier Bertrand 2007-2013 +// TDBMYSQL.H Olivier Bertrand 2007-2014 #include "myconn.h" // MySQL connection declares typedef class MYSQLDEF *PMYDEF; @@ -92,6 +92,7 @@ class TDBMYSQL : public TDBASE { // Database routines virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); + virtual int Cardinality(PGLOBAL g); virtual int GetMaxSize(PGLOBAL g); virtual bool OpenDB(PGLOBAL g); virtual int ReadDB(PGLOBAL g); diff --git a/storage/connect/tabodbc.cpp b/storage/connect/tabodbc.cpp index 65226c9e36f..0b05fc68299 100644 --- a/storage/connect/tabodbc.cpp +++ b/storage/connect/tabodbc.cpp @@ -100,7 +100,13 @@ ODBCDEF::ODBCDEF(void) /***********************************************************************/ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) { - Desc = Connect = GetStringCatInfo(g, "Connect", ""); + Desc = Connect = GetStringCatInfo(g, "Connect", NULL); + + if (!Connect && !Catfunc) { + sprintf(g->Message, "Missing connection for ODBC table %s", Name); + return true; + } // endif Connect + Tabname = GetStringCatInfo(g, "Name", (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name); Tabname = GetStringCatInfo(g, "Tabname", Tabname); @@ -108,7 +114,10 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) Tabschema = GetStringCatInfo(g, "Schema", Tabschema); Tabcat = GetStringCatInfo(g, "Qualifier", NULL); Tabcat = GetStringCatInfo(g, "Catalog", Tabcat); - Srcdef = GetStringCatInfo(g, "Srcdef", NULL); + + if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL))) + Read_Only = true; + Qrystr = GetStringCatInfo(g, "Query_String", "?"); Sep = GetStringCatInfo(g, "Separator", NULL); Catver = GetIntCatInfo("Catver", 2); @@ -654,41 +663,58 @@ void TDBODBC::ResetSize(void) } // end of ResetSize +/***********************************************************************/ +/* ODBC Cardinality: returns table size in number of rows. */ +/***********************************************************************/ +int TDBODBC::Cardinality(PGLOBAL g) + { + if (!g) + return (Mode == MODE_ANY && !Srcdef) ? 1 : 0; + + if (Cardinal < 0 && Mode == MODE_ANY && !Srcdef) { + // Info command, we must return the exact table row number + char qry[96], tbn[64]; + ODBConn *ocp = new(g) ODBConn(g, this); + + if (ocp->Open(Connect, Options) < 1) + return -1; + + // Table name can be encoded in UTF-8 + Decode(TableName, tbn, sizeof(tbn)); + strcpy(qry, "SELECT COUNT(*) FROM "); + + if (Quote) + strcat(strcat(strcat(qry, Quote), tbn), Quote); + else + strcat(qry, tbn); + + // Allocate a Count(*) column (must not use the default constructor) + Cnp = new(g) ODBCCOL; + Cnp->InitValue(g); + + if ((Cardinal = ocp->GetResultSize(qry, Cnp)) < 0) + return -3; + + ocp->Close(); + } // endif Cardinal + + return Cardinal; + } // end of Cardinality + /***********************************************************************/ /* ODBC GetMaxSize: returns table size estimate in number of lines. */ /***********************************************************************/ int TDBODBC::GetMaxSize(PGLOBAL g) { if (MaxSize < 0) { - // Make MariaDB happy - MaxSize = (Mode == MODE_DELETE) ? 0 : 10; -#if 0 - // This is unuseful and takes time - if (Srcdef) { - // Return a reasonable guess - MaxSize = 100; - return MaxSize; - } // endif Srcdef - - if (!Ocp) - Ocp = new(g) ODBConn(g, this); - - if (!Ocp->IsOpen()) - if (Ocp->Open(Connect, Options) < 1) - return -1; - - if (!Count && !(Count = MakeSQL(g, true))) - return -2; - - if (!Cnp) { - // Allocate a Count(*) column (must not use the default constructor) - Cnp = new(g) ODBCCOL; - Cnp->InitValue(g); - } // endif Cnp - - if ((MaxSize = Ocp->GetResultSize(Count, Cnp)) < 0) - return -3; -#endif // 0 + if (Mode == MODE_DELETE) + // Return 0 in mode DELETE in case of delete all. + MaxSize = 0; + else if (!Cardinality(NULL)) + MaxSize = 10; // To make MySQL happy + else if ((MaxSize = Cardinality(g)) < 0) + MaxSize = 12; // So we can see an error occured + } // endif MaxSize return MaxSize; diff --git a/storage/connect/tabodbc.h b/storage/connect/tabodbc.h index 5db8cbb8cff..e1594b3b44e 100644 --- a/storage/connect/tabodbc.h +++ b/storage/connect/tabodbc.h @@ -94,8 +94,9 @@ class TDBODBC : public TDBASE { // Database routines virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); - virtual int GetProgMax(PGLOBAL g); + virtual int Cardinality(PGLOBAL g); virtual int GetMaxSize(PGLOBAL g); + virtual int GetProgMax(PGLOBAL g); virtual bool OpenDB(PGLOBAL g); virtual int ReadDB(PGLOBAL g); virtual int WriteDB(PGLOBAL g); diff --git a/storage/connect/tabsys.cpp b/storage/connect/tabsys.cpp index e8ea7f4e43a..c7b0baddadc 100644 --- a/storage/connect/tabsys.cpp +++ b/storage/connect/tabsys.cpp @@ -1,9 +1,9 @@ /************* TabSys C++ Program Source Code File (.CPP) **************/ /* PROGRAM NAME: TABSYS */ /* ------------- */ -/* Version 2.2 */ +/* Version 2.3 */ /* */ -/* Author Olivier BERTRAND 2004-2013 */ +/* Author Olivier BERTRAND 2004-2014 */ /* */ /* This program are the INI/CFG tables classes. */ /***********************************************************************/ @@ -203,18 +203,35 @@ PCOL TDBINI::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) } // end of MakeCol /***********************************************************************/ -/* INI GetMaxSize: returns the number of sections in the INI file. */ +/* INI Cardinality: returns the number of sections in the INI file. */ /***********************************************************************/ -int TDBINI::GetMaxSize(PGLOBAL g) +int TDBINI::Cardinality(PGLOBAL g) { - if (MaxSize < 0 && GetSeclist(g)) { + if (!g) + return 1; + + if (Cardinal < 0) { // Count the number of sections from the section list - char *p; + char *p = GetSeclist(g); + + Cardinal = 0; + + if (p) + for (; *p; p += (strlen(p) + 1)) + Cardinal++; - for (MaxSize = 0, p = Seclist; *p; p += (strlen(p) + 1)) - MaxSize++; + } // endif Cardinal - } // endif MaxSize + return Cardinal; + } // end of Cardinality + +/***********************************************************************/ +/* INI GetMaxSize: returns the table cardinality. */ +/***********************************************************************/ +int TDBINI::GetMaxSize(PGLOBAL g) + { + if (MaxSize < 0) + MaxSize = Cardinality(g); return MaxSize; } // end of GetMaxSize @@ -609,22 +626,28 @@ PCOL TDBXIN::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) } // end of MakeCol /***********************************************************************/ -/* XIN GetMaxSize: returns the number of sections in the XIN file. */ +/* XIN Cardinality: returns the number of keys in the XIN file. */ /***********************************************************************/ -int TDBXIN::GetMaxSize(PGLOBAL g) +int TDBXIN::Cardinality(PGLOBAL g) { - if (MaxSize < 0 && GetSeclist(g)) { + if (!g) + return 1; + + if (Cardinal < 0) { // Count the number of keys from the section list - char *p, *k; + char *k, *p = GetSeclist(g); - for (MaxSize = 0, p = Seclist; *p; p += (strlen(p) + 1)) - for (k = GetKeylist(g, p); *k; k += (strlen(k) + 1)) - MaxSize++; + Cardinal = 0; - } // endif MaxSize + if (p) + for (; *p; p += (strlen(p) + 1)) + for (k = GetKeylist(g, p); *k; k += (strlen(k) + 1)) + Cardinal++; - return MaxSize; - } // end of GetMaxSize + } // endif Cardinal + + return Cardinal; + } // end of Cardinality /***********************************************************************/ /* Record position is Section+Key. */ diff --git a/storage/connect/tabsys.h b/storage/connect/tabsys.h index b508aa5fe96..9741a43434c 100644 --- a/storage/connect/tabsys.h +++ b/storage/connect/tabsys.h @@ -1,7 +1,7 @@ /*************** TabSys H Declares Source Code File (.H) ***************/ -/* Name: TABSYS.H Version 2.2 */ +/* Name: TABSYS.H Version 2.3 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2004-2013 */ +/* (C) Copyright to the author Olivier BERTRAND 2004-2014 */ /* */ /* This file contains the XDB system tables classes declares. */ /***********************************************************************/ @@ -37,7 +37,7 @@ class DllExport INIDEF : public TABDEF { /* INI table description */ // Members char *Fn; /* Path/Name of corresponding file */ char *Xname; /* The eventual table name */ - char Layout; /* R: Row, C: Column */ + char Layout; /* R: Row, C: Column */ int Ln; /* Length of section list buffer */ }; // end of INIDEF @@ -61,7 +61,7 @@ class TDBINI : public TDBASE { virtual int GetRecpos(void) {return N;} virtual int GetProgCur(void) {return N;} virtual int GetAffectedRows(void) {return 0;} - virtual PSZ GetFile(PGLOBAL g) {return Ifile;} + virtual PSZ GetFile(PGLOBAL g) {return Ifile;} virtual void SetFile(PGLOBAL g, PSZ fn) {Ifile = fn;} virtual void ResetDB(void) {Seclist = Section = NULL; N = 0;} virtual void ResetSize(void) {MaxSize = -1; Seclist = NULL;} @@ -70,6 +70,7 @@ class TDBINI : public TDBASE { // Database routines virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); + virtual int Cardinality(PGLOBAL g); virtual int GetMaxSize(PGLOBAL g); virtual bool OpenDB(PGLOBAL g); virtual int ReadDB(PGLOBAL g); @@ -144,7 +145,7 @@ class TDBXIN : public TDBINI { // Database routines virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); - virtual int GetMaxSize(PGLOBAL g); + virtual int Cardinality(PGLOBAL g); virtual bool OpenDB(PGLOBAL g); virtual int ReadDB(PGLOBAL g); virtual int WriteDB(PGLOBAL g); diff --git a/storage/connect/tabtbl.cpp b/storage/connect/tabtbl.cpp index 0aeeb0b9d8d..4f2cf3038b9 100644 --- a/storage/connect/tabtbl.cpp +++ b/storage/connect/tabtbl.cpp @@ -435,7 +435,7 @@ bool TDBTBL::OpenDB(PGLOBAL g) if ((CurTable = Tablist)) { Tdbp = (PTDBASE)CurTable->GetTo_Tdb(); - Tdbp->SetMode(Mode); +// Tdbp->SetMode(Mode); // Tdbp->ResetDB(); // Tdbp->ResetSize(); @@ -685,7 +685,7 @@ bool TDBTBM::OpenDB(PGLOBAL g) /*********************************************************************/ if ((CurTable = Tablist)) { Tdbp = (PTDBASE)CurTable->GetTo_Tdb(); - Tdbp->SetMode(Mode); +// Tdbp->SetMode(Mode); // Check and initialize the subtable columns for (PCOL cp = Columns; cp; cp = cp->GetNext()) diff --git a/storage/connect/tabutil.cpp b/storage/connect/tabutil.cpp index e1dc58ce404..bc048f1bdfe 100644 --- a/storage/connect/tabutil.cpp +++ b/storage/connect/tabutil.cpp @@ -425,7 +425,7 @@ PTDBASE TDBPRX::GetSubTable(PGLOBAL g, PTABLE tabp, bool b) if (mysql) { #if defined(MYSQL_SUPPORT) // Access sub-table via MySQL API - if (!(tdbp= cat->GetTable(g, tabp, MODE_READ, "MYPRX"))) { + if (!(tdbp= cat->GetTable(g, tabp, Mode, "MYPRX"))) { char buf[MAX_STR]; strcpy(buf, g->Message); @@ -437,6 +437,9 @@ PTDBASE TDBPRX::GetSubTable(PGLOBAL g, PTABLE tabp, bool b) if (db) ((PTDBMY)tdbp)->SetDatabase(tabp->GetQualifier()); + if (Mode == MODE_UPDATE || Mode == MODE_DELETE) + tdbp->SetName(Name); // For Make_Command + #else // !MYSQL_SUPPORT sprintf(g->Message, "%s.%s is not a CONNECT table", db, tblp->Name); @@ -480,7 +483,7 @@ bool TDBPRX::InitTable(PGLOBAL g) if (!(Tdbp = GetSubTable(g, ((PPRXDEF)To_Def)->Tablep))) return true; - Tdbp->SetMode(Mode); +// Tdbp->SetMode(Mode); } // endif Tdbp return false; @@ -530,16 +533,12 @@ bool TDBPRX::OpenDB(PGLOBAL g) return Tdbp->OpenDB(g); } // endif use - if (Mode == MODE_DELETE) { - /*******************************************************************/ - /* Currently XCOL tables cannot be modified. */ - /*******************************************************************/ - strcpy(g->Message, "No DELETE for PROXY tables"); - return true; - } // endif Mode - if (InitTable(g)) return true; + else if (Mode != MODE_READ && (Read_Only || Tdbp->IsReadOnly())) { + strcpy(g->Message, "Cannot modify a read only table"); + return true; + } // endif tp /*********************************************************************/ /* Check and initialize the subtable columns. */ @@ -565,7 +564,8 @@ bool TDBPRX::OpenDB(PGLOBAL g) if (((PPRXCOL)cp)->Init(g, utp)) return true; - } // endif MODE_UPDATE + } else if (Mode == MODE_DELETE) + Tdbp->SetNext(Next); /*********************************************************************/ /* Physically open the object table. */ @@ -573,6 +573,7 @@ bool TDBPRX::OpenDB(PGLOBAL g) if (Tdbp->OpenDB(g)) return true; + Tdbp->SetNext(NULL); Use = USE_OPEN; return false; } // end of OpenDB @@ -593,8 +594,6 @@ int TDBPRX::ReadDB(PGLOBAL g) /***********************************************************************/ int TDBPRX::WriteDB(PGLOBAL g) { -//sprintf(g->Message, "%s tables are read only", To_Def->GetType()); -//return RC_FX; return Tdbp->WriteDB(g); } // end of WriteDB @@ -603,9 +602,7 @@ int TDBPRX::WriteDB(PGLOBAL g) /***********************************************************************/ int TDBPRX::DeleteDB(PGLOBAL g, int irc) { - sprintf(g->Message, "Delete not enabled for %s tables", - To_Def->GetType()); - return RC_FX; + return Tdbp->DeleteDB(g, irc); } // end of DeleteDB /***********************************************************************/ diff --git a/storage/connect/tabvct.cpp b/storage/connect/tabvct.cpp index ba5cf36a640..d90ec66c982 100644 --- a/storage/connect/tabvct.cpp +++ b/storage/connect/tabvct.cpp @@ -388,7 +388,7 @@ void TDBVCT::CloseDB(PGLOBAL g) To_Kindex = NULL; } // endif - Txfp->CloseTableFile(g); + Txfp->CloseTableFile(g, false); } // end of CloseDB // ------------------------ VCTCOL functions ---------------------------- diff --git a/storage/connect/tabxml.cpp b/storage/connect/tabxml.cpp index ee5749d8ab7..88c029aefd2 100644 --- a/storage/connect/tabxml.cpp +++ b/storage/connect/tabxml.cpp @@ -366,7 +366,7 @@ int TDBXML::LoadTableFile(PGLOBAL g, char *filename) /*********************************************************************/ /* Firstly we check whether this file have been already loaded. */ /*********************************************************************/ - if (Mode == MODE_READ) + if (Mode == MODE_READ || Mode == MODE_ANY) for (fp = dup->Openlist; fp; fp = fp->Next) if (fp->Type == type && fp->Length && fp->Count) if (!stricmp(fp->Fname, filename)) diff --git a/storage/connect/xindex.cpp b/storage/connect/xindex.cpp index ff682517251..4f8cab213fe 100755 --- a/storage/connect/xindex.cpp +++ b/storage/connect/xindex.cpp @@ -1380,16 +1380,19 @@ err: /***********************************************************************/ /* Get Ndif and Num_K from the index file. */ /***********************************************************************/ -bool XINDEX::GetAllSizes(PGLOBAL g, int &ndif, int &numk) +bool XINDEX::GetAllSizes(PGLOBAL g,/* int &ndif,*/ int &numk) { char *ftype; char fn[_MAX_PATH]; - int n, nv[NZ], id = -1; - bool estim = false; + int nv[NZ], id = -1; // n +//bool estim = false; + bool rc = true; PDOSDEF defp = (PDOSDEF)Tdbp->To_Def; - ndif = numk = 0; +// ndif = numk = 0; + numk = 0; +#if 0 /*********************************************************************/ /* Get the estimated table size. */ /* Note: for fixed tables we must use cardinality to avoid the call */ @@ -1417,6 +1420,7 @@ bool XINDEX::GetAllSizes(PGLOBAL g, int &ndif, int &numk) strcpy(g->Message, MSG(NO_KEY_COL)); return true; // Error } // endif Nk +#endif // 0 switch (Tdbp->Ftype) { case RECFM_VAR: ftype = ".dnx"; break; @@ -1480,6 +1484,7 @@ bool XINDEX::GetAllSizes(PGLOBAL g, int &ndif, int &numk) goto err; } // endif +#if 0 if (nv[2]) { Mul = true; Ndif = nv[2] - 1; // nv[2] is offset size, equal to Ndif + 1 @@ -1495,9 +1500,11 @@ bool XINDEX::GetAllSizes(PGLOBAL g, int &ndif, int &numk) sprintf(g->Message, MSG(OPT_NOT_MATCH), fn); goto err; } // endif +#endif // 0 Num_K = nv[3]; +#if 0 if (Nk > 1) { if (nv[2] && X->Seek(g, nv[2] * sizeof(int), 0, SEEK_CUR)) goto err; @@ -1518,17 +1525,18 @@ bool XINDEX::GetAllSizes(PGLOBAL g, int &ndif, int &numk) Ndif = nv[0]; } // endif Nk +#endif // 0 /*********************************************************************/ /* Set size values. */ /*********************************************************************/ - ndif = Ndif; +//ndif = Ndif; numk = Num_K; - return false; + rc = false; err: X->Close(); - return true; + return rc; } // end of GetAllSizes /***********************************************************************/ diff --git a/storage/connect/xindex.h b/storage/connect/xindex.h index 6800c18944d..c5ab829b33f 100644 --- a/storage/connect/xindex.h +++ b/storage/connect/xindex.h @@ -275,7 +275,7 @@ class DllExport XINDEX : public XXBASE { virtual bool Make(PGLOBAL g, PIXDEF sxp); virtual bool SaveIndex(PGLOBAL g, PIXDEF sxp); virtual bool Reorder(PGLOBAL g); - bool GetAllSizes(PGLOBAL g, int &ndif, int &numk); + bool GetAllSizes(PGLOBAL g,/* int &ndif,*/ int &numk); protected: bool AddColumns(PIXDEF xdp); diff --git a/storage/connect/xtable.h b/storage/connect/xtable.h index c4537ac0417..ff1f0bce899 100644 --- a/storage/connect/xtable.h +++ b/storage/connect/xtable.h @@ -79,6 +79,7 @@ class DllExport TDB: public BLOCK { // Table Descriptor Block. virtual int GetTdb_No(void) {return Tdb_No;} virtual PTDB GetNext(void) {return Next;} virtual PCATLG GetCat(void) {return NULL;} + virtual void SetAbort(bool b) {;} // Methods virtual bool IsSame(PTDB tp) {return tp == this;} @@ -125,6 +126,7 @@ class DllExport TDB: public BLOCK { // Table Descriptor Block. PCOL Columns; // Points to the first column of the table MODE Mode; // 10 Read, 30 Update, 40 Insert, 50 Delete int Degree; // Number of columns + int Cardinal; // Table number of rows }; // end of class TDB /***********************************************************************/ -- cgit v1.2.1