diff --git a/storage/connect/colblk.cpp b/storage/connect/colblk.cpp index dfdc82e99a7..a3206243cc1 100644 --- a/storage/connect/colblk.cpp +++ b/storage/connect/colblk.cpp @@ -350,8 +350,7 @@ TIDBLK::TIDBLK(PCOLUMN cp) : SPCBLK(cp) *Format.Type = 'C'; Format.Length = Long; Format.Prec = 1; // Case insensitive - Constant = (To_Tdb->GetAmType() != TYPE_AM_PLG && - To_Tdb->GetAmType() != TYPE_AM_PLM); + Constant = (To_Tdb->GetAmType() != TYPE_AM_TBL); Tname = NULL; } // end of TIDBLK constructor @@ -367,3 +366,30 @@ void TIDBLK::ReadColumn(PGLOBAL g) } // end of ReadColumn +/***********************************************************************/ +/* SIDBLK constructor for the SERVID special column. */ +/***********************************************************************/ +SIDBLK::SIDBLK(PCOLUMN cp) : SPCBLK(cp) + { +//Is_Key = 2; for when the MUL table indexed reading will be implemented. + Long = 64; + Buf_Type = TYPE_STRING; + *Format.Type = 'C'; + Format.Length = Long; + Format.Prec = 1; // Case insensitive + Constant = (To_Tdb->GetAmType() != TYPE_AM_TBL); + Sname = NULL; + } // end of TIDBLK constructor + +/***********************************************************************/ +/* ReadColumn: what this routine does is to return the server ID. */ +/***********************************************************************/ +void SIDBLK::ReadColumn(PGLOBAL g) + { +//if (Sname == NULL) { + Sname = (char*)To_Tdb->GetServer(); + Value->SetValue_psz(Sname); +// } // endif Sname + + } // end of ReadColumn + diff --git a/storage/connect/colblk.h b/storage/connect/colblk.h index 5fbb118fc72..a5771ccc6fa 100644 --- a/storage/connect/colblk.h +++ b/storage/connect/colblk.h @@ -62,7 +62,7 @@ class DllExport COLBLK : public XOBJECT { virtual bool SetFormat(PGLOBAL, FORMAT&); virtual int CheckColumn(PGLOBAL g, PSQL sqlp, PXOB &xp, int &ag); virtual bool IsSpecial(void) {return false;} - virtual int CheckSpcCol(PTDB tdbp, int n) {return 2;} + virtual int CheckSpcCol(PTDB tdbp, int n) {return 2;} virtual bool CheckSort(PTDB tdbp); virtual bool Eval(PGLOBAL g); virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check); @@ -168,7 +168,7 @@ class TIDBLK : public SPCBLK { // Methods virtual void Reset(void) {} // This is a pseudo constant column virtual int CheckSpcCol(PTDB tdbp, int n) - {return (n == 3 && tdbp == To_Tdb) ? 1 : 2;} + {return (n == 3 && tdbp == To_Tdb) ? 1 : 2;} virtual void ReadColumn(PGLOBAL g); protected: @@ -179,4 +179,29 @@ class TIDBLK : public SPCBLK { PSZ Tname; // The current table name }; // end of class TIDBLK +/***********************************************************************/ +/* Class SIDBLK: SERVID special column descriptor. */ +/***********************************************************************/ +class SIDBLK : public SPCBLK { + public: + // Constructor + SIDBLK(PCOLUMN cp); + + // Implementation + virtual int GetAmType(void) {return TYPE_AM_SRVID;} + + // Methods + virtual void Reset(void) {} // This is a pseudo constant column + virtual int CheckSpcCol(PTDB tdbp, int n) + {return (n == 3 && tdbp == To_Tdb) ? 1 : 2;} + virtual void ReadColumn(PGLOBAL g); + + protected: + // Default constructor not to be used + SIDBLK(void) {} + + // Members + PSZ Sname; // The current server name + }; // end of class SIDBLK + #endif // __COLBLK__H diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc index e0c722bc01f..2f7ec8299df 100644 --- a/storage/connect/connect.cc +++ b/storage/connect/connect.cc @@ -239,7 +239,7 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2, char *p; int i, n; PCOL colp; - PCOLUMN cp; +//PCOLUMN cp; PDBUSER dup= PlgGetUser(g); if (xtrace) @@ -251,6 +251,8 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2, return true; } // endif tdbp + tdbp->SetMode(mode); + if (!c1) { if (mode == MODE_INSERT) // Allocate all column blocks for that table @@ -261,12 +263,12 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2, if (xtrace) printf("Allocating column %s\n", p); - if (*p == '*') { - // This is a special column - cp= new(g) COLUMN(p + 1); - cp->SetTo_Table(tdbp->GetTable()); - colp= ((PTDBASE)tdbp)->InsertSpcBlk(g, cp); - } else +// if (*p == '*') { +// // This is a special column +// cp= new(g) COLUMN(p + 1); +// cp->SetTo_Table(tdbp->GetTable()); +// colp= ((PTDBASE)tdbp)->InsertSpcBlk(g, cp); +// } else colp= tdbp->ColDB(g, p, 0); if (!colp) { @@ -330,7 +332,7 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2, printf("Opening table %s in mode %d tdbp=%p\n", tdbp->GetName(), mode, tdbp); - tdbp->SetMode(mode); +//tdbp->SetMode(mode); if (del && ((PTDBASE)tdbp)->GetFtype() != RECFM_NAF) { // To avoid erasing the table when doing a partial delete diff --git a/storage/connect/connect.h b/storage/connect/connect.h index e81e54776c9..4b3e2fb7347 100644 --- a/storage/connect/connect.h +++ b/storage/connect/connect.h @@ -47,20 +47,9 @@ int CntIndexRange(PGLOBAL g, PTDB ptdb, const uchar* *key, uint *len, PGLOBAL CntExit(PGLOBAL g); /***********************************************************************/ -/* Definition of classes XCOLCRT, XIXDEF, XKPDEF, DOXDEF, TDBDOX */ +/* Definition of classes XKPDEF, DOXDEF, TDBDOX */ /* These classes purpose is chiefly to access protected items! */ /***********************************************************************/ -class XCOLCRT: public COLCRT { - friend class ha_connect; - friend bool CntCreateTable(PGLOBAL, char *, PCXF); - public: - XCOLCRT(PSZ name) : COLCRT(name) {Nulls= -1;} // Constructor - bool HasNulls(void) {return (Nulls != 0);} - -private: - int Nulls; - }; // end of class XCOLCRT - class DOXDEF: public DOSDEF { //friend class TDBDOX; //friend int MakeIndex(PGLOBAL, PTDB, PIXDEF); @@ -87,11 +76,7 @@ class XKPDEF: public KPARTDEF { //friend int CntMakeIndex(PGLOBAL, const char *, PIXDEF); friend int CntIndexInit(PGLOBAL, PTDB, int); public: - XKPDEF(const char *name, int n) : KPARTDEF((PSZ)name, n) {HasNulls= false;} - void SetNulls(bool b) {HasNulls= b;} - - protected: - bool HasNulls; /* Can have null values */ + XKPDEF(const char *name, int n) : KPARTDEF((PSZ)name, n) {} }; // end of class XKPDEF //RCODE CheckRecord(PGLOBAL g, PTDB tdbp, char *oldbuf, char *newbuf); diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 0718d4c613f..57770567cd6 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -107,6 +107,9 @@ #include "field.h" #include "sql_parse.h" #include "sql_base.h" +#if defined(NEW_WAY) +#include "sql_table.h" +#endif // NEW_WAY #undef OFFSET #define NOPARSE @@ -162,7 +165,7 @@ extern "C" char nmfile[]; extern "C" char pdebug[]; extern "C" { - char version[]= "Version 1.01.0006 Mai 21, 2013"; + char version[]= "Version 1.01.0007 July 26, 2013"; #if defined(XMSG) char msglang[]; // Default message language @@ -468,6 +471,7 @@ ha_connect::ha_connect(handlerton *hton, TABLE_SHARE *table_arg) creat_query_id= (table && table->in_use) ? table->in_use->query_id : 0; stop= false; indexing= -1; + locked= 0; data_file_name= NULL; index_file_name= NULL; enable_activate_all_index= 0; @@ -844,11 +848,13 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf) pcf->Flags= 0; // Now get column information + pcf->Name= (char*)fp->field_name; + if (fop && fop->special) { - pcf->Name= "*"; + pcf->Fieldfmt= (char*)fop->special; + pcf->Flags= U_SPECIAL; return fldp; - } else - pcf->Name= (char*)fp->field_name; + } // endif special pcf->Prec= 0; pcf->Opt= (fop) ? (int)fop->opt : 0; @@ -874,9 +880,13 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf) case MYSQL_TYPE_VAR_STRING: pcf->Flags |= U_VAR; /* no break */ - case MYSQL_TYPE_STRING: - pcf->Type= TYPE_STRING; + default: + pcf->Type= MYSQLtoPLG(fp->type()); + break; + } // endswitch SQL type + switch (pcf->Type) { + case TYPE_STRING: // Do something for case cp= fp->charset()->name; @@ -887,26 +897,10 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf) } // endif ci break; - case MYSQL_TYPE_LONG: - pcf->Type= TYPE_INT; - break; - case MYSQL_TYPE_SHORT: - pcf->Type= TYPE_SHORT; - break; - case MYSQL_TYPE_TINY: - pcf->Type= TYPE_TINY; - break; - case MYSQL_TYPE_DOUBLE: - case MYSQL_TYPE_FLOAT: - pcf->Type= TYPE_FLOAT; + case TYPE_FLOAT: pcf->Prec= max(min(fp->decimals(), ((unsigned)pcf->Length - 2)), 0); break; - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIMESTAMP: - pcf->Type= TYPE_DATE; - + case TYPE_DATE: // Field_length is only used for DATE columns if (fop->fldlen) pcf->Length= (int)fop->fldlen; @@ -931,12 +925,8 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf) pcf->Length= (len) ? len : 11; } // endelse - break; - case MYSQL_TYPE_LONGLONG: - pcf->Type= TYPE_BIGINT; break; default: - pcf->Type=TYPE_ERROR; break; } // endswitch type @@ -954,7 +944,7 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf) if (fp->comment.str && fp->comment.length) { pcf->Remark= (char*)PlugSubAlloc(g, NULL, fp->comment.length + 1); memcpy(pcf->Remark, fp->comment.str, fp->comment.length); - pcf->Remark[fp->comment.length] = 0; + pcf->Remark[fp->comment.length]= 0; } else pcf->Remark= NULL; @@ -1042,6 +1032,7 @@ const char *ha_connect::GetTableName(void) return (tshp) ? tshp->table_name.str : table->s->table_name.str; } // end of GetTableName +#if 0 /****************************************************************************/ /* Returns the column real or special name length of a field. */ /****************************************************************************/ @@ -1054,7 +1045,7 @@ int ha_connect::GetColNameLen(Field *fp) if (fop && fop->special) n= strlen(fop->special) + 1; else - n= strlen(fp->field_name) + 1; + n= strlen(fp->field_name); return n; } // end of GetColNameLen @@ -1084,6 +1075,7 @@ void ha_connect::AddColName(char *cp, Field *fp) strcpy(cp, (char*)fp->field_name); } // end of AddColName +#endif // 0 /****************************************************************************/ /* Get the table description block of a CONNECT table. */ @@ -1145,20 +1137,21 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del) char *p; unsigned int k1, k2, n1, n2; Field* *field; + Field* fp; MY_BITMAP *map= table->read_set; MY_BITMAP *ump= (xmod == MODE_UPDATE) ? table->write_set : NULL; k1= k2= 0; n1= n2= 1; // 1 is space for final null character - for (field= table->field; *field; field++) { - if (bitmap_is_set(map, (*field)->field_index)) { - n1+= (GetColNameLen(*field) + 1); + for (field= table->field; fp= *field; field++) { + if (bitmap_is_set(map, fp->field_index)) { + n1+= (strlen(fp->field_name) + 1); k1++; } // endif - if (ump && bitmap_is_set(ump, (*field)->field_index)) { - n2+= GetColNameLen(*field); + if (ump && bitmap_is_set(ump, fp->field_index)) { + n2+= (strlen(fp->field_name) + 1); k2++; } // endif @@ -1167,9 +1160,9 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del) if (k1) { p= c1= (char*)PlugSubAlloc(g, NULL, n1); - for (field= table->field; *field; field++) - if (bitmap_is_set(map, (*field)->field_index)) { - AddColName(p, *field); + for (field= table->field; fp= *field; field++) + if (bitmap_is_set(map, fp->field_index)) { + strcpy(p, (char*)fp->field_name); p+= (strlen(p) + 1); } // endif used field @@ -1179,9 +1172,9 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del) if (k2) { p= c2= (char*)PlugSubAlloc(g, NULL, n2); - for (field= table->field; *field; field++) - if (bitmap_is_set(ump, (*field)->field_index)) { - AddColName(p, *field); + for (field= table->field; fp= *field; field++) + if (bitmap_is_set(ump, fp->field_index)) { + strcpy(p, (char*)fp->field_name); p+= (strlen(p) + 1); } // endif used field @@ -1280,7 +1273,7 @@ int ha_connect::MakeRecord(char *buf) if (bitmap_is_set(map, fp->field_index)) { // This is a used field, fill the buffer with value for (colp= tdbp->GetColumns(); colp; colp= colp->GetNext()) - if (!stricmp(colp->GetName(), GetColName(fp))) + if (!stricmp(colp->GetName(), (char*)fp->field_name)) break; if (!colp) { @@ -1847,7 +1840,7 @@ int ha_connect::open(const char *name, int mode, uint test_if_locked) DBUG_ENTER("ha_connect::open"); if (xtrace) - printf("open: name=%s mode=%d test=%ud\n", name, mode, test_if_locked); + printf("open: name=%s mode=%d test=%u\n", name, mode, test_if_locked); if (!(share= get_share())) DBUG_RETURN(1); @@ -1891,7 +1884,7 @@ int ha_connect::optimize(THD* thd, HA_CHECK_OPT* check_opt) push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); rc= 0; } else - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; } // endif's @@ -1964,8 +1957,11 @@ int ha_connect::write_row(uchar *buf) PGLOBAL& g= xp->g; DBUG_ENTER("ha_connect::write_row"); - // Open the table if it was not opened yet (possible ???) - if (!IsOpened()) + // Open the table if it was not opened yet (locked) + if (!IsOpened() || xmod != tdbp->GetMode()) { + if (IsOpened()) + CloseTable(g); + if (OpenTable(g)) { if (strstr(g->Message, "read only")) rc= HA_ERR_TABLE_READONLY; @@ -1975,6 +1971,8 @@ int ha_connect::write_row(uchar *buf) DBUG_RETURN(rc); } // endif tdbp + } // endif isopened + if (tdbp->GetMode() == MODE_ANY) DBUG_RETURN(0); @@ -2093,6 +2091,13 @@ int ha_connect::index_init(uint idx, bool sorted) if ((rc= rnd_init(0))) return rc; + if (locked == 2) { + // Indexes are not updated in lock write mode + active_index= MAX_KEY; + indexing= 0; + DBUG_RETURN(0); + } // endif locked + indexing= CntIndexInit(g, tdbp, (signed)idx); if (indexing <= 0) { @@ -2337,16 +2342,15 @@ int ha_connect::rnd_init(bool scan) printf("%p in rnd_init: scan=%d\n", this, scan); if (g) { - // Open the table if it was not opened yet (possible ???) - if (!IsOpened()) { - if (!table || xmod == MODE_INSERT) - DBUG_RETURN(HA_ERR_INITIALIZATION); + if (!table || xmod == MODE_INSERT) + DBUG_RETURN(HA_ERR_INITIALIZATION); - if (OpenTable(g, xmod == MODE_DELETE)) - DBUG_RETURN(HA_ERR_INITIALIZATION); + // Close the table if it was opened yet (locked?) + if (IsOpened()) + CloseTable(g); - } else - void(CntRewindTable(g, tdbp)); // Read from beginning + if (OpenTable(g, xmod == MODE_DELETE)) + DBUG_RETURN(HA_ERR_INITIALIZATION); } // endif g @@ -2761,6 +2765,153 @@ bool ha_connect::IsSameIndex(PIXDEF xp1, PIXDEF xp2) return b; } // end of IsSameIndex +MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, + MODE newmode, bool *chk, bool *cras) +{ + if (xtrace) { + LEX_STRING *query_string= thd_query_string(thd); + printf("%p check_mode: cmdtype=%d\n", this, thd_sql_command(thd)); + printf("Cmd=%.*s\n", (int) query_string->length, query_string->str); + } // endif xtrace + + // Next code is temporarily replaced until sql_command is set + stop= false; + + if (newmode == MODE_WRITE) { + switch (thd_sql_command(thd)) { + case SQLCOM_LOCK_TABLES: + locked= 2; + case SQLCOM_CREATE_TABLE: + case SQLCOM_INSERT: + case SQLCOM_LOAD: + case SQLCOM_INSERT_SELECT: + newmode= MODE_INSERT; + break; +// case SQLCOM_REPLACE: +// case SQLCOM_REPLACE_SELECT: +// newmode= MODE_UPDATE; // To be checked +// break; + case SQLCOM_DELETE: + case SQLCOM_DELETE_MULTI: + case SQLCOM_TRUNCATE: + newmode= MODE_DELETE; + break; + case SQLCOM_UPDATE: + case SQLCOM_UPDATE_MULTI: + newmode= MODE_UPDATE; + break; + case SQLCOM_SELECT: + case SQLCOM_OPTIMIZE: + newmode= MODE_READ; + break; + case SQLCOM_DROP_TABLE: + case SQLCOM_RENAME_TABLE: + case SQLCOM_ALTER_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; + break; + default: + printf("Unsupported sql_command=%d", thd_sql_command(thd)); + strcpy(g->Message, "CONNECT Unsupported command"); + my_message(ER_NOT_ALLOWED_COMMAND, g->Message, MYF(0)); + newmode= MODE_ERROR; + break; + } // endswitch newmode + + } else if (newmode == MODE_READ) { + switch (thd_sql_command(thd)) { + case SQLCOM_CREATE_TABLE: + *chk= true; + *cras= true; + case SQLCOM_INSERT: + case SQLCOM_LOAD: + case SQLCOM_INSERT_SELECT: +// case SQLCOM_REPLACE: +// case SQLCOM_REPLACE_SELECT: + case SQLCOM_DELETE: + case SQLCOM_DELETE_MULTI: + case SQLCOM_TRUNCATE: + case SQLCOM_UPDATE: + case SQLCOM_UPDATE_MULTI: + case SQLCOM_SELECT: + case SQLCOM_OPTIMIZE: + break; + case SQLCOM_LOCK_TABLES: + locked= 1; + break; + case SQLCOM_DROP_INDEX: + case SQLCOM_CREATE_INDEX: + case SQLCOM_ALTER_TABLE: + *chk= true; +// stop= true; + case SQLCOM_DROP_TABLE: + case SQLCOM_RENAME_TABLE: + newmode= MODE_ANY; + break; + case SQLCOM_CREATE_VIEW: + case SQLCOM_DROP_VIEW: + newmode= MODE_ANY; + break; + default: + printf("Unsupported sql_command=%d", thd_sql_command(thd)); + strcpy(g->Message, "CONNECT Unsupported command"); + my_message(ER_NOT_ALLOWED_COMMAND, g->Message, MYF(0)); + newmode= MODE_ERROR; + break; + } // endswitch newmode + + } // endif's newmode + + if (xtrace) + printf("New mode=%d\n", newmode); + + return newmode; +} // end of check_mode + +int ha_connect::start_stmt(THD *thd, thr_lock_type lock_type) +{ + int rc= 0; + bool chk=false, cras= false; + MODE newmode; + PGLOBAL g= GetPlug(thd, xp); + DBUG_ENTER("ha_connect::start_stmt"); + + // Action will depend on lock_type + switch (lock_type) { + case TL_WRITE_ALLOW_WRITE: + case TL_WRITE_CONCURRENT_INSERT: + case TL_WRITE_DELAYED: + case TL_WRITE_DEFAULT: + case TL_WRITE_LOW_PRIORITY: + case TL_WRITE: + case TL_WRITE_ONLY: + newmode= MODE_WRITE; + break; + case TL_READ: + case TL_READ_WITH_SHARED_LOCKS: + case TL_READ_HIGH_PRIORITY: + case TL_READ_NO_INSERT: + case TL_READ_DEFAULT: + newmode= MODE_READ; + break; + case TL_UNLOCK: + default: + newmode= MODE_ANY; + break; + } // endswitch mode + + xmod= CheckMode(g, thd, newmode, &chk, &cras); + DBUG_RETURN((xmod == MODE_ERROR) ? HA_ERR_INTERNAL_ERROR : 0); +} // end of start_stmt + /** @brief This create a lock on the table. If you are implementing a storage engine @@ -2822,7 +2973,8 @@ int ha_connect::external_lock(THD *thd, int lock_type) if (newmode == MODE_ANY) { // This is unlocking, do it by closing the table - if (xp->CheckQueryID()) + if (xp->CheckQueryID() && thd_sql_command(thd) != SQLCOM_UNLOCK_TABLES + && thd_sql_command(thd) != SQLCOM_LOCK_TABLES) rc= 2; // Logical error ??? else if (g->Xchk) { if (!tdbp || *tdbp->GetName() == '#') { @@ -2910,117 +3062,25 @@ int ha_connect::external_lock(THD *thd, int lock_type) if (CloseTable(g)) { // This is an error while builing index -#if defined(_DEBUG) - // Make it a warning to avoid crash +//#if defined(_DEBUG) + // Make it a warning to avoid crash on debug push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); rc= 0; -#else // !_DEBUG - my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); - rc= HA_ERR_INTERNAL_ERROR; -#endif // !DEBUG +//#else // !_DEBUG +// my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); +// rc= HA_ERR_INTERNAL_ERROR; +//#endif // !DEBUG } // endif Close + locked= 0; DBUG_RETURN(rc); } // endif MODE_ANY - if (xtrace) { - LEX_STRING *query_string= thd_query_string(thd); - printf("%p external_lock: cmdtype=%d\n", this, thd_sql_command(thd)); - printf("Cmd=%.*s\n", (int) query_string->length, query_string->str); - } // endif xtrace + // Table mode depends on the query type + newmode= CheckMode(g, thd, newmode, &xcheck, &cras); - // Next code is temporarily replaced until sql_command is set - stop= false; - - if (newmode == MODE_WRITE) { - switch (thd_sql_command(thd)) { - case SQLCOM_CREATE_TABLE: - case SQLCOM_INSERT: - case SQLCOM_LOAD: - case SQLCOM_INSERT_SELECT: - newmode= MODE_INSERT; - break; -// case SQLCOM_REPLACE: -// case SQLCOM_REPLACE_SELECT: -// newmode= MODE_UPDATE; // To be checked -// break; - case SQLCOM_DELETE: - case SQLCOM_DELETE_MULTI: - case SQLCOM_TRUNCATE: - newmode= MODE_DELETE; - break; - case SQLCOM_UPDATE: - case SQLCOM_UPDATE_MULTI: - newmode= MODE_UPDATE; - break; - case SQLCOM_SELECT: - case SQLCOM_OPTIMIZE: - newmode= MODE_READ; - break; - case SQLCOM_DROP_TABLE: - case SQLCOM_RENAME_TABLE: - case SQLCOM_ALTER_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; - break; - default: - printf("Unsupported sql_command=%d", thd_sql_command(thd)); - sprintf(g->Message, "Unsupported sql_command=%d", thd_sql_command(thd)); - DBUG_RETURN(HA_ERR_INTERNAL_ERROR); - break; - } // endswitch newmode - - } else if (newmode == MODE_READ) { - switch (thd_sql_command(thd)) { - case SQLCOM_CREATE_TABLE: - xcheck= true; - cras= true; - case SQLCOM_INSERT: - case SQLCOM_LOAD: - case SQLCOM_INSERT_SELECT: -// case SQLCOM_REPLACE: -// case SQLCOM_REPLACE_SELECT: - case SQLCOM_DELETE: - case SQLCOM_DELETE_MULTI: - case SQLCOM_TRUNCATE: - case SQLCOM_UPDATE: - case SQLCOM_UPDATE_MULTI: - case SQLCOM_SELECT: - case SQLCOM_OPTIMIZE: - break; - case SQLCOM_DROP_INDEX: - case SQLCOM_CREATE_INDEX: - case SQLCOM_ALTER_TABLE: - xcheck= true; -// stop= true; - case SQLCOM_DROP_TABLE: - case SQLCOM_RENAME_TABLE: - newmode= MODE_ANY; - break; - case SQLCOM_CREATE_VIEW: - case SQLCOM_DROP_VIEW: - newmode= MODE_ANY; - break; - default: - printf("Unsupported sql_command=%d", thd_sql_command(thd)); - sprintf(g->Message, "Unsupported sql_command=%d", thd_sql_command(thd)); - DBUG_RETURN(HA_ERR_INTERNAL_ERROR); - break; - } // endswitch newmode - - } // endif's newmode - - - if (xtrace) - printf("New mode=%d\n", newmode); + if (newmode == MODE_ERROR) + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); // If this is the start of a new query, cleanup the previous one if (xp->CheckCleanup()) { @@ -3205,7 +3265,7 @@ int ha_connect::delete_or_rename_table(const char *name, const char *to) /* We have to retrieve the information about this table options. */ ha_table_option_struct *pos; char key[MAX_DBKEY_LENGTH], db[128], tabname[128]; - int rc = 0; + int rc= 0; uint key_length; TABLE_SHARE *share; THD *thd= current_thd; @@ -3340,11 +3400,69 @@ static char *encode(PGLOBAL g, char *cnm) @return Return 0 if ok */ +#if defined(NEW_WAY) +static bool add_fields(PGLOBAL g, + THD *thd, + Alter_info *alter_info, + char *name, + int typ, int len, int dec, + uint type_modifier, + char *rem, +// CHARSET_INFO *cs, +// void *vcolinfo, +// engine_option_value *create_options, + int flg, + bool dbf) +{ + register Create_field *new_field; + char *length, *decimals; + enum_field_types type= PLGtoMYSQL(typ, dbf); +//Virtual_column_info *vcol_info= (Virtual_column_info *)vcolinfo; + engine_option_value *crop; + LEX_STRING *comment= thd->make_lex_string(rem, strlen(rem)); + LEX_STRING *field_name= thd->make_lex_string(name, strlen(name)); -static bool add_field(String *sql, const char *field_name, const char *type, - int len, int dec, uint tm, const char *rem, int flag) + DBUG_ENTER("ha_connect::add_fields"); + length= (char*)PlugSubAlloc(g, NULL, 8); + sprintf(length, "%d", len); + + if (dec) { + decimals= (char*)PlugSubAlloc(g, NULL, 8); + sprintf(decimals, "%d", dec); + } else + decimals= NULL; + + if (flg) { + engine_option_value *start= NULL, *end= NULL; + LEX_STRING *flag= thd->make_lex_string("flag", 4); + + crop= new(thd->mem_root) engine_option_value(*flag, (ulonglong)flg, + &start, &end, thd->mem_root); + } else + crop= NULL; + + if (check_string_char_length(field_name, "", NAME_CHAR_LEN, + system_charset_info, 1)) { + my_error(ER_TOO_LONG_IDENT, MYF(0), field_name->str); /* purecov: inspected */ + DBUG_RETURN(1); /* purecov: inspected */ + } // endif field_name + + if (!(new_field= new Create_field()) || + new_field->init(thd, field_name->str, type, length, decimals, + type_modifier, NULL, NULL, comment, NULL, + NULL, NULL, 0, NULL, crop, true)) + DBUG_RETURN(1); + + alter_info->create_list.push_back(new_field); + DBUG_RETURN(0); +} // end of add_fields +#else // !NEW_WAY +static bool add_field(String *sql, const char *field_name, int typ, int len, + int dec, uint tm, const char *rem, int flag, bool dbf) { bool error= false; + const char *type= PLGtoMYSQLtype(typ, dbf); + type= PLGtoMYSQLtype(typ, true); error|= sql->append('`'); error|= sql->append(field_name); @@ -3355,7 +3473,7 @@ static bool add_field(String *sql, const char *field_name, const char *type, error|= sql->append('('); error|= sql->append_ulonglong(len); - if (dec || !strcmp(type, "DOUBLE")) { + if (!strcmp(type, "DOUBLE")) { error|= sql->append(','); error|= sql->append_ulonglong(dec); } // endif dec @@ -3377,9 +3495,225 @@ static bool add_field(String *sql, const char *field_name, const char *type, error|= sql->append_ulonglong(flag); } // endif flag - sql->append(','); + error|= sql->append(','); return error; } // end of add_field +#endif // !NEW_WAY + +/** + Initialise the table share with the new columns. + + @return + Return 0 if ok +*/ +#if defined(NEW_WAY) +//static bool sql_unusable_for_discovery(THD *thd, const char *sql); + +static int init_table_share(THD *thd, + TABLE_SHARE *table_s, + HA_CREATE_INFO *create_info, + Alter_info *alter_info) +{ + int rc= 0; + handler *file; + LEX_CUSTRING frm= {0,0}; + + DBUG_ENTER("init_table_share"); + +#if 0 + ulonglong saved_mode= thd->variables.sql_mode; + CHARSET_INFO *old_cs= thd->variables.character_set_client; + Parser_state parser_state; + char *sql_copy; + LEX *old_lex; + Query_arena *arena, backup; + LEX tmp_lex; + + /* + Ouch. Parser may *change* the string it's working on. + Currently (2013-02-26) it is used to permanently disable + conditional comments. + Anyway, let's copy the caller's string... + */ + if (!(sql_copy= thd->strmake(sql, sql_length))) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + + if (parser_state.init(thd, sql_copy, sql_length)) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + + thd->variables.sql_mode= MODE_NO_ENGINE_SUBSTITUTION | MODE_NO_DIR_IN_CREATE; + thd->variables.character_set_client= system_charset_info; + old_lex= thd->lex; + thd->lex= &tmp_lex; + + arena= thd->stmt_arena; + + if (arena->is_conventional()) + arena= 0; + else + thd->set_n_backup_active_arena(arena, &backup); + + lex_start(thd); + + if ((error= parse_sql(thd, & parser_state, NULL))) + goto ret; + + if (table_s->sql_unusable_for_discovery(thd, NULL)) { + my_error(ER_SQL_DISCOVER_ERROR, MYF(0), plugin_name(db_plugin)->str, + db.str, table_name.str, sql_copy); + goto ret; + } // endif unusable + + thd->lex->create_info.db_type= plugin_data(db_plugin, handlerton *); + + if (tabledef_version.str) + thd->lex->create_info.tabledef_version= tabledef_version; +#endif // 0 + + tmp_disable_binlog(thd); + + file= mysql_create_frm_image(thd, table_s->db.str, table_s->table_name.str, + create_info, alter_info, +// &thd->lex->create_info, &thd->lex->alter_info, + C_ORDINARY_CREATE, &frm); + if (file) + delete file; + else + rc= OPEN_FRM_CORRUPTED; + + if (!rc && frm.str) { + table_s->option_list= 0; // cleanup existing options ... + table_s->option_struct= 0; // ... if it's an assisted discovery + rc= table_s->init_from_binary_frm_image(thd, true, frm.str, frm.length); + } // endif frm + +//ret: + my_free(const_cast(frm.str)); + reenable_binlog(thd); +#if 0 + lex_end(thd->lex); + thd->lex= old_lex; + if (arena) + thd->restore_active_arena(arena, &backup); + thd->variables.sql_mode= saved_mode; + thd->variables.character_set_client= old_cs; +#endif // 0 + + if (thd->is_error() || rc) { + thd->clear_error(); + my_error(ER_NO_SUCH_TABLE, MYF(0), table_s->db.str, + table_s->table_name.str); + DBUG_RETURN(HA_ERR_NOT_A_TABLE); + } else + DBUG_RETURN(0); + +} // end of init_table_share +#else // !NEW_WAY +static int init_table_share(THD* thd, + TABLE_SHARE *table_s, + HA_CREATE_INFO *create_info, + String *sql) +{ + bool oom= false; + PTOS topt= table_s->option_struct; + + sql->length(sql->length()-1); // remove the trailing comma + sql->append(')'); + + for (ha_create_table_option *opt= connect_table_option_list; + opt->name; opt++) { + ulonglong vull; + const char *vstr; + + switch (opt->type) { + case HA_OPTION_TYPE_ULL: + vull= *(ulonglong*)(((char*)topt) + opt->offset); + + if (vull != opt->def_value) { + oom|= sql->append(' '); + oom|= sql->append(opt->name); + oom|= sql->append('='); + oom|= sql->append_ulonglong(vull); + } // endif vull + + break; + case HA_OPTION_TYPE_STRING: + vstr= *(char**)(((char*)topt) + opt->offset); + + if (vstr) { + oom|= sql->append(' '); + oom|= sql->append(opt->name); + oom|= sql->append("='"); + oom|= sql->append_for_single_quote(vstr, strlen(vstr)); + oom|= sql->append('\''); + } // endif vstr + + break; + case HA_OPTION_TYPE_BOOL: + vull= *(bool*)(((char*)topt) + opt->offset); + + if (vull != opt->def_value) { + oom|= sql->append(' '); + oom|= sql->append(opt->name); + oom|= sql->append('='); + oom|= sql->append(vull ? "ON" : "OFF"); + } // endif vull + + break; + default: // no enums here, good :) + break; + } // endswitch type + + if (oom) + return HA_ERR_OUT_OF_MEM; + + } // endfor opt + + if (create_info->connect_string.length) { + oom|= sql->append(' '); + oom|= sql->append("CONNECTION='"); + oom|= sql->append_for_single_quote(create_info->connect_string.str, + create_info->connect_string.length); + oom|= sql->append('\''); + + if (oom) + return HA_ERR_OUT_OF_MEM; + + } // endif string + + if (create_info->default_table_charset) { + oom|= sql->append(' '); + oom|= sql->append("CHARSET="); + oom|= sql->append(create_info->default_table_charset->csname); + + if (oom) + return HA_ERR_OUT_OF_MEM; + + } // endif charset + + if (xtrace) + htrc("s_init: %.*s\n", sql->length(), sql->ptr()); + + return table_s->init_from_sql_statement_string(thd, true, + sql->ptr(), sql->length()); +} // end of init_table_share +#endif // !NEW_WAY + +// Add an option to the create_info option list +static void add_option(THD* thd, HA_CREATE_INFO *create_info, + const char *opname, const char *opval) +{ +#if defined(NEW_WAY) + LEX_STRING *opn= thd->make_lex_string(opname, strlen(opname)); + LEX_STRING *val= thd->make_lex_string(opval, strlen(opval)); + engine_option_value *pov, **start= &create_info->option_list, *end= NULL; + + for (pov= *start; pov; pov= pov->next) + end= pov; + + pov= new(thd->mem_root) engine_option_value(*opn, *val, false, start, &end); +#endif // NEW_WAY +} // end of add_option /** @brief @@ -3389,6 +3723,9 @@ static bool add_field(String *sql, const char *field_name, const char *type, When assisted discovery is used the .frm file have not already been created. You can overwrite some definitions at this point but the main purpose of it is to define the columns for some table types. + + @note + this function is no more called in case of CREATE .. SELECT */ static int connect_assisted_discovery(handlerton *hton, THD* thd, TABLE_SHARE *table_s, @@ -3402,7 +3739,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, #if defined(WIN32) char *nsp= NULL, *cls= NULL; #endif // WIN32 - int port= 0, hdr= 0, mxr= 0, b= 0; + int port= 0, hdr= 0, mxr= 0, rc= 0; uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL); bool bif, ok= false, dbf= false; TABTYPE ttp= TAB_UNDEF; @@ -3410,15 +3747,19 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, PCOLRES crp; PGLOBAL g= GetPlug(thd, NULL); PTOS topt= table_s->option_struct; - +#if defined(NEW_WAY) +//CHARSET_INFO *cs; + Alter_info alter_info; +#else // !NEW_WAY char buf[1024]; String sql(buf, sizeof(buf), system_charset_info); + sql.copy(STRING_WITH_LEN("CREATE TABLE whatever ("), system_charset_info); +#endif // !NEW_WAY + if (!g) return HA_ERR_INTERNAL_ERROR; - sql.copy(STRING_WITH_LEN("CREATE TABLE whatever ("), system_charset_info); - user= host= pwd= prt= tbl= src= col= ocl= pic= fcl= rnk= dsn= NULL; // Get the useful create options @@ -3468,6 +3809,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ttp= GetTypeID(topt->type); sprintf(g->Message, "No table_type. Was set to %s", topt->type); push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); + add_option(thd, create_info, "table_type", topt->type); } else if (ttp == TAB_NIY) { sprintf(g->Message, "Unsupported table type %s", topt->type); my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); @@ -3500,6 +3842,9 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, } else if (ttp != TAB_ODBC || !(fnc & (FNC_TABLE | FNC_COL))) tab= (char*)create_info->alias; +#if defined(NEW_WAY) + add_option(thd, create_info, "tabname", tab); +#endif // NEW_WAY } // endif tab switch (ttp) { @@ -3536,7 +3881,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, dsn= (char*)PlugSubAlloc(g, NULL, strlen(dsn) + 1); strncpy(dsn, create_info->connect_string.str, create_info->connect_string.length); - dsn[create_info->connect_string.length] = 0; + dsn[create_info->connect_string.length]= 0; mydef->SetName(create_info->alias); mydef->SetCat(cat); @@ -3561,12 +3906,17 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, break; #endif // WIN32 case TAB_PIVOT: - supfnc = FNC_NO; + supfnc= FNC_NO; case TAB_PRX: case TAB_TBL: case TAB_XCL: case TAB_OCCUR: - ok= true; + if (!stricmp(tab, create_info->alias) && + (!db || !stricmp(db, table_s->db.str))) + sprintf(g->Message, "A %s table cannot refer to itself", topt->type); + else + ok= true; + break; default: sprintf(g->Message, "Cannot get column info for table type %s", topt->type); @@ -3585,13 +3935,9 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ok= false; } // endif src - // Here we should test the flag column options when - // this function is called in case of CREATE .. SELECT - if (ok) { - char *cnm, *rem; - int i, len, dec, typ, flg; - const char *type; + char *cnm, *rem; + int i, len, dec, typ, flg; PDBUSER dup= PlgGetUser(g); PCATLG cat= (dup) ? dup->Catalog : NULL; @@ -3682,24 +4028,35 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, if (fnc != FNC_NO || src || ttp == TAB_PIVOT) { // Catalog like table - for (crp= qrp->Colresp; !b && crp; crp= crp->Next) { + for (crp= qrp->Colresp; !rc && crp; crp= crp->Next) { cnm= encode(g, crp->Name); - type= PLGtoMYSQLtype(crp->Type, dbf); + typ= crp->Type; len= crp->Length; dec= crp->Prec; flg= crp->Flag; +#if defined(NEW_WAY) // Now add the field - if (add_field(&sql, cnm, type, len, dec, NOT_NULL_FLAG, 0, flg)) - b= HA_ERR_OUT_OF_MEM; - } // endfor crp + rc= add_fields(g, thd, &alter_info, cnm, typ, len, dec, + NOT_NULL_FLAG, "", flg, dbf); +#else // !NEW_WAY + // Now add the field + if (add_field(&sql, cnm, typ, len, dec, NOT_NULL_FLAG, 0, flg, dbf)) + rc= HA_ERR_OUT_OF_MEM; +#endif // !NEW_WAY + } // endfor crp } else // Not a catalog table - for (i= 0; !b && i < qrp->Nblin; i++) { - rem= NULL; + for (i= 0; !rc && i < qrp->Nblin; i++) { typ= len= dec= 0; tm= NOT_NULL_FLAG; cnm= (char*)"noname"; +#if defined(NEW_WAY) + rem= ""; +// cs= NULL; +#else // !NEW_WAY + rem= NULL; +#endif // !NEW_WAY for (crp= qrp->Colresp; crp; crp= crp->Next) switch (crp->Fld) { @@ -3755,103 +4112,27 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, #endif // ODBC_SUPPORT // Make the arguments as required by add_fields - type= PLGtoMYSQLtype(typ, true); - if (typ == TYPE_DATE) len= 0; // Now add the field - if (add_field(&sql, cnm, type, len, dec, tm, rem, 0)) - b= HA_ERR_OUT_OF_MEM; - +#if defined(NEW_WAY) + rc= add_fields(g, thd, &alter_info, cnm, typ, len, dec, + tm, rem, 0, true); +#else // !NEW_WAY + if (add_field(&sql, cnm, typ, len, dec, tm, rem, 0, true)) + rc= HA_ERR_OUT_OF_MEM; +#endif // !NEW_WAY } // endfor i - sql.length(sql.length()-1); // remove the trailing comma - sql.append(')'); +#if defined(NEW_WAY) + rc= init_table_share(thd, table_s, create_info, &alter_info); +#else // !NEW_WAY + if (!rc) + rc= init_table_share(thd, table_s, create_info, &sql); +#endif // !NEW_WAY - for (ha_create_table_option *opt= connect_table_option_list; - opt->name; opt++) { - ulonglong vull; - const char *vstr; - bool oom= false; - - switch (opt->type) { - case HA_OPTION_TYPE_ULL: - vull= *(ulonglong*)(((char*)topt) + opt->offset); - - if (vull != opt->def_value) { - oom|= sql.append(' '); - oom|= sql.append(opt->name); - oom|= sql.append('='); - oom|= sql.append_ulonglong(vull); - } // endif vull - - break; - case HA_OPTION_TYPE_STRING: - vstr= *(char**)(((char*)topt) + opt->offset); - - if (vstr) { - oom|= sql.append(' '); - oom|= sql.append(opt->name); - oom|= sql.append("='"); - oom|= sql.append_for_single_quote(vstr, strlen(vstr)); - oom|= sql.append('\''); - } // endif vstr - - break; - case HA_OPTION_TYPE_BOOL: - vull= *(bool*)(((char*)topt) + opt->offset); - - if (vull != opt->def_value) { - oom|= sql.append(' '); - oom|= sql.append(opt->name); - oom|= sql.append('='); - oom|= sql.append(vull ? "ON" : "OFF"); - } // endif vull - - break; - default: // no enums here, good :) - break; - } // endswitch type - - if (oom) - b= HA_ERR_OUT_OF_MEM; - - } // endfor opt - - if (create_info->connect_string.length) { - bool oom= false; - - oom|= sql.append(' '); - oom|= sql.append("CONNECTION='"); - oom|= sql.append_for_single_quote(create_info->connect_string.str, - create_info->connect_string.length); - oom|= sql.append('\''); - - if (oom) - b= HA_ERR_OUT_OF_MEM; - - } // endif string - - if (create_info->default_table_charset) { - bool oom= false; - - oom|= sql.append(' '); - oom|= sql.append("CHARSET="); - oom|= sql.append(create_info->default_table_charset->csname); - - if (oom) - b= HA_ERR_OUT_OF_MEM; - - } // endif charset - - if (xtrace) - printf("s_init: %.*s\n", sql.length(), sql.ptr()); - - if (!b) - b= table_s->init_from_sql_statement_string(thd, true, - sql.ptr(), sql.length()); - return b; + return rc; } // endif ok my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); @@ -3949,6 +4230,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, switch (type) { case TAB_PRX: case TAB_XCL: + case TAB_PIVOT: case TAB_OCCUR: if (options->srcdef) { strcpy(g->Message, "Cannot check looping reference"); diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h index d248b351081..8fc88098794 100644 --- a/storage/connect/ha_connect.h +++ b/storage/connect/ha_connect.h @@ -167,9 +167,9 @@ public: PIXDEF GetIndexInfo(void); const char *GetDBName(const char *name); const char *GetTableName(void); - int GetColNameLen(Field *fp); - char *GetColName(Field *fp); - void AddColName(char *cp, Field *fp); +//int GetColNameLen(Field *fp); +//char *GetColName(Field *fp); +//void AddColName(char *cp, Field *fp); TABLE *GetTable(void) {return table;} bool IsSameIndex(PIXDEF xp1, PIXDEF xp2); @@ -208,7 +208,7 @@ public: return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_HAS_RECORDS | HA_NO_AUTO_INCREMENT | HA_NO_PREFIX_CHAR_KEYS | HA_NO_COPY_ON_ALTER | HA_CAN_VIRTUAL_COLUMNS | - HA_NULL_IN_KEY | HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE); + /*HA_NULL_IN_KEY |*/ HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE); } /** @brief @@ -319,6 +319,21 @@ const char *GetValStr(OPVAL vop, bool neg); */ virtual ha_rows records(); + /** + Type of table for caching query + CONNECT should not use caching because its tables are external + data prone to me modified out of MariaDB + */ + virtual uint8 table_cache_type(void) + { +#if defined(MEMORY_TRACE) + // Temporary until bug MDEV-4771 is fixed + return HA_CACHE_TBL_NONTRANSACT; +#else + return HA_CACHE_TBL_NOCACHE; +#endif + } + /** @brief We implement this in ha_connect.cc; it's a required method. */ @@ -400,6 +415,7 @@ const char *GetValStr(OPVAL vop, bool neg); void position(const uchar *record); ///< required int info(uint); ///< required int extra(enum ha_extra_function operation); + int start_stmt(THD *thd, thr_lock_type lock_type); int external_lock(THD *thd, int lock_type); ///< required int delete_all_rows(void); ha_rows records_in_range(uint inx, key_range *min_key, @@ -429,6 +445,7 @@ const char *GetValStr(OPVAL vop, bool neg); protected: bool check_privileges(THD *thd, PTOS options); + MODE CheckMode(PGLOBAL g, THD *thd, MODE newmode, bool *chk, bool *cras); // Members static ulong num; // Tracable handler number @@ -446,6 +463,7 @@ protected: bool valid_info; // True if xinfo is valid bool stop; // Used when creating index int indexing; // Type of indexing for CONNECT + int locked; // Table lock THR_LOCK_DATA lock_data; public: diff --git a/storage/connect/macutil.cpp b/storage/connect/macutil.cpp index 44382cdafb4..3069aa71cd6 100644 --- a/storage/connect/macutil.cpp +++ b/storage/connect/macutil.cpp @@ -315,4 +315,4 @@ bool MACINFO::GetOneInfo(PGLOBAL g, int flag, void *v, int lv) *((int*)v) = n; return false; - } // end of ReadColumn + } // end of GetOneInfo diff --git a/storage/connect/mycat.cc b/storage/connect/mycat.cc index 3c75c0b63b3..a9326b38bb5 100644 --- a/storage/connect/mycat.cc +++ b/storage/connect/mycat.cc @@ -468,9 +468,9 @@ int MYCAT::GetColCatInfo(PGLOBAL g, PTABDEF defp) break; } // endswitch tc - do { +// do { field= Hc->GetColumnOption(g, field, pcf); - } while (field && (*pcf->Name =='*' /*|| pcf->Flags & U_VIRTUAL*/)); +// } while (field && (*pcf->Name =='*' /*|| pcf->Flags & U_VIRTUAL*/)); if (tc == TAB_DBF && pcf->Type == TYPE_DATE && !pcf->Datefmt) { // DBF date format defaults to 'YYYMMDD' diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp index 4cad68a9a1e..ea0425d3fae 100644 --- a/storage/connect/myconn.cpp +++ b/storage/connect/myconn.cpp @@ -134,7 +134,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, /* Allocate the structures used to refer to the result set. */ /**********************************************************************/ qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3, - buftyp, fldtyp, length, true, true); + buftyp, fldtyp, length, false, true); // Some columns must be renamed for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next) diff --git a/storage/connect/mysql-test/connect/r/mysql.result b/storage/connect/mysql-test/connect/r/mysql.result index 8d5507e121a..784162cae33 100644 --- a/storage/connect/mysql-test/connect/r/mysql.result +++ b/storage/connect/mysql-test/connect/r/mysql.result @@ -30,10 +30,12 @@ t2 CREATE TABLE `t2` ( SELECT * FROM t2; ERROR HY000: Got error 174 '(1054) Unknown column 'x' in 'field list' [SELECT `x`, `y` FROM `t1`]' from CONNECT DROP TABLE t2; +CREATE TABLE t2 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT'; ALTER TABLE t1 RENAME t1backup; SELECT * FROM t2; -ERROR 42S02: Table 'test.t2' doesn't exist +ERROR HY000: Got error 174 '(1146) Table 'test.t1' doesn't exist [SELECT `a`, `b` FROM `t1`]' from CONNECT ALTER TABLE t1backup RENAME t1; +DROP TABLE t2; # # Testing SELECT, etc. # diff --git a/storage/connect/mysql-test/connect/r/pivot.result b/storage/connect/mysql-test/connect/r/pivot.result index 1b790662c4b..11eee6233a4 100644 --- a/storage/connect/mysql-test/connect/r/pivot.result +++ b/storage/connect/mysql-test/connect/r/pivot.result @@ -78,6 +78,8 @@ Car DOUBLE(8,2) FLAG=1, Food DOUBLE(8,2) FLAG=1) ENGINE=CONNECT TABLE_TYPE=PIVOT SRCDEF='select who, week, what, sum(amount) as amount from expenses where week in (4,5) group by who, week, what'; +Warnings: +Warning 1105 Cannot check looping reference ALTER TABLE pivex OPTION_LIST='PivotCol=what,FncCol=amount,port=PORT'; Warnings: Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk @@ -125,6 +127,8 @@ Middle DOUBLE(8,2) FLAG=1, Last DOUBLE(8,2) FLAG=1) ENGINE=CONNECT TABLE_TYPE=PIVOT SRCDEF='select who, what, case when week=3 then ''First'' when week=5 then ''Last'' else ''Middle'' end as wk, sum(amount) * 6.56 as amnt from expenses group by who, what, wk'; +Warnings: +Warning 1105 Cannot check looping reference ALTER TABLE pivex OPTION_LIST='PivotCol=wk,FncCol=amnt,port=PORT'; Warnings: Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk diff --git a/storage/connect/mysql-test/connect/r/xml.result b/storage/connect/mysql-test/connect/r/xml.result index 67fcc5f121e..19b5c936e6c 100644 --- a/storage/connect/mysql-test/connect/r/xml.result +++ b/storage/connect/mysql-test/connect/r/xml.result @@ -413,7 +413,7 @@ DROP TABLE t1; SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml'); SELECT CAST(@a AS CHAR CHARACTER SET latin1); CAST(@a AS CHAR CHARACTER SET latin1) - + ÀÁÂÃ diff --git a/storage/connect/mysql-test/connect/t/mysql.test b/storage/connect/mysql-test/connect/t/mysql.test index c7eacbd3d06..bb4b2e78e56 100644 --- a/storage/connect/mysql-test/connect/t/mysql.test +++ b/storage/connect/mysql-test/connect/t/mysql.test @@ -1,420 +1,422 @@ --- source include/not_embedded.inc - -# -# TODO: consider a possibility to run this test -# against some remote MySQL server -# - -let $PORT= `select @@port`; - ---disable_query_log ---replace_result $PORT PORT ---error 0,ER_UNKNOWN_ERROR ---eval CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES - WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1' - AND ENGINE='CONNECT' - AND CREATE_OPTIONS LIKE '%`table_type`=MySQL%'`) -{ - Skip Need MySQL support; -} -DROP TABLE t1; ---enable_query_log - -# TODO: remote VARCHAR is displayed as CHAR - -CREATE TABLE t1 (a int, b char(10)); -INSERT INTO t1 VALUES (NULL,NULL),(0,'test00'),(1,'test01'),(2,'test02'),(3,'test03'); -SELECT * FROM t1; - ---echo # ---echo # Testing errors ---echo # - -# Bad user name -# Suppress "mysql_real_connect failed:" (printed in _DEBUG build) ---replace_result $PORT PORT "mysql_real_connect failed: " "" ---error ER_UNKNOWN_ERROR ---eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root1,port=$PORT' - -# Bad database name ---replace_result $PORT PORT "mysql_real_connect failed: " "" ---error ER_UNKNOWN_ERROR ---eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL DBNAME='unknown' TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' - -# Bad database name, with OPTION_LIST going first. ---replace_result $PORT PORT "mysql_real_connect failed: " "" ---error ER_UNKNOWN_ERROR ---eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL OPTION_LIST='host=localhost,user=root,port=$PORT' DBNAME='unknown' TABNAME='t1' - -# Bad table name ---replace_result $PORT PORT ---error ER_UNKNOWN_ERROR ---eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='unknown' OPTION_LIST='host=localhost,user=root,port=$PORT' ---error ER_NO_SUCH_TABLE -SHOW CREATE TABLE t2; - -# Bad column name ---replace_result $PORT PORT ---eval CREATE TABLE t2 (x int, y char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' ---replace_result $PORT PORT -SHOW CREATE TABLE t2; ---error ER_GET_ERRMSG -SELECT * FROM t2; -DROP TABLE t2; - -# The remote table disappeared -ALTER TABLE t1 RENAME t1backup; ---error ER_NO_SUCH_TABLE -SELECT * FROM t2; -ALTER TABLE t1backup RENAME t1; - - - ---echo # ---echo # Testing SELECT, etc. ---echo # - -# Automatic table structure ---replace_result $PORT PORT ---eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' ---replace_result $PORT PORT -SHOW CREATE TABLE t2; -SELECT * FROM t2; -DROP TABLE t2; - - -# Explicit table structure ---replace_result $PORT PORT ---eval CREATE TABLE t2 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' ---replace_result $PORT PORT -SHOW CREATE TABLE t2; -SELECT * FROM t2; -DROP TABLE t2; - - -# Explicit table structure: remote NULL, local NOT NULL ---replace_result $PORT PORT ---eval CREATE TABLE t2 (a INT NOT NULL, b CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' ---replace_result $PORT PORT -SHOW CREATE TABLE t2; -SELECT * FROM t2; -DROP TABLE t2; - - -# Explicit table structure with wrong column types ---replace_result $PORT PORT ---eval CREATE TABLE t2 (a char(10), b int) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' ---replace_result $PORT PORT -SHOW CREATE TABLE t2; -SELECT * FROM t2; -DROP TABLE t2; - -DROP TABLE t1; - ---echo # ---echo # Testing numeric data types ---echo # - -# TODO: tinyint is mapped to smallint -#CREATE TABLE t1 (a tinyint); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -# TODO: unsigned does not work -#CREATE TABLE t1 (a tinyint unsigned); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -CREATE TABLE t1 (a smallint); ---replace_result $PORT PORT ---eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' ---replace_result $PORT PORT -SHOW CREATE TABLE t1; ---replace_result $PORT PORT -SHOW CREATE TABLE t2; -SELECT * FROM t2; -DROP TABLE t2, t1; - -CREATE TABLE t1 (a mediumint); ---replace_result $PORT PORT ---eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' ---replace_result $PORT PORT -SHOW CREATE TABLE t1; ---replace_result $PORT PORT -SHOW CREATE TABLE t2; -SELECT * FROM t2; -DROP TABLE t2, t1; - -CREATE TABLE t1 (a int); ---replace_result $PORT PORT ---eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' ---replace_result $PORT PORT -SHOW CREATE TABLE t1; ---replace_result $PORT PORT -SHOW CREATE TABLE t2; -SELECT * FROM t2; -DROP TABLE t2, t1; - - -# TODO: bigint is mapped to double(20,0) -CREATE TABLE t1 (a bigint); ---replace_result $PORT PORT ---eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' ---replace_result $PORT PORT -SHOW CREATE TABLE t1; ---replace_result $PORT PORT -SHOW CREATE TABLE t2; -SELECT * FROM t2; -DROP TABLE t2, t1; - - -# TODO: ERROR 1439: Display width out of range for 'a' (max = 255) -#CREATE TABLE t1 (a float); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -# TODO: ERROR 1439: Display width out of range for 'a' (max = 255) -#CREATE TABLE t1 (a double); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -# TODO: decimal is converted to double -#CREATE TABLE t1 (a decimal(20,5)); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -# TODO: add test for BIT - ---echo # ---echo # Testing character data types ---echo # - -# TODO: char is mapped to varchar -CREATE TABLE t1 (a char(10)); ---replace_result $PORT PORT ---eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' ---replace_result $PORT PORT -SHOW CREATE TABLE t1; ---replace_result $PORT PORT -SHOW CREATE TABLE t2; -SELECT * FROM t2; -DROP TABLE t2, t1; - -CREATE TABLE t1 (a varchar(10)); ---replace_result $PORT PORT ---eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' ---replace_result $PORT PORT -SHOW CREATE TABLE t1; ---replace_result $PORT PORT -SHOW CREATE TABLE t2; -SELECT * FROM t2; -DROP TABLE t2, t1; - -# TODO: ERROR 1105: Unsupported column type tinytext -#CREATE TABLE t1 (a tinytext); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -# TODO: ERROR 1105: Unsupported column type mediumtext -#CREATE TABLE t1 (a mediumtext); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -# TODO: text is converted to varchar(256) -#CREATE TABLE t1 (a text); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -# TODO: ERROR 1105: Unsupported column type longtext -#CREATE TABLE t1 (a longtext); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -#TODO: add tests for ENUM -#TODO: add tests for SET - ---echo # ---echo # Testing binary data types ---echo # - -# TODO: ERROR 1105: Unsupported column type binary -#CREATE TABLE t1 (a binary(10)); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -# TODO: ERROR 1105: Unsupported column type varbinary -#CREATE TABLE t1 (a varbinary(10)); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -# TODO: ERROR 1105: Unsupported column type tinyblob -#CREATE TABLE t1 (a tinyblob); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -# TODO: ERROR 1105: Unsupported column type mediumblob -#CREATE TABLE t1 (a mediumblob); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -# TODO: blob is converted to varchar(256) -#CREATE TABLE t1 (a blob); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -# TODO: ERROR 1105: Unsupported column type longblob -#CREATE TABLE t1 (a longblob); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -# TODO: ERROR 1105: Unsupported column type geometry -#CREATE TABLE t1 (a geometry); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - ---echo # ---echo # Testing temporal data types ---echo # - -# TODO: time is converted to date -#CREATE TABLE t1 (a time); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -CREATE TABLE t1 (a date); ---replace_result $PORT PORT ---eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' ---replace_result $PORT PORT -SHOW CREATE TABLE t1; ---replace_result $PORT PORT -SHOW CREATE TABLE t2; -SELECT * FROM t2; -DROP TABLE t2, t1; - -# TODO: datetime is converted to date -#CREATE TABLE t1 (a datetime); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -# TODO: timestamp is converted to date -#CREATE TABLE t1 (a timestamp); -#--replace_result $PORT PORT -#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' -#--replace_result $PORT PORT -#SHOW CREATE TABLE t1; -#--replace_result $PORT PORT -#SHOW CREATE TABLE t2; -#SELECT * FROM t2; -#DROP TABLE t2, t1; - -# TODO: add test for YEAR -# TODO: add tests for fractional seconds - +-- source include/not_embedded.inc + +# +# TODO: consider a possibility to run this test +# against some remote MySQL server +# + +let $PORT= `select @@port`; + +--disable_query_log +--replace_result $PORT PORT +--error 0,ER_UNKNOWN_ERROR +--eval CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1' + AND ENGINE='CONNECT' + AND CREATE_OPTIONS LIKE '%`table_type`=MySQL%'`) +{ + Skip Need MySQL support; +} +DROP TABLE t1; +--enable_query_log + +# TODO: remote VARCHAR is displayed as CHAR + +CREATE TABLE t1 (a int, b char(10)); +INSERT INTO t1 VALUES (NULL,NULL),(0,'test00'),(1,'test01'),(2,'test02'),(3,'test03'); +SELECT * FROM t1; + +--echo # +--echo # Testing errors +--echo # + +# Bad user name +# Suppress "mysql_real_connect failed:" (printed in _DEBUG build) +--replace_result $PORT PORT "mysql_real_connect failed: " "" +--error ER_UNKNOWN_ERROR +--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root1,port=$PORT' + +# Bad database name +--replace_result $PORT PORT "mysql_real_connect failed: " "" +--error ER_UNKNOWN_ERROR +--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL DBNAME='unknown' TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' + +# Bad database name, with OPTION_LIST going first. +--replace_result $PORT PORT "mysql_real_connect failed: " "" +--error ER_UNKNOWN_ERROR +--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL OPTION_LIST='host=localhost,user=root,port=$PORT' DBNAME='unknown' TABNAME='t1' + +# Bad table name +--replace_result $PORT PORT +--error ER_UNKNOWN_ERROR +--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='unknown' OPTION_LIST='host=localhost,user=root,port=$PORT' +--error ER_NO_SUCH_TABLE +SHOW CREATE TABLE t2; + +# Bad column name +--replace_result $PORT PORT +--eval CREATE TABLE t2 (x int, y char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +--replace_result $PORT PORT +SHOW CREATE TABLE t2; +--error ER_GET_ERRMSG +SELECT * FROM t2; +DROP TABLE t2; + +# The remote table disappeared +--replace_result $PORT PORT +--eval CREATE TABLE t2 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +ALTER TABLE t1 RENAME t1backup; +--error ER_GET_ERRMSG +SELECT * FROM t2; +ALTER TABLE t1backup RENAME t1; +DROP TABLE t2; + + +--echo # +--echo # Testing SELECT, etc. +--echo # + +# Automatic table structure +--replace_result $PORT PORT +--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +--replace_result $PORT PORT +SHOW CREATE TABLE t2; +SELECT * FROM t2; +DROP TABLE t2; + + +# Explicit table structure +--replace_result $PORT PORT +--eval CREATE TABLE t2 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +--replace_result $PORT PORT +SHOW CREATE TABLE t2; +SELECT * FROM t2; +DROP TABLE t2; + + +# Explicit table structure: remote NULL, local NOT NULL +--replace_result $PORT PORT +--eval CREATE TABLE t2 (a INT NOT NULL, b CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +--replace_result $PORT PORT +SHOW CREATE TABLE t2; +SELECT * FROM t2; +DROP TABLE t2; + + +# Explicit table structure with wrong column types +--replace_result $PORT PORT +--eval CREATE TABLE t2 (a char(10), b int) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +--replace_result $PORT PORT +SHOW CREATE TABLE t2; +SELECT * FROM t2; +DROP TABLE t2; + +DROP TABLE t1; + +--echo # +--echo # Testing numeric data types +--echo # + +# TODO: tinyint is mapped to smallint +#CREATE TABLE t1 (a tinyint); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +# TODO: unsigned does not work +#CREATE TABLE t1 (a tinyint unsigned); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +CREATE TABLE t1 (a smallint); +--replace_result $PORT PORT +--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +--replace_result $PORT PORT +SHOW CREATE TABLE t1; +--replace_result $PORT PORT +SHOW CREATE TABLE t2; +SELECT * FROM t2; +DROP TABLE t2, t1; + +CREATE TABLE t1 (a mediumint); +--replace_result $PORT PORT +--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +--replace_result $PORT PORT +SHOW CREATE TABLE t1; +--replace_result $PORT PORT +SHOW CREATE TABLE t2; +SELECT * FROM t2; +DROP TABLE t2, t1; + +CREATE TABLE t1 (a int); +--replace_result $PORT PORT +--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +--replace_result $PORT PORT +SHOW CREATE TABLE t1; +--replace_result $PORT PORT +SHOW CREATE TABLE t2; +SELECT * FROM t2; +DROP TABLE t2, t1; + + +# TODO: bigint is mapped to double(20,0) +CREATE TABLE t1 (a bigint); +--replace_result $PORT PORT +--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +--replace_result $PORT PORT +SHOW CREATE TABLE t1; +--replace_result $PORT PORT +SHOW CREATE TABLE t2; +SELECT * FROM t2; +DROP TABLE t2, t1; + + +# TODO: ERROR 1439: Display width out of range for 'a' (max = 255) +#CREATE TABLE t1 (a float); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +# TODO: ERROR 1439: Display width out of range for 'a' (max = 255) +#CREATE TABLE t1 (a double); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +# TODO: decimal is converted to double +#CREATE TABLE t1 (a decimal(20,5)); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +# TODO: add test for BIT + +--echo # +--echo # Testing character data types +--echo # + +# TODO: char is mapped to varchar +CREATE TABLE t1 (a char(10)); +--replace_result $PORT PORT +--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +--replace_result $PORT PORT +SHOW CREATE TABLE t1; +--replace_result $PORT PORT +SHOW CREATE TABLE t2; +SELECT * FROM t2; +DROP TABLE t2, t1; + +CREATE TABLE t1 (a varchar(10)); +--replace_result $PORT PORT +--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +--replace_result $PORT PORT +SHOW CREATE TABLE t1; +--replace_result $PORT PORT +SHOW CREATE TABLE t2; +SELECT * FROM t2; +DROP TABLE t2, t1; + +# TODO: ERROR 1105: Unsupported column type tinytext +#CREATE TABLE t1 (a tinytext); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +# TODO: ERROR 1105: Unsupported column type mediumtext +#CREATE TABLE t1 (a mediumtext); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +# TODO: text is converted to varchar(256) +#CREATE TABLE t1 (a text); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +# TODO: ERROR 1105: Unsupported column type longtext +#CREATE TABLE t1 (a longtext); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +#TODO: add tests for ENUM +#TODO: add tests for SET + +--echo # +--echo # Testing binary data types +--echo # + +# TODO: ERROR 1105: Unsupported column type binary +#CREATE TABLE t1 (a binary(10)); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +# TODO: ERROR 1105: Unsupported column type varbinary +#CREATE TABLE t1 (a varbinary(10)); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +# TODO: ERROR 1105: Unsupported column type tinyblob +#CREATE TABLE t1 (a tinyblob); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +# TODO: ERROR 1105: Unsupported column type mediumblob +#CREATE TABLE t1 (a mediumblob); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +# TODO: blob is converted to varchar(256) +#CREATE TABLE t1 (a blob); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +# TODO: ERROR 1105: Unsupported column type longblob +#CREATE TABLE t1 (a longblob); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +# TODO: ERROR 1105: Unsupported column type geometry +#CREATE TABLE t1 (a geometry); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +--echo # +--echo # Testing temporal data types +--echo # + +# TODO: time is converted to date +#CREATE TABLE t1 (a time); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +CREATE TABLE t1 (a date); +--replace_result $PORT PORT +--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +--replace_result $PORT PORT +SHOW CREATE TABLE t1; +--replace_result $PORT PORT +SHOW CREATE TABLE t2; +SELECT * FROM t2; +DROP TABLE t2, t1; + +# TODO: datetime is converted to date +#CREATE TABLE t1 (a datetime); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +# TODO: timestamp is converted to date +#CREATE TABLE t1 (a timestamp); +#--replace_result $PORT PORT +#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' +#--replace_result $PORT PORT +#SHOW CREATE TABLE t1; +#--replace_result $PORT PORT +#SHOW CREATE TABLE t2; +#SELECT * FROM t2; +#DROP TABLE t2, t1; + +# TODO: add test for YEAR +# TODO: add tests for fractional seconds + diff --git a/storage/connect/odbconn.cpp b/storage/connect/odbconn.cpp index 757bd09a3ef..6129c93d388 100644 --- a/storage/connect/odbconn.cpp +++ b/storage/connect/odbconn.cpp @@ -281,7 +281,7 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table, /* Allocate the structures used to refer to the result set. */ /************************************************************************/ qrp = PlgAllocResult(g, ncol, maxres, IDS_COLUMNS, - buftyp, fldtyp, length, true, true); + buftyp, fldtyp, length, false, true); if (info) // Info table return qrp; @@ -423,7 +423,7 @@ PQRYRES ODBCDataSources(PGLOBAL g, bool info) /* Allocate the structures used to refer to the result set. */ /************************************************************************/ qrp = PlgAllocResult(g, ncol, maxres, IDS_DSRC, - buftyp, fldtyp, length, true, true); + buftyp, fldtyp, length, false, true); /************************************************************************/ /* Now get the results into blocks. */ @@ -468,7 +468,7 @@ PQRYRES ODBCDrivers(PGLOBAL g, bool info) /* Allocate the structures used to refer to the result set. */ /************************************************************************/ qrp = PlgAllocResult(g, ncol, maxres, IDS_DRIVER, - buftyp, fldtyp, length, true, true); + buftyp, fldtyp, length, false, true); /************************************************************************/ /* Now get the results into blocks. */ @@ -533,7 +533,7 @@ PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *tabpat, bool info) /* Allocate the structures used to refer to the result set. */ /************************************************************************/ qrp = PlgAllocResult(g, ncol, maxres, IDS_TABLES, buftyp, - fldtyp, length, true, true); + fldtyp, length, false, true); if (info) return qrp; @@ -617,7 +617,7 @@ PQRYRES ODBCPrimaryKeys(PGLOBAL g, ODBConn *op, char *dsn, char *table) /* Allocate the structure used to refer to the result set. */ /************************************************************************/ qrp = PlgAllocResult(g, ncol, maxres, IDS_PKEY, - buftyp, NULL, length, true, true); + buftyp, NULL, length, false, true); if (trace) htrc("Getting pkey results ncol=%d\n", qrp->Nbcol); @@ -699,7 +699,7 @@ PQRYRES ODBCStatistics(PGLOBAL g, ODBConn *op, char *dsn, char *pat, /* Allocate the structure used to refer to the result set. */ /************************************************************************/ qrp = PlgAllocResult(g, ncol, maxres, IDS_STAT, - buftyp, NULL, length, true, true); + buftyp, NULL, length, false, true); if (trace) htrc("Getting stat results ncol=%d\n", qrp->Nbcol); @@ -1210,20 +1210,19 @@ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols) RETCODE rc; HSTMT hstmt; -//m_Recset = new(m_G) RECSET(this); -//ASSERT(m_Recset); - try { b = false; if (m_hstmt) { - /*RETCODE rc;*/ - // All this did not seems to make sense and was been commented out // if (IsOpen()) // Close(SQL_CLOSE); - /*rc =*/ SQLFreeStmt(m_hstmt, SQL_CLOSE); + rc = SQLFreeStmt(m_hstmt, SQL_CLOSE); + + if (trace && !Check(rc)) + htrc("Error: SQLFreeStmt rc=%d\n", rc); + hstmt = m_hstmt; m_hstmt = NULL; ThrowDBX(MSG(SEQUENCE_ERROR)); @@ -1340,7 +1339,6 @@ int ODBConn::GetResultSize(char *sql, ODBCCOL *colp) } // endfor n } catch(DBX *x) { -// strcpy(m_G->Message, x->m_ErrMsg[0]); strcpy(m_G->Message, x->GetErrorMessage(0)); if (trace) @@ -1516,7 +1514,6 @@ bool ODBConn::BindParam(ODBCCOL *colp) #endif // 0 buf = colp->GetBuffer(0); -// len = colp->GetBuflen(); len = IsTypeNum(colp->GetResultType()) ? 0 : colp->GetBuflen(); ct = GetSQLCType(colp->GetResultType()); sqlt = GetSQLType(colp->GetResultType()); @@ -1580,7 +1577,6 @@ bool ODBConn::GetDataSources(PQRYRES qrp) rv = true; } // end try/catch -//SQLFreeEnv(m_henv); Close(); return rv; } // end of GetDataSources @@ -1632,7 +1628,6 @@ bool ODBConn::GetDrivers(PQRYRES qrp) rv = true; } // end try/catch -//SQLFreeEnv(m_henv); Close(); return rv; } // end of GetDrivers @@ -1801,7 +1796,6 @@ int ODBConn::GetCatInfo(CATPARM *cap) } else // ODBC Ver 3 rc = SQLFetch(hstmt); -// if (!Check(rc)) if (rc == SQL_NO_DATA_FOUND) { if (cap->Pat) sprintf(m_G->Message, MSG(NO_TABCOL_DATA), cap->Tab, cap->Pat); @@ -1837,270 +1831,35 @@ int ODBConn::GetCatInfo(CATPARM *cap) /***********************************************************************/ void ODBConn::Close() { - /*RETCODE rc;*/ - -#if 0 - // Close any open recordsets - AfxLockGlobals(CRIT_ODBC); - TRY - { - while (!m_listRecordsets.IsEmpty()) - { - CRecordset* pSet = (CRecordset*)m_listRecordsets.GetHead(); - pSet->Close(); // will implicitly remove from list - pSet->m_pDatabase = NULL; - } - } - CATCH_ALL(e) - { - AfxUnlockGlobals(CRIT_ODBC); - THROW_LAST(); - } - END_CATCH_ALL - AfxUnlockGlobals(CRIT_ODBC); -#endif // 0 + RETCODE rc; if (m_hstmt) { // Is required for multiple tables - /*rc =*/ SQLFreeStmt(m_hstmt, SQL_DROP); + rc = SQLFreeStmt(m_hstmt, SQL_DROP); m_hstmt = NULL; } // endif m_hstmt if (m_hdbc != SQL_NULL_HDBC) { - /*rc =*/ SQLDisconnect(m_hdbc); - /*rc =*/ SQLFreeConnect(m_hdbc); - m_hdbc = SQL_NULL_HDBC; + rc = SQLDisconnect(m_hdbc); -// AfxLockGlobals(CRIT_ODBC); -// ASSERT(m_nAlloc != 0); -// m_nAlloc--; -// AfxUnlockGlobals(CRIT_ODBC); + if (trace && rc != SQL_SUCCESS) + htrc("Error: SQLDisconnect rc=%d\n", rc); + + rc = SQLFreeConnect(m_hdbc); + + if (trace && rc != SQL_SUCCESS) + htrc("Error: SQLFreeConnect rc=%d\n", rc); + + m_hdbc = SQL_NULL_HDBC; } // endif m_hdbc if (m_henv != SQL_NULL_HENV) { - if (trace) { - RETCODE rc = SQLFreeEnv(m_henv); - - if (rc != SQL_SUCCESS) // Nothing we can do - htrc("Error: SQLFreeEnv failure ignored in Close\n"); - - } else - SQLFreeEnv(m_henv); + rc = SQLFreeEnv(m_henv); - m_henv = SQL_NULL_HENV; + if (trace && rc != SQL_SUCCESS) // Nothing we can do + htrc("Error: SQLFreeEnv failure ignored in Close\n"); + + m_henv = SQL_NULL_HENV; } // endif m_henv } // end of Close - -#if 0 -// Silently disconnect and free all ODBC resources. -// Don't throw any exceptions -void ODBConn::Free() - { - // Trap failures upon close - try { - Close(); - } catch(DBX*) { - // Nothing we can do - if (trace) - htrc("Error: exception by Close ignored in Free\n"); - -// DELETE_EXCEPTION(x); - } // endcatch - - // free henv if refcount goes to 0 -//AfxLockGlobals(CRIT_ODBC); - if (m_henv != SQL_NULL_HENV) { - ASSERT(m_nAlloc >= 0); - - if (m_nAlloc == 0) { - // free last connection - release HENV - if (trace) { - RETCODE rc = SQLFreeEnv(m_henv); - - if (rc != SQL_SUCCESS) // Nothing we can do - htrc("Error: SQLFreeEnv failure ignored in Free\n"); - - } else - SQLFreeEnv(m_henv); - - m_henv = SQL_NULL_HENV; - } // endif m_nAlloc - } // endif m_henv -//AfxUnlockGlobals(CRIT_ODBC); - } // end of Free - -////////////////////////////////////////////////////////////////////////////// -// CRecordset helpers - -//id AFXAPI AfxSetCurrentRecord(int* plCurrentRecord, int nRows, RETCODE nRetCode); -//id AFXAPI AfxSetRecordCount(int* plRecordCount, int lCurrentRecord, -//bool bEOFSeen, RETCODE nRetCode); - -/***********************************************************************/ -/* RECSET class implementation */ -/***********************************************************************/ -RECSET::RECSET(ODBConn *dbcp) - { - m_pDB = dbcp; - m_hstmt = SQL_NULL_HSTMT; - m_OpenType = snapshot; - m_Options = none; - -#if 0 - m_lOpen = AFX_RECORDSET_STATUS_UNKNOWN; - m_nEditMode = noMode; - m_nDefaultType = snapshot; - - m_bAppendable = false; - m_bUpdatable = false; - m_bScrollable = false; - m_bRecordsetDb = false; - m_bRebindParams = false; - m_bLongBinaryColumns = false; - m_nLockMode = optimistic; - m_dwInitialGetDataLen = 0; - m_rgODBCFieldInfos = NULL; - m_rgFieldInfos = NULL; - m_rgRowStatus = NULL; - m_dwRowsetSize = 25; - m_dwAllocatedRowsetSize = 0; - - m_nFields = 0; - m_nParams = 0; - m_nFieldsBound = 0; - m_lCurrentRecord = AFX_CURRENT_RECORD_UNDEFINED; - m_lRecordCount = 0; - m_bUseUpdateSQL = false; - m_bUseODBCCursorLib = false; - m_nResultCols = -1; - m_bCheckCacheForDirtyFields = true; - - m_pbFieldFlags = NULL; - m_pbParamFlags = NULL; - m_plParamLength = NULL; - m_pvFieldProxy = NULL; - m_pvParamProxy = NULL; - m_nProxyFields = 0; - m_nProxyParams = 0; - - m_hstmtUpdate = SQL_NULL_HSTMT; -#endif // 0 - } // end of RECSET constructor - -RECSET::~RECSET() - { - try { - if (m_hstmt) { - if (trace && (m_dwOptions & useMultiRowFetch)) { - htrc("WARNING: Close called implicitly from destructor\n"); - htrc("Use of multi row fetch requires explicit call\n"); - htrc("to Close or memory leaks will result\n"); - } // endif trace - - Close(); - } // endif m_hstmt - -// if (m_bRecordsetDb) -// delete m_pDB; ?????? - - m_pDB = NULL; - } catch(DBX*) { - // Nothing we can do - if (trace) - htrc("Error: Exception ignored in ~RECSET\n"); - - } // endtry/catch - - } // end of ~RECSET - -/***********************************************************************/ -/* Open: this function does the following: */ -/* Allocates the hstmt, */ -/* Bind columns, */ -/* Execute the SQL statement */ -/***********************************************************************/ -bool RECSET::Open(PSZ sql, uint Type, DWORD options) - { - ASSERT(m_pDB && m_pDB->IsOpen()); - ASSERT(Type == DB_USE_DEFAULT_TYPE || Type == dynaset || - Type == snapshot || Type == forwardOnly || Type == dynamic); -//ASSERT(!(options & readOnly && options & appendOnly)); - - // Cache state info and allocate hstmt - SetState(Type, sql, options); - - try { - if (m_hstmt) { - if (IsOpen()) - Close(SQL_CLOSE); - - } else { - RETCODE rc = SQLAllocStmt(m_pDB->m_hdbc, &m_hstmt); - - if (!Check(rc)) - ThrowDBException(SQL_INVALID_HANDLE); - - } // endif m_hstmt - - m_pDB->OnSetOptions(m_hstmt); - - // Allocate the field/param status arrays, if necessary -// bool bUnbound = false; - -// if (m_nFields > 0 || m_nParams > 0) -// AllocStatusArrays(); -// else -// bUnbound = true; - - // Build SQL and prep/execute or just execute direct -// BuildSQL(sql); - PrepareAndExecute(sql); - - // Cache some field info and prepare the rowset - AllocAndCacheFieldInfo(); - AllocRowset(); - - // If late binding, still need to allocate status arrays -// if (bUnbound && (m_nFields > 0 || m_nParams > 0)) -// AllocStatusArrays(); - - } catch(DBX *x) { - Close(SQL_DROP); -// strcpy(m_pDB->m_G->Message, x->GetErrorMessage[0]); - strcpy(m_pDB->m_G->Message, x->GetErrorMessage(0)); - return true; - } // endtry/catch - - return false; - } // end of Open - -/***********************************************************************/ -/* Close a hstmt. */ -/***********************************************************************/ -void RECSET::Close(SWORD option) - { - if (m_hstmt != SQL_NULL_HSTMT) { - RETCODE rc = SQLFreeStmt(m_hstmt, option); - - if (option == SQL_DROP) - m_hstmt = SQL_NULL_HSTMT; - - } // endif m_hstmt - -#if 0 - m_lOpen = RECORDSET_STATUS_CLOSED; - m_bBOF = true; - m_bEOF = true; - m_bDeleted = false; - m_bAppendable = false; - m_bUpdatable = false; - m_bScrollable = false; - m_bRebindParams = false; - m_bLongBinaryColumns = false; - m_nLockMode = optimistic; - m_nFieldsBound = 0; - m_nResultCols = -1; -#endif // 0 - } // end of Close -#endif // 0 diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h index 44ad8605747..11fe5694bc6 100644 --- a/storage/connect/plgdbsem.h +++ b/storage/connect/plgdbsem.h @@ -151,7 +151,8 @@ enum ALGMOD {AMOD_AUTO = 0, /* PLG chooses best algorithm */ #define NAM_LEN 128 #endif // !0 -enum MODE {MODE_ANY = 0, /* Unspecified mode */ +enum MODE {MODE_ERROR = -1, /* Invalid mode */ + MODE_ANY = 0, /* Unspecified mode */ MODE_READ = 10, /* Input/Output mode */ MODE_WRITE = 20, /* Input/Output mode */ MODE_UPDATE = 30, /* Input/Output mode */ @@ -319,7 +320,8 @@ enum COLUSE {U_P = 0x01, /* the projection list. */ U_VAR = 0x10, /* a VARCHAR column */ U_VIRTUAL = 0x20, /* a VIRTUAL column */ U_NULLS = 0x40, /* The column may have nulls */ - U_IS_NULL = 0x80}; /* The column has a null value */ + U_IS_NULL = 0x80, /* The column has a null value */ + U_SPECIAL = 0x100}; /* The column is special */ /***********************************************************************/ /* DB description class and block pointer definitions. */ diff --git a/storage/connect/reldef.cpp b/storage/connect/reldef.cpp index 8525fd09cbc..93d15747911 100644 --- a/storage/connect/reldef.cpp +++ b/storage/connect/reldef.cpp @@ -383,32 +383,35 @@ int COLDEF::Define(PGLOBAL g, void *memp, PCOLINFO cfp, int poff) Name = (PSZ)PlugSubAlloc(g, memp, strlen(cfp->Name) + 1); strcpy(Name, cfp->Name); - Poff = poff; - Buf_Type = cfp->Type; + if (!(cfp->Flags & U_SPECIAL)) { + Poff = poff; + Buf_Type = cfp->Type; - if ((Clen = GetTypeSize(Buf_Type, cfp->Length)) <= 0) { - sprintf(g->Message, MSG(BAD_COL_TYPE), GetTypeName(Buf_Type), Name); - return -1; - } // endswitch + if ((Clen = GetTypeSize(Buf_Type, cfp->Length)) <= 0) { + sprintf(g->Message, MSG(BAD_COL_TYPE), GetTypeName(Buf_Type), Name); + return -1; + } // endswitch - strcpy(F.Type, GetFormatType(Buf_Type)); - F.Length = cfp->Length; - F.Prec = cfp->Prec; - Offset = (cfp->Offset < 0) ? poff : cfp->Offset; - Long = cfp->Length; - Opt = cfp->Opt; - Key = cfp->Key; -//Freq = cfp->Freq; + strcpy(F.Type, GetFormatType(Buf_Type)); + F.Length = cfp->Length; + F.Prec = cfp->Prec; + Offset = (cfp->Offset < 0) ? poff : cfp->Offset; + Long = cfp->Length; + Opt = cfp->Opt; + Key = cfp->Key; +// Freq = cfp->Freq; - if (cfp->Remark && *cfp->Remark) { - Desc = (PSZ)PlugSubAlloc(g, memp, strlen(cfp->Remark) + 1); - strcpy(Desc, cfp->Remark); - } // endif Remark + if (cfp->Remark && *cfp->Remark) { + Desc = (PSZ)PlugSubAlloc(g, memp, strlen(cfp->Remark) + 1); + strcpy(Desc, cfp->Remark); + } // endif Remark - if (cfp->Datefmt) { - Decode = (PSZ)PlugSubAlloc(g, memp, strlen(cfp->Datefmt) + 1); - strcpy(Decode, cfp->Datefmt); - } // endif Datefmt + if (cfp->Datefmt) { + Decode = (PSZ)PlugSubAlloc(g, memp, strlen(cfp->Datefmt) + 1); + strcpy(Decode, cfp->Datefmt); + } // endif Datefmt + + } // endif special if (cfp->Fieldfmt) { Fmt = (PSZ)PlugSubAlloc(g, memp, strlen(cfp->Fieldfmt) + 1); @@ -416,7 +419,7 @@ int COLDEF::Define(PGLOBAL g, void *memp, PCOLINFO cfp, int poff) } // endif Fieldfmt Flags = cfp->Flags; - return (Flags & U_VIRTUAL) ? 0 : Long; + return (Flags & (U_VIRTUAL|U_SPECIAL)) ? 0 : Long; } // end of Define /* ------------------------- End of RelDef --------------------------- */ diff --git a/storage/connect/reldef.h b/storage/connect/reldef.h index b21488c7ded..e443374b676 100644 --- a/storage/connect/reldef.h +++ b/storage/connect/reldef.h @@ -175,6 +175,7 @@ class DllExport COLDEF : public COLCRT { /* Column description block friend class MYCAT; friend class COLBLK; friend class DBFFAM; + friend class TDBASE; public: COLDEF(void); // Constructor diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp index 860a1304a14..b538383b766 100644 --- a/storage/connect/tabfmt.cpp +++ b/storage/connect/tabfmt.cpp @@ -339,7 +339,7 @@ PQRYRES CSVColumns(PGLOBAL g, const char *fn, char sep, char q, /* Allocate the structures used to refer to the result set. */ /*********************************************************************/ qrp = PlgAllocResult(g, ncol, imax, IDS_COLUMNS + 3, - buftyp, fldtyp, length, true, false); + buftyp, fldtyp, length, false, false); qrp->Nblin = imax; if (info) diff --git a/storage/connect/table.cpp b/storage/connect/table.cpp index 3768109809e..8f12a04a71a 100644 --- a/storage/connect/table.cpp +++ b/storage/connect/table.cpp @@ -307,15 +307,17 @@ PCOL TDBASE::ColDB(PGLOBAL g, PSZ name, int num) /*****************************************************************/ if (cp) colp = cp; - else + else if (!(cdp->Flags & U_SPECIAL)) colp = MakeCol(g, cdp, cprec, i); + else if (Mode == MODE_READ) + colp = InsertSpcBlk(g, cdp); if (trace) htrc("colp=%p\n", colp); if (name || num) break; - else if (colp) + else if (colp && !colp->IsSpecial()) cprec = colp; } // endif Name @@ -339,30 +341,35 @@ PCOL TDBASE::InsertSpecialColumn(PGLOBAL g, PCOL colp) /***********************************************************************/ /* Make a special COLBLK to insert in a table. */ /***********************************************************************/ -PCOL TDBASE::InsertSpcBlk(PGLOBAL g, PCOLUMN cp) +PCOL TDBASE::InsertSpcBlk(PGLOBAL g, PCOLDEF cdp) { - char *name = (char*)cp->GetName(); - PCOL colp; +//char *name = cdp->GetName(); + char *name = cdp->GetFmt(); + PCOLUMN cp; + PCOL colp; - if (!strcmp(name, "FILEID")) { -// !strcmp(name, "SERVID")) { + cp= new(g) COLUMN(cdp->GetName()); + cp->SetTo_Table(To_Table); + + if (!stricmp(name, "FILEID") || + !stricmp(name, "SERVID")) { if (!To_Def || !(To_Def->GetPseudo() & 2)) { sprintf(g->Message, MSG(BAD_SPEC_COLUMN)); return NULL; } // endif Pseudo -// if (!strcmp(name, "FILEID")) + if (!stricmp(name, "FILEID")) colp = new(g) FIDBLK(cp); -// else -// colp = new(g) SIDBLK(cp); + else + colp = new(g) SIDBLK(cp); - } else if (!strcmp(name, "TABID")) { + } else if (!stricmp(name, "TABID")) { colp = new(g) TIDBLK(cp); -//} else if (!strcmp(name, "CONID")) { +//} else if (!stricmp(name, "CONID")) { // colp = new(g) CIDBLK(cp); - } else if (!strcmp(name, "ROWID")) { + } else if (!stricmp(name, "ROWID")) { colp = new(g) RIDBLK(cp, false); - } else if (!strcmp(name, "ROWNUM")) { + } else if (!stricmp(name, "ROWNUM")) { colp = new(g) RIDBLK(cp, true); } else { sprintf(g->Message, MSG(BAD_SPECIAL_COL), name); diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp index 030f5760601..6d91a444d5e 100644 --- a/storage/connect/tabmysql.cpp +++ b/storage/connect/tabmysql.cpp @@ -194,6 +194,7 @@ bool MYSQLDEF::ParseURL(PGLOBAL g, char *url) if (trace) htrc("server: %s Tabname: %s", url, Tabname); + Server = url; return GetServerInfo(g, url); } else { // URL, parse it @@ -216,8 +217,10 @@ bool MYSQLDEF::ParseURL(PGLOBAL g, char *url) if (!(Hostname = strchr(Username, '@'))) { strcpy(g->Message, "No host specified in URL"); return true; - } else + } else { *Hostname++ = 0; // End Username + Server = Hostname; + } // endif Hostname if ((Password = strchr(Username, ':'))) { *Password++ = 0; // End username @@ -308,6 +311,7 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) Username = Cat->GetStringCatInfo(g, "User", "*"); Password = Cat->GetStringCatInfo(g, "Password", NULL); Portnumber = Cat->GetIntCatInfo("Port", GetDefaultPort()); + Server = Hostname; } else if (ParseURL(g, url)) return TRUE; @@ -327,6 +331,7 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) Username = Cat->GetStringCatInfo(g, "User", "*"); Password = Cat->GetStringCatInfo(g, "Password", NULL); Portnumber = Cat->GetIntCatInfo("Port", GetDefaultPort()); + Server = Hostname; } else { char *locdb = Database; @@ -365,13 +370,14 @@ PTDB MYSQLDEF::GetTable(PGLOBAL g, MODE m) TDBMYSQL::TDBMYSQL(PMYDEF tdp) : TDBASE(tdp) { if (tdp) { - Host = tdp->GetHostname(); - Database = tdp->GetDatabase(); - Tabname = tdp->GetTabname(); - Srcdef = tdp->GetSrcdef(); - User = tdp->GetUsername(); - Pwd = tdp->GetPassword(); - Port = tdp->GetPortnumber(); + Host = tdp->Hostname; + Database = tdp->Database; + Tabname = tdp->Tabname; + Srcdef = tdp->Srcdef; + User = tdp->Username; + Pwd = tdp->Password; + Server = tdp->Server; + Port = tdp->Portnumber; Isview = tdp->Isview; Prep = tdp->Bind; Delayed = tdp->Delayed; @@ -382,6 +388,7 @@ TDBMYSQL::TDBMYSQL(PMYDEF tdp) : TDBASE(tdp) Srcdef = NULL; User = NULL; Pwd = NULL; + Server = NULL; Port = 0; Isview = FALSE; Prep = FALSE; @@ -473,10 +480,11 @@ bool TDBMYSQL::MakeSelect(PGLOBAL g) if (Columns) { for (colp = Columns; colp; colp = colp->GetNext()) - if (colp->IsSpecial()) { - strcpy(g->Message, MSG(NO_SPEC_COL)); - return TRUE; - } else { + if (!colp->IsSpecial()) { +// if (colp->IsSpecial()) { +// strcpy(g->Message, MSG(NO_SPEC_COL)); +// return TRUE; +// } else { if (b) strcat(Query, ", "); else @@ -519,10 +527,11 @@ bool TDBMYSQL::MakeInsert(PGLOBAL g) return FALSE; // already done for (colp = Columns; colp; colp = colp->GetNext()) - if (colp->IsSpecial()) { - strcpy(g->Message, MSG(NO_SPEC_COL)); - return TRUE; - } else { + if (!colp->IsSpecial()) { +// if (colp->IsSpecial()) { +// strcpy(g->Message, MSG(NO_SPEC_COL)); +// return TRUE; +// } else { len += (strlen(colp->GetName()) + 4); ((PMYCOL)colp)->Rank = Nparm++; } // endif colp @@ -1232,7 +1241,7 @@ void MYSQLCOL::ReadColumn(PGLOBAL g) if (trace) htrc("MySQL ReadColumn: name=%s buf=%s\n", Name, buf); - Value->SetValue_char(buf, Long); + Value->SetValue_char(buf, min((unsigned)Long, strlen(buf))); } else { if (Nullable) Value->SetNull(true); diff --git a/storage/connect/tabmysql.h b/storage/connect/tabmysql.h index 16e2d650229..2573259ec3c 100644 --- a/storage/connect/tabmysql.h +++ b/storage/connect/tabmysql.h @@ -49,6 +49,7 @@ class MYSQLDEF : public TABDEF {/* Logical table description */ PSZ Srcdef; /* The source table SQL definition */ PSZ Username; /* User logon name */ PSZ Password; /* Password logon info */ + PSZ Server; /* PServerID */ int Portnumber; /* MySQL port number (0 = default) */ bool Isview; /* TRUE if this table is a MySQL view */ bool Bind; /* Use prepared statement on insert */ @@ -77,6 +78,7 @@ class TDBMYSQL : public TDBASE { virtual void ResetDB(void) {N = 0;} virtual int RowNumber(PGLOBAL g, bool b = FALSE); virtual bool IsView(void) {return Isview;} + virtual PSZ GetServer(void) {return Server;} void SetDatabase(LPCSTR db) {Database = (char*)db;} // Database routines @@ -110,6 +112,7 @@ class TDBMYSQL : public TDBASE { char *Database; // Database to be used by server char *Tabname; // External table name char *Srcdef; // The source table SQL definition + char *Server; // The server ID char *Query; // Points to SQL query char *Qbuf; // Used for not prepared insert bool Fetched; // True when fetch was done diff --git a/storage/connect/tabodbc.h b/storage/connect/tabodbc.h index 645426eef78..a470655bd11 100644 --- a/storage/connect/tabodbc.h +++ b/storage/connect/tabodbc.h @@ -71,10 +71,11 @@ class TDBODBC : public TDBASE { // Methods virtual PTDB CopyOne(PTABS t); virtual int GetRecpos(void); - virtual PSZ GetFile(PGLOBAL g); + virtual PSZ GetFile(PGLOBAL g); virtual void SetFile(PGLOBAL g, PSZ fn); virtual void ResetSize(void); virtual int GetAffectedRows(void) {return AftRows;} + virtual PSZ GetServer(void) {return "ODBC";} // Database routines virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); diff --git a/storage/connect/tabsys.cpp b/storage/connect/tabsys.cpp index c5186f42666..a7fc9346d1f 100644 --- a/storage/connect/tabsys.cpp +++ b/storage/connect/tabsys.cpp @@ -36,7 +36,9 @@ #include "global.h" #include "plgdbsem.h" #include "reldef.h" -//#include "xobject.h" +#if !defined(WIN32) +#include "osutil.h" +#endif // !WIN32 #include "filamtxt.h" #include "tabdos.h" #include "tabsys.h" @@ -320,7 +322,11 @@ int TDBINI::DeleteDB(PGLOBAL g, int irc) break; case RC_FX: while (ReadDB(g) == RC_OK) - WritePrivateProfileString(Section, NULL, NULL, Ifile); + if (!WritePrivateProfileString(Section, NULL, NULL, Ifile)) { + sprintf(g->Message, "Error %d accessing %s", + GetLastError(), Ifile); + return RC_FX; + } // endif break; default: @@ -328,7 +334,11 @@ int TDBINI::DeleteDB(PGLOBAL g, int irc) strcpy(g->Message, MSG(NO_SECTION_NAME)); return RC_FX; } else - WritePrivateProfileString(Section, NULL, NULL, Ifile); + if (!WritePrivateProfileString(Section, NULL, NULL, Ifile)) { + sprintf(g->Message, "Error %d accessing %s", + GetLastError(), Ifile); + return RC_FX; + } // endif rc } // endswitch irc @@ -461,13 +471,13 @@ void INICOL::ReadColumn(PGLOBAL g) Valbuf[Long] = '\0'; break; default: - GetPrivateProfileString(tdbp->Section, Name, "", + GetPrivateProfileString(tdbp->Section, Name, "\b", Valbuf, Long + 1, tdbp->Ifile); break; } // endswitch Flag // Missing keys are interpreted as null values - if (!strcmp(Valbuf, "")) { + if (!strcmp(Valbuf, "\b")) { if (Nullable) Value->SetNull(true); @@ -485,6 +495,7 @@ void INICOL::ReadColumn(PGLOBAL g) void INICOL::WriteColumn(PGLOBAL g) { char *p; + bool rc; PTDBINI tdbp = (PTDBINI)To_Tdb; if (trace > 1) @@ -510,11 +521,12 @@ void INICOL::WriteColumn(PGLOBAL g) if (tdbp->Mode == MODE_UPDATE) { strcpy(g->Message, MSG(NO_SEC_UPDATE)); longjmp(g->jumper[g->jump_level], 31); - } else { + } else if (*p) { tdbp->Section = p; - return; - } // endif Mode + } else + tdbp->Section = NULL; + return; } else if (!tdbp->Section) { strcpy(g->Message, MSG(SEC_NAME_FIRST)); longjmp(g->jumper[g->jump_level], 31); @@ -523,8 +535,16 @@ void INICOL::WriteColumn(PGLOBAL g) /*********************************************************************/ /* Updating must be done only when not in checking pass. */ /*********************************************************************/ - if (Status) - WritePrivateProfileString(tdbp->Section, Name, p, tdbp->Ifile); + if (Status) { + rc = WritePrivateProfileString(tdbp->Section, Name, p, tdbp->Ifile); + + if (!rc) { + sprintf(g->Message, "Error %d writing to %s", + GetLastError(), tdbp->Ifile); + longjmp(g->jumper[g->jump_level], 31); + } // endif rc + + } // endif Status } // end of WriteColumn @@ -724,14 +744,21 @@ int TDBXIN::DeleteDB(PGLOBAL g, int irc) if (irc == RC_EF) { } else if (irc == RC_FX) { for (Section = Seclist; *Section; Section += (strlen(Section) + 1)) - WritePrivateProfileString(Section, NULL, NULL, Ifile); + if (!WritePrivateProfileString(Section, NULL, NULL, Ifile)) { + sprintf(g->Message, "Error %d accessing %s", + GetLastError(), Ifile); + return RC_FX; + } // endif - } else if (Section) { - WritePrivateProfileString(Section, Keycur, NULL, Ifile); - } else { + } else if (!Section) { strcpy(g->Message, MSG(NO_SECTION_NAME)); return RC_FX; - } // endif's + } else + if (!WritePrivateProfileString(Section, Keycur, NULL, Ifile)) { + sprintf(g->Message, "Error %d accessing %s", + GetLastError(), Ifile); + return RC_FX; + } // endif return RC_OK; } // end of DeleteDB @@ -792,6 +819,7 @@ void XINCOL::ReadColumn(PGLOBAL g) void XINCOL::WriteColumn(PGLOBAL g) { char *p; + bool rc; PTDBXIN tdbp = (PTDBXIN)To_Tdb; if (trace > 1) @@ -813,20 +841,22 @@ void XINCOL::WriteColumn(PGLOBAL g) if (tdbp->Mode == MODE_UPDATE) { strcpy(g->Message, MSG(NO_SEC_UPDATE)); longjmp(g->jumper[g->jump_level], 31); - } else { + } else if (*p) { tdbp->Section = p; - return; - } // endif Mode + } else + tdbp->Section = NULL; + return; } else if (Flag == 2) { if (tdbp->Mode == MODE_UPDATE) { strcpy(g->Message, MSG(NO_KEY_UPDATE)); longjmp(g->jumper[g->jump_level], 31); - } else { + } else if (*p) { tdbp->Keycur = p; - return; - } // endif Mode + } else + tdbp->Keycur = NULL; + return; } else if (!tdbp->Section || !tdbp->Keycur) { strcpy(g->Message, MSG(SEC_KEY_FIRST)); longjmp(g->jumper[g->jump_level], 31); @@ -835,8 +865,16 @@ void XINCOL::WriteColumn(PGLOBAL g) /*********************************************************************/ /* Updating must be done only when not in checking pass. */ /*********************************************************************/ - if (Status) - WritePrivateProfileString(tdbp->Section, tdbp->Keycur, p, tdbp->Ifile); + if (Status) { + rc = WritePrivateProfileString(tdbp->Section, tdbp->Keycur, p, tdbp->Ifile); + + if (!rc) { + sprintf(g->Message, "Error %d writing to %s", + GetLastError(), tdbp->Ifile); + longjmp(g->jumper[g->jump_level], 31); + } // endif rc + + } // endif Status } // end of WriteColumn diff --git a/storage/connect/tabtbl.cpp b/storage/connect/tabtbl.cpp index 534834350af..2ed6c150d85 100644 --- a/storage/connect/tabtbl.cpp +++ b/storage/connect/tabtbl.cpp @@ -380,7 +380,8 @@ int TDBTBL::GetMaxSize(PGLOBAL g) void TDBTBL::ResetDB(void) { for (PCOL colp = Columns; colp; colp = colp->GetNext()) - if (colp->GetAmType() == TYPE_AM_TABID) + if (colp->GetAmType() == TYPE_AM_TABID || + colp->GetAmType() == TYPE_AM_SRVID) colp->COLBLK::Reset(); for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext()) @@ -492,7 +493,8 @@ int TDBTBL::ReadDB(PGLOBAL g) // Check and initialize the subtable columns for (PCOL cp = Columns; cp; cp = cp->GetNext()) - if (cp->GetAmType() == TYPE_AM_TABID) + if (cp->GetAmType() == TYPE_AM_TABID || + cp->GetAmType() == TYPE_AM_SRVID) cp->COLBLK::Reset(); else if (((PPRXCOL)cp)->Init(g) && !Accept) return RC_FX; diff --git a/storage/connect/tabutil.cpp b/storage/connect/tabutil.cpp index 6e5f6784d3a..110c53c33b2 100644 --- a/storage/connect/tabutil.cpp +++ b/storage/connect/tabutil.cpp @@ -159,7 +159,7 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, /* Allocate the structures used to refer to the result set. */ /**********************************************************************/ qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3, - buftyp, fldtyp, length, true, true); + buftyp, fldtyp, length, false, true); // Some columns must be renamed for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next) @@ -226,8 +226,12 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, crp->Kdata->SetValue((fp->null_ptr != 0) ? 1 : 0, i); crp = crp->Next; // Remark - fld = fp->comment.str; - crp->Kdata->SetValue(fld, fp->comment.length, i); + + // For Valgrind + if (fp->comment.length > 0 && (fld = fp->comment.str)) + crp->Kdata->SetValue(fld, fp->comment.length, i); + else + crp->Kdata->Reset(i); crp = crp->Next; // New crp->Kdata->SetValue((fmt) ? fmt : (char*) "", i); @@ -364,7 +368,11 @@ PTDBASE TDBPRX::GetSubTable(PGLOBAL g, PTABLE tabp, bool b) #if defined(MYSQL_SUPPORT) // Access sub-table via MySQL API if (!(tdbp= cat->GetTable(g, tabp, MODE_READ, "MYPRX"))) { - sprintf(g->Message, "Cannot access %s.%s", db, name); + char buf[MAX_STR]; + + strcpy(buf, g->Message); + sprintf(g->Message, "Error accessing %s.%s: %s", db, name, buf); + hc->tshp = NULL; goto err; } // endif Define diff --git a/storage/connect/tabutil.h b/storage/connect/tabutil.h index ddf6c2eb601..56c4667b258 100644 --- a/storage/connect/tabutil.h +++ b/storage/connect/tabutil.h @@ -70,6 +70,7 @@ class DllExport TDBPRX : public TDBASE { virtual int GetRecpos(void) {return Tdbp->GetRecpos();} virtual void ResetDB(void) {Tdbp->ResetDB();} virtual int RowNumber(PGLOBAL g, bool b = FALSE); + virtual PSZ GetServer(void) {return (Tdbp) ? Tdbp->GetServer() : "?";} // Database routines virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); diff --git a/storage/connect/tabwmi.cpp b/storage/connect/tabwmi.cpp index dbd4330a2f9..1c626a06256 100644 --- a/storage/connect/tabwmi.cpp +++ b/storage/connect/tabwmi.cpp @@ -211,7 +211,7 @@ PQRYRES WMIColumns(PGLOBAL g, char *nsp, char *cls, bool info) /* Allocate the structures used to refer to the result set. */ /*********************************************************************/ qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3, - buftyp, fldtyp, length, true, true); + buftyp, fldtyp, length, false, true); if (info) return qrp; diff --git a/storage/connect/valblk.cpp b/storage/connect/valblk.cpp index cee4571bc0d..55f9da7571b 100644 --- a/storage/connect/valblk.cpp +++ b/storage/connect/valblk.cpp @@ -592,7 +592,7 @@ void CHRBLK::SetValue(char *sp, uint len, int n) #endif if (sp) - memcpy(p, sp, Long); + memcpy(p, sp, min((unsigned)Long, len)); if (Blanks) { // Suppress eventual ending zero and right fill with blanks @@ -712,7 +712,7 @@ void *CHRBLK::GetValPtrEx(int n) // For VCT blocks we must remove rightmost blanks. char *p = Valp + Long; - for (p--; *p == ' ' && p >= Valp; p--) ; + for (p--; p >= Valp && *p == ' '; p--) ; *(++p) = '\0'; } // endif Blanks diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index 10e3be7e889..e59575534c9 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -583,12 +583,12 @@ template <> void TYPVAL::SetValue_char(char *p, int n) { if (p) { - char *p2, buf[32]; + char buf[32]; - for (p2 = p + n; p < p2 && *p == ' '; p++) ; + for (; n > 0 && *p == ' '; p++) + n--; - n = min(p2 - p, 31); - memcpy(buf, p, n); + memcpy(buf, p, min(n, 31)); buf[n] = '\0'; Tval = atof(buf); @@ -875,12 +875,16 @@ TYPVAL::TYPVAL(PSZ s) : VALUE(TYPE_STRING) TYPVAL::TYPVAL(PGLOBAL g, PSZ s, int n, int c) : VALUE(TYPE_STRING) { - assert(Type == TYPE_STRING && (g || s)); + assert(Type == TYPE_STRING); Len = (g) ? n : strlen(s); - if (g && !s) { - Strp = (char *)PlugSubAlloc(g, NULL, Len + 1); - Strp[Len] = '\0'; + if (!s) { + if (g) { + Strp = (char *)PlugSubAlloc(g, NULL, Len + 1); + Strp[Len] = '\0'; + } else + assert(false); + } else Strp = s; @@ -912,15 +916,21 @@ bool TYPVAL::SetValue_pval(PVAL valp, bool chktype) void TYPVAL::SetValue_char(char *p, int n) { if (p) { - n = min(n, Len); - strncpy(Strp, p, n); + if ((n = min(n, Len))) { + strncpy(Strp, p, n); - for (p = Strp + n - 1; (*p == ' ' || *p == '\0') && p >= Strp; p--) ; +// for (p = Strp + n - 1; p >= Strp && (*p == ' ' || *p == '\0'); p--) ; + for (p = Strp + n - 1; p >= Strp; p--) + if (*p && *p != ' ') + break; - *(++p) = '\0'; + *(++p) = '\0'; - if (trace > 1) - htrc(" Setting string to: '%s'\n", Strp); + if (trace > 1) + htrc(" Setting string to: '%s'\n", Strp); + + } else + Reset(); Null = false; } else { diff --git a/storage/connect/value.h b/storage/connect/value.h index 62b4ea4617a..d94c1da6920 100644 --- a/storage/connect/value.h +++ b/storage/connect/value.h @@ -83,6 +83,7 @@ class DllExport VALUE : public BLOCK { virtual void SetPrec(int prec) {Prec = prec;} bool IsNull(void) {return Null;} void SetNull(bool b) {Null = b;} + bool GetNullable(void) {return Nullable;} void SetNullable(bool b) {Nullable = b;} int GetType(void) {return Type;} int GetClen(void) {return Clen;} diff --git a/storage/connect/xindex.cpp b/storage/connect/xindex.cpp index 4a0067e30be..1086e46650b 100755 --- a/storage/connect/xindex.cpp +++ b/storage/connect/xindex.cpp @@ -1832,8 +1832,9 @@ int XINDXS::Range(PGLOBAL g, int limit, bool incl) /*********************************************************************/ if (xp->GetType() == TYPE_CONST) { kp->Valp->SetValue_pval(xp->GetValue(), !kp->Prefix); + k = FastFind(Nval); - if ((k = FastFind(Nval)) < Num_K) + if (k < Num_K || Op != OP_EQ) if (limit) n = (Mul) ? k : kp->Val_K; else @@ -2797,7 +2798,7 @@ bool KXYCOL::Init(PGLOBAL g, PCOL colp, int n, bool sm, int kln) if (Asc) IsSorted = colp->GetOpt() < 0; -//MayHaveNulls = colp->HasNulls(); +//SetNulls(colp->IsNullable()); for when null columns will be indexable return false; } // end of Init @@ -2956,6 +2957,11 @@ void KXYCOL::InitBinFind(void *vp) void KXYCOL::FillValue(PVAL valp) { valp->SetValue_pvblk(Kblp, Val_K); + + // Set null when applicable (NIY) +//if (valp->GetNullable()) +// valp->SetNull(valp->IsZero()); + } // end of FillValue /***********************************************************************/ diff --git a/storage/connect/xindex.h b/storage/connect/xindex.h index 6ff2b4be237..b7e597b9e6d 100644 --- a/storage/connect/xindex.h +++ b/storage/connect/xindex.h @@ -473,10 +473,10 @@ class KXYCOL: public BLOCK { protected: // Members - PXCOL Next; // To next in the key part list + PXCOL Next; // To next in the key part list PXCOL Previous; // To previous in the key part list PKXBASE Kxp; // To the INDEX class block - PCOL Colp; // To matching object if a column + PCOL Colp; // To matching object if a column bool IsSorted; // true if column is already sorted bool Asc; // true for ascending sort, false for Desc MBLOCK Keys; // Data array allocation block diff --git a/storage/connect/xtable.h b/storage/connect/xtable.h index 7ef2d26136c..98c7305acd4 100644 --- a/storage/connect/xtable.h +++ b/storage/connect/xtable.h @@ -113,6 +113,7 @@ class DllExport TDB: public TBX { // Table Descriptor Block. {fprintf(f, "%s AM(%d)\n", m, GetAmType());} virtual void Print(PGLOBAL g, FILE *f, uint n); virtual void Print(PGLOBAL g, char *ps, uint z); + virtual PSZ GetServer(void) = 0; // Database pure virtual routines virtual PCOL ColDB(PGLOBAL g, PSZ name, int num) = 0; @@ -192,13 +193,14 @@ class DllExport TDBASE : public TDB { virtual void ResetSize(void) {MaxSize = -1;} virtual void RestoreNrec(void) {} virtual int ResetTableOpt(PGLOBAL g, bool dox); + virtual PSZ GetServer(void) {return "Current";} // Database routines virtual PCOL ColDB(PGLOBAL g, PSZ name, int num); virtual PCOL MakeCol(PGLOBAL, PCOLDEF, PCOL, int) {assert(false); return NULL;} virtual PCOL InsertSpecialColumn(PGLOBAL g, PCOL colp); - virtual PCOL InsertSpcBlk(PGLOBAL g, PCOLUMN cp); + virtual PCOL InsertSpcBlk(PGLOBAL g, PCOLDEF cdp); virtual void MarkDB(PGLOBAL g, PTDB tdb2); protected: